@embedpdf/plugin-metadata 3.0.0-next.14 → 3.0.0-next.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract-BQQulRec.cjs +22 -0
- package/dist/contract-BQQulRec.cjs.map +1 -0
- package/dist/contract-Cljrf00d.d.cts +101 -0
- package/dist/contract-Cljrf00d.d.ts +101 -0
- package/dist/contract-o3j9MoH5.js +18 -0
- package/dist/contract-o3j9MoH5.js.map +1 -0
- package/dist/contract.cjs +1 -1
- package/dist/contract.d.cts +2 -2
- package/dist/contract.d.ts +2 -2
- package/dist/contract.js +1 -1
- package/dist/index.cjs +112 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -8
- package/dist/index.d.ts +11 -8
- package/dist/index.js +113 -81
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/contract-CqhcLHxo.cjs +0 -11
- package/dist/contract-CqhcLHxo.cjs.map +0 -1
- package/dist/contract-DXGV7Wpx.js +0 -7
- package/dist/contract-DXGV7Wpx.js.map +0 -1
- package/dist/contract-Dk5SGhEP.d.cts +0 -40
- package/dist/contract-Dk5SGhEP.d.ts +0 -40
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/token.ts
|
|
2
|
+
/** The package token — created once here; `contract.ts` re-exports it and
|
|
3
|
+
* `host-contract.ts` widens it. */
|
|
4
|
+
const MetadataToken = (0, require("@embedpdf/core").createCapabilityToken)("metadata", {
|
|
5
|
+
hint: "add metadataPlugin() from '@embedpdf/plugin-metadata' to your plugins list",
|
|
6
|
+
promises: {
|
|
7
|
+
update: true,
|
|
8
|
+
refresh: true,
|
|
9
|
+
ensureLoaded: true,
|
|
10
|
+
"custom.update": true,
|
|
11
|
+
"custom.refresh": true
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
Object.defineProperty(exports, "MetadataToken", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function() {
|
|
18
|
+
return MetadataToken;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=contract-BQQulRec.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-BQQulRec.cjs","names":[],"sources":["../src/token.ts"],"sourcesContent":["/** The package token — created once here; `contract.ts` re-exports it and\n * `host-contract.ts` widens it. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { MetadataCapability } from './contract';\n\nexport const MetadataToken = createCapabilityToken<MetadataCapability>('metadata', {\n hint: \"add metadataPlugin() from '@embedpdf/plugin-metadata' to your plugins list\",\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n update: true,\n refresh: true,\n ensureLoaded: true,\n 'custom.update': true,\n 'custom.refresh': true,\n },\n});\n"],"mappings":";;;AAMA,MAAa,iBAAA,2BAAA,CAAA,CAAA,sBAAA,CAA0D,YAAY;CACjF,MAAM;CAGN,UAAU;EACR,QAAQ;EACR,SAAS;EACT,cAAc;EACd,iBAAiB;EACjB,kBAAkB;CACpB;AACF,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CustomMetadata, CustomMetadataPatch, DocumentMetadata, EventHook, EventOrigin, MetadataPatch, OperationOptions, ResourceStatus } from "@embedpdf/core";
|
|
2
|
+
//#region src/token.d.ts
|
|
3
|
+
declare const MetadataToken: import("@embedpdf/core").CapabilityToken<MetadataCapability>;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/contract.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A confirmed change of the Info dict's standard fields. Local edits, other
|
|
8
|
+
* plugins, scripts and other sessions all reach the same confirmed
|
|
9
|
+
* `metadata.updated` document event, which is the one path that updates the
|
|
10
|
+
* snapshot and fires this.
|
|
11
|
+
*/
|
|
12
|
+
interface MetadataUpdatedEvent {
|
|
13
|
+
readonly metadata: DocumentMetadata;
|
|
14
|
+
readonly previous: DocumentMetadata | null;
|
|
15
|
+
readonly changedKeys: readonly (keyof DocumentMetadata)[];
|
|
16
|
+
readonly origin: EventOrigin;
|
|
17
|
+
}
|
|
18
|
+
/** The metadata was (re)loaded from the engine. */
|
|
19
|
+
interface MetadataResyncedEvent {
|
|
20
|
+
readonly metadata: DocumentMetadata;
|
|
21
|
+
}
|
|
22
|
+
/** A confirmed change of the custom keys (`metadata.customUpdated`), whoever caused it. */
|
|
23
|
+
interface CustomMetadataUpdatedEvent {
|
|
24
|
+
readonly custom: CustomMetadata;
|
|
25
|
+
readonly previous: CustomMetadata | null;
|
|
26
|
+
/** The keys that were added, changed or removed. */
|
|
27
|
+
readonly changedKeys: readonly string[];
|
|
28
|
+
readonly origin: EventOrigin;
|
|
29
|
+
}
|
|
30
|
+
/** The custom keys were (re)loaded from the engine. */
|
|
31
|
+
interface CustomMetadataResyncedEvent {
|
|
32
|
+
readonly custom: CustomMetadata;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The Info dict's custom keys: the same reads and verbs as the standard
|
|
36
|
+
* fields, on an object of their own. Changing them needs the same permission,
|
|
37
|
+
* so `canUpdate()` on the metadata capability answers for both.
|
|
38
|
+
*/
|
|
39
|
+
interface CustomMetadataCapability {
|
|
40
|
+
/** The current keys, reference-stable until they change; `null` until the first read lands. */
|
|
41
|
+
getSnapshot(): CustomMetadata | null;
|
|
42
|
+
/** Load state: `idle` until `ensureLoaded()` asks, then `loading` → `ready`, or `forbidden` / `error`. */
|
|
43
|
+
getStatus(): ResourceStatus;
|
|
44
|
+
/**
|
|
45
|
+
* Set and remove keys: a key left out stays, `null` removes it, a string
|
|
46
|
+
* sets it. Resolves `{ custom }`, the keys after the change; by then the
|
|
47
|
+
* snapshot shows it and `onUpdated` has fired. Rejects with
|
|
48
|
+
* `permission-denied`, `invalid-input`, `instance-closed` or
|
|
49
|
+
* `operation-cancelled`.
|
|
50
|
+
*/
|
|
51
|
+
update(patch: CustomMetadataPatch, options?: OperationOptions): Promise<{
|
|
52
|
+
readonly custom: CustomMetadata;
|
|
53
|
+
}>;
|
|
54
|
+
/** Re-read from the engine. Rarely needed: the event stream keeps the snapshot fresh. */
|
|
55
|
+
refresh(options?: OperationOptions): Promise<void>;
|
|
56
|
+
/** A confirmed change, whoever caused it. Fires after the snapshot changed. */
|
|
57
|
+
readonly onUpdated: EventHook<CustomMetadataUpdatedEvent>;
|
|
58
|
+
/** The keys were loaded or reloaded from the engine. */
|
|
59
|
+
readonly onResynced: EventHook<CustomMetadataResyncedEvent>;
|
|
60
|
+
}
|
|
61
|
+
interface MetadataCapability {
|
|
62
|
+
/**
|
|
63
|
+
* The current metadata, reference-stable until it changes; `null` until
|
|
64
|
+
* the first read lands or while reading is forbidden — see `getStatus()`.
|
|
65
|
+
*/
|
|
66
|
+
getSnapshot(): DocumentMetadata | null;
|
|
67
|
+
/** Load state: `idle` until `ensureLoaded()` asks, then `loading` → `ready`, or `forbidden` / `error`. */
|
|
68
|
+
getStatus(): ResourceStatus;
|
|
69
|
+
/**
|
|
70
|
+
* Read the standard fields and the custom keys from the document, unless they are loaded or
|
|
71
|
+
* loading: nothing reads them when a document opens. Resolves once both have landed, when
|
|
72
|
+
* `onResynced` has fired; a later call resolves at once. Rejects with `permission-denied` when
|
|
73
|
+
* reading is refused, `operation-cancelled` or `instance-closed`; after a failure it reads again.
|
|
74
|
+
*/
|
|
75
|
+
ensureLoaded(options?: OperationOptions): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this session may change the Info dict (`doc.metadata.modify`):
|
|
78
|
+
* `update()` and `custom.update()`. The engine enforces the same permission.
|
|
79
|
+
*/
|
|
80
|
+
canUpdate(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Change the standard fields: a field left out stays, `null` clears it, a
|
|
83
|
+
* value sets it. Resolves `{ metadata }`, the fields after the change; by
|
|
84
|
+
* then the snapshot shows it and `onUpdated` has fired. Rejects with
|
|
85
|
+
* `permission-denied`, `instance-closed` or `operation-cancelled`.
|
|
86
|
+
*/
|
|
87
|
+
update(patch: MetadataPatch, options?: OperationOptions): Promise<{
|
|
88
|
+
readonly metadata: DocumentMetadata;
|
|
89
|
+
}>;
|
|
90
|
+
/** Re-read from the engine. Rarely needed: the event stream keeps the snapshot fresh. */
|
|
91
|
+
refresh(options?: OperationOptions): Promise<void>;
|
|
92
|
+
/** A confirmed change, whoever caused it. Fires after the snapshot changed. */
|
|
93
|
+
readonly onUpdated: EventHook<MetadataUpdatedEvent>;
|
|
94
|
+
/** The metadata was loaded or reloaded from the engine. */
|
|
95
|
+
readonly onResynced: EventHook<MetadataResyncedEvent>;
|
|
96
|
+
/** The Info dict's other keys. */
|
|
97
|
+
readonly custom: CustomMetadataCapability;
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { MetadataResyncedEvent as a, MetadataCapability as i, CustomMetadataResyncedEvent as n, MetadataUpdatedEvent as o, CustomMetadataUpdatedEvent as r, MetadataToken as s, CustomMetadataCapability as t };
|
|
101
|
+
//# sourceMappingURL=contract-Cljrf00d.d.cts.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { CustomMetadata, CustomMetadataPatch, DocumentMetadata, EventHook, EventOrigin, MetadataPatch, OperationOptions, ResourceStatus } from "@embedpdf/core";
|
|
2
|
+
//#region src/token.d.ts
|
|
3
|
+
declare const MetadataToken: import("@embedpdf/core").CapabilityToken<MetadataCapability>;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region src/contract.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A confirmed change of the Info dict's standard fields. Local edits, other
|
|
8
|
+
* plugins, scripts and other sessions all reach the same confirmed
|
|
9
|
+
* `metadata.updated` document event, which is the one path that updates the
|
|
10
|
+
* snapshot and fires this.
|
|
11
|
+
*/
|
|
12
|
+
interface MetadataUpdatedEvent {
|
|
13
|
+
readonly metadata: DocumentMetadata;
|
|
14
|
+
readonly previous: DocumentMetadata | null;
|
|
15
|
+
readonly changedKeys: readonly (keyof DocumentMetadata)[];
|
|
16
|
+
readonly origin: EventOrigin;
|
|
17
|
+
}
|
|
18
|
+
/** The metadata was (re)loaded from the engine. */
|
|
19
|
+
interface MetadataResyncedEvent {
|
|
20
|
+
readonly metadata: DocumentMetadata;
|
|
21
|
+
}
|
|
22
|
+
/** A confirmed change of the custom keys (`metadata.customUpdated`), whoever caused it. */
|
|
23
|
+
interface CustomMetadataUpdatedEvent {
|
|
24
|
+
readonly custom: CustomMetadata;
|
|
25
|
+
readonly previous: CustomMetadata | null;
|
|
26
|
+
/** The keys that were added, changed or removed. */
|
|
27
|
+
readonly changedKeys: readonly string[];
|
|
28
|
+
readonly origin: EventOrigin;
|
|
29
|
+
}
|
|
30
|
+
/** The custom keys were (re)loaded from the engine. */
|
|
31
|
+
interface CustomMetadataResyncedEvent {
|
|
32
|
+
readonly custom: CustomMetadata;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The Info dict's custom keys: the same reads and verbs as the standard
|
|
36
|
+
* fields, on an object of their own. Changing them needs the same permission,
|
|
37
|
+
* so `canUpdate()` on the metadata capability answers for both.
|
|
38
|
+
*/
|
|
39
|
+
interface CustomMetadataCapability {
|
|
40
|
+
/** The current keys, reference-stable until they change; `null` until the first read lands. */
|
|
41
|
+
getSnapshot(): CustomMetadata | null;
|
|
42
|
+
/** Load state: `idle` until `ensureLoaded()` asks, then `loading` → `ready`, or `forbidden` / `error`. */
|
|
43
|
+
getStatus(): ResourceStatus;
|
|
44
|
+
/**
|
|
45
|
+
* Set and remove keys: a key left out stays, `null` removes it, a string
|
|
46
|
+
* sets it. Resolves `{ custom }`, the keys after the change; by then the
|
|
47
|
+
* snapshot shows it and `onUpdated` has fired. Rejects with
|
|
48
|
+
* `permission-denied`, `invalid-input`, `instance-closed` or
|
|
49
|
+
* `operation-cancelled`.
|
|
50
|
+
*/
|
|
51
|
+
update(patch: CustomMetadataPatch, options?: OperationOptions): Promise<{
|
|
52
|
+
readonly custom: CustomMetadata;
|
|
53
|
+
}>;
|
|
54
|
+
/** Re-read from the engine. Rarely needed: the event stream keeps the snapshot fresh. */
|
|
55
|
+
refresh(options?: OperationOptions): Promise<void>;
|
|
56
|
+
/** A confirmed change, whoever caused it. Fires after the snapshot changed. */
|
|
57
|
+
readonly onUpdated: EventHook<CustomMetadataUpdatedEvent>;
|
|
58
|
+
/** The keys were loaded or reloaded from the engine. */
|
|
59
|
+
readonly onResynced: EventHook<CustomMetadataResyncedEvent>;
|
|
60
|
+
}
|
|
61
|
+
interface MetadataCapability {
|
|
62
|
+
/**
|
|
63
|
+
* The current metadata, reference-stable until it changes; `null` until
|
|
64
|
+
* the first read lands or while reading is forbidden — see `getStatus()`.
|
|
65
|
+
*/
|
|
66
|
+
getSnapshot(): DocumentMetadata | null;
|
|
67
|
+
/** Load state: `idle` until `ensureLoaded()` asks, then `loading` → `ready`, or `forbidden` / `error`. */
|
|
68
|
+
getStatus(): ResourceStatus;
|
|
69
|
+
/**
|
|
70
|
+
* Read the standard fields and the custom keys from the document, unless they are loaded or
|
|
71
|
+
* loading: nothing reads them when a document opens. Resolves once both have landed, when
|
|
72
|
+
* `onResynced` has fired; a later call resolves at once. Rejects with `permission-denied` when
|
|
73
|
+
* reading is refused, `operation-cancelled` or `instance-closed`; after a failure it reads again.
|
|
74
|
+
*/
|
|
75
|
+
ensureLoaded(options?: OperationOptions): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this session may change the Info dict (`doc.metadata.modify`):
|
|
78
|
+
* `update()` and `custom.update()`. The engine enforces the same permission.
|
|
79
|
+
*/
|
|
80
|
+
canUpdate(): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Change the standard fields: a field left out stays, `null` clears it, a
|
|
83
|
+
* value sets it. Resolves `{ metadata }`, the fields after the change; by
|
|
84
|
+
* then the snapshot shows it and `onUpdated` has fired. Rejects with
|
|
85
|
+
* `permission-denied`, `instance-closed` or `operation-cancelled`.
|
|
86
|
+
*/
|
|
87
|
+
update(patch: MetadataPatch, options?: OperationOptions): Promise<{
|
|
88
|
+
readonly metadata: DocumentMetadata;
|
|
89
|
+
}>;
|
|
90
|
+
/** Re-read from the engine. Rarely needed: the event stream keeps the snapshot fresh. */
|
|
91
|
+
refresh(options?: OperationOptions): Promise<void>;
|
|
92
|
+
/** A confirmed change, whoever caused it. Fires after the snapshot changed. */
|
|
93
|
+
readonly onUpdated: EventHook<MetadataUpdatedEvent>;
|
|
94
|
+
/** The metadata was loaded or reloaded from the engine. */
|
|
95
|
+
readonly onResynced: EventHook<MetadataResyncedEvent>;
|
|
96
|
+
/** The Info dict's other keys. */
|
|
97
|
+
readonly custom: CustomMetadataCapability;
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
export { MetadataResyncedEvent as a, MetadataCapability as i, CustomMetadataResyncedEvent as n, MetadataUpdatedEvent as o, CustomMetadataUpdatedEvent as r, MetadataToken as s, CustomMetadataCapability as t };
|
|
101
|
+
//# sourceMappingURL=contract-Cljrf00d.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createCapabilityToken } from "@embedpdf/core";
|
|
2
|
+
//#region src/token.ts
|
|
3
|
+
/** The package token — created once here; `contract.ts` re-exports it and
|
|
4
|
+
* `host-contract.ts` widens it. */
|
|
5
|
+
const MetadataToken = createCapabilityToken("metadata", {
|
|
6
|
+
hint: "add metadataPlugin() from '@embedpdf/plugin-metadata' to your plugins list",
|
|
7
|
+
promises: {
|
|
8
|
+
update: true,
|
|
9
|
+
refresh: true,
|
|
10
|
+
ensureLoaded: true,
|
|
11
|
+
"custom.update": true,
|
|
12
|
+
"custom.refresh": true
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
//#endregion
|
|
16
|
+
export { MetadataToken as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=contract-o3j9MoH5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-o3j9MoH5.js","names":[],"sources":["../src/token.ts"],"sourcesContent":["/** The package token — created once here; `contract.ts` re-exports it and\n * `host-contract.ts` widens it. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { MetadataCapability } from './contract';\n\nexport const MetadataToken = createCapabilityToken<MetadataCapability>('metadata', {\n hint: \"add metadataPlugin() from '@embedpdf/plugin-metadata' to your plugins list\",\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n update: true,\n refresh: true,\n ensureLoaded: true,\n 'custom.update': true,\n 'custom.refresh': true,\n },\n});\n"],"mappings":";;;;AAMA,MAAa,gBAAgB,sBAA0C,YAAY;CACjF,MAAM;CAGN,UAAU;EACR,QAAQ;EACR,SAAS;EACT,cAAc;EACd,iBAAiB;EACjB,kBAAkB;CACpB;AACF,CAAC"}
|
package/dist/contract.cjs
CHANGED
package/dist/contract.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as
|
|
2
|
-
export {
|
|
1
|
+
import { a as MetadataResyncedEvent, i as MetadataCapability, n as CustomMetadataResyncedEvent, o as MetadataUpdatedEvent, r as CustomMetadataUpdatedEvent, s as MetadataToken, t as CustomMetadataCapability } from "./contract-Cljrf00d.cjs";
|
|
2
|
+
export { CustomMetadataCapability, CustomMetadataResyncedEvent, CustomMetadataUpdatedEvent, MetadataCapability, MetadataResyncedEvent, MetadataToken, MetadataUpdatedEvent };
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as
|
|
2
|
-
export {
|
|
1
|
+
import { a as MetadataResyncedEvent, i as MetadataCapability, n as CustomMetadataResyncedEvent, o as MetadataUpdatedEvent, r as CustomMetadataUpdatedEvent, s as MetadataToken, t as CustomMetadataCapability } from "./contract-Cljrf00d.js";
|
|
2
|
+
export { CustomMetadataCapability, CustomMetadataResyncedEvent, CustomMetadataUpdatedEvent, MetadataCapability, MetadataResyncedEvent, MetadataToken, MetadataUpdatedEvent };
|
package/dist/contract.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as MetadataToken } from "./contract-
|
|
1
|
+
import { t as MetadataToken } from "./contract-o3j9MoH5.js";
|
|
2
2
|
export { MetadataToken };
|
package/dist/index.cjs
CHANGED
|
@@ -1,102 +1,135 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_contract = require("./contract-
|
|
2
|
+
const require_contract = require("./contract-BQQulRec.cjs");
|
|
3
3
|
let _embedpdf_core = require("@embedpdf/core");
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/model.ts
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* guard, not the guard itself. Typed as `DocCapability` so a typo is a compile
|
|
10
|
-
* error.
|
|
6
|
+
* The keys whose values differ between two snapshots, removed keys included.
|
|
7
|
+
* Both snapshots (the standard fields, the custom keys) hold only strings,
|
|
8
|
+
* `null` and enums, so a shallow compare is exact.
|
|
11
9
|
*/
|
|
12
|
-
|
|
10
|
+
function changedKeys(previous, next) {
|
|
11
|
+
const keys = Object.keys(next);
|
|
12
|
+
if (!previous) return keys;
|
|
13
|
+
return [.../* @__PURE__ */ new Set([...Object.keys(previous), ...keys])].filter((key) => previous[key] !== next[key]);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/controller.ts
|
|
17
|
+
const METADATA_MODIFY = "doc.metadata.modify";
|
|
13
18
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* The metadata controller. Both halves of the Info dict are mirrors: each
|
|
20
|
+
* changes only when a load lands or its confirmed document event arrives
|
|
21
|
+
* (`metadata.updated`, `metadata.customUpdated`), whoever caused the edit,
|
|
22
|
+
* and that is also the one place its `onUpdated` and `onResynced` fire.
|
|
23
|
+
* Nothing needs them when a document opens, so they load on demand: the
|
|
24
|
+
* first `ensureLoaded()` (what `metadataState` asks for) reads them.
|
|
17
25
|
*/
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
metadata:
|
|
26
|
+
function createMetadataController(ctx) {
|
|
27
|
+
const updated = ctx.events.source();
|
|
28
|
+
const resynced = ctx.events.source();
|
|
29
|
+
const customUpdated = ctx.events.source();
|
|
30
|
+
const customResynced = ctx.events.source();
|
|
31
|
+
const metadata = ctx.mirror({
|
|
32
|
+
name: "metadata",
|
|
33
|
+
onDemand: true,
|
|
34
|
+
initial: () => null,
|
|
35
|
+
load: async (doc) => ({ value: await doc.metadata.get() }),
|
|
36
|
+
fold: (value, event) => event.type === "metadata.updated" ? event.metadata : value,
|
|
37
|
+
changed: ({ cause, event, previous, next }) => {
|
|
38
|
+
if (!next) return;
|
|
39
|
+
if (cause === "load") resynced.emit({ metadata: next });
|
|
40
|
+
else if (event && "origin" in event) updated.emit({
|
|
41
|
+
metadata: next,
|
|
42
|
+
previous,
|
|
43
|
+
changedKeys: changedKeys(previous, next),
|
|
44
|
+
origin: event.origin
|
|
34
45
|
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
const custom = ctx.mirror({
|
|
49
|
+
name: "customMetadata",
|
|
50
|
+
onDemand: true,
|
|
51
|
+
initial: () => null,
|
|
52
|
+
load: async (doc) => ({ value: await doc.metadata.custom.get() }),
|
|
53
|
+
fold: (value, event) => event.type === "metadata.customUpdated" ? event.custom : value,
|
|
54
|
+
changed: ({ cause, event, previous, next }) => {
|
|
55
|
+
if (!next) return;
|
|
56
|
+
if (cause === "load") customResynced.emit({ custom: next });
|
|
57
|
+
else if (event && "origin" in event) customUpdated.emit({
|
|
58
|
+
custom: next,
|
|
59
|
+
previous,
|
|
60
|
+
changedKeys: changedKeys(previous, next),
|
|
61
|
+
origin: event.origin
|
|
41
62
|
});
|
|
42
63
|
}
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/effects.ts
|
|
47
|
-
/**
|
|
48
|
-
* Makes metadata REACTIVE — the reason this is a plugin, not a kernel IO call.
|
|
49
|
-
*
|
|
50
|
-
* 1. Seed: read the Info dict once when the document opens.
|
|
51
|
-
* 2. Live: subscribe to the document event stream. A `metadata.updated` event
|
|
52
|
-
* carries the full re-read metadata and fires for OWN edits AND for remote
|
|
53
|
-
* edits delivered over SSE (another session) — both just become `setState`.
|
|
54
|
-
*
|
|
55
|
-
* The handle's stream is synchronous fan-out, so this coexists with the kernel's
|
|
56
|
-
* own subscription (page registry) on the same handle.
|
|
57
|
-
*/
|
|
58
|
-
function registerMetadataEffects(ctx) {
|
|
59
|
-
const doc = ctx.doc;
|
|
60
|
-
if (!doc) return;
|
|
61
|
-
doc.metadata.read().then((metadata) => ctx.dispatch({
|
|
62
|
-
type: "SET",
|
|
63
|
-
metadata
|
|
64
|
-
}), () => {});
|
|
65
|
-
const unsubscribe = doc.events.subscribe((event) => {
|
|
66
|
-
if (event.type === "metadata.updated") ctx.dispatch({
|
|
67
|
-
type: "SET",
|
|
68
|
-
metadata: event.metadata
|
|
69
|
-
});
|
|
70
64
|
});
|
|
71
|
-
ctx.
|
|
65
|
+
const canUpdate = () => ctx.allows(METADATA_MODIFY);
|
|
66
|
+
/**
|
|
67
|
+
* Both writes refuse the same way before reaching the engine: the verbs are
|
|
68
|
+
* async, so a refusal rejects, and nothing changes.
|
|
69
|
+
*/
|
|
70
|
+
const refuseWrite = (verb, options) => {
|
|
71
|
+
ctx.assertAllowed(METADATA_MODIFY, verb);
|
|
72
|
+
if (options?.signal?.aborted) throw new _embedpdf_core.PluginError("operation-cancelled", "metadata", `${verb} was cancelled`);
|
|
73
|
+
};
|
|
74
|
+
const customApi = {
|
|
75
|
+
getSnapshot: custom.get,
|
|
76
|
+
getStatus: custom.getStatus,
|
|
77
|
+
update: async (patch, options) => {
|
|
78
|
+
refuseWrite("metadata.custom.update", options);
|
|
79
|
+
return { custom: (await ctx.cancellable(options?.signal, ctx.doc.metadata.custom.update(patch))).custom };
|
|
80
|
+
},
|
|
81
|
+
refresh: (options) => ctx.cancellable(options?.signal, custom.refresh()),
|
|
82
|
+
onUpdated: customUpdated.on,
|
|
83
|
+
onResynced: customResynced.on
|
|
84
|
+
};
|
|
85
|
+
return { api: {
|
|
86
|
+
getSnapshot: metadata.get,
|
|
87
|
+
getStatus: metadata.getStatus,
|
|
88
|
+
ensureLoaded: (options) => ctx.cancellable(options?.signal, Promise.all([metadata.ensureLoaded(), custom.ensureLoaded()]).then(() => void 0)),
|
|
89
|
+
canUpdate,
|
|
90
|
+
update: async (patch, options) => {
|
|
91
|
+
refuseWrite("metadata.update", options);
|
|
92
|
+
return { metadata: (await ctx.cancellable(options?.signal, ctx.doc.metadata.update(patch))).metadata };
|
|
93
|
+
},
|
|
94
|
+
refresh: (options) => ctx.cancellable(options?.signal, metadata.refresh()),
|
|
95
|
+
onUpdated: updated.on,
|
|
96
|
+
onResynced: resynced.on,
|
|
97
|
+
custom: customApi
|
|
98
|
+
} };
|
|
72
99
|
}
|
|
73
100
|
//#endregion
|
|
74
|
-
//#region src/reducer.ts
|
|
75
|
-
const initialMetadataState = () => ({ metadata: null });
|
|
76
|
-
/** Pure. The only transition: replace the metadata snapshot (from a read or an
|
|
77
|
-
* event). */
|
|
78
|
-
const metadataReducer = (state, a) => a.type === "SET" ? {
|
|
79
|
-
...state,
|
|
80
|
-
metadata: a.metadata
|
|
81
|
-
} : state;
|
|
82
|
-
//#endregion
|
|
83
101
|
//#region src/metadata.plugin.ts
|
|
84
|
-
/**
|
|
85
|
-
* Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it
|
|
86
|
-
* from the engine and keeps it live off the document event stream (own + remote
|
|
87
|
-
* SSE edits); the capability is the read/write surface.
|
|
88
|
-
*/
|
|
102
|
+
/** Document-scoped, reactive Info-dict metadata. Takes no configuration. */
|
|
89
103
|
const metadataPlugin = () => (0, _embedpdf_core.definePlugin)({
|
|
90
104
|
id: "metadata",
|
|
91
105
|
token: require_contract.MetadataToken,
|
|
92
106
|
scope: "document",
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
107
|
+
create: createMetadataController
|
|
108
|
+
});
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/state.ts
|
|
111
|
+
/**
|
|
112
|
+
* The metadata page's State table as code: what `useMetadataState()` returns,
|
|
113
|
+
* and the same fields in every other framework. `status` is the standard
|
|
114
|
+
* fields' load state; `custom.getStatus()` has the custom keys' own. Reading
|
|
115
|
+
* the state loads it (`ensure`): the first reader of a document starts the read.
|
|
116
|
+
*/
|
|
117
|
+
const metadataState = (0, _embedpdf_core.defineState)(require_contract.MetadataToken, {
|
|
118
|
+
read: (metadata) => ({
|
|
119
|
+
metadata: metadata.getSnapshot(),
|
|
120
|
+
custom: metadata.custom.getSnapshot(),
|
|
121
|
+
status: metadata.getStatus()
|
|
122
|
+
}),
|
|
123
|
+
empty: {
|
|
124
|
+
metadata: null,
|
|
125
|
+
custom: null,
|
|
126
|
+
status: "idle"
|
|
127
|
+
},
|
|
128
|
+
ensure: (metadata) => metadata.ensureLoaded()
|
|
97
129
|
});
|
|
98
130
|
//#endregion
|
|
99
131
|
exports.MetadataToken = require_contract.MetadataToken;
|
|
100
132
|
exports.metadataPlugin = metadataPlugin;
|
|
133
|
+
exports.metadataState = metadataState;
|
|
101
134
|
|
|
102
135
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["MetadataToken"],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["PluginError","MetadataToken","MetadataToken"],"sources":["../src/model.ts","../src/controller.ts","../src/metadata.plugin.ts","../src/state.ts"],"sourcesContent":["/**\n * The keys whose values differ between two snapshots, removed keys included.\n * Both snapshots (the standard fields, the custom keys) hold only strings,\n * `null` and enums, so a shallow compare is exact.\n */\nexport function changedKeys<T extends object>(\n previous: T | null,\n next: T,\n): readonly (keyof T & string)[] {\n const keys = Object.keys(next) as (keyof T & string)[];\n if (!previous) return keys;\n const all = new Set([...(Object.keys(previous) as (keyof T & string)[]), ...keys]);\n return [...all].filter((key) => previous[key] !== next[key]);\n}\n","import {\n PluginError,\n type PluginContext,\n type CustomMetadata,\n type DocCapability,\n type DocumentMetadata,\n type OperationOptions,\n} from '@embedpdf/core';\n\nimport type {\n CustomMetadataCapability,\n CustomMetadataResyncedEvent,\n CustomMetadataUpdatedEvent,\n MetadataCapability,\n MetadataResyncedEvent,\n MetadataUpdatedEvent,\n} from './contract';\nimport { changedKeys } from './model';\n\nconst METADATA_MODIFY: DocCapability = 'doc.metadata.modify';\n\n/**\n * The metadata controller. Both halves of the Info dict are mirrors: each\n * changes only when a load lands or its confirmed document event arrives\n * (`metadata.updated`, `metadata.customUpdated`), whoever caused the edit,\n * and that is also the one place its `onUpdated` and `onResynced` fire.\n * Nothing needs them when a document opens, so they load on demand: the\n * first `ensureLoaded()` (what `metadataState` asks for) reads them.\n */\nexport function createMetadataController(ctx: PluginContext<void>) {\n const updated = ctx.events.source<MetadataUpdatedEvent>();\n const resynced = ctx.events.source<MetadataResyncedEvent>();\n const customUpdated = ctx.events.source<CustomMetadataUpdatedEvent>();\n const customResynced = ctx.events.source<CustomMetadataResyncedEvent>();\n\n const metadata = ctx.mirror<DocumentMetadata | null>({\n name: 'metadata',\n onDemand: true,\n initial: () => null,\n load: async (doc) => ({ value: await doc.metadata.get() }),\n fold: (value, event) => (event.type === 'metadata.updated' ? event.metadata : value),\n changed: ({ cause, event, previous, next }) => {\n if (!next) return;\n if (cause === 'load') {\n resynced.emit({ metadata: next });\n } else if (event && 'origin' in event) {\n updated.emit({\n metadata: next,\n previous,\n changedKeys: changedKeys(previous, next),\n origin: event.origin,\n });\n }\n },\n });\n\n const custom = ctx.mirror<CustomMetadata | null>({\n name: 'customMetadata',\n onDemand: true,\n initial: () => null,\n load: async (doc) => ({ value: await doc.metadata.custom.get() }),\n fold: (value, event) => (event.type === 'metadata.customUpdated' ? event.custom : value),\n changed: ({ cause, event, previous, next }) => {\n if (!next) return;\n if (cause === 'load') {\n customResynced.emit({ custom: next });\n } else if (event && 'origin' in event) {\n customUpdated.emit({\n custom: next,\n previous,\n changedKeys: changedKeys(previous, next),\n origin: event.origin,\n });\n }\n },\n });\n\n const canUpdate = () => ctx.allows(METADATA_MODIFY);\n\n /**\n * Both writes refuse the same way before reaching the engine: the verbs are\n * async, so a refusal rejects, and nothing changes.\n */\n const refuseWrite = (verb: string, options?: OperationOptions): void => {\n ctx.assertAllowed(METADATA_MODIFY, verb);\n if (options?.signal?.aborted) {\n throw new PluginError('operation-cancelled', 'metadata', `${verb} was cancelled`);\n }\n };\n\n const customApi: CustomMetadataCapability = {\n getSnapshot: custom.get,\n getStatus: custom.getStatus,\n update: async (patch, options) => {\n refuseWrite('metadata.custom.update', options);\n const result = await ctx.cancellable(options?.signal, ctx.doc.metadata.custom.update(patch));\n return { custom: result.custom };\n },\n refresh: (options) => ctx.cancellable(options?.signal, custom.refresh()),\n onUpdated: customUpdated.on,\n onResynced: customResynced.on,\n };\n\n const api: MetadataCapability = {\n getSnapshot: metadata.get,\n getStatus: metadata.getStatus,\n ensureLoaded: (options) =>\n ctx.cancellable(\n options?.signal,\n Promise.all([metadata.ensureLoaded(), custom.ensureLoaded()]).then(() => undefined),\n ),\n canUpdate,\n update: async (patch, options) => {\n refuseWrite('metadata.update', options);\n const result = await ctx.cancellable(options?.signal, ctx.doc.metadata.update(patch));\n return { metadata: result.metadata };\n },\n refresh: (options) => ctx.cancellable(options?.signal, metadata.refresh()),\n onUpdated: updated.on,\n onResynced: resynced.on,\n custom: customApi,\n };\n\n return { api };\n}\n","import { definePlugin } from '@embedpdf/core';\n\nimport { MetadataToken } from './contract';\nimport { createMetadataController } from './controller';\n\n/** Document-scoped, reactive Info-dict metadata. Takes no configuration. */\nexport const metadataPlugin = () =>\n definePlugin({\n id: 'metadata',\n token: MetadataToken,\n scope: 'document',\n create: createMetadataController,\n });\n","/**\n * The metadata page's State table as code: what `useMetadataState()` returns,\n * and the same fields in every other framework. `status` is the standard\n * fields' load state; `custom.getStatus()` has the custom keys' own. Reading\n * the state loads it (`ensure`): the first reader of a document starts the read.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { MetadataToken } from './contract';\n\nexport const metadataState = defineState(MetadataToken, {\n read: (metadata) => ({\n metadata: metadata.getSnapshot(),\n custom: metadata.custom.getSnapshot(),\n status: metadata.getStatus(),\n }),\n empty: {\n metadata: null,\n custom: null,\n status: 'idle',\n },\n ensure: (metadata) => metadata.ensureLoaded(),\n});\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { a as MetadataResyncedEvent, i as MetadataCapability, n as CustomMetadataResyncedEvent, o as MetadataUpdatedEvent, r as CustomMetadataUpdatedEvent, s as MetadataToken, t as CustomMetadataCapability } from "./contract-Cljrf00d.cjs";
|
|
2
2
|
//#region src/metadata.plugin.d.ts
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
* from the engine and keeps it live off the document event stream (own + remote
|
|
6
|
-
* SSE edits); the capability is the read/write surface.
|
|
7
|
-
*/
|
|
8
|
-
declare const metadataPlugin: () => import("@embedpdf/core").PluginDef<MetadataState, MetadataAction, MetadataCapability>;
|
|
3
|
+
/** Document-scoped, reactive Info-dict metadata. Takes no configuration. */
|
|
4
|
+
declare const metadataPlugin: () => import("@embedpdf/core").PluginDef<void, MetadataCapability, import("@embedpdf/core").NoSettings>;
|
|
9
5
|
//#endregion
|
|
10
|
-
|
|
6
|
+
//#region src/state.d.ts
|
|
7
|
+
declare const metadataState: import("@embedpdf/core").StateDeclaration<MetadataCapability, {
|
|
8
|
+
metadata: import("@embedpdf/core").DocumentMetadata | null;
|
|
9
|
+
custom: import("@embedpdf/core").CustomMetadata | null;
|
|
10
|
+
status: import("@embedpdf/core").ResourceStatus;
|
|
11
|
+
}>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { CustomMetadataCapability, CustomMetadataResyncedEvent, CustomMetadataUpdatedEvent, MetadataCapability, MetadataResyncedEvent, MetadataToken, MetadataUpdatedEvent, metadataPlugin, metadataState };
|
|
11
14
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { i as
|
|
1
|
+
import { a as MetadataResyncedEvent, i as MetadataCapability, n as CustomMetadataResyncedEvent, o as MetadataUpdatedEvent, r as CustomMetadataUpdatedEvent, s as MetadataToken, t as CustomMetadataCapability } from "./contract-Cljrf00d.js";
|
|
2
2
|
//#region src/metadata.plugin.d.ts
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
* from the engine and keeps it live off the document event stream (own + remote
|
|
6
|
-
* SSE edits); the capability is the read/write surface.
|
|
7
|
-
*/
|
|
8
|
-
declare const metadataPlugin: () => import("@embedpdf/core").PluginDef<MetadataState, MetadataAction, MetadataCapability>;
|
|
3
|
+
/** Document-scoped, reactive Info-dict metadata. Takes no configuration. */
|
|
4
|
+
declare const metadataPlugin: () => import("@embedpdf/core").PluginDef<void, MetadataCapability, import("@embedpdf/core").NoSettings>;
|
|
9
5
|
//#endregion
|
|
10
|
-
|
|
6
|
+
//#region src/state.d.ts
|
|
7
|
+
declare const metadataState: import("@embedpdf/core").StateDeclaration<MetadataCapability, {
|
|
8
|
+
metadata: import("@embedpdf/core").DocumentMetadata | null;
|
|
9
|
+
custom: import("@embedpdf/core").CustomMetadata | null;
|
|
10
|
+
status: import("@embedpdf/core").ResourceStatus;
|
|
11
|
+
}>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { CustomMetadataCapability, CustomMetadataResyncedEvent, CustomMetadataUpdatedEvent, MetadataCapability, MetadataResyncedEvent, MetadataToken, MetadataUpdatedEvent, metadataPlugin, metadataState };
|
|
11
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,100 +1,132 @@
|
|
|
1
|
-
import { t as MetadataToken } from "./contract-
|
|
2
|
-
import { definePlugin } from "@embedpdf/core";
|
|
3
|
-
//#region src/
|
|
1
|
+
import { t as MetadataToken } from "./contract-o3j9MoH5.js";
|
|
2
|
+
import { PluginError, definePlugin, defineState } from "@embedpdf/core";
|
|
3
|
+
//#region src/model.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* guard, not the guard itself. Typed as `DocCapability` so a typo is a compile
|
|
9
|
-
* error.
|
|
5
|
+
* The keys whose values differ between two snapshots, removed keys included.
|
|
6
|
+
* Both snapshots (the standard fields, the custom keys) hold only strings,
|
|
7
|
+
* `null` and enums, so a shallow compare is exact.
|
|
10
8
|
*/
|
|
11
|
-
|
|
9
|
+
function changedKeys(previous, next) {
|
|
10
|
+
const keys = Object.keys(next);
|
|
11
|
+
if (!previous) return keys;
|
|
12
|
+
return [.../* @__PURE__ */ new Set([...Object.keys(previous), ...keys])].filter((key) => previous[key] !== next[key]);
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/controller.ts
|
|
16
|
+
const METADATA_MODIFY = "doc.metadata.modify";
|
|
12
17
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
18
|
+
* The metadata controller. Both halves of the Info dict are mirrors: each
|
|
19
|
+
* changes only when a load lands or its confirmed document event arrives
|
|
20
|
+
* (`metadata.updated`, `metadata.customUpdated`), whoever caused the edit,
|
|
21
|
+
* and that is also the one place its `onUpdated` and `onResynced` fire.
|
|
22
|
+
* Nothing needs them when a document opens, so they load on demand: the
|
|
23
|
+
* first `ensureLoaded()` (what `metadataState` asks for) reads them.
|
|
16
24
|
*/
|
|
17
|
-
function
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
metadata:
|
|
25
|
+
function createMetadataController(ctx) {
|
|
26
|
+
const updated = ctx.events.source();
|
|
27
|
+
const resynced = ctx.events.source();
|
|
28
|
+
const customUpdated = ctx.events.source();
|
|
29
|
+
const customResynced = ctx.events.source();
|
|
30
|
+
const metadata = ctx.mirror({
|
|
31
|
+
name: "metadata",
|
|
32
|
+
onDemand: true,
|
|
33
|
+
initial: () => null,
|
|
34
|
+
load: async (doc) => ({ value: await doc.metadata.get() }),
|
|
35
|
+
fold: (value, event) => event.type === "metadata.updated" ? event.metadata : value,
|
|
36
|
+
changed: ({ cause, event, previous, next }) => {
|
|
37
|
+
if (!next) return;
|
|
38
|
+
if (cause === "load") resynced.emit({ metadata: next });
|
|
39
|
+
else if (event && "origin" in event) updated.emit({
|
|
40
|
+
metadata: next,
|
|
41
|
+
previous,
|
|
42
|
+
changedKeys: changedKeys(previous, next),
|
|
43
|
+
origin: event.origin
|
|
33
44
|
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
const custom = ctx.mirror({
|
|
48
|
+
name: "customMetadata",
|
|
49
|
+
onDemand: true,
|
|
50
|
+
initial: () => null,
|
|
51
|
+
load: async (doc) => ({ value: await doc.metadata.custom.get() }),
|
|
52
|
+
fold: (value, event) => event.type === "metadata.customUpdated" ? event.custom : value,
|
|
53
|
+
changed: ({ cause, event, previous, next }) => {
|
|
54
|
+
if (!next) return;
|
|
55
|
+
if (cause === "load") customResynced.emit({ custom: next });
|
|
56
|
+
else if (event && "origin" in event) customUpdated.emit({
|
|
57
|
+
custom: next,
|
|
58
|
+
previous,
|
|
59
|
+
changedKeys: changedKeys(previous, next),
|
|
60
|
+
origin: event.origin
|
|
40
61
|
});
|
|
41
62
|
}
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region src/effects.ts
|
|
46
|
-
/**
|
|
47
|
-
* Makes metadata REACTIVE — the reason this is a plugin, not a kernel IO call.
|
|
48
|
-
*
|
|
49
|
-
* 1. Seed: read the Info dict once when the document opens.
|
|
50
|
-
* 2. Live: subscribe to the document event stream. A `metadata.updated` event
|
|
51
|
-
* carries the full re-read metadata and fires for OWN edits AND for remote
|
|
52
|
-
* edits delivered over SSE (another session) — both just become `setState`.
|
|
53
|
-
*
|
|
54
|
-
* The handle's stream is synchronous fan-out, so this coexists with the kernel's
|
|
55
|
-
* own subscription (page registry) on the same handle.
|
|
56
|
-
*/
|
|
57
|
-
function registerMetadataEffects(ctx) {
|
|
58
|
-
const doc = ctx.doc;
|
|
59
|
-
if (!doc) return;
|
|
60
|
-
doc.metadata.read().then((metadata) => ctx.dispatch({
|
|
61
|
-
type: "SET",
|
|
62
|
-
metadata
|
|
63
|
-
}), () => {});
|
|
64
|
-
const unsubscribe = doc.events.subscribe((event) => {
|
|
65
|
-
if (event.type === "metadata.updated") ctx.dispatch({
|
|
66
|
-
type: "SET",
|
|
67
|
-
metadata: event.metadata
|
|
68
|
-
});
|
|
69
63
|
});
|
|
70
|
-
ctx.
|
|
64
|
+
const canUpdate = () => ctx.allows(METADATA_MODIFY);
|
|
65
|
+
/**
|
|
66
|
+
* Both writes refuse the same way before reaching the engine: the verbs are
|
|
67
|
+
* async, so a refusal rejects, and nothing changes.
|
|
68
|
+
*/
|
|
69
|
+
const refuseWrite = (verb, options) => {
|
|
70
|
+
ctx.assertAllowed(METADATA_MODIFY, verb);
|
|
71
|
+
if (options?.signal?.aborted) throw new PluginError("operation-cancelled", "metadata", `${verb} was cancelled`);
|
|
72
|
+
};
|
|
73
|
+
const customApi = {
|
|
74
|
+
getSnapshot: custom.get,
|
|
75
|
+
getStatus: custom.getStatus,
|
|
76
|
+
update: async (patch, options) => {
|
|
77
|
+
refuseWrite("metadata.custom.update", options);
|
|
78
|
+
return { custom: (await ctx.cancellable(options?.signal, ctx.doc.metadata.custom.update(patch))).custom };
|
|
79
|
+
},
|
|
80
|
+
refresh: (options) => ctx.cancellable(options?.signal, custom.refresh()),
|
|
81
|
+
onUpdated: customUpdated.on,
|
|
82
|
+
onResynced: customResynced.on
|
|
83
|
+
};
|
|
84
|
+
return { api: {
|
|
85
|
+
getSnapshot: metadata.get,
|
|
86
|
+
getStatus: metadata.getStatus,
|
|
87
|
+
ensureLoaded: (options) => ctx.cancellable(options?.signal, Promise.all([metadata.ensureLoaded(), custom.ensureLoaded()]).then(() => void 0)),
|
|
88
|
+
canUpdate,
|
|
89
|
+
update: async (patch, options) => {
|
|
90
|
+
refuseWrite("metadata.update", options);
|
|
91
|
+
return { metadata: (await ctx.cancellable(options?.signal, ctx.doc.metadata.update(patch))).metadata };
|
|
92
|
+
},
|
|
93
|
+
refresh: (options) => ctx.cancellable(options?.signal, metadata.refresh()),
|
|
94
|
+
onUpdated: updated.on,
|
|
95
|
+
onResynced: resynced.on,
|
|
96
|
+
custom: customApi
|
|
97
|
+
} };
|
|
71
98
|
}
|
|
72
99
|
//#endregion
|
|
73
|
-
//#region src/reducer.ts
|
|
74
|
-
const initialMetadataState = () => ({ metadata: null });
|
|
75
|
-
/** Pure. The only transition: replace the metadata snapshot (from a read or an
|
|
76
|
-
* event). */
|
|
77
|
-
const metadataReducer = (state, a) => a.type === "SET" ? {
|
|
78
|
-
...state,
|
|
79
|
-
metadata: a.metadata
|
|
80
|
-
} : state;
|
|
81
|
-
//#endregion
|
|
82
100
|
//#region src/metadata.plugin.ts
|
|
83
|
-
/**
|
|
84
|
-
* Document-scoped metadata plugin: reactive Info-dict state. The effect seeds it
|
|
85
|
-
* from the engine and keeps it live off the document event stream (own + remote
|
|
86
|
-
* SSE edits); the capability is the read/write surface.
|
|
87
|
-
*/
|
|
101
|
+
/** Document-scoped, reactive Info-dict metadata. Takes no configuration. */
|
|
88
102
|
const metadataPlugin = () => definePlugin({
|
|
89
103
|
id: "metadata",
|
|
90
104
|
token: MetadataToken,
|
|
91
105
|
scope: "document",
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
create: createMetadataController
|
|
107
|
+
});
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/state.ts
|
|
110
|
+
/**
|
|
111
|
+
* The metadata page's State table as code: what `useMetadataState()` returns,
|
|
112
|
+
* and the same fields in every other framework. `status` is the standard
|
|
113
|
+
* fields' load state; `custom.getStatus()` has the custom keys' own. Reading
|
|
114
|
+
* the state loads it (`ensure`): the first reader of a document starts the read.
|
|
115
|
+
*/
|
|
116
|
+
const metadataState = defineState(MetadataToken, {
|
|
117
|
+
read: (metadata) => ({
|
|
118
|
+
metadata: metadata.getSnapshot(),
|
|
119
|
+
custom: metadata.custom.getSnapshot(),
|
|
120
|
+
status: metadata.getStatus()
|
|
121
|
+
}),
|
|
122
|
+
empty: {
|
|
123
|
+
metadata: null,
|
|
124
|
+
custom: null,
|
|
125
|
+
status: "idle"
|
|
126
|
+
},
|
|
127
|
+
ensure: (metadata) => metadata.ensureLoaded()
|
|
96
128
|
});
|
|
97
129
|
//#endregion
|
|
98
|
-
export { MetadataToken, metadataPlugin };
|
|
130
|
+
export { MetadataToken, metadataPlugin, metadataState };
|
|
99
131
|
|
|
100
132
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/model.ts","../src/controller.ts","../src/metadata.plugin.ts","../src/state.ts"],"sourcesContent":["/**\n * The keys whose values differ between two snapshots, removed keys included.\n * Both snapshots (the standard fields, the custom keys) hold only strings,\n * `null` and enums, so a shallow compare is exact.\n */\nexport function changedKeys<T extends object>(\n previous: T | null,\n next: T,\n): readonly (keyof T & string)[] {\n const keys = Object.keys(next) as (keyof T & string)[];\n if (!previous) return keys;\n const all = new Set([...(Object.keys(previous) as (keyof T & string)[]), ...keys]);\n return [...all].filter((key) => previous[key] !== next[key]);\n}\n","import {\n PluginError,\n type PluginContext,\n type CustomMetadata,\n type DocCapability,\n type DocumentMetadata,\n type OperationOptions,\n} from '@embedpdf/core';\n\nimport type {\n CustomMetadataCapability,\n CustomMetadataResyncedEvent,\n CustomMetadataUpdatedEvent,\n MetadataCapability,\n MetadataResyncedEvent,\n MetadataUpdatedEvent,\n} from './contract';\nimport { changedKeys } from './model';\n\nconst METADATA_MODIFY: DocCapability = 'doc.metadata.modify';\n\n/**\n * The metadata controller. Both halves of the Info dict are mirrors: each\n * changes only when a load lands or its confirmed document event arrives\n * (`metadata.updated`, `metadata.customUpdated`), whoever caused the edit,\n * and that is also the one place its `onUpdated` and `onResynced` fire.\n * Nothing needs them when a document opens, so they load on demand: the\n * first `ensureLoaded()` (what `metadataState` asks for) reads them.\n */\nexport function createMetadataController(ctx: PluginContext<void>) {\n const updated = ctx.events.source<MetadataUpdatedEvent>();\n const resynced = ctx.events.source<MetadataResyncedEvent>();\n const customUpdated = ctx.events.source<CustomMetadataUpdatedEvent>();\n const customResynced = ctx.events.source<CustomMetadataResyncedEvent>();\n\n const metadata = ctx.mirror<DocumentMetadata | null>({\n name: 'metadata',\n onDemand: true,\n initial: () => null,\n load: async (doc) => ({ value: await doc.metadata.get() }),\n fold: (value, event) => (event.type === 'metadata.updated' ? event.metadata : value),\n changed: ({ cause, event, previous, next }) => {\n if (!next) return;\n if (cause === 'load') {\n resynced.emit({ metadata: next });\n } else if (event && 'origin' in event) {\n updated.emit({\n metadata: next,\n previous,\n changedKeys: changedKeys(previous, next),\n origin: event.origin,\n });\n }\n },\n });\n\n const custom = ctx.mirror<CustomMetadata | null>({\n name: 'customMetadata',\n onDemand: true,\n initial: () => null,\n load: async (doc) => ({ value: await doc.metadata.custom.get() }),\n fold: (value, event) => (event.type === 'metadata.customUpdated' ? event.custom : value),\n changed: ({ cause, event, previous, next }) => {\n if (!next) return;\n if (cause === 'load') {\n customResynced.emit({ custom: next });\n } else if (event && 'origin' in event) {\n customUpdated.emit({\n custom: next,\n previous,\n changedKeys: changedKeys(previous, next),\n origin: event.origin,\n });\n }\n },\n });\n\n const canUpdate = () => ctx.allows(METADATA_MODIFY);\n\n /**\n * Both writes refuse the same way before reaching the engine: the verbs are\n * async, so a refusal rejects, and nothing changes.\n */\n const refuseWrite = (verb: string, options?: OperationOptions): void => {\n ctx.assertAllowed(METADATA_MODIFY, verb);\n if (options?.signal?.aborted) {\n throw new PluginError('operation-cancelled', 'metadata', `${verb} was cancelled`);\n }\n };\n\n const customApi: CustomMetadataCapability = {\n getSnapshot: custom.get,\n getStatus: custom.getStatus,\n update: async (patch, options) => {\n refuseWrite('metadata.custom.update', options);\n const result = await ctx.cancellable(options?.signal, ctx.doc.metadata.custom.update(patch));\n return { custom: result.custom };\n },\n refresh: (options) => ctx.cancellable(options?.signal, custom.refresh()),\n onUpdated: customUpdated.on,\n onResynced: customResynced.on,\n };\n\n const api: MetadataCapability = {\n getSnapshot: metadata.get,\n getStatus: metadata.getStatus,\n ensureLoaded: (options) =>\n ctx.cancellable(\n options?.signal,\n Promise.all([metadata.ensureLoaded(), custom.ensureLoaded()]).then(() => undefined),\n ),\n canUpdate,\n update: async (patch, options) => {\n refuseWrite('metadata.update', options);\n const result = await ctx.cancellable(options?.signal, ctx.doc.metadata.update(patch));\n return { metadata: result.metadata };\n },\n refresh: (options) => ctx.cancellable(options?.signal, metadata.refresh()),\n onUpdated: updated.on,\n onResynced: resynced.on,\n custom: customApi,\n };\n\n return { api };\n}\n","import { definePlugin } from '@embedpdf/core';\n\nimport { MetadataToken } from './contract';\nimport { createMetadataController } from './controller';\n\n/** Document-scoped, reactive Info-dict metadata. Takes no configuration. */\nexport const metadataPlugin = () =>\n definePlugin({\n id: 'metadata',\n token: MetadataToken,\n scope: 'document',\n create: createMetadataController,\n });\n","/**\n * The metadata page's State table as code: what `useMetadataState()` returns,\n * and the same fields in every other framework. `status` is the standard\n * fields' load state; `custom.getStatus()` has the custom keys' own. Reading\n * the state loads it (`ensure`): the first reader of a document starts the read.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { MetadataToken } from './contract';\n\nexport const metadataState = defineState(MetadataToken, {\n read: (metadata) => ({\n metadata: metadata.getSnapshot(),\n custom: metadata.custom.getSnapshot(),\n status: metadata.getStatus(),\n }),\n empty: {\n metadata: null,\n custom: null,\n status: 'idle',\n },\n ensure: (metadata) => metadata.ensureLoaded(),\n});\n"],"mappings":"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"}
|
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.16",
|
|
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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@embedpdf/core": "3.0.0-next.
|
|
25
|
+
"@embedpdf/core": "3.0.0-next.16"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"typescript": "^5.0.0",
|
|
@@ -1,11 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,40 +0,0 @@
|
|
|
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
|
|
@@ -1,40 +0,0 @@
|
|
|
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
|