@cloudpdf/engine 3.0.0-next.14 → 3.0.0-next.16

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