@embedpdf/plugin-redaction 3.0.0-next.1 → 3.0.0-next.11

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.
@@ -0,0 +1,84 @@
1
+ import { AnnotationRef, RedactionApplyResult, RedactionApplyResult as RedactionApplyResult$1 } from "@embedpdf/engine-core";
2
+ //#region src/types.d.ts
3
+ /**
4
+ * One pending redaction mark — a live projection of a `redact` annotation on
5
+ * the annotation plane (the plugin owns NO mark state of its own; delete the
6
+ * annotation and the pending item is gone).
7
+ */
8
+ interface RedactionPendingItem {
9
+ /** Stable list key derived from the ref. */
10
+ id: string;
11
+ ref: AnnotationRef;
12
+ pageObjectNumber: number;
13
+ /** Display index (0-based) from the page registry — for "page N" labels. */
14
+ pageIndex: number;
15
+ /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */
16
+ kind: 'area' | 'text';
17
+ /** `/OverlayText` label, when set. */
18
+ overlayText: string | null;
19
+ }
20
+ interface RedactionState {
21
+ /** A destructive apply is in flight. */
22
+ applying: boolean;
23
+ /** The last apply result seen (own or remote), for status UI. */
24
+ lastResult: RedactionApplyResult | null;
25
+ }
26
+ type RedactionAction = {
27
+ type: 'APPLY_STARTED';
28
+ } | {
29
+ type: 'APPLY_FINISHED';
30
+ result: RedactionApplyResult | null;
31
+ };
32
+ /** A label edit: `overlayText: null` clears it; `repeat` tiles it. */
33
+ interface RedactionLabelPatch {
34
+ overlayText?: string | null;
35
+ repeat?: boolean;
36
+ }
37
+ interface RedactionCapability {
38
+ /**
39
+ * The twins (permissions.md). Marking and applying are DIFFERENT powers:
40
+ * a mark is an ordinary `redact` annotation, so `canMark()` is annotation
41
+ * create authority (any reviewer who can annotate can propose redactions —
42
+ * Acrobat parity); `canApply()` is the destructive rewrite — engine support
43
+ * present AND every capability the engine's apply asserts (`doc.redact`,
44
+ * `doc.pages.modify`, `doc.annotate.modify`). The engine enforces both
45
+ * independently — these are the UI mirrors.
46
+ */
47
+ canMark(): boolean;
48
+ canApply(): boolean;
49
+ isApplying(): boolean;
50
+ lastResult(): RedactionApplyResult | null;
51
+ /** The composed marking tool (text-selection over text + area drag elsewhere). */
52
+ enableRedact(): void;
53
+ toggleRedact(): void;
54
+ isRedactActive(): boolean;
55
+ /** Mark the current text selection (per page) and clear it. False when
56
+ * there is no selection plugin or no selection. */
57
+ queueCurrentSelection(): Promise<boolean>;
58
+ /** Load every page's annotations so the pending view is complete (the
59
+ * annotation plane loads lazily per page). Call when opening a panel. */
60
+ preparePending(): Promise<void>;
61
+ /** Pending marks over the LOADED annotation state (see preparePending). */
62
+ getPending(): RedactionPendingItem[];
63
+ pendingCount(): number;
64
+ /**
65
+ * Client-side estimate of how many OTHER annotations the given pending
66
+ * marks (default: all) would destroy — for confirm dialogs BEFORE the
67
+ * apply. The authoritative count comes back on the result.
68
+ */
69
+ estimateCollateral(ids?: string[]): number;
70
+ /** Edit a mark's label. Reads the mark's current `/DA` styling and writes
71
+ * the full label set, so a text-only edit never resets the styling. */
72
+ setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;
73
+ /** Apply specific pending marks (refs scope). Irreversible. */
74
+ apply(ids: string[]): Promise<RedactionApplyResult>;
75
+ /** Apply every redaction in the document (pages scope — including marks on
76
+ * pages this client never loaded). Irreversible. */
77
+ applyAll(): Promise<RedactionApplyResult>;
78
+ /** Fires after ANY confirmed apply — own or a remote collaborator's. */
79
+ onApplied(cb: (result: RedactionApplyResult) => void): () => void;
80
+ }
81
+ declare const RedactionToken: import("@embedpdf/core").CapabilityToken<RedactionCapability>;
82
+ //#endregion
83
+ export { RedactionPendingItem as a, RedactionLabelPatch as i, RedactionAction as n, RedactionState as o, RedactionCapability as r, RedactionToken as s, RedactionApplyResult$1 as t };
84
+ //# sourceMappingURL=contract--fJOCVRN.d.cts.map
@@ -0,0 +1,84 @@
1
+ import { AnnotationRef, RedactionApplyResult, RedactionApplyResult as RedactionApplyResult$1 } from "@embedpdf/engine-core";
2
+ //#region src/types.d.ts
3
+ /**
4
+ * One pending redaction mark — a live projection of a `redact` annotation on
5
+ * the annotation plane (the plugin owns NO mark state of its own; delete the
6
+ * annotation and the pending item is gone).
7
+ */
8
+ interface RedactionPendingItem {
9
+ /** Stable list key derived from the ref. */
10
+ id: string;
11
+ ref: AnnotationRef;
12
+ pageObjectNumber: number;
13
+ /** Display index (0-based) from the page registry — for "page N" labels. */
14
+ pageIndex: number;
15
+ /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */
16
+ kind: 'area' | 'text';
17
+ /** `/OverlayText` label, when set. */
18
+ overlayText: string | null;
19
+ }
20
+ interface RedactionState {
21
+ /** A destructive apply is in flight. */
22
+ applying: boolean;
23
+ /** The last apply result seen (own or remote), for status UI. */
24
+ lastResult: RedactionApplyResult | null;
25
+ }
26
+ type RedactionAction = {
27
+ type: 'APPLY_STARTED';
28
+ } | {
29
+ type: 'APPLY_FINISHED';
30
+ result: RedactionApplyResult | null;
31
+ };
32
+ /** A label edit: `overlayText: null` clears it; `repeat` tiles it. */
33
+ interface RedactionLabelPatch {
34
+ overlayText?: string | null;
35
+ repeat?: boolean;
36
+ }
37
+ interface RedactionCapability {
38
+ /**
39
+ * The twins (permissions.md). Marking and applying are DIFFERENT powers:
40
+ * a mark is an ordinary `redact` annotation, so `canMark()` is annotation
41
+ * create authority (any reviewer who can annotate can propose redactions —
42
+ * Acrobat parity); `canApply()` is the destructive rewrite — engine support
43
+ * present AND every capability the engine's apply asserts (`doc.redact`,
44
+ * `doc.pages.modify`, `doc.annotate.modify`). The engine enforces both
45
+ * independently — these are the UI mirrors.
46
+ */
47
+ canMark(): boolean;
48
+ canApply(): boolean;
49
+ isApplying(): boolean;
50
+ lastResult(): RedactionApplyResult | null;
51
+ /** The composed marking tool (text-selection over text + area drag elsewhere). */
52
+ enableRedact(): void;
53
+ toggleRedact(): void;
54
+ isRedactActive(): boolean;
55
+ /** Mark the current text selection (per page) and clear it. False when
56
+ * there is no selection plugin or no selection. */
57
+ queueCurrentSelection(): Promise<boolean>;
58
+ /** Load every page's annotations so the pending view is complete (the
59
+ * annotation plane loads lazily per page). Call when opening a panel. */
60
+ preparePending(): Promise<void>;
61
+ /** Pending marks over the LOADED annotation state (see preparePending). */
62
+ getPending(): RedactionPendingItem[];
63
+ pendingCount(): number;
64
+ /**
65
+ * Client-side estimate of how many OTHER annotations the given pending
66
+ * marks (default: all) would destroy — for confirm dialogs BEFORE the
67
+ * apply. The authoritative count comes back on the result.
68
+ */
69
+ estimateCollateral(ids?: string[]): number;
70
+ /** Edit a mark's label. Reads the mark's current `/DA` styling and writes
71
+ * the full label set, so a text-only edit never resets the styling. */
72
+ setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;
73
+ /** Apply specific pending marks (refs scope). Irreversible. */
74
+ apply(ids: string[]): Promise<RedactionApplyResult>;
75
+ /** Apply every redaction in the document (pages scope — including marks on
76
+ * pages this client never loaded). Irreversible. */
77
+ applyAll(): Promise<RedactionApplyResult>;
78
+ /** Fires after ANY confirmed apply — own or a remote collaborator's. */
79
+ onApplied(cb: (result: RedactionApplyResult) => void): () => void;
80
+ }
81
+ declare const RedactionToken: import("@embedpdf/core").CapabilityToken<RedactionCapability>;
82
+ //#endregion
83
+ export { RedactionPendingItem as a, RedactionLabelPatch as i, RedactionAction as n, RedactionState as o, RedactionCapability as r, RedactionToken as s, RedactionApplyResult$1 as t };
84
+ //# sourceMappingURL=contract--fJOCVRN.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { createCapabilityToken } from "@embedpdf/core";
2
+ //#region src/types.ts
3
+ const RedactionToken = createCapabilityToken("redaction");
4
+ //#endregion
5
+ export { RedactionToken as t };
6
+
7
+ //# sourceMappingURL=contract-BZLrD3p2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-BZLrD3p2.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken } from '@embedpdf/core';\nimport type { AnnotationRef, RedactionApplyResult } from '@embedpdf/engine-core';\n\n/**\n * One pending redaction mark — a live projection of a `redact` annotation on\n * the annotation plane (the plugin owns NO mark state of its own; delete the\n * annotation and the pending item is gone).\n */\nexport interface RedactionPendingItem {\n /** Stable list key derived from the ref. */\n id: string;\n ref: AnnotationRef;\n pageObjectNumber: number;\n /** Display index (0-based) from the page registry — for \"page N\" labels. */\n pageIndex: number;\n /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */\n kind: 'area' | 'text';\n /** `/OverlayText` label, when set. */\n overlayText: string | null;\n}\n\nexport interface RedactionState {\n /** A destructive apply is in flight. */\n applying: boolean;\n /** The last apply result seen (own or remote), for status UI. */\n lastResult: RedactionApplyResult | null;\n}\n\nexport type RedactionAction =\n | { type: 'APPLY_STARTED' }\n | { type: 'APPLY_FINISHED'; result: RedactionApplyResult | null };\n\n/** A label edit: `overlayText: null` clears it; `repeat` tiles it. */\nexport interface RedactionLabelPatch {\n overlayText?: string | null;\n repeat?: boolean;\n}\n\nexport interface RedactionCapability {\n /**\n * The twins (permissions.md). Marking and applying are DIFFERENT powers:\n * a mark is an ordinary `redact` annotation, so `canMark()` is annotation\n * create authority (any reviewer who can annotate can propose redactions —\n * Acrobat parity); `canApply()` is the destructive rewrite — engine support\n * present AND every capability the engine's apply asserts (`doc.redact`,\n * `doc.pages.modify`, `doc.annotate.modify`). The engine enforces both\n * independently — these are the UI mirrors.\n */\n canMark(): boolean;\n canApply(): boolean;\n isApplying(): boolean;\n lastResult(): RedactionApplyResult | null;\n\n /** The composed marking tool (text-selection over text + area drag elsewhere). */\n enableRedact(): void;\n toggleRedact(): void;\n isRedactActive(): boolean;\n\n /** Mark the current text selection (per page) and clear it. False when\n * there is no selection plugin or no selection. */\n queueCurrentSelection(): Promise<boolean>;\n\n /** Load every page's annotations so the pending view is complete (the\n * annotation plane loads lazily per page). Call when opening a panel. */\n preparePending(): Promise<void>;\n /** Pending marks over the LOADED annotation state (see preparePending). */\n getPending(): RedactionPendingItem[];\n pendingCount(): number;\n /**\n * Client-side estimate of how many OTHER annotations the given pending\n * marks (default: all) would destroy — for confirm dialogs BEFORE the\n * apply. The authoritative count comes back on the result.\n */\n estimateCollateral(ids?: string[]): number;\n\n /** Edit a mark's label. Reads the mark's current `/DA` styling and writes\n * the full label set, so a text-only edit never resets the styling. */\n setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;\n\n /** Apply specific pending marks (refs scope). Irreversible. */\n apply(ids: string[]): Promise<RedactionApplyResult>;\n /** Apply every redaction in the document (pages scope — including marks on\n * pages this client never loaded). Irreversible. */\n applyAll(): Promise<RedactionApplyResult>;\n\n /** Fires after ANY confirmed apply — own or a remote collaborator's. */\n onApplied(cb: (result: RedactionApplyResult) => void): () => void;\n}\n\nexport const RedactionToken = createCapabilityToken<RedactionCapability>('redaction');\n"],"mappings":";;AAyFA,MAAa,iBAAiB,sBAA2C,WAAW"}
@@ -0,0 +1,11 @@
1
+ //#region src/types.ts
2
+ const RedactionToken = (0, require("@embedpdf/core").createCapabilityToken)("redaction");
3
+ //#endregion
4
+ Object.defineProperty(exports, "RedactionToken", {
5
+ enumerable: true,
6
+ get: function() {
7
+ return RedactionToken;
8
+ }
9
+ });
10
+
11
+ //# sourceMappingURL=contract-CyLm5eeQ.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-CyLm5eeQ.cjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken } from '@embedpdf/core';\nimport type { AnnotationRef, RedactionApplyResult } from '@embedpdf/engine-core';\n\n/**\n * One pending redaction mark — a live projection of a `redact` annotation on\n * the annotation plane (the plugin owns NO mark state of its own; delete the\n * annotation and the pending item is gone).\n */\nexport interface RedactionPendingItem {\n /** Stable list key derived from the ref. */\n id: string;\n ref: AnnotationRef;\n pageObjectNumber: number;\n /** Display index (0-based) from the page registry — for \"page N\" labels. */\n pageIndex: number;\n /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */\n kind: 'area' | 'text';\n /** `/OverlayText` label, when set. */\n overlayText: string | null;\n}\n\nexport interface RedactionState {\n /** A destructive apply is in flight. */\n applying: boolean;\n /** The last apply result seen (own or remote), for status UI. */\n lastResult: RedactionApplyResult | null;\n}\n\nexport type RedactionAction =\n | { type: 'APPLY_STARTED' }\n | { type: 'APPLY_FINISHED'; result: RedactionApplyResult | null };\n\n/** A label edit: `overlayText: null` clears it; `repeat` tiles it. */\nexport interface RedactionLabelPatch {\n overlayText?: string | null;\n repeat?: boolean;\n}\n\nexport interface RedactionCapability {\n /**\n * The twins (permissions.md). Marking and applying are DIFFERENT powers:\n * a mark is an ordinary `redact` annotation, so `canMark()` is annotation\n * create authority (any reviewer who can annotate can propose redactions —\n * Acrobat parity); `canApply()` is the destructive rewrite — engine support\n * present AND every capability the engine's apply asserts (`doc.redact`,\n * `doc.pages.modify`, `doc.annotate.modify`). The engine enforces both\n * independently — these are the UI mirrors.\n */\n canMark(): boolean;\n canApply(): boolean;\n isApplying(): boolean;\n lastResult(): RedactionApplyResult | null;\n\n /** The composed marking tool (text-selection over text + area drag elsewhere). */\n enableRedact(): void;\n toggleRedact(): void;\n isRedactActive(): boolean;\n\n /** Mark the current text selection (per page) and clear it. False when\n * there is no selection plugin or no selection. */\n queueCurrentSelection(): Promise<boolean>;\n\n /** Load every page's annotations so the pending view is complete (the\n * annotation plane loads lazily per page). Call when opening a panel. */\n preparePending(): Promise<void>;\n /** Pending marks over the LOADED annotation state (see preparePending). */\n getPending(): RedactionPendingItem[];\n pendingCount(): number;\n /**\n * Client-side estimate of how many OTHER annotations the given pending\n * marks (default: all) would destroy — for confirm dialogs BEFORE the\n * apply. The authoritative count comes back on the result.\n */\n estimateCollateral(ids?: string[]): number;\n\n /** Edit a mark's label. Reads the mark's current `/DA` styling and writes\n * the full label set, so a text-only edit never resets the styling. */\n setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;\n\n /** Apply specific pending marks (refs scope). Irreversible. */\n apply(ids: string[]): Promise<RedactionApplyResult>;\n /** Apply every redaction in the document (pages scope — including marks on\n * pages this client never loaded). Irreversible. */\n applyAll(): Promise<RedactionApplyResult>;\n\n /** Fires after ANY confirmed apply — own or a remote collaborator's. */\n onApplied(cb: (result: RedactionApplyResult) => void): () => void;\n}\n\nexport const RedactionToken = createCapabilityToken<RedactionCapability>('redaction');\n"],"mappings":";AAyFA,MAAa,kBAAA,2BAAA,CAAA,CAAA,sBAAA,CAA4D,WAAW"}
@@ -0,0 +1,3 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_contract = require("./contract-CyLm5eeQ.cjs");
3
+ exports.RedactionToken = require_contract.RedactionToken;
@@ -0,0 +1,2 @@
1
+ import { a as RedactionPendingItem, i as RedactionLabelPatch, o as RedactionState, r as RedactionCapability, s as RedactionToken, t as RedactionApplyResult } from "./contract--fJOCVRN.cjs";
2
+ export { type RedactionApplyResult, type RedactionCapability, type RedactionLabelPatch, type RedactionPendingItem, type RedactionState, RedactionToken };
@@ -0,0 +1,2 @@
1
+ import { a as RedactionPendingItem, i as RedactionLabelPatch, o as RedactionState, r as RedactionCapability, s as RedactionToken, t as RedactionApplyResult } from "./contract--fJOCVRN.js";
2
+ export { type RedactionApplyResult, type RedactionCapability, type RedactionLabelPatch, type RedactionPendingItem, type RedactionState, RedactionToken };
@@ -0,0 +1,2 @@
1
+ import { t as RedactionToken } from "./contract-BZLrD3p2.js";
2
+ export { RedactionToken };
package/dist/index.cjs CHANGED
@@ -1,11 +1,19 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_contract = require("./contract-CyLm5eeQ.cjs");
2
3
  let _embedpdf_core = require("@embedpdf/core");
3
- let _embedpdf_plugin_annotation_internal = require("@embedpdf/plugin-annotation/internal");
4
- let _embedpdf_plugin_interaction = require("@embedpdf/plugin-interaction");
5
- let _embedpdf_plugin_selection = require("@embedpdf/plugin-selection");
4
+ let _embedpdf_plugin_annotation_contract_host = require("@embedpdf/plugin-annotation/contract/host");
5
+ let _embedpdf_plugin_interaction_contract = require("@embedpdf/plugin-interaction/contract");
6
+ let _embedpdf_plugin_selection_contract = require("@embedpdf/plugin-selection/contract");
6
7
  //#region src/capability.ts
7
- /** Applying destroys content — its own granted power, narrower than annotate. */
8
- const REDACT_CAPABILITY = "doc.redact";
8
+ /** Applying destroys content — its own granted power, narrower than annotate.
9
+ * The engine's apply asserts all three (LocalDocumentRedactionService; the
10
+ * cloud route guards match): the redact grant itself, the page-content
11
+ * rewrite, and the annotation consumption. `canApply` mirrors the full set. */
12
+ const APPLY_CAPABILITIES = [
13
+ "doc.redact",
14
+ "doc.pages.modify",
15
+ "doc.annotate.modify"
16
+ ];
9
17
  /** The annotation plugin's model-id convention for a durable ref. */
10
18
  const idOf = (ref) => ref.kind === "objectNumber" ? `obj:${ref.annotObjectNumber}` : ref.kind === "nm" ? `nm:${ref.nm}` : `idx:${ref.pageObjectNumber}:${ref.index}`;
11
19
  /** The PDF-space regions a redact mark targets: its quads' boxes, else `/Rect`. */
@@ -35,7 +43,7 @@ function regionsOf(dto) {
35
43
  /** Positive-area intersection — the engine's collateral rule. */
36
44
  const intersects = (a, b) => Math.min(a.right, b.right) > Math.max(a.left, b.left) && Math.min(a.top, b.top) > Math.max(a.bottom, b.bottom);
37
45
  function createRedactionCapability(ctx) {
38
- const anno = ctx.get(_embedpdf_plugin_annotation_internal.AnnotationToken);
46
+ const anno = ctx.get(_embedpdf_plugin_annotation_contract_host.AnnotationToken);
39
47
  const appliedCallbacks = /* @__PURE__ */ new Set();
40
48
  const requireDoc = () => {
41
49
  const doc = ctx.doc;
@@ -99,23 +107,29 @@ function createRedactionCapability(ctx) {
99
107
  fireApplied(event);
100
108
  }));
101
109
  return {
102
- canApply: () => (ctx.doc?.redaction !== void 0 && ctx.doc?.security.allows(REDACT_CAPABILITY)) ?? false,
110
+ canMark: () => anno.canCreate(),
111
+ canApply: () => {
112
+ const doc = ctx.doc;
113
+ if (!doc || doc.redaction === void 0) return false;
114
+ return APPLY_CAPABILITIES.every((cap) => doc.security.allows(cap));
115
+ },
103
116
  isApplying: () => ctx.getState().applying,
104
117
  lastResult: () => ctx.getState().lastResult,
105
- enableRedact: () => ctx.tryGet(_embedpdf_plugin_interaction.InteractionToken)?.activateTool("redact"),
118
+ enableRedact: () => ctx.tryGet(_embedpdf_plugin_interaction_contract.InteractionToken)?.activateTool("redact"),
106
119
  toggleRedact: () => {
107
- const interaction = ctx.tryGet(_embedpdf_plugin_interaction.InteractionToken);
120
+ const interaction = ctx.tryGet(_embedpdf_plugin_interaction_contract.InteractionToken);
108
121
  if (!interaction) return;
109
122
  interaction.activateTool(interaction.activeToolId() === "redact" ? "pointer" : "redact");
110
123
  },
111
- isRedactActive: () => ctx.tryGet(_embedpdf_plugin_interaction.InteractionToken)?.activeToolId() === "redact",
124
+ isRedactActive: () => ctx.tryGet(_embedpdf_plugin_interaction_contract.InteractionToken)?.activeToolId() === "redact",
112
125
  queueCurrentSelection: async () => {
113
- const selection = ctx.tryGet(_embedpdf_plugin_selection.SelectionToken);
126
+ if (!anno.canCreate()) return false;
127
+ const selection = ctx.tryGet(_embedpdf_plugin_selection_contract.SelectionToken);
114
128
  if (!selection || !selection.hasSelection()) return false;
115
129
  const snapshot = selection.snapshot();
116
130
  for (const page of snapshot.pages) {
117
- if (page.rects.length === 0) continue;
118
- anno.createMarkup("redact", page.pon, page.rects, "redact");
131
+ if (page.segments.length === 0) continue;
132
+ anno.createMarkup("redact", page.pon, page.segments.map((segment) => segment.quad), "redact");
119
133
  }
120
134
  selection.clear();
121
135
  return true;
@@ -196,9 +210,6 @@ const redactionReducer = (state, action) => {
196
210
  }
197
211
  };
198
212
  //#endregion
199
- //#region src/types.ts
200
- const RedactionToken = (0, _embedpdf_core.createCapabilityToken)("redaction");
201
- //#endregion
202
213
  //#region src/redaction.plugin.ts
203
214
  /**
204
215
  * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage
@@ -212,16 +223,16 @@ const RedactionToken = (0, _embedpdf_core.createCapabilityToken)("redaction");
212
223
  */
213
224
  const redactionPlugin = () => (0, _embedpdf_core.definePlugin)({
214
225
  id: "redaction",
215
- token: RedactionToken,
226
+ token: require_contract.RedactionToken,
216
227
  scope: "document",
217
- requires: [_embedpdf_plugin_annotation_internal.AnnotationToken],
218
- optional: [_embedpdf_plugin_interaction.InteractionToken, _embedpdf_plugin_selection.SelectionToken],
228
+ requires: [_embedpdf_plugin_annotation_contract_host.AnnotationToken],
229
+ optional: [_embedpdf_plugin_interaction_contract.InteractionToken, _embedpdf_plugin_selection_contract.SelectionToken],
219
230
  initialState: initialRedactionState,
220
231
  reduce: redactionReducer,
221
232
  capability: createRedactionCapability
222
233
  });
223
234
  //#endregion
224
- exports.RedactionToken = RedactionToken;
235
+ exports.RedactionToken = require_contract.RedactionToken;
225
236
  exports.redactionPlugin = redactionPlugin;
226
237
 
227
238
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["AnnotationToken","InteractionToken","SelectionToken","AnnotationToken","InteractionToken","SelectionToken"],"sources":["../src/capability.ts","../src/reducer.ts","../src/types.ts","../src/redaction.plugin.ts"],"sourcesContent":["import type { DocCapability, PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/internal';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport type {\n AnnotationDTO,\n AnnotationRef,\n PdfRect,\n RedactionApplyResult,\n} from '@embedpdf/engine-core';\nimport type {\n RedactionAction,\n RedactionCapability,\n RedactionLabelPatch,\n RedactionPendingItem,\n RedactionState,\n} from './types';\n\n/** Applying destroys content — its own granted power, narrower than annotate. */\nconst REDACT_CAPABILITY: DocCapability = 'doc.redact';\n\n/** The annotation plugin's model-id convention for a durable ref. */\nconst idOf = (ref: AnnotationRef): string =>\n ref.kind === 'objectNumber'\n ? `obj:${ref.annotObjectNumber}`\n : ref.kind === 'nm'\n ? `nm:${ref.nm}`\n : `idx:${ref.pageObjectNumber}:${ref.index}`;\n\ntype RedactDTO = Extract<AnnotationDTO, { subtype: 'redact' }>;\n\n/** The PDF-space regions a redact mark targets: its quads' boxes, else `/Rect`. */\nfunction regionsOf(dto: RedactDTO): PdfRect[] {\n if (dto.quadPoints.length === 0) return [dto.rect];\n return dto.quadPoints.map((q) => {\n const xs = [q.p1.x, q.p2.x, q.p3.x, q.p4.x];\n const ys = [q.p1.y, q.p2.y, q.p3.y, q.p4.y];\n return {\n left: Math.min(...xs),\n right: Math.max(...xs),\n bottom: Math.min(...ys),\n top: Math.max(...ys),\n };\n });\n}\n\n/** Positive-area intersection — the engine's collateral rule. */\nconst intersects = (a: PdfRect, b: PdfRect): boolean =>\n Math.min(a.right, b.right) > Math.max(a.left, b.left) &&\n Math.min(a.top, b.top) > Math.max(a.bottom, b.bottom);\n\nexport function createRedactionCapability(\n ctx: PluginContext<RedactionState, RedactionAction>,\n): RedactionCapability {\n const anno = ctx.get(AnnotationToken);\n const appliedCallbacks = new Set<(result: RedactionApplyResult) => void>();\n\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[redaction] no document bound');\n return doc;\n };\n const requireService = () => {\n const doc = requireDoc();\n if (!doc.redaction) throw new Error('[redaction] engine has no redaction service');\n return doc.redaction;\n };\n\n const pons = (): number[] => (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber);\n\n const pageIndexOf = (pon: number): number =>\n ctx.document()?.pages.find((p) => p.pageObjectNumber === pon)?.index ?? -1;\n\n const pendingOn = (pon: number): RedactDTO[] =>\n anno.list(pon).filter((a): a is RedactDTO => a.subtype === 'redact');\n\n const collectPending = (): RedactionPendingItem[] => {\n const items: RedactionPendingItem[] = [];\n for (const pon of pons()) {\n for (const dto of pendingOn(pon)) {\n items.push({\n id: idOf(dto.ref),\n ref: dto.ref,\n pageObjectNumber: pon,\n pageIndex: pageIndexOf(pon),\n kind: dto.quadPoints.length > 0 ? 'text' : 'area',\n overlayText: dto.overlayText,\n });\n }\n }\n return items;\n };\n\n const fireApplied = (result: RedactionApplyResult) => {\n for (const cb of appliedCallbacks) {\n try {\n cb(result);\n } catch (err) {\n console.error('[redaction] onApplied callback failed', err);\n }\n }\n };\n\n const runApply = async (\n scope: Parameters<ReturnType<typeof requireService>['apply']>[0],\n ): Promise<RedactionApplyResult> => {\n const service = requireService();\n ctx.dispatch({ type: 'APPLY_STARTED' });\n try {\n const result = await service.apply(scope);\n ctx.dispatch({ type: 'APPLY_FINISHED', result });\n fireApplied(result);\n return result;\n } catch (err) {\n ctx.dispatch({ type: 'APPLY_FINISHED', result: null });\n throw err;\n }\n };\n\n // A REMOTE collaborator's apply arrives only as a document event (own\n // applies flow through runApply above). Annotation state + raster\n // invalidation are handled by their own planes; here we only surface it.\n const doc = ctx.doc;\n if (doc) {\n ctx.cleanup(\n doc.events.subscribe((event) => {\n if (event.type !== 'redaction.applied') return;\n if (event.origin.kind !== 'remote') return;\n ctx.dispatch({ type: 'APPLY_FINISHED', result: event });\n fireApplied(event);\n }),\n );\n }\n\n return {\n canApply: () =>\n (ctx.doc?.redaction !== undefined && ctx.doc?.security.allows(REDACT_CAPABILITY)) ?? false,\n isApplying: () => ctx.getState().applying,\n lastResult: () => ctx.getState().lastResult,\n\n enableRedact: () => ctx.tryGet(InteractionToken)?.activateTool('redact'),\n toggleRedact: () => {\n const interaction = ctx.tryGet(InteractionToken);\n if (!interaction) return;\n interaction.activateTool(interaction.activeToolId() === 'redact' ? 'pointer' : 'redact');\n },\n isRedactActive: () => ctx.tryGet(InteractionToken)?.activeToolId() === 'redact',\n\n queueCurrentSelection: async () => {\n const selection = ctx.tryGet(SelectionToken);\n if (!selection || !selection.hasSelection()) return false;\n const snapshot = selection.snapshot();\n for (const page of snapshot.pages) {\n if (page.rects.length === 0) continue;\n anno.createMarkup('redact', page.pon, page.rects, 'redact');\n }\n selection.clear();\n return true;\n },\n\n preparePending: async () => {\n await Promise.all(pons().map((pon) => anno.ensurePage(pon)));\n },\n getPending: collectPending,\n pendingCount: () => collectPending().length,\n\n estimateCollateral: (ids) => {\n const wanted = ids ? new Set(ids) : null;\n let count = 0;\n for (const pon of pons()) {\n const all = anno.list(pon);\n const marks = all.filter(\n (a): a is RedactDTO => a.subtype === 'redact' && (!wanted || wanted.has(idOf(a.ref))),\n );\n if (marks.length === 0) continue;\n const regions = marks.flatMap(regionsOf);\n for (const other of all) {\n if (other.subtype === 'redact') continue;\n if (regions.some((r) => intersects(r, other.rect))) count++;\n }\n }\n return count;\n },\n\n setLabel: async (ref, patch: RedactionLabelPatch) => {\n const current = anno.get(ref);\n if (!current || current.subtype !== 'redact') {\n throw new Error('[redaction] setLabel target is not a redact annotation');\n }\n // Always carry the current /DA styling: the engine rewrites /DA whenever\n // a label field rides a patch, so a text-only edit must not let the\n // styling fall back to defaults.\n await anno.update(ref, {\n subtype: 'redact',\n ...(patch.overlayText !== undefined ? { overlayText: patch.overlayText } : {}),\n ...(patch.repeat !== undefined ? { repeat: patch.repeat } : {}),\n fontFamily: current.fontFamily,\n fontSize: current.fontSize,\n fontColor: current.fontColor,\n textAlign: current.textAlign,\n });\n },\n\n apply: async (ids) => {\n const wanted = new Set(ids);\n const refs = collectPending()\n .filter((p) => wanted.has(p.id))\n .map((p) => p.ref);\n if (refs.length === 0) throw new Error('[redaction] no matching pending redactions');\n return runApply({ kind: 'annotations', refs });\n },\n\n applyAll: async () => {\n // Pages scope: authoritative for the WHOLE document, including marks on\n // pages this client never loaded. Pages without marks report 'unchanged'.\n const pageObjectNumbers = pons();\n if (pageObjectNumbers.length === 0) throw new Error('[redaction] document has no pages');\n return runApply({ kind: 'pages', pageObjectNumbers });\n },\n\n onApplied: (cb) => {\n appliedCallbacks.add(cb);\n return () => appliedCallbacks.delete(cb);\n },\n };\n}\n","import type { RedactionAction, RedactionState } from './types';\n\nexport const initialRedactionState = (): RedactionState => ({\n applying: false,\n lastResult: null,\n});\n\nexport const redactionReducer = (\n state: RedactionState,\n action: RedactionAction,\n): RedactionState => {\n switch (action.type) {\n case 'APPLY_STARTED':\n return { ...state, applying: true };\n case 'APPLY_FINISHED':\n return { applying: false, lastResult: action.result ?? state.lastResult };\n default:\n return state;\n }\n};\n","import { createCapabilityToken } from '@embedpdf/core';\nimport type { AnnotationRef, RedactionApplyResult } from '@embedpdf/engine-core';\n\n/**\n * One pending redaction mark — a live projection of a `redact` annotation on\n * the annotation plane (the plugin owns NO mark state of its own; delete the\n * annotation and the pending item is gone).\n */\nexport interface RedactionPendingItem {\n /** Stable list key derived from the ref. */\n id: string;\n ref: AnnotationRef;\n pageObjectNumber: number;\n /** Display index (0-based) from the page registry — for \"page N\" labels. */\n pageIndex: number;\n /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */\n kind: 'area' | 'text';\n /** `/OverlayText` label, when set. */\n overlayText: string | null;\n}\n\nexport interface RedactionState {\n /** A destructive apply is in flight. */\n applying: boolean;\n /** The last apply result seen (own or remote), for status UI. */\n lastResult: RedactionApplyResult | null;\n}\n\nexport type RedactionAction =\n | { type: 'APPLY_STARTED' }\n | { type: 'APPLY_FINISHED'; result: RedactionApplyResult | null };\n\n/** A label edit: `overlayText: null` clears it; `repeat` tiles it. */\nexport interface RedactionLabelPatch {\n overlayText?: string | null;\n repeat?: boolean;\n}\n\nexport interface RedactionCapability {\n /** Engine support present AND this session holds `doc.redact`. The engine\n * enforces the same capability independently — this is the UI mirror. */\n canApply(): boolean;\n isApplying(): boolean;\n lastResult(): RedactionApplyResult | null;\n\n /** The composed marking tool (text-selection over text + area drag elsewhere). */\n enableRedact(): void;\n toggleRedact(): void;\n isRedactActive(): boolean;\n\n /** Mark the current text selection (per page) and clear it. False when\n * there is no selection plugin or no selection. */\n queueCurrentSelection(): Promise<boolean>;\n\n /** Load every page's annotations so the pending view is complete (the\n * annotation plane loads lazily per page). Call when opening a panel. */\n preparePending(): Promise<void>;\n /** Pending marks over the LOADED annotation state (see preparePending). */\n getPending(): RedactionPendingItem[];\n pendingCount(): number;\n /**\n * Client-side estimate of how many OTHER annotations the given pending\n * marks (default: all) would destroy — for confirm dialogs BEFORE the\n * apply. The authoritative count comes back on the result.\n */\n estimateCollateral(ids?: string[]): number;\n\n /** Edit a mark's label. Reads the mark's current `/DA` styling and writes\n * the full label set, so a text-only edit never resets the styling. */\n setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;\n\n /** Apply specific pending marks (refs scope). Irreversible. */\n apply(ids: string[]): Promise<RedactionApplyResult>;\n /** Apply every redaction in the document (pages scope — including marks on\n * pages this client never loaded). Irreversible. */\n applyAll(): Promise<RedactionApplyResult>;\n\n /** Fires after ANY confirmed apply — own or a remote collaborator's. */\n onApplied(cb: (result: RedactionApplyResult) => void): () => void;\n}\n\nexport const RedactionToken = createCapabilityToken<RedactionCapability>('redaction');\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/internal';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport { createRedactionCapability } from './capability';\nimport { initialRedactionState, redactionReducer } from './reducer';\nimport { RedactionToken } from './types';\nimport type { RedactionAction, RedactionCapability, RedactionState } from './types';\n\n/**\n * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage\n * model. Marking is annotation-plane work (the composed `redact` tool ships\n * with plugin-annotation); this plugin wraps `doc.redaction.apply`, projects\n * the pending queue out of annotation state, and estimates collateral for\n * confirm dialogs. It owns no mark state of its own.\n *\n * Trust boundary: on a layered document, applying rewrites the LAYER's bytes;\n * the immutable base keeps the original. See the package README.\n */\nexport const redactionPlugin = () =>\n definePlugin<RedactionState, RedactionAction, RedactionCapability>({\n id: 'redaction',\n token: RedactionToken,\n scope: 'document',\n requires: [AnnotationToken],\n optional: [InteractionToken, SelectionToken],\n initialState: initialRedactionState,\n reduce: redactionReducer,\n capability: createRedactionCapability,\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["AnnotationToken","InteractionToken","SelectionToken","RedactionToken","AnnotationToken","InteractionToken","SelectionToken"],"sources":["../src/capability.ts","../src/reducer.ts","../src/redaction.plugin.ts"],"sourcesContent":["import type { DocCapability, PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { SelectionToken } from '@embedpdf/plugin-selection/contract';\nimport type {\n AnnotationDTO,\n AnnotationRef,\n PdfRect,\n RedactionApplyResult,\n} from '@embedpdf/engine-core';\nimport type {\n RedactionAction,\n RedactionCapability,\n RedactionLabelPatch,\n RedactionPendingItem,\n RedactionState,\n} from './types';\n\n/** Applying destroys content — its own granted power, narrower than annotate.\n * The engine's apply asserts all three (LocalDocumentRedactionService; the\n * cloud route guards match): the redact grant itself, the page-content\n * rewrite, and the annotation consumption. `canApply` mirrors the full set. */\nconst APPLY_CAPABILITIES: readonly DocCapability[] = [\n 'doc.redact',\n 'doc.pages.modify',\n 'doc.annotate.modify',\n];\n\n/** The annotation plugin's model-id convention for a durable ref. */\nconst idOf = (ref: AnnotationRef): string =>\n ref.kind === 'objectNumber'\n ? `obj:${ref.annotObjectNumber}`\n : ref.kind === 'nm'\n ? `nm:${ref.nm}`\n : `idx:${ref.pageObjectNumber}:${ref.index}`;\n\ntype RedactDTO = Extract<AnnotationDTO, { subtype: 'redact' }>;\n\n/** The PDF-space regions a redact mark targets: its quads' boxes, else `/Rect`. */\nfunction regionsOf(dto: RedactDTO): PdfRect[] {\n if (dto.quadPoints.length === 0) return [dto.rect];\n return dto.quadPoints.map((q) => {\n const xs = [q.p1.x, q.p2.x, q.p3.x, q.p4.x];\n const ys = [q.p1.y, q.p2.y, q.p3.y, q.p4.y];\n return {\n left: Math.min(...xs),\n right: Math.max(...xs),\n bottom: Math.min(...ys),\n top: Math.max(...ys),\n };\n });\n}\n\n/** Positive-area intersection — the engine's collateral rule. */\nconst intersects = (a: PdfRect, b: PdfRect): boolean =>\n Math.min(a.right, b.right) > Math.max(a.left, b.left) &&\n Math.min(a.top, b.top) > Math.max(a.bottom, b.bottom);\n\nexport function createRedactionCapability(\n ctx: PluginContext<RedactionState, RedactionAction>,\n): RedactionCapability {\n const anno = ctx.get(AnnotationToken);\n const appliedCallbacks = new Set<(result: RedactionApplyResult) => void>();\n\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[redaction] no document bound');\n return doc;\n };\n const requireService = () => {\n const doc = requireDoc();\n if (!doc.redaction) throw new Error('[redaction] engine has no redaction service');\n return doc.redaction;\n };\n\n const pons = (): number[] => (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber);\n\n const pageIndexOf = (pon: number): number =>\n ctx.document()?.pages.find((p) => p.pageObjectNumber === pon)?.index ?? -1;\n\n const pendingOn = (pon: number): RedactDTO[] =>\n anno.list(pon).filter((a): a is RedactDTO => a.subtype === 'redact');\n\n const collectPending = (): RedactionPendingItem[] => {\n const items: RedactionPendingItem[] = [];\n for (const pon of pons()) {\n for (const dto of pendingOn(pon)) {\n items.push({\n id: idOf(dto.ref),\n ref: dto.ref,\n pageObjectNumber: pon,\n pageIndex: pageIndexOf(pon),\n kind: dto.quadPoints.length > 0 ? 'text' : 'area',\n overlayText: dto.overlayText,\n });\n }\n }\n return items;\n };\n\n const fireApplied = (result: RedactionApplyResult) => {\n for (const cb of appliedCallbacks) {\n try {\n cb(result);\n } catch (err) {\n console.error('[redaction] onApplied callback failed', err);\n }\n }\n };\n\n const runApply = async (\n scope: Parameters<ReturnType<typeof requireService>['apply']>[0],\n ): Promise<RedactionApplyResult> => {\n const service = requireService();\n ctx.dispatch({ type: 'APPLY_STARTED' });\n try {\n const result = await service.apply(scope);\n ctx.dispatch({ type: 'APPLY_FINISHED', result });\n fireApplied(result);\n return result;\n } catch (err) {\n ctx.dispatch({ type: 'APPLY_FINISHED', result: null });\n throw err;\n }\n };\n\n // A REMOTE collaborator's apply arrives only as a document event (own\n // applies flow through runApply above). Annotation state + raster\n // invalidation are handled by their own planes; here we only surface it.\n const doc = ctx.doc;\n if (doc) {\n ctx.cleanup(\n doc.events.subscribe((event) => {\n if (event.type !== 'redaction.applied') return;\n if (event.origin.kind !== 'remote') return;\n ctx.dispatch({ type: 'APPLY_FINISHED', result: event });\n fireApplied(event);\n }),\n );\n }\n\n return {\n // Marks are annotations — marking authority IS annotation create\n // authority (the annotation plugin's own twin, not a re-derivation).\n canMark: () => anno.canCreate(),\n // Mirror EVERYTHING the engine's apply asserts, not just the headline\n // capability — a token granted `doc.redact` à la carte without its bit-4\n // siblings must not see an armed Apply button.\n canApply: () => {\n const doc = ctx.doc;\n if (!doc || doc.redaction === undefined) return false;\n return APPLY_CAPABILITIES.every((cap) => doc.security.allows(cap));\n },\n isApplying: () => ctx.getState().applying,\n lastResult: () => ctx.getState().lastResult,\n\n enableRedact: () => ctx.tryGet(InteractionToken)?.activateTool('redact'),\n toggleRedact: () => {\n const interaction = ctx.tryGet(InteractionToken);\n if (!interaction) return;\n interaction.activateTool(interaction.activeToolId() === 'redact' ? 'pointer' : 'redact');\n },\n isRedactActive: () => ctx.tryGet(InteractionToken)?.activeToolId() === 'redact',\n\n queueCurrentSelection: async () => {\n // Marks are optimistic annotation creates — the same gate the pointer\n // path has (the annotation plugin refuses ungated creates too).\n if (!anno.canCreate()) return false;\n const selection = ctx.tryGet(SelectionToken);\n if (!selection || !selection.hasSelection()) return false;\n const snapshot = selection.snapshot();\n for (const page of snapshot.pages) {\n if (page.segments.length === 0) continue;\n // Preserve the selected text frame all the way into `/QuadPoints`.\n // Native apply now uses these exact cells for text removal and the\n // final overlay, so marked == previewed == applied for oriented text.\n anno.createMarkup(\n 'redact',\n page.pon,\n page.segments.map((segment) => segment.quad),\n 'redact',\n );\n }\n selection.clear();\n return true;\n },\n\n preparePending: async () => {\n await Promise.all(pons().map((pon) => anno.ensurePage(pon)));\n },\n getPending: collectPending,\n pendingCount: () => collectPending().length,\n\n estimateCollateral: (ids) => {\n const wanted = ids ? new Set(ids) : null;\n let count = 0;\n for (const pon of pons()) {\n const all = anno.list(pon);\n const marks = all.filter(\n (a): a is RedactDTO => a.subtype === 'redact' && (!wanted || wanted.has(idOf(a.ref))),\n );\n if (marks.length === 0) continue;\n const regions = marks.flatMap(regionsOf);\n for (const other of all) {\n if (other.subtype === 'redact') continue;\n if (regions.some((r) => intersects(r, other.rect))) count++;\n }\n }\n return count;\n },\n\n setLabel: async (ref, patch: RedactionLabelPatch) => {\n const current = anno.get(ref);\n if (!current || current.subtype !== 'redact') {\n throw new Error('[redaction] setLabel target is not a redact annotation');\n }\n // Always carry the current /DA styling: the engine rewrites /DA whenever\n // a label field rides a patch, so a text-only edit must not let the\n // styling fall back to defaults.\n await anno.update(ref, {\n subtype: 'redact',\n ...(patch.overlayText !== undefined ? { overlayText: patch.overlayText } : {}),\n ...(patch.repeat !== undefined ? { repeat: patch.repeat } : {}),\n fontFamily: current.fontFamily,\n fontSize: current.fontSize,\n fontColor: current.fontColor,\n textAlign: current.textAlign,\n });\n },\n\n apply: async (ids) => {\n const wanted = new Set(ids);\n const refs = collectPending()\n .filter((p) => wanted.has(p.id))\n .map((p) => p.ref);\n if (refs.length === 0) throw new Error('[redaction] no matching pending redactions');\n return runApply({ kind: 'annotations', refs });\n },\n\n applyAll: async () => {\n // Pages scope: authoritative for the WHOLE document, including marks on\n // pages this client never loaded. Pages without marks report 'unchanged'.\n const pageObjectNumbers = pons();\n if (pageObjectNumbers.length === 0) throw new Error('[redaction] document has no pages');\n return runApply({ kind: 'pages', pageObjectNumbers });\n },\n\n onApplied: (cb) => {\n appliedCallbacks.add(cb);\n return () => appliedCallbacks.delete(cb);\n },\n };\n}\n","import type { RedactionAction, RedactionState } from './types';\n\nexport const initialRedactionState = (): RedactionState => ({\n applying: false,\n lastResult: null,\n});\n\nexport const redactionReducer = (\n state: RedactionState,\n action: RedactionAction,\n): RedactionState => {\n switch (action.type) {\n case 'APPLY_STARTED':\n return { ...state, applying: true };\n case 'APPLY_FINISHED':\n return { applying: false, lastResult: action.result ?? state.lastResult };\n default:\n return state;\n }\n};\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { SelectionToken } from '@embedpdf/plugin-selection/contract';\nimport { createRedactionCapability } from './capability';\nimport { initialRedactionState, redactionReducer } from './reducer';\nimport { RedactionToken } from './types';\nimport type { RedactionAction, RedactionCapability, RedactionState } from './types';\n\n/**\n * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage\n * model. Marking is annotation-plane work (the composed `redact` tool ships\n * with plugin-annotation); this plugin wraps `doc.redaction.apply`, projects\n * the pending queue out of annotation state, and estimates collateral for\n * confirm dialogs. It owns no mark state of its own.\n *\n * Trust boundary: on a layered document, applying rewrites the LAYER's bytes;\n * the immutable base keeps the original. See the package README.\n */\nexport const redactionPlugin = () =>\n definePlugin<RedactionState, RedactionAction, RedactionCapability>({\n id: 'redaction',\n token: RedactionToken,\n scope: 'document',\n requires: [AnnotationToken],\n optional: [InteractionToken, SelectionToken],\n initialState: initialRedactionState,\n reduce: redactionReducer,\n capability: createRedactionCapability,\n });\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -1,77 +1,4 @@
1
- import { AnnotationRef, RedactionApplyResult, RedactionApplyResult as RedactionApplyResult$1 } from "@embedpdf/engine-core";
2
- //#region src/types.d.ts
3
- /**
4
- * One pending redaction mark — a live projection of a `redact` annotation on
5
- * the annotation plane (the plugin owns NO mark state of its own; delete the
6
- * annotation and the pending item is gone).
7
- */
8
- interface RedactionPendingItem {
9
- /** Stable list key derived from the ref. */
10
- id: string;
11
- ref: AnnotationRef;
12
- pageObjectNumber: number;
13
- /** Display index (0-based) from the page registry — for "page N" labels. */
14
- pageIndex: number;
15
- /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */
16
- kind: 'area' | 'text';
17
- /** `/OverlayText` label, when set. */
18
- overlayText: string | null;
19
- }
20
- interface RedactionState {
21
- /** A destructive apply is in flight. */
22
- applying: boolean;
23
- /** The last apply result seen (own or remote), for status UI. */
24
- lastResult: RedactionApplyResult$1 | null;
25
- }
26
- type RedactionAction = {
27
- type: 'APPLY_STARTED';
28
- } | {
29
- type: 'APPLY_FINISHED';
30
- result: RedactionApplyResult$1 | null;
31
- };
32
- /** A label edit: `overlayText: null` clears it; `repeat` tiles it. */
33
- interface RedactionLabelPatch {
34
- overlayText?: string | null;
35
- repeat?: boolean;
36
- }
37
- interface RedactionCapability {
38
- /** Engine support present AND this session holds `doc.redact`. The engine
39
- * enforces the same capability independently — this is the UI mirror. */
40
- canApply(): boolean;
41
- isApplying(): boolean;
42
- lastResult(): RedactionApplyResult$1 | null;
43
- /** The composed marking tool (text-selection over text + area drag elsewhere). */
44
- enableRedact(): void;
45
- toggleRedact(): void;
46
- isRedactActive(): boolean;
47
- /** Mark the current text selection (per page) and clear it. False when
48
- * there is no selection plugin or no selection. */
49
- queueCurrentSelection(): Promise<boolean>;
50
- /** Load every page's annotations so the pending view is complete (the
51
- * annotation plane loads lazily per page). Call when opening a panel. */
52
- preparePending(): Promise<void>;
53
- /** Pending marks over the LOADED annotation state (see preparePending). */
54
- getPending(): RedactionPendingItem[];
55
- pendingCount(): number;
56
- /**
57
- * Client-side estimate of how many OTHER annotations the given pending
58
- * marks (default: all) would destroy — for confirm dialogs BEFORE the
59
- * apply. The authoritative count comes back on the result.
60
- */
61
- estimateCollateral(ids?: string[]): number;
62
- /** Edit a mark's label. Reads the mark's current `/DA` styling and writes
63
- * the full label set, so a text-only edit never resets the styling. */
64
- setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;
65
- /** Apply specific pending marks (refs scope). Irreversible. */
66
- apply(ids: string[]): Promise<RedactionApplyResult$1>;
67
- /** Apply every redaction in the document (pages scope — including marks on
68
- * pages this client never loaded). Irreversible. */
69
- applyAll(): Promise<RedactionApplyResult$1>;
70
- /** Fires after ANY confirmed apply — own or a remote collaborator's. */
71
- onApplied(cb: (result: RedactionApplyResult$1) => void): () => void;
72
- }
73
- declare const RedactionToken: import("@embedpdf/core").CapabilityToken<RedactionCapability>;
74
- //#endregion
1
+ import { a as RedactionPendingItem, i as RedactionLabelPatch, n as RedactionAction, o as RedactionState, r as RedactionCapability, s as RedactionToken, t as RedactionApplyResult } from "./contract--fJOCVRN.cjs";
75
2
  //#region src/redaction.plugin.d.ts
76
3
  /**
77
4
  * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage
package/dist/index.d.ts CHANGED
@@ -1,77 +1,4 @@
1
- import { AnnotationRef, RedactionApplyResult, RedactionApplyResult as RedactionApplyResult$1 } from "@embedpdf/engine-core";
2
- //#region src/types.d.ts
3
- /**
4
- * One pending redaction mark — a live projection of a `redact` annotation on
5
- * the annotation plane (the plugin owns NO mark state of its own; delete the
6
- * annotation and the pending item is gone).
7
- */
8
- interface RedactionPendingItem {
9
- /** Stable list key derived from the ref. */
10
- id: string;
11
- ref: AnnotationRef;
12
- pageObjectNumber: number;
13
- /** Display index (0-based) from the page registry — for "page N" labels. */
14
- pageIndex: number;
15
- /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */
16
- kind: 'area' | 'text';
17
- /** `/OverlayText` label, when set. */
18
- overlayText: string | null;
19
- }
20
- interface RedactionState {
21
- /** A destructive apply is in flight. */
22
- applying: boolean;
23
- /** The last apply result seen (own or remote), for status UI. */
24
- lastResult: RedactionApplyResult$1 | null;
25
- }
26
- type RedactionAction = {
27
- type: 'APPLY_STARTED';
28
- } | {
29
- type: 'APPLY_FINISHED';
30
- result: RedactionApplyResult$1 | null;
31
- };
32
- /** A label edit: `overlayText: null` clears it; `repeat` tiles it. */
33
- interface RedactionLabelPatch {
34
- overlayText?: string | null;
35
- repeat?: boolean;
36
- }
37
- interface RedactionCapability {
38
- /** Engine support present AND this session holds `doc.redact`. The engine
39
- * enforces the same capability independently — this is the UI mirror. */
40
- canApply(): boolean;
41
- isApplying(): boolean;
42
- lastResult(): RedactionApplyResult$1 | null;
43
- /** The composed marking tool (text-selection over text + area drag elsewhere). */
44
- enableRedact(): void;
45
- toggleRedact(): void;
46
- isRedactActive(): boolean;
47
- /** Mark the current text selection (per page) and clear it. False when
48
- * there is no selection plugin or no selection. */
49
- queueCurrentSelection(): Promise<boolean>;
50
- /** Load every page's annotations so the pending view is complete (the
51
- * annotation plane loads lazily per page). Call when opening a panel. */
52
- preparePending(): Promise<void>;
53
- /** Pending marks over the LOADED annotation state (see preparePending). */
54
- getPending(): RedactionPendingItem[];
55
- pendingCount(): number;
56
- /**
57
- * Client-side estimate of how many OTHER annotations the given pending
58
- * marks (default: all) would destroy — for confirm dialogs BEFORE the
59
- * apply. The authoritative count comes back on the result.
60
- */
61
- estimateCollateral(ids?: string[]): number;
62
- /** Edit a mark's label. Reads the mark's current `/DA` styling and writes
63
- * the full label set, so a text-only edit never resets the styling. */
64
- setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;
65
- /** Apply specific pending marks (refs scope). Irreversible. */
66
- apply(ids: string[]): Promise<RedactionApplyResult$1>;
67
- /** Apply every redaction in the document (pages scope — including marks on
68
- * pages this client never loaded). Irreversible. */
69
- applyAll(): Promise<RedactionApplyResult$1>;
70
- /** Fires after ANY confirmed apply — own or a remote collaborator's. */
71
- onApplied(cb: (result: RedactionApplyResult$1) => void): () => void;
72
- }
73
- declare const RedactionToken: import("@embedpdf/core").CapabilityToken<RedactionCapability>;
74
- //#endregion
1
+ import { a as RedactionPendingItem, i as RedactionLabelPatch, n as RedactionAction, o as RedactionState, r as RedactionCapability, s as RedactionToken, t as RedactionApplyResult } from "./contract--fJOCVRN.js";
75
2
  //#region src/redaction.plugin.d.ts
76
3
  /**
77
4
  * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage
package/dist/index.js CHANGED
@@ -1,10 +1,18 @@
1
- import { createCapabilityToken, definePlugin } from "@embedpdf/core";
2
- import { AnnotationToken } from "@embedpdf/plugin-annotation/internal";
3
- import { InteractionToken } from "@embedpdf/plugin-interaction";
4
- import { SelectionToken } from "@embedpdf/plugin-selection";
1
+ import { t as RedactionToken } from "./contract-BZLrD3p2.js";
2
+ import { definePlugin } from "@embedpdf/core";
3
+ import { AnnotationToken } from "@embedpdf/plugin-annotation/contract/host";
4
+ import { InteractionToken } from "@embedpdf/plugin-interaction/contract";
5
+ import { SelectionToken } from "@embedpdf/plugin-selection/contract";
5
6
  //#region src/capability.ts
6
- /** Applying destroys content — its own granted power, narrower than annotate. */
7
- const REDACT_CAPABILITY = "doc.redact";
7
+ /** Applying destroys content — its own granted power, narrower than annotate.
8
+ * The engine's apply asserts all three (LocalDocumentRedactionService; the
9
+ * cloud route guards match): the redact grant itself, the page-content
10
+ * rewrite, and the annotation consumption. `canApply` mirrors the full set. */
11
+ const APPLY_CAPABILITIES = [
12
+ "doc.redact",
13
+ "doc.pages.modify",
14
+ "doc.annotate.modify"
15
+ ];
8
16
  /** The annotation plugin's model-id convention for a durable ref. */
9
17
  const idOf = (ref) => ref.kind === "objectNumber" ? `obj:${ref.annotObjectNumber}` : ref.kind === "nm" ? `nm:${ref.nm}` : `idx:${ref.pageObjectNumber}:${ref.index}`;
10
18
  /** The PDF-space regions a redact mark targets: its quads' boxes, else `/Rect`. */
@@ -98,7 +106,12 @@ function createRedactionCapability(ctx) {
98
106
  fireApplied(event);
99
107
  }));
100
108
  return {
101
- canApply: () => (ctx.doc?.redaction !== void 0 && ctx.doc?.security.allows(REDACT_CAPABILITY)) ?? false,
109
+ canMark: () => anno.canCreate(),
110
+ canApply: () => {
111
+ const doc = ctx.doc;
112
+ if (!doc || doc.redaction === void 0) return false;
113
+ return APPLY_CAPABILITIES.every((cap) => doc.security.allows(cap));
114
+ },
102
115
  isApplying: () => ctx.getState().applying,
103
116
  lastResult: () => ctx.getState().lastResult,
104
117
  enableRedact: () => ctx.tryGet(InteractionToken)?.activateTool("redact"),
@@ -109,12 +122,13 @@ function createRedactionCapability(ctx) {
109
122
  },
110
123
  isRedactActive: () => ctx.tryGet(InteractionToken)?.activeToolId() === "redact",
111
124
  queueCurrentSelection: async () => {
125
+ if (!anno.canCreate()) return false;
112
126
  const selection = ctx.tryGet(SelectionToken);
113
127
  if (!selection || !selection.hasSelection()) return false;
114
128
  const snapshot = selection.snapshot();
115
129
  for (const page of snapshot.pages) {
116
- if (page.rects.length === 0) continue;
117
- anno.createMarkup("redact", page.pon, page.rects, "redact");
130
+ if (page.segments.length === 0) continue;
131
+ anno.createMarkup("redact", page.pon, page.segments.map((segment) => segment.quad), "redact");
118
132
  }
119
133
  selection.clear();
120
134
  return true;
@@ -195,9 +209,6 @@ const redactionReducer = (state, action) => {
195
209
  }
196
210
  };
197
211
  //#endregion
198
- //#region src/types.ts
199
- const RedactionToken = createCapabilityToken("redaction");
200
- //#endregion
201
212
  //#region src/redaction.plugin.ts
202
213
  /**
203
214
  * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/capability.ts","../src/reducer.ts","../src/types.ts","../src/redaction.plugin.ts"],"sourcesContent":["import type { DocCapability, PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/internal';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport type {\n AnnotationDTO,\n AnnotationRef,\n PdfRect,\n RedactionApplyResult,\n} from '@embedpdf/engine-core';\nimport type {\n RedactionAction,\n RedactionCapability,\n RedactionLabelPatch,\n RedactionPendingItem,\n RedactionState,\n} from './types';\n\n/** Applying destroys content — its own granted power, narrower than annotate. */\nconst REDACT_CAPABILITY: DocCapability = 'doc.redact';\n\n/** The annotation plugin's model-id convention for a durable ref. */\nconst idOf = (ref: AnnotationRef): string =>\n ref.kind === 'objectNumber'\n ? `obj:${ref.annotObjectNumber}`\n : ref.kind === 'nm'\n ? `nm:${ref.nm}`\n : `idx:${ref.pageObjectNumber}:${ref.index}`;\n\ntype RedactDTO = Extract<AnnotationDTO, { subtype: 'redact' }>;\n\n/** The PDF-space regions a redact mark targets: its quads' boxes, else `/Rect`. */\nfunction regionsOf(dto: RedactDTO): PdfRect[] {\n if (dto.quadPoints.length === 0) return [dto.rect];\n return dto.quadPoints.map((q) => {\n const xs = [q.p1.x, q.p2.x, q.p3.x, q.p4.x];\n const ys = [q.p1.y, q.p2.y, q.p3.y, q.p4.y];\n return {\n left: Math.min(...xs),\n right: Math.max(...xs),\n bottom: Math.min(...ys),\n top: Math.max(...ys),\n };\n });\n}\n\n/** Positive-area intersection — the engine's collateral rule. */\nconst intersects = (a: PdfRect, b: PdfRect): boolean =>\n Math.min(a.right, b.right) > Math.max(a.left, b.left) &&\n Math.min(a.top, b.top) > Math.max(a.bottom, b.bottom);\n\nexport function createRedactionCapability(\n ctx: PluginContext<RedactionState, RedactionAction>,\n): RedactionCapability {\n const anno = ctx.get(AnnotationToken);\n const appliedCallbacks = new Set<(result: RedactionApplyResult) => void>();\n\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[redaction] no document bound');\n return doc;\n };\n const requireService = () => {\n const doc = requireDoc();\n if (!doc.redaction) throw new Error('[redaction] engine has no redaction service');\n return doc.redaction;\n };\n\n const pons = (): number[] => (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber);\n\n const pageIndexOf = (pon: number): number =>\n ctx.document()?.pages.find((p) => p.pageObjectNumber === pon)?.index ?? -1;\n\n const pendingOn = (pon: number): RedactDTO[] =>\n anno.list(pon).filter((a): a is RedactDTO => a.subtype === 'redact');\n\n const collectPending = (): RedactionPendingItem[] => {\n const items: RedactionPendingItem[] = [];\n for (const pon of pons()) {\n for (const dto of pendingOn(pon)) {\n items.push({\n id: idOf(dto.ref),\n ref: dto.ref,\n pageObjectNumber: pon,\n pageIndex: pageIndexOf(pon),\n kind: dto.quadPoints.length > 0 ? 'text' : 'area',\n overlayText: dto.overlayText,\n });\n }\n }\n return items;\n };\n\n const fireApplied = (result: RedactionApplyResult) => {\n for (const cb of appliedCallbacks) {\n try {\n cb(result);\n } catch (err) {\n console.error('[redaction] onApplied callback failed', err);\n }\n }\n };\n\n const runApply = async (\n scope: Parameters<ReturnType<typeof requireService>['apply']>[0],\n ): Promise<RedactionApplyResult> => {\n const service = requireService();\n ctx.dispatch({ type: 'APPLY_STARTED' });\n try {\n const result = await service.apply(scope);\n ctx.dispatch({ type: 'APPLY_FINISHED', result });\n fireApplied(result);\n return result;\n } catch (err) {\n ctx.dispatch({ type: 'APPLY_FINISHED', result: null });\n throw err;\n }\n };\n\n // A REMOTE collaborator's apply arrives only as a document event (own\n // applies flow through runApply above). Annotation state + raster\n // invalidation are handled by their own planes; here we only surface it.\n const doc = ctx.doc;\n if (doc) {\n ctx.cleanup(\n doc.events.subscribe((event) => {\n if (event.type !== 'redaction.applied') return;\n if (event.origin.kind !== 'remote') return;\n ctx.dispatch({ type: 'APPLY_FINISHED', result: event });\n fireApplied(event);\n }),\n );\n }\n\n return {\n canApply: () =>\n (ctx.doc?.redaction !== undefined && ctx.doc?.security.allows(REDACT_CAPABILITY)) ?? false,\n isApplying: () => ctx.getState().applying,\n lastResult: () => ctx.getState().lastResult,\n\n enableRedact: () => ctx.tryGet(InteractionToken)?.activateTool('redact'),\n toggleRedact: () => {\n const interaction = ctx.tryGet(InteractionToken);\n if (!interaction) return;\n interaction.activateTool(interaction.activeToolId() === 'redact' ? 'pointer' : 'redact');\n },\n isRedactActive: () => ctx.tryGet(InteractionToken)?.activeToolId() === 'redact',\n\n queueCurrentSelection: async () => {\n const selection = ctx.tryGet(SelectionToken);\n if (!selection || !selection.hasSelection()) return false;\n const snapshot = selection.snapshot();\n for (const page of snapshot.pages) {\n if (page.rects.length === 0) continue;\n anno.createMarkup('redact', page.pon, page.rects, 'redact');\n }\n selection.clear();\n return true;\n },\n\n preparePending: async () => {\n await Promise.all(pons().map((pon) => anno.ensurePage(pon)));\n },\n getPending: collectPending,\n pendingCount: () => collectPending().length,\n\n estimateCollateral: (ids) => {\n const wanted = ids ? new Set(ids) : null;\n let count = 0;\n for (const pon of pons()) {\n const all = anno.list(pon);\n const marks = all.filter(\n (a): a is RedactDTO => a.subtype === 'redact' && (!wanted || wanted.has(idOf(a.ref))),\n );\n if (marks.length === 0) continue;\n const regions = marks.flatMap(regionsOf);\n for (const other of all) {\n if (other.subtype === 'redact') continue;\n if (regions.some((r) => intersects(r, other.rect))) count++;\n }\n }\n return count;\n },\n\n setLabel: async (ref, patch: RedactionLabelPatch) => {\n const current = anno.get(ref);\n if (!current || current.subtype !== 'redact') {\n throw new Error('[redaction] setLabel target is not a redact annotation');\n }\n // Always carry the current /DA styling: the engine rewrites /DA whenever\n // a label field rides a patch, so a text-only edit must not let the\n // styling fall back to defaults.\n await anno.update(ref, {\n subtype: 'redact',\n ...(patch.overlayText !== undefined ? { overlayText: patch.overlayText } : {}),\n ...(patch.repeat !== undefined ? { repeat: patch.repeat } : {}),\n fontFamily: current.fontFamily,\n fontSize: current.fontSize,\n fontColor: current.fontColor,\n textAlign: current.textAlign,\n });\n },\n\n apply: async (ids) => {\n const wanted = new Set(ids);\n const refs = collectPending()\n .filter((p) => wanted.has(p.id))\n .map((p) => p.ref);\n if (refs.length === 0) throw new Error('[redaction] no matching pending redactions');\n return runApply({ kind: 'annotations', refs });\n },\n\n applyAll: async () => {\n // Pages scope: authoritative for the WHOLE document, including marks on\n // pages this client never loaded. Pages without marks report 'unchanged'.\n const pageObjectNumbers = pons();\n if (pageObjectNumbers.length === 0) throw new Error('[redaction] document has no pages');\n return runApply({ kind: 'pages', pageObjectNumbers });\n },\n\n onApplied: (cb) => {\n appliedCallbacks.add(cb);\n return () => appliedCallbacks.delete(cb);\n },\n };\n}\n","import type { RedactionAction, RedactionState } from './types';\n\nexport const initialRedactionState = (): RedactionState => ({\n applying: false,\n lastResult: null,\n});\n\nexport const redactionReducer = (\n state: RedactionState,\n action: RedactionAction,\n): RedactionState => {\n switch (action.type) {\n case 'APPLY_STARTED':\n return { ...state, applying: true };\n case 'APPLY_FINISHED':\n return { applying: false, lastResult: action.result ?? state.lastResult };\n default:\n return state;\n }\n};\n","import { createCapabilityToken } from '@embedpdf/core';\nimport type { AnnotationRef, RedactionApplyResult } from '@embedpdf/engine-core';\n\n/**\n * One pending redaction mark — a live projection of a `redact` annotation on\n * the annotation plane (the plugin owns NO mark state of its own; delete the\n * annotation and the pending item is gone).\n */\nexport interface RedactionPendingItem {\n /** Stable list key derived from the ref. */\n id: string;\n ref: AnnotationRef;\n pageObjectNumber: number;\n /** Display index (0-based) from the page registry — for \"page N\" labels. */\n pageIndex: number;\n /** `area` = rect-only mark (marquee); `text` = per-line quads (selection). */\n kind: 'area' | 'text';\n /** `/OverlayText` label, when set. */\n overlayText: string | null;\n}\n\nexport interface RedactionState {\n /** A destructive apply is in flight. */\n applying: boolean;\n /** The last apply result seen (own or remote), for status UI. */\n lastResult: RedactionApplyResult | null;\n}\n\nexport type RedactionAction =\n | { type: 'APPLY_STARTED' }\n | { type: 'APPLY_FINISHED'; result: RedactionApplyResult | null };\n\n/** A label edit: `overlayText: null` clears it; `repeat` tiles it. */\nexport interface RedactionLabelPatch {\n overlayText?: string | null;\n repeat?: boolean;\n}\n\nexport interface RedactionCapability {\n /** Engine support present AND this session holds `doc.redact`. The engine\n * enforces the same capability independently — this is the UI mirror. */\n canApply(): boolean;\n isApplying(): boolean;\n lastResult(): RedactionApplyResult | null;\n\n /** The composed marking tool (text-selection over text + area drag elsewhere). */\n enableRedact(): void;\n toggleRedact(): void;\n isRedactActive(): boolean;\n\n /** Mark the current text selection (per page) and clear it. False when\n * there is no selection plugin or no selection. */\n queueCurrentSelection(): Promise<boolean>;\n\n /** Load every page's annotations so the pending view is complete (the\n * annotation plane loads lazily per page). Call when opening a panel. */\n preparePending(): Promise<void>;\n /** Pending marks over the LOADED annotation state (see preparePending). */\n getPending(): RedactionPendingItem[];\n pendingCount(): number;\n /**\n * Client-side estimate of how many OTHER annotations the given pending\n * marks (default: all) would destroy — for confirm dialogs BEFORE the\n * apply. The authoritative count comes back on the result.\n */\n estimateCollateral(ids?: string[]): number;\n\n /** Edit a mark's label. Reads the mark's current `/DA` styling and writes\n * the full label set, so a text-only edit never resets the styling. */\n setLabel(ref: AnnotationRef, patch: RedactionLabelPatch): Promise<void>;\n\n /** Apply specific pending marks (refs scope). Irreversible. */\n apply(ids: string[]): Promise<RedactionApplyResult>;\n /** Apply every redaction in the document (pages scope — including marks on\n * pages this client never loaded). Irreversible. */\n applyAll(): Promise<RedactionApplyResult>;\n\n /** Fires after ANY confirmed apply — own or a remote collaborator's. */\n onApplied(cb: (result: RedactionApplyResult) => void): () => void;\n}\n\nexport const RedactionToken = createCapabilityToken<RedactionCapability>('redaction');\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/internal';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport { SelectionToken } from '@embedpdf/plugin-selection';\nimport { createRedactionCapability } from './capability';\nimport { initialRedactionState, redactionReducer } from './reducer';\nimport { RedactionToken } from './types';\nimport type { RedactionAction, RedactionCapability, RedactionState } from './types';\n\n/**\n * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage\n * model. Marking is annotation-plane work (the composed `redact` tool ships\n * with plugin-annotation); this plugin wraps `doc.redaction.apply`, projects\n * the pending queue out of annotation state, and estimates collateral for\n * confirm dialogs. It owns no mark state of its own.\n *\n * Trust boundary: on a layered document, applying rewrites the LAYER's bytes;\n * the immutable base keeps the original. See the package README.\n */\nexport const redactionPlugin = () =>\n definePlugin<RedactionState, RedactionAction, RedactionCapability>({\n id: 'redaction',\n token: RedactionToken,\n scope: 'document',\n requires: [AnnotationToken],\n optional: [InteractionToken, SelectionToken],\n initialState: initialRedactionState,\n reduce: redactionReducer,\n capability: createRedactionCapability,\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/capability.ts","../src/reducer.ts","../src/redaction.plugin.ts"],"sourcesContent":["import type { DocCapability, PluginContext } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { SelectionToken } from '@embedpdf/plugin-selection/contract';\nimport type {\n AnnotationDTO,\n AnnotationRef,\n PdfRect,\n RedactionApplyResult,\n} from '@embedpdf/engine-core';\nimport type {\n RedactionAction,\n RedactionCapability,\n RedactionLabelPatch,\n RedactionPendingItem,\n RedactionState,\n} from './types';\n\n/** Applying destroys content — its own granted power, narrower than annotate.\n * The engine's apply asserts all three (LocalDocumentRedactionService; the\n * cloud route guards match): the redact grant itself, the page-content\n * rewrite, and the annotation consumption. `canApply` mirrors the full set. */\nconst APPLY_CAPABILITIES: readonly DocCapability[] = [\n 'doc.redact',\n 'doc.pages.modify',\n 'doc.annotate.modify',\n];\n\n/** The annotation plugin's model-id convention for a durable ref. */\nconst idOf = (ref: AnnotationRef): string =>\n ref.kind === 'objectNumber'\n ? `obj:${ref.annotObjectNumber}`\n : ref.kind === 'nm'\n ? `nm:${ref.nm}`\n : `idx:${ref.pageObjectNumber}:${ref.index}`;\n\ntype RedactDTO = Extract<AnnotationDTO, { subtype: 'redact' }>;\n\n/** The PDF-space regions a redact mark targets: its quads' boxes, else `/Rect`. */\nfunction regionsOf(dto: RedactDTO): PdfRect[] {\n if (dto.quadPoints.length === 0) return [dto.rect];\n return dto.quadPoints.map((q) => {\n const xs = [q.p1.x, q.p2.x, q.p3.x, q.p4.x];\n const ys = [q.p1.y, q.p2.y, q.p3.y, q.p4.y];\n return {\n left: Math.min(...xs),\n right: Math.max(...xs),\n bottom: Math.min(...ys),\n top: Math.max(...ys),\n };\n });\n}\n\n/** Positive-area intersection — the engine's collateral rule. */\nconst intersects = (a: PdfRect, b: PdfRect): boolean =>\n Math.min(a.right, b.right) > Math.max(a.left, b.left) &&\n Math.min(a.top, b.top) > Math.max(a.bottom, b.bottom);\n\nexport function createRedactionCapability(\n ctx: PluginContext<RedactionState, RedactionAction>,\n): RedactionCapability {\n const anno = ctx.get(AnnotationToken);\n const appliedCallbacks = new Set<(result: RedactionApplyResult) => void>();\n\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[redaction] no document bound');\n return doc;\n };\n const requireService = () => {\n const doc = requireDoc();\n if (!doc.redaction) throw new Error('[redaction] engine has no redaction service');\n return doc.redaction;\n };\n\n const pons = (): number[] => (ctx.document()?.pages ?? []).map((p) => p.pageObjectNumber);\n\n const pageIndexOf = (pon: number): number =>\n ctx.document()?.pages.find((p) => p.pageObjectNumber === pon)?.index ?? -1;\n\n const pendingOn = (pon: number): RedactDTO[] =>\n anno.list(pon).filter((a): a is RedactDTO => a.subtype === 'redact');\n\n const collectPending = (): RedactionPendingItem[] => {\n const items: RedactionPendingItem[] = [];\n for (const pon of pons()) {\n for (const dto of pendingOn(pon)) {\n items.push({\n id: idOf(dto.ref),\n ref: dto.ref,\n pageObjectNumber: pon,\n pageIndex: pageIndexOf(pon),\n kind: dto.quadPoints.length > 0 ? 'text' : 'area',\n overlayText: dto.overlayText,\n });\n }\n }\n return items;\n };\n\n const fireApplied = (result: RedactionApplyResult) => {\n for (const cb of appliedCallbacks) {\n try {\n cb(result);\n } catch (err) {\n console.error('[redaction] onApplied callback failed', err);\n }\n }\n };\n\n const runApply = async (\n scope: Parameters<ReturnType<typeof requireService>['apply']>[0],\n ): Promise<RedactionApplyResult> => {\n const service = requireService();\n ctx.dispatch({ type: 'APPLY_STARTED' });\n try {\n const result = await service.apply(scope);\n ctx.dispatch({ type: 'APPLY_FINISHED', result });\n fireApplied(result);\n return result;\n } catch (err) {\n ctx.dispatch({ type: 'APPLY_FINISHED', result: null });\n throw err;\n }\n };\n\n // A REMOTE collaborator's apply arrives only as a document event (own\n // applies flow through runApply above). Annotation state + raster\n // invalidation are handled by their own planes; here we only surface it.\n const doc = ctx.doc;\n if (doc) {\n ctx.cleanup(\n doc.events.subscribe((event) => {\n if (event.type !== 'redaction.applied') return;\n if (event.origin.kind !== 'remote') return;\n ctx.dispatch({ type: 'APPLY_FINISHED', result: event });\n fireApplied(event);\n }),\n );\n }\n\n return {\n // Marks are annotations — marking authority IS annotation create\n // authority (the annotation plugin's own twin, not a re-derivation).\n canMark: () => anno.canCreate(),\n // Mirror EVERYTHING the engine's apply asserts, not just the headline\n // capability — a token granted `doc.redact` à la carte without its bit-4\n // siblings must not see an armed Apply button.\n canApply: () => {\n const doc = ctx.doc;\n if (!doc || doc.redaction === undefined) return false;\n return APPLY_CAPABILITIES.every((cap) => doc.security.allows(cap));\n },\n isApplying: () => ctx.getState().applying,\n lastResult: () => ctx.getState().lastResult,\n\n enableRedact: () => ctx.tryGet(InteractionToken)?.activateTool('redact'),\n toggleRedact: () => {\n const interaction = ctx.tryGet(InteractionToken);\n if (!interaction) return;\n interaction.activateTool(interaction.activeToolId() === 'redact' ? 'pointer' : 'redact');\n },\n isRedactActive: () => ctx.tryGet(InteractionToken)?.activeToolId() === 'redact',\n\n queueCurrentSelection: async () => {\n // Marks are optimistic annotation creates — the same gate the pointer\n // path has (the annotation plugin refuses ungated creates too).\n if (!anno.canCreate()) return false;\n const selection = ctx.tryGet(SelectionToken);\n if (!selection || !selection.hasSelection()) return false;\n const snapshot = selection.snapshot();\n for (const page of snapshot.pages) {\n if (page.segments.length === 0) continue;\n // Preserve the selected text frame all the way into `/QuadPoints`.\n // Native apply now uses these exact cells for text removal and the\n // final overlay, so marked == previewed == applied for oriented text.\n anno.createMarkup(\n 'redact',\n page.pon,\n page.segments.map((segment) => segment.quad),\n 'redact',\n );\n }\n selection.clear();\n return true;\n },\n\n preparePending: async () => {\n await Promise.all(pons().map((pon) => anno.ensurePage(pon)));\n },\n getPending: collectPending,\n pendingCount: () => collectPending().length,\n\n estimateCollateral: (ids) => {\n const wanted = ids ? new Set(ids) : null;\n let count = 0;\n for (const pon of pons()) {\n const all = anno.list(pon);\n const marks = all.filter(\n (a): a is RedactDTO => a.subtype === 'redact' && (!wanted || wanted.has(idOf(a.ref))),\n );\n if (marks.length === 0) continue;\n const regions = marks.flatMap(regionsOf);\n for (const other of all) {\n if (other.subtype === 'redact') continue;\n if (regions.some((r) => intersects(r, other.rect))) count++;\n }\n }\n return count;\n },\n\n setLabel: async (ref, patch: RedactionLabelPatch) => {\n const current = anno.get(ref);\n if (!current || current.subtype !== 'redact') {\n throw new Error('[redaction] setLabel target is not a redact annotation');\n }\n // Always carry the current /DA styling: the engine rewrites /DA whenever\n // a label field rides a patch, so a text-only edit must not let the\n // styling fall back to defaults.\n await anno.update(ref, {\n subtype: 'redact',\n ...(patch.overlayText !== undefined ? { overlayText: patch.overlayText } : {}),\n ...(patch.repeat !== undefined ? { repeat: patch.repeat } : {}),\n fontFamily: current.fontFamily,\n fontSize: current.fontSize,\n fontColor: current.fontColor,\n textAlign: current.textAlign,\n });\n },\n\n apply: async (ids) => {\n const wanted = new Set(ids);\n const refs = collectPending()\n .filter((p) => wanted.has(p.id))\n .map((p) => p.ref);\n if (refs.length === 0) throw new Error('[redaction] no matching pending redactions');\n return runApply({ kind: 'annotations', refs });\n },\n\n applyAll: async () => {\n // Pages scope: authoritative for the WHOLE document, including marks on\n // pages this client never loaded. Pages without marks report 'unchanged'.\n const pageObjectNumbers = pons();\n if (pageObjectNumbers.length === 0) throw new Error('[redaction] document has no pages');\n return runApply({ kind: 'pages', pageObjectNumbers });\n },\n\n onApplied: (cb) => {\n appliedCallbacks.add(cb);\n return () => appliedCallbacks.delete(cb);\n },\n };\n}\n","import type { RedactionAction, RedactionState } from './types';\n\nexport const initialRedactionState = (): RedactionState => ({\n applying: false,\n lastResult: null,\n});\n\nexport const redactionReducer = (\n state: RedactionState,\n action: RedactionAction,\n): RedactionState => {\n switch (action.type) {\n case 'APPLY_STARTED':\n return { ...state, applying: true };\n case 'APPLY_FINISHED':\n return { applying: false, lastResult: action.result ?? state.lastResult };\n default:\n return state;\n }\n};\n","import { definePlugin } from '@embedpdf/core';\nimport { AnnotationToken } from '@embedpdf/plugin-annotation/contract/host';\nimport { InteractionToken } from '@embedpdf/plugin-interaction/contract';\nimport { SelectionToken } from '@embedpdf/plugin-selection/contract';\nimport { createRedactionCapability } from './capability';\nimport { initialRedactionState, redactionReducer } from './reducer';\nimport { RedactionToken } from './types';\nimport type { RedactionAction, RedactionCapability, RedactionState } from './types';\n\n/**\n * Document-scoped redaction plugin — the DESTRUCTIVE half of the two-stage\n * model. Marking is annotation-plane work (the composed `redact` tool ships\n * with plugin-annotation); this plugin wraps `doc.redaction.apply`, projects\n * the pending queue out of annotation state, and estimates collateral for\n * confirm dialogs. It owns no mark state of its own.\n *\n * Trust boundary: on a layered document, applying rewrites the LAYER's bytes;\n * the immutable base keeps the original. See the package README.\n */\nexport const redactionPlugin = () =>\n definePlugin<RedactionState, RedactionAction, RedactionCapability>({\n id: 'redaction',\n token: RedactionToken,\n scope: 'document',\n requires: [AnnotationToken],\n optional: [InteractionToken, SelectionToken],\n initialState: initialRedactionState,\n reduce: redactionReducer,\n capability: createRedactionCapability,\n });\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-redaction",
3
- "version": "3.0.0-next.1",
3
+ "version": "3.0.0-next.11",
4
4
  "private": false,
5
5
  "description": "Document-scoped redaction: the destructive apply stage over redact annotation marks — pending queue view, collateral estimation, and the doc.redaction.apply wrapper. Marking itself rides the annotation plane.",
6
6
  "type": "module",
@@ -12,17 +12,21 @@
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
14
  },
15
+ "./contract": {
16
+ "import": "./dist/contract.js",
17
+ "require": "./dist/contract.cjs"
18
+ },
15
19
  "./package.json": "./package.json"
16
20
  },
17
21
  "files": [
18
22
  "dist"
19
23
  ],
20
24
  "dependencies": {
21
- "@embedpdf/core": "3.0.0-next.1",
22
- "@embedpdf/plugin-interaction": "3.0.0-next.1",
23
- "@embedpdf/plugin-selection": "3.0.0-next.1",
24
- "@embedpdf/plugin-annotation": "3.0.0-next.1",
25
- "@embedpdf/engine-core": "3.0.0-next.1"
25
+ "@embedpdf/core": "3.0.0-next.11",
26
+ "@embedpdf/plugin-annotation": "3.0.0-next.11",
27
+ "@embedpdf/plugin-interaction": "3.0.0-next.11",
28
+ "@embedpdf/plugin-selection": "3.0.0-next.11",
29
+ "@embedpdf/engine-core": "3.0.0-next.11"
26
30
  },
27
31
  "devDependencies": {
28
32
  "typescript": "^5.0.0",