circuitjson-toolkit 1.2.1 → 1.4.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 +57 -0
- package/docs/api.md +106 -0
- package/docs/release-notes-v1.3.0.md +45 -0
- package/docs/release-notes-v1.4.0.md +84 -0
- package/docs/testing.md +14 -0
- package/package.json +4 -2
- package/src/core/Parser.mjs +1 -1
- package/src/core/context/BinaryDataSnapshot.mjs +242 -43
- package/src/core/context/CircuitJsonDocumentContext.mjs +85 -3
- package/src/core/context/CircuitJsonExtensionBoundary.mjs +312 -0
- package/src/core/context/CircuitJsonReadOnlyDocument.mjs +129 -60
- package/src/core/context/CircuitJsonValidationProof.mjs +126 -12
- package/src/core/context/ProtectedExtensionBinaryBoundary.mjs +235 -2
- package/src/core/context/StructuredCloneAdoption.mjs +975 -0
- package/src/core/context/StructuredCloneCollectionNormalizer.mjs +86 -0
- package/src/core/context/StructuredCloneTextAccounting.mjs +55 -0
- package/src/core/context/StructuredDataSnapshot.mjs +64 -6
- package/src/core/contracts/DocumentResult.mjs +38 -6
|
@@ -22,6 +22,10 @@ const TYPED_ARRAY_LENGTH = Object.getOwnPropertyDescriptor(
|
|
|
22
22
|
TYPED_ARRAY_PROTOTYPE,
|
|
23
23
|
'byteLength'
|
|
24
24
|
)?.get
|
|
25
|
+
const TYPED_ARRAY_TAG = Object.getOwnPropertyDescriptor(
|
|
26
|
+
TYPED_ARRAY_PROTOTYPE,
|
|
27
|
+
Symbol.toStringTag
|
|
28
|
+
)?.get
|
|
25
29
|
const DATA_VIEW_BUFFER = Object.getOwnPropertyDescriptor(
|
|
26
30
|
DataView.prototype,
|
|
27
31
|
'buffer'
|
|
@@ -34,7 +38,40 @@ const DATA_VIEW_LENGTH = Object.getOwnPropertyDescriptor(
|
|
|
34
38
|
DataView.prototype,
|
|
35
39
|
'byteLength'
|
|
36
40
|
)?.get
|
|
41
|
+
const ARRAY_BUFFER_IS_VIEW = ArrayBuffer.isView
|
|
42
|
+
const ARRAY_IS_ARRAY = Array.isArray
|
|
43
|
+
const OBJECT_GET_PROTOTYPE_OF = Object.getPrototypeOf
|
|
44
|
+
const REFLECT_APPLY = Reflect.apply
|
|
45
|
+
const ARRAY_BUFFER_PROTOTYPE = ArrayBuffer.prototype
|
|
46
|
+
const SHARED_ARRAY_BUFFER_PROTOTYPE =
|
|
47
|
+
typeof SharedArrayBuffer === 'function' ? SharedArrayBuffer.prototype : null
|
|
48
|
+
const ARRAY_PROTOTYPE = Array.prototype
|
|
49
|
+
const OBJECT_PROTOTYPE = Object.prototype
|
|
50
|
+
const DATE_PROTOTYPE = Date.prototype
|
|
51
|
+
const REGEXP_PROTOTYPE = RegExp.prototype
|
|
52
|
+
const MAP_PROTOTYPE = Map.prototype
|
|
53
|
+
const SET_PROTOTYPE = Set.prototype
|
|
37
54
|
const UINT8_ARRAY_SET = Uint8Array.prototype.set
|
|
55
|
+
const TYPED_ARRAY_CONSTRUCTORS = new Map([
|
|
56
|
+
['Int8Array', Int8Array],
|
|
57
|
+
['Uint8Array', Uint8Array],
|
|
58
|
+
['Uint8ClampedArray', Uint8ClampedArray],
|
|
59
|
+
['Int16Array', Int16Array],
|
|
60
|
+
['Uint16Array', Uint16Array],
|
|
61
|
+
['Int32Array', Int32Array],
|
|
62
|
+
['Uint32Array', Uint32Array],
|
|
63
|
+
...(typeof globalThis.Float16Array === 'function'
|
|
64
|
+
? [['Float16Array', globalThis.Float16Array]]
|
|
65
|
+
: []),
|
|
66
|
+
['Float32Array', Float32Array],
|
|
67
|
+
['Float64Array', Float64Array],
|
|
68
|
+
...(typeof BigInt64Array === 'function'
|
|
69
|
+
? [
|
|
70
|
+
['BigInt64Array', BigInt64Array],
|
|
71
|
+
['BigUint64Array', BigUint64Array]
|
|
72
|
+
]
|
|
73
|
+
: [])
|
|
74
|
+
])
|
|
38
75
|
|
|
39
76
|
/**
|
|
40
77
|
* Reads and copies binary platform objects through captured intrinsic slots.
|
|
@@ -46,6 +83,104 @@ export class BinaryDataSnapshot {
|
|
|
46
83
|
* @returns {{ buffer: ArrayBuffer | SharedArrayBuffer, byteOffset: number, byteLength: number, kind: 'buffer' | 'typed-array' | 'data-view' } | null} Intrinsic binary range.
|
|
47
84
|
*/
|
|
48
85
|
static describe(value) {
|
|
86
|
+
return BinaryDataSnapshot.#describe(value, false)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Describes binary data in a graph whose platform built-ins are proven to
|
|
91
|
+
* have their standard local prototypes.
|
|
92
|
+
* @param {unknown} value Binary candidate from a normalized graph.
|
|
93
|
+
* @returns {{ buffer: ArrayBuffer | SharedArrayBuffer, byteOffset: number, byteLength: number, kind: 'buffer' | 'typed-array' | 'data-view' } | null} Intrinsic binary range.
|
|
94
|
+
*/
|
|
95
|
+
static describeStandard(value) {
|
|
96
|
+
return BinaryDataSnapshot.#describe(value, true)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Classifies one binary candidate with either exact or proven-standard
|
|
101
|
+
* raw-buffer handling.
|
|
102
|
+
* @param {unknown} value Binary candidate.
|
|
103
|
+
* @param {boolean} standardBuiltins Whether local prototype identity is proven.
|
|
104
|
+
* @returns {{ buffer: ArrayBuffer | SharedArrayBuffer, byteOffset: number, byteLength: number, kind: 'buffer' | 'typed-array' | 'data-view' } | null} Intrinsic binary range.
|
|
105
|
+
*/
|
|
106
|
+
static #describe(value, standardBuiltins) {
|
|
107
|
+
if (value === null || typeof value !== 'object') return null
|
|
108
|
+
|
|
109
|
+
if (BinaryDataSnapshot.#isView(value)) {
|
|
110
|
+
const typed = BinaryDataSnapshot.#view(
|
|
111
|
+
value,
|
|
112
|
+
TYPED_ARRAY_BUFFER,
|
|
113
|
+
TYPED_ARRAY_OFFSET,
|
|
114
|
+
TYPED_ARRAY_LENGTH,
|
|
115
|
+
'typed-array'
|
|
116
|
+
)
|
|
117
|
+
if (typed) return typed
|
|
118
|
+
return BinaryDataSnapshot.#view(
|
|
119
|
+
value,
|
|
120
|
+
DATA_VIEW_BUFFER,
|
|
121
|
+
DATA_VIEW_OFFSET,
|
|
122
|
+
DATA_VIEW_LENGTH,
|
|
123
|
+
'data-view'
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!standardBuiltins) {
|
|
128
|
+
return BinaryDataSnapshot.#rawBuffer(value)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let prototype
|
|
132
|
+
try {
|
|
133
|
+
prototype = OBJECT_GET_PROTOTYPE_OF(value)
|
|
134
|
+
} catch {
|
|
135
|
+
return null
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (prototype === ARRAY_BUFFER_PROTOTYPE) {
|
|
139
|
+
const byteLength = BinaryDataSnapshot.#callLength(
|
|
140
|
+
ARRAY_BUFFER_LENGTH,
|
|
141
|
+
value
|
|
142
|
+
)
|
|
143
|
+
return byteLength === null
|
|
144
|
+
? null
|
|
145
|
+
: {
|
|
146
|
+
buffer: value,
|
|
147
|
+
byteOffset: 0,
|
|
148
|
+
byteLength,
|
|
149
|
+
kind: 'buffer'
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (
|
|
153
|
+
SHARED_ARRAY_BUFFER_PROTOTYPE &&
|
|
154
|
+
prototype === SHARED_ARRAY_BUFFER_PROTOTYPE
|
|
155
|
+
) {
|
|
156
|
+
const byteLength = BinaryDataSnapshot.#callLength(
|
|
157
|
+
SHARED_ARRAY_BUFFER_LENGTH,
|
|
158
|
+
value
|
|
159
|
+
)
|
|
160
|
+
return byteLength === null
|
|
161
|
+
? null
|
|
162
|
+
: {
|
|
163
|
+
buffer: value,
|
|
164
|
+
byteOffset: 0,
|
|
165
|
+
byteLength,
|
|
166
|
+
kind: 'buffer'
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (BinaryDataSnapshot.#isKnownNonBinary(value, prototype)) {
|
|
170
|
+
return null
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Unknown prototypes can represent genuine buffers from another realm.
|
|
174
|
+
// Keep intrinsic brand checks as the authority for that uncommon path.
|
|
175
|
+
return BinaryDataSnapshot.#rawBuffer(value)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Applies exact raw ArrayBuffer and SharedArrayBuffer brand getters.
|
|
180
|
+
* @param {object} value Raw-buffer candidate.
|
|
181
|
+
* @returns {{ buffer: ArrayBuffer | SharedArrayBuffer, byteOffset: 0, byteLength: number, kind: 'buffer' } | null} Raw buffer range.
|
|
182
|
+
*/
|
|
183
|
+
static #rawBuffer(value) {
|
|
49
184
|
const arrayBufferLength = BinaryDataSnapshot.#callLength(
|
|
50
185
|
ARRAY_BUFFER_LENGTH,
|
|
51
186
|
value
|
|
@@ -71,21 +206,7 @@ export class BinaryDataSnapshot {
|
|
|
71
206
|
}
|
|
72
207
|
}
|
|
73
208
|
|
|
74
|
-
|
|
75
|
-
value,
|
|
76
|
-
TYPED_ARRAY_BUFFER,
|
|
77
|
-
TYPED_ARRAY_OFFSET,
|
|
78
|
-
TYPED_ARRAY_LENGTH,
|
|
79
|
-
'typed-array'
|
|
80
|
-
)
|
|
81
|
-
if (typed) return typed
|
|
82
|
-
return BinaryDataSnapshot.#view(
|
|
83
|
-
value,
|
|
84
|
-
DATA_VIEW_BUFFER,
|
|
85
|
-
DATA_VIEW_OFFSET,
|
|
86
|
-
DATA_VIEW_LENGTH,
|
|
87
|
-
'data-view'
|
|
88
|
-
)
|
|
209
|
+
return null
|
|
89
210
|
}
|
|
90
211
|
|
|
91
212
|
/**
|
|
@@ -120,6 +241,44 @@ export class BinaryDataSnapshot {
|
|
|
120
241
|
}
|
|
121
242
|
}
|
|
122
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Copies one bounded byte range into an existing isolated byte array.
|
|
246
|
+
* @param {{ buffer: ArrayBuffer | SharedArrayBuffer, byteOffset: number, byteLength: number }} range Captured intrinsic range.
|
|
247
|
+
* @param {Uint8Array} target Isolated destination bytes.
|
|
248
|
+
* @param {number} offset Visible-range byte offset.
|
|
249
|
+
* @param {number} count Number of bytes to copy.
|
|
250
|
+
* @returns {void}
|
|
251
|
+
* @internal
|
|
252
|
+
*/
|
|
253
|
+
static copyBytesInto(range, target, offset, count) {
|
|
254
|
+
if (
|
|
255
|
+
!(target instanceof Uint8Array) ||
|
|
256
|
+
!Number.isSafeInteger(offset) ||
|
|
257
|
+
!Number.isSafeInteger(count) ||
|
|
258
|
+
offset < 0 ||
|
|
259
|
+
count < 0 ||
|
|
260
|
+
offset + count > range?.byteLength ||
|
|
261
|
+
target.byteLength !== range?.byteLength
|
|
262
|
+
) {
|
|
263
|
+
throw new TypeError('Invalid binary copy range.')
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const source = new Uint8Array(
|
|
267
|
+
range.buffer,
|
|
268
|
+
range.byteOffset + offset,
|
|
269
|
+
count
|
|
270
|
+
)
|
|
271
|
+
const destination = new Uint8Array(
|
|
272
|
+
target.buffer,
|
|
273
|
+
target.byteOffset + offset,
|
|
274
|
+
count
|
|
275
|
+
)
|
|
276
|
+
UINT8_ARRAY_SET.call(destination, source)
|
|
277
|
+
} catch {
|
|
278
|
+
throw new TypeError('Binary data changed during capture.')
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
123
282
|
/**
|
|
124
283
|
* Copies one binary metadata value while retaining its common view type.
|
|
125
284
|
* @param {unknown} value Binary metadata.
|
|
@@ -133,8 +292,28 @@ export class BinaryDataSnapshot {
|
|
|
133
292
|
if (range.kind === 'buffer') return bytes.buffer
|
|
134
293
|
if (range.kind === 'data-view') return new DataView(bytes.buffer)
|
|
135
294
|
|
|
136
|
-
const
|
|
137
|
-
|
|
295
|
+
const Constructor = BinaryDataSnapshot.#typedArrayConstructor(value)
|
|
296
|
+
if (!Constructor || Constructor === Uint8Array) return bytes
|
|
297
|
+
const bytesPerElement = Constructor.BYTES_PER_ELEMENT
|
|
298
|
+
if (bytes.byteLength % bytesPerElement !== 0) return bytes
|
|
299
|
+
return new Constructor(bytes.buffer)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Restores one common binary view type from completely isolated bytes.
|
|
304
|
+
* @param {unknown} value Original binary value used only for view type.
|
|
305
|
+
* @param {{ kind: 'buffer' | 'typed-array' | 'data-view' }} range Captured intrinsic kind.
|
|
306
|
+
* @param {Uint8Array} bytes Completely copied isolated bytes.
|
|
307
|
+
* @returns {ArrayBuffer | Uint8Array | DataView} Isolated binary clone.
|
|
308
|
+
* @internal
|
|
309
|
+
*/
|
|
310
|
+
static cloneFromBytes(value, range, bytes) {
|
|
311
|
+
if (!(bytes instanceof Uint8Array)) {
|
|
312
|
+
throw new TypeError('Expected isolated binary bytes.')
|
|
313
|
+
}
|
|
314
|
+
if (range.kind === 'buffer') return bytes.buffer
|
|
315
|
+
if (range.kind === 'data-view') return new DataView(bytes.buffer)
|
|
316
|
+
const Constructor = BinaryDataSnapshot.#typedArrayConstructor(value)
|
|
138
317
|
if (!Constructor || Constructor === Uint8Array) return bytes
|
|
139
318
|
const bytesPerElement = Constructor.BYTES_PER_ELEMENT
|
|
140
319
|
if (bytes.byteLength % bytesPerElement !== 0) return bytes
|
|
@@ -150,12 +329,44 @@ export class BinaryDataSnapshot {
|
|
|
150
329
|
static #callLength(getter, value) {
|
|
151
330
|
if (typeof getter !== 'function') return null
|
|
152
331
|
try {
|
|
153
|
-
return getter
|
|
332
|
+
return REFLECT_APPLY(getter, value, [])
|
|
154
333
|
} catch {
|
|
155
334
|
return null
|
|
156
335
|
}
|
|
157
336
|
}
|
|
158
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Uses the platform's side-effect-free view brand classifier.
|
|
340
|
+
* @param {unknown} value Candidate value.
|
|
341
|
+
* @returns {boolean} Whether the value has ArrayBuffer view slots.
|
|
342
|
+
*/
|
|
343
|
+
static #isView(value) {
|
|
344
|
+
try {
|
|
345
|
+
return REFLECT_APPLY(ARRAY_BUFFER_IS_VIEW, ArrayBuffer, [value])
|
|
346
|
+
} catch {
|
|
347
|
+
return false
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Returns true for common local containers that cannot be binary objects.
|
|
353
|
+
* @param {object} value Candidate object.
|
|
354
|
+
* @param {object | null} prototype Captured prototype.
|
|
355
|
+
* @returns {boolean} Whether intrinsic buffer probing can be skipped.
|
|
356
|
+
*/
|
|
357
|
+
static #isKnownNonBinary(value, prototype) {
|
|
358
|
+
return (
|
|
359
|
+
ARRAY_IS_ARRAY(value) ||
|
|
360
|
+
prototype === ARRAY_PROTOTYPE ||
|
|
361
|
+
prototype === OBJECT_PROTOTYPE ||
|
|
362
|
+
prototype === null ||
|
|
363
|
+
prototype === DATE_PROTOTYPE ||
|
|
364
|
+
prototype === REGEXP_PROTOTYPE ||
|
|
365
|
+
prototype === MAP_PROTOTYPE ||
|
|
366
|
+
prototype === SET_PROTOTYPE
|
|
367
|
+
)
|
|
368
|
+
}
|
|
369
|
+
|
|
159
370
|
/**
|
|
160
371
|
* Reads captured intrinsic view slots without ordinary property access.
|
|
161
372
|
* @param {unknown} value View candidate.
|
|
@@ -175,9 +386,9 @@ export class BinaryDataSnapshot {
|
|
|
175
386
|
}
|
|
176
387
|
try {
|
|
177
388
|
return {
|
|
178
|
-
buffer: bufferGetter
|
|
179
|
-
byteOffset: offsetGetter
|
|
180
|
-
byteLength: lengthGetter
|
|
389
|
+
buffer: REFLECT_APPLY(bufferGetter, value, []),
|
|
390
|
+
byteOffset: REFLECT_APPLY(offsetGetter, value, []),
|
|
391
|
+
byteLength: REFLECT_APPLY(lengthGetter, value, []),
|
|
181
392
|
kind
|
|
182
393
|
}
|
|
183
394
|
} catch {
|
|
@@ -186,30 +397,18 @@ export class BinaryDataSnapshot {
|
|
|
186
397
|
}
|
|
187
398
|
|
|
188
399
|
/**
|
|
189
|
-
* Maps a genuine typed
|
|
190
|
-
* @param {
|
|
400
|
+
* Maps a genuine typed array's intrinsic tag to a local constructor.
|
|
401
|
+
* @param {unknown} value Genuine typed-array value.
|
|
191
402
|
* @returns {Function | null} Matching typed-array constructor.
|
|
192
403
|
*/
|
|
193
|
-
static #typedArrayConstructor(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
Uint32Array,
|
|
202
|
-
Float32Array,
|
|
203
|
-
Float64Array,
|
|
204
|
-
...(typeof BigInt64Array === 'function'
|
|
205
|
-
? [BigInt64Array, BigUint64Array]
|
|
206
|
-
: [])
|
|
207
|
-
]
|
|
208
|
-
return (
|
|
209
|
-
constructors.find(
|
|
210
|
-
(Constructor) => Constructor.prototype === prototype
|
|
211
|
-
) || null
|
|
212
|
-
)
|
|
404
|
+
static #typedArrayConstructor(value) {
|
|
405
|
+
if (typeof TYPED_ARRAY_TAG !== 'function') return null
|
|
406
|
+
try {
|
|
407
|
+
const tag = REFLECT_APPLY(TYPED_ARRAY_TAG, value, [])
|
|
408
|
+
return TYPED_ARRAY_CONSTRUCTORS.get(tag) || null
|
|
409
|
+
} catch {
|
|
410
|
+
return null
|
|
411
|
+
}
|
|
213
412
|
}
|
|
214
413
|
}
|
|
215
414
|
|
|
@@ -74,9 +74,56 @@ export class CircuitJsonDocumentContext {
|
|
|
74
74
|
* @returns {CircuitJsonDocumentContext} Prepared request-scoped context.
|
|
75
75
|
*/
|
|
76
76
|
static prepare(input, options = {}) {
|
|
77
|
+
return CircuitJsonDocumentContext.#prepare(input, options, false)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Prepares a document whose platform built-ins were normalized by the
|
|
82
|
+
* structured-clone algorithm.
|
|
83
|
+
* @param {unknown} input Structured-cloned document result or existing context.
|
|
84
|
+
* @param {{ indexes?: unknown }} [options] Requested context options.
|
|
85
|
+
* @returns {CircuitJsonDocumentContext} Prepared request-scoped context.
|
|
86
|
+
*/
|
|
87
|
+
static prepareStructuredClone(input, options = {}) {
|
|
88
|
+
return CircuitJsonDocumentContext.#prepare(input, options, true)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Destructively adopts an exclusively transferred structured-clone graph
|
|
93
|
+
* while allowing hosts to service input and paint between bounded slices.
|
|
94
|
+
* @param {unknown} input Structured-cloned document result or existing context.
|
|
95
|
+
* @param {{ indexes?: unknown, ownership: 'exclusive', yield?: () => Promise<void> | void }} [options] Requested indexes, required exclusive ownership authority, and host scheduler.
|
|
96
|
+
* @returns {Promise<CircuitJsonDocumentContext>} Prepared request-scoped context.
|
|
97
|
+
*/
|
|
98
|
+
static async prepareStructuredCloneAsync(input, options = {}) {
|
|
99
|
+
if (CircuitJsonDocumentContext.#isContext(input)) {
|
|
100
|
+
return CircuitJsonDocumentContext.#prepare(input, options, true)
|
|
101
|
+
}
|
|
102
|
+
if (options?.ownership !== 'exclusive') {
|
|
103
|
+
throw new TypeError(
|
|
104
|
+
'Cooperative structured-clone preparation requires exclusive ownership.'
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
const context = await CircuitJsonDocumentContext.#fromInputAsync(
|
|
108
|
+
input,
|
|
109
|
+
true,
|
|
110
|
+
options?.yield
|
|
111
|
+
)
|
|
112
|
+
context.#indexes.ensure(options?.indexes || [])
|
|
113
|
+
return context
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Prepares one context with explicit metadata provenance.
|
|
118
|
+
* @param {unknown} input Document result, CircuitJSON model, or context.
|
|
119
|
+
* @param {{ indexes?: unknown }} options Requested context options.
|
|
120
|
+
* @param {boolean} standardBuiltins Whether metadata built-ins have standard local prototypes.
|
|
121
|
+
* @returns {CircuitJsonDocumentContext} Prepared request-scoped context.
|
|
122
|
+
*/
|
|
123
|
+
static #prepare(input, options, standardBuiltins) {
|
|
77
124
|
const context = CircuitJsonDocumentContext.#isContext(input)
|
|
78
125
|
? input
|
|
79
|
-
: CircuitJsonDocumentContext.#fromInput(input)
|
|
126
|
+
: CircuitJsonDocumentContext.#fromInput(input, standardBuiltins)
|
|
80
127
|
context.#indexes.ensure(options?.indexes || [])
|
|
81
128
|
return context
|
|
82
129
|
}
|
|
@@ -181,15 +228,50 @@ export class CircuitJsonDocumentContext {
|
|
|
181
228
|
/**
|
|
182
229
|
* Creates one context and establishes a matching immutable model proof.
|
|
183
230
|
* @param {unknown} input Document result or CircuitJSON model.
|
|
231
|
+
* @param {boolean} standardBuiltins Whether metadata built-ins have standard local prototypes.
|
|
184
232
|
* @returns {CircuitJsonDocumentContext} New context.
|
|
185
233
|
*/
|
|
186
|
-
static #fromInput(input) {
|
|
234
|
+
static #fromInput(input, standardBuiltins) {
|
|
235
|
+
const document = CircuitJsonDocumentContext.#normalizeDocument(input)
|
|
236
|
+
const validationPasses = CircuitJsonValidationProof.has(document)
|
|
237
|
+
? 0
|
|
238
|
+
: 1
|
|
239
|
+
const readonlyDocument = CircuitJsonValidationProof.validateAndAttach(
|
|
240
|
+
document,
|
|
241
|
+
{
|
|
242
|
+
standardBuiltins
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
const model = CircuitJsonDocumentContext.#ownData(
|
|
246
|
+
readonlyDocument,
|
|
247
|
+
'model'
|
|
248
|
+
)
|
|
249
|
+
return new CircuitJsonDocumentContext(
|
|
250
|
+
readonlyDocument,
|
|
251
|
+
model,
|
|
252
|
+
validationPasses,
|
|
253
|
+
CONTEXT_CONSTRUCTION_AUTHORITY
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Creates one context while yielding between model validation and envelope
|
|
259
|
+
* sealing for a proven structured-clone graph.
|
|
260
|
+
* @param {unknown} input Document result or CircuitJSON model.
|
|
261
|
+
* @param {boolean} standardBuiltins Whether metadata built-ins have standard local prototypes.
|
|
262
|
+
* @param {(() => Promise<void> | void) | undefined} yieldControl Host scheduler.
|
|
263
|
+
* @returns {Promise<CircuitJsonDocumentContext>} New context.
|
|
264
|
+
*/
|
|
265
|
+
static async #fromInputAsync(input, standardBuiltins, yieldControl) {
|
|
187
266
|
const document = CircuitJsonDocumentContext.#normalizeDocument(input)
|
|
188
267
|
const validationPasses = CircuitJsonValidationProof.has(document)
|
|
189
268
|
? 0
|
|
190
269
|
: 1
|
|
191
270
|
const readonlyDocument =
|
|
192
|
-
CircuitJsonValidationProof.
|
|
271
|
+
await CircuitJsonValidationProof.validateAndAttachAsync(document, {
|
|
272
|
+
standardBuiltins,
|
|
273
|
+
yield: yieldControl
|
|
274
|
+
})
|
|
193
275
|
const model = CircuitJsonDocumentContext.#ownData(
|
|
194
276
|
readonlyDocument,
|
|
195
277
|
'model'
|