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

94 lines
6.0 KiB
Markdown

# @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.
<!-- begin:auto-docs -->
## 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…
<!-- end:auto-docs -->
## 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<void> {
await this.client.invalidate(key);
}
public override async signUrl(key: string, options: SignUrlOptions): Promise<string> {
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.