@craftainer/crud-sdk 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -65,7 +65,18 @@ await heroes.update(1, { name: "Ada" }, { ifMatch: etag }); // 412 -> Preconditi
65
65
  order `id`, filters sorted by (field, operator), sort, skip, limit,
66
66
  `include_archived`, `include_unpublished`; everything but `A-Za-z0-9-._~`
67
67
  percent-encoded; datetimes are `Date`s sent as UTC with milliseconds
68
- trimmed; `date` fields take `YYYY-MM-DD` strings.
68
+ trimmed; `date` fields take `YYYY-MM-DD` strings. `only_archived` is
69
+ emitted right after `include_archived`, and only when `true`.
70
+ - **Archived rows.** `list` and `iterAll` take `includeArchived` and
71
+ `onlyArchived`. `onlyArchived: true` returns only rows with `archived_at`
72
+ set (the server's reserved `only_archived` list parameter; it implies
73
+ `include_archived` and combines with filters, sort and paging). It is not
74
+ sent when `false` or absent. Combined with `includeArchived: false` it
75
+ rejects with `InvalidQueryError` before any request (the server would
76
+ answer `422`). It is a list option only (not on `stats`, writes, `restore`
77
+ or `get`); a non-archivable resource ignores it. The wire query is part of
78
+ the HTTP cache key, and in the TanStack layer put it in the list query (`listOptions(ns, "heroes", api, { onlyArchived: true })`), so
79
+ archived-only and normal lists never share a cache entry.
69
80
  - **Errors.** `ProblemError` (RFC 9457) with subclasses `BadRequest`,
70
81
  `Unauthorized`, `Forbidden`, `NotFound`, `PreconditionFailed`,
71
82
  `ValidationFailed` (`errors`), `Locked`, `RateLimited` (`retryAfter`),
@@ -879,13 +879,14 @@ var IndexedDbStore = class {
879
879
  }
880
880
  /** Run `work` on the database; a failure drops the handle (so a later call retries) and yields `fallback`. */
881
881
  async run(fallback, work) {
882
+ let used;
882
883
  try {
883
- return await work(await this.open());
884
+ used = this.open();
885
+ return await work(await used);
884
886
  } catch {
885
- const dropped = this.opening;
886
- this.opening = void 0;
887
+ if (this.opening === used) this.opening = void 0;
887
888
  try {
888
- (await dropped)?.close();
889
+ (await used)?.close();
889
890
  } catch {}
890
891
  return fallback;
891
892
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/entry.ts","../../src/cache/keys.ts","../../src/cache/scope.ts","../../src/cache/middleware.ts","../../src/cache/memory.ts","../../node_modules/.pnpm/idb@8.0.4/node_modules/idb/build/index.js","../../src/cache/idb.ts","../../src/cache/wire.ts"],"sourcesContent":["/** Turning responses into `CacheEntry` values and back. */\nimport type { CacheEntry } from \"../interfaces.ts\";\n\n/** How the cache answered a read: see `cacheStatus`. */\nexport type CacheStatus = \"hit\" | \"stale\" | \"revalidated\" | \"miss\";\n\nconst statuses = new WeakMap<Response, CacheStatus>();\n\n/**\n * How the cache answered `response`: `hit` (fresh, no network), `stale`\n * (inside the stale-while-revalidate window, refreshed in the background),\n * `revalidated` (a `304` rebuilt from the stored entry) or `miss`.\n * `undefined` when the cache did not handle the request.\n */\nexport function cacheStatus(response: Response): CacheStatus | undefined {\n return statuses.get(response);\n}\n\n/** Tag `response` with how the cache answered. */\nexport function tagStatus(response: Response, status: CacheStatus): Response {\n statuses.set(response, status);\n return response;\n}\n\n// Describe the transfer, not the representation: the stored body is decoded.\nconst TRANSFER_HEADERS: ReadonlySet<string> = new Set([\n \"content-length\",\n \"content-encoding\",\n \"transfer-encoding\",\n \"connection\",\n \"keep-alive\",\n]);\nconst VARY_OK: ReadonlySet<string> = new Set([\n \"authorization\",\n \"accept\",\n \"accept-encoding\",\n]);\n\n/** The lower-cased directive names of the `Cache-Control` header. */\nexport function cacheControl(headers: Headers): ReadonlySet<string> {\n const names = (headers.get(\"cache-control\") ?? \"\")\n .split(\",\")\n .map((part) => (part.split(\"=\", 1)[0] as string).trim().toLowerCase())\n .filter((name) => name !== \"\");\n return new Set(names);\n}\n\n/** Whether the media type is JSON (`application/json` or `+json`). */\nexport function isJson(response: Response): boolean {\n const media = (response.headers.get(\"content-type\") ?? \"\")\n .split(\";\", 1)[0]!\n .trim()\n .toLowerCase();\n return media === \"application/json\" || media.endsWith(\"+json\");\n}\n\n/** `Vary` may only name headers the key already accounts for; `*` never caches. */\nexport function varyAllowsCaching(response: Response): boolean {\n const names = (response.headers.get(\"vary\") ?? \"\")\n .split(\",\")\n .map((part) => part.trim().toLowerCase())\n .filter((name) => name !== \"\");\n return names.every((name) => VARY_OK.has(name));\n}\n\nfunction storableHeaders(headers: Headers): Array<readonly [string, string]> {\n const items: Array<readonly [string, string]> = [];\n for (const [name, value] of headers) {\n if (!TRANSFER_HEADERS.has(name)) {\n items.push([name, value]);\n }\n }\n return items;\n}\n\nexport interface EntryTimes {\n readonly now: number;\n /** Milliseconds fresh. */\n readonly fresh: number;\n /** Milliseconds of stale-while-revalidate after `fresh`. */\n readonly stale: number;\n}\n\n/** Snapshot a read response whose body text was already read. */\nexport function buildEntry(\n response: Response,\n body: string,\n times: EntryTimes,\n keepEtag: boolean,\n): CacheEntry {\n const etag = keepEtag ? response.headers.get(\"etag\") : null;\n const base = {\n status: response.status,\n headers: storableHeaders(response.headers),\n body,\n storedAt: times.now,\n freshUntil: times.now + times.fresh,\n staleUntil: times.now + times.fresh + times.stale,\n };\n return etag === null ? base : { ...base, etag };\n}\n\n/** RFC 9111 4.3.4: headers of a `304` replace the stored ones of the same name. */\nexport function mergeHeaders(\n stored: CacheEntry[\"headers\"],\n update: Headers,\n): CacheEntry[\"headers\"] {\n const fresh = storableHeaders(update);\n const replaced = new Set(fresh.map(([name]) => name));\n return [...stored.filter(([name]) => !replaced.has(name)), ...fresh];\n}\n\n/** Rebuild a response from an entry, tagged with how the cache produced it. */\nexport function toResponse(entry: CacheEntry, status: CacheStatus): Response {\n const headers = new Headers();\n for (const [name, value] of entry.headers) {\n headers.append(name, value);\n }\n return tagStatus(\n new Response(entry.body, { status: entry.status, headers }),\n status,\n );\n}\n","/**\n * Cache keys and the invalidation prefixes.\n *\n * Keys are slash-separated:\n * `v1/{resource}/{kind}/{subject}/{apiVersion}/{scope}/{canonicalQuery}`.\n * Versions of one resource never share an entry, but they share one event\n * stream; because the version comes after kind and subject, one prefix such\n * as `v1/{resource}/record/{id}/` clears an entry in every version and for\n * every caller at once.\n */\nimport type { Op } from \"../interfaces.ts\";\n\n/** The ops that read and are cached (`manifest` has its own key). */\nexport type CacheKind =\n \"list\" | \"record\" | \"stats\" | \"predict\" | \"revisions\" | \"filters\";\n\nconst KINDS: ReadonlySet<string> = new Set<CacheKind>([\n \"list\",\n \"record\",\n \"stats\",\n \"predict\",\n \"revisions\",\n \"filters\",\n]);\nconst STATS_KINDS: ReadonlySet<string> = new Set([\"stats\", \"predict\"]);\nconst COLLECTION_KINDS = [\"list\", \"stats\", \"predict\"] as const;\nconst PER_RECORD_KINDS = [\"record\", \"revisions\"] as const;\n\n/** `true` when the op is a cacheable read kind. */\nexport function isCacheKind(op: Op): op is CacheKind {\n return KINDS.has(op);\n}\n\n/** `true` for `stats` and `predict`, which `stats_ttl` bounds. */\nexport function isStatsKind(kind: string): boolean {\n return STATS_KINDS.has(kind);\n}\n\n/**\n * Sorts the query pairs the client sent and drops `id` (it is the subject).\n * Values are kept verbatim: the client already emits canonical,\n * percent-encoded text, so nothing is decoded or re-encoded here.\n */\nexport function canonicalQuery(query: string): string {\n const text = query.startsWith(\"?\") ? query.slice(1) : query;\n const pairs = text\n .split(\"&\")\n .filter((part) => part !== \"\" && part.split(\"=\", 1)[0] !== \"id\")\n .map((part) => {\n const at = part.indexOf(\"=\");\n return at < 0\n ? ([part, \"\"] as const)\n : ([part.slice(0, at), part.slice(at)] as const);\n });\n pairs.sort(([an, av], [bn, bv]) =>\n an === bn ? (av < bv ? -1 : av > bv ? 1 : 0) : an < bn ? -1 : 1,\n );\n return pairs.map(([name, rest]) => name + rest).join(\"&\");\n}\n\nexport interface KeyParts {\n readonly resource: string;\n readonly kind: CacheKind;\n readonly recordId?: number | undefined;\n readonly scope: string;\n readonly query?: string;\n /** `null` (no version) renders as `_`. */\n readonly apiVersion: string | null;\n}\n\n/** The key of one cached response. */\nexport function buildKey(parts: KeyParts): string {\n const subject =\n (parts.kind === \"record\" || parts.kind === \"revisions\") &&\n parts.recordId !== undefined\n ? String(parts.recordId)\n : \"_\";\n const version = parts.apiVersion ?? \"_\";\n return `v1/${parts.resource}/${parts.kind}/${subject}/${version}/${parts.scope}/${canonicalQuery(parts.query ?? \"\")}`;\n}\n\n/** Key of the manifest document for one caller scope. */\nexport function manifestKey(scope: string): string {\n return `v1/_manifest/${scope}`;\n}\n\n/** Prefix of all entries of one kind for `resource` (every scope and subject). */\nexport function kindPrefix(resource: string, kind: CacheKind): string {\n return `v1/${resource}/${kind}/`;\n}\n\n/** Prefix of the `record` entries of one record (every version, scope, query). */\nexport function recordPrefix(resource: string, recordId: number): string {\n return `v1/${resource}/record/${recordId}/`;\n}\n\n/** Prefix of the `revisions` entries of one record. */\nexport function revisionsPrefix(resource: string, recordId: number): string {\n return `v1/${resource}/revisions/${recordId}/`;\n}\n\n/** The list, stats and predict prefixes of `resource`. */\nexport function collectionPrefixes(resource: string): string[] {\n return COLLECTION_KINDS.map((kind) => kindPrefix(resource, kind));\n}\n\n/** Everything cached for `resource` except `filters` (a reconnect or an unknown change). */\nexport function resourcePrefixes(resource: string): string[] {\n return [...COLLECTION_KINDS, ...PER_RECORD_KINDS].map((kind) =>\n kindPrefix(resource, kind),\n );\n}\n\n/**\n * Prefixes an SSE event clears, per the spec's table: `create` clears the\n * collection kinds; `update`/`delete`/`restore` also clear the record and its\n * revisions; an unknown action or a missing record id clears the resource.\n */\nexport function eventPrefixes(\n resource: string,\n action: string,\n recordId: number | undefined,\n): string[] {\n if (action === \"create\") {\n return collectionPrefixes(resource);\n }\n if (\n (action === \"update\" || action === \"delete\" || action === \"restore\") &&\n recordId !== undefined\n ) {\n return [\n ...collectionPrefixes(resource),\n recordPrefix(resource, recordId),\n revisionsPrefix(resource, recordId),\n ];\n }\n return resourcePrefixes(resource);\n}\n","import { ANON, cacheScope } from \"../auth.ts\";\n\n/**\n * `\"anon\"` when the request has no Authorization header; otherwise the first\n * 32 hex characters of the SHA-256 of the whole credential, the same digest as\n * the client's `cacheScope(token)` (a `Bearer ` prefix is dropped, any other value is hashed as it is). It is read from the\n * request the cache sees, so it must be the innermost middleware that matters:\n * whatever sets Authorization has to run before the cache. The raw credential\n * never enters a key or a log, and the unverified `sub` claim is never used.\n */\nexport async function credentialScope(headers: Headers): Promise<string> {\n const value = headers.get(\"authorization\");\n if (value === null) {\n return ANON;\n }\n const credential = /^bearer\\s+(.+)$/i.exec(value)?.[1] ?? value;\n return cacheScope(credential);\n}\n","/**\n * The caching middleware (`createCache`): an I3 `Middleware` plus the control\n * surface that events and the client use.\n *\n * It reads the resource, op, record id, API version and caller scope from\n * `RequestContext` and never touches the Authorization header. A read is\n * answered in one of four ways, see `cacheStatus`: `hit` (fresh, no\n * network), `stale` (inside the stale-while-revalidate window, refreshed in\n * the background), `revalidated` (a `304` rebuilt from the stored entry with\n * merged headers) or `miss`.\n *\n * Freshness beyond \"revalidate every time\" is granted only while the\n * resource's SSE stream is up (`setEventsActive`): events are the only thing\n * that can end a fresh window early. `stats` and `predict` are bounded by\n * `statsTtl` instead, as the server caches those bodies the same way. A\n * per-resource generation counter stops a response that was in flight when\n * an invalidation landed from being stored fresh.\n */\nimport type {\n CacheEntry,\n MaybePromise,\n CacheStore,\n Middleware,\n Next,\n RequestContext,\n} from \"../interfaces.ts\";\nimport {\n buildEntry,\n cacheControl,\n isJson,\n mergeHeaders,\n tagStatus,\n toResponse,\n varyAllowsCaching,\n} from \"./entry.ts\";\nimport {\n buildKey,\n collectionPrefixes,\n eventPrefixes,\n isCacheKind,\n isStatsKind,\n kindPrefix,\n manifestKey,\n recordPrefix,\n resourcePrefixes,\n revisionsPrefix,\n} from \"./keys.ts\";\nimport type { CacheKind } from \"./keys.ts\";\nimport { cachePolicyFromManifest } from \"./policy.ts\";\nimport { credentialScope } from \"./scope.ts\";\nimport type { CachePolicy } from \"./policy.ts\";\n\n/**\n * A store may clear several prefixes in one pass (one walk, one transaction);\n * the cache uses it when present and falls back to `clear` per prefix.\n */\nexport interface CacheStoreMany extends CacheStore {\n clearMany?(prefixes: readonly string[]): MaybePromise<void>;\n}\n\nexport interface CacheOptions {\n readonly store: CacheStoreMany;\n /**\n * Policy per manifest resource: `name@apiVersion` (built from that version's\n * manifest entry) or, for every version, plain `name`. A resource without\n * one is not cached. The event stream and the freshness gate are per name.\n */\n readonly policies: Readonly<Record<string, CachePolicy>>;\n /** Cache the manifest document per caller scope. Default `true`. */\n readonly cacheManifest?: boolean;\n /** Epoch milliseconds; injectable for tests. */\n readonly now?: () => number;\n}\n\nexport interface Cache {\n /** Put it in the client's middleware chain. */\n readonly middleware: Middleware;\n /** Record whether the SSE stream of `resource` is connected (gates fresh hits). */\n setEventsActive(resource: string, active: boolean): void;\n eventsActive(resource: string): boolean;\n /** Clear what an SSE event makes stale, in every API version. */\n invalidateEvent(\n resource: string,\n action: string,\n recordId: number | undefined,\n ): Promise<void>;\n /** Clear everything cached for `resource` except `filters` (after a reconnect). */\n clearResource(resource: string): Promise<void>;\n /** Clear keys under `prefix` (everything the store owns when omitted). */\n clear(prefix?: string): Promise<void>;\n /**\n * Adds `If-Match` from the cached record ETag to `PATCH`/`DELETE ?id=` that\n * have none. Put it innermost, next to `middleware`, so it sees the same\n * Authorization (and so scope) the request is sent with.\n */\n readonly autoIfMatch: Middleware;\n /** The stored ETag of a record of one API version, for `auto_if_match`. */\n cachedEtag(\n resource: string,\n recordId: number,\n scope: string,\n apiVersion: string | null,\n ): Promise<string | undefined>;\n /** Abort background revalidations and wait for them. */\n close(): Promise<void>;\n}\n\ntype Kind = CacheKind | \"manifest\";\ntype Decision = \"hit\" | \"stale\" | \"revalidate\" | \"miss\";\ntype StoreOp =\n | { readonly type: \"clear\"; readonly prefixes: readonly string[] }\n | {\n readonly type: \"set\";\n readonly key: string;\n readonly entry: CacheEntry;\n readonly ttlMs: number;\n }\n | { readonly type: \"delete\"; readonly key: string };\n\n/** What `begin` learned about one request. */\ninterface State {\n readonly ctx: RequestContext;\n readonly policy: CachePolicy;\n /** The cache kind of a read; `undefined` for a write. */\n readonly kind: Kind | undefined;\n readonly key: string | undefined;\n /** The resource's invalidation count when the request was made. */\n readonly generation: number;\n /** From the Authorization header of the request as the cache sees it. */\n readonly scope: string;\n readonly forceRevalidate: boolean;\n entry?: CacheEntry | undefined;\n /** Whether we put `If-None-Match` on the request. */\n validated?: boolean;\n}\n\nconst MIN_RETENTION_MS = 3_600_000;\nconst MANIFEST_POLICY: CachePolicy = cachePolicyFromManifest({});\nconst WRITE_METHODS: ReadonlySet<string> = new Set([\n \"POST\",\n \"PATCH\",\n \"PUT\",\n \"DELETE\",\n]);\nconst BULK_OPS: ReadonlySet<string> = new Set([\"bulk_update\", \"bulk_delete\"]);\nconst RECORD_WRITES: ReadonlySet<string> = new Set([\n \"delete\",\n \"publish\",\n \"restore\",\n]);\nconst CREATES: ReadonlySet<string> = new Set([\"create\", \"clone\", \"draft\"]);\n\nfunction isStorable(response: Response): boolean {\n return (\n isJson(response) &&\n !cacheControl(response.headers).has(\"no-store\") &&\n varyAllowsCaching(response)\n );\n}\n\nfunction retentionMs(freshMs: number, staleMs: number): number {\n return Math.max(freshMs + staleMs, MIN_RETENTION_MS);\n}\n\n/** The ids of a bulk response (`{matched, ids}`), or `undefined` if unreadable. */\nfunction idsFromBody(body: string): number[] | undefined {\n try {\n const ids = (JSON.parse(body) as { ids?: unknown }).ids;\n return Array.isArray(ids) && ids.every((id) => Number.isInteger(id))\n ? (ids as number[])\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The resource names in a manifest document, or none if unreadable. */\nfunction manifestResources(body: string): string[] {\n try {\n const resources = (JSON.parse(body) as { resources?: unknown }).resources;\n return Array.isArray(resources)\n ? resources\n .map((item: { name?: unknown }) => item.name)\n .filter((name): name is string => typeof name === \"string\")\n : [];\n } catch {\n return [];\n }\n}\n\nasync function safe<T>(call: () => T | Promise<T>): Promise<T | undefined> {\n try {\n return await call();\n } catch {\n return undefined; // a failing store is a miss, never a failed request\n }\n}\n\nexport function createCache(options: CacheOptions): Cache {\n const { store } = options;\n const policies = new Map(Object.entries(options.policies));\n const policyFor = (\n resource: string | undefined,\n apiVersion: string | null,\n ): CachePolicy | undefined =>\n resource === undefined\n ? undefined\n : (policies.get(`${resource}@${apiVersion}`) ?? policies.get(resource));\n const cacheManifest = options.cacheManifest ?? true;\n const now = options.now ?? Date.now;\n const eventsActive = new Set<string>();\n const generations = new Map<string, number>();\n const inflight = new Set<string>();\n const tasks = new Set<Promise<void>>();\n const background = new AbortController();\n\n let globalGeneration = 0; // bumped by `clear`, which may span resources\n const generation = (resource: string | undefined): number =>\n (generations.get(resource ?? \"\") ?? 0) + globalGeneration;\n const bump = (resource: string): void => {\n generations.set(resource, generation(resource) + 1);\n };\n\n // -- freshness ---------------------------------------------------------------\n\n /**\n * Whether an entry of `kind` may be served without the network right now:\n * only while the stream is up, except `stats`/`predict`, which `stats_ttl`\n * bounds on its own. Never `filters` (events never clear them) or the manifest.\n */\n const gateOpen = (\n policy: CachePolicy,\n resource: string | undefined,\n kind: Kind,\n ): boolean =>\n !policy.revalidateOnly &&\n kind !== \"manifest\" &&\n kind !== \"filters\" &&\n (isStatsKind(kind) || eventsActive.has(resource as string));\n\n /** Stale-while-revalidate needs the stream for every kind, stats and predict included. */\n const staleOpen = (\n policy: CachePolicy,\n resource: string | undefined,\n kind: Kind,\n ): boolean =>\n gateOpen(policy, resource, kind) && eventsActive.has(resource as string);\n\n /** Milliseconds fresh and of stale-while-revalidate for a new entry; none if the response may predate an invalidation. */\n const entryTimes = (\n state: State,\n kind: Kind,\n ): { fresh: number; stale: number } => {\n const resource = state.ctx.resource;\n if (\n generation(resource) !== state.generation ||\n !gateOpen(state.policy, resource, kind)\n ) {\n return { fresh: 0, stale: 0 };\n }\n const fresh = isStatsKind(kind)\n ? state.policy.statsTtl\n : state.policy.maxAge;\n return {\n fresh: fresh * 1000,\n stale: staleOpen(state.policy, resource, kind)\n ? state.policy.staleWhileRevalidate * 1000\n : 0,\n };\n };\n\n const decide = (state: State, entry: CacheEntry | undefined): Decision => {\n if (entry === undefined) {\n return \"miss\";\n }\n if (\n !state.forceRevalidate &&\n gateOpen(state.policy, state.ctx.resource, state.kind as Kind)\n ) {\n const at = now();\n if (at < entry.freshUntil) {\n return \"hit\";\n }\n if (\n at < entry.staleUntil &&\n staleOpen(state.policy, state.ctx.resource, state.kind as Kind)\n ) {\n return \"stale\";\n }\n }\n return entry.etag !== undefined && state.policy.etag\n ? \"revalidate\"\n : \"miss\";\n };\n\n // -- request side ------------------------------------------------------------\n\n const begin = async (ctx: RequestContext): Promise<State | undefined> => {\n const { request, resource } = ctx;\n const scope = await credentialScope(request.headers);\n const generationNow = generation(resource);\n if (request.method !== \"GET\") {\n if (!WRITE_METHODS.has(request.method)) {\n return undefined; // HEAD, OPTIONS and the like change nothing\n }\n const policy = policyFor(resource, ctx.apiVersion);\n return policy?.enabled === true\n ? {\n ctx,\n policy,\n kind: undefined,\n key: undefined,\n generation: generationNow,\n scope,\n forceRevalidate: false,\n }\n : undefined;\n }\n let policy: CachePolicy | undefined;\n let kind: Kind;\n let key: string;\n if (ctx.op === \"manifest\") {\n if (!cacheManifest) {\n return undefined;\n }\n policy = MANIFEST_POLICY;\n kind = \"manifest\";\n key = manifestKey(scope);\n } else {\n policy = policyFor(resource, ctx.apiVersion);\n if (\n resource === undefined ||\n policy?.enabled !== true ||\n !isCacheKind(ctx.op)\n ) {\n return undefined;\n }\n kind = ctx.op;\n key = buildKey({\n resource,\n kind,\n recordId: ctx.recordId,\n scope,\n query: new URL(request.url).search,\n apiVersion: ctx.apiVersion,\n });\n }\n const control = cacheControl(request.headers);\n if (control.has(\"no-store\") || request.headers.has(\"if-none-match\")) {\n return undefined; // the caller forbids storing or manages validators itself\n }\n return {\n ctx,\n policy,\n kind,\n key,\n generation: generationNow,\n scope,\n forceRevalidate: control.has(\"no-cache\"),\n };\n };\n\n /** A copy of `ctx` whose request carries our validator (a `GET` has no body to lose). */\n const withValidator = (ctx: RequestContext, etag: string): RequestContext => {\n const headers = new Headers(ctx.request.headers);\n headers.set(\"if-none-match\", etag);\n return { ...ctx, request: new Request(ctx.request, { headers }) };\n };\n\n // -- response side -----------------------------------------------------------\n\n const readBody = async (\n state: State,\n response: Response,\n ): Promise<string | undefined> => {\n const { status } = response;\n const { op, recordId } = state.ctx;\n let wanted: boolean;\n if (state.kind !== undefined) {\n wanted = status === 200 && isStorable(response);\n } else if (op === \"update\") {\n wanted = status === 200 && recordId !== undefined && isStorable(response);\n } else {\n wanted =\n status >= 200 &&\n status < 300 &&\n (BULK_OPS.has(op) || (op === \"restore\" && recordId === undefined));\n }\n return wanted ? response.clone().text() : undefined;\n };\n\n /** One clear op for all `prefixes`: the store clears them in a single pass. */\n const clears = (prefixes: readonly string[]): StoreOp[] => [\n { type: \"clear\", prefixes },\n ];\n\n const manifestOps = (\n old: CacheEntry | undefined,\n entry: CacheEntry,\n ): StoreOp[] => {\n if (\n old === undefined ||\n (old.etag !== undefined && old.etag === entry.etag)\n ) {\n return [];\n }\n const names = new Set([\n ...[...policies.keys()].map((key) => key.replace(/@[^@]*$/, \"\")),\n ...manifestResources(old.body),\n ...manifestResources(entry.body),\n ]);\n return clears([...names].sort().map((name) => kindPrefix(name, \"filters\")));\n };\n\n const readPlan = (\n state: State,\n response: Response,\n body: string | undefined,\n ): { result: Response; ops: StoreOp[] } => {\n const key = state.key as string;\n const kind = state.kind as Kind;\n const { status } = response;\n const at = now();\n const { fresh, stale } = entryTimes(state, kind);\n const old = state.entry;\n if (status === 304 && state.validated === true && old !== undefined) {\n // `validated` means the request carried `old.etag`.\n const updated: CacheEntry = {\n ...old,\n headers: mergeHeaders(old.headers, response.headers),\n storedAt: at,\n freshUntil: at + fresh,\n staleUntil: at + fresh + stale,\n etag: response.headers.get(\"etag\") ?? (old.etag as string),\n };\n return {\n result: toResponse(updated, \"revalidated\"),\n ops: [\n {\n type: \"set\",\n key,\n entry: updated,\n ttlMs: retentionMs(fresh, stale),\n },\n ],\n };\n }\n if (status === 200 && body !== undefined) {\n tagStatus(response, \"miss\");\n const entry = buildEntry(\n response,\n body,\n { now: at, fresh, stale },\n state.policy.etag,\n );\n if (entry.etag === undefined && fresh <= 0) {\n // No validator and never fresh: drop the old entry.\n return { result: response, ops: [{ type: \"delete\", key }] };\n }\n const ops: StoreOp[] = [\n { type: \"set\", key, entry, ttlMs: retentionMs(fresh, stale) },\n ];\n if (kind === \"manifest\") {\n ops.push(...manifestOps(old, entry));\n }\n return { result: response, ops };\n }\n if (status === 200 || status === 404 || status === 410) {\n return { result: response, ops: [{ type: \"delete\", key }] };\n }\n return { result: response, ops: [] };\n };\n\n /** Store the PATCH response as the record's entry (it is the read view plus ETag). */\n const writeThrough = (\n state: State,\n response: Response,\n body: string | undefined,\n resource: string,\n recordId: number,\n ): StoreOp[] => {\n if (body === undefined) {\n return [];\n }\n const { fresh, stale } = entryTimes(state, \"record\");\n const entry = buildEntry(\n response,\n body,\n { now: now(), fresh, stale },\n state.policy.etag,\n );\n if (entry.etag === undefined && fresh <= 0) {\n return [];\n }\n const key = buildKey({\n resource,\n kind: \"record\",\n recordId,\n scope: state.scope,\n apiVersion: state.ctx.apiVersion,\n });\n return [{ type: \"set\", key, entry, ttlMs: retentionMs(fresh, stale) }];\n };\n\n const writeOps = (\n state: State,\n response: Response,\n body: string | undefined,\n ): StoreOp[] => {\n const { op, recordId } = state.ctx;\n const resource = state.ctx.resource as string;\n const { status } = response;\n if (status === 412) {\n return recordId === undefined\n ? []\n : clears([recordPrefix(resource, recordId)]);\n }\n if (status < 200 || status >= 300) {\n return [];\n }\n const collections = collectionPrefixes(resource);\n if (CREATES.has(op)) {\n return clears(collections);\n }\n if (recordId !== undefined && (RECORD_WRITES.has(op) || op === \"update\")) {\n return [\n ...clears([\n ...collections,\n revisionsPrefix(resource, recordId),\n recordPrefix(resource, recordId),\n ]),\n ...(op === \"update\"\n ? writeThrough(state, response, body, resource, recordId)\n : []),\n ];\n }\n if (BULK_OPS.has(op) || op === \"restore\") {\n // Bulk ops and a bulk restore always have their body read (see `readBody`).\n const ids = idsFromBody(body as string);\n if (ids !== undefined) {\n return clears([\n ...collections,\n ...ids.flatMap((id) => [\n recordPrefix(resource, id),\n revisionsPrefix(resource, id),\n ]),\n ]);\n }\n }\n return clears(resourcePrefixes(resource));\n };\n\n /** One pass when the store can, else one `clear` per prefix; a failure is a miss. */\n const clearPrefixes = async (prefixes: readonly string[]): Promise<void> => {\n if (store.clearMany !== undefined) {\n await safe(() => store.clearMany?.(prefixes));\n return;\n }\n for (const prefix of prefixes) {\n await safe(() => store.clear(prefix));\n }\n };\n\n const apply = async (op: StoreOp): Promise<void> => {\n await safe(() =>\n op.type === \"clear\"\n ? clearPrefixes(op.prefixes)\n : op.type === \"set\"\n ? store.set(op.key, op.entry, op.ttlMs)\n : store.delete(op.key),\n );\n };\n\n /** Plan, then apply, the store changes a response calls for. */\n const finish = async (\n state: State,\n response: Response,\n ): Promise<Response> => {\n const body = await readBody(state, response);\n const { result, ops } =\n state.kind === undefined\n ? { result: response, ops: writeOps(state, response, body) }\n : readPlan(state, response, body);\n if (state.kind === undefined && ops.some((op) => op.type === \"clear\")) {\n bump(state.ctx.resource as string); // before applying: reads now in flight must not store fresh\n }\n const expected = generation(state.ctx.resource);\n for (const op of ops) {\n await apply(op);\n }\n if (generation(state.ctx.resource) !== expected) {\n // An invalidation landed while storing: drop what was just stored.\n for (const op of ops.filter((candidate) => candidate.type === \"set\")) {\n await apply({ type: \"delete\", key: op.key });\n }\n }\n return result;\n };\n\n // -- stale-while-revalidate --------------------------------------------------\n\n const schedule = (state: State, next: Next): void => {\n const key = state.key as string;\n if (background.signal.aborted || inflight.has(key)) {\n return;\n }\n inflight.add(key);\n const entry = state.entry as CacheEntry;\n const task = (async (): Promise<void> => {\n try {\n const signal = background.signal;\n const headers = new Headers(state.ctx.request.headers);\n if (entry.etag !== undefined) {\n headers.set(\"if-none-match\", entry.etag);\n }\n // Detached from the caller's signal: this outlives their request.\n const request = new Request(state.ctx.request.url, {\n method: \"GET\",\n headers,\n signal,\n });\n const fresh: State = {\n ...state,\n validated: entry.etag !== undefined,\n };\n const response = await next({ ...state.ctx, request, signal });\n const result = await finish(fresh, response);\n await result.body?.cancel();\n } catch {\n // Nothing to report to: the caller already has the stale answer.\n } finally {\n inflight.delete(key);\n }\n })();\n tasks.add(task);\n void task.then(() => tasks.delete(task));\n };\n\n // -- the middleware ----------------------------------------------------------\n\n const middleware: Middleware = async (ctx, next) => {\n const state = await begin(ctx);\n if (state === undefined) {\n return next(ctx);\n }\n if (state.kind === undefined) {\n return finish(state, await next(ctx));\n }\n state.entry = await safe(() => store.get(state.key as string));\n const decision = decide(state, state.entry);\n const entry = state.entry as CacheEntry;\n if (decision === \"hit\") {\n return toResponse(entry, \"hit\");\n }\n if (decision === \"stale\") {\n schedule(state, next);\n return toResponse(entry, \"stale\");\n }\n let sent = ctx;\n if (decision === \"revalidate\") {\n sent = withValidator(ctx, entry.etag as string);\n state.validated = true;\n }\n return finish(state, await next(sent));\n };\n\n // -- control surface ---------------------------------------------------------\n\n const autoIfMatch: Middleware = async (ctx, next) => {\n const { request, resource, recordId } = ctx;\n if (\n (ctx.op === \"update\" || ctx.op === \"delete\") &&\n recordId !== undefined &&\n resource !== undefined &&\n policyFor(resource, ctx.apiVersion)?.enabled === true &&\n !request.headers.has(\"if-match\")\n ) {\n const etag = await lookupEtag(\n resource,\n recordId,\n await credentialScope(request.headers),\n ctx.apiVersion,\n );\n if (etag !== undefined) {\n const headers = new Headers(request.headers);\n headers.set(\"if-match\", etag);\n return next({ ...ctx, request: new Request(request, { headers }) });\n }\n }\n return next(ctx);\n };\n\n const lookupEtag = async (\n resource: string,\n recordId: number,\n scope: string,\n apiVersion: string | null,\n ): Promise<string | undefined> => {\n const entry = await safe(() =>\n store.get(\n buildKey({ resource, kind: \"record\", recordId, scope, apiVersion }),\n ),\n );\n return entry?.etag;\n };\n\n return {\n middleware,\n autoIfMatch,\n setEventsActive(resource, active) {\n if (active) {\n eventsActive.add(resource);\n } else {\n eventsActive.delete(resource);\n }\n },\n eventsActive: (resource) => eventsActive.has(resource),\n async invalidateEvent(resource, action, recordId) {\n bump(resource);\n await clearPrefixes(eventPrefixes(resource, action, recordId));\n },\n async clearResource(resource) {\n bump(resource);\n await clearPrefixes(resourcePrefixes(resource));\n },\n async clear(prefix) {\n globalGeneration += 1; // reads in flight must not store fresh over the clear\n await safe(() => store.clear(prefix));\n },\n cachedEtag: lookupEtag,\n async close() {\n background.abort();\n await Promise.allSettled(tasks);\n },\n };\n}\n","/** In-memory cache store: LRU with a per-entry TTL. */\nimport type { CacheEntry, CacheStore } from \"../interfaces.ts\";\n\n/** How long a store keeps an entry when the caller gives no ttl (the spec's retention floor). */\nexport const DEFAULT_TTL_MS = 3_600_000;\n\nexport interface MemoryStoreOptions {\n /** Default 1024. */\n readonly maxEntries?: number;\n readonly defaultTtlMs?: number;\n /** Epoch milliseconds; injectable for tests. */\n readonly now?: () => number;\n}\n\n/** LRU store (default 1024 entries) that also honours each entry's ttl. */\nexport class MemoryStore implements CacheStore {\n private readonly data = new Map<\n string,\n { readonly expiresAt: number; readonly entry: CacheEntry }\n >();\n private readonly maxEntries: number;\n private readonly defaultTtlMs: number;\n private readonly now: () => number;\n\n constructor(options: MemoryStoreOptions = {}) {\n const maxEntries = options.maxEntries ?? 1024;\n if (!Number.isInteger(maxEntries) || maxEntries < 1) {\n throw new RangeError(\"maxEntries must be an integer of at least 1\");\n }\n this.maxEntries = maxEntries;\n this.defaultTtlMs = options.defaultTtlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? Date.now;\n }\n\n /** Number of stored entries (expired ones included until touched). */\n get size(): number {\n return this.data.size;\n }\n\n get(key: string): CacheEntry | undefined {\n const item = this.data.get(key);\n if (item === undefined) {\n return undefined;\n }\n if (item.expiresAt <= this.now()) {\n this.data.delete(key);\n return undefined;\n }\n this.data.delete(key); // re-insert: Map order is the recency order\n this.data.set(key, item);\n return item.entry;\n }\n\n set(key: string, entry: CacheEntry, ttlMs?: number): void {\n this.data.delete(key);\n this.data.set(key, {\n expiresAt: this.now() + (ttlMs ?? this.defaultTtlMs),\n entry,\n });\n while (this.data.size > this.maxEntries) {\n // The first key is the least recently used.\n this.data.delete(this.data.keys().next().value as string);\n }\n }\n\n delete(key: string): void {\n this.data.delete(key);\n }\n\n /** Remove every key under any of `prefixes` in one walk. */\n clearMany(prefixes: readonly string[]): void {\n for (const key of this.data.keys()) {\n if (prefixes.some((prefix) => key.startsWith(prefix))) {\n this.data.delete(key);\n }\n }\n }\n\n clear(prefix?: string): void {\n for (const key of this.data.keys()) {\n if (prefix === undefined || key.startsWith(prefix)) {\n this.data.delete(key);\n }\n }\n }\n}\n","const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBIndex,\n IDBObjectStore,\n IDBCursor,\n IDBDatabase,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = ['advance', 'continue', 'continuePrimaryKey'].map((method) => IDBCursor.prototype[method])));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (!Object.is(newValue, value)) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event.newVersion, event));\n }\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking) {\n db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event));\n }\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = {};\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods[prop])\n return cachedMethods[prop];\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n return (cachedMethods[prop] = method);\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['advance', 'continue', 'continuePrimaryKey'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function (...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n },\n};\nasync function* iterate(...args) {\n // tslint:disable-next-line:no-this-assignment\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n // Map this double-proxy back to the original, so other cursor methods work.\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n // If one of the advancing methods was not called, call continue().\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return ((prop === Symbol.asyncIterator &&\n instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","/**\n * IndexedDB cache store (one object store, out-of-line string keys).\n *\n * Every call is wrapped: a blocked database, private mode or a missing\n * `indexedDB` is a miss (or a no-op), never a failed request. `clear(prefix)`\n * is one `IDBKeyRange.bound(prefix, prefix + \"\\uffff\")` delete.\n */\nimport { openDB } from \"idb\";\nimport type { IDBPDatabase } from \"idb\";\nimport type { CacheEntry, CacheStore } from \"../interfaces.ts\";\nimport { DEFAULT_TTL_MS } from \"./memory.ts\";\n\n// The package compiles without the DOM lib; this is the one global it needs.\ndeclare const IDBKeyRange: {\n bound(lower: string, upper: string): unknown;\n};\n\nconst STORE = \"entries\";\n\ninterface Stored {\n readonly expiresAt: number;\n readonly entry: CacheEntry;\n}\n\nexport interface IndexedDbStoreOptions {\n /** Database name; default `craftainer-crud-cache`. */\n readonly name?: string;\n readonly defaultTtlMs?: number;\n /** Epoch milliseconds; injectable for tests. */\n readonly now?: () => number;\n}\n\nexport class IndexedDbStore implements CacheStore {\n private readonly name: string;\n private readonly defaultTtlMs: number;\n private readonly now: () => number;\n private opening: Promise<IDBPDatabase> | undefined;\n\n constructor(options: IndexedDbStoreOptions = {}) {\n this.name = options.name ?? \"craftainer-crud-cache\";\n if (this.name === \"\") {\n // The name is the per-origin namespace of the store.\n throw new RangeError(\"IndexedDbStore: name must not be empty\");\n }\n this.defaultTtlMs = options.defaultTtlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? Date.now;\n }\n\n private open(): Promise<IDBPDatabase> {\n this.opening ??= openDB(this.name, 1, {\n upgrade(db) {\n db.createObjectStore(STORE);\n },\n });\n return this.opening;\n }\n\n /** Run `work` on the database; a failure drops the handle (so a later call retries) and yields `fallback`. */\n private async run<T>(\n fallback: T,\n work: (db: IDBPDatabase) => Promise<T>,\n ): Promise<T> {\n try {\n return await work(await this.open());\n } catch {\n // Close the handle we drop: an orphaned connection can block an upgrade.\n const dropped = this.opening;\n this.opening = undefined;\n try {\n (await dropped)?.close();\n } catch {\n // It never opened.\n }\n return fallback;\n }\n }\n\n get(key: string): Promise<CacheEntry | undefined> {\n return this.run<CacheEntry | undefined>(undefined, async (db) => {\n const stored = (await db.get(STORE, key)) as Stored | undefined;\n if (stored === undefined) {\n return undefined;\n }\n if (stored.expiresAt <= this.now()) {\n await db.delete(STORE, key);\n return undefined;\n }\n return stored.entry;\n });\n }\n\n set(key: string, entry: CacheEntry, ttlMs?: number): Promise<void> {\n return this.run(undefined, async (db) => {\n const stored: Stored = {\n expiresAt: this.now() + (ttlMs ?? this.defaultTtlMs),\n entry,\n };\n await db.put(STORE, stored, key);\n });\n }\n\n delete(key: string): Promise<void> {\n return this.run(undefined, (db) => db.delete(STORE, key));\n }\n\n clear(prefix?: string): Promise<void> {\n return this.run(undefined, (db) =>\n prefix === undefined\n ? db.clear(STORE)\n : db.delete(STORE, IDBKeyRange.bound(prefix, `${prefix}\\uffff`)),\n );\n }\n\n /** Clear several prefixes in one transaction (one bound range each). */\n clearMany(prefixes: readonly string[]): Promise<void> {\n return this.run(undefined, async (db) => {\n const tx = db.transaction(STORE, \"readwrite\");\n await Promise.all([\n ...prefixes.map((prefix) =>\n tx.store.delete(IDBKeyRange.bound(prefix, `${prefix}\\uffff`)),\n ),\n tx.done,\n ]);\n });\n }\n\n /** Close the database handle; a later call reopens it. */\n async close(): Promise<void> {\n const opening = this.opening;\n this.opening = undefined;\n try {\n (await opening)?.close();\n } catch {\n // Never opened.\n }\n }\n}\n","/** Wiring an event hub to a cache. */\nimport type { EventHub } from \"../events.ts\";\nimport type { Cache } from \"./middleware.ts\";\n\n/** The subscriptions that currently see a connected stream, per cache and resource. */\nconst connected = new WeakMap<Cache, Map<string, Set<object>>>();\n\n/**\n * Subscribe `cache` to `hub` for the manifest resource `resource`. Events\n * clear the spec's prefixes, a reconnect clears the resource, and fresh hits\n * are allowed only while the stream is connected. Returns the unsubscribe\n * (it also closes the freshness gate).\n */\nexport function invalidateOnEvents(\n cache: Cache,\n hub: EventHub,\n resource: string,\n): () => void {\n const byResource = connected.get(cache) ?? new Map<string, Set<object>>();\n connected.set(cache, byResource);\n const live = byResource.get(resource) ?? new Set<object>();\n byResource.set(resource, live);\n const self = {}; // this subscription's identity\n // The gate is open while any subscription sees a connected stream.\n const mark = (up: boolean): void => {\n if (up) {\n live.add(self);\n } else {\n live.delete(self);\n }\n cache.setEventsActive(resource, live.size > 0);\n };\n const unsubscribe = hub.subscribe({\n onEvent: (event) =>\n cache.invalidateEvent(resource, event.action, event.recordId),\n onReset: () => cache.clearResource(resource),\n onStatus: mark,\n });\n return () => {\n try {\n unsubscribe();\n } finally {\n mark(false); // idempotent; the gate stays open while another subscription is connected\n }\n };\n}\n"],"ignoreList":[5],"mappings":";;;AAMA,MAAM,2BAAW,IAAI,QAA+B;;;;;;;AAQpD,SAAgB,YAAY,UAA6C;CACvE,OAAO,SAAS,IAAI,QAAQ;AAC9B;;AAGA,SAAgB,UAAU,UAAoB,QAA+B;CAC3E,SAAS,IAAI,UAAU,MAAM;CAC7B,OAAO;AACT;AAGA,MAAM,mCAAwC,IAAI,IAAI;CACpD;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,0BAA+B,IAAI,IAAI;CAC3C;CACA;CACA;AACF,CAAC;;AAGD,SAAgB,aAAa,SAAuC;CAClE,MAAM,SAAS,QAAQ,IAAI,eAAe,KAAK,GAAA,CAC5C,MAAM,GAAG,CAAC,CACV,KAAK,SAAU,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,CAAY,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CACrE,QAAQ,SAAS,SAAS,EAAE;CAC/B,OAAO,IAAI,IAAI,KAAK;AACtB;;AAGA,SAAgB,OAAO,UAA6B;CAClD,MAAM,SAAS,SAAS,QAAQ,IAAI,cAAc,KAAK,GAAA,CACpD,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,CAChB,KAAK,CAAC,CACN,YAAY;CACf,OAAO,UAAU,sBAAsB,MAAM,SAAS,OAAO;AAC/D;;AAGA,SAAgB,kBAAkB,UAA6B;CAK7D,QAJe,SAAS,QAAQ,IAAI,MAAM,KAAK,GAAA,CAC5C,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CACxC,QAAQ,SAAS,SAAS,EAClB,CAAC,CAAC,OAAO,SAAS,QAAQ,IAAI,IAAI,CAAC;AAChD;AAEA,SAAS,gBAAgB,SAAoD;CAC3E,MAAM,QAA0C,CAAC;CACjD,KAAK,MAAM,CAAC,MAAM,UAAU,SAC1B,IAAI,CAAC,iBAAiB,IAAI,IAAI,GAC5B,MAAM,KAAK,CAAC,MAAM,KAAK,CAAC;CAG5B,OAAO;AACT;;AAWA,SAAgB,WACd,UACA,MACA,OACA,UACY;CACZ,MAAM,OAAO,WAAW,SAAS,QAAQ,IAAI,MAAM,IAAI;CACvD,MAAM,OAAO;EACX,QAAQ,SAAS;EACjB,SAAS,gBAAgB,SAAS,OAAO;EACzC;EACA,UAAU,MAAM;EAChB,YAAY,MAAM,MAAM,MAAM;EAC9B,YAAY,MAAM,MAAM,MAAM,QAAQ,MAAM;CAC9C;CACA,OAAO,SAAS,OAAO,OAAO;EAAE,GAAG;EAAM;CAAK;AAChD;;AAGA,SAAgB,aACd,QACA,QACuB;CACvB,MAAM,QAAQ,gBAAgB,MAAM;CACpC,MAAM,WAAW,IAAI,IAAI,MAAM,KAAK,CAAC,UAAU,IAAI,CAAC;CACpD,OAAO,CAAC,GAAG,OAAO,QAAQ,CAAC,UAAU,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,GAAG,KAAK;AACrE;;AAGA,SAAgB,WAAW,OAAmB,QAA+B;CAC3E,MAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,MAAM,CAAC,MAAM,UAAU,MAAM,SAChC,QAAQ,OAAO,MAAM,KAAK;CAE5B,OAAO,UACL,IAAI,SAAS,MAAM,MAAM;EAAE,QAAQ,MAAM;EAAQ;CAAQ,CAAC,GAC1D,MACF;AACF;;;AC1GA,MAAM,wBAA6B,IAAI,IAAe;CACpD;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,8BAAmC,IAAI,IAAI,CAAC,SAAS,SAAS,CAAC;AACrE,MAAM,mBAAmB;CAAC;CAAQ;CAAS;AAAS;AACpD,MAAM,mBAAmB,CAAC,UAAU,WAAW;;AAG/C,SAAgB,YAAY,IAAyB;CACnD,OAAO,MAAM,IAAI,EAAE;AACrB;;AAGA,SAAgB,YAAY,MAAuB;CACjD,OAAO,YAAY,IAAI,IAAI;AAC7B;;;;;;AAOA,SAAgB,eAAe,OAAuB;CAEpD,MAAM,SADO,MAAM,WAAW,GAAG,IAAI,MAAM,MAAM,CAAC,IAAI,MAAA,CAEnD,MAAM,GAAG,CAAC,CACV,QAAQ,SAAS,SAAS,MAAM,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAC/D,KAAK,SAAS;EACb,MAAM,KAAK,KAAK,QAAQ,GAAG;EAC3B,OAAO,KAAK,IACP,CAAC,MAAM,EAAE,IACT,CAAC,KAAK,MAAM,GAAG,EAAE,GAAG,KAAK,MAAM,EAAE,CAAC;CACzC,CAAC;CACH,MAAM,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,QACzB,OAAO,KAAM,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,IAAK,KAAK,KAAK,KAAK,CAChE;CACA,OAAO,MAAM,KAAK,CAAC,MAAM,UAAU,OAAO,IAAI,CAAC,CAAC,KAAK,GAAG;AAC1D;;AAaA,SAAgB,SAAS,OAAyB;CAChD,MAAM,WACH,MAAM,SAAS,YAAY,MAAM,SAAS,gBAC3C,MAAM,aAAa,KAAA,IACf,OAAO,MAAM,QAAQ,IACrB;CACN,MAAM,UAAU,MAAM,cAAc;CACpC,OAAO,MAAM,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,MAAM,GAAG,eAAe,MAAM,SAAS,EAAE;AACpH;;AAGA,SAAgB,YAAY,OAAuB;CACjD,OAAO,gBAAgB;AACzB;;AAGA,SAAgB,WAAW,UAAkB,MAAyB;CACpE,OAAO,MAAM,SAAS,GAAG,KAAK;AAChC;;AAGA,SAAgB,aAAa,UAAkB,UAA0B;CACvE,OAAO,MAAM,SAAS,UAAU,SAAS;AAC3C;;AAGA,SAAgB,gBAAgB,UAAkB,UAA0B;CAC1E,OAAO,MAAM,SAAS,aAAa,SAAS;AAC9C;;AAGA,SAAgB,mBAAmB,UAA4B;CAC7D,OAAO,iBAAiB,KAAK,SAAS,WAAW,UAAU,IAAI,CAAC;AAClE;;AAGA,SAAgB,iBAAiB,UAA4B;CAC3D,OAAO,CAAC,GAAG,kBAAkB,GAAG,gBAAgB,CAAC,CAAC,KAAK,SACrD,WAAW,UAAU,IAAI,CAC3B;AACF;;;;;;AAOA,SAAgB,cACd,UACA,QACA,UACU;CACV,IAAI,WAAW,UACb,OAAO,mBAAmB,QAAQ;CAEpC,KACG,WAAW,YAAY,WAAW,YAAY,WAAW,cAC1D,aAAa,KAAA,GAEb,OAAO;EACL,GAAG,mBAAmB,QAAQ;EAC9B,aAAa,UAAU,QAAQ;EAC/B,gBAAgB,UAAU,QAAQ;CACpC;CAEF,OAAO,iBAAiB,QAAQ;AAClC;;;;;;;;;;;AC/HA,eAAsB,gBAAgB,SAAmC;CACvE,MAAM,QAAQ,QAAQ,IAAI,eAAe;CACzC,IAAI,UAAU,MACZ,OAAO;CAET,MAAM,aAAa,mBAAmB,KAAK,KAAK,CAAC,GAAG,MAAM;CAC1D,OAAO,WAAW,UAAU;AAC9B;;;ACuHA,MAAM,mBAAmB;AACzB,MAAM,kBAA+B,wBAAwB,CAAC,CAAC;AAC/D,MAAM,gCAAqC,IAAI,IAAI;CACjD;CACA;CACA;CACA;AACF,CAAC;AACD,MAAM,2BAAgC,IAAI,IAAI,CAAC,eAAe,aAAa,CAAC;AAC5E,MAAM,gCAAqC,IAAI,IAAI;CACjD;CACA;CACA;AACF,CAAC;AACD,MAAM,0BAA+B,IAAI,IAAI;CAAC;CAAU;CAAS;AAAO,CAAC;AAEzE,SAAS,WAAW,UAA6B;CAC/C,OACE,OAAO,QAAQ,KACf,CAAC,aAAa,SAAS,OAAO,CAAC,CAAC,IAAI,UAAU,KAC9C,kBAAkB,QAAQ;AAE9B;AAEA,SAAS,YAAY,SAAiB,SAAyB;CAC7D,OAAO,KAAK,IAAI,UAAU,SAAS,gBAAgB;AACrD;;AAGA,SAAS,YAAY,MAAoC;CACvD,IAAI;EACF,MAAM,MAAO,KAAK,MAAM,IAAI,CAAC,CAAuB;EACpD,OAAO,MAAM,QAAQ,GAAG,KAAK,IAAI,OAAO,OAAO,OAAO,UAAU,EAAE,CAAC,IAC9D,MACD,KAAA;CACN,QAAQ;EACN;CACF;AACF;;AAGA,SAAS,kBAAkB,MAAwB;CACjD,IAAI;EACF,MAAM,YAAa,KAAK,MAAM,IAAI,CAAC,CAA6B;EAChE,OAAO,MAAM,QAAQ,SAAS,IAC1B,UACG,KAAK,SAA6B,KAAK,IAAI,CAAC,CAC5C,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAC5D,CAAC;CACP,QAAQ;EACN,OAAO,CAAC;CACV;AACF;AAEA,eAAe,KAAQ,MAAoD;CACzE,IAAI;EACF,OAAO,MAAM,KAAK;CACpB,QAAQ;EACN;CACF;AACF;AAEA,SAAgB,YAAY,SAA8B;CACxD,MAAM,EAAE,UAAU;CAClB,MAAM,WAAW,IAAI,IAAI,OAAO,QAAQ,QAAQ,QAAQ,CAAC;CACzD,MAAM,aACJ,UACA,eAEA,aAAa,KAAA,IACT,KAAA,IACC,SAAS,IAAI,GAAG,SAAS,GAAG,YAAY,KAAK,SAAS,IAAI,QAAQ;CACzE,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,MAAM,QAAQ,OAAO,KAAK;CAChC,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,8BAAc,IAAI,IAAoB;CAC5C,MAAM,2BAAW,IAAI,IAAY;CACjC,MAAM,wBAAQ,IAAI,IAAmB;CACrC,MAAM,aAAa,IAAI,gBAAgB;CAEvC,IAAI,mBAAmB;CACvB,MAAM,cAAc,cACjB,YAAY,IAAI,YAAY,EAAE,KAAK,KAAK;CAC3C,MAAM,QAAQ,aAA2B;EACvC,YAAY,IAAI,UAAU,WAAW,QAAQ,IAAI,CAAC;CACpD;;;;;;CASA,MAAM,YACJ,QACA,UACA,SAEA,CAAC,OAAO,kBACR,SAAS,cACT,SAAS,cACR,YAAY,IAAI,KAAK,aAAa,IAAI,QAAkB;;CAG3D,MAAM,aACJ,QACA,UACA,SAEA,SAAS,QAAQ,UAAU,IAAI,KAAK,aAAa,IAAI,QAAkB;;CAGzE,MAAM,cACJ,OACA,SACqC;EACrC,MAAM,WAAW,MAAM,IAAI;EAC3B,IACE,WAAW,QAAQ,MAAM,MAAM,cAC/B,CAAC,SAAS,MAAM,QAAQ,UAAU,IAAI,GAEtC,OAAO;GAAE,OAAO;GAAG,OAAO;EAAE;EAK9B,OAAO;GACL,QAJY,YAAY,IAAI,IAC1B,MAAM,OAAO,WACb,MAAM,OAAO,UAEA;GACf,OAAO,UAAU,MAAM,QAAQ,UAAU,IAAI,IACzC,MAAM,OAAO,uBAAuB,MACpC;EACN;CACF;CAEA,MAAM,UAAU,OAAc,UAA4C;EACxE,IAAI,UAAU,KAAA,GACZ,OAAO;EAET,IACE,CAAC,MAAM,mBACP,SAAS,MAAM,QAAQ,MAAM,IAAI,UAAU,MAAM,IAAY,GAC7D;GACA,MAAM,KAAK,IAAI;GACf,IAAI,KAAK,MAAM,YACb,OAAO;GAET,IACE,KAAK,MAAM,cACX,UAAU,MAAM,QAAQ,MAAM,IAAI,UAAU,MAAM,IAAY,GAE9D,OAAO;EAEX;EACA,OAAO,MAAM,SAAS,KAAA,KAAa,MAAM,OAAO,OAC5C,eACA;CACN;CAIA,MAAM,QAAQ,OAAO,QAAoD;EACvE,MAAM,EAAE,SAAS,aAAa;EAC9B,MAAM,QAAQ,MAAM,gBAAgB,QAAQ,OAAO;EACnD,MAAM,gBAAgB,WAAW,QAAQ;EACzC,IAAI,QAAQ,WAAW,OAAO;GAC5B,IAAI,CAAC,cAAc,IAAI,QAAQ,MAAM,GACnC;GAEF,MAAM,SAAS,UAAU,UAAU,IAAI,UAAU;GACjD,OAAO,QAAQ,YAAY,OACvB;IACE;IACA;IACA,MAAM,KAAA;IACN,KAAK,KAAA;IACL,YAAY;IACZ;IACA,iBAAiB;GACnB,IACA,KAAA;EACN;EACA,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI,IAAI,OAAO,YAAY;GACzB,IAAI,CAAC,eACH;GAEF,SAAS;GACT,OAAO;GACP,MAAM,YAAY,KAAK;EACzB,OAAO;GACL,SAAS,UAAU,UAAU,IAAI,UAAU;GAC3C,IACE,aAAa,KAAA,KACb,QAAQ,YAAY,QACpB,CAAC,YAAY,IAAI,EAAE,GAEnB;GAEF,OAAO,IAAI;GACX,MAAM,SAAS;IACb;IACA;IACA,UAAU,IAAI;IACd;IACA,OAAO,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC;IAC5B,YAAY,IAAI;GAClB,CAAC;EACH;EACA,MAAM,UAAU,aAAa,QAAQ,OAAO;EAC5C,IAAI,QAAQ,IAAI,UAAU,KAAK,QAAQ,QAAQ,IAAI,eAAe,GAChE;EAEF,OAAO;GACL;GACA;GACA;GACA;GACA,YAAY;GACZ;GACA,iBAAiB,QAAQ,IAAI,UAAU;EACzC;CACF;;CAGA,MAAM,iBAAiB,KAAqB,SAAiC;EAC3E,MAAM,UAAU,IAAI,QAAQ,IAAI,QAAQ,OAAO;EAC/C,QAAQ,IAAI,iBAAiB,IAAI;EACjC,OAAO;GAAE,GAAG;GAAK,SAAS,IAAI,QAAQ,IAAI,SAAS,EAAE,QAAQ,CAAC;EAAE;CAClE;CAIA,MAAM,WAAW,OACf,OACA,aACgC;EAChC,MAAM,EAAE,WAAW;EACnB,MAAM,EAAE,IAAI,aAAa,MAAM;EAC/B,IAAI;EACJ,IAAI,MAAM,SAAS,KAAA,GACjB,SAAS,WAAW,OAAO,WAAW,QAAQ;OACzC,IAAI,OAAO,UAChB,SAAS,WAAW,OAAO,aAAa,KAAA,KAAa,WAAW,QAAQ;OAExE,SACE,UAAU,OACV,SAAS,QACR,SAAS,IAAI,EAAE,KAAM,OAAO,aAAa,aAAa,KAAA;EAE3D,OAAO,SAAS,SAAS,MAAM,CAAC,CAAC,KAAK,IAAI,KAAA;CAC5C;;CAGA,MAAM,UAAU,aAA2C,CACzD;EAAE,MAAM;EAAS;CAAS,CAC5B;CAEA,MAAM,eACJ,KACA,UACc;EACd,IACE,QAAQ,KAAA,KACP,IAAI,SAAS,KAAA,KAAa,IAAI,SAAS,MAAM,MAE9C,OAAO,CAAC;EAEV,MAAM,wBAAQ,IAAI,IAAI;GACpB,GAAG,CAAC,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,QAAQ,WAAW,EAAE,CAAC;GAC/D,GAAG,kBAAkB,IAAI,IAAI;GAC7B,GAAG,kBAAkB,MAAM,IAAI;EACjC,CAAC;EACD,OAAO,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,SAAS,WAAW,MAAM,SAAS,CAAC,CAAC;CAC5E;CAEA,MAAM,YACJ,OACA,UACA,SACyC;EACzC,MAAM,MAAM,MAAM;EAClB,MAAM,OAAO,MAAM;EACnB,MAAM,EAAE,WAAW;EACnB,MAAM,KAAK,IAAI;EACf,MAAM,EAAE,OAAO,UAAU,WAAW,OAAO,IAAI;EAC/C,MAAM,MAAM,MAAM;EAClB,IAAI,WAAW,OAAO,MAAM,cAAc,QAAQ,QAAQ,KAAA,GAAW;GAEnE,MAAM,UAAsB;IAC1B,GAAG;IACH,SAAS,aAAa,IAAI,SAAS,SAAS,OAAO;IACnD,UAAU;IACV,YAAY,KAAK;IACjB,YAAY,KAAK,QAAQ;IACzB,MAAM,SAAS,QAAQ,IAAI,MAAM,KAAM,IAAI;GAC7C;GACA,OAAO;IACL,QAAQ,WAAW,SAAS,aAAa;IACzC,KAAK,CACH;KACE,MAAM;KACN;KACA,OAAO;KACP,OAAO,YAAY,OAAO,KAAK;IACjC,CACF;GACF;EACF;EACA,IAAI,WAAW,OAAO,SAAS,KAAA,GAAW;GACxC,UAAU,UAAU,MAAM;GAC1B,MAAM,QAAQ,WACZ,UACA,MACA;IAAE,KAAK;IAAI;IAAO;GAAM,GACxB,MAAM,OAAO,IACf;GACA,IAAI,MAAM,SAAS,KAAA,KAAa,SAAS,GAEvC,OAAO;IAAE,QAAQ;IAAU,KAAK,CAAC;KAAE,MAAM;KAAU;IAAI,CAAC;GAAE;GAE5D,MAAM,MAAiB,CACrB;IAAE,MAAM;IAAO;IAAK;IAAO,OAAO,YAAY,OAAO,KAAK;GAAE,CAC9D;GACA,IAAI,SAAS,YACX,IAAI,KAAK,GAAG,YAAY,KAAK,KAAK,CAAC;GAErC,OAAO;IAAE,QAAQ;IAAU;GAAI;EACjC;EACA,IAAI,WAAW,OAAO,WAAW,OAAO,WAAW,KACjD,OAAO;GAAE,QAAQ;GAAU,KAAK,CAAC;IAAE,MAAM;IAAU;GAAI,CAAC;EAAE;EAE5D,OAAO;GAAE,QAAQ;GAAU,KAAK,CAAC;EAAE;CACrC;;CAGA,MAAM,gBACJ,OACA,UACA,MACA,UACA,aACc;EACd,IAAI,SAAS,KAAA,GACX,OAAO,CAAC;EAEV,MAAM,EAAE,OAAO,UAAU,WAAW,OAAO,QAAQ;EACnD,MAAM,QAAQ,WACZ,UACA,MACA;GAAE,KAAK,IAAI;GAAG;GAAO;EAAM,GAC3B,MAAM,OAAO,IACf;EACA,IAAI,MAAM,SAAS,KAAA,KAAa,SAAS,GACvC,OAAO,CAAC;EASV,OAAO,CAAC;GAAE,MAAM;GAAO,KAPX,SAAS;IACnB;IACA,MAAM;IACN;IACA,OAAO,MAAM;IACb,YAAY,MAAM,IAAI;GACxB,CACyB;GAAG;GAAO,OAAO,YAAY,OAAO,KAAK;EAAE,CAAC;CACvE;CAEA,MAAM,YACJ,OACA,UACA,SACc;EACd,MAAM,EAAE,IAAI,aAAa,MAAM;EAC/B,MAAM,WAAW,MAAM,IAAI;EAC3B,MAAM,EAAE,WAAW;EACnB,IAAI,WAAW,KACb,OAAO,aAAa,KAAA,IAChB,CAAC,IACD,OAAO,CAAC,aAAa,UAAU,QAAQ,CAAC,CAAC;EAE/C,IAAI,SAAS,OAAO,UAAU,KAC5B,OAAO,CAAC;EAEV,MAAM,cAAc,mBAAmB,QAAQ;EAC/C,IAAI,QAAQ,IAAI,EAAE,GAChB,OAAO,OAAO,WAAW;EAE3B,IAAI,aAAa,KAAA,MAAc,cAAc,IAAI,EAAE,KAAK,OAAO,WAC7D,OAAO,CACL,GAAG,OAAO;GACR,GAAG;GACH,gBAAgB,UAAU,QAAQ;GAClC,aAAa,UAAU,QAAQ;EACjC,CAAC,GACD,GAAI,OAAO,WACP,aAAa,OAAO,UAAU,MAAM,UAAU,QAAQ,IACtD,CAAC,CACP;EAEF,IAAI,SAAS,IAAI,EAAE,KAAK,OAAO,WAAW;GAExC,MAAM,MAAM,YAAY,IAAc;GACtC,IAAI,QAAQ,KAAA,GACV,OAAO,OAAO,CACZ,GAAG,aACH,GAAG,IAAI,SAAS,OAAO,CACrB,aAAa,UAAU,EAAE,GACzB,gBAAgB,UAAU,EAAE,CAC9B,CAAC,CACH,CAAC;EAEL;EACA,OAAO,OAAO,iBAAiB,QAAQ,CAAC;CAC1C;;CAGA,MAAM,gBAAgB,OAAO,aAA+C;EAC1E,IAAI,MAAM,cAAc,KAAA,GAAW;GACjC,MAAM,WAAW,MAAM,YAAY,QAAQ,CAAC;GAC5C;EACF;EACA,KAAK,MAAM,UAAU,UACnB,MAAM,WAAW,MAAM,MAAM,MAAM,CAAC;CAExC;CAEA,MAAM,QAAQ,OAAO,OAA+B;EAClD,MAAM,WACJ,GAAG,SAAS,UACR,cAAc,GAAG,QAAQ,IACzB,GAAG,SAAS,QACV,MAAM,IAAI,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK,IACpC,MAAM,OAAO,GAAG,GAAG,CAC3B;CACF;;CAGA,MAAM,SAAS,OACb,OACA,aACsB;EACtB,MAAM,OAAO,MAAM,SAAS,OAAO,QAAQ;EAC3C,MAAM,EAAE,QAAQ,QACd,MAAM,SAAS,KAAA,IACX;GAAE,QAAQ;GAAU,KAAK,SAAS,OAAO,UAAU,IAAI;EAAE,IACzD,SAAS,OAAO,UAAU,IAAI;EACpC,IAAI,MAAM,SAAS,KAAA,KAAa,IAAI,MAAM,OAAO,GAAG,SAAS,OAAO,GAClE,KAAK,MAAM,IAAI,QAAkB;EAEnC,MAAM,WAAW,WAAW,MAAM,IAAI,QAAQ;EAC9C,KAAK,MAAM,MAAM,KACf,MAAM,MAAM,EAAE;EAEhB,IAAI,WAAW,MAAM,IAAI,QAAQ,MAAM,UAErC,KAAK,MAAM,MAAM,IAAI,QAAQ,cAAc,UAAU,SAAS,KAAK,GACjE,MAAM,MAAM;GAAE,MAAM;GAAU,KAAK,GAAG;EAAI,CAAC;EAG/C,OAAO;CACT;CAIA,MAAM,YAAY,OAAc,SAAqB;EACnD,MAAM,MAAM,MAAM;EAClB,IAAI,WAAW,OAAO,WAAW,SAAS,IAAI,GAAG,GAC/C;EAEF,SAAS,IAAI,GAAG;EAChB,MAAM,QAAQ,MAAM;EACpB,MAAM,QAAQ,YAA2B;GACvC,IAAI;IACF,MAAM,SAAS,WAAW;IAC1B,MAAM,UAAU,IAAI,QAAQ,MAAM,IAAI,QAAQ,OAAO;IACrD,IAAI,MAAM,SAAS,KAAA,GACjB,QAAQ,IAAI,iBAAiB,MAAM,IAAI;IAGzC,MAAM,UAAU,IAAI,QAAQ,MAAM,IAAI,QAAQ,KAAK;KACjD,QAAQ;KACR;KACA;IACF,CAAC;IACD,MAAM,QAAe;KACnB,GAAG;KACH,WAAW,MAAM,SAAS,KAAA;IAC5B;IACA,MAAM,WAAW,MAAM,KAAK;KAAE,GAAG,MAAM;KAAK;KAAS;IAAO,CAAC;IAE7D,OAAM,MADe,OAAO,OAAO,QAAQ,EAAA,CAC9B,MAAM,OAAO;GAC5B,QAAQ,CAER,UAAU;IACR,SAAS,OAAO,GAAG;GACrB;EACF,EAAA,CAAG;EACH,MAAM,IAAI,IAAI;EACd,KAAU,WAAW,MAAM,OAAO,IAAI,CAAC;CACzC;CAIA,MAAM,aAAyB,OAAO,KAAK,SAAS;EAClD,MAAM,QAAQ,MAAM,MAAM,GAAG;EAC7B,IAAI,UAAU,KAAA,GACZ,OAAO,KAAK,GAAG;EAEjB,IAAI,MAAM,SAAS,KAAA,GACjB,OAAO,OAAO,OAAO,MAAM,KAAK,GAAG,CAAC;EAEtC,MAAM,QAAQ,MAAM,WAAW,MAAM,IAAI,MAAM,GAAa,CAAC;EAC7D,MAAM,WAAW,OAAO,OAAO,MAAM,KAAK;EAC1C,MAAM,QAAQ,MAAM;EACpB,IAAI,aAAa,OACf,OAAO,WAAW,OAAO,KAAK;EAEhC,IAAI,aAAa,SAAS;GACxB,SAAS,OAAO,IAAI;GACpB,OAAO,WAAW,OAAO,OAAO;EAClC;EACA,IAAI,OAAO;EACX,IAAI,aAAa,cAAc;GAC7B,OAAO,cAAc,KAAK,MAAM,IAAc;GAC9C,MAAM,YAAY;EACpB;EACA,OAAO,OAAO,OAAO,MAAM,KAAK,IAAI,CAAC;CACvC;CAIA,MAAM,cAA0B,OAAO,KAAK,SAAS;EACnD,MAAM,EAAE,SAAS,UAAU,aAAa;EACxC,KACG,IAAI,OAAO,YAAY,IAAI,OAAO,aACnC,aAAa,KAAA,KACb,aAAa,KAAA,KACb,UAAU,UAAU,IAAI,UAAU,CAAC,EAAE,YAAY,QACjD,CAAC,QAAQ,QAAQ,IAAI,UAAU,GAC/B;GACA,MAAM,OAAO,MAAM,WACjB,UACA,UACA,MAAM,gBAAgB,QAAQ,OAAO,GACrC,IAAI,UACN;GACA,IAAI,SAAS,KAAA,GAAW;IACtB,MAAM,UAAU,IAAI,QAAQ,QAAQ,OAAO;IAC3C,QAAQ,IAAI,YAAY,IAAI;IAC5B,OAAO,KAAK;KAAE,GAAG;KAAK,SAAS,IAAI,QAAQ,SAAS,EAAE,QAAQ,CAAC;IAAE,CAAC;GACpE;EACF;EACA,OAAO,KAAK,GAAG;CACjB;CAEA,MAAM,aAAa,OACjB,UACA,UACA,OACA,eACgC;EAMhC,QAAO,MALa,WAClB,MAAM,IACJ,SAAS;GAAE;GAAU,MAAM;GAAU;GAAU;GAAO;EAAW,CAAC,CACpE,CACF,EAAA,EACc;CAChB;CAEA,OAAO;EACL;EACA;EACA,gBAAgB,UAAU,QAAQ;GAChC,IAAI,QACF,aAAa,IAAI,QAAQ;QAEzB,aAAa,OAAO,QAAQ;EAEhC;EACA,eAAe,aAAa,aAAa,IAAI,QAAQ;EACrD,MAAM,gBAAgB,UAAU,QAAQ,UAAU;GAChD,KAAK,QAAQ;GACb,MAAM,cAAc,cAAc,UAAU,QAAQ,QAAQ,CAAC;EAC/D;EACA,MAAM,cAAc,UAAU;GAC5B,KAAK,QAAQ;GACb,MAAM,cAAc,iBAAiB,QAAQ,CAAC;EAChD;EACA,MAAM,MAAM,QAAQ;GAClB,oBAAoB;GACpB,MAAM,WAAW,MAAM,MAAM,MAAM,CAAC;EACtC;EACA,YAAY;EACZ,MAAM,QAAQ;GACZ,WAAW,MAAM;GACjB,MAAM,QAAQ,WAAW,KAAK;EAChC;CACF;AACF;;AChtBA,IAAa,cAAb,MAA+C;CAC7C,uBAAwB,IAAI,IAG1B;CACF;CACA;CACA;CAEA,YAAY,UAA8B,CAAC,GAAG;EAC5C,MAAM,aAAa,QAAQ,cAAc;EACzC,IAAI,CAAC,OAAO,UAAU,UAAU,KAAK,aAAa,GAChD,MAAM,IAAI,WAAW,6CAA6C;EAEpE,KAAK,aAAa;EAClB,KAAK,eAAe,QAAQ,gBAAA;EAC5B,KAAK,MAAM,QAAQ,OAAO,KAAK;CACjC;;CAGA,IAAI,OAAe;EACjB,OAAO,KAAK,KAAK;CACnB;CAEA,IAAI,KAAqC;EACvC,MAAM,OAAO,KAAK,KAAK,IAAI,GAAG;EAC9B,IAAI,SAAS,KAAA,GACX;EAEF,IAAI,KAAK,aAAa,KAAK,IAAI,GAAG;GAChC,KAAK,KAAK,OAAO,GAAG;GACpB;EACF;EACA,KAAK,KAAK,OAAO,GAAG;EACpB,KAAK,KAAK,IAAI,KAAK,IAAI;EACvB,OAAO,KAAK;CACd;CAEA,IAAI,KAAa,OAAmB,OAAsB;EACxD,KAAK,KAAK,OAAO,GAAG;EACpB,KAAK,KAAK,IAAI,KAAK;GACjB,WAAW,KAAK,IAAI,KAAK,SAAS,KAAK;GACvC;EACF,CAAC;EACD,OAAO,KAAK,KAAK,OAAO,KAAK,YAE3B,KAAK,KAAK,OAAO,KAAK,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAe;CAE5D;CAEA,OAAO,KAAmB;EACxB,KAAK,KAAK,OAAO,GAAG;CACtB;;CAGA,UAAU,UAAmC;EAC3C,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK,GAC/B,IAAI,SAAS,MAAM,WAAW,IAAI,WAAW,MAAM,CAAC,GAClD,KAAK,KAAK,OAAO,GAAG;CAG1B;CAEA,MAAM,QAAuB;EAC3B,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK,GAC/B,IAAI,WAAW,KAAA,KAAa,IAAI,WAAW,MAAM,GAC/C,KAAK,KAAK,OAAO,GAAG;CAG1B;AACF;;;ACrFA,MAAM,iBAAiB,QAAQ,iBAAiB,aAAa,MAAM,MAAM,kBAAkB,CAAC;AAE5F,IAAI;AACJ,IAAI;AAEJ,SAAS,uBAAuB;CAC5B,OAAQ,sBACH,oBAAoB;EACjB;EACA;EACA;EACA;EACA;CACJ;AACR;AAEA,SAAS,0BAA0B;CAC/B,OAAQ,yBACH,uBAAuB;EAAC;EAAW;EAAY;CAAoB,CAAC,CAAC,KAAK,WAAW,UAAU,UAAU,OAAO;AACzH;AACA,MAAM,qCAAqB,IAAI,QAAQ;AACvC,MAAM,iCAAiB,IAAI,QAAQ;AACnC,MAAM,wCAAwB,IAAI,QAAQ;AAC1C,SAAS,iBAAiB,SAAS;CAC/B,MAAM,UAAU,IAAI,SAAS,SAAS,WAAW;EAC7C,MAAM,iBAAiB;GACnB,QAAQ,oBAAoB,WAAW,OAAO;GAC9C,QAAQ,oBAAoB,SAAS,KAAK;EAC9C;EACA,MAAM,gBAAgB;GAClB,QAAQ,KAAK,QAAQ,MAAM,CAAC;GAC5B,SAAS;EACb;EACA,MAAM,cAAc;GAChB,OAAO,QAAQ,KAAK;GACpB,SAAS;EACb;EACA,QAAQ,iBAAiB,WAAW,OAAO;EAC3C,QAAQ,iBAAiB,SAAS,KAAK;CAC3C,CAAC;CAGD,sBAAsB,IAAI,SAAS,OAAO;CAC1C,OAAO;AACX;AACA,SAAS,+BAA+B,IAAI;CAExC,IAAI,mBAAmB,IAAI,EAAE,GACzB;CACJ,MAAM,OAAO,IAAI,SAAS,SAAS,WAAW;EAC1C,MAAM,iBAAiB;GACnB,GAAG,oBAAoB,YAAY,QAAQ;GAC3C,GAAG,oBAAoB,SAAS,KAAK;GACrC,GAAG,oBAAoB,SAAS,KAAK;EACzC;EACA,MAAM,iBAAiB;GACnB,QAAQ;GACR,SAAS;EACb;EACA,MAAM,cAAc;GAChB,OAAO,GAAG,SAAS,IAAI,aAAa,cAAc,YAAY,CAAC;GAC/D,SAAS;EACb;EACA,GAAG,iBAAiB,YAAY,QAAQ;EACxC,GAAG,iBAAiB,SAAS,KAAK;EAClC,GAAG,iBAAiB,SAAS,KAAK;CACtC,CAAC;CAED,mBAAmB,IAAI,IAAI,IAAI;AACnC;AACA,IAAI,gBAAgB;CAChB,IAAI,QAAQ,MAAM,UAAU;EACxB,IAAI,kBAAkB,gBAAgB;GAElC,IAAI,SAAS,QACT,OAAO,mBAAmB,IAAI,MAAM;GAExC,IAAI,SAAS,SACT,OAAO,SAAS,iBAAiB,KAC3B,KAAA,IACA,SAAS,YAAY,SAAS,iBAAiB,EAAE;EAE/D;EAEA,OAAO,KAAK,OAAO,KAAK;CAC5B;CACA,IAAI,QAAQ,MAAM,OAAO;EACrB,OAAO,QAAQ;EACf,OAAO;CACX;CACA,IAAI,QAAQ,MAAM;EACd,IAAI,kBAAkB,mBACjB,SAAS,UAAU,SAAS,UAC7B,OAAO;EAEX,OAAO,QAAQ;CACnB;AACJ;AACA,SAAS,aAAa,UAAU;CAC5B,gBAAgB,SAAS,aAAa;AAC1C;AACA,SAAS,aAAa,MAAM;CAQxB,IAAI,wBAAwB,CAAC,CAAC,SAAS,IAAI,GACvC,OAAO,SAAU,GAAG,MAAM;EAGtB,KAAK,MAAM,OAAO,IAAI,GAAG,IAAI;EAC7B,OAAO,KAAK,KAAK,OAAO;CAC5B;CAEJ,OAAO,SAAU,GAAG,MAAM;EAGtB,OAAO,KAAK,KAAK,MAAM,OAAO,IAAI,GAAG,IAAI,CAAC;CAC9C;AACJ;AACA,SAAS,uBAAuB,OAAO;CACnC,IAAI,OAAO,UAAU,YACjB,OAAO,aAAa,KAAK;CAG7B,IAAI,iBAAiB,gBACjB,+BAA+B,KAAK;CACxC,IAAI,cAAc,OAAO,qBAAqB,CAAC,GAC3C,OAAO,IAAI,MAAM,OAAO,aAAa;CAEzC,OAAO;AACX;AACA,SAAS,KAAK,OAAO;CAGjB,IAAI,iBAAiB,YACjB,OAAO,iBAAiB,KAAK;CAGjC,IAAI,eAAe,IAAI,KAAK,GACxB,OAAO,eAAe,IAAI,KAAK;CACnC,MAAM,WAAW,uBAAuB,KAAK;CAG7C,IAAI,CAAC,OAAO,GAAG,UAAU,KAAK,GAAG;EAC7B,eAAe,IAAI,OAAO,QAAQ;EAClC,sBAAsB,IAAI,UAAU,KAAK;CAC7C;CACA,OAAO;AACX;AACA,MAAM,UAAU,UAAU,sBAAsB,IAAI,KAAK;;;;;;;;AASzD,SAAS,OAAO,MAAM,SAAS,EAAE,SAAS,SAAS,UAAU,eAAe,CAAC,GAAG;CAC5E,MAAM,UAAU,UAAU,KAAK,MAAM,OAAO;CAC5C,MAAM,cAAc,KAAK,OAAO;CAChC,IAAI,SACA,QAAQ,iBAAiB,kBAAkB,UAAU;EACjD,QAAQ,KAAK,QAAQ,MAAM,GAAG,MAAM,YAAY,MAAM,YAAY,KAAK,QAAQ,WAAW,GAAG,KAAK;CACtG,CAAC;CAEL,IAAI,SACA,QAAQ,iBAAiB,YAAY,UAAU,QAE/C,MAAM,YAAY,MAAM,YAAY,KAAK,CAAC;CAE9C,YACK,MAAM,OAAO;EACd,IAAI,YACA,GAAG,iBAAiB,eAAe,WAAW,CAAC;EACnD,IAAI,UACA,GAAG,iBAAiB,kBAAkB,UAAU,SAAS,MAAM,YAAY,MAAM,YAAY,KAAK,CAAC;CAE3G,CAAC,CAAC,CACG,YAAY,CAAE,CAAC;CACpB,OAAO;AACX;AAgBA,MAAM,cAAc;CAAC;CAAO;CAAU;CAAU;CAAc;AAAO;AACrE,MAAM,eAAe;CAAC;CAAO;CAAO;CAAU;AAAO;AACrD,MAAM,gBAAgB,CAAC;AACvB,SAAS,UAAU,QAAQ,MAAM;CAC7B,IAAI,EAAE,kBAAkB,eACpB,EAAE,QAAQ,WACV,OAAO,SAAS,WAChB;CAEJ,IAAI,cAAc,OACd,OAAO,cAAc;CACzB,MAAM,iBAAiB,KAAK,QAAQ,cAAc,EAAE;CACpD,MAAM,WAAW,SAAS;CAC1B,MAAM,UAAU,aAAa,SAAS,cAAc;CACpD,IAEA,EAAE,mBAAmB,WAAW,WAAW,eAAA,CAAgB,cACvD,EAAE,WAAW,YAAY,SAAS,cAAc,IAChD;CAEJ,MAAM,SAAS,eAAgB,WAAW,GAAG,MAAM;EAE/C,MAAM,KAAK,KAAK,YAAY,WAAW,UAAU,cAAc,UAAU;EACzE,IAAI,SAAS,GAAG;EAChB,IAAI,UACA,SAAS,OAAO,MAAM,KAAK,MAAM,CAAC;EAMtC,QAAQ,MAAM,QAAQ,IAAI,CACtB,OAAO,eAAe,CAAC,GAAG,IAAI,GAC9B,WAAW,GAAG,IAClB,CAAC,EAAA,CAAG;CACR;CACA,OAAQ,cAAc,QAAQ;AAClC;AACA,cAAc,cAAc;CACxB,GAAG;CACH,MAAM,QAAQ,MAAM,aAAa,UAAU,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,MAAM,QAAQ;CAC/F,MAAM,QAAQ,SAAS,CAAC,CAAC,UAAU,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,IAAI;AACjF,EAAE;AAEF,MAAM,qBAAqB;CAAC;CAAW;CAAY;AAAoB;AACvE,MAAM,YAAY,CAAC;AACnB,MAAM,iCAAiB,IAAI,QAAQ;AACnC,MAAM,mDAAmC,IAAI,QAAQ;AACrD,MAAM,sBAAsB,EACxB,IAAI,QAAQ,MAAM;CACd,IAAI,CAAC,mBAAmB,SAAS,IAAI,GACjC,OAAO,OAAO;CAClB,IAAI,aAAa,UAAU;CAC3B,IAAI,CAAC,YACD,aAAa,UAAU,QAAQ,SAAU,GAAG,MAAM;EAC9C,eAAe,IAAI,MAAM,iCAAiC,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;CACtF;CAEJ,OAAO;AACX,EACJ;AACA,gBAAgB,QAAQ,GAAG,MAAM;CAE7B,IAAI,SAAS;CACb,IAAI,EAAE,kBAAkB,YACpB,SAAS,MAAM,OAAO,WAAW,GAAG,IAAI;CAE5C,IAAI,CAAC,QACD;CACJ,SAAS;CACT,MAAM,gBAAgB,IAAI,MAAM,QAAQ,mBAAmB;CAC3D,iCAAiC,IAAI,eAAe,MAAM;CAE1D,sBAAsB,IAAI,eAAe,OAAO,MAAM,CAAC;CACvD,OAAO,QAAQ;EACX,MAAM;EAEN,SAAS,OAAO,eAAe,IAAI,aAAa,KAAK,OAAO,SAAS;EACrE,eAAe,OAAO,aAAa;CACvC;AACJ;AACA,SAAS,eAAe,QAAQ,MAAM;CAClC,OAAS,SAAS,OAAO,iBACrB,cAAc,QAAQ;EAAC;EAAU;EAAgB;CAAS,CAAC,KAC1D,SAAS,aAAa,cAAc,QAAQ,CAAC,UAAU,cAAc,CAAC;AAC/E;AACA,cAAc,cAAc;CACxB,GAAG;CACH,IAAI,QAAQ,MAAM,UAAU;EACxB,IAAI,eAAe,QAAQ,IAAI,GAC3B,OAAO;EACX,OAAO,SAAS,IAAI,QAAQ,MAAM,QAAQ;CAC9C;CACA,IAAI,QAAQ,MAAM;EACd,OAAO,eAAe,QAAQ,IAAI,KAAK,SAAS,IAAI,QAAQ,IAAI;CACpE;AACJ,EAAE;;;;;;;;;;ACxRF,MAAM,QAAQ;AAed,IAAa,iBAAb,MAAkD;CAChD;CACA;CACA;CACA;CAEA,YAAY,UAAiC,CAAC,GAAG;EAC/C,KAAK,OAAO,QAAQ,QAAQ;EAC5B,IAAI,KAAK,SAAS,IAEhB,MAAM,IAAI,WAAW,wCAAwC;EAE/D,KAAK,eAAe,QAAQ,gBAAA;EAC5B,KAAK,MAAM,QAAQ,OAAO,KAAK;CACjC;CAEA,OAAsC;EACpC,KAAK,YAAY,OAAO,KAAK,MAAM,GAAG,EACpC,QAAQ,IAAI;GACV,GAAG,kBAAkB,KAAK;EAC5B,EACF,CAAC;EACD,OAAO,KAAK;CACd;;CAGA,MAAc,IACZ,UACA,MACY;EACZ,IAAI;GACF,OAAO,MAAM,KAAK,MAAM,KAAK,KAAK,CAAC;EACrC,QAAQ;GAEN,MAAM,UAAU,KAAK;GACrB,KAAK,UAAU,KAAA;GACf,IAAI;IACF,CAAC,MAAM,QAAA,EAAU,MAAM;GACzB,QAAQ,CAER;GACA,OAAO;EACT;CACF;CAEA,IAAI,KAA8C;EAChD,OAAO,KAAK,IAA4B,KAAA,GAAW,OAAO,OAAO;GAC/D,MAAM,SAAU,MAAM,GAAG,IAAI,OAAO,GAAG;GACvC,IAAI,WAAW,KAAA,GACb;GAEF,IAAI,OAAO,aAAa,KAAK,IAAI,GAAG;IAClC,MAAM,GAAG,OAAO,OAAO,GAAG;IAC1B;GACF;GACA,OAAO,OAAO;EAChB,CAAC;CACH;CAEA,IAAI,KAAa,OAAmB,OAA+B;EACjE,OAAO,KAAK,IAAI,KAAA,GAAW,OAAO,OAAO;GACvC,MAAM,SAAiB;IACrB,WAAW,KAAK,IAAI,KAAK,SAAS,KAAK;IACvC;GACF;GACA,MAAM,GAAG,IAAI,OAAO,QAAQ,GAAG;EACjC,CAAC;CACH;CAEA,OAAO,KAA4B;EACjC,OAAO,KAAK,IAAI,KAAA,IAAY,OAAO,GAAG,OAAO,OAAO,GAAG,CAAC;CAC1D;CAEA,MAAM,QAAgC;EACpC,OAAO,KAAK,IAAI,KAAA,IAAY,OAC1B,WAAW,KAAA,IACP,GAAG,MAAM,KAAK,IACd,GAAG,OAAO,OAAO,YAAY,MAAM,QAAQ,GAAG,OAAO,OAAO,CAAC,CACnE;CACF;;CAGA,UAAU,UAA4C;EACpD,OAAO,KAAK,IAAI,KAAA,GAAW,OAAO,OAAO;GACvC,MAAM,KAAK,GAAG,YAAY,OAAO,WAAW;GAC5C,MAAM,QAAQ,IAAI,CAChB,GAAG,SAAS,KAAK,WACf,GAAG,MAAM,OAAO,YAAY,MAAM,QAAQ,GAAG,OAAO,OAAO,CAAC,CAC9D,GACA,GAAG,IACL,CAAC;EACH,CAAC;CACH;;CAGA,MAAM,QAAuB;EAC3B,MAAM,UAAU,KAAK;EACrB,KAAK,UAAU,KAAA;EACf,IAAI;GACF,CAAC,MAAM,QAAA,EAAU,MAAM;EACzB,QAAQ,CAER;CACF;AACF;;;;ACnIA,MAAM,4BAAY,IAAI,QAAyC;;;;;;;AAQ/D,SAAgB,mBACd,OACA,KACA,UACY;CACZ,MAAM,aAAa,UAAU,IAAI,KAAK,qBAAK,IAAI,IAAyB;CACxE,UAAU,IAAI,OAAO,UAAU;CAC/B,MAAM,OAAO,WAAW,IAAI,QAAQ,qBAAK,IAAI,IAAY;CACzD,WAAW,IAAI,UAAU,IAAI;CAC7B,MAAM,OAAO,CAAC;CAEd,MAAM,QAAQ,OAAsB;EAClC,IAAI,IACF,KAAK,IAAI,IAAI;OAEb,KAAK,OAAO,IAAI;EAElB,MAAM,gBAAgB,UAAU,KAAK,OAAO,CAAC;CAC/C;CACA,MAAM,cAAc,IAAI,UAAU;EAChC,UAAU,UACR,MAAM,gBAAgB,UAAU,MAAM,QAAQ,MAAM,QAAQ;EAC9D,eAAe,MAAM,cAAc,QAAQ;EAC3C,UAAU;CACZ,CAAC;CACD,aAAa;EACX,IAAI;GACF,YAAY;EACd,UAAU;GACR,KAAK,KAAK;EACZ;CACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/cache/entry.ts","../../src/cache/keys.ts","../../src/cache/scope.ts","../../src/cache/middleware.ts","../../src/cache/memory.ts","../../node_modules/.pnpm/idb@8.0.4/node_modules/idb/build/index.js","../../src/cache/idb.ts","../../src/cache/wire.ts"],"sourcesContent":["/** Turning responses into `CacheEntry` values and back. */\nimport type { CacheEntry } from \"../interfaces.ts\";\n\n/** How the cache answered a read: see `cacheStatus`. */\nexport type CacheStatus = \"hit\" | \"stale\" | \"revalidated\" | \"miss\";\n\nconst statuses = new WeakMap<Response, CacheStatus>();\n\n/**\n * How the cache answered `response`: `hit` (fresh, no network), `stale`\n * (inside the stale-while-revalidate window, refreshed in the background),\n * `revalidated` (a `304` rebuilt from the stored entry) or `miss`.\n * `undefined` when the cache did not handle the request.\n */\nexport function cacheStatus(response: Response): CacheStatus | undefined {\n return statuses.get(response);\n}\n\n/** Tag `response` with how the cache answered. */\nexport function tagStatus(response: Response, status: CacheStatus): Response {\n statuses.set(response, status);\n return response;\n}\n\n// Describe the transfer, not the representation: the stored body is decoded.\nconst TRANSFER_HEADERS: ReadonlySet<string> = new Set([\n \"content-length\",\n \"content-encoding\",\n \"transfer-encoding\",\n \"connection\",\n \"keep-alive\",\n]);\nconst VARY_OK: ReadonlySet<string> = new Set([\n \"authorization\",\n \"accept\",\n \"accept-encoding\",\n]);\n\n/** The lower-cased directive names of the `Cache-Control` header. */\nexport function cacheControl(headers: Headers): ReadonlySet<string> {\n const names = (headers.get(\"cache-control\") ?? \"\")\n .split(\",\")\n .map((part) => (part.split(\"=\", 1)[0] as string).trim().toLowerCase())\n .filter((name) => name !== \"\");\n return new Set(names);\n}\n\n/** Whether the media type is JSON (`application/json` or `+json`). */\nexport function isJson(response: Response): boolean {\n const media = (response.headers.get(\"content-type\") ?? \"\")\n .split(\";\", 1)[0]!\n .trim()\n .toLowerCase();\n return media === \"application/json\" || media.endsWith(\"+json\");\n}\n\n/** `Vary` may only name headers the key already accounts for; `*` never caches. */\nexport function varyAllowsCaching(response: Response): boolean {\n const names = (response.headers.get(\"vary\") ?? \"\")\n .split(\",\")\n .map((part) => part.trim().toLowerCase())\n .filter((name) => name !== \"\");\n return names.every((name) => VARY_OK.has(name));\n}\n\nfunction storableHeaders(headers: Headers): Array<readonly [string, string]> {\n const items: Array<readonly [string, string]> = [];\n for (const [name, value] of headers) {\n if (!TRANSFER_HEADERS.has(name)) {\n items.push([name, value]);\n }\n }\n return items;\n}\n\nexport interface EntryTimes {\n readonly now: number;\n /** Milliseconds fresh. */\n readonly fresh: number;\n /** Milliseconds of stale-while-revalidate after `fresh`. */\n readonly stale: number;\n}\n\n/** Snapshot a read response whose body text was already read. */\nexport function buildEntry(\n response: Response,\n body: string,\n times: EntryTimes,\n keepEtag: boolean,\n): CacheEntry {\n const etag = keepEtag ? response.headers.get(\"etag\") : null;\n const base = {\n status: response.status,\n headers: storableHeaders(response.headers),\n body,\n storedAt: times.now,\n freshUntil: times.now + times.fresh,\n staleUntil: times.now + times.fresh + times.stale,\n };\n return etag === null ? base : { ...base, etag };\n}\n\n/** RFC 9111 4.3.4: headers of a `304` replace the stored ones of the same name. */\nexport function mergeHeaders(\n stored: CacheEntry[\"headers\"],\n update: Headers,\n): CacheEntry[\"headers\"] {\n const fresh = storableHeaders(update);\n const replaced = new Set(fresh.map(([name]) => name));\n return [...stored.filter(([name]) => !replaced.has(name)), ...fresh];\n}\n\n/** Rebuild a response from an entry, tagged with how the cache produced it. */\nexport function toResponse(entry: CacheEntry, status: CacheStatus): Response {\n const headers = new Headers();\n for (const [name, value] of entry.headers) {\n headers.append(name, value);\n }\n return tagStatus(\n new Response(entry.body, { status: entry.status, headers }),\n status,\n );\n}\n","/**\n * Cache keys and the invalidation prefixes.\n *\n * Keys are slash-separated:\n * `v1/{resource}/{kind}/{subject}/{apiVersion}/{scope}/{canonicalQuery}`.\n * Versions of one resource never share an entry, but they share one event\n * stream; because the version comes after kind and subject, one prefix such\n * as `v1/{resource}/record/{id}/` clears an entry in every version and for\n * every caller at once.\n */\nimport type { Op } from \"../interfaces.ts\";\n\n/** The ops that read and are cached (`manifest` has its own key). */\nexport type CacheKind =\n \"list\" | \"record\" | \"stats\" | \"predict\" | \"revisions\" | \"filters\";\n\nconst KINDS: ReadonlySet<string> = new Set<CacheKind>([\n \"list\",\n \"record\",\n \"stats\",\n \"predict\",\n \"revisions\",\n \"filters\",\n]);\nconst STATS_KINDS: ReadonlySet<string> = new Set([\"stats\", \"predict\"]);\nconst COLLECTION_KINDS = [\"list\", \"stats\", \"predict\"] as const;\nconst PER_RECORD_KINDS = [\"record\", \"revisions\"] as const;\n\n/** `true` when the op is a cacheable read kind. */\nexport function isCacheKind(op: Op): op is CacheKind {\n return KINDS.has(op);\n}\n\n/** `true` for `stats` and `predict`, which `stats_ttl` bounds. */\nexport function isStatsKind(kind: string): boolean {\n return STATS_KINDS.has(kind);\n}\n\n/**\n * Sorts the query pairs the client sent and drops `id` (it is the subject).\n * Values are kept verbatim: the client already emits canonical,\n * percent-encoded text, so nothing is decoded or re-encoded here.\n */\nexport function canonicalQuery(query: string): string {\n const text = query.startsWith(\"?\") ? query.slice(1) : query;\n const pairs = text\n .split(\"&\")\n .filter((part) => part !== \"\" && part.split(\"=\", 1)[0] !== \"id\")\n .map((part) => {\n const at = part.indexOf(\"=\");\n return at < 0\n ? ([part, \"\"] as const)\n : ([part.slice(0, at), part.slice(at)] as const);\n });\n pairs.sort(([an, av], [bn, bv]) =>\n an === bn ? (av < bv ? -1 : av > bv ? 1 : 0) : an < bn ? -1 : 1,\n );\n return pairs.map(([name, rest]) => name + rest).join(\"&\");\n}\n\nexport interface KeyParts {\n readonly resource: string;\n readonly kind: CacheKind;\n readonly recordId?: number | undefined;\n readonly scope: string;\n readonly query?: string;\n /** `null` (no version) renders as `_`. */\n readonly apiVersion: string | null;\n}\n\n/** The key of one cached response. */\nexport function buildKey(parts: KeyParts): string {\n const subject =\n (parts.kind === \"record\" || parts.kind === \"revisions\") &&\n parts.recordId !== undefined\n ? String(parts.recordId)\n : \"_\";\n const version = parts.apiVersion ?? \"_\";\n return `v1/${parts.resource}/${parts.kind}/${subject}/${version}/${parts.scope}/${canonicalQuery(parts.query ?? \"\")}`;\n}\n\n/** Key of the manifest document for one caller scope. */\nexport function manifestKey(scope: string): string {\n return `v1/_manifest/${scope}`;\n}\n\n/** Prefix of all entries of one kind for `resource` (every scope and subject). */\nexport function kindPrefix(resource: string, kind: CacheKind): string {\n return `v1/${resource}/${kind}/`;\n}\n\n/** Prefix of the `record` entries of one record (every version, scope, query). */\nexport function recordPrefix(resource: string, recordId: number): string {\n return `v1/${resource}/record/${recordId}/`;\n}\n\n/** Prefix of the `revisions` entries of one record. */\nexport function revisionsPrefix(resource: string, recordId: number): string {\n return `v1/${resource}/revisions/${recordId}/`;\n}\n\n/** The list, stats and predict prefixes of `resource`. */\nexport function collectionPrefixes(resource: string): string[] {\n return COLLECTION_KINDS.map((kind) => kindPrefix(resource, kind));\n}\n\n/** Everything cached for `resource` except `filters` (a reconnect or an unknown change). */\nexport function resourcePrefixes(resource: string): string[] {\n return [...COLLECTION_KINDS, ...PER_RECORD_KINDS].map((kind) =>\n kindPrefix(resource, kind),\n );\n}\n\n/**\n * Prefixes an SSE event clears, per the spec's table: `create` clears the\n * collection kinds; `update`/`delete`/`restore` also clear the record and its\n * revisions; an unknown action or a missing record id clears the resource.\n */\nexport function eventPrefixes(\n resource: string,\n action: string,\n recordId: number | undefined,\n): string[] {\n if (action === \"create\") {\n return collectionPrefixes(resource);\n }\n if (\n (action === \"update\" || action === \"delete\" || action === \"restore\") &&\n recordId !== undefined\n ) {\n return [\n ...collectionPrefixes(resource),\n recordPrefix(resource, recordId),\n revisionsPrefix(resource, recordId),\n ];\n }\n return resourcePrefixes(resource);\n}\n","import { ANON, cacheScope } from \"../auth.ts\";\n\n/**\n * `\"anon\"` when the request has no Authorization header; otherwise the first\n * 32 hex characters of the SHA-256 of the whole credential, the same digest as\n * the client's `cacheScope(token)` (a `Bearer ` prefix is dropped, any other value is hashed as it is). It is read from the\n * request the cache sees, so it must be the innermost middleware that matters:\n * whatever sets Authorization has to run before the cache. The raw credential\n * never enters a key or a log, and the unverified `sub` claim is never used.\n */\nexport async function credentialScope(headers: Headers): Promise<string> {\n const value = headers.get(\"authorization\");\n if (value === null) {\n return ANON;\n }\n const credential = /^bearer\\s+(.+)$/i.exec(value)?.[1] ?? value;\n return cacheScope(credential);\n}\n","/**\n * The caching middleware (`createCache`): an I3 `Middleware` plus the control\n * surface that events and the client use.\n *\n * It reads the resource, op, record id, API version and caller scope from\n * `RequestContext` and never touches the Authorization header. A read is\n * answered in one of four ways, see `cacheStatus`: `hit` (fresh, no\n * network), `stale` (inside the stale-while-revalidate window, refreshed in\n * the background), `revalidated` (a `304` rebuilt from the stored entry with\n * merged headers) or `miss`.\n *\n * Freshness beyond \"revalidate every time\" is granted only while the\n * resource's SSE stream is up (`setEventsActive`): events are the only thing\n * that can end a fresh window early. `stats` and `predict` are bounded by\n * `statsTtl` instead, as the server caches those bodies the same way. A\n * per-resource generation counter stops a response that was in flight when\n * an invalidation landed from being stored fresh.\n */\nimport type {\n CacheEntry,\n MaybePromise,\n CacheStore,\n Middleware,\n Next,\n RequestContext,\n} from \"../interfaces.ts\";\nimport {\n buildEntry,\n cacheControl,\n isJson,\n mergeHeaders,\n tagStatus,\n toResponse,\n varyAllowsCaching,\n} from \"./entry.ts\";\nimport {\n buildKey,\n collectionPrefixes,\n eventPrefixes,\n isCacheKind,\n isStatsKind,\n kindPrefix,\n manifestKey,\n recordPrefix,\n resourcePrefixes,\n revisionsPrefix,\n} from \"./keys.ts\";\nimport type { CacheKind } from \"./keys.ts\";\nimport { cachePolicyFromManifest } from \"./policy.ts\";\nimport { credentialScope } from \"./scope.ts\";\nimport type { CachePolicy } from \"./policy.ts\";\n\n/**\n * A store may clear several prefixes in one pass (one walk, one transaction);\n * the cache uses it when present and falls back to `clear` per prefix.\n */\nexport interface CacheStoreMany extends CacheStore {\n clearMany?(prefixes: readonly string[]): MaybePromise<void>;\n}\n\nexport interface CacheOptions {\n readonly store: CacheStoreMany;\n /**\n * Policy per manifest resource: `name@apiVersion` (built from that version's\n * manifest entry) or, for every version, plain `name`. A resource without\n * one is not cached. The event stream and the freshness gate are per name.\n */\n readonly policies: Readonly<Record<string, CachePolicy>>;\n /** Cache the manifest document per caller scope. Default `true`. */\n readonly cacheManifest?: boolean;\n /** Epoch milliseconds; injectable for tests. */\n readonly now?: () => number;\n}\n\nexport interface Cache {\n /** Put it in the client's middleware chain. */\n readonly middleware: Middleware;\n /** Record whether the SSE stream of `resource` is connected (gates fresh hits). */\n setEventsActive(resource: string, active: boolean): void;\n eventsActive(resource: string): boolean;\n /** Clear what an SSE event makes stale, in every API version. */\n invalidateEvent(\n resource: string,\n action: string,\n recordId: number | undefined,\n ): Promise<void>;\n /** Clear everything cached for `resource` except `filters` (after a reconnect). */\n clearResource(resource: string): Promise<void>;\n /** Clear keys under `prefix` (everything the store owns when omitted). */\n clear(prefix?: string): Promise<void>;\n /**\n * Adds `If-Match` from the cached record ETag to `PATCH`/`DELETE ?id=` that\n * have none. Put it innermost, next to `middleware`, so it sees the same\n * Authorization (and so scope) the request is sent with.\n */\n readonly autoIfMatch: Middleware;\n /** The stored ETag of a record of one API version, for `auto_if_match`. */\n cachedEtag(\n resource: string,\n recordId: number,\n scope: string,\n apiVersion: string | null,\n ): Promise<string | undefined>;\n /** Abort background revalidations and wait for them. */\n close(): Promise<void>;\n}\n\ntype Kind = CacheKind | \"manifest\";\ntype Decision = \"hit\" | \"stale\" | \"revalidate\" | \"miss\";\ntype StoreOp =\n | { readonly type: \"clear\"; readonly prefixes: readonly string[] }\n | {\n readonly type: \"set\";\n readonly key: string;\n readonly entry: CacheEntry;\n readonly ttlMs: number;\n }\n | { readonly type: \"delete\"; readonly key: string };\n\n/** What `begin` learned about one request. */\ninterface State {\n readonly ctx: RequestContext;\n readonly policy: CachePolicy;\n /** The cache kind of a read; `undefined` for a write. */\n readonly kind: Kind | undefined;\n readonly key: string | undefined;\n /** The resource's invalidation count when the request was made. */\n readonly generation: number;\n /** From the Authorization header of the request as the cache sees it. */\n readonly scope: string;\n readonly forceRevalidate: boolean;\n entry?: CacheEntry | undefined;\n /** Whether we put `If-None-Match` on the request. */\n validated?: boolean;\n}\n\nconst MIN_RETENTION_MS = 3_600_000;\nconst MANIFEST_POLICY: CachePolicy = cachePolicyFromManifest({});\nconst WRITE_METHODS: ReadonlySet<string> = new Set([\n \"POST\",\n \"PATCH\",\n \"PUT\",\n \"DELETE\",\n]);\nconst BULK_OPS: ReadonlySet<string> = new Set([\"bulk_update\", \"bulk_delete\"]);\nconst RECORD_WRITES: ReadonlySet<string> = new Set([\n \"delete\",\n \"publish\",\n \"restore\",\n]);\nconst CREATES: ReadonlySet<string> = new Set([\"create\", \"clone\", \"draft\"]);\n\nfunction isStorable(response: Response): boolean {\n return (\n isJson(response) &&\n !cacheControl(response.headers).has(\"no-store\") &&\n varyAllowsCaching(response)\n );\n}\n\nfunction retentionMs(freshMs: number, staleMs: number): number {\n return Math.max(freshMs + staleMs, MIN_RETENTION_MS);\n}\n\n/** The ids of a bulk response (`{matched, ids}`), or `undefined` if unreadable. */\nfunction idsFromBody(body: string): number[] | undefined {\n try {\n const ids = (JSON.parse(body) as { ids?: unknown }).ids;\n return Array.isArray(ids) && ids.every((id) => Number.isInteger(id))\n ? (ids as number[])\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The resource names in a manifest document, or none if unreadable. */\nfunction manifestResources(body: string): string[] {\n try {\n const resources = (JSON.parse(body) as { resources?: unknown }).resources;\n return Array.isArray(resources)\n ? resources\n .map((item: { name?: unknown }) => item.name)\n .filter((name): name is string => typeof name === \"string\")\n : [];\n } catch {\n return [];\n }\n}\n\nasync function safe<T>(call: () => T | Promise<T>): Promise<T | undefined> {\n try {\n return await call();\n } catch {\n return undefined; // a failing store is a miss, never a failed request\n }\n}\n\nexport function createCache(options: CacheOptions): Cache {\n const { store } = options;\n const policies = new Map(Object.entries(options.policies));\n const policyFor = (\n resource: string | undefined,\n apiVersion: string | null,\n ): CachePolicy | undefined =>\n resource === undefined\n ? undefined\n : (policies.get(`${resource}@${apiVersion}`) ?? policies.get(resource));\n const cacheManifest = options.cacheManifest ?? true;\n const now = options.now ?? Date.now;\n const eventsActive = new Set<string>();\n const generations = new Map<string, number>();\n const inflight = new Set<string>();\n const tasks = new Set<Promise<void>>();\n const background = new AbortController();\n\n let globalGeneration = 0; // bumped by `clear`, which may span resources\n const generation = (resource: string | undefined): number =>\n (generations.get(resource ?? \"\") ?? 0) + globalGeneration;\n const bump = (resource: string): void => {\n generations.set(resource, generation(resource) + 1);\n };\n\n // -- freshness ---------------------------------------------------------------\n\n /**\n * Whether an entry of `kind` may be served without the network right now:\n * only while the stream is up, except `stats`/`predict`, which `stats_ttl`\n * bounds on its own. Never `filters` (events never clear them) or the manifest.\n */\n const gateOpen = (\n policy: CachePolicy,\n resource: string | undefined,\n kind: Kind,\n ): boolean =>\n !policy.revalidateOnly &&\n kind !== \"manifest\" &&\n kind !== \"filters\" &&\n (isStatsKind(kind) || eventsActive.has(resource as string));\n\n /** Stale-while-revalidate needs the stream for every kind, stats and predict included. */\n const staleOpen = (\n policy: CachePolicy,\n resource: string | undefined,\n kind: Kind,\n ): boolean =>\n gateOpen(policy, resource, kind) && eventsActive.has(resource as string);\n\n /** Milliseconds fresh and of stale-while-revalidate for a new entry; none if the response may predate an invalidation. */\n const entryTimes = (\n state: State,\n kind: Kind,\n ): { fresh: number; stale: number } => {\n const resource = state.ctx.resource;\n if (\n generation(resource) !== state.generation ||\n !gateOpen(state.policy, resource, kind)\n ) {\n return { fresh: 0, stale: 0 };\n }\n const fresh = isStatsKind(kind)\n ? state.policy.statsTtl\n : state.policy.maxAge;\n return {\n fresh: fresh * 1000,\n stale: staleOpen(state.policy, resource, kind)\n ? state.policy.staleWhileRevalidate * 1000\n : 0,\n };\n };\n\n const decide = (state: State, entry: CacheEntry | undefined): Decision => {\n if (entry === undefined) {\n return \"miss\";\n }\n if (\n !state.forceRevalidate &&\n gateOpen(state.policy, state.ctx.resource, state.kind as Kind)\n ) {\n const at = now();\n if (at < entry.freshUntil) {\n return \"hit\";\n }\n if (\n at < entry.staleUntil &&\n staleOpen(state.policy, state.ctx.resource, state.kind as Kind)\n ) {\n return \"stale\";\n }\n }\n return entry.etag !== undefined && state.policy.etag\n ? \"revalidate\"\n : \"miss\";\n };\n\n // -- request side ------------------------------------------------------------\n\n const begin = async (ctx: RequestContext): Promise<State | undefined> => {\n const { request, resource } = ctx;\n const scope = await credentialScope(request.headers);\n const generationNow = generation(resource);\n if (request.method !== \"GET\") {\n if (!WRITE_METHODS.has(request.method)) {\n return undefined; // HEAD, OPTIONS and the like change nothing\n }\n const policy = policyFor(resource, ctx.apiVersion);\n return policy?.enabled === true\n ? {\n ctx,\n policy,\n kind: undefined,\n key: undefined,\n generation: generationNow,\n scope,\n forceRevalidate: false,\n }\n : undefined;\n }\n let policy: CachePolicy | undefined;\n let kind: Kind;\n let key: string;\n if (ctx.op === \"manifest\") {\n if (!cacheManifest) {\n return undefined;\n }\n policy = MANIFEST_POLICY;\n kind = \"manifest\";\n key = manifestKey(scope);\n } else {\n policy = policyFor(resource, ctx.apiVersion);\n if (\n resource === undefined ||\n policy?.enabled !== true ||\n !isCacheKind(ctx.op)\n ) {\n return undefined;\n }\n kind = ctx.op;\n key = buildKey({\n resource,\n kind,\n recordId: ctx.recordId,\n scope,\n query: new URL(request.url).search,\n apiVersion: ctx.apiVersion,\n });\n }\n const control = cacheControl(request.headers);\n if (control.has(\"no-store\") || request.headers.has(\"if-none-match\")) {\n return undefined; // the caller forbids storing or manages validators itself\n }\n return {\n ctx,\n policy,\n kind,\n key,\n generation: generationNow,\n scope,\n forceRevalidate: control.has(\"no-cache\"),\n };\n };\n\n /** A copy of `ctx` whose request carries our validator (a `GET` has no body to lose). */\n const withValidator = (ctx: RequestContext, etag: string): RequestContext => {\n const headers = new Headers(ctx.request.headers);\n headers.set(\"if-none-match\", etag);\n return { ...ctx, request: new Request(ctx.request, { headers }) };\n };\n\n // -- response side -----------------------------------------------------------\n\n const readBody = async (\n state: State,\n response: Response,\n ): Promise<string | undefined> => {\n const { status } = response;\n const { op, recordId } = state.ctx;\n let wanted: boolean;\n if (state.kind !== undefined) {\n wanted = status === 200 && isStorable(response);\n } else if (op === \"update\") {\n wanted = status === 200 && recordId !== undefined && isStorable(response);\n } else {\n wanted =\n status >= 200 &&\n status < 300 &&\n (BULK_OPS.has(op) || (op === \"restore\" && recordId === undefined));\n }\n return wanted ? response.clone().text() : undefined;\n };\n\n /** One clear op for all `prefixes`: the store clears them in a single pass. */\n const clears = (prefixes: readonly string[]): StoreOp[] => [\n { type: \"clear\", prefixes },\n ];\n\n const manifestOps = (\n old: CacheEntry | undefined,\n entry: CacheEntry,\n ): StoreOp[] => {\n if (\n old === undefined ||\n (old.etag !== undefined && old.etag === entry.etag)\n ) {\n return [];\n }\n const names = new Set([\n ...[...policies.keys()].map((key) => key.replace(/@[^@]*$/, \"\")),\n ...manifestResources(old.body),\n ...manifestResources(entry.body),\n ]);\n return clears([...names].sort().map((name) => kindPrefix(name, \"filters\")));\n };\n\n const readPlan = (\n state: State,\n response: Response,\n body: string | undefined,\n ): { result: Response; ops: StoreOp[] } => {\n const key = state.key as string;\n const kind = state.kind as Kind;\n const { status } = response;\n const at = now();\n const { fresh, stale } = entryTimes(state, kind);\n const old = state.entry;\n if (status === 304 && state.validated === true && old !== undefined) {\n // `validated` means the request carried `old.etag`.\n const updated: CacheEntry = {\n ...old,\n headers: mergeHeaders(old.headers, response.headers),\n storedAt: at,\n freshUntil: at + fresh,\n staleUntil: at + fresh + stale,\n etag: response.headers.get(\"etag\") ?? (old.etag as string),\n };\n return {\n result: toResponse(updated, \"revalidated\"),\n ops: [\n {\n type: \"set\",\n key,\n entry: updated,\n ttlMs: retentionMs(fresh, stale),\n },\n ],\n };\n }\n if (status === 200 && body !== undefined) {\n tagStatus(response, \"miss\");\n const entry = buildEntry(\n response,\n body,\n { now: at, fresh, stale },\n state.policy.etag,\n );\n if (entry.etag === undefined && fresh <= 0) {\n // No validator and never fresh: drop the old entry.\n return { result: response, ops: [{ type: \"delete\", key }] };\n }\n const ops: StoreOp[] = [\n { type: \"set\", key, entry, ttlMs: retentionMs(fresh, stale) },\n ];\n if (kind === \"manifest\") {\n ops.push(...manifestOps(old, entry));\n }\n return { result: response, ops };\n }\n if (status === 200 || status === 404 || status === 410) {\n return { result: response, ops: [{ type: \"delete\", key }] };\n }\n return { result: response, ops: [] };\n };\n\n /** Store the PATCH response as the record's entry (it is the read view plus ETag). */\n const writeThrough = (\n state: State,\n response: Response,\n body: string | undefined,\n resource: string,\n recordId: number,\n ): StoreOp[] => {\n if (body === undefined) {\n return [];\n }\n const { fresh, stale } = entryTimes(state, \"record\");\n const entry = buildEntry(\n response,\n body,\n { now: now(), fresh, stale },\n state.policy.etag,\n );\n if (entry.etag === undefined && fresh <= 0) {\n return [];\n }\n const key = buildKey({\n resource,\n kind: \"record\",\n recordId,\n scope: state.scope,\n apiVersion: state.ctx.apiVersion,\n });\n return [{ type: \"set\", key, entry, ttlMs: retentionMs(fresh, stale) }];\n };\n\n const writeOps = (\n state: State,\n response: Response,\n body: string | undefined,\n ): StoreOp[] => {\n const { op, recordId } = state.ctx;\n const resource = state.ctx.resource as string;\n const { status } = response;\n if (status === 412) {\n return recordId === undefined\n ? []\n : clears([recordPrefix(resource, recordId)]);\n }\n if (status < 200 || status >= 300) {\n return [];\n }\n const collections = collectionPrefixes(resource);\n if (CREATES.has(op)) {\n return clears(collections);\n }\n if (recordId !== undefined && (RECORD_WRITES.has(op) || op === \"update\")) {\n return [\n ...clears([\n ...collections,\n revisionsPrefix(resource, recordId),\n recordPrefix(resource, recordId),\n ]),\n ...(op === \"update\"\n ? writeThrough(state, response, body, resource, recordId)\n : []),\n ];\n }\n if (BULK_OPS.has(op) || op === \"restore\") {\n // Bulk ops and a bulk restore always have their body read (see `readBody`).\n const ids = idsFromBody(body as string);\n if (ids !== undefined) {\n return clears([\n ...collections,\n ...ids.flatMap((id) => [\n recordPrefix(resource, id),\n revisionsPrefix(resource, id),\n ]),\n ]);\n }\n }\n return clears(resourcePrefixes(resource));\n };\n\n /** One pass when the store can, else one `clear` per prefix; a failure is a miss. */\n const clearPrefixes = async (prefixes: readonly string[]): Promise<void> => {\n if (store.clearMany !== undefined) {\n await safe(() => store.clearMany?.(prefixes));\n return;\n }\n for (const prefix of prefixes) {\n await safe(() => store.clear(prefix));\n }\n };\n\n const apply = async (op: StoreOp): Promise<void> => {\n await safe(() =>\n op.type === \"clear\"\n ? clearPrefixes(op.prefixes)\n : op.type === \"set\"\n ? store.set(op.key, op.entry, op.ttlMs)\n : store.delete(op.key),\n );\n };\n\n /** Plan, then apply, the store changes a response calls for. */\n const finish = async (\n state: State,\n response: Response,\n ): Promise<Response> => {\n const body = await readBody(state, response);\n const { result, ops } =\n state.kind === undefined\n ? { result: response, ops: writeOps(state, response, body) }\n : readPlan(state, response, body);\n if (state.kind === undefined && ops.some((op) => op.type === \"clear\")) {\n bump(state.ctx.resource as string); // before applying: reads now in flight must not store fresh\n }\n const expected = generation(state.ctx.resource);\n for (const op of ops) {\n await apply(op);\n }\n if (generation(state.ctx.resource) !== expected) {\n // An invalidation landed while storing: drop what was just stored.\n for (const op of ops.filter((candidate) => candidate.type === \"set\")) {\n await apply({ type: \"delete\", key: op.key });\n }\n }\n return result;\n };\n\n // -- stale-while-revalidate --------------------------------------------------\n\n const schedule = (state: State, next: Next): void => {\n const key = state.key as string;\n if (background.signal.aborted || inflight.has(key)) {\n return;\n }\n inflight.add(key);\n const entry = state.entry as CacheEntry;\n const task = (async (): Promise<void> => {\n try {\n const signal = background.signal;\n const headers = new Headers(state.ctx.request.headers);\n if (entry.etag !== undefined) {\n headers.set(\"if-none-match\", entry.etag);\n }\n // Detached from the caller's signal: this outlives their request.\n const request = new Request(state.ctx.request.url, {\n method: \"GET\",\n headers,\n signal,\n });\n const fresh: State = {\n ...state,\n validated: entry.etag !== undefined,\n };\n const response = await next({ ...state.ctx, request, signal });\n const result = await finish(fresh, response);\n await result.body?.cancel();\n } catch {\n // Nothing to report to: the caller already has the stale answer.\n } finally {\n inflight.delete(key);\n }\n })();\n tasks.add(task);\n void task.then(() => tasks.delete(task));\n };\n\n // -- the middleware ----------------------------------------------------------\n\n const middleware: Middleware = async (ctx, next) => {\n const state = await begin(ctx);\n if (state === undefined) {\n return next(ctx);\n }\n if (state.kind === undefined) {\n return finish(state, await next(ctx));\n }\n state.entry = await safe(() => store.get(state.key as string));\n const decision = decide(state, state.entry);\n const entry = state.entry as CacheEntry;\n if (decision === \"hit\") {\n return toResponse(entry, \"hit\");\n }\n if (decision === \"stale\") {\n schedule(state, next);\n return toResponse(entry, \"stale\");\n }\n let sent = ctx;\n if (decision === \"revalidate\") {\n sent = withValidator(ctx, entry.etag as string);\n state.validated = true;\n }\n return finish(state, await next(sent));\n };\n\n // -- control surface ---------------------------------------------------------\n\n const autoIfMatch: Middleware = async (ctx, next) => {\n const { request, resource, recordId } = ctx;\n if (\n (ctx.op === \"update\" || ctx.op === \"delete\") &&\n recordId !== undefined &&\n resource !== undefined &&\n policyFor(resource, ctx.apiVersion)?.enabled === true &&\n !request.headers.has(\"if-match\")\n ) {\n const etag = await lookupEtag(\n resource,\n recordId,\n await credentialScope(request.headers),\n ctx.apiVersion,\n );\n if (etag !== undefined) {\n const headers = new Headers(request.headers);\n headers.set(\"if-match\", etag);\n return next({ ...ctx, request: new Request(request, { headers }) });\n }\n }\n return next(ctx);\n };\n\n const lookupEtag = async (\n resource: string,\n recordId: number,\n scope: string,\n apiVersion: string | null,\n ): Promise<string | undefined> => {\n const entry = await safe(() =>\n store.get(\n buildKey({ resource, kind: \"record\", recordId, scope, apiVersion }),\n ),\n );\n return entry?.etag;\n };\n\n return {\n middleware,\n autoIfMatch,\n setEventsActive(resource, active) {\n if (active) {\n eventsActive.add(resource);\n } else {\n eventsActive.delete(resource);\n }\n },\n eventsActive: (resource) => eventsActive.has(resource),\n async invalidateEvent(resource, action, recordId) {\n bump(resource);\n await clearPrefixes(eventPrefixes(resource, action, recordId));\n },\n async clearResource(resource) {\n bump(resource);\n await clearPrefixes(resourcePrefixes(resource));\n },\n async clear(prefix) {\n globalGeneration += 1; // reads in flight must not store fresh over the clear\n await safe(() => store.clear(prefix));\n },\n cachedEtag: lookupEtag,\n async close() {\n background.abort();\n await Promise.allSettled(tasks);\n },\n };\n}\n","/** In-memory cache store: LRU with a per-entry TTL. */\nimport type { CacheEntry, CacheStore } from \"../interfaces.ts\";\n\n/** How long a store keeps an entry when the caller gives no ttl (the spec's retention floor). */\nexport const DEFAULT_TTL_MS = 3_600_000;\n\nexport interface MemoryStoreOptions {\n /** Default 1024. */\n readonly maxEntries?: number;\n readonly defaultTtlMs?: number;\n /** Epoch milliseconds; injectable for tests. */\n readonly now?: () => number;\n}\n\n/** LRU store (default 1024 entries) that also honours each entry's ttl. */\nexport class MemoryStore implements CacheStore {\n private readonly data = new Map<\n string,\n { readonly expiresAt: number; readonly entry: CacheEntry }\n >();\n private readonly maxEntries: number;\n private readonly defaultTtlMs: number;\n private readonly now: () => number;\n\n constructor(options: MemoryStoreOptions = {}) {\n const maxEntries = options.maxEntries ?? 1024;\n if (!Number.isInteger(maxEntries) || maxEntries < 1) {\n throw new RangeError(\"maxEntries must be an integer of at least 1\");\n }\n this.maxEntries = maxEntries;\n this.defaultTtlMs = options.defaultTtlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? Date.now;\n }\n\n /** Number of stored entries (expired ones included until touched). */\n get size(): number {\n return this.data.size;\n }\n\n get(key: string): CacheEntry | undefined {\n const item = this.data.get(key);\n if (item === undefined) {\n return undefined;\n }\n if (item.expiresAt <= this.now()) {\n this.data.delete(key);\n return undefined;\n }\n this.data.delete(key); // re-insert: Map order is the recency order\n this.data.set(key, item);\n return item.entry;\n }\n\n set(key: string, entry: CacheEntry, ttlMs?: number): void {\n this.data.delete(key);\n this.data.set(key, {\n expiresAt: this.now() + (ttlMs ?? this.defaultTtlMs),\n entry,\n });\n while (this.data.size > this.maxEntries) {\n // The first key is the least recently used.\n this.data.delete(this.data.keys().next().value as string);\n }\n }\n\n delete(key: string): void {\n this.data.delete(key);\n }\n\n /** Remove every key under any of `prefixes` in one walk. */\n clearMany(prefixes: readonly string[]): void {\n for (const key of this.data.keys()) {\n if (prefixes.some((prefix) => key.startsWith(prefix))) {\n this.data.delete(key);\n }\n }\n }\n\n clear(prefix?: string): void {\n for (const key of this.data.keys()) {\n if (prefix === undefined || key.startsWith(prefix)) {\n this.data.delete(key);\n }\n }\n }\n}\n","const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBIndex,\n IDBObjectStore,\n IDBCursor,\n IDBDatabase,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = ['advance', 'continue', 'continuePrimaryKey'].map((method) => IDBCursor.prototype[method])));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (!Object.is(newValue, value)) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event.newVersion, event));\n }\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking) {\n db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event));\n }\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = {};\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods[prop])\n return cachedMethods[prop];\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n return (cachedMethods[prop] = method);\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['advance', 'continue', 'continuePrimaryKey'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function (...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n },\n};\nasync function* iterate(...args) {\n // tslint:disable-next-line:no-this-assignment\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n // Map this double-proxy back to the original, so other cursor methods work.\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n // If one of the advancing methods was not called, call continue().\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return ((prop === Symbol.asyncIterator &&\n instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","/**\n * IndexedDB cache store (one object store, out-of-line string keys).\n *\n * Every call is wrapped: a blocked database, private mode or a missing\n * `indexedDB` is a miss (or a no-op), never a failed request. `clear(prefix)`\n * is one `IDBKeyRange.bound(prefix, prefix + \"\\uffff\")` delete.\n */\nimport { openDB } from \"idb\";\nimport type { IDBPDatabase } from \"idb\";\nimport type { CacheEntry, CacheStore } from \"../interfaces.ts\";\nimport { DEFAULT_TTL_MS } from \"./memory.ts\";\n\n// The package compiles without the DOM lib; this is the one global it needs.\ndeclare const IDBKeyRange: {\n bound(lower: string, upper: string): unknown;\n};\n\nconst STORE = \"entries\";\n\ninterface Stored {\n readonly expiresAt: number;\n readonly entry: CacheEntry;\n}\n\nexport interface IndexedDbStoreOptions {\n /** Database name; default `craftainer-crud-cache`. */\n readonly name?: string;\n readonly defaultTtlMs?: number;\n /** Epoch milliseconds; injectable for tests. */\n readonly now?: () => number;\n}\n\nexport class IndexedDbStore implements CacheStore {\n private readonly name: string;\n private readonly defaultTtlMs: number;\n private readonly now: () => number;\n private opening: Promise<IDBPDatabase> | undefined;\n\n constructor(options: IndexedDbStoreOptions = {}) {\n this.name = options.name ?? \"craftainer-crud-cache\";\n if (this.name === \"\") {\n // The name is the per-origin namespace of the store.\n throw new RangeError(\"IndexedDbStore: name must not be empty\");\n }\n this.defaultTtlMs = options.defaultTtlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? Date.now;\n }\n\n private open(): Promise<IDBPDatabase> {\n this.opening ??= openDB(this.name, 1, {\n upgrade(db) {\n db.createObjectStore(STORE);\n },\n });\n return this.opening;\n }\n\n /** Run `work` on the database; a failure drops the handle (so a later call retries) and yields `fallback`. */\n private async run<T>(\n fallback: T,\n work: (db: IDBPDatabase) => Promise<T>,\n ): Promise<T> {\n // The handle this call runs on: a concurrent call may already have replaced it.\n let used: Promise<IDBPDatabase> | undefined;\n try {\n used = this.open(); // may throw at once when indexedDB is unusable\n return await work(await used);\n } catch {\n // Drop only our own handle, and close it: an orphaned connection can\n // block an upgrade, while a newer handle belongs to other calls.\n if (this.opening === used) {\n this.opening = undefined;\n }\n try {\n (await used)?.close();\n } catch {\n // It never opened.\n }\n return fallback;\n }\n }\n\n get(key: string): Promise<CacheEntry | undefined> {\n return this.run<CacheEntry | undefined>(undefined, async (db) => {\n const stored = (await db.get(STORE, key)) as Stored | undefined;\n if (stored === undefined) {\n return undefined;\n }\n if (stored.expiresAt <= this.now()) {\n await db.delete(STORE, key);\n return undefined;\n }\n return stored.entry;\n });\n }\n\n set(key: string, entry: CacheEntry, ttlMs?: number): Promise<void> {\n return this.run(undefined, async (db) => {\n const stored: Stored = {\n expiresAt: this.now() + (ttlMs ?? this.defaultTtlMs),\n entry,\n };\n await db.put(STORE, stored, key);\n });\n }\n\n delete(key: string): Promise<void> {\n return this.run(undefined, (db) => db.delete(STORE, key));\n }\n\n clear(prefix?: string): Promise<void> {\n return this.run(undefined, (db) =>\n prefix === undefined\n ? db.clear(STORE)\n : db.delete(STORE, IDBKeyRange.bound(prefix, `${prefix}\\uffff`)),\n );\n }\n\n /** Clear several prefixes in one transaction (one bound range each). */\n clearMany(prefixes: readonly string[]): Promise<void> {\n return this.run(undefined, async (db) => {\n const tx = db.transaction(STORE, \"readwrite\");\n await Promise.all([\n ...prefixes.map((prefix) =>\n tx.store.delete(IDBKeyRange.bound(prefix, `${prefix}\\uffff`)),\n ),\n tx.done,\n ]);\n });\n }\n\n /** Close the database handle; a later call reopens it. */\n async close(): Promise<void> {\n const opening = this.opening;\n this.opening = undefined;\n try {\n (await opening)?.close();\n } catch {\n // Never opened.\n }\n }\n}\n","/** Wiring an event hub to a cache. */\nimport type { EventHub } from \"../events.ts\";\nimport type { Cache } from \"./middleware.ts\";\n\n/** The subscriptions that currently see a connected stream, per cache and resource. */\nconst connected = new WeakMap<Cache, Map<string, Set<object>>>();\n\n/**\n * Subscribe `cache` to `hub` for the manifest resource `resource`. Events\n * clear the spec's prefixes, a reconnect clears the resource, and fresh hits\n * are allowed only while the stream is connected. Returns the unsubscribe\n * (it also closes the freshness gate).\n */\nexport function invalidateOnEvents(\n cache: Cache,\n hub: EventHub,\n resource: string,\n): () => void {\n const byResource = connected.get(cache) ?? new Map<string, Set<object>>();\n connected.set(cache, byResource);\n const live = byResource.get(resource) ?? new Set<object>();\n byResource.set(resource, live);\n const self = {}; // this subscription's identity\n // The gate is open while any subscription sees a connected stream.\n const mark = (up: boolean): void => {\n if (up) {\n live.add(self);\n } else {\n live.delete(self);\n }\n cache.setEventsActive(resource, live.size > 0);\n };\n const unsubscribe = hub.subscribe({\n onEvent: (event) =>\n cache.invalidateEvent(resource, event.action, event.recordId),\n onReset: () => cache.clearResource(resource),\n onStatus: mark,\n });\n return () => {\n try {\n unsubscribe();\n } finally {\n mark(false); // idempotent; the gate stays open while another subscription is connected\n }\n };\n}\n"],"ignoreList":[5],"mappings":"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"}
@@ -142,6 +142,12 @@ interface QueryParams {
142
142
  readonly limitParam?: string | undefined;
143
143
  readonly sortParam?: string | undefined;
144
144
  readonly includeArchived?: boolean | undefined;
145
+ /**
146
+ * Only rows with `archived_at` set (list only; implies `include_archived`).
147
+ * Emitted only when `true`; combining `true` with `includeArchived: false`
148
+ * throws `InvalidQueryError`, as the server answers 422.
149
+ */
150
+ readonly onlyArchived?: boolean | undefined;
145
151
  readonly includeUnpublished?: boolean | undefined;
146
152
  }
147
153
  /** Percent-encodes everything but the RFC 3986 unreserved characters `A-Za-z0-9-._~`. */
@@ -157,10 +163,11 @@ declare function formatScalar(field: QueryField, value: unknown): string;
157
163
  /**
158
164
  * The query string (no leading `?`) for a list, get or bulk call. Order of
159
165
  * parameters: `id`, filters sorted by (field, operator), sort, skip, limit,
160
- * `include_archived`, `include_unpublished`. The sort/skip/limit names are
166
+ * `include_archived`, `only_archived`, `include_unpublished`. The sort/skip/limit names are
161
167
  * `sortParam`/`skipParam`/`limitParam` (the manifest's `pagination`); the
162
168
  * `id` parameter is always `id`. Flags are emitted whenever they are not
163
- * `undefined`.
169
+ * `undefined`, except `only_archived`, which is emitted only when `true`
170
+ * (absent means false; it is a reserved key, not a filter).
164
171
  */
165
172
  declare function buildQuery(fields: readonly QueryField[], params?: QueryParams): string;
166
173
  //#endregion
@@ -169,20 +176,26 @@ declare function buildQuery(fields: readonly QueryField[], params?: QueryParams)
169
176
  interface RequestOptions {
170
177
  readonly signal?: AbortSignal | undefined;
171
178
  }
172
- /** Options of `list` and `iterAll`. */
179
+ /**
180
+ * Options of `list` and `iterAll`. `onlyArchived: true` returns only archived
181
+ * rows (it implies `includeArchived`; with `includeArchived: false` the call
182
+ * throws `InvalidQueryError` before any request). Non-archivable resources
183
+ * ignore it.
184
+ */
173
185
  interface ListOptions extends RequestOptions {
174
186
  readonly filters?: Filters | undefined;
175
187
  readonly sort?: Sort | undefined;
176
188
  readonly skip?: number | undefined;
177
189
  readonly limit?: number | undefined;
178
190
  readonly includeArchived?: boolean | undefined;
191
+ readonly onlyArchived?: boolean | undefined;
179
192
  readonly includeUnpublished?: boolean | undefined;
180
193
  }
181
194
  /** Options of `update` and `delete`: `ifMatch` is an ETag (`412` when stale). */
182
195
  interface WriteOptions extends RequestOptions {
183
196
  readonly ifMatch?: string | undefined;
184
197
  }
185
- /** Options of `stats`. */
198
+ /** Options of `stats`. There is no `onlyArchived` (the server rejects it on `/stats`). */
186
199
  interface StatsOptions extends RequestOptions {
187
200
  readonly bucket?: string | undefined;
188
201
  readonly includeArchived?: boolean | undefined;
@@ -313,4 +326,4 @@ declare class CrudClient {
313
326
  declare function createClient(options: ClientOptions): CrudClient;
314
327
  //#endregion
315
328
  export { Pagination as A, Capabilities as C, JsonObject as D, GetJson as E, manifestUrlFromCatalog as F, parseManifest as I, Schemas as M, findResource as N, Manifest as O, loadManifest as P, CacheHints as S, FieldSpec as T, encodeParams as _, PredictOptions as a, AuthSpec as b, RestoreOptions as c, createClient as d, Filters as f, buildQuery as g, Sort as h, ListOptions as i, Resource as j, PROFILE as k, StatsOptions as l, QueryParams as m, ClientOptions as n, RequestOptions as o, QueryField as p, CrudClient as r, ResourceClient as s, BulkResult as t, WriteOptions as u, formatScalar as v, EventsSpec as w, CATALOG_PATH as x, quote as y };
316
- //# sourceMappingURL=client-B8fSsx4L.d.mts.map
329
+ //# sourceMappingURL=client-BU9rPr8h.d.mts.map
@@ -423,9 +423,20 @@ const MAX_REGEX_LENGTH = 200;
423
423
  function quote(text) {
424
424
  return encodeURIComponent(text).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
425
425
  }
426
+ /**
427
+ * {@link quote} for caller input: a lone surrogate (an emoji cut in half)
428
+ * cannot be UTF-8 encoded, which is an invalid argument, not a `URIError`.
429
+ */
430
+ function encode(text) {
431
+ try {
432
+ return quote(text);
433
+ } catch (error) {
434
+ throw new InvalidQueryError("a query value is not well-formed Unicode (lone surrogate)", { cause: error });
435
+ }
436
+ }
426
437
  /** Joins already-stringified pairs, encoding keys and values. */
427
438
  function encodeParams(pairs) {
428
- return pairs.map(([k, v]) => `${quote(k)}=${quote(v)}`).join("&");
439
+ return pairs.map(([k, v]) => `${encode(k)}=${encode(v)}`).join("&");
429
440
  }
430
441
  function formatDatetime(value) {
431
442
  if (Number.isNaN(value.getTime())) return;
@@ -466,11 +477,11 @@ function filterPair(field, op, value) {
466
477
  if (!Array.isArray(value) || value.length === 0) throw new InvalidQueryError(`"${key}" takes a non-empty array`);
467
478
  const parts = value.map((item) => formatScalar(field, item));
468
479
  if (parts.some((part) => part.includes(","))) throw new InvalidQueryError(`"${key}": a value contains a comma, which separates the list`);
469
- return [key, parts.map(quote).join(",")];
480
+ return [key, parts.map((part) => encode(part)).join(",")];
470
481
  }
471
482
  const text = formatScalar(field, value);
472
483
  if (op === "regex" && [...text].length > MAX_REGEX_LENGTH) throw new InvalidQueryError(`"${key}": a regex is limited to ${MAX_REGEX_LENGTH} characters`);
473
- return [key, quote(text)];
484
+ return [key, encode(text)];
474
485
  }
475
486
  const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
476
487
  function filterPairs(fields, filters) {
@@ -498,7 +509,7 @@ function sortValue(fields, sort) {
498
509
  const name = part.startsWith("-") ? part.slice(1) : part;
499
510
  const field = fields.get(name);
500
511
  if (field === void 0 || !field.sortable) throw new InvalidQueryError(`cannot sort by "${name}"`);
501
- return quote(part);
512
+ return encode(part);
502
513
  });
503
514
  if (out.length === 0) throw new InvalidQueryError("sort is empty");
504
515
  return out.join(",");
@@ -510,24 +521,27 @@ function intArg(name, value, minimum) {
510
521
  /**
511
522
  * The query string (no leading `?`) for a list, get or bulk call. Order of
512
523
  * parameters: `id`, filters sorted by (field, operator), sort, skip, limit,
513
- * `include_archived`, `include_unpublished`. The sort/skip/limit names are
524
+ * `include_archived`, `only_archived`, `include_unpublished`. The sort/skip/limit names are
514
525
  * `sortParam`/`skipParam`/`limitParam` (the manifest's `pagination`); the
515
526
  * `id` parameter is always `id`. Flags are emitted whenever they are not
516
- * `undefined`.
527
+ * `undefined`, except `only_archived`, which is emitted only when `true`
528
+ * (absent means false; it is a reserved key, not a filter).
517
529
  */
518
530
  function buildQuery(fields, params = {}) {
531
+ if (params.onlyArchived === true && params.includeArchived === false) throw new InvalidQueryError("onlyArchived cannot be combined with includeArchived: false");
519
532
  const byName = new Map(fields.map((f) => [f.name, f]));
520
533
  const parts = [];
521
534
  if (params.recordId !== void 0) parts.push(`id=${intArg("recordId", params.recordId, 0)}`);
522
- for (const [key, value] of filterPairs(byName, params.filters ?? {})) parts.push(`${quote(key)}=${value}`);
523
- if (params.sort !== void 0) parts.push(`${quote(params.sortParam ?? "sort")}=${sortValue(byName, params.sort)}`);
524
- if (params.skip !== void 0) parts.push(`${quote(params.skipParam ?? "skip")}=${intArg("skip", params.skip, 0)}`);
535
+ for (const [key, value] of filterPairs(byName, params.filters ?? {})) parts.push(`${encode(key)}=${value}`);
536
+ if (params.sort !== void 0) parts.push(`${encode(params.sortParam ?? "sort")}=${sortValue(byName, params.sort)}`);
537
+ if (params.skip !== void 0) parts.push(`${encode(params.skipParam ?? "skip")}=${intArg("skip", params.skip, 0)}`);
525
538
  if (params.limit !== void 0) {
526
539
  const text = intArg("limit", params.limit, 1);
527
540
  if (params.maxLimit !== void 0 && params.limit > params.maxLimit) throw new InvalidQueryError(`limit ${params.limit} exceeds the server maximum ${params.maxLimit}`);
528
- parts.push(`${quote(params.limitParam ?? "limit")}=${text}`);
541
+ parts.push(`${encode(params.limitParam ?? "limit")}=${text}`);
529
542
  }
530
543
  if (params.includeArchived !== void 0) parts.push(`include_archived=${params.includeArchived}`);
544
+ if (params.onlyArchived === true) parts.push("only_archived=true");
531
545
  if (params.includeUnpublished !== void 0) parts.push(`include_unpublished=${params.includeUnpublished}`);
532
546
  return parts.join("&");
533
547
  }
@@ -592,6 +606,7 @@ var Plan = class {
592
606
  skip: o.skip,
593
607
  limit: o.limit,
594
608
  includeArchived: o.includeArchived,
609
+ onlyArchived: o.onlyArchived,
595
610
  includeUnpublished: o.includeUnpublished
596
611
  });
597
612
  return this.#call("GET", "list", this.#base, query);
@@ -920,4 +935,4 @@ function createClient(options) {
920
935
  //#endregion
921
936
  export { UnknownResourceError as A, NotFound as C, ResponseError as D, RateLimited as E, problemFromResponse as M, composeMiddleware as N, ServerError as O, ManifestError as S, ProblemError as T, ConnectionFailed as _, encodeParams as a, InvalidQueryError as b, CATALOG_PATH as c, loadManifest as d, manifestUrlFromCatalog as f, ClientError as g, CapabilityError as h, buildQuery as i, ValidationFailed as j, Unauthorized as k, PROFILE as l, BadRequest as m, ResourceClient as n, formatScalar as o, parseManifest as p, createClient as r, quote as s, CrudClient as t, findResource as u, CrudError as v, PreconditionFailed as w, Locked as x, Forbidden as y };
922
937
 
923
- //# sourceMappingURL=client-Bv0yCuwC.mjs.map
938
+ //# sourceMappingURL=client-DJkbw9_q.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-DJkbw9_q.mjs","names":["isObject"],"sources":["../src/interfaces.ts","../src/errors.ts","../src/manifest.ts","../src/query.ts","../src/client.ts"],"sourcesContent":["/**\n * Contracts shared by the client core (TS1) and the cache layer (TS2).\n * Fixed in TS0 (plan interface I3): change them only through the plan.\n */\n\n/** A value or a promise of it. */\nexport type MaybePromise<T> = T | Promise<T>;\n\n/** What a request does, as classified by the client. */\nexport type Op =\n | \"manifest\"\n | \"list\"\n | \"record\"\n | \"filters\"\n | \"stats\"\n | \"predict\"\n | \"revisions\"\n | \"create\"\n | \"update\"\n | \"delete\"\n | \"bulk_update\"\n | \"bulk_delete\"\n | \"clone\"\n | \"draft\"\n | \"publish\"\n | \"restore\"\n | \"events\";\n\n/**\n * One stored `200` response. Times are epoch milliseconds (`Date.now()`).\n * Structured-clone safe, so IndexedDB can store it as is.\n */\nexport interface CacheEntry {\n readonly status: number;\n readonly headers: ReadonlyArray<readonly [string, string]>;\n /** JSON text; the SDK only caches JSON. */\n readonly body: string;\n readonly storedAt: number;\n /** `<= storedAt` means \"always revalidate\". */\n readonly freshUntil: number;\n /** End of the stale-while-revalidate window (`>= freshUntil`). */\n readonly staleUntil: number;\n readonly etag?: string;\n}\n\n/**\n * Cache backend. Keys are opaque, slash-separated strings built by\n * `./cache`'s `cacheKey`\n * (`v1/{resource}/{kind}/{subject}/{apiVersion}/{scope}/{query}`, with `_`\n * when there is no apiVersion).\n * `ttlMs` is how long the backend may keep the entry (undefined = backend\n * default); freshness lives in `CacheEntry`. `clear(prefix)` removes every\n * key starting with `prefix`; `clear()` removes everything the store owns.\n * Methods may be sync or async. They must not reject for a missing key\n * (`get` resolves `undefined`), and a failing backend must not fail the\n * request: the cache layer swallows store errors and treats them as a miss.\n */\nexport interface CacheStore {\n get(key: string): MaybePromise<CacheEntry | undefined>;\n set(key: string, entry: CacheEntry, ttlMs?: number): MaybePromise<void>;\n delete(key: string): MaybePromise<void>;\n clear(prefix?: string): MaybePromise<void>;\n}\n\n/**\n * What the client knows about a request that a bare `Request` does not. The\n * client builds it for every call; middleware read it, so they never parse\n * URLs or read Authorization.\n */\nexport interface RequestContext {\n /** The request about to be sent; replace it by passing a new context to `next`. */\n readonly request: Request;\n /** Manifest name; `undefined` for the manifest document itself. */\n readonly resource: string | undefined;\n readonly op: Op;\n /** The record the request targets, when it targets one. */\n readonly recordId: number | undefined;\n /**\n * \"anon\", or the first 32 hex characters of the SHA-256 of the\n * Authorization credential actually sent.\n */\n readonly scope: string;\n /**\n * The resource's `api_version` from the manifest, or `null` when it has\n * none. Part of the cache key, so versions never share entries (the cache\n * layer renders `null` as `_`).\n */\n readonly apiVersion: string | null;\n readonly signal: AbortSignal | undefined;\n}\n\n/** Calls the next middleware, or the network when none is left. */\nexport type Next = (ctx: RequestContext) => Promise<Response>;\n\n/**\n * Onion middleware. In `chain = [a, b]`, `a` is outermost: the request runs\n * a -> b -> fetch and the response returns fetch -> b -> a. A middleware may\n * replace `ctx.request` (pass `{ ...ctx, request }` to `next`), return\n * without calling `next` (short-circuit, e.g. a fresh cache hit), or replace\n * the response (e.g. a `304` rebuilt from the cache). It must not consume\n * `response.body` unless it returns a different `Response`; use\n * `response.clone()` to read it.\n */\nexport type Middleware = (ctx: RequestContext, next: Next) => Promise<Response>;\n\n/**\n * Returns the bearer token, or `null`/`undefined` for an anonymous call.\n * `refresh: true` is passed once after a `401`, to force a new token.\n */\nexport type TokenProvider = (opts: {\n readonly refresh: boolean;\n}) => MaybePromise<string | null | undefined>;\n\n/** One record-mutation event from `GET {basePath}/events` (the server's event envelope). */\nexport interface CrudEvent {\n /** The server's event label (e.g. \"hero\"), not the manifest name. */\n readonly resource: string;\n readonly recordId: number;\n readonly action: \"create\" | \"update\" | \"delete\" | \"restore\";\n /** The read view of the record after the change. */\n readonly snapshot: Readonly<Record<string, unknown>>;\n /** ISO 8601, UTC. */\n readonly timestamp: string;\n}\n\n/**\n * Folds `chain` (outermost first) around `terminal`, usually the network\n * `fetch`, into one `Next`. Each middleware's `next` is the rest of the\n * chain; an empty chain is `terminal`. A throwing middleware yields a\n * rejected promise.\n */\nexport function composeMiddleware(\n chain: readonly Middleware[],\n terminal: Next,\n): Next {\n const dispatch = async (\n index: number,\n ctx: RequestContext,\n ): Promise<Response> => {\n const middleware = chain[index];\n if (middleware === undefined) {\n return terminal(ctx);\n }\n return middleware(ctx, (next) => dispatch(index + 1, next));\n };\n return (ctx) => dispatch(0, ctx);\n}\n","/**\n * Error hierarchy: client-side errors and RFC 9457 problem details (ADR-0004).\n * Mirrors the Python SDK class for class.\n */\n\n/** Base class of every error this package throws on purpose. */\nexport class CrudError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\n/** The call was refused before any request was sent. */\nexport class ClientError extends CrudError {}\n\n/** The resource does not support the operation (manifest capability or path missing). */\nexport class CapabilityError extends ClientError {}\n\n/** A filter, sort or paging argument is not valid for the resource. */\nexport class InvalidQueryError extends ClientError {}\n\n/** The discovery document or the manifest is missing, unusable or of an unknown version. */\nexport class ManifestError extends ClientError {}\n\n/** The manifest lists no such resource for this caller. */\nexport class UnknownResourceError extends ClientError {}\n\n/** A successful response whose body is not the JSON the client expects; `cause` holds the parse error. */\nexport class ResponseError extends CrudError {}\n\n/** The request never produced a response; `cause` holds the transport error. */\nexport class ConnectionFailed extends CrudError {}\n\n/** One normalized validation error (`422`). */\nexport interface ProblemDetail {\n readonly loc: readonly (string | number)[];\n readonly msg: string;\n readonly type: string;\n}\n\n/** Members of a {@link ProblemError}. */\nexport interface ProblemInit {\n readonly status: number;\n readonly title: string;\n readonly detail?: string | undefined;\n readonly type?: string | undefined;\n readonly instance?: string | undefined;\n readonly errors?: readonly ProblemDetail[] | undefined;\n readonly headers?: Headers | undefined;\n readonly response?: Response | undefined;\n}\n\nconst NO_TYPE = \"about:blank\";\n\n/** An error response, as RFC 9457 problem details. */\nexport class ProblemError extends CrudError {\n readonly status: number;\n readonly title: string;\n readonly detail: string | undefined;\n readonly type: string;\n readonly instance: string | undefined;\n readonly errors: readonly ProblemDetail[];\n readonly headers: Headers;\n readonly response: Response | undefined;\n\n constructor(init: ProblemInit) {\n const errors = init.errors ?? [];\n let message = `${init.status} ${init.title}`;\n if (init.detail) {\n message += `: ${init.detail}`;\n } else if (errors.length > 0) {\n message += `: ${errors.map((e) => `${e.loc.join(\".\")}: ${e.msg}`).join(\"; \")}`;\n }\n super(message);\n this.status = init.status;\n this.title = init.title;\n this.detail = init.detail;\n this.type = init.type ?? NO_TYPE;\n this.instance = init.instance;\n this.errors = errors;\n this.headers = init.headers ?? new Headers();\n this.response = init.response;\n }\n}\n\n/** 400. */\nexport class BadRequest extends ProblemError {}\n\n/** 401; `wwwAuthenticate` keeps the challenge. */\nexport class Unauthorized extends ProblemError {\n get wwwAuthenticate(): string | undefined {\n return this.headers.get(\"www-authenticate\") ?? undefined;\n }\n}\n\n/** 403. */\nexport class Forbidden extends ProblemError {}\n\n/** 404. */\nexport class NotFound extends ProblemError {}\n\n/** 412: a stale `If-Match`. */\nexport class PreconditionFailed extends ProblemError {}\n\n/** 422; `errors` holds normalized `{loc, msg, type}` entries. */\nexport class ValidationFailed extends ProblemError {}\n\n/** 423. */\nexport class Locked extends ProblemError {}\n\n/** 429; `retryAfter` is the `Retry-After` header in seconds, when it is a number. */\nexport class RateLimited extends ProblemError {\n get retryAfter(): number | undefined {\n const raw = this.headers.get(\"retry-after\");\n if (raw === null || raw.trim() === \"\") {\n return undefined;\n }\n const seconds = Number(raw);\n return Number.isNaN(seconds) ? undefined : seconds;\n }\n}\n\n/** 5xx. */\nexport class ServerError extends ProblemError {}\n\nconst BY_STATUS: ReadonlyMap<number, typeof ProblemError> = new Map([\n [400, BadRequest],\n [401, Unauthorized],\n [403, Forbidden],\n [404, NotFound],\n [412, PreconditionFailed],\n [422, ValidationFailed],\n [423, Locked],\n [429, RateLimited],\n]);\n\n// Python's `http.HTTPStatus` phrases, so both SDKs synthesize the same title.\nconst PHRASES: ReadonlyMap<number, string> = new Map([\n [100, \"Continue\"],\n [101, \"Switching Protocols\"],\n [102, \"Processing\"],\n [103, \"Early Hints\"],\n [200, \"OK\"],\n [201, \"Created\"],\n [202, \"Accepted\"],\n [203, \"Non-Authoritative Information\"],\n [204, \"No Content\"],\n [205, \"Reset Content\"],\n [206, \"Partial Content\"],\n [207, \"Multi-Status\"],\n [208, \"Already Reported\"],\n [226, \"IM Used\"],\n [300, \"Multiple Choices\"],\n [301, \"Moved Permanently\"],\n [302, \"Found\"],\n [303, \"See Other\"],\n [304, \"Not Modified\"],\n [305, \"Use Proxy\"],\n [307, \"Temporary Redirect\"],\n [308, \"Permanent Redirect\"],\n [400, \"Bad Request\"],\n [401, \"Unauthorized\"],\n [402, \"Payment Required\"],\n [403, \"Forbidden\"],\n [404, \"Not Found\"],\n [405, \"Method Not Allowed\"],\n [406, \"Not Acceptable\"],\n [407, \"Proxy Authentication Required\"],\n [408, \"Request Timeout\"],\n [409, \"Conflict\"],\n [410, \"Gone\"],\n [411, \"Length Required\"],\n [412, \"Precondition Failed\"],\n [413, \"Content Too Large\"],\n [414, \"URI Too Long\"],\n [415, \"Unsupported Media Type\"],\n [416, \"Range Not Satisfiable\"],\n [417, \"Expectation Failed\"],\n [418, \"I'm a Teapot\"],\n [421, \"Misdirected Request\"],\n [422, \"Unprocessable Content\"],\n [423, \"Locked\"],\n [424, \"Failed Dependency\"],\n [425, \"Too Early\"],\n [426, \"Upgrade Required\"],\n [428, \"Precondition Required\"],\n [429, \"Too Many Requests\"],\n [431, \"Request Header Fields Too Large\"],\n [451, \"Unavailable For Legal Reasons\"],\n [500, \"Internal Server Error\"],\n [501, \"Not Implemented\"],\n [502, \"Bad Gateway\"],\n [503, \"Service Unavailable\"],\n [504, \"Gateway Timeout\"],\n [505, \"HTTP Version Not Supported\"],\n [506, \"Variant Also Negotiates\"],\n [507, \"Insufficient Storage\"],\n [508, \"Loop Detected\"],\n [510, \"Not Extended\"],\n [511, \"Network Authentication Required\"],\n]);\n\ntype Obj = Record<string, unknown>;\n\nconst isObject = (value: unknown): value is Obj =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction normalizeErrors(items: readonly unknown[]): ProblemDetail[] {\n return items.map((item) => {\n if (isObject(item)) {\n return {\n loc: Array.isArray(item[\"loc\"])\n ? (item[\"loc\"] as (string | number)[])\n : [],\n msg: String(item[\"msg\"] ?? \"\"),\n type: String(item[\"type\"] ?? \"\"),\n };\n }\n return { loc: [], msg: String(item), type: \"\" };\n });\n}\n\n/**\n * Builds the matching `ProblemError` subclass from an error response. A body\n * that is not a JSON object yields a synthesized problem from the status\n * phrase. Reads a clone, so `response.body` stays readable.\n */\nexport async function problemFromResponse(\n response: Response,\n): Promise<ProblemError> {\n const status = response.status;\n const phrase = PHRASES.get(status) ?? \"Error\";\n let parsed: unknown;\n try {\n parsed = JSON.parse(await response.clone().text());\n } catch {\n parsed = undefined;\n }\n const body: Obj = isObject(parsed) ? parsed : {};\n const rawDetail = body[\"detail\"];\n const rawErrors = Array.isArray(rawDetail) ? rawDetail : body[\"errors\"];\n const Cls =\n BY_STATUS.get(status) ?? (status >= 500 ? ServerError : ProblemError);\n const instance = body[\"instance\"];\n return new Cls({\n status,\n title: String(body[\"title\"] || phrase),\n detail: typeof rawDetail === \"string\" ? rawDetail : undefined,\n type: String(body[\"type\"] || NO_TYPE),\n instance: typeof instance === \"string\" ? instance : undefined,\n errors: Array.isArray(rawErrors) ? normalizeErrors(rawErrors) : [],\n headers: response.headers,\n response,\n });\n}\n","/**\n * Typed models of the CRUD manifest (v1) and discovery via the api-catalog.\n * Members keep their wire names (`skip_param`, `max_age`, ...). Members this\n * version does not know are ignored, as the manifest spec requires.\n */\nimport { ManifestError } from \"./errors.ts\";\n\nexport const PROFILE = \"https://craftainer.github.io/schemas/crud-manifest/v1\";\nexport const CATALOG_PATH = \"/.well-known/api-catalog\";\n\n/** A JSON object. */\nexport type JsonObject = Record<string, unknown>;\n\n/** One filterable and sortable field. */\nexport interface FieldSpec {\n readonly name: string;\n readonly value_type: string;\n readonly filter_ops: readonly string[];\n readonly sortable: boolean;\n readonly choices: readonly string[] | null;\n readonly numeric: boolean;\n readonly categorical: boolean;\n readonly read_only: boolean;\n readonly required: boolean;\n}\n\n/** Offset paging parameters and bounds. */\nexport interface Pagination {\n readonly style: string;\n readonly skip_param: string;\n readonly limit_param: string;\n readonly sort_param: string;\n readonly default_limit: number;\n readonly max_limit: number;\n readonly total: boolean;\n}\n\n/** The SSE stream of a resource. */\nexport interface EventsSpec {\n readonly transport: string;\n readonly path: string;\n /** The server-side event label (not the manifest name). */\n readonly resource: string;\n readonly resume_param: string;\n readonly replay: string;\n readonly keepalive_seconds: number;\n readonly actions: readonly string[];\n}\n\n/** What the resource supports. */\nexport interface Capabilities {\n readonly bulk_update: boolean;\n readonly bulk_delete: boolean;\n readonly clone: boolean;\n readonly draft_publish: boolean;\n readonly archive_restore: boolean;\n readonly revisions: boolean;\n readonly events: EventsSpec | null;\n readonly stats: boolean;\n readonly predict: boolean;\n readonly conditional_requests: boolean;\n readonly owner_scoped: boolean;\n readonly schedulable: boolean;\n}\n\n/** Authentication scheme and roles. */\nexport interface AuthSpec {\n readonly scheme: string;\n readonly oidc_discovery_url: string | null;\n readonly public_read: boolean;\n readonly read_roles: readonly string[];\n readonly write_roles: readonly string[];\n readonly delete_roles: readonly string[];\n}\n\n/** The manifest `cache` hints of a resource. */\nexport interface CacheHints {\n readonly etag: boolean;\n readonly max_age: number;\n readonly stats_ttl: number | null;\n readonly stale_while_revalidate: number;\n readonly list_etag: string | null;\n readonly record_etag: string | null;\n readonly revalidate_only: boolean;\n}\n\n/** JSON Schemas of the record views (plain objects). */\nexport interface Schemas {\n readonly read: JsonObject;\n readonly create: JsonObject;\n readonly update: JsonObject;\n readonly draft: JsonObject | null;\n}\n\n/** One resource (`name` + `api_version`). */\nexport interface Resource {\n readonly name: string;\n readonly title: string;\n readonly api_version: string;\n readonly base_path: string;\n readonly formats: Readonly<Record<string, string>>;\n readonly id_field: string;\n readonly schemas: Schemas;\n readonly fields: readonly FieldSpec[];\n readonly pagination: Pagination;\n readonly capabilities: Capabilities;\n readonly paths: Readonly<Record<string, string>>;\n readonly bulk: { readonly max_matched: number };\n readonly auth: AuthSpec;\n readonly cache: CacheHints;\n}\n\n/** The manifest document, as filtered to the caller. */\nexport interface Manifest {\n readonly manifest_version: string;\n readonly service: { readonly name: string; readonly version: string };\n readonly resources: readonly Resource[];\n}\n\nconst isObject = (value: unknown): value is JsonObject =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction bad(where: string, key: string, what: string): never {\n throw new ManifestError(`${where}.${key}: ${what}`);\n}\n\nfunction str(obj: JsonObject, key: string, where: string): string {\n const value = obj[key];\n return typeof value === \"string\"\n ? value\n : bad(where, key, \"missing or not a string\");\n}\n\nfunction bool(obj: JsonObject, key: string, where: string): boolean {\n const value = obj[key];\n return typeof value === \"boolean\"\n ? value\n : bad(where, key, \"missing or not a boolean\");\n}\n\nfunction num(obj: JsonObject, key: string, where: string): number {\n const value = obj[key];\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : bad(where, key, \"missing or not a number\");\n}\n\nfunction int(obj: JsonObject, key: string, where: string): number {\n const value = num(obj, key, where);\n return Number.isInteger(value) ? value : bad(where, key, \"not an integer\");\n}\n\nfunction obj(parent: JsonObject, key: string, where: string): JsonObject {\n const value = parent[key];\n return isObject(value) ? value : bad(where, key, \"missing or not an object\");\n}\n\nfunction list(\n parent: JsonObject,\n key: string,\n where: string,\n): readonly unknown[] {\n const value = parent[key];\n return Array.isArray(value)\n ? value\n : bad(where, key, \"missing or not a list\");\n}\n\nfunction strs(\n parent: JsonObject,\n key: string,\n where: string,\n): readonly string[] {\n const items = list(parent, key, where);\n return items.every((item) => typeof item === \"string\")\n ? (items as readonly string[])\n : bad(where, key, \"expected a list of strings\");\n}\n\n/** A member that may be absent or `null`. */\nfunction opt<T>(\n parent: JsonObject,\n key: string,\n where: string,\n read: (parent: JsonObject, key: string, where: string) => T,\n): T | null {\n return parent[key] === undefined || parent[key] === null\n ? null\n : read(parent, key, where);\n}\n\nfunction stringMap(\n parent: JsonObject,\n key: string,\n where: string,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(obj(parent, key, where))) {\n if (typeof v === \"string\") {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction objects(parent: JsonObject, key: string, where: string): JsonObject[] {\n return list(parent, key, where).map((item, i) =>\n isObject(item) ? item : bad(`${where}.${key}`, `[${i}]`, \"not an object\"),\n );\n}\n\nfunction parseField(o: JsonObject, w: string): FieldSpec {\n return {\n name: str(o, \"name\", w),\n value_type: str(o, \"value_type\", w),\n filter_ops: strs(o, \"filter_ops\", w),\n sortable: bool(o, \"sortable\", w),\n choices: opt(o, \"choices\", w, strs),\n numeric: bool(o, \"numeric\", w),\n categorical: bool(o, \"categorical\", w),\n read_only: bool(o, \"read_only\", w),\n required: bool(o, \"required\", w),\n };\n}\n\nfunction parseEvents(o: JsonObject, w: string): EventsSpec {\n return {\n transport: str(o, \"transport\", w),\n path: str(o, \"path\", w),\n resource: str(o, \"resource\", w),\n resume_param: str(o, \"resume_param\", w),\n replay: str(o, \"replay\", w),\n keepalive_seconds: num(o, \"keepalive_seconds\", w),\n actions: strs(o, \"actions\", w),\n };\n}\n\nfunction parseCapabilities(o: JsonObject, w: string): Capabilities {\n return {\n bulk_update: bool(o, \"bulk_update\", w),\n bulk_delete: bool(o, \"bulk_delete\", w),\n clone: bool(o, \"clone\", w),\n draft_publish: bool(o, \"draft_publish\", w),\n archive_restore: bool(o, \"archive_restore\", w),\n revisions: bool(o, \"revisions\", w),\n events: opt(o, \"events\", w, (p, k, ww) =>\n parseEvents(obj(p, k, ww), `${ww}.${k}`),\n ),\n stats: bool(o, \"stats\", w),\n predict: bool(o, \"predict\", w),\n conditional_requests: bool(o, \"conditional_requests\", w),\n owner_scoped: bool(o, \"owner_scoped\", w),\n schedulable: bool(o, \"schedulable\", w),\n };\n}\n\nfunction parseResource(o: JsonObject, w: string): Resource {\n const schemas = obj(o, \"schemas\", w);\n const pagination = obj(o, \"pagination\", w);\n const auth = obj(o, \"auth\", w);\n const cache = obj(o, \"cache\", w);\n const sw = `${w}.schemas`;\n return {\n name: str(o, \"name\", w),\n title: str(o, \"title\", w),\n api_version: str(o, \"api_version\", w),\n base_path: str(o, \"base_path\", w),\n formats: stringMap(o, \"formats\", w),\n id_field: str(o, \"id_field\", w),\n schemas: {\n read: obj(schemas, \"read\", sw),\n create: obj(schemas, \"create\", sw),\n update: obj(schemas, \"update\", sw),\n draft: opt(schemas, \"draft\", sw, obj),\n },\n fields: objects(o, \"fields\", w).map((f, i) =>\n parseField(f, `${w}.fields[${i}]`),\n ),\n pagination: {\n style: str(pagination, \"style\", w),\n skip_param: str(pagination, \"skip_param\", w),\n limit_param: str(pagination, \"limit_param\", w),\n sort_param: str(pagination, \"sort_param\", w),\n default_limit: int(pagination, \"default_limit\", w),\n max_limit: int(pagination, \"max_limit\", w),\n total: bool(pagination, \"total\", w),\n },\n capabilities: parseCapabilities(\n obj(o, \"capabilities\", w),\n `${w}.capabilities`,\n ),\n paths: stringMap(o, \"paths\", w),\n bulk: { max_matched: int(obj(o, \"bulk\", w), \"max_matched\", `${w}.bulk`) },\n auth: {\n scheme: str(auth, \"scheme\", w),\n oidc_discovery_url: opt(auth, \"oidc_discovery_url\", w, str),\n public_read: bool(auth, \"public_read\", w),\n read_roles: strs(auth, \"read_roles\", w),\n write_roles: strs(auth, \"write_roles\", w),\n delete_roles: strs(auth, \"delete_roles\", w),\n },\n cache: {\n etag: bool(cache, \"etag\", w),\n max_age: int(cache, \"max_age\", w),\n stats_ttl: opt(cache, \"stats_ttl\", w, int),\n stale_while_revalidate: int(cache, \"stale_while_revalidate\", w),\n list_etag: opt(cache, \"list_etag\", w, str),\n record_etag: opt(cache, \"record_etag\", w, str),\n revalidate_only: bool(cache, \"revalidate_only\", w),\n },\n };\n}\n\n/** Parses a manifest document; unknown members are ignored, unknown versions refused. */\nexport function parseManifest(document: unknown): Manifest {\n if (!isObject(document)) {\n throw new ManifestError(\"the manifest is not a JSON object\");\n }\n const version = str(document, \"manifest_version\", \"manifest\");\n if (version !== \"1\") {\n throw new ManifestError(`unsupported manifest_version \"${version}\"`);\n }\n const service = obj(document, \"service\", \"manifest\");\n return {\n manifest_version: version,\n service: {\n name: str(service, \"name\", \"manifest.service\"),\n version: str(service, \"version\", \"manifest.service\"),\n },\n resources: objects(document, \"resources\", \"manifest\").map((r, i) =>\n parseResource(r, `resources[${i}]`),\n ),\n };\n}\n\n/**\n * The resource called `name`: the one with `apiVersion` when given, else the\n * highest `api_version` (`v2` beats `v1`); `undefined` when there is none.\n */\nexport function findResource(\n manifest: Manifest,\n name: string,\n apiVersion?: string,\n): Resource | undefined {\n const rank = (r: Resource): number =>\n Number.parseInt(r.api_version.slice(1), 10) || 0;\n let best: Resource | undefined;\n for (const r of manifest.resources) {\n if (\n r.name === name &&\n (apiVersion === undefined || r.api_version === apiVersion)\n ) {\n if (best === undefined || rank(r) > rank(best)) {\n best = r;\n }\n }\n }\n return best;\n}\n\n/** The absolute manifest URL: the first `describedby` link with the manifest profile. */\nexport function manifestUrlFromCatalog(\n linkset: unknown,\n catalogUrl: string,\n): string {\n const entries = isObject(linkset) ? linkset[\"linkset\"] : undefined;\n for (const entry of Array.isArray(entries) ? entries : []) {\n const links = isObject(entry) ? entry[\"describedby\"] : undefined;\n for (const link of Array.isArray(links) ? links : []) {\n if (\n isObject(link) &&\n link[\"profile\"] === PROFILE &&\n typeof link[\"href\"] === \"string\"\n ) {\n const url = new URL(link[\"href\"], catalogUrl);\n if (url.origin !== new URL(catalogUrl).origin) {\n // The client sends its bearer token to this URL: stay on the server's origin.\n throw new ManifestError(\n `the api-catalog points at another origin (${url.origin}); pass manifestUrl to use it`,\n );\n }\n return url.href;\n }\n }\n }\n throw new ManifestError(\n `the api-catalog has no describedby link with profile ${PROFILE}`,\n );\n}\n\n/** Fetches a JSON document; `catalog` marks the api-catalog request (kept out of the manifest cache). */\nexport type GetJson = (url: string, catalog: boolean) => Promise<unknown>;\n\n/**\n * Loads and parses the manifest, via api-catalog discovery from `baseUrl` or\n * a direct `manifestUrl`.\n */\nexport async function loadManifest(\n getJson: GetJson,\n baseUrl: string,\n manifestUrl?: string,\n): Promise<Manifest> {\n let url = manifestUrl;\n if (url === undefined) {\n const catalogUrl = new URL(CATALOG_PATH, baseUrl).href;\n url = manifestUrlFromCatalog(await getJson(catalogUrl, true), catalogUrl);\n }\n return parseManifest(await getJson(url, false));\n}\n","/**\n * Query-string builder with `crud_query` semantics, validated against the\n * manifest fields. Produces the same bytes as the Python SDK.\n */\nimport { InvalidQueryError } from \"./errors.ts\";\nimport type { FieldSpec } from \"./manifest.ts\";\n\nconst MAX_REGEX_LENGTH = 200;\n\n/** The part of a manifest field the builder needs. */\nexport type QueryField = Pick<\n FieldSpec,\n \"name\" | \"value_type\" | \"filter_ops\" | \"sortable\" | \"choices\"\n>;\n\n/** Filter arguments: `field` (equality, emitted bare) or `field__op` -> value. */\nexport type Filters = Readonly<Record<string, unknown>>;\n\n/** `\"name,-other\"` or `[\"name\", \"-other\"]`. */\nexport type Sort = string | readonly string[];\n\n/** Everything {@link buildQuery} takes beside the fields. */\nexport interface QueryParams {\n readonly recordId?: number | undefined;\n readonly filters?: Filters | undefined;\n readonly sort?: Sort | undefined;\n readonly skip?: number | undefined;\n readonly limit?: number | undefined;\n readonly maxLimit?: number | undefined;\n readonly skipParam?: string | undefined;\n readonly limitParam?: string | undefined;\n readonly sortParam?: string | undefined;\n readonly includeArchived?: boolean | undefined;\n /**\n * Only rows with `archived_at` set (list only; implies `include_archived`).\n * Emitted only when `true`; combining `true` with `includeArchived: false`\n * throws `InvalidQueryError`, as the server answers 422.\n */\n readonly onlyArchived?: boolean | undefined;\n readonly includeUnpublished?: boolean | undefined;\n}\n\n/** Percent-encodes everything but the RFC 3986 unreserved characters `A-Za-z0-9-._~`. */\nexport function quote(text: string): string {\n return encodeURIComponent(text).replace(\n /[!'()*]/g,\n (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n}\n\n/**\n * {@link quote} for caller input: a lone surrogate (an emoji cut in half)\n * cannot be UTF-8 encoded, which is an invalid argument, not a `URIError`.\n */\nfunction encode(text: string): string {\n try {\n return quote(text);\n } catch (error) {\n // `encodeURIComponent` throws only `URIError`.\n throw new InvalidQueryError(\n \"a query value is not well-formed Unicode (lone surrogate)\",\n { cause: error },\n );\n }\n}\n\n/** Joins already-stringified pairs, encoding keys and values. */\nexport function encodeParams(\n pairs: readonly (readonly [string, string])[],\n): string {\n return pairs.map(([k, v]) => `${encode(k)}=${encode(v)}`).join(\"&\");\n}\n\nfunction formatDatetime(value: Date): string | undefined {\n if (Number.isNaN(value.getTime())) {\n return undefined;\n }\n const iso = value.toISOString();\n if (iso.length !== 24) {\n return undefined; // expanded years (outside 0000-9999)\n }\n const millis = iso.slice(20, 23).replace(/0+$/, \"\");\n return millis === \"\"\n ? `${iso.slice(0, 19)}Z`\n : `${iso.slice(0, 19)}.${millis}Z`;\n}\n\nfunction formatDate(value: string): string | undefined {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n return undefined;\n }\n const parsed = new Date(`${value}T00:00:00Z`);\n return Number.isNaN(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value\n ? undefined\n : value;\n}\n\nfunction scalarText(kind: string, value: unknown): string | undefined {\n switch (kind) {\n case \"integer\":\n return typeof value === \"number\" && Number.isSafeInteger(value)\n ? String(value)\n : undefined;\n case \"number\":\n return typeof value === \"number\" && Number.isFinite(value)\n ? String(value)\n : undefined;\n case \"boolean\":\n return typeof value === \"boolean\" ? String(value) : undefined;\n case \"date\":\n return typeof value === \"string\" ? formatDate(value) : undefined;\n case \"datetime\":\n return value instanceof Date ? formatDatetime(value) : undefined;\n default:\n return typeof value === \"string\" ? value : undefined;\n }\n}\n\n/**\n * Wire form of one value for `field`; throws `InvalidQueryError` on a type\n * mismatch. Dates are `YYYY-MM-DD` strings, datetimes `Date`s (UTC, with\n * millisecond precision, trailing zeros trimmed).\n */\nexport function formatScalar(field: QueryField, value: unknown): string {\n const text = scalarText(field.value_type, value);\n if (text === undefined) {\n throw new InvalidQueryError(\n `field \"${field.name}\" (${field.value_type}) cannot take ${String(value)}`,\n );\n }\n if (\n field.value_type === \"enum\" &&\n field.choices !== null &&\n !field.choices.includes(text)\n ) {\n throw new InvalidQueryError(\n `field \"${field.name}\" accepts only ${JSON.stringify(field.choices)}, not \"${text}\"`,\n );\n }\n return text;\n}\n\nfunction filterPair(\n field: QueryField,\n op: string,\n value: unknown,\n): [string, string] {\n const key = op === \"eq\" ? field.name : `${field.name}__${op}`;\n if (op === \"in\") {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidQueryError(`\"${key}\" takes a non-empty array`);\n }\n const parts = value.map((item: unknown) => formatScalar(field, item));\n if (parts.some((part) => part.includes(\",\"))) {\n throw new InvalidQueryError(\n `\"${key}\": a value contains a comma, which separates the list`,\n );\n }\n return [key, parts.map((part) => encode(part)).join(\",\")];\n }\n const text = formatScalar(field, value);\n if (op === \"regex\" && [...text].length > MAX_REGEX_LENGTH) {\n throw new InvalidQueryError(\n `\"${key}\": a regex is limited to ${MAX_REGEX_LENGTH} characters`,\n );\n }\n return [key, encode(text)];\n}\n\nconst compare = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0);\n\nfunction filterPairs(\n fields: ReadonlyMap<string, QueryField>,\n filters: Filters,\n): [string, string][] {\n const parsed = new Map<\n string,\n { name: string; op: string; pair: [string, string] }\n >();\n for (const [rawKey, value] of Object.entries(filters)) {\n const at = rawKey.lastIndexOf(\"__\");\n const name = at < 0 ? rawKey : rawKey.slice(0, at);\n const op = at < 0 ? \"eq\" : rawKey.slice(at + 2);\n const field = fields.get(name);\n if (field === undefined) {\n throw new InvalidQueryError(`unknown filter field \"${name}\"`);\n }\n if (!field.filter_ops.includes(op)) {\n throw new InvalidQueryError(\n `field \"${name}\" does not support the \"${op}\" operator`,\n );\n }\n if (name === \"id\" && op === \"eq\") {\n throw new InvalidQueryError(\n \"filter on id with recordId, not an equality filter\",\n );\n }\n const id = `${name}\\u0000${op}`;\n if (parsed.has(id)) {\n throw new InvalidQueryError(`filter \"${name}\" \"${op}\" given twice`);\n }\n parsed.set(id, { name, op, pair: filterPair(field, op, value) });\n }\n return [...parsed.values()]\n .sort((a, b) => compare(a.name, b.name) || compare(a.op, b.op))\n .map((entry) => entry.pair);\n}\n\nfunction sortValue(\n fields: ReadonlyMap<string, QueryField>,\n sort: Sort,\n): string {\n const parts = typeof sort === \"string\" ? sort.split(\",\") : sort;\n const out = parts.map((part) => {\n const name = part.startsWith(\"-\") ? part.slice(1) : part;\n const field = fields.get(name);\n if (field === undefined || !field.sortable) {\n throw new InvalidQueryError(`cannot sort by \"${name}\"`);\n }\n return encode(part);\n });\n if (out.length === 0) {\n throw new InvalidQueryError(\"sort is empty\");\n }\n return out.join(\",\");\n}\n\nfunction intArg(name: string, value: unknown, minimum: number): string {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n value < minimum\n ) {\n throw new InvalidQueryError(`${name} must be an integer >= ${minimum}`);\n }\n return String(value);\n}\n\n/**\n * The query string (no leading `?`) for a list, get or bulk call. Order of\n * parameters: `id`, filters sorted by (field, operator), sort, skip, limit,\n * `include_archived`, `only_archived`, `include_unpublished`. The sort/skip/limit names are\n * `sortParam`/`skipParam`/`limitParam` (the manifest's `pagination`); the\n * `id` parameter is always `id`. Flags are emitted whenever they are not\n * `undefined`, except `only_archived`, which is emitted only when `true`\n * (absent means false; it is a reserved key, not a filter).\n */\nexport function buildQuery(\n fields: readonly QueryField[],\n params: QueryParams = {},\n): string {\n if (params.onlyArchived === true && params.includeArchived === false) {\n throw new InvalidQueryError(\n \"onlyArchived cannot be combined with includeArchived: false\",\n );\n }\n const byName = new Map(fields.map((f) => [f.name, f]));\n const parts: string[] = [];\n if (params.recordId !== undefined) {\n parts.push(`id=${intArg(\"recordId\", params.recordId, 0)}`);\n }\n for (const [key, value] of filterPairs(byName, params.filters ?? {})) {\n parts.push(`${encode(key)}=${value}`); // values arrive encoded; `in` keeps its commas\n }\n if (params.sort !== undefined) {\n parts.push(\n `${encode(params.sortParam ?? \"sort\")}=${sortValue(byName, params.sort)}`,\n );\n }\n if (params.skip !== undefined) {\n parts.push(\n `${encode(params.skipParam ?? \"skip\")}=${intArg(\"skip\", params.skip, 0)}`,\n );\n }\n if (params.limit !== undefined) {\n const text = intArg(\"limit\", params.limit, 1);\n if (params.maxLimit !== undefined && params.limit > params.maxLimit) {\n throw new InvalidQueryError(\n `limit ${params.limit} exceeds the server maximum ${params.maxLimit}`,\n );\n }\n parts.push(`${encode(params.limitParam ?? \"limit\")}=${text}`);\n }\n if (params.includeArchived !== undefined) {\n parts.push(`include_archived=${params.includeArchived}`);\n }\n if (params.onlyArchived === true) {\n parts.push(\"only_archived=true\");\n }\n if (params.includeUnpublished !== undefined) {\n parts.push(`include_unpublished=${params.includeUnpublished}`);\n }\n return parts.join(\"&\");\n}\n","/** Fetch client: manifest-driven resource handles over a middleware chain. */\nimport { cacheScope } from \"./auth.ts\";\nimport {\n CapabilityError,\n ConnectionFailed,\n InvalidQueryError,\n ManifestError,\n ResponseError,\n UnknownResourceError,\n problemFromResponse,\n} from \"./errors.ts\";\nimport { composeMiddleware } from \"./interfaces.ts\";\nimport type { Middleware, Op, TokenProvider } from \"./interfaces.ts\";\nimport { findResource, loadManifest } from \"./manifest.ts\";\nimport type { JsonObject, Manifest, Resource } from \"./manifest.ts\";\nimport { buildQuery, encodeParams } from \"./query.ts\";\nimport type { Filters, QueryParams, Sort } from \"./query.ts\";\n\n/** Per-call options. */\nexport interface RequestOptions {\n readonly signal?: AbortSignal | undefined;\n}\n\n/**\n * Options of `list` and `iterAll`. `onlyArchived: true` returns only archived\n * rows (it implies `includeArchived`; with `includeArchived: false` the call\n * throws `InvalidQueryError` before any request). Non-archivable resources\n * ignore it.\n */\nexport interface ListOptions extends RequestOptions {\n readonly filters?: Filters | undefined;\n readonly sort?: Sort | undefined;\n readonly skip?: number | undefined;\n readonly limit?: number | undefined;\n readonly includeArchived?: boolean | undefined;\n readonly onlyArchived?: boolean | undefined;\n readonly includeUnpublished?: boolean | undefined;\n}\n\n/** Options of `update` and `delete`: `ifMatch` is an ETag (`412` when stale). */\nexport interface WriteOptions extends RequestOptions {\n readonly ifMatch?: string | undefined;\n}\n\n/** Options of `stats`. There is no `onlyArchived` (the server rejects it on `/stats`). */\nexport interface StatsOptions extends RequestOptions {\n readonly bucket?: string | undefined;\n readonly includeArchived?: boolean | undefined;\n readonly includeUnpublished?: boolean | undefined;\n}\n\n/** Options of `predict`. */\nexport interface PredictOptions extends RequestOptions {\n readonly field?: string | undefined;\n readonly periods?: number | undefined;\n readonly bucket?: string | undefined;\n}\n\n/** Options of `restore`: exactly one of `id` and `filters`. */\nexport interface RestoreOptions extends RequestOptions {\n readonly id?: number | undefined;\n readonly filters?: Filters | undefined;\n}\n\n/** The result of a bulk call. */\nexport interface BulkResult {\n readonly matched: number;\n readonly ids: readonly number[];\n}\n\nexport interface Call {\n readonly method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n readonly url: string;\n readonly op: Op;\n readonly resource: string | undefined;\n readonly recordId: number | undefined;\n readonly apiVersion: string | null;\n readonly json?: unknown;\n readonly headers?: Readonly<Record<string, string>>;\n}\n\n/** What a {@link ResourceClient} needs from its client. */\nexport interface Transport {\n json(call: Call, signal: AbortSignal | undefined): Promise<unknown>;\n none(call: Call, signal: AbortSignal | undefined): Promise<void>;\n}\n\nconst joinUrl = (base: string, path: string): string =>\n new URL(path, base).href;\n\n/** Builds the requests of one resource. */\nclass Plan {\n readonly #baseUrl: string;\n readonly resource: Resource;\n\n constructor(baseUrl: string, resource: Resource) {\n this.#baseUrl = baseUrl;\n this.resource = resource;\n }\n\n #call(\n method: Call[\"method\"],\n op: Op,\n path: string,\n query = \"\",\n extra: {\n recordId?: number | undefined;\n json?: unknown;\n ifMatch?: string | undefined;\n } = {},\n ): Call {\n const url =\n joinUrl(this.#baseUrl, path) + (query === \"\" ? \"\" : `?${query}`);\n return {\n method,\n url,\n op,\n resource: this.resource.name,\n recordId: extra.recordId,\n apiVersion: this.resource.api_version,\n ...(extra.json === undefined ? {} : { json: extra.json }),\n ...(extra.ifMatch === undefined\n ? {}\n : { headers: { \"If-Match\": extra.ifMatch } }),\n };\n }\n\n #query(params: QueryParams = {}): string {\n const paging = this.resource.pagination;\n return buildQuery(this.resource.fields, {\n maxLimit: paging.max_limit,\n skipParam: paging.skip_param,\n limitParam: paging.limit_param,\n sortParam: paging.sort_param,\n ...params,\n });\n }\n\n #subPath(key: string, supported: boolean): string {\n const path = this.resource.paths[key];\n if (!supported || path === undefined) {\n throw new CapabilityError(\n `resource \"${this.resource.name}\" does not support ${key}`,\n );\n }\n return path;\n }\n\n #need(supported: boolean, what: string): void {\n if (!supported) {\n throw new CapabilityError(\n `resource \"${this.resource.name}\" does not support ${what}`,\n );\n }\n }\n\n #bulkFilters(filters: Filters): string {\n if (Object.keys(filters).length === 0) {\n throw new InvalidQueryError(\"a bulk operation needs at least one filter\");\n }\n return this.#query({ filters });\n }\n\n get #base(): string {\n return this.resource.base_path;\n }\n\n eventsUrl(): string {\n const events = this.resource.capabilities.events;\n if (events === null) {\n throw new CapabilityError(\n `resource \"${this.resource.name}\" does not support events`,\n );\n }\n return joinUrl(this.#baseUrl, events.path);\n }\n\n list(o: ListOptions): Call {\n const query = this.#query({\n filters: o.filters,\n sort: o.sort,\n skip: o.skip,\n limit: o.limit,\n includeArchived: o.includeArchived,\n onlyArchived: o.onlyArchived,\n includeUnpublished: o.includeUnpublished,\n });\n return this.#call(\"GET\", \"list\", this.#base, query);\n }\n\n get(id: number): Call {\n return this.#call(\n \"GET\",\n \"record\",\n this.#base,\n this.#query({ recordId: id }),\n {\n recordId: id,\n },\n );\n }\n\n create(data: unknown): Call {\n return this.#call(\"POST\", \"create\", this.#base, \"\", { json: data });\n }\n\n update(id: number, data: unknown, ifMatch: string | undefined): Call {\n return this.#call(\n \"PATCH\",\n \"update\",\n this.#base,\n this.#query({ recordId: id }),\n {\n recordId: id,\n json: data,\n ifMatch,\n },\n );\n }\n\n updateMany(filters: Filters, data: unknown): Call {\n this.#need(this.resource.capabilities.bulk_update, \"bulk_update\");\n return this.#call(\n \"PATCH\",\n \"bulk_update\",\n this.#base,\n this.#bulkFilters(filters),\n {\n json: data,\n },\n );\n }\n\n delete(id: number, ifMatch: string | undefined): Call {\n return this.#call(\n \"DELETE\",\n \"delete\",\n this.#base,\n this.#query({ recordId: id }),\n {\n recordId: id,\n ifMatch,\n },\n );\n }\n\n deleteMany(filters: Filters): Call {\n this.#need(this.resource.capabilities.bulk_delete, \"bulk_delete\");\n return this.#call(\n \"DELETE\",\n \"bulk_delete\",\n this.#base,\n this.#bulkFilters(filters),\n );\n }\n\n restore(id: number | undefined, filters: Filters | undefined): Call {\n const path = this.#subPath(\n \"restore\",\n this.resource.capabilities.archive_restore,\n );\n if ((id === undefined) === (filters === undefined)) {\n throw new InvalidQueryError(\n \"restore takes exactly one of id and filters\",\n );\n }\n const query =\n filters === undefined\n ? this.#query({ recordId: id })\n : this.#bulkFilters(filters);\n return this.#call(\"POST\", \"restore\", path, query, { recordId: id });\n }\n\n stats(o: StatsOptions): Call {\n const path = this.#subPath(\"stats\", this.resource.capabilities.stats);\n const pairs: [string, string][] =\n o.bucket === undefined ? [] : [[\"bucket\", o.bucket]];\n if (o.includeArchived !== undefined) {\n pairs.push([\"include_archived\", String(o.includeArchived)]);\n }\n if (o.includeUnpublished !== undefined) {\n pairs.push([\"include_unpublished\", String(o.includeUnpublished)]);\n }\n return this.#call(\"GET\", \"stats\", path, encodeParams(pairs));\n }\n\n predict(o: PredictOptions): Call {\n const path = this.#subPath(\"predict\", this.resource.capabilities.predict);\n const pairs: [string, string][] = [];\n if (o.field !== undefined) {\n const spec = this.resource.fields.find((f) => f.name === o.field);\n if (spec === undefined || !spec.numeric) {\n throw new InvalidQueryError(\n `cannot predict \"${o.field}\": not a numeric field`,\n );\n }\n pairs.push([\"field\", o.field]);\n }\n if (o.periods !== undefined) {\n if (!Number.isSafeInteger(o.periods) || o.periods < 1) {\n throw new InvalidQueryError(\"periods must be an integer >= 1\");\n }\n pairs.push([\"periods\", String(o.periods)]);\n }\n if (o.bucket !== undefined) {\n pairs.push([\"bucket\", o.bucket]);\n }\n return this.#call(\"GET\", \"predict\", path, encodeParams(pairs));\n }\n\n clone(id: number): Call {\n const path = this.#subPath(\"clone\", this.resource.capabilities.clone);\n return this.#call(\"POST\", \"clone\", path, this.#query({ recordId: id }), {\n recordId: id,\n });\n }\n\n draft(data: unknown): Call {\n const path = this.#subPath(\n \"draft\",\n this.resource.capabilities.draft_publish,\n );\n return this.#call(\"POST\", \"draft\", path, \"\", { json: data });\n }\n\n publish(id: number): Call {\n const path = this.#subPath(\n \"publish\",\n this.resource.capabilities.draft_publish,\n );\n return this.#call(\"POST\", \"publish\", path, this.#query({ recordId: id }), {\n recordId: id,\n });\n }\n\n filters(): Call {\n return this.#call(\"GET\", \"filters\", this.#subPath(\"filters\", true));\n }\n\n revisions(id: number): Call {\n const path = this.#subPath(\n \"revisions\",\n this.resource.capabilities.revisions,\n );\n return this.#call(\"GET\", \"revisions\", path, this.#query({ recordId: id }), {\n recordId: id,\n });\n }\n}\n\n/**\n * Operations on one resource. The type parameters are the record views;\n * `crud-sdk-codegen` writes interfaces to pass for them (they are not\n * checked against the manifest at runtime).\n */\nexport class ResourceClient<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n> {\n /** The manifest entry this handle is bound to. */\n readonly resource: Resource;\n readonly #plan: Plan;\n readonly #transport: Transport;\n\n /** Use `CrudClient.resource`. */\n constructor(baseUrl: string, resource: Resource, transport: Transport) {\n this.resource = resource;\n this.#plan = new Plan(baseUrl, resource);\n this.#transport = transport;\n }\n\n async #one<T>(call: Call, options: RequestOptions): Promise<T> {\n return (await this.#transport.json(call, options.signal)) as T;\n }\n\n /** One page of records. */\n async list(options: ListOptions = {}): Promise<Read[]> {\n return this.#one(this.#plan.list(options), options);\n }\n\n /** Every record, paging with `skip += limit` until a page shorter than `limit`. */\n async *iterAll(\n options: ListOptions = {},\n ): AsyncGenerator<Read, void, undefined> {\n const size = options.limit ?? this.resource.pagination.default_limit;\n let skip = options.skip ?? 0;\n for (;;) {\n const page = await this.list({ ...options, skip, limit: size });\n yield* page;\n if (page.length < size) {\n return;\n }\n skip += size;\n }\n }\n\n /** One record. */\n async get(id: number, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.get(id), options);\n }\n\n /** Creates a record. */\n async create(data: Create, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.create(data), options);\n }\n\n /** Patches one record; `ifMatch` is an ETag (`412` when stale). */\n async update(\n id: number,\n data: Update,\n options: WriteOptions = {},\n ): Promise<Read> {\n return this.#one(this.#plan.update(id, data, options.ifMatch), options);\n }\n\n /** Patches every record matching `filters`. */\n async updateMany(\n filters: Filters,\n data: Update,\n options: RequestOptions = {},\n ): Promise<BulkResult> {\n return this.#one(this.#plan.updateMany(filters, data), options);\n }\n\n /** Deletes one record; `ifMatch` as for `update`. */\n async delete(id: number, options: WriteOptions = {}): Promise<void> {\n await this.#transport.none(\n this.#plan.delete(id, options.ifMatch),\n options.signal,\n );\n }\n\n /** Deletes every record matching `filters`. */\n async deleteMany(\n filters: Filters,\n options: RequestOptions = {},\n ): Promise<BulkResult> {\n return this.#one(this.#plan.deleteMany(filters), options);\n }\n\n /** Restores archived records, by `id` or by `filters`. */\n async restore(options: RestoreOptions): Promise<BulkResult> {\n return this.#one(this.#plan.restore(options.id, options.filters), options);\n }\n\n /** Aggregates over the resource. */\n async stats(options: StatsOptions = {}): Promise<JsonObject> {\n return this.#one(this.#plan.stats(options), options);\n }\n\n /** A forecast. */\n async predict(options: PredictOptions = {}): Promise<JsonObject> {\n return this.#one(this.#plan.predict(options), options);\n }\n\n /** Copies a record; returns the copy. */\n async clone(id: number, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.clone(id), options);\n }\n\n /** Creates a draft (needs `draft_publish`). */\n async createDraft(data: Create, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.draft(data), options);\n }\n\n /** Publishes a draft (needs `draft_publish`). */\n async publish(id: number, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.publish(id), options);\n }\n\n /** The server's filter metadata (`kind` instead of `value_type`). */\n async filters(options: RequestOptions = {}): Promise<JsonObject[]> {\n return this.#one(this.#plan.filters(), options);\n }\n\n /** Revisions of one record, newest first. */\n async revisions(\n id: number,\n options: RequestOptions = {},\n ): Promise<JsonObject[]> {\n return this.#one(this.#plan.revisions(id), options);\n }\n\n /** Absolute URL of the resource's SSE stream. */\n eventsUrl(): string {\n return this.#plan.eventsUrl();\n }\n}\n\n/** Options of {@link createClient}. */\nexport interface ClientOptions {\n /** The server origin (or any URL on it). */\n readonly baseUrl: string;\n /** The network `fetch`; defaults to `globalThis.fetch`. */\n readonly fetch?: typeof fetch | undefined;\n /** Returns the bearer token; called again with `refresh: true` once after a `401`. */\n readonly tokenProvider?: TokenProvider | undefined;\n /** Outermost first; see `composeMiddleware`. */\n readonly middleware?: readonly Middleware[] | undefined;\n /** Skips api-catalog discovery. */\n readonly manifestUrl?: string | undefined;\n /**\n * Stable identity of this client in TanStack query keys. Defaults to\n * `baseUrl`; set it when two clients share a `baseUrl` but must not share\n * cached data, and keep it constant across reloads of a persisted cache.\n */\n readonly id?: string | undefined;\n}\n\n/** Discovers the manifest and hands out {@link ResourceClient}s. */\nexport class CrudClient {\n readonly baseUrl: string;\n /** Stable identity in TanStack query keys (`ClientOptions.id`, else `baseUrl`). */\n readonly id: string;\n readonly #fetch: typeof fetch | undefined;\n readonly #tokenProvider: TokenProvider | undefined;\n readonly #middleware: Middleware[];\n readonly #manifestUrl: string | undefined;\n readonly #manifests = new Map<string, Promise<Manifest>>();\n readonly #transport: Transport;\n\n constructor(options: ClientOptions) {\n this.baseUrl = options.baseUrl;\n this.id = options.id ?? options.baseUrl;\n this.#fetch = options.fetch;\n this.#tokenProvider = options.tokenProvider;\n this.#middleware = [...(options.middleware ?? [])];\n this.#manifestUrl = options.manifestUrl;\n this.#transport = {\n json: async (call, signal) => {\n const response = await this.#send(call, signal);\n if (response.status === 204) {\n return undefined;\n }\n try {\n return (await response.json()) as unknown;\n } catch (error) {\n throw new ResponseError(\n `${call.method} ${call.url}: the ${response.status} response body is not valid JSON`,\n { cause: error },\n );\n }\n },\n none: async (call, signal) => {\n await (await this.#send(call, signal)).body?.cancel();\n },\n };\n }\n\n /** Adds middleware after the existing ones (innermost); it sees every later request. */\n use(middleware: Middleware): this {\n this.#middleware.push(middleware);\n return this;\n }\n\n async #token(refresh: boolean): Promise<string | null> {\n // An empty token sends no header, so it is anonymous for the scope too.\n return (await this.#tokenProvider?.({ refresh })) || null;\n }\n\n /** The current bearer token, or `null` when anonymous. */\n token(refresh = false): Promise<string | null> {\n return this.#token(refresh);\n }\n\n /** The cache scope of the current caller (`\"anon\"` or a hash of the token). */\n async scope(): Promise<string> {\n return cacheScope(await this.#token(false));\n }\n\n /** The `{ client, scope }` namespace the `./tanstack` key factory takes. */\n async namespace(): Promise<{\n readonly client: string;\n readonly scope: string;\n }> {\n return { client: this.id, scope: await this.scope() };\n }\n\n async #dispatch(\n call: Call,\n token: string | null,\n signal: AbortSignal | undefined,\n ): Promise<Response> {\n const headers = new Headers({\n Accept: \"application/json\",\n ...call.headers,\n });\n if (token !== null) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n const init: RequestInit = {\n method: call.method,\n headers,\n signal: signal ?? null,\n };\n if (call.json !== undefined) {\n headers.set(\"Content-Type\", \"application/json\");\n init.body = JSON.stringify(call.json);\n }\n const request = new Request(call.url, init);\n const terminal = async (ctx: {\n readonly request: Request;\n }): Promise<Response> => {\n try {\n return await (this.#fetch ?? globalThis.fetch)(ctx.request);\n } catch (error) {\n if (ctx.request.signal.aborted) {\n throw error;\n }\n throw new ConnectionFailed(\n error instanceof Error ? error.message : String(error),\n {\n cause: error,\n },\n );\n }\n };\n return composeMiddleware(\n this.#middleware,\n terminal,\n )({\n request,\n resource: call.resource,\n op: call.op,\n recordId: call.recordId,\n scope: await cacheScope(token),\n apiVersion: call.apiVersion,\n signal,\n });\n }\n\n /** Sends `call`, retrying once with a refreshed token after a `401`; throws on `>= 400`. */\n async #send(call: Call, signal: AbortSignal | undefined): Promise<Response> {\n const token = await this.#token(false);\n let response = await this.#dispatch(call, token, signal);\n if (response.status === 401 && this.#tokenProvider !== undefined) {\n const fresh = await this.#token(true);\n if (fresh !== null && fresh !== token) {\n await response.body?.cancel();\n response = await this.#dispatch(call, fresh, signal);\n }\n }\n if (response.status >= 400) {\n throw await problemFromResponse(response);\n }\n return response;\n }\n\n async #getJson(url: string, catalog: boolean): Promise<unknown> {\n const call: Call = {\n method: \"GET\",\n url,\n op: \"manifest\",\n resource: undefined,\n recordId: undefined,\n apiVersion: null,\n // The catalog shares the \"manifest\" op; no-store keeps it out of the manifest cache entry.\n ...(catalog ? { headers: { \"Cache-Control\": \"no-store\" } } : {}),\n };\n const response = await this.#send(call, undefined);\n try {\n return (await response.json()) as unknown;\n } catch (error) {\n throw new ManifestError(`${url} is not JSON`, { cause: error });\n }\n }\n\n /** The manifest for this caller, loaded once per caller scope (`refresh: true` reloads). */\n async manifest(\n options: { readonly refresh?: boolean } = {},\n ): Promise<Manifest> {\n const scope = await this.scope(); // the manifest is filtered per caller\n let loading = this.#manifests.get(scope);\n if (loading === undefined || options.refresh === true) {\n const started = loadManifest(\n (url, catalog) => this.#getJson(url, catalog),\n this.baseUrl,\n this.#manifestUrl,\n );\n loading = started;\n if (!this.#manifests.has(scope)) {\n this.#manifests.clear(); // rotated tokens must not pile up manifests\n }\n this.#manifests.set(scope, started);\n started.catch(() => {\n if (this.#manifests.get(scope) === started) {\n this.#manifests.delete(scope);\n }\n });\n }\n return loading;\n }\n\n /** A handle for `name` (the highest `api_version` unless given). */\n async resource<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n >(\n name: string,\n apiVersion?: string,\n ): Promise<ResourceClient<Read, Create, Update>> {\n const resource = findResource(await this.manifest(), name, apiVersion);\n if (resource === undefined) {\n throw new UnknownResourceError(\n `the manifest has no resource \"${name}\"${apiVersion === undefined ? \"\" : ` ${apiVersion}`} for this caller`,\n );\n }\n return new ResourceClient<Read, Create, Update>(\n this.baseUrl,\n resource,\n this.#transport,\n );\n }\n}\n\n/** Creates a client; the manifest loads on first use. */\nexport function createClient(options: ClientOptions): CrudClient {\n return new CrudClient(options);\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { p as parseManifest, r as createClient, v as CrudError } from "../client-Bv0yCuwC.mjs";
2
+ import { p as parseManifest, r as createClient, v as CrudError } from "../client-DJkbw9_q.mjs";
3
3
  import { readFile, writeFile } from "node:fs/promises";
4
4
  //#region src/codegen/generate.ts
5
5
  /** Loads the optional peer `json-schema-to-typescript`; a clear error when it is missing. */
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as Middleware, c as RequestContext, i as MaybePromise, l as TokenProvider, n as CacheStore, o as Next, r as CrudEvent, s as Op, t as CacheEntry, u as composeMiddleware } from "./interfaces-s73cVfIF.mjs";
2
- import { A as Pagination, C as Capabilities, D as JsonObject, E as GetJson, F as manifestUrlFromCatalog, I as parseManifest, M as Schemas, N as findResource, O as Manifest, P as loadManifest, S as CacheHints, T as FieldSpec, _ as encodeParams, a as PredictOptions, b as AuthSpec, c as RestoreOptions, d as createClient, f as Filters, g as buildQuery, h as Sort, i as ListOptions, j as Resource, k as PROFILE, l as StatsOptions, m as QueryParams, n as ClientOptions, o as RequestOptions, p as QueryField, r as CrudClient, s as ResourceClient, t as BulkResult, u as WriteOptions, v as formatScalar, w as EventsSpec, x as CATALOG_PATH, y as quote } from "./client-B8fSsx4L.mjs";
2
+ import { A as Pagination, C as Capabilities, D as JsonObject, E as GetJson, F as manifestUrlFromCatalog, I as parseManifest, M as Schemas, N as findResource, O as Manifest, P as loadManifest, S as CacheHints, T as FieldSpec, _ as encodeParams, a as PredictOptions, b as AuthSpec, c as RestoreOptions, d as createClient, f as Filters, g as buildQuery, h as Sort, i as ListOptions, j as Resource, k as PROFILE, l as StatsOptions, m as QueryParams, n as ClientOptions, o as RequestOptions, p as QueryField, r as CrudClient, s as ResourceClient, t as BulkResult, u as WriteOptions, v as formatScalar, w as EventsSpec, x as CATALOG_PATH, y as quote } from "./client-BU9rPr8h.mjs";
3
3
  //#region src/auth.d.ts
4
4
  /** The scope of an anonymous caller. */
5
5
  export declare const ANON = "anon";
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { A as UnknownResourceError, C as NotFound, D as ResponseError, E as RateLimited, M as problemFromResponse, N as composeMiddleware, O as ServerError, S as ManifestError, T as ProblemError, _ as ConnectionFailed, a as encodeParams, b as InvalidQueryError, c as CATALOG_PATH, d as loadManifest, f as manifestUrlFromCatalog, g as ClientError, h as CapabilityError, i as buildQuery, j as ValidationFailed, k as Unauthorized, l as PROFILE, m as BadRequest, n as ResourceClient, o as formatScalar, p as parseManifest, r as createClient, s as quote, t as CrudClient, u as findResource, v as CrudError, w as PreconditionFailed, x as Locked, y as Forbidden } from "./client-Bv0yCuwC.mjs";
1
+ import { A as UnknownResourceError, C as NotFound, D as ResponseError, E as RateLimited, M as problemFromResponse, N as composeMiddleware, O as ServerError, S as ManifestError, T as ProblemError, _ as ConnectionFailed, a as encodeParams, b as InvalidQueryError, c as CATALOG_PATH, d as loadManifest, f as manifestUrlFromCatalog, g as ClientError, h as CapabilityError, i as buildQuery, j as ValidationFailed, k as Unauthorized, l as PROFILE, m as BadRequest, n as ResourceClient, o as formatScalar, p as parseManifest, r as createClient, s as quote, t as CrudClient, u as findResource, v as CrudError, w as PreconditionFailed, x as Locked, y as Forbidden } from "./client-DJkbw9_q.mjs";
2
2
  import { n as cacheScope, r as staticToken, t as ANON } from "./auth-DwtNEKrw.mjs";
3
3
  export { ANON, BadRequest, CATALOG_PATH, CapabilityError, ClientError, ConnectionFailed, CrudClient, CrudError, Forbidden, InvalidQueryError, Locked, ManifestError, NotFound, PROFILE, PreconditionFailed, ProblemError, RateLimited, ResourceClient, ResponseError, ServerError, Unauthorized, UnknownResourceError, ValidationFailed, buildQuery, cacheScope, composeMiddleware, createClient, encodeParams, findResource, formatScalar, loadManifest, manifestUrlFromCatalog, parseManifest, problemFromResponse, quote, staticToken };
@@ -1,6 +1,6 @@
1
1
  import { r as CrudEvent } from "../interfaces-s73cVfIF.mjs";
2
2
  import { a as SubscribeEventsOptions, c as CachePolicy, d as tanstackCachePolicy, i as EventsConfig, l as ManifestCacheHints, n as EventHub, o as getEventHub, r as EventHubOptions, s as subscribeEvents, t as EventHandlers } from "../events-DpSWzSN9.mjs";
3
- import { D as JsonObject, O as Manifest, r as CrudClient, s as ResourceClient } from "../client-B8fSsx4L.mjs";
3
+ import { D as JsonObject, O as Manifest, r as CrudClient, s as ResourceClient } from "../client-BU9rPr8h.mjs";
4
4
  import { DataTag, QueryClient } from "@tanstack/query-core";
5
5
  //#region src/tanstack/adapter.d.ts
6
6
  type Init = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craftainer/crud-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Typed fetch client for craftainer CRUD APIs: manifest-driven resources, query builder, problem-details errors, opt-in cache with SSE invalidation and TanStack Query helpers.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-Bv0yCuwC.mjs","names":["isObject"],"sources":["../src/interfaces.ts","../src/errors.ts","../src/manifest.ts","../src/query.ts","../src/client.ts"],"sourcesContent":["/**\n * Contracts shared by the client core (TS1) and the cache layer (TS2).\n * Fixed in TS0 (plan interface I3): change them only through the plan.\n */\n\n/** A value or a promise of it. */\nexport type MaybePromise<T> = T | Promise<T>;\n\n/** What a request does, as classified by the client. */\nexport type Op =\n | \"manifest\"\n | \"list\"\n | \"record\"\n | \"filters\"\n | \"stats\"\n | \"predict\"\n | \"revisions\"\n | \"create\"\n | \"update\"\n | \"delete\"\n | \"bulk_update\"\n | \"bulk_delete\"\n | \"clone\"\n | \"draft\"\n | \"publish\"\n | \"restore\"\n | \"events\";\n\n/**\n * One stored `200` response. Times are epoch milliseconds (`Date.now()`).\n * Structured-clone safe, so IndexedDB can store it as is.\n */\nexport interface CacheEntry {\n readonly status: number;\n readonly headers: ReadonlyArray<readonly [string, string]>;\n /** JSON text; the SDK only caches JSON. */\n readonly body: string;\n readonly storedAt: number;\n /** `<= storedAt` means \"always revalidate\". */\n readonly freshUntil: number;\n /** End of the stale-while-revalidate window (`>= freshUntil`). */\n readonly staleUntil: number;\n readonly etag?: string;\n}\n\n/**\n * Cache backend. Keys are opaque, slash-separated strings built by\n * `./cache`'s `cacheKey`\n * (`v1/{resource}/{kind}/{subject}/{apiVersion}/{scope}/{query}`, with `_`\n * when there is no apiVersion).\n * `ttlMs` is how long the backend may keep the entry (undefined = backend\n * default); freshness lives in `CacheEntry`. `clear(prefix)` removes every\n * key starting with `prefix`; `clear()` removes everything the store owns.\n * Methods may be sync or async. They must not reject for a missing key\n * (`get` resolves `undefined`), and a failing backend must not fail the\n * request: the cache layer swallows store errors and treats them as a miss.\n */\nexport interface CacheStore {\n get(key: string): MaybePromise<CacheEntry | undefined>;\n set(key: string, entry: CacheEntry, ttlMs?: number): MaybePromise<void>;\n delete(key: string): MaybePromise<void>;\n clear(prefix?: string): MaybePromise<void>;\n}\n\n/**\n * What the client knows about a request that a bare `Request` does not. The\n * client builds it for every call; middleware read it, so they never parse\n * URLs or read Authorization.\n */\nexport interface RequestContext {\n /** The request about to be sent; replace it by passing a new context to `next`. */\n readonly request: Request;\n /** Manifest name; `undefined` for the manifest document itself. */\n readonly resource: string | undefined;\n readonly op: Op;\n /** The record the request targets, when it targets one. */\n readonly recordId: number | undefined;\n /**\n * \"anon\", or the first 32 hex characters of the SHA-256 of the\n * Authorization credential actually sent.\n */\n readonly scope: string;\n /**\n * The resource's `api_version` from the manifest, or `null` when it has\n * none. Part of the cache key, so versions never share entries (the cache\n * layer renders `null` as `_`).\n */\n readonly apiVersion: string | null;\n readonly signal: AbortSignal | undefined;\n}\n\n/** Calls the next middleware, or the network when none is left. */\nexport type Next = (ctx: RequestContext) => Promise<Response>;\n\n/**\n * Onion middleware. In `chain = [a, b]`, `a` is outermost: the request runs\n * a -> b -> fetch and the response returns fetch -> b -> a. A middleware may\n * replace `ctx.request` (pass `{ ...ctx, request }` to `next`), return\n * without calling `next` (short-circuit, e.g. a fresh cache hit), or replace\n * the response (e.g. a `304` rebuilt from the cache). It must not consume\n * `response.body` unless it returns a different `Response`; use\n * `response.clone()` to read it.\n */\nexport type Middleware = (ctx: RequestContext, next: Next) => Promise<Response>;\n\n/**\n * Returns the bearer token, or `null`/`undefined` for an anonymous call.\n * `refresh: true` is passed once after a `401`, to force a new token.\n */\nexport type TokenProvider = (opts: {\n readonly refresh: boolean;\n}) => MaybePromise<string | null | undefined>;\n\n/** One record-mutation event from `GET {basePath}/events` (the server's event envelope). */\nexport interface CrudEvent {\n /** The server's event label (e.g. \"hero\"), not the manifest name. */\n readonly resource: string;\n readonly recordId: number;\n readonly action: \"create\" | \"update\" | \"delete\" | \"restore\";\n /** The read view of the record after the change. */\n readonly snapshot: Readonly<Record<string, unknown>>;\n /** ISO 8601, UTC. */\n readonly timestamp: string;\n}\n\n/**\n * Folds `chain` (outermost first) around `terminal`, usually the network\n * `fetch`, into one `Next`. Each middleware's `next` is the rest of the\n * chain; an empty chain is `terminal`. A throwing middleware yields a\n * rejected promise.\n */\nexport function composeMiddleware(\n chain: readonly Middleware[],\n terminal: Next,\n): Next {\n const dispatch = async (\n index: number,\n ctx: RequestContext,\n ): Promise<Response> => {\n const middleware = chain[index];\n if (middleware === undefined) {\n return terminal(ctx);\n }\n return middleware(ctx, (next) => dispatch(index + 1, next));\n };\n return (ctx) => dispatch(0, ctx);\n}\n","/**\n * Error hierarchy: client-side errors and RFC 9457 problem details (ADR-0004).\n * Mirrors the Python SDK class for class.\n */\n\n/** Base class of every error this package throws on purpose. */\nexport class CrudError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\n/** The call was refused before any request was sent. */\nexport class ClientError extends CrudError {}\n\n/** The resource does not support the operation (manifest capability or path missing). */\nexport class CapabilityError extends ClientError {}\n\n/** A filter, sort or paging argument is not valid for the resource. */\nexport class InvalidQueryError extends ClientError {}\n\n/** The discovery document or the manifest is missing, unusable or of an unknown version. */\nexport class ManifestError extends ClientError {}\n\n/** The manifest lists no such resource for this caller. */\nexport class UnknownResourceError extends ClientError {}\n\n/** A successful response whose body is not the JSON the client expects; `cause` holds the parse error. */\nexport class ResponseError extends CrudError {}\n\n/** The request never produced a response; `cause` holds the transport error. */\nexport class ConnectionFailed extends CrudError {}\n\n/** One normalized validation error (`422`). */\nexport interface ProblemDetail {\n readonly loc: readonly (string | number)[];\n readonly msg: string;\n readonly type: string;\n}\n\n/** Members of a {@link ProblemError}. */\nexport interface ProblemInit {\n readonly status: number;\n readonly title: string;\n readonly detail?: string | undefined;\n readonly type?: string | undefined;\n readonly instance?: string | undefined;\n readonly errors?: readonly ProblemDetail[] | undefined;\n readonly headers?: Headers | undefined;\n readonly response?: Response | undefined;\n}\n\nconst NO_TYPE = \"about:blank\";\n\n/** An error response, as RFC 9457 problem details. */\nexport class ProblemError extends CrudError {\n readonly status: number;\n readonly title: string;\n readonly detail: string | undefined;\n readonly type: string;\n readonly instance: string | undefined;\n readonly errors: readonly ProblemDetail[];\n readonly headers: Headers;\n readonly response: Response | undefined;\n\n constructor(init: ProblemInit) {\n const errors = init.errors ?? [];\n let message = `${init.status} ${init.title}`;\n if (init.detail) {\n message += `: ${init.detail}`;\n } else if (errors.length > 0) {\n message += `: ${errors.map((e) => `${e.loc.join(\".\")}: ${e.msg}`).join(\"; \")}`;\n }\n super(message);\n this.status = init.status;\n this.title = init.title;\n this.detail = init.detail;\n this.type = init.type ?? NO_TYPE;\n this.instance = init.instance;\n this.errors = errors;\n this.headers = init.headers ?? new Headers();\n this.response = init.response;\n }\n}\n\n/** 400. */\nexport class BadRequest extends ProblemError {}\n\n/** 401; `wwwAuthenticate` keeps the challenge. */\nexport class Unauthorized extends ProblemError {\n get wwwAuthenticate(): string | undefined {\n return this.headers.get(\"www-authenticate\") ?? undefined;\n }\n}\n\n/** 403. */\nexport class Forbidden extends ProblemError {}\n\n/** 404. */\nexport class NotFound extends ProblemError {}\n\n/** 412: a stale `If-Match`. */\nexport class PreconditionFailed extends ProblemError {}\n\n/** 422; `errors` holds normalized `{loc, msg, type}` entries. */\nexport class ValidationFailed extends ProblemError {}\n\n/** 423. */\nexport class Locked extends ProblemError {}\n\n/** 429; `retryAfter` is the `Retry-After` header in seconds, when it is a number. */\nexport class RateLimited extends ProblemError {\n get retryAfter(): number | undefined {\n const raw = this.headers.get(\"retry-after\");\n if (raw === null || raw.trim() === \"\") {\n return undefined;\n }\n const seconds = Number(raw);\n return Number.isNaN(seconds) ? undefined : seconds;\n }\n}\n\n/** 5xx. */\nexport class ServerError extends ProblemError {}\n\nconst BY_STATUS: ReadonlyMap<number, typeof ProblemError> = new Map([\n [400, BadRequest],\n [401, Unauthorized],\n [403, Forbidden],\n [404, NotFound],\n [412, PreconditionFailed],\n [422, ValidationFailed],\n [423, Locked],\n [429, RateLimited],\n]);\n\n// Python's `http.HTTPStatus` phrases, so both SDKs synthesize the same title.\nconst PHRASES: ReadonlyMap<number, string> = new Map([\n [100, \"Continue\"],\n [101, \"Switching Protocols\"],\n [102, \"Processing\"],\n [103, \"Early Hints\"],\n [200, \"OK\"],\n [201, \"Created\"],\n [202, \"Accepted\"],\n [203, \"Non-Authoritative Information\"],\n [204, \"No Content\"],\n [205, \"Reset Content\"],\n [206, \"Partial Content\"],\n [207, \"Multi-Status\"],\n [208, \"Already Reported\"],\n [226, \"IM Used\"],\n [300, \"Multiple Choices\"],\n [301, \"Moved Permanently\"],\n [302, \"Found\"],\n [303, \"See Other\"],\n [304, \"Not Modified\"],\n [305, \"Use Proxy\"],\n [307, \"Temporary Redirect\"],\n [308, \"Permanent Redirect\"],\n [400, \"Bad Request\"],\n [401, \"Unauthorized\"],\n [402, \"Payment Required\"],\n [403, \"Forbidden\"],\n [404, \"Not Found\"],\n [405, \"Method Not Allowed\"],\n [406, \"Not Acceptable\"],\n [407, \"Proxy Authentication Required\"],\n [408, \"Request Timeout\"],\n [409, \"Conflict\"],\n [410, \"Gone\"],\n [411, \"Length Required\"],\n [412, \"Precondition Failed\"],\n [413, \"Content Too Large\"],\n [414, \"URI Too Long\"],\n [415, \"Unsupported Media Type\"],\n [416, \"Range Not Satisfiable\"],\n [417, \"Expectation Failed\"],\n [418, \"I'm a Teapot\"],\n [421, \"Misdirected Request\"],\n [422, \"Unprocessable Content\"],\n [423, \"Locked\"],\n [424, \"Failed Dependency\"],\n [425, \"Too Early\"],\n [426, \"Upgrade Required\"],\n [428, \"Precondition Required\"],\n [429, \"Too Many Requests\"],\n [431, \"Request Header Fields Too Large\"],\n [451, \"Unavailable For Legal Reasons\"],\n [500, \"Internal Server Error\"],\n [501, \"Not Implemented\"],\n [502, \"Bad Gateway\"],\n [503, \"Service Unavailable\"],\n [504, \"Gateway Timeout\"],\n [505, \"HTTP Version Not Supported\"],\n [506, \"Variant Also Negotiates\"],\n [507, \"Insufficient Storage\"],\n [508, \"Loop Detected\"],\n [510, \"Not Extended\"],\n [511, \"Network Authentication Required\"],\n]);\n\ntype Obj = Record<string, unknown>;\n\nconst isObject = (value: unknown): value is Obj =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction normalizeErrors(items: readonly unknown[]): ProblemDetail[] {\n return items.map((item) => {\n if (isObject(item)) {\n return {\n loc: Array.isArray(item[\"loc\"])\n ? (item[\"loc\"] as (string | number)[])\n : [],\n msg: String(item[\"msg\"] ?? \"\"),\n type: String(item[\"type\"] ?? \"\"),\n };\n }\n return { loc: [], msg: String(item), type: \"\" };\n });\n}\n\n/**\n * Builds the matching `ProblemError` subclass from an error response. A body\n * that is not a JSON object yields a synthesized problem from the status\n * phrase. Reads a clone, so `response.body` stays readable.\n */\nexport async function problemFromResponse(\n response: Response,\n): Promise<ProblemError> {\n const status = response.status;\n const phrase = PHRASES.get(status) ?? \"Error\";\n let parsed: unknown;\n try {\n parsed = JSON.parse(await response.clone().text());\n } catch {\n parsed = undefined;\n }\n const body: Obj = isObject(parsed) ? parsed : {};\n const rawDetail = body[\"detail\"];\n const rawErrors = Array.isArray(rawDetail) ? rawDetail : body[\"errors\"];\n const Cls =\n BY_STATUS.get(status) ?? (status >= 500 ? ServerError : ProblemError);\n const instance = body[\"instance\"];\n return new Cls({\n status,\n title: String(body[\"title\"] || phrase),\n detail: typeof rawDetail === \"string\" ? rawDetail : undefined,\n type: String(body[\"type\"] || NO_TYPE),\n instance: typeof instance === \"string\" ? instance : undefined,\n errors: Array.isArray(rawErrors) ? normalizeErrors(rawErrors) : [],\n headers: response.headers,\n response,\n });\n}\n","/**\n * Typed models of the CRUD manifest (v1) and discovery via the api-catalog.\n * Members keep their wire names (`skip_param`, `max_age`, ...). Members this\n * version does not know are ignored, as the manifest spec requires.\n */\nimport { ManifestError } from \"./errors.ts\";\n\nexport const PROFILE = \"https://craftainer.github.io/schemas/crud-manifest/v1\";\nexport const CATALOG_PATH = \"/.well-known/api-catalog\";\n\n/** A JSON object. */\nexport type JsonObject = Record<string, unknown>;\n\n/** One filterable and sortable field. */\nexport interface FieldSpec {\n readonly name: string;\n readonly value_type: string;\n readonly filter_ops: readonly string[];\n readonly sortable: boolean;\n readonly choices: readonly string[] | null;\n readonly numeric: boolean;\n readonly categorical: boolean;\n readonly read_only: boolean;\n readonly required: boolean;\n}\n\n/** Offset paging parameters and bounds. */\nexport interface Pagination {\n readonly style: string;\n readonly skip_param: string;\n readonly limit_param: string;\n readonly sort_param: string;\n readonly default_limit: number;\n readonly max_limit: number;\n readonly total: boolean;\n}\n\n/** The SSE stream of a resource. */\nexport interface EventsSpec {\n readonly transport: string;\n readonly path: string;\n /** The server-side event label (not the manifest name). */\n readonly resource: string;\n readonly resume_param: string;\n readonly replay: string;\n readonly keepalive_seconds: number;\n readonly actions: readonly string[];\n}\n\n/** What the resource supports. */\nexport interface Capabilities {\n readonly bulk_update: boolean;\n readonly bulk_delete: boolean;\n readonly clone: boolean;\n readonly draft_publish: boolean;\n readonly archive_restore: boolean;\n readonly revisions: boolean;\n readonly events: EventsSpec | null;\n readonly stats: boolean;\n readonly predict: boolean;\n readonly conditional_requests: boolean;\n readonly owner_scoped: boolean;\n readonly schedulable: boolean;\n}\n\n/** Authentication scheme and roles. */\nexport interface AuthSpec {\n readonly scheme: string;\n readonly oidc_discovery_url: string | null;\n readonly public_read: boolean;\n readonly read_roles: readonly string[];\n readonly write_roles: readonly string[];\n readonly delete_roles: readonly string[];\n}\n\n/** The manifest `cache` hints of a resource. */\nexport interface CacheHints {\n readonly etag: boolean;\n readonly max_age: number;\n readonly stats_ttl: number | null;\n readonly stale_while_revalidate: number;\n readonly list_etag: string | null;\n readonly record_etag: string | null;\n readonly revalidate_only: boolean;\n}\n\n/** JSON Schemas of the record views (plain objects). */\nexport interface Schemas {\n readonly read: JsonObject;\n readonly create: JsonObject;\n readonly update: JsonObject;\n readonly draft: JsonObject | null;\n}\n\n/** One resource (`name` + `api_version`). */\nexport interface Resource {\n readonly name: string;\n readonly title: string;\n readonly api_version: string;\n readonly base_path: string;\n readonly formats: Readonly<Record<string, string>>;\n readonly id_field: string;\n readonly schemas: Schemas;\n readonly fields: readonly FieldSpec[];\n readonly pagination: Pagination;\n readonly capabilities: Capabilities;\n readonly paths: Readonly<Record<string, string>>;\n readonly bulk: { readonly max_matched: number };\n readonly auth: AuthSpec;\n readonly cache: CacheHints;\n}\n\n/** The manifest document, as filtered to the caller. */\nexport interface Manifest {\n readonly manifest_version: string;\n readonly service: { readonly name: string; readonly version: string };\n readonly resources: readonly Resource[];\n}\n\nconst isObject = (value: unknown): value is JsonObject =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction bad(where: string, key: string, what: string): never {\n throw new ManifestError(`${where}.${key}: ${what}`);\n}\n\nfunction str(obj: JsonObject, key: string, where: string): string {\n const value = obj[key];\n return typeof value === \"string\"\n ? value\n : bad(where, key, \"missing or not a string\");\n}\n\nfunction bool(obj: JsonObject, key: string, where: string): boolean {\n const value = obj[key];\n return typeof value === \"boolean\"\n ? value\n : bad(where, key, \"missing or not a boolean\");\n}\n\nfunction num(obj: JsonObject, key: string, where: string): number {\n const value = obj[key];\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : bad(where, key, \"missing or not a number\");\n}\n\nfunction int(obj: JsonObject, key: string, where: string): number {\n const value = num(obj, key, where);\n return Number.isInteger(value) ? value : bad(where, key, \"not an integer\");\n}\n\nfunction obj(parent: JsonObject, key: string, where: string): JsonObject {\n const value = parent[key];\n return isObject(value) ? value : bad(where, key, \"missing or not an object\");\n}\n\nfunction list(\n parent: JsonObject,\n key: string,\n where: string,\n): readonly unknown[] {\n const value = parent[key];\n return Array.isArray(value)\n ? value\n : bad(where, key, \"missing or not a list\");\n}\n\nfunction strs(\n parent: JsonObject,\n key: string,\n where: string,\n): readonly string[] {\n const items = list(parent, key, where);\n return items.every((item) => typeof item === \"string\")\n ? (items as readonly string[])\n : bad(where, key, \"expected a list of strings\");\n}\n\n/** A member that may be absent or `null`. */\nfunction opt<T>(\n parent: JsonObject,\n key: string,\n where: string,\n read: (parent: JsonObject, key: string, where: string) => T,\n): T | null {\n return parent[key] === undefined || parent[key] === null\n ? null\n : read(parent, key, where);\n}\n\nfunction stringMap(\n parent: JsonObject,\n key: string,\n where: string,\n): Record<string, string> {\n const out: Record<string, string> = {};\n for (const [k, v] of Object.entries(obj(parent, key, where))) {\n if (typeof v === \"string\") {\n out[k] = v;\n }\n }\n return out;\n}\n\nfunction objects(parent: JsonObject, key: string, where: string): JsonObject[] {\n return list(parent, key, where).map((item, i) =>\n isObject(item) ? item : bad(`${where}.${key}`, `[${i}]`, \"not an object\"),\n );\n}\n\nfunction parseField(o: JsonObject, w: string): FieldSpec {\n return {\n name: str(o, \"name\", w),\n value_type: str(o, \"value_type\", w),\n filter_ops: strs(o, \"filter_ops\", w),\n sortable: bool(o, \"sortable\", w),\n choices: opt(o, \"choices\", w, strs),\n numeric: bool(o, \"numeric\", w),\n categorical: bool(o, \"categorical\", w),\n read_only: bool(o, \"read_only\", w),\n required: bool(o, \"required\", w),\n };\n}\n\nfunction parseEvents(o: JsonObject, w: string): EventsSpec {\n return {\n transport: str(o, \"transport\", w),\n path: str(o, \"path\", w),\n resource: str(o, \"resource\", w),\n resume_param: str(o, \"resume_param\", w),\n replay: str(o, \"replay\", w),\n keepalive_seconds: num(o, \"keepalive_seconds\", w),\n actions: strs(o, \"actions\", w),\n };\n}\n\nfunction parseCapabilities(o: JsonObject, w: string): Capabilities {\n return {\n bulk_update: bool(o, \"bulk_update\", w),\n bulk_delete: bool(o, \"bulk_delete\", w),\n clone: bool(o, \"clone\", w),\n draft_publish: bool(o, \"draft_publish\", w),\n archive_restore: bool(o, \"archive_restore\", w),\n revisions: bool(o, \"revisions\", w),\n events: opt(o, \"events\", w, (p, k, ww) =>\n parseEvents(obj(p, k, ww), `${ww}.${k}`),\n ),\n stats: bool(o, \"stats\", w),\n predict: bool(o, \"predict\", w),\n conditional_requests: bool(o, \"conditional_requests\", w),\n owner_scoped: bool(o, \"owner_scoped\", w),\n schedulable: bool(o, \"schedulable\", w),\n };\n}\n\nfunction parseResource(o: JsonObject, w: string): Resource {\n const schemas = obj(o, \"schemas\", w);\n const pagination = obj(o, \"pagination\", w);\n const auth = obj(o, \"auth\", w);\n const cache = obj(o, \"cache\", w);\n const sw = `${w}.schemas`;\n return {\n name: str(o, \"name\", w),\n title: str(o, \"title\", w),\n api_version: str(o, \"api_version\", w),\n base_path: str(o, \"base_path\", w),\n formats: stringMap(o, \"formats\", w),\n id_field: str(o, \"id_field\", w),\n schemas: {\n read: obj(schemas, \"read\", sw),\n create: obj(schemas, \"create\", sw),\n update: obj(schemas, \"update\", sw),\n draft: opt(schemas, \"draft\", sw, obj),\n },\n fields: objects(o, \"fields\", w).map((f, i) =>\n parseField(f, `${w}.fields[${i}]`),\n ),\n pagination: {\n style: str(pagination, \"style\", w),\n skip_param: str(pagination, \"skip_param\", w),\n limit_param: str(pagination, \"limit_param\", w),\n sort_param: str(pagination, \"sort_param\", w),\n default_limit: int(pagination, \"default_limit\", w),\n max_limit: int(pagination, \"max_limit\", w),\n total: bool(pagination, \"total\", w),\n },\n capabilities: parseCapabilities(\n obj(o, \"capabilities\", w),\n `${w}.capabilities`,\n ),\n paths: stringMap(o, \"paths\", w),\n bulk: { max_matched: int(obj(o, \"bulk\", w), \"max_matched\", `${w}.bulk`) },\n auth: {\n scheme: str(auth, \"scheme\", w),\n oidc_discovery_url: opt(auth, \"oidc_discovery_url\", w, str),\n public_read: bool(auth, \"public_read\", w),\n read_roles: strs(auth, \"read_roles\", w),\n write_roles: strs(auth, \"write_roles\", w),\n delete_roles: strs(auth, \"delete_roles\", w),\n },\n cache: {\n etag: bool(cache, \"etag\", w),\n max_age: int(cache, \"max_age\", w),\n stats_ttl: opt(cache, \"stats_ttl\", w, int),\n stale_while_revalidate: int(cache, \"stale_while_revalidate\", w),\n list_etag: opt(cache, \"list_etag\", w, str),\n record_etag: opt(cache, \"record_etag\", w, str),\n revalidate_only: bool(cache, \"revalidate_only\", w),\n },\n };\n}\n\n/** Parses a manifest document; unknown members are ignored, unknown versions refused. */\nexport function parseManifest(document: unknown): Manifest {\n if (!isObject(document)) {\n throw new ManifestError(\"the manifest is not a JSON object\");\n }\n const version = str(document, \"manifest_version\", \"manifest\");\n if (version !== \"1\") {\n throw new ManifestError(`unsupported manifest_version \"${version}\"`);\n }\n const service = obj(document, \"service\", \"manifest\");\n return {\n manifest_version: version,\n service: {\n name: str(service, \"name\", \"manifest.service\"),\n version: str(service, \"version\", \"manifest.service\"),\n },\n resources: objects(document, \"resources\", \"manifest\").map((r, i) =>\n parseResource(r, `resources[${i}]`),\n ),\n };\n}\n\n/**\n * The resource called `name`: the one with `apiVersion` when given, else the\n * highest `api_version` (`v2` beats `v1`); `undefined` when there is none.\n */\nexport function findResource(\n manifest: Manifest,\n name: string,\n apiVersion?: string,\n): Resource | undefined {\n const rank = (r: Resource): number =>\n Number.parseInt(r.api_version.slice(1), 10) || 0;\n let best: Resource | undefined;\n for (const r of manifest.resources) {\n if (\n r.name === name &&\n (apiVersion === undefined || r.api_version === apiVersion)\n ) {\n if (best === undefined || rank(r) > rank(best)) {\n best = r;\n }\n }\n }\n return best;\n}\n\n/** The absolute manifest URL: the first `describedby` link with the manifest profile. */\nexport function manifestUrlFromCatalog(\n linkset: unknown,\n catalogUrl: string,\n): string {\n const entries = isObject(linkset) ? linkset[\"linkset\"] : undefined;\n for (const entry of Array.isArray(entries) ? entries : []) {\n const links = isObject(entry) ? entry[\"describedby\"] : undefined;\n for (const link of Array.isArray(links) ? links : []) {\n if (\n isObject(link) &&\n link[\"profile\"] === PROFILE &&\n typeof link[\"href\"] === \"string\"\n ) {\n const url = new URL(link[\"href\"], catalogUrl);\n if (url.origin !== new URL(catalogUrl).origin) {\n // The client sends its bearer token to this URL: stay on the server's origin.\n throw new ManifestError(\n `the api-catalog points at another origin (${url.origin}); pass manifestUrl to use it`,\n );\n }\n return url.href;\n }\n }\n }\n throw new ManifestError(\n `the api-catalog has no describedby link with profile ${PROFILE}`,\n );\n}\n\n/** Fetches a JSON document; `catalog` marks the api-catalog request (kept out of the manifest cache). */\nexport type GetJson = (url: string, catalog: boolean) => Promise<unknown>;\n\n/**\n * Loads and parses the manifest, via api-catalog discovery from `baseUrl` or\n * a direct `manifestUrl`.\n */\nexport async function loadManifest(\n getJson: GetJson,\n baseUrl: string,\n manifestUrl?: string,\n): Promise<Manifest> {\n let url = manifestUrl;\n if (url === undefined) {\n const catalogUrl = new URL(CATALOG_PATH, baseUrl).href;\n url = manifestUrlFromCatalog(await getJson(catalogUrl, true), catalogUrl);\n }\n return parseManifest(await getJson(url, false));\n}\n","/**\n * Query-string builder with `crud_query` semantics, validated against the\n * manifest fields. Produces the same bytes as the Python SDK.\n */\nimport { InvalidQueryError } from \"./errors.ts\";\nimport type { FieldSpec } from \"./manifest.ts\";\n\nconst MAX_REGEX_LENGTH = 200;\n\n/** The part of a manifest field the builder needs. */\nexport type QueryField = Pick<\n FieldSpec,\n \"name\" | \"value_type\" | \"filter_ops\" | \"sortable\" | \"choices\"\n>;\n\n/** Filter arguments: `field` (equality, emitted bare) or `field__op` -> value. */\nexport type Filters = Readonly<Record<string, unknown>>;\n\n/** `\"name,-other\"` or `[\"name\", \"-other\"]`. */\nexport type Sort = string | readonly string[];\n\n/** Everything {@link buildQuery} takes beside the fields. */\nexport interface QueryParams {\n readonly recordId?: number | undefined;\n readonly filters?: Filters | undefined;\n readonly sort?: Sort | undefined;\n readonly skip?: number | undefined;\n readonly limit?: number | undefined;\n readonly maxLimit?: number | undefined;\n readonly skipParam?: string | undefined;\n readonly limitParam?: string | undefined;\n readonly sortParam?: string | undefined;\n readonly includeArchived?: boolean | undefined;\n readonly includeUnpublished?: boolean | undefined;\n}\n\n/** Percent-encodes everything but the RFC 3986 unreserved characters `A-Za-z0-9-._~`. */\nexport function quote(text: string): string {\n return encodeURIComponent(text).replace(\n /[!'()*]/g,\n (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,\n );\n}\n\n/** Joins already-stringified pairs, encoding keys and values. */\nexport function encodeParams(\n pairs: readonly (readonly [string, string])[],\n): string {\n return pairs.map(([k, v]) => `${quote(k)}=${quote(v)}`).join(\"&\");\n}\n\nfunction formatDatetime(value: Date): string | undefined {\n if (Number.isNaN(value.getTime())) {\n return undefined;\n }\n const iso = value.toISOString();\n if (iso.length !== 24) {\n return undefined; // expanded years (outside 0000-9999)\n }\n const millis = iso.slice(20, 23).replace(/0+$/, \"\");\n return millis === \"\"\n ? `${iso.slice(0, 19)}Z`\n : `${iso.slice(0, 19)}.${millis}Z`;\n}\n\nfunction formatDate(value: string): string | undefined {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) {\n return undefined;\n }\n const parsed = new Date(`${value}T00:00:00Z`);\n return Number.isNaN(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value\n ? undefined\n : value;\n}\n\nfunction scalarText(kind: string, value: unknown): string | undefined {\n switch (kind) {\n case \"integer\":\n return typeof value === \"number\" && Number.isSafeInteger(value)\n ? String(value)\n : undefined;\n case \"number\":\n return typeof value === \"number\" && Number.isFinite(value)\n ? String(value)\n : undefined;\n case \"boolean\":\n return typeof value === \"boolean\" ? String(value) : undefined;\n case \"date\":\n return typeof value === \"string\" ? formatDate(value) : undefined;\n case \"datetime\":\n return value instanceof Date ? formatDatetime(value) : undefined;\n default:\n return typeof value === \"string\" ? value : undefined;\n }\n}\n\n/**\n * Wire form of one value for `field`; throws `InvalidQueryError` on a type\n * mismatch. Dates are `YYYY-MM-DD` strings, datetimes `Date`s (UTC, with\n * millisecond precision, trailing zeros trimmed).\n */\nexport function formatScalar(field: QueryField, value: unknown): string {\n const text = scalarText(field.value_type, value);\n if (text === undefined) {\n throw new InvalidQueryError(\n `field \"${field.name}\" (${field.value_type}) cannot take ${String(value)}`,\n );\n }\n if (\n field.value_type === \"enum\" &&\n field.choices !== null &&\n !field.choices.includes(text)\n ) {\n throw new InvalidQueryError(\n `field \"${field.name}\" accepts only ${JSON.stringify(field.choices)}, not \"${text}\"`,\n );\n }\n return text;\n}\n\nfunction filterPair(\n field: QueryField,\n op: string,\n value: unknown,\n): [string, string] {\n const key = op === \"eq\" ? field.name : `${field.name}__${op}`;\n if (op === \"in\") {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidQueryError(`\"${key}\" takes a non-empty array`);\n }\n const parts = value.map((item: unknown) => formatScalar(field, item));\n if (parts.some((part) => part.includes(\",\"))) {\n throw new InvalidQueryError(\n `\"${key}\": a value contains a comma, which separates the list`,\n );\n }\n return [key, parts.map(quote).join(\",\")];\n }\n const text = formatScalar(field, value);\n if (op === \"regex\" && [...text].length > MAX_REGEX_LENGTH) {\n throw new InvalidQueryError(\n `\"${key}\": a regex is limited to ${MAX_REGEX_LENGTH} characters`,\n );\n }\n return [key, quote(text)];\n}\n\nconst compare = (a: string, b: string): number => (a < b ? -1 : a > b ? 1 : 0);\n\nfunction filterPairs(\n fields: ReadonlyMap<string, QueryField>,\n filters: Filters,\n): [string, string][] {\n const parsed = new Map<\n string,\n { name: string; op: string; pair: [string, string] }\n >();\n for (const [rawKey, value] of Object.entries(filters)) {\n const at = rawKey.lastIndexOf(\"__\");\n const name = at < 0 ? rawKey : rawKey.slice(0, at);\n const op = at < 0 ? \"eq\" : rawKey.slice(at + 2);\n const field = fields.get(name);\n if (field === undefined) {\n throw new InvalidQueryError(`unknown filter field \"${name}\"`);\n }\n if (!field.filter_ops.includes(op)) {\n throw new InvalidQueryError(\n `field \"${name}\" does not support the \"${op}\" operator`,\n );\n }\n if (name === \"id\" && op === \"eq\") {\n throw new InvalidQueryError(\n \"filter on id with recordId, not an equality filter\",\n );\n }\n const id = `${name}\\u0000${op}`;\n if (parsed.has(id)) {\n throw new InvalidQueryError(`filter \"${name}\" \"${op}\" given twice`);\n }\n parsed.set(id, { name, op, pair: filterPair(field, op, value) });\n }\n return [...parsed.values()]\n .sort((a, b) => compare(a.name, b.name) || compare(a.op, b.op))\n .map((entry) => entry.pair);\n}\n\nfunction sortValue(\n fields: ReadonlyMap<string, QueryField>,\n sort: Sort,\n): string {\n const parts = typeof sort === \"string\" ? sort.split(\",\") : sort;\n const out = parts.map((part) => {\n const name = part.startsWith(\"-\") ? part.slice(1) : part;\n const field = fields.get(name);\n if (field === undefined || !field.sortable) {\n throw new InvalidQueryError(`cannot sort by \"${name}\"`);\n }\n return quote(part);\n });\n if (out.length === 0) {\n throw new InvalidQueryError(\"sort is empty\");\n }\n return out.join(\",\");\n}\n\nfunction intArg(name: string, value: unknown, minimum: number): string {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n value < minimum\n ) {\n throw new InvalidQueryError(`${name} must be an integer >= ${minimum}`);\n }\n return String(value);\n}\n\n/**\n * The query string (no leading `?`) for a list, get or bulk call. Order of\n * parameters: `id`, filters sorted by (field, operator), sort, skip, limit,\n * `include_archived`, `include_unpublished`. The sort/skip/limit names are\n * `sortParam`/`skipParam`/`limitParam` (the manifest's `pagination`); the\n * `id` parameter is always `id`. Flags are emitted whenever they are not\n * `undefined`.\n */\nexport function buildQuery(\n fields: readonly QueryField[],\n params: QueryParams = {},\n): string {\n const byName = new Map(fields.map((f) => [f.name, f]));\n const parts: string[] = [];\n if (params.recordId !== undefined) {\n parts.push(`id=${intArg(\"recordId\", params.recordId, 0)}`);\n }\n for (const [key, value] of filterPairs(byName, params.filters ?? {})) {\n parts.push(`${quote(key)}=${value}`); // values arrive encoded; `in` keeps its commas\n }\n if (params.sort !== undefined) {\n parts.push(\n `${quote(params.sortParam ?? \"sort\")}=${sortValue(byName, params.sort)}`,\n );\n }\n if (params.skip !== undefined) {\n parts.push(\n `${quote(params.skipParam ?? \"skip\")}=${intArg(\"skip\", params.skip, 0)}`,\n );\n }\n if (params.limit !== undefined) {\n const text = intArg(\"limit\", params.limit, 1);\n if (params.maxLimit !== undefined && params.limit > params.maxLimit) {\n throw new InvalidQueryError(\n `limit ${params.limit} exceeds the server maximum ${params.maxLimit}`,\n );\n }\n parts.push(`${quote(params.limitParam ?? \"limit\")}=${text}`);\n }\n if (params.includeArchived !== undefined) {\n parts.push(`include_archived=${params.includeArchived}`);\n }\n if (params.includeUnpublished !== undefined) {\n parts.push(`include_unpublished=${params.includeUnpublished}`);\n }\n return parts.join(\"&\");\n}\n","/** Fetch client: manifest-driven resource handles over a middleware chain. */\nimport { cacheScope } from \"./auth.ts\";\nimport {\n CapabilityError,\n ConnectionFailed,\n InvalidQueryError,\n ManifestError,\n ResponseError,\n UnknownResourceError,\n problemFromResponse,\n} from \"./errors.ts\";\nimport { composeMiddleware } from \"./interfaces.ts\";\nimport type { Middleware, Op, TokenProvider } from \"./interfaces.ts\";\nimport { findResource, loadManifest } from \"./manifest.ts\";\nimport type { JsonObject, Manifest, Resource } from \"./manifest.ts\";\nimport { buildQuery, encodeParams } from \"./query.ts\";\nimport type { Filters, QueryParams, Sort } from \"./query.ts\";\n\n/** Per-call options. */\nexport interface RequestOptions {\n readonly signal?: AbortSignal | undefined;\n}\n\n/** Options of `list` and `iterAll`. */\nexport interface ListOptions extends RequestOptions {\n readonly filters?: Filters | undefined;\n readonly sort?: Sort | undefined;\n readonly skip?: number | undefined;\n readonly limit?: number | undefined;\n readonly includeArchived?: boolean | undefined;\n readonly includeUnpublished?: boolean | undefined;\n}\n\n/** Options of `update` and `delete`: `ifMatch` is an ETag (`412` when stale). */\nexport interface WriteOptions extends RequestOptions {\n readonly ifMatch?: string | undefined;\n}\n\n/** Options of `stats`. */\nexport interface StatsOptions extends RequestOptions {\n readonly bucket?: string | undefined;\n readonly includeArchived?: boolean | undefined;\n readonly includeUnpublished?: boolean | undefined;\n}\n\n/** Options of `predict`. */\nexport interface PredictOptions extends RequestOptions {\n readonly field?: string | undefined;\n readonly periods?: number | undefined;\n readonly bucket?: string | undefined;\n}\n\n/** Options of `restore`: exactly one of `id` and `filters`. */\nexport interface RestoreOptions extends RequestOptions {\n readonly id?: number | undefined;\n readonly filters?: Filters | undefined;\n}\n\n/** The result of a bulk call. */\nexport interface BulkResult {\n readonly matched: number;\n readonly ids: readonly number[];\n}\n\nexport interface Call {\n readonly method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n readonly url: string;\n readonly op: Op;\n readonly resource: string | undefined;\n readonly recordId: number | undefined;\n readonly apiVersion: string | null;\n readonly json?: unknown;\n readonly headers?: Readonly<Record<string, string>>;\n}\n\n/** What a {@link ResourceClient} needs from its client. */\nexport interface Transport {\n json(call: Call, signal: AbortSignal | undefined): Promise<unknown>;\n none(call: Call, signal: AbortSignal | undefined): Promise<void>;\n}\n\nconst joinUrl = (base: string, path: string): string =>\n new URL(path, base).href;\n\n/** Builds the requests of one resource. */\nclass Plan {\n readonly #baseUrl: string;\n readonly resource: Resource;\n\n constructor(baseUrl: string, resource: Resource) {\n this.#baseUrl = baseUrl;\n this.resource = resource;\n }\n\n #call(\n method: Call[\"method\"],\n op: Op,\n path: string,\n query = \"\",\n extra: {\n recordId?: number | undefined;\n json?: unknown;\n ifMatch?: string | undefined;\n } = {},\n ): Call {\n const url =\n joinUrl(this.#baseUrl, path) + (query === \"\" ? \"\" : `?${query}`);\n return {\n method,\n url,\n op,\n resource: this.resource.name,\n recordId: extra.recordId,\n apiVersion: this.resource.api_version,\n ...(extra.json === undefined ? {} : { json: extra.json }),\n ...(extra.ifMatch === undefined\n ? {}\n : { headers: { \"If-Match\": extra.ifMatch } }),\n };\n }\n\n #query(params: QueryParams = {}): string {\n const paging = this.resource.pagination;\n return buildQuery(this.resource.fields, {\n maxLimit: paging.max_limit,\n skipParam: paging.skip_param,\n limitParam: paging.limit_param,\n sortParam: paging.sort_param,\n ...params,\n });\n }\n\n #subPath(key: string, supported: boolean): string {\n const path = this.resource.paths[key];\n if (!supported || path === undefined) {\n throw new CapabilityError(\n `resource \"${this.resource.name}\" does not support ${key}`,\n );\n }\n return path;\n }\n\n #need(supported: boolean, what: string): void {\n if (!supported) {\n throw new CapabilityError(\n `resource \"${this.resource.name}\" does not support ${what}`,\n );\n }\n }\n\n #bulkFilters(filters: Filters): string {\n if (Object.keys(filters).length === 0) {\n throw new InvalidQueryError(\"a bulk operation needs at least one filter\");\n }\n return this.#query({ filters });\n }\n\n get #base(): string {\n return this.resource.base_path;\n }\n\n eventsUrl(): string {\n const events = this.resource.capabilities.events;\n if (events === null) {\n throw new CapabilityError(\n `resource \"${this.resource.name}\" does not support events`,\n );\n }\n return joinUrl(this.#baseUrl, events.path);\n }\n\n list(o: ListOptions): Call {\n const query = this.#query({\n filters: o.filters,\n sort: o.sort,\n skip: o.skip,\n limit: o.limit,\n includeArchived: o.includeArchived,\n includeUnpublished: o.includeUnpublished,\n });\n return this.#call(\"GET\", \"list\", this.#base, query);\n }\n\n get(id: number): Call {\n return this.#call(\n \"GET\",\n \"record\",\n this.#base,\n this.#query({ recordId: id }),\n {\n recordId: id,\n },\n );\n }\n\n create(data: unknown): Call {\n return this.#call(\"POST\", \"create\", this.#base, \"\", { json: data });\n }\n\n update(id: number, data: unknown, ifMatch: string | undefined): Call {\n return this.#call(\n \"PATCH\",\n \"update\",\n this.#base,\n this.#query({ recordId: id }),\n {\n recordId: id,\n json: data,\n ifMatch,\n },\n );\n }\n\n updateMany(filters: Filters, data: unknown): Call {\n this.#need(this.resource.capabilities.bulk_update, \"bulk_update\");\n return this.#call(\n \"PATCH\",\n \"bulk_update\",\n this.#base,\n this.#bulkFilters(filters),\n {\n json: data,\n },\n );\n }\n\n delete(id: number, ifMatch: string | undefined): Call {\n return this.#call(\n \"DELETE\",\n \"delete\",\n this.#base,\n this.#query({ recordId: id }),\n {\n recordId: id,\n ifMatch,\n },\n );\n }\n\n deleteMany(filters: Filters): Call {\n this.#need(this.resource.capabilities.bulk_delete, \"bulk_delete\");\n return this.#call(\n \"DELETE\",\n \"bulk_delete\",\n this.#base,\n this.#bulkFilters(filters),\n );\n }\n\n restore(id: number | undefined, filters: Filters | undefined): Call {\n const path = this.#subPath(\n \"restore\",\n this.resource.capabilities.archive_restore,\n );\n if ((id === undefined) === (filters === undefined)) {\n throw new InvalidQueryError(\n \"restore takes exactly one of id and filters\",\n );\n }\n const query =\n filters === undefined\n ? this.#query({ recordId: id })\n : this.#bulkFilters(filters);\n return this.#call(\"POST\", \"restore\", path, query, { recordId: id });\n }\n\n stats(o: StatsOptions): Call {\n const path = this.#subPath(\"stats\", this.resource.capabilities.stats);\n const pairs: [string, string][] =\n o.bucket === undefined ? [] : [[\"bucket\", o.bucket]];\n if (o.includeArchived !== undefined) {\n pairs.push([\"include_archived\", String(o.includeArchived)]);\n }\n if (o.includeUnpublished !== undefined) {\n pairs.push([\"include_unpublished\", String(o.includeUnpublished)]);\n }\n return this.#call(\"GET\", \"stats\", path, encodeParams(pairs));\n }\n\n predict(o: PredictOptions): Call {\n const path = this.#subPath(\"predict\", this.resource.capabilities.predict);\n const pairs: [string, string][] = [];\n if (o.field !== undefined) {\n const spec = this.resource.fields.find((f) => f.name === o.field);\n if (spec === undefined || !spec.numeric) {\n throw new InvalidQueryError(\n `cannot predict \"${o.field}\": not a numeric field`,\n );\n }\n pairs.push([\"field\", o.field]);\n }\n if (o.periods !== undefined) {\n if (!Number.isSafeInteger(o.periods) || o.periods < 1) {\n throw new InvalidQueryError(\"periods must be an integer >= 1\");\n }\n pairs.push([\"periods\", String(o.periods)]);\n }\n if (o.bucket !== undefined) {\n pairs.push([\"bucket\", o.bucket]);\n }\n return this.#call(\"GET\", \"predict\", path, encodeParams(pairs));\n }\n\n clone(id: number): Call {\n const path = this.#subPath(\"clone\", this.resource.capabilities.clone);\n return this.#call(\"POST\", \"clone\", path, this.#query({ recordId: id }), {\n recordId: id,\n });\n }\n\n draft(data: unknown): Call {\n const path = this.#subPath(\n \"draft\",\n this.resource.capabilities.draft_publish,\n );\n return this.#call(\"POST\", \"draft\", path, \"\", { json: data });\n }\n\n publish(id: number): Call {\n const path = this.#subPath(\n \"publish\",\n this.resource.capabilities.draft_publish,\n );\n return this.#call(\"POST\", \"publish\", path, this.#query({ recordId: id }), {\n recordId: id,\n });\n }\n\n filters(): Call {\n return this.#call(\"GET\", \"filters\", this.#subPath(\"filters\", true));\n }\n\n revisions(id: number): Call {\n const path = this.#subPath(\n \"revisions\",\n this.resource.capabilities.revisions,\n );\n return this.#call(\"GET\", \"revisions\", path, this.#query({ recordId: id }), {\n recordId: id,\n });\n }\n}\n\n/**\n * Operations on one resource. The type parameters are the record views;\n * `crud-sdk-codegen` writes interfaces to pass for them (they are not\n * checked against the manifest at runtime).\n */\nexport class ResourceClient<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n> {\n /** The manifest entry this handle is bound to. */\n readonly resource: Resource;\n readonly #plan: Plan;\n readonly #transport: Transport;\n\n /** Use `CrudClient.resource`. */\n constructor(baseUrl: string, resource: Resource, transport: Transport) {\n this.resource = resource;\n this.#plan = new Plan(baseUrl, resource);\n this.#transport = transport;\n }\n\n async #one<T>(call: Call, options: RequestOptions): Promise<T> {\n return (await this.#transport.json(call, options.signal)) as T;\n }\n\n /** One page of records. */\n async list(options: ListOptions = {}): Promise<Read[]> {\n return this.#one(this.#plan.list(options), options);\n }\n\n /** Every record, paging with `skip += limit` until a page shorter than `limit`. */\n async *iterAll(\n options: ListOptions = {},\n ): AsyncGenerator<Read, void, undefined> {\n const size = options.limit ?? this.resource.pagination.default_limit;\n let skip = options.skip ?? 0;\n for (;;) {\n const page = await this.list({ ...options, skip, limit: size });\n yield* page;\n if (page.length < size) {\n return;\n }\n skip += size;\n }\n }\n\n /** One record. */\n async get(id: number, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.get(id), options);\n }\n\n /** Creates a record. */\n async create(data: Create, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.create(data), options);\n }\n\n /** Patches one record; `ifMatch` is an ETag (`412` when stale). */\n async update(\n id: number,\n data: Update,\n options: WriteOptions = {},\n ): Promise<Read> {\n return this.#one(this.#plan.update(id, data, options.ifMatch), options);\n }\n\n /** Patches every record matching `filters`. */\n async updateMany(\n filters: Filters,\n data: Update,\n options: RequestOptions = {},\n ): Promise<BulkResult> {\n return this.#one(this.#plan.updateMany(filters, data), options);\n }\n\n /** Deletes one record; `ifMatch` as for `update`. */\n async delete(id: number, options: WriteOptions = {}): Promise<void> {\n await this.#transport.none(\n this.#plan.delete(id, options.ifMatch),\n options.signal,\n );\n }\n\n /** Deletes every record matching `filters`. */\n async deleteMany(\n filters: Filters,\n options: RequestOptions = {},\n ): Promise<BulkResult> {\n return this.#one(this.#plan.deleteMany(filters), options);\n }\n\n /** Restores archived records, by `id` or by `filters`. */\n async restore(options: RestoreOptions): Promise<BulkResult> {\n return this.#one(this.#plan.restore(options.id, options.filters), options);\n }\n\n /** Aggregates over the resource. */\n async stats(options: StatsOptions = {}): Promise<JsonObject> {\n return this.#one(this.#plan.stats(options), options);\n }\n\n /** A forecast. */\n async predict(options: PredictOptions = {}): Promise<JsonObject> {\n return this.#one(this.#plan.predict(options), options);\n }\n\n /** Copies a record; returns the copy. */\n async clone(id: number, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.clone(id), options);\n }\n\n /** Creates a draft (needs `draft_publish`). */\n async createDraft(data: Create, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.draft(data), options);\n }\n\n /** Publishes a draft (needs `draft_publish`). */\n async publish(id: number, options: RequestOptions = {}): Promise<Read> {\n return this.#one(this.#plan.publish(id), options);\n }\n\n /** The server's filter metadata (`kind` instead of `value_type`). */\n async filters(options: RequestOptions = {}): Promise<JsonObject[]> {\n return this.#one(this.#plan.filters(), options);\n }\n\n /** Revisions of one record, newest first. */\n async revisions(\n id: number,\n options: RequestOptions = {},\n ): Promise<JsonObject[]> {\n return this.#one(this.#plan.revisions(id), options);\n }\n\n /** Absolute URL of the resource's SSE stream. */\n eventsUrl(): string {\n return this.#plan.eventsUrl();\n }\n}\n\n/** Options of {@link createClient}. */\nexport interface ClientOptions {\n /** The server origin (or any URL on it). */\n readonly baseUrl: string;\n /** The network `fetch`; defaults to `globalThis.fetch`. */\n readonly fetch?: typeof fetch | undefined;\n /** Returns the bearer token; called again with `refresh: true` once after a `401`. */\n readonly tokenProvider?: TokenProvider | undefined;\n /** Outermost first; see `composeMiddleware`. */\n readonly middleware?: readonly Middleware[] | undefined;\n /** Skips api-catalog discovery. */\n readonly manifestUrl?: string | undefined;\n /**\n * Stable identity of this client in TanStack query keys. Defaults to\n * `baseUrl`; set it when two clients share a `baseUrl` but must not share\n * cached data, and keep it constant across reloads of a persisted cache.\n */\n readonly id?: string | undefined;\n}\n\n/** Discovers the manifest and hands out {@link ResourceClient}s. */\nexport class CrudClient {\n readonly baseUrl: string;\n /** Stable identity in TanStack query keys (`ClientOptions.id`, else `baseUrl`). */\n readonly id: string;\n readonly #fetch: typeof fetch | undefined;\n readonly #tokenProvider: TokenProvider | undefined;\n readonly #middleware: Middleware[];\n readonly #manifestUrl: string | undefined;\n readonly #manifests = new Map<string, Promise<Manifest>>();\n readonly #transport: Transport;\n\n constructor(options: ClientOptions) {\n this.baseUrl = options.baseUrl;\n this.id = options.id ?? options.baseUrl;\n this.#fetch = options.fetch;\n this.#tokenProvider = options.tokenProvider;\n this.#middleware = [...(options.middleware ?? [])];\n this.#manifestUrl = options.manifestUrl;\n this.#transport = {\n json: async (call, signal) => {\n const response = await this.#send(call, signal);\n if (response.status === 204) {\n return undefined;\n }\n try {\n return (await response.json()) as unknown;\n } catch (error) {\n throw new ResponseError(\n `${call.method} ${call.url}: the ${response.status} response body is not valid JSON`,\n { cause: error },\n );\n }\n },\n none: async (call, signal) => {\n await (await this.#send(call, signal)).body?.cancel();\n },\n };\n }\n\n /** Adds middleware after the existing ones (innermost); it sees every later request. */\n use(middleware: Middleware): this {\n this.#middleware.push(middleware);\n return this;\n }\n\n async #token(refresh: boolean): Promise<string | null> {\n // An empty token sends no header, so it is anonymous for the scope too.\n return (await this.#tokenProvider?.({ refresh })) || null;\n }\n\n /** The current bearer token, or `null` when anonymous. */\n token(refresh = false): Promise<string | null> {\n return this.#token(refresh);\n }\n\n /** The cache scope of the current caller (`\"anon\"` or a hash of the token). */\n async scope(): Promise<string> {\n return cacheScope(await this.#token(false));\n }\n\n /** The `{ client, scope }` namespace the `./tanstack` key factory takes. */\n async namespace(): Promise<{\n readonly client: string;\n readonly scope: string;\n }> {\n return { client: this.id, scope: await this.scope() };\n }\n\n async #dispatch(\n call: Call,\n token: string | null,\n signal: AbortSignal | undefined,\n ): Promise<Response> {\n const headers = new Headers({\n Accept: \"application/json\",\n ...call.headers,\n });\n if (token !== null) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n const init: RequestInit = {\n method: call.method,\n headers,\n signal: signal ?? null,\n };\n if (call.json !== undefined) {\n headers.set(\"Content-Type\", \"application/json\");\n init.body = JSON.stringify(call.json);\n }\n const request = new Request(call.url, init);\n const terminal = async (ctx: {\n readonly request: Request;\n }): Promise<Response> => {\n try {\n return await (this.#fetch ?? globalThis.fetch)(ctx.request);\n } catch (error) {\n if (ctx.request.signal.aborted) {\n throw error;\n }\n throw new ConnectionFailed(\n error instanceof Error ? error.message : String(error),\n {\n cause: error,\n },\n );\n }\n };\n return composeMiddleware(\n this.#middleware,\n terminal,\n )({\n request,\n resource: call.resource,\n op: call.op,\n recordId: call.recordId,\n scope: await cacheScope(token),\n apiVersion: call.apiVersion,\n signal,\n });\n }\n\n /** Sends `call`, retrying once with a refreshed token after a `401`; throws on `>= 400`. */\n async #send(call: Call, signal: AbortSignal | undefined): Promise<Response> {\n const token = await this.#token(false);\n let response = await this.#dispatch(call, token, signal);\n if (response.status === 401 && this.#tokenProvider !== undefined) {\n const fresh = await this.#token(true);\n if (fresh !== null && fresh !== token) {\n await response.body?.cancel();\n response = await this.#dispatch(call, fresh, signal);\n }\n }\n if (response.status >= 400) {\n throw await problemFromResponse(response);\n }\n return response;\n }\n\n async #getJson(url: string, catalog: boolean): Promise<unknown> {\n const call: Call = {\n method: \"GET\",\n url,\n op: \"manifest\",\n resource: undefined,\n recordId: undefined,\n apiVersion: null,\n // The catalog shares the \"manifest\" op; no-store keeps it out of the manifest cache entry.\n ...(catalog ? { headers: { \"Cache-Control\": \"no-store\" } } : {}),\n };\n const response = await this.#send(call, undefined);\n try {\n return (await response.json()) as unknown;\n } catch (error) {\n throw new ManifestError(`${url} is not JSON`, { cause: error });\n }\n }\n\n /** The manifest for this caller, loaded once per caller scope (`refresh: true` reloads). */\n async manifest(\n options: { readonly refresh?: boolean } = {},\n ): Promise<Manifest> {\n const scope = await this.scope(); // the manifest is filtered per caller\n let loading = this.#manifests.get(scope);\n if (loading === undefined || options.refresh === true) {\n const started = loadManifest(\n (url, catalog) => this.#getJson(url, catalog),\n this.baseUrl,\n this.#manifestUrl,\n );\n loading = started;\n if (!this.#manifests.has(scope)) {\n this.#manifests.clear(); // rotated tokens must not pile up manifests\n }\n this.#manifests.set(scope, started);\n started.catch(() => {\n if (this.#manifests.get(scope) === started) {\n this.#manifests.delete(scope);\n }\n });\n }\n return loading;\n }\n\n /** A handle for `name` (the highest `api_version` unless given). */\n async resource<\n Read extends object = JsonObject,\n Create extends object = JsonObject,\n Update extends object = JsonObject,\n >(\n name: string,\n apiVersion?: string,\n ): Promise<ResourceClient<Read, Create, Update>> {\n const resource = findResource(await this.manifest(), name, apiVersion);\n if (resource === undefined) {\n throw new UnknownResourceError(\n `the manifest has no resource \"${name}\"${apiVersion === undefined ? \"\" : ` ${apiVersion}`} for this caller`,\n );\n }\n return new ResourceClient<Read, Create, Update>(\n this.baseUrl,\n resource,\n this.#transport,\n );\n }\n}\n\n/** Creates a client; the manifest loads on first use. */\nexport function createClient(options: ClientOptions): CrudClient {\n return new CrudClient(options);\n}\n"],"mappings":"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"}