poe-code 12.0.3 → 12.0.4

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 (35) hide show
  1. package/dist/index.js +423 -5
  2. package/dist/index.js.map +4 -4
  3. package/dist/metafile.json +1 -1
  4. package/package.json +1 -1
  5. package/packages/safejs/dist/chunks/{chunk-T55OILHA.js → chunk-LF5LY5O3.js} +2 -2
  6. package/packages/safejs/dist/chunks/{chunk-Z3ZMLYCK.js → chunk-XBRQ72W6.js} +387 -5
  7. package/packages/safejs/dist/chunks/chunk-XBRQ72W6.js.map +7 -0
  8. package/packages/safejs/dist/cli.js +2 -2
  9. package/packages/safejs/dist/core.js +1 -1
  10. package/packages/safejs/dist/index.js +2 -2
  11. package/packages/safejs/dist/interp/float32.d.ts +16 -0
  12. package/packages/safejs/dist/interp/float32.js +65 -0
  13. package/packages/safejs/dist/interp/globals/float32array.d.ts +6 -0
  14. package/packages/safejs/dist/interp/globals/float32array.js +130 -0
  15. package/packages/safejs/dist/interp/globals/object-array.js +6 -0
  16. package/packages/safejs/dist/interp/host-bridge.js +18 -0
  17. package/packages/safejs/dist/interp/host-call.js +15 -0
  18. package/packages/safejs/dist/interp/interpreter.js +17 -1
  19. package/packages/safejs/dist/interp/iteration.js +4 -0
  20. package/packages/safejs/dist/interp/values.d.ts +1 -1
  21. package/packages/safejs/dist/interp/values.js +56 -0
  22. package/packages/safejs/dist/lint/rules/known-globals.d.ts +1 -1
  23. package/packages/safejs/dist/lint/rules/known-globals.js +1 -0
  24. package/packages/safejs/dist/run.js +2 -0
  25. package/packages/safejs/dist/snapshot/dump-format.js +20 -2
  26. package/packages/safejs/dist/snapshot/float32array.d.ts +12 -0
  27. package/packages/safejs/dist/snapshot/float32array.js +46 -0
  28. package/packages/safejs/dist/snapshot/replay-data.d.ts +5 -1
  29. package/packages/safejs/dist/snapshot/replay-data.js +29 -0
  30. package/packages/safejs/dist/snapshot/restore.js +14 -0
  31. package/packages/safejs/dist/snapshot/serialize.d.ts +5 -2
  32. package/packages/safejs/dist/snapshot/serialize.js +17 -2
  33. package/packages/safejs/dist/snapshot/validation.js +11 -1
  34. package/packages/safejs/dist/chunks/chunk-Z3ZMLYCK.js.map +0 -7
  35. /package/packages/safejs/dist/chunks/{chunk-T55OILHA.js.map → chunk-LF5LY5O3.js.map} +0 -0
@@ -20,7 +20,7 @@ import {
20
20
  parseMcpConfig,
21
21
  splitFrontmatter,
22
22
  withBrokenPipeGuard
23
- } from "./chunks/chunk-T55OILHA.js";
23
+ } from "./chunks/chunk-LF5LY5O3.js";
24
24
  import {
25
25
  Budget,
26
26
  SandboxError,
@@ -32,7 +32,7 @@ import {
32
32
  replaceErrorStack,
33
33
  restore,
34
34
  run
35
- } from "./chunks/chunk-Z3ZMLYCK.js";
35
+ } from "./chunks/chunk-XBRQ72W6.js";
36
36
  import "./chunks/chunk-4YIDX44G.js";
37
37
 
38
38
  // packages/safejs/src/cli.ts
@@ -3,7 +3,7 @@ import {
3
3
  createReplayableRandom,
4
4
  lint,
5
5
  run
6
- } from "./chunks/chunk-Z3ZMLYCK.js";
6
+ } from "./chunks/chunk-XBRQ72W6.js";
7
7
  import "./chunks/chunk-4YIDX44G.js";
8
8
  export {
9
9
  Budget,
@@ -27,7 +27,7 @@ import {
27
27
  runWithSpawnUsageAccumulator,
28
28
  splitFrontmatter,
29
29
  supportsSpawnMode
30
- } from "./chunks/chunk-T55OILHA.js";
30
+ } from "./chunks/chunk-LF5LY5O3.js";
31
31
  import {
32
32
  Budget,
33
33
  FileSnapshotBackend,
@@ -49,7 +49,7 @@ import {
49
49
  registerPendingHostCallPolicy,
50
50
  restore,
51
51
  run
52
- } from "./chunks/chunk-Z3ZMLYCK.js";
52
+ } from "./chunks/chunk-XBRQ72W6.js";
53
53
  import "./chunks/chunk-4YIDX44G.js";
54
54
 
55
55
  // packages/safejs/src/runner/run-harness.ts
@@ -0,0 +1,16 @@
1
+ import type { Budget } from "./budget.js";
2
+ export declare function isFloat32Array(value: unknown): value is Float32Array;
3
+ export declare function float32Storage(value: Float32Array): {
4
+ buffer: ArrayBuffer;
5
+ byteOffset: number;
6
+ length: number;
7
+ byteLength: number;
8
+ };
9
+ export declare function float32DataProperties(value: Float32Array): Array<[string, PropertyDescriptor]>;
10
+ export declare function isFloat32Index(key: string): boolean;
11
+ export declare function float32Number(value: unknown): number;
12
+ export declare function checkFloat32Allocation(length: number, budget: Budget): void;
13
+ export declare function copyFloat32Storage<TValue>(value: Float32Array, state: {
14
+ seen: WeakMap<object, TValue>;
15
+ float32Buffers?: WeakMap<ArrayBuffer, ArrayBuffer>;
16
+ }): Float32Array;
@@ -0,0 +1,65 @@
1
+ const typedArrayPrototype = Object.getPrototypeOf(Float32Array.prototype);
2
+ const readLength = Object.getOwnPropertyDescriptor(typedArrayPrototype, "length").get;
3
+ const readOffset = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset").get;
4
+ const readBuffer = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer").get;
5
+ const readTag = Object.getOwnPropertyDescriptor(typedArrayPrototype, Symbol.toStringTag).get;
6
+ const bufferLength = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get;
7
+ const bufferResizable = Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "resizable")?.get;
8
+ export function isFloat32Array(value) {
9
+ return (ArrayBuffer.isView(value) &&
10
+ Object.getPrototypeOf(value) === Float32Array.prototype &&
11
+ Reflect.apply(readTag, value, []) === "Float32Array");
12
+ }
13
+ export function float32Storage(value) {
14
+ const buffer = Reflect.apply(readBuffer, value, []);
15
+ if (Object.getPrototypeOf(buffer) !== ArrayBuffer.prototype ||
16
+ (bufferResizable !== undefined && Reflect.apply(bufferResizable, buffer, []))) {
17
+ throw new TypeError("Float32Array requires a fixed, non-shared ArrayBuffer.");
18
+ }
19
+ return {
20
+ buffer,
21
+ byteOffset: Reflect.apply(readOffset, value, []),
22
+ length: Reflect.apply(readLength, value, []),
23
+ byteLength: Reflect.apply(bufferLength, buffer, [])
24
+ };
25
+ }
26
+ export function float32DataProperties(value) {
27
+ if (Object.getOwnPropertySymbols(value).length > 0)
28
+ throw new TypeError("Float32Array symbol properties are not supported.");
29
+ const properties = [];
30
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
31
+ if (isFloat32Index(key))
32
+ continue;
33
+ if (!("value" in descriptor))
34
+ throw new TypeError(`Float32Array accessor property '${key}' is not supported.`);
35
+ properties.push([key, descriptor]);
36
+ }
37
+ return properties;
38
+ }
39
+ export function isFloat32Index(key) {
40
+ return key === "-0" || String(Number(key)) === key;
41
+ }
42
+ export function float32Number(value) {
43
+ if ((value !== null && typeof value === "object") ||
44
+ typeof value === "function" ||
45
+ typeof value === "symbol" ||
46
+ typeof value === "bigint") {
47
+ throw new TypeError("Float32Array numeric arguments must be primitive numeric-coercible values.");
48
+ }
49
+ return Number(value);
50
+ }
51
+ export function checkFloat32Allocation(length, budget) {
52
+ budget.allocateArrayLength(length);
53
+ budget.provisionDataUsage(length * Float32Array.BYTES_PER_ELEMENT + 1)();
54
+ }
55
+ export function copyFloat32Storage(value, state) {
56
+ const storage = float32Storage(value);
57
+ state.float32Buffers ??= new WeakMap();
58
+ let buffer = state.float32Buffers.get(storage.buffer);
59
+ if (buffer === undefined) {
60
+ buffer = new ArrayBuffer(storage.byteLength);
61
+ new Uint8Array(buffer).set(new Uint8Array(storage.buffer));
62
+ state.float32Buffers.set(storage.buffer, buffer);
63
+ }
64
+ return new Float32Array(buffer, storage.byteOffset, storage.length);
65
+ }
@@ -0,0 +1,6 @@
1
+ import type { Budget } from "../budget.js";
2
+ import { type SandboxClosure, type SandboxValue } from "../values.js";
3
+ export declare function createFloat32ArrayGlobal(budget: Budget): SandboxClosure;
4
+ export declare function isFloat32ArrayConstructor(value: unknown): boolean;
5
+ export declare function getFloat32Member(value: Float32Array, property: string | number, budget: Budget): SandboxValue;
6
+ export declare function setFloat32Member(value: Float32Array, property: string | number, entry: SandboxValue): void;
@@ -0,0 +1,130 @@
1
+ import { checkFloat32Allocation, float32Number, float32Storage, isFloat32Array, isFloat32Index } from "../float32.js";
2
+ import { createSandboxClosure } from "../values.js";
3
+ const constructors = new WeakSet();
4
+ export function createFloat32ArrayGlobal(budget) {
5
+ const constructor = createSandboxClosure({
6
+ sandbox: true,
7
+ name: "Float32Array",
8
+ length: 3,
9
+ properties: { BYTES_PER_ELEMENT: 4 },
10
+ call: () => {
11
+ throw new TypeError("Constructor Float32Array requires 'new'.");
12
+ },
13
+ construct: ([source]) => {
14
+ if (Array.isArray(source) || isFloat32Array(source)) {
15
+ const length = isFloat32Array(source) ? float32Storage(source).length : source.length;
16
+ checkFloat32Allocation(length, budget);
17
+ if (isFloat32Array(source))
18
+ return new Float32Array(source);
19
+ const result = new Float32Array(length);
20
+ for (let index = 0; index < length; index += 1) {
21
+ budget.visitNode();
22
+ const descriptor = Object.getOwnPropertyDescriptor(source, index);
23
+ if (descriptor !== undefined && !("value" in descriptor))
24
+ throw new TypeError("Float32Array input accessors are not supported.");
25
+ result[index] = float32Number(descriptor?.value);
26
+ }
27
+ return result;
28
+ }
29
+ const number = float32Number(source);
30
+ const length = Number.isNaN(number) ? 0 : Math.trunc(number);
31
+ if (length < 0 || !Number.isSafeInteger(length))
32
+ throw new RangeError("Invalid typed array length.");
33
+ checkFloat32Allocation(length, budget);
34
+ return new Float32Array(length);
35
+ }
36
+ });
37
+ constructors.add(constructor);
38
+ return constructor;
39
+ }
40
+ export function isFloat32ArrayConstructor(value) {
41
+ return typeof value === "object" && value !== null && constructors.has(value);
42
+ }
43
+ export function getFloat32Member(value, property, budget) {
44
+ const key = String(property);
45
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
46
+ if (descriptor !== undefined) {
47
+ if (!("value" in descriptor))
48
+ throw new TypeError("Float32Array accessors are not supported.");
49
+ return descriptor.value;
50
+ }
51
+ const storage = float32Storage(value);
52
+ if (key === "length")
53
+ return storage.length;
54
+ if (key === "byteLength")
55
+ return storage.length * 4;
56
+ if (key === "byteOffset")
57
+ return storage.byteOffset;
58
+ if (key === "BYTES_PER_ELEMENT")
59
+ return 4;
60
+ if (!["set", "slice", "subarray"].includes(key))
61
+ return undefined;
62
+ return createSandboxClosure({
63
+ sandbox: true,
64
+ name: key,
65
+ length: key === "set" ? 1 : 2,
66
+ call: (args, context) => {
67
+ const receiver = context?.thisValue;
68
+ if (!isFloat32Array(receiver))
69
+ throw new TypeError(`Float32Array#${key} requires a Float32Array receiver.`);
70
+ const storage = float32Storage(receiver);
71
+ if (key === "set") {
72
+ const [source, offsetValue = 0] = args;
73
+ if (!Array.isArray(source) && !isFloat32Array(source))
74
+ throw new TypeError("Float32Array#set requires an array or Float32Array.");
75
+ const number = float32Number(offsetValue);
76
+ const offset = Number.isNaN(number) ? 0 : Math.trunc(number);
77
+ const length = isFloat32Array(source) ? float32Storage(source).length : source.length;
78
+ if (offset < 0 || !Number.isSafeInteger(offset) || offset + length > storage.length)
79
+ throw new RangeError("Float32Array#set source is out of bounds.");
80
+ if (isFloat32Array(source)) {
81
+ Float32Array.prototype.set.call(receiver, source, offset);
82
+ return undefined;
83
+ }
84
+ checkFloat32Allocation(length, budget);
85
+ const copied = new Float32Array(length);
86
+ for (let index = 0; index < length; index += 1) {
87
+ budget.visitNode();
88
+ const entry = Object.getOwnPropertyDescriptor(source, index);
89
+ if (entry !== undefined && !("value" in entry))
90
+ throw new TypeError("Float32Array input accessors are not supported.");
91
+ copied[index] = float32Number(entry?.value);
92
+ }
93
+ Float32Array.prototype.set.call(receiver, copied, offset);
94
+ return undefined;
95
+ }
96
+ const start = relativeIndex(args[0], storage.length, 0);
97
+ const end = relativeIndex(args[1], storage.length, storage.length);
98
+ const length = Math.max(end - start, 0);
99
+ if (key === "subarray")
100
+ return new Float32Array(storage.buffer, storage.byteOffset + start * 4, length);
101
+ checkFloat32Allocation(length, budget);
102
+ const result = new Float32Array(length);
103
+ new Uint8Array(result.buffer).set(new Uint8Array(storage.buffer, storage.byteOffset + start * 4, length * 4));
104
+ return result;
105
+ }
106
+ });
107
+ }
108
+ export function setFloat32Member(value, property, entry) {
109
+ const key = String(property);
110
+ if (isFloat32Index(key)) {
111
+ Reflect.set(value, key, float32Number(entry));
112
+ return;
113
+ }
114
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
115
+ if (descriptor === undefined &&
116
+ ["length", "byteLength", "byteOffset", "buffer", "BYTES_PER_ELEMENT"].includes(key))
117
+ throw new TypeError(`Cannot assign to read only property '${key}'.`);
118
+ if (descriptor !== undefined && (!("value" in descriptor) || !descriptor.writable))
119
+ throw new TypeError(`Cannot assign to read only property '${key}'.`);
120
+ Object.defineProperty(value, key, descriptor === undefined
121
+ ? { value: entry, configurable: true, enumerable: true, writable: true }
122
+ : { value: entry });
123
+ }
124
+ function relativeIndex(value, length, fallback) {
125
+ if (value === undefined)
126
+ return fallback;
127
+ const numeric = float32Number(value);
128
+ const integer = Number.isNaN(numeric) ? 0 : Math.trunc(numeric);
129
+ return integer < 0 ? Math.max(length + integer, 0) : Math.min(integer, length);
130
+ }
@@ -1,4 +1,6 @@
1
1
  import { sandboxErrorTypes } from "../../error/shape.js";
2
+ import { isFloat32Array } from "../float32.js";
3
+ import { setFloat32Member } from "./float32array.js";
2
4
  import { getSandboxIterator } from "../iteration.js";
3
5
  import { allocateProducedSandboxValue, createSandboxClosure, deepCopyToSandbox, isSandboxClosure, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet } from "../values.js";
4
6
  export function createObjectArrayGlobals(options) {
@@ -213,6 +215,10 @@ function assignSandboxValues(target, sources) {
213
215
  continue;
214
216
  }
215
217
  for (const [key, value] of getOwnEnumerableEntries(source)) {
218
+ if (isFloat32Array(target)) {
219
+ setFloat32Member(target, key, value);
220
+ continue;
221
+ }
216
222
  Object.defineProperty(target, key, {
217
223
  configurable: true,
218
224
  enumerable: true,
@@ -1,6 +1,7 @@
1
1
  import { normalizeClosureResult } from "./async.js";
2
2
  import { attachErrorSpan, replaceErrorStack } from "../error/shape.js";
3
3
  import { SandboxError } from "./budget.js";
4
+ import { checkFloat32Allocation, copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
4
5
  import { createSubsetErrorValue } from "./exceptions.js";
5
6
  import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
6
7
  import { digestHostCallArguments, HostCallResumabilityError, UnresolvedReplayCapabilityError } from "./host-call.js";
@@ -593,6 +594,23 @@ function copyHostValueToSandbox(value, stackFrames, options, state, path) {
593
594
  : path
594
595
  }, state);
595
596
  }
597
+ if (isFloat32Array(value)) {
598
+ const existing = state.seen.get(value);
599
+ if (existing !== undefined)
600
+ return existing;
601
+ checkFloat32Allocation(Math.ceil(float32Storage(value).byteLength / 4), budget);
602
+ const copy = copyFloat32Storage(value, state);
603
+ state.seen.set(value, copy);
604
+ for (const [key, descriptor] of float32DataProperties(value)) {
605
+ Object.defineProperty(copy, key, {
606
+ ...descriptor,
607
+ value: copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), key] }, state, joinPath(path, key))
608
+ });
609
+ }
610
+ if (!Object.isExtensible(value))
611
+ Object.preventExtensions(copy);
612
+ return copy;
613
+ }
596
614
  if (!options.errorData && isPromiseLike(value)) {
597
615
  if (options.proofFunctions !== undefined)
598
616
  throw new TypeError(`Unsupported proof value at ${path}: promise`);
@@ -1,4 +1,5 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
+ import { float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
2
3
  import { cloneSandboxValue, createSandboxClosure, defineOwnDataProperty, isArrayIndexKey, measureSandboxData } from "./values.js";
3
4
  import { decodeReplayData, encodeReplayData } from "../snapshot/replay-data.js";
4
5
  import { validateSnapshotData } from "../snapshot/validation.js";
@@ -534,6 +535,20 @@ function normalize(value, seen) {
534
535
  throw new TypeError("Host call arguments cannot contain cycles.");
535
536
  seen.add(value);
536
537
  try {
538
+ if (isFloat32Array(value)) {
539
+ const storage = float32Storage(value);
540
+ const properties = Object.create(null);
541
+ for (const [key, descriptor] of float32DataProperties(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)) {
542
+ defineOwnDataProperty(properties, key, normalize(descriptor.value, seen));
543
+ }
544
+ return Object.assign(Object.create(null), {
545
+ $type: "float32array",
546
+ bytes: normalize(Array.from(new Uint8Array(storage.buffer)), seen),
547
+ byteOffset: storage.byteOffset,
548
+ length: storage.length,
549
+ properties
550
+ });
551
+ }
537
552
  if (Array.isArray(value)) {
538
553
  const normalized = new Array(value.length);
539
554
  Object.setPrototypeOf(normalized, null);
@@ -21,6 +21,8 @@ import { callStringMethod, getStringMember, isStringMethodName, validateStringMe
21
21
  import { callSetMethod, getSetMember, isSetMethodName } from "./methods/set.js";
22
22
  import { isSandboxErrorConstructor, isSandboxErrorConstructorInstance } from "./globals/error.js";
23
23
  import { isSandboxMapConstructor, isSandboxSetConstructor } from "./globals/collections.js";
24
+ import { getFloat32Member, isFloat32ArrayConstructor, setFloat32Member } from "./globals/float32array.js";
25
+ import { isFloat32Array } from "./float32.js";
24
26
  import { createSandboxRegex, allocateProducedSandboxValue, isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, isSandboxRegex, isSandboxSet, measureSandboxData } from "./values.js";
25
27
  import { Scope } from "./scope.js";
26
28
  import { hoistVarDeclarations } from "./var-hoist.js";
@@ -1071,7 +1073,10 @@ function forInObject(value) {
1071
1073
  if (value === null || value === undefined || isSandboxClosure(value) || isSandboxPromise(value)) {
1072
1074
  return undefined;
1073
1075
  }
1074
- if (typeof value === "string" || Array.isArray(value) || isPlainForInObject(value)) {
1076
+ if (typeof value === "string" ||
1077
+ Array.isArray(value) ||
1078
+ isFloat32Array(value) ||
1079
+ isPlainForInObject(value)) {
1075
1080
  return Object(value);
1076
1081
  }
1077
1082
  return undefined;
@@ -1573,6 +1578,8 @@ function getPropertyValue(target, property, context) {
1573
1578
  return getNumberMember(target, property, context.budget);
1574
1579
  if (typeof target === "boolean")
1575
1580
  return undefined;
1581
+ if (isFloat32Array(target))
1582
+ return getFloat32Member(target, property, context.budget);
1576
1583
  if (isSandboxMap(target))
1577
1584
  return getMapMember(target, property, createMapMethodOptions(context));
1578
1585
  if (isSandboxSet(target))
@@ -1781,6 +1788,9 @@ async function evaluateMemberCallExpression(node, context) {
1781
1788
  if (isSandboxMap(member.object)) {
1782
1789
  return evaluatePrimitiveMemberCall(node, "Map", member.property, getMapMember(member.object, member.property, createMapMethodOptions(context)), context);
1783
1790
  }
1791
+ if (isFloat32Array(member.object)) {
1792
+ return evaluateResolvedCallExpression(node, getFloat32Member(member.object, member.property, context.budget), context, member.object);
1793
+ }
1784
1794
  if (isSandboxSet(member.object)) {
1785
1795
  return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
1786
1796
  }
@@ -1988,6 +1998,8 @@ function applyBinaryOperator(node, left, right, context) {
1988
1998
  if (isSandboxMapConstructor(right) && isSandboxMap(left)) {
1989
1999
  return true;
1990
2000
  }
2001
+ if (isFloat32ArrayConstructor(right))
2002
+ return isFloat32Array(left);
1991
2003
  if (isSandboxSetConstructor(right) && isSandboxSet(left)) {
1992
2004
  return true;
1993
2005
  }
@@ -2208,6 +2220,10 @@ function getArrayMemberValue(target, property, context) {
2208
2220
  return getArrayMember(target, property, createArrayMethodOptions(context));
2209
2221
  }
2210
2222
  function setSandboxProperty(target, property, value) {
2223
+ if (isFloat32Array(target)) {
2224
+ setFloat32Member(target, property, value);
2225
+ return;
2226
+ }
2211
2227
  if (isSandboxRegex(target)) {
2212
2228
  setRegexMember(target, property, value);
2213
2229
  return;
@@ -1,6 +1,10 @@
1
1
  import { isSandboxGenerator, isSandboxMap, isSandboxSet } from "./values.js";
2
2
  import { enterRunningState } from "./running-state.js";
3
+ import { isFloat32Array } from "./float32.js";
3
4
  export function getSandboxIterator(value) {
5
+ if (isFloat32Array(value)) {
6
+ return syncIterator(Float32Array.prototype.values.call(value));
7
+ }
4
8
  if (isSandboxGenerator(value)) {
5
9
  return generatorIterator(value);
6
10
  }
@@ -11,7 +11,7 @@ declare const sandboxRegexPattern: unique symbol;
11
11
  declare const sandboxSetBrand: unique symbol;
12
12
  declare const sandboxRetainedValues: unique symbol;
13
13
  export type SandboxPrimitive = string | number | boolean | null | undefined;
14
- export type SandboxValue = SandboxPrimitive | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
14
+ export type SandboxValue = SandboxPrimitive | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
15
15
  export type SandboxObject = {
16
16
  [key: string]: SandboxValue;
17
17
  };
@@ -1,4 +1,5 @@
1
1
  import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
2
+ import { copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
2
3
  import { SandboxError } from "./budget.js";
3
4
  import { observeSandboxPromise, trackSandboxPromise } from "./promise-tracker.js";
4
5
  import { promiseReplayContext } from "./promise-replay.js";
@@ -198,6 +199,18 @@ export function measureSandboxData(values, options = {}) {
198
199
  return;
199
200
  seen.add(value);
200
201
  usage += 1;
202
+ if (isFloat32Array(value)) {
203
+ const storage = float32Storage(value);
204
+ if (!seen.has(storage.buffer)) {
205
+ seen.add(storage.buffer);
206
+ usage += storage.byteLength;
207
+ }
208
+ for (const [key, descriptor] of float32DataProperties(value)) {
209
+ usage += key.length + 1;
210
+ visit(descriptor.value);
211
+ }
212
+ return;
213
+ }
201
214
  if (Array.isArray(value)) {
202
215
  usage += value.length;
203
216
  for (let index = 0; index < value.length; index += 1) {
@@ -315,6 +328,22 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
315
328
  }
316
329
  return sandboxPromise;
317
330
  }
331
+ if (isFloat32Array(value)) {
332
+ const existing = state.seen.get(value);
333
+ if (existing !== undefined)
334
+ return existing;
335
+ const copy = copyFloat32Storage(value, state);
336
+ state.seen.set(value, copy);
337
+ for (const [key, descriptor] of float32DataProperties(value)) {
338
+ Object.defineProperty(copy, key, {
339
+ ...descriptor,
340
+ value: copyToSandbox(descriptor.value, state, joinPath(path, key), cloneSandboxCollections, depth + 1)
341
+ });
342
+ }
343
+ if (!Object.isExtensible(value))
344
+ Object.preventExtensions(copy);
345
+ return copy;
346
+ }
318
347
  if (value instanceof Map) {
319
348
  const existing = state.seen.get(value);
320
349
  if (existing !== undefined) {
@@ -382,6 +411,22 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
382
411
  if (isSandboxPrimitive(value)) {
383
412
  return value;
384
413
  }
414
+ if (isFloat32Array(value)) {
415
+ const existing = state.seen.get(value);
416
+ if (existing !== undefined)
417
+ return existing;
418
+ const copy = copyFloat32Storage(value, state);
419
+ state.seen.set(value, copy);
420
+ for (const [key, descriptor] of float32DataProperties(value)) {
421
+ Object.defineProperty(copy, key, {
422
+ ...descriptor,
423
+ value: copyFromSandbox(descriptor.value, state, joinPath(path, key), options, depth + 1)
424
+ });
425
+ }
426
+ if (!Object.isExtensible(value))
427
+ Object.preventExtensions(copy);
428
+ return copy;
429
+ }
385
430
  if (isSandboxClosure(value)) {
386
431
  if (options.wrapClosure === undefined) {
387
432
  throw new TypeError("Sandbox closures cannot cross into host values without an explicit wrapper.");
@@ -482,6 +527,17 @@ function allocateSandboxValue(value, budget, seen) {
482
527
  budget.allocateString(value);
483
528
  return;
484
529
  }
530
+ if (isFloat32Array(value)) {
531
+ if (seen.has(value))
532
+ return;
533
+ seen.add(value);
534
+ budget.allocateArrayLength(Math.ceil(float32Storage(value).byteLength / 4));
535
+ for (const [key, descriptor] of float32DataProperties(value)) {
536
+ budget.allocateString(key);
537
+ allocateSandboxValue(descriptor.value, budget, seen);
538
+ }
539
+ return;
540
+ }
485
541
  if (Array.isArray(value)) {
486
542
  if (seen.has(value)) {
487
543
  return;
@@ -1 +1 @@
1
- export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "Error", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "structuredClone", "SyntaxError", "TypeError", "console"];
1
+ export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "Error", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "structuredClone", "SyntaxError", "TypeError", "console"];
@@ -8,6 +8,7 @@ export const KNOWN_RUNTIME_GLOBALS = [
8
8
  "isNaN",
9
9
  "JSON",
10
10
  "Map",
11
+ "Float32Array",
11
12
  "Math",
12
13
  "NaN",
13
14
  "Number",
@@ -13,6 +13,7 @@ import { createSandboxPromiseRejectionTracker, observeSandboxPromise, withSandbo
13
13
  import { HostCallJournal } from "./interp/host-call.js";
14
14
  import { createConsoleJsonGlobals } from "./interp/globals/console-json.js";
15
15
  import { createCollectionGlobals } from "./interp/globals/collections.js";
16
+ import { createFloat32ArrayGlobal } from "./interp/globals/float32array.js";
16
17
  import { createErrorGlobals } from "./interp/globals/error.js";
17
18
  import { createMathGlobals } from "./interp/globals/math.js";
18
19
  import { createRegexGlobals } from "./interp/globals/regex.js";
@@ -111,6 +112,7 @@ export function run(source, options = {}) {
111
112
  sink: options.sink
112
113
  }),
113
114
  ...createCollectionGlobals({ budget }),
115
+ Float32Array: createFloat32ArrayGlobal(budget),
114
116
  ...createErrorGlobals({
115
117
  budget
116
118
  }),
@@ -5,6 +5,8 @@ import { sandboxErrorTypes } from "../error/shape.js";
5
5
  import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/arguments.js";
6
6
  import { serializeArguments } from "./arguments.js";
7
7
  import { requiresArrayEntries, serializeArray } from "./arrays.js";
8
+ import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
9
+ import { encodeFloat32Storage } from "./float32array.js";
8
10
  const SKIP_VALUE = Symbol("SafeJS.skip-dump-value");
9
11
  export function serializeSafeJSSnapshot(snapshot) {
10
12
  const replayError = Object.getOwnPropertyDescriptor(snapshot, "replayError");
@@ -23,6 +25,7 @@ export function serializeSafeJSSnapshot(snapshot) {
23
25
  }
24
26
  function createDumpFile(snapshot) {
25
27
  const state = {
28
+ float32Buffers: new WeakMap(),
26
29
  heap: {},
27
30
  heapIds: indexHeapContainers(snapshot),
28
31
  serializedHeapIds: new Set()
@@ -65,6 +68,8 @@ function serializeDumpValue(value, path, state) {
65
68
  if (typeof value !== "object") {
66
69
  return SKIP_VALUE;
67
70
  }
71
+ if (isFloat32Array(value))
72
+ return serializeHeapReference(value, path, state);
68
73
  if (Array.isArray(value)) {
69
74
  const reference = serializeHeapReference(value, path, state);
70
75
  if (reference !== undefined) {
@@ -88,7 +93,19 @@ function serializeHeapReference(value, path, state) {
88
93
  }
89
94
  if (!state.serializedHeapIds.has(id)) {
90
95
  state.serializedHeapIds.add(id);
91
- if (isSandboxArguments(value)) {
96
+ if (isFloat32Array(value)) {
97
+ const storage = encodeFloat32Storage(value, id, state.float32Buffers, (id) => ({
98
+ kind: "ref",
99
+ id
100
+ }));
101
+ const entries = Object.create(null);
102
+ state.heap[String(id)] = { ...storage, entries };
103
+ for (const [key, descriptor] of float32DataProperties(value)) {
104
+ const serialized = serializeDumpValue(descriptor.value, `${path}.${key}`, state);
105
+ entries[key] = serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
106
+ }
107
+ }
108
+ else if (isSandboxArguments(value)) {
92
109
  state.heap[String(id)] = serializeArguments(value, (entry, key) => {
93
110
  const serialized = serializeDumpValue(entry, `${path}.${key}`, state);
94
111
  return serialized === SKIP_VALUE ? { kind: "undefined" } : serialized;
@@ -138,6 +155,7 @@ function indexHeapContainers(snapshot) {
138
155
  for (const [value, stat] of stats.entries()) {
139
156
  if (stat.count > 1 ||
140
157
  stat.cyclic ||
158
+ isFloat32Array(value) ||
141
159
  (Array.isArray(value) && requiresArrayEntries(value)) ||
142
160
  isSandboxArguments(value) ||
143
161
  sandboxErrorTypes.has(value)) {
@@ -151,7 +169,7 @@ function collectContainerStats(value, stats, ancestors) {
151
169
  if (value === null || typeof value !== "object") {
152
170
  return;
153
171
  }
154
- if (!Array.isArray(value) && !isPlainObject(value)) {
172
+ if (!Array.isArray(value) && !isPlainObject(value) && !isFloat32Array(value)) {
155
173
  return;
156
174
  }
157
175
  let stat = stats.get(value);
@@ -0,0 +1,12 @@
1
+ export type Float32Data<TReference> = {
2
+ kind: "float32array";
3
+ byteOffset: number;
4
+ length: number;
5
+ } & ({
6
+ bytes: number[];
7
+ } | {
8
+ buffer: TReference;
9
+ });
10
+ export declare function encodeFloat32Storage<TReference>(value: Float32Array, id: number, buffers: WeakMap<ArrayBuffer, number>, reference: (id: number) => TReference): Float32Data<TReference>;
11
+ export declare function validateFloat32Storage(value: Record<string, unknown>): void;
12
+ export declare function decodeFloat32Storage(value: Record<string, unknown>, resolve: (reference: unknown) => unknown): Float32Array;