@embedpdf/engine-core 3.0.0-next.13 → 3.0.0-next.14
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/dist/{AbortError-DHqPBnYc.js → AbortError-DwuHPK_I.js} +2 -2
- package/dist/{AbortError-DHqPBnYc.js.map → AbortError-DwuHPK_I.js.map} +1 -1
- package/dist/{AbortError-Cq2igpZ6.cjs → AbortError-P0RU0Mgg.cjs} +4 -4
- package/dist/{AbortError-Cq2igpZ6.cjs.map → AbortError-P0RU0Mgg.cjs.map} +1 -1
- package/dist/{AnnotationListSnapshot-D3mFut1e.d.cts → AnnotationListSnapshot-D9R5n2Kf.d.cts} +237 -7
- package/dist/{AnnotationListSnapshot-D3mFut1e.d.ts → AnnotationListSnapshot-D9R5n2Kf.d.ts} +237 -7
- package/dist/{DocumentSecurityService-ClTZc0zO.d.cts → DocumentSecurityService-CIx1MT0T.d.cts} +2 -2
- package/dist/{DocumentSecurityService-_JRjqvoI.d.ts → DocumentSecurityService-Ca6EK3-3.d.ts} +2 -2
- package/dist/{Engine-Bx0NOfmd.d.cts → Engine-EWWHhEIi.d.ts} +17 -4
- package/dist/{Engine-DxtpCYcP.d.ts → Engine-FNaAEjfb.d.cts} +17 -4
- package/dist/conformance.cjs +382 -95
- package/dist/conformance.cjs.map +1 -1
- package/dist/conformance.d.cts +7 -3
- package/dist/conformance.d.ts +7 -3
- package/dist/conformance.js +302 -16
- package/dist/conformance.js.map +1 -1
- package/dist/derive-BbsDk_Kz.cjs +880 -0
- package/dist/derive-BbsDk_Kz.cjs.map +1 -0
- package/dist/derive-DAFJolWu.js +647 -0
- package/dist/derive-DAFJolWu.js.map +1 -0
- package/dist/{PageInsertBlankInput-cHq9-i-z.js → format-Bbphf4zR.js} +59 -2
- package/dist/format-Bbphf4zR.js.map +1 -0
- package/dist/{PageInsertBlankInput-CqXBmFhN.cjs → format-D_epWlob.cjs} +70 -1
- package/dist/format-D_epWlob.cjs.map +1 -0
- package/dist/index.cjs +127 -107
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +4 -4
- package/dist/runtime.cjs +137 -117
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +29 -5
- package/dist/runtime.d.ts +29 -5
- package/dist/runtime.js +5 -5
- package/dist/{schemas-BLARNCgx.js → schemas-CFQGvWiu.js} +134 -4
- package/dist/schemas-CFQGvWiu.js.map +1 -0
- package/dist/{schemas-DIqFMmrC.cjs → schemas-D0g6tKa9.cjs} +250 -24
- package/dist/schemas-D0g6tKa9.cjs.map +1 -0
- package/dist/{builders-Bqm8yTpi.cjs → viewport-BWeNHZmb.cjs} +71 -132
- package/dist/viewport-BWeNHZmb.cjs.map +1 -0
- package/dist/{builders-Dqo2X-dt.js → viewport-CvMcadfQ.js} +39 -88
- package/dist/viewport-CvMcadfQ.js.map +1 -0
- package/dist/wire.cjs +25 -2
- package/dist/wire.cjs.map +1 -1
- package/dist/wire.d.cts +2739 -8
- package/dist/wire.d.ts +2739 -8
- package/dist/wire.js +10 -3
- package/dist/wire.js.map +1 -1
- package/package.json +1 -1
- package/dist/PageInsertBlankInput-CqXBmFhN.cjs.map +0 -1
- package/dist/PageInsertBlankInput-cHq9-i-z.js.map +0 -1
- package/dist/builders-Bqm8yTpi.cjs.map +0 -1
- package/dist/builders-Dqo2X-dt.js.map +0 -1
- package/dist/fold-2V29cxCV.cjs +0 -447
- package/dist/fold-2V29cxCV.cjs.map +0 -1
- package/dist/fold-CdEJTBTn.js +0 -334
- package/dist/fold-CdEJTBTn.js.map +0 -1
- package/dist/schemas-BLARNCgx.js.map +0 -1
- package/dist/schemas-DIqFMmrC.cjs.map +0 -1
package/dist/wire.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wire.js","names":[],"sources":["../src/forms/submission.ts","../src/wire/token.ts","../src/wire/tokenSchemas.ts","../src/wire/tokens.ts","../src/wire/paths.ts","../src/wire/resources.ts","../src/wire/cdn/coverage.ts","../src/wire/cdn/applyCdnAccess.ts","../src/wire/flatten.ts","../src/wire/renderOptionsCodec.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * One resolved entry of a form submission. The viewer resolved it with the\n * ISO 32000-2 Table 239/240 semantics already applied (Include/Exclude +\n * descendants, the unconditional NoExport veto, push-button and\n * unsupported-value exclusion), so the home never re-derives selection.\n * `value === null` is a NAME-ONLY entry (the IncludeNoValueFields shape);\n * `string[]` is a multi-select list box.\n */\nexport interface FormSubmissionEntry {\n name: string;\n value: string | string[] | null;\n}\n\n/**\n * What a submit-capable document HOME receives — the resolved dataset plus\n * the document's declared intent as METADATA. The stack never fetches the\n * declared URL itself (a PDF-controlled URL reaching a server-side fetcher\n * is the SSRF class this contract exists to prevent); the home stores the\n * intent so its consumers can decide what to honor.\n *\n * Deliberately ABSENT: identity. The home derives who submitted from its\n * OWN verified session (the JWT it authenticated) — a client-supplied\n * identity would be a spoofing surface.\n */\nexport interface FormSubmissionRequest {\n entries: FormSubmissionEntry[];\n /** The document's declared routing wish, verbatim (metadata, not orders).\n * `url` is null for scripted submits that named no target. */\n intent: {\n url: string | null;\n format: 'fdf' | 'html' | 'xfdf' | 'pdf';\n method: 'post' | 'get';\n /** Raw ISO Table 240 flag word (0 for scripted submits without one). */\n flagsRaw: number;\n /** /CharSet (PDF 2.0), extracted but never encoded by this stack. */\n charSet?: string;\n };\n /** How the submission was triggered — the viewer-derived origin axis. */\n origin: 'user' | 'hover' | 'lifecycle';\n /** Client wall-clock, milliseconds since epoch. Informational — the home\n * stamps its own authoritative `receivedAt`. */\n clientTimeMs: number;\n}\n\n/** The home's acknowledgment: the stored submission's durable identity. */\nexport interface FormSubmissionReceipt {\n submissionId: string;\n /** ISO 8601, the home's clock. */\n receivedAt: string;\n}\n\nexport const FormSubmissionEntrySchema: z.ZodType<FormSubmissionEntry> = z.object({\n name: z.string(),\n value: z.union([z.string(), z.array(z.string()), z.null()]),\n});\n\nexport const FormSubmissionRequestSchema: z.ZodType<FormSubmissionRequest> = z.object({\n entries: z.array(FormSubmissionEntrySchema),\n intent: z.object({\n url: z.string().nullable(),\n format: z.enum(['fdf', 'html', 'xfdf', 'pdf']),\n method: z.enum(['post', 'get']),\n flagsRaw: z.number().int().nonnegative(),\n charSet: z.string().optional(),\n }),\n origin: z.enum(['user', 'hover', 'lifecycle']),\n clientTimeMs: z.number().finite(),\n}) as unknown as z.ZodType<FormSubmissionRequest>;\n\nexport const FormSubmissionReceiptSchema: z.ZodType<FormSubmissionReceipt> = z.object({\n submissionId: z.string().min(1),\n receivedAt: z.string().min(1),\n});\n","export type TokenScalar = string | number | boolean;\nexport type TokenInput = Record<string, TokenScalar | undefined>;\nexport type TokenQuery = Record<string, string>;\n\nexport interface TokenSchema {\n /**\n * Allowed field names. Field names are dotted paths of camelCase segments\n * (e.g. `viewport.kind`, `target.rect.left`). `=` is reserved as the\n * key/value delimiter and `,` as the pair separator, so neither may appear\n * in field names. `.` is the path separator that lets dotted keys round-\n * trip generically through `flatten`/`unflatten`.\n *\n * The token form is intentionally isomorphic to a query string: swap `,`\n * for `&` and you have a query string with identical keys and values.\n * Both `=` and `,` are RFC 3986 sub-delims, allowed unencoded in path\n * segments, so the token never needs URL-encoding for its grammar.\n */\n fields: readonly string[];\n maxLength?: number;\n}\n\nconst DEFAULT_MAX_TOKEN_LENGTH = 256;\n// One or more camelCase segments joined by `.`. Each segment must start with\n// a letter and contain only [A-Za-z0-9]. Reserved characters `=` and `,` are\n// excluded by construction so the codec can parse without escape handling.\nconst FIELD_NAME_RE = /^[A-Za-z][A-Za-z0-9]*(?:\\.[A-Za-z][A-Za-z0-9]*)*$/;\nconst VALUE_RE = /^[A-Za-z0-9.-]+$/;\n\nexport function encodeToken(schema: TokenSchema, input: TokenInput): string {\n assertSchema(schema);\n const allowed = new Set(schema.fields);\n const pairs: Array<[string, string]> = [];\n for (const [key, value] of Object.entries(input)) {\n if (value === undefined) continue;\n assertKnownField(allowed, key);\n const encoded = encodeScalar(key, value);\n assertSafeValue(key, encoded);\n pairs.push([key, encoded]);\n }\n\n pairs.sort(([a], [b]) => a.localeCompare(b));\n const token = pairs.map(([key, value]) => `${key}=${value}`).join(',');\n if (token.length === 0) throw new Error('token must not be empty');\n assertTokenLength(schema, token);\n return token;\n}\n\nexport function decodeToken(schema: TokenSchema, raw: string): TokenQuery {\n assertSchema(schema);\n const token = raw.startsWith('@') ? raw.slice(1) : raw;\n assertTokenLength(schema, token);\n if (token.length === 0) throw new Error('token must not be empty');\n\n const allowed = new Set(schema.fields);\n const output: TokenQuery = {};\n let previousKey: string | undefined;\n\n for (const pair of token.split(',')) {\n if (pair.length === 0) throw new Error('token contains an empty field');\n const separator = pair.indexOf('=');\n if (separator <= 0 || separator === pair.length - 1) {\n throw new Error(`token field \"${pair}\" must be key=value`);\n }\n\n const key = pair.slice(0, separator);\n const value = pair.slice(separator + 1);\n assertKnownField(allowed, key);\n assertSafeValue(key, value);\n if (output[key] !== undefined) throw new Error(`token field \"${key}\" appears more than once`);\n if (previousKey !== undefined && key.localeCompare(previousKey) <= 0) {\n throw new Error('token fields must be in alphabetical order');\n }\n previousKey = key;\n output[key] = value;\n }\n\n return output;\n}\n\nfunction assertSchema(schema: TokenSchema): void {\n for (const field of schema.fields) {\n if (!FIELD_NAME_RE.test(field)) {\n throw new Error(`token field name \"${field}\" must be camelCase segments joined by \".\"`);\n }\n }\n}\n\nfunction assertKnownField(allowed: Set<string>, key: string): void {\n if (!allowed.has(key)) throw new Error(`unknown token field \"${key}\"`);\n}\n\nfunction encodeScalar(key: string, value: TokenScalar): string {\n if (typeof value === 'boolean') return value ? 'true' : 'false';\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) throw new Error(`token field \"${key}\" must be finite`);\n return Number.isInteger(value) ? String(value) : trimDecimal(value);\n }\n return value;\n}\n\nfunction trimDecimal(value: number): string {\n return value.toFixed(6).replace(/0+$/, '').replace(/\\.$/, '');\n}\n\nfunction assertSafeValue(key: string, value: string): void {\n if (!VALUE_RE.test(value)) {\n throw new Error(`token field \"${key}\" value contains a reserved character`);\n }\n}\n\nfunction assertTokenLength(schema: TokenSchema, token: string): void {\n const maxLength = schema.maxLength ?? DEFAULT_MAX_TOKEN_LENGTH;\n if (token.length > maxLength) {\n throw new Error(`token exceeds ${maxLength} characters`);\n }\n}\n","import type { TokenSchema } from './token';\n\nexport const DocTokenSchema = {\n fields: ['docVersion'],\n} as const satisfies TokenSchema;\n\nexport const ContentTokenSchema = {\n fields: ['contentVersion'],\n} as const satisfies TokenSchema;\n\nexport const LayoutTokenSchema = {\n fields: ['layoutVersion'],\n} as const satisfies TokenSchema;\n\nexport const MetadataTokenSchema = {\n fields: ['metadataVersion'],\n} as const satisfies TokenSchema;\n\nexport const AnnotationTokenSchema = {\n fields: ['annotationVersion'],\n} as const satisfies TokenSchema;\n\n/** Doc-level bulk annotations listing pin (plural, vs the per-page\n * `annotationVersion` token above). */\nexport const AnnotationsAllTokenSchema = {\n fields: ['annotationsVersion'],\n} as const satisfies TokenSchema;\n\nexport const ActionsTokenSchema = {\n fields: ['actionsVersion'],\n} as const satisfies TokenSchema;\n\nexport const AttachmentsTokenSchema = {\n fields: ['attachmentsVersion'],\n} as const satisfies TokenSchema;\n\n/**\n * Layer signature analysis: the working copy judged against the base,\n * pinned by `docVersion`; `since.signature` XOR `since.revision`; `level`\n * only in exploratory mode.\n */\nexport const AnalysisTokenSchema = {\n // `policy`: the judging policy version the caller expects — part of the\n // cache key, so a policy bump never serves a verdict judged the old way.\n fields: ['docVersion', 'since.signature', 'since.revision', 'level', 'policy', 'detail'],\n} as const;\n\nexport const DownloadTokenSchema = {\n fields: ['docVersion', 'mode'],\n maxLength: 128,\n} as const satisfies TokenSchema;\n\n/**\n * Allowed flat keys for the render token, expressed as dotted paths that\n * mirror the SDK `PageImageOptions` shape 1:1. The token codec is fully\n * generic over this list — adding a new render option means adding its\n * dotted path here and a matching branch in `PageImageOptionsWireSchema`.\n * No encoder/decoder code changes.\n *\n * `includeAnnotations` is deliberately NOT a token field: annotatedness\n * changes the artifact's plane-dependency\n * set, so it is expressed by the path FAMILY (`…/render/pages/` vs\n * `…/render/annotated/pages/`), never inside the token. `annotationVersion`\n * belongs to the annotated family's tokens only — each family's query\n * schema enforces its own pin grammar.\n */\nexport const RenderTokenSchema = {\n fields: [\n 'annotationVersion',\n 'background',\n 'contentVersion',\n 'format',\n 'quality',\n 'rotation',\n 'target.kind',\n 'target.rect.bottom',\n 'target.rect.left',\n 'target.rect.right',\n 'target.rect.top',\n 'viewport.kind',\n 'viewport.scale',\n 'viewport.width',\n ],\n maxLength: 512,\n} as const satisfies TokenSchema;\n\n/**\n * Token for the versioned search endpoints (`/search/{rects,full}/data@…`).\n * One token carries the whole cache key: the content epoch, the query\n * (text/pattern rides base64-variant-encoded in `q` — the token value\n * charset excludes free text), and the resume position. Canonical by\n * construction: the codec sorts fields and the encoder omits every\n * default, so equal searches produce byte-equal tokens — the property CDN\n * cache hits live on. Mode is NOT a field; it is the endpoint (separate\n * permission tiers must never share cache entries).\n */\nexport const SearchTokenSchema = {\n fields: [\n 'epoch',\n 'format',\n 'matchCase',\n 'matchDiacritics',\n 'maxMatches',\n 'maxPages',\n 'q',\n 'regex',\n 'skip',\n 'startPage',\n 'wholeWord',\n ],\n maxLength: 2048,\n} as const satisfies TokenSchema;\n\n/**\n * Token for the batch annotation-appearance render endpoint. Narrower than\n * the page render token: appearance bitmaps are sized per annotation `/Rect`\n * so there is no target/viewport — only a uniform `scale` and page\n * `rotation`. Keyed by `annotationVersion` only (appearances do not depend on\n * page base content). The cloud endpoint renders the Normal appearance only,\n * so `modes` is intentionally absent here (it is a worker/local-only option).\n */\nexport const AnnotationAppearancesRenderTokenSchema = {\n fields: ['annotationVersion', 'format', 'quality', 'rotation', 'scale'],\n maxLength: 256,\n} as const satisfies TokenSchema;\n","import { decodeToken, encodeToken, type TokenInput, type TokenQuery } from './token';\n\nexport type { TokenInput } from './token';\nimport { SIGNATURE_POLICY_VERSION } from '../signature/protection';\nimport {\n AnalysisTokenSchema,\n AnnotationAppearancesRenderTokenSchema,\n AnnotationTokenSchema,\n AnnotationsAllTokenSchema,\n ActionsTokenSchema,\n AttachmentsTokenSchema,\n ContentTokenSchema,\n DocTokenSchema,\n DownloadTokenSchema,\n LayoutTokenSchema,\n MetadataTokenSchema,\n RenderTokenSchema,\n SearchTokenSchema,\n} from './tokenSchemas';\nimport type { PdfSaveMode } from '../dto/PdfSaveMode';\nimport type { ModificationLevel } from '../signature/types';\nimport type { SearchQuery, SearchSliceBudget } from '../search/types';\n\nexport interface DownloadToken {\n docVersion: number;\n mode: PdfSaveMode;\n}\n\n/** The layer analysis token: the pin plus the flat `AnalyzeInput` (until = the working copy). */\nexport interface AnalysisToken {\n docVersion: number;\n since: { signatureIndex: number } | { revisionIndex: number };\n exploratoryLevel?: ModificationLevel;\n /** The judging policy version the caller expects (`SIGNATURE_POLICY_VERSION`); keys the cache. */\n policyVersion?: number;\n /** `full` carries every pairwise step; default `summary`. */\n detail?: 'summary' | 'full';\n}\n\nexport const encodeAnalysisToken = (input: AnalysisToken): string =>\n encodeToken(AnalysisTokenSchema, {\n docVersion: input.docVersion,\n 'since.signature': 'signatureIndex' in input.since ? input.since.signatureIndex : undefined,\n 'since.revision': 'revisionIndex' in input.since ? input.since.revisionIndex : undefined,\n level: input.exploratoryLevel,\n policy: input.policyVersion ?? SIGNATURE_POLICY_VERSION,\n detail: input.detail,\n });\n\nexport const decodeAnalysisToken = (raw: string): AnalysisToken => {\n const t = decodeToken(AnalysisTokenSchema, raw);\n const sinceSignature = t['since.signature'];\n const sinceRevision = t['since.revision'];\n if ((sinceSignature === undefined) === (sinceRevision === undefined)) {\n throw new Error('analysis token needs exactly one of \"since.signature\" / \"since.revision\"');\n }\n return {\n docVersion: decodePositiveInteger(t.docVersion, 'docVersion'),\n since:\n sinceSignature !== undefined\n ? { signatureIndex: decodeNonNegativeInteger(sinceSignature, 'since.signature') }\n : { revisionIndex: decodeNonNegativeInteger(sinceRevision!, 'since.revision') },\n ...(t.level !== undefined ? { exploratoryLevel: decodeModificationLevel(t.level) } : {}),\n ...(t.policy !== undefined ? { policyVersion: decodePositiveInteger(t.policy, 'policy') } : {}),\n ...(t.detail !== undefined ? { detail: decodeDetail(t.detail) } : {}),\n };\n};\n\nfunction decodeDetail(raw: string): 'summary' | 'full' {\n if (raw !== 'summary' && raw !== 'full') {\n throw new Error('token field \"detail\" must be summary|full');\n }\n return raw;\n}\n\nconst MODIFICATION_LEVELS: ReadonlyArray<ModificationLevel> = ['none', 'lta', 'fill', 'annotate'];\nfunction decodeModificationLevel(raw: string): ModificationLevel {\n if (!(MODIFICATION_LEVELS as readonly string[]).includes(raw)) {\n throw new Error(`token field \"level\" must be one of ${MODIFICATION_LEVELS.join('|')}`);\n }\n return raw as ModificationLevel;\n}\n\nfunction decodeNonNegativeInteger(raw: string | undefined, field: string): number {\n if (raw === undefined) throw new Error(`token is missing \"${field}\"`);\n if (!/^(0|[1-9][0-9]*)$/.test(raw))\n throw new Error(`token field \"${field}\" must be a non-negative integer`);\n return Number(raw);\n}\n\nexport const encodeDocToken = (docVersion: number): string =>\n encodeToken(DocTokenSchema, { docVersion });\nexport const decodeDocToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(DocTokenSchema, raw).docVersion, 'docVersion');\n\nexport const encodeContentToken = (contentVersion: number): string =>\n encodeToken(ContentTokenSchema, { contentVersion });\nexport const decodeContentToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(ContentTokenSchema, raw).contentVersion, 'contentVersion');\n\nexport const encodeLayoutToken = (layoutVersion: number): string =>\n encodeToken(LayoutTokenSchema, { layoutVersion });\nexport const decodeLayoutToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(LayoutTokenSchema, raw).layoutVersion, 'layoutVersion');\n\nexport const encodeMetadataToken = (metadataVersion: number): string =>\n encodeToken(MetadataTokenSchema, { metadataVersion });\nexport const decodeMetadataToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(MetadataTokenSchema, raw).metadataVersion, 'metadataVersion');\n\nexport const encodeAnnotationToken = (annotationVersion: number): string =>\n encodeToken(AnnotationTokenSchema, { annotationVersion });\nexport const decodeAnnotationToken = (raw: string): number =>\n decodePositiveInteger(\n decodeToken(AnnotationTokenSchema, raw).annotationVersion,\n 'annotationVersion',\n );\n\nexport const encodeAnnotationsAllToken = (annotationsVersion: number): string =>\n encodeToken(AnnotationsAllTokenSchema, { annotationsVersion });\nexport const decodeAnnotationsAllToken = (raw: string): number =>\n decodePositiveInteger(\n decodeToken(AnnotationsAllTokenSchema, raw).annotationsVersion,\n 'annotationsVersion',\n );\n\nexport const encodeActionsToken = (actionsVersion: number): string =>\n encodeToken(ActionsTokenSchema, { actionsVersion });\nexport const decodeActionsToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(ActionsTokenSchema, raw).actionsVersion, 'actionsVersion');\n\nexport const encodeAttachmentsToken = (attachmentsVersion: number): string =>\n encodeToken(AttachmentsTokenSchema, { attachmentsVersion });\nexport const decodeAttachmentsToken = (raw: string): number =>\n decodePositiveInteger(\n decodeToken(AttachmentsTokenSchema, raw).attachmentsVersion,\n 'attachmentsVersion',\n );\n\nexport const encodeDownloadToken = (input: DownloadToken): string =>\n encodeToken(DownloadTokenSchema, { docVersion: input.docVersion, mode: input.mode });\nexport const decodeDownloadToken = (raw: string): DownloadToken => {\n const decoded = decodeToken(DownloadTokenSchema, raw);\n return {\n docVersion: decodePositiveInteger(decoded.docVersion, 'docVersion'),\n mode: decodePdfSaveMode(decoded.mode),\n };\n};\n\n/**\n * Encode a render token from a flat wire-shape input. The input is the\n * output of `flatten(...)` over an SDK `PageImageOptions`-shaped object plus\n * cache versions. Semantic invariants (viewport-kind XOR fields, per-family\n * pin grammar — annotatedness itself is PATH-expressed, never a token key —\n * target rect coherence) live in the per-family render query schemas —\n * running them here would duplicate the spec.\n */\nexport const encodeRenderToken = (input: TokenInput): string =>\n encodeToken(RenderTokenSchema, input);\n\n/**\n * Decode a render token to a flat `Record<string, string>` of allowed\n * fields. Use `unflatten(...)` + `PageImageOptionsWireSchema.parse(...)` to\n * recover the nested SDK shape with full coercion + validation.\n */\nexport const decodeRenderToken = (raw: string): TokenQuery => decodeToken(RenderTokenSchema, raw);\n\n/**\n * Encode an annotation-appearance render token from a flat wire-shape input\n * (the `flatten(...)` of an `AnnotationAppearanceImageOptions`-shaped object\n * plus cache versions). Semantic validation lives in\n * `AnnotationAppearancesQuerySchema`.\n */\nexport const encodeAnnotationAppearancesRenderToken = (input: TokenInput): string =>\n encodeToken(AnnotationAppearancesRenderTokenSchema, input);\n\n/** Decode an annotation-appearance render token to a flat field map. */\nexport const decodeAnnotationAppearancesRenderToken = (raw: string): TokenQuery =>\n decodeToken(AnnotationAppearancesRenderTokenSchema, raw);\n\n/**\n * The decoded state of a versioned search URL — the WHOLE cache key.\n * `epoch` is `searchContentEpoch(manifest)`; `skip` is the number of\n * scan-order pages already consumed (0 = first slice). The server mints\n * continuation tokens (same epoch, advanced skip); the client decodes\n * them only to verify a resumed cursor still belongs to its query.\n */\nexport interface SearchToken {\n epoch: string;\n query: SearchQuery;\n startPage?: number;\n skip: number;\n budget?: SearchSliceBudget;\n}\n\n/**\n * The search RESULT representation this client speaks — part of the token\n * (and therefore the versioned URL), so a response-shape change can never\n * serve a stale CDN body to a newer client: new tokens are new cache keys,\n * and old tokens fail decode on new servers. Deliberately ALWAYS encoded —\n * an exception to the omit-defaults rule, because its entire job is to\n * change the token bytes when the format changes.\n */\nexport const SEARCH_RESULT_FORMAT = 'segments1';\n\nexport const encodeSearchToken = (input: SearchToken): string => {\n const q = input.query;\n return encodeToken(SearchTokenSchema, {\n epoch: input.epoch,\n format: SEARCH_RESULT_FORMAT,\n q: encodeTokenText(q.text),\n // Canonical keys: every default is OMITTED, never encoded as false/0.\n regex: q.regex ? true : undefined,\n matchCase: q.matchCase ? true : undefined,\n matchDiacritics: q.matchDiacritics ? true : undefined,\n wholeWord: q.wholeWord ? true : undefined,\n startPage: input.startPage,\n skip: input.skip > 0 ? input.skip : undefined,\n maxPages: input.budget?.maxPages,\n maxMatches: input.budget?.maxMatches,\n });\n};\n\nexport const decodeSearchToken = (raw: string): SearchToken => {\n const t = decodeToken(SearchTokenSchema, raw);\n if (t.epoch === undefined) throw new Error('search token is missing \"epoch\"');\n if (t.q === undefined) throw new Error('search token is missing \"q\"');\n if (t.format !== SEARCH_RESULT_FORMAT) {\n throw new Error(\n `search token has unsupported result format \"${t.format ?? 'legacy'}\" ` +\n `(expected \"${SEARCH_RESULT_FORMAT}\")`,\n );\n }\n const query: SearchQuery = {\n text: decodeTokenText(t.q),\n ...(t.regex === 'true' ? { regex: true } : {}),\n ...(t.matchCase === 'true' ? { matchCase: true } : {}),\n ...(t.matchDiacritics === 'true' ? { matchDiacritics: true } : {}),\n ...(t.wholeWord === 'true' ? { wholeWord: true } : {}),\n };\n const maxPages =\n t.maxPages === undefined ? undefined : decodePositiveInteger(t.maxPages, 'maxPages');\n const maxMatches =\n t.maxMatches === undefined ? undefined : decodePositiveInteger(t.maxMatches, 'maxMatches');\n return {\n epoch: t.epoch,\n query,\n ...(t.startPage === undefined\n ? {}\n : { startPage: decodePositiveInteger(t.startPage, 'startPage') }),\n skip: t.skip === undefined ? 0 : decodePositiveInteger(t.skip, 'skip'),\n ...(maxPages !== undefined || maxMatches !== undefined\n ? {\n budget: {\n ...(maxPages !== undefined ? { maxPages } : {}),\n ...(maxMatches !== undefined ? { maxMatches } : {}),\n },\n }\n : {}),\n };\n};\n\n// Query text inside a token: UTF-8 → base64 with `-` for `+` and `.` for\n// `/`, unpadded — exactly the token grammar's value charset [A-Za-z0-9.-].\n// Dependency-free (no Buffer: this runs in browsers too).\nconst TOKEN_TEXT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';\n\nexport function encodeTokenText(text: string): string {\n const bytes = new TextEncoder().encode(text);\n let out = '';\n for (let i = 0; i < bytes.length; i += 3) {\n const b0 = bytes[i];\n const b1 = bytes[i + 1];\n const b2 = bytes[i + 2];\n out += TOKEN_TEXT_ALPHABET[b0 >> 2];\n out += TOKEN_TEXT_ALPHABET[((b0 & 0x03) << 4) | ((b1 ?? 0) >> 4)];\n if (b1 === undefined) break;\n out += TOKEN_TEXT_ALPHABET[((b1 & 0x0f) << 2) | ((b2 ?? 0) >> 6)];\n if (b2 === undefined) break;\n out += TOKEN_TEXT_ALPHABET[b2 & 0x3f];\n }\n return out;\n}\n\nexport function decodeTokenText(encoded: string): string {\n if (encoded.length % 4 === 1) throw new Error('malformed token text');\n const bytes: number[] = [];\n let buffer = 0;\n let bits = 0;\n for (const ch of encoded) {\n const value = TOKEN_TEXT_ALPHABET.indexOf(ch);\n if (value < 0) throw new Error('malformed token text');\n buffer = (buffer << 6) | value;\n bits += 6;\n if (bits >= 8) {\n bits -= 8;\n bytes.push((buffer >> bits) & 0xff);\n }\n }\n return new TextDecoder('utf-8', { fatal: true }).decode(Uint8Array.from(bytes));\n}\n\nfunction decodePositiveInteger(raw: string | undefined, field: string): number {\n if (raw === undefined || !/^\\d+$/.test(raw)) {\n throw new Error(`token field \"${field}\" must be a positive integer`);\n }\n const value = Number(raw);\n if (!Number.isInteger(value) || value <= 0) {\n throw new Error(`token field \"${field}\" must be a positive integer`);\n }\n return value;\n}\n\nfunction decodePdfSaveMode(raw: string | undefined): PdfSaveMode {\n if (raw === 'incremental' || raw === 'rewrite') return raw;\n throw new Error(`token field \"mode\" must be \"incremental\" or \"rewrite\"`);\n}\n","import type { ModificationLevel } from '../signature/types';\nimport { SIGNATURE_POLICY_VERSION } from '../signature/protection';\nimport type { AnalysisToken } from './tokens';\n/**\n * Single source of truth for cloud HTTP paths. Both @cloudpdf/engine and\n * @cloudpdf/server import these so they cannot drift.\n *\n * **URL layout convention (paths v2)**\n *\n * Each resource type lives at its own distinct path prefix. This\n * lets prefix-matching CDNs (Bunny, Cloud CDN, Azure FD) enforce\n * per-resource scope at the edge — a Bunny token signed at\n * `/v1/docs/{id}/render/pages/` can only authorize render bytes,\n * never text or annotations.\n *\n * Shape:\n * /v1/docs/{id} — doc root\n * /v1/docs/{id}/manifest@{ver} — doc-level read\n * /v1/docs/{id}/render/pages/{N}/data@{ver} — render is its own prefix\n * /v1/docs/{id}/text/pages/{N}/data@{ver} — text is its own prefix\n * /v1/docs/{id}/geometry/pages/{N}/data@{ver} — geometry is its own prefix\n * /v1/docs/{id}/layers/{L}/manifest@{ver}\n * /v1/docs/{id}/layers/{L}/metadata@{ver}\n * /v1/docs/{id}/layers/{L}/render/pages/{N}/data@{ver}\n * /v1/docs/{id}/layers/{L}/text/pages/{N}/data@{ver}\n * /v1/docs/{id}/layers/{L}/geometry/pages/{N}/data@{ver}\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items@{ver} — collection (read)\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items — collection (create)\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items/{key} — member\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items/move — batch reorder\n * /v1/docs/{id}/layers/{L}/pages/move — batch page reorder\n * /v1/docs/{id}/layers/{L}/pages/rotate — batch absolute rotation\n * /v1/docs/{id}/layers/{L}/pages/delete — batch page delete\n * /v1/docs/{id}/layers/{L}/form — reconciled snapshot (read)\n * /v1/docs/{id}/layers/{L}/form/fields — field collection (create)\n * /v1/docs/{id}/layers/{L}/form/fields/{key} — field member (read/patch/delete)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/value — value write (fill)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/reset — reset to /DV (fill)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/widgets — adopt a widget (attach)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/widgets/detach — release a widget\n * /v1/docs/{id}/layers/{L}/form/data — FDF/XFDF export (GET) / import (POST)\n * /v1/docs/{id}/layers/{L}/form/repair — durable reconciliation\n * /v1/docs/{id}/layers/{L}/download@{ver}\n *\n * `items` appears on both the read collection (`items@{ver}`) and\n * the mutation surface (`items` POST, `items/{key}` PATCH/DELETE)\n * for symmetry — `items@version` is the page's versioned annotation\n * collection; `items/{key}` is one annotation inside it.\n */\nimport {\n encodeActionsToken,\n encodeAnalysisToken,\n encodeAnnotationAppearancesRenderToken,\n encodeAnnotationToken,\n encodeAnnotationsAllToken,\n encodeAttachmentsToken,\n encodeContentToken,\n encodeDocToken,\n encodeDownloadToken,\n encodeLayoutToken,\n encodeMetadataToken,\n encodeRenderToken,\n encodeTokenText,\n type DownloadToken,\n type TokenInput,\n} from './tokens';\n\nexport const DEFAULT_LAYER_NAME = 'default';\n\nexport const wirePaths = {\n /**\n * POST: grant access/caching credentials for the current bearer on\n * the document + layer namespace the path names (cross-checked\n * against the token like every layer route — the grant is\n * layer-scoped in substance: CDN coverage, scopes, and the client's\n * binding all carry the layer). Path-addressed so the affinity tier —\n * the `X-CloudPDF-Doc` header derivation AND the chart's uri-mode\n * regex — pins the session bootstrap to the document's pod from the\n * very first request. Default-layer callers spell `layers/default/`,\n * same as every other layer route.\n */\n access: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/access`,\n\n /** Deprecated alias (docId in the BODY) — served for one prerelease\n * cycle so pre-rename clients keep working; remove after. */\n accessLegacy: '/v1/access',\n\n /**\n * GET: open the document referenced by the doc-scoped JWT and\n * return its `DocumentHead`. The server materialises the base\n * PDF into its file cache and binds it to a worker the first\n * time this is hit.\n */\n docHead: (docId: string) => `/v1/docs/${encodeURIComponent(docId)}/head`,\n\n /**\n * GET: layer-scoped head. The cloud SDK always uses a layer namespace;\n * tokens without `layer_name` bind to `DEFAULT_LAYER_NAME`.\n */\n layerHead: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/head`,\n\n /**\n * GET: full document manifest at a specific `docVersion`. Content-\n * addressed: the URL bytes are immutable for the lifetime of the\n * version, so CDNs may cache `public, max-age=31536000, immutable`.\n * A request whose `docVersion` mismatches the current version\n * returns 404 — the SDK refetches `/head` to learn the new\n * version, then re-requests the manifest at the new URL.\n */\n docManifest: (docId: string, docVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/manifest@${encodeDocToken(docVersion)}`,\n\n /**\n * GET: full layer manifest at a specific layer document version.\n * Never-mutated layers may fall through to the immutable base view;\n * once a layer row exists, `layers.doc_version` and `layer_pages`\n * drive the response.\n */\n layerManifest: (docId: string, layerName: string, docVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/manifest@${encodeDocToken(docVersion)}`,\n\n /**\n * GET: page-geometry list for the whole layer at a specific\n * `layoutVersion`. Content-addressed; CDN may cache forever. The\n * `layoutVersion` lives in the manifest (doc-level pointer) and bumps\n * only on structural page ops. Stale-version requests 404 and the SDK's\n * transparent retry walks `/head` -> `/manifest@docVersion=N` to learn\n * the new `layoutVersion`.\n */\n layerLayout: (docId: string, layerName: string, layoutVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/layout@${encodeLayoutToken(layoutVersion)}`,\n\n /**\n * Immutable BASE page-geometry list (plane-scope model): the shared-URL\n * variant a layout-inheriting layer resolves at — every visitor's page\n * list is ONE CDN object served from the base worker session.\n */\n docLayout: (docId: string, layoutVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layout@${encodeLayoutToken(layoutVersion)}`,\n\n layerLayoutCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/layout`,\n\n /**\n * GET: full document metadata for the layer at a specific\n * `metadataVersion`. Content-addressed; CDN may cache forever. The\n * `metadataVersion` lives in the manifest (doc-level pointer) and bumps\n * only on metadata writes. Stale-version requests 404 and the SDK's\n * transparent retry walks `/head` -> `/manifest@docVersion=N` to learn\n * the new `metadataVersion`.\n */\n layerMetadata: (docId: string, layerName: string, metadataVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/metadata@${encodeMetadataToken(metadataVersion)}`,\n\n layerMetadataCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/metadata`,\n\n /** Immutable BASE metadata (plane-scope model): the shared-URL variant a\n * metadata-inheriting layer resolves at. */\n docMetadata: (docId: string, metadataVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/metadata@${encodeMetadataToken(metadataVersion)}`,\n\n /** Immutable catalog-owned actions, independently pinned in the manifest. */\n layerActions: (docId: string, layerName: string, actionsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/actions@${encodeActionsToken(actionsVersion)}`,\n\n /** Immutable BASE catalog actions (plane-scope model): the shared-URL\n * variant an actions-inheriting layer resolves at. */\n docActions: (docId: string, actionsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/actions@${encodeActionsToken(actionsVersion)}`,\n\n // ---------------------------------------------------------------------\n // Digital signatures. Layer reads pin `docVersion` (a signature is a\n // layer state change like any other edit); version-scoped reads are\n // content-addressed by the base sha and immutable forever. The RESOURCE\n // comes before the sha so each family keeps its own CDN prefix.\n // ---------------------------------------------------------------------\n\n /** Immutable layer signature snapshot (base signatures + the layer's fields + protection). */\n layerSignatures: (docId: string, layerName: string, docVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures@${encodeDocToken(docVersion)}`,\n layerSignaturesCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures`,\n /** Immutable: the layer's working copy judged against the base, pinned by `docVersion`. */\n layerSignaturesAnalysis: (docId: string, layerName: string, token: AnalysisToken) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/analysis@${encodeAnalysisToken(token)}`,\n layerSignaturesAnalysisCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/analysis`,\n /** POST (multipart envelope): author and seal a signing candidate. */\n layerSignaturesPrepare: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/prepare`,\n /** POST (JSON): install the CMS and publish the sealed bytes as the next base version. */\n layerSignatureComplete: (docId: string, layerName: string, signingId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/${encodeURIComponent(signingId)}/complete`,\n /** DELETE: discard a pending signing. */\n layerSignatureAbort: (docId: string, layerName: string, signingId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/${encodeURIComponent(signingId)}`,\n\n /** The document's base versions, oldest first (grows; never cached). */\n docVersions: (docId: string) => `/v1/docs/${encodeURIComponent(docId)}/versions`,\n /** Immutable: the signature snapshot of one base version. */\n docVersionSignatures: (docId: string, sha256: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/signatures/${sha256}`,\n /** Immutable: a signed field's DER `/Contents` in one base version (`application/pkcs7-signature`). */\n docVersionSignatureContents: (docId: string, sha256: string, fieldName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/signatures/${sha256}/${encodeTokenText(fieldName)}/contents`,\n /** Immutable: the digest of a signed field's `/ByteRange` in one base version. */\n docVersionSignatureDigest: (\n docId: string,\n sha256: string,\n fieldName: string,\n algorithm: 'sha1' | 'sha256' | 'sha384' | 'sha512',\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/signatures/${sha256}/${encodeTokenText(fieldName)}/digest/${algorithm}`,\n /** Immutable: history between two revisions of one base version. */\n docVersionAnalysis: (docId: string, sha256: string, query: AnalysisQueryInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/analysis/${sha256}?${analysisQueryString(query)}`,\n /** Immutable: the bytes of one base version. */\n docVersionDownload: (docId: string, sha256: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/download/${sha256}`,\n /** Immutable: the byte prefix `[0, end)` of revision `index` of one base version. */\n docVersionRevision: (docId: string, sha256: string, index: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/revisions/${sha256}/${index}`,\n\n /** POST (multipart envelope): draw a PDF page into an unsigned signature field's widgets. */\n layerFormFieldSignatureAppearance: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/signature-appearance`,\n\n /** POST: rewrite the document Info dict for the layer (metadata edit). */\n layerMetadataUpdate: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/metadata`,\n\n /**\n * Immutable BASE /EmbeddedFiles listing: the shared-URL variant an\n * attachments-undiverged layer resolves at — every visitor's sidebar list\n * is ONE CDN object served from the base worker session.\n */\n docAttachments: (docId: string, attachmentsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/attachments@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** Immutable BASE decoded bytes of one embedded file (twin of\n * `layerAttachmentFile` — same capability tier split). */\n docAttachmentFile: (docId: string, key: string, attachmentsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/attachment-files/${encodeTokenText(key)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** Immutable /EmbeddedFiles listing, pinned by `attachmentsVersion`. */\n layerAttachments: (docId: string, layerName: string, attachmentsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachments@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** POST: create a document-level embedded file (multipart mutation envelope). */\n layerAttachmentsCollection: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachments`,\n\n /** DELETE: remove a document-level embedded file by name-tree key. */\n layerAttachmentItem: (docId: string, layerName: string, key: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachments/${encodeTokenText(key)}`,\n\n /**\n * Immutable decoded bytes of one document-level embedded file. Lives\n * under its own `attachment-files` prefix — a stronger capability tier\n * than the metadata listing, so a CDN credential for one can never\n * authorize the other (the search-rects/search-full rule).\n */\n layerAttachmentFile: (\n docId: string,\n layerName: string,\n key: string,\n attachmentsVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachment-files/${encodeTokenText(key)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** Immutable decoded bytes of a FileAttachment annotation's embedded file. */\n layerAnnotationFile: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n annotKey: string,\n attachmentsVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachment-files/pages/${pageObjectNumber}/items/${encodeURIComponent(annotKey)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /**\n * Immutable BASE bytes of a FileAttachment annotation's embedded file\n * (plane-scope model). Depends on the `annotations` plane (the annotation\n * exists in this view) AND the `attachments` plane (the pin); the origin\n * guard requires both inherited.\n */\n docAnnotationFile: (\n docId: string,\n pageObjectNumber: number,\n annotKey: string,\n attachmentsVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/attachment-files/pages/${pageObjectNumber}/items/${encodeURIComponent(annotKey)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /**\n * GET: full plain-text extraction for a single page at a specific\n * `contentVersion`. Content-addressed; CDN may cache forever.\n * Stale-version requests return 404 and the SDK's transparent\n * retry walks `/head` → `/manifest@docVersion=N` to learn the new\n * `contentVersion`.\n */\n docPageText: (docId: string, pageObjectNumber: number, contentVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/text/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n layerPageText: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n contentVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/text/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n layerPageTextCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/text/pages/${pageObjectNumber}/data`,\n\n docPageGeometry: (docId: string, pageObjectNumber: number, contentVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/geometry/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n docPageGeometryCurrent: (docId: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/geometry/pages/${pageObjectNumber}/data`,\n\n docPageRender: (docId: string, pageObjectNumber: number, token: TokenInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/render/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n docPageRenderCurrent: (docId: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/render/pages/${pageObjectNumber}/data`,\n\n /**\n * Immutable BASE annotated render (plane-scope model). Its OWN path family,\n * not a token flag under `/render/pages/`: an annotated render depends on\n * `content + annotations`, an annotation-free one on `content` alone, and\n * edge grants are prefix-scoped — the prefix law says a path's prefix must\n * identify its full plane-dependency set. Annotatedness is therefore\n * PATH-ONLY (the token/path law): the wire token has no\n * `includeAnnotations` key at all; the annotated family's token carries\n * `annotationVersion`, the free family's cannot.\n */\n docPageRenderAnnotated: (docId: string, pageObjectNumber: number, token: TokenInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/render/annotated/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n layerPageGeometry: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n contentVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/geometry/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n layerPageGeometryCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/geometry/pages/${pageObjectNumber}/data`,\n\n layerPageRender: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n token: TokenInput,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n layerPageRenderCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/pages/${pageObjectNumber}/data`,\n\n /** Layer twin of `docPageRenderAnnotated` — the grammar is uniform:\n * annotatedness is path-only at BOTH tiers. */\n layerPageRenderAnnotated: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n token: TokenInput,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/annotated/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n layerPageRenderAnnotatedCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/annotated/pages/${pageObjectNumber}/data`,\n\n /**\n * Immutable BASE annotation list for a single page (plane-scope model):\n * the shared-URL variant an annotations-inheriting layer resolves at — a\n * base's own annotations (weak-identity ones included) are simply visible\n * through every pristine layer, so 1,000 visitors' sidebars are ONE CDN\n * object served from the base worker session.\n */\n docPageAnnotations: (docId: string, pageObjectNumber: number, annotationVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/annotations/pages/${pageObjectNumber}/items@${encodeAnnotationToken(annotationVersion)}`,\n\n /** Immutable BASE whole-document annotation listing (bulk hydration). */\n docAnnotationsAll: (docId: string, annotationsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/annotations/items@${encodeAnnotationsAllToken(annotationsVersion)}`,\n\n /** Immutable BASE appearance batch (twin of\n * `layerPageAnnotationAppearances` — same `annotations` plane gate). */\n docPageAnnotationAppearances: (docId: string, pageObjectNumber: number, token: TokenInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/annotations/pages/${pageObjectNumber}/appearances@${encodeAnnotationAppearancesRenderToken(token)}`,\n\n /**\n * GET: full annotation list for a single page at a specific\n * `annotationVersion`. Same cache-control rules and 404-retry\n * semantics as `docPageText`. The `items` suffix is the\n * collection name — see file-level docstring.\n */\n layerPageAnnotations: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n annotationVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items@${encodeAnnotationToken(annotationVersion)}`,\n\n /** Immutable LAYER whole-document annotation listing (bulk hydration). */\n layerAnnotationsAll: (docId: string, layerName: string, annotationsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/items@${encodeAnnotationsAllToken(annotationsVersion)}`,\n\n layerPageAnnotationsCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items`,\n\n /**\n * GET: batch-rendered annotation appearance bitmaps for a single page as a\n * `multipart/form-data` body. Sibling collection of `items` under the same\n * `annotations/pages/{N}/` resource, so it shares the `annotations-read`\n * gate (`doc.annotate.read`) and CDN coverage — reading an annotation lets\n * you see its rendered appearance, the same boundary Adobe uses.\n *\n * Content-addressed via the appearance render token (`annotationVersion`\n * plus render options like scale/format); CDN may cache forever. Appearance\n * pixels depend only on the annotation `/AP` stream, so `contentVersion` is\n * deliberately NOT part of the key.\n */\n layerPageAnnotationAppearances: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n token: TokenInput,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/appearances@${encodeAnnotationAppearancesRenderToken(token)}`,\n\n layerPageAnnotationAppearancesCurrent: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/appearances`,\n\n layerPageAnnotationsCreate: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items`,\n\n layerAnnotationByKey: (docId: string, layerName: string, pageObjectNumber: number, key: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/${encodeURIComponent(key)}`,\n\n layerPageAnnotationsMove: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/move`,\n /** POST: flatten a chosen set of the page's annotations into its content\n * (a content + annotation mutation of that page). */\n layerPageAnnotationsFlatten: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/flatten`,\n /** POST: the chosen annotations' appearances as one single-page PDF — a\n * derived read (application/pdf, no-store), gated like pages/extract. */\n layerPageAnnotationsAppearance: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/appearance`,\n\n /**\n * GET: the reconciled form snapshot (field tree + widget joins) for the\n * layer's CURRENT state. Forms are document-scoped (one AcroForm per\n * document), so there is no per-page collection and — unlike annotations —\n * no content-addressed `@version` variant: the snapshot is always served\n * `no-store`. Mutation results carry the per-page `cacheDelta` that keeps\n * annotation/render caches coherent when widget appearances change.\n */\n layerForm: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form`,\n\n /** POST: create a field (optionally with styled widget placements). */\n layerFormFields: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields`,\n\n /**\n * Field member: GET (single field) / PATCH (updateField) / DELETE\n * (deleteField + widget cascade). `fieldKey` is an encoded `FormFieldRef`\n * (`encodeFieldRefKey`): `obj:12` or `fqn:billing.name`.\n */\n layerFormFieldByKey: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}`,\n\n /** POST: replace the field's value (`{ value: FormFieldValue }`). */\n layerFormFieldValue: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/value`,\n\n /** POST: reset the field to /DV (or clear). Empty body. */\n layerFormFieldReset: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/reset`,\n\n /** POST: adopt an inert widget annotation (`{ widget, onState? }`). */\n layerFormFieldWidgets: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/widgets`,\n\n /**\n * POST: release a widget back to the inert annotation plane\n * (`{ widget }`). An action POST rather than a member DELETE because a\n * widget ref is a (page, annotation) pair — carrying it in the body keeps\n * one codec instead of inventing a second composite key syntax.\n */\n layerFormFieldWidgetsDetach: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/widgets/detach`,\n\n /**\n * GET: serialized form data (`?format=fdf|xfdf`, default `xfdf`).\n * POST: import an FDF/XFDF payload (raw bytes body; format sniffed\n * server-side unless `?format=` pins it).\n */\n layerFormData: (docId: string, layerName: string, format?: 'fdf' | 'xfdf') =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/data${format ? `?format=${format}` : ''}`,\n\n /** POST: durable reconciliation (`{ bakeAppearances? }`). */\n layerFormRepair: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/repair`,\n\n layerFormEffects: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/effects`,\n\n /**\n * GET: one budgeted search slice, versioned form. The token\n * (`encodeSearchToken`) IS the cache key: content epoch + query +\n * position. Immutable; CDN may cache forever. Mode is the path — rects\n * and full are separate resources so permission tiers never share\n * cache entries (`'rects'` needs `doc.text.search`; `'full'` also\n * needs `doc.text.copy`).\n */\n layerSearchRects: (docId: string, layerName: string, token: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/rects/data@${token}`,\n\n layerSearchFull: (docId: string, layerName: string, token: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/full/data@${token}`,\n\n /**\n * GET: unversioned form — same fields as flat query params (`q` as\n * plain text), served from the CURRENT content, always `no-store`.\n * The debug/simple-client variant; the SDK uses the versioned form.\n */\n layerSearchRectsCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/rects/data`,\n\n layerSearchFullCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/full/data`,\n\n layerPagesMove: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/move`,\n\n layerPagesRotate: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/rotate`,\n\n layerPagesDelete: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/delete`,\n /** POST: register/rename a `/Names /Pages` entry — a page-STRUCTURE\n * mutation (docVersion + layoutVersion advance; reads ride `/layout`). */\n layerPagesNames: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/names`,\n /** POST: remove a `/Names /Pages` entry (the page stays). */\n layerPagesNamesDelete: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/names/delete`,\n\n layerPagesFlatten: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/flatten`,\n\n /**\n * POST (multipart mutation envelope): copy every page of the `source`\n * resource part (a standalone PDF) in at the body's `destIndex`.\n */\n layerPagesInsert: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/insert`,\n\n /** POST (plain JSON): create blank pages — pages.insert minus the bytes. */\n layerPagesInsertBlank: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/insert-blank`,\n\n /**\n * POST (plain JSON → `application/pdf` bytes): export the listed pages,\n * in caller order, as a standalone PDF. A READ over the current layer\n * state (gated like /download), so it is a POST only for its body —\n * nothing mutates and no event is published.\n */\n layerPagesExtract: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/extract`,\n\n layerRedactionsApply: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/redactions/apply`,\n\n layerEvents: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/events`,\n\n layerDownload: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/download`,\n\n layerDownloadVersioned: (docId: string, layerName: string, token: DownloadToken) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/download@${encodeDownloadToken(token)}`,\n\n /**\n * Weak-annotation-sessions: pluralized in v2 so the collection\n * lives at `/weak-annotation-sessions` and members at\n * `/weak-annotation-sessions/{sessionId}` — REST-conventional.\n */\n layerWeakAnnotationSession: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions`,\n\n layerWeakAnnotationSessionHeartbeat: (docId: string, layerName: string, sessionId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions/${encodeURIComponent(sessionId)}/heartbeat`,\n\n layerWeakAnnotationSessionPages: (docId: string, layerName: string, sessionId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions/${encodeURIComponent(sessionId)}/pages`,\n\n layerWeakAnnotationSessionRelease: (docId: string, layerName: string, sessionId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions/${encodeURIComponent(sessionId)}`,\n\n /**\n * POST: pre-warm the doc cache + worker open before any user\n * request lands. Body is `{ docId }`. Doc-scoped token required.\n */\n docWarm: '/v1/warm',\n} as const;\n\n/**\n * Fastify-style templates for the PLAIN (unversioned) doc-plane routes —\n * the backend-callable subset that the `@cloudpdf/contract` contract\n * documents. The immutable `@{version}` variants above remain viewer\n * protocol and are deliberately absent. These templates are the single\n * statement of those paths: the contract package imports them, and the\n * server's route table is pinned to them by the doc-plane registry\n * conformance test.\n */\n/** The flat query of a version analysis (the contract's dotted keys). */\nexport interface AnalysisQueryInput {\n since: { signatureIndex: number } | { revisionIndex: number };\n /** Revision index the analysis ends at; default the last. */\n until?: number;\n exploratoryLevel?: ModificationLevel;\n detail?: 'summary' | 'full';\n}\n\nexport function analysisQueryString(query: AnalysisQueryInput): string {\n const params = new URLSearchParams();\n if ('signatureIndex' in query.since)\n params.set('since.signature', String(query.since.signatureIndex));\n else params.set('since.revision', String(query.since.revisionIndex));\n if (query.until !== undefined) params.set('until', String(query.until));\n if (query.exploratoryLevel !== undefined) params.set('level', query.exploratoryLevel);\n if (query.detail !== undefined) params.set('detail', query.detail);\n // The judging policy version: a cache key on the immutable version URL, so\n // a policy bump never serves a verdict judged the old way.\n params.set('policy', String(SIGNATURE_POLICY_VERSION));\n return params.toString();\n}\n\nexport const wireTemplates = {\n docHead: '/v1/docs/:docId/head',\n layerManifest: '/v1/docs/:docId/layers/:layerName/manifest',\n layerMetadata: '/v1/docs/:docId/layers/:layerName/metadata',\n layerRenderPage: '/v1/docs/:docId/layers/:layerName/render/pages/:pon/data',\n layerTextPage: '/v1/docs/:docId/layers/:layerName/text/pages/:pon/data',\n layerAnnotationItemsAll: '/v1/docs/:docId/layers/:layerName/annotations/items',\n layerAnnotationItems: '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items',\n layerAnnotationItem: '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items/:annotKey',\n layerAnnotationItemsFlatten:\n '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items/flatten',\n layerAnnotationItemsAppearance:\n '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items/appearance',\n layerForm: '/v1/docs/:docId/layers/:layerName/form',\n layerFormFieldValue: '/v1/docs/:docId/layers/:layerName/form/fields/:fieldKey/value',\n layerFormFieldReset: '/v1/docs/:docId/layers/:layerName/form/fields/:fieldKey/reset',\n layerFormFieldSignatureAppearance:\n '/v1/docs/:docId/layers/:layerName/form/fields/:fieldKey/signature-appearance',\n layerFormData: '/v1/docs/:docId/layers/:layerName/form/data',\n layerPagesMove: '/v1/docs/:docId/layers/:layerName/pages/move',\n layerPagesRotate: '/v1/docs/:docId/layers/:layerName/pages/rotate',\n layerPagesDelete: '/v1/docs/:docId/layers/:layerName/pages/delete',\n layerPagesNames: '/v1/docs/:docId/layers/:layerName/pages/names',\n layerPagesNamesDelete: '/v1/docs/:docId/layers/:layerName/pages/names/delete',\n layerPagesFlatten: '/v1/docs/:docId/layers/:layerName/pages/flatten',\n layerPagesInsert: '/v1/docs/:docId/layers/:layerName/pages/insert',\n layerPagesInsertBlank: '/v1/docs/:docId/layers/:layerName/pages/insert-blank',\n layerPagesExtract: '/v1/docs/:docId/layers/:layerName/pages/extract',\n layerRedactionsApply: '/v1/docs/:docId/layers/:layerName/redactions/apply',\n layerDownload: '/v1/docs/:docId/layers/:layerName/download',\n layerSignatures: '/v1/docs/:docId/layers/:layerName/signatures',\n layerSignaturesAnalysis: '/v1/docs/:docId/layers/:layerName/signatures/analysis',\n layerSignaturesPrepare: '/v1/docs/:docId/layers/:layerName/signatures/prepare',\n layerSignatureComplete: '/v1/docs/:docId/layers/:layerName/signatures/:signingId/complete',\n layerSignatureAbort: '/v1/docs/:docId/layers/:layerName/signatures/:signingId',\n docVersions: '/v1/docs/:docId/versions',\n docVersionSignatures: '/v1/docs/:docId/versions/signatures/:sha',\n docVersionSignatureContents: '/v1/docs/:docId/versions/signatures/:sha/:fieldKey/contents',\n docVersionSignatureDigest: '/v1/docs/:docId/versions/signatures/:sha/:fieldKey/digest/:algorithm',\n docVersionAnalysis: '/v1/docs/:docId/versions/analysis/:sha',\n docVersionDownload: '/v1/docs/:docId/versions/download/:sha',\n docVersionRevision: '/v1/docs/:docId/versions/revisions/:sha/:index',\n} as const;\n","/**\n * Single source of truth mapping every CDN-relevant read resource to:\n * - its URL path pattern (with glob wildcards for CDN signing)\n * - the capability requirement that gates it\n * - whether it's CDN-cacheable\n * - whether the route is origin-only or versioned-read\n *\n * Consumed by:\n * - server route guards via `requireResource(req, docId, id, pdfBits)`\n * - the CDN signer to determine which path prefixes to cover for a token\n * - documentation generators\n *\n * NOTE: only READ resources go in this table. Mutation routes\n * (POST/PATCH/DELETE) use collab scopes with target lookup and don't\n * fit a single capability requirement. /access is also NOT in the\n * table — it's a session-establishment POST that performs its own\n * doc-access check without requiring any capability.\n */\n\nimport type { DocCapability, PdfBits } from '../auth/scope';\nimport { checkAnyCapability, checkCapability } from '../auth/scope';\n\n/**\n * Canonical id for every read resource the server exposes.\n *\n * Adding a new resource:\n * 1. Add the id to this union\n * 2. Add a `DOC_RESOURCES` entry\n * 3. Update the route handler to call `requireResource(req, docId, '<id>', pdfBits)`\n * 4. CDN signer automatically considers it\n */\nexport type DocResourceId =\n | 'head'\n | 'manifest'\n | 'page-render'\n // Plane-prefix rule: annotated renders are their OWN family — they depend\n // on content+annotations while `/render/pages/` depends on content alone,\n // and edge grants see only prefixes, so the dependency set must be\n // visible in the path.\n | 'page-render-annotated'\n | 'page-text'\n | 'page-geometry'\n // Plane-scope model: doc-level shared variants, one per plane-dependent\n // read family. Each resolves at the base view while the planes it depends\n // on are inherited — see the RESOURCE_PLANES map in wire/cdn/coverage.ts.\n | 'page-annotations'\n // Whole-document bulk annotation listing, doc-level + layer twin. Its\n // own family: the path is NOT under the per-page `annotations/pages/`\n // prefix, so it needs its own catalogue entry for edge grants.\n | 'annotations-all'\n | 'layout'\n | 'metadata'\n | 'actions'\n | 'attachments'\n | 'attachment-files'\n // Layer-scoped variants of the page resources. Same capability\n // gates as their doc-level cousins (the layer just provides a\n // possibly-divergent VIEW of the underlying page content — e.g.\n // server-side redactions in the future). Cataloguing both shapes\n // means the CDN signer covers the prefixes the SDK actually\n // requests. See ADR-002 / paths-v2 design for the doc-vs-layer\n // split rationale.\n | 'layer-manifest'\n | 'layer-layout'\n | 'layer-metadata'\n // Digital signatures: the layer's snapshot and analysis (pinned by\n // docVersion, like the manifest), and the version-scoped families —\n // content-addressed by base sha, each under its OWN prefix (the CDN\n // signs literal prefixes, so a grant for signature reads must never\n // also cover version downloads). The versions LIST is origin-only.\n | 'layer-signatures'\n | 'layer-signatures-analysis'\n | 'versions'\n | 'version-signatures'\n | 'version-analysis'\n | 'version-download'\n | 'version-revisions'\n | 'layer-actions'\n | 'layer-page-render'\n // Layer twin of `page-render-annotated`: annotatedness is path-only at\n // BOTH tiers (uniform grammar), even though layer grants don't need the\n // distinction — see the token/path law in wire/paths.ts.\n | 'layer-page-render-annotated'\n | 'layer-page-text'\n | 'layer-page-geometry'\n // Search slices, one resource per PERMISSION TIER: rects-only results\n // vs snippet-carrying results live under distinct path prefixes, so a\n // CDN credential for one can never authorize (or cache-hit) the other.\n | 'layer-search-rects'\n | 'layer-search-full'\n | 'annotations-read'\n | 'layer-annotations-all'\n // Attachments, split by permission tier under DISTINCT prefixes (the\n // search-rects/search-full rule): the metadata listing rides the base\n // read capability, while decoded file bytes egress content and gate on\n // the download capability — an edge credential for the listing prefix\n // must never authorize the byte prefix.\n | 'layer-attachments'\n | 'layer-attachment-files'\n | 'download-current'\n | 'download-versioned';\n\n/**\n * 'origin' — unversioned URL, response can change over time. CDN must\n * not cache (the bytes are not immutable). Routed straight to origin\n * with the JWT bearer.\n *\n * 'versioned-read' — URL is content-addressed via `@<token>`. Response\n * is immutable for the lifetime of the version. Safe to cache forever\n * at the CDN edge.\n */\nexport type RouteKind = 'origin' | 'versioned-read';\n\n/**\n * Capability requirement attached to a resource. Three shapes:\n * - `single` — one capability gates the resource\n * - `any` — any one of N capabilities gates the resource\n * (used by /text and /geometry which accept either the\n * copy/select scope OR the future search scope)\n * - `all` — every one of N capabilities is required\n * (used by /search/full: a snippet IS extracted text, so\n * the search scope alone is not enough — the copy denial\n * must hold here too)\n */\nexport type CapabilityRequirement =\n | { kind: 'single'; capability: DocCapability }\n | { kind: 'any'; capabilities: ReadonlyArray<DocCapability> }\n | { kind: 'all'; capabilities: ReadonlyArray<DocCapability> };\n\nexport interface DocResourceDescriptor {\n /** Stable id used by route guards and the CDN signer. */\n id: DocResourceId;\n /**\n * Display pattern with `{docId}` / `{layerName}` placeholders for\n * docs + telemetry. Use {@link DocResourceDescriptor.resolvePathPattern}\n * to get a concrete pattern with values filled in.\n */\n pathPattern: string;\n /**\n * Concrete CDN path pattern with `*` wildcards. Used by adapters\n * that do explicit pattern matching at the edge (CloudFront via\n * Resource globs). For path prefixes with no layer component,\n * `layerName` is ignored.\n */\n resolvePathPattern(docId: string, layerName?: string): string;\n /**\n * Display prefix with `{docId}` / `{layerName}` placeholders. The\n * literal path-prefix the CDN signs for this resource — by design,\n * each resource type has its OWN distinct prefix, so a token\n * signed at this prefix authorizes only this resource type at the\n * edge (works on prefix-matching CDNs like Bunny / Cloud CDN /\n * Azure FD with no extra cleverness).\n */\n pathPrefix: string;\n /**\n * Concrete path prefix the CDN signer uses. The literal string\n * `pathPattern` would have *before* the first `*` wildcard — but\n * stored explicitly here rather than derived so future pattern\n * syntax changes can't accidentally break CDN security.\n *\n * For resources with no layer component, `layerName` is ignored.\n */\n resolvePathPrefix(docId: string, layerName?: string): string;\n /** What capability (or set) is needed to access this resource. */\n requirement: CapabilityRequirement;\n /** Versioned-immutable vs. unversioned-mutable. */\n routeKind: RouteKind;\n /**\n * Can the CDN sign coverage for this resource? Mutable/unversioned\n * resources (head, current download) are always false even though\n * they're routed via origin.\n */\n cdnCacheable: boolean;\n}\n\n/**\n * URL layout (paths v2): each resource type lives at a distinct path\n * prefix so prefix-matching CDNs (Bunny, Cloud CDN, Azure FD) can\n * enforce per-resource scope at the edge. See wire/paths.ts for the\n * full shape and rationale.\n */\nexport const DOC_RESOURCES: Readonly<Record<DocResourceId, DocResourceDescriptor>> = {\n head: {\n id: 'head',\n pathPattern: '/v1/docs/{docId}/head',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/head`,\n pathPrefix: '/v1/docs/{docId}/head',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/head`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'origin',\n cdnCacheable: false,\n },\n manifest: {\n id: 'manifest',\n pathPattern: '/v1/docs/{docId}/manifest@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/manifest@*`,\n pathPrefix: '/v1/docs/{docId}/manifest@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/manifest@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-manifest': {\n id: 'layer-manifest',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/manifest@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/manifest@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/manifest@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/manifest@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-render': {\n id: 'page-render',\n pathPattern: '/v1/docs/{docId}/render/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/render/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/render/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/render/pages/`,\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-render-annotated': {\n id: 'page-render-annotated',\n pathPattern: '/v1/docs/{docId}/render/annotated/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/render/annotated/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/render/annotated/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/render/annotated/pages/`,\n // Same capability tier as `page-render` — the split is about PLANE\n // dependencies (content+annotations vs content), not permissions.\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-annotations': {\n id: 'page-annotations',\n pathPattern: '/v1/docs/{docId}/annotations/pages/*/items@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/annotations/pages/*/items@*`,\n // Prefix deliberately covers the `appearances@` sibling too, mirroring\n // the layer-scoped `annotations-read` rule: reading an annotation lets\n // you see its rendered appearance.\n pathPrefix: '/v1/docs/{docId}/annotations/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/annotations/pages/`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'annotations-all': {\n id: 'annotations-all',\n pathPattern: '/v1/docs/{docId}/annotations/items@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/annotations/items@*`,\n pathPrefix: '/v1/docs/{docId}/annotations/items@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/annotations/items@`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n layout: {\n id: 'layout',\n pathPattern: '/v1/docs/{docId}/layout@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/layout@*`,\n pathPrefix: '/v1/docs/{docId}/layout@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/layout@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n metadata: {\n id: 'metadata',\n pathPattern: '/v1/docs/{docId}/metadata@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/metadata@*`,\n pathPrefix: '/v1/docs/{docId}/metadata@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/metadata@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n actions: {\n id: 'actions',\n pathPattern: '/v1/docs/{docId}/actions@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/actions@*`,\n pathPrefix: '/v1/docs/{docId}/actions@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/actions@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-layout': {\n id: 'layer-layout',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/layout@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/layout@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/layout@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/layout@`,\n // Geometry is the same session-level read as the manifest; gate it\n // behind `doc.open` just like `layer-manifest`.\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-metadata': {\n id: 'layer-metadata',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/metadata@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/metadata@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/metadata@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/metadata@`,\n // Metadata is the same session-level read as the manifest; gate it\n // behind `doc.open` just like `layer-manifest` / `layer-layout`.\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-actions': {\n id: 'layer-actions',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/actions@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/actions@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/actions@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/actions@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n attachments: {\n id: 'attachments',\n pathPattern: '/v1/docs/{docId}/attachments@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/attachments@*`,\n pathPrefix: '/v1/docs/{docId}/attachments@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/attachments@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'attachment-files': {\n id: 'attachment-files',\n pathPattern: '/v1/docs/{docId}/attachment-files/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/attachment-files/*`,\n pathPrefix: '/v1/docs/{docId}/attachment-files/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/attachment-files/`,\n // Same tier split as the layer variants: the byte leaf is a stronger\n // capability than the metadata listing.\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-attachments': {\n id: 'layer-attachments',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/attachments@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachments@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/attachments@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachments@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-attachment-files': {\n id: 'layer-attachment-files',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/attachment-files/*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachment-files/*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/attachment-files/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachment-files/`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-render': {\n id: 'layer-page-render',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/render/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/render/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/pages/`,\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-render-annotated': {\n id: 'layer-page-render-annotated',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/render/annotated/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/annotated/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/render/annotated/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/annotated/pages/`,\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-text': {\n id: 'page-text',\n pathPattern: '/v1/docs/{docId}/text/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/text/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/text/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/text/pages/`,\n // Only doc.text.copy gates /text. doc.text.search is reserved for a\n // future dedicated /search endpoint and intentionally does NOT\n // grant /text access here.\n requirement: { kind: 'single', capability: 'doc.text.copy' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-text': {\n id: 'layer-page-text',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/text/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/text/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/text/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/text/pages/`,\n requirement: { kind: 'single', capability: 'doc.text.copy' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-geometry': {\n id: 'page-geometry',\n pathPattern: '/v1/docs/{docId}/geometry/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/geometry/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/geometry/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/geometry/pages/`,\n // Same logic as /text: search is reserved for a future endpoint.\n requirement: { kind: 'single', capability: 'doc.text.select' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-geometry': {\n id: 'layer-page-geometry',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/geometry/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/geometry/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/geometry/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/geometry/pages/`,\n requirement: { kind: 'single', capability: 'doc.text.select' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-search-rects': {\n id: 'layer-search-rects',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/search/rects/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/rects/data@*`,\n // Prefix ends at `data@`: the CDN credential covers ONLY the\n // versioned, immutable form — the unversioned `data` URL is\n // origin-routed and never edge-cached.\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/search/rects/data@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/rects/data@`,\n requirement: { kind: 'single', capability: 'doc.text.search' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-search-full': {\n id: 'layer-search-full',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/search/full/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/full/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/search/full/data@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/full/data@`,\n requirement: { kind: 'all', capabilities: ['doc.text.search', 'doc.text.copy'] },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'annotations-read': {\n id: 'annotations-read',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/annotations/pages/*/items@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/pages/*/items@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/annotations/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/pages/`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-annotations-all': {\n id: 'layer-annotations-all',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/annotations/items@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/items@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/annotations/items@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/items@`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'download-current': {\n id: 'download-current',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/download',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/download',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'origin',\n cdnCacheable: false,\n },\n 'download-versioned': {\n id: 'download-versioned',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/download@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/download@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download@`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-signatures': {\n id: 'layer-signatures',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/signatures@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/signatures@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures@`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-signatures-analysis': {\n id: 'layer-signatures-analysis',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/signatures/analysis@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures/analysis@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/signatures/analysis@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures/analysis@`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n versions: {\n id: 'versions',\n pathPattern: '/v1/docs/{docId}/versions',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions`,\n pathPrefix: '/v1/docs/{docId}/versions',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'origin',\n // The list grows with every signature and its prefix covers every\n // version family below: never signed at the edge.\n cdnCacheable: false,\n },\n 'version-signatures': {\n id: 'version-signatures',\n pathPattern: '/v1/docs/{docId}/versions/signatures/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/signatures/*`,\n pathPrefix: '/v1/docs/{docId}/versions/signatures/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/signatures/`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'version-analysis': {\n id: 'version-analysis',\n pathPattern: '/v1/docs/{docId}/versions/analysis/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/analysis/*`,\n pathPrefix: '/v1/docs/{docId}/versions/analysis/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/analysis/`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'version-download': {\n id: 'version-download',\n pathPattern: '/v1/docs/{docId}/versions/download/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/download/*`,\n pathPrefix: '/v1/docs/{docId}/versions/download/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/download/`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'version-revisions': {\n id: 'version-revisions',\n pathPattern: '/v1/docs/{docId}/versions/revisions/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/revisions/*`,\n pathPrefix: '/v1/docs/{docId}/versions/revisions/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/revisions/`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n};\n\n/**\n * True iff the scope grants access to the named resource.\n *\n * Looks up the resource descriptor, then dispatches to\n * `checkCapability` or `checkAnyCapability` based on the requirement\n * shape. Used by both server route guards and the CDN signer.\n */\nexport function checkResourceAccess(\n resourceId: DocResourceId,\n rawScope: ReadonlyArray<string>,\n pdfBits: PdfBits,\n): boolean {\n const r = DOC_RESOURCES[resourceId];\n switch (r.requirement.kind) {\n case 'single':\n return checkCapability(r.requirement.capability, rawScope, pdfBits);\n case 'any':\n return checkAnyCapability(r.requirement.capabilities, rawScope, pdfBits);\n case 'all':\n return r.requirement.capabilities.every((cap) => checkCapability(cap, rawScope, pdfBits));\n }\n}\n\n// CDN-specific helpers (cdnCoverageForScope, CdnCoverageEntry,\n// applyCdnAccess, resolveResourceIdForPath) live under ./cdn/. They\n// build on DOC_RESOURCES + checkResourceAccess but are intentionally\n// segregated so cloud-only consumers don't accidentally pull general\n// route-guard code via the CDN module, and vice versa.\n","/**\n * Per-scope CDN coverage enumeration.\n *\n * Filters DOC_RESOURCES to the cacheable entries the caller's scope\n * grants, returning both URL projections every signer family needs:\n * - `pathPattern` — for glob-matching signers (CloudFront)\n * - `pathPrefix` — for prefix-matching signers (Bunny / Cloud CDN /\n * Azure FD / custom HMAC)\n *\n * Consumed by:\n * - the server's /access route, which feeds it into the CDN signer\n * - tests that pin per-scope coverage\n *\n * Never imported by engine-local — this is HTTP-wire territory.\n */\n\nimport type { PdfBits } from '../../auth/scope';\nimport type { LayerScopePlane, LayerScopes } from '../../dto/LayerScopes';\nimport { checkResourceAccess, DOC_RESOURCES, type DocResourceId } from '../resources';\n\n/**\n * One CDN-coverage entry: the resource id plus both projections of its\n * URL — the wildcard `pathPattern` (for pattern-matching CDN signers\n * like CloudFront) and the literal `pathPrefix` (for prefix-matching\n * CDN signers like Bunny / Cloud CDN / Azure FD / custom HMAC).\n *\n * Each entry corresponds to one cacheable resource the caller's\n * scope grants access to. Both projections are pre-resolved with the\n * concrete `docId` / `layerName` filled in.\n */\nexport interface CdnCoverageEntry {\n readonly resourceId: DocResourceId;\n /** Resolved CDN path pattern with `*` wildcards (for glob signers). */\n readonly pathPattern: string;\n /** Resolved literal path prefix (for prefix-match signers). */\n readonly pathPrefix: string;\n}\n\n/**\n * Enumerate the CDN-cacheable resources the scope can access. Returns\n * one {@link CdnCoverageEntry} per granted cacheable resource, carrying\n * both the pattern and the prefix so each adapter can pick the\n * projection it needs.\n *\n * Resources that are not cacheable (head, download-current) are\n * filtered out automatically — they're still gated by their\n * `requirement` at the origin route, but the CDN never gets a\n * credential for them.\n *\n * The URL restructure (paths v2) guarantees each cacheable resource\n * type has a distinct prefix, so prefix-matching adapters get\n * per-resource scope enforcement at the edge — a Bunny token signed\n * at `/v1/docs/{id}/render/pages/` can only authorize render bytes,\n * never text or annotations.\n */\n/**\n * Plane map: the planes each DOC-LEVEL shared resource depends on. A\n * layer token's edge credential covers a resource's prefix iff EVERY listed\n * plane is inherited (`'base'`) in the caller's scopes — the same condition\n * the origin guard enforces (origin is the truth; this grant is the\n * TTL-bounded optimization). Resources absent from this map (head, manifest,\n * every layer-scoped resource) are not plane-gated.\n *\n * `attachment-files` deliberately lists only `attachments` even though its\n * prefix also serves FileAttachment-annotation bytes (an `annotations`-plane\n * read): the origin guard on that route additionally requires `annotations`\n * inherited, and withholding the whole prefix on annotation divergence would\n * break plain attachment-file sharing for the most common divergence. The\n * residual is a warm-edge window bounded by the grant TTL — the same class\n * as every edge grant.\n */\nconst RESOURCE_PLANES: Partial<Record<DocResourceId, readonly LayerScopePlane[]>> = {\n 'page-render': ['content'],\n 'page-text': ['content'],\n 'page-geometry': ['content'],\n 'page-render-annotated': ['content', 'annotations'],\n 'page-annotations': ['annotations'],\n 'annotations-all': ['annotations'],\n layout: ['layout'],\n metadata: ['metadata'],\n actions: ['actions'],\n attachments: ['attachments'],\n 'attachment-files': ['attachments'],\n};\n\nexport function cdnCoverageForScope(\n rawScope: ReadonlyArray<string>,\n pdfBits: PdfBits,\n context: {\n docId: string;\n layerName?: string;\n /**\n * Plane scopes of the caller's pinned layer. A doc-level shared\n * resource's prefix is covered iff every plane it depends on is\n * inherited (`'base'`). Omitted = no layer in play (tenant tokens) —\n * everything the capability scope allows is granted.\n */\n scopes?: LayerScopes;\n },\n): ReadonlyArray<CdnCoverageEntry> {\n const out: CdnCoverageEntry[] = [];\n const scopes = context.scopes;\n for (const id of Object.keys(DOC_RESOURCES) as DocResourceId[]) {\n const r = DOC_RESOURCES[id];\n if (!r.cdnCacheable) continue;\n const planes = RESOURCE_PLANES[id];\n if (planes && scopes && planes.some((plane) => scopes[plane] === 'layer')) continue;\n if (!checkResourceAccess(id, rawScope, pdfBits)) continue;\n out.push({\n resourceId: id,\n pathPattern: r.resolvePathPattern(context.docId, context.layerName),\n pathPrefix: r.resolvePathPrefix(context.docId, context.layerName),\n });\n }\n return out;\n}\n","/**\n * Pure function that turns a request path + a `CdnAccessInfo` block\n * into the final URL the SDK should hit, plus any header/cookie side\n * effects to attach. Used by both:\n * - the @cloudpdf/engine HttpClient (to actually route requests through\n * the CDN edge when an /access response says it can)\n * - the smoke/diagnostic inspector (to PREVIEW what the SDK would do\n * for a given path, with no network)\n *\n * Keeping this in engine-core means cloud-side request routing and\n * server-side test fixtures use the SAME algorithm. If a regression\n * sneaks in, both ends break together.\n *\n * Selection rules\n * ───────────────\n * 1. Resolve the request path to a `DocResourceId` via DOC_RESOURCES\n * (longest-prefix-match on the resolved `pathPrefix`). Routes\n * that don't map to a known resource (admin, /access itself) get\n * `routedToCdn: false` and stay on origin.\n * 2. If `baseUrlOverrides[resourceId]` exists, swap the request's\n * origin to that CDN origin. If absent, the request stays on\n * origin — that's how scope narrowing works at the edge: the\n * server only emits overrides for resources the caller's scope\n * grants.\n * 3. Find the LONGEST-matching `signedPathPolicies` entry (its\n * `pathPrefix` is a prefix of the request path). Append its\n * `queryParams`. No match falls back to `signedQueryParams` if\n * the adapter emitted a global token.\n * 4. `signedCookies` and `authHeader` are surfaced verbatim — the\n * HttpClient sets cookies once per session and applies the\n * header to every CDN request.\n */\n\nimport { DOC_RESOURCES, type DocResourceId } from '../resources';\n\n/**\n * Subset of `CdnAccessInfo` this function needs. The full type lives\n * in `engine/DocumentSecurityService.ts` (it's part of the access\n * response); we mirror just the fields we read so this module is\n * decoupled from the security service surface.\n */\nexport interface CdnAccessInfoForApply {\n readonly adapter: string;\n readonly baseUrlOverrides: Partial<Record<string, string>> | null;\n readonly authHeader: { readonly name: string; readonly value: string } | null;\n readonly signedQueryParams: Record<string, string> | null;\n readonly signedCookies: ReadonlyArray<{\n readonly name: string;\n readonly value: string;\n readonly domain?: string;\n readonly path?: string;\n readonly expires?: number;\n }> | null;\n readonly signedPathPolicies: ReadonlyArray<{\n readonly pathPrefix: string;\n readonly queryParams: Record<string, string>;\n }> | null;\n}\n\nexport interface ApplyCdnAccessInput {\n /** Path portion of the request (must begin with `/`). */\n readonly path: string;\n /** API server origin the SDK would normally hit, e.g. `https://api.example.com`. */\n readonly originUrl: string;\n /** Doc id used to resolve resource path prefixes. */\n readonly docId: string;\n /** Layer name for layer-scoped resources (defaults to `'default'`). */\n readonly layerName?: string;\n /** Access block from /v1/access. When null, every call goes to origin. */\n readonly cdn: CdnAccessInfoForApply | null;\n}\n\nexport interface ApplyCdnAccessResult {\n /** Final URL the SDK should fetch. */\n readonly url: string;\n /** Resource the path was identified as, or null if it's not a DOC_RESOURCES route. */\n readonly resourceId: DocResourceId | null;\n /** True iff the request was routed to the CDN; false means origin fallthrough. */\n readonly routedToCdn: boolean;\n /** The signedPathPolicies entry that matched, if any. */\n readonly matchedPolicy: {\n readonly pathPrefix: string;\n readonly queryParams: Record<string, string>;\n } | null;\n /** Single global header to attach (custom-hmac header mode only). */\n readonly authHeader: { readonly name: string; readonly value: string } | null;\n /** Cookies the SDK should set on the CDN origin before this request. */\n readonly cookies: CdnAccessInfoForApply['signedCookies'];\n /**\n * Human-readable explanation when `routedToCdn` is false. Empty\n * string when the request did route to CDN.\n */\n readonly fallbackReason: string;\n}\n\nexport function applyCdnAccess(input: ApplyCdnAccessInput): ApplyCdnAccessResult {\n const { path, originUrl, docId, layerName, cdn } = input;\n const layer = layerName ?? 'default';\n\n // 1. Identify the resource by path prefix (or null if it's not a\n // DOC_RESOURCES route — admin endpoints, /access itself, /warm).\n const resourceId = resolveResourceIdForPath(path, docId, layer);\n\n // No CDN configured (no /access call yet, or signer is `none`).\n if (!cdn || cdn.adapter === 'none') {\n return {\n url: `${trimRight(originUrl)}${path}`,\n resourceId,\n routedToCdn: false,\n matchedPolicy: null,\n authHeader: null,\n cookies: null,\n fallbackReason: cdn\n ? 'CDN signer is `none` — every request stays on origin.'\n : 'No CdnAccessInfo on this session — request stays on origin.',\n };\n }\n\n // 2. Not a known cacheable resource → stays on origin.\n if (!resourceId) {\n return {\n url: `${trimRight(originUrl)}${path}`,\n resourceId: null,\n routedToCdn: false,\n matchedPolicy: null,\n authHeader: null,\n cookies: null,\n fallbackReason: 'Request path does not match any known DOC_RESOURCES route.',\n };\n }\n\n const cdnOrigin = cdn.baseUrlOverrides?.[resourceId];\n if (!cdnOrigin) {\n // Resource granted no CDN override → caller's scope didn't grant\n // it (or it's a non-cacheable resource like /head /download).\n return {\n url: `${trimRight(originUrl)}${path}`,\n resourceId,\n routedToCdn: false,\n matchedPolicy: null,\n authHeader: null,\n cookies: null,\n fallbackReason: `No baseUrlOverrides[${resourceId}] — scope does not grant this resource through the CDN.`,\n };\n }\n\n // 3. Find the longest matching signedPathPolicies entry.\n const matchedPolicy = (cdn.signedPathPolicies ?? [])\n .filter((p) => path.startsWith(p.pathPrefix))\n .sort((a, b) => b.pathPrefix.length - a.pathPrefix.length)[0];\n\n const url = new URL(`${trimRight(cdnOrigin)}${path}`);\n if (matchedPolicy) {\n for (const [k, v] of Object.entries(matchedPolicy.queryParams)) {\n url.searchParams.set(k, v);\n }\n } else if (cdn.signedQueryParams) {\n for (const [k, v] of Object.entries(cdn.signedQueryParams)) {\n url.searchParams.set(k, v);\n }\n }\n\n return {\n url: url.toString(),\n resourceId,\n routedToCdn: true,\n matchedPolicy: matchedPolicy\n ? { pathPrefix: matchedPolicy.pathPrefix, queryParams: matchedPolicy.queryParams }\n : null,\n authHeader: cdn.authHeader,\n cookies: cdn.signedCookies,\n fallbackReason: '',\n };\n}\n\n/**\n * Walk DOC_RESOURCES and pick the entry whose resolved `pathPrefix`\n * is a (longest) prefix of `path`. Returns null when no resource\n * matches — admin routes, /access, /warm fall into this bucket.\n *\n * Each cacheable resource has a DISTINCT prefix (paths v2 invariant),\n * so longest-match is deterministic.\n */\nexport function resolveResourceIdForPath(\n path: string,\n docId: string,\n layerName: string,\n): DocResourceId | null {\n let best: { id: DocResourceId; prefixLength: number } | null = null;\n for (const id of Object.keys(DOC_RESOURCES) as DocResourceId[]) {\n const r = DOC_RESOURCES[id];\n const prefix = r.resolvePathPrefix(docId, layerName);\n if (!path.startsWith(prefix)) continue;\n if (!best || prefix.length > best.prefixLength) {\n best = { id, prefixLength: prefix.length };\n }\n }\n return best?.id ?? null;\n}\n\nfunction trimRight(url: string): string {\n return url.endsWith('/') ? url.slice(0, -1) : url;\n}\n","/**\n * Generic recursive flattener for nested option objects into dotted-key flat\n * maps, and its inverse. The wire format (token + query) is a flat key/value\n * shape, but SDK option types (e.g. `PageImageOptions`) are nested with\n * discriminated unions. Keeping these conversions generic means new options\n * never require bespoke encoder/decoder code — they're just shape changes to\n * the schema.\n *\n * Rules:\n * - Nested object keys are joined with `.` (e.g. `viewport.kind`,\n * `target.rect.left`).\n * - `undefined` and `null` are dropped.\n * - Arrays are not supported (the wire format has no list grammar yet).\n * - Scalar leaves must be `string | number | boolean`.\n * - Round-trip: `unflatten(flatten(x))` equals `x` modulo dropped\n * `undefined`/`null` and array leaves.\n *\n * The path separator `.` is reserved in field names by the token codec, which\n * lets us distinguish wire-level structure from value content (values may\n * still contain `.` for decimals — values are not split on `.`).\n */\n\nexport type WireScalar = string | number | boolean;\nexport type WireFlat = Record<string, WireScalar>;\n\nconst PATH_SEPARATOR = '.';\n\nexport function flatten(value: unknown, prefix = ''): WireFlat {\n const out: WireFlat = {};\n flattenInto(value, prefix, out);\n return out;\n}\n\nfunction flattenInto(value: unknown, prefix: string, out: WireFlat): void {\n if (value === undefined || value === null) return;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n if (!prefix) throw new Error('flatten: root value must be an object, not a scalar');\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw new Error(`flatten: non-finite number at \"${prefix}\"`);\n }\n out[prefix] = value;\n return;\n }\n if (Array.isArray(value)) {\n throw new Error(`flatten: arrays are not supported (at \"${prefix || '<root>'}\")`);\n }\n if (typeof value !== 'object') {\n throw new Error(`flatten: unsupported value type at \"${prefix || '<root>'}\"`);\n }\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k.includes(PATH_SEPARATOR)) {\n throw new Error(`flatten: object key \"${k}\" must not contain \"${PATH_SEPARATOR}\"`);\n }\n flattenInto(v, prefix ? `${prefix}${PATH_SEPARATOR}${k}` : k, out);\n }\n}\n\n/**\n * Inverse of `flatten`. Takes a flat string-or-scalar map and reconstructs a\n * nested object using `.` as the path separator. Values are passed through\n * unchanged — downstream schema validation (e.g. Zod with `.coerce`) is\n * responsible for type coercion from `string` to numbers/booleans when the\n * input came from a token or query string.\n *\n * Throws on conflicting paths (e.g. having both `viewport` and\n * `viewport.kind` in the same input).\n */\nexport function unflatten(flat: Record<string, unknown>): Record<string, unknown> {\n const root: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(flat)) {\n if (value === undefined) continue;\n if (key.length === 0) throw new Error('unflatten: empty key');\n if (key.startsWith(PATH_SEPARATOR) || key.endsWith(PATH_SEPARATOR)) {\n throw new Error(`unflatten: key \"${key}\" must not start or end with \"${PATH_SEPARATOR}\"`);\n }\n if (key.includes(`${PATH_SEPARATOR}${PATH_SEPARATOR}`)) {\n throw new Error(`unflatten: key \"${key}\" must not contain empty segments`);\n }\n const path = key.split(PATH_SEPARATOR);\n let cur: Record<string, unknown> = root;\n for (let i = 0; i < path.length - 1; i++) {\n const seg = path[i];\n const existing = cur[seg];\n if (existing === undefined) {\n const next: Record<string, unknown> = {};\n cur[seg] = next;\n cur = next;\n continue;\n }\n if (existing === null || typeof existing !== 'object' || Array.isArray(existing)) {\n throw new Error(\n `unflatten: conflicting paths at \"${path.slice(0, i + 1).join(PATH_SEPARATOR)}\"`,\n );\n }\n cur = existing as Record<string, unknown>;\n }\n const leaf = path[path.length - 1];\n if (cur[leaf] !== undefined) {\n throw new Error(`unflatten: duplicate key \"${key}\"`);\n }\n cur[leaf] = value;\n }\n return root;\n}\n","import { flatten, type WireFlat } from './flatten';\nimport { encodeAnnotationAppearancesRenderToken, encodeRenderToken } from './tokens';\nimport type {\n AnnotationAppearanceImageOptions,\n AnnotationAppearanceRenderOptions,\n} from '../dto/AnnotationRender';\nimport type { PageImageOptions, PageRenderOptions } from '../dto/PageRender';\n\nexport interface RenderVersions {\n contentVersion: number;\n annotationVersion?: number;\n}\n\n/**\n * Project image render options plus cache versions into the flat wire shape\n * the render token encoder consumes. The output is a generic dotted-key map\n * (`viewport.kind`, `target.rect.left`, …) — the schema and codec never need\n * to know about specific option fields. Adding a new render option means\n * extending `PageImageOptions`, the render query schemas, and\n * `RenderTokenSchema.fields`; this function does not change.\n *\n * Token/path rule: tokens carry VERSION PINS and RENDER\n * PARAMETERS; anything that changes the artifact's plane-dependency set is\n * PATH-expressed. Annotatedness changes the planes (`content` vs\n * `content + annotations`), so the wire map never carries\n * `includeAnnotations` — the caller picks the path FAMILY\n * (`…/render/pages/` vs `…/render/annotated/pages/`) and passes\n * `annotationVersion` iff it chose the annotated one. Contradictory states\n * are unrepresentable; each family's query schema enforces its own pin\n * grammar structurally.\n *\n * Semantic validation (viewport-kind invariants, per-family pin presence,\n * rect coherence) lives in `PageRenderQuerySchema` /\n * `PageRenderAnnotatedQuerySchema` and runs when the resulting URL is\n * decoded server-side. Round-tripping (flatten → encode → decode →\n * unflatten → schema parse) recovers the original SDK options.\n */\nexport function renderImageOptionsToWire(\n options: PageImageOptions,\n versions: RenderVersions,\n): WireFlat {\n // Path-expressed, never token-expressed (see above).\n const { includeAnnotations: _pathExpressed, ...wireOptions } = options;\n return flatten({\n ...wireOptions,\n contentVersion: versions.contentVersion,\n ...(versions.annotationVersion !== undefined\n ? { annotationVersion: versions.annotationVersion }\n : {}),\n });\n}\n\n/**\n * Convenience: build the full encoded render token in one call. Equivalent\n * to `encodeRenderToken(renderImageOptionsToWire(options, versions))`.\n */\nexport function renderImageOptionsToToken(\n options: PageImageOptions,\n versions: RenderVersions,\n): string {\n return encodeRenderToken(renderImageOptionsToWire(options, versions));\n}\n\n/**\n * Re-attach `includeAnnotations` onto the worker-side `PageRenderOptions`\n * shape. Pure shape transform; consumed by the server route after\n * `PageRenderQuerySchema` has produced the SDK-shaped options.\n */\nexport function pageRenderOptionsFromImageOptions(\n options: PageImageOptions,\n includeAnnotations: boolean,\n): PageRenderOptions {\n return {\n ...(options.target ? { target: options.target } : {}),\n ...(options.viewport ? { viewport: options.viewport } : {}),\n ...(options.rotation !== undefined ? { rotation: options.rotation } : {}),\n ...(options.background !== undefined ? { background: options.background } : {}),\n includeAnnotations,\n };\n}\n\n/**\n * Cache version for the appearance render token. Appearances depend only on\n * the annotation `/AP` stream, so `annotationVersion` is the sole key —\n * deliberately NOT `contentVersion`.\n */\nexport interface AnnotationRenderVersion {\n annotationVersion: number;\n}\n\n/**\n * Project annotation-appearance image options plus the annotation version\n * into the flat wire shape the appearance render token encoder consumes.\n * Mirrors {@link renderImageOptionsToWire}.\n */\nexport function annotationAppearancesImageOptionsToWire(\n options: AnnotationAppearanceImageOptions,\n versions: AnnotationRenderVersion,\n): WireFlat {\n return flatten({\n ...options,\n annotationVersion: versions.annotationVersion,\n });\n}\n\n/** Convenience: build the full encoded appearance render token in one call. */\nexport function annotationAppearancesImageOptionsToToken(\n options: AnnotationAppearanceImageOptions,\n versions: AnnotationRenderVersion,\n): string {\n return encodeAnnotationAppearancesRenderToken(\n annotationAppearancesImageOptionsToWire(options, versions),\n );\n}\n\n/**\n * Strip image-encoding fields, leaving the worker-side\n * `AnnotationAppearanceRenderOptions`. Pure shape transform consumed by the\n * server route after `AnnotationAppearancesQuerySchema` produces the\n * SDK-shaped options.\n */\nexport function annotationRenderOptionsFromImageOptions(\n options: AnnotationAppearanceImageOptions,\n): AnnotationAppearanceRenderOptions {\n return {\n ...(options.scale !== undefined ? { scale: options.scale } : {}),\n ...(options.rotation !== undefined ? { rotation: options.rotation } : {}),\n ...(options.modes ? { modes: options.modes } : {}),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wire.js","names":[],"sources":["../src/forms/submission.ts","../src/wire/token.ts","../src/wire/tokenSchemas.ts","../src/wire/tokens.ts","../src/wire/paths.ts","../src/wire/resources.ts","../src/wire/cdn/coverage.ts","../src/wire/cdn/applyCdnAccess.ts","../src/wire/flatten.ts","../src/wire/renderOptionsCodec.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * One resolved entry of a form submission. The viewer resolved it with the\n * ISO 32000-2 Table 239/240 semantics already applied (Include/Exclude +\n * descendants, the unconditional NoExport veto, push-button and\n * unsupported-value exclusion), so the home never re-derives selection.\n * `value === null` is a NAME-ONLY entry (the IncludeNoValueFields shape);\n * `string[]` is a multi-select list box.\n */\nexport interface FormSubmissionEntry {\n name: string;\n value: string | string[] | null;\n}\n\n/**\n * What a submit-capable document HOME receives — the resolved dataset plus\n * the document's declared intent as METADATA. The stack never fetches the\n * declared URL itself (a PDF-controlled URL reaching a server-side fetcher\n * is the SSRF class this contract exists to prevent); the home stores the\n * intent so its consumers can decide what to honor.\n *\n * Deliberately ABSENT: identity. The home derives who submitted from its\n * OWN verified session (the JWT it authenticated) — a client-supplied\n * identity would be a spoofing surface.\n */\nexport interface FormSubmissionRequest {\n entries: FormSubmissionEntry[];\n /** The document's declared routing wish, verbatim (metadata, not orders).\n * `url` is null for scripted submits that named no target. */\n intent: {\n url: string | null;\n format: 'fdf' | 'html' | 'xfdf' | 'pdf';\n method: 'post' | 'get';\n /** Raw ISO Table 240 flag word (0 for scripted submits without one). */\n flagsRaw: number;\n /** /CharSet (PDF 2.0), extracted but never encoded by this stack. */\n charSet?: string;\n };\n /** How the submission was triggered — the viewer-derived origin axis. */\n origin: 'user' | 'hover' | 'lifecycle';\n /** Client wall-clock, milliseconds since epoch. Informational — the home\n * stamps its own authoritative `receivedAt`. */\n clientTimeMs: number;\n}\n\n/** The home's acknowledgment: the stored submission's durable identity. */\nexport interface FormSubmissionReceipt {\n submissionId: string;\n /** ISO 8601, the home's clock. */\n receivedAt: string;\n}\n\nexport const FormSubmissionEntrySchema: z.ZodType<FormSubmissionEntry> = z.object({\n name: z.string(),\n value: z.union([z.string(), z.array(z.string()), z.null()]),\n});\n\nexport const FormSubmissionRequestSchema: z.ZodType<FormSubmissionRequest> = z.object({\n entries: z.array(FormSubmissionEntrySchema),\n intent: z.object({\n url: z.string().nullable(),\n format: z.enum(['fdf', 'html', 'xfdf', 'pdf']),\n method: z.enum(['post', 'get']),\n flagsRaw: z.number().int().nonnegative(),\n charSet: z.string().optional(),\n }),\n origin: z.enum(['user', 'hover', 'lifecycle']),\n clientTimeMs: z.number().finite(),\n}) as unknown as z.ZodType<FormSubmissionRequest>;\n\nexport const FormSubmissionReceiptSchema: z.ZodType<FormSubmissionReceipt> = z.object({\n submissionId: z.string().min(1),\n receivedAt: z.string().min(1),\n});\n","export type TokenScalar = string | number | boolean;\nexport type TokenInput = Record<string, TokenScalar | undefined>;\nexport type TokenQuery = Record<string, string>;\n\nexport interface TokenSchema {\n /**\n * Allowed field names. Field names are dotted paths of camelCase segments\n * (e.g. `viewport.kind`, `target.rect.left`). `=` is reserved as the\n * key/value delimiter and `,` as the pair separator, so neither may appear\n * in field names. `.` is the path separator that lets dotted keys round-\n * trip generically through `flatten`/`unflatten`.\n *\n * The token form is intentionally isomorphic to a query string: swap `,`\n * for `&` and you have a query string with identical keys and values.\n * Both `=` and `,` are RFC 3986 sub-delims, allowed unencoded in path\n * segments, so the token never needs URL-encoding for its grammar.\n */\n fields: readonly string[];\n maxLength?: number;\n}\n\nconst DEFAULT_MAX_TOKEN_LENGTH = 256;\n// One or more camelCase segments joined by `.`. Each segment must start with\n// a letter and contain only [A-Za-z0-9]. Reserved characters `=` and `,` are\n// excluded by construction so the codec can parse without escape handling.\nconst FIELD_NAME_RE = /^[A-Za-z][A-Za-z0-9]*(?:\\.[A-Za-z][A-Za-z0-9]*)*$/;\nconst VALUE_RE = /^[A-Za-z0-9.-]+$/;\n\nexport function encodeToken(schema: TokenSchema, input: TokenInput): string {\n assertSchema(schema);\n const allowed = new Set(schema.fields);\n const pairs: Array<[string, string]> = [];\n for (const [key, value] of Object.entries(input)) {\n if (value === undefined) continue;\n assertKnownField(allowed, key);\n const encoded = encodeScalar(key, value);\n assertSafeValue(key, encoded);\n pairs.push([key, encoded]);\n }\n\n pairs.sort(([a], [b]) => a.localeCompare(b));\n const token = pairs.map(([key, value]) => `${key}=${value}`).join(',');\n if (token.length === 0) throw new Error('token must not be empty');\n assertTokenLength(schema, token);\n return token;\n}\n\nexport function decodeToken(schema: TokenSchema, raw: string): TokenQuery {\n assertSchema(schema);\n const token = raw.startsWith('@') ? raw.slice(1) : raw;\n assertTokenLength(schema, token);\n if (token.length === 0) throw new Error('token must not be empty');\n\n const allowed = new Set(schema.fields);\n const output: TokenQuery = {};\n let previousKey: string | undefined;\n\n for (const pair of token.split(',')) {\n if (pair.length === 0) throw new Error('token contains an empty field');\n const separator = pair.indexOf('=');\n if (separator <= 0 || separator === pair.length - 1) {\n throw new Error(`token field \"${pair}\" must be key=value`);\n }\n\n const key = pair.slice(0, separator);\n const value = pair.slice(separator + 1);\n assertKnownField(allowed, key);\n assertSafeValue(key, value);\n if (output[key] !== undefined) throw new Error(`token field \"${key}\" appears more than once`);\n if (previousKey !== undefined && key.localeCompare(previousKey) <= 0) {\n throw new Error('token fields must be in alphabetical order');\n }\n previousKey = key;\n output[key] = value;\n }\n\n return output;\n}\n\nfunction assertSchema(schema: TokenSchema): void {\n for (const field of schema.fields) {\n if (!FIELD_NAME_RE.test(field)) {\n throw new Error(`token field name \"${field}\" must be camelCase segments joined by \".\"`);\n }\n }\n}\n\nfunction assertKnownField(allowed: Set<string>, key: string): void {\n if (!allowed.has(key)) throw new Error(`unknown token field \"${key}\"`);\n}\n\nfunction encodeScalar(key: string, value: TokenScalar): string {\n if (typeof value === 'boolean') return value ? 'true' : 'false';\n if (typeof value === 'number') {\n if (!Number.isFinite(value)) throw new Error(`token field \"${key}\" must be finite`);\n return Number.isInteger(value) ? String(value) : trimDecimal(value);\n }\n return value;\n}\n\nfunction trimDecimal(value: number): string {\n return value.toFixed(6).replace(/0+$/, '').replace(/\\.$/, '');\n}\n\nfunction assertSafeValue(key: string, value: string): void {\n if (!VALUE_RE.test(value)) {\n throw new Error(`token field \"${key}\" value contains a reserved character`);\n }\n}\n\nfunction assertTokenLength(schema: TokenSchema, token: string): void {\n const maxLength = schema.maxLength ?? DEFAULT_MAX_TOKEN_LENGTH;\n if (token.length > maxLength) {\n throw new Error(`token exceeds ${maxLength} characters`);\n }\n}\n","import type { TokenSchema } from './token';\n\nexport const DocTokenSchema = {\n fields: ['docVersion'],\n} as const satisfies TokenSchema;\n\nexport const ContentTokenSchema = {\n fields: ['contentVersion'],\n} as const satisfies TokenSchema;\n\nexport const LayoutTokenSchema = {\n fields: ['layoutVersion'],\n} as const satisfies TokenSchema;\n\nexport const MetadataTokenSchema = {\n fields: ['metadataVersion'],\n} as const satisfies TokenSchema;\n\nexport const AnnotationTokenSchema = {\n fields: ['annotationVersion'],\n} as const satisfies TokenSchema;\n\n/** Doc-level bulk annotations listing pin (plural, vs the per-page\n * `annotationVersion` token above). */\nexport const AnnotationsAllTokenSchema = {\n fields: ['annotationsVersion'],\n} as const satisfies TokenSchema;\n\nexport const ActionsTokenSchema = {\n fields: ['actionsVersion'],\n} as const satisfies TokenSchema;\n\nexport const AttachmentsTokenSchema = {\n fields: ['attachmentsVersion'],\n} as const satisfies TokenSchema;\n\n/**\n * Layer signature analysis: the working copy judged against the base,\n * pinned by `docVersion`; `since.signature` XOR `since.revision`; `level`\n * only in exploratory mode.\n */\nexport const AnalysisTokenSchema = {\n // `policy`: the judging policy version the caller expects — part of the\n // cache key, so a policy bump never serves a verdict judged the old way.\n fields: ['docVersion', 'since.signature', 'since.revision', 'level', 'policy', 'detail'],\n} as const;\n\nexport const DownloadTokenSchema = {\n fields: ['docVersion', 'mode'],\n maxLength: 128,\n} as const satisfies TokenSchema;\n\n/**\n * Allowed flat keys for the render token, expressed as dotted paths that\n * mirror the SDK `PageImageOptions` shape 1:1. The token codec is fully\n * generic over this list — adding a new render option means adding its\n * dotted path here and a matching branch in `PageImageOptionsWireSchema`.\n * No encoder/decoder code changes.\n *\n * `includeAnnotations` is deliberately NOT a token field: annotatedness\n * changes the artifact's plane-dependency\n * set, so it is expressed by the path FAMILY (`…/render/pages/` vs\n * `…/render/annotated/pages/`), never inside the token. `annotationVersion`\n * belongs to the annotated family's tokens only — each family's query\n * schema enforces its own pin grammar.\n */\nexport const RenderTokenSchema = {\n fields: [\n 'annotationVersion',\n 'background',\n 'contentVersion',\n 'format',\n 'quality',\n 'rotation',\n 'target.kind',\n 'target.rect.bottom',\n 'target.rect.left',\n 'target.rect.right',\n 'target.rect.top',\n 'viewport.kind',\n 'viewport.scale',\n 'viewport.width',\n ],\n maxLength: 512,\n} as const satisfies TokenSchema;\n\n/**\n * Token for the versioned search endpoints (`/search/{rects,full}/data@…`).\n * One token carries the whole cache key: the content epoch, the query\n * (text/pattern rides base64-variant-encoded in `q` — the token value\n * charset excludes free text), and the resume position. Canonical by\n * construction: the codec sorts fields and the encoder omits every\n * default, so equal searches produce byte-equal tokens — the property CDN\n * cache hits live on. Mode is NOT a field; it is the endpoint (separate\n * permission tiers must never share cache entries).\n */\nexport const SearchTokenSchema = {\n fields: [\n 'epoch',\n 'format',\n 'ignoreWhitespace',\n 'matchCase',\n 'matchDiacritics',\n 'maxMatches',\n 'maxPages',\n 'q',\n 'regex',\n 'skip',\n 'startPage',\n 'wholeWord',\n ],\n maxLength: 2048,\n} as const satisfies TokenSchema;\n\n/**\n * Token for the batch annotation-appearance render endpoint. Narrower than\n * the page render token: appearance bitmaps are sized per annotation `/Rect`\n * so there is no target/viewport — only a uniform `scale` and page\n * `rotation`. Keyed by `annotationVersion` only (appearances do not depend on\n * page base content). The cloud endpoint renders the Normal appearance only,\n * so `modes` is intentionally absent here (it is a worker/local-only option).\n */\nexport const AnnotationAppearancesRenderTokenSchema = {\n fields: ['annotationVersion', 'format', 'quality', 'rotation', 'scale'],\n maxLength: 256,\n} as const satisfies TokenSchema;\n","import { decodeToken, encodeToken, type TokenInput, type TokenQuery } from './token';\n\nexport type { TokenInput } from './token';\nimport { SIGNATURE_POLICY_VERSION } from '../signature/protection';\nimport {\n AnalysisTokenSchema,\n AnnotationAppearancesRenderTokenSchema,\n AnnotationTokenSchema,\n AnnotationsAllTokenSchema,\n ActionsTokenSchema,\n AttachmentsTokenSchema,\n ContentTokenSchema,\n DocTokenSchema,\n DownloadTokenSchema,\n LayoutTokenSchema,\n MetadataTokenSchema,\n RenderTokenSchema,\n SearchTokenSchema,\n} from './tokenSchemas';\nimport type { PdfSaveMode } from '../dto/PdfSaveMode';\nimport type { ModificationLevel } from '../signature/types';\nimport type { SearchQuery, SearchSliceBudget } from '../search/types';\n\nexport interface DownloadToken {\n docVersion: number;\n mode: PdfSaveMode;\n}\n\n/** The layer analysis token: the pin plus the flat `AnalyzeInput` (until = the working copy). */\nexport interface AnalysisToken {\n docVersion: number;\n since: { signatureIndex: number } | { revisionIndex: number };\n exploratoryLevel?: ModificationLevel;\n /** The judging policy version the caller expects (`SIGNATURE_POLICY_VERSION`); keys the cache. */\n policyVersion?: number;\n /** `full` carries every pairwise step; default `summary`. */\n detail?: 'summary' | 'full';\n}\n\nexport const encodeAnalysisToken = (input: AnalysisToken): string =>\n encodeToken(AnalysisTokenSchema, {\n docVersion: input.docVersion,\n 'since.signature': 'signatureIndex' in input.since ? input.since.signatureIndex : undefined,\n 'since.revision': 'revisionIndex' in input.since ? input.since.revisionIndex : undefined,\n level: input.exploratoryLevel,\n policy: input.policyVersion ?? SIGNATURE_POLICY_VERSION,\n detail: input.detail,\n });\n\nexport const decodeAnalysisToken = (raw: string): AnalysisToken => {\n const t = decodeToken(AnalysisTokenSchema, raw);\n const sinceSignature = t['since.signature'];\n const sinceRevision = t['since.revision'];\n if ((sinceSignature === undefined) === (sinceRevision === undefined)) {\n throw new Error('analysis token needs exactly one of \"since.signature\" / \"since.revision\"');\n }\n return {\n docVersion: decodePositiveInteger(t.docVersion, 'docVersion'),\n since:\n sinceSignature !== undefined\n ? { signatureIndex: decodeNonNegativeInteger(sinceSignature, 'since.signature') }\n : { revisionIndex: decodeNonNegativeInteger(sinceRevision!, 'since.revision') },\n ...(t.level !== undefined ? { exploratoryLevel: decodeModificationLevel(t.level) } : {}),\n ...(t.policy !== undefined ? { policyVersion: decodePositiveInteger(t.policy, 'policy') } : {}),\n ...(t.detail !== undefined ? { detail: decodeDetail(t.detail) } : {}),\n };\n};\n\nfunction decodeDetail(raw: string): 'summary' | 'full' {\n if (raw !== 'summary' && raw !== 'full') {\n throw new Error('token field \"detail\" must be summary|full');\n }\n return raw;\n}\n\nconst MODIFICATION_LEVELS: ReadonlyArray<ModificationLevel> = ['none', 'lta', 'fill', 'annotate'];\nfunction decodeModificationLevel(raw: string): ModificationLevel {\n if (!(MODIFICATION_LEVELS as readonly string[]).includes(raw)) {\n throw new Error(`token field \"level\" must be one of ${MODIFICATION_LEVELS.join('|')}`);\n }\n return raw as ModificationLevel;\n}\n\nfunction decodeNonNegativeInteger(raw: string | undefined, field: string): number {\n if (raw === undefined) throw new Error(`token is missing \"${field}\"`);\n if (!/^(0|[1-9][0-9]*)$/.test(raw))\n throw new Error(`token field \"${field}\" must be a non-negative integer`);\n return Number(raw);\n}\n\nexport const encodeDocToken = (docVersion: number): string =>\n encodeToken(DocTokenSchema, { docVersion });\nexport const decodeDocToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(DocTokenSchema, raw).docVersion, 'docVersion');\n\nexport const encodeContentToken = (contentVersion: number): string =>\n encodeToken(ContentTokenSchema, { contentVersion });\nexport const decodeContentToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(ContentTokenSchema, raw).contentVersion, 'contentVersion');\n\nexport const encodeLayoutToken = (layoutVersion: number): string =>\n encodeToken(LayoutTokenSchema, { layoutVersion });\nexport const decodeLayoutToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(LayoutTokenSchema, raw).layoutVersion, 'layoutVersion');\n\nexport const encodeMetadataToken = (metadataVersion: number): string =>\n encodeToken(MetadataTokenSchema, { metadataVersion });\nexport const decodeMetadataToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(MetadataTokenSchema, raw).metadataVersion, 'metadataVersion');\n\nexport const encodeAnnotationToken = (annotationVersion: number): string =>\n encodeToken(AnnotationTokenSchema, { annotationVersion });\nexport const decodeAnnotationToken = (raw: string): number =>\n decodePositiveInteger(\n decodeToken(AnnotationTokenSchema, raw).annotationVersion,\n 'annotationVersion',\n );\n\nexport const encodeAnnotationsAllToken = (annotationsVersion: number): string =>\n encodeToken(AnnotationsAllTokenSchema, { annotationsVersion });\nexport const decodeAnnotationsAllToken = (raw: string): number =>\n decodePositiveInteger(\n decodeToken(AnnotationsAllTokenSchema, raw).annotationsVersion,\n 'annotationsVersion',\n );\n\nexport const encodeActionsToken = (actionsVersion: number): string =>\n encodeToken(ActionsTokenSchema, { actionsVersion });\nexport const decodeActionsToken = (raw: string): number =>\n decodePositiveInteger(decodeToken(ActionsTokenSchema, raw).actionsVersion, 'actionsVersion');\n\nexport const encodeAttachmentsToken = (attachmentsVersion: number): string =>\n encodeToken(AttachmentsTokenSchema, { attachmentsVersion });\nexport const decodeAttachmentsToken = (raw: string): number =>\n decodePositiveInteger(\n decodeToken(AttachmentsTokenSchema, raw).attachmentsVersion,\n 'attachmentsVersion',\n );\n\nexport const encodeDownloadToken = (input: DownloadToken): string =>\n encodeToken(DownloadTokenSchema, { docVersion: input.docVersion, mode: input.mode });\nexport const decodeDownloadToken = (raw: string): DownloadToken => {\n const decoded = decodeToken(DownloadTokenSchema, raw);\n return {\n docVersion: decodePositiveInteger(decoded.docVersion, 'docVersion'),\n mode: decodePdfSaveMode(decoded.mode),\n };\n};\n\n/**\n * Encode a render token from a flat wire-shape input. The input is the\n * output of `flatten(...)` over an SDK `PageImageOptions`-shaped object plus\n * cache versions. Semantic invariants (viewport-kind XOR fields, per-family\n * pin grammar — annotatedness itself is PATH-expressed, never a token key —\n * target rect coherence) live in the per-family render query schemas —\n * running them here would duplicate the spec.\n */\nexport const encodeRenderToken = (input: TokenInput): string =>\n encodeToken(RenderTokenSchema, input);\n\n/**\n * Decode a render token to a flat `Record<string, string>` of allowed\n * fields. Use `unflatten(...)` + `PageImageOptionsWireSchema.parse(...)` to\n * recover the nested SDK shape with full coercion + validation.\n */\nexport const decodeRenderToken = (raw: string): TokenQuery => decodeToken(RenderTokenSchema, raw);\n\n/**\n * Encode an annotation-appearance render token from a flat wire-shape input\n * (the `flatten(...)` of an `AnnotationAppearanceImageOptions`-shaped object\n * plus cache versions). Semantic validation lives in\n * `AnnotationAppearancesQuerySchema`.\n */\nexport const encodeAnnotationAppearancesRenderToken = (input: TokenInput): string =>\n encodeToken(AnnotationAppearancesRenderTokenSchema, input);\n\n/** Decode an annotation-appearance render token to a flat field map. */\nexport const decodeAnnotationAppearancesRenderToken = (raw: string): TokenQuery =>\n decodeToken(AnnotationAppearancesRenderTokenSchema, raw);\n\n/**\n * The decoded state of a versioned search URL — the WHOLE cache key.\n * `epoch` is `searchContentEpoch(manifest)`; `skip` is the number of\n * scan-order pages already consumed (0 = first slice). The server mints\n * continuation tokens (same epoch, advanced skip); the client decodes\n * them only to verify a resumed cursor still belongs to its query.\n */\nexport interface SearchToken {\n epoch: string;\n query: SearchQuery;\n startPage?: number;\n skip: number;\n budget?: SearchSliceBudget;\n}\n\n/**\n * The search RESULT representation this client speaks — part of the token\n * (and therefore the versioned URL), so a response-shape change can never\n * serve a stale CDN body to a newer client: new tokens are new cache keys,\n * and old tokens fail decode on new servers. Deliberately ALWAYS encoded —\n * an exception to the omit-defaults rule, because its entire job is to\n * change the token bytes when the format changes.\n */\nexport const SEARCH_RESULT_FORMAT = 'segments1';\n\nexport const encodeSearchToken = (input: SearchToken): string => {\n const q = input.query;\n return encodeToken(SearchTokenSchema, {\n epoch: input.epoch,\n format: SEARCH_RESULT_FORMAT,\n q: encodeTokenText(q.text),\n // Canonical keys: every default is OMITTED, never encoded as false/0.\n regex: q.regex ? true : undefined,\n matchCase: q.matchCase ? true : undefined,\n matchDiacritics: q.matchDiacritics ? true : undefined,\n wholeWord: q.wholeWord ? true : undefined,\n ignoreWhitespace: q.ignoreWhitespace ? true : undefined,\n startPage: input.startPage,\n skip: input.skip > 0 ? input.skip : undefined,\n maxPages: input.budget?.maxPages,\n maxMatches: input.budget?.maxMatches,\n });\n};\n\nexport const decodeSearchToken = (raw: string): SearchToken => {\n const t = decodeToken(SearchTokenSchema, raw);\n if (t.epoch === undefined) throw new Error('search token is missing \"epoch\"');\n if (t.q === undefined) throw new Error('search token is missing \"q\"');\n if (t.format !== SEARCH_RESULT_FORMAT) {\n throw new Error(\n `search token has unsupported result format \"${t.format ?? 'legacy'}\" ` +\n `(expected \"${SEARCH_RESULT_FORMAT}\")`,\n );\n }\n const query: SearchQuery = {\n text: decodeTokenText(t.q),\n ...(t.regex === 'true' ? { regex: true } : {}),\n ...(t.matchCase === 'true' ? { matchCase: true } : {}),\n ...(t.matchDiacritics === 'true' ? { matchDiacritics: true } : {}),\n ...(t.wholeWord === 'true' ? { wholeWord: true } : {}),\n ...(t.ignoreWhitespace === 'true' ? { ignoreWhitespace: true } : {}),\n };\n const maxPages =\n t.maxPages === undefined ? undefined : decodePositiveInteger(t.maxPages, 'maxPages');\n const maxMatches =\n t.maxMatches === undefined ? undefined : decodePositiveInteger(t.maxMatches, 'maxMatches');\n return {\n epoch: t.epoch,\n query,\n ...(t.startPage === undefined\n ? {}\n : { startPage: decodePositiveInteger(t.startPage, 'startPage') }),\n skip: t.skip === undefined ? 0 : decodePositiveInteger(t.skip, 'skip'),\n ...(maxPages !== undefined || maxMatches !== undefined\n ? {\n budget: {\n ...(maxPages !== undefined ? { maxPages } : {}),\n ...(maxMatches !== undefined ? { maxMatches } : {}),\n },\n }\n : {}),\n };\n};\n\n// Query text inside a token: UTF-8 → base64 with `-` for `+` and `.` for\n// `/`, unpadded — exactly the token grammar's value charset [A-Za-z0-9.-].\n// Dependency-free (no Buffer: this runs in browsers too).\nconst TOKEN_TEXT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-.';\n\nexport function encodeTokenText(text: string): string {\n const bytes = new TextEncoder().encode(text);\n let out = '';\n for (let i = 0; i < bytes.length; i += 3) {\n const b0 = bytes[i];\n const b1 = bytes[i + 1];\n const b2 = bytes[i + 2];\n out += TOKEN_TEXT_ALPHABET[b0 >> 2];\n out += TOKEN_TEXT_ALPHABET[((b0 & 0x03) << 4) | ((b1 ?? 0) >> 4)];\n if (b1 === undefined) break;\n out += TOKEN_TEXT_ALPHABET[((b1 & 0x0f) << 2) | ((b2 ?? 0) >> 6)];\n if (b2 === undefined) break;\n out += TOKEN_TEXT_ALPHABET[b2 & 0x3f];\n }\n return out;\n}\n\nexport function decodeTokenText(encoded: string): string {\n if (encoded.length % 4 === 1) throw new Error('malformed token text');\n const bytes: number[] = [];\n let buffer = 0;\n let bits = 0;\n for (const ch of encoded) {\n const value = TOKEN_TEXT_ALPHABET.indexOf(ch);\n if (value < 0) throw new Error('malformed token text');\n buffer = (buffer << 6) | value;\n bits += 6;\n if (bits >= 8) {\n bits -= 8;\n bytes.push((buffer >> bits) & 0xff);\n }\n }\n return new TextDecoder('utf-8', { fatal: true }).decode(Uint8Array.from(bytes));\n}\n\nfunction decodePositiveInteger(raw: string | undefined, field: string): number {\n if (raw === undefined || !/^\\d+$/.test(raw)) {\n throw new Error(`token field \"${field}\" must be a positive integer`);\n }\n const value = Number(raw);\n if (!Number.isInteger(value) || value <= 0) {\n throw new Error(`token field \"${field}\" must be a positive integer`);\n }\n return value;\n}\n\nfunction decodePdfSaveMode(raw: string | undefined): PdfSaveMode {\n if (raw === 'incremental' || raw === 'rewrite') return raw;\n throw new Error(`token field \"mode\" must be \"incremental\" or \"rewrite\"`);\n}\n","import type { ModificationLevel } from '../signature/types';\nimport { SIGNATURE_POLICY_VERSION } from '../signature/protection';\nimport type { AnalysisToken } from './tokens';\n/**\n * Single source of truth for cloud HTTP paths. Both @cloudpdf/engine and\n * @cloudpdf/server import these so they cannot drift.\n *\n * **URL layout convention (paths v2)**\n *\n * Each resource type lives at its own distinct path prefix. This\n * lets prefix-matching CDNs (Bunny, Cloud CDN, Azure FD) enforce\n * per-resource scope at the edge — a Bunny token signed at\n * `/v1/docs/{id}/render/pages/` can only authorize render bytes,\n * never text or annotations.\n *\n * Shape:\n * /v1/docs/{id} — doc root\n * /v1/docs/{id}/manifest@{ver} — doc-level read\n * /v1/docs/{id}/render/pages/{N}/data@{ver} — render is its own prefix\n * /v1/docs/{id}/text/pages/{N}/data@{ver} — text is its own prefix\n * /v1/docs/{id}/geometry/pages/{N}/data@{ver} — geometry is its own prefix\n * /v1/docs/{id}/layers/{L}/manifest@{ver}\n * /v1/docs/{id}/layers/{L}/metadata@{ver}\n * /v1/docs/{id}/layers/{L}/render/pages/{N}/data@{ver}\n * /v1/docs/{id}/layers/{L}/text/pages/{N}/data@{ver}\n * /v1/docs/{id}/layers/{L}/geometry/pages/{N}/data@{ver}\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items@{ver} — collection (read)\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items — collection (create)\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items/{key} — member\n * /v1/docs/{id}/layers/{L}/annotations/pages/{N}/items/move — batch reorder\n * /v1/docs/{id}/layers/{L}/pages/move — batch page reorder\n * /v1/docs/{id}/layers/{L}/pages/rotate — batch absolute rotation\n * /v1/docs/{id}/layers/{L}/pages/delete — batch page delete\n * /v1/docs/{id}/layers/{L}/form — reconciled snapshot (read)\n * /v1/docs/{id}/layers/{L}/form/fields — field collection (create)\n * /v1/docs/{id}/layers/{L}/form/fields/{key} — field member (read/patch/delete)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/value — value write (fill)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/reset — reset to /DV (fill)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/widgets — adopt a widget (attach)\n * /v1/docs/{id}/layers/{L}/form/fields/{key}/widgets/detach — release a widget\n * /v1/docs/{id}/layers/{L}/form/data — FDF/XFDF export (GET) / import (POST)\n * /v1/docs/{id}/layers/{L}/form/repair — durable reconciliation\n * /v1/docs/{id}/layers/{L}/download@{ver}\n *\n * `items` appears on both the read collection (`items@{ver}`) and\n * the mutation surface (`items` POST, `items/{key}` PATCH/DELETE)\n * for symmetry — `items@version` is the page's versioned annotation\n * collection; `items/{key}` is one annotation inside it.\n */\nimport {\n encodeActionsToken,\n encodeAnalysisToken,\n encodeAnnotationAppearancesRenderToken,\n encodeAnnotationToken,\n encodeAnnotationsAllToken,\n encodeAttachmentsToken,\n encodeContentToken,\n encodeDocToken,\n encodeDownloadToken,\n encodeLayoutToken,\n encodeMetadataToken,\n encodeRenderToken,\n encodeTokenText,\n type DownloadToken,\n type TokenInput,\n} from './tokens';\n\nexport const DEFAULT_LAYER_NAME = 'default';\n\nexport const wirePaths = {\n /**\n * POST: grant access/caching credentials for the current bearer on\n * the document + layer namespace the path names (cross-checked\n * against the token like every layer route — the grant is\n * layer-scoped in substance: CDN coverage, scopes, and the client's\n * binding all carry the layer). Path-addressed so the affinity tier —\n * the `X-CloudPDF-Doc` header derivation AND the chart's uri-mode\n * regex — pins the session bootstrap to the document's pod from the\n * very first request. Default-layer callers spell `layers/default/`,\n * same as every other layer route.\n */\n access: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/access`,\n\n /** Deprecated alias (docId in the BODY) — served for one prerelease\n * cycle so pre-rename clients keep working; remove after. */\n accessLegacy: '/v1/access',\n\n /**\n * GET: open the document referenced by the doc-scoped JWT and\n * return its `DocumentHead`. The server materialises the base\n * PDF into its file cache and binds it to a worker the first\n * time this is hit.\n */\n docHead: (docId: string) => `/v1/docs/${encodeURIComponent(docId)}/head`,\n\n /**\n * GET: layer-scoped head. The cloud SDK always uses a layer namespace;\n * tokens without `layer_name` bind to `DEFAULT_LAYER_NAME`.\n */\n layerHead: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/head`,\n\n /**\n * GET: full document manifest at a specific `docVersion`. Content-\n * addressed: the URL bytes are immutable for the lifetime of the\n * version, so CDNs may cache `public, max-age=31536000, immutable`.\n * A request whose `docVersion` mismatches the current version\n * returns 404 — the SDK refetches `/head` to learn the new\n * version, then re-requests the manifest at the new URL.\n */\n docManifest: (docId: string, docVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/manifest@${encodeDocToken(docVersion)}`,\n\n /**\n * GET: full layer manifest at a specific layer document version.\n * Never-mutated layers may fall through to the immutable base view;\n * once a layer row exists, `layers.doc_version` and `layer_pages`\n * drive the response.\n */\n layerManifest: (docId: string, layerName: string, docVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/manifest@${encodeDocToken(docVersion)}`,\n\n /**\n * GET: page-geometry list for the whole layer at a specific\n * `layoutVersion`. Content-addressed; CDN may cache forever. The\n * `layoutVersion` lives in the manifest (doc-level pointer) and bumps\n * only on structural page ops. Stale-version requests 404 and the SDK's\n * transparent retry walks `/head` -> `/manifest@docVersion=N` to learn\n * the new `layoutVersion`.\n */\n layerLayout: (docId: string, layerName: string, layoutVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/layout@${encodeLayoutToken(layoutVersion)}`,\n\n /**\n * Immutable BASE page-geometry list (plane-scope model): the shared-URL\n * variant a layout-inheriting layer resolves at — every visitor's page\n * list is ONE CDN object served from the base worker session.\n */\n docLayout: (docId: string, layoutVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layout@${encodeLayoutToken(layoutVersion)}`,\n\n layerLayoutCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/layout`,\n\n /**\n * GET: full document metadata for the layer at a specific\n * `metadataVersion`. Content-addressed; CDN may cache forever. The\n * `metadataVersion` lives in the manifest (doc-level pointer) and bumps\n * only on metadata writes. Stale-version requests 404 and the SDK's\n * transparent retry walks `/head` -> `/manifest@docVersion=N` to learn\n * the new `metadataVersion`.\n */\n layerMetadata: (docId: string, layerName: string, metadataVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/metadata@${encodeMetadataToken(metadataVersion)}`,\n\n layerMetadataCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/metadata`,\n\n /** Immutable BASE metadata (plane-scope model): the shared-URL variant a\n * metadata-inheriting layer resolves at. */\n docMetadata: (docId: string, metadataVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/metadata@${encodeMetadataToken(metadataVersion)}`,\n\n /** Immutable catalog-owned actions, independently pinned in the manifest. */\n layerActions: (docId: string, layerName: string, actionsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/actions@${encodeActionsToken(actionsVersion)}`,\n\n /** Immutable BASE catalog actions (plane-scope model): the shared-URL\n * variant an actions-inheriting layer resolves at. */\n docActions: (docId: string, actionsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/actions@${encodeActionsToken(actionsVersion)}`,\n\n // ---------------------------------------------------------------------\n // Digital signatures. Layer reads pin `docVersion` (a signature is a\n // layer state change like any other edit); version-scoped reads are\n // content-addressed by the base sha and immutable forever. The RESOURCE\n // comes before the sha so each family keeps its own CDN prefix.\n // ---------------------------------------------------------------------\n\n /** Immutable layer signature snapshot (base signatures + the layer's fields + protection). */\n layerSignatures: (docId: string, layerName: string, docVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures@${encodeDocToken(docVersion)}`,\n layerSignaturesCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures`,\n /** Immutable: the layer's working copy judged against the base, pinned by `docVersion`. */\n layerSignaturesAnalysis: (docId: string, layerName: string, token: AnalysisToken) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/analysis@${encodeAnalysisToken(token)}`,\n layerSignaturesAnalysisCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/analysis`,\n /** POST (multipart envelope): author and seal a signing candidate. */\n layerSignaturesPrepare: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/prepare`,\n /** POST (JSON): install the CMS and publish the sealed bytes as the next base version. */\n layerSignatureComplete: (docId: string, layerName: string, signingId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/${encodeURIComponent(signingId)}/complete`,\n /** DELETE: discard a pending signing. */\n layerSignatureAbort: (docId: string, layerName: string, signingId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/signatures/${encodeURIComponent(signingId)}`,\n\n /** The document's base versions, oldest first (grows; never cached). */\n docVersions: (docId: string) => `/v1/docs/${encodeURIComponent(docId)}/versions`,\n /** Immutable: the signature snapshot of one base version. */\n docVersionSignatures: (docId: string, sha256: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/signatures/${sha256}`,\n /** Immutable: a signed field's DER `/Contents` in one base version (`application/pkcs7-signature`). */\n docVersionSignatureContents: (docId: string, sha256: string, fieldName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/signatures/${sha256}/${encodeTokenText(fieldName)}/contents`,\n /** Immutable: the digest of a signed field's `/ByteRange` in one base version. */\n docVersionSignatureDigest: (\n docId: string,\n sha256: string,\n fieldName: string,\n algorithm: 'sha1' | 'sha256' | 'sha384' | 'sha512',\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/signatures/${sha256}/${encodeTokenText(fieldName)}/digest/${algorithm}`,\n /** Immutable: history between two revisions of one base version. */\n docVersionAnalysis: (docId: string, sha256: string, query: AnalysisQueryInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/analysis/${sha256}?${analysisQueryString(query)}`,\n /** Immutable: the bytes of one base version. */\n docVersionDownload: (docId: string, sha256: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/download/${sha256}`,\n /** Immutable: the byte prefix `[0, end)` of revision `index` of one base version. */\n docVersionRevision: (docId: string, sha256: string, index: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/versions/revisions/${sha256}/${index}`,\n\n /** POST (multipart envelope): draw a PDF page into an unsigned signature field's widgets. */\n layerFormFieldSignatureAppearance: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/signature-appearance`,\n\n /** POST: rewrite the document Info dict for the layer (metadata edit). */\n layerMetadataUpdate: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/metadata`,\n\n /**\n * Immutable BASE /EmbeddedFiles listing: the shared-URL variant an\n * attachments-undiverged layer resolves at — every visitor's sidebar list\n * is ONE CDN object served from the base worker session.\n */\n docAttachments: (docId: string, attachmentsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/attachments@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** Immutable BASE decoded bytes of one embedded file (twin of\n * `layerAttachmentFile` — same capability tier split). */\n docAttachmentFile: (docId: string, key: string, attachmentsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/attachment-files/${encodeTokenText(key)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** Immutable /EmbeddedFiles listing, pinned by `attachmentsVersion`. */\n layerAttachments: (docId: string, layerName: string, attachmentsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachments@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** POST: create a document-level embedded file (multipart mutation envelope). */\n layerAttachmentsCollection: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachments`,\n\n /** DELETE: remove a document-level embedded file by name-tree key. */\n layerAttachmentItem: (docId: string, layerName: string, key: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachments/${encodeTokenText(key)}`,\n\n /**\n * Immutable decoded bytes of one document-level embedded file. Lives\n * under its own `attachment-files` prefix — a stronger capability tier\n * than the metadata listing, so a CDN credential for one can never\n * authorize the other (the search-rects/search-full rule).\n */\n layerAttachmentFile: (\n docId: string,\n layerName: string,\n key: string,\n attachmentsVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachment-files/${encodeTokenText(key)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /** Immutable decoded bytes of a FileAttachment annotation's embedded file. */\n layerAnnotationFile: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n annotKey: string,\n attachmentsVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/attachment-files/pages/${pageObjectNumber}/items/${encodeURIComponent(annotKey)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /**\n * Immutable BASE bytes of a FileAttachment annotation's embedded file\n * (plane-scope model). Depends on the `annotations` plane (the annotation\n * exists in this view) AND the `attachments` plane (the pin); the origin\n * guard requires both inherited.\n */\n docAnnotationFile: (\n docId: string,\n pageObjectNumber: number,\n annotKey: string,\n attachmentsVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/attachment-files/pages/${pageObjectNumber}/items/${encodeURIComponent(annotKey)}/data@${encodeAttachmentsToken(attachmentsVersion)}`,\n\n /**\n * GET: full plain-text extraction for a single page at a specific\n * `contentVersion`. Content-addressed; CDN may cache forever.\n * Stale-version requests return 404 and the SDK's transparent\n * retry walks `/head` → `/manifest@docVersion=N` to learn the new\n * `contentVersion`.\n */\n docPageText: (docId: string, pageObjectNumber: number, contentVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/text/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n layerPageText: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n contentVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/text/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n layerPageTextCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/text/pages/${pageObjectNumber}/data`,\n\n docPageGeometry: (docId: string, pageObjectNumber: number, contentVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/geometry/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n docPageGeometryCurrent: (docId: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/geometry/pages/${pageObjectNumber}/data`,\n\n docPageRender: (docId: string, pageObjectNumber: number, token: TokenInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/render/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n docPageRenderCurrent: (docId: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/render/pages/${pageObjectNumber}/data`,\n\n /**\n * Immutable BASE annotated render (plane-scope model). Its OWN path family,\n * not a token flag under `/render/pages/`: an annotated render depends on\n * `content + annotations`, an annotation-free one on `content` alone, and\n * edge grants are prefix-scoped — the prefix law says a path's prefix must\n * identify its full plane-dependency set. Annotatedness is therefore\n * PATH-ONLY (the token/path law): the wire token has no\n * `includeAnnotations` key at all; the annotated family's token carries\n * `annotationVersion`, the free family's cannot.\n */\n docPageRenderAnnotated: (docId: string, pageObjectNumber: number, token: TokenInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/render/annotated/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n layerPageGeometry: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n contentVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/geometry/pages/${pageObjectNumber}/data@${encodeContentToken(contentVersion)}`,\n\n layerPageGeometryCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/geometry/pages/${pageObjectNumber}/data`,\n\n layerPageRender: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n token: TokenInput,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n layerPageRenderCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/pages/${pageObjectNumber}/data`,\n\n /** Layer twin of `docPageRenderAnnotated` — the grammar is uniform:\n * annotatedness is path-only at BOTH tiers. */\n layerPageRenderAnnotated: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n token: TokenInput,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/annotated/pages/${pageObjectNumber}/data@${encodeRenderToken(token)}`,\n\n layerPageRenderAnnotatedCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/render/annotated/pages/${pageObjectNumber}/data`,\n\n /**\n * Immutable BASE annotation list for a single page (plane-scope model):\n * the shared-URL variant an annotations-inheriting layer resolves at — a\n * base's own annotations (weak-identity ones included) are simply visible\n * through every pristine layer, so 1,000 visitors' sidebars are ONE CDN\n * object served from the base worker session.\n */\n docPageAnnotations: (docId: string, pageObjectNumber: number, annotationVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/annotations/pages/${pageObjectNumber}/items@${encodeAnnotationToken(annotationVersion)}`,\n\n /** Immutable BASE whole-document annotation listing (bulk hydration). */\n docAnnotationsAll: (docId: string, annotationsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/annotations/items@${encodeAnnotationsAllToken(annotationsVersion)}`,\n\n /** Immutable BASE appearance batch (twin of\n * `layerPageAnnotationAppearances` — same `annotations` plane gate). */\n docPageAnnotationAppearances: (docId: string, pageObjectNumber: number, token: TokenInput) =>\n `/v1/docs/${encodeURIComponent(docId)}/annotations/pages/${pageObjectNumber}/appearances@${encodeAnnotationAppearancesRenderToken(token)}`,\n\n /**\n * GET: full annotation list for a single page at a specific\n * `annotationVersion`. Same cache-control rules and 404-retry\n * semantics as `docPageText`. The `items` suffix is the\n * collection name — see file-level docstring.\n */\n layerPageAnnotations: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n annotationVersion: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items@${encodeAnnotationToken(annotationVersion)}`,\n\n /** Immutable LAYER whole-document annotation listing (bulk hydration). */\n layerAnnotationsAll: (docId: string, layerName: string, annotationsVersion: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/items@${encodeAnnotationsAllToken(annotationsVersion)}`,\n\n layerPageAnnotationsCurrent: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items`,\n\n /**\n * GET: batch-rendered annotation appearance bitmaps for a single page as a\n * `multipart/form-data` body. Sibling collection of `items` under the same\n * `annotations/pages/{N}/` resource, so it shares the `annotations-read`\n * gate (`doc.annotate.read`) and CDN coverage — reading an annotation lets\n * you see its rendered appearance, the same boundary Adobe uses.\n *\n * Content-addressed via the appearance render token (`annotationVersion`\n * plus render options like scale/format); CDN may cache forever. Appearance\n * pixels depend only on the annotation `/AP` stream, so `contentVersion` is\n * deliberately NOT part of the key.\n */\n layerPageAnnotationAppearances: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n token: TokenInput,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/appearances@${encodeAnnotationAppearancesRenderToken(token)}`,\n\n layerPageAnnotationAppearancesCurrent: (\n docId: string,\n layerName: string,\n pageObjectNumber: number,\n ) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/appearances`,\n\n layerPageAnnotationsCreate: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items`,\n\n layerAnnotationByKey: (docId: string, layerName: string, pageObjectNumber: number, key: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/${encodeURIComponent(key)}`,\n\n layerPageAnnotationsMove: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/move`,\n /** POST: flatten a chosen set of the page's annotations into its content\n * (a content + annotation mutation of that page). */\n layerPageAnnotationsFlatten: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/flatten`,\n /** POST: the chosen annotations' appearances as one single-page PDF — a\n * derived read (application/pdf, no-store), gated like pages/extract. */\n layerPageAnnotationsAppearance: (docId: string, layerName: string, pageObjectNumber: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/annotations/pages/${pageObjectNumber}/items/appearance`,\n\n /**\n * GET: the reconciled form snapshot (field tree + widget joins) for the\n * layer's CURRENT state. Forms are document-scoped (one AcroForm per\n * document), so there is no per-page collection and — unlike annotations —\n * no content-addressed `@version` variant: the snapshot is always served\n * `no-store`. Mutation results carry the per-page `cacheDelta` that keeps\n * annotation/render caches coherent when widget appearances change.\n */\n layerForm: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form`,\n\n /** POST: create a field (optionally with styled widget placements). */\n layerFormFields: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields`,\n\n /**\n * Field member: GET (single field) / PATCH (updateField) / DELETE\n * (deleteField + widget cascade). `fieldKey` is an encoded `FormFieldRef`\n * (`encodeFieldRefKey`): `obj:12` or `fqn:billing.name`.\n */\n layerFormFieldByKey: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}`,\n\n /** POST: replace the field's value (`{ value: FormFieldValue }`). */\n layerFormFieldValue: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/value`,\n\n /** POST: reset the field to /DV (or clear). Empty body. */\n layerFormFieldReset: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/reset`,\n\n /** POST: adopt an inert widget annotation (`{ widget, onState? }`). */\n layerFormFieldWidgets: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/widgets`,\n\n /**\n * POST: release a widget back to the inert annotation plane\n * (`{ widget }`). An action POST rather than a member DELETE because a\n * widget ref is a (page, annotation) pair — carrying it in the body keeps\n * one codec instead of inventing a second composite key syntax.\n */\n layerFormFieldWidgetsDetach: (docId: string, layerName: string, fieldKey: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/fields/${encodeURIComponent(fieldKey)}/widgets/detach`,\n\n /**\n * GET: serialized form data (`?format=fdf|xfdf`, default `xfdf`).\n * POST: import an FDF/XFDF payload (raw bytes body; format sniffed\n * server-side unless `?format=` pins it).\n */\n layerFormData: (docId: string, layerName: string, format?: 'fdf' | 'xfdf') =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/data${format ? `?format=${format}` : ''}`,\n\n /** POST: durable reconciliation (`{ bakeAppearances? }`). */\n layerFormRepair: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/repair`,\n\n layerFormEffects: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/form/effects`,\n\n /**\n * GET: one budgeted search slice, versioned form. The token\n * (`encodeSearchToken`) IS the cache key: content epoch + query +\n * position. Immutable; CDN may cache forever. Mode is the path — rects\n * and full are separate resources so permission tiers never share\n * cache entries (`'rects'` needs `doc.text.search`; `'full'` also\n * needs `doc.text.copy`).\n */\n layerSearchRects: (docId: string, layerName: string, token: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/rects/data@${token}`,\n\n layerSearchFull: (docId: string, layerName: string, token: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/full/data@${token}`,\n\n /**\n * GET: unversioned form — same fields as flat query params (`q` as\n * plain text), served from the CURRENT content, always `no-store`.\n * The debug/simple-client variant; the SDK uses the versioned form.\n */\n layerSearchRectsCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/rects/data`,\n\n layerSearchFullCurrent: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/search/full/data`,\n\n layerPageViewports: (docId: string, layerName: string, pon: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/${pon}/viewports`,\n layerPageScale: (docId: string, layerName: string, pon: number) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/${pon}/scale`,\n\n layerPagesMove: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/move`,\n\n layerPagesRotate: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/rotate`,\n\n layerPagesDelete: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/delete`,\n /** POST: register/rename a `/Names /Pages` entry — a page-STRUCTURE\n * mutation (docVersion + layoutVersion advance; reads ride `/layout`). */\n layerPagesNames: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/names`,\n /** POST: remove a `/Names /Pages` entry (the page stays). */\n layerPagesNamesDelete: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/names/delete`,\n\n layerPagesFlatten: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/flatten`,\n\n /**\n * POST (multipart mutation envelope): copy every page of the `source`\n * resource part (a standalone PDF) in at the body's `destIndex`.\n */\n layerPagesInsert: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/insert`,\n\n /** POST (plain JSON): create blank pages — pages.insert minus the bytes. */\n layerPagesInsertBlank: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/insert-blank`,\n\n /**\n * POST (plain JSON → `application/pdf` bytes): export the listed pages,\n * in caller order, as a standalone PDF. A READ over the current layer\n * state (gated like /download), so it is a POST only for its body —\n * nothing mutates and no event is published.\n */\n layerPagesExtract: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/pages/extract`,\n\n layerRedactionsApply: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/redactions/apply`,\n\n layerEvents: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/events`,\n\n layerDownload: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/download`,\n\n layerDownloadVersioned: (docId: string, layerName: string, token: DownloadToken) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/download@${encodeDownloadToken(token)}`,\n\n /**\n * Weak-annotation-sessions: pluralized in v2 so the collection\n * lives at `/weak-annotation-sessions` and members at\n * `/weak-annotation-sessions/{sessionId}` — REST-conventional.\n */\n layerWeakAnnotationSession: (docId: string, layerName: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions`,\n\n layerWeakAnnotationSessionHeartbeat: (docId: string, layerName: string, sessionId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions/${encodeURIComponent(sessionId)}/heartbeat`,\n\n layerWeakAnnotationSessionPages: (docId: string, layerName: string, sessionId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions/${encodeURIComponent(sessionId)}/pages`,\n\n layerWeakAnnotationSessionRelease: (docId: string, layerName: string, sessionId: string) =>\n `/v1/docs/${encodeURIComponent(docId)}/layers/${encodeURIComponent(layerName)}/weak-annotation-sessions/${encodeURIComponent(sessionId)}`,\n\n /**\n * POST: pre-warm the doc cache + worker open before any user\n * request lands. Body is `{ docId }`. Doc-scoped token required.\n */\n docWarm: '/v1/warm',\n} as const;\n\n/**\n * Fastify-style templates for the PLAIN (unversioned) doc-plane routes —\n * the backend-callable subset that the `@cloudpdf/contract` contract\n * documents. The immutable `@{version}` variants above remain viewer\n * protocol and are deliberately absent. These templates are the single\n * statement of those paths: the contract package imports them, and the\n * server's route table is pinned to them by the doc-plane registry\n * conformance test.\n */\n/** The flat query of a version analysis (the contract's dotted keys). */\nexport interface AnalysisQueryInput {\n since: { signatureIndex: number } | { revisionIndex: number };\n /** Revision index the analysis ends at; default the last. */\n until?: number;\n exploratoryLevel?: ModificationLevel;\n detail?: 'summary' | 'full';\n}\n\nexport function analysisQueryString(query: AnalysisQueryInput): string {\n const params = new URLSearchParams();\n if ('signatureIndex' in query.since)\n params.set('since.signature', String(query.since.signatureIndex));\n else params.set('since.revision', String(query.since.revisionIndex));\n if (query.until !== undefined) params.set('until', String(query.until));\n if (query.exploratoryLevel !== undefined) params.set('level', query.exploratoryLevel);\n if (query.detail !== undefined) params.set('detail', query.detail);\n // The judging policy version: a cache key on the immutable version URL, so\n // a policy bump never serves a verdict judged the old way.\n params.set('policy', String(SIGNATURE_POLICY_VERSION));\n return params.toString();\n}\n\nexport const wireTemplates = {\n docHead: '/v1/docs/:docId/head',\n layerManifest: '/v1/docs/:docId/layers/:layerName/manifest',\n layerMetadata: '/v1/docs/:docId/layers/:layerName/metadata',\n layerRenderPage: '/v1/docs/:docId/layers/:layerName/render/pages/:pon/data',\n layerTextPage: '/v1/docs/:docId/layers/:layerName/text/pages/:pon/data',\n layerAnnotationItemsAll: '/v1/docs/:docId/layers/:layerName/annotations/items',\n layerAnnotationItems: '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items',\n layerAnnotationItem: '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items/:annotKey',\n layerAnnotationItemsFlatten:\n '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items/flatten',\n layerAnnotationItemsAppearance:\n '/v1/docs/:docId/layers/:layerName/annotations/pages/:pon/items/appearance',\n layerForm: '/v1/docs/:docId/layers/:layerName/form',\n layerFormFieldValue: '/v1/docs/:docId/layers/:layerName/form/fields/:fieldKey/value',\n layerFormFieldReset: '/v1/docs/:docId/layers/:layerName/form/fields/:fieldKey/reset',\n layerFormFieldSignatureAppearance:\n '/v1/docs/:docId/layers/:layerName/form/fields/:fieldKey/signature-appearance',\n layerFormData: '/v1/docs/:docId/layers/:layerName/form/data',\n layerPageViewports: '/v1/docs/:docId/layers/:layerName/pages/:pon/viewports',\n layerPageScale: '/v1/docs/:docId/layers/:layerName/pages/:pon/scale',\n layerPagesMove: '/v1/docs/:docId/layers/:layerName/pages/move',\n layerPagesRotate: '/v1/docs/:docId/layers/:layerName/pages/rotate',\n layerPagesDelete: '/v1/docs/:docId/layers/:layerName/pages/delete',\n layerPagesNames: '/v1/docs/:docId/layers/:layerName/pages/names',\n layerPagesNamesDelete: '/v1/docs/:docId/layers/:layerName/pages/names/delete',\n layerPagesFlatten: '/v1/docs/:docId/layers/:layerName/pages/flatten',\n layerPagesInsert: '/v1/docs/:docId/layers/:layerName/pages/insert',\n layerPagesInsertBlank: '/v1/docs/:docId/layers/:layerName/pages/insert-blank',\n layerPagesExtract: '/v1/docs/:docId/layers/:layerName/pages/extract',\n layerRedactionsApply: '/v1/docs/:docId/layers/:layerName/redactions/apply',\n layerDownload: '/v1/docs/:docId/layers/:layerName/download',\n layerSignatures: '/v1/docs/:docId/layers/:layerName/signatures',\n layerSignaturesAnalysis: '/v1/docs/:docId/layers/:layerName/signatures/analysis',\n layerSignaturesPrepare: '/v1/docs/:docId/layers/:layerName/signatures/prepare',\n layerSignatureComplete: '/v1/docs/:docId/layers/:layerName/signatures/:signingId/complete',\n layerSignatureAbort: '/v1/docs/:docId/layers/:layerName/signatures/:signingId',\n docVersions: '/v1/docs/:docId/versions',\n docVersionSignatures: '/v1/docs/:docId/versions/signatures/:sha',\n docVersionSignatureContents: '/v1/docs/:docId/versions/signatures/:sha/:fieldKey/contents',\n docVersionSignatureDigest: '/v1/docs/:docId/versions/signatures/:sha/:fieldKey/digest/:algorithm',\n docVersionAnalysis: '/v1/docs/:docId/versions/analysis/:sha',\n docVersionDownload: '/v1/docs/:docId/versions/download/:sha',\n docVersionRevision: '/v1/docs/:docId/versions/revisions/:sha/:index',\n} as const;\n","/**\n * Single source of truth mapping every CDN-relevant read resource to:\n * - its URL path pattern (with glob wildcards for CDN signing)\n * - the capability requirement that gates it\n * - whether it's CDN-cacheable\n * - whether the route is origin-only or versioned-read\n *\n * Consumed by:\n * - server route guards via `requireResource(req, docId, id, pdfBits)`\n * - the CDN signer to determine which path prefixes to cover for a token\n * - documentation generators\n *\n * NOTE: only READ resources go in this table. Mutation routes\n * (POST/PATCH/DELETE) use collab scopes with target lookup and don't\n * fit a single capability requirement. /access is also NOT in the\n * table — it's a session-establishment POST that performs its own\n * doc-access check without requiring any capability.\n */\n\nimport type { DocCapability, PdfBits } from '../auth/scope';\nimport { checkAnyCapability, checkCapability } from '../auth/scope';\n\n/**\n * Canonical id for every read resource the server exposes.\n *\n * Adding a new resource:\n * 1. Add the id to this union\n * 2. Add a `DOC_RESOURCES` entry\n * 3. Update the route handler to call `requireResource(req, docId, '<id>', pdfBits)`\n * 4. CDN signer automatically considers it\n */\nexport type DocResourceId =\n | 'head'\n | 'manifest'\n | 'page-render'\n // Plane-prefix rule: annotated renders are their OWN family — they depend\n // on content+annotations while `/render/pages/` depends on content alone,\n // and edge grants see only prefixes, so the dependency set must be\n // visible in the path.\n | 'page-render-annotated'\n | 'page-text'\n | 'page-geometry'\n // Plane-scope model: doc-level shared variants, one per plane-dependent\n // read family. Each resolves at the base view while the planes it depends\n // on are inherited — see the RESOURCE_PLANES map in wire/cdn/coverage.ts.\n | 'page-annotations'\n // Whole-document bulk annotation listing, doc-level + layer twin. Its\n // own family: the path is NOT under the per-page `annotations/pages/`\n // prefix, so it needs its own catalogue entry for edge grants.\n | 'annotations-all'\n | 'layout'\n | 'metadata'\n | 'actions'\n | 'attachments'\n | 'attachment-files'\n // Layer-scoped variants of the page resources. Same capability\n // gates as their doc-level cousins (the layer just provides a\n // possibly-divergent VIEW of the underlying page content — e.g.\n // server-side redactions in the future). Cataloguing both shapes\n // means the CDN signer covers the prefixes the SDK actually\n // requests. See ADR-002 / paths-v2 design for the doc-vs-layer\n // split rationale.\n | 'layer-manifest'\n | 'layer-layout'\n | 'layer-metadata'\n // Digital signatures: the layer's snapshot and analysis (pinned by\n // docVersion, like the manifest), and the version-scoped families —\n // content-addressed by base sha, each under its OWN prefix (the CDN\n // signs literal prefixes, so a grant for signature reads must never\n // also cover version downloads). The versions LIST is origin-only.\n | 'layer-signatures'\n | 'layer-signatures-analysis'\n | 'versions'\n | 'version-signatures'\n | 'version-analysis'\n | 'version-download'\n | 'version-revisions'\n | 'layer-actions'\n | 'layer-page-render'\n // Layer twin of `page-render-annotated`: annotatedness is path-only at\n // BOTH tiers (uniform grammar), even though layer grants don't need the\n // distinction — see the token/path law in wire/paths.ts.\n | 'layer-page-render-annotated'\n | 'layer-page-text'\n | 'layer-page-geometry'\n // Search slices, one resource per PERMISSION TIER: rects-only results\n // vs snippet-carrying results live under distinct path prefixes, so a\n // CDN credential for one can never authorize (or cache-hit) the other.\n | 'layer-search-rects'\n | 'layer-search-full'\n | 'annotations-read'\n | 'layer-annotations-all'\n // Attachments, split by permission tier under DISTINCT prefixes (the\n // search-rects/search-full rule): the metadata listing rides the base\n // read capability, while decoded file bytes egress content and gate on\n // the download capability — an edge credential for the listing prefix\n // must never authorize the byte prefix.\n | 'layer-attachments'\n | 'layer-attachment-files'\n | 'download-current'\n | 'download-versioned';\n\n/**\n * 'origin' — unversioned URL, response can change over time. CDN must\n * not cache (the bytes are not immutable). Routed straight to origin\n * with the JWT bearer.\n *\n * 'versioned-read' — URL is content-addressed via `@<token>`. Response\n * is immutable for the lifetime of the version. Safe to cache forever\n * at the CDN edge.\n */\nexport type RouteKind = 'origin' | 'versioned-read';\n\n/**\n * Capability requirement attached to a resource. Three shapes:\n * - `single` — one capability gates the resource\n * - `any` — any one of N capabilities gates the resource\n * (used by /text and /geometry which accept either the\n * copy/select scope OR the future search scope)\n * - `all` — every one of N capabilities is required\n * (used by /search/full: a snippet IS extracted text, so\n * the search scope alone is not enough — the copy denial\n * must hold here too)\n */\nexport type CapabilityRequirement =\n | { kind: 'single'; capability: DocCapability }\n | { kind: 'any'; capabilities: ReadonlyArray<DocCapability> }\n | { kind: 'all'; capabilities: ReadonlyArray<DocCapability> };\n\nexport interface DocResourceDescriptor {\n /** Stable id used by route guards and the CDN signer. */\n id: DocResourceId;\n /**\n * Display pattern with `{docId}` / `{layerName}` placeholders for\n * docs + telemetry. Use {@link DocResourceDescriptor.resolvePathPattern}\n * to get a concrete pattern with values filled in.\n */\n pathPattern: string;\n /**\n * Concrete CDN path pattern with `*` wildcards. Used by adapters\n * that do explicit pattern matching at the edge (CloudFront via\n * Resource globs). For path prefixes with no layer component,\n * `layerName` is ignored.\n */\n resolvePathPattern(docId: string, layerName?: string): string;\n /**\n * Display prefix with `{docId}` / `{layerName}` placeholders. The\n * literal path-prefix the CDN signs for this resource — by design,\n * each resource type has its OWN distinct prefix, so a token\n * signed at this prefix authorizes only this resource type at the\n * edge (works on prefix-matching CDNs like Bunny / Cloud CDN /\n * Azure FD with no extra cleverness).\n */\n pathPrefix: string;\n /**\n * Concrete path prefix the CDN signer uses. The literal string\n * `pathPattern` would have *before* the first `*` wildcard — but\n * stored explicitly here rather than derived so future pattern\n * syntax changes can't accidentally break CDN security.\n *\n * For resources with no layer component, `layerName` is ignored.\n */\n resolvePathPrefix(docId: string, layerName?: string): string;\n /** What capability (or set) is needed to access this resource. */\n requirement: CapabilityRequirement;\n /** Versioned-immutable vs. unversioned-mutable. */\n routeKind: RouteKind;\n /**\n * Can the CDN sign coverage for this resource? Mutable/unversioned\n * resources (head, current download) are always false even though\n * they're routed via origin.\n */\n cdnCacheable: boolean;\n}\n\n/**\n * URL layout (paths v2): each resource type lives at a distinct path\n * prefix so prefix-matching CDNs (Bunny, Cloud CDN, Azure FD) can\n * enforce per-resource scope at the edge. See wire/paths.ts for the\n * full shape and rationale.\n */\nexport const DOC_RESOURCES: Readonly<Record<DocResourceId, DocResourceDescriptor>> = {\n head: {\n id: 'head',\n pathPattern: '/v1/docs/{docId}/head',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/head`,\n pathPrefix: '/v1/docs/{docId}/head',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/head`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'origin',\n cdnCacheable: false,\n },\n manifest: {\n id: 'manifest',\n pathPattern: '/v1/docs/{docId}/manifest@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/manifest@*`,\n pathPrefix: '/v1/docs/{docId}/manifest@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/manifest@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-manifest': {\n id: 'layer-manifest',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/manifest@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/manifest@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/manifest@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/manifest@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-render': {\n id: 'page-render',\n pathPattern: '/v1/docs/{docId}/render/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/render/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/render/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/render/pages/`,\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-render-annotated': {\n id: 'page-render-annotated',\n pathPattern: '/v1/docs/{docId}/render/annotated/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/render/annotated/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/render/annotated/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/render/annotated/pages/`,\n // Same capability tier as `page-render` — the split is about PLANE\n // dependencies (content+annotations vs content), not permissions.\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-annotations': {\n id: 'page-annotations',\n pathPattern: '/v1/docs/{docId}/annotations/pages/*/items@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/annotations/pages/*/items@*`,\n // Prefix deliberately covers the `appearances@` sibling too, mirroring\n // the layer-scoped `annotations-read` rule: reading an annotation lets\n // you see its rendered appearance.\n pathPrefix: '/v1/docs/{docId}/annotations/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/annotations/pages/`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'annotations-all': {\n id: 'annotations-all',\n pathPattern: '/v1/docs/{docId}/annotations/items@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/annotations/items@*`,\n pathPrefix: '/v1/docs/{docId}/annotations/items@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/annotations/items@`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n layout: {\n id: 'layout',\n pathPattern: '/v1/docs/{docId}/layout@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/layout@*`,\n pathPrefix: '/v1/docs/{docId}/layout@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/layout@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n metadata: {\n id: 'metadata',\n pathPattern: '/v1/docs/{docId}/metadata@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/metadata@*`,\n pathPrefix: '/v1/docs/{docId}/metadata@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/metadata@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n actions: {\n id: 'actions',\n pathPattern: '/v1/docs/{docId}/actions@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/actions@*`,\n pathPrefix: '/v1/docs/{docId}/actions@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/actions@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-layout': {\n id: 'layer-layout',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/layout@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/layout@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/layout@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/layout@`,\n // Geometry is the same session-level read as the manifest; gate it\n // behind `doc.open` just like `layer-manifest`.\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-metadata': {\n id: 'layer-metadata',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/metadata@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/metadata@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/metadata@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/metadata@`,\n // Metadata is the same session-level read as the manifest; gate it\n // behind `doc.open` just like `layer-manifest` / `layer-layout`.\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-actions': {\n id: 'layer-actions',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/actions@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/actions@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/actions@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/actions@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n attachments: {\n id: 'attachments',\n pathPattern: '/v1/docs/{docId}/attachments@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/attachments@*`,\n pathPrefix: '/v1/docs/{docId}/attachments@',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/attachments@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'attachment-files': {\n id: 'attachment-files',\n pathPattern: '/v1/docs/{docId}/attachment-files/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/attachment-files/*`,\n pathPrefix: '/v1/docs/{docId}/attachment-files/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/attachment-files/`,\n // Same tier split as the layer variants: the byte leaf is a stronger\n // capability than the metadata listing.\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-attachments': {\n id: 'layer-attachments',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/attachments@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachments@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/attachments@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachments@`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-attachment-files': {\n id: 'layer-attachment-files',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/attachment-files/*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachment-files/*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/attachment-files/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/attachment-files/`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-render': {\n id: 'layer-page-render',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/render/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/render/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/pages/`,\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-render-annotated': {\n id: 'layer-page-render-annotated',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/render/annotated/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/annotated/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/render/annotated/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/render/annotated/pages/`,\n requirement: { kind: 'single', capability: 'doc.render' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-text': {\n id: 'page-text',\n pathPattern: '/v1/docs/{docId}/text/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/text/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/text/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/text/pages/`,\n // Only doc.text.copy gates /text. doc.text.search is reserved for a\n // future dedicated /search endpoint and intentionally does NOT\n // grant /text access here.\n requirement: { kind: 'single', capability: 'doc.text.copy' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-text': {\n id: 'layer-page-text',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/text/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/text/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/text/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/text/pages/`,\n requirement: { kind: 'single', capability: 'doc.text.copy' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'page-geometry': {\n id: 'page-geometry',\n pathPattern: '/v1/docs/{docId}/geometry/pages/*/data@*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/geometry/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/geometry/pages/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/geometry/pages/`,\n // Same logic as /text: search is reserved for a future endpoint.\n requirement: { kind: 'single', capability: 'doc.text.select' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-page-geometry': {\n id: 'layer-page-geometry',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/geometry/pages/*/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/geometry/pages/*/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/geometry/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/geometry/pages/`,\n requirement: { kind: 'single', capability: 'doc.text.select' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-search-rects': {\n id: 'layer-search-rects',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/search/rects/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/rects/data@*`,\n // Prefix ends at `data@`: the CDN credential covers ONLY the\n // versioned, immutable form — the unversioned `data` URL is\n // origin-routed and never edge-cached.\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/search/rects/data@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/rects/data@`,\n requirement: { kind: 'single', capability: 'doc.text.search' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-search-full': {\n id: 'layer-search-full',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/search/full/data@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/full/data@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/search/full/data@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/search/full/data@`,\n requirement: { kind: 'all', capabilities: ['doc.text.search', 'doc.text.copy'] },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'annotations-read': {\n id: 'annotations-read',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/annotations/pages/*/items@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/pages/*/items@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/annotations/pages/',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/pages/`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-annotations-all': {\n id: 'layer-annotations-all',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/annotations/items@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/items@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/annotations/items@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/annotations/items@`,\n requirement: { kind: 'single', capability: 'doc.annotate.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'download-current': {\n id: 'download-current',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/download',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/download',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'origin',\n cdnCacheable: false,\n },\n 'download-versioned': {\n id: 'download-versioned',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/download@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/download@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/download@`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-signatures': {\n id: 'layer-signatures',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/signatures@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/signatures@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures@`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'layer-signatures-analysis': {\n id: 'layer-signatures-analysis',\n pathPattern: '/v1/docs/{docId}/layers/{layerName}/signatures/analysis@*',\n resolvePathPattern: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures/analysis@*`,\n pathPrefix: '/v1/docs/{docId}/layers/{layerName}/signatures/analysis@',\n resolvePathPrefix: (docId, layerName = 'default') =>\n `/v1/docs/${docId}/layers/${layerName}/signatures/analysis@`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n versions: {\n id: 'versions',\n pathPattern: '/v1/docs/{docId}/versions',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions`,\n pathPrefix: '/v1/docs/{docId}/versions',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions`,\n requirement: { kind: 'single', capability: 'doc.open' },\n routeKind: 'origin',\n // The list grows with every signature and its prefix covers every\n // version family below: never signed at the edge.\n cdnCacheable: false,\n },\n 'version-signatures': {\n id: 'version-signatures',\n pathPattern: '/v1/docs/{docId}/versions/signatures/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/signatures/*`,\n pathPrefix: '/v1/docs/{docId}/versions/signatures/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/signatures/`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'version-analysis': {\n id: 'version-analysis',\n pathPattern: '/v1/docs/{docId}/versions/analysis/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/analysis/*`,\n pathPrefix: '/v1/docs/{docId}/versions/analysis/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/analysis/`,\n requirement: { kind: 'single', capability: 'doc.forms.read' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'version-download': {\n id: 'version-download',\n pathPattern: '/v1/docs/{docId}/versions/download/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/download/*`,\n pathPrefix: '/v1/docs/{docId}/versions/download/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/download/`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n 'version-revisions': {\n id: 'version-revisions',\n pathPattern: '/v1/docs/{docId}/versions/revisions/*',\n resolvePathPattern: (docId) => `/v1/docs/${docId}/versions/revisions/*`,\n pathPrefix: '/v1/docs/{docId}/versions/revisions/',\n resolvePathPrefix: (docId) => `/v1/docs/${docId}/versions/revisions/`,\n requirement: { kind: 'single', capability: 'doc.download' },\n routeKind: 'versioned-read',\n cdnCacheable: true,\n },\n};\n\n/**\n * True iff the scope grants access to the named resource.\n *\n * Looks up the resource descriptor, then dispatches to\n * `checkCapability` or `checkAnyCapability` based on the requirement\n * shape. Used by both server route guards and the CDN signer.\n */\nexport function checkResourceAccess(\n resourceId: DocResourceId,\n rawScope: ReadonlyArray<string>,\n pdfBits: PdfBits,\n): boolean {\n const r = DOC_RESOURCES[resourceId];\n switch (r.requirement.kind) {\n case 'single':\n return checkCapability(r.requirement.capability, rawScope, pdfBits);\n case 'any':\n return checkAnyCapability(r.requirement.capabilities, rawScope, pdfBits);\n case 'all':\n return r.requirement.capabilities.every((cap) => checkCapability(cap, rawScope, pdfBits));\n }\n}\n\n// CDN-specific helpers (cdnCoverageForScope, CdnCoverageEntry,\n// applyCdnAccess, resolveResourceIdForPath) live under ./cdn/. They\n// build on DOC_RESOURCES + checkResourceAccess but are intentionally\n// segregated so cloud-only consumers don't accidentally pull general\n// route-guard code via the CDN module, and vice versa.\n","/**\n * Per-scope CDN coverage enumeration.\n *\n * Filters DOC_RESOURCES to the cacheable entries the caller's scope\n * grants, returning both URL projections every signer family needs:\n * - `pathPattern` — for glob-matching signers (CloudFront)\n * - `pathPrefix` — for prefix-matching signers (Bunny / Cloud CDN /\n * Azure FD / custom HMAC)\n *\n * Consumed by:\n * - the server's /access route, which feeds it into the CDN signer\n * - tests that pin per-scope coverage\n *\n * Never imported by engine-local — this is HTTP-wire territory.\n */\n\nimport type { PdfBits } from '../../auth/scope';\nimport type { LayerScopePlane, LayerScopes } from '../../dto/LayerScopes';\nimport { checkResourceAccess, DOC_RESOURCES, type DocResourceId } from '../resources';\n\n/**\n * One CDN-coverage entry: the resource id plus both projections of its\n * URL — the wildcard `pathPattern` (for pattern-matching CDN signers\n * like CloudFront) and the literal `pathPrefix` (for prefix-matching\n * CDN signers like Bunny / Cloud CDN / Azure FD / custom HMAC).\n *\n * Each entry corresponds to one cacheable resource the caller's\n * scope grants access to. Both projections are pre-resolved with the\n * concrete `docId` / `layerName` filled in.\n */\nexport interface CdnCoverageEntry {\n readonly resourceId: DocResourceId;\n /** Resolved CDN path pattern with `*` wildcards (for glob signers). */\n readonly pathPattern: string;\n /** Resolved literal path prefix (for prefix-match signers). */\n readonly pathPrefix: string;\n}\n\n/**\n * Enumerate the CDN-cacheable resources the scope can access. Returns\n * one {@link CdnCoverageEntry} per granted cacheable resource, carrying\n * both the pattern and the prefix so each adapter can pick the\n * projection it needs.\n *\n * Resources that are not cacheable (head, download-current) are\n * filtered out automatically — they're still gated by their\n * `requirement` at the origin route, but the CDN never gets a\n * credential for them.\n *\n * The URL restructure (paths v2) guarantees each cacheable resource\n * type has a distinct prefix, so prefix-matching adapters get\n * per-resource scope enforcement at the edge — a Bunny token signed\n * at `/v1/docs/{id}/render/pages/` can only authorize render bytes,\n * never text or annotations.\n */\n/**\n * Plane map: the planes each DOC-LEVEL shared resource depends on. A\n * layer token's edge credential covers a resource's prefix iff EVERY listed\n * plane is inherited (`'base'`) in the caller's scopes — the same condition\n * the origin guard enforces (origin is the truth; this grant is the\n * TTL-bounded optimization). Resources absent from this map (head, manifest,\n * every layer-scoped resource) are not plane-gated.\n *\n * `attachment-files` deliberately lists only `attachments` even though its\n * prefix also serves FileAttachment-annotation bytes (an `annotations`-plane\n * read): the origin guard on that route additionally requires `annotations`\n * inherited, and withholding the whole prefix on annotation divergence would\n * break plain attachment-file sharing for the most common divergence. The\n * residual is a warm-edge window bounded by the grant TTL — the same class\n * as every edge grant.\n */\nconst RESOURCE_PLANES: Partial<Record<DocResourceId, readonly LayerScopePlane[]>> = {\n 'page-render': ['content'],\n 'page-text': ['content'],\n 'page-geometry': ['content'],\n 'page-render-annotated': ['content', 'annotations'],\n 'page-annotations': ['annotations'],\n 'annotations-all': ['annotations'],\n layout: ['layout'],\n metadata: ['metadata'],\n actions: ['actions'],\n attachments: ['attachments'],\n 'attachment-files': ['attachments'],\n};\n\nexport function cdnCoverageForScope(\n rawScope: ReadonlyArray<string>,\n pdfBits: PdfBits,\n context: {\n docId: string;\n layerName?: string;\n /**\n * Plane scopes of the caller's pinned layer. A doc-level shared\n * resource's prefix is covered iff every plane it depends on is\n * inherited (`'base'`). Omitted = no layer in play (tenant tokens) —\n * everything the capability scope allows is granted.\n */\n scopes?: LayerScopes;\n },\n): ReadonlyArray<CdnCoverageEntry> {\n const out: CdnCoverageEntry[] = [];\n const scopes = context.scopes;\n for (const id of Object.keys(DOC_RESOURCES) as DocResourceId[]) {\n const r = DOC_RESOURCES[id];\n if (!r.cdnCacheable) continue;\n const planes = RESOURCE_PLANES[id];\n if (planes && scopes && planes.some((plane) => scopes[plane] === 'layer')) continue;\n if (!checkResourceAccess(id, rawScope, pdfBits)) continue;\n out.push({\n resourceId: id,\n pathPattern: r.resolvePathPattern(context.docId, context.layerName),\n pathPrefix: r.resolvePathPrefix(context.docId, context.layerName),\n });\n }\n return out;\n}\n","/**\n * Pure function that turns a request path + a `CdnAccessInfo` block\n * into the final URL the SDK should hit, plus any header/cookie side\n * effects to attach. Used by both:\n * - the @cloudpdf/engine HttpClient (to actually route requests through\n * the CDN edge when an /access response says it can)\n * - the smoke/diagnostic inspector (to PREVIEW what the SDK would do\n * for a given path, with no network)\n *\n * Keeping this in engine-core means cloud-side request routing and\n * server-side test fixtures use the SAME algorithm. If a regression\n * sneaks in, both ends break together.\n *\n * Selection rules\n * ───────────────\n * 1. Resolve the request path to a `DocResourceId` via DOC_RESOURCES\n * (longest-prefix-match on the resolved `pathPrefix`). Routes\n * that don't map to a known resource (admin, /access itself) get\n * `routedToCdn: false` and stay on origin.\n * 2. If `baseUrlOverrides[resourceId]` exists, swap the request's\n * origin to that CDN origin. If absent, the request stays on\n * origin — that's how scope narrowing works at the edge: the\n * server only emits overrides for resources the caller's scope\n * grants.\n * 3. Find the LONGEST-matching `signedPathPolicies` entry (its\n * `pathPrefix` is a prefix of the request path). Append its\n * `queryParams`. No match falls back to `signedQueryParams` if\n * the adapter emitted a global token.\n * 4. `signedCookies` and `authHeader` are surfaced verbatim — the\n * HttpClient sets cookies once per session and applies the\n * header to every CDN request.\n */\n\nimport { DOC_RESOURCES, type DocResourceId } from '../resources';\n\n/**\n * Subset of `CdnAccessInfo` this function needs. The full type lives\n * in `engine/DocumentSecurityService.ts` (it's part of the access\n * response); we mirror just the fields we read so this module is\n * decoupled from the security service surface.\n */\nexport interface CdnAccessInfoForApply {\n readonly adapter: string;\n readonly baseUrlOverrides: Partial<Record<string, string>> | null;\n readonly authHeader: { readonly name: string; readonly value: string } | null;\n readonly signedQueryParams: Record<string, string> | null;\n readonly signedCookies: ReadonlyArray<{\n readonly name: string;\n readonly value: string;\n readonly domain?: string;\n readonly path?: string;\n readonly expires?: number;\n }> | null;\n readonly signedPathPolicies: ReadonlyArray<{\n readonly pathPrefix: string;\n readonly queryParams: Record<string, string>;\n }> | null;\n}\n\nexport interface ApplyCdnAccessInput {\n /** Path portion of the request (must begin with `/`). */\n readonly path: string;\n /** API server origin the SDK would normally hit, e.g. `https://api.example.com`. */\n readonly originUrl: string;\n /** Doc id used to resolve resource path prefixes. */\n readonly docId: string;\n /** Layer name for layer-scoped resources (defaults to `'default'`). */\n readonly layerName?: string;\n /** Access block from /v1/access. When null, every call goes to origin. */\n readonly cdn: CdnAccessInfoForApply | null;\n}\n\nexport interface ApplyCdnAccessResult {\n /** Final URL the SDK should fetch. */\n readonly url: string;\n /** Resource the path was identified as, or null if it's not a DOC_RESOURCES route. */\n readonly resourceId: DocResourceId | null;\n /** True iff the request was routed to the CDN; false means origin fallthrough. */\n readonly routedToCdn: boolean;\n /** The signedPathPolicies entry that matched, if any. */\n readonly matchedPolicy: {\n readonly pathPrefix: string;\n readonly queryParams: Record<string, string>;\n } | null;\n /** Single global header to attach (custom-hmac header mode only). */\n readonly authHeader: { readonly name: string; readonly value: string } | null;\n /** Cookies the SDK should set on the CDN origin before this request. */\n readonly cookies: CdnAccessInfoForApply['signedCookies'];\n /**\n * Human-readable explanation when `routedToCdn` is false. Empty\n * string when the request did route to CDN.\n */\n readonly fallbackReason: string;\n}\n\nexport function applyCdnAccess(input: ApplyCdnAccessInput): ApplyCdnAccessResult {\n const { path, originUrl, docId, layerName, cdn } = input;\n const layer = layerName ?? 'default';\n\n // 1. Identify the resource by path prefix (or null if it's not a\n // DOC_RESOURCES route — admin endpoints, /access itself, /warm).\n const resourceId = resolveResourceIdForPath(path, docId, layer);\n\n // No CDN configured (no /access call yet, or signer is `none`).\n if (!cdn || cdn.adapter === 'none') {\n return {\n url: `${trimRight(originUrl)}${path}`,\n resourceId,\n routedToCdn: false,\n matchedPolicy: null,\n authHeader: null,\n cookies: null,\n fallbackReason: cdn\n ? 'CDN signer is `none` — every request stays on origin.'\n : 'No CdnAccessInfo on this session — request stays on origin.',\n };\n }\n\n // 2. Not a known cacheable resource → stays on origin.\n if (!resourceId) {\n return {\n url: `${trimRight(originUrl)}${path}`,\n resourceId: null,\n routedToCdn: false,\n matchedPolicy: null,\n authHeader: null,\n cookies: null,\n fallbackReason: 'Request path does not match any known DOC_RESOURCES route.',\n };\n }\n\n const cdnOrigin = cdn.baseUrlOverrides?.[resourceId];\n if (!cdnOrigin) {\n // Resource granted no CDN override → caller's scope didn't grant\n // it (or it's a non-cacheable resource like /head /download).\n return {\n url: `${trimRight(originUrl)}${path}`,\n resourceId,\n routedToCdn: false,\n matchedPolicy: null,\n authHeader: null,\n cookies: null,\n fallbackReason: `No baseUrlOverrides[${resourceId}] — scope does not grant this resource through the CDN.`,\n };\n }\n\n // 3. Find the longest matching signedPathPolicies entry.\n const matchedPolicy = (cdn.signedPathPolicies ?? [])\n .filter((p) => path.startsWith(p.pathPrefix))\n .sort((a, b) => b.pathPrefix.length - a.pathPrefix.length)[0];\n\n const url = new URL(`${trimRight(cdnOrigin)}${path}`);\n if (matchedPolicy) {\n for (const [k, v] of Object.entries(matchedPolicy.queryParams)) {\n url.searchParams.set(k, v);\n }\n } else if (cdn.signedQueryParams) {\n for (const [k, v] of Object.entries(cdn.signedQueryParams)) {\n url.searchParams.set(k, v);\n }\n }\n\n return {\n url: url.toString(),\n resourceId,\n routedToCdn: true,\n matchedPolicy: matchedPolicy\n ? { pathPrefix: matchedPolicy.pathPrefix, queryParams: matchedPolicy.queryParams }\n : null,\n authHeader: cdn.authHeader,\n cookies: cdn.signedCookies,\n fallbackReason: '',\n };\n}\n\n/**\n * Walk DOC_RESOURCES and pick the entry whose resolved `pathPrefix`\n * is a (longest) prefix of `path`. Returns null when no resource\n * matches — admin routes, /access, /warm fall into this bucket.\n *\n * Each cacheable resource has a DISTINCT prefix (paths v2 invariant),\n * so longest-match is deterministic.\n */\nexport function resolveResourceIdForPath(\n path: string,\n docId: string,\n layerName: string,\n): DocResourceId | null {\n let best: { id: DocResourceId; prefixLength: number } | null = null;\n for (const id of Object.keys(DOC_RESOURCES) as DocResourceId[]) {\n const r = DOC_RESOURCES[id];\n const prefix = r.resolvePathPrefix(docId, layerName);\n if (!path.startsWith(prefix)) continue;\n if (!best || prefix.length > best.prefixLength) {\n best = { id, prefixLength: prefix.length };\n }\n }\n return best?.id ?? null;\n}\n\nfunction trimRight(url: string): string {\n return url.endsWith('/') ? url.slice(0, -1) : url;\n}\n","/**\n * Generic recursive flattener for nested option objects into dotted-key flat\n * maps, and its inverse. The wire format (token + query) is a flat key/value\n * shape, but SDK option types (e.g. `PageImageOptions`) are nested with\n * discriminated unions. Keeping these conversions generic means new options\n * never require bespoke encoder/decoder code — they're just shape changes to\n * the schema.\n *\n * Rules:\n * - Nested object keys are joined with `.` (e.g. `viewport.kind`,\n * `target.rect.left`).\n * - `undefined` and `null` are dropped.\n * - Arrays are not supported (the wire format has no list grammar yet).\n * - Scalar leaves must be `string | number | boolean`.\n * - Round-trip: `unflatten(flatten(x))` equals `x` modulo dropped\n * `undefined`/`null` and array leaves.\n *\n * The path separator `.` is reserved in field names by the token codec, which\n * lets us distinguish wire-level structure from value content (values may\n * still contain `.` for decimals — values are not split on `.`).\n */\n\nexport type WireScalar = string | number | boolean;\nexport type WireFlat = Record<string, WireScalar>;\n\nconst PATH_SEPARATOR = '.';\n\nexport function flatten(value: unknown, prefix = ''): WireFlat {\n const out: WireFlat = {};\n flattenInto(value, prefix, out);\n return out;\n}\n\nfunction flattenInto(value: unknown, prefix: string, out: WireFlat): void {\n if (value === undefined || value === null) return;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n if (!prefix) throw new Error('flatten: root value must be an object, not a scalar');\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw new Error(`flatten: non-finite number at \"${prefix}\"`);\n }\n out[prefix] = value;\n return;\n }\n if (Array.isArray(value)) {\n throw new Error(`flatten: arrays are not supported (at \"${prefix || '<root>'}\")`);\n }\n if (typeof value !== 'object') {\n throw new Error(`flatten: unsupported value type at \"${prefix || '<root>'}\"`);\n }\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (k.includes(PATH_SEPARATOR)) {\n throw new Error(`flatten: object key \"${k}\" must not contain \"${PATH_SEPARATOR}\"`);\n }\n flattenInto(v, prefix ? `${prefix}${PATH_SEPARATOR}${k}` : k, out);\n }\n}\n\n/**\n * Inverse of `flatten`. Takes a flat string-or-scalar map and reconstructs a\n * nested object using `.` as the path separator. Values are passed through\n * unchanged — downstream schema validation (e.g. Zod with `.coerce`) is\n * responsible for type coercion from `string` to numbers/booleans when the\n * input came from a token or query string.\n *\n * Throws on conflicting paths (e.g. having both `viewport` and\n * `viewport.kind` in the same input).\n */\nexport function unflatten(flat: Record<string, unknown>): Record<string, unknown> {\n const root: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(flat)) {\n if (value === undefined) continue;\n if (key.length === 0) throw new Error('unflatten: empty key');\n if (key.startsWith(PATH_SEPARATOR) || key.endsWith(PATH_SEPARATOR)) {\n throw new Error(`unflatten: key \"${key}\" must not start or end with \"${PATH_SEPARATOR}\"`);\n }\n if (key.includes(`${PATH_SEPARATOR}${PATH_SEPARATOR}`)) {\n throw new Error(`unflatten: key \"${key}\" must not contain empty segments`);\n }\n const path = key.split(PATH_SEPARATOR);\n let cur: Record<string, unknown> = root;\n for (let i = 0; i < path.length - 1; i++) {\n const seg = path[i];\n const existing = cur[seg];\n if (existing === undefined) {\n const next: Record<string, unknown> = {};\n cur[seg] = next;\n cur = next;\n continue;\n }\n if (existing === null || typeof existing !== 'object' || Array.isArray(existing)) {\n throw new Error(\n `unflatten: conflicting paths at \"${path.slice(0, i + 1).join(PATH_SEPARATOR)}\"`,\n );\n }\n cur = existing as Record<string, unknown>;\n }\n const leaf = path[path.length - 1];\n if (cur[leaf] !== undefined) {\n throw new Error(`unflatten: duplicate key \"${key}\"`);\n }\n cur[leaf] = value;\n }\n return root;\n}\n","import { flatten, type WireFlat } from './flatten';\nimport { encodeAnnotationAppearancesRenderToken, encodeRenderToken } from './tokens';\nimport type {\n AnnotationAppearanceImageOptions,\n AnnotationAppearanceRenderOptions,\n} from '../dto/AnnotationRender';\nimport type { PageImageOptions, PageRenderOptions } from '../dto/PageRender';\n\nexport interface RenderVersions {\n contentVersion: number;\n annotationVersion?: number;\n}\n\n/**\n * Project image render options plus cache versions into the flat wire shape\n * the render token encoder consumes. The output is a generic dotted-key map\n * (`viewport.kind`, `target.rect.left`, …) — the schema and codec never need\n * to know about specific option fields. Adding a new render option means\n * extending `PageImageOptions`, the render query schemas, and\n * `RenderTokenSchema.fields`; this function does not change.\n *\n * Token/path rule: tokens carry VERSION PINS and RENDER\n * PARAMETERS; anything that changes the artifact's plane-dependency set is\n * PATH-expressed. Annotatedness changes the planes (`content` vs\n * `content + annotations`), so the wire map never carries\n * `includeAnnotations` — the caller picks the path FAMILY\n * (`…/render/pages/` vs `…/render/annotated/pages/`) and passes\n * `annotationVersion` iff it chose the annotated one. Contradictory states\n * are unrepresentable; each family's query schema enforces its own pin\n * grammar structurally.\n *\n * Semantic validation (viewport-kind invariants, per-family pin presence,\n * rect coherence) lives in `PageRenderQuerySchema` /\n * `PageRenderAnnotatedQuerySchema` and runs when the resulting URL is\n * decoded server-side. Round-tripping (flatten → encode → decode →\n * unflatten → schema parse) recovers the original SDK options.\n */\nexport function renderImageOptionsToWire(\n options: PageImageOptions,\n versions: RenderVersions,\n): WireFlat {\n // Path-expressed, never token-expressed (see above).\n const { includeAnnotations: _pathExpressed, ...wireOptions } = options;\n return flatten({\n ...wireOptions,\n contentVersion: versions.contentVersion,\n ...(versions.annotationVersion !== undefined\n ? { annotationVersion: versions.annotationVersion }\n : {}),\n });\n}\n\n/**\n * Convenience: build the full encoded render token in one call. Equivalent\n * to `encodeRenderToken(renderImageOptionsToWire(options, versions))`.\n */\nexport function renderImageOptionsToToken(\n options: PageImageOptions,\n versions: RenderVersions,\n): string {\n return encodeRenderToken(renderImageOptionsToWire(options, versions));\n}\n\n/**\n * Re-attach `includeAnnotations` onto the worker-side `PageRenderOptions`\n * shape. Pure shape transform; consumed by the server route after\n * `PageRenderQuerySchema` has produced the SDK-shaped options.\n */\nexport function pageRenderOptionsFromImageOptions(\n options: PageImageOptions,\n includeAnnotations: boolean,\n): PageRenderOptions {\n return {\n ...(options.target ? { target: options.target } : {}),\n ...(options.viewport ? { viewport: options.viewport } : {}),\n ...(options.rotation !== undefined ? { rotation: options.rotation } : {}),\n ...(options.background !== undefined ? { background: options.background } : {}),\n includeAnnotations,\n };\n}\n\n/**\n * Cache version for the appearance render token. Appearances depend only on\n * the annotation `/AP` stream, so `annotationVersion` is the sole key —\n * deliberately NOT `contentVersion`.\n */\nexport interface AnnotationRenderVersion {\n annotationVersion: number;\n}\n\n/**\n * Project annotation-appearance image options plus the annotation version\n * into the flat wire shape the appearance render token encoder consumes.\n * Mirrors {@link renderImageOptionsToWire}.\n */\nexport function annotationAppearancesImageOptionsToWire(\n options: AnnotationAppearanceImageOptions,\n versions: AnnotationRenderVersion,\n): WireFlat {\n return flatten({\n ...options,\n annotationVersion: versions.annotationVersion,\n });\n}\n\n/** Convenience: build the full encoded appearance render token in one call. */\nexport function annotationAppearancesImageOptionsToToken(\n options: AnnotationAppearanceImageOptions,\n versions: AnnotationRenderVersion,\n): string {\n return encodeAnnotationAppearancesRenderToken(\n annotationAppearancesImageOptionsToWire(options, versions),\n );\n}\n\n/**\n * Strip image-encoding fields, leaving the worker-side\n * `AnnotationAppearanceRenderOptions`. Pure shape transform consumed by the\n * server route after `AnnotationAppearancesQuerySchema` produces the\n * SDK-shaped options.\n */\nexport function annotationRenderOptionsFromImageOptions(\n options: AnnotationAppearanceImageOptions,\n): AnnotationAppearanceRenderOptions {\n return {\n ...(options.scale !== undefined ? { scale: options.scale } : {}),\n ...(options.rotation !== undefined ? { rotation: options.rotation } : {}),\n ...(options.modes ? { modes: options.modes } : {}),\n };\n}\n"],"mappings":"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"}
|