@cloudpdf/engine 3.0.0-next.13 → 3.0.0-next.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,9 +1,13 @@
1
- import { AbortError, AbortablePromise, AbortablePromise as AbortablePromise$1, AnnotationAppearanceImageOptions, AnnotationAppearanceImagesResult, AnnotationAppearanceRenderOptions, AnnotationAppearancesResult, AnnotationCreateResult, AnnotationDeleteResult, AnnotationDraft, AnnotationFlattenResult, AnnotationListPageSnapshot, AnnotationListSnapshotAllPages, AnnotationMoveResult, AnnotationPatch, AnnotationRef, AnnotationUpdateResult, AttachmentContent, AttachmentsCache, DocumentAccessInfo, DocumentActionsService, DocumentAnnotationsService, DocumentAnnotationsService as DocumentAnnotationsService$1, DocumentAttachmentsService, DocumentCapabilities, DocumentEventStream, DocumentFormsService, DocumentHandle, DocumentHandle as DocumentHandle$1, DocumentIdentity, DocumentMetadata, DocumentPagesService, DocumentPagesService as DocumentPagesService$1, DocumentRedactionService, DocumentRenderService, DocumentSearchService, DocumentSecurityService, DocumentSecurityService as DocumentSecurityService$1, DocumentSecurityState, DocumentSignaturesService, DocumentUnlockInput, DocumentUnlockResult, Engine, Engine as Engine$1, EngineError, EngineError as EngineError$1, EngineErrorCode, EngineFactory, MetadataCache, MetadataPatch, MetadataService, MetadataService as MetadataService$1, MetadataUpdateResult, MutationMeta, OpenInput, OpenInput as OpenInput$1, OpenInputShare, OpenOptions, OpenOptions as OpenOptions$1, PageAnnotationsService, PageAnnotationsService as PageAnnotationsService$1, PageDeleteResult, PageFlattenResult, PageFlattenUsage, PageGeometryService, PageGeometryService as PageGeometryService$1, PageGeometrySnapshot, PageHandle, PageHandle as PageHandle$1, PageImageHandle, PageImageOptions, PageInsertBlankSpec, PageInsertResult, PageListSnapshot, PageMoveResult, PageNameInput, PageNameResult, PageObjectNumber, PageRaster, PageRemoveNameInput, PageRenderOptions, PageRenderService, PageRenderService as PageRenderService$1, PageRotateResult, PageRotation, PageStructureCache, PageTextService, PageTextService as PageTextService$1, PageTextSnapshot, PdfSaveMode, PdfSaveMode as PdfSaveMode$1, SearchRequest, SearchSlice, TokenSource, WeakAnnotationEditSession } from "@embedpdf/engine-core/runtime";
1
+ import { AbortablePromise, AnnotationAppearanceImageOptions, AnnotationAppearanceImagesResult, AnnotationBundle, AnnotationCreateOptions, AnnotationCreateResult, AnnotationDeleteResult, AnnotationDraft, AnnotationExportSelection, AnnotationFlattenResult, AnnotationImportOptions, AnnotationImportResult, AnnotationList, AnnotationListOptions, AnnotationPatch, AnnotationPosition, AnnotationRef, AnnotationReorderResult, AnnotationResourceRole, AnnotationUpdateOptions, AnnotationUpdateResult, BundleLimits, CallFacts, Change, ChangeAnswer, ChangeResult, CustomMetadataService, DocumentActionsService, DocumentAnnotationsService, DocumentAttachmentsService, DocumentEventStream, DocumentFormsService, DocumentHandle, DocumentMetadata, DocumentPagesService, DocumentRedactionService, DocumentRenderService, DocumentSearchService, DocumentSecurityService, DocumentSignaturesService, DownloadOptions, EditSessionAccess, EditSessionStatus, Engine, EngineError, FlattenWriteOptions, MetadataPatch, MetadataService, MetadataUpdateResult, MutationMeta, ObjectNumberPool, ObjectNumberRange, ObjectNumbersLost, OpenInput, OpenOptions, PageAnnotationsService, PageCoordinates, PageDeleteResult, PageFlattenResult, PageFormsService, PageHandle, PageImageOptions, PageInsertBlankOptions, PageInsertBlankSpec, PageInsertResult, PageLayerRights, PageLayout, PageListSnapshot, PageMeasureService, PageMeasurementViewportList, PageNameInput, PageNameResult, PagePosition, PageRef, PageRemoveNameInput, PageRenderImage, PageRenderService, PageReorderResult, PageRotateResult, PageScaleResult, PageTextService, PageTextSnapshot, PdfMeasure, PdfRotation, SearchRequest, SearchSlice, SessionEventPublisher, TextLayout, TextRange, TokenSource, WireAnnotationResources, WorkingSetPage, WriteOptions } from "@embedpdf/engine-core/runtime";
2
2
  import { CdnAccessInfoForApply, DocumentHead, DocumentManifest, LayerScopePlane } from "@embedpdf/engine-core/wire";
3
- import { SessionEventPublisher } from "@embedpdf/engine-services";
3
+ export * from "@embedpdf/engine-core/public";
4
4
  //#region src/transport/HttpClient.d.ts
5
+ /** CloudPDF SaaS: where an engine connects when it names no server of its own. */
6
+ declare const CLOUDPDF_SAAS_URL = "https://engine.cloudpdf.com";
5
7
  interface HttpClientOptions {
6
- baseUrl: string;
8
+ /** Where your CloudPDF runs: your own `@cloudpdf/server`, or CloudPDF SaaS
9
+ * ({@link CLOUDPDF_SAAS_URL}) when left out. */
10
+ baseUrl?: string;
7
11
  /**
8
12
  * Optional bearer token. Either a string or a function that
9
13
  * returns a fresh token on every call (so callers can rotate
@@ -12,26 +16,30 @@ interface HttpClientOptions {
12
16
  * scenario where the doc-scoped token is provided per-`open` and
13
17
  * the engine itself has no engine-level credentials.
14
18
  */
15
- token?: string | (() => string | Promise<string>);
19
+ token?: TokenSource;
16
20
  /**
17
- * Engine-instance session id, sent as `X-Engine-Session-Id` on every
18
- * request. The server stores it on mutation audit rows so this
19
- * instance's SSE stream can drop its own echoes (exactly-once events).
21
+ * The open document's session id, sent as `X-Engine-Session-Id` where the
22
+ * server reads it: on writes, `/access`, the event stream and the bulk
23
+ * reservation (see {@link RequestOptions}). The server keeps the editing
24
+ * session's object numbers under it, and stores it on a write's audit
25
+ * row, so the document's own stream can drop its echoes. Each open
26
+ * document has its own (see {@link HttpClient.forDocument}); the engine's
27
+ * client has none.
20
28
  */
21
29
  sessionId?: string;
22
30
  /** Replace the global fetch (e.g. in Node tests with undici). */
23
31
  fetch?: typeof globalThis.fetch;
24
32
  /**
25
- * Document affinity key: `X-CloudPDF-Doc` is sent BY DEFAULT on
33
+ * Document affinity key: `X-CloudPDF-Doc` is sent by default on
26
34
  * origin-bound doc requests so consistent-hash load balancers can pin
27
35
  * a document's traffic to one warm replica. Routing hints are
28
- * unconditional client behavior — whether they are USED is the
36
+ * unconditional client behavior — whether they are used is the
29
37
  * operator's choice at the load balancer, never the app's. Derived
30
38
  * from the request path (`/v1/docs/:docId/…` — the same extraction
31
39
  * the Helm chart's uri-mode fallback uses); never sent on
32
40
  * CDN-rewritten requests.
33
41
  *
34
- * `false` is an ESCAPE HATCH, not a feature toggle: use it only
42
+ * `false` is an escape hatch, not a feature toggle: use it only
35
43
  * against a stale server whose CORS allowlist predates the header
36
44
  * (browser preflights would fail) or behind a proxy that rejects
37
45
  * unknown request headers.
@@ -62,6 +70,29 @@ interface CdnBinding {
62
70
  readonly docId: string;
63
71
  readonly layerName: string;
64
72
  }
73
+ /**
74
+ * What a write sends beside its request: its `opId` as `Idempotency-Key`,
75
+ * so a retry is answered with what the first try committed, and how many
76
+ * object numbers to top the editing session up by.
77
+ */
78
+ interface WriteRequest {
79
+ /** Absent for a request of changes: its body names each change by its own `opId`. */
80
+ readonly opId?: string;
81
+ /** `EmbedPDF-Reserve-Object-Numbers`, when more than 0. */
82
+ readonly reserveObjectNumbers?: number;
83
+ /** Called with the numbers the response hands out (`EmbedPDF-Object-Numbers`). */
84
+ readonly onObjectNumbers?: (ranges: ObjectNumberRange[]) => void;
85
+ }
86
+ /** How one request is sent, beyond its path and body. */
87
+ interface RequestOptions {
88
+ /**
89
+ * A write: sent as the editing session with its `Idempotency-Key`, and
90
+ * sent again with the same key after a network failure.
91
+ */
92
+ readonly write?: WriteRequest;
93
+ /** Sent as the editing session though not a write: `/access`, the bulk reservation. */
94
+ readonly session?: boolean;
95
+ }
65
96
  /**
66
97
  * A raw-bytes response plus its headers. The attachment-file leaves carry
67
98
  * their metadata as headers (`Content-Type`, `X-EmbedPDF-File-Name`), so
@@ -72,6 +103,7 @@ interface HttpFileResponse {
72
103
  headers: Headers;
73
104
  }
74
105
  declare class HttpClient {
106
+ private readonly options;
75
107
  private readonly base;
76
108
  private readonly tokenFn;
77
109
  private readonly fetchFn;
@@ -80,9 +112,12 @@ declare class HttpClient {
80
112
  private static readonly MAX_RETRIES;
81
113
  private static readonly RETRY_AFTER_CAP_MS;
82
114
  private static readonly RETRY_AFTER_DEFAULT_MS;
83
- private readonly sessionId;
115
+ /** A write whose request failed on the network is sent again after these waits. */
116
+ private static readonly NETWORK_RETRY_MS;
117
+ /** The open document's session id; `null` on the engine's own client. */
118
+ readonly sessionId: string | null;
84
119
  private cdnBinding;
85
- constructor(opts: HttpClientOptions);
120
+ constructor(options: HttpClientOptions);
86
121
  /** Normalized server base URL (no trailing slash). */
87
122
  get baseUrl(): string;
88
123
  /**
@@ -93,13 +128,16 @@ declare class HttpClient {
93
128
  */
94
129
  get fetchImpl(): typeof globalThis.fetch;
95
130
  /**
96
- * Return a clone of this client bound to a different bearer. Used
97
- * by `CloudEngine.open` to mint a per-handle client carrying the
98
- * per-open token, so each opened document's RPCs go out under
99
- * the right authorization without disturbing the engine-level
100
- * token.
131
+ * A client for one open document: this client's settings, the document's
132
+ * own editing session, its own CDN binding, and `token` as its bearer
133
+ * when the open names one (else this client's). Two open documents never
134
+ * share object numbers, event echoes or a CDN binding, even two opens of
135
+ * the same document on one engine.
101
136
  */
102
- withToken(token: string | (() => string | Promise<string>)): HttpClient;
137
+ forDocument({ sessionId, token }: {
138
+ sessionId: string;
139
+ token?: TokenSource;
140
+ }): HttpClient;
103
141
  /**
104
142
  * Raw streaming GET (the SSE channel). Same auth/session headers and
105
143
  * error mapping as every other request; the caller owns the body stream.
@@ -110,13 +148,13 @@ declare class HttpClient {
110
148
  * route everything to origin again — useful on session close or
111
149
  * when an adapter swap happens mid-session (rare).
112
150
  *
113
- * The HttpClient stays dumb about WHEN to do this; the cloud
151
+ * The HttpClient stays dumb about when to do this; the cloud
114
152
  * document handle pushes the binding in after /access succeeds.
115
153
  *
116
154
  * Side effect: in the browser, signedCookies are written to
117
155
  * `document.cookie` once per setCdnAccess call so the CDN edge
118
- * receives them on subsequent fetches. Node side ignores cookies
119
- * for now (cookie jar wiring deferred until needed for tests).
156
+ * receives them on subsequent fetches. Outside the browser signed
157
+ * cookies are ignored: this client keeps no cookie jar.
120
158
  */
121
159
  setCdnAccess(binding: CdnBinding | null): void;
122
160
  /** Current CDN binding (or null). Exposed for diagnostics/tests. */
@@ -175,25 +213,28 @@ declare class HttpClient {
175
213
  * `onStaleVersion` (a manifest refresh) and one re-resolve + retry.
176
214
  */
177
215
  getFileWithRefresh(buildPath: (signal: AbortSignal) => Promise<string>, onStaleVersion: (signal: AbortSignal) => Promise<void>, signal: AbortSignal): Promise<HttpFileResponse>;
178
- postMultipartJson<T>(path: string, body: FormData, parser: (raw: unknown) => T, signal: AbortSignal): Promise<T>;
216
+ postMultipartJson<T>(path: string, body: FormData, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
179
217
  /** PATCH counterpart of {@link postMultipartJson} (binary-carrying mutations). */
180
- patchMultipartJson<T>(path: string, body: FormData, parser: (raw: unknown) => T, signal: AbortSignal): Promise<T>;
181
- postJson<T>(path: string, body: unknown, parser: (raw: unknown) => T, signal: AbortSignal): Promise<T>;
218
+ patchMultipartJson<T>(path: string, body: FormData, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
219
+ postJson<T>(path: string, body: unknown, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
220
+ putJson<T>(path: string, body: unknown, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
221
+ /** POST a JSON body and parse a `multipart/form-data` response (a large annotation export). */
222
+ postJsonFormData(path: string, body: unknown, signal: AbortSignal): Promise<FormData>;
182
223
  /** POST a JSON body and return the raw binary response (pages.extract). */
183
224
  postJsonBytes(path: string, body: unknown, signal: AbortSignal): Promise<Uint8Array>;
184
225
  /** POST a raw binary body (FDF/XFDF import) and parse the JSON response. */
185
- postBytesJson<T>(path: string, bytes: Uint8Array, contentType: string, parser: (raw: unknown) => T, signal: AbortSignal): Promise<T>;
186
- patchJson<T>(path: string, body: unknown, parser: (raw: unknown) => T, signal: AbortSignal): Promise<T>;
187
- deleteJson<T>(path: string, parser: (raw: unknown) => T, signal: AbortSignal): Promise<T>;
188
- deleteEmpty(path: string, signal: AbortSignal): Promise<void>;
189
- postEmpty(path: string, body: unknown, signal: AbortSignal): Promise<void>;
226
+ postBytesJson<T>(path: string, bytes: Uint8Array, contentType: string, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
227
+ patchJson<T>(path: string, body: unknown, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
228
+ deleteJson<T>(path: string, parser: (raw: unknown) => T, signal: AbortSignal, options?: RequestOptions): Promise<T>;
190
229
  private requestJson;
191
230
  private request;
192
231
  private execute;
193
232
  private parseJsonResponse;
194
233
  /**
195
234
  * Decide where this request actually goes. With no CDN binding (or
196
- * binding's `cdn` is null) every request stays on origin. Otherwise
235
+ * binding's `cdn` is null) every request stays on origin, and so does
236
+ * every request that isn't a read (`GET`, `HEAD`): a write must reach the
237
+ * server itself, whatever read its path looks like. Otherwise
197
238
  * `applyCdnAccess` decides per-request based on the resource the
198
239
  * path resolves to (and whether the caller's scope granted CDN
199
240
  * access to it).
@@ -203,21 +244,275 @@ declare class HttpClient {
203
244
  }
204
245
  //#endregion
205
246
  //#region src/CloudEngine.d.ts
206
- interface CloudEngineOptions extends HttpClientOptions {}
247
+ /**
248
+ * `cloudEngine()`'s options: the HTTP client's, minus the session id, which
249
+ * the engine mints for each document it opens.
250
+ */
251
+ interface CloudEngineOptions extends Omit<HttpClientOptions, 'sessionId'> {}
207
252
  /**
208
253
  * Cloud engine: speaks the same Engine interface as @embedpdf/engine
209
254
  * but routes everything through HTTPS to a remote @cloudpdf/server (or
210
255
  * CloudPDF SaaS). Identical observable contract; only the transport differs.
211
256
  */
212
- declare class CloudEngine implements Engine$1 {
257
+ declare class CloudEngine implements Engine {
213
258
  private readonly http;
214
- /** This engine instance's identity on every event's `origin.sessionId`. */
215
- private readonly sessionId;
216
259
  static fromOptions(opts: CloudEngineOptions): CloudEngine;
260
+ /** It opens the documents your server holds, never a file's bytes. */
261
+ readonly canOpenFiles = false;
217
262
  private destroyed;
263
+ /** The documents this engine opened and nobody closed yet. */
264
+ private readonly handles;
218
265
  private constructor();
219
- open(input: OpenInput$1, options?: OpenOptions$1): AbortablePromise$1<DocumentHandle$1>;
220
- destroy(): AbortablePromise$1<void>;
266
+ open(input: OpenInput, options?: OpenOptions): AbortablePromise<DocumentHandle>;
267
+ /**
268
+ * Close every document this engine opened (their event streams stop), then
269
+ * refuse new opens. As on the local engine, a handle is unusable after.
270
+ */
271
+ destroy(): AbortablePromise<void>;
272
+ }
273
+ //#endregion
274
+ //#region src/document/CloudObjectNumberPool.d.ts
275
+ interface CloudObjectNumberPoolOptions {
276
+ /** `POST …/object-numbers`: `count` more numbers for this editing session. */
277
+ reserve(count: number, signal: AbortSignal): Promise<{
278
+ objectNumbers: ObjectNumberRange[];
279
+ expiresIn: number;
280
+ }>;
281
+ now?: () => number;
282
+ }
283
+ /** What became of the numbers a write named. */
284
+ type WriteOutcome =
285
+ /** It committed: they are spent. */
286
+ 'committed' |
287
+ /** The server refused them (`ObjectNumberUnavailable`): the caller knows. */
288
+ 'refused' |
289
+ /** It failed otherwise: the caller still holds them, for a retry. */
290
+ 'failed';
291
+ /**
292
+ * The cloud engine's object numbers: what the server handed this editing
293
+ * session (the engine's `X-Engine-Session-Id` with the token's subject).
294
+ *
295
+ * Numbers arrive with `/access`, with a write's response (the top-up a
296
+ * write asks for when fewer than 8 are held), with the event stream's
297
+ * `session` events, and from `reserve`'s bulk reservation. A number
298
+ * `take` hands out is the caller's until a write naming it commits.
299
+ *
300
+ * The session lives while the event stream is connected or something
301
+ * keeps it alive; without that it expires, and its numbers may go to
302
+ * another session. So once its expiry has passed while the stream is down,
303
+ * the pool hands out nothing until the server says again what it holds.
304
+ * The stream's `session` event lists everything the session holds: any
305
+ * number this pool held or handed out that isn't on it, and that no write
306
+ * in flight names, is lost (`onLost`, `'reclaimed'`). A new version of the
307
+ * document numbers objects anew: everything is lost (`'versioned'`).
308
+ */
309
+ declare class CloudObjectNumberPool implements ObjectNumberPool {
310
+ private readonly opts;
311
+ private readonly now;
312
+ /** Held and not handed out, lowest first. */
313
+ private available;
314
+ /** Handed out by `take`, not yet spent by a write. */
315
+ private readonly taken;
316
+ /** Named by a write in flight, and how many writes name each. */
317
+ private readonly writing;
318
+ /** When the session expires unless kept alive (ms since the epoch). */
319
+ private expiresAt;
320
+ /** Half the longest lifetime the server has told: what a write's touch guarantees. */
321
+ private halfLifetimeMs;
322
+ private streamConnected;
323
+ private readonly listeners;
324
+ /** The bulk reservation in flight, which later `reserve` calls wait behind. */
325
+ private reserving;
326
+ /** The newest version a `versioned` call named. */
327
+ private version;
328
+ constructor(opts: CloudObjectNumberPoolOptions);
329
+ get held(): number;
330
+ take(): number | null;
331
+ reserve(count: number): AbortablePromise<void>;
332
+ onLost(listener: (lost: ObjectNumbersLost) => void): () => void;
333
+ /** How many numbers a write should ask the server for: 0 while enough are held. */
334
+ topUp(): number;
335
+ /** How many numbers `/access` should ask for: enough to make up the first block. */
336
+ wantedAtAccess(): number;
337
+ /**
338
+ * `/access` answered for the editing session. A session the server made
339
+ * anew holds nothing of what this pool had.
340
+ */
341
+ opened(edit: EditSessionAccess): void;
342
+ /**
343
+ * Numbers handed to the session: by `/access`, a write's top-up or the
344
+ * bulk reservation; `expiresIn` (seconds) when the answer told it. Numbers
345
+ * held from before an expiry the server can't vouch for any more are
346
+ * dropped: only a `session` event says which survived.
347
+ */
348
+ receive(ranges: readonly ObjectNumberRange[], expiresIn?: number): void;
349
+ /**
350
+ * The event stream's `session` event: everything the session holds now.
351
+ * What this pool held or handed out and the list doesn't name, unless a
352
+ * write in flight names it, is lost.
353
+ */
354
+ sync(status: EditSessionStatus): void;
355
+ /**
356
+ * Version `sha256` was published: it numbers objects anew, so every number
357
+ * held or handed out is gone. Told once per version (the stream and this
358
+ * engine's own completion both tell it, in either order).
359
+ */
360
+ versioned(sha256: string): void;
361
+ /** The event stream connected or dropped: while it's up, the server keeps the session alive. */
362
+ connected(connected: boolean): void;
363
+ /** A write that names `numbers` was called. */
364
+ beginWrite(numbers: readonly number[]): void;
365
+ /**
366
+ * The write that named `numbers` settled. A committed write also kept the
367
+ * session alive: at least half its lifetime is left.
368
+ */
369
+ endWrite(numbers: readonly number[], outcome: WriteOutcome): void;
370
+ private usable;
371
+ private expiresIn;
372
+ private add;
373
+ /** Held or handed out, and named by no write in flight. */
374
+ private unspent;
375
+ private lose;
376
+ private emit;
377
+ }
378
+ //#endregion
379
+ //#region src/document/CloudWrites.d.ts
380
+ /**
381
+ * One write's place in its document's line (see {@link CloudWrites}): its
382
+ * request goes out once every write called before it has settled.
383
+ */
384
+ interface CloudWrite {
385
+ /**
386
+ * Wait for this write's turn, then send its request with `options`: the
387
+ * write's `opId` as `Idempotency-Key`, a top-up when the pool runs low,
388
+ * and the numbers the response hands out back into the pool.
389
+ */
390
+ send<T>(request: (options: RequestOptions) => Promise<T>): Promise<T>;
391
+ }
392
+ /** A change as its request sends it: its `opId`, and its ops with the bytes they carry. */
393
+ interface SentChange {
394
+ readonly opId: string;
395
+ readonly change: Change<PageCoordinates, WireAnnotationResources>;
396
+ }
397
+ /**
398
+ * Sends one request of changes (`POST …/changes`) with `options`, the
399
+ * changes in line order, and answers each, in the same order.
400
+ */
401
+ type ChangeSender = (changes: readonly SentChange[], options: RequestOptions) => Promise<readonly ChangeAnswer[]>;
402
+ /** How a change takes its place in the line (see {@link CloudWrites.change}). */
403
+ interface LinedChangeOptions {
404
+ /** The object numbers the change creates objects at. */
405
+ readonly named?: readonly number[];
406
+ /**
407
+ * The change carries bytes: it goes in a request of its own, so bytes the
408
+ * server refuses refuse only this change.
409
+ */
410
+ readonly alone?: boolean;
411
+ }
412
+ /**
413
+ * A document's writes, sent one at a time in the order they were called,
414
+ * so the server applies them in that order: a create, then an update of
415
+ * what it made, never the other way round. Reads don't wait.
416
+ *
417
+ * A write takes its place when it is called: `run` must be the first thing
418
+ * a write does, before anything it awaits. What it does before `send`
419
+ * (reading a file to upload, say) happens meanwhile; its turn ends when it
420
+ * settles, after the event it publishes.
421
+ *
422
+ * Changes (`doc.apply`) called one after another share a place: while the
423
+ * write before them is in flight they wait together, and go out as one
424
+ * request when their turn comes, each answered on its own.
425
+ */
426
+ declare class CloudWrites {
427
+ private readonly pool;
428
+ private readonly sendChanges;
429
+ /** Settles when every write so far has settled. */
430
+ private last;
431
+ /** The changes still waiting for their turn, which the next change joins. */
432
+ private open;
433
+ constructor(pool: CloudObjectNumberPool, sendChanges?: ChangeSender);
434
+ run<T>(opId: string, signal: AbortSignal, body: (write: CloudWrite) => Promise<T>,
435
+ /** The object numbers the write creates objects at. */
436
+ named?: readonly (number | undefined)[]): Promise<T>;
437
+ /**
438
+ * Take a change's place in the line: it joins the changes waiting for
439
+ * their turn, and goes out with them. `ready` is what the request sends
440
+ * for it, which it may still be preparing (reading bytes). A change aborted
441
+ * before its request goes out is left out of it; once out, it is answered.
442
+ */
443
+ change(signal: AbortSignal, ready: Promise<SentChange>, { named, alone }?: LinedChangeOptions): Promise<ChangeAnswer>;
444
+ /** A new batch at the end of the line, open for the changes that follow. */
445
+ private queue;
446
+ /** A batch's turn: nothing joins it any more, and what's ready goes out. */
447
+ private send;
448
+ }
449
+ //#endregion
450
+ //#region src/document/CloudDocumentPagesService.d.ts
451
+ /**
452
+ * Cloud-side document pages service. Mirrors `LocalDocumentPagesService`
453
+ * over HTTP: GET /pages for `list`, POST /pages/reorder for the reorder.
454
+ *
455
+ * Page identity rule (locked with the user, do not change):
456
+ * - Pages are addressed exclusively by `PageRef` (their indirect
457
+ * `pageObjectNumber`); mutation bodies ship `{ pages: PageRef[] }`.
458
+ * The wire never sends a page index for a mutation. This keeps
459
+ * multi-call client logic from having to account for index drift
460
+ * between requests.
461
+ * - Successful `reorder()` returns the new `layout` (order + geometry) plus
462
+ * cloud coherence pins. A page reorder bumps only `docVersion` +
463
+ * `layoutVersion`; every per-page pin stays warm.
464
+ */
465
+ declare class CloudDocumentPagesService implements DocumentPagesService {
466
+ private readonly http;
467
+ private readonly docId;
468
+ private readonly layerName;
469
+ private readonly isClosed;
470
+ private readonly manifest;
471
+ private readonly publisher;
472
+ private readonly writes;
473
+ /** The last layout leaf read by {@link pageLayout}, keyed by its URL path. */
474
+ private layoutMemo;
475
+ constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher, writes: CloudWrites);
476
+ /**
477
+ * Page-geometry list. The geometry bytes live at the content-addressed
478
+ * `/layout@layoutVersion=N` leaf (not in the manifest); the manifest only
479
+ * publishes the `layoutVersion` pointer. So `list()` reads `layoutVersion`
480
+ * from the cached manifest, fetches the layout leaf, and on a 404 (stale
481
+ * pointer) transparently refreshes the manifest and retries once — the
482
+ * same ladder the per-page text/geometry reads use. `layoutVersion` bumps
483
+ * only on structural page ops, so this leaf stays cached across content
484
+ * and annotation edits.
485
+ */
486
+ list(): AbortablePromise<PageListSnapshot>;
487
+ /**
488
+ * One page's layout, for renders to size their image without a round
489
+ * trip per tile. The layout leaf never changes at a given URL, so the
490
+ * last one read is kept and shared until the manifest points elsewhere.
491
+ */
492
+ pageLayout(ref: PageRef, signal: AbortSignal): Promise<PageLayout>;
493
+ /**
494
+ * Plane-scope rule: the layout leaf depends on the `layout` plane —
495
+ * while inherited (no reorder/rotate/insert/delete ever ran), every
496
+ * visitor's page list is one doc-level URL served from the base
497
+ * session; the SDK open sequence creates no layer session.
498
+ */
499
+ private layoutPath;
500
+ private fetchLayout;
501
+ reorder(pages: PageRef[], position: PagePosition, options?: WriteOptions): AbortablePromise<PageReorderResult>;
502
+ setName(input: PageNameInput, options?: WriteOptions): AbortablePromise<PageNameResult>;
503
+ removeName(input: PageRemoveNameInput, options?: WriteOptions): AbortablePromise<PageNameResult>;
504
+ /**
505
+ * Named pages are layout: both verbs share the page-reorder patch exactly —
506
+ * docVersion + layoutVersion advance, no per-page pin changes, so the
507
+ * cached manifest is patched in place and the fresh layout is published.
508
+ */
509
+ private runNameMutation;
510
+ rotate(pages: PageRef[], rotation: PdfRotation, options?: WriteOptions): AbortablePromise<PageRotateResult>;
511
+ delete(pages: PageRef[], options?: WriteOptions): AbortablePromise<PageDeleteResult>;
512
+ insert(bytes: Uint8Array | ArrayBuffer, position?: PagePosition, options?: WriteOptions): AbortablePromise<PageInsertResult>;
513
+ insertBlank(spec: PageInsertBlankSpec, position?: PagePosition, options?: PageInsertBlankOptions): AbortablePromise<PageInsertResult>;
514
+ extract(pages: PageRef[]): AbortablePromise<Uint8Array>;
515
+ flatten(pages: PageRef[], options?: FlattenWriteOptions): AbortablePromise<PageFlattenResult>;
221
516
  }
222
517
  //#endregion
223
518
  //#region src/document/CloudDocumentSearchService.d.ts
@@ -226,14 +521,14 @@ declare class CloudEngine implements Engine$1 {
226
521
  *
227
522
  * Every slice URL is a canonical cache key — the search token pins the
228
523
  * layer's content epoch (computed from the cached manifest), the
229
- * CANONICAL query (default-fold literals collapse case/diacritic
524
+ * canonical query (default-fold literals collapse case/diacritic
230
525
  * variants into one entry), and the resume position. Identical searches
231
526
  * from any reader of the document hit the same CDN entry; matches are
232
527
  * all that ever crosses the trust boundary, and the rects/full endpoint
233
528
  * split keeps permission tiers in disjoint cache namespaces.
234
529
  *
235
530
  * Staleness rides the standard versioned-read signal: a first slice
236
- * answered `NotFound` means OUR manifest is stale → refresh and retry
531
+ * answered `NotFound` means our manifest is stale → refresh and retry
237
532
  * once; a continuation answered `NotFound` means the document changed
238
533
  * mid-search → `InvalidArg`, same contract as the local engine's cursor.
239
534
  */
@@ -244,29 +539,16 @@ declare class CloudDocumentSearchService implements DocumentSearchService {
244
539
  private readonly isClosed;
245
540
  private readonly manifest;
246
541
  constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor);
247
- query(request: SearchRequest): AbortablePromise$1<SearchSlice>;
542
+ query(request: SearchRequest): AbortablePromise<SearchSlice>;
248
543
  }
249
544
  //#endregion
250
545
  //#region src/document/CloudMetadataService.d.ts
251
- declare class CloudMetadataService implements MetadataService$1 {
252
- private readonly http;
253
- private readonly docId;
254
- private readonly layerName;
255
- private readonly isClosed;
256
- private readonly manifest;
257
- private readonly publisher;
258
- constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher);
259
- /**
260
- * Document metadata read. The Info-dict JSON lives at the
261
- * content-addressed `/metadata@metadataVersion=N` leaf (not in the
262
- * manifest); the manifest only publishes the `metadataVersion` pointer.
263
- * So `read()` pulls `metadataVersion` from the cached manifest, fetches
264
- * the leaf, and on a 404 (stale pointer) transparently refreshes the
265
- * manifest and retries once. `metadataVersion` bumps only on metadata
266
- * writes, so this leaf stays cached across page and annotation edits.
267
- */
268
- read(): AbortablePromise$1<DocumentMetadata>;
269
- update(patch: MetadataPatch): AbortablePromise$1<MetadataUpdateResult>;
546
+ declare class CloudMetadataService implements MetadataService {
547
+ readonly custom: CustomMetadataService;
548
+ private readonly deps;
549
+ constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher, writes: CloudWrites);
550
+ get(): AbortablePromise<DocumentMetadata>;
551
+ update(patch: MetadataPatch, options?: WriteOptions): AbortablePromise<MetadataUpdateResult>;
270
552
  }
271
553
  //#endregion
272
554
  //#region src/document/CloudDocumentHandle.d.ts
@@ -290,42 +572,36 @@ interface ManifestAccessor {
290
572
  * base → layer, so any observed mutation proves the plane diverged.
291
573
  */
292
574
  apply(meta: MutationMeta, owns: readonly LayerScopePlane[]): void;
293
- /** Advance the cached manifest's docVersion + layoutVersion after a page
294
- * STRUCTURE op that keeps the page set intact (move, rotate). */
295
- applyPageStructure(cache: PageStructureCache): void;
296
- /** Same advance for a page delete, additionally dropping the deleted
297
- * pages' manifest rows so per-page leaf URLs stop resolving locally. */
298
- applyPageDelete(cache: PageStructureCache, deletedPages: PageObjectNumber[]): void;
299
- /** Page insert: the cached manifest has no rows for the fresh PONs (the
575
+ /** A page delete: the advance, plus dropping the deleted pages' manifest
576
+ * rows so per-page leaf URLs stop resolving locally. */
577
+ applyPageDelete(meta: MutationMeta, deletedPages: readonly PageRef[]): void;
578
+ /** Page insert: the cached manifest has no rows for the fresh page object numbers (the
300
579
  * result carries only their object numbers), so the absorb drops the
301
580
  * cache for a lazy refetch instead of patching. */
302
- applyPageInsert(cache: PageStructureCache): void;
303
- /** Advance the cached manifest's docVersion + metadataVersion after a metadata write. */
304
- applyMetadata(cache: MetadataCache): void;
305
- /** Advance the cached manifest's docVersion + attachmentsVersion after an
306
- * attachment create/delete. */
307
- applyAttachments(cache: AttachmentsCache): void;
581
+ applyPageInsert(meta: MutationMeta): void;
308
582
  }
309
- declare class CloudDocumentHandle implements DocumentHandle$1 {
583
+ declare class CloudDocumentHandle implements DocumentHandle {
310
584
  private readonly http;
311
585
  private readonly layerName;
586
+ /** Called once, when the handle closes (the engine forgets it). */
587
+ private readonly onClose;
312
588
  readonly id: string;
313
- readonly capabilities: {
314
- readonly weakAnnotationEditSessions: "required";
315
- readonly pageEditSessions: "unsupported";
316
- };
317
589
  readonly metadata: CloudMetadataService;
318
- readonly annotations: DocumentAnnotationsService$1;
590
+ readonly annotations: DocumentAnnotationsService;
319
591
  readonly actions: DocumentActionsService;
320
592
  readonly attachments: DocumentAttachmentsService;
321
593
  readonly signatures: DocumentSignaturesService;
322
594
  readonly forms: DocumentFormsService;
323
595
  readonly search: CloudDocumentSearchService;
324
- readonly pages: DocumentPagesService$1;
596
+ readonly pages: CloudDocumentPagesService;
325
597
  readonly redaction: DocumentRedactionService;
326
- readonly security: DocumentSecurityService$1;
598
+ readonly security: DocumentSecurityService;
327
599
  readonly render: DocumentRenderService;
328
600
  readonly events: DocumentEventStream;
601
+ readonly objectNumbers: ObjectNumberPool;
602
+ private readonly pool;
603
+ private readonly writes;
604
+ private readonly changes;
329
605
  private readonly publisher;
330
606
  private readonly hub;
331
607
  private readonly sessionId;
@@ -348,6 +624,7 @@ declare class CloudDocumentHandle implements DocumentHandle$1 {
348
624
  private manifestFloorVersion;
349
625
  private pendingInitialHead;
350
626
  private readonly manifestAccessor;
627
+ private readonly cloudSecurity;
351
628
  constructor(http: HttpClient, id: string, layerName?: string, initialHead?: DocumentHead,
352
629
  /**
353
630
  * The doc-scoped JWT the engine was opened with, decoded
@@ -356,11 +633,28 @@ declare class CloudDocumentHandle implements DocumentHandle$1 {
356
633
  * compatibility; without it the local-fallback path returns an
357
634
  * empty scope and null identity until /access is called.
358
635
  */
359
- initialToken?: string | null, sessionId?: string);
360
- page(pageObjectNumber: PageObjectNumber): PageHandle$1;
361
- download(opts?: {
362
- mode?: PdfSaveMode$1;
363
- }): AbortablePromise$1<Uint8Array>;
636
+ initialToken?: string | null,
637
+ /** Called once, when the handle closes (the engine forgets it). */
638
+ onClose?: () => void);
639
+ page(ref: PageRef): PageHandle;
640
+ /**
641
+ * This handle: the cloud engine sends every call as it's made, in
642
+ * parallel, and the server runs them in arrival order, so a call's facts
643
+ * change nothing here.
644
+ */
645
+ with(_facts: CallFacts): DocumentHandle;
646
+ /** One change as one transaction, or the undo of one (see `DocumentHandle.apply`). */
647
+ apply(change: Change, options?: WriteOptions): AbortablePromise<ChangeResult>;
648
+ /** Ignored: the server learns what's needed from what is asked of it. */
649
+ setWorkingSet(_view: string, _pages: readonly WorkingSetPage[]): void;
650
+ download(options?: DownloadOptions): AbortablePromise<Uint8Array>;
651
+ /**
652
+ * Learn what the document's signatures forbid before the caller's first
653
+ * question: the manifest carries it, so `open()` fetches it up front and
654
+ * `security.allows()` answers as the server would from the start. A locked
655
+ * document, which the server won't describe yet, learns it from `unlock()`.
656
+ */
657
+ learnProtection(signal: AbortSignal): Promise<void>;
364
658
  /**
365
659
  * Return the cached manifest, fetching cold-cache once if needed.
366
660
  * Concurrent callers share a single inflight request (singleflight)
@@ -375,9 +669,9 @@ declare class CloudDocumentHandle implements DocumentHandle$1 {
375
669
  */
376
670
  refreshManifest(signal: AbortSignal): Promise<DocumentManifest>;
377
671
  /**
378
- * Monotone plane-scope flip: mark the planes a mutation OWNS as layer-scoped in
672
+ * Monotone plane-scope flip: mark the planes a mutation owns as layer-scoped in
379
673
  * the cached manifest. Scopes only ever move base → layer (no revert op
380
- * exists), so flipping is safe under ANY event ordering — a duplicate or
674
+ * exists), so flipping is safe under any event ordering — a duplicate or
381
675
  * out-of-order event still proves the plane diverged at some point — and
382
676
  * the manifest fetch stays the authoritative source (the 404 → refresh
383
677
  * rail heals any miss, e.g. a future mutation kind this client doesn't
@@ -386,148 +680,101 @@ declare class CloudDocumentHandle implements DocumentHandle$1 {
386
680
  private flipScopes;
387
681
  absorbMutation(meta: MutationMeta, owns: readonly LayerScopePlane[]): void;
388
682
  /**
389
- * Patch the cached manifest after a set-preserving page-structure op (move,
390
- * rotate). Both are purely structural: they advance `docVersion` (so leaf
391
- * URLs re-resolve) and `layoutVersion` (so the /layout leaf re-fetches),
392
- * but leave every per-page pin untouched — a rotate renders the SAME
393
- * normalized bitmaps, a move the same pages. We raise the floor
394
- * unconditionally and, when our cache is exactly one version behind,
395
- * advance it in place; otherwise we drop it and refetch lazily.
396
- */
397
- private absorbPageStructure;
398
- /**
399
- * Patch the cached manifest after a page delete: the shared structural
400
- * advance plus dropping the deleted pages' manifest rows, so no leaf URL
401
- * for a retired PON can be built from the cache (a stale request would
402
- * 404 anyway — this keeps the failure local and instant).
683
+ * Patch the cached manifest after a page delete: the shared advance plus
684
+ * dropping the deleted pages' manifest rows, so no leaf URL for a retired
685
+ * page object number can be built from the cache (a stale request would
686
+ * 404 anyway — this keeps the failure local and instant). Delete changes
687
+ * the page set: a view that removed content must never resolve base
688
+ * artifacts again, so content, annotations and forms flip with layout.
403
689
  */
404
690
  private absorbPageDelete;
405
691
  /**
406
692
  * Patch bookkeeping after a page insert — the mirror of
407
693
  * {@link absorbPageDelete}, with one asymmetry: delete can patch the
408
- * cached manifest losslessly (it only REMOVES rows), but an insert needs
409
- * manifest rows for the fresh PONs and the result doesn't carry them. So
410
- * this absorb flips the planes (insert changes the page SET, so like
411
- * delete it owns content + annotations alongside layout), raises the
412
- * version floor, and DROPS the cache — the next read refetches a manifest
694
+ * cached manifest losslessly (it only removes rows), but an insert needs
695
+ * manifest rows for the fresh page object numbers and the result doesn't carry them. So
696
+ * this absorb flips the planes (insert changes the page set, so like
697
+ * delete it owns content, annotations and forms alongside layout), raises the
698
+ * version floor, and drops the cache — the next read refetches a manifest
413
699
  * that includes the new pages' rows. The UI never waits on that refetch:
414
700
  * the mutation result / event already carries the full new layout.
415
701
  */
416
702
  private absorbPageInsert;
417
- /**
418
- * Patch the cached manifest after a metadata write. Symmetric with
419
- * {@link absorbPageMove}: a metadata edit advances `docVersion` (so leaf
420
- * URLs re-resolve) and `metadataVersion` (so the /metadata leaf re-fetches),
421
- * but leaves `layoutVersion` and every per-page pin untouched. Raise the
422
- * floor unconditionally and, when our cache is exactly one version behind,
423
- * advance it in place; otherwise drop it and refetch lazily.
424
- */
425
- private absorbMetadata;
426
- /**
427
- * Patch the cached manifest after an attachment create/delete. Symmetric
428
- * with {@link absorbMetadata}: an attachment write advances `docVersion`
429
- * (so leaf URLs re-resolve) and `attachmentsVersion` (so the /attachments
430
- * listing and /attachment-files leaves re-fetch), but leaves
431
- * `layoutVersion` and every per-page pin untouched. Raise the floor
432
- * unconditionally and, when our cache is exactly one version behind,
433
- * advance it in place; otherwise drop it and refetch lazily.
434
- */
435
- private absorbAttachments;
436
703
  private startManifestFetch;
437
704
  private fetchManifest;
438
705
  private consumeInitialHead;
439
706
  private fetchManifestForHead;
440
- close(): AbortablePromise$1<void>;
707
+ close(): AbortablePromise<void>;
441
708
  private retainRemoteStream;
442
709
  private releaseRemoteStream;
443
- /** Patch the cached manifest from a REMOTE event's coherence pins — the
710
+ /** Patch the cached manifest from a remote event's coherence pins — the
444
711
  * same absorb rails local mutations use, so reads stay warm no matter
445
712
  * whose hand caused the change. */
446
713
  private absorbRemoteEvent;
447
714
  }
448
715
  //#endregion
449
716
  //#region src/document/CloudDocumentAnnotationsService.d.ts
450
- declare class CloudDocumentAnnotationsService implements DocumentAnnotationsService$1 {
717
+ declare class CloudDocumentAnnotationsService implements DocumentAnnotationsService {
451
718
  private readonly http;
452
719
  private readonly docId;
453
720
  private readonly layerName;
454
721
  private readonly isClosed;
455
722
  private readonly manifest;
456
- constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor);
723
+ private readonly publisher;
724
+ private readonly writes;
725
+ /** The server's import limits, as its `/v1/access` advertises them. */
726
+ private readonly importLimits;
727
+ constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher, writes: CloudWrites,
728
+ /** The server's import limits, as its `/v1/access` advertises them. */
729
+ importLimits: () => Promise<BundleLimits>);
457
730
  /**
458
- * One COHERENT whole-document snapshot: a single read of the immutable
459
- * `annotations/items@annotationsVersion=N` leaf at the manifest's pin —
460
- * materialized server-side by one raw (no page-load) sweep, CDN-cacheable
461
- * because the pin bumps only when annotation list bodies actually change.
462
- * A stale pin mid-read (a concurrent mutation → 404) refreshes the
463
- * manifest and retries, so the result always belongs to one document
464
- * moment (the torn read this method exists to prevent).
731
+ * Every page: one coherent whole-document snapshot, a single read of the
732
+ * immutable `annotations/items@annotationsVersion=N` leaf at the
733
+ * manifest's pin — materialized server-side by one raw (no page-load)
734
+ * sweep, CDN-cacheable because the pin bumps only when annotation list
735
+ * bodies actually change. A stale pin mid-read (a concurrent mutation →
736
+ * 404) refreshes the manifest and retries, so the result always belongs
737
+ * to one document moment (the torn read this method exists to prevent).
738
+ *
739
+ * Some pages: each page's versioned leaf, the same read as
740
+ * `page.annotations.list()`, in the order asked.
465
741
  */
466
- listRawAll(): AbortablePromise$1<AnnotationListSnapshotAllPages>;
742
+ list(options?: AnnotationListOptions): AbortablePromise<AnnotationList>;
467
743
  /** One bulk leaf read at the manifest's pin. The server stamps the body's
468
744
  * `auditHead` at materialization time; a CDN-cached body may carry a
469
745
  * cursor older than the current manifest's, which is still safe — the
470
746
  * pin proves no items-affecting mutation landed in between, so replaying
471
747
  * that window over the body is all no-ops. */
472
748
  private readBulkAt;
473
- listRaw(pageObjectNumber: PageObjectNumber): AbortablePromise$1<AnnotationListPageSnapshot>;
749
+ /** One page's versioned leaf, with the standard stale-pin retry
750
+ * (404 → refresh the manifest → once). */
751
+ private readPage;
752
+ /**
753
+ * One versioned, CDN-cacheable read at the manifest's annotation and
754
+ * layout pins, with the stale-pin retry (404 → refresh the manifest →
755
+ * once). The response is the bundle without its bytes and one part per
756
+ * resource; every part is checked against its id before it is returned.
757
+ */
758
+ export(selection?: AnnotationExportSelection): AbortablePromise<AnnotationBundle>;
759
+ /**
760
+ * One request: the bundle's manifest and each resource once, as parts of
761
+ * one multipart POST under the import's `opId` as `Idempotency-Key`, so a
762
+ * retry applies once. The server holds the limits; the same numbers are checked
763
+ * here first, so a bundle past one fails before its bytes move.
764
+ */
765
+ import(bundle: AnnotationBundle, options?: AnnotationImportOptions): AbortablePromise<AnnotationImportResult>;
766
+ /**
767
+ * The cacheable export URL for `selection` at the manifest's pins — the
768
+ * base leaf while the layer inherits both planes the bundle depends on —
769
+ * or `null` when a URL can't carry it: a URL has room for a few hundred
770
+ * refs.
771
+ */
772
+ private exportPathAt;
474
773
  /** Versioned leaf URL for one manifest page entry, with the same
475
774
  * plane routing as `CloudPageAnnotationsService.list()`: an inherited
476
775
  * `annotations` plane reads the doc-level base leaf. */
477
776
  private pagePathAt;
478
777
  private versionedPagePath;
479
- beginWeakEdit(pageObjectNumbers: readonly PageObjectNumber[]): AbortablePromise$1<WeakAnnotationEditSession>;
480
- }
481
- //#endregion
482
- //#region src/document/CloudDocumentPagesService.d.ts
483
- /**
484
- * Cloud-side document pages service. Mirrors `LocalDocumentPagesService`
485
- * over HTTP: GET /pages for `list`, POST /pages/move for the reorder.
486
- *
487
- * Page identity rule (locked with the user, do not change):
488
- * - Pages are addressed exclusively by their indirect
489
- * `pageObjectNumber`. The wire never sends a page index for a
490
- * mutation. This keeps multi-call client logic from having to
491
- * account for index drift between requests.
492
- * - Successful `move()` returns the new `layout` (order + geometry) plus
493
- * cloud coherence pins. The server does NOT bump per-page revisions on a
494
- * page move (page reorder is intentionally outside the weak-ref staleness
495
- * model), only `docVersion` + `layoutVersion`.
496
- */
497
- declare class CloudDocumentPagesService implements DocumentPagesService$1 {
498
- private readonly http;
499
- private readonly docId;
500
- private readonly layerName;
501
- private readonly isClosed;
502
- private readonly manifest;
503
- private readonly publisher;
504
- constructor(http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher);
505
- /**
506
- * Page-geometry list. The geometry bytes live at the content-addressed
507
- * `/layout@layoutVersion=N` leaf (not in the manifest); the manifest only
508
- * publishes the `layoutVersion` pointer. So `list()` reads `layoutVersion`
509
- * from the cached manifest, fetches the layout leaf, and on a 404 (stale
510
- * pointer) transparently refreshes the manifest and retries once — the
511
- * same ladder the per-page text/geometry reads use. `layoutVersion` bumps
512
- * only on structural page ops, so this leaf stays cached across content
513
- * and annotation edits.
514
- */
515
- list(): AbortablePromise$1<PageListSnapshot>;
516
- move(pageObjectNumbers: PageObjectNumber[], destIndex: number): AbortablePromise$1<PageMoveResult>;
517
- setName(input: PageNameInput): AbortablePromise$1<PageNameResult>;
518
- removeName(input: PageRemoveNameInput): AbortablePromise$1<PageNameResult>;
519
- /**
520
- * Named pages are LAYOUT: both verbs share the page-move patch exactly —
521
- * docVersion + layoutVersion advance, no per-page pin changes, so the
522
- * cached manifest is patched in place and the fresh layout is published.
523
- */
524
- private runNameMutation;
525
- rotate(pageObjectNumbers: PageObjectNumber[], rotation: PageRotation): AbortablePromise$1<PageRotateResult>;
526
- delete(pageObjectNumbers: PageObjectNumber[]): AbortablePromise$1<PageDeleteResult>;
527
- insert(bytes: Uint8Array | ArrayBuffer, destIndex?: number): AbortablePromise$1<PageInsertResult>;
528
- insertBlank(spec: PageInsertBlankSpec, destIndex?: number): AbortablePromise$1<PageInsertResult>;
529
- extract(pageObjectNumbers: PageObjectNumber[]): AbortablePromise$1<Uint8Array>;
530
- flatten(pageObjectNumbers: PageObjectNumber[], usage?: PageFlattenUsage): AbortablePromise$1<PageFlattenResult>;
531
778
  }
532
779
  //#endregion
533
780
  //#region src/document/CloudPageAnnotationsService.d.ts
@@ -540,36 +787,35 @@ declare class CloudDocumentPagesService implements DocumentPagesService$1 {
540
787
  * Reads use immutable versioned layer URLs discovered from the
541
788
  * manifest. Mutations use unversioned layer URLs and are never cached.
542
789
  */
543
- declare class CloudPageAnnotationsService implements PageAnnotationsService$1 {
790
+ declare class CloudPageAnnotationsService implements PageAnnotationsService {
544
791
  private readonly http;
545
792
  private readonly docId;
546
793
  private readonly layerName;
547
- private readonly pageObjectNumber;
794
+ private readonly pageRef;
548
795
  private readonly isClosed;
549
796
  private readonly manifest;
550
797
  private readonly publisher;
551
- constructor(http: HttpClient, docId: string, layerName: string, pageObjectNumber: PageObjectNumber, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher);
552
- list(): AbortablePromise$1<AnnotationListPageSnapshot>;
553
- renderAppearances(_options?: AnnotationAppearanceRenderOptions): AbortablePromise$1<AnnotationAppearancesResult>;
554
- renderAppearanceImages(options?: AnnotationAppearanceImageOptions): AbortablePromise$1<AnnotationAppearanceImagesResult>;
555
- /**
556
- * Decode and return the file embedded in a FileAttachment annotation.
557
- * A read over the immutable `attachment-files` leaf, pinned by the
558
- * manifest's `attachmentsVersion` (annotation-level files re-key on the
559
- * same pin as document-level ones), with the same stale-404 refresh
560
- * retry as {@link list}. Weak `index` refs cannot be spliced into a GET
561
- * URL (no body to carry the revision), so bytes reads require a stable
562
- * id — the same `:annotKey` routing update()/delete() use.
563
- */
564
- downloadFile(ref: AnnotationRef): AbortablePromise$1<AttachmentContent>;
565
- create(draft: AnnotationDraft): AbortablePromise$1<AnnotationCreateResult>;
566
- update(ref: AnnotationRef, patch: AnnotationPatch): AbortablePromise$1<AnnotationUpdateResult>;
567
- /** PATCH as plain JSON, or as multipart when the patch carried binaries. */
798
+ private readonly writes;
799
+ constructor(http: HttpClient, docId: string, layerName: string, pageRef: PageRef, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher, writes: CloudWrites);
800
+ list(): AbortablePromise<AnnotationList>;
801
+ renderAppearances(options?: AnnotationAppearanceImageOptions): AbortablePromise<AnnotationAppearanceImagesResult>;
802
+ /**
803
+ * One of the annotation's resources. `file` is a read over the immutable
804
+ * `attachment-files` leaf, pinned by the manifest's `attachmentsVersion`
805
+ * (annotation-level files re-key on the same pin as document-level ones),
806
+ * with the same stale-404 refresh retry as {@link list}. `appearance` is a
807
+ * derived read (no-store), like {@link exportAppearance}. Both address the
808
+ * annotation by the same `:annotKey` update()/delete() use.
809
+ */
810
+ downloadResource(ref: AnnotationRef, role: AnnotationResourceRole): AbortablePromise<Uint8Array>;
811
+ create(draft: AnnotationDraft, options?: AnnotationCreateOptions): AbortablePromise<AnnotationCreateResult>;
812
+ update(ref: AnnotationRef, patch: AnnotationPatch, options?: AnnotationUpdateOptions): AbortablePromise<AnnotationUpdateResult>;
813
+ /** PATCH as plain JSON, or as multipart when resources came with the patch. */
568
814
  private patchMutation;
569
- delete(ref: AnnotationRef): AbortablePromise$1<AnnotationDeleteResult>;
570
- move(refs: AnnotationRef[], toIndex: number): AbortablePromise$1<AnnotationMoveResult>;
571
- flatten(refs: AnnotationRef[], usage?: PageFlattenUsage): AbortablePromise$1<AnnotationFlattenResult>;
572
- exportAppearance(refs: AnnotationRef[]): AbortablePromise$1<Uint8Array>;
815
+ delete(ref: AnnotationRef, options?: WriteOptions): AbortablePromise<AnnotationDeleteResult>;
816
+ reorder(refs: AnnotationRef[], position: AnnotationPosition, options?: WriteOptions): AbortablePromise<AnnotationReorderResult>;
817
+ flatten(refs: AnnotationRef[], options?: FlattenWriteOptions): AbortablePromise<AnnotationFlattenResult>;
818
+ exportAppearance(refs: AnnotationRef[]): AbortablePromise<Uint8Array>;
573
819
  /**
574
820
  * Patch the cached manifest, then publish the mutation to the document's
575
821
  * event stream (in that order — listeners reading the manifest in their
@@ -577,63 +823,107 @@ declare class CloudPageAnnotationsService implements PageAnnotationsService$1 {
577
823
  * `type` with the matching result by construction; the cast localizes that
578
824
  * pairing here instead of widening every site.
579
825
  */
826
+ /** A delete's event names what went, for listeners that didn't delete it. */
827
+ private absorbDelete;
580
828
  private absorbMutation;
581
829
  }
582
830
  //#endregion
583
- //#region src/document/CloudPageGeometryService.d.ts
584
- declare class CloudPageGeometryService implements PageGeometryService$1 {
831
+ //#region src/document/CloudPageFormsService.d.ts
832
+ /**
833
+ * Cloud page form service: the page's widget images, one read of the
834
+ * immutable `form/pages/{p}/appearances@` leaf at the page's `widgetVersion`,
835
+ * at the base's URL while the layer inherits the `forms` plane.
836
+ */
837
+ declare class CloudPageFormsService implements PageFormsService {
585
838
  private readonly http;
586
839
  private readonly docId;
587
840
  private readonly layerName;
588
- private readonly pageObjectNumber;
841
+ private readonly pageRef;
589
842
  private readonly isClosed;
590
843
  private readonly manifest;
591
- constructor(http: HttpClient, docId: string, layerName: string, pageObjectNumber: PageObjectNumber, isClosed: () => boolean, manifest: ManifestAccessor);
592
- read(): AbortablePromise$1<PageGeometrySnapshot>;
844
+ constructor(http: HttpClient, docId: string, layerName: string, pageRef: PageRef, isClosed: () => boolean, manifest: ManifestAccessor);
845
+ renderAppearances(options?: AnnotationAppearanceImageOptions): AbortablePromise<AnnotationAppearanceImagesResult>;
593
846
  }
594
847
  //#endregion
595
848
  //#region src/document/CloudPageRenderService.d.ts
596
- declare class CloudPageRenderService implements PageRenderService$1 {
849
+ declare class CloudPageRenderService implements PageRenderService {
597
850
  private readonly http;
598
851
  private readonly docId;
599
852
  private readonly layerName;
600
- private readonly pageObjectNumber;
853
+ private readonly pageRef;
601
854
  private readonly isClosed;
602
855
  private readonly manifest;
603
- constructor(http: HttpClient, docId: string, layerName: string, pageObjectNumber: PageObjectNumber, isClosed: () => boolean, manifest: ManifestAccessor);
604
- image(options?: PageImageOptions): AbortablePromise$1<PageImageHandle>;
605
- raw(_options?: PageRenderOptions): AbortablePromise$1<PageRaster>;
856
+ private readonly layout;
857
+ /** What the caller may read, when the client can know it; null leaves it to the server. */
858
+ private readonly layerRights;
859
+ constructor(http: HttpClient, docId: string, layerName: string, pageRef: PageRef, isClosed: () => boolean, manifest: ManifestAccessor, layout: (signal: AbortSignal) => Promise<PageLayout>,
860
+ /** What the caller may read, when the client can know it; null leaves it to the server. */
861
+ layerRights: () => PageLayerRights | null);
862
+ image(options?: PageImageOptions): AbortablePromise<PageRenderImage>;
863
+ /**
864
+ * The image's transform, computed like the server's render (the same
865
+ * `renderSize` and matrix), so the handle knows its size and its pixels
866
+ * before any are fetched. Only a full page needs the page's layout.
867
+ */
868
+ private transformOf;
606
869
  }
607
870
  //#endregion
608
871
  //#region src/document/CloudPageTextService.d.ts
609
872
  /**
610
- * Cloud-side per-page text service. `read()` fetches the
611
- * content-addressed URL `/v1/docs/:id/text/pages/:pon/data@contentVersion=N`, where
612
- * `:P` is the page's current `contentVersion` from the cached
613
- * manifest. On a 404 (stale version) the SDK transparently refreshes
614
- * `/head` + `/manifest@docVersion=N`, rebuilds the URL with the fresh `cN`,
615
- * and retries exactly once.
873
+ * Cloud-side per-page text service. `get()` fetches the content-addressed
874
+ * URL `/v1/docs/:id/text/pages/:pon/data@contentVersion=N` and `layout()`
875
+ * its geometry twin, where `N` is the page's current `contentVersion` from
876
+ * the cached manifest. On a 404 (stale version) the SDK transparently
877
+ * refreshes `/head` + `/manifest@docVersion=N`, rebuilds the URL with the
878
+ * fresh version, and retries exactly once.
616
879
  */
617
- declare class CloudPageTextService implements PageTextService$1 {
880
+ declare class CloudPageTextService implements PageTextService {
618
881
  private readonly http;
619
882
  private readonly docId;
620
883
  private readonly layerName;
621
- private readonly pageObjectNumber;
884
+ private readonly pageRef;
622
885
  private readonly isClosed;
623
886
  private readonly manifest;
624
- constructor(http: HttpClient, docId: string, layerName: string, pageObjectNumber: PageObjectNumber, isClosed: () => boolean, manifest: ManifestAccessor);
625
- read(): AbortablePromise$1<PageTextSnapshot>;
887
+ constructor(http: HttpClient, docId: string, layerName: string, pageRef: PageRef, isClosed: () => boolean, manifest: ManifestAccessor);
888
+ get(): AbortablePromise<PageTextSnapshot>;
889
+ slice(range: TextRange): AbortablePromise<string>;
890
+ layout(): AbortablePromise<TextLayout>;
891
+ /** One of the page's content leaves at the manifest's pin, with the stale-pin retry. */
892
+ private readLeaf;
893
+ private leafPath;
894
+ }
895
+ //#endregion
896
+ //#region src/document/CloudPageMeasureService.d.ts
897
+ declare class CloudPageMeasureService implements PageMeasureService {
898
+ private readonly http;
899
+ private readonly docId;
900
+ private readonly layerName;
901
+ private readonly pageRef;
902
+ private readonly isClosed;
903
+ private readonly manifest;
904
+ private readonly publisher;
905
+ private readonly writes;
906
+ constructor(http: HttpClient, docId: string, layerName: string, pageRef: PageRef, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher, writes: CloudWrites);
907
+ listViewports(): AbortablePromise<PageMeasurementViewportList>;
908
+ setScale(measure: PdfMeasure | null, options?: WriteOptions): AbortablePromise<PageScaleResult>;
909
+ private check;
626
910
  }
627
911
  //#endregion
628
912
  //#region src/document/CloudPageHandle.d.ts
629
- declare class CloudPageHandle implements PageHandle$1 {
630
- readonly pageObjectNumber: PageObjectNumber;
631
- readonly pageIndex: number;
913
+ /**
914
+ * Cloud page handle, keyed on `ref` — the page's durable address (its
915
+ * object number). Every service below addresses the wire by it
916
+ * (`/pages/obj:N/…`), keys the manifest by its number, and publishes
917
+ * that number in events.
918
+ */
919
+ declare class CloudPageHandle implements PageHandle {
920
+ readonly ref: PageRef;
632
921
  readonly annotations: CloudPageAnnotationsService;
922
+ readonly forms: CloudPageFormsService;
633
923
  readonly text: CloudPageTextService;
634
- readonly geometry: CloudPageGeometryService;
635
924
  readonly render: CloudPageRenderService;
636
- constructor(pageObjectNumber: PageObjectNumber, pageIndex: number, http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher);
925
+ readonly measure: CloudPageMeasureService;
926
+ constructor(ref: PageRef, http: HttpClient, docId: string, layerName: string, isClosed: () => boolean, manifest: ManifestAccessor, publisher: SessionEventPublisher, writes: CloudWrites, layout: (signal: AbortSignal) => Promise<PageLayout>, layerRights: () => PageLayerRights | null);
637
927
  }
638
928
  //#endregion
639
929
  //#region src/transport/decodeUnverifiedClaims.d.ts
@@ -666,7 +956,7 @@ declare function decodeUnverifiedClaims(token: string): UnverifiedClaims;
666
956
  /**
667
957
  * Share-session exchange: the client half of the no-backend embed flow.
668
958
  *
669
- * A share token (`shr_…`) is a REFERENCE to a stored grant on the
959
+ * A share token (`shr_…`) is a reference to a stored grant on the
670
960
  * server, not a credential — `exchangeShareToken` trades it for an
671
961
  * ordinary short-lived doc JWT, and `shareSessionSource` wraps that in
672
962
  * a self-renewing token source. Because the engine's transport
@@ -715,7 +1005,7 @@ declare function exchangeShareToken(baseUrl: string, shareToken: string, opts?:
715
1005
  * retry). Everything else maps by meaning, with the HTTP status as the
716
1006
  * fallback discriminator.
717
1007
  */
718
- declare function engineErrorFromShareExchange(error: ShareExchangeError): EngineError$1;
1008
+ declare function engineErrorFromShareExchange(error: ShareExchangeError): EngineError;
719
1009
  /**
720
1010
  * A caching, self-renewing token source over the exchange — the callable
721
1011
  * member of the engine's `TokenSource` union, assignable wherever one is
@@ -726,7 +1016,6 @@ declare function engineErrorFromShareExchange(error: ShareExchangeError): Engine
726
1016
  declare function shareSessionSource(baseUrl: string, shareToken: string, opts?: ShareExchangeOptions): () => Promise<string>;
727
1017
  //#endregion
728
1018
  //#region src/index.d.ts
729
- declare function createCloudEngine(opts: CloudEngineOptions): CloudEngine;
730
1019
  /**
731
1020
  * Create a cloud {@link CloudEngine} — the drop-in counterpart of
732
1021
  * `localEngine()`, so swapping local for cloud is a one-import change.
@@ -738,16 +1027,19 @@ declare function createCloudEngine(opts: CloudEngineOptions): CloudEngine;
738
1027
  * to let a `<Viewer>` own the lifetime instead.
739
1028
  *
740
1029
  * Note the deliberate asymmetry with `localEngine()`: there is no `fonts`
741
- * option. Fallback fonts are a SERVER policy on the cloud (`Engine.fonts` is
1030
+ * option. Fallback fonts are a server policy on the cloud (`Engine.fonts` is
742
1031
  * `undefined` cloud-side), so they cannot be configured from the client. This
743
1032
  * is the local-vs-cloud split, surfaced in the API.
744
1033
  *
1034
+ * Without a `baseUrl` it connects to CloudPDF SaaS; your own server names itself:
1035
+ *
745
1036
  * ```ts
746
- * const engine = cloudEngine({ baseUrl: 'https://pdf.example.com', token });
1037
+ * const engine = cloudEngine(); // CloudPDF SaaS
1038
+ * const own = cloudEngine({ baseUrl: 'https://pdf.example.com' }); // your @cloudpdf/server
747
1039
  * <Viewer engine={engine} plugins={[stagePlugin(), renderPlugin()]} />
748
1040
  * ```
749
1041
  */
750
- declare function cloudEngine(opts: CloudEngineOptions): CloudEngine;
1042
+ declare function cloudEngine(opts?: CloudEngineOptions): CloudEngine;
751
1043
  //#endregion
752
- export { AbortError, AbortablePromise, CloudDocumentAnnotationsService, CloudDocumentHandle, CloudDocumentPagesService, CloudEngine, type CloudEngineOptions, CloudMetadataService, CloudPageAnnotationsService, CloudPageGeometryService, CloudPageHandle, CloudPageRenderService, type DocumentAccessInfo, type DocumentAnnotationsService, type DocumentCapabilities, type DocumentHandle, type DocumentIdentity, type DocumentPagesService, type DocumentSecurityService, type DocumentSecurityState, type DocumentUnlockInput, type DocumentUnlockResult, type Engine, EngineError, EngineErrorCode, type EngineFactory, HttpClient, type HttpClientOptions, type MetadataService, type OpenInput, type OpenInputShare, type OpenOptions, type PageAnnotationsService, type PageGeometryService, type PageHandle, type PageRenderService, type PageTextService, type PdfSaveMode, ShareExchangeError, type ShareExchangeOptions, type ShareSession, type TokenSource, type UnverifiedClaims, cloudEngine, createCloudEngine, decodeUnverifiedClaims, engineErrorFromShareExchange, exchangeShareToken, shareSessionSource };
1044
+ export { CLOUDPDF_SAAS_URL, CloudDocumentAnnotationsService, CloudDocumentHandle, CloudDocumentPagesService, CloudEngine, type CloudEngineOptions, CloudMetadataService, CloudPageAnnotationsService, CloudPageHandle, CloudPageRenderService, HttpClient, type HttpClientOptions, ShareExchangeError, type ShareExchangeOptions, type ShareSession, type UnverifiedClaims, cloudEngine, decodeUnverifiedClaims, engineErrorFromShareExchange, exchangeShareToken, shareSessionSource };
753
1045
  //# sourceMappingURL=index.d.ts.map