Loading
feat(npm): slug/repository resolver (S11 Step 6, 2/4)
What
Part 2 of 4 splitting !425 (closed) (S11 Step 6). The slug/repository resolver.
Resolverwalks{slug}→namespace_id→{repo}→repository_id, composed from two small finder interfaces (NamespaceFinder,RepositoryFinder) injected at the wire boundary in Step 8.- Mirrors OCI's
internal/namespaceresolver: two-sentinel pattern (ErrNamespaceNotFound/ErrRepositoryNotFound), nil-finder panic-at-construction,%wwrapping, short-circuit on a namespace miss. Resolution.Slugcarries the resolved row's canonicalnamespaces.slug, not the raw{slug}request segment, so the downstream tarball /dist.tarballURL construction never embeds caller-supplied path bytes (per the AppSec review note below).
The npm repository row is resolved by (namespace_id, {repo}, format=npm, kind=local), excluding soft-deleted rows. The private-repo collapse to namespace_not_found for anonymous reads (AC 33) is deferred by design to the S08/S09 auth layer.
Stack
Targets dm/npm-step6-transport (part 1). Merge order: transport → resolver → middleware → integration.
Tests
resolver_test.go (unit): resolver happy / namespace-miss / repo-miss / underlying-error-at-each-tier, nil-dependency panics, canonical-slug sourcing. Integration coverage lands in part 4.
Spec / plan
- Spec: S11 npm-local — API Contracts, Error Cases (AC 32 / AC 33)
- Plan: 2026-05-11 npm-local, Step 6
Edited by Dzmitry (Dima) Meshcharakou