-- SPDX-FileCopyrightText: 2026 Alexandra de Wit
--
-- SPDX-License-Identifier: MIT

{- | npm's entry in the ecosystem adapter registry: the
'Ecluse.Core.Registry.Adapter.Types.RegistryAdapter' assembled from the existing
npm modules.

Pure assembly, no protocol logic of its own: every field is a function an npm
module already exports -- the path grammar ("Ecluse.Core.Registry.Npm.Route"), the
denial renderer ("Ecluse.Core.Registry.Npm.Serve"), the metadata client and served
packument assembly ("Ecluse.Core.Registry.Npm.Metadata",
"Ecluse.Core.Registry.Npm.Filter"), the artifact request builders
("Ecluse.Core.Registry.Npm.Request"), the publish relay
("Ecluse.Core.Registry.Npm"), and the mirror-write codec with the body-name
extractor the anti-shadowing guard reads through ("Ecluse.Core.Registry.Npm.Publish"),
with the name canonicaliser from "Ecluse.Core.Registry.Npm.Project".
-}
module Ecluse.Core.Registry.Npm.Adapter (
    npmAdapter,
) where

import Ecluse.Core.Ecosystem (Ecosystem (Npm))
import Ecluse.Core.Registry.Adapter.Types (
    AdapterArtifact (..),
    AdapterMetadata (..),
    AdapterPublish (..),
    AdapterServe (..),
    RegistryAdapter (..),
 )
import Ecluse.Core.Registry.Npm (
    NpmClientConfig (NpmClientConfig),
    relayPublishDocument,
 )
import Ecluse.Core.Registry.Npm.Filter (assembleMergedDocument, serialiseMergedDocument)
import Ecluse.Core.Registry.Npm.Metadata (newNpmMetadataClient)
import Ecluse.Core.Registry.Npm.Project (projectName)
import Ecluse.Core.Registry.Npm.Publish (declaredNames, npmPublishCodec)
import Ecluse.Core.Registry.Npm.Request qualified as NpmRequest
import Ecluse.Core.Registry.Npm.Route qualified as NpmRoute

{- | npm's capability record. The artifact builders ignore the response-bound and
manager parameters (npm request formation needs neither), and the publish slice
contributes protocol only: the mirror-write codec's transport (manager, credential
mint, response bound) is supplied at the composition root's marriage.
-}
npmAdapter :: RegistryAdapter
npmAdapter :: RegistryAdapter
npmAdapter =
    RegistryAdapter
        { adapterEcosystem :: Ecosystem
adapterEcosystem = Ecosystem
Npm
        , adapterServe :: AdapterServe
adapterServe =
            AdapterServe
                { serveRouter :: MountRouter
serveRouter = MountRouter
NpmRoute.npmRouter
                , serveRoutes :: NonEmpty RouteSpec
serveRoutes = NonEmpty RouteSpec
NpmRoute.npmRouteSpecs
                }
        , adapterMetadata :: AdapterMetadata
adapterMetadata =
            AdapterMetadata
                { metadataNewClient :: TracingPort
-> MetricsPort
-> Upstream
-> ManifestCaching
-> (PackageName -> MetadataError -> IO ())
-> (PackageName -> [InvalidEntry] -> IO ())
-> (PackageName -> IO ())
-> Limits
-> Manager
-> Text
-> Maybe Secret
-> MetadataClient
metadataNewClient = \TracingPort
tracing MetricsPort
metrics Upstream
upstream ManifestCaching
caching PackageName -> MetadataError -> IO ()
logFailure PackageName -> [InvalidEntry] -> IO ()
logInvalid PackageName -> IO ()
logFetch Limits
limits Manager
manager Text
baseUrl Maybe Secret
token ->
                    TracingPort
-> MetricsPort
-> Upstream
-> ManifestCaching
-> (PackageName -> MetadataError -> IO ())
-> (PackageName -> [InvalidEntry] -> IO ())
-> (PackageName -> IO ())
-> NpmClientConfig
-> MetadataClient
newNpmMetadataClient TracingPort
tracing MetricsPort
metrics Upstream
upstream ManifestCaching
caching PackageName -> MetadataError -> IO ()
logFailure PackageName -> [InvalidEntry] -> IO ()
logInvalid PackageName -> IO ()
logFetch (Text -> Manager -> Maybe Secret -> Limits -> NpmClientConfig
NpmClientConfig Text
baseUrl Manager
manager Maybe Secret
token Limits
limits)
                , metadataAssemble :: Text
-> Map SourceId CachedDoc
-> MergePlan
-> Maybe CachedDoc
-> CachedDoc
metadataAssemble = Text
-> Map SourceId CachedDoc
-> MergePlan
-> Maybe CachedDoc
-> CachedDoc
assembleMergedDocument
                , metadataSerialise :: CachedDoc -> LByteString
metadataSerialise = CachedDoc -> LByteString
serialiseMergedDocument
                }
        , adapterArtifact :: AdapterArtifact
adapterArtifact =
            AdapterArtifact
                { artifactByFile :: Limits
-> Manager
-> Text
-> Maybe Secret
-> PackageName
-> Text
-> Either UrlFormationError Request
artifactByFile = \Limits
_ Manager
_ Text
baseUrl Maybe Secret
token -> Text
-> Maybe Secret
-> PackageName
-> Text
-> Either UrlFormationError Request
NpmRequest.artifactRequestByFile Text
baseUrl Maybe Secret
token
                , artifactByUrl :: Limits
-> Manager
-> Text
-> Maybe Secret
-> Text
-> Either UrlFormationError Request
artifactByUrl = \Limits
_ Manager
_ Text
baseUrl Maybe Secret
token -> Text -> Maybe Secret -> Text -> Either UrlFormationError Request
NpmRequest.artifactRequestByUrl Text
baseUrl Maybe Secret
token
                , -- npm serves tarball bytes from the registry host itself; there is
                  -- no canonical separate files host to admit.
                  artifactHosts :: [Text]
artifactHosts = []
                }
        , adapterPublish :: AdapterPublish
adapterPublish =
            AdapterPublish
                { publishRelay :: Limits
-> Manager
-> Text
-> Maybe Secret
-> PackageName
-> ByteString
-> IO (Either PublishRelayFault PublishRelayResponse)
publishRelay = \Limits
limits Manager
manager Text
targetUrl Maybe Secret
token ->
                    NpmClientConfig
-> PackageName
-> ByteString
-> IO (Either PublishRelayFault PublishRelayResponse)
relayPublishDocument (Text -> Manager -> Maybe Secret -> Limits -> NpmClientConfig
NpmClientConfig Text
targetUrl Manager
manager Maybe Secret
token Limits
limits)
                , publishCanonicaliseName :: Text -> Maybe PackageName
publishCanonicaliseName = Either ParseError PackageName -> Maybe PackageName
forall l r. Either l r -> Maybe r
rightToMaybe (Either ParseError PackageName -> Maybe PackageName)
-> (Text -> Either ParseError PackageName)
-> Text
-> Maybe PackageName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either ParseError PackageName
projectName
                , publishDeclaredNames :: LByteString -> [Text]
publishDeclaredNames = LByteString -> [Text]
declaredNames
                , publishCodec :: PublishCodec
publishCodec = PublishCodec
npmPublishCodec
                }
        }