@embedpdf/plugin-actions 3.0.0-next.11 → 3.0.0-next.13

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.js CHANGED
@@ -1,7 +1,39 @@
1
1
  import { n as eventOf, r as originOf, t as ActionsToken } from "./types-DgBMy5nE.js";
2
2
  import { n as createHoverPump, t as submitEntriesToUrlEncoded } from "./contract-DAem-EST.js";
3
3
  import { DocumentsToken, createEventHook, createSerialQueue, definePlugin } from "@embedpdf/core";
4
- import { createScriptHost, javaScriptProgramFromActionTree, resolveScriptIdentity, scriptFieldsFromSnapshot, seedFrom } from "@embedpdf/core-acrojs";
4
+ import { DEFAULT_SCRIPT_BUDGET, createScriptHost, javaScriptProgramFromActionTree, resolveScriptIdentity, scriptFieldsFromSnapshot, seedFrom } from "@embedpdf/core-acrojs";
5
+ //#region src/script-environment.ts
6
+ function createScriptRealmFactory(js, identityDoc) {
7
+ const sandboxFactory = js.sandboxFactory ?? (() => import("@embedpdf/core-js-sandbox").then(({ createQuickJsSandbox }) => createQuickJsSandbox()));
8
+ const budget = js.budget ?? DEFAULT_SCRIPT_BUDGET;
9
+ return {
10
+ budget,
11
+ realmFor: (target) => createScriptHost({
12
+ sandboxFactory,
13
+ document: () => {
14
+ const meta = target.document();
15
+ return {
16
+ id: target.doc.id,
17
+ fileName: js.fileName?.() ?? meta?.name ?? "document.pdf",
18
+ pageCount: meta?.pageCount ?? 0,
19
+ pageNumber: 0
20
+ };
21
+ },
22
+ identity: () => resolveScriptIdentity(identityDoc, js.identity),
23
+ environment: (sequence) => {
24
+ const nowMs = js.now?.() ?? Date.now();
25
+ return {
26
+ nowMs,
27
+ utcOffsetMinutes: js.utcOffsetMinutes?.() ?? -new Date(nowMs).getTimezoneOffset(),
28
+ randomSeed: js.randomSeed?.() ?? seedFrom(target.doc.id, sequence)
29
+ };
30
+ },
31
+ bootSources: target.bootSources,
32
+ budget
33
+ })
34
+ };
35
+ }
36
+ //#endregion
5
37
  //#region src/capability.ts
6
38
  const ALLOW_ALL = {
7
39
  user: "allow",
@@ -225,35 +257,13 @@ function createActionsCapability(ctx, config = {}) {
225
257
  };
226
258
  };
227
259
  const js = config.javascript;
228
- const scriptHost = js?.enabled && ctx.doc ? createScriptHost({
229
- sandboxFactory: js.sandboxFactory ?? (() => import("@embedpdf/core-js-sandbox").then(({ createQuickJsSandbox }) => createQuickJsSandbox())),
230
- document: () => {
231
- const meta = ctx.document();
232
- return {
233
- id: ctx.documentId ?? "document",
234
- fileName: js.fileName?.() ?? meta?.name ?? "document.pdf",
235
- pageCount: meta?.pageCount ?? 0,
236
- pageNumber: 0
237
- };
238
- },
239
- identity: () => ctx.doc ? resolveScriptIdentity(ctx.doc, js.identity) : {
240
- name: "",
241
- loginName: "",
242
- corporation: "",
243
- email: ""
244
- },
245
- environment: (sequence) => {
246
- const nowMs = js.now?.() ?? Date.now();
247
- return {
248
- nowMs,
249
- utcOffsetMinutes: js.utcOffsetMinutes?.() ?? -new Date(nowMs).getTimezoneOffset(),
250
- randomSeed: js.randomSeed?.() ?? seedFrom(ctx.documentId ?? "document", sequence)
251
- };
252
- },
260
+ const realms = js?.enabled && ctx.doc ? createScriptRealmFactory(js, ctx.doc) : null;
261
+ const scriptHost = realms && ctx.doc ? realms.realmFor({
262
+ doc: ctx.doc,
263
+ document: () => ctx.document(),
253
264
  bootSources: async () => {
254
265
  return ((await readDocumentActions())?.nameTreeScripts ?? []).map(({ action }) => javaScriptProgramFromActionTree(action));
255
- },
256
- ...js.budget ? { budget: js.budget } : {}
266
+ }
257
267
  }) : null;
258
268
  if (scriptHost) ctx.cleanup(() => scriptHost.dispose());
259
269
  const surfaceScriptResult = (result) => {
@@ -262,6 +272,13 @@ function createActionsCapability(ctx, config = {}) {
262
272
  phase: result.phase
263
273
  };
264
274
  for (const effect of result.uiEffects) {
275
+ if (result.realm === "detached" && effect.kind !== "alert") {
276
+ scriptDiagnosticHook.emit({
277
+ code: "ui-effect-suppressed",
278
+ message: `script ${effect.kind} request from a detached realm suppressed: no document surface`
279
+ });
280
+ continue;
281
+ }
265
282
  if (effect.kind === "submitForm") {
266
283
  performSubmit(intentOfSubmitEffect(effect), {
267
284
  origin: result.origin,
@@ -302,6 +319,23 @@ function createActionsCapability(ctx, config = {}) {
302
319
  for (const diagnostic of result.diagnostics) scriptDiagnosticHook.emit(diagnostic);
303
320
  if (result.error) scriptErrorHook.emit(result.error);
304
321
  };
322
+ /** A K/V/C/F commit surfaces as up to two results: the boot phase (only
323
+ * when it produced effects) and the user phase (always — it carries the
324
+ * diagnostics and the error). */
325
+ const surfaceScriptCommit = (commit, context) => {
326
+ for (const phase of ["boot", "user"]) {
327
+ const uiEffects = commit.uiEffects.filter((effect) => effect.phase === phase);
328
+ if (uiEffects.length === 0 && phase === "boot") continue;
329
+ surfaceScriptResult({
330
+ uiEffects,
331
+ diagnostics: phase === "user" ? commit.diagnostics : [],
332
+ ...phase === "user" && commit.error ? { error: commit.error } : {},
333
+ origin: context.origin,
334
+ phase,
335
+ realm: context.realm
336
+ });
337
+ }
338
+ };
305
339
  /** Script `doc.submitForm(...)` → the one normalized intent. Script field
306
340
  * names are include-mode by definition (Acrobat's aFields). */
307
341
  const intentOfSubmitEffect = (effect) => {
@@ -498,7 +532,8 @@ function createActionsCapability(ctx, config = {}) {
498
532
  diagnostics: boot.diagnostics,
499
533
  ...boot.error ? { error: boot.error } : {},
500
534
  origin: actionCtx.origin,
501
- phase: "boot"
535
+ phase: "boot",
536
+ realm: "document"
502
537
  });
503
538
  if (boot.formEffects.length || boot.annotEffects.length) built = await scriptWorldFor(pon);
504
539
  }
@@ -511,7 +546,8 @@ function createActionsCapability(ctx, config = {}) {
511
546
  diagnostics: output.diagnostics,
512
547
  ...output.error ? { error: output.error } : {},
513
548
  origin: actionCtx.origin,
514
- phase: "user"
549
+ phase: "user",
550
+ realm: "document"
515
551
  });
516
552
  if (output.error) return {
517
553
  status: "failed",
@@ -1335,8 +1371,22 @@ function createActionsCapability(ctx, config = {}) {
1335
1371
  if (formCommitSink === sink) formCommitSink = null;
1336
1372
  };
1337
1373
  },
1338
- ...scriptHost ? { scriptTransaction: (body) => scriptHost.transaction(body) } : {},
1374
+ ...scriptHost && realms ? {
1375
+ scriptRealm: {
1376
+ transaction: (body) => scriptHost.transaction(body),
1377
+ budget: realms.budget
1378
+ },
1379
+ createDetachedScriptRealm: (target) => {
1380
+ const host = realms.realmFor(target);
1381
+ return {
1382
+ transaction: (body) => host.transaction(body),
1383
+ budget: realms.budget,
1384
+ dispose: () => host.dispose()
1385
+ };
1386
+ }
1387
+ } : {},
1339
1388
  surfaceScriptResult,
1389
+ surfaceScriptCommit,
1340
1390
  reportPageState,
1341
1391
  registerSubmitResolver: (resolver) => {
1342
1392
  submitResolver = resolver;