circuitjson-toolkit 1.3.0 → 1.4.1

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.
@@ -88,6 +88,31 @@ export class CircuitJsonDocumentContext {
88
88
  return CircuitJsonDocumentContext.#prepare(input, options, true)
89
89
  }
90
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
+
91
116
  /**
92
117
  * Prepares one context with explicit metadata provenance.
93
118
  * @param {unknown} input Document result, CircuitJSON model, or context.
@@ -229,6 +254,36 @@ export class CircuitJsonDocumentContext {
229
254
  )
230
255
  }
231
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) {
266
+ const document = CircuitJsonDocumentContext.#normalizeDocument(input)
267
+ const validationPasses = CircuitJsonValidationProof.has(document)
268
+ ? 0
269
+ : 1
270
+ const readonlyDocument =
271
+ await CircuitJsonValidationProof.validateAndAttachAsync(document, {
272
+ standardBuiltins,
273
+ yield: yieldControl
274
+ })
275
+ const model = CircuitJsonDocumentContext.#ownData(
276
+ readonlyDocument,
277
+ 'model'
278
+ )
279
+ return new CircuitJsonDocumentContext(
280
+ readonlyDocument,
281
+ model,
282
+ validationPasses,
283
+ CONTEXT_CONSTRUCTION_AUTHORITY
284
+ )
285
+ }
286
+
232
287
  /**
233
288
  * Normalizes supported context input into a canonical document envelope.
234
289
  * @param {unknown} input Document result or CircuitJSON model.
@@ -0,0 +1,312 @@
1
+ import { BinaryDataSnapshot } from './BinaryDataSnapshot.mjs'
2
+ import { ProtectedExtensionBinaryBoundary } from './ProtectedExtensionBinaryBoundary.mjs'
3
+ import { StructuredDataSnapshot } from './StructuredDataSnapshot.mjs'
4
+
5
+ const OWNED_EXTENSION_ROOTS = new WeakSet()
6
+ const EXTENSION_METADATA_LIMITS = Object.freeze({
7
+ label: 'Canonical extension data',
8
+ maxBytes: 128 * 1024 * 1024,
9
+ maxItems: 4_000_000,
10
+ preserveBinary: true
11
+ })
12
+
13
+ /**
14
+ * Owns and seals canonical extension graphs independently of document fields.
15
+ */
16
+ export class CircuitJsonExtensionBoundary {
17
+ /**
18
+ * Returns whether an object is an already owned extension root.
19
+ * @param {unknown} value Extension candidate.
20
+ * @returns {boolean} Whether this boundary owns the root.
21
+ */
22
+ static owns(value) {
23
+ return Boolean(
24
+ value &&
25
+ typeof value === 'object' &&
26
+ OWNED_EXTENSION_ROOTS.has(value)
27
+ )
28
+ }
29
+
30
+ /**
31
+ * Creates one deeply frozen source-extension snapshot.
32
+ * @param {unknown} value Extension candidate.
33
+ * @param {((snapshot: unknown) => unknown) | null} [normalize] Optional normalizer.
34
+ * @param {{ standardBuiltins?: boolean }} [options] Proven graph provenance.
35
+ * @returns {unknown} Deeply immutable owned extension metadata.
36
+ */
37
+ static copyReadonly(value, normalize = null, options = {}) {
38
+ if (
39
+ CircuitJsonExtensionBoundary.owns(value) &&
40
+ Object.isFrozen(value) &&
41
+ normalize === null
42
+ ) {
43
+ return value
44
+ }
45
+ if (normalize !== null && typeof normalize !== 'function') {
46
+ throw new TypeError('Extension normalizer must be a function.')
47
+ }
48
+ const standardBuiltins = options?.standardBuiltins === true
49
+ const state = StructuredDataSnapshot.createState({
50
+ ...EXTENSION_METADATA_LIMITS,
51
+ standardBuiltins
52
+ })
53
+ const snapshot = standardBuiltins
54
+ ? StructuredDataSnapshot.adoptStructuredClone(value, state)
55
+ : StructuredDataSnapshot.capture(value, state)
56
+ CircuitJsonExtensionBoundary.#rejectBinaryRoot(snapshot)
57
+ const adoption = standardBuiltins
58
+ ? StructuredDataSnapshot.consumeStructuredCloneAdoption(snapshot)
59
+ : null
60
+ if (adoption && normalize === null) {
61
+ StructuredDataSnapshot.sealStructuredCloneAdoption(adoption)
62
+ } else {
63
+ ProtectedExtensionBinaryBoundary.protect(snapshot)
64
+ }
65
+ const normalized = normalize ? normalize(snapshot) : snapshot
66
+ if (normalized !== snapshot) {
67
+ ProtectedExtensionBinaryBoundary.protect(normalized)
68
+ }
69
+ if (!adoption || normalize !== null) {
70
+ CircuitJsonExtensionBoundary.#freezeValue(normalized)
71
+ }
72
+ CircuitJsonExtensionBoundary.#markOwned(normalized)
73
+ return normalized
74
+ }
75
+
76
+ /**
77
+ * Cooperatively adopts one structured-clone extension graph.
78
+ * @param {unknown} value Extension candidate.
79
+ * @param {{ standardBuiltins?: boolean, yield: () => Promise<void> | void }} options Proven provenance and host scheduler.
80
+ * @returns {Promise<unknown>} Deeply immutable owned extension metadata.
81
+ */
82
+ static async copyReadonlyAsync(value, options) {
83
+ if (
84
+ CircuitJsonExtensionBoundary.owns(value) &&
85
+ Object.isFrozen(value)
86
+ ) {
87
+ return value
88
+ }
89
+ if (
90
+ options?.standardBuiltins !== true ||
91
+ typeof options?.yield !== 'function'
92
+ ) {
93
+ return CircuitJsonExtensionBoundary.copyReadonly(
94
+ value,
95
+ null,
96
+ options
97
+ )
98
+ }
99
+ const state = StructuredDataSnapshot.createState({
100
+ ...EXTENSION_METADATA_LIMITS,
101
+ standardBuiltins: true
102
+ })
103
+ const snapshot = await StructuredDataSnapshot.adoptStructuredCloneAsync(
104
+ value,
105
+ state,
106
+ options.yield
107
+ )
108
+ CircuitJsonExtensionBoundary.#rejectBinaryRoot(snapshot)
109
+ CircuitJsonExtensionBoundary.#markOwned(snapshot)
110
+ return snapshot
111
+ }
112
+
113
+ /**
114
+ * Captures one document extension field synchronously.
115
+ * @param {Record<string, any>} document Canonical document envelope.
116
+ * @param {boolean} standardBuiltins Whether built-ins have local prototypes.
117
+ * @returns {unknown} Owned extension root or undefined.
118
+ */
119
+ static captureDocument(document, standardBuiltins) {
120
+ const descriptor =
121
+ CircuitJsonExtensionBoundary.#documentDescriptor(document)
122
+ if (!descriptor) return undefined
123
+ const captured = CircuitJsonExtensionBoundary.copyReadonly(
124
+ descriptor.value,
125
+ null,
126
+ { standardBuiltins }
127
+ )
128
+ if (captured === descriptor.value) return captured
129
+ Object.defineProperty(document, 'extensions', {
130
+ ...descriptor,
131
+ value: captured
132
+ })
133
+ return captured
134
+ }
135
+
136
+ /**
137
+ * Cooperatively captures a document extension field and rejects replacement
138
+ * races across scheduling boundaries.
139
+ * @param {Record<string, any>} document Canonical document envelope.
140
+ * @param {boolean} standardBuiltins Whether built-ins have local prototypes.
141
+ * @param {() => Promise<void> | void} yieldControl Host scheduler.
142
+ * @returns {Promise<unknown>} Owned extension root or undefined.
143
+ */
144
+ static async captureDocumentAsync(
145
+ document,
146
+ standardBuiltins,
147
+ yieldControl
148
+ ) {
149
+ const descriptor =
150
+ CircuitJsonExtensionBoundary.#documentDescriptor(document)
151
+ if (!descriptor) return undefined
152
+ const captured = await CircuitJsonExtensionBoundary.copyReadonlyAsync(
153
+ descriptor.value,
154
+ {
155
+ standardBuiltins,
156
+ yield: yieldControl
157
+ }
158
+ )
159
+ const current =
160
+ CircuitJsonExtensionBoundary.#documentDescriptor(document)
161
+ if (
162
+ !current ||
163
+ !CircuitJsonExtensionBoundary.#sameDataDescriptor(
164
+ current,
165
+ descriptor
166
+ )
167
+ ) {
168
+ throw new TypeError(
169
+ 'Canonical document extensions changed during adoption.'
170
+ )
171
+ }
172
+ if (captured === descriptor.value) return captured
173
+ Object.defineProperty(document, 'extensions', {
174
+ ...descriptor,
175
+ value: captured
176
+ })
177
+ return captured
178
+ }
179
+
180
+ /**
181
+ * Reads and validates the optional document extension descriptor.
182
+ * @param {Record<string, any>} document Canonical document envelope.
183
+ * @returns {PropertyDescriptor | undefined} Extension descriptor.
184
+ */
185
+ static #documentDescriptor(document) {
186
+ let descriptor
187
+ try {
188
+ descriptor = Object.getOwnPropertyDescriptor(document, 'extensions')
189
+ } catch {
190
+ throw new TypeError(
191
+ 'Canonical document extensions could not be inspected safely.'
192
+ )
193
+ }
194
+ if (descriptor && !Object.hasOwn(descriptor, 'value')) {
195
+ throw new TypeError(
196
+ 'Canonical document extensions must be an own data property.'
197
+ )
198
+ }
199
+ return descriptor
200
+ }
201
+
202
+ /**
203
+ * Rejects unsupported binary extension roots.
204
+ * @param {unknown} value Extension root.
205
+ * @returns {void}
206
+ */
207
+ static #rejectBinaryRoot(value) {
208
+ if (BinaryDataSnapshot.describeStandard(value)) {
209
+ throw new TypeError(
210
+ 'Canonical extension root must be a plain data container.'
211
+ )
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Marks one object root as owned by this boundary.
217
+ * @param {unknown} value Extension root.
218
+ * @returns {void}
219
+ */
220
+ static #markOwned(value) {
221
+ if (value && typeof value === 'object') {
222
+ OWNED_EXTENSION_ROOTS.add(value)
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Deeply freezes one captured plain-data graph.
228
+ * @param {unknown} value Captured graph.
229
+ * @returns {void}
230
+ */
231
+ static #freezeValue(value) {
232
+ const seen = new Set()
233
+ const stack = [{ exit: false, value }]
234
+ while (stack.length) {
235
+ const frame = stack.pop()
236
+ const current = frame.value
237
+ if (frame.exit) {
238
+ try {
239
+ Object.freeze(current)
240
+ } catch {
241
+ throw new TypeError(
242
+ 'Canonical document values could not be frozen safely.'
243
+ )
244
+ }
245
+ continue
246
+ }
247
+ if (!CircuitJsonExtensionBoundary.#container(current)) continue
248
+ if (seen.has(current)) continue
249
+ seen.add(current)
250
+ let descriptors
251
+ try {
252
+ descriptors = Object.getOwnPropertyDescriptors(current)
253
+ } catch {
254
+ throw new TypeError(
255
+ 'Canonical document values could not be inspected safely.'
256
+ )
257
+ }
258
+ const children = []
259
+ for (const descriptor of Object.values(descriptors)) {
260
+ if (!Object.hasOwn(descriptor, 'value')) {
261
+ if (
262
+ ProtectedExtensionBinaryBoundary.isProtected(descriptor)
263
+ ) {
264
+ continue
265
+ }
266
+ throw new TypeError(
267
+ 'Canonical document may contain only data properties.'
268
+ )
269
+ }
270
+ children.push(descriptor.value)
271
+ }
272
+ stack.push({ exit: true, value: current })
273
+ for (let index = children.length - 1; index >= 0; index -= 1) {
274
+ stack.push({ exit: false, value: children[index] })
275
+ }
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Returns true for plain extension containers.
281
+ * @param {unknown} value Candidate value.
282
+ * @returns {boolean} Whether the value is a plain container.
283
+ */
284
+ static #container(value) {
285
+ if (!value || typeof value !== 'object') return false
286
+ if (Array.isArray(value)) {
287
+ return Object.getPrototypeOf(value) === Array.prototype
288
+ }
289
+ const prototype = Object.getPrototypeOf(value)
290
+ return prototype === Object.prototype || prototype === null
291
+ }
292
+
293
+ /**
294
+ * Compares exact ordinary data descriptor semantics.
295
+ * @param {PropertyDescriptor} current Current descriptor.
296
+ * @param {PropertyDescriptor} expected Captured descriptor.
297
+ * @returns {boolean} Whether both descriptors match.
298
+ */
299
+ static #sameDataDescriptor(current, expected) {
300
+ return Boolean(
301
+ Object.hasOwn(current, 'value') &&
302
+ Object.hasOwn(expected, 'value') &&
303
+ Object.is(current.value, expected.value) &&
304
+ current.configurable === expected.configurable &&
305
+ current.enumerable === expected.enumerable &&
306
+ current.writable === expected.writable
307
+ )
308
+ }
309
+ }
310
+
311
+ Object.freeze(CircuitJsonExtensionBoundary.prototype)
312
+ Object.freeze(CircuitJsonExtensionBoundary)
@@ -1,4 +1,5 @@
1
1
  import { BinaryDataSnapshot } from './BinaryDataSnapshot.mjs'
2
+ import { CircuitJsonExtensionBoundary } from './CircuitJsonExtensionBoundary.mjs'
2
3
  import { CircuitJsonMetadataBoundary } from './CircuitJsonMetadataBoundary.mjs'
3
4
  import { CircuitJsonValidationAuthority } from './CircuitJsonValidationAuthority.mjs'
4
5
  import { ProtectedExtensionBinaryBoundary } from './ProtectedExtensionBinaryBoundary.mjs'
@@ -10,12 +11,6 @@ const SEALED_ASSETS = new WeakSet()
10
11
  const ASSET_PAYLOAD_LENGTHS = new WeakMap()
11
12
  const OWNED_METADATA_ROOTS = new WeakSet()
12
13
  const METADATA_BUDGETS = new WeakMap()
13
- const EXTENSION_METADATA_LIMITS = Object.freeze({
14
- label: 'Canonical extension data',
15
- maxBytes: 128 * 1024 * 1024,
16
- maxItems: 4_000_000,
17
- preserveBinary: true
18
- })
19
14
  const ASSET_SCALAR_FIELDS = new Set([
20
15
  'id',
21
16
  'kind',
@@ -82,6 +77,53 @@ export class CircuitJsonReadOnlyDocument {
82
77
  )
83
78
  }
84
79
 
80
+ /**
81
+ * Cooperatively seals an envelope whose exact model is already validated.
82
+ * @param {Record<string, any>} document Canonical document envelope.
83
+ * @param {object[]} model Exact deeply frozen model owned by the proof.
84
+ * @param {{ standardBuiltins?: boolean, yield: () => Promise<void> | void }} options Proven provenance and host scheduler.
85
+ * @returns {Promise<Record<string, any>>} The same read-only envelope.
86
+ */
87
+ static async freezeValidatedAsync(document, model, options) {
88
+ if (!CircuitJsonValidationAuthority.permitsSeal(model)) {
89
+ throw new TypeError(
90
+ 'Validated document sealing requires an unforgeable validation proof.'
91
+ )
92
+ }
93
+ const descriptor = Object.getOwnPropertyDescriptor(document, 'model')
94
+ if (
95
+ !descriptor ||
96
+ !Object.hasOwn(descriptor, 'value') ||
97
+ descriptor.value !== model ||
98
+ !Array.isArray(model) ||
99
+ !Object.isFrozen(model) ||
100
+ typeof options?.yield !== 'function'
101
+ ) {
102
+ throw new TypeError(
103
+ 'Validated document sealing requires its exact frozen model.'
104
+ )
105
+ }
106
+ const frozenRoots = new Set([model])
107
+ const sourceReference = Object.getOwnPropertyDescriptor(
108
+ document,
109
+ 'sourceReference'
110
+ )
111
+ if (
112
+ sourceReference &&
113
+ Object.hasOwn(sourceReference, 'value') &&
114
+ sourceReference.value &&
115
+ typeof sourceReference.value === 'object'
116
+ ) {
117
+ frozenRoots.add(sourceReference.value)
118
+ }
119
+ return CircuitJsonReadOnlyDocument.#freezeDocumentAsync(
120
+ document,
121
+ frozenRoots,
122
+ options?.standardBuiltins === true,
123
+ options.yield
124
+ )
125
+ }
126
+
85
127
  /**
86
128
  * Captures owned boundaries and freezes an envelope with known frozen roots.
87
129
  * @param {Record<string, any>} document Canonical document envelope.
@@ -111,6 +153,43 @@ export class CircuitJsonReadOnlyDocument {
111
153
  return document
112
154
  }
113
155
 
156
+ /**
157
+ * Captures ordinary document boundaries while adopting extensions in
158
+ * bounded work slices.
159
+ * @param {Record<string, any>} document Canonical document envelope.
160
+ * @param {Set<object>} frozenRoots Deeply frozen roots.
161
+ * @param {boolean} standardBuiltins Whether built-ins have local prototypes.
162
+ * @param {() => Promise<void> | void} yieldControl Host scheduler.
163
+ * @returns {Promise<Record<string, any>>} The same read-only envelope.
164
+ */
165
+ static async #freezeDocumentAsync(
166
+ document,
167
+ frozenRoots,
168
+ standardBuiltins,
169
+ yieldControl
170
+ ) {
171
+ const assets = CircuitJsonReadOnlyDocument.#documentAssets(document)
172
+ const metadataState = StructuredDataSnapshot.createState()
173
+ CircuitJsonReadOnlyDocument.#captureAssetData(assets, metadataState)
174
+ const extensions =
175
+ await CircuitJsonReadOnlyDocument.#captureDocumentExtensionsAsync(
176
+ document,
177
+ standardBuiltins,
178
+ yieldControl
179
+ )
180
+ if (extensions && typeof extensions === 'object') {
181
+ frozenRoots.add(extensions)
182
+ }
183
+ CircuitJsonMetadataBoundary.normalize(document, assets, (value) =>
184
+ CircuitJsonReadOnlyDocument.#captureMetadataRoot(
185
+ value,
186
+ metadataState
187
+ )
188
+ )
189
+ CircuitJsonReadOnlyDocument.#freezeValue(document, frozenRoots)
190
+ return document
191
+ }
192
+
114
193
  /**
115
194
  * Reads only an internally-created defensive asset data getter.
116
195
  * @param {PropertyDescriptor | undefined} descriptor Data descriptor.
@@ -184,7 +263,8 @@ export class CircuitJsonReadOnlyDocument {
184
263
  if (
185
264
  value &&
186
265
  typeof value === 'object' &&
187
- OWNED_METADATA_ROOTS.has(value) &&
266
+ (OWNED_METADATA_ROOTS.has(value) ||
267
+ CircuitJsonExtensionBoundary.owns(value)) &&
188
268
  Object.isFrozen(value)
189
269
  ) {
190
270
  return value
@@ -209,35 +289,11 @@ export class CircuitJsonReadOnlyDocument {
209
289
  * @returns {unknown} Deeply immutable owned extension metadata.
210
290
  */
211
291
  static copyReadonlyExtensionValue(value, normalize = null, options = {}) {
212
- if (
213
- value &&
214
- typeof value === 'object' &&
215
- OWNED_METADATA_ROOTS.has(value) &&
216
- Object.isFrozen(value) &&
217
- normalize === null
218
- ) {
219
- return value
220
- }
221
- if (normalize !== null && typeof normalize !== 'function') {
222
- throw new TypeError('Extension normalizer must be a function.')
223
- }
224
- const snapshot = StructuredDataSnapshot.capture(
292
+ return CircuitJsonExtensionBoundary.copyReadonly(
225
293
  value,
226
- StructuredDataSnapshot.createState({
227
- ...EXTENSION_METADATA_LIMITS,
228
- standardBuiltins: options?.standardBuiltins === true
229
- })
294
+ normalize,
295
+ options
230
296
  )
231
- ProtectedExtensionBinaryBoundary.protect(snapshot)
232
- const normalized = normalize ? normalize(snapshot) : snapshot
233
- if (normalized !== snapshot) {
234
- ProtectedExtensionBinaryBoundary.protect(normalized)
235
- }
236
- CircuitJsonReadOnlyDocument.#freezeValue(normalized, new Set())
237
- if (normalized && typeof normalized === 'object') {
238
- OWNED_METADATA_ROOTS.add(normalized)
239
- }
240
- return normalized
241
297
  }
242
298
 
243
299
  /**
@@ -341,31 +397,30 @@ export class CircuitJsonReadOnlyDocument {
341
397
  * @returns {unknown} Owned extension root or undefined.
342
398
  */
343
399
  static #captureDocumentExtensions(document, standardBuiltins) {
344
- let descriptor
345
- try {
346
- descriptor = Object.getOwnPropertyDescriptor(document, 'extensions')
347
- } catch {
348
- throw new TypeError(
349
- 'Canonical document extensions could not be inspected safely.'
350
- )
351
- }
352
- if (!descriptor) return undefined
353
- if (!Object.hasOwn(descriptor, 'value')) {
354
- throw new TypeError(
355
- 'Canonical document extensions must be an own data property.'
356
- )
357
- }
358
- const captured = CircuitJsonReadOnlyDocument.copyReadonlyExtensionValue(
359
- descriptor.value,
360
- null,
361
- { standardBuiltins }
400
+ return CircuitJsonExtensionBoundary.captureDocument(
401
+ document,
402
+ standardBuiltins
403
+ )
404
+ }
405
+
406
+ /**
407
+ * Cooperatively captures a worker extension root and rejects document-level
408
+ * replacement races across scheduling boundaries.
409
+ * @param {Record<string, any>} document Canonical document envelope.
410
+ * @param {boolean} standardBuiltins Whether built-ins have local prototypes.
411
+ * @param {() => Promise<void> | void} yieldControl Host scheduler.
412
+ * @returns {Promise<unknown>} Owned extension root or undefined.
413
+ */
414
+ static async #captureDocumentExtensionsAsync(
415
+ document,
416
+ standardBuiltins,
417
+ yieldControl
418
+ ) {
419
+ return CircuitJsonExtensionBoundary.captureDocumentAsync(
420
+ document,
421
+ standardBuiltins,
422
+ yieldControl
362
423
  )
363
- if (captured === descriptor.value) return captured
364
- Object.defineProperty(document, 'extensions', {
365
- ...descriptor,
366
- value: captured
367
- })
368
- return captured
369
424
  }
370
425
 
371
426
  /**
@@ -684,7 +739,8 @@ export class CircuitJsonReadOnlyDocument {
684
739
  if (
685
740
  value &&
686
741
  typeof value === 'object' &&
687
- OWNED_METADATA_ROOTS.has(value)
742
+ (OWNED_METADATA_ROOTS.has(value) ||
743
+ CircuitJsonExtensionBoundary.owns(value))
688
744
  ) {
689
745
  return value
690
746
  }