@embedpdf/plugin-page-edit 3.0.0-next.15 → 3.0.0-next.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/controller.ts","../src/page-edit.plugin.ts"],"sourcesContent":["/**\n * The page-edit controller. Stateless: it turns the engine handle's page\n * service into page edits that take refs or indexes. Turning a page relative\n * to its own rotation, and fixing a placement's page, live here once instead\n * of in every app's click handler.\n *\n * A verb refuses before anything starts (permission, pages, placement), then\n * queues its edit: edits run one at a time, in the order they were called.\n */\nimport { DocumentsToken, PluginError, toPluginError } from '@embedpdf/core';\nimport type {\n DocCapability,\n PageInfo,\n PagePosition,\n PageRef,\n PdfRotation,\n PdfSize,\n PluginContext,\n} from '@embedpdf/core';\n\nimport type { PageEditCapability, PageEditInsertResult, PagePlacement } from './contract';\n\n/** Inserting, rotating and deleting pages (PDF permission bit 4 or 11). The engine enforces it too. */\nconst ASSEMBLE: DocCapability = 'doc.pages.assemble';\n/** Copying pages out of a document is a partial download. The engine enforces it too. */\nconst DOWNLOAD: DocCapability = 'doc.download';\n\n/** The size of a blank page when the document has no page to match: Letter, in points. */\nconst LETTER_SIZE: PdfSize = { width: 612, height: 792 };\n\nexport function createPageEditController(ctx: PluginContext<void>) {\n const enqueue = ctx.serialQueue('edits');\n // A download waits for the page edits on their way.\n ctx.onSettle(() => enqueue.idle());\n\n /** Engine calls outside the guarded `ctx.doc` (another document, a scratch document) map their errors here. */\n const mapErrors = async <T>(work: () => Promise<T>): Promise<T> => {\n try {\n return await work();\n } catch (error) {\n throw toPluginError('page-edit', error);\n }\n };\n const registry = (): readonly PageInfo[] => ctx.document()?.pages ?? [];\n const noPages = () => new PluginError('invalid-input', 'page-edit', 'no pages given');\n\n /**\n * A verb's pages as refs, checked when it is called: an index names the\n * page at that position now, which is the page the user clicked.\n */\n const refsOf = (pages: readonly (PageRef | number)[]): PageRef[] => {\n if (pages.length === 0) throw noPages();\n return pages.map((page) => ctx.pageOf(page).ref);\n };\n\n /**\n * A placement as the engine's position, its page fixed when the verb is\n * called, like the verb's own pages. Default `'end'`.\n */\n const positionOf = (placement: PagePlacement | undefined): PagePosition => {\n if (!placement || placement === 'start' || placement === 'end') return placement ?? 'end';\n if ('after' in placement) return { after: ctx.pageOf(placement.after).ref };\n return { before: ctx.pageOf(placement.before).ref };\n };\n /**\n * Default blank-page size: the page the placement names, else the page the\n * new ones go next to (the first or the last), else Letter.\n */\n const sizeAt = (position: PagePosition): PdfSize => {\n if (typeof position === 'object') {\n return ctx.pageOf('after' in position ? position.after : position.before).size;\n }\n const pages = registry();\n if (pages.length === 0) return LETTER_SIZE;\n return (position === 'start' ? pages[0] : pages[pages.length - 1]).size;\n };\n\n /** Insert a PDF's pages; resolves the new pages. */\n const insertBytes = async (\n bytes: Uint8Array | ArrayBuffer,\n position: PagePosition,\n signal: AbortSignal | undefined,\n ): Promise<PageEditInsertResult> => {\n const result = await ctx.cancellable(signal, ctx.doc.pages.insert(bytes, position));\n return { pages: result.insertedPages };\n };\n\n const api: PageEditCapability = {\n canEdit: () => ctx.allows(ASSEMBLE),\n canExtract: () => ctx.allows(DOWNLOAD),\n\n rotateBy: async (pages, delta, options) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.rotateBy');\n const refs = refsOf(pages);\n const signal = options?.signal;\n await enqueue(async () => {\n // The engine sets one rotation per call, so pages are grouped by where\n // they end up. Each page's rotation is read when the edit runs, after\n // the edits queued before it; the double modulo keeps -90 from 0 at 270.\n const groups = new Map<PdfRotation, PageRef[]>();\n for (const ref of refs) {\n const turned = (ctx.pageOf(ref).rotation + delta) % 360;\n const rotation = ((turned + 360) % 360) as PdfRotation;\n groups.set(rotation, [...(groups.get(rotation) ?? []), ref]);\n }\n for (const [rotation, group] of groups) {\n await ctx.cancellable(signal, ctx.doc.pages.rotate(group, rotation));\n }\n }, options);\n },\n\n setRotation: async (pages, rotation, options) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.setRotation');\n const refs = refsOf(pages);\n await enqueue(\n () => ctx.cancellable(options?.signal, ctx.doc.pages.rotate(refs, rotation)),\n options,\n );\n },\n\n reorder: async (pages, placement, options) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.reorder');\n const refs = refsOf(pages);\n const position = positionOf(placement);\n await enqueue(\n () => ctx.cancellable(options?.signal, ctx.doc.pages.reorder(refs, position)),\n options,\n );\n },\n\n delete: async (pages, options) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.delete');\n const refs = refsOf(pages);\n const deleting = new Set(refs.map((ref) => ref.objectNumber));\n if (registry().every((page) => deleting.has(page.ref.objectNumber))) {\n throw new PluginError('invalid-input', 'page-edit', 'a document keeps at least one page');\n }\n await enqueue(() => ctx.cancellable(options?.signal, ctx.doc.pages.delete(refs)), options);\n },\n\n insertBlank: async (options = {}) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.insertBlank');\n const position = positionOf(options.placement);\n return enqueue(async () => {\n const size = options.size ?? sizeAt(position);\n const result = await ctx.cancellable(\n options.signal,\n ctx.doc.pages.insertBlank({ size, count: options.count }, position),\n );\n return { pages: result.insertedPages };\n }, options);\n },\n\n insertFromBytes: async (bytes, options = {}) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.insertFromBytes');\n const position = positionOf(options.placement);\n const { pageIndexes, signal } = options;\n if (pageIndexes?.length === 0) throw noPages();\n return enqueue(async () => {\n if (!pageIndexes) return insertBytes(bytes, position, signal);\n // Some of the pages: open the bytes beside the document, extract them, insert those.\n const source = await mapErrors(() =>\n ctx.engine.open(\n {\n kind: 'bytes',\n id: `page-edit-source-${Date.now().toString(36)}`,\n bytes: new Uint8Array(bytes),\n },\n { scope: ['*'] },\n ),\n );\n try {\n const layout = await mapErrors(() => ctx.cancellable(signal, source.pages.list()));\n const refs = pageIndexes.map((index) => {\n const page = layout.pages[index];\n if (!page) {\n throw new PluginError('not-found', 'page-edit', `the PDF has no page ${index}`);\n }\n return page.ref;\n });\n const subset = await mapErrors(() => ctx.cancellable(signal, source.pages.extract(refs)));\n return await insertBytes(subset, position, signal);\n } finally {\n await source.close();\n }\n }, options);\n },\n\n insertFromDocument: async (documentId, pages, options = {}) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.insertFromDocument');\n if (pages.length === 0) throw noPages();\n const other = ctx.documentHandle(documentId);\n if (!other) {\n throw new PluginError('not-found', 'page-edit', `document '${documentId}' is not open`);\n }\n // The pages are the other document's, so its page list resolves them.\n const otherPages = ctx.get(DocumentsToken).listPages(documentId);\n const refs = pages.map((page) => {\n const found =\n typeof page === 'number'\n ? otherPages[page]\n : otherPages.find((candidate) => candidate.ref.objectNumber === page.objectNumber);\n if (!found) {\n throw new PluginError(\n 'not-found',\n 'page-edit',\n `document '${documentId}' has no such page`,\n );\n }\n return found.ref;\n });\n const position = positionOf(options.placement);\n return enqueue(async () => {\n // The other document's session decides whether its pages may be copied\n // out: the engine refuses `doc.download` there with the permission named.\n const bytes = await mapErrors(() =>\n ctx.cancellable(options.signal, other.pages.extract(refs)),\n );\n return insertBytes(bytes, position, options.signal);\n }, options);\n },\n\n duplicate: async (pages, options = {}) => {\n ctx.assertAllowed(ASSEMBLE, 'pageEdit.duplicate');\n ctx.assertAllowed(DOWNLOAD, 'pageEdit.duplicate');\n const refs = refsOf(pages);\n const position = options.placement\n ? positionOf(options.placement)\n : { after: refs[refs.length - 1]! };\n return enqueue(async () => {\n const bytes = await ctx.cancellable(options.signal, ctx.doc.pages.extract(refs));\n return insertBytes(bytes, position, options.signal);\n }, options);\n },\n\n extract: async (pages, options) => {\n ctx.assertAllowed(DOWNLOAD, 'pageEdit.extract');\n const refs = refsOf(pages);\n return enqueue(() => ctx.cancellable(options?.signal, ctx.doc.pages.extract(refs)), options);\n },\n };\n return { api };\n}\n","import { definePlugin } from '@embedpdf/core';\n\nimport { PageEditToken } from './contract';\nimport { createPageEditController } from './controller';\n\n/**\n * Document-scoped and stateless: the engine handle's page service as page\n * edits that take refs or indexes. Turning a page relative to its own\n * rotation lives in the controller, so no app re-derives it.\n */\nexport const pageEditPlugin = () =>\n definePlugin({\n id: 'page-edit',\n scope: 'document',\n token: PageEditToken,\n create: createPageEditController,\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/model.ts","../src/controller.ts","../src/page-edit.plugin.ts","../src/state.ts"],"sourcesContent":["/**\n * The page-edit session state: which pages are selected. A plain list of\n * refs, changed only by the transitions here; the controller reads it over the\n * document's pages, so a page that went leaves the selection.\n */\nimport type { PageRef } from '@embedpdf/core';\n\nexport interface PageEditState {\n /** The selected pages, in the order they were selected. */\n readonly selected: readonly PageRef[];\n}\n\nexport const initialPageEditState = (): PageEditState => ({ selected: [] });\n\n/** The selection becomes `refs`, each page once. */\nexport function selected(state: PageEditState, refs: readonly PageRef[]): PageEditState {\n const numbers = refs.map((ref) => ref.objectNumber);\n const unique = refs.filter((_ref, i) => numbers.indexOf(numbers[i]!) === i);\n const same =\n unique.length === state.selected.length &&\n unique.every((ref, i) => ref.objectNumber === state.selected[i]!.objectNumber);\n return same ? state : { ...state, selected: unique };\n}\n","/**\n * The page-edit controller: page edits that take refs or indexes, and the\n * page selection. Turning a page relative to its own rotation, and fixing a\n * position's page, live here once instead of in every app's click handler.\n *\n * A verb refuses before anything starts (permission, pages, position), then\n * stages its edit as one change on the document's queue (`ctx.changes`): one\n * step of the history, sent after everything staged before it. The page list\n * shows it once the engine answers; nothing predicts pages yet.\n */\nimport { memo, PluginError, toPluginError, DocumentsToken } from '@embedpdf/core';\nimport type {\n ChangeLabel,\n DocCapability,\n OperationOptions,\n PageLayout,\n PagePosition,\n PageRef,\n PdfRotation,\n PdfSize,\n PendingChange,\n PluginContext,\n PredictedOp,\n} from '@embedpdf/core';\n\nimport type { PageEditCapability, PageEditInsertResult } from './contract';\nimport { selected, type PageEditState } from './model';\n\n/** Inserting, rotating and deleting pages (PDF permission bit 4 or 11). The engine enforces it too. */\nconst ASSEMBLE: DocCapability = 'doc.pages.assemble';\n/** Copying pages out of a document is a partial download. The engine enforces it too. */\nconst DOWNLOAD: DocCapability = 'doc.download';\n\n/** The size of a blank page when the document has no page to match: Letter, in points. */\nconst LETTER_SIZE: PdfSize = { width: 612, height: 792 };\n\nconst NO_PAGES: readonly PageRef[] = Object.freeze([]);\nconst NO_LAYOUTS: readonly PageLayout[] = Object.freeze([]);\n\n/** A page op, as a verb stages it. */\ntype PageOp = Extract<PredictedOp, { type: `pages.${string}` }>;\n\n/** What a change is called in history and refusals. */\ntype PageVerb = 'rotate' | 'reorder' | 'delete' | 'insertBlank' | 'insert' | 'duplicate';\n\nexport function createPageEditController(ctx: PluginContext<PageEditState>) {\n /** Engine calls outside the guarded `ctx.doc` (another document, a scratch document) map their errors here. */\n const mapErrors = async <T>(work: () => Promise<T>): Promise<T> => {\n try {\n return await work();\n } catch (error) {\n throw toPluginError('page-edit', error);\n }\n };\n const registry = (): readonly PageLayout[] => ctx.document()?.pages ?? NO_LAYOUTS;\n const noPages = () => new PluginError('invalid-input', 'page-edit', 'no pages given');\n\n /**\n * A verb's pages as refs, checked when it is called: an index names the\n * page at that position now, which is the page the user clicked.\n */\n const refsOf = (pages: readonly (PageRef | number)[]): PageRef[] => {\n if (pages.length === 0) throw noPages();\n return pages.map((page) => ctx.pageOf(page).ref);\n };\n\n /** A position, its page checked when the verb is called, like the verb's own pages. Default `'end'`. */\n const positionOf = (position: PagePosition | undefined): PagePosition => {\n if (!position || position === 'start' || position === 'end') return position ?? 'end';\n if ('after' in position) return { after: ctx.pageOf(position.after).ref };\n return { before: ctx.pageOf(position.before).ref };\n };\n /**\n * Default blank-page size: the page the position names, else the page the\n * new ones go next to (the first or the last), else Letter.\n */\n const sizeAt = (position: PagePosition): PdfSize => {\n if (typeof position === 'object') {\n return ctx.pageOf('after' in position ? position.after : position.before).size;\n }\n const pages = registry();\n if (pages.length === 0) return LETTER_SIZE;\n return (position === 'start' ? pages[0] : pages[pages.length - 1]).size;\n };\n\n /* ── the selection ─────────────────────────────────────────────────────── */\n\n const getSelected = memo(\n () => [registry(), ctx.state.get().selected] as const,\n (pages, refs) => {\n if (refs.length === 0) return NO_PAGES;\n const present = new Set(pages.map((page) => page.ref.objectNumber));\n return refs.filter((ref) => present.has(ref.objectNumber));\n },\n );\n const select = (pages: readonly (PageRef | number)[]): void => {\n const refs = pages.flatMap((page) => {\n const found = ctx.getPage(page);\n return found ? [found.ref] : [];\n });\n ctx.state.update(selected, refs);\n };\n\n /* ── writes ────────────────────────────────────────────────────────────── */\n\n /** Refuse before anything starts: without the right, or once the caller cancelled. */\n const refuse = (\n permission: DocCapability,\n operation: string,\n options: OperationOptions | undefined,\n ): void => {\n ctx.assertAllowed(permission, operation);\n if (options?.signal?.aborted) {\n throw new PluginError('operation-cancelled', 'page-edit', `${operation} was cancelled`);\n }\n };\n\n /**\n * Stage one user action: one change, one step of the history. Its label\n * counts the pages it acts on, when the verb knows how many.\n */\n const stageChange = (\n verb: PageVerb,\n count: number | null,\n ops: readonly PageOp[],\n undo?: readonly PageOp[],\n ): PendingChange => {\n const label: ChangeLabel =\n count === null ? { key: `pages.${verb}` } : { key: `pages.${verb}`, count };\n return ctx.changes.stage({ label, ops, ...(undo ? { undo } : {}) });\n };\n\n /** The engine's answer to a staged change: its first item. */\n const answer = async (change: PendingChange, options: OperationOptions | undefined) => {\n try {\n const result = await ctx.cancellable(options?.signal, change.result);\n return result.items[0]!;\n } catch (error) {\n throw toPluginError('page-edit', error);\n }\n };\n\n /** What an insert's answer names: the new pages. */\n const inserted = async (\n change: PendingChange,\n options: OperationOptions | undefined,\n ): Promise<PageEditInsertResult> => {\n const item = await answer(change, options);\n return { pages: 'insertedPages' in item ? item.insertedPages : NO_PAGES };\n };\n\n /**\n * A page's rotation once this session's changes on their way apply: the\n * last rotation one of them gives it, else the page's own. What a turn\n * starts from, so two quick quarter turns are a half turn.\n */\n const rotationOf = (ref: PageRef): PdfRotation => {\n let rotation = ctx.pageOf(ref).rotation;\n for (const change of ctx.changes.pending()) {\n for (const op of change.shows) {\n if (op.type !== 'pages.rotate') continue;\n if (op.pages.some((page) => page.objectNumber === ref.objectNumber)) {\n rotation = op.rotation;\n }\n }\n }\n return rotation;\n };\n\n /**\n * Rotate pages as one change: one op per rotation they end up with. What\n * undoing it looks like is each page turned back, so a turn right after an\n * undo starts from where the undo leaves the page.\n */\n const rotate = (refs: readonly PageRef[], rotationAfter: (ref: PageRef) => PdfRotation) => {\n const after = new Map<PdfRotation, PageRef[]>();\n const before = new Map<PdfRotation, PageRef[]>();\n for (const ref of refs) {\n const add = (groups: Map<PdfRotation, PageRef[]>, rotation: PdfRotation) =>\n groups.set(rotation, [...(groups.get(rotation) ?? []), ref]);\n add(before, rotationOf(ref));\n add(after, rotationAfter(ref));\n }\n const opsOf = (groups: Map<PdfRotation, PageRef[]>): PageOp[] =>\n [...groups].map(([rotation, pages]) => ({ type: 'pages.rotate', pages, rotation }));\n return stageChange('rotate', refs.length, opsOf(after), opsOf(before));\n };\n\n /**\n * The pages as they show: every change on its way sent and answered first,\n * so a copy holds the edits made before it.\n */\n const settled = async (options: OperationOptions | undefined): Promise<void> => {\n ctx.changes.sendHolds();\n await ctx.cancellable(options?.signal, ctx.changes.whenSettled());\n };\n\n /** Copy pages of this document out, as they show. */\n const extractShown = async (\n refs: readonly PageRef[],\n options: OperationOptions | undefined,\n ): Promise<Uint8Array> => {\n await settled(options);\n return ctx.cancellable(options?.signal, ctx.doc.pages.extract([...refs]));\n };\n\n /** Stage the insert of a PDF's pages; resolves the new pages. */\n const insertBytes = (\n verb: 'insert' | 'duplicate',\n count: number | null,\n bytes: Uint8Array | ArrayBuffer,\n position: PagePosition,\n options: OperationOptions | undefined,\n ): Promise<PageEditInsertResult> => {\n const source = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);\n const change = stageChange(verb, count, [{ type: 'pages.insert', source, position }]);\n return inserted(change, options);\n };\n\n /** Some pages of a PDF: open the bytes beside the document and extract them. */\n const pagesOfBytes = async (\n bytes: Uint8Array | ArrayBuffer,\n pageIndexes: readonly number[],\n signal: AbortSignal | undefined,\n ): Promise<Uint8Array> => {\n const source = await mapErrors(() =>\n ctx.engine.open(\n {\n kind: 'bytes',\n id: `page-edit-source-${Date.now().toString(36)}`,\n bytes: new Uint8Array(bytes),\n },\n { scope: ['*'] },\n ),\n );\n try {\n const layout = await mapErrors(() => ctx.cancellable(signal, source.pages.list()));\n const refs = pageIndexes.map((index) => {\n const page = layout.pages[index];\n if (!page) {\n throw new PluginError('not-found', 'page-edit', `the PDF has no page ${index}`);\n }\n return page.ref;\n });\n return await mapErrors(() => ctx.cancellable(signal, source.pages.extract(refs)));\n } finally {\n await source.close();\n }\n };\n\n const api: PageEditCapability = {\n canEdit: () => ctx.allows(ASSEMBLE),\n canExtract: () => ctx.allows(DOWNLOAD),\n\n getSelected,\n select,\n\n rotateBy: async (pages, delta, options) => {\n refuse(ASSEMBLE, 'pageEdit.rotateBy', options);\n const refs = refsOf(pages);\n // The double modulo keeps -90 from 0 at 270.\n const change = rotate(\n refs,\n (ref) => ((((rotationOf(ref) + delta) % 360) + 360) % 360) as PdfRotation,\n );\n await answer(change, options);\n },\n\n setRotation: async (pages, rotation, options) => {\n refuse(ASSEMBLE, 'pageEdit.setRotation', options);\n const change = rotate(refsOf(pages), () => rotation);\n await answer(change, options);\n },\n\n reorder: async (pages, position, options) => {\n refuse(ASSEMBLE, 'pageEdit.reorder', options);\n const refs = refsOf(pages);\n const change = stageChange('reorder', refs.length, [\n { type: 'pages.reorder', pages: refs, position: positionOf(position) },\n ]);\n await answer(change, options);\n },\n\n delete: async (pages, options) => {\n refuse(ASSEMBLE, 'pageEdit.delete', options);\n const refs = refsOf(pages);\n const deleting = new Set(refs.map((ref) => ref.objectNumber));\n if (registry().every((page) => deleting.has(page.ref.objectNumber))) {\n throw new PluginError('invalid-input', 'page-edit', 'a document keeps at least one page');\n }\n const change = stageChange('delete', refs.length, [{ type: 'pages.delete', pages: refs }]);\n await answer(change, options);\n },\n\n insertBlank: async (options = {}) => {\n refuse(ASSEMBLE, 'pageEdit.insertBlank', options);\n const position = positionOf(options.position);\n const count = options.count ?? 1;\n const size = options.size ?? sizeAt(position);\n const change = stageChange('insertBlank', count, [\n { type: 'pages.insertBlank', spec: { size, count }, position },\n ]);\n return inserted(change, options);\n },\n\n insertFromBytes: async (bytes, options = {}) => {\n refuse(ASSEMBLE, 'pageEdit.insertFromBytes', options);\n const position = positionOf(options.position);\n const { pageIndexes, signal } = options;\n if (pageIndexes?.length === 0) throw noPages();\n const source = pageIndexes ? await pagesOfBytes(bytes, pageIndexes, signal) : bytes;\n return insertBytes('insert', pageIndexes?.length ?? null, source, position, options);\n },\n\n insertFromDocument: async (documentId, pages, options = {}) => {\n refuse(ASSEMBLE, 'pageEdit.insertFromDocument', options);\n if (pages.length === 0) throw noPages();\n const other = ctx.documentHandle(documentId);\n if (!other) {\n throw new PluginError('not-found', 'page-edit', `document '${documentId}' is not open`);\n }\n // The pages are the other document's, so its page list resolves them.\n const otherPages = ctx.get(DocumentsToken).listPages(documentId);\n const refs = pages.map((page) => {\n const found =\n typeof page === 'number'\n ? otherPages[page]\n : otherPages.find((candidate) => candidate.ref.objectNumber === page.objectNumber);\n if (!found) {\n throw new PluginError(\n 'not-found',\n 'page-edit',\n `document '${documentId}' has no such page`,\n );\n }\n return found.ref;\n });\n const position = positionOf(options.position);\n // The other document's session decides whether its pages may be copied\n // out: the engine refuses `doc.download` there with the permission named.\n const bytes = await mapErrors(() =>\n ctx.cancellable(options.signal, other.pages.extract(refs)),\n );\n return insertBytes('insert', refs.length, bytes, position, options);\n },\n\n duplicate: async (pages, options = {}) => {\n refuse(ASSEMBLE, 'pageEdit.duplicate', options);\n ctx.assertAllowed(DOWNLOAD, 'pageEdit.duplicate');\n const refs = refsOf(pages);\n const position = options.position\n ? positionOf(options.position)\n : { after: refs[refs.length - 1]! };\n const bytes = await extractShown(refs, options);\n return insertBytes('duplicate', refs.length, bytes, position, options);\n },\n\n extract: async (pages, options) => {\n refuse(DOWNLOAD, 'pageEdit.extract', options);\n return extractShown(refsOf(pages), options);\n },\n };\n return { api };\n}\n","import { definePlugin } from '@embedpdf/core';\n\nimport { PageEditToken } from './contract';\nimport { createPageEditController } from './controller';\nimport { initialPageEditState } from './model';\n\n/**\n * Document-scoped: the document's page edits, each one change of its\n * history, and which of its pages are selected. Turning a page relative to\n * its own rotation lives in the controller, so no app re-derives it.\n */\nexport const pageEditPlugin = () =>\n definePlugin({\n id: 'page-edit',\n scope: 'document',\n token: PageEditToken,\n state: initialPageEditState,\n create: createPageEditController,\n });\n","/**\n * The pages page's State table as code: what `usePageEditState()` returns,\n * and the same fields in every other framework.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { PageEditToken } from './contract';\n\nexport const pageEditState = defineState(PageEditToken, {\n read: (pageEdit) => ({\n selected: pageEdit.getSelected(),\n canEdit: pageEdit.canEdit(),\n canExtract: pageEdit.canExtract(),\n }),\n empty: {\n selected: [],\n canEdit: false,\n canExtract: false,\n },\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-page-edit",
3
- "version": "3.0.0-next.15",
3
+ "version": "3.0.0-next.16",
4
4
  "private": false,
5
- "description": "Document-scoped page-edit capability: ref-addressed rotate/move/delete/insert over the engine DocumentHandle. Owns relative→absolute rotation and placement resolution so framework adapters never re-derive them.",
5
+ "description": "Document-scoped page-edit capability: ref-addressed rotate/move/delete/insert over the engine DocumentHandle, each one change of the history, and the page selection. Owns relative→absolute rotation and position resolution so framework adapters never re-derive them.",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
8
8
  "module": "./dist/index.js",
@@ -22,11 +22,14 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@embedpdf/core": "3.0.0-next.15"
25
+ "@embedpdf/core": "3.0.0-next.16"
26
26
  },
27
27
  "devDependencies": {
28
28
  "typescript": "^5.0.0",
29
29
  "vitest": "^2.1.9",
30
+ "@embedpdf/engine": "3.0.0-next.16",
31
+ "@embedpdf/engine-core": "3.0.0-next.16",
32
+ "@embedpdf/plugin-history": "3.0.0-next.16",
30
33
  "@embedpdf/tooling-build": "0.0.0"
31
34
  },
32
35
  "license": "Apache-2.0",