@embedpdf/plugin-metadata 3.0.0-next.10 → 3.0.0-next.12
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/contract-CqhcLHxo.cjs +11 -0
- package/dist/contract-CqhcLHxo.cjs.map +1 -0
- package/dist/contract-DXGV7Wpx.js +7 -0
- package/dist/contract-DXGV7Wpx.js.map +1 -0
- package/dist/contract-Dk5SGhEP.d.cts +40 -0
- package/dist/contract-Dk5SGhEP.d.ts +40 -0
- package/dist/contract.cjs +3 -0
- package/dist/contract.d.cts +2 -0
- package/dist/contract.d.ts +2 -0
- package/dist/contract.js +2 -0
- package/dist/index.cjs +3 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -38
- package/dist/index.d.ts +1 -38
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/types.ts
|
|
2
|
+
const MetadataToken = (0, require("@embedpdf/core").createCapabilityToken)("metadata");
|
|
3
|
+
//#endregion
|
|
4
|
+
Object.defineProperty(exports, "MetadataToken", {
|
|
5
|
+
enumerable: true,
|
|
6
|
+
get: function() {
|
|
7
|
+
return MetadataToken;
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=contract-CqhcLHxo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-CqhcLHxo.cjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken, type DocumentMetadata, type MetadataPatch } from '@embedpdf/core';\n\n/**\n * The document's Info-dict metadata, held as REACTIVE state — not a one-shot\n * read. It changes from local edits AND from other sessions (a remote edit\n * arrives over SSE as a `metadata.updated` event), so the plugin subscribes to\n * the document event stream and keeps `current()` live. `update` writes a\n * three-state patch into the LAYER (like a page mutation), so a metadata edit\n * saves with the layer.\n */\nexport interface MetadataState {\n /** Current metadata, or null until the first read resolves. */\n metadata: DocumentMetadata | null;\n}\n\nexport type MetadataAction = { type: 'SET'; metadata: DocumentMetadata | null };\n\nexport interface MetadataCapability {\n /**\n * Whether this caller is authorized to edit the Info dict —\n * `effectiveScope` includes `doc.metadata.modify` (PDF bit 4). UIs gate their\n * edit affordances on this; the engine independently enforces the same\n * capability and throws `PermissionDenied` if a write slips through.\n */\n canEdit(): boolean;\n /** Current metadata; null until the initial read lands. Reactive — reflects\n * own edits and remote (SSE) edits via the event stream. */\n current(): DocumentMetadata | null;\n /** Patch the Info dict (undefined=leave, null=clear, value=set). Writes to the\n * layer; state refreshes from the resulting `metadata.updated` event. */\n update(patch: MetadataPatch): Promise<void>;\n /** Force a re-read from the engine (rarely needed — the event stream keeps\n * state fresh). */\n reload(): Promise<void>;\n}\n\nexport const MetadataToken = createCapabilityToken<MetadataCapability>('metadata');\n"],"mappings":";AAoCA,MAAa,iBAAA,2BAAA,CAAA,CAAA,sBAAA,CAA0D,UAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-DXGV7Wpx.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import { createCapabilityToken, type DocumentMetadata, type MetadataPatch } from '@embedpdf/core';\n\n/**\n * The document's Info-dict metadata, held as REACTIVE state — not a one-shot\n * read. It changes from local edits AND from other sessions (a remote edit\n * arrives over SSE as a `metadata.updated` event), so the plugin subscribes to\n * the document event stream and keeps `current()` live. `update` writes a\n * three-state patch into the LAYER (like a page mutation), so a metadata edit\n * saves with the layer.\n */\nexport interface MetadataState {\n /** Current metadata, or null until the first read resolves. */\n metadata: DocumentMetadata | null;\n}\n\nexport type MetadataAction = { type: 'SET'; metadata: DocumentMetadata | null };\n\nexport interface MetadataCapability {\n /**\n * Whether this caller is authorized to edit the Info dict —\n * `effectiveScope` includes `doc.metadata.modify` (PDF bit 4). UIs gate their\n * edit affordances on this; the engine independently enforces the same\n * capability and throws `PermissionDenied` if a write slips through.\n */\n canEdit(): boolean;\n /** Current metadata; null until the initial read lands. Reactive — reflects\n * own edits and remote (SSE) edits via the event stream. */\n current(): DocumentMetadata | null;\n /** Patch the Info dict (undefined=leave, null=clear, value=set). Writes to the\n * layer; state refreshes from the resulting `metadata.updated` event. */\n update(patch: MetadataPatch): Promise<void>;\n /** Force a re-read from the engine (rarely needed — the event stream keeps\n * state fresh). */\n reload(): Promise<void>;\n}\n\nexport const MetadataToken = createCapabilityToken<MetadataCapability>('metadata');\n"],"mappings":";;AAoCA,MAAa,gBAAgB,sBAA0C,UAAU"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DocumentMetadata, MetadataPatch } from "@embedpdf/core";
|
|
2
|
+
//#region src/types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The document's Info-dict metadata, held as REACTIVE state — not a one-shot
|
|
5
|
+
* read. It changes from local edits AND from other sessions (a remote edit
|
|
6
|
+
* arrives over SSE as a `metadata.updated` event), so the plugin subscribes to
|
|
7
|
+
* the document event stream and keeps `current()` live. `update` writes a
|
|
8
|
+
* three-state patch into the LAYER (like a page mutation), so a metadata edit
|
|
9
|
+
* saves with the layer.
|
|
10
|
+
*/
|
|
11
|
+
interface MetadataState {
|
|
12
|
+
/** Current metadata, or null until the first read resolves. */
|
|
13
|
+
metadata: DocumentMetadata | null;
|
|
14
|
+
}
|
|
15
|
+
type MetadataAction = {
|
|
16
|
+
type: 'SET';
|
|
17
|
+
metadata: DocumentMetadata | null;
|
|
18
|
+
};
|
|
19
|
+
interface MetadataCapability {
|
|
20
|
+
/**
|
|
21
|
+
* Whether this caller is authorized to edit the Info dict —
|
|
22
|
+
* `effectiveScope` includes `doc.metadata.modify` (PDF bit 4). UIs gate their
|
|
23
|
+
* edit affordances on this; the engine independently enforces the same
|
|
24
|
+
* capability and throws `PermissionDenied` if a write slips through.
|
|
25
|
+
*/
|
|
26
|
+
canEdit(): boolean;
|
|
27
|
+
/** Current metadata; null until the initial read lands. Reactive — reflects
|
|
28
|
+
* own edits and remote (SSE) edits via the event stream. */
|
|
29
|
+
current(): DocumentMetadata | null;
|
|
30
|
+
/** Patch the Info dict (undefined=leave, null=clear, value=set). Writes to the
|
|
31
|
+
* layer; state refreshes from the resulting `metadata.updated` event. */
|
|
32
|
+
update(patch: MetadataPatch): Promise<void>;
|
|
33
|
+
/** Force a re-read from the engine (rarely needed — the event stream keeps
|
|
34
|
+
* state fresh). */
|
|
35
|
+
reload(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
declare const MetadataToken: import("@embedpdf/core").CapabilityToken<MetadataCapability>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { MetadataToken as i, MetadataCapability as n, MetadataState as r, MetadataAction as t };
|
|
40
|
+
//# sourceMappingURL=contract-Dk5SGhEP.d.cts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DocumentMetadata, MetadataPatch } from "@embedpdf/core";
|
|
2
|
+
//#region src/types.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The document's Info-dict metadata, held as REACTIVE state — not a one-shot
|
|
5
|
+
* read. It changes from local edits AND from other sessions (a remote edit
|
|
6
|
+
* arrives over SSE as a `metadata.updated` event), so the plugin subscribes to
|
|
7
|
+
* the document event stream and keeps `current()` live. `update` writes a
|
|
8
|
+
* three-state patch into the LAYER (like a page mutation), so a metadata edit
|
|
9
|
+
* saves with the layer.
|
|
10
|
+
*/
|
|
11
|
+
interface MetadataState {
|
|
12
|
+
/** Current metadata, or null until the first read resolves. */
|
|
13
|
+
metadata: DocumentMetadata | null;
|
|
14
|
+
}
|
|
15
|
+
type MetadataAction = {
|
|
16
|
+
type: 'SET';
|
|
17
|
+
metadata: DocumentMetadata | null;
|
|
18
|
+
};
|
|
19
|
+
interface MetadataCapability {
|
|
20
|
+
/**
|
|
21
|
+
* Whether this caller is authorized to edit the Info dict —
|
|
22
|
+
* `effectiveScope` includes `doc.metadata.modify` (PDF bit 4). UIs gate their
|
|
23
|
+
* edit affordances on this; the engine independently enforces the same
|
|
24
|
+
* capability and throws `PermissionDenied` if a write slips through.
|
|
25
|
+
*/
|
|
26
|
+
canEdit(): boolean;
|
|
27
|
+
/** Current metadata; null until the initial read lands. Reactive — reflects
|
|
28
|
+
* own edits and remote (SSE) edits via the event stream. */
|
|
29
|
+
current(): DocumentMetadata | null;
|
|
30
|
+
/** Patch the Info dict (undefined=leave, null=clear, value=set). Writes to the
|
|
31
|
+
* layer; state refreshes from the resulting `metadata.updated` event. */
|
|
32
|
+
update(patch: MetadataPatch): Promise<void>;
|
|
33
|
+
/** Force a re-read from the engine (rarely needed — the event stream keeps
|
|
34
|
+
* state fresh). */
|
|
35
|
+
reload(): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
declare const MetadataToken: import("@embedpdf/core").CapabilityToken<MetadataCapability>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { MetadataToken as i, MetadataCapability as n, MetadataState as r, MetadataAction as t };
|
|
40
|
+
//# sourceMappingURL=contract-Dk5SGhEP.d.ts.map
|
package/dist/contract.js
ADDED
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_contract = require("./contract-CqhcLHxo.cjs");
|
|
2
3
|
let _embedpdf_core = require("@embedpdf/core");
|
|
3
4
|
//#region src/capability.ts
|
|
4
5
|
/**
|
|
@@ -79,9 +80,6 @@ const metadataReducer = (state, a) => a.type === "SET" ? {
|
|
|
79
80
|
metadata: a.metadata
|
|
80
81
|
} : state;
|
|
81
82
|
//#endregion
|
|
82
|
-
//#region src/types.ts
|
|
83
|
-
const MetadataToken = (0, _embedpdf_core.createCapabilityToken)("metadata");
|
|
84
|
-
//#endregion
|
|
85
83
|
//#region src/metadata.plugin.ts
|
|
86
84
|
/**
|
|
87
85
|
* Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it
|
|
@@ -90,7 +88,7 @@ const MetadataToken = (0, _embedpdf_core.createCapabilityToken)("metadata");
|
|
|
90
88
|
*/
|
|
91
89
|
const metadataPlugin = () => (0, _embedpdf_core.definePlugin)({
|
|
92
90
|
id: "metadata",
|
|
93
|
-
token: MetadataToken,
|
|
91
|
+
token: require_contract.MetadataToken,
|
|
94
92
|
scope: "document",
|
|
95
93
|
initialState: initialMetadataState,
|
|
96
94
|
reduce: metadataReducer,
|
|
@@ -98,7 +96,7 @@ const metadataPlugin = () => (0, _embedpdf_core.definePlugin)({
|
|
|
98
96
|
effects: registerMetadataEffects
|
|
99
97
|
});
|
|
100
98
|
//#endregion
|
|
101
|
-
exports.MetadataToken = MetadataToken;
|
|
99
|
+
exports.MetadataToken = require_contract.MetadataToken;
|
|
102
100
|
exports.metadataPlugin = metadataPlugin;
|
|
103
101
|
|
|
104
102
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/capability.ts","../src/effects.ts","../src/reducer.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["MetadataToken"],"sources":["../src/capability.ts","../src/effects.ts","../src/reducer.ts","../src/metadata.plugin.ts"],"sourcesContent":["import type { PluginContext, DocCapability } from '@embedpdf/core';\nimport type { MetadataAction, MetadataCapability, MetadataState } from './types';\n\n/**\n * Authorization for Info-dict writes. Maps to PDF bit 4 (MODIFY). The engine\n * ALSO enforces this — `metadata.update` throws `PermissionDenied` without it,\n * identically on local and cloud — so `canEdit()` is the UI mirror of a real\n * guard, not the guard itself. Typed as `DocCapability` so a typo is a compile\n * error.\n */\nconst METADATA_MODIFY_CAPABILITY: DocCapability = 'doc.metadata.modify';\n\n/**\n * Reads/writes the document's Info dict through the engine handle and keeps the\n * plugin's state in sync. The live-update wiring (own + remote events) lives in\n * the effect; this is the read/write surface.\n */\nexport function createMetadataCapability(\n ctx: PluginContext<MetadataState, MetadataAction>,\n): MetadataCapability {\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[metadata] no document bound');\n return doc;\n };\n\n return {\n canEdit() {\n // Wildcard-aware predicate (mirrors the engine's own enforcement),\n // identical on both engines. NOT `effectiveScope.includes(...)` — that\n // enumeration drops the `*` admin grant, so it would hide the UI on a\n // default admin open even though the engine allows the edit.\n return ctx.doc?.security.allows(METADATA_MODIFY_CAPABILITY) ?? false;\n },\n\n current: () => ctx.getState().metadata,\n\n update: async (patch) => {\n // The write also emits a `metadata.updated` event the effect catches, so\n // this dispatch is just for an immediate, in-sync update (idempotent).\n const result = await requireDoc().metadata.update(patch);\n ctx.dispatch({ type: 'SET', metadata: result.metadata });\n },\n\n reload: async () => {\n const metadata = await requireDoc().metadata.read();\n ctx.dispatch({ type: 'SET', metadata });\n },\n };\n}\n","import type { DocumentEvent, EffectContext } from '@embedpdf/core';\nimport type { MetadataAction, MetadataState } from './types';\n\n/**\n * Makes metadata REACTIVE — the reason this is a plugin, not a kernel IO call.\n *\n * 1. Seed: read the Info dict once when the document opens.\n * 2. Live: subscribe to the document event stream. A `metadata.updated` event\n * carries the full re-read metadata and fires for OWN edits AND for remote\n * edits delivered over SSE (another session) — both just become `setState`.\n *\n * The handle's stream is synchronous fan-out, so this coexists with the kernel's\n * own subscription (page registry) on the same handle.\n */\nexport function registerMetadataEffects(ctx: EffectContext<MetadataState, MetadataAction>): void {\n const doc = ctx.doc;\n if (!doc) return;\n\n // 1. seed\n void doc.metadata.read().then(\n (metadata) => ctx.dispatch({ type: 'SET', metadata }),\n () => {}, // doc closed / read aborted — ignore\n );\n\n // 2. live updates (own edits + remote SSE edits)\n const unsubscribe = doc.events.subscribe((event: DocumentEvent) => {\n if (event.type === 'metadata.updated') {\n ctx.dispatch({ type: 'SET', metadata: event.metadata });\n }\n });\n ctx.cleanup(unsubscribe);\n}\n","import type { MetadataAction, MetadataState } from './types';\n\nexport const initialMetadataState = (): MetadataState => ({ metadata: null });\n\n/** Pure. The only transition: replace the metadata snapshot (from a read or an\n * event). */\nexport const metadataReducer = (state: MetadataState, a: MetadataAction): MetadataState =>\n a.type === 'SET' ? { ...state, metadata: a.metadata } : state;\n","import { definePlugin } from '@embedpdf/core';\nimport { createMetadataCapability } from './capability';\nimport { registerMetadataEffects } from './effects';\nimport { initialMetadataState, metadataReducer } from './reducer';\nimport { MetadataToken } from './types';\nimport type { MetadataAction, MetadataCapability, MetadataState } from './types';\n\n/**\n * Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it\n * from the engine and keeps it live off the document event stream (own + remote\n * SSE edits); the capability is the read/write surface.\n */\nexport const metadataPlugin = () =>\n definePlugin<MetadataState, MetadataAction, MetadataCapability>({\n id: 'metadata',\n token: MetadataToken,\n scope: 'document',\n initialState: initialMetadataState,\n reduce: metadataReducer,\n capability: createMetadataCapability,\n effects: registerMetadataEffects,\n });\n"],"mappings":";;;;;;;;;;;AAUA,MAAM,6BAA4C;;;;;;AAOlD,SAAgB,yBACd,KACoB;CACpB,MAAM,mBAAmB;EACvB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,8BAA8B;EACxD,OAAO;CACT;CAEA,OAAO;EACL,UAAU;GAKR,OAAO,IAAI,KAAK,SAAS,OAAO,0BAA0B,KAAK;EACjE;EAEA,eAAe,IAAI,SAAS,CAAC,CAAC;EAE9B,QAAQ,OAAO,UAAU;GAGvB,MAAM,SAAS,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,KAAK;GACvD,IAAI,SAAS;IAAE,MAAM;IAAO,UAAU,OAAO;GAAS,CAAC;EACzD;EAEA,QAAQ,YAAY;GAClB,MAAM,WAAW,MAAM,WAAW,CAAC,CAAC,SAAS,KAAK;GAClD,IAAI,SAAS;IAAE,MAAM;IAAO;GAAS,CAAC;EACxC;CACF;AACF;;;;;;;;;;;;;;ACnCA,SAAgB,wBAAwB,KAAyD;CAC/F,MAAM,MAAM,IAAI;CAChB,IAAI,CAAC,KAAK;CAGV,IAAS,SAAS,KAAK,CAAC,CAAC,MACtB,aAAa,IAAI,SAAS;EAAE,MAAM;EAAO;CAAS,CAAC,SAC9C,CAAC,CACT;CAGA,MAAM,cAAc,IAAI,OAAO,WAAW,UAAyB;EACjE,IAAI,MAAM,SAAS,oBACjB,IAAI,SAAS;GAAE,MAAM;GAAO,UAAU,MAAM;EAAS,CAAC;CAE1D,CAAC;CACD,IAAI,QAAQ,WAAW;AACzB;;;AC7BA,MAAa,8BAA6C,EAAE,UAAU,KAAK;;;AAI3E,MAAa,mBAAmB,OAAsB,MACpD,EAAE,SAAS,QAAQ;CAAE,GAAG;CAAO,UAAU,EAAE;AAAS,IAAI;;;;;;;;ACK1D,MAAa,wBAAA,GAAA,eAAA,aAAA,CACqD;CAC9D,IAAI;CACJ,OAAOA,iBAAAA;CACP,OAAO;CACP,cAAc;CACd,QAAQ;CACR,YAAY;CACZ,SAAS;AACX,CAAC"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,41 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/types.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* The document's Info-dict metadata, held as REACTIVE state — not a one-shot
|
|
5
|
-
* read. It changes from local edits AND from other sessions (a remote edit
|
|
6
|
-
* arrives over SSE as a `metadata.updated` event), so the plugin subscribes to
|
|
7
|
-
* the document event stream and keeps `current()` live. `update` writes a
|
|
8
|
-
* three-state patch into the LAYER (like a page mutation), so a metadata edit
|
|
9
|
-
* saves with the layer.
|
|
10
|
-
*/
|
|
11
|
-
interface MetadataState {
|
|
12
|
-
/** Current metadata, or null until the first read resolves. */
|
|
13
|
-
metadata: DocumentMetadata | null;
|
|
14
|
-
}
|
|
15
|
-
type MetadataAction = {
|
|
16
|
-
type: 'SET';
|
|
17
|
-
metadata: DocumentMetadata | null;
|
|
18
|
-
};
|
|
19
|
-
interface MetadataCapability {
|
|
20
|
-
/**
|
|
21
|
-
* Whether this caller is authorized to edit the Info dict —
|
|
22
|
-
* `effectiveScope` includes `doc.metadata.modify` (PDF bit 4). UIs gate their
|
|
23
|
-
* edit affordances on this; the engine independently enforces the same
|
|
24
|
-
* capability and throws `PermissionDenied` if a write slips through.
|
|
25
|
-
*/
|
|
26
|
-
canEdit(): boolean;
|
|
27
|
-
/** Current metadata; null until the initial read lands. Reactive — reflects
|
|
28
|
-
* own edits and remote (SSE) edits via the event stream. */
|
|
29
|
-
current(): DocumentMetadata | null;
|
|
30
|
-
/** Patch the Info dict (undefined=leave, null=clear, value=set). Writes to the
|
|
31
|
-
* layer; state refreshes from the resulting `metadata.updated` event. */
|
|
32
|
-
update(patch: MetadataPatch): Promise<void>;
|
|
33
|
-
/** Force a re-read from the engine (rarely needed — the event stream keeps
|
|
34
|
-
* state fresh). */
|
|
35
|
-
reload(): Promise<void>;
|
|
36
|
-
}
|
|
37
|
-
declare const MetadataToken: import("@embedpdf/core").CapabilityToken<MetadataCapability>;
|
|
38
|
-
//#endregion
|
|
1
|
+
import { i as MetadataToken, n as MetadataCapability, r as MetadataState, t as MetadataAction } from "./contract-Dk5SGhEP.cjs";
|
|
39
2
|
//#region src/metadata.plugin.d.ts
|
|
40
3
|
/**
|
|
41
4
|
* Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it
|
package/dist/index.d.ts
CHANGED
|
@@ -1,41 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region src/types.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* The document's Info-dict metadata, held as REACTIVE state — not a one-shot
|
|
5
|
-
* read. It changes from local edits AND from other sessions (a remote edit
|
|
6
|
-
* arrives over SSE as a `metadata.updated` event), so the plugin subscribes to
|
|
7
|
-
* the document event stream and keeps `current()` live. `update` writes a
|
|
8
|
-
* three-state patch into the LAYER (like a page mutation), so a metadata edit
|
|
9
|
-
* saves with the layer.
|
|
10
|
-
*/
|
|
11
|
-
interface MetadataState {
|
|
12
|
-
/** Current metadata, or null until the first read resolves. */
|
|
13
|
-
metadata: DocumentMetadata | null;
|
|
14
|
-
}
|
|
15
|
-
type MetadataAction = {
|
|
16
|
-
type: 'SET';
|
|
17
|
-
metadata: DocumentMetadata | null;
|
|
18
|
-
};
|
|
19
|
-
interface MetadataCapability {
|
|
20
|
-
/**
|
|
21
|
-
* Whether this caller is authorized to edit the Info dict —
|
|
22
|
-
* `effectiveScope` includes `doc.metadata.modify` (PDF bit 4). UIs gate their
|
|
23
|
-
* edit affordances on this; the engine independently enforces the same
|
|
24
|
-
* capability and throws `PermissionDenied` if a write slips through.
|
|
25
|
-
*/
|
|
26
|
-
canEdit(): boolean;
|
|
27
|
-
/** Current metadata; null until the initial read lands. Reactive — reflects
|
|
28
|
-
* own edits and remote (SSE) edits via the event stream. */
|
|
29
|
-
current(): DocumentMetadata | null;
|
|
30
|
-
/** Patch the Info dict (undefined=leave, null=clear, value=set). Writes to the
|
|
31
|
-
* layer; state refreshes from the resulting `metadata.updated` event. */
|
|
32
|
-
update(patch: MetadataPatch): Promise<void>;
|
|
33
|
-
/** Force a re-read from the engine (rarely needed — the event stream keeps
|
|
34
|
-
* state fresh). */
|
|
35
|
-
reload(): Promise<void>;
|
|
36
|
-
}
|
|
37
|
-
declare const MetadataToken: import("@embedpdf/core").CapabilityToken<MetadataCapability>;
|
|
38
|
-
//#endregion
|
|
1
|
+
import { i as MetadataToken, n as MetadataCapability, r as MetadataState, t as MetadataAction } from "./contract-Dk5SGhEP.js";
|
|
39
2
|
//#region src/metadata.plugin.d.ts
|
|
40
3
|
/**
|
|
41
4
|
* Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as MetadataToken } from "./contract-DXGV7Wpx.js";
|
|
2
|
+
import { definePlugin } from "@embedpdf/core";
|
|
2
3
|
//#region src/capability.ts
|
|
3
4
|
/**
|
|
4
5
|
* Authorization for Info-dict writes. Maps to PDF bit 4 (MODIFY). The engine
|
|
@@ -78,9 +79,6 @@ const metadataReducer = (state, a) => a.type === "SET" ? {
|
|
|
78
79
|
metadata: a.metadata
|
|
79
80
|
} : state;
|
|
80
81
|
//#endregion
|
|
81
|
-
//#region src/types.ts
|
|
82
|
-
const MetadataToken = createCapabilityToken("metadata");
|
|
83
|
-
//#endregion
|
|
84
82
|
//#region src/metadata.plugin.ts
|
|
85
83
|
/**
|
|
86
84
|
* Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/capability.ts","../src/effects.ts","../src/reducer.ts","../src/
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/capability.ts","../src/effects.ts","../src/reducer.ts","../src/metadata.plugin.ts"],"sourcesContent":["import type { PluginContext, DocCapability } from '@embedpdf/core';\nimport type { MetadataAction, MetadataCapability, MetadataState } from './types';\n\n/**\n * Authorization for Info-dict writes. Maps to PDF bit 4 (MODIFY). The engine\n * ALSO enforces this — `metadata.update` throws `PermissionDenied` without it,\n * identically on local and cloud — so `canEdit()` is the UI mirror of a real\n * guard, not the guard itself. Typed as `DocCapability` so a typo is a compile\n * error.\n */\nconst METADATA_MODIFY_CAPABILITY: DocCapability = 'doc.metadata.modify';\n\n/**\n * Reads/writes the document's Info dict through the engine handle and keeps the\n * plugin's state in sync. The live-update wiring (own + remote events) lives in\n * the effect; this is the read/write surface.\n */\nexport function createMetadataCapability(\n ctx: PluginContext<MetadataState, MetadataAction>,\n): MetadataCapability {\n const requireDoc = () => {\n const doc = ctx.doc;\n if (!doc) throw new Error('[metadata] no document bound');\n return doc;\n };\n\n return {\n canEdit() {\n // Wildcard-aware predicate (mirrors the engine's own enforcement),\n // identical on both engines. NOT `effectiveScope.includes(...)` — that\n // enumeration drops the `*` admin grant, so it would hide the UI on a\n // default admin open even though the engine allows the edit.\n return ctx.doc?.security.allows(METADATA_MODIFY_CAPABILITY) ?? false;\n },\n\n current: () => ctx.getState().metadata,\n\n update: async (patch) => {\n // The write also emits a `metadata.updated` event the effect catches, so\n // this dispatch is just for an immediate, in-sync update (idempotent).\n const result = await requireDoc().metadata.update(patch);\n ctx.dispatch({ type: 'SET', metadata: result.metadata });\n },\n\n reload: async () => {\n const metadata = await requireDoc().metadata.read();\n ctx.dispatch({ type: 'SET', metadata });\n },\n };\n}\n","import type { DocumentEvent, EffectContext } from '@embedpdf/core';\nimport type { MetadataAction, MetadataState } from './types';\n\n/**\n * Makes metadata REACTIVE — the reason this is a plugin, not a kernel IO call.\n *\n * 1. Seed: read the Info dict once when the document opens.\n * 2. Live: subscribe to the document event stream. A `metadata.updated` event\n * carries the full re-read metadata and fires for OWN edits AND for remote\n * edits delivered over SSE (another session) — both just become `setState`.\n *\n * The handle's stream is synchronous fan-out, so this coexists with the kernel's\n * own subscription (page registry) on the same handle.\n */\nexport function registerMetadataEffects(ctx: EffectContext<MetadataState, MetadataAction>): void {\n const doc = ctx.doc;\n if (!doc) return;\n\n // 1. seed\n void doc.metadata.read().then(\n (metadata) => ctx.dispatch({ type: 'SET', metadata }),\n () => {}, // doc closed / read aborted — ignore\n );\n\n // 2. live updates (own edits + remote SSE edits)\n const unsubscribe = doc.events.subscribe((event: DocumentEvent) => {\n if (event.type === 'metadata.updated') {\n ctx.dispatch({ type: 'SET', metadata: event.metadata });\n }\n });\n ctx.cleanup(unsubscribe);\n}\n","import type { MetadataAction, MetadataState } from './types';\n\nexport const initialMetadataState = (): MetadataState => ({ metadata: null });\n\n/** Pure. The only transition: replace the metadata snapshot (from a read or an\n * event). */\nexport const metadataReducer = (state: MetadataState, a: MetadataAction): MetadataState =>\n a.type === 'SET' ? { ...state, metadata: a.metadata } : state;\n","import { definePlugin } from '@embedpdf/core';\nimport { createMetadataCapability } from './capability';\nimport { registerMetadataEffects } from './effects';\nimport { initialMetadataState, metadataReducer } from './reducer';\nimport { MetadataToken } from './types';\nimport type { MetadataAction, MetadataCapability, MetadataState } from './types';\n\n/**\n * Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it\n * from the engine and keeps it live off the document event stream (own + remote\n * SSE edits); the capability is the read/write surface.\n */\nexport const metadataPlugin = () =>\n definePlugin<MetadataState, MetadataAction, MetadataCapability>({\n id: 'metadata',\n token: MetadataToken,\n scope: 'document',\n initialState: initialMetadataState,\n reduce: metadataReducer,\n capability: createMetadataCapability,\n effects: registerMetadataEffects,\n });\n"],"mappings":";;;;;;;;;;AAUA,MAAM,6BAA4C;;;;;;AAOlD,SAAgB,yBACd,KACoB;CACpB,MAAM,mBAAmB;EACvB,MAAM,MAAM,IAAI;EAChB,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,8BAA8B;EACxD,OAAO;CACT;CAEA,OAAO;EACL,UAAU;GAKR,OAAO,IAAI,KAAK,SAAS,OAAO,0BAA0B,KAAK;EACjE;EAEA,eAAe,IAAI,SAAS,CAAC,CAAC;EAE9B,QAAQ,OAAO,UAAU;GAGvB,MAAM,SAAS,MAAM,WAAW,CAAC,CAAC,SAAS,OAAO,KAAK;GACvD,IAAI,SAAS;IAAE,MAAM;IAAO,UAAU,OAAO;GAAS,CAAC;EACzD;EAEA,QAAQ,YAAY;GAClB,MAAM,WAAW,MAAM,WAAW,CAAC,CAAC,SAAS,KAAK;GAClD,IAAI,SAAS;IAAE,MAAM;IAAO;GAAS,CAAC;EACxC;CACF;AACF;;;;;;;;;;;;;;ACnCA,SAAgB,wBAAwB,KAAyD;CAC/F,MAAM,MAAM,IAAI;CAChB,IAAI,CAAC,KAAK;CAGV,IAAS,SAAS,KAAK,CAAC,CAAC,MACtB,aAAa,IAAI,SAAS;EAAE,MAAM;EAAO;CAAS,CAAC,SAC9C,CAAC,CACT;CAGA,MAAM,cAAc,IAAI,OAAO,WAAW,UAAyB;EACjE,IAAI,MAAM,SAAS,oBACjB,IAAI,SAAS;GAAE,MAAM;GAAO,UAAU,MAAM;EAAS,CAAC;CAE1D,CAAC;CACD,IAAI,QAAQ,WAAW;AACzB;;;AC7BA,MAAa,8BAA6C,EAAE,UAAU,KAAK;;;AAI3E,MAAa,mBAAmB,OAAsB,MACpD,EAAE,SAAS,QAAQ;CAAE,GAAG;CAAO,UAAU,EAAE;AAAS,IAAI;;;;;;;;ACK1D,MAAa,uBACX,aAAgE;CAC9D,IAAI;CACJ,OAAO;CACP,OAAO;CACP,cAAc;CACd,QAAQ;CACR,YAAY;CACZ,SAAS;AACX,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embedpdf/plugin-metadata",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.12",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Document-scoped metadata: reactive Info-dict state fed by the document event stream (own edits + remote SSE), with a three-state update that writes to the layer.",
|
|
6
6
|
"type": "module",
|
|
@@ -12,13 +12,17 @@
|
|
|
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.
|
|
25
|
+
"@embedpdf/core": "3.0.0-next.12"
|
|
22
26
|
},
|
|
23
27
|
"devDependencies": {
|
|
24
28
|
"typescript": "^5.0.0",
|