ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Registry.Npm.Route

Description

The npm path grammar: the request router that maps an npm-native request path to a shared Ecluse.Core.Server.Route.

classify turns an npm request -- its HTTP method and the already-mount-stripped, percent-decoded path segments -- into a Route, so the whole npm routing table is unit-testable with no server: feed it a method and segments, assert the Route. The agnostic dispatcher carries a route classifier per mount; this module is npm's, wired in at the composition root.

A PUT /{pkg} is the npm publish request, so the method is part of the match: a PUT over a bare-package path is a Publish, while every read method (GET, HEAD, …) over the same path is a Packument. The read grammar below is otherwise method-independent -- a HEAD classifies like its GET, the dispatcher answering it bodiless.

The model is deny by default: anything not explicitly recognised is Unsupported (a 404 at the edge). Three npm-specific facts shape the matching, all from the protocol research (see docs/research/reverse-engineering/npm.md §2 and §7):

  • Reserved meta-routes (/-/…) are matched first. A real package name can never begin with '-', so a leading "-" segment is unambiguously a meta-route; an unknown one is Unsupported rather than a package.
  • Scoped names arrive in two encodings. The path is percent-decoded before it reaches us, so a scoped name arrives either as one decoded segment (@scope/pkg) or as two (@scope, pkg). Both are normalised to the same PackageName here, so nothing downstream re-checks the encoding.
  • A tarball path is /{pkg}/-/{file}.tgz. The interior "-" segment and the .tgz suffix distinguish it from a packument request (/{pkg}); for a scoped package the basename drops the scope (@babel/code-framecode-frame-7.0.0.tgz). classify is the npm-side parse of the artifact coordinate: it checks the file's basename is exactly {unscoped-name}-{rest} for the requested package and reads rest as the version (mkVersion, total), yielding Tarball name version (Filename file) with the file __preserved verbatim__. A basename that does not match the package is a path-confusion attempt and denies (deny by default), never a fabricated coordinate.

Mount dispatch / prefix-stripping and the liveness/readiness routes are handled in the agnostic web layer (see docs/architecture/web-layer.md); classify only ever sees the npm-native request, so it models exactly the Routes the proxy serves.

Synopsis

Classification

classify :: Classifier Source #

Classify an npm-native request (its method and path) into a shared Route.

A PUT is the publish method, so it is dispatched first: a PUT over a bare-package path is a Publish, everything else under PUT denies. Every other method reads, taking the path through the read grammar where matching order is significant -- reserved meta-routes (a leading "-" segment) are tried first, since a real package name can never begin with '-'; only then is the path read as a package request. See the module header for the npm conventions this encodes.