Files
skills/docs/persistence/storage/storage-cdn-rackspace/src/rackspace-cdn-adapter/rackspace-cdn-adapter.ops.md
2026-05-29 08:20:56 +01:00

4.0 KiB

rackspace-cdn-adapter.ops

Purpose

Reusable Cloud Files HTTP operations used by RackspaceCdnAdapter: object GET (objectGet), HEAD (objectHead), PUT (objectPut), DELETE (objectDelete), Range read (objectPartial), streaming GET (objectStream), and parseMetadata for HEAD response headers. Each function takes a CallContext (fetch + endpoint + token + container + region + signal + retry + headers) and returns the result; the adapter composes them with the OTel wrapper and signal guards.

Split out so tests can exercise each operation in isolation without spinning up a full adapter.

Features

  • objectGet — full-body GET, 404/410 → undefined, 401/403/other → errorForStatus throw, retry on transient.
  • objectHead — HEAD with retry.
  • objectPut — PUT with auth token, content-type and content-length headers.
  • objectDelete — DELETE; returns true/false for 2xx/404 outcomes.
  • objectPartial — Range read; delegates 200/206/416 disambiguation to @suaveplan/storage-http's consumeRangeResponse; increments range-fallback counter on 200.
  • objectStream — single GET without retry; returns the raw Response so the caller can pump body.getReader().
  • parseMetadata — extracts StorageMetadata from HEAD response headers.

Usage: Basic

import { objectGet } from "@suaveplan/storage-cdn-rackspace";

const bytes = await objectGet({
    fetch, storageEndpoint, token, container, region, signal: undefined, retry: {}, headers: {}
}, "a/b.bin");

Usage: Advanced

import {
    objectHead,
    objectPartial,
    parseMetadata,
} from "@suaveplan/storage-cdn-rackspace";

async function existsAndMeta(ctx) {
    const response = await objectHead(ctx, "a/b.bin");
    if (response.status === 404) return null;
    return parseMetadata(response);
}

async function readSlice(ctx, key, off, len) {
    return objectPartial(ctx, key, off, len);
}

API Reference

interface CallContext

{ fetch, storageEndpoint, token, container, region, signal, retry, headers }.

objectGet(ctx, key): Promise<Uint8Array | undefined>

Returns undefined on 404/410, the response bytes on 200, throws on other non-ok.

objectHead(ctx, key): Promise<Response>

Raw response — caller decides.

objectPut(ctx, key, body, contentType): Promise<void>

Throws on non-ok. The caller-supplied contentType overrides headers["content-type"].

objectDelete(ctx, key): Promise<boolean>

true on 2xx, false on 404/410, throws on other non-ok.

objectPartial(ctx, key, offset, length): Promise<Uint8Array | null>

null on 404/410, sliced bytes from 206 or 200-fallback; increments range_fallback_total when origin returned 200.

objectStream(ctx, key): Promise<Response>

Throws on non-ok; otherwise returns the raw response with the body intact for the caller to pump.

parseMetadata(response): StorageMetadata

Extracts Content-Length (defaulting size to 0 when absent or unparsed), Last-Modified (defaulting to Date.now() when missing or unparseable).

Implementation Notes

  • The Range read uses @suaveplan/storage-http's consumeRangeResponse directly to avoid duplicating the 200/206/416 disambiguation. The counter increment is wired locally so the metric carries provider="rackspace".
  • objectStream does NOT go through retryWithBackoff — streaming responses can't be retried mid-stream without buffering, and the underlying retry classifier is response-shape rather than stream-shape.
  • parseMetadata returns a usable shape even when the origin omits Content-Length (some Swift configurations don't set it on partial-content responses). Callers that need exact size must call getItemSize against an origin that does.
  • The baseHeaders helper always re-merges the auth token last so a caller-supplied x-auth-token cannot override it accidentally.
  • objectGet and friends consume ctx.retry directly so callers customise retry per-operation if needed — the adapter currently passes one shared retry config per instance.