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.
- package/dist/index.js +1105 -223
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js → chunk-2EZQJQ2C.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-V6LQP64H.js → chunk-CYVI4ZUK.js} +978 -161
- package/packages/safe-js/dist/chunks/chunk-CYVI4ZUK.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/array-buffer.d.ts +12 -0
- package/packages/safe-js/dist/interp/array-buffer.js +33 -0
- package/packages/safe-js/dist/interp/float32-prototypes.d.ts +3 -0
- package/packages/safe-js/dist/interp/float32-prototypes.js +1 -0
- package/packages/safe-js/dist/interp/float32.d.ts +7 -1
- package/packages/safe-js/dist/interp/float32.js +50 -14
- package/packages/safe-js/dist/interp/globals/array-buffer.d.ts +3 -0
- package/packages/safe-js/dist/interp/globals/array-buffer.js +112 -0
- package/packages/safe-js/dist/interp/globals/float32array.d.ts +4 -3
- package/packages/safe-js/dist/interp/globals/float32array.js +463 -68
- package/packages/safe-js/dist/interp/globals/object-array.js +3 -3
- package/packages/safe-js/dist/interp/globals.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals.js +6 -2
- package/packages/safe-js/dist/interp/host-bridge.d.ts +1 -0
- package/packages/safe-js/dist/interp/host-bridge.js +21 -0
- package/packages/safe-js/dist/interp/host-call.js +26 -2
- package/packages/safe-js/dist/interp/instanceof.js +1 -1
- package/packages/safe-js/dist/interp/interpreter.js +2 -4
- package/packages/safe-js/dist/interp/iteration.js +15 -6
- package/packages/safe-js/dist/interp/methods/array-iterator.js +1 -1
- package/packages/safe-js/dist/interp/object-model.js +22 -1
- package/packages/safe-js/dist/interp/values.d.ts +1 -1
- package/packages/safe-js/dist/interp/values.js +59 -9
- package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
- package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
- package/packages/safe-js/dist/parse/parser.js +8 -3
- package/packages/safe-js/dist/parse/tokenizer.js +45 -3
- package/packages/safe-js/dist/snapshot/array-buffer.d.ts +13 -0
- package/packages/safe-js/dist/snapshot/array-buffer.js +40 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +25 -9
- package/packages/safe-js/dist/snapshot/float32array.d.ts +11 -1
- package/packages/safe-js/dist/snapshot/float32array.js +42 -5
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +5 -0
- package/packages/safe-js/dist/snapshot/replay-data.js +35 -10
- package/packages/safe-js/dist/snapshot/restore.js +30 -3
- package/packages/safe-js/dist/snapshot/serialize.d.ts +7 -3
- package/packages/safe-js/dist/snapshot/serialize.js +24 -14
- package/packages/safe-js/dist/snapshot/validation.js +21 -1
- package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js.map → chunk-2EZQJQ2C.js.map} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createConsoleJsonGlobals } from "./globals/console-json.js";
|
|
2
2
|
import { createCollectionGlobals } from "./globals/collections.js";
|
|
3
|
-
import { createFloat32ArrayGlobal } from "./globals/float32array.js";
|
|
3
|
+
import { createFloat32ArrayGlobal, createFloat32ArrayPrototypes } from "./globals/float32array.js";
|
|
4
4
|
import { createErrorGlobals, createErrorPrototypes } from "./globals/error.js";
|
|
5
5
|
import { createMathGlobals } from "./globals/math.js";
|
|
6
6
|
import { createRegexGlobals } from "./globals/regex.js";
|
|
@@ -13,24 +13,28 @@ import { createPromiseGlobals } from "./promise.js";
|
|
|
13
13
|
import { createDateGlobal } from "./globals/date.js";
|
|
14
14
|
import { createSymbolGlobal } from "./globals/symbol.js";
|
|
15
15
|
import { createBigIntGlobal } from "./globals/bigint.js";
|
|
16
|
+
import { createArrayBufferGlobal } from "./globals/array-buffer.js";
|
|
16
17
|
import { registerBuiltinIdentities } from "./intrinsics.js";
|
|
17
18
|
export function createBuiltinBindings(options) {
|
|
18
19
|
const bindings = {
|
|
19
20
|
...createConsoleJsonGlobals(options),
|
|
20
21
|
...createCollectionGlobals(options),
|
|
21
|
-
Float32Array: createFloat32ArrayGlobal(options.budget),
|
|
22
|
+
Float32Array: createFloat32ArrayGlobal(options.budget, options.float32Prototypes !== false),
|
|
22
23
|
Date: createDateGlobal(options),
|
|
23
24
|
Symbol: createSymbolGlobal(options.budget),
|
|
24
25
|
BigInt: createBigIntGlobal(options.budget),
|
|
25
26
|
...createErrorGlobals({ ...options, errorPrototypes: options.errorPrototypes !== false }),
|
|
26
27
|
...createMathGlobals({ random: options.random, budget: options.budget }),
|
|
27
28
|
...createObjectArrayGlobals(options),
|
|
29
|
+
ArrayBuffer: createArrayBufferGlobal(options.budget),
|
|
28
30
|
...createMiscGlobals(options),
|
|
29
31
|
...createUriGlobals(options.budget),
|
|
30
32
|
...createPromiseGlobals(options),
|
|
31
33
|
...createRegexGlobals(options)
|
|
32
34
|
};
|
|
33
35
|
createFunctionPrototype(options.budget, options.functionHasInstance);
|
|
36
|
+
if (options.float32Prototypes !== false)
|
|
37
|
+
createFloat32ArrayPrototypes(options.budget, bindings.Float32Array);
|
|
34
38
|
if (options.errorPrototypes !== false)
|
|
35
39
|
createErrorPrototypes(options.budget, bindings);
|
|
36
40
|
createGeneratorPrototypes(options.budget);
|
|
@@ -5,6 +5,7 @@ import { exportHostCapability, importHostCapability, isLiveCapability } from "./
|
|
|
5
5
|
import { attachErrorSpan, replaceErrorStack } from "../error/shape.js";
|
|
6
6
|
import { SandboxError } from "./budget.js";
|
|
7
7
|
import { CompileScope } from "./regex/compile-guard.js";
|
|
8
|
+
import { arrayBufferDataProperties, arrayBufferLength, copyArrayBufferStorage, isSandboxArrayBuffer } from "./array-buffer.js";
|
|
8
9
|
import { checkFloat32Allocation, copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
|
|
9
10
|
import { createSubsetErrorValue } from "./exceptions.js";
|
|
10
11
|
import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
@@ -705,6 +706,25 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
|
|
|
705
706
|
state.seen.set(value, date);
|
|
706
707
|
return date;
|
|
707
708
|
}
|
|
709
|
+
if (isSandboxArrayBuffer(value)) {
|
|
710
|
+
const existing = state.seen.get(value);
|
|
711
|
+
if (existing !== undefined)
|
|
712
|
+
return existing;
|
|
713
|
+
const length = arrayBufferLength(value);
|
|
714
|
+
budget.allocateArrayLength(length);
|
|
715
|
+
budget.provisionDataUsage(length + 1)();
|
|
716
|
+
const copy = copyArrayBufferStorage(value, state);
|
|
717
|
+
state.seen.set(value, copy);
|
|
718
|
+
for (const [key, descriptor] of arrayBufferDataProperties(value)) {
|
|
719
|
+
if (typeof key === "symbol")
|
|
720
|
+
throw new TypeError("Host ArrayBuffer symbol properties require an explicit capability path.");
|
|
721
|
+
Object.defineProperty(copy, key, { ...descriptor,
|
|
722
|
+
value: copyHostValueToSandbox(descriptor.value, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), key] }, state, joinPath(path, key)) });
|
|
723
|
+
}
|
|
724
|
+
if (!Object.isExtensible(value))
|
|
725
|
+
Object.preventExtensions(copy);
|
|
726
|
+
return copy;
|
|
727
|
+
}
|
|
708
728
|
if (isFloat32Array(value)) {
|
|
709
729
|
const existing = state.seen.get(value);
|
|
710
730
|
if (existing !== undefined)
|
|
@@ -712,6 +732,7 @@ export function copyHostValueToSandbox(value, stackFrames, options, state, path)
|
|
|
712
732
|
checkFloat32Allocation(Math.ceil(float32Storage(value).byteLength / 4), budget);
|
|
713
733
|
const copy = copyFloat32Storage(value, state);
|
|
714
734
|
state.seen.set(value, copy);
|
|
735
|
+
copyHostValueToSandbox(float32Storage(value).buffer, stackFrames, { ...options, capabilityPath: [...(options.capabilityPath ?? []), "buffer"] }, state, `${path}.buffer`);
|
|
715
736
|
for (const [key, descriptor] of float32DataProperties(value)) {
|
|
716
737
|
Object.defineProperty(copy, key, {
|
|
717
738
|
...descriptor,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
|
|
2
|
+
import { float32DataProperties, float32Storage, float32ViewLayouts, isFloat32Array } from "./float32.js";
|
|
3
|
+
import { arrayBufferDataProperties, arrayBufferLength, arrayBufferOptions, isSandboxArrayBuffer } from "./array-buffer.js";
|
|
3
4
|
import { copyNativeDate, serializedDateTime } from "./date.js";
|
|
4
5
|
import { cloneSandboxValue, createSandboxClosure, defineOwnDataProperty, isArrayIndexKey, measureSandboxData } from "./values.js";
|
|
5
6
|
import { CompileScope } from "./regex/compile-guard.js";
|
|
@@ -585,8 +586,26 @@ function normalize(value, seen) {
|
|
|
585
586
|
const date = copyNativeDate(value);
|
|
586
587
|
if (date !== undefined)
|
|
587
588
|
return Object.assign(Object.create(null), { $type: "date", time: serializedDateTime(date) });
|
|
589
|
+
if (isSandboxArrayBuffer(value)) {
|
|
590
|
+
arrayBufferLength(value);
|
|
591
|
+
const properties = Object.create(null);
|
|
592
|
+
const entries = [];
|
|
593
|
+
for (const [key, descriptor] of arrayBufferDataProperties(value)) {
|
|
594
|
+
if (typeof key === "symbol")
|
|
595
|
+
throw new TypeError("ArrayBuffer symbol properties require an explicit host-call identity.");
|
|
596
|
+
entries.push([key, descriptor]);
|
|
597
|
+
}
|
|
598
|
+
for (const [key, descriptor] of entries.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0))
|
|
599
|
+
defineOwnDataProperty(properties, key, normalize(descriptor.value, seen));
|
|
600
|
+
return Object.assign(Object.create(null), { $type: "arraybuffer",
|
|
601
|
+
bytes: normalize(Array.from(new Uint8Array(value)), seen), ...arrayBufferOptions(value), properties });
|
|
602
|
+
}
|
|
588
603
|
if (isFloat32Array(value)) {
|
|
589
604
|
const storage = float32Storage(value);
|
|
605
|
+
const resizable = arrayBufferOptions(storage.buffer) !== undefined;
|
|
606
|
+
const layout = resizable ? float32ViewLayouts.get(value) : undefined;
|
|
607
|
+
if (resizable && layout === undefined)
|
|
608
|
+
throw new TypeError("Resizable Float32Array host-call identity requires known view layout.");
|
|
590
609
|
const properties = Object.create(null);
|
|
591
610
|
for (const [key, descriptor] of float32DataProperties(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)) {
|
|
592
611
|
defineOwnDataProperty(properties, key, normalize(descriptor.value, seen));
|
|
@@ -596,7 +615,12 @@ function normalize(value, seen) {
|
|
|
596
615
|
bytes: normalize(Array.from(new Uint8Array(storage.buffer)), seen),
|
|
597
616
|
byteOffset: storage.byteOffset,
|
|
598
617
|
length: storage.length,
|
|
599
|
-
properties
|
|
618
|
+
properties,
|
|
619
|
+
...(resizable || Reflect.ownKeys(storage.buffer).length > 0
|
|
620
|
+
? { buffer: normalize(storage.buffer, seen) } : {}),
|
|
621
|
+
...(layout === undefined ? {} : { viewLayout: {
|
|
622
|
+
byteOffset: layout.byteOffset, length: layout.length ?? null
|
|
623
|
+
} })
|
|
600
624
|
});
|
|
601
625
|
}
|
|
602
626
|
if (Array.isArray(value)) {
|
|
@@ -27,7 +27,7 @@ export async function ordinaryHasInstance(value, constructor, budget, context) {
|
|
|
27
27
|
return evaluateInstanceof(value, constructor.boundTarget, budget, context);
|
|
28
28
|
}
|
|
29
29
|
// These existing built-ins do not yet have ordinary prototype graphs.
|
|
30
|
-
if (isFloat32ArrayConstructor(constructor))
|
|
30
|
+
if (isFloat32ArrayConstructor(constructor) && !isGuestClosure(constructor))
|
|
31
31
|
return isFloat32Array(value);
|
|
32
32
|
if ((!isGuestClosure(constructor) || (value !== null && typeof value === "object" && !hasExplicitSandboxPrototype(value))) &&
|
|
33
33
|
isSandboxErrorConstructorInstance(value, constructor))
|
|
@@ -2380,7 +2380,7 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
2380
2380
|
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2381
2381
|
}
|
|
2382
2382
|
if (isFloat32Array(member.object)) {
|
|
2383
|
-
return evaluateResolvedCallExpression(node,
|
|
2383
|
+
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2384
2384
|
}
|
|
2385
2385
|
if (isSandboxSet(member.object)) {
|
|
2386
2386
|
return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
|
|
@@ -2911,9 +2911,7 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
|
|
|
2911
2911
|
if (isSandboxMap(target) || isSandboxSet(target))
|
|
2912
2912
|
target = getCollectionProperties(target);
|
|
2913
2913
|
if (isFloat32Array(target)) {
|
|
2914
|
-
|
|
2915
|
-
throw new TypeError("Typed array symbol properties are not yet supported.");
|
|
2916
|
-
setFloat32Member(target, property, value);
|
|
2914
|
+
setFloat32Member(target, property, value, budget);
|
|
2917
2915
|
return;
|
|
2918
2916
|
}
|
|
2919
2917
|
if (isSandboxRegex(target)) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxSet } from "./values.js";
|
|
2
2
|
import { enterRunningState } from "./running-state.js";
|
|
3
3
|
import { isFloat32Array } from "./float32.js";
|
|
4
|
+
import { float32Prototypes } from "./float32-prototypes.js";
|
|
4
5
|
import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
5
6
|
import { getHostObjectIterator, isGuestHostObject } from "./host-capabilities.js";
|
|
6
7
|
import { isSandboxCollectionIterator, nextCollectionIterator } from "./collection-iterator.js";
|
|
@@ -98,6 +99,9 @@ export async function acquireSandboxIterator(value, budget, context, asyncProtoc
|
|
|
98
99
|
const iterator = await invokeBuiltinClosure(factory, [], budget, context, value);
|
|
99
100
|
if ((typeof iterator !== "object" && typeof iterator !== "function") || iterator === null)
|
|
100
101
|
throw new TypeError("Iterator must be an object.");
|
|
102
|
+
if (!asyncProtocol && isSandboxGenerator(iterator) && !iterator.async &&
|
|
103
|
+
!hasExplicitSandboxPrototype(iterator) && getSandboxPropertyDescriptor(iterator, "next", budget) === undefined)
|
|
104
|
+
return getSandboxIterator(iterator, budget, context);
|
|
101
105
|
const next = await context.getProperty(iterator, "next");
|
|
102
106
|
return guestIterator(iterator, next, asyncProtocol, budget, context, signal);
|
|
103
107
|
}
|
|
@@ -137,7 +141,7 @@ export async function readIteratorResult(iterator, result, property) {
|
|
|
137
141
|
export function getSandboxAsyncIterator(value, budget, context, signal) {
|
|
138
142
|
if (isSandboxGenerator(value) && value.async) {
|
|
139
143
|
return hasExplicitSandboxPrototype(value) ? context?.getProperty === undefined
|
|
140
|
-
?
|
|
144
|
+
? guestProtocolAdapter(value, budget, context, true, signal) : undefined
|
|
141
145
|
: { ...generatorObjectIterator(value, budget, context), asyncProtocol: true };
|
|
142
146
|
}
|
|
143
147
|
if (value !== null &&
|
|
@@ -293,6 +297,11 @@ export function getSandboxIterator(value, budget, context) {
|
|
|
293
297
|
if (isGuestHostObject(value))
|
|
294
298
|
return getHostObjectIterator(value);
|
|
295
299
|
if (isFloat32Array(value)) {
|
|
300
|
+
if (hasExplicitSandboxPrototype(value) || (budget !== undefined && float32Prototypes.has(budget))) {
|
|
301
|
+
if (getSandboxPropertyDescriptor(value, Symbol.iterator, budget) === undefined)
|
|
302
|
+
return undefined;
|
|
303
|
+
return guestProtocolAdapter(value, budget ?? new Budget(), context, false);
|
|
304
|
+
}
|
|
296
305
|
return syncIterator(Float32Array.prototype.values.call(value));
|
|
297
306
|
}
|
|
298
307
|
if (isSandboxGenerator(value)) {
|
|
@@ -300,7 +309,7 @@ export function getSandboxIterator(value, budget, context) {
|
|
|
300
309
|
return undefined;
|
|
301
310
|
if (hasExplicitSandboxPrototype(value))
|
|
302
311
|
return context?.getProperty === undefined
|
|
303
|
-
?
|
|
312
|
+
? guestProtocolAdapter(value, budget ?? new Budget(), context, false) : undefined;
|
|
304
313
|
return generatorObjectIterator(value, budget, context);
|
|
305
314
|
}
|
|
306
315
|
if (typeof value === "string") {
|
|
@@ -386,9 +395,9 @@ function collectionIterator(collection, value) {
|
|
|
386
395
|
return adapter;
|
|
387
396
|
}
|
|
388
397
|
const asyncGeneratorRequests = new WeakMap();
|
|
389
|
-
function
|
|
390
|
-
// Direct
|
|
391
|
-
// cached next methods
|
|
398
|
+
function guestProtocolAdapter(value, budget, context, asyncProtocol, signal) {
|
|
399
|
+
// Direct adapters still need guest property reads, receiver binding and
|
|
400
|
+
// cached next methods without exposing native iterator objects.
|
|
392
401
|
const bridge = {
|
|
393
402
|
...context,
|
|
394
403
|
stack: context?.stack ?? [],
|
|
@@ -403,7 +412,7 @@ function generatorProtocolAdapter(value, budget, context, asyncProtocol, signal)
|
|
|
403
412
|
let pending;
|
|
404
413
|
const initialize = () => pending ??= acquireSandboxIterator(value, budget, bridge, asyncProtocol, signal).then(iterator => {
|
|
405
414
|
if (iterator === undefined)
|
|
406
|
-
throw new TypeError("
|
|
415
|
+
throw new TypeError("Value does not provide an iterator protocol.");
|
|
407
416
|
return resolved = iterator;
|
|
408
417
|
});
|
|
409
418
|
return {
|
|
@@ -18,7 +18,7 @@ export async function nextArrayIterator(value, budget, context) {
|
|
|
18
18
|
?? getSandboxPropertyDescriptor(source, key, budget) ?? { value: undefined }, source, context);
|
|
19
19
|
try {
|
|
20
20
|
budget.visitNode();
|
|
21
|
-
const number = isFloat32Array(source) ? float32Storage(source).length
|
|
21
|
+
const number = isFloat32Array(source) ? float32Storage(source, true).length
|
|
22
22
|
: await sandboxNumber(await read("length"), budget, context);
|
|
23
23
|
const length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
|
|
24
24
|
if (index >= length) {
|
|
@@ -8,6 +8,9 @@ import { isSandboxDate } from "./date.js";
|
|
|
8
8
|
import { retainedAccessorClosures } from "./accessors.js";
|
|
9
9
|
import { getHostObjectMember, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
10
10
|
import { errorPrototypes } from "./error-prototypes.js";
|
|
11
|
+
import { float32Properties, isFloat32Array, isFloat32Index } from "./float32.js";
|
|
12
|
+
import { float32Prototypes } from "./float32-prototypes.js";
|
|
13
|
+
import { arrayBufferPrototypes, isSandboxArrayBuffer } from "./array-buffer.js";
|
|
11
14
|
import { sandboxErrorTypes } from "../error/shape.js";
|
|
12
15
|
import { boxedValue, isSandboxBox } from "./boxed.js";
|
|
13
16
|
import { isSandboxClosure, isSandboxGenerator, isSandboxMap, isSandboxPromise, getPromiseProperties, isSandboxRegex, getRegexProperties, getCollectionProperties, isSandboxSet } from "./values.js";
|
|
@@ -276,12 +279,18 @@ export function releaseObjectPrototype(budget) {
|
|
|
276
279
|
functionPrototypes.delete(budget);
|
|
277
280
|
generatorPrototypes.delete(budget);
|
|
278
281
|
errorPrototypes.delete(budget);
|
|
282
|
+
float32Prototypes.delete(budget);
|
|
283
|
+
arrayBufferPrototypes.delete(budget);
|
|
279
284
|
initialRegexDescriptors.delete(budget);
|
|
280
285
|
intrinsicPrototypes.delete(budget);
|
|
281
286
|
}
|
|
282
287
|
export function getSandboxPrototype(value, budget) {
|
|
283
288
|
if (prototypes.has(value))
|
|
284
289
|
return prototypes.get(value) ?? null;
|
|
290
|
+
if (isSandboxArrayBuffer(value))
|
|
291
|
+
return budget === undefined ? null : arrayBufferPrototypes.get(budget) ?? null;
|
|
292
|
+
if (isFloat32Array(value))
|
|
293
|
+
return budget === undefined ? null : float32Prototypes.get(budget) ?? null;
|
|
285
294
|
// Host transport records are data-only. Resolve their default prototype in
|
|
286
295
|
// the receiving realm without persisting executable intrinsic graphs.
|
|
287
296
|
const errorType = sandboxErrorTypes.get(value);
|
|
@@ -328,6 +337,10 @@ export function getSandboxPropertyDescriptor(value, key, budget) {
|
|
|
328
337
|
while (typeof current === "object" &&
|
|
329
338
|
current !== null &&
|
|
330
339
|
(Array.isArray(current) || isSandboxGenerator(current) || isSandboxDate(current) || isSandboxPromise(current) || isSandboxRegex(current) || isSandboxMap(current) || isSandboxSet(current) || isPrototypeRecord(current))) {
|
|
340
|
+
// An integer-indexed object stops numeric-key lookup even when it occurs
|
|
341
|
+
// inside another object's prototype chain and the index is invalid.
|
|
342
|
+
if (isFloat32Array(current) && typeof key !== "symbol" && isFloat32Index(String(key)))
|
|
343
|
+
return Object.getOwnPropertyDescriptor(current, key);
|
|
331
344
|
const properties = isSandboxGenerator(current) ? getGeneratorProperties(current) : isSandboxPromise(current) ? getPromiseProperties(current) : isGuestClosure(current)
|
|
332
345
|
? key === "prototype" && current.construct !== undefined && current.boundTarget === undefined
|
|
333
346
|
? materializeFunctionProperties(current) : getGuestFunctionProperties(current)
|
|
@@ -350,6 +363,8 @@ export function getSandboxDataProperty(value, key, budget) {
|
|
|
350
363
|
let current = value;
|
|
351
364
|
let depth = 0;
|
|
352
365
|
while (typeof current === "object" && current !== null) {
|
|
366
|
+
if (isFloat32Array(current) && typeof key !== "symbol" && isFloat32Index(String(key)))
|
|
367
|
+
return Object.getOwnPropertyDescriptor(current, key)?.value;
|
|
353
368
|
if (isGuestHostObject(current))
|
|
354
369
|
return typeof key === "symbol" ? undefined : getHostObjectMember(current, String(key));
|
|
355
370
|
if (isSandboxRegex(current))
|
|
@@ -416,6 +431,10 @@ export function setSandboxPrototype(value, prototype, budget) {
|
|
|
416
431
|
prototypes.set(value, prototype);
|
|
417
432
|
}
|
|
418
433
|
function isPrototypeRecord(value) {
|
|
434
|
+
if (isSandboxArrayBuffer(value))
|
|
435
|
+
return true;
|
|
436
|
+
if (isFloat32Array(value))
|
|
437
|
+
return true;
|
|
419
438
|
if (isGuestClosure(value))
|
|
420
439
|
return true;
|
|
421
440
|
if (isGuestHostObject(value))
|
|
@@ -447,5 +466,7 @@ export function hasGuestObjectState(value) {
|
|
|
447
466
|
if (isSandboxBox(value) || isSandboxDate(value))
|
|
448
467
|
return false;
|
|
449
468
|
return (descriptorObjects.has(value) &&
|
|
450
|
-
|
|
469
|
+
(isFloat32Array(value)
|
|
470
|
+
? float32Properties(value).map(([, descriptor]) => descriptor)
|
|
471
|
+
: Object.values(Object.getOwnPropertyDescriptors(value))).some((descriptor) => !descriptor.enumerable || !descriptor.configurable || !descriptor.writable));
|
|
451
472
|
}
|
|
@@ -17,7 +17,7 @@ declare const sandboxRegexBrand: unique symbol;
|
|
|
17
17
|
declare const sandboxRegexPattern: unique symbol;
|
|
18
18
|
declare const sandboxRetainedValues: unique symbol;
|
|
19
19
|
export type SandboxPrimitive = string | number | bigint | boolean | symbol | null | undefined;
|
|
20
|
-
export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
|
|
20
|
+
export type SandboxValue = SandboxPrimitive | Date | Float32Array | ArrayBuffer | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
|
|
21
21
|
export type SandboxObject = {
|
|
22
22
|
[key: string]: SandboxValue;
|
|
23
23
|
[key: symbol]: SandboxValue;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { bindOtelSpan, getBoundOtelSpan } from "../observability/otel.js";
|
|
2
|
+
import { arrayBufferDataProperties, arrayBufferLength, copyArrayBufferStorage, isSandboxArrayBuffer } from "./array-buffer.js";
|
|
2
3
|
import { internalSymbols } from "./internal-symbols.js";
|
|
3
4
|
import { getIntrinsicIdentity } from "./intrinsics.js";
|
|
4
5
|
import { getGeneratorProperties } from "./generator-properties.js";
|
|
@@ -17,7 +18,7 @@ import { boxedDataProperties, boxedValue, createSandboxBox, isSandboxBox, native
|
|
|
17
18
|
import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, measureHostObjectData, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
|
|
18
19
|
import { types as nodeTypes } from "node:util";
|
|
19
20
|
import { CompileScope, RegexCompileGuard, regexCompiledData } from "./regex/compile-guard.js";
|
|
20
|
-
import { copyFloat32Storage, float32DataProperties, float32Storage, isFloat32Array } from "./float32.js";
|
|
21
|
+
import { copyFloat32Storage, float32DataProperties, float32Properties, float32Storage, isFloat32Array } from "./float32.js";
|
|
21
22
|
import { SandboxError } from "./budget.js";
|
|
22
23
|
import { observeSandboxPromise, trackSandboxPromise } from "./promise-tracker.js";
|
|
23
24
|
import { promiseReplayContext } from "./promise-replay.js";
|
|
@@ -399,15 +400,22 @@ export function measureSandboxData(values, options = {}) {
|
|
|
399
400
|
const prototype = getSandboxPrototype(value);
|
|
400
401
|
if (prototype !== null)
|
|
401
402
|
visit(prototype, depth + 1);
|
|
403
|
+
if (isSandboxArrayBuffer(value))
|
|
404
|
+
usage += arrayBufferLength(value);
|
|
402
405
|
if (isFloat32Array(value)) {
|
|
403
406
|
const storage = float32Storage(value);
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
usage +=
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
407
|
+
visit(storage.buffer, depth + 1);
|
|
408
|
+
for (const [key, descriptor] of float32Properties(value)) {
|
|
409
|
+
usage += 1;
|
|
410
|
+
if (typeof key === "string")
|
|
411
|
+
usage += key.length;
|
|
412
|
+
else
|
|
413
|
+
visit(key, depth + 1);
|
|
414
|
+
if ("value" in descriptor)
|
|
415
|
+
visit(descriptor.value, depth + 1);
|
|
416
|
+
else
|
|
417
|
+
for (const closure of retainedAccessorClosures(descriptor))
|
|
418
|
+
visit(closure, depth + 1);
|
|
411
419
|
}
|
|
412
420
|
return;
|
|
413
421
|
}
|
|
@@ -579,7 +587,7 @@ export function measureSandboxData(values, options = {}) {
|
|
|
579
587
|
if (descriptor !== undefined)
|
|
580
588
|
descriptors.push([key, descriptor]);
|
|
581
589
|
}
|
|
582
|
-
const includeNonEnumerable = isSandboxDate(value) || sandboxErrorTypes.has(value) || hasManagedDescriptors(value);
|
|
590
|
+
const includeNonEnumerable = isSandboxDate(value) || isSandboxArrayBuffer(value) || sandboxErrorTypes.has(value) || hasManagedDescriptors(value);
|
|
583
591
|
for (const [key, descriptor] of descriptors) {
|
|
584
592
|
if (!descriptor.enumerable && !includeNonEnumerable)
|
|
585
593
|
continue;
|
|
@@ -796,6 +804,20 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
796
804
|
}
|
|
797
805
|
return sandboxPromise;
|
|
798
806
|
}
|
|
807
|
+
if (isSandboxArrayBuffer(value)) {
|
|
808
|
+
const existing = state.seen.get(value);
|
|
809
|
+
if (existing !== undefined)
|
|
810
|
+
return existing;
|
|
811
|
+
const copy = copyArrayBufferStorage(value, state);
|
|
812
|
+
state.seen.set(value, copy);
|
|
813
|
+
for (const [key, descriptor] of arrayBufferDataProperties(value)) {
|
|
814
|
+
Object.defineProperty(copy, key, { ...descriptor,
|
|
815
|
+
value: copyToSandbox(descriptor.value, state, joinPath(path, key), cloneSandboxCollections, depth + 1) });
|
|
816
|
+
}
|
|
817
|
+
if (!Object.isExtensible(value))
|
|
818
|
+
Object.preventExtensions(copy);
|
|
819
|
+
return copy;
|
|
820
|
+
}
|
|
799
821
|
if (nodeTypes.isDate(value)) {
|
|
800
822
|
const existing = state.seen.get(value);
|
|
801
823
|
if (existing !== undefined)
|
|
@@ -819,6 +841,7 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
|
|
|
819
841
|
return existing;
|
|
820
842
|
const copy = copyFloat32Storage(value, state);
|
|
821
843
|
state.seen.set(value, copy);
|
|
844
|
+
copyToSandbox(float32Storage(value).buffer, state, `${path}.buffer`, cloneSandboxCollections, depth + 1);
|
|
822
845
|
for (const [key, descriptor] of float32DataProperties(value)) {
|
|
823
846
|
Object.defineProperty(copy, key, {
|
|
824
847
|
...descriptor,
|
|
@@ -1013,6 +1036,7 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
1013
1036
|
return existing;
|
|
1014
1037
|
const copy = copyFloat32Storage(value, state);
|
|
1015
1038
|
state.seen.set(value, copy);
|
|
1039
|
+
copyFromSandbox(float32Storage(value).buffer, state, `${path}.buffer`, options, depth + 1);
|
|
1016
1040
|
for (const [key, descriptor] of float32DataProperties(value)) {
|
|
1017
1041
|
Object.defineProperty(copy, key, {
|
|
1018
1042
|
...descriptor,
|
|
@@ -1023,6 +1047,20 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
|
|
|
1023
1047
|
Object.preventExtensions(copy);
|
|
1024
1048
|
return copy;
|
|
1025
1049
|
}
|
|
1050
|
+
if (isSandboxArrayBuffer(value)) {
|
|
1051
|
+
const existing = state.seen.get(value);
|
|
1052
|
+
if (existing !== undefined)
|
|
1053
|
+
return existing;
|
|
1054
|
+
const copy = copyArrayBufferStorage(value, state);
|
|
1055
|
+
state.seen.set(value, copy);
|
|
1056
|
+
for (const [key, descriptor] of arrayBufferDataProperties(value)) {
|
|
1057
|
+
Object.defineProperty(copy, key, { ...descriptor,
|
|
1058
|
+
value: copyFromSandbox(descriptor.value, state, joinPath(path, key), options, depth + 1) });
|
|
1059
|
+
}
|
|
1060
|
+
if (!Object.isExtensible(value))
|
|
1061
|
+
Object.preventExtensions(copy);
|
|
1062
|
+
return copy;
|
|
1063
|
+
}
|
|
1026
1064
|
if (isSandboxDate(value)) {
|
|
1027
1065
|
const existing = state.seen.get(value);
|
|
1028
1066
|
if (existing !== undefined)
|
|
@@ -1180,6 +1218,18 @@ function allocateSandboxValue(value, budget, seen) {
|
|
|
1180
1218
|
budget.allocateString(value);
|
|
1181
1219
|
return;
|
|
1182
1220
|
}
|
|
1221
|
+
if (isSandboxArrayBuffer(value)) {
|
|
1222
|
+
if (seen.has(value))
|
|
1223
|
+
return;
|
|
1224
|
+
seen.add(value);
|
|
1225
|
+
budget.allocateArrayLength(arrayBufferLength(value));
|
|
1226
|
+
for (const [key, descriptor] of arrayBufferDataProperties(value)) {
|
|
1227
|
+
if (typeof key === "string")
|
|
1228
|
+
budget.allocateString(key);
|
|
1229
|
+
allocateSandboxValue(descriptor.value, budget, seen);
|
|
1230
|
+
}
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1183
1233
|
if (isSandboxBox(value)) {
|
|
1184
1234
|
if (seen.has(value))
|
|
1185
1235
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "BigInt", "Date", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "Error", "EvalError", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "Symbol", "structuredClone", "SyntaxError", "TypeError", "URIError", "console"];
|
|
1
|
+
export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "ArrayBuffer", "Boolean", "BigInt", "Date", "decodeURI", "decodeURIComponent", "encodeURI", "encodeURIComponent", "Error", "EvalError", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "Symbol", "structuredClone", "SyntaxError", "TypeError", "URIError", "console"];
|
|
@@ -2709,6 +2709,7 @@ class Parser {
|
|
|
2709
2709
|
return undefined;
|
|
2710
2710
|
}
|
|
2711
2711
|
findTopLevelForIterationOperator(startIndex) {
|
|
2712
|
+
let operator;
|
|
2712
2713
|
let depth = 0;
|
|
2713
2714
|
let previousToken;
|
|
2714
2715
|
for (let index = startIndex; index < this.tokens.length; index += 1) {
|
|
@@ -2719,7 +2720,7 @@ class Parser {
|
|
|
2719
2720
|
}
|
|
2720
2721
|
else if (token.value === ")" || token.value === "]" || token.value === "}") {
|
|
2721
2722
|
if (depth === 0 && token.value === ")") {
|
|
2722
|
-
return
|
|
2723
|
+
return operator;
|
|
2723
2724
|
}
|
|
2724
2725
|
depth -= 1;
|
|
2725
2726
|
}
|
|
@@ -2730,9 +2731,12 @@ class Parser {
|
|
|
2730
2731
|
if (depth === 0 &&
|
|
2731
2732
|
token.type === "keyword" &&
|
|
2732
2733
|
(token.value === "of" || token.value === "in") &&
|
|
2734
|
+
index !== startIndex &&
|
|
2735
|
+
!(token.value === "of" && index === startIndex + 1 &&
|
|
2736
|
+
["const", "let", "var"].includes(previousToken?.value ?? "")) &&
|
|
2733
2737
|
previousToken?.value !== "." &&
|
|
2734
2738
|
previousToken?.value !== "?.") {
|
|
2735
|
-
|
|
2739
|
+
operator ??= token;
|
|
2736
2740
|
}
|
|
2737
2741
|
previousToken = token;
|
|
2738
2742
|
}
|
|
@@ -3752,7 +3756,8 @@ function isLiteralPropertyKey(token) {
|
|
|
3752
3756
|
return token.type === "numeric" || token.type === "string";
|
|
3753
3757
|
}
|
|
3754
3758
|
function isIdentifierLikeToken(token) {
|
|
3755
|
-
return token.type === "identifier" ||
|
|
3759
|
+
return token.type === "identifier" ||
|
|
3760
|
+
(token.type === "keyword" && (token.value === "async" || token.value === "of"));
|
|
3756
3761
|
}
|
|
3757
3762
|
function isNewToken(token) {
|
|
3758
3763
|
return token.value === "new";
|
|
@@ -358,7 +358,7 @@ class Lexer {
|
|
|
358
358
|
}
|
|
359
359
|
if (char === "/" &&
|
|
360
360
|
this.peekChar(1) !== "=" &&
|
|
361
|
-
shouldRejectRegexLiteral(tokens[tokens.length - 1], lastClosedControlParenthesis)) {
|
|
361
|
+
shouldRejectRegexLiteral(tokens[tokens.length - 1], lastClosedControlParenthesis, tokens)) {
|
|
362
362
|
if (!this.options.allowRegexLiterals) {
|
|
363
363
|
this.syntaxError("Regular expression literals are not supported", this.position());
|
|
364
364
|
}
|
|
@@ -633,7 +633,7 @@ class Lexer {
|
|
|
633
633
|
readSlashOrPunctuator(start) {
|
|
634
634
|
if (this.currentChar() === "/" &&
|
|
635
635
|
this.peekChar(1) !== "=" &&
|
|
636
|
-
shouldRejectRegexLiteral(this.lastSignificantToken(), this.lastClosedControlParenthesis)) {
|
|
636
|
+
shouldRejectRegexLiteral(this.lastSignificantToken(), this.lastClosedControlParenthesis, this.tokens)) {
|
|
637
637
|
if (!this.options.allowRegexLiterals) {
|
|
638
638
|
this.syntaxError("Regular expression literals are not supported", start);
|
|
639
639
|
}
|
|
@@ -919,7 +919,7 @@ function matchPunctuator(source, index) {
|
|
|
919
919
|
return PUNCTUATORS.find((punctuator) => source.startsWith(punctuator, index) &&
|
|
920
920
|
(punctuator !== "?." || !isDecimalDigit(source[index + 2] ?? "")));
|
|
921
921
|
}
|
|
922
|
-
function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis) {
|
|
922
|
+
function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis, tokens) {
|
|
923
923
|
if (previousToken === undefined) {
|
|
924
924
|
return true;
|
|
925
925
|
}
|
|
@@ -930,6 +930,8 @@ function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis) {
|
|
|
930
930
|
return false;
|
|
931
931
|
}
|
|
932
932
|
if (previousToken.type === "keyword") {
|
|
933
|
+
if (previousToken.value === "of")
|
|
934
|
+
return endsWithForOfSeparator(tokens);
|
|
933
935
|
return !EXPRESSION_ENDING_KEYWORDS.has(previousToken.value);
|
|
934
936
|
}
|
|
935
937
|
if (previousToken.value === ")") {
|
|
@@ -937,6 +939,46 @@ function shouldRejectRegexLiteral(previousToken, lastClosedControlParenthesis) {
|
|
|
937
939
|
}
|
|
938
940
|
return !isExpressionEndingPunctuator(previousToken.value);
|
|
939
941
|
}
|
|
942
|
+
function endsWithForOfSeparator(tokens) {
|
|
943
|
+
let depth = 0;
|
|
944
|
+
let start = -1;
|
|
945
|
+
for (let index = tokens.length - 2; index >= 0; index--) {
|
|
946
|
+
const token = tokens[index];
|
|
947
|
+
if (token.type !== "punctuator")
|
|
948
|
+
continue;
|
|
949
|
+
if ([")", "]", "}"].includes(token.value))
|
|
950
|
+
depth++;
|
|
951
|
+
else if (["(", "[", "{"].includes(token.value)) {
|
|
952
|
+
if (depth > 0) {
|
|
953
|
+
depth--;
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
if (token.value === "(" && (tokens[index - 1]?.value === "for" ||
|
|
957
|
+
(tokens[index - 1]?.value === "await" && tokens[index - 2]?.value === "for")))
|
|
958
|
+
start = index + 1;
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
961
|
+
else if (depth === 0 && token.value === ";")
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
if (start < 0)
|
|
965
|
+
return false;
|
|
966
|
+
depth = 0;
|
|
967
|
+
for (let index = start; index < tokens.length; index++) {
|
|
968
|
+
const token = tokens[index];
|
|
969
|
+
if (token.type === "punctuator") {
|
|
970
|
+
if (["(", "[", "{"].includes(token.value))
|
|
971
|
+
depth++;
|
|
972
|
+
else if ([")", "]", "}"].includes(token.value))
|
|
973
|
+
depth--;
|
|
974
|
+
}
|
|
975
|
+
if (depth === 0 && token.type === "keyword" && token.value === "of" &&
|
|
976
|
+
index !== start && tokens[index - 1]?.value !== "." && tokens[index - 1]?.value !== "?." &&
|
|
977
|
+
!(index === start + 1 && ["const", "let", "var"].includes(tokens[start].value)))
|
|
978
|
+
return index === tokens.length - 1;
|
|
979
|
+
}
|
|
980
|
+
return false;
|
|
981
|
+
}
|
|
940
982
|
function updateGroupingState(groupingStack, previousToken, punctuator) {
|
|
941
983
|
if (punctuator === "(") {
|
|
942
984
|
groupingStack.push({
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { GuestObjectState } from "./guest-heap.js";
|
|
2
|
+
export type ArrayBufferData<TReference> = {
|
|
3
|
+
kind: "arraybuffer";
|
|
4
|
+
} & ({
|
|
5
|
+
bytes: number[];
|
|
6
|
+
maxByteLength?: number;
|
|
7
|
+
} | {
|
|
8
|
+
buffer: TReference;
|
|
9
|
+
});
|
|
10
|
+
export declare function captureArrayBufferState<T>(value: ArrayBuffer, encode: (value: unknown) => T): GuestObjectState<T>;
|
|
11
|
+
export declare function encodeArrayBufferStorage<T>(value: ArrayBuffer, id: number, buffers: WeakMap<ArrayBuffer, number>, reference: (id: number) => T): ArrayBufferData<T>;
|
|
12
|
+
export declare function validateArrayBufferStorage(value: Record<string, unknown>): void;
|
|
13
|
+
export declare function decodeArrayBufferStorage(value: Record<string, unknown>, resolve: (reference: unknown) => unknown): ArrayBuffer;
|