poe-code 14.0.82 → 14.0.84

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.
Files changed (50) hide show
  1. package/dist/index.js +1105 -223
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js → chunk-2EZQJQ2C.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-V6LQP64H.js → chunk-CYVI4ZUK.js} +978 -161
  7. package/packages/safe-js/dist/chunks/chunk-CYVI4ZUK.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/index.js +2 -2
  11. package/packages/safe-js/dist/interp/array-buffer.d.ts +12 -0
  12. package/packages/safe-js/dist/interp/array-buffer.js +33 -0
  13. package/packages/safe-js/dist/interp/float32-prototypes.d.ts +3 -0
  14. package/packages/safe-js/dist/interp/float32-prototypes.js +1 -0
  15. package/packages/safe-js/dist/interp/float32.d.ts +7 -1
  16. package/packages/safe-js/dist/interp/float32.js +50 -14
  17. package/packages/safe-js/dist/interp/globals/array-buffer.d.ts +3 -0
  18. package/packages/safe-js/dist/interp/globals/array-buffer.js +112 -0
  19. package/packages/safe-js/dist/interp/globals/float32array.d.ts +4 -3
  20. package/packages/safe-js/dist/interp/globals/float32array.js +463 -68
  21. package/packages/safe-js/dist/interp/globals/object-array.js +3 -3
  22. package/packages/safe-js/dist/interp/globals.d.ts +2 -0
  23. package/packages/safe-js/dist/interp/globals.js +6 -2
  24. package/packages/safe-js/dist/interp/host-bridge.d.ts +1 -0
  25. package/packages/safe-js/dist/interp/host-bridge.js +21 -0
  26. package/packages/safe-js/dist/interp/host-call.js +26 -2
  27. package/packages/safe-js/dist/interp/instanceof.js +1 -1
  28. package/packages/safe-js/dist/interp/interpreter.js +2 -4
  29. package/packages/safe-js/dist/interp/iteration.js +15 -6
  30. package/packages/safe-js/dist/interp/methods/array-iterator.js +1 -1
  31. package/packages/safe-js/dist/interp/object-model.js +22 -1
  32. package/packages/safe-js/dist/interp/values.d.ts +1 -1
  33. package/packages/safe-js/dist/interp/values.js +59 -9
  34. package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
  35. package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
  36. package/packages/safe-js/dist/parse/parser.js +8 -3
  37. package/packages/safe-js/dist/parse/tokenizer.js +45 -3
  38. package/packages/safe-js/dist/snapshot/array-buffer.d.ts +13 -0
  39. package/packages/safe-js/dist/snapshot/array-buffer.js +40 -0
  40. package/packages/safe-js/dist/snapshot/dump-format.js +25 -9
  41. package/packages/safe-js/dist/snapshot/float32array.d.ts +11 -1
  42. package/packages/safe-js/dist/snapshot/float32array.js +42 -5
  43. package/packages/safe-js/dist/snapshot/replay-data.d.ts +5 -0
  44. package/packages/safe-js/dist/snapshot/replay-data.js +35 -10
  45. package/packages/safe-js/dist/snapshot/restore.js +30 -3
  46. package/packages/safe-js/dist/snapshot/serialize.d.ts +7 -3
  47. package/packages/safe-js/dist/snapshot/serialize.js +24 -14
  48. package/packages/safe-js/dist/snapshot/validation.js +21 -1
  49. package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +0 -7
  50. /package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js.map → chunk-2EZQJQ2C.js.map} +0 -0
@@ -0,0 +1,40 @@
1
+ import { arrayBufferLength, arrayBufferOptions, isSandboxArrayBuffer } from "../interp/array-buffer.js";
2
+ import { float32Storage, isFloat32Array } from "../interp/float32.js";
3
+ import { getSandboxPrototype, hasExplicitSandboxPrototype } from "../interp/object-model.js";
4
+ import { serializePropertyDescriptors } from "./property-descriptors.js";
5
+ export function captureArrayBufferState(value, encode) {
6
+ return { properties: serializePropertyDescriptors(value, encode),
7
+ ...(hasExplicitSandboxPrototype(value) ? { prototype: encode(getSandboxPrototype(value)) } : {}) };
8
+ }
9
+ export function encodeArrayBufferStorage(value, id, buffers, reference) {
10
+ arrayBufferLength(value);
11
+ const existing = buffers.get(value);
12
+ if (existing === undefined)
13
+ buffers.set(value, id);
14
+ return { kind: "arraybuffer", ...(existing === undefined ? { bytes: Array.from(new Uint8Array(value)), ...arrayBufferOptions(value) } : { buffer: reference(existing) }) };
15
+ }
16
+ export function validateArrayBufferStorage(value) {
17
+ if (Object.hasOwn(value, "bytes") === Object.hasOwn(value, "buffer"))
18
+ throw new TypeError("ArrayBuffer requires one backing storage description.");
19
+ if (Object.hasOwn(value, "bytes") && (!Array.isArray(value.bytes) ||
20
+ value.bytes.some(byte => !Number.isInteger(byte) || byte < 0 || byte > 255)))
21
+ throw new TypeError("Invalid ArrayBuffer bytes.");
22
+ if (Object.hasOwn(value, "maxByteLength") && (!Array.isArray(value.bytes) ||
23
+ !Number.isSafeInteger(value.maxByteLength) || Number(value.maxByteLength) < value.bytes.length))
24
+ throw new TypeError("Invalid ArrayBuffer maximum length.");
25
+ }
26
+ export function decodeArrayBufferStorage(value, resolve) {
27
+ validateArrayBufferStorage(value);
28
+ if (Array.isArray(value.bytes)) {
29
+ const buffer = Reflect.construct(ArrayBuffer, [value.bytes.length,
30
+ Object.hasOwn(value, "maxByteLength") ? { maxByteLength: value.maxByteLength } : undefined]);
31
+ new Uint8Array(buffer).set(value.bytes);
32
+ return buffer;
33
+ }
34
+ const referenced = resolve(value.buffer);
35
+ if (isSandboxArrayBuffer(referenced))
36
+ return referenced;
37
+ if (isFloat32Array(referenced))
38
+ return float32Storage(referenced).buffer;
39
+ throw new TypeError("Invalid ArrayBuffer backing reference.");
40
+ }
@@ -12,8 +12,10 @@ import { sandboxErrorTypes } from "../error/shape.js";
12
12
  import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/arguments.js";
13
13
  import { serializeArguments } from "./arguments.js";
14
14
  import { requiresArrayEntries, serializeArray } from "./arrays.js";
15
- import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
16
- import { encodeFloat32Storage } from "./float32array.js";
15
+ import { float32DataProperties, float32Storage, isFloat32Array } from "../interp/float32.js";
16
+ import { encodeFloat32Layout } from "./float32array.js";
17
+ import { isSandboxArrayBuffer } from "../interp/array-buffer.js";
18
+ import { captureArrayBufferState, encodeArrayBufferStorage } from "./array-buffer.js";
17
19
  import { dateDataProperties, isSandboxDate } from "../interp/date.js";
18
20
  import { serializeDate } from "./date-properties.js";
19
21
  import { boxedDataProperties, isSandboxBox } from "../interp/boxed.js";
@@ -109,7 +111,7 @@ function serializeDumpValue(value, path, state) {
109
111
  if (hasGuestObjectState(value) && !(state.trustedRunReplay && (isSandboxDate(value) || isSandboxPromise(value) || isPromiseResolvingFunction(value)))) {
110
112
  throw new TypeError("Guest function properties and prototype links cannot be serialized.");
111
113
  }
112
- if (isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
114
+ if (isSandboxArrayBuffer(value) || isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
113
115
  return serializeHeapReference(value, path, state);
114
116
  if (Array.isArray(value)) {
115
117
  const reference = serializeHeapReference(value, path, state);
@@ -186,11 +188,17 @@ function serializeHeapReference(value, path, state) {
186
188
  return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
187
189
  });
188
190
  }
191
+ else if (isSandboxArrayBuffer(value)) {
192
+ state.heap[String(id)] = { ...encodeArrayBufferStorage(value, id, state.float32Buffers, id => ({ kind: "ref", id })),
193
+ state: captureArrayBufferState(value, entry => {
194
+ const serialized = serializeDumpValue(entry, `${path}.<buffer>`, state);
195
+ return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
196
+ }) };
197
+ }
189
198
  else if (isFloat32Array(value)) {
190
- const storage = encodeFloat32Storage(value, id, state.float32Buffers, (id) => ({
191
- kind: "ref",
192
- id
193
- }));
199
+ const backing = float32Storage(value);
200
+ const storage = { kind: "float32array", ...encodeFloat32Layout(value),
201
+ buffer: serializeHeapReference(backing.buffer, `${path}.buffer`, state) };
194
202
  const entries = Object.create(null);
195
203
  state.heap[String(id)] = { ...storage, entries };
196
204
  for (const [key, descriptor] of float32DataProperties(value)) {
@@ -271,6 +279,7 @@ function indexHeapContainers(snapshot) {
271
279
  (isSandboxRegex(value) && hasCustomRegexProperties(value)) ||
272
280
  isSandboxDate(value) ||
273
281
  isFloat32Array(value) ||
282
+ isSandboxArrayBuffer(value) ||
274
283
  (Array.isArray(value) && requiresArrayEntries(value)) ||
275
284
  isSandboxArguments(value) ||
276
285
  sandboxErrorTypes.has(value)) {
@@ -305,9 +314,14 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
305
314
  stat.expanded = true;
306
315
  ancestors.add(value);
307
316
  const guestEntries = [];
308
- const guest = captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
317
+ if (isFloat32Array(value))
318
+ guestEntries.push(float32Storage(value).buffer);
319
+ const guest = isSandboxArrayBuffer(value)
320
+ ? { kind: "arraybuffer", state: captureArrayBufferState(value, entry => { guestEntries.push(entry); return null; }) }
321
+ : captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
309
322
  if (guest !== undefined) {
310
- guestValues.add(value);
323
+ if (!isSandboxArrayBuffer(value))
324
+ guestValues.add(value);
311
325
  for (const entry of guestEntries) {
312
326
  collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
313
327
  if (entry !== null && typeof entry === "object")
@@ -316,6 +330,8 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
316
330
  ancestors.delete(value);
317
331
  return;
318
332
  }
333
+ for (const entry of guestEntries)
334
+ collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
319
335
  if (!Array.isArray(value) && !isPlainObject(value) && !isFloat32Array(value) && !isSandboxDate(value)) {
320
336
  ancestors.delete(value);
321
337
  return;
@@ -1,12 +1,22 @@
1
+ import type { GuestObjectState } from "./guest-heap.js";
2
+ import type { Budget } from "../interp/budget.js";
3
+ export declare function captureFloat32State<T>(value: Float32Array, encode: (value: unknown) => T): GuestObjectState<T>;
4
+ export declare function restoreFloat32Properties<T>(value: Float32Array, state: GuestObjectState<T>, decode: (value: T) => unknown): void;
1
5
  export type Float32Data<TReference> = {
2
6
  kind: "float32array";
3
7
  byteOffset: number;
4
8
  length: number;
9
+ lengthTracking?: true;
5
10
  } & ({
6
11
  bytes: number[];
7
12
  } | {
8
13
  buffer: TReference;
9
14
  });
15
+ export declare function encodeFloat32Layout(value: Float32Array): {
16
+ byteOffset: number;
17
+ length: number;
18
+ lengthTracking?: true;
19
+ };
10
20
  export declare function encodeFloat32Storage<TReference>(value: Float32Array, id: number, buffers: WeakMap<ArrayBuffer, number>, reference: (id: number) => TReference): Float32Data<TReference>;
11
21
  export declare function validateFloat32Storage(value: Record<string, unknown>): void;
12
- export declare function decodeFloat32Storage(value: Record<string, unknown>, resolve: (reference: unknown) => unknown): Float32Array;
22
+ export declare function decodeFloat32Storage(value: Record<string, unknown>, resolve: (reference: unknown) => unknown, budget?: Budget): Float32Array;
@@ -1,4 +1,34 @@
1
- import { float32Storage, isFloat32Array } from "../interp/float32.js";
1
+ import { float32Properties, float32Storage, float32ViewLayouts, restoreFloat32View, isFloat32Array, isFloat32Index } from "../interp/float32.js";
2
+ import { getSandboxPrototype, hasExplicitSandboxPrototype } from "../interp/object-model.js";
3
+ import { restorePropertyDescriptors, serializePropertyDescriptors } from "./property-descriptors.js";
4
+ import { arrayBufferOptions, isSandboxArrayBuffer } from "../interp/array-buffer.js";
5
+ export function captureFloat32State(value, encode) {
6
+ const metadata = Object.defineProperties(Object.create(null), Object.fromEntries(float32Properties(value)));
7
+ if (!Object.isExtensible(value))
8
+ Object.preventExtensions(metadata);
9
+ return { properties: serializePropertyDescriptors(metadata, encode),
10
+ ...(hasExplicitSandboxPrototype(value) ? { prototype: encode(getSandboxPrototype(value)) } : {}) };
11
+ }
12
+ export function restoreFloat32Properties(value, state, decode) {
13
+ const metadata = Object.create(null);
14
+ restorePropertyDescriptors(metadata, state.properties, decode);
15
+ const descriptors = Object.getOwnPropertyDescriptors(metadata);
16
+ if (Object.keys(descriptors).some(isFloat32Index))
17
+ throw new TypeError("Float32Array metadata cannot replace numeric storage.");
18
+ Object.defineProperties(value, descriptors);
19
+ if (!Object.isExtensible(metadata))
20
+ Object.preventExtensions(value);
21
+ }
22
+ export function encodeFloat32Layout(value) {
23
+ const storage = float32Storage(value);
24
+ if (arrayBufferOptions(storage.buffer) === undefined)
25
+ return { byteOffset: storage.byteOffset, length: storage.length };
26
+ const layout = float32ViewLayouts.get(value);
27
+ if (layout === undefined)
28
+ throw new TypeError("Resizable Float32Array snapshots require known view layout.");
29
+ return { byteOffset: layout.byteOffset, length: layout.length ?? 0,
30
+ ...(layout.length === undefined ? { lengthTracking: true } : {}) };
31
+ }
2
32
  export function encodeFloat32Storage(value, id, buffers, reference) {
3
33
  const storage = float32Storage(value);
4
34
  const existing = buffers.get(storage.buffer);
@@ -14,6 +44,8 @@ export function encodeFloat32Storage(value, id, buffers, reference) {
14
44
  };
15
45
  }
16
46
  export function validateFloat32Storage(value) {
47
+ if (Object.hasOwn(value, "lengthTracking") && (value.lengthTracking !== true || value.length !== 0 || Object.hasOwn(value, "bytes")))
48
+ throw new TypeError("Invalid Float32Array length-tracking layout.");
17
49
  if (!Number.isSafeInteger(value.length) ||
18
50
  Number(value.length) < 0 ||
19
51
  !Number.isSafeInteger(value.byteOffset) ||
@@ -29,7 +61,7 @@ export function validateFloat32Storage(value) {
29
61
  throw new TypeError("Invalid Float32Array backing bytes.");
30
62
  }
31
63
  }
32
- export function decodeFloat32Storage(value, resolve) {
64
+ export function decodeFloat32Storage(value, resolve, budget) {
33
65
  validateFloat32Storage(value);
34
66
  let buffer;
35
67
  if (Array.isArray(value.bytes)) {
@@ -38,9 +70,14 @@ export function decodeFloat32Storage(value, resolve) {
38
70
  }
39
71
  else {
40
72
  const referenced = resolve(value.buffer);
41
- if (!isFloat32Array(referenced))
73
+ if (isSandboxArrayBuffer(referenced))
74
+ buffer = referenced;
75
+ else if (isFloat32Array(referenced))
76
+ buffer = float32Storage(referenced).buffer;
77
+ else
42
78
  throw new TypeError("Invalid Float32Array backing reference.");
43
- buffer = float32Storage(referenced).buffer;
44
79
  }
45
- return new Float32Array(buffer, Number(value.byteOffset), Number(value.length));
80
+ if (value.lengthTracking === true && arrayBufferOptions(buffer) === undefined)
81
+ throw new TypeError("Length-tracking layout requires resizable backing storage.");
82
+ return restoreFloat32View(buffer, Number(value.byteOffset), value.lengthTracking === true ? undefined : Number(value.length), budget);
46
83
  }
@@ -4,6 +4,7 @@ import { type SerializedSymbol, type SerializedSymbolProperty } from "./symbols.
4
4
  import { type CollectionIterationMethod } from "../interp/collection-iterator.js";
5
5
  import { CompileScope } from "../interp/regex/compile-guard.js";
6
6
  import { type Float32Data } from "./float32array.js";
7
+ import { type ArrayBufferData } from "./array-buffer.js";
7
8
  import { type SandboxErrorName } from "../error/shape.js";
8
9
  import { type SandboxClosure, type SandboxPromise, type SandboxValue } from "../interp/values.js";
9
10
  import { type SerializedArguments } from "./arguments.js";
@@ -69,6 +70,10 @@ type DataNode = {
69
70
  } | (Float32Data<Atom> & {
70
71
  properties: Properties;
71
72
  extensible: boolean;
73
+ }) | (ArrayBufferData<Atom> & {
74
+ properties: Properties;
75
+ extensible: boolean;
76
+ symbolEntries?: Array<SerializedSymbolProperty<Atom>>;
72
77
  }) | {
73
78
  kind: "capability";
74
79
  id: string;
@@ -10,8 +10,10 @@ import { isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshot
10
10
  import { isSandboxRegExpIterator, regexpIteratorState, restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
11
11
  import { hasGuestObjectState, hasNullObjectPrototype, setSandboxPrototype } from "../interp/object-model.js";
12
12
  import { CompileScope } from "../interp/regex/compile-guard.js";
13
- import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
14
- import { decodeFloat32Storage, encodeFloat32Storage } from "./float32array.js";
13
+ import { float32DataProperties, float32Storage, isFloat32Array } from "../interp/float32.js";
14
+ import { decodeFloat32Storage, encodeFloat32Layout } from "./float32array.js";
15
+ import { arrayBufferDataProperties, isSandboxArrayBuffer } from "../interp/array-buffer.js";
16
+ import { decodeArrayBufferStorage, encodeArrayBufferStorage } from "./array-buffer.js";
15
17
  import { dateDataProperties, isSandboxDate, restoreDateTime, serializedDateTime } from "../interp/date.js";
16
18
  import { createRawJson, isRawJson } from "../interp/raw-json.js";
17
19
  import { boxedDataProperties, createSandboxBox, nativeBoxedValue } from "../interp/boxed.js";
@@ -119,11 +121,22 @@ export function encodeReplayData(value, options = {}) {
119
121
  ...(Object.isExtensible(entry) ? {} : { extensible: false })
120
122
  };
121
123
  }
124
+ else if (isSandboxArrayBuffer(entry)) {
125
+ const storage = encodeArrayBufferStorage(entry, id, float32Buffers, id => ({ tag: "ref", id }));
126
+ const properties = Object.create(null);
127
+ for (const [key, descriptor] of arrayBufferDataProperties(entry)) {
128
+ if (typeof key === "symbol")
129
+ continue;
130
+ properties[key] = { value: child(descriptor.value, key), configurable: descriptor.configurable === true,
131
+ enumerable: descriptor.enumerable === true, writable: descriptor.writable === true };
132
+ }
133
+ let symbolIndex = 0;
134
+ const symbolEntries = serializeSymbolProperties(entry, value => encode(value, depth + 1, [...path, { symbol: Math.floor(symbolIndex++ / 2) }]));
135
+ nodes[id] = { ...storage, properties, extensible: Object.isExtensible(entry), symbolEntries };
136
+ }
122
137
  else if (isFloat32Array(entry)) {
123
- const storage = encodeFloat32Storage(entry, id, float32Buffers, (id) => ({
124
- tag: "ref",
125
- id
126
- }));
138
+ const backing = float32Storage(entry);
139
+ const storage = { kind: "float32array", ...encodeFloat32Layout(entry), buffer: child(backing.buffer, "<buffer>") };
127
140
  const properties = Object.create(null);
128
141
  for (const [key, descriptor] of float32DataProperties(entry)) {
129
142
  properties[key] = {
@@ -227,7 +240,7 @@ export function decodeReplayData(input, options = {}, parent) {
227
240
  const graph = record(input);
228
241
  const nodes = list(own(graph, "nodes"));
229
242
  const restored = new Map();
230
- const initializeIterators = [];
243
+ const initializeValues = [];
231
244
  const decode = (entry, depth = 0) => {
232
245
  if (depth > MAX_DATA_DEPTH)
233
246
  throw new TypeError("Replay data exceeds the nesting limit.");
@@ -378,10 +391,22 @@ export function decodeReplayData(input, options = {}, parent) {
378
391
  Object.preventExtensions(result);
379
392
  return result;
380
393
  }
394
+ if (kind === "arraybuffer") {
395
+ if (typeof node.extensible !== "boolean")
396
+ throw new TypeError("Invalid ArrayBuffer extensibility.");
397
+ const result = decodeArrayBufferStorage(node, child);
398
+ restored.set(id, result);
399
+ initializeValues.push(() => {
400
+ defineProperties(result, record(own(node, "properties")), child, node.symbolEntries);
401
+ if (!node.extensible)
402
+ Object.preventExtensions(result);
403
+ });
404
+ return result;
405
+ }
381
406
  if (kind === "float32array") {
382
407
  if (typeof node.extensible !== "boolean")
383
408
  throw new TypeError("Invalid Float32Array extensibility.");
384
- const result = decodeFloat32Storage(node, child);
409
+ const result = decodeFloat32Storage(node, child, compilation.owner?.budget);
385
410
  restored.set(id, result);
386
411
  defineProperties(result, record(own(node, "properties")), child);
387
412
  if (!node.extensible)
@@ -421,7 +446,7 @@ export function decodeReplayData(input, options = {}, parent) {
421
446
  const collection = child(own(node, "collection"));
422
447
  if (collection !== undefined && !isSandboxMap(collection) && !isSandboxSet(collection))
423
448
  throw new TypeError("Invalid replay collection iterator source.");
424
- initializeIterators.push(() => { restoreSandboxCollectionIterator({ collection, collectionKind, method, index, exhausted }, result); });
449
+ initializeValues.push(() => { restoreSandboxCollectionIterator({ collection, collectionKind, method, index, exhausted }, result); });
425
450
  defineProperties(result, record(own(node, "properties")), child);
426
451
  if (!node.extensible)
427
452
  Object.preventExtensions(result);
@@ -503,7 +528,7 @@ export function decodeReplayData(input, options = {}, parent) {
503
528
  return result;
504
529
  };
505
530
  const result = decode(own(graph, "root"));
506
- for (const initialize of initializeIterators)
531
+ for (const initialize of initializeValues)
507
532
  initialize();
508
533
  if (parent !== undefined)
509
534
  compilation.forward(compilation.tickets, parent);
@@ -17,7 +17,8 @@ import { awaitSandboxValue } from "../interp/cancel.js";
17
17
  import { runAsyncPrefix } from "../interp/jobs.js";
18
18
  import { toPropertyKey } from "../interp/property-key.js";
19
19
  import { CompileScope } from "../interp/regex/compile-guard.js";
20
- import { decodeFloat32Storage } from "./float32array.js";
20
+ import { decodeFloat32Storage, restoreFloat32Properties } from "./float32array.js";
21
+ import { decodeArrayBufferStorage } from "./array-buffer.js";
21
22
  import { restoreDateTime } from "../interp/date.js";
22
23
  import { createRawJson } from "../interp/raw-json.js";
23
24
  import { createSandboxBox } from "../interp/boxed.js";
@@ -411,7 +412,11 @@ function initializeIntrinsicRealm(state) {
411
412
  return prototype?.kind === "intrinsic" &&
412
413
  prototype.id === JSON.stringify([...JSON.parse(node.id), "prototype"]);
413
414
  }));
414
- createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes });
415
+ const float32 = Object.values(state.heap).find(node => node.kind === "intrinsic" && node.id === '["Float32Array"]');
416
+ const float32Prototypes = float32?.kind !== "intrinsic" ||
417
+ float32.state?.properties.properties.some(([key, descriptor]) => key === "prototype" && descriptor.kind === "data" &&
418
+ !descriptor.writable && !descriptor.enumerable && !descriptor.configurable) === true;
419
+ createBuiltinBindings({ budget: state.budget, compileOwner: state.compilation.owner, functionHasInstance, errorPrototypes, float32Prototypes });
415
420
  state.intrinsicsInitialized = true;
416
421
  }
417
422
  function restoreHeapValue(id, state) {
@@ -452,9 +457,31 @@ function restoreHeapValue(id, state) {
452
457
  restoreRegexProperties(value, serialized, entry => deserializeValue(entry, state));
453
458
  return value;
454
459
  }
460
+ if (serialized.kind === "arraybuffer") {
461
+ initializeIntrinsicRealm(state);
462
+ const value = decodeArrayBufferStorage(serialized, reference => deserializeValue(reference, state));
463
+ state.heapValueById.set(id, value);
464
+ state.initializeIterators.push(() => {
465
+ if (serialized.state.prototype !== undefined)
466
+ setSandboxPrototype(value, deserializeValue(serialized.state.prototype, state), state.budget);
467
+ restorePropertyDescriptors(value, serialized.state.properties, entry => deserializeValue(entry, state));
468
+ });
469
+ return value;
470
+ }
455
471
  if (serialized.kind === "float32array") {
456
- const value = decodeFloat32Storage(serialized, (reference) => deserializeValue(reference, state));
472
+ if (serialized.state !== undefined)
473
+ initializeIntrinsicRealm(state);
474
+ const value = decodeFloat32Storage(serialized, (reference) => deserializeValue(reference, state), state.budget);
457
475
  state.heapValueById.set(id, value);
476
+ if (serialized.state !== undefined) {
477
+ const objectState = serialized.state;
478
+ state.initializeIterators.push(() => {
479
+ if (objectState.prototype !== undefined)
480
+ setSandboxPrototype(value, deserializeValue(objectState.prototype, state), state.budget);
481
+ restoreFloat32Properties(value, objectState, entry => deserializeValue(entry, state));
482
+ });
483
+ return value;
484
+ }
458
485
  for (const [key, entry] of Object.entries(serialized.entries)) {
459
486
  Object.defineProperty(value, key, {
460
487
  value: deserializeValue(entry, state),
@@ -4,10 +4,11 @@ import { type SerializedSymbol, type SerializedSymbolProperty } from "./symbols.
4
4
  import { type CollectionIterationMethod, type SandboxCollectionIterator } from "../interp/collection-iterator.js";
5
5
  import { type SandboxRegExpIterator } from "../interp/regexp-iterator.js";
6
6
  import { type SandboxErrorName } from "../error/shape.js";
7
- import { type GuestHeapNode } from "./guest-heap.js";
7
+ import { type GuestHeapNode, type GuestObjectState } from "./guest-heap.js";
8
8
  import { type SerializedArguments } from "./arguments.js";
9
9
  import { type SerializedArray } from "./arrays.js";
10
10
  import { type Float32Data } from "./float32array.js";
11
+ import { type ArrayBufferData } from "./array-buffer.js";
11
12
  import { type SerializedDate } from "./date-properties.js";
12
13
  import { type SandboxBox } from "../interp/boxed.js";
13
14
  import { type BoxedData } from "./boxed.js";
@@ -51,7 +52,9 @@ export type SerializedReferenceValue = {
51
52
  kind: "ref";
52
53
  id: number;
53
54
  };
54
- export type SerializedHeapValue = GuestHeapNode<SerializedSnapshotValue> | {
55
+ export type SerializedHeapValue = (ArrayBufferData<SerializedReferenceValue> & {
56
+ state: GuestObjectState<SerializedSnapshotValue>;
57
+ }) | GuestHeapNode<SerializedSnapshotValue> | {
55
58
  kind: "regexp-iterator";
56
59
  matcher: SerializedSnapshotValue;
57
60
  input: SerializedSnapshotValue;
@@ -75,6 +78,7 @@ export type SerializedHeapValue = GuestHeapNode<SerializedSnapshotValue> | {
75
78
  entries: Record<string, SerializedSnapshotValue>;
76
79
  } | SerializedDate<SerializedSnapshotValue> | (Float32Data<SerializedReferenceValue> & {
77
80
  entries: Record<string, SerializedSnapshotValue>;
81
+ state?: GuestObjectState<SerializedSnapshotValue>;
78
82
  }) | SerializedArguments<SerializedSnapshotValue> | SerializedArray<SerializedSnapshotValue> | {
79
83
  kind: "object";
80
84
  sandboxNullPrototype?: true;
@@ -111,7 +115,7 @@ export type RuntimePromiseValue = {
111
115
  id: SnapshotId;
112
116
  promise?: Promise<unknown>;
113
117
  };
114
- export type RuntimeSnapshotValue = bigint | symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
118
+ export type RuntimeSnapshotValue = bigint | symbol | SandboxBox | Date | Float32Array | ArrayBuffer | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
115
119
  [key: string]: RuntimeSnapshotValue;
116
120
  };
117
121
  export type RuntimeScopeFrame = {
@@ -11,8 +11,10 @@ import { captureGuestHeapNode } from "./guest-heap.js";
11
11
  import { getGeneratorOrigin } from "../interp/closure-origin.js";
12
12
  import { serializeArguments } from "./arguments.js";
13
13
  import { requiresArrayEntries, serializeArray } from "./arrays.js";
14
- import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
15
- import { encodeFloat32Storage } from "./float32array.js";
14
+ import { float32Storage, isFloat32Array } from "../interp/float32.js";
15
+ import { captureFloat32State, encodeFloat32Layout } from "./float32array.js";
16
+ import { isSandboxArrayBuffer } from "../interp/array-buffer.js";
17
+ import { captureArrayBufferState, encodeArrayBufferStorage } from "./array-buffer.js";
16
18
  import { dateDataProperties, isSandboxDate } from "../interp/date.js";
17
19
  import { serializeDate } from "./date-properties.js";
18
20
  import { boxedDataProperties, isSandboxBox } from "../interp/boxed.js";
@@ -104,7 +106,7 @@ function serializeValue(value, path, state) {
104
106
  }
105
107
  return { kind: "ref", id };
106
108
  }
107
- if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !isSandboxMap(value) && !isSandboxSet(value)) {
109
+ if (typeof value === "object" && value !== null && hasGuestObjectState(value) && !isSandboxMap(value) && !isSandboxSet(value) && !isFloat32Array(value) && !isSandboxArrayBuffer(value)) {
108
110
  throw new TypeError("Guest function properties and prototype links cannot be serialized.");
109
111
  }
110
112
  if (value === null || typeof value === "string" || typeof value === "boolean") {
@@ -197,7 +199,7 @@ function serializeValue(value, path, state) {
197
199
  throw new TypeError(`Missing regex heap reference at ${path}.`);
198
200
  return { kind: "regex", source: value.source, flags: value.flags, lastIndex: value.lastIndex };
199
201
  }
200
- if (isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxRegExpIterator(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
202
+ if (isSandboxArrayBuffer(value) || isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxRegExpIterator(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
201
203
  const reference = serializeHeapReference(value, path, state);
202
204
  if (reference === undefined) {
203
205
  throw new TypeError(`Cannot serialize collection without a heap reference at ${path}.`);
@@ -260,15 +262,15 @@ function serializeHeapReference(value, path, state) {
260
262
  else if (isSandboxDate(value)) {
261
263
  state.heap[String(id)] = serializeDate(value, entry => serializeValue(entry, `${path}.<date-property>`, state));
262
264
  }
265
+ else if (isSandboxArrayBuffer(value)) {
266
+ state.heap[String(id)] = { ...encodeArrayBufferStorage(value, id, state.float32Buffers, id => ({ kind: "ref", id })),
267
+ state: captureArrayBufferState(value, entry => serializeValue(entry, `${path}.<buffer>`, state)) };
268
+ }
263
269
  else if (isFloat32Array(value)) {
264
- const storage = encodeFloat32Storage(value, id, state.float32Buffers, (id) => ({
265
- kind: "ref",
266
- id
267
- }));
268
- const entries = Object.create(null);
269
- state.heap[String(id)] = { ...storage, entries };
270
- for (const [key, descriptor] of float32DataProperties(value))
271
- entries[key] = serializeValue(descriptor.value, `${path}.${key}`, state);
270
+ const storage = float32Storage(value);
271
+ state.heap[String(id)] = { kind: "float32array", ...encodeFloat32Layout(value),
272
+ buffer: serializeHeapReference(storage.buffer, `${path}.buffer`, state), entries: {},
273
+ state: captureFloat32State(value, entry => serializeValue(entry, `${path}.<typed-array>`, state)) };
272
274
  }
273
275
  else if (isSandboxArguments(value)) {
274
276
  state.heap[String(id)] = serializeArguments(value, (entry, key) => serializeValue(entry, `${path}.${key}`, state));
@@ -389,6 +391,7 @@ function indexHeapContainers(input) {
389
391
  isSandboxBox(value) ||
390
392
  isSandboxDate(value) ||
391
393
  isFloat32Array(value) ||
394
+ isSandboxArrayBuffer(value) ||
392
395
  (Array.isArray(value) && requiresArrayEntries(value)) ||
393
396
  sandboxErrorTypes.has(value) ||
394
397
  isSandboxArguments(value) ||
@@ -431,9 +434,16 @@ function collectContainerStats(value, stats, ancestors, guestValues, depth = 0)
431
434
  stat.expanded = true;
432
435
  ancestors.add(value);
433
436
  const guestEntries = [];
434
- const guest = captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
437
+ if (isFloat32Array(value))
438
+ guestEntries.push(float32Storage(value).buffer);
439
+ const guest = isFloat32Array(value)
440
+ ? { kind: "float32array", state: captureFloat32State(value, entry => { guestEntries.push(entry); return null; }) }
441
+ : isSandboxArrayBuffer(value)
442
+ ? { kind: "arraybuffer", state: captureArrayBufferState(value, entry => { guestEntries.push(entry); return null; }) }
443
+ : captureGuestHeapNode(value, entry => { guestEntries.push(entry); return null; });
435
444
  if (guest !== undefined) {
436
- guestValues.add(value);
445
+ if (!isFloat32Array(value) && !isSandboxArrayBuffer(value))
446
+ guestValues.add(value);
437
447
  for (const entry of guestEntries) {
438
448
  collectContainerStats(entry, stats, ancestors, guestValues, depth + 1);
439
449
  if (entry !== null && typeof entry === "object") {
@@ -6,6 +6,7 @@ import { types } from "node:util";
6
6
  import { DUMP_FORMAT_VERSION } from "./dump-format.js";
7
7
  import { MAX_DATA_DEPTH } from "../graph-depth.js";
8
8
  import { validateFloat32Storage } from "./float32array.js";
9
+ import { validateArrayBufferStorage } from "./array-buffer.js";
9
10
  import { restoreDateTime } from "../interp/date.js";
10
11
  import { validateBoxedProperties } from "./boxed.js";
11
12
  import { hasGuestObjectState } from "../interp/object-model.js";
@@ -117,9 +118,19 @@ function validateDumpHeap(root, state) {
117
118
  validateDateRecord(entry, path);
118
119
  continue;
119
120
  }
121
+ if (entry.kind === "arraybuffer") {
122
+ validateArrayBufferStorage(entry);
123
+ validateGuestHeapNode({ kind: "guest-object", state: entry.state }, heap, state.limits.maxEntries);
124
+ continue;
125
+ }
120
126
  if (entry.kind === "float32array") {
121
127
  validateFloat32Storage(entry);
122
128
  requireRecord(entry.entries, `${path}.entries`);
129
+ if (Object.hasOwn(entry, "state")) {
130
+ if (Object.keys(entry.entries).length !== 0)
131
+ fail("invalidValue", path, "ambiguous Float32Array property state");
132
+ validateGuestHeapNode({ kind: "guest-object", state: entry.state }, heap, state.limits.maxEntries);
133
+ }
123
134
  continue;
124
135
  }
125
136
  if (entry.kind === "arguments") {
@@ -533,7 +544,7 @@ function validateHeapValue(value, path, state, heap) {
533
544
  fail("invalidValue", path, String(error));
534
545
  }
535
546
  validateErrorType(record, path);
536
- if (!["symbol", "arguments", "array", "object", "map", "set", "float32array", "date", "boxed", "collection-iterator", "regexp-iterator", "regex-object"].includes(String(record.kind)))
547
+ if (!["symbol", "arguments", "array", "object", "map", "set", "float32array", "arraybuffer", "date", "boxed", "collection-iterator", "regexp-iterator", "regex-object"].includes(String(record.kind)))
537
548
  fail("unknownTag", `${path}.kind`, "unknown heap tag");
538
549
  validateValue(record, path, 1, state);
539
550
  if (record.kind === "symbol")
@@ -548,9 +559,18 @@ function validateHeapValue(value, path, state, heap) {
548
559
  validateBoxedRecord(record, path, heap);
549
560
  if (record.kind === "date")
550
561
  validateDateRecord(record, path);
562
+ if (record.kind === "arraybuffer") {
563
+ validateArrayBufferStorage(record);
564
+ validateGuestHeapNode({ kind: "guest-object", state: record.state }, heap, state.limits.maxEntries);
565
+ }
551
566
  if (record.kind === "float32array") {
552
567
  validateFloat32Storage(record);
553
568
  requireRecord(record.entries, `${path}.entries`);
569
+ if (Object.hasOwn(record, "state")) {
570
+ if (Object.keys(record.entries).length !== 0)
571
+ fail("invalidValue", path, "ambiguous Float32Array property state");
572
+ validateGuestHeapNode({ kind: "guest-object", state: record.state }, heap, state.limits.maxEntries);
573
+ }
554
574
  }
555
575
  if (record.kind === "map") {
556
576
  const entries = requireArray(record.entries, `${path}.entries`, state);