poe-code 14.0.74 → 14.0.76

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 (65) hide show
  1. package/dist/index.js +1283 -144
  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-YEZOXLY4.js → chunk-UZYQWFMY.js} +1233 -143
  6. package/packages/safe-js/dist/chunks/chunk-UZYQWFMY.js.map +7 -0
  7. package/packages/safe-js/dist/chunks/{chunk-2J6W3YGB.js → chunk-VD2AS4E4.js} +2 -2
  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/index.js.map +1 -1
  12. package/packages/safe-js/dist/interp/bigint-operators.d.ts +3 -0
  13. package/packages/safe-js/dist/interp/bigint-operators.js +62 -0
  14. package/packages/safe-js/dist/interp/boxed.d.ts +2 -2
  15. package/packages/safe-js/dist/interp/boxed.js +4 -1
  16. package/packages/safe-js/dist/interp/globals/bigint.d.ts +2 -0
  17. package/packages/safe-js/dist/interp/globals/bigint.js +85 -0
  18. package/packages/safe-js/dist/interp/globals/console-json.js +57 -24
  19. package/packages/safe-js/dist/interp/globals/object-array.js +1 -1
  20. package/packages/safe-js/dist/interp/globals/regex.js +108 -2
  21. package/packages/safe-js/dist/interp/globals.d.ts +1 -0
  22. package/packages/safe-js/dist/interp/globals.js +2 -0
  23. package/packages/safe-js/dist/interp/host-bridge.js +2 -0
  24. package/packages/safe-js/dist/interp/interpreter.js +59 -12
  25. package/packages/safe-js/dist/interp/iteration.js +5 -2
  26. package/packages/safe-js/dist/interp/methods/number.js +1 -1
  27. package/packages/safe-js/dist/interp/methods/regex-split.d.ts +3 -0
  28. package/packages/safe-js/dist/interp/methods/regex-split.js +102 -0
  29. package/packages/safe-js/dist/interp/methods/regex.d.ts +1 -1
  30. package/packages/safe-js/dist/interp/methods/regex.js +16 -5
  31. package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +5 -1
  32. package/packages/safe-js/dist/interp/methods/regexp-iterator.js +59 -7
  33. package/packages/safe-js/dist/interp/methods/string.js +9 -9
  34. package/packages/safe-js/dist/interp/object-model.d.ts +1 -0
  35. package/packages/safe-js/dist/interp/object-model.js +4 -1
  36. package/packages/safe-js/dist/interp/regex/compile-guard.js +26 -4
  37. package/packages/safe-js/dist/interp/regex/engine.d.ts +4 -0
  38. package/packages/safe-js/dist/interp/regex/engine.js +230 -30
  39. package/packages/safe-js/dist/interp/regex/parse.d.ts +42 -4
  40. package/packages/safe-js/dist/interp/regex/parse.js +429 -25
  41. package/packages/safe-js/dist/interp/regexp-iterator.d.ts +4 -2
  42. package/packages/safe-js/dist/interp/regexp-iterator.js +6 -1
  43. package/packages/safe-js/dist/interp/string-coercion.d.ts +1 -1
  44. package/packages/safe-js/dist/interp/string-coercion.js +8 -3
  45. package/packages/safe-js/dist/interp/values.d.ts +1 -1
  46. package/packages/safe-js/dist/interp/values.js +10 -3
  47. package/packages/safe-js/dist/lint/rules/AS-async-not-needed.js +2 -0
  48. package/packages/safe-js/dist/lint/rules/AS-missing-async.js +2 -0
  49. package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
  50. package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
  51. package/packages/safe-js/dist/parse/parser.d.ts +6 -1
  52. package/packages/safe-js/dist/parse/parser.js +8 -0
  53. package/packages/safe-js/dist/parse/tokenizer.js +12 -4
  54. package/packages/safe-js/dist/parse.d.ts +1 -1
  55. package/packages/safe-js/dist/snapshot/bigint.d.ts +1 -0
  56. package/packages/safe-js/dist/snapshot/bigint.js +14 -0
  57. package/packages/safe-js/dist/snapshot/dump-format.js +12 -2
  58. package/packages/safe-js/dist/snapshot/replay-data.d.ts +6 -0
  59. package/packages/safe-js/dist/snapshot/replay-data.js +23 -5
  60. package/packages/safe-js/dist/snapshot/restore.js +10 -2
  61. package/packages/safe-js/dist/snapshot/serialize.d.ts +4 -1
  62. package/packages/safe-js/dist/snapshot/serialize.js +6 -1
  63. package/packages/safe-js/dist/snapshot/validation.js +27 -0
  64. package/packages/safe-js/dist/chunks/chunk-YEZOXLY4.js.map +0 -7
  65. /package/packages/safe-js/dist/chunks/{chunk-2J6W3YGB.js.map → chunk-VD2AS4E4.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import type { Budget } from "./budget.js";
2
2
  import { type SandboxCallContext, type SandboxPrimitive, type SandboxValue } from "./values.js";
3
- export declare function sandboxNumber(value: SandboxValue, budget: Budget, context?: SandboxCallContext): number | Promise<number>;
3
+ export declare function sandboxNumber(value: SandboxValue, budget: Budget, context?: SandboxCallContext, allowBigInt?: boolean): number | Promise<number>;
4
4
  export declare function sandboxString(value: SandboxValue, budget: Budget, context?: SandboxCallContext, joining?: Set<object>): string | Promise<string>;
5
5
  export declare function joinSandboxArray(value: SandboxValue & object, length: number, separator: string, budget: Budget, context?: SandboxCallContext, joining?: Set<object>): Promise<string>;
6
6
  export declare function objectToPrimitive(value: SandboxValue & object, budget: Budget, context: SandboxCallContext | undefined, joining: Set<object>, hint: "string" | "number" | "default", ordinary?: boolean): Promise<SandboxPrimitive>;
@@ -17,13 +17,18 @@ import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandb
17
17
  const defaultStringHook = Symbol("defaultStringHook");
18
18
  const defaultValueHook = Symbol("defaultValueHook");
19
19
  const joiningArrays = new WeakSet();
20
- export function sandboxNumber(value, budget, context) {
20
+ export function sandboxNumber(value, budget, context, allowBigInt = false) {
21
+ const convert = (primitive) => {
22
+ if (typeof primitive === "bigint" && !allowBigInt)
23
+ throw new TypeError("Cannot convert a BigInt value to a number");
24
+ return Number(primitive);
25
+ };
21
26
  if (value === null || typeof value !== "object") {
22
27
  if (typeof value === "function")
23
28
  throw new TypeError("Expected a sandbox value.");
24
- return Number(value);
29
+ return convert(value);
25
30
  }
26
- return objectToPrimitive(value, budget, context, new Set(), "number").then(Number);
31
+ return objectToPrimitive(value, budget, context, new Set(), "number").then(convert);
27
32
  }
28
33
  export function sandboxString(value, budget, context, joining = new Set()) {
29
34
  if (typeof value === "symbol")
@@ -15,7 +15,7 @@ declare const sandboxPromiseBrand: unique symbol;
15
15
  declare const sandboxRegexBrand: unique symbol;
16
16
  declare const sandboxRegexPattern: unique symbol;
17
17
  declare const sandboxRetainedValues: unique symbol;
18
- export type SandboxPrimitive = string | number | boolean | symbol | null | undefined;
18
+ export type SandboxPrimitive = string | number | bigint | boolean | symbol | null | undefined;
19
19
  export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
20
20
  export type SandboxObject = {
21
21
  [key: string]: SandboxValue;
@@ -19,7 +19,7 @@ import { invokeCancelableClosure, readPromiseCancellation, registerPromiseCancel
19
19
  import { parseRegex } from "./regex/parse.js";
20
20
  import { assertSandboxDataDepth } from "../graph-depth.js";
21
21
  import { sandboxErrorTypes } from "../error/shape.js";
22
- import { getGuestFunctionProperties, getSandboxPrototype, hasGuestObjectState, hasManagedDescriptors, isGuestClosure, isIntrinsicConstructor, registerGuestClosure } from "./object-model.js";
22
+ import { getGuestFunctionProperties, getSandboxPrototype, hasGuestObjectState, hasManagedDescriptors, hasNullObjectPrototype, isGuestClosure, isIntrinsicConstructor, registerGuestClosure, setSandboxPrototype } from "./object-model.js";
23
23
  import { copySandboxArgumentProperties, createSandboxArguments, getSandboxArgumentEntries, isSandboxArguments } from "./arguments.js";
24
24
  export { createSandboxArguments, isSandboxArguments } from "./arguments.js";
25
25
  export { isSandboxMap, isSandboxSet } from "./collection-brands.js";
@@ -299,6 +299,10 @@ export function measureSandboxData(values, options = {}) {
299
299
  const seenSymbols = new Set();
300
300
  let usage = 0;
301
301
  const visit = (value, depth = 0) => {
302
+ if (typeof value === "bigint") {
303
+ usage += value.toString(16).length;
304
+ return;
305
+ }
302
306
  if (typeof value === "symbol") {
303
307
  if (!seenSymbols.has(value)) {
304
308
  seenSymbols.add(value);
@@ -612,7 +616,7 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
612
616
  const copy = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
613
617
  state.seen.set(value, copy);
614
618
  const matcher = copyToSandbox(snapshot.matcher, state, `${path}.<matcher>`, true, depth + 1);
615
- if (matcher !== undefined && !isSandboxRegex(matcher))
619
+ if (matcher !== undefined && (snapshot.global === undefined ? !isSandboxRegex(matcher) : matcher === null || typeof matcher !== "object"))
616
620
  throw new TypeError("Invalid RegExp iterator matcher.");
617
621
  restoreSandboxRegExpIterator({ ...snapshot, matcher }, copy);
618
622
  for (const entry of getEnumerableObjectEntries(value, path)) {
@@ -781,6 +785,8 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
781
785
  return existing;
782
786
  }
783
787
  const copy = createPlainObject(!cloneSandboxCollections || Object.getPrototypeOf(value) === null);
788
+ if (!state.structuredClone && hasNullObjectPrototype(value))
789
+ setSandboxPrototype(copy, null);
784
790
  state.seen.set(value, copy);
785
791
  const errorType = sandboxErrorTypes.get(value);
786
792
  if (errorType !== undefined)
@@ -978,7 +984,7 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
978
984
  if (existing !== undefined) {
979
985
  return existing;
980
986
  }
981
- const copy = createPlainObject(Object.getPrototypeOf(value) === null);
987
+ const copy = createPlainObject(hasNullObjectPrototype(value) || Object.getPrototypeOf(value) === null);
982
988
  state.seen.set(value, copy);
983
989
  for (const entry of getEnumerableObjectEntries(value, path)) {
984
990
  defineOwnDataProperty(copy, entry.key, copyFromSandbox(entry.value, state, joinPath(path, entry.key), options, depth + 1));
@@ -992,6 +998,7 @@ function isSandboxPrimitive(value) {
992
998
  value === undefined ||
993
999
  typeof value === "string" ||
994
1000
  typeof value === "number" ||
1001
+ typeof value === "bigint" ||
995
1002
  typeof value === "boolean" ||
996
1003
  typeof value === "symbol");
997
1004
  }
@@ -229,6 +229,7 @@ class ASAsyncNotNeededScanner {
229
229
  case "MetaProperty":
230
230
  case "NullLiteral":
231
231
  case "NumericLiteral":
232
+ case "BigIntLiteral":
232
233
  case "RegexLiteral":
233
234
  case "StringLiteral":
234
235
  case "UndefinedLiteral":
@@ -539,6 +540,7 @@ function expressionContainsAwait(node) {
539
540
  case "MetaProperty":
540
541
  case "NullLiteral":
541
542
  case "NumericLiteral":
543
+ case "BigIntLiteral":
542
544
  case "RegexLiteral":
543
545
  case "StringLiteral":
544
546
  case "ThisExpression":
@@ -213,6 +213,7 @@ class ASMissingAsyncScanner {
213
213
  case "MetaProperty":
214
214
  case "NullLiteral":
215
215
  case "NumericLiteral":
216
+ case "BigIntLiteral":
216
217
  case "RegexLiteral":
217
218
  case "StringLiteral":
218
219
  case "UndefinedLiteral":
@@ -509,6 +510,7 @@ function expressionContainsAwait(node) {
509
510
  case "MetaProperty":
510
511
  case "NullLiteral":
511
512
  case "NumericLiteral":
513
+ case "BigIntLiteral":
512
514
  case "RegexLiteral":
513
515
  case "StringLiteral":
514
516
  case "ThisExpression":
@@ -1 +1 @@
1
- export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "Date", "Error", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "Symbol", "structuredClone", "SyntaxError", "TypeError", "console"];
1
+ export declare const KNOWN_RUNTIME_GLOBALS: readonly ["AggregateError", "Array", "Boolean", "BigInt", "Date", "Error", "Infinity", "isFinite", "isNaN", "JSON", "Map", "Float32Array", "Math", "NaN", "Number", "Object", "parseFloat", "parseInt", "Promise", "RangeError", "ReferenceError", "RegExp", "Set", "String", "Symbol", "structuredClone", "SyntaxError", "TypeError", "console"];
@@ -2,6 +2,7 @@ export const KNOWN_RUNTIME_GLOBALS = [
2
2
  "AggregateError",
3
3
  "Array",
4
4
  "Boolean",
5
+ "BigInt",
5
6
  "Date",
6
7
  "Error",
7
8
  "Infinity",
@@ -26,6 +26,11 @@ export type NumericLiteral = BaseNode & {
26
26
  raw: string;
27
27
  value: number;
28
28
  };
29
+ export type BigIntLiteral = BaseNode & {
30
+ type: "BigIntLiteral";
31
+ raw: string;
32
+ value: string;
33
+ };
29
34
  export type StringLiteral = BaseNode & {
30
35
  type: "StringLiteral";
31
36
  raw: string;
@@ -390,7 +395,7 @@ export type ArrowFunctionExpression = BaseNode & {
390
395
  params: Array<AssignmentPattern | ArrayPattern | Identifier | ObjectPattern | RestElement>;
391
396
  };
392
397
  export type FunctionNode = ArrowFunctionExpression | FunctionDeclaration | FunctionExpression;
393
- export type Expression = ArrowFunctionExpression | AssignmentExpression | ArrayExpression | AwaitExpression | BinaryExpression | BooleanLiteral | CallExpression | ConditionalExpression | ClassExpression | FunctionExpression | Identifier | LogicalExpression | MemberExpression | MetaProperty | NewExpression | NewTargetExpression | NullLiteral | NumericLiteral | ObjectExpression | RegexLiteral | SequenceExpression | StringLiteral | SuperExpression | TaggedTemplateExpression | TemplateLiteral | ThisExpression | UnaryExpression | UpdateExpression | UndefinedLiteral | YieldExpression;
398
+ export type Expression = ArrowFunctionExpression | AssignmentExpression | ArrayExpression | AwaitExpression | BinaryExpression | BooleanLiteral | CallExpression | ConditionalExpression | ClassExpression | FunctionExpression | Identifier | LogicalExpression | MemberExpression | MetaProperty | NewExpression | NewTargetExpression | NullLiteral | NumericLiteral | BigIntLiteral | ObjectExpression | RegexLiteral | SequenceExpression | StringLiteral | SuperExpression | TaggedTemplateExpression | TemplateLiteral | ThisExpression | UnaryExpression | UpdateExpression | UndefinedLiteral | YieldExpression;
394
399
  export type ParseResult = Expression | Statement;
395
400
  export declare function parse(source: string, filename?: string, owner?: CompileOwner): ParseResult;
396
401
  export declare function parseModule(source: string, filename?: string, owner?: CompileOwner): Module;
@@ -3082,6 +3082,7 @@ function findImportMetaAssignmentInNode(node) {
3082
3082
  case "BooleanLiteral":
3083
3083
  case "NullLiteral":
3084
3084
  case "NumericLiteral":
3085
+ case "BigIntLiteral":
3085
3086
  case "StringLiteral":
3086
3087
  case "ThisExpression":
3087
3088
  case "RegexLiteral":
@@ -3159,6 +3160,13 @@ function isYieldArgumentTerminator(value) {
3159
3160
  return value === ";" || value === "}" || value === ")" || value === "]" || value === ",";
3160
3161
  }
3161
3162
  function createNumericLiteral(token) {
3163
+ if (token.value.endsWith("n"))
3164
+ return {
3165
+ type: "BigIntLiteral",
3166
+ raw: token.value,
3167
+ value: token.value.slice(0, -1).replaceAll("_", ""),
3168
+ span: createTokenSpan(token)
3169
+ };
3162
3170
  return {
3163
3171
  type: "NumericLiteral",
3164
3172
  raw: token.value,
@@ -480,7 +480,8 @@ class Lexer {
480
480
  this.advance();
481
481
  this.advance();
482
482
  this.consumeDigitsForBase(isHexDigit, "hexadecimal");
483
- this.rejectBigIntSuffix();
483
+ if (this.currentChar() === "n")
484
+ this.advance();
484
485
  this.rejectInvalidNumericLiteralContinuation();
485
486
  return this.source.slice(start.offset, this.index);
486
487
  }
@@ -488,7 +489,8 @@ class Lexer {
488
489
  this.advance();
489
490
  this.advance();
490
491
  this.consumeDigitsForBase(isBinaryDigit, "binary");
491
- this.rejectBigIntSuffix();
492
+ if (this.currentChar() === "n")
493
+ this.advance();
492
494
  this.rejectInvalidNumericLiteralContinuation();
493
495
  return this.source.slice(start.offset, this.index);
494
496
  }
@@ -496,7 +498,8 @@ class Lexer {
496
498
  this.advance();
497
499
  this.advance();
498
500
  this.consumeDigitsForBase(isOctalDigit, "octal");
499
- this.rejectBigIntSuffix();
501
+ if (this.currentChar() === "n")
502
+ this.advance();
500
503
  this.rejectInvalidNumericLiteralContinuation();
501
504
  return this.source.slice(start.offset, this.index);
502
505
  }
@@ -512,6 +515,11 @@ class Lexer {
512
515
  }
513
516
  }
514
517
  this.consumeDecimalDigits();
518
+ if (this.currentChar() === "n") {
519
+ this.advance();
520
+ this.rejectInvalidNumericLiteralContinuation();
521
+ return this.source.slice(start.offset, this.index);
522
+ }
515
523
  if (this.currentChar() === "." && (this.peekChar(1) !== "." || this.peekChar(2) !== ".")) {
516
524
  this.advance();
517
525
  this.consumeOptionalDecimalDigits();
@@ -610,7 +618,7 @@ class Lexer {
610
618
  }
611
619
  rejectBigIntSuffix() {
612
620
  if (this.currentChar() === "n") {
613
- this.syntaxError("BigInt not supported", this.position());
621
+ this.syntaxError("BigInt literals cannot contain a fraction or exponent", this.position());
614
622
  }
615
623
  }
616
624
  rejectInvalidNumericLiteralContinuation() {
@@ -1,4 +1,4 @@
1
1
  import { type ParseResult as ParsedNode } from "./parse/parser.js";
2
2
  export { DisallowedSyntaxError } from "./parse/parser.js";
3
3
  export declare const parse: (source: string, filename?: string) => ParsedNode;
4
- export type { ArrayPattern, ArrayExpression, ArrowFunctionExpression, AssignmentExpression, AssignmentPattern, AssignmentProperty, AwaitExpression, BinaryExpression, BlockStatement, BooleanLiteral, BreakStatement, CallExpression, CatchClause, ClassBody, ClassDeclaration, ClassElement, ClassExpression, ClassNode, ConditionalExpression, ContinueStatement, DoWhileStatement, EmptyStatement, Expression, ExpressionStatement, ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ForInStatement, ForOfStatement, ForStatement, FunctionDeclaration, FunctionExpression, Identifier, IfStatement, LogicalExpression, MemberExpression, MetaProperty, NewExpression, NewTargetExpression, NullLiteral, NumericLiteral, ObjectExpression, ObjectPattern, ParseResult, PatternTarget, Property, RegexLiteral, RestElement, ReturnStatement, SequenceExpression, SourceSpan, SpreadElement, Statement, StringLiteral, SuperExpression, SwitchCase, SwitchStatement, TaggedTemplateExpression, TemplateElement, TemplateLiteral, ThisExpression, ThrowStatement, TryStatement, UnaryExpression, UndefinedLiteral, UpdateExpression, UpdateTarget, VariableDeclaration, VariableDeclarationKind, VariableDeclarator, WhileStatement } from "./parse/parser.js";
4
+ export type { ArrayPattern, ArrayExpression, ArrowFunctionExpression, AssignmentExpression, AssignmentPattern, AssignmentProperty, AwaitExpression, BinaryExpression, BigIntLiteral, BlockStatement, BooleanLiteral, BreakStatement, CallExpression, CatchClause, ClassBody, ClassDeclaration, ClassElement, ClassExpression, ClassNode, ConditionalExpression, ContinueStatement, DoWhileStatement, EmptyStatement, Expression, ExpressionStatement, ExportDefaultDeclaration, ExportNamedDeclaration, ImportDeclaration, ImportDefaultSpecifier, ImportNamespaceSpecifier, ImportSpecifier, ForInStatement, ForOfStatement, ForStatement, FunctionDeclaration, FunctionExpression, Identifier, IfStatement, LogicalExpression, MemberExpression, MetaProperty, NewExpression, NewTargetExpression, NullLiteral, NumericLiteral, ObjectExpression, ObjectPattern, ParseResult, PatternTarget, Property, RegexLiteral, RestElement, ReturnStatement, SequenceExpression, SourceSpan, SpreadElement, Statement, StringLiteral, SuperExpression, SwitchCase, SwitchStatement, TaggedTemplateExpression, TemplateElement, TemplateLiteral, ThisExpression, ThrowStatement, TryStatement, UnaryExpression, UndefinedLiteral, UpdateExpression, UpdateTarget, VariableDeclaration, VariableDeclarationKind, VariableDeclarator, WhileStatement } from "./parse/parser.js";
@@ -0,0 +1 @@
1
+ export declare function validateBigIntData(value: unknown): asserts value is string;
@@ -0,0 +1,14 @@
1
+ export function validateBigIntData(value) {
2
+ if (typeof value !== "string" || value.length === 0)
3
+ throw new TypeError("Invalid BigInt snapshot value.");
4
+ if (value === "0")
5
+ return;
6
+ const start = value[0] === "-" ? 1 : 0;
7
+ if (start === value.length || value[start] === "0")
8
+ throw new TypeError("Invalid BigInt snapshot value.");
9
+ for (let index = start; index < value.length; index++) {
10
+ const code = value.charCodeAt(index);
11
+ if (code < 48 || code > 57)
12
+ throw new TypeError("Invalid BigInt snapshot value.");
13
+ }
14
+ }
@@ -4,7 +4,7 @@ import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-i
4
4
  import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-properties.js";
5
5
  export const EXECUTION_SEMANTICS = "jobs-v8";
6
6
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
7
- import { hasGuestObjectState } from "../interp/object-model.js";
7
+ import { hasGuestObjectState, hasNullObjectPrototype } from "../interp/object-model.js";
8
8
  import { sandboxErrorTypes } from "../error/shape.js";
9
9
  import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/arguments.js";
10
10
  import { serializeArguments } from "./arguments.js";
@@ -58,6 +58,8 @@ function createDumpFile(snapshot) {
58
58
  return dumped;
59
59
  }
60
60
  function serializeDumpValue(value, path, state) {
61
+ if (typeof value === "bigint")
62
+ return { kind: "bigint", value: String(value) };
61
63
  if (typeof value === "symbol")
62
64
  return serializeSymbol(value, state.heapIds, state.heap);
63
65
  if (value === null || typeof value === "string" || typeof value === "boolean") {
@@ -110,10 +112,16 @@ function serializeHeapReference(value, path, state) {
110
112
  if (isSandboxRegExpIterator(value)) {
111
113
  const snapshot = regexpIteratorState(value);
112
114
  const matcher = snapshot.matcher;
115
+ const serializedMatcher = snapshot.global === undefined && isSandboxRegex(matcher)
116
+ ? { kind: "regex", source: matcher.source, flags: matcher.flags, lastIndex: Number(matcher.lastIndex) }
117
+ : serializeDumpValue(matcher, `${path}.<matcher>`, state);
118
+ if (serializedMatcher === SKIP_VALUE)
119
+ throw new TypeError("Unsupported RegExp iterator matcher in public dump.");
113
120
  const entries = Object.create(null);
114
121
  state.heap[String(id)] = {
115
122
  kind: "regexp-iterator", exhausted: snapshot.exhausted,
116
- matcher: matcher === undefined ? { kind: "undefined" } : { kind: "regex", source: matcher.source, flags: matcher.flags, lastIndex: Number(matcher.lastIndex) },
123
+ matcher: serializedMatcher,
124
+ ...(snapshot.global === undefined ? {} : { global: snapshot.global, unicode: snapshot.unicode }),
117
125
  input: snapshot.input ?? { kind: "undefined" }, entries,
118
126
  symbolEntries: serializeSymbolProperties(value, entry => {
119
127
  const serialized = serializeDumpValue(entry, `${path}.[symbol]`, state);
@@ -192,6 +200,7 @@ function serializeHeapReference(value, path, state) {
192
200
  });
193
201
  state.heap[String(id)] = {
194
202
  kind: "object",
203
+ ...(hasNullObjectPrototype(value) ? { sandboxNullPrototype: true } : {}),
195
204
  entries: serializeObjectEntries(value, path, state),
196
205
  ...(symbolEntries.length === 0 ? {} : { symbolEntries }),
197
206
  ...(errorType === undefined ? {} : { errorType })
@@ -227,6 +236,7 @@ function indexHeapContainers(snapshot) {
227
236
  for (const [value, stat] of stats.entries()) {
228
237
  if (stat.count > 1 ||
229
238
  stat.cyclic ||
239
+ hasNullObjectPrototype(value) ||
230
240
  ownSerializableSymbolKeys(value).length > 0 ||
231
241
  isSandboxBox(value) ||
232
242
  isSandboxRegExpIterator(value) ||
@@ -8,6 +8,9 @@ import { type SandboxClosure, type SandboxPromise, type SandboxValue } from "../
8
8
  import { type SerializedArguments } from "./arguments.js";
9
9
  type Atom = boolean | null | number | string | {
10
10
  tag: "undefined";
11
+ } | {
12
+ tag: "bigint";
13
+ value: string;
11
14
  } | {
12
15
  tag: "number";
13
16
  value: "NaN" | "Infinity" | "-Infinity" | "-0";
@@ -32,6 +35,8 @@ type DataNode = {
32
35
  matcher: Atom;
33
36
  input: Atom;
34
37
  exhausted: boolean;
38
+ global?: boolean;
39
+ unicode?: boolean;
35
40
  properties: Properties;
36
41
  extensible: boolean;
37
42
  symbolEntries?: Array<SerializedSymbolProperty<Atom>>;
@@ -69,6 +74,7 @@ type DataNode = {
69
74
  symbolProperties?: Array<SerializedSymbolProperty<Atom>>;
70
75
  extensible: boolean;
71
76
  nullPrototype: boolean;
77
+ sandboxNullPrototype?: true;
72
78
  errorType?: SandboxErrorName;
73
79
  } | {
74
80
  kind: "arguments";
@@ -1,10 +1,11 @@
1
1
  import { MAX_DATA_DEPTH } from "../graph-depth.js";
2
+ import { validateBigIntData } from "./bigint.js";
2
3
  import { serializeRegexProperties, restoreRegexProperties } from "./regexp-properties.js";
3
4
  import { wellKnownSymbols } from "../interp/symbols.js";
4
5
  import { symbolData, serializeSymbolProperties } from "./symbols.js";
5
6
  import { isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "../interp/collection-iterator.js";
6
7
  import { isSandboxRegExpIterator, regexpIteratorState, restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
7
- import { hasGuestObjectState } from "../interp/object-model.js";
8
+ import { hasGuestObjectState, hasNullObjectPrototype, setSandboxPrototype } from "../interp/object-model.js";
8
9
  import { CompileScope } from "../interp/regex/compile-guard.js";
9
10
  import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
10
11
  import { decodeFloat32Storage, encodeFloat32Storage } from "./float32array.js";
@@ -29,6 +30,8 @@ export function encodeReplayData(value, options = {}) {
29
30
  return entry;
30
31
  if (entry === undefined)
31
32
  return { tag: "undefined" };
33
+ if (typeof entry === "bigint")
34
+ return { tag: "bigint", value: String(entry) };
32
35
  if (typeof entry === "symbol") {
33
36
  let id = symbols.get(entry);
34
37
  if (id === undefined) {
@@ -134,7 +137,8 @@ export function encodeReplayData(value, options = {}) {
134
137
  }
135
138
  let symbolIndex = 0;
136
139
  const symbolEntries = serializeSymbolProperties(entry, value => encode(value, depth + 1, [...path, { symbol: Math.floor(symbolIndex++ / 2) }]));
137
- nodes[id] = { kind: "regexp-iterator", matcher: child(snapshot.matcher, "<matcher>"), input: child(snapshot.input, "<input>"), exhausted: snapshot.exhausted, properties, extensible: Object.isExtensible(entry), symbolEntries };
140
+ nodes[id] = { kind: "regexp-iterator", matcher: child(snapshot.matcher, "<matcher>"), input: child(snapshot.input, "<input>"), exhausted: snapshot.exhausted, properties, extensible: Object.isExtensible(entry), symbolEntries,
141
+ ...(snapshot.global === undefined ? {} : { global: snapshot.global, unicode: snapshot.unicode }) };
138
142
  }
139
143
  else if (isSandboxCollectionIterator(entry)) {
140
144
  const snapshot = snapshotCollectionIterator(entry);
@@ -195,6 +199,7 @@ export function encodeReplayData(value, options = {}) {
195
199
  nodes[id] = {
196
200
  kind: Array.isArray(entry) ? "array" : "object",
197
201
  nullPrototype: prototype === null,
202
+ ...(hasNullObjectPrototype(entry) ? { sandboxNullPrototype: true } : {}),
198
203
  ...(errorType === undefined ? {} : { errorType }),
199
204
  extensible: Object.isExtensible(entry),
200
205
  properties,
@@ -241,6 +246,11 @@ export function decodeReplayData(input, options = {}, parent) {
241
246
  }
242
247
  if (own(atom, "tag") === "undefined")
243
248
  return undefined;
249
+ if (own(atom, "tag") === "bigint") {
250
+ const value = own(atom, "value");
251
+ validateBigIntData(value);
252
+ return BigInt(value);
253
+ }
244
254
  if (atom.tag === "number") {
245
255
  switch (own(atom, "value")) {
246
256
  case "NaN":
@@ -326,7 +336,7 @@ export function decodeReplayData(input, options = {}, parent) {
326
336
  own(record(nodes[Number(payloadRecord.id)]), "kind") === "symbol";
327
337
  if (typeof payload !== "number" && typeof payload !== "string" && typeof payload !== "boolean" &&
328
338
  !symbolReference &&
329
- (payload === null || typeof payload !== "object" || own(record(payload), "tag") !== "number"))
339
+ (payload === null || typeof payload !== "object" || !["number", "bigint"].includes(String(own(record(payload), "tag")))))
330
340
  throw new TypeError("Invalid boxed primitive payload.");
331
341
  const result = createSandboxBox(child(payload));
332
342
  restored.set(id, result);
@@ -365,11 +375,14 @@ export function decodeReplayData(input, options = {}, parent) {
365
375
  restored.set(id, result);
366
376
  const matcher = child(own(node, "matcher"));
367
377
  const input = child(own(node, "input"));
368
- if (matcher !== undefined && !isSandboxRegex(matcher))
378
+ if ((node.global !== undefined || node.unicode !== undefined) && (typeof node.global !== "boolean" || typeof node.unicode !== "boolean"))
379
+ throw new TypeError("Invalid replay RegExp iterator modes.");
380
+ if (matcher !== undefined && (node.global === undefined ? !isSandboxRegex(matcher) : matcher === null || typeof matcher !== "object"))
369
381
  throw new TypeError("Invalid replay RegExp iterator matcher.");
370
382
  if (input !== undefined && typeof input !== "string")
371
383
  throw new TypeError("Invalid replay RegExp iterator input.");
372
- restoreSandboxRegExpIterator({ matcher, input, exhausted }, result);
384
+ restoreSandboxRegExpIterator({ matcher, input, exhausted,
385
+ ...(node.global === undefined ? {} : { global: node.global, unicode: node.unicode }) }, result);
373
386
  defineProperties(result, record(own(node, "properties")), child, node.symbolEntries);
374
387
  if (!node.extensible)
375
388
  Object.preventExtensions(result);
@@ -450,6 +463,11 @@ export function decodeReplayData(input, options = {}, parent) {
450
463
  throw new TypeError("Invalid replay object metadata.");
451
464
  }
452
465
  const result = kind === "array" ? [] : Object.create(node.nullPrototype ? null : Object.prototype);
466
+ if (Object.hasOwn(node, "sandboxNullPrototype")) {
467
+ if (kind !== "object" || node.sandboxNullPrototype !== true)
468
+ throw new TypeError("Invalid replay object prototype.");
469
+ setSandboxPrototype(result, null);
470
+ }
453
471
  if (Object.hasOwn(node, "errorType")) {
454
472
  sandboxErrorTypes.set(result, node.errorType);
455
473
  }
@@ -234,6 +234,8 @@ function deserializeValue(value, state) {
234
234
  if (Array.isArray(value)) {
235
235
  return value.map((entry) => deserializeValue(entry, state));
236
236
  }
237
+ if (value.kind === "bigint" && typeof value.value === "string")
238
+ return BigInt(value.value);
237
239
  if (isSerializedUndefinedValue(value)) {
238
240
  return undefined;
239
241
  }
@@ -439,11 +441,12 @@ function restoreHeapValue(id, state) {
439
441
  state.heapValueById.set(id, iterator);
440
442
  const matcher = deserializeValue(serialized.matcher, state);
441
443
  const input = deserializeValue(serialized.input, state);
442
- if (matcher !== undefined && !isSandboxRegex(matcher))
444
+ if (matcher !== undefined && (serialized.global === undefined ? !isSandboxRegex(matcher) : matcher === null || typeof matcher !== "object"))
443
445
  throw new TypeError("Invalid RegExp iterator matcher.");
444
446
  if (input !== undefined && typeof input !== "string")
445
447
  throw new TypeError("Invalid RegExp iterator input.");
446
- restoreSandboxRegExpIterator({ matcher, input, exhausted: serialized.exhausted }, iterator);
448
+ restoreSandboxRegExpIterator({ matcher: matcher, input, exhausted: serialized.exhausted,
449
+ ...(serialized.global === undefined ? {} : { global: serialized.global, unicode: serialized.unicode }) }, iterator);
447
450
  for (const [key, entry] of Object.entries(serialized.entries))
448
451
  Object.defineProperty(iterator, key, { value: deserializeValue(entry, state), enumerable: true, configurable: true, writable: true });
449
452
  restoreSymbolProperties(iterator, serialized.symbolEntries, entry => deserializeValue(entry, state));
@@ -478,6 +481,11 @@ function restoreHeapValue(id, state) {
478
481
  }
479
482
  const object = Object.create(null);
480
483
  state.heapValueById.set(id, object);
484
+ if (Object.hasOwn(serialized, "sandboxNullPrototype")) {
485
+ if (serialized.sandboxNullPrototype !== true)
486
+ throw new TypeError("Invalid object prototype.");
487
+ setSandboxPrototype(object, null);
488
+ }
481
489
  if (serialized.errorType !== undefined)
482
490
  sandboxErrorTypes.set(object, serialized.errorType);
483
491
  for (const [key, entry] of Object.entries(serialized.entries)) {
@@ -54,6 +54,8 @@ export type SerializedHeapValue = {
54
54
  matcher: SerializedSnapshotValue;
55
55
  input: SerializedSnapshotValue;
56
56
  exhausted: boolean;
57
+ global?: boolean;
58
+ unicode?: boolean;
57
59
  entries: Record<string, SerializedSnapshotValue>;
58
60
  symbolEntries?: Array<SerializedSymbolProperty<SerializedSnapshotValue>>;
59
61
  } | SerializedSymbol | BoxedData<SerializedSnapshotValue> | ({
@@ -73,6 +75,7 @@ export type SerializedHeapValue = {
73
75
  entries: Record<string, SerializedSnapshotValue>;
74
76
  }) | SerializedArguments<SerializedSnapshotValue> | SerializedArray<SerializedSnapshotValue> | {
75
77
  kind: "object";
78
+ sandboxNullPrototype?: true;
76
79
  entries: Record<string, SerializedSnapshotValue>;
77
80
  symbolEntries?: Array<SerializedSymbolProperty<SerializedSnapshotValue>>;
78
81
  errorType?: SandboxErrorName;
@@ -102,7 +105,7 @@ export type RuntimePromiseValue = {
102
105
  id: SnapshotId;
103
106
  promise?: Promise<unknown>;
104
107
  };
105
- export type RuntimeSnapshotValue = symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
108
+ export type RuntimeSnapshotValue = bigint | symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
106
109
  [key: string]: RuntimeSnapshotValue;
107
110
  };
108
111
  export type RuntimeScopeFrame = {
@@ -3,7 +3,7 @@ import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-pro
3
3
  import { ownSerializableSymbolKeys, serializeSymbol, serializeSymbolProperties } from "./symbols.js";
4
4
  import { collectionIteratorState, isSandboxCollectionIterator, snapshotCollectionIterator } from "../interp/collection-iterator.js";
5
5
  import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-iterator.js";
6
- import { hasGuestObjectState } from "../interp/object-model.js";
6
+ import { hasGuestObjectState, hasNullObjectPrototype } from "../interp/object-model.js";
7
7
  import { sandboxErrorTypes } from "../error/shape.js";
8
8
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
9
9
  import { serializeArguments } from "./arguments.js";
@@ -116,6 +116,8 @@ function serializeValue(value, path, state) {
116
116
  : "-Infinity"
117
117
  };
118
118
  }
119
+ if (typeof value === "bigint")
120
+ return { kind: "bigint", value: String(value) };
119
121
  if (Array.isArray(value)) {
120
122
  const reference = serializeHeapReference(value, path, state);
121
123
  if (reference !== undefined) {
@@ -220,6 +222,7 @@ function serializeHeapReference(value, path, state) {
220
222
  const entries = Object.create(null);
221
223
  state.heap[String(id)] = {
222
224
  kind: "regexp-iterator", matcher: serializeValue(snapshot.matcher, `${path}.<matcher>`, state),
225
+ ...(snapshot.global === undefined ? {} : { global: snapshot.global, unicode: snapshot.unicode }),
223
226
  input: serializeValue(snapshot.input, `${path}.<input>`, state), exhausted: snapshot.exhausted, entries,
224
227
  symbolEntries: serializeSymbolProperties(value, entry => serializeValue(entry, `${path}.[symbol]`, state))
225
228
  };
@@ -283,6 +286,7 @@ function serializeHeapReference(value, path, state) {
283
286
  const errorType = sandboxErrorTypes.get(value);
284
287
  const serializedObject = {
285
288
  kind: "object",
289
+ ...(hasNullObjectPrototype(value) ? { sandboxNullPrototype: true } : {}),
286
290
  entries,
287
291
  ...(errorType === undefined ? {} : { errorType })
288
292
  };
@@ -359,6 +363,7 @@ function indexHeapContainers(input) {
359
363
  for (const [value, stat] of stats.entries()) {
360
364
  if (stat.count > 1 ||
361
365
  stat.cyclic ||
366
+ hasNullObjectPrototype(value) ||
362
367
  ownSerializableSymbolKeys(value).length > 0 ||
363
368
  (isSandboxRegex(value) && (hasCustomRegexProperties(value) || !Number.isSafeInteger(value.lastIndex) ||
364
369
  (typeof value.lastIndex === "number" && value.lastIndex < 0) || Object.is(value.lastIndex, -0))) ||
@@ -1,4 +1,5 @@
1
1
  import { replaceErrorStack, sandboxErrorNames } from "../error/shape.js";
2
+ import { validateBigIntData } from "./bigint.js";
2
3
  import { validateRegexProperties } from "./regexp-properties.js";
3
4
  import { wellKnownSymbols } from "../interp/symbols.js";
4
5
  import { types } from "node:util";
@@ -115,6 +116,8 @@ function validateDumpHeap(root, state) {
115
116
  continue;
116
117
  }
117
118
  if (entry.kind === "object") {
119
+ if (Object.hasOwn(entry, "sandboxNullPrototype") && entry.sandboxNullPrototype !== true)
120
+ fail("invalidValue", `${path}.sandboxNullPrototype`, "invalid object prototype");
118
121
  requireRecord(entry.entries, `${path}.entries`);
119
122
  continue;
120
123
  }
@@ -355,6 +358,15 @@ function validateValue(value, path, depth, state) {
355
358
  }
356
359
  function validateTaggedValue(record, path, state) {
357
360
  switch (record.kind) {
361
+ case "bigint":
362
+ requireString(record.value, `${path}.value`, state.limits);
363
+ try {
364
+ validateBigIntData(record.value);
365
+ }
366
+ catch {
367
+ fail("invalidValue", `${path}.value`, "invalid BigInt value");
368
+ }
369
+ return;
358
370
  case "undefined":
359
371
  return;
360
372
  case "number":
@@ -394,7 +406,11 @@ function validateTaggedValue(record, path, state) {
394
406
  return;
395
407
  case "array":
396
408
  case "arguments":
409
+ return;
397
410
  case "object":
411
+ if (Object.hasOwn(record, "sandboxNullPrototype") && record.sandboxNullPrototype !== true)
412
+ fail("invalidValue", `${path}.sandboxNullPrototype`, "invalid object prototype");
413
+ return;
398
414
  case "map":
399
415
  case "set":
400
416
  case "collection-iterator":
@@ -474,6 +490,8 @@ function validateHeapValue(value, path, state, heap) {
474
490
  if (record.kind === "set")
475
491
  requireArray(record.values, `${path}.values`, state);
476
492
  if (record.kind === "regexp-iterator") {
493
+ if ((record.global !== undefined || record.unicode !== undefined) && (typeof record.global !== "boolean" || typeof record.unicode !== "boolean"))
494
+ fail("invalidValue", path, "invalid RegExp iterator modes");
477
495
  if (typeof record.exhausted !== "boolean")
478
496
  fail("invalidValue", `${path}.exhausted`, "invalid iterator exhaustion");
479
497
  if (!Object.hasOwn(record, "matcher") || !Object.hasOwn(record, "input"))
@@ -539,6 +557,15 @@ function validateBoxedRecord(record, path, heap) {
539
557
  if (typeof value === "number" || typeof value === "string" || typeof value === "boolean")
540
558
  return;
541
559
  const number = requireRecord(value, `${path}.value`);
560
+ if (number.kind === "bigint") {
561
+ try {
562
+ validateBigIntData(number.value);
563
+ }
564
+ catch {
565
+ fail("invalidValue", `${path}.value`, "invalid boxed BigInt payload");
566
+ }
567
+ return;
568
+ }
542
569
  if (number.kind === "ref") {
543
570
  const id = requireSafeInteger(number.id, `${path}.value.id`, 1);
544
571
  const target = requireRecord(heap[String(id)], `${path}.value`);