@embedpdf/core 3.0.0-next.14 → 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/dist/index.d.ts CHANGED
@@ -1,277 +1,71 @@
1
- import { AbortablePromise, CONTINUOUS_RENDER_POLICY, DocCapability, DocumentEvent, DocumentHandle, DocumentMetadata, Engine, EngineFactory, EngineRenderPolicy, EngineRenderPolicy as EngineRenderPolicy$1, MetadataPatch, MetadataUpdateResult, OpenInput, OpenOptions, PageDeleteResult, PageHandle, PageImageHandle, PageImageObjectUrl, PageImageOptions, PageInsertBlankSpec, PageInsertResult, PageLayout, PageMoveResult, PageObjectNumber, PageRaster, PageRenderOptions, PageRenderTarget, PageRenderViewport, PageRotateResult, PageRotation, PdfDestination, PdfRect, PdfSaveMode, PdfSize, PermissionDenied, snapAppearanceScale, snapFullPageViewport, snapTileScale } from "@embedpdf/engine-core/runtime";
2
- //#region src/types.d.ts
3
- type Unsubscribe = () => void;
4
- /** Every state transition is a plain, serializable action. */
5
- interface Action {
6
- readonly type: string;
1
+ import { $ as PdfSaveMode, $t as isPluginError, A as Identity, At as MirrorReload, B as OperationOptions, Bt as ChangeQueue, C as DocumentsToken, Ct as SerialQueue, D as EventOrigin, Dt as PageMirrorSpec, E as EngineFactory, Et as PageMirrorChange, F as OpenDocumentOptions, Ft as Cancel, G as PageInsertResult, Gt as SettledChange, H as PageDestination, Ht as HoldOptions, I as OpenDocumentResult, It as HostClock, J as PagePosition, Jt as EventHookSource, K as PageLayout, Kt as StagedChange, L as OpenInput, Lt as PluginClock, M as LockedDocumentInfo, Mt as reload, N as MetadataPatch, Nt as SliceChange, O as FailedDocumentInfo, Ot as Mirror, P as MetadataUpdateResult, Pt as SliceLease, Q as PdfRotation, Qt as PluginErrorInfo, R as OpenOptions, Rt as timerClock, S as DocumentsCapability, St as mergeSettings, T as Engine, Tt as PageMirror, U as PageInfo, Ut as PendingChange, V as PageDeleteResult, Vt as HeldChange, W as PageInsertBlankSpec, Wt as PredictedOp, X as PageRotateResult, Xt as PluginError, Y as PageReorderResult, Yt as createEventHook, Z as PdfDestination, Zt as PluginErrorCode, _ as DocumentOpenFailedEvent, _t as Settings, a as CustomMetadata, an as createLatestLane, at as PluginScope, b as DocumentStatus, bt as SettingsDeclaration, c as DocCapability, ct as ResourceStatus, d as DocumentEvent, dt as Subscribable, en as toPluginError, et as PdfSize, f as DocumentHandle, ft as UnlockOptions, g as DocumentMetadata, gt as NoSettings, h as DocumentMeta, ht as DeepPartial, i as CoreState, in as LatestRun, it as PluginDef, j as InitialDocument, jt as MirrorSpec, k as GlobalState, kt as MirrorChange, l as DocumentActiveChangedEvent, lt as StateCell, m as DocumentLockedEvent, mt as UrlSource, n as BatchResult, nn as LatestCancellation, nt as Permission, o as CustomMetadataPatch, ot as PromiseMemberOf, p as DocumentInfo, pt as Unsubscribe, q as PageObjectNumber, qt as EventHook, r as CapabilityToken, rn as LatestLane, rt as PluginContext, s as CustomMetadataUpdateResult, st as PromiseMembers, t as AnyPlugin, tn as toPluginErrorInfo, tt as PendingMeta, u as DocumentClosedEvent, ut as StateChange, v as DocumentOpenedEvent, vt as SettingsApi, w as DownloadOptions, wt as createSerialQueue, x as DocumentUnsavedChangesChangedEvent, xt as SettingsOf, y as DocumentPagesChangedEvent, yt as SettingsChangedEvent, z as OpenSource, zt as ChangeLabel } from "./types-t-DaU8VK.js";
2
+ import { AbortablePromise, AnnotationAppearanceImage, AnnotationRef, CONTINUOUS_RENDER_POLICY, CallFacts, CallPriority, DocumentHandle as DocumentHandle$1, EngineRenderPolicy, Identity as Identity$1, PageHandle, PageImageHandle, PageImageObjectUrl, PageImageOptions, PageLayerRights, PageRaster, PageRef, PageRenderLayers, PageRenderOptions, PageRenderTarget, PageRenderViewport, PdfRect, PermissionDenied, WorkingSetPage, annotationKey, decodePageKey, encodePageKey, isLocalEngine, pageRefsEqual, resolvePageLayers, snapAppearanceScale, snapFullPageViewport, snapTileScale, toPageRef } from "@embedpdf/engine-core/runtime";
3
+ //#region src/viewer-settings.d.ts
4
+ /** How each page looks before its picture arrives, and around it. */
5
+ interface ViewerPageSettings {
6
+ /** The page before its picture arrives. */
7
+ readonly background: string;
8
+ /** The shadow under each page, as CSS `box-shadow`; `'none'` for none. */
9
+ readonly shadow: string;
7
10
  }
8
- /** Kernel-emitted document-lifecycle actions; plugins may react via `onAction`. */
9
- declare const CORE_DOCUMENT_ADDED = "@@core/document-added";
10
- declare const CORE_DOCUMENT_REMOVED = "@@core/document-removed";
11
- declare const CORE_ACTIVE_CHANGED = "@@core/active-changed";
12
- declare const CORE_ORDER_CHANGED = "@@core/order-changed";
13
- /** A document's page registry was replaced by a mutation event (rotate/move/delete). */
14
- declare const CORE_DOCUMENT_PAGES_UPDATED = "@@core/document-pages-updated";
15
- /** A tab slot was reserved: `open()` was called; the document is loading. */
16
- declare const CORE_DOCUMENT_OPENING = "@@core/document-opening";
17
- /** The engine reports the document needs a password (`documents.unlock`). */
18
- declare const CORE_DOCUMENT_LOCKED = "@@core/document-locked";
19
- /** The open failed; the tab stays with `status: 'error'` until closed. */
20
- declare const CORE_DOCUMENT_OPEN_FAILED = "@@core/document-open-failed";
21
- /** A typed handle to a capability — typed resolution, no string casts. */
22
- interface CapabilityToken<T> {
23
- readonly name: string;
11
+ interface ViewerSettings {
24
12
  /**
25
- * Authored remedy shown when a plugin `requires` this capability and no
26
- * plugin provides it — the missing-dependency error should contain its own
27
- * fix (e.g. "add interactionPlugin() from '@embedpdf/plugin-interaction' to
28
- * your plugins list").
13
+ * Who the user is, for every document opened without an `identity` of its own: the author of
14
+ * the annotations they make, and whom `:self` and `:group` permissions are checked against.
15
+ * Null for nobody in particular. The local engine only; the cloud reads it from the token.
29
16
  */
30
- readonly hint?: string;
31
- /** phantom — never present at runtime */
32
- readonly __type?: T;
33
- }
34
- /**
35
- * What the kernel knows about an open document — the page registry captured at open.
36
- * `pages` is the engine's own snapshot (`PageLayout`: index, pageObjectNumber, size,
37
- * rotation, label, boxes). The `pageObjectNumber` (pon) is the durable per-page
38
- * identity; the array index is only display order.
39
- */
40
- interface DocumentMeta {
41
- readonly id: string;
42
- readonly name?: string;
43
- readonly pageCount: number;
44
- readonly pages: readonly PageLayout[];
45
- /**
46
- * Bumps every time the page registry is replaced by a document mutation
47
- * event (rotate/move/delete). The registry's monotonic version: anything
48
- * caching a derivation of `pages` (e.g. the Stage's laid-out scene) keys
49
- * on it so a same-`pageCount` change — like a rotation — still invalidates.
50
- */
51
- readonly revision: number;
17
+ readonly identity: Identity$1 | null;
52
18
  /**
53
- * The deployment render policy the document's engine advertises — a
54
- * document FACT like `pages`, materialized by the kernel at open (before
55
- * publish), NOT plugin state. One lifecycle (here), one interpretation
56
- * (engine-core's pure `snap*` helpers); any plugin reads it. Engines
57
- * without a render service — and failed policy reads — resolve to
58
- * `continuous`, so consumers never branch on absence. Naming rule: the
59
- * domain appears exactly once — bare `policy()` on the render SERVICE,
60
- * `renderPolicy` on flat envelopes like this one and `/v1/access`.
19
+ * What the user may do, as permissions, in every document opened without a `scope` of its
20
+ * own. Null for everything. The local engine only; the cloud reads it from the token.
61
21
  */
62
- readonly renderPolicy: EngineRenderPolicy$1;
63
- }
64
- /**
65
- * A tab slot whose document is not (yet) real: still opening, waiting for a
66
- * password, or failed. Lives beside `documents`, never inside it — plugins
67
- * only ever see READY documents; pending slots are pure registry/UI state.
68
- * Request-time lifecycle: `open()` reserves the slot (id, order position,
69
- * activation) synchronously; only the content arrives at completion time.
70
- */
71
- interface PendingMeta {
72
- readonly id: string;
73
- readonly name?: string;
74
- readonly status: 'loading' | 'locked' | 'error';
75
- /** `locked` only: a password was supplied at open and rejected — the
76
- * prompt should show its "incorrect password" copy, not "required". */
77
- readonly passwordProvided?: boolean;
78
- /** `error` only: what the open rejected with. Never carries a password. */
79
- readonly error?: unknown;
80
- }
81
- /** The document registry — what document scope is built on. */
82
- interface CoreState {
83
- readonly documents: Readonly<Record<string, DocumentMeta>>;
84
- readonly pending: Readonly<Record<string, PendingMeta>>;
85
- /** THE tab strip: spans ready docs and pending slots, in request order. */
86
- readonly order: readonly string[];
87
- /** May point at a pending slot (a loading or locked tab can be selected). */
88
- readonly activeId: string | null;
89
- }
90
- interface GlobalState {
91
- readonly core: CoreState;
92
- readonly plugins: Readonly<Record<string, unknown>>;
93
- }
94
- type PluginScope = 'workspace' | 'document';
95
- /**
96
- * The context a plugin receives. Document-scoped plugins get a context bound to a
97
- * single document — `documentId`, `document()` (metadata), `doc` (the engine handle),
98
- * and `get()` resolving document-scoped capabilities for it.
99
- */
100
- interface PluginContext<S, A extends Action = Action> {
101
- readonly id: string;
102
- readonly engine: Engine;
103
- /** The bound document (document-scoped plugins only; undefined for workspace). */
104
- readonly documentId?: string;
105
- /** The bound document's engine handle; for workspace plugins, the active doc's handle, or null. */
106
- readonly doc: DocumentHandle | null;
107
- /** Resolve a live engine handle by document id; omitted follows this context's normal active/bound rule. */
108
- documentHandle(documentId?: string): DocumentHandle | null;
109
- getState(): S;
110
- dispatch(action: A): void;
111
- subscribe(listener: () => void): Unsubscribe;
112
- core(): CoreState;
113
- /** The bound document's metadata; for workspace plugins, the active doc's, or null. */
114
- document(): DocumentMeta | null;
115
- get<T>(token: CapabilityToken<T>): T;
116
- forDocument<T>(token: CapabilityToken<T>, documentId: string): T;
117
- tryGet<T>(token: CapabilityToken<T>): T | null;
118
- /** `forDocument` for an OPTIONAL dependency: null when the plugin is not
119
- * installed or that document is not ready, never a throw. */
120
- tryForDocument<T>(token: CapabilityToken<T>, documentId: string): T | null;
121
- /**
122
- * Register a resource teardown owned by this plugin instance. Document-
123
- * scoped callbacks run when that document closes; workspace callbacks run
124
- * when the kernel is destroyed. Asynchronous teardowns are awaited.
125
- * Registering after the owner is already disposed runs the teardown
126
- * immediately instead of dropping it — a late registration cannot leak.
127
- * Safe for capability-held timers, runtimes, subscriptions, object URLs,
128
- * and binary caches.
129
- */
130
- cleanup(fn: () => void | Promise<void>): void;
131
- }
132
- /** Side-effect context: the only place async/IO/cross-plugin reactions live. */
133
- interface EffectContext<S, A extends Action = Action> extends PluginContext<S, A> {
134
- watch<R>(select: () => R, handler: (value: R, previous: R) => void, isEqual?: (a: R, b: R) => boolean): Unsubscribe;
135
- onAction(type: string, handler: (action: Action) => void): Unsubscribe;
22
+ readonly scope: readonly string[] | null;
23
+ /** The color every part without a color of its own follows. */
24
+ readonly accent: string;
25
+ readonly page: ViewerPageSettings;
136
26
  }
137
- /**
138
- * A plugin definition. `scope` decides multiplexing:
139
- * 'workspace' (default) — one instance; can see every document.
140
- * 'document' — one instance PER open document; authored single-document.
141
- */
142
- interface PluginDef<S = unknown, A extends Action = Action, C = unknown> {
143
- readonly id: string;
144
- readonly token?: CapabilityToken<C>;
145
- readonly scope?: PluginScope;
146
- readonly requires?: ReadonlyArray<CapabilityToken<unknown>>;
147
- readonly optional?: ReadonlyArray<CapabilityToken<unknown>>;
148
- readonly initialState?: S | (() => S);
149
- readonly reduce?: (state: S, action: A) => S;
150
- readonly capability?: (ctx: PluginContext<S, A>) => C;
151
- readonly init?: (ctx: PluginContext<S, A>) => void | Promise<void>;
152
- readonly effects?: (ctx: EffectContext<S, A>) => void;
153
- }
154
- type AnyPlugin = PluginDef<any, any, any>;
155
- type DocStatus = 'loading' | 'locked' | 'ready' | 'error';
156
- interface DocInfo {
157
- id: string;
158
- name?: string;
159
- /** Lifecycle state — the tab bar renders directly off this. */
160
- status: DocStatus;
161
- /** 0 until the document is `ready`. */
162
- pageCount: number;
163
- /** `locked` only: a supplied password was rejected (show "incorrect"). */
164
- passwordProvided?: boolean;
27
+ /** The viewer's settings when the app gives none; the colors are the theming page's defaults. */
28
+ declare const VIEWER_DEFAULTS: ViewerSettings;
29
+ /** An identity is one person: a new one replaces the last instead of merging into it. */
30
+ declare const VIEWER_WHOLE_SETTINGS: readonly ["identity"];
31
+ /** The viewer settings a framework's viewer takes as its props or config; each one is optional. */
32
+ interface ViewerSettingsInput {
33
+ readonly identity?: Identity$1 | null;
34
+ readonly scope?: readonly string[] | null;
35
+ readonly accent?: string;
36
+ readonly page?: Partial<ViewerPageSettings>;
165
37
  }
166
- /** Field-wise DocInfo equality — the ONE definition every adapter's reactive
167
- * `docs` read keys on, so a new lifecycle field can never silently stop
168
- * re-rendering one framework's tab bar. */
169
- declare const docInfoEquals: (a: DocInfo, b: DocInfo) => boolean;
170
- declare const docInfoListEquals: (a: readonly DocInfo[], b: readonly DocInfo[]) => boolean;
171
- /** Options for opening a document: kernel concerns (activate/name) + engine OpenOptions. */
172
- type OpenDocumentOptions = OpenOptions & {
173
- activate?: boolean;
174
- name?: string;
175
- };
176
- /**
177
- * What `open()` accepts: an engine `OpenInput`, or a thunk producing one.
178
- * The thunk form makes the FETCH happen under the loading tab — the slot is
179
- * reserved synchronously, then the thunk runs (network), then the engine
180
- * opens. Prefer it for anything that isn't already in memory.
181
- *
182
- * The thunk receives an AbortSignal that fires if the tab is closed while
183
- * the fetch is still running — pass it to `fetch()` so a closed tab stops
184
- * the network work. Zero-argument thunks keep working unchanged.
185
- */
186
- type OpenSource = OpenInput | ((signal: AbortSignal) => OpenInput | Promise<OpenInput>);
187
38
  /**
188
- * One boot document for `documents.openAll()` — THE shared shape every
189
- * framework adapter's `initialDocuments` input uses (adapters re-export it,
190
- * never redefine it). `active` picks the selected tab (default: the first);
191
- * all other open options (name, password, scope, identity, …) pass straight
192
- * through to `open()`, so the declarative and imperative paths cannot drift.
39
+ * The viewer's settings as a framework's viewer component gives them: a setting left out is its
40
+ * default, and `page` fills in the side it leaves out. Every adapter's viewer starts the kernel
41
+ * with this and passes it again when its props change.
193
42
  */
194
- type InitialDocument = {
195
- source: OpenSource;
196
- active?: boolean;
197
- } & Omit<OpenDocumentOptions, 'activate'>;
198
- interface DocumentsCapability {
199
- open(input: OpenSource, options?: OpenDocumentOptions): Promise<string>;
200
- /**
201
- * Boot-open a batch: fires every `open()` WITHOUT awaiting, so each tab
202
- * slot is reserved synchronously — all tabs exist immediately, in array
203
- * order — and exactly ONE is selected (the `active` entry, else the
204
- * first), decided at request time so a slow document can never steal
205
- * focus. Failures surface as the tab's `error`/`locked` status, never as
206
- * unhandled rejections. This is kernel-owned POLICY: adapters call this
207
- * one line instead of each re-implementing activation and error handling.
208
- */
209
- openAll(docs: readonly InitialDocument[]): void;
210
- /**
211
- * Unlock a `locked` document with a password and promote it to `ready`.
212
- * Rejects with the engine's DocPasswordIncorrect on a wrong password —
213
- * the document stays locked and unlock can be called again. Identical
214
- * behavior on the local (worker loads the parked bytes) and cloud
215
- * (/access grant) engines.
216
- */
217
- unlock(id: string, input: {
218
- password: string;
219
- }): Promise<void>;
220
- close(id: string): Promise<void>;
221
- closeAll(): Promise<void>;
222
- setActive(id: string): void;
223
- activeId(): string | null;
224
- list(): DocInfo[];
225
- get(id: string): DocInfo | null;
226
- has(id: string): boolean;
227
- count(): number;
228
- order(): string[];
229
- /** Move a document (tab) to a new position in the order. */
230
- move(id: string, toIndex: number): void;
231
- /** Swap two documents (tabs) in the order. */
232
- swap(a: string, b: string): void;
233
- /**
234
- * Save the COMPLETE document (base + layer) to PDF bytes. `mode` is
235
- * `'incremental'` (append changes, original bytes preserved) or `'rewrite'`
236
- * (flatten to a fresh PDF). Defaults to the active document.
237
- */
238
- download(id?: string, opts?: {
239
- mode?: PdfSaveMode;
240
- }): Promise<Uint8Array>;
241
- /**
242
- * Export JUST the document's LAYER artifact (re-openable via `OpenInputLayerBytes`).
243
- * Rejects when the document was opened without a layer, or the engine can't
244
- * export one (cloud manages layers server-side — `DocumentHandle.downloadLayer`
245
- * is absent there). Defaults to the active document.
246
- */
247
- downloadLayer(id?: string): Promise<Uint8Array>;
248
- /**
249
- * Session authority over a document — the sanctioned surface for the ONE
250
- * chrome exception in permissions.md: kernel-level features with a 1:1
251
- * capability and no owning plugin (print via `'doc.print'`, download via
252
- * `'doc.download'` — the verbs live on THIS capability). Everything else
253
- * asks the owning plugin's twins, never a raw capability string. Defaults
254
- * to the active document; `false` with no (ready) document.
255
- */
256
- allows(cap: DocCapability, id?: string): boolean;
257
- }
258
- /** Built-in token for the document registry capability (provided by the kernel). */
259
- declare const DocumentsToken: CapabilityToken<DocumentsCapability>;
43
+ declare function viewerSettingsOf({ identity, scope, accent, page }: ViewerSettingsInput): ViewerSettings;
260
44
  //#endregion
261
45
  //#region src/kernel.d.ts
262
46
  /** Kernel lifecycle. Monotonic: created → starting → started, then destroying →
263
47
  * destroyed; `failed` is a terminal branch off starting. */
264
48
  type KernelStatus = 'created' | 'starting' | 'started' | 'failed' | 'destroying' | 'destroyed';
265
- interface Kernel {
49
+ /**
50
+ * The viewer: the engine, the plugins and the open documents. Its own settings
51
+ * (`getSettings()`, `updateSettings()`, …) are what every document gets unless it says
52
+ * otherwise, and what every plugin's colors fall back to (`viewer-settings.ts`).
53
+ */
54
+ interface Kernel extends SettingsApi<ViewerSettings> {
266
55
  readonly engine: Engine;
267
56
  readonly documents: DocumentsCapability;
268
- /** Resolve a capability. For document-scoped tokens, `documentId` defaults to the active doc. */
57
+ /**
58
+ * Resolve a capability. For document-scoped tokens, `documentId` defaults to the active doc.
59
+ * For a workspace token, a `documentId` gives the capability as seen from that document's
60
+ * scope (`PluginDef.inScope`; the documents capability too): the same object on every call
61
+ * while the document is open.
62
+ */
269
63
  capability<T>(token: CapabilityToken<T>, documentId?: string): T;
270
64
  /**
271
65
  * Total sibling of `capability()`: `null` instead of throwing — no
272
66
  * provider, no document, or a document that isn't `ready` yet. This is the
273
67
  * method adapters subscribe to (`useKernelValue`-style): resolution is a
274
- * VALUE derived from kernel state, not a pure function of its arguments —
68
+ * value derived from kernel state, not a pure function of its arguments —
275
69
  * a pending document's promotion changes the result while the id stays the
276
70
  * same, so caching a `capability()` call by id goes stale. The returned
277
71
  * instance is reference-stable per (plugin, document), so equality-cached
@@ -280,6 +74,13 @@ interface Kernel {
280
74
  tryCapability<T>(token: CapabilityToken<T>, documentId?: string): T | null;
281
75
  /** A token's scope — adapters use this to decide whether to bind a document. */
282
76
  scopeOf(token: CapabilityToken<unknown>): PluginScope;
77
+ /**
78
+ * A plugin's settings calls, with or without a document open: settings belong to the plugin
79
+ * as the app registered it, not to a document. For adapters (a settings hook renders before
80
+ * the first document opens) and for an app that changes them before opening one. Throws
81
+ * when no installed plugin provides `token`, or its plugin declares no settings.
82
+ */
83
+ settingsOf<C>(token: CapabilityToken<C>): SettingsApi<SettingsOf<C>>;
283
84
  subscribe(listener: () => void): Unsubscribe;
284
85
  getState(): GlobalState;
285
86
  status(): KernelStatus;
@@ -296,7 +97,10 @@ interface Kernel {
296
97
  * Assemble a kernel from an engine + plugins.
297
98
  *
298
99
  * planPlugins — validate dependencies, order them
299
- * resolveCapability — workspace singletons, or per-document instances built lazily
100
+ * resolveCapability — workspace singletons (or their view from a document's scope),
101
+ * or per-document instances built lazily
102
+ * settings — one store per plugin registration, built up front, shared
103
+ * by its instances and readable with no document
300
104
  * document lifecycle — one DocumentSession per document: transactional open
301
105
  * (publish-last), one idempotent close for every phase
302
106
  * start / destroy — explicit status machine; destroy closes everything
@@ -304,60 +108,161 @@ interface Kernel {
304
108
  * The kernel closes every handle it opened; it never destroys the engine —
305
109
  * ownership follows acquisition, and the engine was handed in by the caller.
306
110
  */
307
- declare function createKernel(opts: {
111
+ declare function createKernel(config: {
308
112
  engine: Engine;
309
113
  plugins: AnyPlugin[];
310
- /** Observability seam: teardown/effect/join failures land here. Default: console.error. */
114
+ /** The viewer's own settings, over `VIEWER_DEFAULTS`: what `resetSettings()` goes back to. */
115
+ settings?: DeepPartial<ViewerSettings>;
116
+ /** Observability seam: teardown, listener and join failures land here. Default: console.error. */
311
117
  report?: (error: unknown) => void;
118
+ /**
119
+ * The host's time: what plugins' `ctx.clock` schedules on. A browser passes
120
+ * `browserClock()` from `@embedpdf/web`, for frames. Default: `timerClock`,
121
+ * timers and no frames.
122
+ */
123
+ clock?: HostClock;
312
124
  }): Kernel;
313
125
  //#endregion
314
- //#region src/event-hook.d.ts
126
+ //#region src/compose.d.ts
315
127
  /**
316
- * Subscribe-only face of a plugin event — the ONE event shape a capability
317
- * exposes (`onX: EventHook<XEvent>`). Events carry occurrences, never state:
318
- * a late subscriber that needs the current value uses a query + selector
319
- * instead. Payloads are plain serializable objects.
128
+ * `composeApi`: the composition root's one primitive. A controller builds
129
+ * its capability from area slices (each `satisfies Partial<Capability>`)
130
+ * plus the service-owned members (authority twins, event hooks); this spreads
131
+ * them into one object and refuses a key that two slices both define, so a
132
+ * new verb can never silently shadow an old one.
133
+ *
134
+ * const api: FormHostCapability = composeApi('form', [
135
+ * fields.api,
136
+ * values.api,
137
+ * { canFill: () => authority.can('doc.forms.fill'), onValueChanged: events.valueChanged.on },
138
+ * ]);
320
139
  */
321
- type EventHook<T> = (listener: (event: T) => void) => Unsubscribe;
140
+ type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends ((value: infer I) => void) ? I : never;
141
+ declare function composeApi<const T extends readonly object[]>(capability: string, slices: T): UnionToIntersection<T[number]>;
142
+ //#endregion
143
+ //#region src/guarded-handle.d.ts
144
+ /** What the guard needs to know about the instance it protects. */
145
+ interface GuardedLifetime {
146
+ /** Aborted when the instance closes (a document session) or the kernel is destroyed. */
147
+ readonly signal: AbortSignal;
148
+ readonly instanceId: string;
149
+ }
322
150
  /**
323
- * The plugin-private pair behind one capability event. Expose `.on` on the
324
- * capability; keep `emit`/`dispose` inside the plugin. Because the capability
325
- * member is the bare function type, the emitting half is unreachable through
326
- * the public contract by construction.
151
+ * The guarded document handle a controller sees as `ctx.doc`. Every call made
152
+ * through it is:
153
+ *
154
+ * - refused (rejected `instance-closed`) once the instance has closed,
155
+ * - raced against the instance lifetime: a call that is still pending when
156
+ * the instance closes rejects `instance-closed`, its late value is dropped,
157
+ * and an abortable engine call is aborted so worker-side work stops,
158
+ * - mapped through `toPluginError`, so a controller sees one error vocabulary.
159
+ *
160
+ * Nested service objects (`doc.annotations`, `doc.page(ref).render`) are
161
+ * wrapped lazily and cached; synchronous reads (`doc.security.allows`) pass
162
+ * straight through. Methods run with the raw target as `this`, so classes
163
+ * with private fields keep working. The returned promises keep an `abort()`
164
+ * when the engine's promise had one, so caller-side cancellation still works.
327
165
  */
328
- interface EventHookSource<T> {
329
- readonly on: EventHook<T>;
330
- emit(event: T): void;
331
- dispose(): void;
166
+ declare function guardHandle(handle: DocumentHandle$1, lifetime: GuardedLifetime, capability: string): DocumentHandle$1;
167
+ //#endregion
168
+ //#region src/memo.d.ts
169
+ /**
170
+ * Identity-stable reads. A capability read returns the same object until its
171
+ * inputs change, so adapter selectors compare with `Object.is` and re-render
172
+ * only when something really changed. These two helpers are how a plugin
173
+ * builds such reads: name the inputs, and the result is recomputed only when
174
+ * one of them is a different value.
175
+ */
176
+ /** The inputs as `compute` receives them; inferred from `inputs()` only, never from `compute`. */
177
+ type Computed<Inputs extends readonly unknown[]> = { -readonly [K in keyof Inputs]: NoInfer<Inputs[K]>; };
178
+ /**
179
+ * Recompute `compute(...inputs())` only when an input changes (compared with
180
+ * `Object.is`, element by element); otherwise return the previous result.
181
+ */
182
+ declare function memo<const Inputs extends readonly unknown[], Result>(inputs: () => Inputs, compute: (...inputs: Computed<Inputs>) => Result): () => Result;
183
+ /**
184
+ * `memo` per key: each key keeps its own last inputs and result. Keys are
185
+ * compared with `Map` semantics, so use primitives (a page object number, an
186
+ * encoded key), not freshly built objects. `maxEntries` bounds the cache;
187
+ * the oldest key is evicted first.
188
+ */
189
+ declare function memoByKey<Key, const Inputs extends readonly unknown[], Result>(inputs: (key: Key) => Inputs, compute: (key: Key, ...inputs: Computed<Inputs>) => Result, options?: {
190
+ maxEntries?: number;
191
+ }): (key: Key) => Result;
192
+ //#endregion
193
+ //#region src/state.d.ts
194
+ interface StateDeclaration<Capability, State extends object> {
195
+ /** The capability the state is read from; a document plugin's resolves per document. */
196
+ readonly token: CapabilityToken<Capability>;
197
+ /**
198
+ * Read every field through the capability's getters. A getter returns the
199
+ * same value while nothing changed, so adapters compare the result field by
200
+ * field ({@link shallowEqual}) and wake readers only when a field changed.
201
+ */
202
+ readonly read: (capability: Capability) => State;
203
+ /**
204
+ * The state while the capability can't resolve: no document is open, it
205
+ * isn't ready yet, or none is in scope. It has exactly `read`'s fields, so
206
+ * an adapter can list the fields without a capability. Frozen, because every
207
+ * reader shares it.
208
+ */
209
+ readonly empty: State;
210
+ /**
211
+ * Start loading what `read` shows, for state the plugin loads on demand. The adapters call it
212
+ * whenever a hook or service starts reading a document's capability, so it must do nothing
213
+ * once loaded or loading (an `ensureLoaded()` verb); a failure shows in the state (its
214
+ * `status`), so they ignore the promise's rejection. Absent for state that is always loaded.
215
+ */
216
+ readonly ensure?: (capability: Capability) => Promise<void>;
332
217
  }
333
218
  /**
334
- * Create one capability event.
335
- *
336
- * Delivery contract: synchronous fan-out over a snapshot of the listener set
337
- * (listeners added or removed during an emit don't affect that emit); a
338
- * throwing listener is isolated — reported through `onListenerError`, never
339
- * allowed to break the emitting operation or its sibling listeners. After
340
- * `dispose()`, `on` returns an inert unsubscribe (teardown races never throw).
341
- * No value cache, no replay, no equality — state belongs to the store.
219
+ * Declare a plugin's state. The fields come from `read`, and `empty` is checked
220
+ * against them (`NoInfer` keeps it out of the inference): a missing field or a
221
+ * value of the wrong type is a type error. Write `empty` inline, because
222
+ * TypeScript refuses an extra field only in an object literal.
342
223
  */
343
- declare function createEventHook<T = void>(onListenerError?: (error: unknown) => void): EventHookSource<T>;
224
+ declare function defineState<Capability, State extends object>(token: CapabilityToken<Capability>, declaration: {
225
+ readonly read: (capability: Capability) => State;
226
+ readonly empty: NoInfer<State>;
227
+ readonly ensure?: (capability: NoInfer<Capability>) => Promise<void>;
228
+ }): StateDeclaration<Capability, State>;
229
+ /**
230
+ * One level of identity: equal when the two values are the same, or are
231
+ * objects (or arrays) holding the same values under the same keys. Declared
232
+ * state compares this way, and so does a value a selector picks from it.
233
+ */
234
+ declare function shallowEqual(left: unknown, right: unknown): boolean;
344
235
  //#endregion
345
- //#region src/serial-queue.d.ts
236
+ //#region src/documents-state.d.ts
346
237
  /**
347
- * Small promise-tail queue: operations run strictly one at a time, in
348
- * submission order, and failures never poison later operations. The shared
349
- * serializer for per-document mutation/dispatch pipelines.
350
- *
351
- * Direction law for nested queues: an operation running on queue A may
352
- * enqueue into queue B and await it, but never the reverse on the same pair —
353
- * a B-operation enqueueing back into A self-deadlocks behind its caller.
238
+ * The document in scope (the capability resolved for a document, or else the active one): its
239
+ * id, name, status, page count, unsaved changes, and why it's locked or failed.
354
240
  */
355
- declare function createSerialQueue(): <T>(operation: () => Promise<T>) => Promise<T>;
241
+ declare const documentState: StateDeclaration<DocumentsCapability, DocumentInfo>;
242
+ /** Every open document, in tab order, and the active one's id. */
243
+ interface DocumentsState {
244
+ /** Every open document, loading, locked and failed ones included. */
245
+ readonly documents: readonly DocumentInfo[];
246
+ /** The active document's id, or null with none open. */
247
+ readonly activeId: string | null;
248
+ }
249
+ declare const documentsState: StateDeclaration<DocumentsCapability, DocumentsState>;
250
+ //#endregion
251
+ //#region src/capability-handle.d.ts
252
+ /** Whether a capability member named `name` is a read: `get*`, `list*`, `is*`, `has*` or `can*`. */
253
+ declare function isReadMember(name: string): boolean;
254
+ /** Whether the member at `path` (`'setValue'`, `'comments.reply'`) returns a promise, as `token` declares. */
255
+ declare function returnsPromise(token: CapabilityToken<unknown>, path: string): boolean;
256
+ /**
257
+ * What a framework adapter's API reaches for a document plugin while its part of the app has no
258
+ * ready document. One per kernel and token, so it is the same object on every read.
259
+ */
260
+ declare function standInFor<T>(kernel: Kernel, token: CapabilityToken<T>): T;
356
261
  //#endregion
357
262
  //#region src/scope.d.ts
358
263
  /**
359
264
  * A lifecycle operation was cancelled — the tab was closed mid-open, or the
360
- * kernel was destroyed mid-start. NOT a failure: callers that race `open()`
265
+ * kernel was destroyed mid-start. Not a failure: callers that race `open()`
361
266
  * against `close()` should treat this rejection as "the close won".
362
267
  */
363
268
  declare class CancelledError extends Error {
@@ -370,12 +275,27 @@ declare const isCancelled: (error: unknown) => error is CancelledError;
370
275
  * Create a typed capability token. `name` is the token's identity (debugging,
371
276
  * error messages); `options.hint` is the authored remedy the kernel appends to
372
277
  * the missing-dependency error, so the error contains its own fix.
278
+ * `options.promises` lists the members that return a promise, so a framework
279
+ * adapter's stand-in rejects them, rather than throwing, while no document is
280
+ * open; a document plugin whose capability has such members gives it.
373
281
  */
374
282
  declare function createCapabilityToken<T>(name: string, options?: {
375
283
  hint?: string;
284
+ promises?: PromiseMembers<T>;
376
285
  }): CapabilityToken<T>;
377
- /** Identity helper that pins a plugin's generics. The real win is inference. */
378
- declare function definePlugin<S = unknown, A extends Action = Action, C = unknown>(def: PluginDef<S, A, C>): PluginDef<S, A, C>;
286
+ /**
287
+ * The host lens over a plugin's token: the same runtime object, typed with
288
+ * the wider capability sibling plugins use. The one place that cast lives.
289
+ */
290
+ declare function createHostToken<Host>(token: CapabilityToken<unknown>): CapabilityToken<Host>;
291
+ /**
292
+ * Define a plugin. It returns the definition as it is, and reads the types from it, so a
293
+ * plugin passes no type arguments: the capability from `token`, the state from `state`, the
294
+ * settings from `settings.defaults`. `create` receives a `PluginContext<State, Settings>`
295
+ * and must return the capability. A plugin without `state` is stateless (`void`); one
296
+ * without `settings` has `NoSettings`, and `ctx.settings()` throws there.
297
+ */
298
+ declare function definePlugin<State = void, Capability = unknown, Settings extends object = NoSettings>(definition: PluginDef<State, Capability, Settings>): PluginDef<State, Capability, Settings>;
379
299
  //#endregion
380
- export { AbortablePromise, Action, AnyPlugin, CONTINUOUS_RENDER_POLICY, CORE_ACTIVE_CHANGED, CORE_DOCUMENT_ADDED, CORE_DOCUMENT_LOCKED, CORE_DOCUMENT_OPENING, CORE_DOCUMENT_OPEN_FAILED, CORE_DOCUMENT_PAGES_UPDATED, CORE_DOCUMENT_REMOVED, CORE_ORDER_CHANGED, CancelledError, CapabilityToken, CoreState, type DocCapability, DocInfo, DocStatus, type DocumentEvent, type DocumentHandle, DocumentMeta, type DocumentMetadata, DocumentsCapability, DocumentsToken, EffectContext, type Engine, type EngineFactory, type EngineRenderPolicy, EventHook, EventHookSource, GlobalState, InitialDocument, Kernel, KernelStatus, type MetadataPatch, type MetadataUpdateResult, OpenDocumentOptions, type OpenInput, type OpenOptions, OpenSource, type PageDeleteResult, type PageHandle, type PageImageHandle, type PageImageObjectUrl, type PageImageOptions, type PageInsertBlankSpec, type PageInsertResult, type PageLayout, type PageMoveResult, type PageObjectNumber, type PageRaster, type PageRenderOptions, type PageRenderTarget, type PageRenderViewport, type PageRotateResult, type PageRotation, type PdfDestination, type PdfRect, type PdfSaveMode, type PdfSize, PendingMeta, PermissionDenied, PluginContext, PluginDef, PluginScope, Unsubscribe, createCapabilityToken, createEventHook, createKernel, createSerialQueue, definePlugin, docInfoEquals, docInfoListEquals, isCancelled, snapAppearanceScale, snapFullPageViewport, snapTileScale };
300
+ export { AbortablePromise, type AnnotationAppearanceImage, type AnnotationRef, AnyPlugin, BatchResult, CONTINUOUS_RENDER_POLICY, type CallFacts, type CallPriority, type Cancel, CancelledError, CapabilityToken, type ChangeLabel, type ChangeQueue, CoreState, type CustomMetadata, type CustomMetadataPatch, type CustomMetadataUpdateResult, type DeepPartial, type DocCapability, DocumentActiveChangedEvent, DocumentClosedEvent, type DocumentEvent, type DocumentHandle, DocumentInfo, DocumentLockedEvent, DocumentMeta, type DocumentMetadata, DocumentOpenFailedEvent, DocumentOpenedEvent, DocumentPagesChangedEvent, DocumentStatus, DocumentUnsavedChangesChangedEvent, DocumentsCapability, type DocumentsState, DocumentsToken, DownloadOptions, type Engine, type EngineFactory, type EngineRenderPolicy, EventHook, EventHookSource, type EventOrigin, FailedDocumentInfo, GlobalState, type HeldChange, type HoldOptions, type HostClock, type Identity, InitialDocument, Kernel, KernelStatus, type LatestCancellation, type LatestLane, type LatestRun, LockedDocumentInfo, type MetadataPatch, type MetadataUpdateResult, type Mirror, type MirrorChange, type MirrorReload, type MirrorSpec, type NoSettings, OpenDocumentOptions, OpenDocumentResult, type OpenInput, type OpenOptions, OpenSource, OperationOptions, type PageDeleteResult, type PageDestination, type PageHandle, type PageImageHandle, type PageImageObjectUrl, type PageImageOptions, PageInfo, type PageInsertBlankSpec, type PageInsertResult, type PageLayerRights, type PageLayout, type PageMirror, type PageMirrorChange, type PageMirrorSpec, type PageObjectNumber, type PagePosition, type PageRaster, type PageRef, type PageRenderLayers, type PageRenderOptions, type PageRenderTarget, type PageRenderViewport, type PageReorderResult, type PageRotateResult, type PdfDestination, type PdfRect, type PdfRotation, type PdfSaveMode, type PdfSize, type PendingChange, PendingMeta, Permission, PermissionDenied, type PluginClock, PluginContext, PluginDef, PluginError, PluginErrorCode, PluginErrorInfo, PluginScope, type PredictedOp, PromiseMemberOf, PromiseMembers, ResourceStatus, SerialQueue, type Settings, type SettingsApi, type SettingsChangedEvent, type SettingsDeclaration, type SettingsOf, type SettledChange, type SliceChange, type SliceLease, type StagedChange, StateCell, StateChange, type StateDeclaration, Subscribable, UnlockOptions, Unsubscribe, UrlSource, VIEWER_DEFAULTS, VIEWER_WHOLE_SETTINGS, type ViewerPageSettings, type ViewerSettings, type ViewerSettingsInput, type WorkingSetPage, annotationKey, composeApi, createCapabilityToken, createEventHook, createHostToken, createKernel, createLatestLane, createSerialQueue, decodePageKey, definePlugin, defineState, documentState, documentsState, encodePageKey, guardHandle, isCancelled, isLocalEngine, isPluginError, isReadMember, memo, memoByKey, mergeSettings, pageRefsEqual, reload, resolvePageLayers, returnsPromise, shallowEqual, snapAppearanceScale, snapFullPageViewport, snapTileScale, standInFor, timerClock, toPageRef, toPluginError, toPluginErrorInfo, viewerSettingsOf };
381
301
  //# sourceMappingURL=index.d.ts.map