| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Registry
Description
The registry-protocol vocabulary: the payload and typed-fault types every registry-facing capability shares.
This is the ecosystem (protocol) axis' common ground (see
docs/architecture/registry-model.md → "Registry Abstraction"): the raw fetched
document (RegistryResponse), the mirror-write descriptor (MirrorArtifact) and
the digest selector (firstHashValue) that reads it, and one typed fault channel
per exchange -- FetchFault for a metadata read,
PublishFault for the mirror write, PublishRelayFault for the first-party
relay, with UrlFormationError the protocol-independent request-formation
failure they all share. The capabilities that speak a protocol over these types
live beside them: the metadata read handle in Ecluse.Core.Registry.Metadata,
the mirror write's codec-over-transport split in Ecluse.Core.Registry.Publish,
and each ecosystem's capability record in Ecluse.Core.Registry.Adapter.
Two design points are load-bearing:
- Failures are values. Each exchange reports every failure -- transport
included -- in its typed channel, never a throw, so a consumer's fall-through
or retry-vs-drop decision is total at the call site
(parse, don't validate; see
docs/architecture/fault-model.md). - The vocabulary carries no authentication. Protocol and auth are orthogonal axes: every managed npm registry (AWS CodeArtifact, GCP Artifact Registry, a self-hosted Verdaccio) speaks the same npm protocol and differs only in how a bearer token is minted, which lives behind the separate Ecluse.Core.Credential handle. So one protocol implementation is reused across every cloud rather than near-duplicated per provider.
Synopsis
- newtype RegistryResponse = RegistryResponse {}
- data MirrorArtifact = MirrorArtifact {}
- firstHashValue :: HashAlg -> MirrorArtifact -> Maybe Text
- newtype ParseError = ParseError {}
- data FetchFault
- newtype PublishError = PublishError {}
- data PublishFault
- data UrlFormationError
- data PublishRelayResponse = PublishRelayResponse {}
- data PublishRelayFault
Fetch payload
newtype RegistryResponse Source #
A raw response fetched from a registry -- the unparsed bytes of a metadata
document, as returned by fetchMetadata. It is kept opaque-of-bytes here so the
protocol/data plane (fetch) is separate from parsing: a parse* field turns a
RegistryResponse into a domain type.
Constructors
| RegistryResponse | |
Fields
| |
Instances
| Show RegistryResponse Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> RegistryResponse -> ShowS # show :: RegistryResponse -> String # showList :: [RegistryResponse] -> ShowS # | |
| Eq RegistryResponse Source # | |
Defined in Ecluse.Core.Registry Methods (==) :: RegistryResponse -> RegistryResponse -> Bool # (/=) :: RegistryResponse -> RegistryResponse -> Bool # | |
Publish descriptor
data MirrorArtifact Source #
The artifact descriptor a mirror publish is assembled from: the filename, integrity digests, and declared size of the artifact the worker's ingest re-evaluation re-admitted under current policy. The worker derives it entirely from current metadata -- the queue payload carries no digest or size -- so the published document can only ever name what the shared admission gate floor-checked (see Ecluse.Core.Worker.Job).
maHashes is a NonEmpty because admission refuses a digest-less version (the
integrity-presence policy), so a descriptor with nothing to verify or publish is
unrepresentable by construction.
Constructors
| MirrorArtifact | |
Fields
| |
Instances
| Show MirrorArtifact Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> MirrorArtifact -> ShowS # show :: MirrorArtifact -> String # showList :: [MirrorArtifact] -> ShowS # | |
| Eq MirrorArtifact Source # | |
Defined in Ecluse.Core.Registry Methods (==) :: MirrorArtifact -> MirrorArtifact -> Bool # (/=) :: MirrorArtifact -> MirrorArtifact -> Bool # | |
firstHashValue :: HashAlg -> MirrorArtifact -> Maybe Text Source #
The digest value of the first admitted Hash computed with the given
HashAlg, or Nothing when the artifact carries none. It reads only maHashes
and consults no ecosystem, so it lives beside the descriptor: npm's publish codec
picks the SRI and SHA1 entries this way to fill dist.integrity and
dist.shasum.
Errors
newtype ParseError Source #
Why parsing a RegistryResponse into a domain type failed. Parsing is the
boundary that turns untrusted wire data into the proxy's precise types, so a
failure is reported (not thrown): the caller decides how to respond.
Constructors
| ParseError | |
Fields
| |
Instances
| Show ParseError Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> ParseError -> ShowS # show :: ParseError -> String # showList :: [ParseError] -> ShowS # | |
| Eq ParseError Source # | |
Defined in Ecluse.Core.Registry | |
data FetchFault Source #
Why a metadata fetch could not produce a response body, reported as a value so a read-path consumer maps each cause onto its own outcome -- the serve read adapter onto the response it renders, the worker's mirror-presence probe onto its fall-through -- rather than catching a typed throw two calls away. Total over the read fetch: an unformable request URL, a response-bound breach, and a transport fault are all in this channel, so no fetch failure rides up outside the declared type.
Constructors
| FetchUrlUnformable UrlFormationError | The request URL could not be formed from configuration (an empty or unparseable base URL). |
| FetchBoundExceeded LimitError | The upstream body crossed the response-size bound and was refused fail-closed. |
| FetchTransport TransportFault | The request never completed: the transport failed before a usable body
returned (a timeout, an unreachable peer, a TLS refusal), carried as the
|
Instances
| Show FetchFault Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> FetchFault -> ShowS # show :: FetchFault -> String # showList :: [FetchFault] -> ShowS # | |
| Eq FetchFault Source # | |
Defined in Ecluse.Core.Registry | |
newtype PublishError Source #
Why publishing an artifact to a registry failed -- a genuine write fault
reported by the mirror write (mpPublishArtifact;
an Queue job is then left un-acked and retried; see
docs/architecture/cloud-backends.md).
This is the write-path fault and nothing more: forming the request URL is a
separate concern (a UrlFormationError), so a read-path fetch can no longer
surface a failure mislabelled as a publish.
Constructors
| PublishError | |
Fields
| |
Instances
| Show PublishError Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> PublishError -> ShowS # show :: PublishError -> String # showList :: [PublishError] -> ShowS # | |
| Eq PublishError Source # | |
Defined in Ecluse.Core.Registry | |
data PublishFault Source #
Why a publish could not complete, surfaced as a value rather than thrown so the mirror worker decides retry vs. drop by an exhaustive pattern match rather than by catching (and re-classifying) an exception. The cases differ in exactly that -- retryability -- which is the whole reason this is a value: a registry rejection or a transport fault is worth redelivering, an unformable URL never is.
Constructors
| PublishUrlUnformable UrlFormationError | The request URL could not be formed (e.g. an empty base URL) -- a
configuration fault carried as its |
| PublishRejected PublishError | The registry rejected the write (a non-2xx, non- |
| PublishTransport TransportFault | The write never reached the registry: the HTTP request threw before any
status returned (a connection failure, a TLS error, a timeout), carried as the
|
Instances
| Show PublishFault Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> PublishFault -> ShowS # show :: PublishFault -> String # showList :: [PublishFault] -> ShowS # | |
| Eq PublishFault Source # | |
Defined in Ecluse.Core.Registry | |
data UrlFormationError Source #
Why an upstream request URL could not be formed from configuration and an
already-parsed PackageName.
This is a protocol-independent fault shared by every request an adapter
builds -- metadata fetch, artifact fetch, and publish alike -- so a read-path
failure is reported as what it is rather than borrowing the write-path's
PublishError. It reports that the configured base URL is empty or the URL the
adapter formed could not be parsed.
Constructors
| EmptyBaseUrl | The configured base URL is empty, so no request URL can be formed. |
| UnparseableUrl Text | The formed URL string could not be parsed into a request. Carries the offending URL. |
Instances
| Show UrlFormationError Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> UrlFormationError -> ShowS # show :: UrlFormationError -> String # showList :: [UrlFormationError] -> ShowS # | |
| Eq UrlFormationError Source # | |
Defined in Ecluse.Core.Registry Methods (==) :: UrlFormationError -> UrlFormationError -> Bool # (/=) :: UrlFormationError -> UrlFormationError -> Bool # | |
data PublishRelayResponse Source #
The response from the publication target after relaying a publish document. Kept in memory (no streaming) -- the relayed body is small (typically a JSON envelope and a tarball under the target's size limit), and buffering it whole lets the proxy catch and log an exception before starting a chunked response it would otherwise abandon mid-stream.
Constructors
| PublishRelayResponse | |
Fields
| |
Instances
| Show PublishRelayResponse Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> PublishRelayResponse -> ShowS # show :: PublishRelayResponse -> String # showList :: [PublishRelayResponse] -> ShowS # | |
| Eq PublishRelayResponse Source # | |
Defined in Ecluse.Core.Registry Methods (==) :: PublishRelayResponse -> PublishRelayResponse -> Bool # (/=) :: PublishRelayResponse -> PublishRelayResponse -> Bool # | |
data PublishRelayFault Source #
Why a first-party publish relay produced no response from the publication
target, reported as a value so the serve path renders each cause directly:
an unformable target URL is the operator-misconfiguration 500, and a transport
fault or an overstepped response bound is the target-unreachable 502 (in both,
the target's own answer never arrived whole). Total over the relay: no relay
failure rides up outside the declared type.
Constructors
| RelayUrlUnformable UrlFormationError | The publication target URL could not be formed from configuration. |
| RelayTransport TransportFault | The write never produced a usable response: the transport failed,
carried as the |
| RelayBoundExceeded LimitError | The target's response body overstepped the response-size bound. |
Instances
| Show PublishRelayFault Source # | |
Defined in Ecluse.Core.Registry Methods showsPrec :: Int -> PublishRelayFault -> ShowS # show :: PublishRelayFault -> String # showList :: [PublishRelayFault] -> ShowS # | |
| Eq PublishRelayFault Source # | |
Defined in Ecluse.Core.Registry Methods (==) :: PublishRelayFault -> PublishRelayFault -> Bool # (/=) :: PublishRelayFault -> PublishRelayFault -> Bool # | |