@embedpdf/plugin-annotation 3.0.0-next.13 → 3.0.0-next.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -0
- package/dist/authoring.cjs +12 -2
- package/dist/authoring.d.cts +2 -2
- package/dist/authoring.d.ts +2 -2
- package/dist/authoring.js +2 -3
- package/dist/contract/host.cjs +18 -2
- package/dist/contract/host.d.cts +3 -2
- package/dist/contract/host.d.ts +3 -2
- package/dist/contract/host.js +3 -2
- package/dist/contract-BK4LHe9v.d.cts +1127 -0
- package/dist/contract-BOo9iZKo.d.ts +1127 -0
- package/dist/contract-CPzpRG3h.cjs +692 -0
- package/dist/contract-CPzpRG3h.cjs.map +1 -0
- package/dist/contract-b2e_LZvu.js +651 -0
- package/dist/contract-b2e_LZvu.js.map +1 -0
- package/dist/contract.cjs +11 -10
- package/dist/contract.d.cts +2 -3
- package/dist/contract.d.ts +2 -3
- package/dist/contract.js +2 -4
- package/dist/host-contract-BbjhS_Fo.d.ts +310 -0
- package/dist/host-contract-CxrQPcPj.js +52 -0
- package/dist/host-contract-CxrQPcPj.js.map +1 -0
- package/dist/{contract-a4eaQWga.cjs → host-contract-DY9jFPPF.cjs} +36 -16
- package/dist/host-contract-DY9jFPPF.cjs.map +1 -0
- package/dist/host-contract-Nzxwh0XS.d.cts +310 -0
- package/dist/index.cjs +4995 -414
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -17
- package/dist/index.d.ts +12 -17
- package/dist/index.js +4949 -388
- package/dist/index.js.map +1 -1
- package/package.json +11 -14
- package/dist/authoring-BhtyfsMx.d.cts +0 -37
- package/dist/authoring-R4ezdnXd.d.ts +0 -37
- package/dist/capability-B_dkoB1K.js +0 -3041
- package/dist/capability-B_dkoB1K.js.map +0 -1
- package/dist/capability-DVx1NmTe.cjs +0 -3064
- package/dist/capability-DVx1NmTe.cjs.map +0 -1
- package/dist/contract-CgAcfAE7.d.cts +0 -34
- package/dist/contract-CiG2_HBq.d.ts +0 -34
- package/dist/contract-DtXE1hjY.js +0 -32
- package/dist/contract-DtXE1hjY.js.map +0 -1
- package/dist/contract-a4eaQWga.cjs.map +0 -1
- package/dist/internal.cjs +0 -8
- package/dist/internal.d.cts +0 -14
- package/dist/internal.d.ts +0 -14
- package/dist/internal.js +0 -5
- package/dist/seam-6pJeKOOJ.cjs +0 -296
- package/dist/seam-6pJeKOOJ.cjs.map +0 -1
- package/dist/seam-C4L_7rDt.js +0 -225
- package/dist/seam-C4L_7rDt.js.map +0 -1
- package/dist/tools-0NI3b9z8.cjs +0 -536
- package/dist/tools-0NI3b9z8.cjs.map +0 -1
- package/dist/tools-DBEYx3-c.js +0 -513
- package/dist/tools-DBEYx3-c.js.map +0 -1
- package/dist/types-BvB1vUKb.js +0 -20
- package/dist/types-BvB1vUKb.js.map +0 -1
- package/dist/types-D5V0TIwk.d.ts +0 -1200
- package/dist/types-Dlhdw2k_.cjs +0 -31
- package/dist/types-Dlhdw2k_.cjs.map +0 -1
- package/dist/types-ObcPYc3-.d.cts +0 -1200
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-BvB1vUKb.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken, type DocumentEvent, type PageObjectNumber } from '@embedpdf/core';\nimport type { AnnotCommitEntry, AnnotCommitResult } from '@embedpdf/plugin-actions/contract/host';\nimport type { PageRotation } from '@embedpdf/core-geometry';\nimport type {\n AnnotationAppearanceImage,\n AnnotationDTO,\n AnnotationDraft,\n AnnotationPatch,\n AnnotationRef,\n AttachmentContent,\n AttachmentFileSource,\n BinarySource,\n CommentThread,\n PdfLinkTarget,\n PdfRect,\n PdfActionTree,\n RichTextParagraph,\n} from '@embedpdf/engine-core/runtime';\nimport type { TextFormat, TextSelection } from './rich-text';\nimport type { AnnotationToolInput, ResolvedTool } from './tools';\nimport type {\n AnnotationFlags,\n AnnotationProps,\n AnnotationPropsPatch,\n ChromeNode,\n CreationDraftAnchor,\n Geom,\n Id,\n Model,\n PropKey,\n PropSpec,\n Rect,\n RenderItem,\n SnapSettings,\n Subtype,\n TextEndAnchor,\n TextQuad,\n Vec,\n ViewEnv,\n} from '@embedpdf/core-annotation';\n\n/**\n * Selection-chrome settings: the outline, resize/vertex handles, and the rotate\n * knob. ONE unit story — every length is CSS px, screen-constant across zoom\n * (the plugin converts to content units per event/page via the view scale).\n * Every color falls back to `accent`, so the common case is one line:\n * `annotationPlugin({ chrome: { accent: '#e91e63' } })`. Deep-partial merged\n * over {@link DEFAULT_CHROME}; live-adjustable via\n * {@link AnnotationCapability.setChrome}.\n */\nexport interface ChromeSettings {\n /** The one color every chrome piece derives from unless overridden. */\n accent: string;\n outline: {\n /** ONE style at rest AND while rotated — the box never flips style mid-gesture. */\n style: 'solid' | 'dashed';\n /** Stroke width, px. */\n width: number;\n /** Overrides `accent`. */\n color?: string;\n };\n /** Resize + vertex handles (independent of the knob — size them apart). */\n handles: {\n /** Visual square side, px. */\n size: number;\n /** Grab-zone square side, px — keep ≥ 24 for touch. */\n hitSize: number;\n fill: string;\n /** Overrides `accent`. */\n stroke?: string;\n };\n /** The rotate handle. Page-bound placement (flip/clamp) always applies. */\n knob: {\n /** Grab-dot diameter, px. */\n size: number;\n /** Grab-zone square side, px — keep ≥ 24 for touch. */\n hitSize: number;\n /** Stalk length, px — selection edge to dot centre. */\n offset: number;\n /** Draw the connector stalk. */\n stalk: boolean;\n fill: string;\n /** Overrides `accent` (dot outline + stalk). */\n stroke?: string;\n };\n /** The rotation guides shown while a rotate gesture runs: a fixed 0°/90°\n * reference cross + a live indicator line, drawn as full-bleed chords of the\n * page through the pivot. */\n guides: {\n /** Show the guides at all. Default true. */\n enabled: boolean;\n style: 'solid' | 'dashed';\n /** Stroke width, px. */\n width: number;\n /** The fixed reference cross. Color overrides `accent`. */\n axisColor?: string;\n axisOpacity: number;\n /** The line riding the live angle. Color overrides `accent`. */\n indicatorColor?: string;\n indicatorOpacity: number;\n };\n}\n\n/** Deep-partial patch for {@link ChromeSettings} — config + `setChrome` input. */\nexport interface ChromeSettingsPatch {\n accent?: string;\n outline?: Partial<ChromeSettings['outline']>;\n handles?: Partial<ChromeSettings['handles']>;\n knob?: Partial<ChromeSettings['knob']>;\n guides?: Partial<ChromeSettings['guides']>;\n}\n\n/**\n * Whole-document annotation hydration. The plugin always hydrates ALL\n * pages through `doc.annotations.listRawAll()` (one bulk request on\n * cloud, one worker job locally) — a comments sidebar needs every page,\n * and per-page lazy loading could never truthfully claim completeness.\n * `loading` covers the initial ingest AND a desync re-ingest; `error`\n * means live events still apply but the whole-document view is\n * incomplete until a rehydrate succeeds.\n */\nexport type AnnotationHydration =\n | { status: 'loading' }\n | { status: 'complete' }\n | { status: 'error'; error: unknown }\n // The scope lacks `doc.annotate.read`: hydration never runs (no doomed\n // request), the comments panel hides, and `rehydrate` re-checks — the\n // state clears if an /access refresh grants read later.\n | { status: 'forbidden' };\n\nexport interface AnnotationState {\n model: Model;\n hydration: AnnotationHydration;\n chrome: ChromeSettings;\n /**\n * The armed tool's FOOTPRINT ghost: where (and what) the NEXT click would\n * place — the stamp's fitted image box, or a click-create tool's default\n * geometry — computed by the same rules the placement uses (WYSIWYG). In the\n * store (not the capability closure) because it is RENDERED — vector ghosts\n * ride `pageItems`, image ghosts (stamp) render via the framework's\n * `ToolGhost`. The armed bytes stay out of the store.\n */\n toolGhost: ToolGhost | null;\n /** Bumps on every arm/disarm — the render layer's cue to rebuild (or drop)\n * the ghost preview object URL. Never rendered itself. */\n stampArmEpoch: number;\n /**\n * The text editor's selection inside the annotation being edited (flat\n * offsets over its plain projection), or null. In the store because it is\n * READ by the property surface: while a range is held, the range keys\n * (`getSelectionProps`) report and take the RUNS, not the body.\n */\n textSelection: TextSelection | null;\n}\n\n/** The armed tool's would-be placement under the cursor (content space). */\nexport type ToolGhost = {\n pon: PageObjectNumber;\n /** The exact box the click's placement would use. */\n box: Rect;\n /** The tool's upright counter-rotation at this hover (deg, CW). */\n rot: number;\n} & (\n | { kind: 'image' } // the armed stamp raster — framework blits it\n | { kind: 'vector'; toolId: string; geom: Geom } // painted via pageItems/scene\n);\n\n/** Registration options for {@link annotationPlugin} — the initial values of the\n * live-adjustable {@link AnnotationCapability.setSnap} /\n * {@link AnnotationCapability.setChrome} settings. */\nexport interface AnnotationConfig {\n snap?: {\n /** Alignment guides while moving (snap to other annotations + the page).\n * Default true. */\n guides?: boolean;\n /** Guide snap tolerance, content units (PDF pt). Default 5. */\n guideThreshold?: number;\n /** Snap the rotate gesture onto `rotationAngles`. Default true. */\n rotation?: boolean;\n /** Default `[0, 90, 180, 270]`. */\n rotationAngles?: number[];\n /** Rotation snap tolerance, degrees. Default 4. */\n rotationThreshold?: number;\n };\n /** Selection-chrome styling + grab geometry (all lengths CSS px). */\n chrome?: ChromeSettingsPatch;\n /**\n * Add or configure authoring tools at load. Entries MERGE over the built-ins by\n * id (configure one — `{ id: 'ink', defaults: { strokeWidth: 6 } }`), ADD a new\n * tool (a fresh id), or make a preset with `extends`\n * (`{ id: 'arrow', extends: 'line', defaults: { lineEndings: { end: 'open-arrow' } } }`).\n * See {@link AnnotationToolDef}. The runtime equivalent is\n * {@link AnnotationCapability.registerTool}.\n */\n tools?: AnnotationToolInput[];\n}\nexport type AnnotationAction =\n | { type: 'SET_MODEL'; model: Model }\n | { type: 'SET_HYDRATION'; hydration: AnnotationHydration }\n | { type: 'SET_CHROME'; patch: ChromeSettingsPatch }\n | { type: 'SET_TOOL_GHOST'; ghost: ToolGhost | null }\n | { type: 'SET_TEXT_SELECTION'; selection: TextSelection | null }\n | { type: 'STAMP_ARM_CHANGED' };\n\n/** A plugin (forms, links) marks some annotations as interactive: while engaged,\n * they render their own DOM and are NOT geometry-editable. Suspend → editable. */\n/**\n * One clickable link area on a page (content space): a standalone link\n * annotation, or one segment of a parent's ATTACHED link. See\n * {@link AnnotationHostCapability.linkItemsOn}.\n */\nexport interface LinkNavItem {\n /** Stable per-page key: the annot id, `#n`-suffixed for attached segments. */\n id: string;\n rect: Rect;\n target: PdfLinkTarget;\n /**\n * True for a link CHILD riding an editable annotation (an `/RT /Group`\n * subordinate) — a PROPERTY of its parent while authoring, a nav behavior\n * only while reading. The nav layer stands its anchors down for attached\n * items whenever the active tool enables `annotation-edit`, so the parent\n * stays selectable/movable; standalone document links navigate regardless.\n */\n attached: boolean;\n /** The full payload-carrying `/A` tree, when one exists — the action\n * engine's dispatch input. `target` remains its root projection. */\n activate?: PdfActionTree;\n /** The annotation ref, carried for ActionSource context. */\n ref?: AnnotationRef;\n /** Which `/AA` hover trees this link carries — the nav layer's pump flags\n * (tree-less hover must cost zero dispatches). Links are behavior-inert\n * to the annotation plane's hover feed while navigable, so THEIR\n * cursorEnter/cursorExit can only fire from the LinkLayer anchors. */\n hoverEvents?: { enter: boolean; exit: boolean };\n}\n\nexport interface Behavior {\n id: string;\n matches(a: { subtype: Subtype; ref: AnnotationRef | null }): boolean;\n engaged(): boolean;\n}\n\n/**\n * The current selection's editable properties, ready to render: the ordered\n * {@link PropSpec}s EVERY selected kind declares (a mixed selection shows the\n * shared subset, in the first kind's order), the first member's `values`, and\n * which keys differ across members (`mixed` — render an indeterminate control).\n * Empty `specs` = nothing selected / nothing editable.\n */\nexport interface SelectionProps {\n specs: PropSpec[];\n values: Partial<AnnotationProps>;\n mixed: PropKey[];\n}\n\n/**\n * The selection's `/F` flag state, ready for a menu/sidebar: one value per\n * flag — `true`/`false` when every selected annotation agrees, `null` when\n * they differ (render an indeterminate control). The read half of\n * {@link AnnotationCapability.updateSelectionFlags}.\n */\nexport type SelectionFlags = { [K in keyof AnnotationFlags]: boolean | null };\n\n/**\n * A free-text annotation projected for the framework: the box (content space,\n * live gesture applied) + the plain text + an `editing` flag + a ready-to-spread\n * CSS style. The framework renders ONE editable element from this and nothing\n * more — all the mapping (fonts, colours, alignment) is done here, once. The\n * element paints the TEXT only: the box's fill and border are the vector\n * scene's (`pageItems`), the same for a plain box and a callout, so the live\n * view matches the baked appearance.\n */\nexport interface TextItem {\n id: Id;\n ref: AnnotationRef | null;\n box: Rect;\n contents: string;\n /** The rich paragraphs the editor renders and edits (run deltas over the\n * body, which `css` carries). `contents` is their plain projection. */\n richText: { paragraphs: RichTextParagraph[] };\n editing: boolean;\n /** Applied rotation (deg, CW). `box` is the UNROTATED text box; the framework\n * rotates the editable element about its centre by this. 0/undefined = none. */\n rot?: number;\n css: {\n fontFamily: string;\n /** Content units (the framework multiplies by the page scale). The line\n * height is NOT here: the editor binding states the engine's line model\n * per face on the element itself (`@embedpdf/web`, `lineModelFor`). */\n fontSize: number;\n color: string;\n /** The body's formatting (runs override it as inline spans). */\n fontWeight: number;\n fontStyle: 'normal' | 'italic';\n textDecoration: 'none' | 'underline';\n align: 'left' | 'center' | 'right';\n padding: number;\n };\n}\n\n/**\n * The PUBLIC annotation API — the documented, stable surface for application code\n * (toolbars, sidebars, app logic). Resolve it with the token re-exported from the\n * package root (`@embedpdf/plugin-annotation`).\n *\n * Framework-only plumbing (render projection, pointer gestures, behavior\n * registration) lives on {@link AnnotationHostCapability}, reachable through\n * `@embedpdf/plugin-annotation/contract/host` (and the framework's `/internal`\n * entry). Both are the SAME runtime\n * object — two typed lenses on one token — so app code simply can't see the host\n * methods.\n */\n/**\n * Per-thread action gates, composed from two axes: authority (the\n * engine's collab-resolver mirrors — `allowsAnnotationCreate` for\n * reply/status, `allowsAnnotationMutation` against each target's\n * stamped owner for edit/delete) and PDF state (the two lock flags\n * gate DIFFERENT aspects, ISO 32000 Table 167: `lockedContents` blocks\n * text edits, `locked` blocks deletion). A courtesy, not the guard — the\n * engine independently enforces every write.\n */\nexport interface CommentPermissions {\n /** A reply is an annotation CREATE. */\n canReply: boolean;\n /** Editing this comment's text (`contents`) — gated by `lockedContents`. */\n canEditText: boolean;\n /** Deleting this one annotation — gated by `locked`. */\n canDelete: boolean;\n /** A status change is a NEW hidden annotation — create authority only,\n * never edit rights on someone else's comment. */\n canSetStatus: boolean;\n /** `canDelete` over EVERY thread member (root, replies, grouped parts,\n * state annotations) — the whole-thread preflight. */\n canDeleteThread: boolean;\n}\n\nexport interface ThreadDeleteResult {\n deleted: AnnotationRef[];\n failed: Array<{ ref: AnnotationRef; error: unknown }>;\n}\n\n/**\n * The conversation plane's surface: a derived, memoized threads index over\n * the annotation substrate, plus the ISO-native verbs. Every verb compiles\n * down to plain annotation creates/patches/deletes — one optimistic\n * pipeline, no second write path — so remote SSE events, own edits, and\n * hydration all update `threads()` for free.\n *\n * Threads carry `pageObjectNumber` (identity is PON, like everything\n * else); DISPLAY order is a behavior of `threads()` (sorted against the\n * live layout at computation time), and display labels (`pageIndex`) are a\n * framework-hook enrichment — the layer that watches both stores.\n */\nexport interface CommentsApi {\n /** Every comment thread in the document, display-ordered, memoized. */\n threads(): CommentThread[];\n /** The thread containing ANY member ref (root, reply, grouped part, or\n * state annotation), or null. */\n thread(ref: AnnotationRef): CommentThread | null;\n /** Whole-document hydration status (the sidebar's honest loading state). */\n hydration(): AnnotationHydration;\n /** Re-run whole-document hydration (desync recovery / manual refresh). */\n rehydrate(): Promise<void>;\n\n /** Reply to a thread. Writes FLAT (`/IRT` → the thread root, ISO reply\n * type), whatever member was passed — presentation stays one level. */\n reply(ref: AnnotationRef, text: string): Promise<AnnotationRef>;\n /** Edit a comment's text. Appearance-inert for every kind except\n * free-text and redaction (whose `/AP` paints `/Contents`). */\n edit(ref: AnnotationRef, text: string): Promise<void>;\n /**\n * Set this session's review status on the thread (ISO 32000 §12.5.6.3):\n * creates a hidden state annotation chained to the caller's previous\n * status when one exists, else to the root. The target annotation is\n * never modified. Known states: accepted / rejected / cancelled /\n * completed / none (custom vocabularies ride the raw create API).\n */\n setStatus(ref: AnnotationRef, state: string): Promise<void>;\n /** Toggle this session's Marked-model checkmark on the thread. */\n setMarked(ref: AnnotationRef, marked: boolean): Promise<void>;\n /** Delete exactly ONE annotation (a reply, a status, or a bare root). */\n remove(ref: AnnotationRef): Promise<void>;\n /**\n * Delete a WHOLE thread, children first. Preflighted: when any member\n * fails the delete gate the call returns every blocked ref as `failed`\n * and deletes nothing; mid-flight races surface the same way.\n */\n removeThread(ref: AnnotationRef): Promise<ThreadDeleteResult>;\n\n /** Truthful per-thread action gates for the ref's thread. */\n permissionsFor(ref: AnnotationRef): CommentPermissions;\n}\n\nexport interface AnnotationCapability {\n // ── data API: the mutation vocabulary (engine-core types, addressable by ref) ──\n /**\n * Create an annotation on a page. `draft` is the engine-core draft for its\n * subtype (PDF-space, sRGB). Resolves to the new annotation's durable `ref`.\n * The same path the draw tools use, so programmatic and interactive creation\n * share one optimistic flow + one event stream.\n */\n create(pon: PageObjectNumber, draft: AnnotationDraft): Promise<AnnotationRef>;\n /**\n * Patch an existing annotation. `patch` is the engine-core patch for the\n * annotation's subtype — style, endings, contents, geometry are ALL just\n * fields here (there is no separate \"set style\"). Attribution is automatic\n * from the session identity.\n */\n update(ref: AnnotationRef, patch: AnnotationPatch): Promise<void>;\n /** Delete an annotation by ref. */\n delete(ref: AnnotationRef): Promise<void>;\n /**\n * Restyle the current selection with ONE flat property patch — the write half\n * of {@link getSelectionProps}. Each selected annotation takes the keys its\n * kind declares (`propsFor`) and ignores the rest, so a single patch restyles\n * a mixed selection. Optimistic: the model updates immediately; one engine\n * write per changed member re-syncs from the authoritative DTO.\n */\n updateSelection(patch: AnnotationPropsPatch): void;\n /**\n * Merge a `/F` flags patch into the current selection — the write half of\n * {@link getSelectionFlags}. Optimistic; one flags-only engine write per\n * changed member, which never re-bakes an appearance. Deliberately NOT\n * blocked by `locked`: this is how you unlock (Acrobat's Locked checkbox\n * stays live on a locked annotation). E.g. `{ locked: true }`,\n * `{ print: false }`, `{ hidden: true }`.\n */\n updateSelectionFlags(patch: Partial<AnnotationFlags>): void;\n /**\n * Flip a rich-text format on the selection — the editor's Cmd/Ctrl+B/I/U\n * and a toolbar toggle: the text range's runs while the editor holds one,\n * else the selected free-text bodies. Reads the current state the way\n * {@link getSelectionProps} reports it and writes its inverse through\n * {@link updateSelection}.\n */\n toggleTextFormat(format: TextFormat): void;\n /**\n * The selection's `/F` flag state: per-flag `true`/`false`, or `null` when\n * the selected annotations disagree (indeterminate). `null` overall when\n * nothing is selected. Stable reference between model changes.\n */\n getSelectionFlags(): SelectionFlags | null;\n\n // ── property introspection (the machine-readable \"what can I edit here\") ──\n /**\n * The selection's editable properties: ordered specs shared by every selected\n * kind + current values + which keys are mixed. THE way to build a property\n * sidebar/toolbar — render `specs` in order, write back via\n * {@link updateSelection}. Stable reference between model changes.\n */\n getSelectionProps(): SelectionProps;\n /** The ordered property specs a TOOL's target kind declares (callout → the\n * free-text kind). Drives the same sidebar when nothing is selected, paired\n * with {@link currentDefaults}/{@link setDefaults}. */\n propsForTool(toolId: string): PropSpec[];\n\n // ── authorization: the `can` twins (permissions.md). Each answers \"would\n // this verb succeed now for this session?\" — authority (the engine's\n // collab mirrors) AND document flags, via the same fused predicates the\n // gestures and chrome consume; the active tool is deliberately excluded\n // (twins are facts; mode gates rendering). `canRead` mirrors\n // `doc.annotate.read`: false → hydration reports `forbidden` and the\n // comments UI hides. The engine independently enforces everything. ──\n canRead(): boolean;\n // ── authorization: per-record mirrors of the engine's collab resolver\n // (`security.allowsAnnotation*`). `canCreate` asks about the caller's\n // own identity; `canEdit`/`canDelete` about the TARGET's stamped owner,\n // so under a narrowed grant (`annotations:update:self`) they answer\n // per annotation. Pure authority — the `locked`/`lockedContents` flag\n // gates live with the surfaces that touch that aspect (see\n // `comments.permissionsFor`). The engine independently enforces. ──\n canCreate(): boolean;\n canEdit(ref: AnnotationRef): boolean;\n canDelete(ref: AnnotationRef): boolean;\n\n /** The conversation plane's read/write surface — see {@link CommentsApi}. */\n comments: CommentsApi;\n\n /**\n * The attached-link lens: an annotation's link is a `/Link` CHILD grouped\n * under it in the document (ISO-native, Acrobat-interoperable) — a\n * PROPERTY while authoring, a nav BEHAVIOR while reading. `of` derives\n * from the committed children (the one source of truth); `set`/`clear`\n * resolve when the children are committed, after which `of` reflects the\n * change. `updateSelection({ link })` remains the props-pipeline alias.\n * On the link KIND itself, `of` reads the annotation's own `/A` target\n * (retarget standalone links via `updateSelection`).\n */\n links: {\n of(ref: AnnotationRef): PdfLinkTarget | null;\n set(ref: AnnotationRef, target: PdfLinkTarget): Promise<void>;\n clear(ref: AnnotationRef): Promise<void>;\n };\n\n // ── reads (canonical engine DTOs) ──\n /** The annotation for a ref, or null if unknown / not yet committed. */\n get(ref: AnnotationRef): AnnotationDTO | null;\n /** Every committed annotation on a page, in z-order. */\n list(pon: PageObjectNumber): AnnotationDTO[];\n /** The selected annotations as DTOs (skips not-yet-committed drafts). */\n getSelected(): AnnotationDTO[];\n\n // ── selection ──\n selection(): Id[];\n /** The current selection as durable annotation refs (skips not-yet-committed drafts). */\n getSelection(): AnnotationRef[];\n /**\n * Select an annotation by ref programmatically — e.g. auto-selecting a\n * freshly placed form widget. Selecting a group member takes the whole\n * group, exactly like a click. Unknown/unselectable refs no-op. `add`\n * extends the current selection instead of replacing it.\n */\n select(ref: AnnotationRef, options?: { add?: boolean }): void;\n\n // ── grouping (engine `/IRT` + `/RT /Group`; selecting one member selects all) ──\n /** Group the current selection into one unit (the bottom-most member is the\n * primary; the rest become `/RT /Group` subordinates). Page-local: no-op\n * unless 2+ committed annotations on a single page are selected. */\n group(): Promise<void>;\n /** Ungroup the group(s) the current selection touches — every subordinate\n * becomes top-level again. */\n ungroup(): Promise<void>;\n /** Whether {@link group} would do something for the current selection. */\n canGroup(): boolean;\n /** Whether {@link ungroup} would do something for the current selection. */\n canUngroup(): boolean;\n\n // ── tool defaults (LOCAL drawing preferences — never collaborative) ──\n /** Patch a tool's defaults for newly drawn annotations — the SAME flat\n * vocabulary {@link updateSelection} writes. */\n setDefaults(subtype: Subtype, patch: AnnotationPropsPatch): void;\n /** The RESOLVED full props bag a tool will use for new annotations. */\n currentDefaults(subtype: Subtype): AnnotationProps;\n // ── snapping (alignment guides while moving + rotation snap) ──\n /** Live-adjust snapping — wire a UI toggle here (e.g.\n * `setSnap({ guides: false })`). Initial values come from the plugin's\n * registration config ({@link AnnotationConfig}). */\n setSnap(patch: Partial<SnapSettings>): void;\n /** The current snap settings. */\n snapSettings(): SnapSettings;\n // ── selection chrome (outline / handles / rotate knob; all lengths CSS px) ──\n /** Live-adjust the selection chrome — wire theming here (e.g.\n * `setChrome({ accent: '#e91e63' })`). Deep-partial merge; initial values\n * come from the plugin's registration config ({@link AnnotationConfig}). */\n setChrome(patch: ChromeSettingsPatch): void;\n /** The current (fully resolved) chrome settings. */\n chromeSettings(): ChromeSettings;\n // ── rotation (selection-scoped; rotatable kinds only) ──\n /** Rotate the current selection a quarter-turn clockwise about its centre\n * (a single shape's own centre / the union-box centre for a group). */\n rotateSelection90(): void;\n /** Reset the current selection to its as-authored orientation (rotation → 0). */\n resetSelectionRotation(): void;\n // ── stamp tool (click-to-place with an armed binary payload) ──\n /**\n * Arm the stamp tool: `source` (PNG, JPEG, or single-page PDF bytes —\n * format sniffed, never trusted) becomes the content of the next stamp(s)\n * placed by clicking a page. The placement rect is sized from the image's\n * intrinsic aspect ratio around `targetWidth` (PDF points, default 150)\n * and centred on the click. Also activates the `'stamp'` interaction tool;\n * the payload stays armed for repeat placement until the tool changes or\n * {@link disarmStamp} is called. Resolves once the payload is validated.\n */\n armStamp(input: StampToolInput): Promise<void>;\n /** Drop the armed stamp payload (a tool change away from 'stamp' does this too). */\n disarmStamp(): void;\n /**\n * Place a stamp WITHOUT the pointer: the same validation, fit, page clamp,\n * `/Name`, and `/Subj` a click after {@link armStamp} produces — the one\n * placement law, exposed for code. Resolves to the created annotation's\n * ref; the placement is selected like a click's.\n */\n placeStamp(input: StampToolInput, placement: StampPlacement): Promise<AnnotationRef>;\n /**\n * Install the ONE file-picker port every click-then-pick tool resolves\n * through (see {@link FilePickerProvider}) — the stamp `'prompt'` source and\n * the file-attachment tool today. The framework adapter installs a\n * file-dialog provider by default; pass your own (asset library, cloud\n * drive — switch on `req.subtype` / `req.toolId`), or `null` to make\n * click-then-pick tools inert. One slot; last write wins.\n */\n setFilePickerProvider(provider: FilePickerProvider | null): void;\n /**\n * Decode and return the file embedded in a FileAttachment annotation —\n * bytes plus the name/mime needed to hand it to the user. Listings carry\n * only metadata (`FileAttachmentAnnotationDTO.file`); this is the explicit\n * bytes-out call. Throws when the engine transport has not shipped\n * attachment download (feature-detected).\n */\n downloadAttachment(ref: AnnotationRef): Promise<AttachmentContent>;\n\n // ── tools (add/configure at runtime; the config equivalent is `tools`) ──\n /**\n * Register (or replace, by id) an authoring tool at runtime — the imperative\n * mirror of the `tools` config. Same {@link AnnotationToolDef} vocabulary\n * (`extends`, per-tool `defaults`, …). Returns an unregister fn.\n */\n registerTool(def: AnnotationToolInput): () => void;\n\n // ── text-selection authoring (one-shot; requires the selection plugin) ──\n /**\n * Turn the CURRENT text selection into markup annotations — one per\n * selected page, from the selection's oriented per-line quads — then clear\n * the selection. The one-call form of what the markup tools do on\n * commit, made for selection-menu buttons (\"Highlight\") and automation.\n * `preset` is a tool id whose defaults style the markup (e.g.\n * `'highlight'`); defaults to the subtype's own. Returns false (and does\n * nothing) when no selection plugin is installed or nothing is selected.\n */\n markupFromSelection(subtype: Subtype, preset?: string): boolean;\n\n // ── multi-click creation drafts (polygon, polyline, …) ──\n /** Commit the in-progress multi-click creation draft (no-op when there is\n * none, or it can't finish yet — see `creationDraftAnchor().canFinish`). */\n finishCreationDraft(): void;\n /** Discard the in-progress multi-click creation draft. */\n cancelCreationDraft(): void;\n\n // ── lifecycle ──\n deleteSelection(): void;\n deselect(): void;\n cancel(): void;\n}\n\n/** Payload for {@link AnnotationCapability.armStamp}. */\nexport interface StampToolInput {\n /** PNG, JPEG, or single-page PDF bytes (`Blob | Uint8Array | BinaryPayload`). */\n source: BinarySource;\n /** Placed width in PDF points (height follows the intrinsic aspect). Default 150. */\n targetWidth?: number;\n /** The placed annotation's `/Name` — the stamp identifier (standard or custom). */\n name?: string;\n /** The placed annotation's `/Subj`. */\n subject?: string;\n /**\n * The hover ghost's image. Either fixed bytes (PNG/JPEG) or — for vector\n * sources, which are only ever right at ONE on-screen size — a\n * {@link StampPreviewProvider} the ghost asks for a render at the device\n * pixel width it is displayed at. Raster sources default to themselves;\n * omit and the tool simply shows no ghost.\n */\n preview?: BinarySource | StampPreviewProvider;\n /**\n * The source's intrinsic size in PDF points. Raster sources are measured\n * from their own header, but PDF bytes carry no sniffable dimensions —\n * callers that know the page size (a stamp library does, from import)\n * pass it here so placement honours the true aspect instead of falling\n * back to a square.\n */\n intrinsicSize?: { width: number; height: number };\n}\n\n/** The armed stamp's paintable preview, for the render layer's ghost `<img>`. */\nexport interface ArmedStampPreview {\n bytes: Uint8Array;\n mimeType?: string;\n}\n\n/**\n * Resolution-aware ghost preview: \"give me this stamp at `devicePixelWidth`\n * pixels wide\". The annotation plugin buckets the request (see\n * {@link previewBucket}) and caches per bucket for the arm's lifetime, so a\n * zoom gesture never renders per frame and one render serves a zoom range.\n * A stamp library renders its page lazily through its asset engine; a raster\n * returns itself (it cannot get sharper than its pixels).\n */\nexport type StampPreviewProvider = (devicePixelWidth: number) => Promise<ArmedStampPreview | null>;\n\n/**\n * Ghost render buckets: powers of two from 128 px up to `cap`. The same policy\n * the page renderer uses — one bitmap per size class, never per zoom step.\n */\nexport function previewBucket(devicePixelWidth: number, cap = 4096): number {\n const px = Math.max(128, Math.ceil(devicePixelWidth));\n return Math.min(cap, 2 ** Math.ceil(Math.log2(px)));\n}\n\n/**\n * Where a programmatic stamp placement lands — the inputs a click supplies.\n * The box is fitted and clamped exactly as the click path does it.\n */\nexport interface StampPlacement {\n pageObjectNumber: PageObjectNumber;\n /** Anchor in page points (content space): the placement is centred here. */\n at: Vec;\n /** Placed width in PDF points; default the payload's intrinsic size. */\n targetWidth?: number;\n /** Content rotation, degrees clockwise. Default 0. */\n rotation?: number;\n}\n\n/**\n * What the {@link FilePickerProvider} is asked for: which tool clicked (id +\n * the kind it creates), the tool's `accept` filter, and the page-space point\n * the click landed on — enough to route per tool (asset library for stamps,\n * cloud drive for attachments) or position a picker near the click. Pure\n * data — the request crosses the plugin↔adapter boundary as a message.\n */\nexport interface FilePromptRequest {\n toolId: string;\n /** The kind the placement creates — the routing key for per-tool pickers. */\n subtype: Subtype;\n /** The tool's file-dialog filter hint (from the tool def). UX only —\n * the engine sniffs/validates the bytes for real. */\n accept?: string;\n pon: PageObjectNumber;\n /** The content-space point the placement is centred on. */\n point: Vec;\n}\n\n/**\n * The ONE environment port behind every click-then-pick tool — the stamp\n * `'prompt'` source and the file-attachment tool (the file is picked AFTER\n * the spot): given a click, produce the file to place, `null` to cancel. The\n * plugin declares this contract but never implements it — \"get bytes from the\n * environment\" is a DOM concern (a file dialog), so the framework adapter\n * installs the implementation via\n * {@link AnnotationCapability.setFilePickerProvider}. This keeps the plugin\n * DOM-free (Rust-portable) while the zero-config file dialog works out of the\n * box. The return shape is the engine's file vocabulary: a stamp consumes\n * only `data`; an attachment embeds the whole thing. A picked `File` carries\n * its own name and mime — a provider returning raw bytes for an attachment\n * must supply `name` itself.\n */\nexport type FilePickerProvider = (req: FilePromptRequest) => Promise<AttachmentFileSource | null>;\n\n/**\n * The HOST (framework) surface: everything the render layer, the interaction hub,\n * and sibling plugins need, on top of the public {@link AnnotationCapability}.\n * Host-only — sibling plugins import the token from\n * `@embedpdf/plugin-annotation/contract/host`; framework implementation code may\n * use `/internal`. Never use either from application code.\n */\nexport interface AnnotationHostCapability extends AnnotationCapability {\n // ── render projection (consumed by the framework render layer) ──\n /** `view` (the page's scale + total display rotation, from its transform)\n * projects screen-anchored (`noZoom`/`noRotate`) bodies to their effective\n * footprint. Pass it from the page context; absent → stored geometry. */\n pageItems(pon: PageObjectNumber, view?: ViewEnv): RenderItem[];\n /** `scale` (view px per content unit, from the page's transform) converts the\n * px chrome settings into content units — pass it so the knob stalk and grab\n * zones are screen-constant. `rotation` (the page's total display rotation)\n * and `zoom` (the page's zoom RELATIVE to its 100% baseline —\n * `transform.zoom`, NOT `viewScale`) complete the view env for\n * screen-anchored bodies. Absent scale → settings are read as content\n * units. */\n chrome(\n pon: PageObjectNumber,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): ChromeNode[];\n /** The anchor for a selection-aware floating menu: the primary page + the\n * selection's union box on that page (content space), or null when nothing\n * selectable is selected. One anchor regardless of cross-page selection.\n * `scale`/`rotation`/`zoom` as in {@link chrome} (the anchor page's view). */\n selectionAnchor(\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): { pon: PageObjectNumber; bounds: Rect; knob?: Vec } | null;\n /** The anchor + action state for a live multi-click creation draft, or null. */\n creationDraftAnchor(): CreationDraftAnchor | null;\n /** Cache key for a page's baked appearances: the COMMITTED id + AP box of every\n * baked annotation (gesture previews excluded). Changes exactly once per\n * committed create/geometry-edit, so the render layer refetches rasters then —\n * and only then (a stamp resize re-fits its AP engine-side, for example). */\n appearanceEpoch(pon: PageObjectNumber): string;\n /**\n * The scale a baked appearance should render at for a desired device\n * scale — `snapAppearanceScale` over the document's `renderPolicy` (the\n * kernel-materialized fact; identity under `continuous`). THE identity a\n * render layer keys its bake effect on: inside an appearance-lattice rung,\n * zoom ticks produce the same value → no re-bake; crossing a rung re-bakes\n * once. This plugin owns its raster product end to end — the policy is a\n * document fact, not another plugin's possession.\n */\n bakeScale(renderScale: number): number;\n /** The engine's rendered /AP appearance images for a page — the `baked` visual. */\n appearances(\n pon: PageObjectNumber,\n scale: number,\n signal?: AbortSignal,\n ): Promise<AnnotationAppearanceImage[]>;\n /** Convert an engine appearance rect (PDF user space) to a content-space box, so\n * the renderer places the baked bitmap by its OWN `/Rect` without touching the\n * PDF↔content seam. Null if the page's crop box is unknown. */\n toContentBox(pon: PageObjectNumber, rect: PdfRect): Rect | null;\n /** No-op since whole-document hydration: the model is seeded by\n * `listRawAll()` at document open. Kept as API for layers that call it\n * on page mount. */\n ensurePage(pon: PageObjectNumber): void;\n /**\n * Drop and RE-READ one page's annotations from the engine — the hook for\n * cross-plane mutations (e.g. `doc.forms.createField`/`deleteField`\n * changing the page's widget population underneath this plugin). Resolves\n * when the fresh page is in the model, so a caller can select what it just\n * created.\n */\n reloadPage(pon: PageObjectNumber): Promise<void>;\n // ── whole-document hydration (see the controller in capability.ts) ──\n /** Live hydration status — `loading` covers initial ingest AND a desync\n * re-ingest. */\n hydration(): AnnotationHydration;\n /** Kick hydration exactly once per document; the effects layer calls\n * this at registration. Subsequent calls no-op. */\n ensureHydrated(): void;\n /** Re-run whole-document hydration (desync recovery). Safe to call while\n * one is in flight — the fresh run is chained after it. */\n rehydrate(): Promise<void>;\n /**\n * The effects layer hands every REMOTE `annotation.*` event here: during\n * a hydration window it queues (replayed by audit cursor after ingest —\n * the delete-resurrection guard); otherwise it applies immediately.\n */\n deliverRemoteAnnotationEvent(event: DocumentEvent): void;\n // ── free-text (the editable-element layer) ──\n /** The free-text boxes on a page, ready to render as editable elements.\n * `view` as in {@link pageItems}. */\n textItems(pon: PageObjectNumber, view?: ViewEnv): TextItem[];\n /** The id of the annotation currently being text-edited, or null. Read live (not\n * from a stale render) so the editor can tell a real exit from a focus-steal. */\n currentEditing(): Id | null;\n /** Enter text-edit on a free-text annotation (focus its editable element). */\n beginTextEdit(ref: AnnotationRef): void;\n /** Enter text-edit on whatever free-text box is under a content point — wired\n * to a double-click / long-press by the interaction edit handler. Returns\n * whether an editable free-text was actually found and opened; false lets\n * the caller fall through to a normal press (so a long-press on a highlight\n * selects it instead of being swallowed by a no-op edit attempt). */\n beginTextEditAt(\n pon: PageObjectNumber,\n point: Vec,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n /** Apply the editor's plain text — optimistic locally, debounced to the engine. */\n setContents(ref: AnnotationRef, text: string): void;\n /** Apply the editor's rich paragraphs (run deltas over the body) —\n * optimistic locally, debounced to the engine. The commit is plain\n * `contents` while nothing overrides the body on a plain annotation, else\n * `richText`. */\n setRichText(ref: AnnotationRef, doc: { paragraphs: RichTextParagraph[] }): void;\n /** The editor's selection inside the annotation (flat offsets over the\n * plain projection), or null when the editor holds none. While a RANGE is\n * held, `updateSelection`'s font/size/colour/format keys restyle the\n * range's runs instead of the body. */\n setTextSelection(ref: AnnotationRef, range: { start: number; end: number } | null): void;\n /** The CSS family list for a face family a run names (\"Helvetica\" → a web\n * stack, a registered family → its key, mounted by `mountWebFont`). */\n cssFontFamily(family: string): string;\n /** Leave text-edit (flush any pending write). */\n endTextEdit(): void;\n // ── hit-testing & cursor (consumed by the interaction edit handler) ──\n /** What's under a content point — for the edit handler's capture decision.\n * `scale` (the page's view px per content unit) keeps grab zones\n * screen-constant; `rotation` + `zoom` (relative, `transform.zoom`)\n * complete the view env for screen-anchored bodies. Pass all three from\n * the pointer sample. */\n hitKind(\n pon: PageObjectNumber,\n point: Vec,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n /** Widen grab zones to finger-sized targets (pass `pointerType === 'touch'`). */\n touch?: boolean,\n ): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';\n /**\n * TOUCH CONSENT (the interaction hub's `claimsTouch` predicate): should a\n * finger landing here own a TOOL gesture instead of navigating? True over\n * the selection's chrome (resize handles, rotate knob, group box) and over\n * the body of an already-SELECTED, transformable annotation — never over an\n * unselected one, so annotation-dense pages still scroll; tap-select first\n * is the platform convention (Apple Markup). Uses finger-sized grab zones.\n * Pure read.\n */\n claimsTouchAt(\n pon: PageObjectNumber,\n point: Vec,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n /** The cursor to show at a content point (resize over a handle, move/pointer over a body, else null). */\n cursorAt(\n pon: PageObjectNumber,\n point: Vec,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): string | null;\n /**\n * Report the pointer's position for hover state (`null` = off every page).\n * Diffs the topmost hit against the model and dispatches only on CHANGE\n * (enter/leave cadence) — drives scene-level hover affordances like the\n * redaction mark's applied-look preview. Called from the edit handler's\n * onHover, which already samples every move for cursor claims.\n */\n hoverAt(\n at: {\n pon: PageObjectNumber;\n point: Vec;\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n } | null,\n ): void;\n behaviorFor(a: { subtype: Subtype; ref: AnnotationRef | null }): Behavior | null;\n /**\n * The clickable link areas of a page (content space): standalone link\n * annotations plus every ATTACHED-link segment (folded children — their\n * rects derived by the SAME rule the reconciler writes, so the clickable\n * area and the written `/Rect`s can't disagree). Hidden annotations are\n * excluded. THE data feed for the navigation plane (plugin-link);\n * memoized by model identity for selector use.\n */\n linkItemsOn(pon: PageObjectNumber): LinkNavItem[];\n /** Drop selected annotations whose Behavior is currently ENGAGED — inert\n * things cannot stay selected. Call after anything that flips engagement\n * (the plugin wires it to tool changes). */\n pruneEngagedSelection(): void;\n // ── interaction intents (run the pure core + perform engine effects) ──\n editPointer(\n phase: 'down' | 'move' | 'up',\n pon: PageObjectNumber,\n point: Vec,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n /** Finger-sized grab zones for the gesture's own hit resolution — pass the\n * sample's `pointerType === 'touch'` so the gesture grabs exactly what\n * {@link claimsTouchAt} claimed. */\n touch?: boolean,\n ): void;\n marqueePointer(\n phase: 'down' | 'move' | 'up',\n pon: PageObjectNumber,\n point: Vec,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): void;\n /** Run the draw gesture for an authoring TOOL (by id). The plugin resolves it\n * to a routing subtype + defaults preset; a bare subtype also works (headless).\n * `displayRotation` (the DOWN sample's page rotation: /Rotate + view rotation)\n * feeds the tool's `upright` policy — omit it and upright is a no-op. */\n createPointer(\n tool: string,\n phase: 'down' | 'move' | 'up',\n pon: PageObjectNumber,\n point: Vec,\n finish?: boolean,\n displayRotation?: PageRotation,\n ): void;\n /** Commit the strokes currently buffered by an ink tool's grouping window. */\n finishInkDraft(): void;\n /** Create one text-markup annotation on a page from the selected text's\n * per-line oriented quads (content space) — the `text-selection` create\n * gesture. Axis-aligned callers build quads with `textQuadFromRect`. */\n createMarkup(subtype: Subtype, pon: PageObjectNumber, quads: TextQuad[], preset?: string): void;\n /** Create a caret annotation at a text-selection end anchor. */\n createCaret(pon: PageObjectNumber, anchor: TextEndAnchor): void;\n /** Create one Adobe-compatible Caret + StrikeOut replace-text group. */\n createReplaceText(\n pon: PageObjectNumber,\n quads: TextQuad[],\n anchor: TextEndAnchor,\n preset?: string,\n ): void;\n /** Set the live markup preview from the selection's per-page quads (renders a\n * ghost that looks like the markup it will become). */\n previewMarkup(subtype: Subtype, quadsByPage: Record<number, TextQuad[]>, preset?: string): void;\n clearMarkupPreview(): void;\n // ── stamp placement (consumed by the interaction stamp handler) ──\n /** Place the armed stamp centred on a content point. Returns false (no\n * capture) when nothing is armed. `displayRotation` (the click sample's page\n * rotation) feeds the active tool's `upright` policy. */\n placeArmedStamp(pon: PageObjectNumber, point: Vec, displayRotation?: PageRotation): boolean;\n /**\n * The one click-to-place entry for every payload-carrying tool (stamp /\n * note / file attachment) — the place handler forwards each down here.\n * Armed payload first, then the active tool's kind routes; returns whether\n * the click was consumed.\n */\n placeAt(pon: PageObjectNumber, point: Vec, displayRotation?: PageRotation): boolean;\n /** Whether a stamp payload is armed — the hover handler's cheap pre-check. */\n hasArmedStamp(): boolean;\n /**\n * Update the armed tool's FOOTPRINT ghost to a content point — the stamp's\n * fitted image box (same fit + clamp as placement), or a click-create tool's\n * default geometry (same anchor + clamp as the click commit). The ghost IS\n * the placement, never an approximation. Tools without a determinable\n * footprint (or with a `false` ghost policy) clear instead.\n */\n ghostHoverAt(\n toolId: string,\n pon: PageObjectNumber,\n point: Vec,\n displayRotation?: PageRotation,\n ): void;\n /** Drop the hover ghost (pointer left the pages / a gesture started). */\n clearGhost(): void;\n /**\n * Drive the transient placement preview during an EXTERNALLY-owned creation\n * gesture (the form plugin's drag-to-place): the box the commit would use,\n * page-clamped, styled from the TOOL's defaults, painted through the same\n * ghost pipeline as every footprint. Sibling plugins call THIS — never the\n * annotation store directly.\n */\n setPlacementPreview(toolId: string, pon: PageObjectNumber, box: Rect): void;\n /** Drop the placement preview (gesture ended — commit, cancel, or error). */\n clearPlacementPreview(): void;\n // ── ghost projection (consumed by the framework render layer) ──\n /** The armed tool's footprint ghost on a page (content space), or null.\n * Vector ghosts also ride {@link pageItems}; only `kind: 'image'` ghosts\n * need the framework's blit. */\n toolGhost(pon: PageObjectNumber): ToolGhost | null;\n /**\n * The armed stamp's paintable preview at (roughly) `devicePixelWidth`\n * pixels wide — bucketed and cached per bucket for the arm's lifetime —\n * or null when there is no ghost to show. Omit the width for the\n * smallest bucket.\n */\n armedStampPreview(devicePixelWidth?: number): Promise<ArmedStampPreview | null>;\n /** Bumps on arm/disarm — keys the render layer's preview object-URL lifetime. */\n stampArmEpoch(): number;\n /**\n * Resolve the ACTIVE tool's {@link StampSourceSpec} for a click and place a\n * stamp centred on `point`: fixed `bytes` land immediately; a `'prompt'` source\n * asks the installed {@link FilePickerProvider} (placement is dropped if it\n * cancels, or if the tool/document changed while it was open). Returns false\n * (no capture) when the active tool has no source. The click-then-pick\n * counterpart of {@link placeArmedStamp}. `displayRotation` as on\n * {@link placeArmedStamp}.\n */\n requestStampAt(pon: PageObjectNumber, point: Vec, displayRotation?: PageRotation): boolean;\n // ── tool registry (consumed by the plugin init + interaction handlers) ──\n /** Every resolved tool (built-ins + config `tools`), for the registration loop. */\n tools(): ResolvedTool[];\n /** One resolved tool by id, or null when it is not registered. */\n tool(id: string): ResolvedTool | null;\n /** A tool's routing subtype (arrow → `line`) — how the draw handler picks the\n * gesture and the created annotation's PDF kind. Falls back to the id. */\n toolSubtype(id: string): Subtype;\n // ── extension point for sibling plugins (forms, links) ──\n registerBehavior(b: Behavior): () => void;\n\n /**\n * The actions plane's session-visibility write (Hide actions, script\n * `annot.hidden`): resolve annotation OBJECT NUMBERS to loaded model ids\n * (the `obj:` refKey seam) and merge session-hidden overrides. Returns how\n * many resolved — unresolved numbers (unloaded pages, nm/index refs) are\n * the caller's diagnostics. Session state only; never an engine write.\n */\n /** The script/Hide DOCUMENT-commit door (full ISO): engine updates +\n * model reconciliation, per entry, stop-on-failure. Never enqueues,\n * never touches the script host — the D2 sink contract. */\n commitScriptEffects(entries: AnnotCommitEntry[]): Promise<AnnotCommitResult>;\n}\n\n/**\n * The annotation capability token. Typed to the full {@link AnnotationHostCapability}\n * here (the package internals, `/contract/host`, and `/internal` use this view).\n * The package root re-exports the SAME token narrowed to\n * {@link AnnotationCapability}.\n */\nexport const AnnotationToken = createCapabilityToken<AnnotationHostCapability>('annotation', {\n hint: `add annotationPlugin() from '@embedpdf/plugin-annotation' to your plugins list`,\n});\n"],"mappings":";;;;;;AAgqBA,SAAgB,cAAc,kBAA0B,MAAM,MAAc;CAE1E,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAD9B,KAAK,IAAI,KAAK,KAAK,KAAK,gBAAgB,CACJ,CAAC,CAAC,CAAC;AACpD;;;;;;;AA2YA,MAAa,kBAAkB,sBAAgD,cAAc,EAC3F,MAAM,iFACR,CAAC"}
|