circuitjson-toolkit 1.2.0 → 1.3.0
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/README.md +25 -6
- package/docs/api.md +28 -5
- package/docs/model-format.md +12 -8
- package/docs/release-notes-v1.2.1.md +26 -0
- package/docs/release-notes-v1.3.0.md +45 -0
- package/docs/testing.md +14 -0
- package/package.json +4 -2
- package/src/core/context/BinaryDataSnapshot.mjs +183 -43
- package/src/core/context/CircuitJsonDocumentContext.mjs +31 -4
- package/src/core/context/CircuitJsonReadOnlyDocument.mjs +22 -9
- package/src/core/context/CircuitJsonValidationProof.mjs +4 -2
- package/src/core/context/ProtectedExtensionBinaryBoundary.mjs +2 -2
- package/src/core/context/StructuredDataSnapshot.mjs +11 -6
- package/src/core/worker/WorkerRequestData.mjs +401 -55
- package/src/core/worker/WorkerResultShape.mjs +222 -0
|
@@ -13,7 +13,7 @@ const METADATA_BUDGETS = new WeakMap()
|
|
|
13
13
|
const EXTENSION_METADATA_LIMITS = Object.freeze({
|
|
14
14
|
label: 'Canonical extension data',
|
|
15
15
|
maxBytes: 128 * 1024 * 1024,
|
|
16
|
-
maxItems:
|
|
16
|
+
maxItems: 4_000_000,
|
|
17
17
|
preserveBinary: true
|
|
18
18
|
})
|
|
19
19
|
const ASSET_SCALAR_FIELDS = new Set([
|
|
@@ -41,9 +41,10 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
41
41
|
* Seals an envelope whose exact model was already deeply frozen by validation.
|
|
42
42
|
* @param {Record<string, any>} document Canonical document envelope.
|
|
43
43
|
* @param {object[]} model Exact deeply frozen model owned by the proof.
|
|
44
|
+
* @param {{ standardBuiltins?: boolean }} [options] Proven metadata provenance.
|
|
44
45
|
* @returns {Record<string, any>} The same read-only envelope.
|
|
45
46
|
*/
|
|
46
|
-
static freezeValidated(document, model) {
|
|
47
|
+
static freezeValidated(document, model, options = {}) {
|
|
47
48
|
if (!CircuitJsonValidationAuthority.permitsSeal(model)) {
|
|
48
49
|
throw new TypeError(
|
|
49
50
|
'Validated document sealing requires an unforgeable validation proof.'
|
|
@@ -76,7 +77,8 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
76
77
|
}
|
|
77
78
|
return CircuitJsonReadOnlyDocument.#freezeDocument(
|
|
78
79
|
document,
|
|
79
|
-
frozenRoots
|
|
80
|
+
frozenRoots,
|
|
81
|
+
options?.standardBuiltins === true
|
|
80
82
|
)
|
|
81
83
|
}
|
|
82
84
|
|
|
@@ -84,14 +86,18 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
84
86
|
* Captures owned boundaries and freezes an envelope with known frozen roots.
|
|
85
87
|
* @param {Record<string, any>} document Canonical document envelope.
|
|
86
88
|
* @param {Set<object>} frozenRoots Deeply frozen roots that need no revisit.
|
|
89
|
+
* @param {boolean} [standardBuiltins] Whether extension built-ins have proven standard prototypes.
|
|
87
90
|
* @returns {Record<string, any>} The same read-only envelope.
|
|
88
91
|
*/
|
|
89
|
-
static #freezeDocument(document, frozenRoots) {
|
|
92
|
+
static #freezeDocument(document, frozenRoots, standardBuiltins = false) {
|
|
90
93
|
const assets = CircuitJsonReadOnlyDocument.#documentAssets(document)
|
|
91
94
|
const metadataState = StructuredDataSnapshot.createState()
|
|
92
95
|
CircuitJsonReadOnlyDocument.#captureAssetData(assets, metadataState)
|
|
93
96
|
const extensions =
|
|
94
|
-
CircuitJsonReadOnlyDocument.#captureDocumentExtensions(
|
|
97
|
+
CircuitJsonReadOnlyDocument.#captureDocumentExtensions(
|
|
98
|
+
document,
|
|
99
|
+
standardBuiltins
|
|
100
|
+
)
|
|
95
101
|
if (extensions && typeof extensions === 'object') {
|
|
96
102
|
frozenRoots.add(extensions)
|
|
97
103
|
}
|
|
@@ -199,9 +205,10 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
199
205
|
* transfer-sized item and byte ceilings.
|
|
200
206
|
* @param {unknown} value Extension candidate.
|
|
201
207
|
* @param {((snapshot: unknown) => unknown) | null} [normalize] Optional normalization over the owned mutable snapshot.
|
|
208
|
+
* @param {{ standardBuiltins?: boolean }} [options] Proven source-graph provenance.
|
|
202
209
|
* @returns {unknown} Deeply immutable owned extension metadata.
|
|
203
210
|
*/
|
|
204
|
-
static copyReadonlyExtensionValue(value, normalize = null) {
|
|
211
|
+
static copyReadonlyExtensionValue(value, normalize = null, options = {}) {
|
|
205
212
|
if (
|
|
206
213
|
value &&
|
|
207
214
|
typeof value === 'object' &&
|
|
@@ -216,7 +223,10 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
216
223
|
}
|
|
217
224
|
const snapshot = StructuredDataSnapshot.capture(
|
|
218
225
|
value,
|
|
219
|
-
StructuredDataSnapshot.createState(
|
|
226
|
+
StructuredDataSnapshot.createState({
|
|
227
|
+
...EXTENSION_METADATA_LIMITS,
|
|
228
|
+
standardBuiltins: options?.standardBuiltins === true
|
|
229
|
+
})
|
|
220
230
|
)
|
|
221
231
|
ProtectedExtensionBinaryBoundary.protect(snapshot)
|
|
222
232
|
const normalized = normalize ? normalize(snapshot) : snapshot
|
|
@@ -327,9 +337,10 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
327
337
|
* Captures an unowned worker or caller extension root with extension-sized
|
|
328
338
|
* bounds before the generic source metadata pass begins.
|
|
329
339
|
* @param {Record<string, any>} document Canonical document envelope.
|
|
340
|
+
* @param {boolean} standardBuiltins Whether extension built-ins have proven standard prototypes.
|
|
330
341
|
* @returns {unknown} Owned extension root or undefined.
|
|
331
342
|
*/
|
|
332
|
-
static #captureDocumentExtensions(document) {
|
|
343
|
+
static #captureDocumentExtensions(document, standardBuiltins) {
|
|
333
344
|
let descriptor
|
|
334
345
|
try {
|
|
335
346
|
descriptor = Object.getOwnPropertyDescriptor(document, 'extensions')
|
|
@@ -345,7 +356,9 @@ export class CircuitJsonReadOnlyDocument {
|
|
|
345
356
|
)
|
|
346
357
|
}
|
|
347
358
|
const captured = CircuitJsonReadOnlyDocument.copyReadonlyExtensionValue(
|
|
348
|
-
descriptor.value
|
|
359
|
+
descriptor.value,
|
|
360
|
+
null,
|
|
361
|
+
{ standardBuiltins }
|
|
349
362
|
)
|
|
350
363
|
if (captured === descriptor.value) return captured
|
|
351
364
|
Object.defineProperty(document, 'extensions', {
|
|
@@ -53,9 +53,10 @@ export class CircuitJsonValidationProof {
|
|
|
53
53
|
/**
|
|
54
54
|
* Validates, freezes, and proves one canonical document envelope.
|
|
55
55
|
* @param {Record<string, any>} document Canonical document envelope.
|
|
56
|
+
* @param {{ standardBuiltins?: boolean }} [options] Proven metadata provenance.
|
|
56
57
|
* @returns {Record<string, any>} The same read-only document envelope.
|
|
57
58
|
*/
|
|
58
|
-
static validateAndAttach(document) {
|
|
59
|
+
static validateAndAttach(document, options = {}) {
|
|
59
60
|
const model = CircuitJsonValidationProof.#requireModelData(document)
|
|
60
61
|
if (!CircuitJsonValidationProof.#matches(document, model)) {
|
|
61
62
|
const errors =
|
|
@@ -80,7 +81,8 @@ export class CircuitJsonValidationProof {
|
|
|
80
81
|
}
|
|
81
82
|
const readonlyDocument = CircuitJsonReadOnlyDocument.freezeValidated(
|
|
82
83
|
document,
|
|
83
|
-
model
|
|
84
|
+
model,
|
|
85
|
+
options
|
|
84
86
|
)
|
|
85
87
|
if (
|
|
86
88
|
CircuitJsonValidationProof.#requireModelData(readonlyDocument) !==
|
|
@@ -12,7 +12,7 @@ export class ProtectedExtensionBinaryBoundary {
|
|
|
12
12
|
* @returns {void}
|
|
13
13
|
*/
|
|
14
14
|
static protect(root) {
|
|
15
|
-
if (BinaryDataSnapshot.
|
|
15
|
+
if (BinaryDataSnapshot.describeStandard(root)) {
|
|
16
16
|
throw new TypeError(
|
|
17
17
|
'Canonical extension root must be a plain data container.'
|
|
18
18
|
)
|
|
@@ -51,7 +51,7 @@ export class ProtectedExtensionBinaryBoundary {
|
|
|
51
51
|
stack.push(child)
|
|
52
52
|
continue
|
|
53
53
|
}
|
|
54
|
-
const binary = BinaryDataSnapshot.
|
|
54
|
+
const binary = BinaryDataSnapshot.describeStandard(child)
|
|
55
55
|
if (!binary) continue
|
|
56
56
|
const ownedBinary = child
|
|
57
57
|
/** @returns {ArrayBuffer | Uint8Array | DataView} A defensive binary copy. */
|
|
@@ -26,8 +26,8 @@ const SET_VALUES = Set.prototype.values
|
|
|
26
26
|
export class StructuredDataSnapshot {
|
|
27
27
|
/**
|
|
28
28
|
* Creates state shared by multiple metadata roots in one request.
|
|
29
|
-
* @param {{ label?: string, maxBytes?: number, maxItems?: number, preserveBinary?: boolean }} [limits] Capture limits.
|
|
30
|
-
* @returns {{ seen: Map<object, unknown>, accounted: Set<object>, bytes: number, items: number, label: string, maxBytes: number, maxItems: number, preserveBinary: boolean }} Capture state.
|
|
29
|
+
* @param {{ label?: string, maxBytes?: number, maxItems?: number, preserveBinary?: boolean, standardBuiltins?: boolean }} [limits] Capture limits and proven graph provenance.
|
|
30
|
+
* @returns {{ seen: Map<object, unknown>, accounted: Set<object>, bytes: number, items: number, label: string, maxBytes: number, maxItems: number, preserveBinary: boolean, standardBuiltins: boolean }} Capture state.
|
|
31
31
|
*/
|
|
32
32
|
static createState(limits = {}) {
|
|
33
33
|
const maxBytes =
|
|
@@ -52,7 +52,8 @@ export class StructuredDataSnapshot {
|
|
|
52
52
|
label: String(limits.label || 'Canonical asset source'),
|
|
53
53
|
maxBytes,
|
|
54
54
|
maxItems,
|
|
55
|
-
preserveBinary: limits.preserveBinary === true
|
|
55
|
+
preserveBinary: limits.preserveBinary === true,
|
|
56
|
+
standardBuiltins: limits.standardBuiltins === true
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
@@ -71,7 +72,8 @@ export class StructuredDataSnapshot {
|
|
|
71
72
|
!Number.isSafeInteger(state.maxBytes) ||
|
|
72
73
|
!Number.isSafeInteger(state.maxItems) ||
|
|
73
74
|
typeof state.label !== 'string' ||
|
|
74
|
-
typeof state.preserveBinary !== 'boolean'
|
|
75
|
+
typeof state.preserveBinary !== 'boolean' ||
|
|
76
|
+
typeof state.standardBuiltins !== 'boolean'
|
|
75
77
|
) {
|
|
76
78
|
throw new TypeError('Invalid source-metadata capture state.')
|
|
77
79
|
}
|
|
@@ -93,7 +95,8 @@ export class StructuredDataSnapshot {
|
|
|
93
95
|
!Number.isSafeInteger(state.maxBytes) ||
|
|
94
96
|
!Number.isSafeInteger(state.maxItems) ||
|
|
95
97
|
typeof state.label !== 'string' ||
|
|
96
|
-
typeof state.preserveBinary !== 'boolean'
|
|
98
|
+
typeof state.preserveBinary !== 'boolean' ||
|
|
99
|
+
typeof state.standardBuiltins !== 'boolean'
|
|
97
100
|
) {
|
|
98
101
|
throw new TypeError('Invalid source-metadata capture state.')
|
|
99
102
|
}
|
|
@@ -224,7 +227,9 @@ export class StructuredDataSnapshot {
|
|
|
224
227
|
if (state.seen.has(value)) return state.seen.get(value)
|
|
225
228
|
StructuredDataSnapshot.#reserve(state, 1)
|
|
226
229
|
|
|
227
|
-
const binary =
|
|
230
|
+
const binary = state.standardBuiltins
|
|
231
|
+
? BinaryDataSnapshot.describeStandard(value)
|
|
232
|
+
: BinaryDataSnapshot.describe(value)
|
|
228
233
|
if (binary) {
|
|
229
234
|
return StructuredDataSnapshot.#binary(value, binary, state)
|
|
230
235
|
}
|