poe-code 14.0.73 → 14.0.75

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 (47) hide show
  1. package/dist/index.js +2732 -1188
  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-I2Z37MKZ.js → chunk-BAJI3K4B.js} +2 -2
  6. package/packages/safe-js/dist/chunks/{chunk-XKCTB5FR.js → chunk-EOTY4PCT.js} +2902 -1425
  7. package/packages/safe-js/dist/chunks/chunk-EOTY4PCT.js.map +7 -0
  8. package/packages/safe-js/dist/cli.js +2 -2
  9. package/packages/safe-js/dist/core.js +1 -1
  10. package/packages/safe-js/dist/graph-depth.js +3 -0
  11. package/packages/safe-js/dist/index.js +2 -2
  12. package/packages/safe-js/dist/interp/cancel.js +3 -0
  13. package/packages/safe-js/dist/interp/globals/misc.js +2 -1
  14. package/packages/safe-js/dist/interp/globals/object.js +3 -0
  15. package/packages/safe-js/dist/interp/globals/regex.js +196 -9
  16. package/packages/safe-js/dist/interp/interpreter.js +14 -7
  17. package/packages/safe-js/dist/interp/iteration.js +9 -1
  18. package/packages/safe-js/dist/interp/methods/regex-split.d.ts +3 -0
  19. package/packages/safe-js/dist/interp/methods/regex-split.js +102 -0
  20. package/packages/safe-js/dist/interp/methods/regex.d.ts +8 -4
  21. package/packages/safe-js/dist/interp/methods/regex.js +141 -24
  22. package/packages/safe-js/dist/interp/methods/regexp-iterator.d.ts +12 -0
  23. package/packages/safe-js/dist/interp/methods/regexp-iterator.js +101 -0
  24. package/packages/safe-js/dist/interp/methods/string.d.ts +2 -0
  25. package/packages/safe-js/dist/interp/methods/string.js +415 -121
  26. package/packages/safe-js/dist/interp/object-model.d.ts +3 -0
  27. package/packages/safe-js/dist/interp/object-model.js +43 -10
  28. package/packages/safe-js/dist/interp/regex/compile-guard.js +26 -4
  29. package/packages/safe-js/dist/interp/regex/engine.d.ts +4 -0
  30. package/packages/safe-js/dist/interp/regex/engine.js +230 -30
  31. package/packages/safe-js/dist/interp/regex/parse.d.ts +42 -4
  32. package/packages/safe-js/dist/interp/regex/parse.js +429 -25
  33. package/packages/safe-js/dist/interp/regexp-iterator.d.ts +16 -0
  34. package/packages/safe-js/dist/interp/regexp-iterator.js +23 -0
  35. package/packages/safe-js/dist/interp/string-coercion.js +11 -7
  36. package/packages/safe-js/dist/interp/values.d.ts +2 -1
  37. package/packages/safe-js/dist/interp/values.js +39 -2
  38. package/packages/safe-js/dist/snapshot/dump-format.js +35 -3
  39. package/packages/safe-js/dist/snapshot/replay-data.d.ts +12 -1
  40. package/packages/safe-js/dist/snapshot/replay-data.js +42 -1
  41. package/packages/safe-js/dist/snapshot/replay-inputs.js +17 -0
  42. package/packages/safe-js/dist/snapshot/restore.js +23 -1
  43. package/packages/safe-js/dist/snapshot/serialize.d.ts +13 -2
  44. package/packages/safe-js/dist/snapshot/serialize.js +30 -11
  45. package/packages/safe-js/dist/snapshot/validation.js +22 -2
  46. package/packages/safe-js/dist/chunks/chunk-XKCTB5FR.js.map +0 -7
  47. /package/packages/safe-js/dist/chunks/{chunk-I2Z37MKZ.js.map → chunk-BAJI3K4B.js.map} +0 -0
@@ -0,0 +1,23 @@
1
+ const states = new WeakMap();
2
+ export function isSandboxRegExpIterator(value) {
3
+ return typeof value === "object" && value !== null && states.has(value);
4
+ }
5
+ export function restoreSandboxRegExpIterator(state, target = Object.create(null)) {
6
+ if ((state.global !== undefined || state.unicode !== undefined) &&
7
+ (typeof state.global !== "boolean" || typeof state.unicode !== "boolean"))
8
+ throw new TypeError("Invalid RegExp iterator modes.");
9
+ if (state.matcher !== undefined && (state.matcher === null || typeof state.matcher !== "object"))
10
+ throw new TypeError("Invalid RegExp iterator matcher.");
11
+ if (!state.exhausted && (state.matcher === undefined || state.input === undefined))
12
+ throw new TypeError("A live RegExp iterator requires its matcher and input.");
13
+ states.set(target, state.exhausted
14
+ ? { ...state, matcher: undefined, input: undefined, exhausted: true }
15
+ : { ...state });
16
+ return target;
17
+ }
18
+ export function regexpIteratorState(value) {
19
+ const state = states.get(value);
20
+ if (state === undefined)
21
+ throw new TypeError("Expected a RegExp string iterator.");
22
+ return state;
23
+ }
@@ -7,12 +7,13 @@ import { float32Storage, isFloat32Array } from "./float32.js";
7
7
  import { assertSandboxDataDepth } from "../graph-depth.js";
8
8
  import { isGuestHostObject } from "./host-capabilities.js";
9
9
  import { collectionIteratorState, isSandboxCollectionIterator } from "./collection-iterator.js";
10
+ import { isSandboxRegExpIterator } from "./regexp-iterator.js";
10
11
  import { getGuestFunctionProperties, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure } from "./object-model.js";
11
- import { getRegexMember } from "./methods/regex.js";
12
+ import { regexToString } from "./methods/regex.js";
12
13
  import { retainValues } from "./resources.js";
13
14
  import { functionString } from "./function-string.js";
14
15
  import { boxedValue, isSandboxBox } from "./boxed.js";
15
- import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandboxRegex, isSandboxGenerator } from "./values.js";
16
+ import { isSandboxClosure, isSandboxPromise, isSandboxMap, isSandboxSet, isSandboxRegex, getRegexProperties, isSandboxGenerator } from "./values.js";
16
17
  const defaultStringHook = Symbol("defaultStringHook");
17
18
  const defaultValueHook = Symbol("defaultValueHook");
18
19
  const joiningArrays = new WeakSet();
@@ -115,14 +116,16 @@ function conversionHook(value, name, budget, context) {
115
116
  isSandboxMap(value) ||
116
117
  isSandboxSet(value) ||
117
118
  isSandboxCollectionIterator(value) ||
119
+ isSandboxRegExpIterator(value) ||
118
120
  isSandboxPromise(value) ||
119
- isSandboxRegex(value) ||
121
+ (isSandboxRegex(value) && getSandboxPrototype(value, budget) === null) ||
120
122
  isSandboxGenerator(value) ||
121
123
  isGuestHostObject(value));
122
124
  let current = value;
123
125
  let depth = 0;
124
126
  while (current !== null) {
125
- const properties = isGuestClosure(current) ? getGuestFunctionProperties(current) : current;
127
+ const properties = isGuestClosure(current) ? getGuestFunctionProperties(current)
128
+ : isSandboxRegex(current) ? getRegexProperties(current) : current;
126
129
  const descriptor = properties === undefined ? undefined : Object.getOwnPropertyDescriptor(properties, name);
127
130
  if (descriptor !== undefined) {
128
131
  return readPropertyDescriptor(descriptor, value, context);
@@ -154,15 +157,16 @@ async function defaultToString(value, budget, context, joining) {
154
157
  return "[object Map]";
155
158
  if (isSandboxSet(value))
156
159
  return "[object Set]";
160
+ if (isSandboxRegExpIterator(value))
161
+ return "[object RegExp String Iterator]";
157
162
  if (isSandboxCollectionIterator(value))
158
163
  return collectionIteratorState(value).collectionKind === "map"
159
164
  ? "[object Map Iterator]"
160
165
  : "[object Set Iterator]";
161
166
  if (isSandboxGenerator(value))
162
167
  return "[object Generator]";
163
- if (isSandboxRegex(value)) {
164
- return budget.allocateString(`/${String(getRegexMember(value, "source", budget))}/${String(getRegexMember(value, "flags", budget))}`);
165
- }
168
+ if (isSandboxRegex(value))
169
+ return regexToString(value, budget, context);
166
170
  if (isSandboxDate(value))
167
171
  return budget.allocateString(dateString(value));
168
172
  if (Array.isArray(value) || isFloat32Array(value)) {
@@ -1,6 +1,7 @@
1
1
  export { getRegexProperties } from "./regexp-properties.js";
2
2
  import { sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
3
3
  import { type SandboxCollectionIterator } from "./collection-iterator.js";
4
+ import { type SandboxRegExpIterator } from "./regexp-iterator.js";
4
5
  import type { Budget, CompileTicket } from "./budget.js";
5
6
  import { CompileScope } from "./regex/compile-guard.js";
6
7
  import type { GeneratorChannel } from "./generator.js";
@@ -15,7 +16,7 @@ declare const sandboxRegexBrand: unique symbol;
15
16
  declare const sandboxRegexPattern: unique symbol;
16
17
  declare const sandboxRetainedValues: unique symbol;
17
18
  export type SandboxPrimitive = string | number | boolean | symbol | null | undefined;
18
- export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
19
+ export type SandboxValue = SandboxPrimitive | Date | Float32Array | SandboxObject | SandboxArray | SandboxClosure | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | SandboxMap | SandboxSet | SandboxPromise | SandboxRegex;
19
20
  export type SandboxObject = {
20
21
  [key: string]: SandboxValue;
21
22
  [key: symbol]: SandboxValue;
@@ -5,6 +5,7 @@ export { getRegexProperties } from "./regexp-properties.js";
5
5
  import { retainedAccessorClosures } from "./accessors.js";
6
6
  import { isSandboxMap, isSandboxSet, sandboxMapBrand, sandboxSetBrand } from "./collection-brands.js";
7
7
  import { collectionIteratorState, isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "./collection-iterator.js";
8
+ import { regexpIteratorState, isSandboxRegExpIterator, restoreSandboxRegExpIterator } from "./regexp-iterator.js";
8
9
  import { copyNativeDate, dateDataProperties, exportDate, isSandboxDate } from "./date.js";
9
10
  import { boxedDataProperties, boxedValue, createSandboxBox, isSandboxBox, nativeBoxedValue } from "./boxed.js";
10
11
  import { getHostObjectKeys, getHostObjectMember, hasHostObjectMember, measureHostObjectData, isGuestHostObject, isLiveCapability } from "./host-capabilities.js";
@@ -18,7 +19,7 @@ import { invokeCancelableClosure, readPromiseCancellation, registerPromiseCancel
18
19
  import { parseRegex } from "./regex/parse.js";
19
20
  import { assertSandboxDataDepth } from "../graph-depth.js";
20
21
  import { sandboxErrorTypes } from "../error/shape.js";
21
- 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";
22
23
  import { copySandboxArgumentProperties, createSandboxArguments, getSandboxArgumentEntries, isSandboxArguments } from "./arguments.js";
23
24
  export { createSandboxArguments, isSandboxArguments } from "./arguments.js";
24
25
  export { isSandboxMap, isSandboxSet } from "./collection-brands.js";
@@ -400,6 +401,17 @@ export function measureSandboxData(values, options = {}) {
400
401
  }
401
402
  return;
402
403
  }
404
+ if (isSandboxRegExpIterator(value)) {
405
+ const state = regexpIteratorState(value);
406
+ visit(state.matcher, depth + 1);
407
+ visit(state.input, depth + 1);
408
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
409
+ usage += key.length + 1;
410
+ if ("value" in descriptor)
411
+ visit(descriptor.value, depth + 1);
412
+ }
413
+ return;
414
+ }
403
415
  if (isSandboxCollectionIterator(value)) {
404
416
  visit(collectionIteratorState(value).collection, depth + 1);
405
417
  for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(value))) {
@@ -588,6 +600,26 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
588
600
  isSandboxPromise(value)) {
589
601
  return value;
590
602
  }
603
+ if (isSandboxRegExpIterator(value)) {
604
+ if (hasGuestObjectState(value))
605
+ throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
606
+ if (!cloneSandboxCollections)
607
+ return value;
608
+ const existing = state.seen.get(value);
609
+ if (existing !== undefined)
610
+ return existing;
611
+ const snapshot = regexpIteratorState(value);
612
+ const copy = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
613
+ state.seen.set(value, copy);
614
+ const matcher = copyToSandbox(snapshot.matcher, state, `${path}.<matcher>`, true, depth + 1);
615
+ if (matcher !== undefined && (snapshot.global === undefined ? !isSandboxRegex(matcher) : matcher === null || typeof matcher !== "object"))
616
+ throw new TypeError("Invalid RegExp iterator matcher.");
617
+ restoreSandboxRegExpIterator({ ...snapshot, matcher }, copy);
618
+ for (const entry of getEnumerableObjectEntries(value, path)) {
619
+ defineOwnDataProperty(copy, entry.key, copyToSandbox(entry.value, state, joinPath(path, entry.key), true, depth + 1));
620
+ }
621
+ return copy;
622
+ }
591
623
  if (isSandboxCollectionIterator(value)) {
592
624
  if (hasGuestObjectState(value))
593
625
  throw new TypeError("Guest prototype links and custom descriptors cannot be copied as data.");
@@ -749,6 +781,8 @@ function copyToSandbox(value, state, path = "<root>", cloneSandboxCollections =
749
781
  return existing;
750
782
  }
751
783
  const copy = createPlainObject(!cloneSandboxCollections || Object.getPrototypeOf(value) === null);
784
+ if (!state.structuredClone && hasNullObjectPrototype(value))
785
+ setSandboxPrototype(copy, null);
752
786
  state.seen.set(value, copy);
753
787
  const errorType = sandboxErrorTypes.get(value);
754
788
  if (errorType !== undefined)
@@ -890,6 +924,9 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
890
924
  if (isSandboxCollectionIterator(value)) {
891
925
  throw new TypeError("Sandbox collection iterators cannot cross into host values.");
892
926
  }
927
+ if (isSandboxRegExpIterator(value)) {
928
+ throw new TypeError("Sandbox RegExp iterators cannot cross into host values.");
929
+ }
893
930
  if (isSandboxRegex(value)) {
894
931
  throw new TypeError("Invalid sandbox RegExp brand.");
895
932
  }
@@ -943,7 +980,7 @@ function copyFromSandbox(value, state, path = "<root>", options, depth = 0) {
943
980
  if (existing !== undefined) {
944
981
  return existing;
945
982
  }
946
- const copy = createPlainObject(Object.getPrototypeOf(value) === null);
983
+ const copy = createPlainObject(hasNullObjectPrototype(value) || Object.getPrototypeOf(value) === null);
947
984
  state.seen.set(value, copy);
948
985
  for (const entry of getEnumerableObjectEntries(value, path)) {
949
986
  defineOwnDataProperty(copy, entry.key, copyFromSandbox(entry.value, state, joinPath(path, entry.key), options, depth + 1));
@@ -1,9 +1,10 @@
1
1
  export const DUMP_FORMAT_VERSION = 1;
2
2
  import { getRegexProperties, isSandboxRegex } from "../interp/values.js";
3
+ import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-iterator.js";
3
4
  import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-properties.js";
4
5
  export const EXECUTION_SEMANTICS = "jobs-v8";
5
6
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
6
- import { hasGuestObjectState } from "../interp/object-model.js";
7
+ import { hasGuestObjectState, hasNullObjectPrototype } from "../interp/object-model.js";
7
8
  import { sandboxErrorTypes } from "../error/shape.js";
8
9
  import { getSandboxArgumentEntries, isSandboxArguments } from "../interp/arguments.js";
9
10
  import { serializeArguments } from "./arguments.js";
@@ -81,7 +82,7 @@ function serializeDumpValue(value, path, state) {
81
82
  if (hasGuestObjectState(value)) {
82
83
  throw new TypeError("Guest function properties and prototype links cannot be serialized.");
83
84
  }
84
- if ((isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
85
+ if (isSandboxRegExpIterator(value) || (isSandboxRegex(value) && hasCustomRegexProperties(value)) || isSandboxBox(value) || isSandboxDate(value) || isFloat32Array(value))
85
86
  return serializeHeapReference(value, path, state);
86
87
  if (Array.isArray(value)) {
87
88
  const reference = serializeHeapReference(value, path, state);
@@ -106,7 +107,35 @@ function serializeHeapReference(value, path, state) {
106
107
  }
107
108
  if (!state.serializedHeapIds.has(id)) {
108
109
  state.serializedHeapIds.add(id);
109
- if (isSandboxRegex(value) && hasCustomRegexProperties(value)) {
110
+ if (isSandboxRegExpIterator(value)) {
111
+ const snapshot = regexpIteratorState(value);
112
+ const matcher = snapshot.matcher;
113
+ const serializedMatcher = snapshot.global === undefined && isSandboxRegex(matcher)
114
+ ? { kind: "regex", source: matcher.source, flags: matcher.flags, lastIndex: Number(matcher.lastIndex) }
115
+ : serializeDumpValue(matcher, `${path}.<matcher>`, state);
116
+ if (serializedMatcher === SKIP_VALUE)
117
+ throw new TypeError("Unsupported RegExp iterator matcher in public dump.");
118
+ const entries = Object.create(null);
119
+ state.heap[String(id)] = {
120
+ kind: "regexp-iterator", exhausted: snapshot.exhausted,
121
+ matcher: serializedMatcher,
122
+ ...(snapshot.global === undefined ? {} : { global: snapshot.global, unicode: snapshot.unicode }),
123
+ input: snapshot.input ?? { kind: "undefined" }, entries,
124
+ symbolEntries: serializeSymbolProperties(value, entry => {
125
+ const serialized = serializeDumpValue(entry, `${path}.[symbol]`, state);
126
+ if (serialized === SKIP_VALUE)
127
+ throw new TypeError("Unsupported RegExp iterator symbol property in public dump.");
128
+ return serialized;
129
+ })
130
+ };
131
+ for (const [key, entry] of getEnumerableDataEntries(value)) {
132
+ const serialized = serializeDumpValue(entry, `${path}.${key}`, state);
133
+ if (serialized === SKIP_VALUE)
134
+ throw new TypeError("Unsupported RegExp iterator property in public dump.");
135
+ entries[key] = serialized;
136
+ }
137
+ }
138
+ else if (isSandboxRegex(value) && hasCustomRegexProperties(value)) {
110
139
  const encode = (entry) => {
111
140
  const serialized = serializeDumpValue(entry, `${path}.<regex-property>`, state);
112
141
  if (serialized === SKIP_VALUE)
@@ -169,6 +198,7 @@ function serializeHeapReference(value, path, state) {
169
198
  });
170
199
  state.heap[String(id)] = {
171
200
  kind: "object",
201
+ ...(hasNullObjectPrototype(value) ? { sandboxNullPrototype: true } : {}),
172
202
  entries: serializeObjectEntries(value, path, state),
173
203
  ...(symbolEntries.length === 0 ? {} : { symbolEntries }),
174
204
  ...(errorType === undefined ? {} : { errorType })
@@ -204,8 +234,10 @@ function indexHeapContainers(snapshot) {
204
234
  for (const [value, stat] of stats.entries()) {
205
235
  if (stat.count > 1 ||
206
236
  stat.cyclic ||
237
+ hasNullObjectPrototype(value) ||
207
238
  ownSerializableSymbolKeys(value).length > 0 ||
208
239
  isSandboxBox(value) ||
240
+ isSandboxRegExpIterator(value) ||
209
241
  (isSandboxRegex(value) && hasCustomRegexProperties(value)) ||
210
242
  isSandboxDate(value) ||
211
243
  isFloat32Array(value) ||
@@ -27,7 +27,17 @@ type Properties = Record<string, {
27
27
  enumerable: boolean;
28
28
  writable: boolean;
29
29
  }>;
30
- type DataNode = SerializedSymbol | {
30
+ type DataNode = {
31
+ kind: "regexp-iterator";
32
+ matcher: Atom;
33
+ input: Atom;
34
+ exhausted: boolean;
35
+ global?: boolean;
36
+ unicode?: boolean;
37
+ properties: Properties;
38
+ extensible: boolean;
39
+ symbolEntries?: Array<SerializedSymbolProperty<Atom>>;
40
+ } | SerializedSymbol | {
31
41
  kind: "boxed";
32
42
  value: Atom;
33
43
  properties: Properties;
@@ -61,6 +71,7 @@ type DataNode = SerializedSymbol | {
61
71
  symbolProperties?: Array<SerializedSymbolProperty<Atom>>;
62
72
  extensible: boolean;
63
73
  nullPrototype: boolean;
74
+ sandboxNullPrototype?: true;
64
75
  errorType?: SandboxErrorName;
65
76
  } | {
66
77
  kind: "arguments";
@@ -3,7 +3,8 @@ import { serializeRegexProperties, restoreRegexProperties } from "./regexp-prope
3
3
  import { wellKnownSymbols } from "../interp/symbols.js";
4
4
  import { symbolData, serializeSymbolProperties } from "./symbols.js";
5
5
  import { isSandboxCollectionIterator, restoreSandboxCollectionIterator, snapshotCollectionIterator } from "../interp/collection-iterator.js";
6
- import { hasGuestObjectState } from "../interp/object-model.js";
6
+ import { isSandboxRegExpIterator, regexpIteratorState, restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
7
+ import { hasGuestObjectState, hasNullObjectPrototype, setSandboxPrototype } from "../interp/object-model.js";
7
8
  import { CompileScope } from "../interp/regex/compile-guard.js";
8
9
  import { float32DataProperties, isFloat32Array } from "../interp/float32.js";
9
10
  import { decodeFloat32Storage, encodeFloat32Storage } from "./float32array.js";
@@ -123,6 +124,19 @@ export function encodeReplayData(value, options = {}) {
123
124
  }
124
125
  nodes[id] = { ...storage, properties, extensible: Object.isExtensible(entry) };
125
126
  }
127
+ else if (isSandboxRegExpIterator(entry)) {
128
+ const snapshot = regexpIteratorState(entry);
129
+ const properties = Object.create(null);
130
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(entry))) {
131
+ if (!("value" in descriptor))
132
+ throw new TypeError(`Cannot record replay data accessor '${key}'.`);
133
+ properties[key] = { value: child(descriptor.value, JSON.stringify(["property", key])), configurable: descriptor.configurable === true, enumerable: descriptor.enumerable === true, writable: descriptor.writable === true };
134
+ }
135
+ let symbolIndex = 0;
136
+ 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,
138
+ ...(snapshot.global === undefined ? {} : { global: snapshot.global, unicode: snapshot.unicode }) };
139
+ }
126
140
  else if (isSandboxCollectionIterator(entry)) {
127
141
  const snapshot = snapshotCollectionIterator(entry);
128
142
  const properties = Object.create(null);
@@ -182,6 +196,7 @@ export function encodeReplayData(value, options = {}) {
182
196
  nodes[id] = {
183
197
  kind: Array.isArray(entry) ? "array" : "object",
184
198
  nullPrototype: prototype === null,
199
+ ...(hasNullObjectPrototype(entry) ? { sandboxNullPrototype: true } : {}),
185
200
  ...(errorType === undefined ? {} : { errorType }),
186
201
  extensible: Object.isExtensible(entry),
187
202
  properties,
@@ -344,6 +359,27 @@ export function decodeReplayData(input, options = {}, parent) {
344
359
  Object.preventExtensions(result);
345
360
  return result;
346
361
  }
362
+ if (kind === "regexp-iterator") {
363
+ const exhausted = own(node, "exhausted");
364
+ if (typeof exhausted !== "boolean" || typeof node.extensible !== "boolean")
365
+ throw new TypeError("Invalid replay RegExp iterator.");
366
+ const result = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
367
+ restored.set(id, result);
368
+ const matcher = child(own(node, "matcher"));
369
+ const input = child(own(node, "input"));
370
+ if ((node.global !== undefined || node.unicode !== undefined) && (typeof node.global !== "boolean" || typeof node.unicode !== "boolean"))
371
+ throw new TypeError("Invalid replay RegExp iterator modes.");
372
+ if (matcher !== undefined && (node.global === undefined ? !isSandboxRegex(matcher) : matcher === null || typeof matcher !== "object"))
373
+ throw new TypeError("Invalid replay RegExp iterator matcher.");
374
+ if (input !== undefined && typeof input !== "string")
375
+ throw new TypeError("Invalid replay RegExp iterator input.");
376
+ restoreSandboxRegExpIterator({ matcher, input, exhausted,
377
+ ...(node.global === undefined ? {} : { global: node.global, unicode: node.unicode }) }, result);
378
+ defineProperties(result, record(own(node, "properties")), child, node.symbolEntries);
379
+ if (!node.extensible)
380
+ Object.preventExtensions(result);
381
+ return result;
382
+ }
347
383
  if (kind === "collection-iterator") {
348
384
  const collectionKind = own(node, "collectionKind");
349
385
  const method = own(node, "method");
@@ -419,6 +455,11 @@ export function decodeReplayData(input, options = {}, parent) {
419
455
  throw new TypeError("Invalid replay object metadata.");
420
456
  }
421
457
  const result = kind === "array" ? [] : Object.create(node.nullPrototype ? null : Object.prototype);
458
+ if (Object.hasOwn(node, "sandboxNullPrototype")) {
459
+ if (kind !== "object" || node.sandboxNullPrototype !== true)
460
+ throw new TypeError("Invalid replay object prototype.");
461
+ setSandboxPrototype(result, null);
462
+ }
422
463
  if (Object.hasOwn(node, "errorType")) {
423
464
  sandboxErrorTypes.set(result, node.errorType);
424
465
  }
@@ -1,4 +1,5 @@
1
1
  import { collectionIteratorState, isSandboxCollectionIterator } from "../interp/collection-iterator.js";
2
+ import { regexpIteratorState, isSandboxRegExpIterator } from "../interp/regexp-iterator.js";
2
3
  import { createSandboxPromise, isSandboxClosure, isSandboxMap, isSandboxSet, isSandboxPromise } from "../interp/values.js";
3
4
  import { decodeReplayData, encodeReplayData } from "./replay-data.js";
4
5
  import { CompileScope } from "../interp/regex/compile-guard.js";
@@ -59,6 +60,20 @@ export function prepareReplayInputs(current, saved, preparePromise, onCapability
59
60
  value = descriptor.value;
60
61
  continue;
61
62
  }
63
+ if (isSandboxRegExpIterator(value)) {
64
+ if (key === "<matcher>")
65
+ value = regexpIteratorState(value).matcher;
66
+ else if (key === "<input>")
67
+ value = regexpIteratorState(value).input;
68
+ else {
69
+ const property = JSON.parse(key);
70
+ if (!Array.isArray(property) || property.length !== 2 || property[0] !== "property" || typeof property[1] !== "string")
71
+ throw new TypeError("Invalid replay input iterator capability path.");
72
+ const descriptor = Object.getOwnPropertyDescriptor(value, property[1]);
73
+ value = descriptor !== undefined && "value" in descriptor ? descriptor.value : undefined;
74
+ }
75
+ continue;
76
+ }
62
77
  if (isSandboxCollectionIterator(value)) {
63
78
  if (key === "<collection>")
64
79
  value = collectionIteratorState(value).collection;
@@ -135,6 +150,7 @@ function assertReplayInputShape(restored) {
135
150
  isSandboxClosure(restored) ||
136
151
  isSandboxPromise(restored) ||
137
152
  isSandboxCollectionIterator(restored) ||
153
+ isSandboxRegExpIterator(restored) ||
138
154
  isSandboxMap(restored) ||
139
155
  isSandboxSet(restored))
140
156
  throw new TypeError("Invalid replay inputs.");
@@ -146,6 +162,7 @@ function assertReplayInputShape(restored) {
146
162
  isSandboxClosure(values[key]) ||
147
163
  isSandboxPromise(values[key]) ||
148
164
  isSandboxCollectionIterator(values[key]) ||
165
+ isSandboxRegExpIterator(values[key]) ||
149
166
  isSandboxMap(values[key]) ||
150
167
  isSandboxSet(values[key]))
151
168
  throw new TypeError(`Invalid replay input ${key}.`);
@@ -14,10 +14,11 @@ import { getGuestFunctionProperties, getGuestFunctionProperty, getSandboxDataPro
14
14
  import { functionSources } from "../parse/function-source.js";
15
15
  import { wrapCallerInjectedBindings } from "../interp/host-bridge.js";
16
16
  import { restoreSandboxCollectionIterator } from "../interp/collection-iterator.js";
17
+ import { restoreSandboxRegExpIterator } from "../interp/regexp-iterator.js";
17
18
  import { wellKnownSymbols } from "../interp/symbols.js";
18
19
  import { restoreSymbolProperties } from "./symbols.js";
19
20
  import { restoreDateProperties } from "./date-properties.js";
20
- import { isSandboxMap, isSandboxSet } from "../interp/values.js";
21
+ import { isSandboxMap, isSandboxSet, isSandboxRegex } from "../interp/values.js";
21
22
  import { createSandboxArguments, createSandboxClosure, createSandboxGenerator, createSandboxMap, createSandboxPromise, createSandboxRegex, createSandboxSet, reconcileCompiledValues } from "../interp/values.js";
22
23
  import { createGeneratorChannel, restoreGeneratorChannel } from "../interp/generator.js";
23
24
  import { hashSource } from "../parse/hash.js";
@@ -433,6 +434,22 @@ function restoreHeapValue(id, state) {
433
434
  Object.preventExtensions(args);
434
435
  return args;
435
436
  }
437
+ if (serialized.kind === "regexp-iterator") {
438
+ const iterator = restoreSandboxRegExpIterator({ matcher: undefined, input: undefined, exhausted: true });
439
+ state.heapValueById.set(id, iterator);
440
+ const matcher = deserializeValue(serialized.matcher, state);
441
+ const input = deserializeValue(serialized.input, state);
442
+ if (matcher !== undefined && (serialized.global === undefined ? !isSandboxRegex(matcher) : matcher === null || typeof matcher !== "object"))
443
+ throw new TypeError("Invalid RegExp iterator matcher.");
444
+ if (input !== undefined && typeof input !== "string")
445
+ throw new TypeError("Invalid RegExp iterator input.");
446
+ restoreSandboxRegExpIterator({ matcher: matcher, input, exhausted: serialized.exhausted,
447
+ ...(serialized.global === undefined ? {} : { global: serialized.global, unicode: serialized.unicode }) }, iterator);
448
+ for (const [key, entry] of Object.entries(serialized.entries))
449
+ Object.defineProperty(iterator, key, { value: deserializeValue(entry, state), enumerable: true, configurable: true, writable: true });
450
+ restoreSymbolProperties(iterator, serialized.symbolEntries, entry => deserializeValue(entry, state));
451
+ return iterator;
452
+ }
436
453
  if (serialized.kind === "collection-iterator") {
437
454
  const iterator = restoreSandboxCollectionIterator({ collection: undefined, collectionKind: serialized.collectionKind, method: serialized.method, index: 0, exhausted: true });
438
455
  state.heapValueById.set(id, iterator);
@@ -462,6 +479,11 @@ function restoreHeapValue(id, state) {
462
479
  }
463
480
  const object = Object.create(null);
464
481
  state.heapValueById.set(id, object);
482
+ if (Object.hasOwn(serialized, "sandboxNullPrototype")) {
483
+ if (serialized.sandboxNullPrototype !== true)
484
+ throw new TypeError("Invalid object prototype.");
485
+ setSandboxPrototype(object, null);
486
+ }
465
487
  if (serialized.errorType !== undefined)
466
488
  sandboxErrorTypes.set(object, serialized.errorType);
467
489
  for (const [key, entry] of Object.entries(serialized.entries)) {
@@ -1,6 +1,7 @@
1
1
  import { type RegexPropertyData } from "./regexp-properties.js";
2
2
  import { type SerializedSymbol, type SerializedSymbolProperty } from "./symbols.js";
3
3
  import { type CollectionIterationMethod, type SandboxCollectionIterator } from "../interp/collection-iterator.js";
4
+ import { type SandboxRegExpIterator } from "../interp/regexp-iterator.js";
4
5
  import { type SandboxErrorName } from "../error/shape.js";
5
6
  import { type SerializedArguments } from "./arguments.js";
6
7
  import { type SerializedArray } from "./arrays.js";
@@ -48,7 +49,16 @@ export type SerializedReferenceValue = {
48
49
  kind: "ref";
49
50
  id: number;
50
51
  };
51
- export type SerializedHeapValue = SerializedSymbol | BoxedData<SerializedSnapshotValue> | ({
52
+ export type SerializedHeapValue = {
53
+ kind: "regexp-iterator";
54
+ matcher: SerializedSnapshotValue;
55
+ input: SerializedSnapshotValue;
56
+ exhausted: boolean;
57
+ global?: boolean;
58
+ unicode?: boolean;
59
+ entries: Record<string, SerializedSnapshotValue>;
60
+ symbolEntries?: Array<SerializedSymbolProperty<SerializedSnapshotValue>>;
61
+ } | SerializedSymbol | BoxedData<SerializedSnapshotValue> | ({
52
62
  kind: "regex-object";
53
63
  source: string;
54
64
  flags: string;
@@ -65,6 +75,7 @@ export type SerializedHeapValue = SerializedSymbol | BoxedData<SerializedSnapsho
65
75
  entries: Record<string, SerializedSnapshotValue>;
66
76
  }) | SerializedArguments<SerializedSnapshotValue> | SerializedArray<SerializedSnapshotValue> | {
67
77
  kind: "object";
78
+ sandboxNullPrototype?: true;
68
79
  entries: Record<string, SerializedSnapshotValue>;
69
80
  symbolEntries?: Array<SerializedSymbolProperty<SerializedSnapshotValue>>;
70
81
  errorType?: SandboxErrorName;
@@ -94,7 +105,7 @@ export type RuntimePromiseValue = {
94
105
  id: SnapshotId;
95
106
  promise?: Promise<unknown>;
96
107
  };
97
- export type RuntimeSnapshotValue = symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxGenerator | SandboxCollectionIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
108
+ export type RuntimeSnapshotValue = symbol | SandboxBox | Date | Float32Array | boolean | null | number | string | undefined | RuntimeClosureValue | SandboxGenerator | SandboxCollectionIterator | SandboxRegExpIterator | RuntimePromiseValue | SandboxMap | SandboxRegex | SandboxSet | RuntimeSnapshotValue[] | {
98
109
  [key: string]: RuntimeSnapshotValue;
99
110
  };
100
111
  export type RuntimeScopeFrame = {
@@ -2,7 +2,8 @@ import { hashSource } from "../parse/hash.js";
2
2
  import { hasCustomRegexProperties, serializeRegexProperties } from "./regexp-properties.js";
3
3
  import { ownSerializableSymbolKeys, serializeSymbol, serializeSymbolProperties } from "./symbols.js";
4
4
  import { collectionIteratorState, isSandboxCollectionIterator, snapshotCollectionIterator } from "../interp/collection-iterator.js";
5
- import { hasGuestObjectState } from "../interp/object-model.js";
5
+ import { isSandboxRegExpIterator, regexpIteratorState } from "../interp/regexp-iterator.js";
6
+ import { hasGuestObjectState, hasNullObjectPrototype } from "../interp/object-model.js";
6
7
  import { sandboxErrorTypes } from "../error/shape.js";
7
8
  import { assertSnapshotGraphDepth } from "../graph-depth.js";
8
9
  import { serializeArguments } from "./arguments.js";
@@ -180,7 +181,7 @@ function serializeValue(value, path, state) {
180
181
  throw new TypeError(`Missing regex heap reference at ${path}.`);
181
182
  return { kind: "regex", source: value.source, flags: value.flags, lastIndex: value.lastIndex };
182
183
  }
183
- if (isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
184
+ if (isSandboxBox(value) || isSandboxDate(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxRegExpIterator(value) || isSandboxCollectionIterator(value) || isFloat32Array(value)) {
184
185
  const reference = serializeHeapReference(value, path, state);
185
186
  if (reference === undefined) {
186
187
  throw new TypeError(`Cannot serialize collection without a heap reference at ${path}.`);
@@ -214,6 +215,18 @@ function serializeHeapReference(value, path, state) {
214
215
  lastIndex: serializeValue(value.lastIndex, `${path}.lastIndex`, state),
215
216
  ...serializeRegexProperties(value, entry => serializeValue(entry, `${path}.<regex-property>`, state)) };
216
217
  }
218
+ else if (isSandboxRegExpIterator(value)) {
219
+ const snapshot = regexpIteratorState(value);
220
+ const entries = Object.create(null);
221
+ state.heap[String(id)] = {
222
+ kind: "regexp-iterator", matcher: serializeValue(snapshot.matcher, `${path}.<matcher>`, state),
223
+ ...(snapshot.global === undefined ? {} : { global: snapshot.global, unicode: snapshot.unicode }),
224
+ input: serializeValue(snapshot.input, `${path}.<input>`, state), exhausted: snapshot.exhausted, entries,
225
+ symbolEntries: serializeSymbolProperties(value, entry => serializeValue(entry, `${path}.[symbol]`, state))
226
+ };
227
+ for (const [key, entry] of Object.entries(value))
228
+ entries[key] = serializeValue(entry, `${path}.${key}`, state);
229
+ }
217
230
  else if (isSandboxCollectionIterator(value)) {
218
231
  const snapshot = snapshotCollectionIterator(value);
219
232
  const entries = Object.create(null);
@@ -271,6 +284,7 @@ function serializeHeapReference(value, path, state) {
271
284
  const errorType = sandboxErrorTypes.get(value);
272
285
  const serializedObject = {
273
286
  kind: "object",
287
+ ...(hasNullObjectPrototype(value) ? { sandboxNullPrototype: true } : {}),
274
288
  entries,
275
289
  ...(errorType === undefined ? {} : { errorType })
276
290
  };
@@ -347,6 +361,7 @@ function indexHeapContainers(input) {
347
361
  for (const [value, stat] of stats.entries()) {
348
362
  if (stat.count > 1 ||
349
363
  stat.cyclic ||
364
+ hasNullObjectPrototype(value) ||
350
365
  ownSerializableSymbolKeys(value).length > 0 ||
351
366
  (isSandboxRegex(value) && (hasCustomRegexProperties(value) || !Number.isSafeInteger(value.lastIndex) ||
352
367
  (typeof value.lastIndex === "number" && value.lastIndex < 0) || Object.is(value.lastIndex, -0))) ||
@@ -357,6 +372,7 @@ function indexHeapContainers(input) {
357
372
  sandboxErrorTypes.has(value) ||
358
373
  isSandboxArguments(value) ||
359
374
  isSandboxCollectionIterator(value) ||
375
+ isSandboxRegExpIterator(value) ||
360
376
  isSandboxMap(value) ||
361
377
  isSandboxSet(value)) {
362
378
  heapIds.set(value, nextId);
@@ -379,6 +395,7 @@ function collectContainerStats(value, stats, ancestors) {
379
395
  !isFloat32Array(value) &&
380
396
  !isSandboxMap(value) &&
381
397
  !isSandboxCollectionIterator(value) &&
398
+ !isSandboxRegExpIterator(value) &&
382
399
  !isSandboxSet(value)) {
383
400
  return;
384
401
  }
@@ -410,15 +427,17 @@ function collectContainerStats(value, stats, ancestors) {
410
427
  ? dateDataProperties(value).flatMap(([key, descriptor]) => typeof key === "string" ? [descriptor.value] : [])
411
428
  : isSandboxBox(value)
412
429
  ? boxedDataProperties(value).map(([, descriptor]) => descriptor.value)
413
- : isSandboxCollectionIterator(value)
414
- ? [collectionIteratorState(value).collection, ...Object.values(value)]
415
- : isSandboxArguments(value)
416
- ? Object.values(Object.getOwnPropertyDescriptors(value)).flatMap((descriptor) => "value" in descriptor ? [descriptor.value] : [])
417
- : isSandboxMap(value)
418
- ? [...value.entries].flatMap(([key, entry]) => [key, entry])
419
- : isSandboxSet(value)
420
- ? [...value.values]
421
- : Object.values(value);
430
+ : isSandboxRegExpIterator(value)
431
+ ? [regexpIteratorState(value).matcher, regexpIteratorState(value).input, ...Object.values(value)]
432
+ : isSandboxCollectionIterator(value)
433
+ ? [collectionIteratorState(value).collection, ...Object.values(value)]
434
+ : isSandboxArguments(value)
435
+ ? Object.values(Object.getOwnPropertyDescriptors(value)).flatMap((descriptor) => "value" in descriptor ? [descriptor.value] : [])
436
+ : isSandboxMap(value)
437
+ ? [...value.entries].flatMap(([key, entry]) => [key, entry])
438
+ : isSandboxSet(value)
439
+ ? [...value.values]
440
+ : Object.values(value);
422
441
  for (const entry of entries) {
423
442
  collectContainerStats(entry, stats, ancestors);
424
443
  }