| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Registry.Npm
Description
The npm data plane: the effectful Ecluse.Core.Registry fields over
http-client.
This module is the network half of the npm protocol boundary. Where
Ecluse.Core.Registry.Npm.Wire and Ecluse.Core.Registry.Npm.Project are the pure decode
and projection, this is the side-effecting fetch and publish: newNpmClient
assembles a Ecluse.Core.Registry.RegistryClient whose effectful fields talk to a
registry over plain HTTP, and whose parse* fields are the pure projection
re-exported through the handle.
It speaks the npm registry protocol directly with http-client, never
amazonka: the control plane (the GetAuthorizationToken mint, the mirror
queue) is amazonka's job behind separate handles, but the data plane: fetch
metadata, stream a tarball, publish: is ordinary HTTPS+JSON, identical across
every npm-speaking backend. Keeping the streaming path off amazonka's
conduit/ResourceT machinery is exactly what makes bounded-memory artifact
proxying tractable.
Streaming and buffering
artifactRequest marks its request non-decompressing
so a tarball is opaque binary that must reach the client byte-for-byte. The
request is exposed so the web layer can relay the open body __without buffering
the whole artifact in memory__. The handle's fetchArtifact
field, by contrast, buffers (its RegistryResponse return is whole bytes) and
is for the mirror worker, which must read the entire artifact to verify its
integrity before publishing.
Authentication
The client accepts an injected bearer token and attaches it to every request; it never originates credential policy. Which token to send on which request is the request pipeline's authority model, decided upstream of this module.
Synopsis
- data NpmClientConfig = NpmClientConfig {
- npmBaseUrl :: Text
- npmManager :: Manager
- npmToken :: Maybe Secret
- npmLimits :: Limits
- defaultNpmConfig :: Manager -> NpmClientConfig
- publicRegistryBaseUrl :: Text
- publicRegistryUrl :: RegistryUrl
- newNpmClient :: NpmClientConfig -> IO RegistryClient
- newNpmPublishClient :: NpmClientConfig -> IO (Maybe Secret) -> IO RegistryClient
- fetchMetadataForm :: NpmClientConfig -> MetadataForm -> Validators -> PackageName -> IO RegistryResponse
- relayPublishDocument :: NpmClientConfig -> PackageName -> ByteString -> IO (Either UrlFormationError PublishRelayResponse)
- newtype ResponseBoundExceeded = ResponseBoundExceeded LimitError
Construction
data NpmClientConfig Source #
Everything newNpmClient needs to talk to one npm-speaking registry: the
base URL, the shared HTTP Manager, and an optional injected bearer token.
The Manager is shared (it owns the connection pool), so it is taken rather than
built here: the same one the composition root reuses across requests. The token
is whatever the request pipeline decided this client should present; this module
never chooses it.
Constructors
| NpmClientConfig | |
Fields
| |
defaultNpmConfig :: Manager -> NpmClientConfig Source #
An anonymous client config against the public registry (publicRegistryBaseUrl),
using the given shared Manager and the secure-default response bounds
(defaultLimits). Override npmBaseUrlnpmTokennpmLimits for
a managed backend or a per-deployment budget.
publicRegistryBaseUrl :: Text Source #
The canonical public npm registry base URL, https://registry.npmjs.org.
The default target when no managed backend is configured.
publicRegistryUrl :: RegistryUrl Source #
The canonical public npm registry as an https RegistryUrl: the
publicRegistryBaseUrl text, https by construction. The default ECLUSE_PUBLIC_UPSTREAM
when none is configured.
newNpmClient :: NpmClientConfig -> IO RegistryClient Source #
Assemble a Ecluse.Core.Registry.RegistryClient for the npm protocol over the given configuration.
The effectful fields close over the config's Manager and token and speak npm
over HTTP; the parse* fields are the pure projection from
Ecluse.Core.Registry.Npm.Project, re-exported through the handle. The handle's
fetchMetadata requests the Abbreviated form
unconditionally; the richer fetchMetadataForm (for the full packument and
relayed validators) is exposed separately for the request pipeline.
newNpmPublishClient :: NpmClientConfig -> IO (Maybe Secret) -> IO RegistryClient Source #
Build an npm RegistryClient whose publishArtifact and
fetchMetadata fields mint a fresh token per call via the provided
IO action; the remaining fields use the token in the config. The metadata read mints
because the worker's mirror-presence probe reads the mirror target through this handle,
and a managed mirror (CodeArtifact) requires auth on reads as on writes -- an anonymous
probe would be refused and the dedup would never confirm anything. For newNpmClient
the mint is the configured token, so its behaviour is unchanged.
Lower-level fetch
fetchMetadataForm :: NpmClientConfig -> MetadataForm -> Validators -> PackageName -> IO RegistryResponse Source #
Fetch a package's metadata in the requested MetadataForm, relaying any
conditional-GET Validators. The bounded-read fetch used by the handle's
fetchMetadata; the request pipeline calls this directly when it
needs the full packument or wants to revalidate against an ETag.
The body is read chunk-by-chunk through boundedRead against
the config's npmLimits, not buffered whole: a hostile or compromised upstream
returning a body larger than maxBodyBytes is aborted
fail-closed rather than exhausting memory.
First-party publish relay
relayPublishDocument :: NpmClientConfig -> PackageName -> ByteString -> IO (Either UrlFormationError PublishRelayResponse) Source #
Relay a client's npm publish document to the publication target and return the
target's own response: the first-party publish primitive behind the PUT /{pkg}
serve path.
Response-bound breach
newtype ResponseBoundExceeded Source #
Raised when an upstream metadata body breaches a Limits
ceiling: the body-size guard here, or: surfaced through the same type by the serve
pipeline: the version-count or nesting-depth guard.
Constructors
| ResponseBoundExceeded LimitError |
Instances
| Exception ResponseBoundExceeded Source # | |
Defined in Ecluse.Core.Registry.Npm | |
| Show ResponseBoundExceeded Source # | |
Defined in Ecluse.Core.Registry.Npm Methods showsPrec :: Int -> ResponseBoundExceeded -> ShowS # show :: ResponseBoundExceeded -> String # showList :: [ResponseBoundExceeded] -> ShowS # | |
| Eq ResponseBoundExceeded Source # | |
Defined in Ecluse.Core.Registry.Npm Methods (==) :: ResponseBoundExceeded -> ResponseBoundExceeded -> Bool # (/=) :: ResponseBoundExceeded -> ResponseBoundExceeded -> Bool # | |