# pull-zone-client _(no submodules)_ ## Purpose Owns the Bunny.net management-API purge operation. `purgeUrl(ctx, edgeUrl, signal?)` issues `POST https://api.bunny.net/purge?url=` with the account-level `AccessKey` header. The caller composes the absolute edge URL (e.g. `https:///` or the same URL with a trailing `*` for prefix purge) — keeping URL composition out of this module means the same helper handles single-key and wildcard purges without branching. The function `purgeApiKey` from the bundle is **required**; missing it throws `STORAGE_CDN_BUNNYCDN.PURGE_API_KEY_MISSING` before any fetch happens. ## Features - Single function with a tight contract — no class state. - `purgeApiKey` enforced at the top; missing or empty key → `PURGE_API_KEY_MISSING` (no fetch issued). - 401/403 → `PURGE_AUTH_FAILED`, other non-ok → `UPSTREAM_ERROR`. - Errors carry `zone`, `region`, and `httpStatus` for diagnostics. - AbortSignal threaded into the fetch init. ## Usage: Basic ```ts import { purgeUrl } from "@suaveplan/storage-cdn-bunnycdn"; await purgeUrl( { fetch, purgeApiKey: "key-1234", pullZoneHostname: "mycdn.b-cdn.net", zone: "myz", region: "de" }, "https://mycdn.b-cdn.net/a/b.bin", ); ``` ## Usage: Advanced ```ts import { purgeUrl } from "@suaveplan/storage-cdn-bunnycdn"; async function purgePrefix(ctx, prefix: string) { // BunnyCDN's purge endpoint treats `*` as a wildcard suffix. await purgeUrl(ctx, `https://${ctx.pullZoneHostname}/${encodeURI(prefix)}*`); } async function purgeSafelyWithKeyRotation(ctx, edgeUrl: string) { try { await purgeUrl(ctx, edgeUrl); } catch (err) { if (err instanceof StorageCdnBunnycdnError && err.code === STORAGE_CDN_BUNNYCDN_CODES.PURGE_AUTH_FAILED) { const refreshed = await rotateAccessKey(); await purgeUrl({ ...ctx, purgeApiKey: refreshed }, edgeUrl); return; } throw err; } } ``` ## API Reference ### `interface PullZoneCtx` `{ fetch, purgeApiKey, pullZoneHostname, zone, region }`. `purgeApiKey` is `string | undefined`; absent value triggers `PURGE_API_KEY_MISSING`. ### `purgeUrl(ctx, edgeUrl, signal?): Promise` - `2xx` → resolves. - `401`/`403` → `STORAGE_CDN_BUNNYCDN.PURGE_AUTH_FAILED`. - other non-ok → `STORAGE_CDN_BUNNYCDN.UPSTREAM_ERROR`. - Missing `purgeApiKey` → `STORAGE_CDN_BUNNYCDN.PURGE_API_KEY_MISSING` (no fetch issued). ## Implementation Notes - Purge URL composition is the caller's responsibility because the same endpoint handles both single keys and prefix purges (caller appends `*` for prefix mode). Pushing composition into the helper would force every caller through an enum or a flag. - The `AccessKey` header is the account-level key from the Bunny.net dashboard, NOT the per-zone storage key. They're rotated independently and have different scopes; conflating them is the typical "purge stopped working after I rotated the storage key" bug. - 404 on purge is treated as success at the *caller* level (we don't see it here because the BunnyCDN API returns `200 OK` even when the object was already evicted) — operators relying on a 404 signal should switch to the management API's status endpoint. - The `pullZoneHostname` field is unused inside this function but is part of the bundle so callers can build edge URLs without a second context object.