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

4.0 KiB

bunny-cdn-adapter.helpers

Purpose

Internal helpers used by BunnyCdnAdapter and its sibling streams module. Splits boundary concerns (option parsing, header resolution, abort guard, response-shape interpretation, outcome classification) out of the public class so the latter stays under the 300-line budget and the helpers can be unit-tested in isolation.

Features

  • resolveConfig(options) — parses options through BunnyCdnAdapterOptionsSchema; throws STORAGE_CDN_BUNNYCDN.INVALID_REGION for region typos and INVALID_OPTIONS for every other validation failure.
  • resolveHeaders(resolver, key) — static record or async per-op callback; defensive copy on return.
  • throwIfAborted(signal) — pre-fetch abort guard producing STORAGE_CDN_BUNNYCDN.UPSTREAM_ERROR (with cause = signal.reason).
  • outcomeFromError(err) — translates any thrown error to the outcome attribute the OTel wrapper records.
  • parseMetadata(response) — extracts StorageMetadata from a HEAD response.
  • consumeHead(response, zone, region, success) — processes a HEAD response: 404 → null, 401/403 → STORAGE_AUTH_FAILED, other non-ok → UPSTREAM_ERROR, 2xx → success(response).

Usage: Basic

import { resolveConfig, parseMetadata } from "@suaveplan/storage-cdn-bunnycdn";

const config = resolveConfig({
    storageZone: "myz",
    storageAccessKey: "ak",
    pullZoneHostname: "mycdn.b-cdn.net",
});

Usage: Advanced

import {
    consumeHead,
    outcomeFromError,
    resolveHeaders,
    throwIfAborted,
} from "@suaveplan/storage-cdn-bunnycdn";

async function customExists(ctx, key, signal) {
    throwIfAborted(signal);
    const headers = await resolveHeaders(ctx.options.headers, key);
    const response = await ctx.fetch(buildUrl(ctx, key), { method: "HEAD", headers, signal });
    try {
        return consumeHead(response, ctx.zone, ctx.region, () => true) ?? false;
    } catch (err) {
        recordOp({ op: "exists", outcome: outcomeFromError(err), durationMs: 0, storageRegion: ctx.region });
        throw err;
    }
}

API Reference

interface ResolvedConfig

{ options, storageZone, accessKey, pullZoneHostname, region, tokenAuthKey, purgeApiKey, fetch, now }.

resolveConfig(options): ResolvedConfig

Routes region-specific schema failures to INVALID_REGION; all others to INVALID_OPTIONS.

resolveHeaders(resolver, key): Promise<Record<string, string>>

  • undefined → {}.
  • Static record → shallow copy.
  • Function → awaited, then shallow-copied.

throwIfAborted(signal?): void

Throws when signal?.aborted === true.

outcomeFromError(err): "auth_failed" | "not_found" | "upstream_error"

StorageCdnBunnycdnError → maps by code; anything else → "upstream_error".

parseMetadata(response): StorageMetadata

Extracts Content-Length (defaulting size to 0 when absent or unparsed) and Last-Modified (defaulting modifiedAt to Date.now() when missing or unparseable). Returns createdAt === modifiedAt.

consumeHead<T>(response, zone, region, success): T | null

  • 404 → null.
  • 401/403 → STORAGE_CDN_BUNNYCDN.STORAGE_AUTH_FAILED.
  • other non-ok → STORAGE_CDN_BUNNYCDN.UPSTREAM_ERROR.
  • 2xx → success(response).

Implementation Notes

  • The error-status table maps 401 and 403 both to STORAGE_AUTH_FAILED because BunnyCDN returns the same access-denied semantics for both — distinguishing them at the adapter would force every caller to handle two paths with identical recovery.
  • outcomeFromError returns a narrower enum than the OTel attribute set because the adapter's wrap augments the outcome with "ok" on the success path. Adding a new error code requires extending the switch.
  • resolveHeaders defensively copies its inputs so a caller mutating their static record between calls doesn't leak into in-flight requests.
  • resolveConfig reads the first issue to detect a region-specific failure; only the dedicated INVALID_REGION code makes it to operators on that single failure mode.