@embedpdf/engine-core 3.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +192 -0
- package/README.md +24 -0
- package/dist/AbortError-ByBflvEl.cjs +38 -0
- package/dist/AbortError-ByBflvEl.cjs.map +1 -0
- package/dist/AbortError-CjSasIlL.js +27 -0
- package/dist/AbortError-CjSasIlL.js.map +1 -0
- package/dist/AnnotationListSnapshot-W0RCsyDE.d.cts +5043 -0
- package/dist/AnnotationListSnapshot-W0RCsyDE.d.ts +5043 -0
- package/dist/DocumentSecurityService-B-tULKNY.d.ts +332 -0
- package/dist/DocumentSecurityService-Df79fgpe.d.cts +332 -0
- package/dist/Engine-B7Oe7f5i.d.ts +1013 -0
- package/dist/Engine-D9loFZc1.d.cts +1013 -0
- package/dist/builders-BvikWRuO.cjs +1684 -0
- package/dist/builders-BvikWRuO.cjs.map +1 -0
- package/dist/builders-C548U47M.js +1367 -0
- package/dist/builders-C548U47M.js.map +1 -0
- package/dist/conformance.cjs +5414 -0
- package/dist/conformance.cjs.map +1 -0
- package/dist/conformance.d.cts +530 -0
- package/dist/conformance.d.ts +530 -0
- package/dist/conformance.js +5394 -0
- package/dist/conformance.js.map +1 -0
- package/dist/fold-CB4fAOOy.js +175 -0
- package/dist/fold-CB4fAOOy.js.map +1 -0
- package/dist/fold-IaMph3CO.cjs +216 -0
- package/dist/fold-IaMph3CO.cjs.map +1 -0
- package/dist/index.cjs +82 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/resolver-DAZWVoJL.cjs +434 -0
- package/dist/resolver-DAZWVoJL.cjs.map +1 -0
- package/dist/resolver-DiPMTfcy.js +363 -0
- package/dist/resolver-DiPMTfcy.js.map +1 -0
- package/dist/runtime.cjs +453 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +1002 -0
- package/dist/runtime.d.ts +1002 -0
- package/dist/runtime.js +361 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schemas-9OpSSeM6.js +2493 -0
- package/dist/schemas-9OpSSeM6.js.map +1 -0
- package/dist/schemas-B_1VyFsm.cjs +3608 -0
- package/dist/schemas-B_1VyFsm.cjs.map +1 -0
- package/dist/subtype-BvAzLCGC.js +196 -0
- package/dist/subtype-BvAzLCGC.js.map +1 -0
- package/dist/subtype-qejjVr6h.cjs +231 -0
- package/dist/subtype-qejjVr6h.cjs.map +1 -0
- package/dist/wire.cjs +1516 -0
- package/dist/wire.cjs.map +1 -0
- package/dist/wire.d.cts +1546 -0
- package/dist/wire.d.ts +1546 -0
- package/dist/wire.js +1280 -0
- package/dist/wire.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builders-C548U47M.js","names":[],"sources":["../src/geometry/convert.ts","../src/dto/PageRender.ts","../src/dto/PdfSaveMode.ts","../src/identity/PageObjectNumber.ts","../src/identity/AnnotationStableId.ts","../src/revision/RevisionToken.ts","../src/revision/WeakAnnotationState.ts","../src/annotation/primitives.ts","../src/resource/BinarySource.ts","../src/resource/binaryMetadata.ts","../src/annotation/kinds/file-attachment/normalize.ts","../src/annotation/kinds/stamp/normalize.ts","../src/annotation/normalize.ts","../src/annotation/relationships.ts","../src/mutation/AnnotationMutationImpactPolicy.ts","../src/annotation/appearance.ts","../src/identity/FormFieldRef.ts","../src/search/literal.ts","../src/search/regex.ts","../src/search/matcher.ts","../src/search/snippet.ts","../src/search/rects.ts","../src/search/epoch.ts","../src/auth/scope/pdf-bits.ts","../src/auth/scope/builders.ts"],"sourcesContent":["/**\n * PDF-space-internal geometry helpers.\n *\n * These operate ENTIRELY within PDF user space (y-up, edges). They never\n * produce viewer-local (y-down) geometry — that conversion needs the crop box\n * plus rotation/scale and lives in the v3 viewer layer (the `Mat2D` matrix\n * model), never here.\n */\n\nimport type { PdfPoint, PdfQuad, PdfRect, PdfSize } from './primitives';\n\n/** Origin + size form of a `PdfRect`, still y-up (origin = bottom-left). */\nexport interface PdfOriginSize {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Normalize a `PdfRect` to the y-up invariant (`left <= right`, `bottom <= top`),\n * regardless of how the PDF ordered the corners (a `/Rect` array or `FS_RECTF`\n * may carry them in any order). THE enforcement point for the \"PdfRect is always\n * normalized\" rule: every producer that reads a raw box from PDFium passes it\n * through here, so the invariant holds once, centrally — downstream `width =\n * right - left` is never negative.\n */\nexport function normalizePdfRect(r: PdfRect): PdfRect {\n return {\n left: Math.min(r.left, r.right),\n right: Math.max(r.left, r.right),\n bottom: Math.min(r.top, r.bottom),\n top: Math.max(r.top, r.bottom),\n };\n}\n\nexport function pdfRectWidth(r: PdfRect): number {\n return r.right - r.left;\n}\n\nexport function pdfRectHeight(r: PdfRect): number {\n return r.top - r.bottom;\n}\n\nexport function pdfRectSize(r: PdfRect): PdfSize {\n return { width: r.right - r.left, height: r.top - r.bottom };\n}\n\n/** Convert edges -> origin+size, staying y-up (origin at bottom-left). */\nexport function pdfRectToOriginSize(r: PdfRect): PdfOriginSize {\n return { x: r.left, y: r.bottom, width: r.right - r.left, height: r.top - r.bottom };\n}\n\n/** Convert y-up origin+size back to edges. */\nexport function pdfRectFromOriginSize(o: PdfOriginSize): PdfRect {\n return { left: o.x, bottom: o.y, right: o.x + o.width, top: o.y + o.height };\n}\n\n/**\n * Enclosing axis-aligned box of a quad, in PDF user space. Orientation\n * agnostic (correct for rotated/skewed quads) — this is what highlight\n * rendering and hit-testing want.\n */\nexport function pdfQuadBounds(q: PdfQuad): PdfRect {\n const xs = [q.p1.x, q.p2.x, q.p3.x, q.p4.x];\n const ys = [q.p1.y, q.p2.y, q.p3.y, q.p4.y];\n return {\n left: Math.min(...xs),\n right: Math.max(...xs),\n bottom: Math.min(...ys),\n top: Math.max(...ys),\n };\n}\n\n/** Named corners of a quad, in PDF user space (y-up). */\nexport interface PdfQuadCorners {\n topLeft: PdfPoint;\n topRight: PdfPoint;\n bottomLeft: PdfPoint;\n bottomRight: PdfPoint;\n}\n\n/**\n * Axis-aligned named-corner interpretation of a quad.\n *\n * VALID ONLY for upright (non-rotated, non-skewed) quads: it is derived from\n * the enclosing bounds, so for rotated/skewed quads it returns the bounding\n * box corners, not the true geometric corners. For arbitrary quads use the\n * positional `p1..p4` or `pdfQuadBounds` directly.\n */\nexport function pdfQuadCorners(q: PdfQuad): PdfQuadCorners {\n const b = pdfQuadBounds(q);\n return {\n topLeft: { x: b.left, y: b.top },\n topRight: { x: b.right, y: b.top },\n bottomLeft: { x: b.left, y: b.bottom },\n bottomRight: { x: b.right, y: b.bottom },\n };\n}\n\n/**\n * Build a quad from named corners, in PDFium `FS_QUADPOINTSF` slot order\n * (`p1 = topLeft`, `p2 = topRight`, `p3 = bottomLeft`, `p4 = bottomRight`).\n * The inverse of `pdfQuadCorners` for upright quads.\n */\nexport function pdfQuadFromCorners(c: PdfQuadCorners): PdfQuad {\n return { p1: c.topLeft, p2: c.topRight, p3: c.bottomLeft, p4: c.bottomRight };\n}\n","import { EngineError } from '../errors/EngineError';\nimport { EngineErrorCode } from '../errors/EngineErrorCode';\nimport type { PdfRect, PdfRotation } from '../geometry/primitives';\n\nexport type PageRenderEncodedFormat = 'png' | 'webp' | 'bmp';\n\n/**\n * Formats that are acceptable for cacheable cloud HTTP render endpoints.\n * BMP and raw RGBA stay local-only because they are intentionally huge.\n */\nexport type PageNetworkRenderFormat = 'png' | 'webp';\n\nexport type PageRenderFormat = PageRenderEncodedFormat | 'rgba';\n\nexport type PageRenderBackground = 'white' | 'transparent';\n\nexport type PageRenderViewport =\n | {\n /**\n * Render one PDF user-space unit as `scale` device pixels. Callers\n * that care about devicePixelRatio should fold it into this value.\n */\n kind: 'scale';\n scale?: number;\n }\n | {\n /**\n * Exact output width in device pixels. Height preserves the region's\n * aspect ratio after rotation.\n */\n kind: 'width';\n width: number;\n };\n\nexport type PageRenderTarget =\n | { kind: 'page' }\n | {\n kind: 'rect';\n /**\n * PDF user-space rectangle. Same convention as annotation rects:\n * top > bottom, origin at the PDF page's bottom-left.\n */\n rect: PdfRect;\n };\n\nexport interface PageRenderOptions {\n target?: PageRenderTarget;\n viewport?: PageRenderViewport;\n rotation?: PdfRotation;\n background?: PageRenderBackground;\n includeAnnotations?: boolean;\n /**\n * Output-pixel budget: the renderer rejects (InvalidArg) instead of\n * allocating when `outputWidth × outputHeight` exceeds it. A WIDTH\n * lattice bounds width but not height — a 1×14,400pt page still\n * explodes vertically — so the guard lives where the allocation\n * happens (the decode-bomb-guard pattern). SERVER requests carry it\n * from the deployment's render policy; LOCAL engines inject it only\n * when `localEngine({ renderPolicy })` configured a budget — the\n * default local policy stays continuous and unbudgeted (exactness is\n * the local product promise).\n */\n maxOutputPixels?: number;\n}\n\nexport interface PageImageOptions extends PageRenderOptions {\n format?: PageRenderEncodedFormat;\n quality?: number;\n}\n\nexport interface PageRenderQuery {\n options: PageImageOptions;\n contentVersion?: number;\n annotationVersion?: number;\n}\n\n/**\n * Raw renderer output shared by local workers and server workers. The pixel\n * buffer is a first-class ArrayBuffer so worker transports can transfer\n * ownership instead of cloning it.\n */\nexport interface PageRaster {\n width: number;\n height: number;\n stride: number;\n color: 'rgba8';\n premultipliedAlpha: false;\n data: ArrayBuffer;\n}\n\nexport interface PageImageResult {\n width?: number;\n height?: number;\n format: PageRenderEncodedFormat;\n contentType: string;\n source: PageImageSource;\n}\n\nexport type PageImageSource = { kind: 'bytes'; bytes: Uint8Array } | { kind: 'url'; url: string };\n\nexport interface PageImageObjectUrl {\n url: string;\n revoke(): void;\n}\n\nexport interface PageImageHandle extends PageImageResult {\n objectUrl(signal?: AbortSignal): Promise<PageImageObjectUrl>;\n}\n\nexport interface PageImageBlobSource {\n blob(signal?: AbortSignal): Promise<Blob>;\n}\n\nexport function createPageImageHandle(\n result: PageImageResult,\n blobSource: PageImageBlobSource,\n): PageImageHandle {\n return {\n ...result,\n async objectUrl(signal?: AbortSignal) {\n if (typeof Blob === 'undefined' || typeof URL === 'undefined' || !URL.createObjectURL) {\n throw new EngineError(\n EngineErrorCode.RuntimeUnavailable,\n 'Object URLs are not available in this environment',\n );\n }\n\n const blob = await blobSource.blob(signal);\n const url = URL.createObjectURL(blob);\n return { url, revoke: () => URL.revokeObjectURL(url) };\n },\n };\n}\n","export type PdfSaveMode = 'incremental' | 'rewrite';\n\nexport const DEFAULT_PDF_SAVE_MODE: PdfSaveMode = 'incremental';\n","/**\n * PDF indirect object number for a page.\n *\n * Resolved via the PDFium runtime helper `EPDFPage_GetObjectNumber(pagePtr)`.\n * Always > 0 for well-formed PDFs. This replaces the v2 page index as the\n * primary addressing key. The page index is kept on `PageHandle` as display\n * metadata only, because it can shift when pages are inserted, deleted, or\n * reordered while a session is open.\n */\nexport type PageObjectNumber = number;\n\n/**\n * Type guard for the rare malformed-PDF case where a page is a direct\n * object. The engine treats `0` as malformed and throws `EngineError(NotFound)`\n * before any page-level operation.\n */\nexport function isValidPageObjectNumber(value: unknown): value is PageObjectNumber {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n}\n","/**\n * The two durable ways to address an annotation across reads.\n *\n * `objectNumber` is the PDF indirect object number, returned by\n * `EPDFAnnot_GetObjectNumber(annotPtr)`. It is `> 0` for indirect objects\n * (the overwhelming common case) and `0` for direct objects (rare, legacy\n * PDFs). When the engine sees `0` it falls back to `nm` if present, or\n * promotes the annotation to a weak ref (`AnnotationRef.kind === 'index'`).\n *\n * `nm` is the value of the annotation's `/NM` entry. The v3 engine never\n * writes `/NM` on read — clients can opt into symbolic IDs by passing one to\n * `create()`, but reads never mutate the document.\n */\nexport type AnnotationStableId =\n | { kind: 'objectNumber'; value: number }\n | { kind: 'nm'; value: string };\n\n/**\n * URL-safe encoding of a stable id, used by the cloud HTTP surface as the\n * `:annotKey` route parameter. Decoded by the server back into an\n * `AnnotationStableId` via `decodeStableIdKey`.\n *\n * Format:\n * `{ kind: 'objectNumber', value: 42 }` -> `'obj:42'`\n * `{ kind: 'nm', value: 'foo bar' }` -> `'nm:foo bar'`\n *\n * The caller is responsible for `encodeURIComponent`-ing the result before\n * splicing it into a URL path; `wirePaths.layerAnnotationByKey` already does\n * that. /NM values are opaque strings and may contain anything; the\n * `nm:` prefix lets the decoder distinguish them from numeric ids\n * unambiguously.\n */\nexport function encodeStableIdKey(id: AnnotationStableId): string {\n if (id.kind === 'objectNumber') {\n if (!Number.isInteger(id.value) || id.value <= 0) {\n throw new RangeError(\n `encodeStableIdKey: objectNumber must be a positive integer, got ${id.value}`,\n );\n }\n return `obj:${id.value}`;\n }\n return `nm:${id.value}`;\n}\n\n/**\n * Inverse of `encodeStableIdKey`. Returns `null` for malformed input so\n * the server can answer 400 InvalidArg with a useful message instead of\n * throwing.\n *\n * The input is the already-`decodeURIComponent`-ed segment from the route\n * path. Empty `/NM` values are rejected: `nm:` with no suffix is not a\n * valid identity.\n */\nexport function decodeStableIdKey(key: string): AnnotationStableId | null {\n if (key.startsWith('obj:')) {\n const rest = key.slice('obj:'.length);\n const n = Number.parseInt(rest, 10);\n if (!Number.isInteger(n) || n <= 0 || String(n) !== rest) return null;\n return { kind: 'objectNumber', value: n };\n }\n if (key.startsWith('nm:')) {\n const value = key.slice('nm:'.length);\n if (value.length === 0) return null;\n return { kind: 'nm', value };\n }\n return null;\n}\n","import type { PageObjectNumber } from '../identity/PageObjectNumber';\n\n/**\n * Opaque token a client must hand back when addressing an annotation by\n * `(pageObjectNumber, index)`. The engine validates strict equality against\n * its own `RevisionStore`; mismatches throw `EngineError(InvalidReference)`.\n *\n * Bleed-over prevention: `docSessionId` ties a token to one open session,\n * so a token minted before close-and-reopen is rejected by the new session.\n */\nexport interface RevisionToken {\n docSessionId: string;\n pageObjectNumber: PageObjectNumber;\n generation: number;\n}\n\nexport function revisionTokensEqual(a: RevisionToken, b: RevisionToken): boolean {\n return (\n a.docSessionId === b.docSessionId &&\n a.pageObjectNumber === b.pageObjectNumber &&\n a.generation === b.generation\n );\n}\n","/**\n * Tri-state knowledge about weak annotation identities on a page.\n *\n * `known(false)` is a stronger claim than \"we have not looked yet\": it means\n * the page's annotations were scanned and every annotation had a durable\n * identity. Cloud/CDN manifests must only publish boolean weak flags from a\n * known state.\n */\nexport type WeakAnnotationState =\n | { kind: 'unknown' }\n | { kind: 'known'; hasAnyWeakAnnotations: boolean };\n\nexport const UNKNOWN_WEAK_ANNOTATION_STATE: WeakAnnotationState = { kind: 'unknown' };\n\nexport function knownWeakAnnotationState(hasAnyWeakAnnotations: boolean): WeakAnnotationState {\n return { kind: 'known', hasAnyWeakAnnotations };\n}\n","/**\n * Wire-stable annotation primitives that are NOT pure geometry.\n *\n * Geometry primitives (points, rects, sizes, quads, rotation) now live in\n * `../geometry` as the canonical `Pdf*` vocabulary. The aliases below are\n * TRANSITIONAL re-exports kept only so existing consumers keep compiling\n * during the geometry consolidation; new code should import `Pdf*` directly\n * from `../geometry`.\n *\n * These do not depend on PDFium or any browser/Node surface; they are\n * the lingua franca between local engine, cloud engine, and server.\n */\n\nimport type { PdfPoint, PdfRect, PdfRotation, PdfSize } from '../geometry/primitives';\n\n/** @deprecated Use `PdfPoint` from `../geometry`. */\nexport type Point = PdfPoint;\n/** @deprecated Use `PdfRect` from `../geometry`. */\nexport type Rect = PdfRect;\n/** @deprecated Use `PdfSize` from `../geometry`. */\nexport type Size = PdfSize;\n/** @deprecated Use `PdfRotation` from `../geometry`. */\nexport type Rotation = PdfRotation;\n\n/**\n * sRGB color. Components are 0..255 integers. Engines normalize PDFium's\n * device color space into sRGB at read time.\n *\n * Colour carries NO alpha: annotation transparency is a separate concern\n * stored in `/CA` and surfaced as the `opacity` style field, so there is a\n * single source of truth for transparency. See `ColorStyleFields.opacity`.\n */\nexport interface Color {\n r: number;\n g: number;\n b: number;\n}\n\n/**\n * /LE entries (line endings). Maps PDFium FPDFAnnot_GetLineEndings codes\n * onto the spec names. We use kebab-case so the wire format is stable\n * across language ports.\n */\nexport type LineEnding =\n | 'none'\n | 'square'\n | 'circle'\n | 'diamond'\n | 'open-arrow'\n | 'closed-arrow'\n | 'butt'\n | 'r-open-arrow'\n | 'r-closed-arrow'\n | 'slash';\n\n/**\n * The `/LE` pair carried by line and polyline annotations: the ending\n * drawn at the start point and the ending drawn at the end point.\n */\nexport interface LineEndings {\n start: LineEnding;\n end: LineEnding;\n}\n\n/**\n * The 14 standard PDF fonts a free-text annotation's `/DA` can name. We use\n * kebab-case so the wire format is stable across language ports; the engine\n * maps these onto PDFium's `FPDF_STANDARD_FONT` integer codes at write time.\n */\nexport type StandardFont =\n | 'courier'\n | 'courier-bold'\n | 'courier-bold-oblique'\n | 'courier-oblique'\n | 'helvetica'\n | 'helvetica-bold'\n | 'helvetica-bold-oblique'\n | 'helvetica-oblique'\n | 'times-roman'\n | 'times-bold'\n | 'times-bold-italic'\n | 'times-italic'\n | 'symbol'\n | 'zapf-dingbats';\n\n/**\n * Font selector for a free-text annotation: either one of the 14 PDF\n * {@link StandardFont} names, or the `key` of a font registered through\n * `engine.fonts` (local/WASM engine only).\n *\n * The `(string & {})` arm keeps the standard-font literals auto-completing\n * while still accepting any registered key. Because the standard names are\n * matched first at write time, those 14 names are reserved: don't register a\n * custom font under a key like `'helvetica'`.\n */\nexport type FreeTextFont = StandardFont | (string & {});\n\n/**\n * Horizontal text alignment (`/Q`) for free-text annotations. Maps onto the\n * ISO 32000 §12.7.3.3 quadding codes 0/1/2 at write time.\n */\nexport type TextAlignment = 'left' | 'center' | 'right';\n\n/**\n * Free-text `/IT` intent. `free-text` is a plain text box; `free-text-callout`\n * adds a `/CL` leader line pointing at the called-out region.\n */\nexport type FreeTextIntent = 'free-text' | 'free-text-callout';\n\n/** Caret `/IT` intent used by an Acrobat-compatible replace-text edit. */\nexport type CaretIntent = 'replace';\n\n/** Strikeout `/IT` intent used by the subordinate part of a replace-text edit. */\nexport type StrikeoutIntent = 'strikeout-text-edit';\n\n/** Ink `/IT` intent used by an Acrobat-compatible freehand highlighter. */\nexport type InkIntent = 'ink-highlight';\n\n/**\n * Effective blend mode of an annotation's normal appearance stream (`/AP /N`).\n * Values use CSS-compatible kebab-case so the wire vocabulary is portable; the\n * engine maps them onto PDFium's `FPDF_BLENDMODE` integer codes.\n */\nexport type BlendMode =\n | 'normal'\n | 'multiply'\n | 'screen'\n | 'overlay'\n | 'darken'\n | 'lighten'\n | 'color-dodge'\n | 'color-burn'\n | 'hard-light'\n | 'soft-light'\n | 'difference'\n | 'exclusion'\n | 'hue'\n | 'saturation'\n | 'color'\n | 'luminosity';\n\n/**\n * Border/line style for shape annotations — the `/BS /S` (border style)\n * subset PDFium can author. Maps onto the ISO 32000 §8.4.3.3 border style\n * names. Cloudy borders are a SEPARATE concern (`/BE` border effect),\n * surfaced as `cloudyIntensity` on the shape DTO, not as a border style.\n *\n * kebab-/lower-case so the wire format is stable across language ports;\n * the engine maps these onto PDFium's integer codes at write time.\n */\nexport type AnnotationBorderStyle = 'solid' | 'dashed' | 'beveled' | 'inset';\n\n/**\n * `/RD` (rectangle differences) for shape annotations — the four margins,\n * in PDF points, between the annotation `/Rect` and the geometry actually\n * drawn inside it. Used so a thick/cloudy border has room to render\n * without being clipped by the `/Rect`. y-up PDF user space, so each value\n * is a non-negative inset from the corresponding `/Rect` edge.\n */\nexport interface PdfRectDifferences {\n left: number;\n top: number;\n right: number;\n bottom: number;\n}\n\n/**\n * The `/RT` (reply type) relationship an annotation declares toward the\n * annotation its `/IRT` points at (ISO 32000 §12.5.6.2). Wire-stable\n * kebab/lower-case strings; the engine maps these onto PDFium's\n * `FPDF_ANNOT_REPLY_TYPE` integer codes at read/write time.\n *\n * 'reply' -> `/R` a comment-thread reply (the ISO default when\n * `/IRT` is present but `/RT` is absent).\n * 'group' -> `/Group` a subordinate part of one logical annotation\n * group (e.g. the Caret of a text-edit pair).\n */\nexport type AnnotationReplyType = 'reply' | 'group';\n\n/**\n * Bitset wrapper for the `/F` (Annotation Flags) PDF entry. We expose each\n * bit as its own boolean so callers don't have to know the bit positions.\n */\nexport interface AnnotationFlags {\n invisible: boolean;\n hidden: boolean;\n print: boolean;\n noZoom: boolean;\n noRotate: boolean;\n noView: boolean;\n readOnly: boolean;\n locked: boolean;\n toggleNoView: boolean;\n lockedContents: boolean;\n}\n\nexport const NO_ANNOTATION_FLAGS: AnnotationFlags = {\n invisible: false,\n hidden: false,\n print: false,\n noZoom: false,\n noRotate: false,\n noView: false,\n readOnly: false,\n locked: false,\n toggleNoView: false,\n lockedContents: false,\n};\n","/**\n * Inline binary payloads for annotation drafts/patches.\n *\n * Public rule (see also `annotation/normalize.ts`): binary data is a call\n * ARGUMENT, never engine state. Callers put bytes directly on the draft\n * field that names their role (stamp `source`, future file-attachment\n * `file`); normalization replaces each such field with a `ResourceRef`\n * and moves the bytes into a `WireResourceMap` that travels out-of-band\n * (worker: transferable buffers; cloud: multipart parts). After the call,\n * the only durable home for the bytes is the PDF itself.\n */\n\n/**\n * Richest accepted input for a binary field. `mimeType` is advisory only —\n * every engine sniffs magic bytes and the sniffed format wins (the server\n * cannot trust a declared type anyway).\n */\nexport type BinarySource = Uint8Array | Blob | BinaryPayload;\n\nexport interface BinaryPayload {\n data: Uint8Array | Blob;\n /** Advisory only — engines always sniff magic bytes. */\n mimeType?: string;\n /** Optional display/file name (multipart `filename`, future /UF). */\n name?: string;\n}\n\n/**\n * A resolved binary payload in wire form: bytes detached from any Blob and\n * ready to ship (worker transfer list or multipart part body).\n */\nexport interface WireResource {\n bytes: ArrayBuffer;\n mimeType?: string;\n name?: string;\n}\n\n/** Keyed resources accompanying one mutation. Keys are allocator-generated (`r0`, `r1`, …). */\nexport type WireResourceMap = Record<string, WireResource>;\n\n/** What replaces a `BinarySource` field in the wire form of a draft/patch. */\nexport interface ResourceRef {\n resource: string;\n}\n\nfunction isBlob(value: unknown): value is Blob {\n return typeof Blob !== 'undefined' && value instanceof Blob;\n}\n\n/**\n * Detach a Uint8Array view into a standalone ArrayBuffer without copying\n * when the view already spans its whole buffer.\n */\nfunction toStandaloneArrayBuffer(view: Uint8Array): ArrayBuffer {\n if (\n view.byteOffset === 0 &&\n view.buffer instanceof ArrayBuffer &&\n view.byteLength === view.buffer.byteLength\n ) {\n return view.buffer;\n }\n return view.slice().buffer as ArrayBuffer;\n}\n\n/**\n * Resolve any accepted `BinarySource` form into a `WireResource`.\n * Async because Blob bytes can only be read asynchronously.\n */\nexport async function resolveBinarySource(source: BinarySource): Promise<WireResource> {\n if (source instanceof Uint8Array) {\n return { bytes: toStandaloneArrayBuffer(source) };\n }\n if (isBlob(source)) {\n const blobName = blobFileName(source);\n return {\n bytes: await source.arrayBuffer(),\n mimeType: source.type || undefined,\n ...(blobName !== undefined ? { name: blobName } : {}),\n };\n }\n const { data, mimeType, name } = source;\n const inner =\n data instanceof Uint8Array\n ? {\n bytes: toStandaloneArrayBuffer(data),\n mimeType: undefined as string | undefined,\n name: undefined as string | undefined,\n }\n : {\n bytes: await data.arrayBuffer(),\n mimeType: data.type || undefined,\n name: blobFileName(data),\n };\n const resolvedName = name ?? inner.name;\n return {\n bytes: inner.bytes,\n ...((mimeType ?? inner.mimeType) ? { mimeType: mimeType ?? inner.mimeType } : {}),\n ...(resolvedName !== undefined ? { name: resolvedName } : {}),\n };\n}\n\n/** A browser `File` is a Blob with a `name` — pick it up so attachment\n * drafts can pass a `File` directly without repeating the file name. */\nfunction blobFileName(blob: Blob): string | undefined {\n const name = (blob as File).name;\n return typeof name === 'string' && name.length > 0 ? name : undefined;\n}\n","/**\n * Magic-byte format detection for inline binary payloads.\n *\n * Ported from v2 (`@embedpdf/models` image-metadata). Declared mime types\n * are never trusted — the sniffed format is canonical on every engine and\n * on the server. Raster formats include intrinsic pixel dimensions (used\n * for aspect-ratio fitting); PDF only identifies the format.\n */\n\nexport type BinaryMimeType = 'image/png' | 'image/jpeg' | 'application/pdf';\n\nexport type BinaryMetadata =\n | { mimeType: 'image/png'; width: number; height: number }\n | { mimeType: 'image/jpeg'; width: number; height: number }\n | { mimeType: 'application/pdf' };\n\n/**\n * Detect format (and intrinsic dimensions for rasters) of a binary buffer.\n *\n * @returns metadata, or `null` for unsupported/corrupt data\n */\nexport function sniffBinaryMetadata(buffer: ArrayBuffer): BinaryMetadata | null {\n if (buffer.byteLength < 4) return null;\n\n const bytes = new Uint8Array(buffer);\n\n if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) {\n return parsePng(buffer);\n }\n\n if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {\n return parseJpeg(buffer);\n }\n\n if (bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46) {\n return { mimeType: 'application/pdf' };\n }\n\n return null;\n}\n\nfunction parsePng(buffer: ArrayBuffer): BinaryMetadata | null {\n if (buffer.byteLength < 24) return null;\n const view = new DataView(buffer);\n const width = view.getUint32(16);\n const height = view.getUint32(20);\n if (width === 0 || height === 0) return null;\n return { mimeType: 'image/png', width, height };\n}\n\nfunction parseJpeg(buffer: ArrayBuffer): BinaryMetadata | null {\n const bytes = new Uint8Array(buffer);\n let offset = 2;\n\n while (offset + 4 < bytes.byteLength) {\n if (bytes[offset] !== 0xff) return null;\n\n const marker = bytes[offset + 1];\n\n // SOF0 through SOF3 (baseline, progressive, lossless)\n if (marker >= 0xc0 && marker <= 0xc3) {\n if (offset + 9 > bytes.byteLength) return null;\n const view = new DataView(buffer, offset + 5);\n const height = view.getUint16(0);\n const width = view.getUint16(2);\n if (width === 0 || height === 0) return null;\n return { mimeType: 'image/jpeg', width, height };\n }\n\n // Skip non-SOF markers\n if (marker === 0xd8 || marker === 0xd9) {\n offset += 2;\n } else if (marker === 0xff) {\n offset += 1;\n } else {\n const segLen = (bytes[offset + 2] << 8) | bytes[offset + 3];\n offset += 2 + segLen;\n }\n }\n\n return null;\n}\n","import type { FileAttachmentDraft, FileAttachmentWireDraft, WireAttachmentFile } from './draft';\nimport type { AttachmentFileSource } from '../../../dto/Attachment';\nimport { EngineError } from '../../../errors/EngineError';\nimport { EngineErrorCode } from '../../../errors/EngineErrorCode';\nimport {\n resolveBinarySource,\n type WireResource,\n type WireResourceMap,\n} from '../../../resource/BinarySource';\n\n/**\n * Resolve an attachment `file` into its wire halves: metadata into the\n * JSON body, bytes into the resource map. Unlike stamps there is NO\n * format allowlist — attaching arbitrary files is the point — so the\n * declared mime type wins (attachment formats cannot be reliably sniffed;\n * the writer falls back to `application/octet-stream` when absent).\n *\n * Shared by the file-attachment annotation draft (below) and the\n * document-level `attachments.create` mutation — one vocabulary, one\n * normalizer for both homes a file can enter a PDF through.\n */\nexport async function normalizeAttachmentFileSource(\n file: AttachmentFileSource,\n key: string,\n): Promise<{ wireFile: WireAttachmentFile; resource: WireResource }> {\n const resolved = await resolveBinarySource(file.data);\n const name = file.name ?? resolved.name;\n if (!name) {\n throw new EngineError(\n EngineErrorCode.InvalidArg,\n 'attachment file requires a name — pass { data, name } or a File whose name is set',\n );\n }\n const mimeType = file.mimeType ?? resolved.mimeType;\n return {\n wireFile: {\n resource: key,\n name,\n ...(mimeType !== undefined ? { mimeType } : {}),\n ...(file.description !== undefined ? { description: file.description } : {}),\n },\n resource: { bytes: resolved.bytes, ...(mimeType !== undefined ? { mimeType } : {}), name },\n };\n}\n\nexport async function normalizeFileAttachmentDraft(\n draft: FileAttachmentDraft,\n allocateKey: () => string,\n): Promise<{ wire: FileAttachmentWireDraft; resources: WireResourceMap }> {\n const { file, ...rest } = draft;\n const key = allocateKey();\n const { wireFile, resource } = await normalizeAttachmentFileSource(file, key);\n return { wire: { ...rest, file: wireFile }, resources: { [key]: resource } };\n}\n","import { EngineError } from '../../../errors/EngineError';\nimport { EngineErrorCode } from '../../../errors/EngineErrorCode';\nimport {\n resolveBinarySource,\n type BinarySource,\n type WireResource,\n type WireResourceMap,\n} from '../../../resource/BinarySource';\nimport { sniffBinaryMetadata } from '../../../resource/binaryMetadata';\nimport type { StampDraft, StampWireDraft } from './draft';\nimport type { StampPatch, StampWirePatch } from './patch';\n\n/**\n * Resolve + validate a stamp `source`. Sniffing happens here — before any\n * transport — so callers get a fast `InvalidArg` instead of a worker/HTTP\n * round-trip. The sniffed mime type overwrites whatever was declared.\n */\nasync function resolveStampSource(source: BinarySource): Promise<WireResource> {\n const resolved = await resolveBinarySource(source);\n const meta = sniffBinaryMetadata(resolved.bytes);\n if (!meta) {\n throw new EngineError(\n EngineErrorCode.InvalidArg,\n 'stamp source must be PNG, JPEG, or single-page PDF bytes (format is detected from the data, not the declared mime type)',\n );\n }\n return { ...resolved, mimeType: meta.mimeType };\n}\n\nexport async function normalizeStampDraft(\n draft: StampDraft,\n allocateKey: () => string,\n): Promise<{ wire: StampWireDraft; resources: WireResourceMap }> {\n const { source, ...rest } = draft;\n const resolved = await resolveStampSource(source);\n const key = allocateKey();\n return { wire: { ...rest, source: { resource: key } }, resources: { [key]: resolved } };\n}\n\nexport async function normalizeStampPatch(\n patch: StampPatch,\n allocateKey: () => string,\n): Promise<{ wire: StampWirePatch; resources: WireResourceMap }> {\n if (patch.source === undefined) {\n const { source: _source, ...rest } = patch;\n return { wire: rest, resources: {} };\n }\n const { source, ...rest } = patch;\n const resolved = await resolveStampSource(source);\n const key = allocateKey();\n return { wire: { ...rest, source: { resource: key } }, resources: { [key]: resolved } };\n}\n","import type {\n AnnotationDraft,\n AnnotationPatch,\n WireAnnotationDraft,\n WireAnnotationPatch,\n} from './kinds';\nimport type { WireResourceMap } from '../resource/BinarySource';\n// Deep imports (not the kind barrels): keeps this module — and the zod-free\n// `shared` entrypoint that re-exports it — free of the kinds' Zod schemas.\nimport { normalizeFileAttachmentDraft } from './kinds/file-attachment/normalize';\nimport { normalizeStampDraft, normalizeStampPatch } from './kinds/stamp/normalize';\n\n/**\n * The one shared splitter between authoring and wire forms — every engine\n * (local, cloud) and no one else runs this; transports never reimplement it.\n *\n * Uniform rule, zero per-kind exceptions: any `BinarySource` field on a\n * draft/patch is replaced by `{ resource: key }` and its bytes move into\n * the returned `WireResourceMap` (worker: transfer list; cloud: multipart\n * `resource:{key}` parts). Kinds without binary fields pass through\n * untouched with an empty map — their wire form IS their authoring form.\n *\n * Zod-free by design: schemas validate the returned wire form; the\n * authoring types are TypeScript-only sugar.\n */\n\nexport interface NormalizedDraft {\n wire: WireAnnotationDraft;\n resources: WireResourceMap;\n}\n\nexport interface NormalizedPatch {\n wire: WireAnnotationPatch;\n resources: WireResourceMap;\n}\n\nfunction createResourceKeyAllocator(): () => string {\n let next = 0;\n return () => `r${next++}`;\n}\n\nexport async function normalizeAnnotationDraft(draft: AnnotationDraft): Promise<NormalizedDraft> {\n switch (draft.subtype) {\n case 'stamp':\n return normalizeStampDraft(draft, createResourceKeyAllocator());\n case 'file-attachment':\n return normalizeFileAttachmentDraft(draft, createResourceKeyAllocator());\n default:\n return { wire: draft, resources: {} };\n }\n}\n\nexport async function normalizeAnnotationPatch(patch: AnnotationPatch): Promise<NormalizedPatch> {\n switch (patch.subtype) {\n case 'stamp':\n return normalizeStampPatch(patch, createResourceKeyAllocator());\n default:\n return { wire: patch, resources: {} };\n }\n}\n","/**\n * Pure, dependency-free composition of the flat annotation list into\n * reply/group threads. No PDFium, no browser, no zod — safe to import from\n * the cloud SDK, the local engine, and any UI plugin.\n *\n * The engine surfaces `/IRT` + `/RT` as flat edges on every DTO\n * ({@link AnnotationBase.inReplyTo} / {@link AnnotationBase.replyType}); it\n * deliberately does NOT nest replies/group members, because each of those\n * is itself a first-class annotation in the page list. This module turns\n * those edges into the shape a comments sidebar wants.\n *\n * See ISO 32000 §12.5.6.2:\n * - `/RT /R` -> a comment-thread reply (default when `/RT` is absent)\n * - `/RT /Group` -> a subordinate part of one logical annotation group\n */\n\nimport type { AnnotationBase } from './base';\nimport type { AnnotationDTO } from './kinds';\nimport type { AnnotationRef } from '../identity/AnnotationRef';\n\n/**\n * Where a single annotation sits in the reply/group taxonomy.\n *\n * 'top-level' no `/IRT` — a primary annotation / thread root.\n * 'reply' `/IRT` + `/RT /R` (or `/RT` absent) — a comment.\n * 'grouped-subordinate' `/IRT` + `/RT /Group` — a visual part of a group.\n */\nexport type AnnotationRelationKind = 'top-level' | 'reply' | 'grouped-subordinate';\n\n/**\n * Classify one annotation by its relationship edge alone. Mirrors the\n * spec's \"practical parser rule\": no `/IRT` is top-level; `/RT /Group` is\n * a grouped subordinate; anything else with an `/IRT` is a reply (the\n * engine has already normalized a missing `/RT` to `'reply'`).\n */\nexport function classifyRelation(\n a: Pick<AnnotationBase, 'inReplyTo' | 'replyType'>,\n): AnnotationRelationKind {\n if (!a.inReplyTo) return 'top-level';\n return a.replyType === 'group' ? 'grouped-subordinate' : 'reply';\n}\n\n/**\n * One composed thread: a primary annotation plus the annotations that\n * point at it.\n *\n * - `groupedParts` (`/RT /Group`) are visual/helper parts of one logical\n * annotation — a sidebar should fold them into the primary, NOT list\n * them as separate comments. Group-level fields (Contents, T, Subj, …)\n * come from the primary; the subordinate's copies are ignored.\n * - `replies` (`/RT /R`) are real comment-thread entries shown threaded\n * under the primary.\n *\n * A primary may legitimately have BOTH (e.g. a StrikeOut with a Caret\n * group part and a Text reply).\n */\nexport interface AnnotationThread<T extends AnnotationDTO = AnnotationDTO> {\n primary: T;\n /** `/RT /Group` children — merge into the primary, don't list separately. */\n groupedParts: T[];\n /** `/RT /R` (or default) children — show as threaded comments. */\n replies: T[];\n}\n\n/**\n * Stable string key for an {@link AnnotationRef}, used to match a child's\n * `inReplyTo` against a candidate parent's `ref`. Both sides are produced\n * by the engine with the same identity precedence (objectNumber, then nm,\n * then index), so equal keys mean \"same annotation\".\n */\nexport function refKey(ref: AnnotationRef): string {\n switch (ref.kind) {\n case 'objectNumber':\n return `obj:${ref.pageObjectNumber}:${ref.annotObjectNumber}`;\n case 'nm':\n return `nm:${ref.pageObjectNumber}:${ref.nm}`;\n case 'index':\n return `idx:${ref.pageObjectNumber}:${ref.index}`;\n }\n}\n\n/**\n * Compose a flat annotation list (one page, or a whole document via\n * `listRawAll()` flattened) into {@link AnnotationThread}s in primary\n * order.\n *\n * Rules (ISO 32000 §12.5.6.2 + the spec's UI rule):\n * - Annotations with no `/IRT` become thread primaries, in input order.\n * - A `/RT /Group` child is attached to its primary's `groupedParts`.\n * - A `/RT /R` (or default) child is attached to its primary's `replies`.\n * - A child whose parent is not in the input set is treated as an\n * orphan primary (defensive — e.g. a partial/filtered page slice).\n *\n * Limitations (v1, matches the legacy stack): threading is one level deep\n * — a reply-to-a-reply is keyed to its direct parent, so it only appears\n * nested if that direct parent is itself a primary. Callers that want a\n * sidebar of \"most annotations, not widgets/popups\" should pre-filter the\n * input; this helper is intentionally unopinionated about eligibility.\n */\nexport function buildThreads(annotations: readonly AnnotationDTO[]): AnnotationThread[] {\n const byKey = new Map<string, AnnotationDTO>();\n for (const a of annotations) {\n byKey.set(refKey(a.ref), a);\n // Index under /NM too, so a child that points at the parent by name\n // still resolves when the parent's own ref is objectNumber-form.\n if (a.nm && a.nm.length > 0) {\n byKey.set(`nm:${a.ref.pageObjectNumber}:${a.nm}`, a);\n }\n }\n\n const threads: AnnotationThread[] = [];\n const threadByPrimaryKey = new Map<string, AnnotationThread>();\n\n const primaryThread = (primary: AnnotationDTO): AnnotationThread => {\n const key = refKey(primary.ref);\n let thread = threadByPrimaryKey.get(key);\n if (!thread) {\n thread = { primary, groupedParts: [], replies: [] };\n threadByPrimaryKey.set(key, thread);\n threads.push(thread);\n }\n return thread;\n };\n\n // Pass 1: every top-level annotation seeds a thread, preserving order.\n for (const a of annotations) {\n if (!a.inReplyTo) primaryThread(a);\n }\n\n // Pass 2: attach children to their primary; orphans become primaries.\n for (const a of annotations) {\n if (!a.inReplyTo) continue;\n const parent = byKey.get(refKey(a.inReplyTo));\n if (!parent || parent.inReplyTo) {\n // Parent missing from the set, or itself a child (one-level-deep\n // limitation): surface the annotation as its own primary so it is\n // never silently dropped.\n primaryThread(a);\n continue;\n }\n const thread = primaryThread(parent);\n if (a.replyType === 'group') thread.groupedParts.push(a);\n else thread.replies.push(a);\n }\n\n return threads;\n}\n","import type { WeakAnnotationState } from '../revision/WeakAnnotationState';\n\nexport type AnnotationMutationKind = 'create' | 'update' | 'delete' | 'move';\n\nexport function changesAnnotationList(_kind: AnnotationMutationKind): boolean {\n return true;\n}\n\nexport function shiftsExistingAnnotationIndices(kind: AnnotationMutationKind): boolean {\n return kind === 'delete' || kind === 'move';\n}\n\nexport function invalidatesWeakIndexRefs(\n kind: AnnotationMutationKind,\n weakStateBefore: WeakAnnotationState,\n): boolean {\n if (!shiftsExistingAnnotationIndices(kind)) {\n return false;\n }\n if (weakStateBefore.kind !== 'known') {\n throw new Error(\n `invalidatesWeakIndexRefs requires a known WeakAnnotationState for ${kind}; got 'unknown'. ` +\n 'Caller must scan the page before computing mutation impact.',\n );\n }\n return weakStateBefore.hasAnyWeakAnnotations;\n}\n","import type { PdfRect } from '../geometry/primitives';\nimport type { AnnotationDTO, WireAnnotationPatch } from './kinds';\n\n/**\n * Appearance-impact classification: the shared, pure decision for whether an\n * update patch requires re-baking the `/AP` normal appearance stream.\n *\n * An `/AP` stream is CONTENT, not cache — a foreign producer's appearance\n * (Acrobat's rich `/AP`, an image-backed stamp) generally cannot be\n * recomputed, so destroying it is only acceptable as the explicit consequence\n * of a semantic edit. Per ISO 32000 §12.5.5 a form XObject's `BBox` is\n * algorithmically fitted into `/Rect`, so a same-size `/Rect` change\n * translates the painted pixels verbatim: preservation on a verified rigid\n * translation is a theorem, not a policy. The engine therefore never trusts a\n * caller's claim of \"this is just a move\" — it checks the geometric fact that\n * licenses preservation.\n *\n * The classifier compares in DTO space on both sides (the patch vocabulary IS\n * the DTO vocabulary, produced by the same readers), so value-diffing drops\n * no-op keys even from clients that send full-object patches. Unknown keys\n * and unknown subtypes classify as `regenerate` — conservative by default.\n */\nexport type AppearanceImpact =\n /** Nothing appearance-affecting changed value — never touch `/AP`. */\n | 'inert'\n /** A verified rigid translation — pixels identical up to translation. */\n | 'translation'\n /** A semantic appearance edit — the owner re-bakes `/AP`. */\n | 'regenerate';\n\n/** What actually happened to `/AP` during an update (the engine's echo). */\nexport type AppearanceAction = 'preserved' | 'regenerated' | 'generation-unavailable';\n\n/**\n * The appearance verdict every `AnnotationUpdateResult` carries. `changed`\n * (not `action`) is the raster-invalidation signal: `true` iff the document's\n * appearance definition changed — a regenerated `/AP`, or appearance-affecting\n * dictionary writes on a subtype the generic generator cannot re-bake.\n */\nexport interface AppearanceOutcome {\n action: AppearanceAction;\n changed: boolean;\n}\n\n/**\n * Coordinate tolerance in PDF user-space points. PDF numbers round-trip\n * through f32 (~7 significant digits) and client-side space conversions, so\n * exact float equality would misclassify no-op writes; 1e-3 pt is far below\n * anything visible while far above accumulated f32 drift at page magnitudes.\n */\nconst EPSILON = 1e-3;\n\n/**\n * Keys that never affect `/AP` on any kind: the discriminator, behavioral\n * flags, reply relationships, and grouping.\n */\nconst INERT_KEYS: ReadonlySet<string> = new Set([\n 'subtype',\n 'flags',\n 'inReplyTo',\n 'replyType',\n 'groupId',\n]);\n\n/**\n * Kinds whose `/AP` paints `/Contents`. Everywhere else `contents` is popup\n * note text — editing a comment must never re-bake (or destroy) the shape's\n * appearance.\n */\nconst CONTENTS_PAINTED: ReadonlySet<string> = new Set(['free-text', 'redact']);\n\n/**\n * The vertex family's `/EMBD_Metadata/Rotation` is an advisory scalar (the\n * vertices are already rotated); it never drives the AP generator, so patches\n * touching it are appearance-inert for these kinds.\n */\nconst ADVISORY_ROTATION: ReadonlySet<string> = new Set(['line', 'polyline', 'polygon', 'ink']);\n\n/**\n * The box kinds carry the `/EMBD_Metadata` transform pair (`rotation` +\n * `unrotatedRect`), tri-state on writes: omitted fields are PRESERVED, `null`\n * (or `0` for rotation) clears. Translation verification therefore compares\n * the after-state — `patch.rotation ?? current.rotation` — not the patch keys.\n */\nconst BOX_TRANSFORM: ReadonlySet<string> = new Set(['square', 'circle', 'free-text', 'stamp']);\n\n/**\n * Per-kind absolute-geometry fields (PDF user space) that a rigid translation\n * shifts together. A kind absent from this table never takes the translation\n * route. `rect` is required in every entry: a translation always moves `/Rect`.\n */\nconst TRANSLATABLE_GEOMETRY: Record<string, readonly string[]> = {\n square: ['rect', 'unrotatedRect'],\n circle: ['rect', 'unrotatedRect'],\n 'free-text': ['rect', 'unrotatedRect', 'calloutLine'],\n line: ['rect', 'linePoints'],\n polygon: ['rect', 'vertices'],\n polyline: ['rect', 'vertices'],\n ink: ['rect', 'inkList'],\n highlight: ['rect', 'quadPoints'],\n underline: ['rect', 'quadPoints'],\n squiggly: ['rect', 'quadPoints'],\n strikeout: ['rect', 'quadPoints'],\n redact: ['rect', 'quadPoints'],\n caret: ['rect'],\n text: ['rect'],\n stamp: ['rect', 'unrotatedRect'],\n 'file-attachment': ['rect'],\n link: ['rect'],\n};\n\nconst numEq = (a: number, b: number): boolean => Math.abs(a - b) <= EPSILON;\n\n/** Degrees normalized to [0,360); absent reads as 0 (no rotation). */\nconst normDeg = (v: unknown): number => {\n const n = typeof v === 'number' ? ((v % 360) + 360) % 360 : 0;\n return n;\n};\n\n/**\n * Semantic equality between a patch value and the current DTO value.\n * Numbers compare within {@link EPSILON}; `null` and `undefined` both mean\n * \"entry absent\" (the tri-state clear of an absent entry is a no-op); arrays\n * and objects compare structurally.\n */\nexport function semanticEqual(a: unknown, b: unknown): boolean {\n if (a == null || b == null) return a == null && b == null;\n if (typeof a === 'number' && typeof b === 'number') return numEq(a, b);\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n return a.every((v, i) => semanticEqual(v, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const keys = new Set([...Object.keys(a), ...Object.keys(b as object)]);\n for (const k of keys) {\n if (!semanticEqual((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k])) {\n return false;\n }\n }\n return true;\n }\n return a === b;\n}\n\n/**\n * Is `next` exactly `cur` shifted by `(dx, dy)`? Walks the value structurally:\n * numeric leaves under x-axis keys (`left`/`right`/`x`) must shift by `dx`,\n * y-axis keys (`bottom`/`top`/`y`) by `dy`, and any other numeric leaf must be\n * unchanged. Arrays walk elementwise (same length required).\n */\nfunction shiftedBy(cur: unknown, next: unknown, dx: number, dy: number): boolean {\n if (cur == null || next == null) return cur == null && next == null;\n if (Array.isArray(cur) || Array.isArray(next)) {\n if (!Array.isArray(cur) || !Array.isArray(next) || cur.length !== next.length) return false;\n return cur.every((v, i) => shiftedBy(v, next[i], dx, dy));\n }\n if (typeof cur === 'object' && typeof next === 'object') {\n const keys = new Set([...Object.keys(cur), ...Object.keys(next as object)]);\n for (const k of keys) {\n const c = (cur as Record<string, unknown>)[k];\n const n = (next as Record<string, unknown>)[k];\n if (typeof c === 'number' && typeof n === 'number') {\n const delta =\n k === 'left' || k === 'right' || k === 'x'\n ? dx\n : k === 'bottom' || k === 'top' || k === 'y'\n ? dy\n : 0;\n if (!numEq(c + delta, n)) return false;\n } else if (!shiftedBy(c, n, dx, dy)) {\n return false;\n }\n }\n return true;\n }\n return cur === next;\n}\n\n/**\n * Verify the touched geometry is one rigid translation of the current state.\n * Requires `patch.rect` (a translation always moves `/Rect`) with width and\n * height preserved; every other geometry field present on the annotation must\n * ride along shifted by the same delta — a rect move that leaves `vertices`\n * behind is NOT a translation (the dictionary would desync from the pixels).\n * For box kinds the `/EMBD_Metadata` transform group is checked as an\n * after-state: writes are tri-state (omitted preserves, null/0 clears), so an\n * omitted rotation keeps the current one — but a preserved-yet-unshifted\n * `unrotatedRect` still fails the congruence check via the field loop.\n */\nfunction isRigidTranslation(\n cur: Record<string, unknown>,\n pat: Record<string, unknown>,\n subtype: string,\n geometryKeys: readonly string[],\n): boolean {\n const curRect = cur.rect as PdfRect | undefined;\n const patRect = pat.rect as PdfRect | undefined;\n if (!curRect || !patRect) return false;\n const dx = patRect.left - curRect.left;\n const dy = patRect.bottom - curRect.bottom;\n if (!numEq(patRect.right - patRect.left, curRect.right - curRect.left)) return false;\n if (!numEq(patRect.top - patRect.bottom, curRect.top - curRect.bottom)) return false;\n\n if (BOX_TRANSFORM.has(subtype)) {\n // Tri-state writes: an omitted rotation PRESERVES the current one; `null`\n // clears (≡ 0). Compare the resulting after-state.\n const rotAfter = pat.rotation === undefined ? cur.rotation : pat.rotation;\n if (!numEq(normDeg(cur.rotation), normDeg(rotAfter))) return false;\n }\n\n for (const key of geometryKeys) {\n if (key === 'rect') continue;\n const c = cur[key];\n const p = pat[key];\n if (c == null && p == null) continue; // absent on both — nothing to shift\n if (c == null || p == null) return false; // geometry appearing/vanishing\n if (!shiftedBy(c, p, dx, dy)) return false;\n }\n return true;\n}\n\n/**\n * Classify an update patch against the annotation's current DTO.\n *\n * 1. Value-diff: drop keys whose value semantically equals the current one,\n * plus the always-inert metadata keys (and per-kind inert keys: `contents`\n * where it isn't painted, advisory `rotation` on the vertex family).\n * Nothing left → `'inert'`.\n * 2. If every remaining key is translatable geometry for this kind AND the\n * values are one rigid translation → `'translation'`.\n * 3. Anything else — style, text, unknown keys, unknown kinds → `'regenerate'`.\n */\nexport function appearanceImpactOf(\n current: AnnotationDTO,\n patch: WireAnnotationPatch,\n): AppearanceImpact {\n if (patch.subtype !== current.subtype) return 'regenerate';\n\n const cur = current as unknown as Record<string, unknown>;\n const pat = patch as unknown as Record<string, unknown>;\n const subtype = patch.subtype;\n\n const touched: string[] = [];\n for (const [key, value] of Object.entries(pat)) {\n if (value === undefined || INERT_KEYS.has(key)) continue;\n if (key === 'contents' && !CONTENTS_PAINTED.has(subtype)) continue;\n if (key === 'rotation' && ADVISORY_ROTATION.has(subtype)) continue;\n if (!semanticEqual(value, cur[key])) touched.push(key);\n }\n if (touched.length === 0) return 'inert';\n\n const geometryKeys = TRANSLATABLE_GEOMETRY[subtype];\n if (!geometryKeys) return 'regenerate';\n if (!touched.every((k) => geometryKeys.includes(k))) return 'regenerate';\n return isRigidTranslation(cur, pat, subtype, geometryKeys) ? 'translation' : 'regenerate';\n}\n","import type { PageObjectNumber } from './PageObjectNumber';\n\n/**\n * How callers address a logical form field.\n *\n * - `objectNumber` — the indirect object number of the field dictionary.\n * ISO 32000 guarantees every real AcroForm field dictionary is an\n * indirect object, and the layer runtime never renumbers (frozen base +\n * incremental deltas), so this is the durable identity for the lifetime\n * of a document. Preferred for all engine calls.\n * - `fqn` — the fully qualified field name (\"billing.name\"). The portable,\n * semantic identity used by interchange formats (FDF/XFDF) and analytics;\n * survives document rewrites but is only as unique as the producer made\n * it. The engine resolves it against the reconciled field tree.\n */\nexport type FormFieldRef =\n | { kind: 'objectNumber'; fieldObjectNumber: number }\n | { kind: 'fqn'; name: string };\n\n/**\n * URL-safe encoding of a `FormFieldRef`, used by the cloud HTTP surface as\n * the `:fieldKey` route parameter. Decoded by the server back into a\n * `FormFieldRef` via `decodeFieldRefKey`. Mirrors the annotation plane's\n * `encodeStableIdKey` (`obj:42` / `nm:…`) so the two member-key syntaxes\n * read the same on the wire:\n *\n * `{ kind: 'objectNumber', fieldObjectNumber: 12 }` -> `'obj:12'`\n * `{ kind: 'fqn', name: 'billing.name' }` -> `'fqn:billing.name'`\n *\n * The caller is responsible for `encodeURIComponent`-ing the result before\n * splicing it into a URL path; the `wirePaths.layerFormField*` builders\n * already do that. FQNs are opaque strings and may contain anything; the\n * `fqn:` prefix keeps them unambiguous from numeric ids.\n */\nexport function encodeFieldRefKey(ref: FormFieldRef): string {\n if (ref.kind === 'objectNumber') {\n if (!Number.isInteger(ref.fieldObjectNumber) || ref.fieldObjectNumber <= 0) {\n throw new RangeError(\n `encodeFieldRefKey: fieldObjectNumber must be a positive integer, got ${ref.fieldObjectNumber}`,\n );\n }\n return `obj:${ref.fieldObjectNumber}`;\n }\n return `fqn:${ref.name}`;\n}\n\n/**\n * Inverse of `encodeFieldRefKey`. Returns `null` for malformed input so the\n * server can answer 400 InvalidArg with a useful message instead of\n * throwing. The input is the already-`decodeURIComponent`-ed segment from\n * the route path. Empty FQNs are rejected: `fqn:` with no suffix is not a\n * valid identity.\n */\nexport function decodeFieldRefKey(key: string): FormFieldRef | null {\n if (key.startsWith('obj:')) {\n const rest = key.slice('obj:'.length);\n const n = Number.parseInt(rest, 10);\n if (!Number.isInteger(n) || n <= 0 || String(n) !== rest) return null;\n return { kind: 'objectNumber', fieldObjectNumber: n };\n }\n if (key.startsWith('fqn:')) {\n const name = key.slice('fqn:'.length);\n if (name.length === 0) return null;\n return { kind: 'fqn', name };\n }\n return null;\n}\n\n/** A widget annotation of a field, as the forms subsystem sees it. */\nexport interface FormWidgetRef {\n /**\n * Indirect object number of the widget annotation — the join key to the\n * annotation subsystem's `objectNumber` refs. `0` when the widget is\n * stored as a direct object (spec-violating; cannot be addressed).\n */\n annotObjectNumber: number;\n /**\n * Object number of the page whose /Annots array references the widget.\n * `0` when the widget is not reachable from any page (\"unplaced\").\n */\n pageObjectNumber: PageObjectNumber;\n}\n","import { foldText, toOriginalRange } from './fold';\nimport type { FoldedText, FoldOptions, SearchMatchRange } from './fold';\nimport type { SearchQuery } from './types';\n\n/**\n * The fold flavor a literal query needs. Haystack and needle MUST be\n * folded with the same options; corpus caches key their pre-folded text\n * on this (the default `{}` fold is the persistable one — non-default\n * queries fold the original page text at query time).\n */\nexport function foldOptionsFor(query: SearchQuery): FoldOptions {\n return { keepCase: !!query.matchCase, keepMarks: !!query.matchDiacritics };\n}\n\n// ONE definition of \"word character\" for the whole search subsystem —\n// Unicode letters/digits, not JS \\b's ASCII set — shared by the literal\n// boundary check and the regex wholeWord post-filter, so the wholeWord\n// toggle means the same thing in both modes (\"caf\" never whole-word\n// matches inside \"café\", regex or not).\nconst WORD_UNIT = /[\\p{L}\\p{N}_]/u;\nconst MARK = /\\p{M}/u;\n\n/** Whether the code point ENDING at `index` (exclusive) is a word char. */\nexport function wordBefore(text: string, index: number): boolean {\n if (index <= 0) return false;\n // Step back over a low surrogate to test the full code point.\n const unit = text.charCodeAt(index - 1);\n const start = unit >= 0xdc00 && unit <= 0xdfff && index >= 2 ? index - 2 : index - 1;\n return WORD_UNIT.test(String.fromCodePoint(text.codePointAt(start)!));\n}\n\n/** Whether the code point starting at `index` is a word char. */\nexport function wordAt(text: string, index: number): boolean {\n if (index >= text.length) return false;\n return WORD_UNIT.test(String.fromCodePoint(text.codePointAt(index)!));\n}\n\n/**\n * All non-overlapping literal matches, in original code-unit space.\n * `haystack` must have been folded with `foldOptionsFor(query)`.\n */\nexport function matchLiteral(haystack: FoldedText, query: SearchQuery): SearchMatchRange[] {\n const needle = foldText(query.text, foldOptionsFor(query)).folded;\n // Nothing searchable: empty or whitespace-only needles would \"match\"\n // every collapsed space.\n if (needle.trim().length === 0) return [];\n\n const out: SearchMatchRange[] = [];\n let from = 0;\n while (from <= haystack.folded.length - needle.length) {\n const at = haystack.folded.indexOf(needle, from);\n if (at < 0) break;\n if (\n query.wholeWord &&\n (wordBefore(haystack.folded, at) || wordAt(haystack.folded, at + needle.length))\n ) {\n from = at + 1;\n continue;\n }\n // Diacritic-sensitive folds are decomposed (base + marks), so a bare\n // needle would otherwise match just the base letters of an accented\n // char — \"cafe\" ending right before the U+0301 of \"café\". A match may\n // not end mid-character.\n if (query.matchDiacritics && at + needle.length < haystack.folded.length) {\n const after = haystack.folded.codePointAt(at + needle.length)!;\n if (MARK.test(String.fromCodePoint(after))) {\n from = at + 1;\n continue;\n }\n }\n out.push(toOriginalRange(haystack, at, needle.length));\n from = at + needle.length;\n }\n return out;\n}\n","import type { SearchMatchRange } from './fold';\nimport { wordAt, wordBefore } from './literal';\nimport type { SearchQuery } from './types';\n\n/**\n * The portable search-regex dialect: JavaScript `u`-mode syntax MINUS the\n * features RE2 refuses (backreferences, lookaround). The local engine\n * executes patterns with JS `RegExp`; the server executes the SAME\n * pattern with RE2, whose linear-time guarantee is the ReDoS defense.\n * Restricting both sides to the common subset keeps one query string\n * valid — and equally powerful — everywhere.\n */\nexport const SEARCH_REGEX_MAX_LENGTH = 512;\n\nexport type SearchRegexIssue = 'empty' | 'too-long' | 'backreference' | 'lookaround' | 'syntax';\n\nexport type SearchRegexValidation =\n | { ok: true }\n | { ok: false; issue: SearchRegexIssue; message: string };\n\n/**\n * Validate a pattern against the dialect. Cheap and dependency-free —\n * viewers call it on keystroke for early feedback; engines re-validate\n * and reject bad patterns with `InvalidArg`.\n */\nexport function validateSearchRegex(pattern: string): SearchRegexValidation {\n if (pattern.length === 0) {\n return { ok: false, issue: 'empty', message: 'Pattern is empty.' };\n }\n if (pattern.length > SEARCH_REGEX_MAX_LENGTH) {\n return {\n ok: false,\n issue: 'too-long',\n message: `Pattern exceeds ${SEARCH_REGEX_MAX_LENGTH} characters.`,\n };\n }\n\n // One pass tracking escape/char-class state: backreferences and\n // lookaround only mean what they mean outside a character class.\n let inClass = false;\n for (let i = 0; i < pattern.length; i++) {\n const ch = pattern[i];\n if (ch === '\\\\') {\n const next = pattern[i + 1] ?? '';\n if (!inClass && next >= '1' && next <= '9') {\n return {\n ok: false,\n issue: 'backreference',\n message: `Backreference \\\\${next} is not supported.`,\n };\n }\n if (!inClass && next === 'k' && pattern[i + 2] === '<') {\n return {\n ok: false,\n issue: 'backreference',\n message: 'Named backreferences (\\\\k<…>) are not supported.',\n };\n }\n i++; // consume the escaped char\n continue;\n }\n if (inClass) {\n if (ch === ']') inClass = false;\n continue;\n }\n if (ch === '[') {\n inClass = true;\n continue;\n }\n if (ch === '(' && pattern[i + 1] === '?') {\n const tag = pattern[i + 2] ?? '';\n if (tag === '=' || tag === '!') {\n return {\n ok: false,\n issue: 'lookaround',\n message: 'Lookahead ((?=…), (?!…)) is not supported.',\n };\n }\n // \"(?<\" is lookbehind when followed by = or !, a named GROUP otherwise.\n if (tag === '<' && (pattern[i + 3] === '=' || pattern[i + 3] === '!')) {\n return {\n ok: false,\n issue: 'lookaround',\n message: 'Lookbehind ((?<=…), (?<!…)) is not supported.',\n };\n }\n }\n }\n\n try {\n // `u` is the strict common ground with RE2's syntax; `m` because ^/$\n // meaning line boundaries is what page-text search wants.\n new RegExp(pattern, 'mu');\n } catch (error) {\n return { ok: false, issue: 'syntax', message: (error as Error).message };\n }\n return { ok: true };\n}\n\n/**\n * Every flag combination has DEFINED semantics — most by behavior, one by\n * loud rejection (see the {@link SearchQuery} table). The single validator\n * a UI needs: call it on keystroke to grey out the diacritics toggle in\n * regex mode and flag bad patterns early; engines run the same check and\n * reject with `InvalidArg`. Literal queries are always valid (an empty\n * literal simply finds nothing).\n */\nexport type SearchQueryIssue = SearchRegexIssue | 'diacritics-with-regex';\n\nexport type SearchQueryValidation =\n | { ok: true }\n | { ok: false; issue: SearchQueryIssue; message: string };\n\nexport function validateSearchQuery(query: SearchQuery): SearchQueryValidation {\n if (!query.regex) return { ok: true };\n if (query.matchDiacritics) {\n return {\n ok: false,\n issue: 'diacritics-with-regex',\n message:\n 'Diacritic-sensitive matching is not available for regex patterns (regex runs on the raw text plane).',\n };\n }\n return validateSearchRegex(query.text);\n}\n\n/**\n * All matches of a dialect-valid pattern over the RAW page text (regex\n * does not run against folded text — case handling is the `i` flag, and\n * diacritic folding never applies). `wholeWord` is a boundary POST-FILTER\n * using the same Unicode word test as the literal path — never `\\b`,\n * whose ASCII word set would give the toggle different semantics in regex\n * mode (\"caf\" whole-word matching inside \"café\"). Filtering after the\n * match also survives the move to RE2 server-side. Zero-length matches\n * are skipped: search UI cannot highlight nothing, and skipping them is\n * also the infinite-loop guard for patterns like `a*`.\n */\nexport function matchRegex(text: string, query: SearchQuery): SearchMatchRange[] {\n const valid = validateSearchQuery({ ...query, regex: true });\n if (!valid.ok) throw new Error(`Invalid search query (${valid.issue}): ${valid.message}`);\n\n const re = new RegExp(query.text, query.matchCase ? 'gmu' : 'gimu');\n const out: SearchMatchRange[] = [];\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n if (m[0].length === 0) {\n // Advance one full code point past the empty match.\n const unit = text.charCodeAt(re.lastIndex);\n re.lastIndex += unit >= 0xd800 && unit <= 0xdbff ? 2 : 1;\n continue;\n }\n if (query.wholeWord && (wordBefore(text, m.index) || wordAt(text, m.index + m[0].length))) {\n continue;\n }\n out.push({ start: m.index, length: m[0].length });\n }\n return out;\n}\n","import { foldText } from './fold';\nimport type { SearchMatchRange } from './fold';\nimport { foldOptionsFor, matchLiteral } from './literal';\nimport { matchRegex } from './regex';\nimport type { SearchQuery } from './types';\n\n/**\n * The whole match stage in one pure call: page text in, original-space\n * match ranges out. Engines with a pre-folded corpus for the default fold\n * skip this and call `matchLiteral` on the cached `FoldedText` directly;\n * everything else (non-default fold options, regex, tests) comes through\n * here.\n */\nexport function matchPageText(text: string, query: SearchQuery): SearchMatchRange[] {\n if (query.regex) return matchRegex(text, query);\n return matchLiteral(foldText(text, foldOptionsFor(query)), query);\n}\n","import type { SearchMatchRange } from './fold';\nimport type { SearchSnippet } from './types';\n\n/** Default context on each side of a match, in code units. */\nexport const SEARCH_SNIPPET_CONTEXT = 48;\n\nconst WHITESPACE = /\\s/;\n// Length-preserving: every whitespace unit becomes one plain space, so\n// `matchStart`/`matchLength` stay valid offsets into the flattened text.\nconst WHITESPACE_ALL = /\\s/g;\n\nconst isLowSurrogate = (text: string, index: number): boolean => {\n const unit = text.charCodeAt(index);\n return unit >= 0xdc00 && unit <= 0xdfff;\n};\n\n/**\n * The `'full'`-mode excerpt around one match: up to `context` code units\n * of page text on each side, trimmed to a whitespace boundary when one\n * exists inside the window (so snippets start and end on whole words),\n * never splitting a surrogate pair, whitespace flattened 1:1.\n */\nexport function buildSnippet(\n text: string,\n range: SearchMatchRange,\n context: number = SEARCH_SNIPPET_CONTEXT,\n): SearchSnippet {\n const matchEnd = range.start + range.length;\n\n let start = Math.max(0, range.start - context);\n if (start > 0) {\n // Cut at the first whitespace inside the leading context, if any —\n // otherwise accept the mid-word cut (one very long token).\n for (let i = start; i < range.start; i++) {\n if (WHITESPACE.test(text[i])) {\n start = i + 1;\n break;\n }\n }\n if (isLowSurrogate(text, start)) start++;\n }\n\n let end = Math.min(text.length, matchEnd + context);\n if (end < text.length) {\n for (let i = end - 1; i >= matchEnd; i--) {\n if (WHITESPACE.test(text[i])) {\n end = i;\n break;\n }\n }\n if (isLowSurrogate(text, end)) end--;\n }\n\n return {\n text: text.slice(start, end).replace(WHITESPACE_ALL, ' '),\n matchStart: range.start - start,\n matchLength: range.length,\n };\n}\n","import type { PageGeometrySnapshot } from '../dto/PageGeometrySnapshot';\nimport type { PdfRect } from '../geometry/primitives';\n\n/**\n * Match-range → merged line rects, in PDF user space (y-up).\n *\n * This is the same line-merge text selection uses (adapted from Chromium's\n * pdf/pdfium/pdfium_range.cc `MergeAdjacentRects`, BSD-licensed, Copyright\n * 2010 The Chromium Authors), operating directly on the engine's\n * `PageGeometrySnapshot`: glyph loose boxes → sub-runs (split on big\n * intra-run gaps) → one rect per visual line. Search highlights therefore\n * look exactly like selections — never a rect per glyph (the v2 bug).\n *\n * It lives in engine-core because BOTH sides need it: the server computes\n * rects here for `'rects'`-mode responses (geometry never leaves the trust\n * boundary), and the local engine computes them in the worker.\n */\n\nconst FLAG_EMPTY = 2;\n\nconst CHAR_DISTANCE_FACTOR = 2.5;\nconst FONT_SIZE_RATIO_THRESHOLD = 1.5;\nconst VERTICAL_OVERLAP_THRESHOLD = 0.8;\n\ninterface SubRun {\n rect: PdfRect;\n charCount: number;\n fontSize?: number;\n}\n\n/**\n * Merged line rects for the text-page char range\n * `[charStart, charStart + charCount)`. Ranges index the same space as\n * `PageGeometryRun.charStart`; chars outside the snapshot are ignored.\n */\nexport function searchRectsForRange(\n snapshot: PageGeometrySnapshot,\n charStart: number,\n charCount: number,\n): PdfRect[] {\n if (charCount <= 0) return [];\n const lo = charStart;\n const hi = charStart + charCount - 1;\n const subRuns: SubRun[] = [];\n\n for (const run of snapshot.runs) {\n const runEnd = run.charStart + run.glyphs.length - 1;\n if (runEnd < lo || run.charStart > hi) continue;\n const s = Math.max(lo, run.charStart);\n const e = Math.min(hi, runEnd);\n\n let left = Infinity;\n let right = -Infinity;\n let bottom = Infinity;\n let top = -Infinity;\n let count = 0;\n let widthSum = 0;\n let prevRight = -Infinity;\n const flush = () => {\n if (count > 0 && right > left && top > bottom) {\n subRuns.push({\n rect: { left, bottom, right, top },\n charCount: count,\n fontSize: run.fontSize,\n });\n }\n left = Infinity;\n right = -Infinity;\n bottom = Infinity;\n top = -Infinity;\n count = 0;\n widthSum = 0;\n prevRight = -Infinity;\n };\n\n for (let ci = s; ci <= e; ci++) {\n const g = run.glyphs[ci - run.charStart];\n if ((g.flags & FLAG_EMPTY) !== 0) continue;\n const b = g.looseBox;\n if (count > 0 && prevRight > -Infinity) {\n const avg = widthSum / count;\n if (avg > 0 && Math.abs(b.left - prevRight) > CHAR_DISTANCE_FACTOR * avg) flush();\n }\n left = Math.min(left, b.left);\n right = Math.max(right, b.right);\n bottom = Math.min(bottom, b.bottom);\n top = Math.max(top, b.top);\n count++;\n widthSum += b.right - b.left;\n prevRight = b.right;\n }\n flush();\n }\n\n return mergeAdjacentRects(subRuns);\n}\n\nfunction mergeAdjacentRects(runs: SubRun[]): PdfRect[] {\n const out: PdfRect[] = [];\n let prev: SubRun | null = null;\n let cur: PdfRect | null = null;\n for (const run of runs) {\n if (prev && cur && shouldMerge(prev, run)) {\n cur = union(cur, run.rect);\n } else {\n if (cur) out.push(cur);\n cur = run.rect;\n }\n prev = run;\n }\n if (cur) out.push(cur);\n return out;\n}\n\nfunction shouldMerge(a: SubRun, b: SubRun): boolean {\n if (a.fontSize != null && b.fontSize != null && a.fontSize > 0 && b.fontSize > 0) {\n const ratio = Math.max(a.fontSize, b.fontSize) / Math.min(a.fontSize, b.fontSize);\n if (ratio > FONT_SIZE_RATIO_THRESHOLD) return false;\n }\n if (verticalOverlap(a.rect, b.rect) < VERTICAL_OVERLAP_THRESHOLD) return false;\n const aw = (a.rect.right - a.rect.left) / a.charCount;\n const bw = (b.rect.right - b.rect.left) / b.charCount;\n const aL = a.rect.left - aw;\n const aR = a.rect.right + aw;\n const bL = b.rect.left - bw;\n const bR = b.rect.right + bw;\n return aL < bR && aR > bL;\n}\n\nfunction union(a: PdfRect, b: PdfRect): PdfRect {\n return {\n left: Math.min(a.left, b.left),\n bottom: Math.min(a.bottom, b.bottom),\n right: Math.max(a.right, b.right),\n top: Math.max(a.top, b.top),\n };\n}\n\nfunction verticalOverlap(a: PdfRect, b: PdfRect): number {\n const ah = a.top - a.bottom;\n const bh = b.top - b.bottom;\n if (ah <= 0 || bh <= 0) return 0;\n const u = Math.max(a.top, b.top) - Math.min(a.bottom, b.bottom);\n if (u === ah || u === bh) return 1;\n const i = Math.max(0, Math.min(a.top, b.top) - Math.max(a.bottom, b.bottom));\n return i / u;\n}\n","import type { DocumentManifest } from '../dto/DocumentManifest';\nimport { foldText } from './fold';\nimport type { SearchQuery } from './types';\n\n/**\n * The search CONTENT EPOCH: a deterministic fingerprint of everything a\n * search result depends on — page order/structure (`layoutVersion`) and\n * each page's text content (`contentVersion`), nothing else. Annotation\n * and metadata churn deliberately do NOT move it, so cached search\n * responses in a collaborative document survive comment storms.\n *\n * Both sides compute it from the manifest they already hold: the client\n * to mint versioned search URLs, the server to validate them (mismatch →\n * NotFound, the standard stale-versioned-read signal). FNV-1a 64-bit —\n * dependency-free and stable; not cryptographic, and doesn't need to be:\n * an adversary can only vary his OWN authorized query results.\n */\nexport function searchContentEpoch(manifest: DocumentManifest): string {\n let input = `${manifest.layoutVersion}`;\n for (const page of manifest.pages) {\n input += `|${page.state.pageObjectNumber}:${page.cache.contentVersion}`;\n }\n return fnv1a64(input);\n}\n\nconst FNV_OFFSET = 0xcbf29ce484222325n;\nconst FNV_PRIME = 0x100000001b3n;\nconst MASK_64 = 0xffffffffffffffffn;\n\nfunction fnv1a64(input: string): string {\n let hash = FNV_OFFSET;\n for (let i = 0; i < input.length; i++) {\n hash ^= BigInt(input.charCodeAt(i));\n hash = (hash * FNV_PRIME) & MASK_64;\n }\n return hash.toString(16).padStart(16, '0');\n}\n\n/**\n * Canonicalize a query for CACHE KEYING: default-fold literal queries are\n * pre-folded (\"Café\", \"café\" and \"CAFE\" are the same search, so they\n * should be the same cache entry). Semantics are unchanged — the fold is\n * idempotent and exactly what the matcher applies to the needle anyway.\n * Case- or diacritic-sensitive literals and regex patterns pass through\n * untouched (their raw form IS the query).\n */\nexport function canonicalSearchQuery(query: SearchQuery): SearchQuery {\n if (query.regex || query.matchCase || query.matchDiacritics) return query;\n const canonical: SearchQuery = { text: foldText(query.text).folded };\n if (query.wholeWord) canonical.wholeWord = true;\n return canonical;\n}\n","import type { PdfBits } from './types';\n\n/**\n * ISO 32000 user-access permission bit positions, expressed as integer\n * masks. Bit numbers in the spec are 1-indexed, so bit 3 = `1 << 2`.\n *\n * Bits 1, 2, 7, 8, and 13+ are reserved and not surfaced here.\n */\nexport const PDF_BITS = {\n /** Bit 3 — print the document. */\n PRINT: 1 << 2,\n /** Bit 4 — modify content streams. */\n MODIFY: 1 << 3,\n /** Bit 5 — copy/extract text and graphics. */\n COPY: 1 << 4,\n /** Bit 6 — annotate + fill forms (+ modify form fields with bit 4). */\n ANNOTATE_FILL: 1 << 5,\n /** Bit 9 — fill existing forms (even if bit 6 is clear). */\n FILL_FORMS: 1 << 8,\n /** Bit 10 — accessibility extraction (deprecated in PDF 2.0). */\n ACCESSIBILITY: 1 << 9,\n /** Bit 11 — assemble document (insert/rotate/delete pages, outline). */\n ASSEMBLE: 1 << 10,\n /** Bit 12 — high-quality print (refines bit 3). */\n PRINT_HIGH: 1 << 11,\n} as const;\n\n/**\n * Decode a raw PDFium permission integer into a typed boolean view.\n *\n * `null` input (the documents row column is nullable until probed)\n * yields all-false bits — i.e., a maximally restrictive interpretation.\n * That keeps `pdf.permissions` expansion safe on unprobed documents.\n */\nexport function decodePdfBits(raw: number | null): PdfBits {\n if (raw === null) {\n return {\n bit3: false,\n bit4: false,\n bit5: false,\n bit6: false,\n bit9: false,\n bit10: false,\n bit11: false,\n bit12: false,\n };\n }\n return {\n bit3: (raw & PDF_BITS.PRINT) !== 0,\n bit4: (raw & PDF_BITS.MODIFY) !== 0,\n bit5: (raw & PDF_BITS.COPY) !== 0,\n bit6: (raw & PDF_BITS.ANNOTATE_FILL) !== 0,\n bit9: (raw & PDF_BITS.FILL_FORMS) !== 0,\n bit10: (raw & PDF_BITS.ACCESSIBILITY) !== 0,\n bit11: (raw & PDF_BITS.ASSEMBLE) !== 0,\n bit12: (raw & PDF_BITS.PRINT_HIGH) !== 0,\n };\n}\n","import type { DocCapability, PdfBits } from './types';\n\n/**\n * Typed capability constants for customer-side JWT minting.\n *\n * The shape mirrors the dotted capability name so it reads naturally:\n * caps.doc.text.copy() // \"doc.text.copy\"\n * caps.doc.download() // \"doc.download\"\n * caps.doc.download.flattened() // \"doc.download.flattened\"\n * caps.doc.print.high() // \"doc.print.high\"\n *\n * Each leaf is a function returning the literal string (as `const`) so\n * TypeScript catches typos at the call site. Wrappers like `download`\n * and `print` are `Object.assign`'d to be callable AND carry child\n * properties for the refinement capabilities.\n */\nexport const caps = {\n doc: {\n open: () => 'doc.open' as const,\n render: () => 'doc.render' as const,\n text: {\n select: () => 'doc.text.select' as const,\n copy: () => 'doc.text.copy' as const,\n search: () => 'doc.text.search' as const,\n },\n content: {\n copy: () => 'doc.content.copy' as const,\n },\n download: Object.assign(() => 'doc.download' as const, {\n flattened: () => 'doc.download.flattened' as const,\n }),\n print: Object.assign(() => 'doc.print' as const, {\n high: () => 'doc.print.high' as const,\n }),\n pages: {\n modify: () => 'doc.pages.modify' as const,\n assemble: () => 'doc.pages.assemble' as const,\n },\n forms: {\n read: () => 'doc.forms.read' as const,\n fill: () => 'doc.forms.fill' as const,\n modify: () => 'doc.forms.modify' as const,\n },\n annotate: {\n read: () => 'doc.annotate.read' as const,\n modify: () => 'doc.annotate.modify' as const,\n },\n metadata: {\n modify: () => 'doc.metadata.modify' as const,\n },\n attachments: {\n modify: () => 'doc.attachments.modify' as const,\n },\n redact: () => 'doc.redact' as const,\n },\n} as const;\n\n/**\n * Builder factory for collab scope filters. Each entity:action pair\n * gets a sub-object with the four filter constructors.\n *\n * collab.annotations.create.self() → \"annotations:create:self\"\n * collab.annotations.create.group(\"legal\") → \"annotations:create:group=legal\"\n * collab.annotations.update.group(\"4\") → \"annotations:update:group=4\"\n * collab.annotations.delete.createdBy(\"u-7\") → \"annotations:delete:createdBy=u-7\"\n * collab.annotations.setGroup.group(\"legal\") → \"annotations:set-group:group=legal\"\n * collab.annotations.all.all() → \"annotations:*:all\" (action wildcard)\n *\n * On create, the filter is evaluated against the caller's own identity\n * (no impersonation), so `:self` and `:all` trivially pass; `:group=X`\n * is the meaningful filter — it constrains creation to callers whose\n * default group is X.\n */\nexport const collab = {\n annotations: {\n create: makeFilterBuilder('annotations', 'create'),\n update: makeFilterBuilder('annotations', 'update'),\n delete: makeFilterBuilder('annotations', 'delete'),\n setGroup: makeSetGroupBuilder(),\n /** Action wildcard — matches create, update, delete, AND set-group with the given filter. */\n all: makeFilterBuilder('annotations', '*'),\n },\n} as const;\n\ninterface FilterBuilder {\n all(): string;\n self(): string;\n createdBy(userId: string): string;\n group(groupId: string): string;\n}\n\nfunction makeFilterBuilder(entity: string, action: string): FilterBuilder {\n return {\n all: () => `${entity}:${action}:all`,\n self: () => `${entity}:${action}:self`,\n createdBy: (userId: string) => `${entity}:${action}:createdBy=${userId}`,\n group: (groupId: string) => `${entity}:${action}:group=${groupId}`,\n };\n}\n\n/**\n * `set-group` is an authority filter, not a per-record collab filter:\n * only `:all` and `:group=X` are meaningful (assign-to-any vs\n * assign-to-X). The builder exposes exactly those two — a typo at JWT\n * mint time is caught by the compiler instead of producing a JWT that\n * fails at verify.\n */\ninterface SetGroupBuilder {\n all(): string;\n group(groupId: string): string;\n}\n\nfunction makeSetGroupBuilder(): SetGroupBuilder {\n return {\n all: () => 'annotations:set-group:all',\n group: (groupId: string) => `annotations:set-group:group=${groupId}`,\n };\n}\n\n/**\n * Builder for the `pdf.permissions` virtual scope. Returns the literal\n * string; provided as a helper for parity with caps/collab in JWT\n * construction code.\n */\nexport const pdfPermissions = (): 'pdf.permissions' => 'pdf.permissions';\n\n/**\n * Materialise `pdf.permissions` into the concrete capability list it\n * would expand to under the given PDF bit configuration.\n *\n * Useful when the customer wants to start from PDF defaults and then\n * subtract specific capabilities — easier to build the JWT scope array\n * by filtering an explicit list than by composing virtual + denials.\n *\n * const defaults = materializePdfPermissions(pdfBits);\n * const scope = [\n * ...defaults.filter(s => s !== 'doc.text.copy'),\n * 'doc.download',\n * ];\n *\n * IMPORTANT: this MUST stay in sync with `addPdfPermissions` inside\n * resolver.ts. A test pins them together.\n */\nexport function materializePdfPermissions(b: PdfBits): DocCapability[] {\n const out = new Set<DocCapability>();\n\n // Always — pdf.permissions means \"give me a working session\"\n out.add('doc.open');\n out.add('doc.render');\n // Reading existing annotations and form values is unconditional —\n // PDF bit 6 governs writes, not visibility.\n out.add('doc.annotate.read');\n out.add('doc.forms.read');\n\n if (b.bit5) {\n out.add('doc.text.select');\n out.add('doc.text.copy');\n out.add('doc.text.search');\n out.add('doc.content.copy');\n }\n if (b.bit3) out.add('doc.print');\n if (b.bit12 && b.bit3) out.add('doc.print.high');\n if (b.bit4) {\n out.add('doc.pages.modify');\n out.add('doc.redact');\n out.add('doc.metadata.modify');\n out.add('doc.attachments.modify');\n }\n if (b.bit11) out.add('doc.pages.assemble');\n if (b.bit6) out.add('doc.annotate.modify');\n if (b.bit6 || b.bit9) out.add('doc.forms.fill');\n if (b.bit6 && b.bit4) out.add('doc.forms.modify');\n\n return [...out];\n}\n"],"mappings":"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"}
|