| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Registry.Npm
Description
The npm read and relay data plane: the effectful metadata fetch and the
first-party publish relay over http-client.
This module is the network half of the npm read-side 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 exchange: fetchMetadataFormBounded
reads a metadata document bounded with every failure in its typed channel, and
relayPublishDocument forwards a client's own publish to the publication target.
The mirror write is not here: its protocol codec lives in
Ecluse.Core.Registry.Npm.Publish and executes through the shared transport
(Ecluse.Core.Registry.Publish).
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
The artifact request builders (artifactRequestByFile
and artifactRequestByUrl) mark their requests
non-decompressing so a tarball is opaque binary that must reach the client
byte-for-byte, and are exposed so the web layer can relay the open body
without buffering the whole artifact in memory. The mirror worker, which must
read the whole artifact to verify its integrity before publishing, buffers it
(bounded) through fetchArtifactBytes instead.
Authentication
Every request here carries an injected bearer token (or none); this module 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
- fetchMetadataFormBounded :: NpmClientConfig -> MetadataForm -> Validators -> PackageName -> IO (Either FetchFault RegistryResponse)
- relayPublishDocument :: NpmClientConfig -> PackageName -> ByteString -> IO (Either PublishRelayFault PublishRelayResponse)
Construction
data NpmClientConfig Source #
Everything this data plane 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
| |
Bounded metadata fetch
fetchMetadataFormBounded :: NpmClientConfig -> MetadataForm -> Validators -> PackageName -> IO (Either FetchFault RegistryResponse) Source #
Fetch a package's metadata in the requested MetadataForm, relaying any
conditional-GET Validators, reporting every fetch failure as a
FetchFault value: an unformable request URL, a response-bound
breach, or a transport fault (classifyTransport folds the http-client exception
into the typed channel at this edge). Total: no fetch failure escapes as an
exception, so the serve read adapter (Ecluse.Core.Registry.Npm.Metadata) threads
it straight into its own typed channel with no throw-then-catch round-trip.
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 refused fail-closed as a
FetchBoundExceeded rather than exhausting memory. The transport wrap covers the
whole exchange, the body read included: metadata is buffered before anything is
served, so a connection lost mid-body is still a pre-commit fault with a value
representation, not a half-delivered response.
First-party publish relay
relayPublishDocument :: NpmClientConfig -> PackageName -> ByteString -> IO (Either PublishRelayFault 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.