@embedpdf/core 3.0.0-next.14 → 3.0.0-next.16

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.
@@ -0,0 +1,1304 @@
1
+ import { Annotation, Attachment, ChangeOp, ChangeResult, CustomMetadata, CustomMetadataPatch, CustomMetadataUpdateResult, DocCapability, DocumentEvent, DocumentEvent as DocumentEvent$1, DocumentHandle, DocumentHandle as DocumentHandle$1, DocumentMetadata, Engine as Engine$1, EngineFactory, EngineRenderPolicy, EventOrigin, FormFieldDTO, Identity as Identity$1, MetadataPatch, MetadataUpdateResult, OpenInput, OpenOptions, OutlineItem, PageDeleteResult, PageDestination, PageInsertBlankSpec, PageInsertResult, PageLayout as PageLayout$1, PageObjectNumber, PagePosition, PageRef, PageReorderResult, PageRotateResult, PdfDestination, PdfRotation, PdfSaveMode, PdfSize, PrintDpi, WidgetAnnotation } from "@embedpdf/engine-core/runtime";
2
+ //#region src/lanes.d.ts
3
+ /** One execution inside a `latest` lane. */
4
+ /** `details` of the `operation-cancelled` error a superseded or cancelled run rejects with. */
5
+ interface LatestCancellation {
6
+ readonly runId: string;
7
+ /** `'superseded'`, `'cancelled'`, the caller's abort reason, or `'instance-closed'`. */
8
+ readonly reason: string;
9
+ }
10
+ interface LatestRun {
11
+ /** `${lane}#${n}`, unique per run; surfaces in cancellation errors and events. */
12
+ readonly id: string;
13
+ /** Aborts when a newer run starts, the caller's signal aborts, or the instance closes. */
14
+ readonly signal: AbortSignal;
15
+ /** True once a newer run has started. */
16
+ readonly superseded: boolean;
17
+ /** Run `fn` only while this run is still the newest and alive; returns whether it ran. */
18
+ commit(fn: () => void): boolean;
19
+ }
20
+ /**
21
+ * Newest wins. Starting a run aborts the previous one; a superseded run cannot
22
+ * publish (`commit` returns false) and its promise rejects
23
+ * `operation-cancelled`, whatever its engine call later does.
24
+ */
25
+ interface LatestLane {
26
+ readonly running: boolean;
27
+ run<T>(fn: (run: LatestRun) => Promise<T>, options?: OperationOptions): Promise<T>;
28
+ /** Cancel the current run, if any. */
29
+ cancel(reason?: unknown): void;
30
+ }
31
+ declare function createLatestLane(lifetime: AbortSignal, capability: string, name: string): LatestLane;
32
+ //#endregion
33
+ //#region src/errors.d.ts
34
+ /**
35
+ * The one error vocabulary a plugin capability rejects with. Stable codes so
36
+ * callers match on `code`, never on message text; the engine's error stays
37
+ * reachable as `cause`.
38
+ */
39
+ type PluginErrorCode = 'permission-denied' | 'unsupported' | 'not-found' | 'not-ready' | 'invalid-input' | 'conflict' | 'instance-closed' | 'operation-cancelled' | 'operation-failed';
40
+ declare class PluginError extends Error {
41
+ readonly name = "PluginError";
42
+ readonly code: PluginErrorCode;
43
+ /** The capability (plugin id) that produced the error. */
44
+ readonly capability: string;
45
+ /**
46
+ * The permission the session lacks, named as the engine names it: a document capability
47
+ * (`'doc.forms.fill'`) or an annotation action (`'annotations:update'`). Set on
48
+ * `permission-denied` when the refusal names one, whether a plugin's own check refused
49
+ * (`ctx.assertAllowed`) or the engine did; null otherwise.
50
+ */
51
+ readonly permission: string | null;
52
+ readonly details: unknown;
53
+ constructor(code: PluginErrorCode, capability: string, message: string, options?: {
54
+ cause?: unknown;
55
+ details?: unknown;
56
+ permission?: string | null;
57
+ });
58
+ }
59
+ /** The serializable summary of a PluginError, for state and event payloads. */
60
+ interface PluginErrorInfo {
61
+ readonly code: PluginErrorCode;
62
+ readonly message: string;
63
+ readonly capability: string;
64
+ /** The permission the session lacks (see `PluginError.permission`), or null. */
65
+ readonly permission: string | null;
66
+ }
67
+ declare function toPluginErrorInfo(error: PluginError): PluginErrorInfo;
68
+ declare function isPluginError(value: unknown, code?: PluginErrorCode): value is PluginError;
69
+ /**
70
+ * The one boundary mapping from whatever an engine call threw to a
71
+ * `PluginError`. Idempotent: an existing PluginError passes through.
72
+ * Cancellation (the kernel's CancelledError, a DOM AbortError, or an engine
73
+ * abort) is `operation-cancelled`, never `operation-failed`, so callers can
74
+ * tell "nobody wanted this anymore" from "this broke". A refusal names the
75
+ * missing permission in `permission`; `details` keeps the rest of what the
76
+ * engine sent (`anyOf`, `context`).
77
+ */
78
+ declare function toPluginError(capability: string, error: unknown): PluginError;
79
+ //#endregion
80
+ //#region src/event-hook.d.ts
81
+ /**
82
+ * Subscribe-only face of a plugin event — the one event shape a capability
83
+ * exposes (`onX: EventHook<XEvent>`). Events carry occurrences, never state:
84
+ * a late subscriber that needs the current value uses a query + selector
85
+ * instead. Payloads are plain serializable objects.
86
+ */
87
+ type EventHook<T> = (listener: (event: T) => void, options?: {
88
+ signal?: AbortSignal;
89
+ }) => Unsubscribe;
90
+ /**
91
+ * The plugin-private pair behind one capability event. Expose `.on` on the
92
+ * capability; keep `emit`/`dispose` inside the plugin. Because the capability
93
+ * member is the bare function type, the emitting half is unreachable through
94
+ * the public contract by construction.
95
+ */
96
+ interface EventHookSource<T> {
97
+ readonly on: EventHook<T>;
98
+ emit(event: T): void;
99
+ dispose(): void;
100
+ }
101
+ /**
102
+ * Create one capability event.
103
+ *
104
+ * Subscribe with `{ signal }` to tie the subscription to an AbortSignal; a
105
+ * pre-aborted signal never registers.
106
+ *
107
+ * Delivery contract: synchronous fan-out over a snapshot of the listener set
108
+ * (listeners added or removed during an emit don't affect that emit); a
109
+ * throwing listener is isolated — reported through `onListenerError`, never
110
+ * allowed to break the emitting operation or its sibling listeners. After
111
+ * `dispose()`, `on` returns an inert unsubscribe (teardown races never throw).
112
+ * No value cache, no replay, no equality — state belongs to the store.
113
+ */
114
+ declare function createEventHook<T = void>(onListenerError?: (error: unknown) => void): EventHookSource<T>;
115
+ //#endregion
116
+ //#region src/changes.d.ts
117
+ /** What a change is called in history and refusals: an i18n key and its values. */
118
+ interface ChangeLabel {
119
+ readonly key: string;
120
+ readonly [value: string]: string | number;
121
+ }
122
+ /** An op a view can predict: the engine's ops, and the ones only an undo brings back. */
123
+ type PredictedOp = ChangeOp | {
124
+ readonly type: 'annotations.restore';
125
+ readonly annotation: Annotation;
126
+ /** Its place among the page's annotations. */
127
+ readonly index: number;
128
+ } | {
129
+ readonly type: 'forms.restore';
130
+ readonly field: FormFieldDTO;
131
+ /** The rows of its widgets, as they were. */
132
+ readonly widgets: readonly WidgetAnnotation[];
133
+ } | {
134
+ readonly type: 'forms.restoreWidget';
135
+ /** The widget's row, as it was. */
136
+ readonly widget: WidgetAnnotation;
137
+ /** Its field as the restore leaves it, with the widget back; `null` when it had none. */
138
+ readonly field: FormFieldDTO | null;
139
+ } | {
140
+ readonly type: 'outline.restore';
141
+ /** The items as they were: the item first, then the items under it, depth first. */
142
+ readonly items: readonly OutlineItem[];
143
+ /** The item's place among its parent's children. */
144
+ readonly index: number;
145
+ } | {
146
+ readonly type: 'attachments.restore';
147
+ /** The embedded file as it was, under the key it had. */
148
+ readonly attachment: Attachment;
149
+ };
150
+ /** One user action, as a plugin stages it. */
151
+ type StagedChange = {
152
+ readonly label: ChangeLabel;
153
+ /** The engine's ops, sent as they are. */
154
+ readonly ops: readonly ChangeOp[];
155
+ /** What undoing it looks like, as ops the views can predict. Drawing only; never sent. */
156
+ readonly undo?: readonly PredictedOp[];
157
+ /** `false`: not a step of the history, such as a recalculation another session caused. */
158
+ readonly history?: false;
159
+ } | {
160
+ readonly label: ChangeLabel;
161
+ /** Undo the change with this `opId`: the engine applies the reverse it recorded. */
162
+ readonly undoOf: string;
163
+ /** What the views show until the engine answers. */
164
+ readonly shows: readonly PredictedOp[];
165
+ };
166
+ /** A change of this session the engine hasn't answered yet. */
167
+ interface PendingChange {
168
+ /** Its name: what the engine's events carry as `origin.tx.id`, and what `undoOf` names. */
169
+ readonly opId: string;
170
+ readonly label: ChangeLabel;
171
+ /** For an undo: the `opId` of the change it undoes. `null` for a change of ops. */
172
+ readonly undoOf: string | null;
173
+ /**
174
+ * A held change's `merge` key: consecutive changes with the same key are one step of the
175
+ * history (the pauses of one typing session). `null` for every other change.
176
+ */
177
+ readonly merge: string | null;
178
+ /** What the views show until the engine answers: its ops, or an undo's prediction. */
179
+ readonly shows: readonly PredictedOp[];
180
+ /** What undoing it looks like (drawing only); empty when the stager gave none. */
181
+ readonly undo: readonly PredictedOp[];
182
+ /** Whether it is a step of the history. An undo isn't: it moves along the history. */
183
+ readonly history: boolean;
184
+ /** An open hold: shown, not sent yet. */
185
+ readonly held: boolean;
186
+ /** The engine's answer: resolves with what the change did, rejects with why it was refused. */
187
+ readonly result: Promise<ChangeResult>;
188
+ }
189
+ /** A change the engine answered. */
190
+ type SettledChange = {
191
+ readonly change: PendingChange;
192
+ readonly status: 'applied';
193
+ readonly result: ChangeResult;
194
+ } | {
195
+ readonly change: PendingChange;
196
+ readonly status: 'refused';
197
+ readonly error: PluginError;
198
+ };
199
+ /** How a held change is put in the history. */
200
+ interface HoldOptions {
201
+ /** Consecutive changes with the same key are one step of the history: typing into one text box. */
202
+ readonly merge?: string;
203
+ }
204
+ /** A change that can still be amended until it is sent. */
205
+ interface HeldChange {
206
+ /**
207
+ * Whether it can still be amended: false once it was sent (by `send`, by a later stage, or
208
+ * before a download) or cancelled. What comes after goes into a new change.
209
+ */
210
+ readonly open: boolean;
211
+ /** The change it is, once it has ops (its `opId`, its answer); `null` before. */
212
+ readonly change: PendingChange | null;
213
+ /** Its ops from now on, and what undoing them looks like. The views show the latest. */
214
+ set(ops: readonly ChangeOp[], undo?: readonly PredictedOp[]): void;
215
+ /**
216
+ * Send it now, after any hold staged before it. A hold is also sent when another change is
217
+ * staged, and before a download. `null` when nothing was ever set.
218
+ */
219
+ send(): PendingChange | null;
220
+ /** Drop it: the views show the truth again, and nothing is sent. */
221
+ cancel(): void;
222
+ }
223
+ /** The document's change queue, as a plugin uses it (`ctx.changes`). */
224
+ interface ChangeQueue {
225
+ /**
226
+ * Stage one user action. Every mirror's view shows it before this returns, and it is sent
227
+ * after everything staged before it; an open hold is sent first. Inside a group it joins the
228
+ * group's change, and the group's change is what it returns.
229
+ */
230
+ stage(change: StagedChange): PendingChange;
231
+ /**
232
+ * A change that can still be amended until it is sent: typing, or a form commit waiting for
233
+ * its scripts. It keeps its place in the order from its first `set`. Refused inside a group.
234
+ */
235
+ hold(label: ChangeLabel, options?: HoldOptions): HeldChange;
236
+ /** Send every open hold now, in staging order: what an undo does first, as a download does. */
237
+ sendHolds(): void;
238
+ /**
239
+ * Everything staged while `run` runs, by any plugin, becomes one change: one request, one
240
+ * undo step. Only what is staged before `run` returns joins; nested groups join the outer
241
+ * one. When `run` throws, nothing of it is sent.
242
+ */
243
+ group<T>(label: ChangeLabel, run: () => T): T;
244
+ /** A final name for an object this session creates, or `null` when none is held (then `reserve`). */
245
+ takeObjectNumber(): number | null;
246
+ /** Resolves once at least `count` names are held. */
247
+ reserveObjectNumbers(count: number): Promise<void>;
248
+ /** This session's changes the engine hasn't answered, open holds included, in staging order. */
249
+ pending(): readonly PendingChange[];
250
+ hasPending(): boolean;
251
+ /** Resolves once every change sent so far is answered; open holds aren't waited for. Never rejects. */
252
+ whenSettled(): Promise<void>;
253
+ /** A change was staged, or a hold was sent. */
254
+ readonly onStaged: EventHook<PendingChange>;
255
+ /** The engine answered a change, or refused it with one it depended on. */
256
+ readonly onSettled: EventHook<SettledChange>;
257
+ }
258
+ //#endregion
259
+ //#region src/clock.d.ts
260
+ /**
261
+ * Time, as the host keeps it. Plugins never read timers or frames from the
262
+ * environment: they ask their context (`ctx.clock`), and the host that built
263
+ * the kernel says what a timer and a frame are (`createKernel({ clock })`).
264
+ *
265
+ * - A browser host passes `browserClock()` from `@embedpdf/web`: timers, and
266
+ * frames from `requestAnimationFrame`. The framework viewers do this.
267
+ * - Without one, the kernel uses {@link timerClock}: timers only, no frames.
268
+ * Every JavaScript runtime has timers, so a kernel in Node, a worker or a
269
+ * test needs no setup.
270
+ * - Tests that step time pass `manualClock()` from `@embedpdf/core/testing`.
271
+ *
272
+ * What an instance schedules belongs to it ({@link instanceClock}): it is
273
+ * cancelled when the instance closes, and nothing runs after that.
274
+ *
275
+ * This file is the one place in the kernel and the plugins that touches the
276
+ * environment's timers (the lint rule in `eslint.config.js` says so).
277
+ */
278
+ /** Cancels what a clock call scheduled. Does nothing once it ran or was cancelled. */
279
+ type Cancel = () => void;
280
+ /** What a host provides: the kernel's only source of time. */
281
+ interface HostClock {
282
+ /** Milliseconds on a clock that only goes forward. */
283
+ now(): number;
284
+ /** Run `run` once, `ms` milliseconds from now. */
285
+ after(ms: number, run: () => void): Cancel;
286
+ /**
287
+ * Run `run` once, just before the host next paints, with the frame's time
288
+ * on the `now()` clock. Absent on a host that never paints.
289
+ */
290
+ nextFrame?(run: (timeMs: number) => void): Cancel;
291
+ }
292
+ /** A plugin instance's clock: `ctx.clock`. */
293
+ interface PluginClock {
294
+ /** Run `run` once, `ms` milliseconds from now. */
295
+ after(ms: number, run: () => void): Cancel;
296
+ /**
297
+ * Run `run` once, just before the host next paints, with the frame's time in
298
+ * milliseconds. On a host that never paints: as soon as possible.
299
+ */
300
+ nextFrame(run: (timeMs: number) => void): Cancel;
301
+ /** False on a host that never paints (Node, a worker, most tests): animations jump to their end. */
302
+ readonly hasFrames: boolean;
303
+ }
304
+ /** Timers only, no frames: the kernel's default. */
305
+ declare const timerClock: HostClock;
306
+ //#endregion
307
+ //#region src/store.d.ts
308
+ /** One committed change of a slice: the value before and after. */
309
+ interface SliceChange<S> {
310
+ readonly next: S;
311
+ readonly previous: S;
312
+ }
313
+ /**
314
+ * A plugin instance's authority over its state slice. Unique per instance:
315
+ * closing and reopening the same document id yields a new lease, and the old
316
+ * one is revoked synchronously at the start of close, so a callback retained
317
+ * by the old instance can never read or write the new instance's state.
318
+ * Writes return false (and are dropped) once the lease is revoked.
319
+ */
320
+ interface SliceLease<S = unknown> {
321
+ readonly key: string;
322
+ readonly instanceId: string;
323
+ readonly live: boolean;
324
+ read(): S;
325
+ /** Replace the slice's value. Writing the current value is a no-op that returns true. */
326
+ write(next: S): boolean;
327
+ /** Fires after every committed change of this slice, once the store's subscribers ran. */
328
+ readonly onChange: EventHook<SliceChange<S>>;
329
+ revoke(): void;
330
+ }
331
+ //#endregion
332
+ //#region src/mirror.d.ts
333
+ declare const RELOAD: unique symbol;
334
+ /** What `fold` returns when an event is too coarse to apply: reload everything, or some pages. */
335
+ interface MirrorReload {
336
+ readonly [RELOAD]: 'all' | readonly PageRef[];
337
+ }
338
+ /** Ask the mirror to reload instead of applying the event. */
339
+ declare function reload(options?: {
340
+ pages?: readonly PageRef[];
341
+ }): MirrorReload;
342
+ /** One applied change of a mirror, handed to the spec's `changed` callback. */
343
+ interface MirrorChange<V> {
344
+ /** `load` for loads and reloads, `event` for a folded event. */
345
+ readonly cause: 'load' | 'event';
346
+ /** The folded event; null for loads. */
347
+ readonly event: DocumentEvent | null;
348
+ /** For loads: every page (`'all'`) or the pages that were reloaded. Null for events. */
349
+ readonly pages: 'all' | readonly PageRef[] | null;
350
+ readonly previous: V;
351
+ readonly next: V;
352
+ }
353
+ interface MirrorSpec<V> {
354
+ /** Unique within the plugin; names the store cell and appears in errors. */
355
+ readonly name: string;
356
+ /** The value before the first load lands. */
357
+ readonly initial: () => V;
358
+ /** False: status `forbidden` and no engine read. Asked before every load. */
359
+ readonly readable?: () => boolean;
360
+ /**
361
+ * Load only when asked: the mirror stays `idle`, folding confirmed events into its value,
362
+ * until `ensureLoaded()` or `refresh()` runs. For data nothing needs when a document opens.
363
+ * Without it, the first load starts once the plugin is connected.
364
+ */
365
+ readonly onDemand?: true;
366
+ /**
367
+ * Read the whole value. `cursor` is the newest server event the snapshot
368
+ * already contains (cloud engines); omit it when the engine has none.
369
+ */
370
+ load(doc: DocumentHandle, signal: AbortSignal): Promise<{
371
+ value: V;
372
+ cursor?: number | null;
373
+ }>;
374
+ /**
375
+ * Apply one confirmed event. Pure, and the same for every origin. Return
376
+ * `value` itself when the event does not apply, or `reload(...)` when the
377
+ * event does not carry enough to apply.
378
+ */
379
+ fold(value: V, event: DocumentEvent): V | MirrorReload;
380
+ /**
381
+ * Apply one op of a change this session staged and the engine hasn't
382
+ * answered, as the engine will: the same rules, and absolute, so an op the
383
+ * value already holds changes nothing. Pure. Return `value` itself for an op
384
+ * it doesn't concern. Without it, `view()` is `get()`.
385
+ */
386
+ predict?(value: V, op: PredictedOp): V;
387
+ /**
388
+ * Read some pages and return how to merge them into the value. Required
389
+ * when `fold` asks for a page-scoped reload; without it such a request
390
+ * reloads everything.
391
+ */
392
+ loadPages?(doc: DocumentHandle, pages: readonly PageRef[], signal: AbortSignal): Promise<(value: V) => V>;
393
+ /**
394
+ * Runs after every load (even one that changed nothing) and every event
395
+ * that changed the value: the one place a plugin emits the events this
396
+ * data drives.
397
+ */
398
+ readonly changed?: (change: MirrorChange<V>) => void;
399
+ }
400
+ interface Mirror<V> {
401
+ /** What the engine confirmed. */
402
+ get(): V;
403
+ /** What the user sees: `get()` with this session's pending changes on top (`predict`). */
404
+ view(): V;
405
+ /** `idle` until the first load starts; stays `ready` while a reload runs. */
406
+ getStatus(): ResourceStatus;
407
+ /**
408
+ * Load unless it is loaded or loading: a load in flight is shared, and a loaded mirror
409
+ * resolves at once. After a failed load it tries again. Rejects when the load fails.
410
+ */
411
+ ensureLoaded(): Promise<void>;
412
+ /** Reload everything. Joins a running load; rejects when the load fails. */
413
+ refresh(): Promise<void>;
414
+ /**
415
+ * Resolves once no load or page reload is running, including reloads
416
+ * started by events that arrive while it waits. Never rejects.
417
+ */
418
+ settled(): Promise<void>;
419
+ }
420
+ //#endregion
421
+ //#region src/page-mirror.d.ts
422
+ /** One applied change of one page, handed to the spec's `changed` callback. */
423
+ interface PageMirrorChange<V> {
424
+ readonly page: PageRef;
425
+ /** `load` for reads, `event` for a folded event, `drop` when the page was deleted. */
426
+ readonly cause: 'load' | 'event' | 'drop';
427
+ readonly event: DocumentEvent | null;
428
+ readonly previous: V | undefined;
429
+ readonly next: V | undefined;
430
+ }
431
+ interface PageMirrorSpec<V> {
432
+ /** Unique within the plugin; names the store cell and appears in errors. */
433
+ readonly name: string;
434
+ /** Read one page's value. */
435
+ load(doc: DocumentHandle, page: PageRef, signal: AbortSignal): Promise<V>;
436
+ /**
437
+ * Which pages an event makes stale: those pages, every loaded page
438
+ * (`'all'`), or none (`null`). Only pages that are loaded are affected.
439
+ */
440
+ affected(event: DocumentEvent): readonly PageRef[] | 'all' | null;
441
+ /**
442
+ * Apply an event to an affected page's value instead of re-reading it.
443
+ * Return `'reload'` to re-read. Without `fold`, affected pages are re-read.
444
+ */
445
+ fold?(value: V, event: DocumentEvent, page: PageRef): V | 'reload';
446
+ /**
447
+ * Apply one op of a pending change of this session to a loaded page's
448
+ * value, as the engine will. Pure and absolute, like a mirror's `predict`;
449
+ * return `value` itself for an op that doesn't concern the page. Without
450
+ * it, `view(page)` is `get(page)`.
451
+ */
452
+ predict?(value: V, op: PredictedOp, page: PageRef): V;
453
+ /** Runs after every load of a page (even one that changed nothing) and every applied change. */
454
+ readonly changed?: (change: PageMirrorChange<V>) => void;
455
+ }
456
+ interface PageMirror<V> {
457
+ /** The page's value, or undefined when it has not loaded. */
458
+ get(page: PageRef): V | undefined;
459
+ /** What the user sees on the page: `get(page)` with this session's pending changes on top. */
460
+ view(page: PageRef): V | undefined;
461
+ getStatus(page: PageRef): ResourceStatus;
462
+ /** Load the page unless it is loaded or loading. */
463
+ ensureLoaded(page: PageRef, options?: OperationOptions): Promise<void>;
464
+ /** Re-read one page, or every loaded page. */
465
+ refresh(page?: PageRef): Promise<void>;
466
+ }
467
+ //#endregion
468
+ //#region src/serial-queue.d.ts
469
+ /**
470
+ * Small promise-tail queue: operations run strictly one at a time, in
471
+ * submission order, and failures never poison later operations. The shared
472
+ * serializer for per-document mutation/dispatch pipelines.
473
+ *
474
+ * Direction law for nested queues: an operation running on queue A may
475
+ * enqueue into queue B and await it, but never the reverse on the same pair —
476
+ * a B-operation enqueueing back into A self-deadlocks behind its caller.
477
+ */
478
+ interface SerialQueue {
479
+ /**
480
+ * Run `operation` once everything queued before it has finished. With
481
+ * `{ signal }`, an operation whose signal fired while it waited never
482
+ * starts: it rejects `operation-cancelled`. Once it has started, cancelling
483
+ * is up to the operation (`ctx.cancellable`).
484
+ */
485
+ <T>(operation: () => Promise<T>, options?: OperationOptions): Promise<T>;
486
+ /** Resolves once every operation queued so far has finished, however it ended. */
487
+ idle(): Promise<void>;
488
+ }
489
+ /** `capability` names the plugin in the error a skipped operation rejects with. */
490
+ declare function createSerialQueue(capability: string): SerialQueue;
491
+ //#endregion
492
+ //#region src/settings.d.ts
493
+ /** A change to one setting: plain objects go deeper, arrays and functions are given whole. */
494
+ type DeepPartialValue<V> = V extends readonly unknown[] | ((...args: never[]) => unknown) ? V : V extends object ? DeepPartial<V> : V;
495
+ /** Every field optional, down through the plain objects. */
496
+ type DeepPartial<T> = { readonly [K in keyof T]?: DeepPartialValue<T[K]>; };
497
+ declare const noSettings: unique symbol;
498
+ /**
499
+ * The settings of a plugin whose definition declares none. A type of its own rather than `never`:
500
+ * a plugin list mixes plugins with and without settings, and `any` stands in for every type but
501
+ * `never`.
502
+ */
503
+ interface NoSettings {
504
+ readonly [noSettings]: true;
505
+ }
506
+ /** A plugin's settings as its definition declares them: `definePlugin({ settings })`. */
507
+ interface SettingsDeclaration<T> {
508
+ /** Every setting's value when the app registers none. */
509
+ readonly defaults: T;
510
+ /** What the app registered, usually the plugin factory's config: merged over `defaults`. */
511
+ readonly registered?: DeepPartial<T> | undefined;
512
+ /**
513
+ * Top-level settings that are one value each, such as a person: a change replaces them
514
+ * whole instead of merging into them, so nothing of the previous value stays.
515
+ */
516
+ readonly whole?: readonly (keyof T & string)[];
517
+ }
518
+ /** What `onSettingsChanged` carries: the settings after the change, and which of them changed. */
519
+ interface SettingsChangedEvent<T> {
520
+ readonly settings: T;
521
+ /** The top-level settings whose value changed (`['highlight']` when only a highlight color did). */
522
+ readonly changed: readonly (keyof T)[];
523
+ }
524
+ /** The four settings calls, spread into a plugin's capability. */
525
+ interface SettingsApi<T> {
526
+ /** The settings in effect: the same object until a setting changes. */
527
+ getSettings(): T;
528
+ /**
529
+ * Merge `changes` into the settings, for every document: plain objects merge key by key,
530
+ * arrays and other values replace, and `undefined` leaves a setting as it is. Fires
531
+ * `onSettingsChanged` once when a setting changed.
532
+ */
533
+ updateSettings(changes: DeepPartial<T>): void;
534
+ /** Go back to what the app registered (not to the plugin's defaults). Fires `onSettingsChanged` when a setting changed. */
535
+ resetSettings(): void;
536
+ /** Fires once for each call that changed a setting. */
537
+ readonly onSettingsChanged: EventHook<SettingsChangedEvent<T>>;
538
+ }
539
+ /** The settings type of a capability that has the settings calls, else `never`. */
540
+ type SettingsOf<Capability> = Capability extends {
541
+ getSettings(): infer T;
542
+ } ? T : never;
543
+ /** What `ctx.settings()` returns: `get()` for the plugin's own code, `api` for its capability. */
544
+ interface Settings<T> {
545
+ /** The settings in effect. */
546
+ get(): T;
547
+ readonly api: SettingsApi<T>;
548
+ }
549
+ /**
550
+ * `changes` merged into `settings`, the `whole` ones replaced instead: the merge every settings
551
+ * store applies, for code that keeps changes before a store exists (an adapter whose engine is
552
+ * still loading). What a change leaves as it was keeps its object, so a reader that compares by
553
+ * reference sees only what really changed.
554
+ */
555
+ declare function mergeSettings<T>(settings: T, changes: DeepPartial<T> | undefined, whole?: readonly string[]): T;
556
+ //#endregion
557
+ //#region src/types.d.ts
558
+ type Unsubscribe = () => void;
559
+ /** The last parameter of every method that does work: cooperative cancellation. */
560
+ interface OperationOptions {
561
+ readonly signal?: AbortSignal;
562
+ }
563
+ /** Load state of a resource a plugin hydrates from the engine. `forbidden` is a permission refusal, not an empty value. */
564
+ type ResourceStatus = 'idle' | 'loading' | 'ready' | 'forbidden' | 'error';
565
+ /**
566
+ * The outcome of a best-effort batch (`renderPages`, `createMany`, …): what
567
+ * was applied, what was skipped with a reason, and what failed with its
568
+ * error summary. `R` is the input's identity (a `PageRef`, an `AnnotationRef`).
569
+ */
570
+ interface BatchResult<T, R = unknown> {
571
+ readonly applied: readonly T[];
572
+ readonly skipped: readonly {
573
+ readonly ref: R;
574
+ readonly reason: string;
575
+ }[];
576
+ readonly failed: readonly {
577
+ readonly ref: R;
578
+ readonly error: PluginErrorInfo;
579
+ }[];
580
+ }
581
+ /**
582
+ * A permission a verb can need, named as the engine names it: a document
583
+ * capability (`'doc.forms.fill'`), or `'annotations:create'`. Creating is the
584
+ * one annotation action that needs no target: whether the session may change
585
+ * or delete an annotation depends on whose it is, so the annotation plugin
586
+ * asks that per annotation (`doc.security.allowsAnnotation`).
587
+ */
588
+ type Permission = DocCapability | 'annotations:create';
589
+ /** Anything `ctx.listen` can subscribe to: an EventHook, or an object with `subscribe`. */
590
+ type Subscribable<T> = ((listener: (event: T) => void) => Unsubscribe) | {
591
+ subscribe(listener: (event: T) => void): Unsubscribe;
592
+ };
593
+ /**
594
+ * The public name of a page-registry entry: `ref` is the durable identity,
595
+ * `index` the display order, plus label, size, rotation, userUnit and boxes.
596
+ * Structurally the engine's `PageLayout`; named for what it is to a developer.
597
+ */
598
+ type PageInfo = PageLayout$1;
599
+ /** A typed handle to a capability — typed resolution, no string casts. */
600
+ interface CapabilityToken<T> {
601
+ readonly name: string;
602
+ /**
603
+ * Authored remedy shown when a plugin `requires` this capability and no
604
+ * plugin provides it — the missing-dependency error should contain its own
605
+ * fix (e.g. "add interactionPlugin() from '@embedpdf/plugin-interaction' to
606
+ * your plugins list").
607
+ */
608
+ readonly hint?: string;
609
+ /**
610
+ * The members of the capability that return a promise, by path (`setValue`,
611
+ * `comments.reply`). Without a document, a framework adapter's stand-in
612
+ * rejects these with `not-ready`, as the capability would, instead of
613
+ * throwing (see `standInFor`).
614
+ */
615
+ readonly promises?: Readonly<Record<string, true>>;
616
+ /** phantom — never present at runtime */
617
+ readonly __type?: T;
618
+ }
619
+ /** The members of an object that return a promise, by name. */
620
+ type PromiseMethodOf<Owner> = { [Key in keyof Owner & string]-?: Owner[Key] extends ((...args: never[]) => infer Result) ? [Result] extends [PromiseLike<unknown>] ? Key : never : never; }[keyof Owner & string];
621
+ /**
622
+ * The path of every member of `Capability` that returns a promise: its own methods
623
+ * (`'setValue'`) and those of its namespaces (`'comments.reply'`).
624
+ */
625
+ type PromiseMemberOf<Capability> = PromiseMethodOf<Capability> | { [Key in keyof Capability & string]-?: Capability[Key] extends ((...args: never[]) => unknown) ? never : Capability[Key] extends object ? `${Key}.${PromiseMethodOf<Capability[Key]>}` : never; }[keyof Capability & string];
626
+ /**
627
+ * A token's `promises`: one entry for each member of `Capability` that returns a promise. The
628
+ * type asks for every one of them, and only them, so the list can't fall behind the contract.
629
+ */
630
+ type PromiseMembers<Capability> = { readonly [Path in PromiseMemberOf<Capability>]: true; };
631
+ /**
632
+ * What the kernel knows about an open document — the page registry captured at open.
633
+ * `pages` is the engine's own snapshot (`PageLayout`: index, ref, size,
634
+ * rotation, label, boxes). `ref` (the page's `PageRef`) is the durable
635
+ * per-page identity; the array index is only display order.
636
+ */
637
+ interface DocumentMeta {
638
+ readonly id: string;
639
+ /**
640
+ * Unique per open of this id: closing and reopening the same document id
641
+ * yields a new instanceId. Events, refs and leases are checked against it,
642
+ * so nothing produced by a closed instance can be mistaken for the new one.
643
+ */
644
+ readonly instanceId: string;
645
+ readonly name?: string;
646
+ readonly pageCount: number;
647
+ readonly pages: readonly PageLayout$1[];
648
+ /**
649
+ * Bumps every time the page registry is replaced by a document mutation
650
+ * event (rotate/move/delete). The registry's monotonic version: anything
651
+ * caching a derivation of `pages` (e.g. the Stage's laid-out scene) keys
652
+ * on it so a same-`pageCount` change — like a rotation — still invalidates.
653
+ */
654
+ readonly revision: number;
655
+ /**
656
+ * The deployment render policy the document's engine advertises — a
657
+ * document fact like `pages`, materialized by the kernel at open (before
658
+ * publish), not plugin state. One lifecycle (here), one interpretation
659
+ * (engine-core's pure `snap*` helpers); any plugin reads it. Engines
660
+ * without a render service — and failed policy reads — resolve to
661
+ * `continuous`, so consumers never branch on absence. Naming rule: the
662
+ * domain appears exactly once — bare `policy()` on the render service,
663
+ * `renderPolicy` on flat envelopes like this one and `/v1/access`.
664
+ */
665
+ readonly renderPolicy: EngineRenderPolicy;
666
+ /**
667
+ * Whether the document changed since it was opened or last downloaded. Only an engine whose
668
+ * changes live in this tab sets it (the local engine); the cloud engine stores every change
669
+ * as it's made.
670
+ */
671
+ readonly hasUnsavedChanges: boolean;
672
+ }
673
+ /**
674
+ * A tab slot whose document is not (yet) real: still opening, waiting for a
675
+ * password, or failed. Lives beside `documents`, never inside it — plugins
676
+ * only ever see ready documents; pending slots are pure registry/UI state.
677
+ * Request-time lifecycle: `open()` reserves the slot (id, order position,
678
+ * activation) synchronously; only the content arrives at completion time.
679
+ */
680
+ interface PendingMeta {
681
+ readonly id: string;
682
+ readonly name?: string;
683
+ readonly status: 'loading' | 'locked' | 'error';
684
+ /** `locked` only: a password was supplied at open and rejected — the
685
+ * prompt should show its "incorrect password" copy, not "required". */
686
+ readonly passwordProvided?: boolean;
687
+ /** `error` only: what the open rejected with. Never carries a password. */
688
+ readonly error?: unknown;
689
+ }
690
+ /** The document registry — what document scope is built on. */
691
+ interface CoreState {
692
+ readonly documents: Readonly<Record<string, DocumentMeta>>;
693
+ readonly pending: Readonly<Record<string, PendingMeta>>;
694
+ /** The tab strip: spans ready docs and pending slots, in request order. */
695
+ readonly order: readonly string[];
696
+ /** May point at a pending slot (a loading or locked tab can be selected). */
697
+ readonly activeId: string | null;
698
+ }
699
+ interface GlobalState {
700
+ readonly core: CoreState;
701
+ readonly plugins: Readonly<Record<string, unknown>>;
702
+ }
703
+ type PluginScope = 'workspace' | 'document';
704
+ /**
705
+ * The context a plugin's `create()` receives. Document-scoped plugins get a
706
+ * context bound to one document; workspace plugins reach documents through
707
+ * `forDocument`. Everything here is bound to the instance's lifetime, so a
708
+ * controller written as plain async code is lifetime-safe by construction.
709
+ * `S` is the plugin's session state and `T` its settings, `NoSettings` for a
710
+ * plugin that declares none.
711
+ */
712
+ interface PluginContext<S = unknown, T extends object = NoSettings> {
713
+ readonly id: string;
714
+ /** Unique per open of this document (workspace plugins: `workspace:<id>`). */
715
+ readonly instanceId: string;
716
+ /** The bound document (document-scoped plugins only; undefined for workspace). */
717
+ readonly documentId?: string;
718
+ readonly engine: Engine$1;
719
+ /**
720
+ * The guarded document handle: every call rejects `instance-closed` once the
721
+ * instance closed, is aborted at close, and throws `PluginError` instead of
722
+ * raw engine errors. Workspace plugins have no bound document and must use
723
+ * `forDocument()`; reading `doc` there throws.
724
+ */
725
+ readonly doc: DocumentHandle$1;
726
+ /** Resolve a live engine handle by document id; omitted follows this context's normal active/bound rule. */
727
+ documentHandle(documentId?: string): DocumentHandle$1 | null;
728
+ /** The bound document's metadata; for workspace plugins, the active document's, or null. */
729
+ document(): DocumentMeta | null;
730
+ /**
731
+ * The page a `PageRef` or a zero-based index names, or null when it names
732
+ * no page of this document. What reads use: they run while rendering, and a
733
+ * page deleted mid-render reads as no page instead of breaking a layer.
734
+ */
735
+ getPage(page: PageRef | number): PageInfo | null;
736
+ /**
737
+ * A page argument as every verb takes it: a `PageRef`, or a zero-based
738
+ * index into the document's page list. Throws `not-found` when neither
739
+ * names a page of this document: a verb refuses a page that isn't there.
740
+ */
741
+ pageOf(page: PageRef | number): PageInfo;
742
+ /** Throw `not-found` unless the ref names a page of this document. */
743
+ assertPageRef(ref: PageRef): void;
744
+ /**
745
+ * Whether the bound document's session holds `permission`: the same answer
746
+ * the engine enforces with. What every `can<Verb>()` reads.
747
+ * Document-scoped plugins only: a workspace context has no bound document,
748
+ * so this throws as reading `doc` does. A workspace plugin asks the `can<Verb>()` of the
749
+ * document plugin it acts through (`ctx.forDocument(token, documentId)`).
750
+ */
751
+ allows(permission: Permission): boolean;
752
+ /**
753
+ * Refuse a verb the session may not run, before any engine call: throws
754
+ * `permission-denied` ("`operation` requires `permission`") with
755
+ * `error.permission` set. Document-scoped plugins only, like `allows`.
756
+ */
757
+ assertAllowed(permission: Permission, operation: string): void;
758
+ /**
759
+ * Whether the session may fill in (`fill`) or sign (`sign`) this form
760
+ * field: a `fields:<action>` permission for its group, or `doc.forms.fill`
761
+ * (`doc.sign`) for every field. The same answer the engine enforces with.
762
+ * Document-scoped plugins only, like `allows`.
763
+ */
764
+ allowsField(action: 'fill' | 'sign', field: {
765
+ readonly groupId: string | null;
766
+ }): boolean;
767
+ /**
768
+ * Refuse a write to a field the session may not fill in or sign: throws
769
+ * `permission-denied` naming what it would take (`fields:fill:group=buyer`).
770
+ */
771
+ assertAllowedField(action: 'fill' | 'sign', field: {
772
+ readonly groupId: string | null;
773
+ }, operation: string): void;
774
+ get<T>(token: CapabilityToken<T>): T;
775
+ tryGet<T>(token: CapabilityToken<T>): T | null;
776
+ forDocument<T>(token: CapabilityToken<T>, documentId: string): T;
777
+ /** `forDocument` for an optional dependency: null when the plugin is not
778
+ * installed or that document is not ready, never a throw. */
779
+ tryForDocument<T>(token: CapabilityToken<T>, documentId: string): T | null;
780
+ /** This instance's session state, changed only through pure transitions. */
781
+ readonly state: StateCell<S>;
782
+ /**
783
+ * The plugin's settings, as its definition declares them (`definePlugin({ settings })`):
784
+ * what the app registered over the defaults. They belong to the plugin as registered, not to
785
+ * this instance: the kernel builds them when it plans the plugin list, before any document
786
+ * opens, and `updateSettings()` reaches every open document and the ones opened later. Spread
787
+ * `api` into the capability and read `get()` in the controller; the instance's
788
+ * `onSettingsChanged` listeners go when it closes. The merge rules are in `settings.ts`.
789
+ * A plugin whose definition declares no settings has none to read: calling it throws.
790
+ */
791
+ readonly settings: () => Settings<T>;
792
+ /**
793
+ * Wake every reader: something this capability reads outside its state
794
+ * (a registry, a cache, a resource) changed. A no-op once the instance closed.
795
+ */
796
+ notify(): void;
797
+ /**
798
+ * Run `handler` whenever `select()` answers differently. For reacting to
799
+ * state this plugin does not own (the page registry, a sibling's getter);
800
+ * this plugin's own changes are observed with `state.onChange`.
801
+ * Unsubscribed when the instance closes.
802
+ */
803
+ watch<R>(select: () => R, handler: (value: R, previous: R) => void, isEqual?: (left: R, right: R) => boolean): Unsubscribe;
804
+ /** Resolve when the predicate holds (checked on every store change); rejects on cancel or close. */
805
+ waitFor(predicate: () => boolean, options?: OperationOptions): Promise<void>;
806
+ /**
807
+ * A local copy of document data the engine owns, kept current from confirmed
808
+ * document events (every origin) and reloads. Document-scoped plugins only;
809
+ * loading starts once the plugin is connected.
810
+ */
811
+ mirror<V>(spec: MirrorSpec<V>): Mirror<V>;
812
+ /** Like `mirror`, for data loaded page by page on demand. */
813
+ pageMirror<V>(spec: PageMirrorSpec<V>): PageMirror<V>;
814
+ /**
815
+ * The document's change queue, shared by its plugins: a user action is one change, staged
816
+ * here, shown by every mirror's `view()` at once, and sent after everything staged before it.
817
+ * Document-scoped plugins only. The rules are in `docs/conventions/state-and-sync.md`.
818
+ */
819
+ readonly changes: ChangeQueue;
820
+ /** Mint a capability event; disposed with the instance. Expose only `.on`. */
821
+ readonly events: {
822
+ source<T>(): {
823
+ readonly on: EventHook<T>;
824
+ emit(event: T): void;
825
+ dispose(): void;
826
+ };
827
+ };
828
+ /** Subscribe for the instance lifetime; the unsubscribe is owned by the kernel. */
829
+ listen<T>(source: Subscribable<T>, listener: (event: T) => void): void;
830
+ /**
831
+ * Register a resource teardown owned by this plugin instance. Document-
832
+ * scoped callbacks run when that document closes; workspace callbacks run
833
+ * when the kernel is destroyed. Asynchronous teardowns are awaited.
834
+ * Registering after the owner is already disposed runs the teardown
835
+ * immediately instead of dropping it, so a late registration cannot leak.
836
+ */
837
+ cleanup(fn: () => void | Promise<void>): void;
838
+ /**
839
+ * Time, from the host: `after(ms, run)` and `nextFrame(run)`, each returning
840
+ * its cancel, and `hasFrames`. What the instance schedules is cancelled when
841
+ * it closes. Plugins never read timers or frames from the environment.
842
+ */
843
+ readonly clock: PluginClock;
844
+ /**
845
+ * Register what this plugin holds back from the engine, such as text typed a moment ago or
846
+ * the writes in its write queue (`() => queue.idle()`). Before anything reads the whole
847
+ * document (`documents.download()`, `downloadLayer()`), the kernel calls every plugin's `flush` and
848
+ * waits for it: send what's held back, and resolve once the engine has it. Document-scoped
849
+ * plugins only; unregistered when the instance closes. The rules are in
850
+ * `docs/conventions/state-and-sync.md`.
851
+ */
852
+ onSettle(flush: (signal: AbortSignal) => Promise<void> | void): void;
853
+ /**
854
+ * Run something of the document's own around every download of its file
855
+ * (`documents.download()`, `downloadLayer()`): `wrap` gets the read and returns its bytes,
856
+ * doing what comes before and after it. The actions plugin runs the document's save actions
857
+ * this way. The document has settled before `wrap` is called; the first registered wraps the
858
+ * others. Document-scoped plugins only; unregistered when the instance closes.
859
+ */
860
+ aroundDownload(wrap: (read: () => Promise<Uint8Array>) => Promise<Uint8Array>): void;
861
+ /**
862
+ * Run something of the document's own around every print of it (`documents.print()`, a
863
+ * prepared print's `print()`): `wrap` gets the print and resolves when it did, doing what
864
+ * comes before and after it. The actions plugin runs the document's print actions this way.
865
+ * The first registered wraps the others. Document-scoped plugins only; unregistered when the
866
+ * instance closes.
867
+ */
868
+ aroundPrint(wrap: (print: () => Promise<void>) => Promise<void>): void;
869
+ /** Acquire a resource whose disposal the instance owns; a late arrival after close is disposed, not returned. */
870
+ acquire<R>(get: (lifetime: AbortSignal) => Promise<R>, dispose: (resource: R) => void | Promise<void>): Promise<R>;
871
+ /**
872
+ * Run an engine call the caller can cancel: when `signal` fires, the call is
873
+ * aborted (if the engine can abort it) and the returned promise rejects
874
+ * `operation-cancelled` at once. A signal that already fired rejects
875
+ * straight away; without a signal, `task` is returned as it is.
876
+ */
877
+ cancellable<T>(signal: AbortSignal | undefined, task: Promise<T>): Promise<T>;
878
+ /** Newest-wins lane for reads a newer call should cancel (visible search, validation). */
879
+ latest(key: string): LatestLane;
880
+ /**
881
+ * Per-key submission-order queue for multi-step writes; failures do not
882
+ * poison later work. An operation queued with `{ signal }` whose signal
883
+ * fired while it waited is skipped and rejects `operation-cancelled`.
884
+ */
885
+ serialQueue(key?: string): SerialQueue;
886
+ }
887
+ /**
888
+ * A plugin instance's session state. The value is replaced, never mutated:
889
+ * `update` applies a pure transition, and a transition that returns the
890
+ * current value changes nothing.
891
+ */
892
+ interface StateCell<S> {
893
+ get(): S;
894
+ update<Args extends unknown[]>(transition: (state: S, ...args: Args) => S, ...args: Args): void;
895
+ /** Fires synchronously after every committed change of this instance's state. */
896
+ readonly onChange: EventHook<StateChange<S>>;
897
+ }
898
+ /** One committed state change: the value before and after. */
899
+ interface StateChange<S> {
900
+ readonly next: S;
901
+ readonly previous: S;
902
+ }
903
+ /**
904
+ * A plugin definition. `scope` decides multiplexing:
905
+ * 'workspace' (default) — one instance; can see every document.
906
+ * 'document' — one instance per open document; authored single-document.
907
+ *
908
+ * Its types come from its own fields: the state `S` from `state`, the capability
909
+ * `C` from `token`, the settings `T` from `settings.defaults`. `create` and
910
+ * `inScope` are checked against them and never name them (`NoInfer`), so a
911
+ * controller that returns less than the capability is a type error, not a
912
+ * narrower capability.
913
+ */
914
+ interface PluginDef<S = unknown, C = unknown, T extends object = NoSettings> {
915
+ readonly id: string;
916
+ readonly token?: CapabilityToken<C>;
917
+ readonly scope?: PluginScope;
918
+ readonly requires?: ReadonlyArray<CapabilityToken<unknown>>;
919
+ readonly optional?: ReadonlyArray<CapabilityToken<unknown>>;
920
+ /**
921
+ * The plugin resolves capabilities for code the host supplies (the commands
922
+ * plugin runs command definitions that act on any capability), so it cannot
923
+ * declare them. Resolving an undeclared token is then allowed; the kernel
924
+ * neither orders nor validates those dependencies.
925
+ */
926
+ readonly resolvesAnyCapability?: true;
927
+ /** Initial session state, built fresh for every instance. Omit for stateless plugins. */
928
+ readonly state?: () => S;
929
+ /**
930
+ * The plugin's settings: its defaults, and what the app registered (the factory's config).
931
+ * The kernel builds one store per registration from it when it plans the plugin list, so the
932
+ * settings can be read and changed before any document opens (`kernel.settingsOf(token)`).
933
+ * The plugin reads them with `ctx.settings()`. Omit for a plugin without settings.
934
+ */
935
+ readonly settings?: SettingsDeclaration<T>;
936
+ /**
937
+ * Build the instance's API and, optionally, the connections (subscriptions
938
+ * to engine events and sibling capabilities) that start once every
939
+ * dependency is constructed. Runs once per instance.
940
+ */
941
+ readonly create: NoInfer<(ctx: PluginContext<S, T>) => {
942
+ api: C;
943
+ connect?: () => void;
944
+ }>;
945
+ /**
946
+ * This capability as seen from inside a document's scope: calls that leave out the document
947
+ * use `documentId` instead of the active one. Workspace plugins only. The kernel builds the
948
+ * view once per document and hands it out whenever that document is named
949
+ * (`kernel.capability(token, documentId)`, `ctx.forDocument`, a `<DocumentScope>`).
950
+ */
951
+ readonly inScope?: NoInfer<(api: C, documentId: string) => C>;
952
+ }
953
+ type AnyPlugin = PluginDef<any, any, any>;
954
+ /** Where a document is: opening, waiting for its password, open, or failed to open. */
955
+ type DocumentStatus = 'loading' | 'locked' | 'ready' | 'error';
956
+ /**
957
+ * An open document, as its tab shows it. The same object until one of its fields changes, so a
958
+ * reader that compares by reference re-renders only for its own document.
959
+ */
960
+ interface DocumentInfo {
961
+ /** The document's id, for `close(id)`, `unlock(id, …)` and a document scope. */
962
+ readonly id: string;
963
+ /** The name its tab shows, from `open()` or `rename()`. */
964
+ readonly name?: string;
965
+ readonly status: DocumentStatus;
966
+ /** How many pages it has; 0 until it's `ready`. */
967
+ readonly pageCount: number;
968
+ /**
969
+ * Whether it has changes that weren't downloaded yet. Always false on an engine that stores
970
+ * every change as it's made (the cloud engine).
971
+ */
972
+ readonly hasUnsavedChanges: boolean;
973
+ /** `locked` only: a password was tried and was wrong. */
974
+ readonly passwordProvided?: boolean;
975
+ /** `error` only: why it couldn't be opened, in the plugin error vocabulary. */
976
+ readonly error?: PluginErrorInfo;
977
+ }
978
+ /** A document waiting for its password. */
979
+ interface LockedDocumentInfo extends DocumentInfo {
980
+ readonly status: 'locked';
981
+ readonly passwordProvided: boolean;
982
+ }
983
+ /** A document that couldn't be opened, and why. */
984
+ interface FailedDocumentInfo extends DocumentInfo {
985
+ readonly status: 'error';
986
+ readonly error: PluginErrorInfo;
987
+ }
988
+ /** A file the viewer downloads itself, with the document's cancel signal: relative to the page, or absolute. */
989
+ interface UrlSource {
990
+ readonly kind: 'url';
991
+ readonly url: string;
992
+ }
993
+ /** Options for opening a document: the tab (`name`, `activate`), the engine's `OpenOptions`, and a `signal`. */
994
+ type OpenDocumentOptions = OpenOptions & {
995
+ /** Make it the active document; true unless given. */
996
+ readonly activate?: boolean;
997
+ /** The name its tab shows. */
998
+ readonly name?: string;
999
+ /** Cancels the open: the document closes, and `open()` rejects `operation-cancelled`. */
1000
+ readonly signal?: AbortSignal;
1001
+ };
1002
+ /**
1003
+ * What `open()` accepts: an engine `OpenInput`, a URL the viewer downloads, or a function that
1004
+ * returns one of them. A function runs under the document's loading state, so the tab exists
1005
+ * while it fetches; the `signal` it receives fires when the document is closed first, so pass it
1006
+ * to `fetch()`.
1007
+ */
1008
+ type OpenSource = OpenInput | UrlSource | ((signal: AbortSignal) => OpenInput | UrlSource | Promise<OpenInput | UrlSource>);
1009
+ /** What `open()` and `retry()` resolve: the document, ready or locked. */
1010
+ interface OpenDocumentResult {
1011
+ readonly document: DocumentInfo;
1012
+ }
1013
+ /** Options for `unlock()`: the password, and a `signal` that stops trying it. */
1014
+ interface UnlockOptions extends OperationOptions {
1015
+ readonly password: string;
1016
+ }
1017
+ /** Options for `download()`. */
1018
+ interface DownloadOptions extends OperationOptions {
1019
+ /**
1020
+ * `'incremental'` (the default) appends the changes to the original file, so existing
1021
+ * signatures stay valid; `'rewrite'` writes a fresh file without earlier revisions.
1022
+ */
1023
+ readonly mode?: PdfSaveMode;
1024
+ }
1025
+ /**
1026
+ * How a print comes out.
1027
+ *
1028
+ * - `'pdf'`: the printer prints a copy of the pages as they print (`pages.extract()` with
1029
+ * `flatten: { usage: 'print' }`): sharp text and lines. It takes `doc.print.high`, a right to
1030
+ * keep the copy (`doc.download` or `doc.download.flattened`: every print dialog can save it as
1031
+ * a file), and a printer that prints a PDF (`HostPrinter.stagePdf`).
1032
+ * - `'images'` otherwise: pictures of the pages, drawn by the print rules, at 150 DPI with
1033
+ * `doc.print` or 300 DPI with `doc.print.high` (Acrobat's low and high resolution printing).
1034
+ */
1035
+ type PrintQuality = {
1036
+ readonly kind: 'pdf';
1037
+ } | {
1038
+ readonly kind: 'images';
1039
+ readonly dpi: PrintDpi;
1040
+ };
1041
+ /** How far preparing a print got. */
1042
+ interface PrintProgress {
1043
+ /** Pages that are ready: one at a time as pictures, all at once as a PDF. */
1044
+ readonly pagesRendered: number;
1045
+ /** Pages the print has. */
1046
+ readonly pageCount: number;
1047
+ }
1048
+ interface PrintOptions extends OperationOptions {
1049
+ /** The pages to print, in this order. Default: every page. */
1050
+ readonly pages?: readonly PageRef[];
1051
+ /**
1052
+ * Print the annotations that print. Default: when the user may read them. Form fields print
1053
+ * when the user may read the form, whatever this says.
1054
+ */
1055
+ readonly includeAnnotations?: boolean;
1056
+ /** Called each time pages are ready, and once before the first. */
1057
+ readonly onProgress?: (progress: PrintProgress) => void;
1058
+ }
1059
+ /**
1060
+ * A print got ready by `documents.preparePrint()`. Everything slow already happened, so
1061
+ * `print()` opens the print dialog at once.
1062
+ */
1063
+ interface PreparedPrint {
1064
+ readonly quality: PrintQuality;
1065
+ /** How many pages it prints. */
1066
+ readonly pageCount: number;
1067
+ /**
1068
+ * Whether `print()` must run inside the user's tap or click: the printer's `needsTap`. Safari
1069
+ * doesn't print what waited for its pages (iOS refuses the dialog, the Mac prints blank pages),
1070
+ * so a dialog that prepared on a tap asks for another once the print is ready. When `false`,
1071
+ * print as soon as it is ready.
1072
+ */
1073
+ readonly needsTap: boolean;
1074
+ /**
1075
+ * Open the print dialog. The document's own print actions run around it, when the actions
1076
+ * plugin is installed; when they, or anyone, change the document after it was prepared, it is
1077
+ * prepared again first. Resolves when the printer has the job. When the printer refuses a
1078
+ * PDF, the same pages print as pictures. Rejects `invalid-input` once disposed,
1079
+ * `operation-cancelled` when `signal` fires before the dialog opens.
1080
+ */
1081
+ print(options?: OperationOptions): Promise<void>;
1082
+ /** Free what preparing took. Closing the document does too. */
1083
+ dispose(): void;
1084
+ }
1085
+ /** One printed sheet: a picture of a page, and the page's size on paper. */
1086
+ interface PrintSheet {
1087
+ /** A PNG of the page, drawn by the print rules. */
1088
+ readonly image: Blob;
1089
+ /** The page's width in points (1/72 inch), as it prints. */
1090
+ readonly widthPt: number;
1091
+ /** The page's height in points. */
1092
+ readonly heightPt: number;
1093
+ }
1094
+ /** What a printer got ready: `print()` opens the print dialog with it. */
1095
+ interface StagedPrint {
1096
+ /** Open the print dialog. Resolves once the printer has the job. */
1097
+ print(): Promise<void>;
1098
+ /** Free what staging took. */
1099
+ dispose(): void;
1100
+ }
1101
+ /**
1102
+ * Where prints go: the host's print dialog. A browser passes `browserPrinter()` from
1103
+ * `@embedpdf/web`; an app with its own print path (a desktop shell, a native app) passes its
1104
+ * own.
1105
+ */
1106
+ interface HostPrinter {
1107
+ /**
1108
+ * `true` when this printer prints only while the user's tap or click is being handled (Safari),
1109
+ * so a print that waited for its pages needs another tap. Default `false`.
1110
+ */
1111
+ readonly needsTap?: boolean;
1112
+ /**
1113
+ * Get the sheets ready to print, so `print()` on what it returns opens the dialog at once.
1114
+ * `name` names the print job. Rejects when `signal` fires.
1115
+ */
1116
+ stage(sheets: readonly PrintSheet[], options: {
1117
+ readonly name: string;
1118
+ readonly signal?: AbortSignal;
1119
+ }): Promise<StagedPrint>;
1120
+ /**
1121
+ * Present when this printer prints a PDF file on this device: a browser whose own PDF viewer
1122
+ * prints it, a desktop shell, a native print API. Gets `pdf`, a copy of the pages as they
1123
+ * print, ready as `stage()` gets sheets ready. A printer without it prints pictures.
1124
+ */
1125
+ stagePdf?(pdf: Uint8Array, options: {
1126
+ readonly name: string;
1127
+ readonly signal?: AbortSignal;
1128
+ }): Promise<StagedPrint>;
1129
+ }
1130
+ /**
1131
+ * One boot document for `documents.openAll()` — the shared shape every
1132
+ * framework adapter's `initialDocuments` input uses (adapters re-export it,
1133
+ * never redefine it). `active` picks the selected tab (default: the first);
1134
+ * all other open options (name, password, scope, identity, …) pass straight
1135
+ * through to `open()`, so the declarative and imperative paths cannot drift.
1136
+ */
1137
+ type InitialDocument = {
1138
+ source: OpenSource;
1139
+ active?: boolean;
1140
+ } & Omit<OpenDocumentOptions, 'activate' | 'signal'>;
1141
+ interface DocumentOpenedEvent {
1142
+ readonly documentId: string;
1143
+ readonly info: DocumentInfo;
1144
+ }
1145
+ interface DocumentOpenFailedEvent {
1146
+ readonly documentId: string;
1147
+ readonly error: PluginErrorInfo;
1148
+ }
1149
+ interface DocumentLockedEvent {
1150
+ readonly documentId: string;
1151
+ readonly passwordProvided: boolean;
1152
+ }
1153
+ interface DocumentClosedEvent {
1154
+ readonly documentId: string;
1155
+ }
1156
+ interface DocumentActiveChangedEvent {
1157
+ readonly documentId: string | null;
1158
+ readonly previousDocumentId: string | null;
1159
+ }
1160
+ interface DocumentPagesChangedEvent {
1161
+ readonly documentId: string;
1162
+ readonly revision: number;
1163
+ readonly pages: readonly PageInfo[];
1164
+ }
1165
+ interface DocumentUnsavedChangesChangedEvent {
1166
+ readonly documentId: string;
1167
+ readonly hasUnsavedChanges: boolean;
1168
+ }
1169
+ /**
1170
+ * The document registry. A call that leaves out the document uses the document in scope when
1171
+ * the capability was resolved for one (`kernel.capability(DocumentsToken, documentId)`, a
1172
+ * `<DocumentScope>`), and the active document otherwise. Its verbs reject with `PluginError`.
1173
+ */
1174
+ interface DocumentsCapability {
1175
+ /**
1176
+ * Open a document and make it the active one (unless `activate: false`). Its tab exists at
1177
+ * once; the promise resolves `{ document }` once it's ready, or locked with a password.
1178
+ * The document's own `scope` and `identity` replace the viewer's. Rejects with the reason it
1179
+ * couldn't be opened (the tab then shows `error`), or `operation-cancelled` when it was closed
1180
+ * or `signal` fired first.
1181
+ */
1182
+ open(source: OpenSource, options?: OpenDocumentOptions): Promise<OpenDocumentResult>;
1183
+ /**
1184
+ * Whether `open()` can open a file from the user's computer (its bytes, or a URL the viewer
1185
+ * downloads): the engine's `canOpenFiles`. True with the local engine; false with the cloud
1186
+ * engine, whose documents come from your server.
1187
+ */
1188
+ canOpenFiles(): boolean;
1189
+ /**
1190
+ * Open a failed document (`status: 'error'`) again, with the same source and options, in its
1191
+ * own tab: it keeps its id and its place, and the active document stays the active one.
1192
+ * Resolves like `open()`. Rejects `invalid-input` for a document that didn't fail.
1193
+ */
1194
+ retry(id: string, options?: OperationOptions): Promise<OpenDocumentResult>;
1195
+ /** Change the name its tab shows; the file doesn't change. */
1196
+ rename(id: string, name: string): void;
1197
+ /**
1198
+ * Open several documents, as `initialDocuments` does: every tab appears at once, in array
1199
+ * order, and the one marked `active` (else the first) becomes the active one, decided now, so
1200
+ * a slow document never steals the focus. A failure shows in that document's `status`
1201
+ * instead of rejecting. Returns the tabs' ids.
1202
+ */
1203
+ openAll(documents: readonly InitialDocument[]): readonly string[];
1204
+ /**
1205
+ * Unlock a `locked` document with its password; it opens as it would have. Rejects
1206
+ * `permission-denied` on a wrong password, and the document stays locked so you can ask
1207
+ * again; `invalid-input` for a document that isn't locked.
1208
+ */
1209
+ unlock(id: string, options: UnlockOptions): Promise<void>;
1210
+ /** Close a document and free its memory; the next one becomes active. Closing one still opening cancels it. */
1211
+ close(id: string): Promise<void>;
1212
+ /** Close every document. */
1213
+ closeAll(): Promise<void>;
1214
+ /** Make a document the active one: the one every component talks to outside a document scope. */
1215
+ setActive(id: string): void;
1216
+ /** The active document's id, or null with none open. */
1217
+ getActiveId(): string | null;
1218
+ /** The active document's fields, or null with none open. */
1219
+ getActive(): DocumentInfo | null;
1220
+ /** Every open document in tab order, loading, locked and failed ones included; the same array until one changes. */
1221
+ list(): readonly DocumentInfo[];
1222
+ /** A document's fields (the one in scope without an id), or null when it isn't open. */
1223
+ get(id?: string): DocumentInfo | null;
1224
+ /** Whether a document is open. */
1225
+ has(id: string): boolean;
1226
+ /** How many documents are open. */
1227
+ getCount(): number;
1228
+ /** The open documents' ids, in tab order. */
1229
+ getOrder(): readonly string[];
1230
+ /** Put every document in a new order at once; `ids` holds the id of every open document. */
1231
+ setOrder(ids: readonly string[]): void;
1232
+ /** Move a document to another place in the tab order. */
1233
+ move(id: string, toIndex: number): void;
1234
+ /** Swap two documents in the tab order. */
1235
+ swap(id: string, otherId: string): void;
1236
+ /**
1237
+ * The PDF with every change, as bytes. It first waits for changes still on their way (text
1238
+ * typed a moment ago, writes queued), and runs the document's own save actions around the
1239
+ * read when the actions plugin is installed. Afterwards `hasUnsavedChanges` is false, unless
1240
+ * something changed meanwhile. Rejects `permission-denied` without `doc.download`,
1241
+ * `not-ready` with no open document, `operation-cancelled` when `signal` fires.
1242
+ */
1243
+ download(id?: string, options?: DownloadOptions): Promise<Uint8Array>;
1244
+ /**
1245
+ * Only the changes, as a layer artifact you open again over the original
1246
+ * (`{ kind: 'layerBytes', baseBytes, layer: { kind: 'artifact', bytes } }`). Waits and runs the
1247
+ * save actions like `download()`. Rejects `unsupported` when the document wasn't opened with a
1248
+ * layer or the engine keeps layers itself (the cloud engine), and as `download()` does.
1249
+ */
1250
+ downloadLayer(id?: string, options?: OperationOptions): Promise<Uint8Array>;
1251
+ /** Whether the document (the one in scope without an id) may be downloaded: `doc.download`. */
1252
+ canDownload(id?: string): boolean;
1253
+ /**
1254
+ * Get a print of the document ready (the one in scope without an id): wait for changes still
1255
+ * on their way, make the pages as they print (a PDF copy or pictures, as `getPrintQuality()`
1256
+ * says), and hand them to the host's printer. `onProgress` follows the pages. Rejects
1257
+ * `permission-denied` without `doc.print`, `unsupported` when the host gave no printer,
1258
+ * `not-found` for a page the document doesn't have, `invalid-input` for an empty `pages` or a
1259
+ * page named twice, `not-ready` with no open document, `operation-cancelled` when `signal`
1260
+ * fires.
1261
+ */
1262
+ preparePrint(id?: string, options?: PrintOptions): Promise<PreparedPrint>;
1263
+ /**
1264
+ * Prepare a print and print it: `preparePrint()`, then its `print()`. The document's own
1265
+ * print actions run around the dialog when the actions plugin is installed. Rejects as
1266
+ * `preparePrint()` does. A printer that `needsTap` may refuse the dialog once preparing took a
1267
+ * while: there, prepare first and print from a tap.
1268
+ */
1269
+ print(id?: string, options?: PrintOptions): Promise<void>;
1270
+ /** How a print of the document comes out for this user, or null when they can't print it. */
1271
+ getPrintQuality(id?: string): PrintQuality | null;
1272
+ /** Whether the document (the one in scope without an id) may be printed: `doc.print`, and the host gave a printer. */
1273
+ canPrint(id?: string): boolean;
1274
+ /**
1275
+ * The document's pages, in order (the one in scope without an id). The same array until a
1276
+ * page is added, removed, moved or rotated.
1277
+ */
1278
+ listPages(id?: string): readonly PageInfo[];
1279
+ /** One page, by its `PageRef` or its zero-based index, or null when the document doesn't have it. */
1280
+ getPage(page: PageRef | number, id?: string): PageInfo | null;
1281
+ /** A page's position, from 0, or `-1` when the document doesn't have it. */
1282
+ getPageIndex(ref: PageRef, id?: string): number;
1283
+ /** A number that goes up each time pages are added, removed, moved or rotated; `-1` with no document. */
1284
+ getRevision(id?: string): number;
1285
+ /** A document is open and ready. */
1286
+ readonly onOpened: EventHook<DocumentOpenedEvent>;
1287
+ /** A document couldn't be opened; its tab shows `error`. */
1288
+ readonly onOpenFailed: EventHook<DocumentOpenFailedEvent>;
1289
+ /** A document needs its password. */
1290
+ readonly onLocked: EventHook<DocumentLockedEvent>;
1291
+ /** A document was closed, after its resources were released. */
1292
+ readonly onClosed: EventHook<DocumentClosedEvent>;
1293
+ /** Another document became the active one. */
1294
+ readonly onActiveChanged: EventHook<DocumentActiveChangedEvent>;
1295
+ /** Pages were added, removed, moved or rotated. */
1296
+ readonly onPagesChanged: EventHook<DocumentPagesChangedEvent>;
1297
+ /** A document got its first unsaved change, or was downloaded. */
1298
+ readonly onUnsavedChangesChanged: EventHook<DocumentUnsavedChangesChangedEvent>;
1299
+ }
1300
+ /** Built-in token for the document registry capability (provided by the kernel). */
1301
+ declare const DocumentsToken: CapabilityToken<DocumentsCapability>;
1302
+ //#endregion
1303
+ export { PdfRotation as $, StagedChange as $t, HostPrinter as A, SerialQueue as At, OpenSource as B, SliceChange as Bt, DocumentsToken as C, NoSettings as Ct, EventOrigin as D, SettingsDeclaration as Dt, EngineFactory as E, SettingsChangedEvent as Et, MetadataUpdateResult as F, Mirror as Ft, PageInsertBlankSpec as G, timerClock as Gt, PageDeleteResult as H, Cancel as Ht, OpenDocumentOptions as I, MirrorChange as It, PageObjectNumber as J, HeldChange as Jt, PageInsertResult as K, ChangeLabel as Kt, OpenDocumentResult as L, MirrorReload as Lt, InitialDocument as M, PageMirror as Mt, LockedDocumentInfo as N, PageMirrorChange as Nt, FailedDocumentInfo as O, SettingsOf as Ot, MetadataPatch as P, PageMirrorSpec as Pt, PdfDestination as Q, SettledChange as Qt, OpenInput as R, MirrorSpec as Rt, DocumentsCapability as S, DeepPartial as St, Engine$1 as T, SettingsApi as Tt, PageDestination as U, HostClock as Ut, OperationOptions as V, SliceLease as Vt, PageInfo as W, PluginClock as Wt, PageReorderResult as X, PendingChange as Xt, PagePosition as Y, HoldOptions as Yt, PageRotateResult as Z, PredictedOp as Zt, DocumentOpenFailedEvent as _, StateChange as _t, CustomMetadata as a, PluginErrorInfo as an, PluginDef as at, DocumentStatus as b, Unsubscribe as bt, DocCapability as c, toPluginErrorInfo as cn, PrintOptions as ct, DocumentEvent$1 as d, LatestRun as dn, PrintSheet as dt, EventHook as en, PdfSaveMode as et, DocumentHandle$1 as f, createLatestLane as fn, PromiseMemberOf as ft, DocumentMetadata as g, StateCell as gt, DocumentMeta as h, StagedPrint as ht, CoreState as i, PluginErrorCode as in, PluginContext as it, Identity$1 as j, createSerialQueue as jt, GlobalState as k, mergeSettings as kt, DocumentActiveChangedEvent as l, LatestCancellation as ln, PrintProgress as lt, DocumentLockedEvent as m, ResourceStatus as mt, BatchResult as n, createEventHook as nn, PendingMeta as nt, CustomMetadataPatch as o, isPluginError as on, PluginScope as ot, DocumentInfo as p, PromiseMembers as pt, PageLayout$1 as q, ChangeQueue as qt, CapabilityToken as r, PluginError as rn, Permission as rt, CustomMetadataUpdateResult as s, toPluginError as sn, PreparedPrint as st, AnyPlugin as t, EventHookSource as tn, PdfSize as tt, DocumentClosedEvent as u, LatestLane as un, PrintQuality as ut, DocumentOpenedEvent as v, Subscribable as vt, DownloadOptions as w, Settings as wt, DocumentUnsavedChangesChangedEvent as x, UrlSource as xt, DocumentPagesChangedEvent as y, UnlockOptions as yt, OpenOptions as z, reload as zt };
1304
+ //# sourceMappingURL=types-CfnZ7go6.d.cts.map