# @suaveplan/storage-cdn - Types-only foundation for CDN-flavoured @suaveplan/storage adapters: CdnAdapter abstract base extending AbstractStorage with purge/signUrl/edgeUrl, CdnCapabilities matrix, Zod-validated SignUrlOptions, STORAGE_CDN error registry, type-guard helpers, and a module-augmentation slot on @suaveplan/storage's capabilities map. Provider packages (storage-cdn-rackspace, storage-cdn-bunnycdn, …) implement against this contract. Types-only foundation for CDN-flavoured `@suaveplan/storage` adapters. Declares `CdnAdapter` (an abstract base class extending `AbstractStorage` with `purge`, `signUrl`, and `edgeUrl`), the `CdnCapabilities` boolean matrix, Zod-validated `SignUrlOptions`, the `STORAGE_CDN` error registry, type-guard helpers, and the module augmentation that adds an optional `cdn?: CdnCapabilities` slot to `@suaveplan/storage`'s capabilities map. Provider packages (`storage-cdn-rackspace`, `storage-cdn-bunnycdn`, …) implement against this contract. ## Documentation tree - [cdn-adapter](./src/cdn-adapter/cdn-adapter.md) — Declares `CdnAdapter`, the abstract base class every CDN-flavoured storage adapter in the family extends. Layers three… - [cdn-adapter](./src/cdn-adapter/cdn-adapter.md) — Declares `CdnAdapter`, the abstract base class every CDN-flavoured storage adapter in the family extends. Layers three… - [error-codes](./src/error-codes/error-codes.md) — Declares the canonical `STORAGE_CDN` error namespace shared by every CDN provider package in the family — `storage-cdn-… - [error-codes](./src/error-codes/error-codes.md) — Declares the canonical `STORAGE_CDN` error namespace shared by every CDN provider package in the family — `storage-cdn-… - [guards](./src/guards/guards.md) — Ships two type-guards for `CdnAdapter`: the non-throwing `isCdnAdapter` predicate and the throwing `assertCdnAdapter` a… - [guards](./src/guards/guards.md) — Ships two type-guards for `CdnAdapter`: the non-throwing `isCdnAdapter` predicate and the throwing `assertCdnAdapter` a… - [sign-url](./src/sign-url/sign-url.md) — Owns the boundary validation for `CdnAdapter.signUrl` callers. Wraps the Zod `SignUrlOptionsSchema` parse and converts… - [sign-url](./src/sign-url/sign-url.md) — Owns the boundary validation for `CdnAdapter.signUrl` callers. Wraps the Zod `SignUrlOptionsSchema` parse and converts… - [storage-augment](./src/storage-augment.md) — Owns the TypeScript module augmentation that adds an optional `cdn?: CdnCapabilities` slot to `@suaveplan/storage`'s `S… ## Install ```bash bun add @suaveplan/storage-cdn ``` ## Quick start ```ts import { CdnAdapter, parseSignUrlOptions } from "@suaveplan/storage-cdn"; import { AbstractStorage } from "@suaveplan/storage/abstract"; class MyCdn extends CdnAdapter { // ... AbstractStorage methods ... public override async purge(key: string): Promise { await this.client.invalidate(key); } public override async signUrl(key: string, options: SignUrlOptions): Promise { const opts = parseSignUrlOptions(options); return await this.client.presign(key, opts); } public override edgeUrl(key: string): string { return `https://edge.example.com/${key}`; } } ``` Consumers that just need to test whether a `StorageLike` supports CDN features use the guards: ```ts import { isCdnAdapter } from "@suaveplan/storage-cdn"; if (isCdnAdapter(storage)) { await storage.purge("a/b.bin"); const signed = await storage.signUrl("a/b.bin", { ttlSeconds: 60 }); } ``` ## Family role ```text @suaveplan/storage AbstractStorage core (key/value, in-memory) └─ @suaveplan/storage-http Generic prefix+key reader (no purge/signing) └─ @suaveplan/storage-cdn CdnAdapter contract (THIS PACKAGE) ├─ @suaveplan/storage-cdn-rackspace Cloud Files origin + Rackspace CDN └─ @suaveplan/storage-cdn-bunnycdn BunnyCDN Storage origin + Pull Zone ``` A consumer that only needs read access to a CDN-fronted static site uses `storage-http`. A consumer that needs purge and signed URLs uses a `storage-cdn-*` provider. The two abstractions stay separable so neither pulls weight the other does not need. ## Modules - [error-codes](./src/error-codes.md) — `STORAGE_CDN_CODES` registry + `StorageCdnError`. - [cdn-adapter](./src/cdn-adapter/cdn-adapter.md) — abstract `CdnAdapter` base + `defaultPurgeNotSupported` / `defaultSignUrlNotSupported` / `defaultPrefixPurgeNotSupported` helpers. - [sign-url](./src/sign-url/sign-url.md) — `parseSignUrlOptions` boundary validator. - [guards](./src/guards/guards.md) — `isCdnAdapter` / `assertCdnAdapter`. - [storage-augment](./src/storage-augment.md) — module augmentation for `capabilities.cdn`. - [types/cdn-adapter.types](./src/types/cdn-adapter.types.md) — `CdnAdapterOptions` base interface. - [types/cdn-capabilities.types](./src/types/cdn-capabilities.types.md) — `CdnCapabilities` + `DEFAULT_CDN_CAPABILITIES`. - [types/sign-url.types](./src/types/sign-url.types.md) — `SignUrlOptions` + `SignUrlMethod`. ## Features - **Universal purity** — no `node:*` or DOM-only imports. Types and Zod schemas only — no network, no I/O. - **Abstract `CdnAdapter` base** — three abstract methods (`purge`, `signUrl`, `edgeUrl`) every provider implements. - **Tightened capabilities** — `CdnAdapter.capabilities` requires a nested `cdn: CdnCapabilities` matrix; base `AbstractStorage` keeps it optional. - **Canonical error registry** — 8 stable codes (`PURGE_FAILED`, `SIGN_URL_NOT_SUPPORTED`, `PURGE_NOT_SUPPORTED`, `PREFIX_PURGE_NOT_SUPPORTED`, `INVALID_TTL`, `INVALID_OPTIONS`, `EDGE_ORIGIN_MISMATCH`, `CREDENTIAL_EXPIRED`) shared by every provider. - **Boundary validation** — `parseSignUrlOptions` maps Zod issues to the canonical codes so every provider's diagnostic surface is identical. - **Type guards** — `isCdnAdapter` / `assertCdnAdapter` for safe narrowing from `StorageLike`. - **100 / 100 / 100 / 100 Istanbul coverage**. ## License MIT — see `LICENSE` at the repo root.