@embedpdf/plugin-page-edit 3.0.0-next.0 → 3.0.0-next.10

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.cjs CHANGED
@@ -26,6 +26,43 @@ function createPageEditCapability(ctx) {
26
26
  const rotationOf = (pon) => {
27
27
  return (ctx.document()?.pages.find((p) => p.pageObjectNumber === pon))?.rotation ?? 0;
28
28
  };
29
+ /**
30
+ * Resolve a placement to the engine's index wire, from the registry at
31
+ * call time — the PON anchors are why "add after this thumbnail" survives
32
+ * a concurrent reorder. Returns the anchor page too, so `addBlank` can
33
+ * default its size without a second lookup.
34
+ */
35
+ const resolvePlacement = (placement) => {
36
+ if (!placement) return {
37
+ destIndex: void 0,
38
+ anchor: void 0
39
+ };
40
+ if ("index" in placement) return {
41
+ destIndex: placement.index,
42
+ anchor: void 0
43
+ };
44
+ const pon = "after" in placement ? placement.after : placement.before;
45
+ const anchor = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);
46
+ if (!anchor) throw new Error(`[page-edit] placement page not found: ${pon}`);
47
+ return {
48
+ destIndex: "after" in placement ? anchor.index + 1 : anchor.index,
49
+ anchor
50
+ };
51
+ };
52
+ /**
53
+ * Default blank-page size: the insertion point's predecessor (the page
54
+ * the new one will follow), else the first page, else — only reachable
55
+ * with an empty registry, which an open document never has — US Letter.
56
+ */
57
+ const neighbourSize = (destIndex) => {
58
+ const pages = ctx.document()?.pages ?? [];
59
+ if (pages.length === 0) return {
60
+ width: 612,
61
+ height: 792
62
+ };
63
+ if (destIndex === void 0) return pages[pages.length - 1].size;
64
+ return pages[Math.max(0, Math.min(destIndex - 1, pages.length - 1))].size;
65
+ };
29
66
  return {
30
67
  canEdit() {
31
68
  return ctx.doc?.security.allows(ASSEMBLE_CAPABILITY) ?? false;
@@ -42,6 +79,20 @@ function createPageEditCapability(ctx) {
42
79
  },
43
80
  delete(pons) {
44
81
  return requireDoc().pages.delete(pons);
82
+ },
83
+ addBlank(opts = {}) {
84
+ const doc = requireDoc();
85
+ const { destIndex, anchor } = resolvePlacement(opts.placement);
86
+ const size = opts.size ?? anchor?.size ?? neighbourSize(destIndex);
87
+ return doc.pages.insertBlank({
88
+ size,
89
+ count: opts.count
90
+ }, destIndex);
91
+ },
92
+ insert(bytes, opts = {}) {
93
+ const doc = requireDoc();
94
+ const { destIndex } = resolvePlacement(opts.placement);
95
+ return doc.pages.insert(bytes, destIndex);
45
96
  }
46
97
  };
47
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/capability.ts","../src/types.ts","../src/page-edit.plugin.ts"],"sourcesContent":["import type { PluginContext, PageObjectNumber, PageRotation, DocCapability } from '@embedpdf/core';\nimport type { PageEditCapability } from './types';\n\n/**\n * Authorization for structural page edits. Maps to PDF bit 11 (ASSEMBLE =\n * insert/rotate/delete pages). The engine ALSO enforces this — every\n * page-structure verb throws `PermissionDenied` without it, identically on\n * local and cloud — so `canEdit()` is the UI mirror of a real guard, not the\n * guard itself. Typed as `DocCapability` so a typo is a compile error.\n */\nconst ASSEMBLE_CAPABILITY: DocCapability = 'doc.pages.assemble';\n\n/**\n * Forwards structural edits to the document's engine handle, addressed by PON.\n * The handle (`ctx.doc`) and the page registry (`ctx.document()`, kept in sync\n * by the kernel's event→registry bridge) are both already on the plugin\n * context — this capability is the thin layer that turns the relative rotate\n * gesture into the engine's absolute wire.\n */\nexport function createPageEditCapability(ctx: PluginContext<unknown>): PageEditCapability {\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[page-edit] no document bound');\n return doc;\n };\n\n /** Current absolute rotation of a page from the registry; 0 if unknown. */\n const rotationOf = (pon: PageObjectNumber): PageRotation => {\n const page = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n return page?.rotation ?? 0;\n };\n\n return {\n canEdit() {\n // Wildcard-aware predicate (mirrors the engine's own enforcement),\n // identical on both engines. NOT `effectiveScope.includes(...)` — that\n // enumeration drops the `*` admin grant, so it would hide the UI on a\n // default admin open even though the engine allows the edit.\n return ctx.doc?.security.allows(ASSEMBLE_CAPABILITY) ?? false;\n },\n\n rotateBy(pon, delta) {\n // Wrap to [0, 360) — the double-mod keeps -90 from current 0 landing on 270.\n const next = ((((rotationOf(pon) + delta) % 360) + 360) % 360) as PageRotation;\n return requireDoc().pages.rotate([pon], next);\n },\n\n setRotation(pons, rotation) {\n return requireDoc().pages.rotate(pons, rotation);\n },\n\n move(pons, destIndex) {\n return requireDoc().pages.move(pons, destIndex);\n },\n\n delete(pons) {\n return requireDoc().pages.delete(pons);\n },\n };\n}\n","import {\n createCapabilityToken,\n type AbortablePromise,\n type PageObjectNumber,\n type PageRotation,\n type PageRotateResult,\n type PageMoveResult,\n type PageDeleteResult,\n} from '@embedpdf/core';\n\n/**\n * Structural page edits, addressed by durable PON (never display index — an\n * index shifts the moment a sibling is moved or deleted). Mirrors the engine's\n * `DocumentPagesService` 1:1, with one addition the engine can't have: the\n * relative `rotateBy` gesture. The engine wire is always ABSOLUTE; turning a\n * \"+90° on this thumbnail\" click into an absolute value needs the page's\n * current rotation, so that read+arithmetic lives HERE — once — instead of\n * being re-derived in every framework adapter's click handler.\n *\n * Document-scoped: rotation is shared document metadata, so editing through the\n * sidebar lens and seeing it in the main lens is automatic (both read the same\n * registry, which the kernel keeps in sync from the engine's event stream).\n */\nexport interface PageEditCapability {\n /**\n * Whether this caller is authorized to perform structural page edits —\n * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate their\n * edit affordances on this; the engine independently enforces the same\n * capability and throws `PermissionDenied` if a call slips through.\n */\n canEdit(): boolean;\n\n /**\n * Rotate a SINGLE page by a relative quarter-turn — the per-thumbnail button\n * gesture. Reads the page's current rotation from the registry and forwards\n * the resulting absolute rotation to the engine.\n */\n rotateBy(pon: PageObjectNumber, delta: 90 | -90): AbortablePromise<PageRotateResult>;\n\n /**\n * Set the ABSOLUTE rotation of one or more pages to a single shared value —\n * the multi-select gesture. Maps 1:1 to the engine.\n */\n setRotation(pons: PageObjectNumber[], rotation: PageRotation): AbortablePromise<PageRotateResult>;\n\n /** Reorder pages (by PON) as a contiguous block starting at `destIndex`. */\n move(pons: PageObjectNumber[], destIndex: number): AbortablePromise<PageMoveResult>;\n\n /** Delete pages by PON. The engine rejects deleting every page. */\n delete(pons: PageObjectNumber[]): AbortablePromise<PageDeleteResult>;\n}\n\nexport const PageEditToken = createCapabilityToken<PageEditCapability>('page-edit');\n","import { definePlugin } from '@embedpdf/core';\nimport { createPageEditCapability } from './capability';\nimport { PageEditToken } from './types';\n\n/**\n * Document-scoped, stateless: turns the engine handle's page service into a\n * PON-addressed edit capability. The relative→absolute rotation lives in the\n * capability so the four framework adapters never re-derive it, and this is the\n * home for client-side edit state (pending/optimistic/undo) when it lands —\n * adapters keep their thin hook over `PageEditToken` unchanged.\n */\nexport const pageEditPlugin = () =>\n definePlugin({\n id: 'page-edit',\n scope: 'document',\n token: PageEditToken,\n capability: createPageEditCapability,\n });\n"],"mappings":";;;;;;;;;;AAUA,MAAM,sBAAqC;;;;;;;;AAS3C,SAAgB,yBAAyB,KAAiD;CACxF,MAAM,mBAAmB;EACvB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,+BAA+B;EACzD,OAAO;CACT;;CAGA,MAAM,cAAc,QAAwC;EAE1D,QADa,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,EAAE,qBAAqB,GAAG,EAAA,EAC5D,YAAY;CAC3B;CAEA,OAAO;EACL,UAAU;GAKR,OAAO,IAAI,KAAK,SAAS,OAAO,mBAAmB,KAAK;EAC1D;EAEA,SAAS,KAAK,OAAO;GAEnB,MAAM,SAAW,WAAW,GAAG,IAAI,SAAS,MAAO,OAAO;GAC1D,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,GAAG,IAAI;EAC9C;EAEA,YAAY,MAAM,UAAU;GAC1B,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,MAAM,QAAQ;EACjD;EAEA,KAAK,MAAM,WAAW;GACpB,OAAO,WAAW,CAAC,CAAC,MAAM,KAAK,MAAM,SAAS;EAChD;EAEA,OAAO,MAAM;GACX,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,IAAI;EACvC;CACF;AACF;;;ACPA,MAAa,iBAAA,GAAA,eAAA,sBAAA,CAA0D,WAAW;;;;;;;;;;ACzClF,MAAa,wBAAA,GAAA,eAAA,aAAA,CACE;CACX,IAAI;CACJ,OAAO;CACP,OAAO;CACP,YAAY;AACd,CAAC"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/capability.ts","../src/types.ts","../src/page-edit.plugin.ts"],"sourcesContent":["import type {\n PluginContext,\n PageObjectNumber,\n PageRotation,\n DocCapability,\n PdfSize,\n} from '@embedpdf/core';\nimport type { PageEditCapability, PagePlacement } from './types';\n\n/**\n * Authorization for structural page edits. Maps to PDF bit 11 (ASSEMBLE =\n * insert/rotate/delete pages). The engine ALSO enforces this — every\n * page-structure verb throws `PermissionDenied` without it, identically on\n * local and cloud — so `canEdit()` is the UI mirror of a real guard, not the\n * guard itself. Typed as `DocCapability` so a typo is a compile error.\n */\nconst ASSEMBLE_CAPABILITY: DocCapability = 'doc.pages.assemble';\n\n/**\n * Forwards structural edits to the document's engine handle, addressed by PON.\n * The handle (`ctx.doc`) and the page registry (`ctx.document()`, kept in sync\n * by the kernel's event→registry bridge) are both already on the plugin\n * context — this capability is the thin layer that turns the relative rotate\n * gesture into the engine's absolute wire.\n */\nexport function createPageEditCapability(ctx: PluginContext<unknown>): PageEditCapability {\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[page-edit] no document bound');\n return doc;\n };\n\n /** Current absolute rotation of a page from the registry; 0 if unknown. */\n const rotationOf = (pon: PageObjectNumber): PageRotation => {\n const page = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n return page?.rotation ?? 0;\n };\n\n /**\n * Resolve a placement to the engine's index wire, from the registry at\n * call time — the PON anchors are why \"add after this thumbnail\" survives\n * a concurrent reorder. Returns the anchor page too, so `addBlank` can\n * default its size without a second lookup.\n */\n const resolvePlacement = (placement?: PagePlacement) => {\n if (!placement) return { destIndex: undefined, anchor: undefined };\n if ('index' in placement) return { destIndex: placement.index, anchor: undefined };\n const pon = 'after' in placement ? placement.after : placement.before;\n const anchor = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n if (!anchor) throw new Error(`[page-edit] placement page not found: ${pon}`);\n return { destIndex: 'after' in placement ? anchor.index + 1 : anchor.index, anchor };\n };\n\n /**\n * Default blank-page size: the insertion point's predecessor (the page\n * the new one will follow), else the first page, else — only reachable\n * with an empty registry, which an open document never has — US Letter.\n */\n const neighbourSize = (destIndex: number | undefined): PdfSize => {\n const pages = ctx.document()?.pages ?? [];\n if (pages.length === 0) return { width: 612, height: 792 };\n if (destIndex === undefined) return pages[pages.length - 1].size;\n return pages[Math.max(0, Math.min(destIndex - 1, pages.length - 1))].size;\n };\n\n return {\n canEdit() {\n // Wildcard-aware predicate (mirrors the engine's own enforcement),\n // identical on both engines. NOT `effectiveScope.includes(...)` — that\n // enumeration drops the `*` admin grant, so it would hide the UI on a\n // default admin open even though the engine allows the edit.\n return ctx.doc?.security.allows(ASSEMBLE_CAPABILITY) ?? false;\n },\n\n rotateBy(pon, delta) {\n // Wrap to [0, 360) — the double-mod keeps -90 from current 0 landing on 270.\n const next = ((((rotationOf(pon) + delta) % 360) + 360) % 360) as PageRotation;\n return requireDoc().pages.rotate([pon], next);\n },\n\n setRotation(pons, rotation) {\n return requireDoc().pages.rotate(pons, rotation);\n },\n\n move(pons, destIndex) {\n return requireDoc().pages.move(pons, destIndex);\n },\n\n delete(pons) {\n return requireDoc().pages.delete(pons);\n },\n\n addBlank(opts = {}) {\n const doc = requireDoc();\n const { destIndex, anchor } = resolvePlacement(opts.placement);\n // PON placements match the anchor the user is looking at; everything\n // else matches the neighbour the new page will follow.\n const size = opts.size ?? anchor?.size ?? neighbourSize(destIndex);\n return doc.pages.insertBlank({ size, count: opts.count }, destIndex);\n },\n\n insert(bytes, opts = {}) {\n const doc = requireDoc();\n const { destIndex } = resolvePlacement(opts.placement);\n return doc.pages.insert(bytes, destIndex);\n },\n };\n}\n","import {\n createCapabilityToken,\n type AbortablePromise,\n type PageObjectNumber,\n type PageRotation,\n type PageRotateResult,\n type PageMoveResult,\n type PageDeleteResult,\n type PageInsertResult,\n type PdfSize,\n} from '@embedpdf/core';\n\n/**\n * Where added pages land. The PON anchors are the thumbnail gestures (\"+\n * after this page\") and stay correct across a concurrent reorder between\n * click and call — a raw index does not; `index` remains for absolute\n * positions (\"at the start\"). Omitted → append. Resolved to the engine's\n * index wire by the capability at call time, from the registry.\n */\nexport type PagePlacement =\n | { after: PageObjectNumber }\n | { before: PageObjectNumber }\n | { index: number };\n\n/**\n * Structural page edits, addressed by durable PON (never display index — an\n * index shifts the moment a sibling is moved or deleted). Mirrors the engine's\n * `DocumentPagesService` 1:1, with one addition the engine can't have: the\n * relative `rotateBy` gesture. The engine wire is always ABSOLUTE; turning a\n * \"+90° on this thumbnail\" click into an absolute value needs the page's\n * current rotation, so that read+arithmetic lives HERE — once — instead of\n * being re-derived in every framework adapter's click handler.\n *\n * Document-scoped: rotation is shared document metadata, so editing through the\n * sidebar lens and seeing it in the main lens is automatic (both read the same\n * registry, which the kernel keeps in sync from the engine's event stream).\n */\nexport interface PageEditCapability {\n /**\n * Whether this caller is authorized to perform structural page edits —\n * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate\n * ALL their edit affordances on this, the add verbs included (rotate,\n * move, delete, addBlank, and insert share the one capability); the\n * engine independently enforces the same capability and throws\n * `PermissionDenied` if a call slips through.\n */\n canEdit(): boolean;\n\n /**\n * Rotate a SINGLE page by a relative quarter-turn — the per-thumbnail button\n * gesture. Reads the page's current rotation from the registry and forwards\n * the resulting absolute rotation to the engine.\n */\n rotateBy(pon: PageObjectNumber, delta: 90 | -90): AbortablePromise<PageRotateResult>;\n\n /**\n * Set the ABSOLUTE rotation of one or more pages to a single shared value —\n * the multi-select gesture. Maps 1:1 to the engine.\n */\n setRotation(pons: PageObjectNumber[], rotation: PageRotation): AbortablePromise<PageRotateResult>;\n\n /** Reorder pages (by PON) as a contiguous block starting at `destIndex`. */\n move(pons: PageObjectNumber[], destIndex: number): AbortablePromise<PageMoveResult>;\n\n /** Delete pages by PON. The engine rejects deleting every page. */\n delete(pons: PageObjectNumber[]): AbortablePromise<PageDeleteResult>;\n\n /**\n * Create blank pages — gate the affordance on `canEdit()`, like every\n * other structure verb (the add verbs share the `doc.pages.assemble`\n * capability and are mandatory on the engine contract). `size` defaults\n * to the page the new pages sit beside — the anchor for PON placements,\n * else the insertion point's predecessor, else the last page — so \"add\n * page\" matches the document without an A4-vs-Letter guess. That default\n * is a registry read, which is why it lives HERE and the engine wire\n * stays explicit (the `rotateBy` law). `count` defaults to 1.\n */\n addBlank(opts?: {\n size?: PdfSize;\n count?: number;\n placement?: PagePlacement;\n }): AbortablePromise<PageInsertResult>;\n\n /**\n * Copy every page of a standalone PDF (`bytes`) in at the placement —\n * the merge/import gesture. Forwards to `pages.insert`; the inserted\n * copies get fresh PONs, returned in insertion order.\n */\n insert(\n bytes: Uint8Array | ArrayBuffer,\n opts?: { placement?: PagePlacement },\n ): AbortablePromise<PageInsertResult>;\n}\n\nexport const PageEditToken = createCapabilityToken<PageEditCapability>('page-edit');\n","import { definePlugin } from '@embedpdf/core';\nimport { createPageEditCapability } from './capability';\nimport { PageEditToken } from './types';\n\n/**\n * Document-scoped, stateless: turns the engine handle's page service into a\n * PON-addressed edit capability. The relative→absolute rotation lives in the\n * capability so the four framework adapters never re-derive it, and this is the\n * home for client-side edit state (pending/optimistic/undo) when it lands —\n * adapters keep their thin hook over `PageEditToken` unchanged.\n */\nexport const pageEditPlugin = () =>\n definePlugin({\n id: 'page-edit',\n scope: 'document',\n token: PageEditToken,\n capability: createPageEditCapability,\n });\n"],"mappings":";;;;;;;;;;AAgBA,MAAM,sBAAqC;;;;;;;;AAS3C,SAAgB,yBAAyB,KAAiD;CACxF,MAAM,mBAAmB;EACvB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,+BAA+B;EACzD,OAAO;CACT;;CAGA,MAAM,cAAc,QAAwC;EAE1D,QADa,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,EAAE,qBAAqB,GAAG,EAAA,EAC5D,YAAY;CAC3B;;;;;;;CAQA,MAAM,oBAAoB,cAA8B;EACtD,IAAI,CAAC,WAAW,OAAO;GAAE,WAAW,KAAA;GAAW,QAAQ,KAAA;EAAU;EACjE,IAAI,WAAW,WAAW,OAAO;GAAE,WAAW,UAAU;GAAO,QAAQ,KAAA;EAAU;EACjF,MAAM,MAAM,WAAW,YAAY,UAAU,QAAQ,UAAU;EAC/D,MAAM,SAAS,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,EAAE,qBAAqB,GAAG;EAC3E,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,yCAAyC,KAAK;EAC3E,OAAO;GAAE,WAAW,WAAW,YAAY,OAAO,QAAQ,IAAI,OAAO;GAAO;EAAO;CACrF;;;;;;CAOA,MAAM,iBAAiB,cAA2C;EAChE,MAAM,QAAQ,IAAI,SAAS,CAAC,EAAE,SAAS,CAAC;EACxC,IAAI,MAAM,WAAW,GAAG,OAAO;GAAE,OAAO;GAAK,QAAQ;EAAI;EACzD,IAAI,cAAc,KAAA,GAAW,OAAO,MAAM,MAAM,SAAS,EAAE,CAAC;EAC5D,OAAO,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,YAAY,GAAG,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC;CACvE;CAEA,OAAO;EACL,UAAU;GAKR,OAAO,IAAI,KAAK,SAAS,OAAO,mBAAmB,KAAK;EAC1D;EAEA,SAAS,KAAK,OAAO;GAEnB,MAAM,SAAW,WAAW,GAAG,IAAI,SAAS,MAAO,OAAO;GAC1D,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,GAAG,IAAI;EAC9C;EAEA,YAAY,MAAM,UAAU;GAC1B,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,MAAM,QAAQ;EACjD;EAEA,KAAK,MAAM,WAAW;GACpB,OAAO,WAAW,CAAC,CAAC,MAAM,KAAK,MAAM,SAAS;EAChD;EAEA,OAAO,MAAM;GACX,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,IAAI;EACvC;EAEA,SAAS,OAAO,CAAC,GAAG;GAClB,MAAM,MAAM,WAAW;GACvB,MAAM,EAAE,WAAW,WAAW,iBAAiB,KAAK,SAAS;GAG7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,QAAQ,cAAc,SAAS;GACjE,OAAO,IAAI,MAAM,YAAY;IAAE;IAAM,OAAO,KAAK;GAAM,GAAG,SAAS;EACrE;EAEA,OAAO,OAAO,OAAO,CAAC,GAAG;GACvB,MAAM,MAAM,WAAW;GACvB,MAAM,EAAE,cAAc,iBAAiB,KAAK,SAAS;GACrD,OAAO,IAAI,MAAM,OAAO,OAAO,SAAS;EAC1C;CACF;AACF;;;ACbA,MAAa,iBAAA,GAAA,eAAA,sBAAA,CAA0D,WAAW;;;;;;;;;;ACnFlF,MAAa,wBAAA,GAAA,eAAA,aAAA,CACE;CACX,IAAI;CACJ,OAAO;CACP,OAAO;CACP,YAAY;AACd,CAAC"}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,19 @@
1
- import { AbortablePromise, PageDeleteResult, PageMoveResult, PageObjectNumber, PageRotateResult, PageRotation } from "@embedpdf/core";
1
+ import { AbortablePromise, PageDeleteResult, PageInsertResult, PageMoveResult, PageObjectNumber, PageRotateResult, PageRotation, PdfSize } from "@embedpdf/core";
2
2
  //#region src/types.d.ts
3
+ /**
4
+ * Where added pages land. The PON anchors are the thumbnail gestures ("+
5
+ * after this page") and stay correct across a concurrent reorder between
6
+ * click and call — a raw index does not; `index` remains for absolute
7
+ * positions ("at the start"). Omitted → append. Resolved to the engine's
8
+ * index wire by the capability at call time, from the registry.
9
+ */
10
+ type PagePlacement = {
11
+ after: PageObjectNumber;
12
+ } | {
13
+ before: PageObjectNumber;
14
+ } | {
15
+ index: number;
16
+ };
3
17
  /**
4
18
  * Structural page edits, addressed by durable PON (never display index — an
5
19
  * index shifts the moment a sibling is moved or deleted). Mirrors the engine's
@@ -16,9 +30,11 @@ import { AbortablePromise, PageDeleteResult, PageMoveResult, PageObjectNumber, P
16
30
  interface PageEditCapability {
17
31
  /**
18
32
  * Whether this caller is authorized to perform structural page edits —
19
- * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate their
20
- * edit affordances on this; the engine independently enforces the same
21
- * capability and throws `PermissionDenied` if a call slips through.
33
+ * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate
34
+ * ALL their edit affordances on this, the add verbs included (rotate,
35
+ * move, delete, addBlank, and insert share the one capability); the
36
+ * engine independently enforces the same capability and throws
37
+ * `PermissionDenied` if a call slips through.
22
38
  */
23
39
  canEdit(): boolean;
24
40
  /**
@@ -36,6 +52,29 @@ interface PageEditCapability {
36
52
  move(pons: PageObjectNumber[], destIndex: number): AbortablePromise<PageMoveResult>;
37
53
  /** Delete pages by PON. The engine rejects deleting every page. */
38
54
  delete(pons: PageObjectNumber[]): AbortablePromise<PageDeleteResult>;
55
+ /**
56
+ * Create blank pages — gate the affordance on `canEdit()`, like every
57
+ * other structure verb (the add verbs share the `doc.pages.assemble`
58
+ * capability and are mandatory on the engine contract). `size` defaults
59
+ * to the page the new pages sit beside — the anchor for PON placements,
60
+ * else the insertion point's predecessor, else the last page — so "add
61
+ * page" matches the document without an A4-vs-Letter guess. That default
62
+ * is a registry read, which is why it lives HERE and the engine wire
63
+ * stays explicit (the `rotateBy` law). `count` defaults to 1.
64
+ */
65
+ addBlank(opts?: {
66
+ size?: PdfSize;
67
+ count?: number;
68
+ placement?: PagePlacement;
69
+ }): AbortablePromise<PageInsertResult>;
70
+ /**
71
+ * Copy every page of a standalone PDF (`bytes`) in at the placement —
72
+ * the merge/import gesture. Forwards to `pages.insert`; the inserted
73
+ * copies get fresh PONs, returned in insertion order.
74
+ */
75
+ insert(bytes: Uint8Array | ArrayBuffer, opts?: {
76
+ placement?: PagePlacement;
77
+ }): AbortablePromise<PageInsertResult>;
39
78
  }
40
79
  declare const PageEditToken: import("@embedpdf/core").CapabilityToken<PageEditCapability>;
41
80
  //#endregion
package/dist/index.d.ts CHANGED
@@ -1,5 +1,19 @@
1
- import { AbortablePromise, PageDeleteResult, PageMoveResult, PageObjectNumber, PageRotateResult, PageRotation } from "@embedpdf/core";
1
+ import { AbortablePromise, PageDeleteResult, PageInsertResult, PageMoveResult, PageObjectNumber, PageRotateResult, PageRotation, PdfSize } from "@embedpdf/core";
2
2
  //#region src/types.d.ts
3
+ /**
4
+ * Where added pages land. The PON anchors are the thumbnail gestures ("+
5
+ * after this page") and stay correct across a concurrent reorder between
6
+ * click and call — a raw index does not; `index` remains for absolute
7
+ * positions ("at the start"). Omitted → append. Resolved to the engine's
8
+ * index wire by the capability at call time, from the registry.
9
+ */
10
+ type PagePlacement = {
11
+ after: PageObjectNumber;
12
+ } | {
13
+ before: PageObjectNumber;
14
+ } | {
15
+ index: number;
16
+ };
3
17
  /**
4
18
  * Structural page edits, addressed by durable PON (never display index — an
5
19
  * index shifts the moment a sibling is moved or deleted). Mirrors the engine's
@@ -16,9 +30,11 @@ import { AbortablePromise, PageDeleteResult, PageMoveResult, PageObjectNumber, P
16
30
  interface PageEditCapability {
17
31
  /**
18
32
  * Whether this caller is authorized to perform structural page edits —
19
- * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate their
20
- * edit affordances on this; the engine independently enforces the same
21
- * capability and throws `PermissionDenied` if a call slips through.
33
+ * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate
34
+ * ALL their edit affordances on this, the add verbs included (rotate,
35
+ * move, delete, addBlank, and insert share the one capability); the
36
+ * engine independently enforces the same capability and throws
37
+ * `PermissionDenied` if a call slips through.
22
38
  */
23
39
  canEdit(): boolean;
24
40
  /**
@@ -36,6 +52,29 @@ interface PageEditCapability {
36
52
  move(pons: PageObjectNumber[], destIndex: number): AbortablePromise<PageMoveResult>;
37
53
  /** Delete pages by PON. The engine rejects deleting every page. */
38
54
  delete(pons: PageObjectNumber[]): AbortablePromise<PageDeleteResult>;
55
+ /**
56
+ * Create blank pages — gate the affordance on `canEdit()`, like every
57
+ * other structure verb (the add verbs share the `doc.pages.assemble`
58
+ * capability and are mandatory on the engine contract). `size` defaults
59
+ * to the page the new pages sit beside — the anchor for PON placements,
60
+ * else the insertion point's predecessor, else the last page — so "add
61
+ * page" matches the document without an A4-vs-Letter guess. That default
62
+ * is a registry read, which is why it lives HERE and the engine wire
63
+ * stays explicit (the `rotateBy` law). `count` defaults to 1.
64
+ */
65
+ addBlank(opts?: {
66
+ size?: PdfSize;
67
+ count?: number;
68
+ placement?: PagePlacement;
69
+ }): AbortablePromise<PageInsertResult>;
70
+ /**
71
+ * Copy every page of a standalone PDF (`bytes`) in at the placement —
72
+ * the merge/import gesture. Forwards to `pages.insert`; the inserted
73
+ * copies get fresh PONs, returned in insertion order.
74
+ */
75
+ insert(bytes: Uint8Array | ArrayBuffer, opts?: {
76
+ placement?: PagePlacement;
77
+ }): AbortablePromise<PageInsertResult>;
39
78
  }
40
79
  declare const PageEditToken: import("@embedpdf/core").CapabilityToken<PageEditCapability>;
41
80
  //#endregion
package/dist/index.js CHANGED
@@ -25,6 +25,43 @@ function createPageEditCapability(ctx) {
25
25
  const rotationOf = (pon) => {
26
26
  return (ctx.document()?.pages.find((p) => p.pageObjectNumber === pon))?.rotation ?? 0;
27
27
  };
28
+ /**
29
+ * Resolve a placement to the engine's index wire, from the registry at
30
+ * call time — the PON anchors are why "add after this thumbnail" survives
31
+ * a concurrent reorder. Returns the anchor page too, so `addBlank` can
32
+ * default its size without a second lookup.
33
+ */
34
+ const resolvePlacement = (placement) => {
35
+ if (!placement) return {
36
+ destIndex: void 0,
37
+ anchor: void 0
38
+ };
39
+ if ("index" in placement) return {
40
+ destIndex: placement.index,
41
+ anchor: void 0
42
+ };
43
+ const pon = "after" in placement ? placement.after : placement.before;
44
+ const anchor = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);
45
+ if (!anchor) throw new Error(`[page-edit] placement page not found: ${pon}`);
46
+ return {
47
+ destIndex: "after" in placement ? anchor.index + 1 : anchor.index,
48
+ anchor
49
+ };
50
+ };
51
+ /**
52
+ * Default blank-page size: the insertion point's predecessor (the page
53
+ * the new one will follow), else the first page, else — only reachable
54
+ * with an empty registry, which an open document never has — US Letter.
55
+ */
56
+ const neighbourSize = (destIndex) => {
57
+ const pages = ctx.document()?.pages ?? [];
58
+ if (pages.length === 0) return {
59
+ width: 612,
60
+ height: 792
61
+ };
62
+ if (destIndex === void 0) return pages[pages.length - 1].size;
63
+ return pages[Math.max(0, Math.min(destIndex - 1, pages.length - 1))].size;
64
+ };
28
65
  return {
29
66
  canEdit() {
30
67
  return ctx.doc?.security.allows(ASSEMBLE_CAPABILITY) ?? false;
@@ -41,6 +78,20 @@ function createPageEditCapability(ctx) {
41
78
  },
42
79
  delete(pons) {
43
80
  return requireDoc().pages.delete(pons);
81
+ },
82
+ addBlank(opts = {}) {
83
+ const doc = requireDoc();
84
+ const { destIndex, anchor } = resolvePlacement(opts.placement);
85
+ const size = opts.size ?? anchor?.size ?? neighbourSize(destIndex);
86
+ return doc.pages.insertBlank({
87
+ size,
88
+ count: opts.count
89
+ }, destIndex);
90
+ },
91
+ insert(bytes, opts = {}) {
92
+ const doc = requireDoc();
93
+ const { destIndex } = resolvePlacement(opts.placement);
94
+ return doc.pages.insert(bytes, destIndex);
44
95
  }
45
96
  };
46
97
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/capability.ts","../src/types.ts","../src/page-edit.plugin.ts"],"sourcesContent":["import type { PluginContext, PageObjectNumber, PageRotation, DocCapability } from '@embedpdf/core';\nimport type { PageEditCapability } from './types';\n\n/**\n * Authorization for structural page edits. Maps to PDF bit 11 (ASSEMBLE =\n * insert/rotate/delete pages). The engine ALSO enforces this — every\n * page-structure verb throws `PermissionDenied` without it, identically on\n * local and cloud — so `canEdit()` is the UI mirror of a real guard, not the\n * guard itself. Typed as `DocCapability` so a typo is a compile error.\n */\nconst ASSEMBLE_CAPABILITY: DocCapability = 'doc.pages.assemble';\n\n/**\n * Forwards structural edits to the document's engine handle, addressed by PON.\n * The handle (`ctx.doc`) and the page registry (`ctx.document()`, kept in sync\n * by the kernel's event→registry bridge) are both already on the plugin\n * context — this capability is the thin layer that turns the relative rotate\n * gesture into the engine's absolute wire.\n */\nexport function createPageEditCapability(ctx: PluginContext<unknown>): PageEditCapability {\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[page-edit] no document bound');\n return doc;\n };\n\n /** Current absolute rotation of a page from the registry; 0 if unknown. */\n const rotationOf = (pon: PageObjectNumber): PageRotation => {\n const page = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n return page?.rotation ?? 0;\n };\n\n return {\n canEdit() {\n // Wildcard-aware predicate (mirrors the engine's own enforcement),\n // identical on both engines. NOT `effectiveScope.includes(...)` — that\n // enumeration drops the `*` admin grant, so it would hide the UI on a\n // default admin open even though the engine allows the edit.\n return ctx.doc?.security.allows(ASSEMBLE_CAPABILITY) ?? false;\n },\n\n rotateBy(pon, delta) {\n // Wrap to [0, 360) — the double-mod keeps -90 from current 0 landing on 270.\n const next = ((((rotationOf(pon) + delta) % 360) + 360) % 360) as PageRotation;\n return requireDoc().pages.rotate([pon], next);\n },\n\n setRotation(pons, rotation) {\n return requireDoc().pages.rotate(pons, rotation);\n },\n\n move(pons, destIndex) {\n return requireDoc().pages.move(pons, destIndex);\n },\n\n delete(pons) {\n return requireDoc().pages.delete(pons);\n },\n };\n}\n","import {\n createCapabilityToken,\n type AbortablePromise,\n type PageObjectNumber,\n type PageRotation,\n type PageRotateResult,\n type PageMoveResult,\n type PageDeleteResult,\n} from '@embedpdf/core';\n\n/**\n * Structural page edits, addressed by durable PON (never display index — an\n * index shifts the moment a sibling is moved or deleted). Mirrors the engine's\n * `DocumentPagesService` 1:1, with one addition the engine can't have: the\n * relative `rotateBy` gesture. The engine wire is always ABSOLUTE; turning a\n * \"+90° on this thumbnail\" click into an absolute value needs the page's\n * current rotation, so that read+arithmetic lives HERE — once — instead of\n * being re-derived in every framework adapter's click handler.\n *\n * Document-scoped: rotation is shared document metadata, so editing through the\n * sidebar lens and seeing it in the main lens is automatic (both read the same\n * registry, which the kernel keeps in sync from the engine's event stream).\n */\nexport interface PageEditCapability {\n /**\n * Whether this caller is authorized to perform structural page edits —\n * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate their\n * edit affordances on this; the engine independently enforces the same\n * capability and throws `PermissionDenied` if a call slips through.\n */\n canEdit(): boolean;\n\n /**\n * Rotate a SINGLE page by a relative quarter-turn — the per-thumbnail button\n * gesture. Reads the page's current rotation from the registry and forwards\n * the resulting absolute rotation to the engine.\n */\n rotateBy(pon: PageObjectNumber, delta: 90 | -90): AbortablePromise<PageRotateResult>;\n\n /**\n * Set the ABSOLUTE rotation of one or more pages to a single shared value —\n * the multi-select gesture. Maps 1:1 to the engine.\n */\n setRotation(pons: PageObjectNumber[], rotation: PageRotation): AbortablePromise<PageRotateResult>;\n\n /** Reorder pages (by PON) as a contiguous block starting at `destIndex`. */\n move(pons: PageObjectNumber[], destIndex: number): AbortablePromise<PageMoveResult>;\n\n /** Delete pages by PON. The engine rejects deleting every page. */\n delete(pons: PageObjectNumber[]): AbortablePromise<PageDeleteResult>;\n}\n\nexport const PageEditToken = createCapabilityToken<PageEditCapability>('page-edit');\n","import { definePlugin } from '@embedpdf/core';\nimport { createPageEditCapability } from './capability';\nimport { PageEditToken } from './types';\n\n/**\n * Document-scoped, stateless: turns the engine handle's page service into a\n * PON-addressed edit capability. The relative→absolute rotation lives in the\n * capability so the four framework adapters never re-derive it, and this is the\n * home for client-side edit state (pending/optimistic/undo) when it lands —\n * adapters keep their thin hook over `PageEditToken` unchanged.\n */\nexport const pageEditPlugin = () =>\n definePlugin({\n id: 'page-edit',\n scope: 'document',\n token: PageEditToken,\n capability: createPageEditCapability,\n });\n"],"mappings":";;;;;;;;;AAUA,MAAM,sBAAqC;;;;;;;;AAS3C,SAAgB,yBAAyB,KAAiD;CACxF,MAAM,mBAAmB;EACvB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,+BAA+B;EACzD,OAAO;CACT;;CAGA,MAAM,cAAc,QAAwC;EAE1D,QADa,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,EAAE,qBAAqB,GAAG,EAAA,EAC5D,YAAY;CAC3B;CAEA,OAAO;EACL,UAAU;GAKR,OAAO,IAAI,KAAK,SAAS,OAAO,mBAAmB,KAAK;EAC1D;EAEA,SAAS,KAAK,OAAO;GAEnB,MAAM,SAAW,WAAW,GAAG,IAAI,SAAS,MAAO,OAAO;GAC1D,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,GAAG,IAAI;EAC9C;EAEA,YAAY,MAAM,UAAU;GAC1B,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,MAAM,QAAQ;EACjD;EAEA,KAAK,MAAM,WAAW;GACpB,OAAO,WAAW,CAAC,CAAC,MAAM,KAAK,MAAM,SAAS;EAChD;EAEA,OAAO,MAAM;GACX,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,IAAI;EACvC;CACF;AACF;;;ACPA,MAAa,gBAAgB,sBAA0C,WAAW;;;;;;;;;;ACzClF,MAAa,uBACX,aAAa;CACX,IAAI;CACJ,OAAO;CACP,OAAO;CACP,YAAY;AACd,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/capability.ts","../src/types.ts","../src/page-edit.plugin.ts"],"sourcesContent":["import type {\n PluginContext,\n PageObjectNumber,\n PageRotation,\n DocCapability,\n PdfSize,\n} from '@embedpdf/core';\nimport type { PageEditCapability, PagePlacement } from './types';\n\n/**\n * Authorization for structural page edits. Maps to PDF bit 11 (ASSEMBLE =\n * insert/rotate/delete pages). The engine ALSO enforces this — every\n * page-structure verb throws `PermissionDenied` without it, identically on\n * local and cloud — so `canEdit()` is the UI mirror of a real guard, not the\n * guard itself. Typed as `DocCapability` so a typo is a compile error.\n */\nconst ASSEMBLE_CAPABILITY: DocCapability = 'doc.pages.assemble';\n\n/**\n * Forwards structural edits to the document's engine handle, addressed by PON.\n * The handle (`ctx.doc`) and the page registry (`ctx.document()`, kept in sync\n * by the kernel's event→registry bridge) are both already on the plugin\n * context — this capability is the thin layer that turns the relative rotate\n * gesture into the engine's absolute wire.\n */\nexport function createPageEditCapability(ctx: PluginContext<unknown>): PageEditCapability {\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[page-edit] no document bound');\n return doc;\n };\n\n /** Current absolute rotation of a page from the registry; 0 if unknown. */\n const rotationOf = (pon: PageObjectNumber): PageRotation => {\n const page = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n return page?.rotation ?? 0;\n };\n\n /**\n * Resolve a placement to the engine's index wire, from the registry at\n * call time — the PON anchors are why \"add after this thumbnail\" survives\n * a concurrent reorder. Returns the anchor page too, so `addBlank` can\n * default its size without a second lookup.\n */\n const resolvePlacement = (placement?: PagePlacement) => {\n if (!placement) return { destIndex: undefined, anchor: undefined };\n if ('index' in placement) return { destIndex: placement.index, anchor: undefined };\n const pon = 'after' in placement ? placement.after : placement.before;\n const anchor = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n if (!anchor) throw new Error(`[page-edit] placement page not found: ${pon}`);\n return { destIndex: 'after' in placement ? anchor.index + 1 : anchor.index, anchor };\n };\n\n /**\n * Default blank-page size: the insertion point's predecessor (the page\n * the new one will follow), else the first page, else — only reachable\n * with an empty registry, which an open document never has — US Letter.\n */\n const neighbourSize = (destIndex: number | undefined): PdfSize => {\n const pages = ctx.document()?.pages ?? [];\n if (pages.length === 0) return { width: 612, height: 792 };\n if (destIndex === undefined) return pages[pages.length - 1].size;\n return pages[Math.max(0, Math.min(destIndex - 1, pages.length - 1))].size;\n };\n\n return {\n canEdit() {\n // Wildcard-aware predicate (mirrors the engine's own enforcement),\n // identical on both engines. NOT `effectiveScope.includes(...)` — that\n // enumeration drops the `*` admin grant, so it would hide the UI on a\n // default admin open even though the engine allows the edit.\n return ctx.doc?.security.allows(ASSEMBLE_CAPABILITY) ?? false;\n },\n\n rotateBy(pon, delta) {\n // Wrap to [0, 360) — the double-mod keeps -90 from current 0 landing on 270.\n const next = ((((rotationOf(pon) + delta) % 360) + 360) % 360) as PageRotation;\n return requireDoc().pages.rotate([pon], next);\n },\n\n setRotation(pons, rotation) {\n return requireDoc().pages.rotate(pons, rotation);\n },\n\n move(pons, destIndex) {\n return requireDoc().pages.move(pons, destIndex);\n },\n\n delete(pons) {\n return requireDoc().pages.delete(pons);\n },\n\n addBlank(opts = {}) {\n const doc = requireDoc();\n const { destIndex, anchor } = resolvePlacement(opts.placement);\n // PON placements match the anchor the user is looking at; everything\n // else matches the neighbour the new page will follow.\n const size = opts.size ?? anchor?.size ?? neighbourSize(destIndex);\n return doc.pages.insertBlank({ size, count: opts.count }, destIndex);\n },\n\n insert(bytes, opts = {}) {\n const doc = requireDoc();\n const { destIndex } = resolvePlacement(opts.placement);\n return doc.pages.insert(bytes, destIndex);\n },\n };\n}\n","import {\n createCapabilityToken,\n type AbortablePromise,\n type PageObjectNumber,\n type PageRotation,\n type PageRotateResult,\n type PageMoveResult,\n type PageDeleteResult,\n type PageInsertResult,\n type PdfSize,\n} from '@embedpdf/core';\n\n/**\n * Where added pages land. The PON anchors are the thumbnail gestures (\"+\n * after this page\") and stay correct across a concurrent reorder between\n * click and call — a raw index does not; `index` remains for absolute\n * positions (\"at the start\"). Omitted → append. Resolved to the engine's\n * index wire by the capability at call time, from the registry.\n */\nexport type PagePlacement =\n | { after: PageObjectNumber }\n | { before: PageObjectNumber }\n | { index: number };\n\n/**\n * Structural page edits, addressed by durable PON (never display index — an\n * index shifts the moment a sibling is moved or deleted). Mirrors the engine's\n * `DocumentPagesService` 1:1, with one addition the engine can't have: the\n * relative `rotateBy` gesture. The engine wire is always ABSOLUTE; turning a\n * \"+90° on this thumbnail\" click into an absolute value needs the page's\n * current rotation, so that read+arithmetic lives HERE — once — instead of\n * being re-derived in every framework adapter's click handler.\n *\n * Document-scoped: rotation is shared document metadata, so editing through the\n * sidebar lens and seeing it in the main lens is automatic (both read the same\n * registry, which the kernel keeps in sync from the engine's event stream).\n */\nexport interface PageEditCapability {\n /**\n * Whether this caller is authorized to perform structural page edits —\n * `effectiveScope` includes `doc.pages.assemble` (PDF bit 11). UIs gate\n * ALL their edit affordances on this, the add verbs included (rotate,\n * move, delete, addBlank, and insert share the one capability); the\n * engine independently enforces the same capability and throws\n * `PermissionDenied` if a call slips through.\n */\n canEdit(): boolean;\n\n /**\n * Rotate a SINGLE page by a relative quarter-turn — the per-thumbnail button\n * gesture. Reads the page's current rotation from the registry and forwards\n * the resulting absolute rotation to the engine.\n */\n rotateBy(pon: PageObjectNumber, delta: 90 | -90): AbortablePromise<PageRotateResult>;\n\n /**\n * Set the ABSOLUTE rotation of one or more pages to a single shared value —\n * the multi-select gesture. Maps 1:1 to the engine.\n */\n setRotation(pons: PageObjectNumber[], rotation: PageRotation): AbortablePromise<PageRotateResult>;\n\n /** Reorder pages (by PON) as a contiguous block starting at `destIndex`. */\n move(pons: PageObjectNumber[], destIndex: number): AbortablePromise<PageMoveResult>;\n\n /** Delete pages by PON. The engine rejects deleting every page. */\n delete(pons: PageObjectNumber[]): AbortablePromise<PageDeleteResult>;\n\n /**\n * Create blank pages — gate the affordance on `canEdit()`, like every\n * other structure verb (the add verbs share the `doc.pages.assemble`\n * capability and are mandatory on the engine contract). `size` defaults\n * to the page the new pages sit beside — the anchor for PON placements,\n * else the insertion point's predecessor, else the last page — so \"add\n * page\" matches the document without an A4-vs-Letter guess. That default\n * is a registry read, which is why it lives HERE and the engine wire\n * stays explicit (the `rotateBy` law). `count` defaults to 1.\n */\n addBlank(opts?: {\n size?: PdfSize;\n count?: number;\n placement?: PagePlacement;\n }): AbortablePromise<PageInsertResult>;\n\n /**\n * Copy every page of a standalone PDF (`bytes`) in at the placement —\n * the merge/import gesture. Forwards to `pages.insert`; the inserted\n * copies get fresh PONs, returned in insertion order.\n */\n insert(\n bytes: Uint8Array | ArrayBuffer,\n opts?: { placement?: PagePlacement },\n ): AbortablePromise<PageInsertResult>;\n}\n\nexport const PageEditToken = createCapabilityToken<PageEditCapability>('page-edit');\n","import { definePlugin } from '@embedpdf/core';\nimport { createPageEditCapability } from './capability';\nimport { PageEditToken } from './types';\n\n/**\n * Document-scoped, stateless: turns the engine handle's page service into a\n * PON-addressed edit capability. The relative→absolute rotation lives in the\n * capability so the four framework adapters never re-derive it, and this is the\n * home for client-side edit state (pending/optimistic/undo) when it lands —\n * adapters keep their thin hook over `PageEditToken` unchanged.\n */\nexport const pageEditPlugin = () =>\n definePlugin({\n id: 'page-edit',\n scope: 'document',\n token: PageEditToken,\n capability: createPageEditCapability,\n });\n"],"mappings":";;;;;;;;;AAgBA,MAAM,sBAAqC;;;;;;;;AAS3C,SAAgB,yBAAyB,KAAiD;CACxF,MAAM,mBAAmB;EACvB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,+BAA+B;EACzD,OAAO;CACT;;CAGA,MAAM,cAAc,QAAwC;EAE1D,QADa,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,EAAE,qBAAqB,GAAG,EAAA,EAC5D,YAAY;CAC3B;;;;;;;CAQA,MAAM,oBAAoB,cAA8B;EACtD,IAAI,CAAC,WAAW,OAAO;GAAE,WAAW,KAAA;GAAW,QAAQ,KAAA;EAAU;EACjE,IAAI,WAAW,WAAW,OAAO;GAAE,WAAW,UAAU;GAAO,QAAQ,KAAA;EAAU;EACjF,MAAM,MAAM,WAAW,YAAY,UAAU,QAAQ,UAAU;EAC/D,MAAM,SAAS,IAAI,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,EAAE,qBAAqB,GAAG;EAC3E,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,yCAAyC,KAAK;EAC3E,OAAO;GAAE,WAAW,WAAW,YAAY,OAAO,QAAQ,IAAI,OAAO;GAAO;EAAO;CACrF;;;;;;CAOA,MAAM,iBAAiB,cAA2C;EAChE,MAAM,QAAQ,IAAI,SAAS,CAAC,EAAE,SAAS,CAAC;EACxC,IAAI,MAAM,WAAW,GAAG,OAAO;GAAE,OAAO;GAAK,QAAQ;EAAI;EACzD,IAAI,cAAc,KAAA,GAAW,OAAO,MAAM,MAAM,SAAS,EAAE,CAAC;EAC5D,OAAO,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,YAAY,GAAG,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC;CACvE;CAEA,OAAO;EACL,UAAU;GAKR,OAAO,IAAI,KAAK,SAAS,OAAO,mBAAmB,KAAK;EAC1D;EAEA,SAAS,KAAK,OAAO;GAEnB,MAAM,SAAW,WAAW,GAAG,IAAI,SAAS,MAAO,OAAO;GAC1D,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,GAAG,IAAI;EAC9C;EAEA,YAAY,MAAM,UAAU;GAC1B,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,MAAM,QAAQ;EACjD;EAEA,KAAK,MAAM,WAAW;GACpB,OAAO,WAAW,CAAC,CAAC,MAAM,KAAK,MAAM,SAAS;EAChD;EAEA,OAAO,MAAM;GACX,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,IAAI;EACvC;EAEA,SAAS,OAAO,CAAC,GAAG;GAClB,MAAM,MAAM,WAAW;GACvB,MAAM,EAAE,WAAW,WAAW,iBAAiB,KAAK,SAAS;GAG7D,MAAM,OAAO,KAAK,QAAQ,QAAQ,QAAQ,cAAc,SAAS;GACjE,OAAO,IAAI,MAAM,YAAY;IAAE;IAAM,OAAO,KAAK;GAAM,GAAG,SAAS;EACrE;EAEA,OAAO,OAAO,OAAO,CAAC,GAAG;GACvB,MAAM,MAAM,WAAW;GACvB,MAAM,EAAE,cAAc,iBAAiB,KAAK,SAAS;GACrD,OAAO,IAAI,MAAM,OAAO,OAAO,SAAS;EAC1C;CACF;AACF;;;ACbA,MAAa,gBAAgB,sBAA0C,WAAW;;;;;;;;;;ACnFlF,MAAa,uBACX,aAAa;CACX,IAAI;CACJ,OAAO;CACP,OAAO;CACP,YAAY;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-page-edit",
3
- "version": "3.0.0-next.0",
3
+ "version": "3.0.0-next.10",
4
4
  "private": false,
5
5
  "description": "Document-scoped page-edit capability: PON-addressed rotate/move/delete over the engine DocumentHandle. Owns relative→absolute rotation so framework adapters never re-derive it; the home for pending/undo/gating state.",
6
6
  "type": "module",
@@ -18,7 +18,7 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
- "@embedpdf/core": "3.0.0-next.0"
21
+ "@embedpdf/core": "3.0.0-next.10"
22
22
  },
23
23
  "devDependencies": {
24
24
  "typescript": "^5.0.0",