@embedpdf/engine-core 3.0.0-next.0
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/LICENSE +192 -0
- package/README.md +24 -0
- package/dist/AbortError-ByBflvEl.cjs +38 -0
- package/dist/AbortError-ByBflvEl.cjs.map +1 -0
- package/dist/AbortError-CjSasIlL.js +27 -0
- package/dist/AbortError-CjSasIlL.js.map +1 -0
- package/dist/AnnotationListSnapshot-W0RCsyDE.d.cts +5043 -0
- package/dist/AnnotationListSnapshot-W0RCsyDE.d.ts +5043 -0
- package/dist/DocumentSecurityService-B-tULKNY.d.ts +332 -0
- package/dist/DocumentSecurityService-Df79fgpe.d.cts +332 -0
- package/dist/Engine-B7Oe7f5i.d.ts +1013 -0
- package/dist/Engine-D9loFZc1.d.cts +1013 -0
- package/dist/builders-BvikWRuO.cjs +1684 -0
- package/dist/builders-BvikWRuO.cjs.map +1 -0
- package/dist/builders-C548U47M.js +1367 -0
- package/dist/builders-C548U47M.js.map +1 -0
- package/dist/conformance.cjs +5414 -0
- package/dist/conformance.cjs.map +1 -0
- package/dist/conformance.d.cts +530 -0
- package/dist/conformance.d.ts +530 -0
- package/dist/conformance.js +5394 -0
- package/dist/conformance.js.map +1 -0
- package/dist/fold-CB4fAOOy.js +175 -0
- package/dist/fold-CB4fAOOy.js.map +1 -0
- package/dist/fold-IaMph3CO.cjs +216 -0
- package/dist/fold-IaMph3CO.cjs.map +1 -0
- package/dist/index.cjs +82 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/resolver-DAZWVoJL.cjs +434 -0
- package/dist/resolver-DAZWVoJL.cjs.map +1 -0
- package/dist/resolver-DiPMTfcy.js +363 -0
- package/dist/resolver-DiPMTfcy.js.map +1 -0
- package/dist/runtime.cjs +453 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +1002 -0
- package/dist/runtime.d.ts +1002 -0
- package/dist/runtime.js +361 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schemas-9OpSSeM6.js +2493 -0
- package/dist/schemas-9OpSSeM6.js.map +1 -0
- package/dist/schemas-B_1VyFsm.cjs +3608 -0
- package/dist/schemas-B_1VyFsm.cjs.map +1 -0
- package/dist/subtype-BvAzLCGC.js +196 -0
- package/dist/subtype-BvAzLCGC.js.map +1 -0
- package/dist/subtype-qejjVr6h.cjs +231 -0
- package/dist/subtype-qejjVr6h.cjs.map +1 -0
- package/dist/wire.cjs +1516 -0
- package/dist/wire.cjs.map +1 -0
- package/dist/wire.d.cts +1546 -0
- package/dist/wire.d.ts +1546 -0
- package/dist/wire.js +1280 -0
- package/dist/wire.js.map +1 -0
- package/package.json +74 -0
package/dist/runtime.cjs
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_builders = require("./builders-BvikWRuO.cjs");
|
|
3
|
+
const require_subtype = require("./subtype-qejjVr6h.cjs");
|
|
4
|
+
const require_fold = require("./fold-IaMph3CO.cjs");
|
|
5
|
+
const require_resolver = require("./resolver-DAZWVoJL.cjs");
|
|
6
|
+
const require_AbortError = require("./AbortError-ByBflvEl.cjs");
|
|
7
|
+
//#region src/promise/AbortablePromise.ts
|
|
8
|
+
let _Symbol$species;
|
|
9
|
+
_Symbol$species = Symbol.species;
|
|
10
|
+
/**
|
|
11
|
+
* Awaitable Promise subclass with abort and progress.
|
|
12
|
+
*
|
|
13
|
+
* Symbol.species returns plain Promise so chained .then/.catch/.finally
|
|
14
|
+
* return regular promises and never try to synthesize a new
|
|
15
|
+
* AbortablePromise (which would have no executor).
|
|
16
|
+
*
|
|
17
|
+
* Settlement contract:
|
|
18
|
+
* - The first settlement wins. resolve/reject handed to the executor
|
|
19
|
+
* are wrapped so that any subsequent call (whether by the executor,
|
|
20
|
+
* by abort(), or by both racing) becomes a silent no-op.
|
|
21
|
+
* - abort() rejects the public promise with AbortError immediately,
|
|
22
|
+
* even if the executor never observes the AbortSignal. The executor
|
|
23
|
+
* still receives the AbortSignal so it can stop real work
|
|
24
|
+
* cooperatively (release a queue slot, abort fetch, post a worker
|
|
25
|
+
* abort, etc.). Anything the executor does after that — including
|
|
26
|
+
* a late resolve(value), a late reject(error), or a rejected inner
|
|
27
|
+
* Promise inside AbortablePromise.run — is dropped silently.
|
|
28
|
+
* - abort() after settlement is a no-op.
|
|
29
|
+
*/
|
|
30
|
+
var AbortablePromise = class AbortablePromise extends Promise {
|
|
31
|
+
static get [_Symbol$species]() {
|
|
32
|
+
return Promise;
|
|
33
|
+
}
|
|
34
|
+
constructor(executor) {
|
|
35
|
+
const ctrl = new AbortController();
|
|
36
|
+
const progressCbs = /* @__PURE__ */ new Set();
|
|
37
|
+
const state = { settled: false };
|
|
38
|
+
let capturedReject;
|
|
39
|
+
super((resolve, reject) => {
|
|
40
|
+
capturedReject = reject;
|
|
41
|
+
const wrappedResolve = (value) => {
|
|
42
|
+
if (state.settled) return;
|
|
43
|
+
state.settled = true;
|
|
44
|
+
resolve(value);
|
|
45
|
+
};
|
|
46
|
+
const wrappedReject = (reason) => {
|
|
47
|
+
if (state.settled) return;
|
|
48
|
+
state.settled = true;
|
|
49
|
+
reject(reason);
|
|
50
|
+
};
|
|
51
|
+
const progress = (p) => {
|
|
52
|
+
if (state.settled) return;
|
|
53
|
+
for (const cb of progressCbs) try {
|
|
54
|
+
cb(p);
|
|
55
|
+
} catch {}
|
|
56
|
+
};
|
|
57
|
+
executor(wrappedResolve, wrappedReject, progress, ctrl.signal);
|
|
58
|
+
});
|
|
59
|
+
require_fold._defineProperty(this, "signal", void 0);
|
|
60
|
+
require_fold._defineProperty(this, "_ctrl", void 0);
|
|
61
|
+
require_fold._defineProperty(this, "_progressCbs", void 0);
|
|
62
|
+
require_fold._defineProperty(this, "_state", void 0);
|
|
63
|
+
require_fold._defineProperty(this, "_internalReject", void 0);
|
|
64
|
+
this._ctrl = ctrl;
|
|
65
|
+
this.signal = ctrl.signal;
|
|
66
|
+
this._progressCbs = progressCbs;
|
|
67
|
+
this._state = state;
|
|
68
|
+
this._internalReject = capturedReject;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Abort the underlying operation.
|
|
72
|
+
*
|
|
73
|
+
* - If the promise has already settled, this is a no-op.
|
|
74
|
+
* - Otherwise the public promise rejects synchronously with an
|
|
75
|
+
* AbortError (wrapping the supplied reason if it is not already an
|
|
76
|
+
* AbortError) and the AbortSignal fires for any cooperative
|
|
77
|
+
* cancellation the executor wired up.
|
|
78
|
+
*/
|
|
79
|
+
abort(reason) {
|
|
80
|
+
if (this._state.settled) return;
|
|
81
|
+
if (this._ctrl.signal.aborted) return;
|
|
82
|
+
const err = reason instanceof require_AbortError.AbortError ? reason : new require_AbortError.AbortError(reason);
|
|
83
|
+
this._state.settled = true;
|
|
84
|
+
this._ctrl.abort(err);
|
|
85
|
+
this._internalReject(err);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Subscribe to progress events. Returns an unsubscribe function.
|
|
89
|
+
*/
|
|
90
|
+
onProgress(cb) {
|
|
91
|
+
this._progressCbs.add(cb);
|
|
92
|
+
return () => {
|
|
93
|
+
this._progressCbs.delete(cb);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Wrap a value in an already-resolved AbortablePromise. Mirrors Promise.resolve.
|
|
98
|
+
*/
|
|
99
|
+
static resolveValue(value) {
|
|
100
|
+
return new AbortablePromise((resolve) => resolve(value));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Wrap a thrown reason in an already-rejected AbortablePromise.
|
|
104
|
+
*/
|
|
105
|
+
static rejectReason(reason) {
|
|
106
|
+
return new AbortablePromise((_resolve, reject) => reject(reason));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Run an async function as an AbortablePromise so callers get .abort() and .signal.
|
|
110
|
+
* The async function receives the AbortSignal (and a progress emitter) so it can
|
|
111
|
+
* cooperate with the abort.
|
|
112
|
+
*
|
|
113
|
+
* If abort() fires while the inner async function is still running, the
|
|
114
|
+
* public promise rejects with AbortError immediately. The inner async
|
|
115
|
+
* function's eventual settlement (resolve or reject) is funneled through
|
|
116
|
+
* the wrapped settlers and silently dropped — including a late rejection
|
|
117
|
+
* from the underlying work, which prevents an UnhandledRejection because
|
|
118
|
+
* the .then(resolve, reject) below "handles" it via the no-op.
|
|
119
|
+
*/
|
|
120
|
+
static run(fn) {
|
|
121
|
+
return new AbortablePromise((resolve, reject, progress, signal) => {
|
|
122
|
+
fn(signal, progress).then(resolve, reject);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
//#endregion
|
|
127
|
+
//#region src/engine/document-security-state.ts
|
|
128
|
+
function securityStateFromHead(head) {
|
|
129
|
+
return {
|
|
130
|
+
encryption: {
|
|
131
|
+
state: head.encryption.state,
|
|
132
|
+
requiresPassword: head.encryption.requiresPassword
|
|
133
|
+
},
|
|
134
|
+
permissions: { ...head.permissions },
|
|
135
|
+
access: {
|
|
136
|
+
required: head.access.required,
|
|
137
|
+
reasons: [...head.access.reasons],
|
|
138
|
+
...head.access.endpoint ? { endpoint: head.access.endpoint } : {}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function permissionInfoFromProbe(info) {
|
|
143
|
+
if (info.pdfPermissionsBits === null) return null;
|
|
144
|
+
return {
|
|
145
|
+
known: true,
|
|
146
|
+
bits: info.pdfPermissionsBits,
|
|
147
|
+
allAllowed: info.pdfPermissionsAllAllowed,
|
|
148
|
+
openedAs: info.pdfOpenedAs,
|
|
149
|
+
securityHandlerRevision: info.securityHandlerRevision
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Same as {@link permissionInfoFromProbe} but additionally populates
|
|
154
|
+
* `flags` (typed PdfBits view) and `advisory` (capability-shaped
|
|
155
|
+
* booleans for UI badges). Used by routes that have a decoded `PdfBits`
|
|
156
|
+
* in hand — notably `/access`, which always does.
|
|
157
|
+
*
|
|
158
|
+
* Returns `null` for the same reason as the base function — when the
|
|
159
|
+
* PDF hasn't been probed yet so bits are unknown.
|
|
160
|
+
*/
|
|
161
|
+
function permissionInfoWithAdvisory(info, pdfBits) {
|
|
162
|
+
const base = permissionInfoFromProbe(info);
|
|
163
|
+
if (!base) return null;
|
|
164
|
+
return {
|
|
165
|
+
...base,
|
|
166
|
+
flags: pdfBits,
|
|
167
|
+
advisory: advisoryFromPdfBits(pdfBits)
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Translate a {@link PdfBits} view into the capability-shaped
|
|
172
|
+
* {@link PdfPermissionAdvisory}. The rules here MUST mirror the bit
|
|
173
|
+
* combinations the scope resolver uses for `pdf.permissions`
|
|
174
|
+
* expansion — `doc.print.high` requires bit 12 AND bit 3, etc.
|
|
175
|
+
*/
|
|
176
|
+
function advisoryFromPdfBits(b) {
|
|
177
|
+
return {
|
|
178
|
+
canPrint: b.bit3,
|
|
179
|
+
canPrintHigh: b.bit12 && b.bit3,
|
|
180
|
+
canCopy: b.bit5,
|
|
181
|
+
canAnnotate: b.bit6,
|
|
182
|
+
canFillForms: b.bit6 || b.bit9,
|
|
183
|
+
canModifyForms: b.bit6 && b.bit4,
|
|
184
|
+
canModifyPages: b.bit4,
|
|
185
|
+
canAssemble: b.bit11
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function securityStateFromProbe(info, opts = {}) {
|
|
189
|
+
const permission = permissionInfoFromProbe(info);
|
|
190
|
+
const reasons = [];
|
|
191
|
+
if (info.encryptionRequiresPassword === true && !permission) reasons.push("password");
|
|
192
|
+
if (opts.cdnRequired) reasons.push("cdn");
|
|
193
|
+
if (info.encryptionState === "unknown") reasons.push("permissions-unknown");
|
|
194
|
+
return {
|
|
195
|
+
encryption: {
|
|
196
|
+
state: info.encryptionState,
|
|
197
|
+
requiresPassword: info.encryptionRequiresPassword
|
|
198
|
+
},
|
|
199
|
+
permissions: {
|
|
200
|
+
known: permission?.known ?? false,
|
|
201
|
+
bits: permission?.bits ?? null,
|
|
202
|
+
allAllowed: permission?.allAllowed ?? null,
|
|
203
|
+
openedAs: permission?.openedAs ?? null,
|
|
204
|
+
securityHandlerRevision: permission?.securityHandlerRevision ?? null,
|
|
205
|
+
canUpgradeToOwner: info.encryptionState === "encrypted" && info.pdfOpenedAs !== "owner"
|
|
206
|
+
},
|
|
207
|
+
access: {
|
|
208
|
+
required: reasons.length > 0,
|
|
209
|
+
reasons,
|
|
210
|
+
...reasons.length > 0 && opts.accessEndpoint ? { endpoint: opts.accessEndpoint } : {}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region src/engine/DocumentRenderService.ts
|
|
216
|
+
const CONTINUOUS_RENDER_POLICY = { kind: "continuous" };
|
|
217
|
+
/**
|
|
218
|
+
* Conform a FULL-PAGE viewport to a render policy — the ONE snap
|
|
219
|
+
* implementation, shared by every engine and plugin. Pure and explicit
|
|
220
|
+
* by design:
|
|
221
|
+
*
|
|
222
|
+
* - `continuous` → identity (local/cloud plugin code stays byte-identical).
|
|
223
|
+
* - `lattice` → returns a `width`-kind viewport at the smallest ladder
|
|
224
|
+
* width ≥ the requested detail (snap UP: always crisp, CSS downscales
|
|
225
|
+
* for free), capped at the largest width — detail beyond the cap is the
|
|
226
|
+
* tile pyramid's job, by design.
|
|
227
|
+
* - `scale`-kind requests convert through the page's width in PDF user
|
|
228
|
+
* units — pass `opts.pageWidth` (the caller has it from the layout);
|
|
229
|
+
* omitting it for a scale viewport under a lattice policy is a
|
|
230
|
+
* programmer error and throws `InvalidArg`.
|
|
231
|
+
*/
|
|
232
|
+
function snapFullPageViewport(policy, viewport, opts) {
|
|
233
|
+
if (policy.kind === "continuous") return viewport;
|
|
234
|
+
if (policy.fullPage.widths.length === 0) throw new require_fold.EngineError(require_subtype.EngineErrorCode.InvalidArg, "render policy has an empty width ladder");
|
|
235
|
+
const widths = [...policy.fullPage.widths].sort((a, b) => a - b);
|
|
236
|
+
let requested;
|
|
237
|
+
if (viewport.kind === "width") requested = viewport.width;
|
|
238
|
+
else {
|
|
239
|
+
const pageWidth = opts?.pageWidth;
|
|
240
|
+
if (pageWidth === void 0 || pageWidth <= 0) throw new require_fold.EngineError(require_subtype.EngineErrorCode.InvalidArg, "snapping a scale viewport to a width lattice requires opts.pageWidth");
|
|
241
|
+
requested = (viewport.scale ?? 1) * pageWidth;
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
kind: "width",
|
|
245
|
+
width: widths.find((width) => width >= requested) ?? widths[widths.length - 1]
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Conform an annotation-appearance scale to the policy's appearance
|
|
250
|
+
* lattice. Same discipline as {@link snapFullPageViewport}: identity on
|
|
251
|
+
* continuous (and when the policy carries no appearance block), snap UP,
|
|
252
|
+
* cap at the largest point. Callers derive `scale` from the page's
|
|
253
|
+
* effective render scale (`snappedWidth / pageWidth`, × devicePixelRatio
|
|
254
|
+
* as needed) so composites stay crisp against the page raster.
|
|
255
|
+
*/
|
|
256
|
+
function snapAppearanceScale(policy, scale) {
|
|
257
|
+
if (policy.kind === "continuous" || policy.appearances === void 0) return scale;
|
|
258
|
+
if (policy.appearances.scales.length === 0) throw new require_fold.EngineError(require_subtype.EngineErrorCode.InvalidArg, "render policy has an empty appearance-scale lattice");
|
|
259
|
+
const scales = [...policy.appearances.scales].sort((a, b) => a - b);
|
|
260
|
+
return scales.find((s) => s >= scale) ?? scales[scales.length - 1];
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Conform a tile-pyramid scale to the policy's tile lattice — the third
|
|
264
|
+
* member of the `snap<PolicyBlock><Quantity>` family. Identity on
|
|
265
|
+
* continuous and while the deployment doesn't advertise a `tiles` block
|
|
266
|
+
* (the block is reserved until the deep-zoom vertical ships server-side;
|
|
267
|
+
* the tiling client uses its own default pyramid then — see
|
|
268
|
+
* plugin-render). Snap UP, cap at the largest scale: per-tile cost is
|
|
269
|
+
* constant by construction (`tileSize²` pixels regardless of level), so
|
|
270
|
+
* the cap bounds artifact COUNT, not memory.
|
|
271
|
+
*/
|
|
272
|
+
function snapTileScale(policy, scale) {
|
|
273
|
+
if (policy.kind === "continuous" || policy.tiles === void 0) return scale;
|
|
274
|
+
if (policy.tiles.scales.length === 0) throw new require_fold.EngineError(require_subtype.EngineErrorCode.InvalidArg, "render policy has an empty tile-scale lattice");
|
|
275
|
+
const scales = [...policy.tiles.scales].sort((a, b) => a - b);
|
|
276
|
+
return scales.find((s) => s >= scale) ?? scales[scales.length - 1];
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/engine/passwordPrompt.ts
|
|
280
|
+
/**
|
|
281
|
+
* Derive the high-level password prompt from the raw security state.
|
|
282
|
+
*
|
|
283
|
+
* The function is pure and total — every `DocumentSecurityState`
|
|
284
|
+
* maps to exactly one `PasswordPrompt`. Use this as the SINGLE source
|
|
285
|
+
* of truth wherever the SDK exposes a "do you need a password?" flag:
|
|
286
|
+
* both `LocalDocumentSecurityService` and `CloudDocumentSecurityService`
|
|
287
|
+
* call it, so the contract can never drift.
|
|
288
|
+
*
|
|
289
|
+
* Mapping rules (top to bottom; first match wins):
|
|
290
|
+
*
|
|
291
|
+
* 1. encryption.state === 'none'
|
|
292
|
+
* → { state: 'none' } the document isn't encrypted
|
|
293
|
+
*
|
|
294
|
+
* 2. !permissions.known
|
|
295
|
+
* → { state: 'required', hint: null } we haven't probed yet; can't
|
|
296
|
+
* tell user-vs-owner; show
|
|
297
|
+
* generic prompt
|
|
298
|
+
*
|
|
299
|
+
* 3. requiresPassword && openedAs === 'none'
|
|
300
|
+
* → { state: 'required', hint: 'user' } encrypted, anonymous open
|
|
301
|
+
* failed → user pwd needed
|
|
302
|
+
*
|
|
303
|
+
* 4. openedAs === 'owner'
|
|
304
|
+
* → { state: 'none' } already at the top — nothing more
|
|
305
|
+
* to unlock
|
|
306
|
+
*
|
|
307
|
+
* 5. permissions.canUpgradeToOwner === true
|
|
308
|
+
* → { state: 'optional', hint: 'owner' } open as user (or as none
|
|
309
|
+
* for owner-pwd-only docs)
|
|
310
|
+
* but more is available
|
|
311
|
+
*
|
|
312
|
+
* 6. fallthrough → { state: 'none' } open and nothing more available
|
|
313
|
+
*/
|
|
314
|
+
function passwordPromptFromState(state) {
|
|
315
|
+
if (state.encryption.state === "none") return { state: "none" };
|
|
316
|
+
if (!state.permissions.known) return {
|
|
317
|
+
state: "required",
|
|
318
|
+
hint: null
|
|
319
|
+
};
|
|
320
|
+
if (state.encryption.requiresPassword && state.permissions.openedAs === "none") return {
|
|
321
|
+
state: "required",
|
|
322
|
+
hint: "user"
|
|
323
|
+
};
|
|
324
|
+
if (state.permissions.openedAs === "owner") return { state: "none" };
|
|
325
|
+
if (state.permissions.canUpgradeToOwner) return {
|
|
326
|
+
state: "optional",
|
|
327
|
+
hint: "owner"
|
|
328
|
+
};
|
|
329
|
+
return { state: "none" };
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/wire/WirePack.ts
|
|
333
|
+
/**
|
|
334
|
+
* Singleton empty transfer list. Frozen so accidental in-place
|
|
335
|
+
* mutation throws in strict mode rather than silently mutating the
|
|
336
|
+
* default for future calls.
|
|
337
|
+
*/
|
|
338
|
+
const EMPTY_TRANSFER = Object.freeze([]);
|
|
339
|
+
/**
|
|
340
|
+
* Producer-side helper: pair a typed payload with its transfer list.
|
|
341
|
+
*
|
|
342
|
+
* The `transfer` argument is optional; omitting it (or passing `[]`)
|
|
343
|
+
* is the explicit, type-checked way to say "I declare this message
|
|
344
|
+
* carries no transferables." That's structurally identical to the
|
|
345
|
+
* shape the v2 walker generated for non-binary messages, but here
|
|
346
|
+
* the declaration is at construction time, in the producer's own
|
|
347
|
+
* code, where the knowledge actually lives.
|
|
348
|
+
*
|
|
349
|
+
* wirePack({ kind: 'metadata.read', jobId, docId })
|
|
350
|
+
* wirePack({ kind: 'open.fatMem', jobId, docId, bytes }, [bytes])
|
|
351
|
+
* wirePack({ tag: 'page.render', pixels }, [pixels.buffer])
|
|
352
|
+
*/
|
|
353
|
+
function wirePack(payload, transfer = EMPTY_TRANSFER) {
|
|
354
|
+
return {
|
|
355
|
+
payload,
|
|
356
|
+
transfer
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
exports.ANNOTATION_SUBTYPES = require_subtype.ANNOTATION_SUBTYPES;
|
|
361
|
+
exports.AbortError = require_AbortError.AbortError;
|
|
362
|
+
exports.AbortablePromise = AbortablePromise;
|
|
363
|
+
exports.CONTINUOUS_RENDER_POLICY = CONTINUOUS_RENDER_POLICY;
|
|
364
|
+
exports.DEFAULT_PDF_SAVE_MODE = require_builders.DEFAULT_PDF_SAVE_MODE;
|
|
365
|
+
exports.EMPTY_TRANSFER = EMPTY_TRANSFER;
|
|
366
|
+
exports.EngineError = require_fold.EngineError;
|
|
367
|
+
exports.EngineErrorCode = require_subtype.EngineErrorCode;
|
|
368
|
+
exports.InvalidScope = require_resolver.InvalidScope;
|
|
369
|
+
exports.MissingIdentity = require_resolver.MissingIdentity;
|
|
370
|
+
exports.NO_ANNOTATION_FLAGS = require_builders.NO_ANNOTATION_FLAGS;
|
|
371
|
+
exports.PDF_BITS = require_builders.PDF_BITS;
|
|
372
|
+
exports.PDF_CODE_TO_SUBTYPE = require_subtype.PDF_CODE_TO_SUBTYPE;
|
|
373
|
+
exports.PDF_SUBTYPE_TO_CODE = require_subtype.PDF_SUBTYPE_TO_CODE;
|
|
374
|
+
exports.PdfAnnotationSubtypeCode = require_subtype.PdfAnnotationSubtypeCode;
|
|
375
|
+
exports.PermissionDenied = require_resolver.PermissionDenied;
|
|
376
|
+
exports.SEARCH_FOLD_VERSION = require_fold.SEARCH_FOLD_VERSION;
|
|
377
|
+
exports.SEARCH_REGEX_MAX_LENGTH = require_builders.SEARCH_REGEX_MAX_LENGTH;
|
|
378
|
+
exports.SEARCH_SNIPPET_CONTEXT = require_builders.SEARCH_SNIPPET_CONTEXT;
|
|
379
|
+
exports.UNKNOWN_WEAK_ANNOTATION_STATE = require_builders.UNKNOWN_WEAK_ANNOTATION_STATE;
|
|
380
|
+
exports.advisoryFromPdfBits = advisoryFromPdfBits;
|
|
381
|
+
exports.appearanceImpactOf = require_builders.appearanceImpactOf;
|
|
382
|
+
exports.buildSnippet = require_builders.buildSnippet;
|
|
383
|
+
exports.buildThreads = require_builders.buildThreads;
|
|
384
|
+
exports.canonicalSearchQuery = require_builders.canonicalSearchQuery;
|
|
385
|
+
exports.caps = require_builders.caps;
|
|
386
|
+
exports.changesAnnotationList = require_builders.changesAnnotationList;
|
|
387
|
+
exports.checkAnyCapability = require_resolver.checkAnyCapability;
|
|
388
|
+
exports.checkCapability = require_resolver.checkCapability;
|
|
389
|
+
exports.checkCollab = require_resolver.checkCollab;
|
|
390
|
+
exports.checkSetGroup = require_resolver.checkSetGroup;
|
|
391
|
+
exports.classifyRelation = require_builders.classifyRelation;
|
|
392
|
+
exports.collab = require_builders.collab;
|
|
393
|
+
exports.createPageImageHandle = require_builders.createPageImageHandle;
|
|
394
|
+
exports.decodeFieldRefKey = require_builders.decodeFieldRefKey;
|
|
395
|
+
exports.decodePdfBits = require_builders.decodePdfBits;
|
|
396
|
+
exports.decodeStableIdKey = require_builders.decodeStableIdKey;
|
|
397
|
+
exports.deserializeError = require_fold.deserializeError;
|
|
398
|
+
exports.encodeFieldRefKey = require_builders.encodeFieldRefKey;
|
|
399
|
+
exports.encodeStableIdKey = require_builders.encodeStableIdKey;
|
|
400
|
+
exports.expandRawScope = require_resolver.expandRawScope;
|
|
401
|
+
exports.expandedCapabilities = require_resolver.expandedCapabilities;
|
|
402
|
+
exports.filterMatches = require_resolver.filterMatches;
|
|
403
|
+
exports.foldOptionsFor = require_builders.foldOptionsFor;
|
|
404
|
+
exports.foldText = require_fold.foldText;
|
|
405
|
+
exports.invalidatesWeakIndexRefs = require_builders.invalidatesWeakIndexRefs;
|
|
406
|
+
exports.isAbortError = require_AbortError.isAbortError;
|
|
407
|
+
exports.isValidPageObjectNumber = require_builders.isValidPageObjectNumber;
|
|
408
|
+
exports.knownWeakAnnotationState = require_builders.knownWeakAnnotationState;
|
|
409
|
+
exports.matchLiteral = require_builders.matchLiteral;
|
|
410
|
+
exports.matchPageText = require_builders.matchPageText;
|
|
411
|
+
exports.matchRegex = require_builders.matchRegex;
|
|
412
|
+
exports.materializePdfPermissions = require_builders.materializePdfPermissions;
|
|
413
|
+
exports.normalizeAnnotationDraft = require_builders.normalizeAnnotationDraft;
|
|
414
|
+
exports.normalizeAnnotationPatch = require_builders.normalizeAnnotationPatch;
|
|
415
|
+
exports.normalizeAttachmentFileSource = require_builders.normalizeAttachmentFileSource;
|
|
416
|
+
exports.normalizePdfRect = require_builders.normalizePdfRect;
|
|
417
|
+
exports.parseScope = require_resolver.parseScope;
|
|
418
|
+
exports.passwordPromptFromState = passwordPromptFromState;
|
|
419
|
+
exports.pdfPermissions = require_builders.pdfPermissions;
|
|
420
|
+
exports.pdfQuadBounds = require_builders.pdfQuadBounds;
|
|
421
|
+
exports.pdfQuadCorners = require_builders.pdfQuadCorners;
|
|
422
|
+
exports.pdfQuadFromCorners = require_builders.pdfQuadFromCorners;
|
|
423
|
+
exports.pdfRectFromOriginSize = require_builders.pdfRectFromOriginSize;
|
|
424
|
+
exports.pdfRectHeight = require_builders.pdfRectHeight;
|
|
425
|
+
exports.pdfRectSize = require_builders.pdfRectSize;
|
|
426
|
+
exports.pdfRectToOriginSize = require_builders.pdfRectToOriginSize;
|
|
427
|
+
exports.pdfRectWidth = require_builders.pdfRectWidth;
|
|
428
|
+
exports.permissionInfoFromProbe = permissionInfoFromProbe;
|
|
429
|
+
exports.permissionInfoWithAdvisory = permissionInfoWithAdvisory;
|
|
430
|
+
exports.refKey = require_builders.refKey;
|
|
431
|
+
exports.resolveBinarySource = require_builders.resolveBinarySource;
|
|
432
|
+
exports.revisionTokensEqual = require_builders.revisionTokensEqual;
|
|
433
|
+
exports.searchContentEpoch = require_builders.searchContentEpoch;
|
|
434
|
+
exports.searchRectsForRange = require_builders.searchRectsForRange;
|
|
435
|
+
exports.securityStateFromHead = securityStateFromHead;
|
|
436
|
+
exports.securityStateFromProbe = securityStateFromProbe;
|
|
437
|
+
exports.semanticEqual = require_builders.semanticEqual;
|
|
438
|
+
exports.serializeError = require_fold.serializeError;
|
|
439
|
+
exports.shiftsExistingAnnotationIndices = require_builders.shiftsExistingAnnotationIndices;
|
|
440
|
+
exports.snapAppearanceScale = snapAppearanceScale;
|
|
441
|
+
exports.snapFullPageViewport = snapFullPageViewport;
|
|
442
|
+
exports.snapTileScale = snapTileScale;
|
|
443
|
+
exports.sniffBinaryMetadata = require_builders.sniffBinaryMetadata;
|
|
444
|
+
exports.subtypeFromCode = require_subtype.subtypeFromCode;
|
|
445
|
+
exports.toOriginalRange = require_fold.toOriginalRange;
|
|
446
|
+
exports.validateScopeArray = require_resolver.validateScopeArray;
|
|
447
|
+
exports.validateSearchQuery = require_builders.validateSearchQuery;
|
|
448
|
+
exports.validateSearchRegex = require_builders.validateSearchRegex;
|
|
449
|
+
exports.wirePack = wirePack;
|
|
450
|
+
exports.wordAt = require_builders.wordAt;
|
|
451
|
+
exports.wordBefore = require_builders.wordBefore;
|
|
452
|
+
|
|
453
|
+
//# sourceMappingURL=runtime.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.cjs","names":["AbortError","EngineError","EngineErrorCode"],"sources":["../src/promise/AbortablePromise.ts","../src/engine/document-security-state.ts","../src/engine/DocumentRenderService.ts","../src/engine/passwordPrompt.ts","../src/wire/WirePack.ts"],"sourcesContent":["import { AbortError } from './AbortError';\n\nexport type AbortableExecutor<T, P> = (\n resolve: (value: T | PromiseLike<T>) => void,\n reject: (reason: unknown) => void,\n progress: (p: P) => void,\n signal: AbortSignal,\n) => void;\n\n/**\n * Awaitable Promise subclass with abort and progress.\n *\n * Symbol.species returns plain Promise so chained .then/.catch/.finally\n * return regular promises and never try to synthesize a new\n * AbortablePromise (which would have no executor).\n *\n * Settlement contract:\n * - The first settlement wins. resolve/reject handed to the executor\n * are wrapped so that any subsequent call (whether by the executor,\n * by abort(), or by both racing) becomes a silent no-op.\n * - abort() rejects the public promise with AbortError immediately,\n * even if the executor never observes the AbortSignal. The executor\n * still receives the AbortSignal so it can stop real work\n * cooperatively (release a queue slot, abort fetch, post a worker\n * abort, etc.). Anything the executor does after that — including\n * a late resolve(value), a late reject(error), or a rejected inner\n * Promise inside AbortablePromise.run — is dropped silently.\n * - abort() after settlement is a no-op.\n */\nexport class AbortablePromise<T, P = never> extends Promise<T> {\n static override get [Symbol.species](): PromiseConstructor {\n return Promise;\n }\n\n readonly signal: AbortSignal;\n\n private readonly _ctrl: AbortController;\n private readonly _progressCbs: Set<(p: P) => void>;\n private readonly _state: { settled: boolean };\n private readonly _internalReject: (reason: unknown) => void;\n\n constructor(executor: AbortableExecutor<T, P>) {\n const ctrl = new AbortController();\n const progressCbs = new Set<(p: P) => void>();\n const state = { settled: false };\n let capturedReject!: (reason: unknown) => void;\n\n super((resolve, reject) => {\n capturedReject = reject;\n\n const wrappedResolve = (value: T | PromiseLike<T>) => {\n if (state.settled) return;\n state.settled = true;\n resolve(value);\n };\n const wrappedReject = (reason: unknown) => {\n if (state.settled) return;\n state.settled = true;\n reject(reason);\n };\n const progress = (p: P) => {\n if (state.settled) return;\n for (const cb of progressCbs) {\n try {\n cb(p);\n } catch {\n // ignore subscriber errors\n }\n }\n };\n\n executor(wrappedResolve, wrappedReject, progress, ctrl.signal);\n });\n\n this._ctrl = ctrl;\n this.signal = ctrl.signal;\n this._progressCbs = progressCbs;\n this._state = state;\n this._internalReject = capturedReject;\n }\n\n /**\n * Abort the underlying operation.\n *\n * - If the promise has already settled, this is a no-op.\n * - Otherwise the public promise rejects synchronously with an\n * AbortError (wrapping the supplied reason if it is not already an\n * AbortError) and the AbortSignal fires for any cooperative\n * cancellation the executor wired up.\n */\n abort(reason?: unknown): void {\n if (this._state.settled) return;\n if (this._ctrl.signal.aborted) return;\n\n const err = reason instanceof AbortError ? reason : new AbortError(reason);\n\n // Mark settled before signalling so any abort listener the executor\n // attached cannot race a late resolve/reject through the wrapped\n // settlers (they all consult state.settled).\n this._state.settled = true;\n this._ctrl.abort(err);\n this._internalReject(err);\n }\n\n /**\n * Subscribe to progress events. Returns an unsubscribe function.\n */\n onProgress(cb: (p: P) => void): () => void {\n this._progressCbs.add(cb);\n return () => {\n this._progressCbs.delete(cb);\n };\n }\n\n /**\n * Wrap a value in an already-resolved AbortablePromise. Mirrors Promise.resolve.\n */\n static resolveValue<T>(value: T | PromiseLike<T>): AbortablePromise<T> {\n return new AbortablePromise<T>((resolve) => resolve(value));\n }\n\n /**\n * Wrap a thrown reason in an already-rejected AbortablePromise.\n */\n static rejectReason<T = never>(reason: unknown): AbortablePromise<T> {\n return new AbortablePromise<T>((_resolve, reject) => reject(reason));\n }\n\n /**\n * Run an async function as an AbortablePromise so callers get .abort() and .signal.\n * The async function receives the AbortSignal (and a progress emitter) so it can\n * cooperate with the abort.\n *\n * If abort() fires while the inner async function is still running, the\n * public promise rejects with AbortError immediately. The inner async\n * function's eventual settlement (resolve or reject) is funneled through\n * the wrapped settlers and silently dropped — including a late rejection\n * from the underlying work, which prevents an UnhandledRejection because\n * the .then(resolve, reject) below \"handles\" it via the no-op.\n */\n static run<T, P = never>(\n fn: (signal: AbortSignal, progress: (p: P) => void) => Promise<T>,\n ): AbortablePromise<T, P> {\n return new AbortablePromise<T, P>((resolve, reject, progress, signal) => {\n fn(signal, progress).then(resolve, reject);\n });\n }\n}\n","import type {\n DocumentAccessReason,\n DocumentSecurityState,\n PdfPermissionAdvisory,\n PdfPermissionInfo,\n} from './DocumentSecurityService';\nimport type { PdfBits } from '../auth/scope';\nimport type { DocumentSecurityProbeInfo } from '../wire/worker-protocol';\n\nexport interface DocumentHeadLike {\n encryption: {\n state: DocumentSecurityState['encryption']['state'];\n requiresPassword: boolean | null;\n };\n permissions: DocumentSecurityState['permissions'];\n access: DocumentSecurityState['access'];\n}\n\nexport function securityStateFromHead(head: DocumentHeadLike): DocumentSecurityState {\n return {\n encryption: {\n state: head.encryption.state,\n requiresPassword: head.encryption.requiresPassword,\n },\n permissions: { ...head.permissions },\n access: {\n required: head.access.required,\n reasons: [...head.access.reasons],\n ...(head.access.endpoint ? { endpoint: head.access.endpoint } : {}),\n },\n };\n}\n\nexport function permissionInfoFromProbe(info: DocumentSecurityProbeInfo): PdfPermissionInfo | null {\n if (info.pdfPermissionsBits === null) return null;\n return {\n known: true,\n bits: info.pdfPermissionsBits,\n allAllowed: info.pdfPermissionsAllAllowed,\n openedAs: info.pdfOpenedAs,\n securityHandlerRevision: info.securityHandlerRevision,\n };\n}\n\n/**\n * Same as {@link permissionInfoFromProbe} but additionally populates\n * `flags` (typed PdfBits view) and `advisory` (capability-shaped\n * booleans for UI badges). Used by routes that have a decoded `PdfBits`\n * in hand — notably `/access`, which always does.\n *\n * Returns `null` for the same reason as the base function — when the\n * PDF hasn't been probed yet so bits are unknown.\n */\nexport function permissionInfoWithAdvisory(\n info: DocumentSecurityProbeInfo,\n pdfBits: PdfBits,\n): PdfPermissionInfo | null {\n const base = permissionInfoFromProbe(info);\n if (!base) return null;\n return {\n ...base,\n flags: pdfBits,\n advisory: advisoryFromPdfBits(pdfBits),\n };\n}\n\n/**\n * Translate a {@link PdfBits} view into the capability-shaped\n * {@link PdfPermissionAdvisory}. The rules here MUST mirror the bit\n * combinations the scope resolver uses for `pdf.permissions`\n * expansion — `doc.print.high` requires bit 12 AND bit 3, etc.\n */\nexport function advisoryFromPdfBits(b: PdfBits): PdfPermissionAdvisory {\n return {\n canPrint: b.bit3,\n canPrintHigh: b.bit12 && b.bit3,\n canCopy: b.bit5,\n canAnnotate: b.bit6,\n canFillForms: b.bit6 || b.bit9,\n canModifyForms: b.bit6 && b.bit4,\n canModifyPages: b.bit4,\n canAssemble: b.bit11,\n };\n}\n\nexport function securityStateFromProbe(\n info: DocumentSecurityProbeInfo,\n opts: { accessEndpoint?: string; cdnRequired?: boolean } = {},\n): DocumentSecurityState {\n const permission = permissionInfoFromProbe(info);\n const reasons: DocumentAccessReason[] = [];\n if (info.encryptionRequiresPassword === true && !permission) reasons.push('password');\n if (opts.cdnRequired) reasons.push('cdn');\n if (info.encryptionState === 'unknown') reasons.push('permissions-unknown');\n\n return {\n encryption: {\n state: info.encryptionState,\n requiresPassword: info.encryptionRequiresPassword,\n },\n permissions: {\n known: permission?.known ?? false,\n bits: permission?.bits ?? null,\n allAllowed: permission?.allAllowed ?? null,\n openedAs: permission?.openedAs ?? null,\n securityHandlerRevision: permission?.securityHandlerRevision ?? null,\n canUpgradeToOwner: info.encryptionState === 'encrypted' && info.pdfOpenedAs !== 'owner',\n },\n access: {\n required: reasons.length > 0,\n reasons,\n ...(reasons.length > 0 && opts.accessEndpoint ? { endpoint: opts.accessEndpoint } : {}),\n },\n };\n}\n","import { EngineError } from '../errors/EngineError';\nimport { EngineErrorCode } from '../errors/EngineErrorCode';\nimport type { PageRenderViewport } from '../dto/PageRender';\n\n/**\n * The engine's render-parameter policy.\n *\n * - `continuous` — any viewport renders exactly as requested. The LOCAL\n * engine always answers this: rendering is in-process, there is no\n * shared cache to protect, and exactness is the local product promise.\n * - `lattice` — the deployment treats a finite set of render points as\n * durable, CDN-shared artifacts. The bounded quantity\n * is OUTPUT PIXELS, never zoom:\n *\n * - `fullPage.widths` — full-page renders quantize on `viewport.width`\n * (a scale lattice bounds artifact COUNT but not SIZE: PDF page space\n * is effectively unbounded, so scale 1 of a poster page is a memory\n * bomb while width caps the dominant dimension by construction).\n * - `tiles` — RESERVED for the deep-zoom vertical: a scale-based\n * pyramid × fixed tile size, where per-job cost is constant. Absent\n * until the tiling plugin ships; reserving the shape keeps the SDK\n * contract from churning twice.\n * - `maxRenderPixels` — the worker-side output budget for degenerate\n * geometry (width bounds width, not height).\n *\n * The SDK never conforms a request implicitly — the same `render.image`\n * call must not return different pixels on local vs cloud. Conformance is\n * the caller's visible choice via {@link snapFullPageViewport}.\n */\nexport type EngineRenderPolicy =\n | { readonly kind: 'continuous' }\n | {\n readonly kind: 'lattice';\n readonly fullPage: { readonly widths: readonly number[] };\n readonly tiles?: {\n readonly tileSizes: readonly number[];\n readonly scales: readonly number[];\n };\n /**\n * Annotation-appearance lattice — SCALE-based, unlike full pages:\n * an appearance is sized by `annotation.rect × scale`, rects span\n * orders of magnitude (a 4pt caret vs a page-sized stamp), and the\n * composite must track the PAGE's effective render scale or\n * annotations sit blurry on a crisp raster. Small images → the\n * ladder affords finer, taller steps than pages ever could.\n */\n readonly appearances?: { readonly scales: readonly number[] };\n readonly maxRenderPixels?: number;\n readonly formats: readonly ('webp' | 'png')[];\n readonly background: 'white';\n readonly enforced: boolean;\n };\n\nexport const CONTINUOUS_RENDER_POLICY: EngineRenderPolicy = { kind: 'continuous' };\n\n/**\n * Document-scoped render policy surface (`doc.render`). Async because the\n * cloud engine learns its policy from `/v1/access`; the local engine\n * resolves immediately with `continuous`.\n *\n * Per-page rendering itself stays on `page(pon).render` — this service\n * carries POLICY, not pixels.\n */\nexport interface DocumentRenderService {\n policy(): Promise<EngineRenderPolicy>;\n}\n\n/**\n * Conform a FULL-PAGE viewport to a render policy — the ONE snap\n * implementation, shared by every engine and plugin. Pure and explicit\n * by design:\n *\n * - `continuous` → identity (local/cloud plugin code stays byte-identical).\n * - `lattice` → returns a `width`-kind viewport at the smallest ladder\n * width ≥ the requested detail (snap UP: always crisp, CSS downscales\n * for free), capped at the largest width — detail beyond the cap is the\n * tile pyramid's job, by design.\n * - `scale`-kind requests convert through the page's width in PDF user\n * units — pass `opts.pageWidth` (the caller has it from the layout);\n * omitting it for a scale viewport under a lattice policy is a\n * programmer error and throws `InvalidArg`.\n */\nexport function snapFullPageViewport(\n policy: EngineRenderPolicy,\n viewport: PageRenderViewport,\n opts?: { pageWidth?: number },\n): PageRenderViewport {\n if (policy.kind === 'continuous') return viewport;\n if (policy.fullPage.widths.length === 0) {\n throw new EngineError(EngineErrorCode.InvalidArg, 'render policy has an empty width ladder');\n }\n const widths = [...policy.fullPage.widths].sort((a, b) => a - b);\n\n let requested: number;\n if (viewport.kind === 'width') {\n requested = viewport.width;\n } else {\n const pageWidth = opts?.pageWidth;\n if (pageWidth === undefined || pageWidth <= 0) {\n throw new EngineError(\n EngineErrorCode.InvalidArg,\n 'snapping a scale viewport to a width lattice requires opts.pageWidth',\n );\n }\n requested = (viewport.scale ?? 1) * pageWidth;\n }\n\n const snapped = widths.find((width) => width >= requested) ?? widths[widths.length - 1]!;\n return { kind: 'width', width: snapped };\n}\n\n/**\n * Conform an annotation-appearance scale to the policy's appearance\n * lattice. Same discipline as {@link snapFullPageViewport}: identity on\n * continuous (and when the policy carries no appearance block), snap UP,\n * cap at the largest point. Callers derive `scale` from the page's\n * effective render scale (`snappedWidth / pageWidth`, × devicePixelRatio\n * as needed) so composites stay crisp against the page raster.\n */\nexport function snapAppearanceScale(policy: EngineRenderPolicy, scale: number): number {\n if (policy.kind === 'continuous' || policy.appearances === undefined) return scale;\n if (policy.appearances.scales.length === 0) {\n throw new EngineError(\n EngineErrorCode.InvalidArg,\n 'render policy has an empty appearance-scale lattice',\n );\n }\n const scales = [...policy.appearances.scales].sort((a, b) => a - b);\n return scales.find((s) => s >= scale) ?? scales[scales.length - 1]!;\n}\n\n/**\n * Conform a tile-pyramid scale to the policy's tile lattice — the third\n * member of the `snap<PolicyBlock><Quantity>` family. Identity on\n * continuous and while the deployment doesn't advertise a `tiles` block\n * (the block is reserved until the deep-zoom vertical ships server-side;\n * the tiling client uses its own default pyramid then — see\n * plugin-render). Snap UP, cap at the largest scale: per-tile cost is\n * constant by construction (`tileSize²` pixels regardless of level), so\n * the cap bounds artifact COUNT, not memory.\n */\nexport function snapTileScale(policy: EngineRenderPolicy, scale: number): number {\n if (policy.kind === 'continuous' || policy.tiles === undefined) return scale;\n if (policy.tiles.scales.length === 0) {\n throw new EngineError(\n EngineErrorCode.InvalidArg,\n 'render policy has an empty tile-scale lattice',\n );\n }\n const scales = [...policy.tiles.scales].sort((a, b) => a - b);\n return scales.find((s) => s >= scale) ?? scales[scales.length - 1]!;\n}\n","/**\n * Unified \"should I ask the user for a password?\" shape.\n *\n * A PDF has two distinct password moments:\n * 1. **Required** — the document is encrypted and we couldn't read\n * anything anonymously. The dev MUST gather a password and call\n * `unlock()` before any other operation succeeds.\n * 2. **Optional** — the document is open and readable, but more\n * permissions become available with the owner password. The dev\n * MAY surface an \"unlock for full access\" affordance.\n *\n * Plus the trivial third state: **none** — nothing to do.\n *\n * The discriminated union encodes the invariants:\n * - `required` and `optional` cannot both be true (a doc you can't\n * read can't be \"upgraded\" — you have to read first).\n * - `hint` is only present when meaningful (no hint in the `none` arm,\n * mandatory `owner` hint in `optional` since that's the only thing\n * an upgrade asks for).\n *\n * Computed identically on local + cloud via\n * {@link passwordPromptFromState} so the dev's UI gating code is\n * engine-agnostic.\n */\nimport type { DocumentSecurityState } from './DocumentSecurityService';\n\nexport type PasswordPrompt =\n | { readonly state: 'none' }\n | { readonly state: 'required'; readonly hint: 'user' | 'owner' | null }\n | { readonly state: 'optional'; readonly hint: 'owner' };\n\n/**\n * Derive the high-level password prompt from the raw security state.\n *\n * The function is pure and total — every `DocumentSecurityState`\n * maps to exactly one `PasswordPrompt`. Use this as the SINGLE source\n * of truth wherever the SDK exposes a \"do you need a password?\" flag:\n * both `LocalDocumentSecurityService` and `CloudDocumentSecurityService`\n * call it, so the contract can never drift.\n *\n * Mapping rules (top to bottom; first match wins):\n *\n * 1. encryption.state === 'none'\n * → { state: 'none' } the document isn't encrypted\n *\n * 2. !permissions.known\n * → { state: 'required', hint: null } we haven't probed yet; can't\n * tell user-vs-owner; show\n * generic prompt\n *\n * 3. requiresPassword && openedAs === 'none'\n * → { state: 'required', hint: 'user' } encrypted, anonymous open\n * failed → user pwd needed\n *\n * 4. openedAs === 'owner'\n * → { state: 'none' } already at the top — nothing more\n * to unlock\n *\n * 5. permissions.canUpgradeToOwner === true\n * → { state: 'optional', hint: 'owner' } open as user (or as none\n * for owner-pwd-only docs)\n * but more is available\n *\n * 6. fallthrough → { state: 'none' } open and nothing more available\n */\nexport function passwordPromptFromState(state: DocumentSecurityState): PasswordPrompt {\n if (state.encryption.state === 'none') {\n return { state: 'none' };\n }\n\n if (!state.permissions.known) {\n return { state: 'required', hint: null };\n }\n\n if (state.encryption.requiresPassword && state.permissions.openedAs === 'none') {\n return { state: 'required', hint: 'user' };\n }\n\n if (state.permissions.openedAs === 'owner') {\n return { state: 'none' };\n }\n\n if (state.permissions.canUpgradeToOwner) {\n return { state: 'optional', hint: 'owner' };\n }\n\n return { state: 'none' };\n}\n","/**\n * Wire-level packaging for messages crossing a Web Worker / Node\n * `worker_thread` boundary.\n *\n * `WirePack<P>` is the typed pair every producer hands to a transport:\n * the structured payload (validated against the wire schema) and an\n * explicit, ordered list of `Transferable` objects that the producer\n * intends to move (zero-copy) to the receiver.\n *\n * Why this is a first-class type and not a transport-side argument:\n *\n * - **Producer is the only one who knows.** Whether a particular\n * `ArrayBuffer` should be moved (zero-copy, sender's reference\n * detached) or copied (structured-cloned, both sides retain\n * access) is a semantic decision belonging to the code that\n * produced the buffer. Inferring it later — by walking the\n * payload looking for `ArrayBuffer` instances and assuming they\n * should all be transferred — is the v2 footgun this design\n * replaces.\n *\n * - **Type-checked at the boundary.** A handler returning\n * `WirePack<RenderResult>` cannot forget to declare its\n * transfer list; the producer literally writes\n * `wirePack({ ..., pixels }, [pixels.buffer])` in a single\n * return statement. Forgetting yields a structurally identical\n * copy (slow but correct), never a silent leak.\n *\n * - **Symmetric across the boundary.** Same `WirePack<P>` on the\n * request path (main → worker) and the response path (worker →\n * main). Inline transports treat `transfer` as a no-op since\n * there's no thread boundary to cross.\n *\n * - **Schema-orthogonal.** Zod schemas validate `payload` and\n * nothing else. `transfer` is not data; it's a memory-ownership\n * manifest, and the design keeps those concerns separate.\n *\n * The receiver of a `postMessage(payload, { transfer })` call gets\n * the payload back **with the listed buffers already moved into it**\n * — there's no second argument on the receiving end. So `WirePack`\n * only ever travels the producer-to-transport leg of the trip; the\n * consumer side just sees the unwrapped `payload`.\n */\nexport interface WirePack<P> {\n readonly payload: P;\n readonly transfer: readonly Transferable[];\n}\n\n/**\n * Singleton empty transfer list. Frozen so accidental in-place\n * mutation throws in strict mode rather than silently mutating the\n * default for future calls.\n */\nexport const EMPTY_TRANSFER: readonly Transferable[] = Object.freeze([]);\n\n/**\n * Producer-side helper: pair a typed payload with its transfer list.\n *\n * The `transfer` argument is optional; omitting it (or passing `[]`)\n * is the explicit, type-checked way to say \"I declare this message\n * carries no transferables.\" That's structurally identical to the\n * shape the v2 walker generated for non-binary messages, but here\n * the declaration is at construction time, in the producer's own\n * code, where the knowledge actually lives.\n *\n * wirePack({ kind: 'metadata.read', jobId, docId })\n * wirePack({ kind: 'open.fatMem', jobId, docId, bytes }, [bytes])\n * wirePack({ tag: 'page.render', pixels }, [pixels.buffer])\n */\nexport function wirePack<P>(\n payload: P,\n transfer: readonly Transferable[] = EMPTY_TRANSFER,\n): WirePack<P> {\n return { payload, transfer };\n}\n"],"mappings":"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"}
|