9.5 KiB
Capability Spec Delta: storage-cdn-rackspace (complete-storage-uri-adapters)
Package: @suaveplan/storage-cdn-rackspace
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time.
ADDED Requirements
Requirement: rackspace:// URI plugin factory
The package SHALL export rackspaceUriPlugin(options) from
./uri-plugin/uri-plugin returning a UriPlugin whose scheme is
"rackspace" and whose adapter is the supplied
RackspaceCdnAdapter. The factory SHALL validate options.container
is a non-empty string; failure raises
StorageCdnRackspaceUriError(STORAGE_CDN_RACKSPACE_URI.INVALID_URI)
synchronously.
Scenario: factory returns a UriPlugin with scheme rackspace
- WHEN
rackspaceUriPlugin({ adapter, container: "assets" })is called - THEN the returned plugin's
scheme === "rackspace",adapteris the same reference, andrunUriPluginConformancepasses
Scenario: empty container is rejected
- WHEN
rackspaceUriPlugin({ adapter, container: "" })is called - THEN the call throws with
code === "STORAGE_CDN_RACKSPACE_URI.INVALID_URI"
Verified by: src/uri-plugin/uri-plugin.test.ts::"exports a UriPlugin with scheme rackspace" AND src/uri-plugin/uri-plugin.test.ts::"rejects empty container"
Requirement: Container + object-key parsing
The plugin SHALL parse rackspace://<container>/<object-key> URIs by
taking the authority as the container and the path (minus leading /)
as the object key. The literal authority _ (or empty) SHALL rebind to
the factory's configured container. A mismatched non-_ container
SHALL raise STORAGE_CDN_RACKSPACE_URI.CONTAINER_MISMATCH.
Scenario: matching container parses successfully
- WHEN
plugin.parse("rackspace://assets/img/a.jpg")is called against a plugin withcontainer: "assets" - THEN the returned
key === "img/a.jpg"andmeta.container === "assets"
Scenario: underscore authority rebinds to configured container
- WHEN
plugin.parse("rackspace://_/img/a.jpg")is called against the same plugin - THEN the returned
key === "img/a.jpg"andmeta.container === "assets"
Scenario: mismatched container raises CONTAINER_MISMATCH
- WHEN
plugin.parse("rackspace://wrong/img/a.jpg")is called - THEN the call throws with
code === "STORAGE_CDN_RACKSPACE_URI.CONTAINER_MISMATCH"
Verified by: src/uri-plugin/uri-plugin.test.ts::"parses matching container" AND src/uri-plugin/uri-plugin.test.ts::"underscore rebinds to configured container" AND src/uri-plugin/uri-plugin.test.ts::"raises CONTAINER_MISMATCH for wrong container"
Requirement: Auth-token threading without URI exposure
The plugin SHALL NOT carry the Rackspace auth token in URIs.
Authentication lives entirely on the bound RackspaceAuthClient /
RackspaceCdnAdapter. When the adapter's token has expired and refresh
fails, the plugin SHALL re-wrap the failure as
STORAGE_CDN_RACKSPACE_URI.AUTH_TOKEN_EXPIRED preserving the original
on cause.
Scenario: token expiry on adapter becomes AUTH_TOKEN_EXPIRED
- WHEN the bound adapter raises a token-expired error during a routed read
- THEN the resolver's caller sees
StorageCdnRackspaceUriErrorwithcode === "STORAGE_CDN_RACKSPACE_URI.AUTH_TOKEN_EXPIRED"andcauseset
Scenario: no auth token appears in parsed URI
- WHEN
plugin.parse("rackspace://assets/img/a.jpg")is called - THEN the returned
metadoes NOT includeX-Auth-Tokenor anyauthkey
Verified by: src/uri-plugin/uri-plugin.test.ts::"wraps token expiry as AUTH_TOKEN_EXPIRED" AND src/uri-plugin/uri-plugin.test.ts::"never exposes auth token on parsed meta"
Requirement: TempURL signed-URL verification
The plugin SHALL verify ?temp_url_sig=<sig>&temp_url_expires=<unix>
query parameters when present, using the existing
buildTempUrlSignature helper against the configured tempUrlKey on
the bound adapter. Mismatched signatures SHALL raise
STORAGE_CDN_RACKSPACE_URI.TEMP_URL_INVALID.
Scenario: valid temp-URL passes verification
- WHEN
plugin.parse("rackspace://assets/x?temp_url_sig=<valid>&temp_url_expires=99")is called against a plugin whose adapter'stempUrlKeyproduces the same signature - THEN the parse succeeds and the resolver routes the read normally
Scenario: invalid temp-URL raises TEMP_URL_INVALID
- WHEN
plugin.parse("rackspace://assets/x?temp_url_sig=bogus&temp_url_expires=99")is called - THEN the call throws with
code === "STORAGE_CDN_RACKSPACE_URI.TEMP_URL_INVALID"
Verified by: src/uri-plugin/uri-plugin.test.ts::"accepts a valid temp-URL signature" AND src/uri-plugin/uri-plugin.test.ts::"raises TEMP_URL_INVALID on bad signature"
Requirement: build(key, meta?) with optional region echo
The plugin SHALL implement build(key, meta?) returning
rackspace://<container>/<key>. When meta?.region is set, the result
SHALL append ?region=<region> so downstream resolvers can re-bind
regions per URI. Unsupported region values SHALL raise
STORAGE_CDN_RACKSPACE_URI.REGION_UNSUPPORTED.
Scenario: build without region omits query string
- WHEN
plugin.build("img/a.jpg")is called against a plugin withcontainer: "assets" - THEN the result is
"rackspace://assets/img/a.jpg"
Scenario: build with valid region appends query
- WHEN
plugin.build("img/a.jpg", { region: "iad" })is called - THEN the result is
"rackspace://assets/img/a.jpg?region=iad"
Scenario: unsupported region raises REGION_UNSUPPORTED
- WHEN
plugin.build("x", { region: "mars" })is called - THEN the call throws with
code === "STORAGE_CDN_RACKSPACE_URI.REGION_UNSUPPORTED"
Verified by: src/uri-plugin/uri-plugin.test.ts::"build omits region when absent" AND src/uri-plugin/uri-plugin.test.ts::"build appends valid region" AND src/uri-plugin/uri-plugin.test.ts::"raises REGION_UNSUPPORTED for invalid region"
Requirement: Span-attribute redaction
The plugin SHALL redact temp_url_sig, temp_url_expires, and
X-Auth-Token from any URI surfaced on OTel span attributes or in
raised error .uri discriminants. Redaction SHALL be exposed as
redactSignedUrl(uri): string.
Scenario: temp-URL parameters are redacted on span attribute
- WHEN the resolver routes
read("rackspace://assets/x?temp_url_sig=abc&temp_url_expires=99")and emits a span - THEN the
cdn.uriattribute is"rackspace://assets/x?temp_url_sig=<redacted>&temp_url_expires=<redacted>"
Verified by: src/uri-plugin/redact-signed-url.test.ts::"redacts temp_url and auth-token parameters"
Requirement: STORAGE_CDN_RACKSPACE_URI_CODES registry
The package SHALL export STORAGE_CDN_RACKSPACE_URI_CODES produced by
defineCodes("STORAGE_CDN_RACKSPACE_URI", [...] as const) covering
exactly 6 codes: INVALID_URI, CONTAINER_MISMATCH,
REGION_UNSUPPORTED, TEMP_URL_INVALID, AUTH_TOKEN_EXPIRED,
KEY_TOO_LONG. Every code SHALL be reachable, and
StorageCdnRackspaceUriError SHALL extend
SuaveplanError<StorageCdnRackspaceUriErrorCode> with uri/scheme
discriminants.
Scenario: every code is reachable
- WHEN the test suite exercises every documented failure path
- THEN every member of
STORAGE_CDN_RACKSPACE_URI_CODESappears on at least one raised error instance
Verified by: src/uri-plugin/error-codes.test.ts::"exposes 6 codes all reachable"
Requirement: AbortSignal threading
The plugin SHALL forward AbortSignal unchanged to every adapter call.
A pre-aborted signal SHALL short-circuit with the adapter's existing
STORAGE_CDN_RACKSPACE.ABORTED code without invoking the adapter.
Scenario: pre-aborted signal short-circuits
- WHEN the resolver routes
read("rackspace://assets/x", AbortSignal.abort()) - THEN the rejection has
code === "STORAGE_CDN_RACKSPACE.ABORTED"and the adapter is NEVER invoked
Verified by: src/uri-plugin/uri-plugin.test.ts::"short-circuits on pre-aborted signal"
Requirement: Universal-tier purity
Every source file under src/uri-plugin/ SHALL be universal-tier: ZERO
imports from node:*, bun:*, browser-specific globals, or React.
Scenario: tier-purity grep returns empty
- WHEN
grep -rnE "from ['\"](node:|bun:)" packages/storage/storage-cdn-rackspace/src/uri-plugin/is run - THEN the command returns zero matches
Verified by: src/uri-plugin/uri-plugin.test.ts::"uri-plugin module has no node: or bun: imports"
Requirement: Subpath exports
The package SHALL declare subpath exports for
"./uri-plugin/uri-plugin", "./uri-plugin/redact-signed-url", and
"./uri-plugin/error-codes".
Scenario: subpath imports resolve
- WHEN
import("@suaveplan/storage-cdn-rackspace/uri-plugin/uri-plugin")is executed - THEN the module resolves and re-exports
rackspaceUriPlugin
Verified by: src/uri-plugin/uri-plugin.test.ts::"is importable via the documented subpath"
Requirement: Conformance harness pass
rackspaceUriPlugin SHALL pass runUriPluginConformance with fixtures
covering container-match cases, underscore-rebind cases,
container-mismatch failures, temp-URL forms, and a non-empty
buildRoundTrip set.
Scenario: conformance fixtures pass
- WHEN
runUriPluginConformance(rackspaceUriPlugin(opts), fixtures)is invoked with the documented fixture set - THEN the call returns without throwing
Verified by: src/uri-plugin/uri-plugin.test.ts::"passes runUriPluginConformance"