@poe-platform/safe-js 0.1.88 → 0.1.90

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.
@@ -6997,6 +6997,9 @@ function getSandboxPrototype(value, budget) {
6997
6997
  if (prototypes.has(value)) return prototypes.get(value) ?? null;
6998
6998
  return budget !== void 0 && isPrototypeRecord(value) ? intrinsicPrototypes.get(budget) ?? null : null;
6999
6999
  }
7000
+ function hasExplicitSandboxPrototype(value) {
7001
+ return prototypes.has(value);
7002
+ }
7000
7003
  function setSandboxPrototype(value, prototype, budget) {
7001
7004
  if (budget !== void 0 && intrinsicPrototypes.get(budget) === value && prototype !== null) {
7002
7005
  throw new TypeError("Object.prototype has an immutable null prototype.");
@@ -8157,98 +8160,532 @@ function isCounter(value) {
8157
8160
  // packages/safe-js/src/interp/cancel.ts
8158
8161
  import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
8159
8162
 
8160
- // packages/safe-js/src/interp/exceptions.ts
8161
- var capturedExceptionBrand = /* @__PURE__ */ Symbol("CapturedException");
8162
- async function evaluateThrowStatement(node, context, evaluateNode2) {
8163
- const argument = await evaluateNode2(node.argument, context);
8164
- if (argument.kind !== "normal") {
8165
- return argument;
8163
+ // packages/safe-js/src/interp/regex/engine.ts
8164
+ function matchRegex(pattern, input, lastIndex = 0) {
8165
+ const startIndex = pattern.flags.global ? normalizeLastIndex(lastIndex) : 0;
8166
+ return matchRegexFrom(pattern, input, startIndex);
8167
+ }
8168
+ function matchRegexFrom(pattern, input, startIndex) {
8169
+ if (startIndex > input.length) {
8170
+ return null;
8166
8171
  }
8167
- return {
8168
- kind: "throw",
8169
- hasValue: true,
8170
- span: node.span,
8171
- stackFrames: context.callStack,
8172
- value: argument.value
8173
- };
8172
+ for (let attempt = startIndex; attempt <= input.length; attempt += 1) {
8173
+ const context = { input, flags: pattern.flags, steps: 0 };
8174
+ charge(context);
8175
+ const initialState = {
8176
+ position: attempt,
8177
+ captures: new Array(pattern.captureCount)
8178
+ };
8179
+ const result = matchNode(pattern.body, initialState, context).next();
8180
+ if (!result.done) {
8181
+ return toRegexMatch(input, attempt, result.value);
8182
+ }
8183
+ }
8184
+ return null;
8174
8185
  }
8175
- async function evaluateTryStatement(node, context, evaluateNode2) {
8176
- let fatalBudgetError;
8177
- let tryResult;
8178
- try {
8179
- tryResult = await evaluateBlockCompletion(node.block, context, evaluateNode2);
8180
- } catch (error) {
8181
- if (!isBudgetExceeded(error) || node.finalizer === void 0) {
8182
- throw error;
8186
+ function* matchNode(node, state, context) {
8187
+ charge(context);
8188
+ switch (node.type) {
8189
+ case "empty":
8190
+ yield state;
8191
+ return;
8192
+ case "literal":
8193
+ if (charactersEqual(context.input[state.position], node.value, context.flags.ignoreCase)) {
8194
+ yield { ...state, position: state.position + 1 };
8195
+ }
8196
+ return;
8197
+ case "dot":
8198
+ if (state.position < context.input.length && (context.flags.dotAll || !isLineTerminator(context.input[state.position]))) {
8199
+ yield { ...state, position: state.position + 1 };
8200
+ }
8201
+ return;
8202
+ case "anchor":
8203
+ if (matchesAnchor(node.kind, state.position, context)) {
8204
+ yield state;
8205
+ }
8206
+ return;
8207
+ case "wordBoundary": {
8208
+ const previousWord = state.position > 0 && isWordCharacter(context.input[state.position - 1]);
8209
+ const nextWord = state.position < context.input.length && isWordCharacter(context.input[state.position]);
8210
+ if (previousWord !== nextWord !== node.negated) {
8211
+ yield state;
8212
+ }
8213
+ return;
8183
8214
  }
8184
- fatalBudgetError = error;
8185
- tryResult = {
8186
- kind: "throw",
8187
- hasValue: true,
8188
- value: void 0
8189
- };
8215
+ case "characterClass": {
8216
+ const character = context.input[state.position];
8217
+ if (character !== void 0 && matchesCharacterClass(character, node.items, node.negated, context.flags.ignoreCase)) {
8218
+ yield { ...state, position: state.position + 1 };
8219
+ }
8220
+ return;
8221
+ }
8222
+ case "sequence":
8223
+ yield* matchSequence(node.elements, 0, state, context);
8224
+ return;
8225
+ case "alternation":
8226
+ for (const alternative of node.alternatives) {
8227
+ yield* matchNode(alternative, cloneState(state), context);
8228
+ }
8229
+ return;
8230
+ case "group":
8231
+ for (const result of matchNode(node.body, cloneState(state), context)) {
8232
+ if (!node.capturing || node.index === void 0) {
8233
+ yield result;
8234
+ continue;
8235
+ }
8236
+ const captures = result.captures.slice();
8237
+ captures[node.index - 1] = { start: state.position, end: result.position };
8238
+ yield { position: result.position, captures };
8239
+ }
8240
+ return;
8241
+ case "quantifier":
8242
+ yield* matchQuantifier(node, state, context, 0);
8190
8243
  }
8191
- const tryOrCatchResult = fatalBudgetError === void 0 && tryResult.kind === "throw" && node.handler !== void 0 ? await evaluateCatchClause(node.handler, tryResult.value, context, evaluateNode2) : tryResult;
8192
- if (node.finalizer === void 0 || tryOrCatchResult.kind === "error") {
8193
- return tryOrCatchResult;
8244
+ }
8245
+ function* matchSequence(elements, index, state, context) {
8246
+ charge(context);
8247
+ if (index === elements.length) {
8248
+ yield state;
8249
+ return;
8194
8250
  }
8195
- const evaluateFinalizer = () => fatalBudgetError?.budget === "deadline" ? evaluateWithoutDeadlineChecks(
8196
- context,
8197
- () => evaluateBlockCompletion(node.finalizer, context, evaluateNode2)
8198
- ) : evaluateBlockCompletion(node.finalizer, context, evaluateNode2);
8199
- const finalizerResult = await (fatalBudgetError === void 0 ? evaluateFinalizer() : withFatalPromiseCleanup(evaluateFinalizer));
8200
- if (fatalBudgetError !== void 0) {
8201
- throw fatalBudgetError;
8251
+ for (const result of matchNode(elements[index], state, context)) {
8252
+ yield* matchSequence(elements, index + 1, result, context);
8202
8253
  }
8203
- if (finalizerResult.kind === "normal") {
8204
- return tryOrCatchResult;
8254
+ }
8255
+ function* matchQuantifier(node, state, context, count) {
8256
+ charge(context);
8257
+ const canRepeat = node.max === void 0 || count < node.max;
8258
+ if (!node.greedy && count >= node.min) {
8259
+ yield state;
8260
+ }
8261
+ if (canRepeat) {
8262
+ for (const result of matchNode(node.body, clearCaptures(node.body, state), context)) {
8263
+ if (result.position === state.position) {
8264
+ if (count >= node.min) {
8265
+ continue;
8266
+ }
8267
+ if (count + 1 >= node.min) {
8268
+ yield result;
8269
+ } else {
8270
+ yield* matchQuantifier(node, result, context, count + 1);
8271
+ }
8272
+ continue;
8273
+ }
8274
+ yield* matchQuantifier(node, result, context, count + 1);
8275
+ }
8276
+ }
8277
+ if (node.greedy && count >= node.min) {
8278
+ yield state;
8205
8279
  }
8206
- return finalizerResult;
8207
8280
  }
8208
- function createCapturedException(reason, stackFrames, sandbox = false) {
8281
+ function matchesAnchor(kind, position, context) {
8282
+ if (kind === "start") {
8283
+ return position === 0 || context.flags.multiline && position > 0 && isLineTerminator(context.input[position - 1]);
8284
+ }
8285
+ return position === context.input.length || context.flags.multiline && position < context.input.length && isLineTerminator(context.input[position]);
8286
+ }
8287
+ function matchesCharacterClass(character, items, negated, ignoreCase) {
8288
+ const matched = items.some((item) => matchesCharacterClassItem(character, item, ignoreCase));
8289
+ return negated ? !matched : matched;
8290
+ }
8291
+ function matchesCharacterClassItem(character, item, ignoreCase) {
8292
+ if (item.type === "character") {
8293
+ return charactersEqual(character, item.value, ignoreCase);
8294
+ }
8295
+ if (item.type === "range") {
8296
+ const candidate = character.charCodeAt(0);
8297
+ const from = item.from.charCodeAt(0);
8298
+ const to = item.to.charCodeAt(0);
8299
+ if (candidate >= from && candidate <= to) {
8300
+ return true;
8301
+ }
8302
+ if (!ignoreCase) {
8303
+ return false;
8304
+ }
8305
+ const foldedCandidate = foldCharacter(character, true).charCodeAt(0);
8306
+ const foldedFrom = foldCharacter(item.from, true).charCodeAt(0);
8307
+ const foldedTo = foldCharacter(item.to, true).charCodeAt(0);
8308
+ return foldedCandidate >= foldedFrom && foldedCandidate <= foldedTo;
8309
+ }
8310
+ const matched = item.kind === "digit" ? isDigit(character) : item.kind === "word" ? isWordCharacter(character) : isSpaceCharacter(character);
8311
+ return item.negated ? !matched : matched;
8312
+ }
8313
+ function toRegexMatch(input, start, state) {
8209
8314
  return {
8210
- reason,
8211
- sandbox,
8212
- stackFrames,
8213
- [capturedExceptionBrand]: true
8315
+ index: start,
8316
+ text: input.slice(start, state.position),
8317
+ captures: state.captures.map(
8318
+ (capture) => capture === void 0 ? void 0 : input.slice(capture.start, capture.end)
8319
+ )
8214
8320
  };
8215
8321
  }
8216
- function isCapturedException(value) {
8217
- return typeof value === "object" && value !== null && capturedExceptionBrand in value;
8322
+ function cloneState(state) {
8323
+ return { position: state.position, captures: state.captures.slice() };
8218
8324
  }
8219
- function coerceThrownValue(reason, budget, stackFrames, span, sandbox = false) {
8220
- if (reason instanceof HostCallResumabilityError) {
8221
- throw reason;
8222
- }
8223
- if (isSubsetErrorValue(reason)) {
8224
- attachErrorSpan(reason, readErrorSpan(reason) ?? span);
8225
- return reason;
8325
+ function clearCaptures(node, state) {
8326
+ const captures = state.captures.slice();
8327
+ clearNodeCaptures(node, captures);
8328
+ return { position: state.position, captures };
8329
+ }
8330
+ function clearNodeCaptures(node, captures) {
8331
+ if (node.type === "group") {
8332
+ if (node.capturing && node.index !== void 0) {
8333
+ captures[node.index - 1] = void 0;
8334
+ }
8335
+ clearNodeCaptures(node.body, captures);
8336
+ return;
8226
8337
  }
8227
- if (reason instanceof Error) {
8228
- return createSubsetErrorValue(reason.name || "Error", reason.message, stackFrames, budget, {
8229
- chargeBudget: false,
8230
- cause: readErrorCause(reason),
8231
- span
8232
- });
8338
+ if (node.type === "sequence") {
8339
+ for (const element of node.elements) {
8340
+ clearNodeCaptures(element, captures);
8341
+ }
8342
+ return;
8233
8343
  }
8234
- if (sandbox) {
8235
- return reason;
8344
+ if (node.type === "alternation") {
8345
+ for (const alternative of node.alternatives) {
8346
+ clearNodeCaptures(alternative, captures);
8347
+ }
8348
+ return;
8236
8349
  }
8237
- if (isErrorLikeValue(reason)) {
8238
- return createSubsetErrorValue(reason.name || "Error", reason.message, stackFrames, budget, {
8239
- chargeBudget: false,
8240
- cause: readErrorCause(reason),
8241
- span
8242
- });
8350
+ if (node.type === "quantifier") {
8351
+ clearNodeCaptures(node.body, captures);
8243
8352
  }
8244
- return deepCopyToSandbox(reason);
8245
8353
  }
8246
- function surfaceThrownValue(reason, budget, stackFrames = [], span) {
8247
- if (reason instanceof HostCallResumabilityError) {
8248
- throw reason;
8354
+ function charge(context) {
8355
+ context.steps += 1;
8356
+ allocateRegexSteps(context.steps);
8357
+ }
8358
+ function normalizeLastIndex(lastIndex) {
8359
+ if (!Number.isFinite(lastIndex) || lastIndex <= 0) {
8360
+ return 0;
8249
8361
  }
8250
- if (isSubsetErrorValue(reason)) {
8251
- normalizeSurfacedSubsetError(reason, budget, stackFrames, span);
8362
+ return Math.floor(lastIndex);
8363
+ }
8364
+ function charactersEqual(left, right, ignoreCase) {
8365
+ return left !== void 0 && foldCharacter(left, ignoreCase) === foldCharacter(right, ignoreCase);
8366
+ }
8367
+ function foldCharacter(character, ignoreCase) {
8368
+ if (!ignoreCase) {
8369
+ return character;
8370
+ }
8371
+ const folded = character.toUpperCase();
8372
+ if (folded.length !== 1) {
8373
+ return character;
8374
+ }
8375
+ if (character.charCodeAt(0) >= 128 && folded.charCodeAt(0) < 128) {
8376
+ return character;
8377
+ }
8378
+ return folded;
8379
+ }
8380
+ function isDigit(character) {
8381
+ return character >= "0" && character <= "9";
8382
+ }
8383
+ function isWordCharacter(character) {
8384
+ return isDigit(character) || character >= "A" && character <= "Z" || character >= "a" && character <= "z" || character === "_";
8385
+ }
8386
+ function isSpaceCharacter(character) {
8387
+ return character === " " || character === "\f" || character === "\n" || character === "\r" || character === " " || character === "\v" || character === "\xA0" || character === "\u1680" || character >= "\u2000" && character <= "\u200A" || character === "\u2028" || character === "\u2029" || character === "\u202F" || character === "\u205F" || character === "\u3000" || character === "\uFEFF";
8388
+ }
8389
+ function isLineTerminator(character) {
8390
+ return character === "\n" || character === "\r" || character === "\u2028" || character === "\u2029";
8391
+ }
8392
+
8393
+ // packages/safe-js/src/interp/methods/regex.ts
8394
+ var regexMethodNames = /* @__PURE__ */ new Set(["exec", "test"]);
8395
+ function isRegexMethodName(property) {
8396
+ return typeof property === "string" && regexMethodNames.has(property);
8397
+ }
8398
+ function getRegexMember(target, property, budget) {
8399
+ if (property === "source") return escapeRegexSource(target.source, budget);
8400
+ if (property === "flags") {
8401
+ const flags = [..."gims"].filter((flag) => target.flags.includes(flag)).join("");
8402
+ return budget === void 0 ? flags : budget.allocateString(flags);
8403
+ }
8404
+ if (property === "lastIndex") return target.lastIndex;
8405
+ if (!isRegexMethodName(property)) {
8406
+ return void 0;
8407
+ }
8408
+ return createSandboxClosure({
8409
+ sandbox: true,
8410
+ name: `RegExp#${property}`,
8411
+ call: (args) => callRegexMethod(target, property, args)
8412
+ });
8413
+ }
8414
+ function escapeRegexSource(source, budget) {
8415
+ let text = "";
8416
+ let escaped = false;
8417
+ let inClass = false;
8418
+ for (const character of source) {
8419
+ budget?.visitNode();
8420
+ if (character === "\n" || character === "\r" || character === "\u2028" || character === "\u2029") {
8421
+ if (escaped) text = text.slice(0, -1);
8422
+ text += character === "\n" ? "\\n" : character === "\r" ? "\\r" : character === "\u2028" ? "\\u2028" : "\\u2029";
8423
+ escaped = false;
8424
+ } else {
8425
+ if (!escaped && character === "[") inClass = true;
8426
+ if (!escaped && character === "]") inClass = false;
8427
+ text += character === "/" && !escaped && !inClass ? "\\/" : character;
8428
+ escaped = character === "\\" && !escaped;
8429
+ }
8430
+ budget?.allocateString(text);
8431
+ }
8432
+ text = text === "" ? "(?:)" : text;
8433
+ return budget === void 0 ? text : budget.allocateString(text);
8434
+ }
8435
+ function setRegexMember(target, property, value) {
8436
+ if (property !== "lastIndex") {
8437
+ throw new TypeError(`RegExp#${String(property)} is not writable.`);
8438
+ }
8439
+ target.lastIndex = Number(value);
8440
+ }
8441
+ function callRegexMethod(target, methodName, args) {
8442
+ const match = executeRegex(target, String(args[0]));
8443
+ return methodName === "test" ? match !== null : toMatchArray(match, String(args[0]));
8444
+ }
8445
+ function executeRegex(target, input) {
8446
+ const pattern = getSandboxRegexPattern(target);
8447
+ const match = matchRegex(pattern, input, target.lastIndex);
8448
+ if (pattern.flags.global) {
8449
+ target.lastIndex = match === null ? 0 : match.index + match.text.length;
8450
+ }
8451
+ return match;
8452
+ }
8453
+ function toMatchArray(match, input) {
8454
+ if (match === null) {
8455
+ return null;
8456
+ }
8457
+ const result = [match.text, ...match.captures];
8458
+ Object.assign(result, { index: match.index, input, groups: void 0 });
8459
+ return result;
8460
+ }
8461
+
8462
+ // packages/safe-js/src/interp/string-coercion.ts
8463
+ var defaultStringHook = /* @__PURE__ */ Symbol("defaultStringHook");
8464
+ function sandboxString(value, budget, context, joining = /* @__PURE__ */ new Set()) {
8465
+ if (value === null || typeof value !== "object") {
8466
+ if (typeof value === "function") throw new TypeError("Expected a sandbox value.");
8467
+ return budget.allocateString(String(value));
8468
+ }
8469
+ const invocation = context?.invokeClosure !== void 0 ? context : {
8470
+ ...context,
8471
+ stack: context?.stack ?? [],
8472
+ thisValue: context?.thisValue,
8473
+ invokeClosure: async (closure, args, thisValue) => {
8474
+ const leaveCall = budget.enterCall();
8475
+ try {
8476
+ const result = closure.call(args, { ...invocation, thisValue });
8477
+ if (isSandboxPromise(result)) {
8478
+ await result.synchronousPrefix;
8479
+ return result;
8480
+ }
8481
+ return await result;
8482
+ } finally {
8483
+ leaveCall();
8484
+ }
8485
+ }
8486
+ };
8487
+ return stringifyObject(value, budget, invocation, joining);
8488
+ }
8489
+ async function stringifyObject(value, budget, context, joining) {
8490
+ const leaveCall = budget.enterCall();
8491
+ try {
8492
+ budget.visitNode();
8493
+ for (const name of ["toString", "valueOf"]) {
8494
+ const hook = conversionHook(value, name, budget);
8495
+ let result;
8496
+ if (hook === defaultStringHook) {
8497
+ result = await defaultToString(value, budget, context, joining);
8498
+ } else {
8499
+ if (!isSandboxClosure(hook)) continue;
8500
+ if (context?.invokeClosure === void 0) {
8501
+ throw new TypeError("String hooks require a sandbox call context.");
8502
+ }
8503
+ result = await context.invokeClosure(hook, [], value);
8504
+ }
8505
+ if (result === null || typeof result !== "object") {
8506
+ return sandboxString(result, budget, context, joining);
8507
+ }
8508
+ }
8509
+ throw new TypeError("Cannot convert object to primitive value");
8510
+ } finally {
8511
+ leaveCall();
8512
+ }
8513
+ }
8514
+ function conversionHook(value, name, budget) {
8515
+ const implicitBuiltin = !hasExplicitSandboxPrototype(value) && (Array.isArray(value) || isSandboxDate(value) || isFloat32Array(value) || sandboxErrorTypes.has(value) || isSandboxClosure(value) || isSandboxMap(value) || isSandboxSet(value) || isSandboxPromise(value) || isSandboxRegex(value) || isSandboxGenerator(value) || isGuestHostObject(value));
8516
+ let current = value;
8517
+ let depth = 0;
8518
+ while (current !== null) {
8519
+ const properties = isGuestClosure(current) ? getGuestFunctionProperties(current) : current;
8520
+ const descriptor = properties === void 0 ? void 0 : Object.getOwnPropertyDescriptor(properties, name);
8521
+ if (descriptor !== void 0) {
8522
+ if (!Object.hasOwn(descriptor, "value"))
8523
+ throw new TypeError("String conversion requires sandbox data properties.");
8524
+ return descriptor.value;
8525
+ }
8526
+ const parent = getSandboxPrototype(current, budget);
8527
+ if (current === value && (implicitBuiltin || parent === null && !hasExplicitSandboxPrototype(value))) {
8528
+ return name === "toString" ? defaultStringHook : void 0;
8529
+ }
8530
+ current = parent;
8531
+ if (current !== null) {
8532
+ budget.visitNode();
8533
+ assertSandboxDataDepth(++depth);
8534
+ }
8535
+ }
8536
+ return void 0;
8537
+ }
8538
+ async function defaultToString(value, budget, context, joining) {
8539
+ if (isSandboxMap(value)) return "[object Map]";
8540
+ if (isSandboxSet(value)) return "[object Set]";
8541
+ if (isSandboxGenerator(value)) return "[object Generator]";
8542
+ if (isSandboxRegex(value)) {
8543
+ return budget.allocateString(
8544
+ `/${getRegexMember(value, "source", budget)}/${getRegexMember(value, "flags", budget)}`
8545
+ );
8546
+ }
8547
+ if (isSandboxDate(value)) return budget.allocateString(dateString(value));
8548
+ if (Array.isArray(value) || isFloat32Array(value)) {
8549
+ if (Object.hasOwn(value, "join")) {
8550
+ const join = ownDataValue(value, "join");
8551
+ if (!isSandboxClosure(join))
8552
+ return isFloat32Array(value) ? "[object Float32Array]" : "[object Array]";
8553
+ if (context?.invokeClosure === void 0) {
8554
+ throw new TypeError("String hooks require a sandbox call context.");
8555
+ }
8556
+ return context.invokeClosure(join, [], value);
8557
+ }
8558
+ if (joining.has(value)) return "";
8559
+ joining.add(value);
8560
+ try {
8561
+ const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
8562
+ let text = "";
8563
+ for (let index = 0; index < length; index++) {
8564
+ budget.visitNode();
8565
+ const element = ownDataValue(value, String(index));
8566
+ const part = element === null || element === void 0 ? "" : await sandboxString(element, budget, context, joining);
8567
+ text = budget.allocateString(text + (index === 0 ? "" : ",") + part);
8568
+ }
8569
+ return text;
8570
+ } finally {
8571
+ joining.delete(value);
8572
+ }
8573
+ }
8574
+ if (sandboxErrorTypes.has(value)) {
8575
+ const nameValue = ownDataValue(value, "name");
8576
+ const name = nameValue === void 0 ? "Error" : await sandboxString(nameValue, budget, context, joining);
8577
+ const messageValue = ownDataValue(value, "message");
8578
+ const message = messageValue === void 0 ? "" : await sandboxString(messageValue, budget, context, joining);
8579
+ return name === "" ? message : message === "" ? name : `${name}: ${message}`;
8580
+ }
8581
+ return isSandboxPromise(value) ? "[object Promise]" : "[object Object]";
8582
+ }
8583
+ function ownDataValue(value, name) {
8584
+ const descriptor = Object.getOwnPropertyDescriptor(value, name);
8585
+ if (descriptor !== void 0 && !Object.hasOwn(descriptor, "value")) {
8586
+ throw new TypeError("String conversion requires sandbox data properties.");
8587
+ }
8588
+ return descriptor?.value;
8589
+ }
8590
+
8591
+ // packages/safe-js/src/interp/property-key.ts
8592
+ async function toPropertyKey(value, budget, context) {
8593
+ if (typeof value === "string") return value;
8594
+ return sandboxString(value, budget, context);
8595
+ }
8596
+
8597
+ // packages/safe-js/src/interp/exceptions.ts
8598
+ var capturedExceptionBrand = /* @__PURE__ */ Symbol("CapturedException");
8599
+ async function evaluateThrowStatement(node, context, evaluateNode2) {
8600
+ const argument = await evaluateNode2(node.argument, context);
8601
+ if (argument.kind !== "normal") {
8602
+ return argument;
8603
+ }
8604
+ return {
8605
+ kind: "throw",
8606
+ hasValue: true,
8607
+ span: node.span,
8608
+ stackFrames: context.callStack,
8609
+ value: argument.value
8610
+ };
8611
+ }
8612
+ async function evaluateTryStatement(node, context, evaluateNode2) {
8613
+ let fatalBudgetError;
8614
+ let tryResult;
8615
+ try {
8616
+ tryResult = await evaluateBlockCompletion(node.block, context, evaluateNode2);
8617
+ } catch (error) {
8618
+ if (!isBudgetExceeded(error) || node.finalizer === void 0) {
8619
+ throw error;
8620
+ }
8621
+ fatalBudgetError = error;
8622
+ tryResult = {
8623
+ kind: "throw",
8624
+ hasValue: true,
8625
+ value: void 0
8626
+ };
8627
+ }
8628
+ const tryOrCatchResult = fatalBudgetError === void 0 && tryResult.kind === "throw" && node.handler !== void 0 ? await evaluateCatchClause(node.handler, tryResult.value, context, evaluateNode2) : tryResult;
8629
+ if (node.finalizer === void 0 || tryOrCatchResult.kind === "error") {
8630
+ return tryOrCatchResult;
8631
+ }
8632
+ const evaluateFinalizer = () => fatalBudgetError?.budget === "deadline" ? evaluateWithoutDeadlineChecks(
8633
+ context,
8634
+ () => evaluateBlockCompletion(node.finalizer, context, evaluateNode2)
8635
+ ) : evaluateBlockCompletion(node.finalizer, context, evaluateNode2);
8636
+ const finalizerResult = await (fatalBudgetError === void 0 ? evaluateFinalizer() : withFatalPromiseCleanup(evaluateFinalizer));
8637
+ if (fatalBudgetError !== void 0) {
8638
+ throw fatalBudgetError;
8639
+ }
8640
+ if (finalizerResult.kind === "normal") {
8641
+ return tryOrCatchResult;
8642
+ }
8643
+ return finalizerResult;
8644
+ }
8645
+ function createCapturedException(reason, stackFrames, sandbox = false) {
8646
+ return {
8647
+ reason,
8648
+ sandbox,
8649
+ stackFrames,
8650
+ [capturedExceptionBrand]: true
8651
+ };
8652
+ }
8653
+ function isCapturedException(value) {
8654
+ return typeof value === "object" && value !== null && capturedExceptionBrand in value;
8655
+ }
8656
+ function coerceThrownValue(reason, budget, stackFrames, span, sandbox = false) {
8657
+ if (reason instanceof HostCallResumabilityError) {
8658
+ throw reason;
8659
+ }
8660
+ if (isSubsetErrorValue(reason)) {
8661
+ attachErrorSpan(reason, readErrorSpan(reason) ?? span);
8662
+ return reason;
8663
+ }
8664
+ if (reason instanceof Error) {
8665
+ return createSubsetErrorValue(reason.name || "Error", reason.message, stackFrames, budget, {
8666
+ chargeBudget: false,
8667
+ cause: readErrorCause(reason),
8668
+ span
8669
+ });
8670
+ }
8671
+ if (sandbox) {
8672
+ return reason;
8673
+ }
8674
+ if (isErrorLikeValue(reason)) {
8675
+ return createSubsetErrorValue(reason.name || "Error", reason.message, stackFrames, budget, {
8676
+ chargeBudget: false,
8677
+ cause: readErrorCause(reason),
8678
+ span
8679
+ });
8680
+ }
8681
+ return deepCopyToSandbox(reason);
8682
+ }
8683
+ function surfaceThrownValue(reason, budget, stackFrames = [], span) {
8684
+ if (reason instanceof HostCallResumabilityError) {
8685
+ throw reason;
8686
+ }
8687
+ if (isSubsetErrorValue(reason)) {
8688
+ normalizeSurfacedSubsetError(reason, budget, stackFrames, span);
8252
8689
  return reason;
8253
8690
  }
8254
8691
  if (reason instanceof Error) {
@@ -8547,12 +8984,13 @@ async function resolvePatternPropertyKey(property, context, evaluateNode2) {
8547
8984
  result: computedKey
8548
8985
  };
8549
8986
  }
8550
- if (typeof computedKey.value !== "string" && typeof computedKey.value !== "number") {
8551
- throw new TypeError("Computed catch binding keys must evaluate to a string or number.");
8552
- }
8553
8987
  return {
8554
8988
  ok: true,
8555
- value: computedKey.value
8989
+ value: await (context.toPropertyKey?.(computedKey.value) ?? toPropertyKey(
8990
+ computedKey.value,
8991
+ context.budget,
8992
+ { stack: context.callStack, thisValue: void 0 }
8993
+ ))
8556
8994
  };
8557
8995
  }
8558
8996
  function getStaticPropertyKey(property) {
@@ -23089,17 +23527,17 @@ async function bindMemberExpression(pattern, value, scope, context) {
23089
23527
  if (object.kind !== "normal") {
23090
23528
  return { ok: false, result: object };
23091
23529
  }
23530
+ const property = pattern.computed ? await context.evaluate(pattern.property) : { kind: "normal", value: getStaticPropertyName(pattern.property) };
23531
+ if (property.kind !== "normal") {
23532
+ return { ok: false, result: property };
23533
+ }
23092
23534
  if (object.value === null || object.value === void 0) {
23093
23535
  throw new TypeError("Cannot assign properties of null or undefined.");
23094
23536
  }
23095
23537
  if (!isIndexableValue(object.value)) {
23096
23538
  throw new TypeError("Assignment expressions require a sandbox object property.");
23097
23539
  }
23098
- const property = pattern.computed ? await evaluateProperty(pattern.property, context) : { ok: true, value: getStaticPropertyName(pattern.property) };
23099
- if (!property.ok) {
23100
- return property;
23101
- }
23102
- context.setProperty(object.value, property.value, value);
23540
+ context.setProperty(object.value, await context.toPropertyKey(property.value), value);
23103
23541
  return { ok: true };
23104
23542
  }
23105
23543
  async function evaluatePatternKey(property, context) {
@@ -23110,10 +23548,7 @@ async function evaluateProperty(property, context) {
23110
23548
  if (result.kind !== "normal") {
23111
23549
  return { ok: false, result };
23112
23550
  }
23113
- if (typeof result.value !== "string" && typeof result.value !== "number") {
23114
- throw new TypeError("Computed property access requires a string or number key.");
23115
- }
23116
- return { ok: true, value: result.value };
23551
+ return { ok: true, value: await context.toPropertyKey(result.value) };
23117
23552
  }
23118
23553
  function getStaticPropertyName(property) {
23119
23554
  if (property.type === "Identifier") {
@@ -23153,116 +23588,36 @@ function describeRuntimeValue(value) {
23153
23588
  if (typeof value === "object") return value.constructor?.name ?? "Object";
23154
23589
  return typeof value;
23155
23590
  }
23156
- function copyObjectRestValue(value, excludedKeys) {
23157
- const rest = /* @__PURE__ */ Object.create(null);
23158
- for (const [key, entryValue] of ownEnumerableSandboxEntries(value)) {
23159
- if (!excludedKeys.has(key)) {
23160
- defineProperty(rest, key, entryValue);
23161
- }
23162
- }
23163
- return rest;
23164
- }
23165
- function isIndexableValue(value) {
23166
- return typeof value === "object" && value !== null;
23167
- }
23168
- function defineProperty(target, key, value) {
23169
- Object.defineProperty(target, key, {
23170
- configurable: true,
23171
- enumerable: true,
23172
- value,
23173
- writable: true
23174
- });
23175
- }
23176
-
23177
- // packages/safe-js/src/interp/var-hoist.ts
23178
- function hoistVarDeclarations(node, scope) {
23179
- for (const declaration of hoistedVarDeclarations([node])) {
23180
- for (const declarator of declaration.declarations) {
23181
- for (const identifier of boundIdentifiers(declarator.id)) {
23182
- scope.declareVar(identifier.name);
23183
- }
23184
- }
23185
- }
23186
- }
23187
-
23188
- // packages/safe-js/src/interp/string-coercion.ts
23189
- function sandboxString(value, budget, context, joining = /* @__PURE__ */ new Set()) {
23190
- if (value === null || typeof value !== "object") {
23191
- if (typeof value === "function") throw new TypeError("Expected a sandbox value.");
23192
- return budget.allocateString(String(value));
23193
- }
23194
- return stringifyObject(value, budget, context, joining);
23195
- }
23196
- async function stringifyObject(value, budget, context, joining) {
23197
- const leaveCall = budget.enterCall();
23198
- try {
23199
- budget.visitNode();
23200
- for (const name of ["toString", "valueOf"]) {
23201
- const descriptor = Object.getOwnPropertyDescriptor(value, name);
23202
- let result;
23203
- if (descriptor === void 0) {
23204
- if (name === "valueOf") continue;
23205
- result = await defaultToString(value, budget, context, joining);
23206
- } else {
23207
- const hook = ownDataValue(value, name);
23208
- if (!isSandboxClosure(hook)) continue;
23209
- if (context?.invokeClosure === void 0) {
23210
- throw new TypeError("String hooks require a sandbox call context.");
23211
- }
23212
- result = await context.invokeClosure(hook, [], value);
23213
- }
23214
- if (result === null || typeof result !== "object") {
23215
- return sandboxString(result, budget, context, joining);
23216
- }
23217
- }
23218
- throw new TypeError("Cannot convert object to primitive value");
23219
- } finally {
23220
- leaveCall();
23221
- }
23222
- }
23223
- async function defaultToString(value, budget, context, joining) {
23224
- if (isSandboxDate(value)) return budget.allocateString(dateString(value));
23225
- if (Array.isArray(value) || isFloat32Array(value)) {
23226
- if (Object.hasOwn(value, "join")) {
23227
- const join = ownDataValue(value, "join");
23228
- if (!isSandboxClosure(join))
23229
- return isFloat32Array(value) ? "[object Float32Array]" : "[object Array]";
23230
- if (context?.invokeClosure === void 0) {
23231
- throw new TypeError("String hooks require a sandbox call context.");
23232
- }
23233
- return context.invokeClosure(join, [], value);
23234
- }
23235
- if (joining.has(value)) return "";
23236
- joining.add(value);
23237
- try {
23238
- const length = isFloat32Array(value) ? float32Storage(value).length : value.length;
23239
- let text = "";
23240
- for (let index = 0; index < length; index++) {
23241
- budget.visitNode();
23242
- const element = ownDataValue(value, String(index));
23243
- const part = element === null || element === void 0 ? "" : await sandboxString(element, budget, context, joining);
23244
- text = budget.allocateString(text + (index === 0 ? "" : ",") + part);
23245
- }
23246
- return text;
23247
- } finally {
23248
- joining.delete(value);
23591
+ function copyObjectRestValue(value, excludedKeys) {
23592
+ const rest = /* @__PURE__ */ Object.create(null);
23593
+ for (const [key, entryValue] of ownEnumerableSandboxEntries(value)) {
23594
+ if (!excludedKeys.has(key)) {
23595
+ defineProperty(rest, key, entryValue);
23249
23596
  }
23250
23597
  }
23251
- if (sandboxErrorTypes.has(value)) {
23252
- const nameValue = ownDataValue(value, "name");
23253
- const name = nameValue === void 0 ? "Error" : await sandboxString(nameValue, budget, context, joining);
23254
- const messageValue = ownDataValue(value, "message");
23255
- const message = messageValue === void 0 ? "" : await sandboxString(messageValue, budget, context, joining);
23256
- return name === "" ? message : message === "" ? name : `${name}: ${message}`;
23257
- }
23258
- return isSandboxPromise(value) ? "[object Promise]" : "[object Object]";
23598
+ return rest;
23259
23599
  }
23260
- function ownDataValue(value, name) {
23261
- const descriptor = Object.getOwnPropertyDescriptor(value, name);
23262
- if (descriptor !== void 0 && !Object.hasOwn(descriptor, "value")) {
23263
- throw new TypeError("String conversion requires sandbox data properties.");
23600
+ function isIndexableValue(value) {
23601
+ return typeof value === "object" && value !== null;
23602
+ }
23603
+ function defineProperty(target, key, value) {
23604
+ Object.defineProperty(target, key, {
23605
+ configurable: true,
23606
+ enumerable: true,
23607
+ value,
23608
+ writable: true
23609
+ });
23610
+ }
23611
+
23612
+ // packages/safe-js/src/interp/var-hoist.ts
23613
+ function hoistVarDeclarations(node, scope) {
23614
+ for (const declaration of hoistedVarDeclarations([node])) {
23615
+ for (const declarator of declaration.declarations) {
23616
+ for (const identifier of boundIdentifiers(declarator.id)) {
23617
+ scope.declareVar(identifier.name);
23618
+ }
23619
+ }
23264
23620
  }
23265
- return descriptor?.value;
23266
23621
  }
23267
23622
 
23268
23623
  // packages/safe-js/src/interp/methods/array.ts
@@ -24145,387 +24500,112 @@ async function callMapMethod(target, methodName, args, options, stack = []) {
24145
24500
  const value = target.entries.get(key);
24146
24501
  await options.callClosure(callback, [value, key, target], stack, args[1]);
24147
24502
  }
24148
- } finally {
24149
- cursor.leave();
24150
- }
24151
- return void 0;
24152
- }
24153
- case "keys":
24154
- return allocateProducedSandboxValue([...target.entries.keys()], options.budget);
24155
- case "values":
24156
- return allocateProducedSandboxValue([...target.entries.values()], options.budget);
24157
- case "entries":
24158
- return allocateProducedSandboxValue(
24159
- [...target.entries].map(([key, value]) => [key, value]),
24160
- options.budget
24161
- );
24162
- }
24163
- }
24164
-
24165
- // packages/safe-js/src/interp/methods/number.ts
24166
- var numberMethodNames = /* @__PURE__ */ new Set([
24167
- "toExponential",
24168
- "toFixed",
24169
- "toPrecision",
24170
- "toString"
24171
- ]);
24172
- function getNumberMember(value, property, budget) {
24173
- if (!isNumberMethodName(property)) {
24174
- return void 0;
24175
- }
24176
- return createSandboxClosure({
24177
- sandbox: true,
24178
- name: `Number#${property}`,
24179
- call: (args) => callNumberMethod(value, property, args, budget)
24180
- });
24181
- }
24182
- function isNumberMethodName(property) {
24183
- return typeof property === "string" && numberMethodNames.has(property);
24184
- }
24185
- function callNumberMethod(value, methodName, args, budget) {
24186
- return budget.allocateString(callNativeNumberMethod(value, methodName, args));
24187
- }
24188
- function callNativeNumberMethod(value, methodName, args) {
24189
- switch (methodName) {
24190
- case "toString":
24191
- return value.toString(asValidatedRadix(args[0]));
24192
- case "toExponential":
24193
- return args[0] === void 0 ? value.toExponential() : value.toExponential(asValidatedFractionDigits(args[0], methodName));
24194
- case "toFixed":
24195
- return value.toFixed(asValidatedFractionDigits(args[0], methodName));
24196
- case "toPrecision":
24197
- return args[0] === void 0 ? value.toPrecision() : value.toPrecision(asValidatedPrecision(args[0]));
24198
- }
24199
- }
24200
- function asValidatedRadix(value) {
24201
- if (value === void 0) {
24202
- return void 0;
24203
- }
24204
- const radix = toIntegerOrInfinity2(value);
24205
- if (radix < 2 || radix > 36) {
24206
- throw new RangeError("Number#toString radix must be between 2 and 36.");
24207
- }
24208
- return radix;
24209
- }
24210
- function asValidatedFractionDigits(value, methodName) {
24211
- const digits = toIntegerOrInfinity2(value);
24212
- if (digits < 0 || digits > 100) {
24213
- throw new RangeError(`Number#${methodName} digits must be between 0 and 100.`);
24214
- }
24215
- return digits;
24216
- }
24217
- function asValidatedPrecision(value) {
24218
- const precision = toIntegerOrInfinity2(value);
24219
- if (precision < 1 || precision > 100) {
24220
- throw new RangeError("Number#toPrecision precision must be between 1 and 100.");
24221
- }
24222
- return precision;
24223
- }
24224
- function toIntegerOrInfinity2(value) {
24225
- const number = Number(value);
24226
- if (Number.isNaN(number) || Object.is(number, 0) || Object.is(number, -0)) {
24227
- return 0;
24228
- }
24229
- if (!Number.isFinite(number)) {
24230
- return number;
24231
- }
24232
- return Math.trunc(number);
24233
- }
24234
-
24235
- // packages/safe-js/src/interp/methods/generator.ts
24236
- var generatorMethodNames = /* @__PURE__ */ new Set(["next", "return", "throw"]);
24237
- function getGeneratorMember(target, property, budget) {
24238
- if (typeof property !== "string" || !generatorMethodNames.has(property)) {
24239
- return void 0;
24240
- }
24241
- return createSandboxClosure({
24242
- sandbox: true,
24243
- name: property,
24244
- call: async ([value]) => {
24245
- const iterator = getSandboxIterator(target);
24246
- const result = await iterator[property](value);
24247
- return allocateProducedSandboxValue(
24248
- { value: result.value, done: result.done === true },
24249
- budget
24250
- );
24251
- }
24252
- });
24253
- }
24254
-
24255
- // packages/safe-js/src/interp/regex/engine.ts
24256
- function matchRegex(pattern, input, lastIndex = 0) {
24257
- const startIndex = pattern.flags.global ? normalizeLastIndex(lastIndex) : 0;
24258
- return matchRegexFrom(pattern, input, startIndex);
24259
- }
24260
- function matchRegexFrom(pattern, input, startIndex) {
24261
- if (startIndex > input.length) {
24262
- return null;
24263
- }
24264
- for (let attempt = startIndex; attempt <= input.length; attempt += 1) {
24265
- const context = { input, flags: pattern.flags, steps: 0 };
24266
- charge(context);
24267
- const initialState = {
24268
- position: attempt,
24269
- captures: new Array(pattern.captureCount)
24270
- };
24271
- const result = matchNode(pattern.body, initialState, context).next();
24272
- if (!result.done) {
24273
- return toRegexMatch(input, attempt, result.value);
24274
- }
24275
- }
24276
- return null;
24277
- }
24278
- function* matchNode(node, state, context) {
24279
- charge(context);
24280
- switch (node.type) {
24281
- case "empty":
24282
- yield state;
24283
- return;
24284
- case "literal":
24285
- if (charactersEqual(context.input[state.position], node.value, context.flags.ignoreCase)) {
24286
- yield { ...state, position: state.position + 1 };
24287
- }
24288
- return;
24289
- case "dot":
24290
- if (state.position < context.input.length && (context.flags.dotAll || !isLineTerminator(context.input[state.position]))) {
24291
- yield { ...state, position: state.position + 1 };
24292
- }
24293
- return;
24294
- case "anchor":
24295
- if (matchesAnchor(node.kind, state.position, context)) {
24296
- yield state;
24297
- }
24298
- return;
24299
- case "wordBoundary": {
24300
- const previousWord = state.position > 0 && isWordCharacter(context.input[state.position - 1]);
24301
- const nextWord = state.position < context.input.length && isWordCharacter(context.input[state.position]);
24302
- if (previousWord !== nextWord !== node.negated) {
24303
- yield state;
24304
- }
24305
- return;
24306
- }
24307
- case "characterClass": {
24308
- const character = context.input[state.position];
24309
- if (character !== void 0 && matchesCharacterClass(character, node.items, node.negated, context.flags.ignoreCase)) {
24310
- yield { ...state, position: state.position + 1 };
24311
- }
24312
- return;
24313
- }
24314
- case "sequence":
24315
- yield* matchSequence(node.elements, 0, state, context);
24316
- return;
24317
- case "alternation":
24318
- for (const alternative of node.alternatives) {
24319
- yield* matchNode(alternative, cloneState(state), context);
24320
- }
24321
- return;
24322
- case "group":
24323
- for (const result of matchNode(node.body, cloneState(state), context)) {
24324
- if (!node.capturing || node.index === void 0) {
24325
- yield result;
24326
- continue;
24327
- }
24328
- const captures = result.captures.slice();
24329
- captures[node.index - 1] = { start: state.position, end: result.position };
24330
- yield { position: result.position, captures };
24331
- }
24332
- return;
24333
- case "quantifier":
24334
- yield* matchQuantifier(node, state, context, 0);
24335
- }
24336
- }
24337
- function* matchSequence(elements, index, state, context) {
24338
- charge(context);
24339
- if (index === elements.length) {
24340
- yield state;
24341
- return;
24342
- }
24343
- for (const result of matchNode(elements[index], state, context)) {
24344
- yield* matchSequence(elements, index + 1, result, context);
24345
- }
24346
- }
24347
- function* matchQuantifier(node, state, context, count) {
24348
- charge(context);
24349
- const canRepeat = node.max === void 0 || count < node.max;
24350
- if (!node.greedy && count >= node.min) {
24351
- yield state;
24352
- }
24353
- if (canRepeat) {
24354
- for (const result of matchNode(node.body, clearCaptures(node.body, state), context)) {
24355
- if (result.position === state.position) {
24356
- if (count >= node.min) {
24357
- continue;
24358
- }
24359
- if (count + 1 >= node.min) {
24360
- yield result;
24361
- } else {
24362
- yield* matchQuantifier(node, result, context, count + 1);
24363
- }
24364
- continue;
24503
+ } finally {
24504
+ cursor.leave();
24365
24505
  }
24366
- yield* matchQuantifier(node, result, context, count + 1);
24506
+ return void 0;
24367
24507
  }
24508
+ case "keys":
24509
+ return allocateProducedSandboxValue([...target.entries.keys()], options.budget);
24510
+ case "values":
24511
+ return allocateProducedSandboxValue([...target.entries.values()], options.budget);
24512
+ case "entries":
24513
+ return allocateProducedSandboxValue(
24514
+ [...target.entries].map(([key, value]) => [key, value]),
24515
+ options.budget
24516
+ );
24368
24517
  }
24369
- if (node.greedy && count >= node.min) {
24370
- yield state;
24371
- }
24372
- }
24373
- function matchesAnchor(kind, position, context) {
24374
- if (kind === "start") {
24375
- return position === 0 || context.flags.multiline && position > 0 && isLineTerminator(context.input[position - 1]);
24376
- }
24377
- return position === context.input.length || context.flags.multiline && position < context.input.length && isLineTerminator(context.input[position]);
24378
- }
24379
- function matchesCharacterClass(character, items, negated, ignoreCase) {
24380
- const matched = items.some((item) => matchesCharacterClassItem(character, item, ignoreCase));
24381
- return negated ? !matched : matched;
24382
24518
  }
24383
- function matchesCharacterClassItem(character, item, ignoreCase) {
24384
- if (item.type === "character") {
24385
- return charactersEqual(character, item.value, ignoreCase);
24386
- }
24387
- if (item.type === "range") {
24388
- const candidate = character.charCodeAt(0);
24389
- const from = item.from.charCodeAt(0);
24390
- const to = item.to.charCodeAt(0);
24391
- if (candidate >= from && candidate <= to) {
24392
- return true;
24393
- }
24394
- if (!ignoreCase) {
24395
- return false;
24396
- }
24397
- const foldedCandidate = foldCharacter(character, true).charCodeAt(0);
24398
- const foldedFrom = foldCharacter(item.from, true).charCodeAt(0);
24399
- const foldedTo = foldCharacter(item.to, true).charCodeAt(0);
24400
- return foldedCandidate >= foldedFrom && foldedCandidate <= foldedTo;
24519
+
24520
+ // packages/safe-js/src/interp/methods/number.ts
24521
+ var numberMethodNames = /* @__PURE__ */ new Set([
24522
+ "toExponential",
24523
+ "toFixed",
24524
+ "toPrecision",
24525
+ "toString"
24526
+ ]);
24527
+ function getNumberMember(value, property, budget) {
24528
+ if (!isNumberMethodName(property)) {
24529
+ return void 0;
24401
24530
  }
24402
- const matched = item.kind === "digit" ? isDigit(character) : item.kind === "word" ? isWordCharacter(character) : isSpaceCharacter(character);
24403
- return item.negated ? !matched : matched;
24404
- }
24405
- function toRegexMatch(input, start, state) {
24406
- return {
24407
- index: start,
24408
- text: input.slice(start, state.position),
24409
- captures: state.captures.map(
24410
- (capture) => capture === void 0 ? void 0 : input.slice(capture.start, capture.end)
24411
- )
24412
- };
24531
+ return createSandboxClosure({
24532
+ sandbox: true,
24533
+ name: `Number#${property}`,
24534
+ call: (args) => callNumberMethod(value, property, args, budget)
24535
+ });
24413
24536
  }
24414
- function cloneState(state) {
24415
- return { position: state.position, captures: state.captures.slice() };
24537
+ function isNumberMethodName(property) {
24538
+ return typeof property === "string" && numberMethodNames.has(property);
24416
24539
  }
24417
- function clearCaptures(node, state) {
24418
- const captures = state.captures.slice();
24419
- clearNodeCaptures(node, captures);
24420
- return { position: state.position, captures };
24540
+ function callNumberMethod(value, methodName, args, budget) {
24541
+ return budget.allocateString(callNativeNumberMethod(value, methodName, args));
24421
24542
  }
24422
- function clearNodeCaptures(node, captures) {
24423
- if (node.type === "group") {
24424
- if (node.capturing && node.index !== void 0) {
24425
- captures[node.index - 1] = void 0;
24426
- }
24427
- clearNodeCaptures(node.body, captures);
24428
- return;
24429
- }
24430
- if (node.type === "sequence") {
24431
- for (const element of node.elements) {
24432
- clearNodeCaptures(element, captures);
24433
- }
24434
- return;
24543
+ function callNativeNumberMethod(value, methodName, args) {
24544
+ switch (methodName) {
24545
+ case "toString":
24546
+ return value.toString(asValidatedRadix(args[0]));
24547
+ case "toExponential":
24548
+ return args[0] === void 0 ? value.toExponential() : value.toExponential(asValidatedFractionDigits(args[0], methodName));
24549
+ case "toFixed":
24550
+ return value.toFixed(asValidatedFractionDigits(args[0], methodName));
24551
+ case "toPrecision":
24552
+ return args[0] === void 0 ? value.toPrecision() : value.toPrecision(asValidatedPrecision(args[0]));
24435
24553
  }
24436
- if (node.type === "alternation") {
24437
- for (const alternative of node.alternatives) {
24438
- clearNodeCaptures(alternative, captures);
24439
- }
24440
- return;
24554
+ }
24555
+ function asValidatedRadix(value) {
24556
+ if (value === void 0) {
24557
+ return void 0;
24441
24558
  }
24442
- if (node.type === "quantifier") {
24443
- clearNodeCaptures(node.body, captures);
24559
+ const radix = toIntegerOrInfinity2(value);
24560
+ if (radix < 2 || radix > 36) {
24561
+ throw new RangeError("Number#toString radix must be between 2 and 36.");
24444
24562
  }
24563
+ return radix;
24445
24564
  }
24446
- function charge(context) {
24447
- context.steps += 1;
24448
- allocateRegexSteps(context.steps);
24449
- }
24450
- function normalizeLastIndex(lastIndex) {
24451
- if (!Number.isFinite(lastIndex) || lastIndex <= 0) {
24452
- return 0;
24565
+ function asValidatedFractionDigits(value, methodName) {
24566
+ const digits = toIntegerOrInfinity2(value);
24567
+ if (digits < 0 || digits > 100) {
24568
+ throw new RangeError(`Number#${methodName} digits must be between 0 and 100.`);
24453
24569
  }
24454
- return Math.floor(lastIndex);
24455
- }
24456
- function charactersEqual(left, right, ignoreCase) {
24457
- return left !== void 0 && foldCharacter(left, ignoreCase) === foldCharacter(right, ignoreCase);
24570
+ return digits;
24458
24571
  }
24459
- function foldCharacter(character, ignoreCase) {
24460
- if (!ignoreCase) {
24461
- return character;
24572
+ function asValidatedPrecision(value) {
24573
+ const precision = toIntegerOrInfinity2(value);
24574
+ if (precision < 1 || precision > 100) {
24575
+ throw new RangeError("Number#toPrecision precision must be between 1 and 100.");
24462
24576
  }
24463
- const folded = character.toUpperCase();
24464
- if (folded.length !== 1) {
24465
- return character;
24577
+ return precision;
24578
+ }
24579
+ function toIntegerOrInfinity2(value) {
24580
+ const number = Number(value);
24581
+ if (Number.isNaN(number) || Object.is(number, 0) || Object.is(number, -0)) {
24582
+ return 0;
24466
24583
  }
24467
- if (character.charCodeAt(0) >= 128 && folded.charCodeAt(0) < 128) {
24468
- return character;
24584
+ if (!Number.isFinite(number)) {
24585
+ return number;
24469
24586
  }
24470
- return folded;
24471
- }
24472
- function isDigit(character) {
24473
- return character >= "0" && character <= "9";
24474
- }
24475
- function isWordCharacter(character) {
24476
- return isDigit(character) || character >= "A" && character <= "Z" || character >= "a" && character <= "z" || character === "_";
24477
- }
24478
- function isSpaceCharacter(character) {
24479
- return character === " " || character === "\f" || character === "\n" || character === "\r" || character === " " || character === "\v" || character === "\xA0" || character === "\u1680" || character >= "\u2000" && character <= "\u200A" || character === "\u2028" || character === "\u2029" || character === "\u202F" || character === "\u205F" || character === "\u3000" || character === "\uFEFF";
24480
- }
24481
- function isLineTerminator(character) {
24482
- return character === "\n" || character === "\r" || character === "\u2028" || character === "\u2029";
24587
+ return Math.trunc(number);
24483
24588
  }
24484
24589
 
24485
- // packages/safe-js/src/interp/methods/regex.ts
24486
- var regexMethodNames = /* @__PURE__ */ new Set(["exec", "test"]);
24487
- function isRegexMethodName(property) {
24488
- return typeof property === "string" && regexMethodNames.has(property);
24489
- }
24490
- function getRegexMember(target, property) {
24491
- if (property === "source" || property === "flags" || property === "lastIndex") {
24492
- return target[property];
24493
- }
24494
- if (!isRegexMethodName(property)) {
24590
+ // packages/safe-js/src/interp/methods/generator.ts
24591
+ var generatorMethodNames = /* @__PURE__ */ new Set(["next", "return", "throw"]);
24592
+ function getGeneratorMember(target, property, budget) {
24593
+ if (typeof property !== "string" || !generatorMethodNames.has(property)) {
24495
24594
  return void 0;
24496
24595
  }
24497
24596
  return createSandboxClosure({
24498
24597
  sandbox: true,
24499
- name: `RegExp#${property}`,
24500
- call: (args) => callRegexMethod(target, property, args)
24598
+ name: property,
24599
+ call: async ([value]) => {
24600
+ const iterator = getSandboxIterator(target);
24601
+ const result = await iterator[property](value);
24602
+ return allocateProducedSandboxValue(
24603
+ { value: result.value, done: result.done === true },
24604
+ budget
24605
+ );
24606
+ }
24501
24607
  });
24502
24608
  }
24503
- function setRegexMember(target, property, value) {
24504
- if (property !== "lastIndex") {
24505
- throw new TypeError(`RegExp#${String(property)} is not writable.`);
24506
- }
24507
- target.lastIndex = Number(value);
24508
- }
24509
- function callRegexMethod(target, methodName, args) {
24510
- const match = executeRegex(target, String(args[0]));
24511
- return methodName === "test" ? match !== null : toMatchArray(match, String(args[0]));
24512
- }
24513
- function executeRegex(target, input) {
24514
- const pattern = getSandboxRegexPattern(target);
24515
- const match = matchRegex(pattern, input, target.lastIndex);
24516
- if (pattern.flags.global) {
24517
- target.lastIndex = match === null ? 0 : match.index + match.text.length;
24518
- }
24519
- return match;
24520
- }
24521
- function toMatchArray(match, input) {
24522
- if (match === null) {
24523
- return null;
24524
- }
24525
- const result = [match.text, ...match.captures];
24526
- Object.assign(result, { index: match.index, input, groups: void 0 });
24527
- return result;
24528
- }
24529
24609
 
24530
24610
  // packages/safe-js/src/interp/methods/string.ts
24531
24611
  var SPLIT_STRING_MESSAGE = "String#split only supports string separator values.";
@@ -26217,7 +26297,7 @@ async function evaluateBinaryExpression(node, context) {
26217
26297
  if (typeof right.value !== "object" || right.value === null) {
26218
26298
  throw new TypeError("Right-hand side of 'in' must be an object.");
26219
26299
  }
26220
- leftValue = await toPropertyKey(leftValue, context);
26300
+ leftValue = await toPropertyKey(leftValue, context.budget, createCoercionContext(context));
26221
26301
  }
26222
26302
  const value = applyBinaryOperator(node, leftValue, right.value, context);
26223
26303
  return {
@@ -26307,7 +26387,15 @@ async function evaluateMemberAssignmentExpression(node, context) {
26307
26387
  if (member.kind === "nullish") {
26308
26388
  throw new TypeError("Cannot assign properties of null or undefined.");
26309
26389
  }
26310
- const current = node.operator === "=" ? void 0 : getPropertyValue(member.object, member.property, context);
26390
+ let property;
26391
+ let current = void 0;
26392
+ if (node.operator !== "=") {
26393
+ if (member.object === null || member.object === void 0) {
26394
+ throw new TypeError("Cannot assign properties of null or undefined.");
26395
+ }
26396
+ property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
26397
+ current = getPropertyValue(member.object, property, context);
26398
+ }
26311
26399
  if (node.operator === "&&=" && !isTruthy(current)) {
26312
26400
  return {
26313
26401
  kind: "normal",
@@ -26334,7 +26422,11 @@ async function evaluateMemberAssignmentExpression(node, context) {
26334
26422
  return right;
26335
26423
  }
26336
26424
  const value = node.operator === "=" || node.operator === "&&=" || node.operator === "||=" || node.operator === "??=" ? right.value : await applyCompoundAssignmentOperator(node.operator, current, right.value, context);
26337
- setSandboxProperty(member.object, member.property, value, context.budget);
26425
+ if (member.object === null || member.object === void 0) {
26426
+ throw new TypeError("Cannot assign properties of null or undefined.");
26427
+ }
26428
+ property ??= await toPropertyKey(member.property, context.budget, createCoercionContext(context));
26429
+ setSandboxProperty(member.object, property, value, context.budget);
26338
26430
  return {
26339
26431
  kind: "normal",
26340
26432
  hasValue: true,
@@ -27273,7 +27365,10 @@ async function evaluateThrowStatement2(node, context) {
27273
27365
  return evaluateThrowStatement(node, context, evaluateNode);
27274
27366
  }
27275
27367
  async function evaluateTryStatement2(node, context) {
27276
- return evaluateTryStatement(node, context, evaluateNode);
27368
+ return evaluateTryStatement(node, {
27369
+ ...context,
27370
+ toPropertyKey: (value) => toPropertyKey(value, context.budget, createCoercionContext(context))
27371
+ }, evaluateNode);
27277
27372
  }
27278
27373
  async function evaluateUnaryExpression(node, context) {
27279
27374
  if (node.operator === "delete") {
@@ -27318,8 +27413,8 @@ async function evaluateDeleteExpression(node, context) {
27318
27413
  if (member.kind === "completion") {
27319
27414
  return member.result;
27320
27415
  }
27321
- if (member.kind === "nullish") {
27322
- if (node.argument.optional) {
27416
+ if (member.kind === "nullish" || member.object === null || member.object === void 0) {
27417
+ if (member.kind === "nullish" && node.argument.optional) {
27323
27418
  return {
27324
27419
  kind: "normal",
27325
27420
  hasValue: true,
@@ -27331,7 +27426,8 @@ async function evaluateDeleteExpression(node, context) {
27331
27426
  if (!isIndexableSandboxValue(member.object)) {
27332
27427
  throw new TypeError("Unary operator 'delete' requires a sandbox object property.");
27333
27428
  }
27334
- const deleted = deleteSandboxProperty(member.object, member.property);
27429
+ const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
27430
+ const deleted = deleteSandboxProperty(member.object, property);
27335
27431
  return {
27336
27432
  kind: "normal",
27337
27433
  hasValue: true,
@@ -27379,14 +27475,15 @@ async function evaluateMemberUpdateExpression(node, context) {
27379
27475
  if (member.kind === "completion") {
27380
27476
  return member.result;
27381
27477
  }
27382
- if (member.kind === "nullish") {
27478
+ if (member.kind === "nullish" || member.object === null || member.object === void 0) {
27383
27479
  throw new TypeError("Cannot update properties of null or undefined.");
27384
27480
  }
27481
+ const property = await toPropertyKey(member.property, context.budget, createCoercionContext(context));
27385
27482
  const current = toNumber(
27386
- await toNumericPrimitive(getPropertyValue(member.object, member.property, context), context)
27483
+ await toNumericPrimitive(getPropertyValue(member.object, property, context), context)
27387
27484
  );
27388
27485
  const next = node.operator === "++" ? current + 1 : current - 1;
27389
- setSandboxProperty(member.object, member.property, next, context.budget);
27486
+ setSandboxProperty(member.object, property, next, context.budget);
27390
27487
  return {
27391
27488
  kind: "normal",
27392
27489
  hasValue: true,
@@ -27397,14 +27494,14 @@ async function evaluateMemberExpression(node, context) {
27397
27494
  const member = await evaluateMemberAccess(node, context);
27398
27495
  if (member.kind === "error") return member;
27399
27496
  if (member.kind === "completion") return member.result;
27400
- if (member.kind === "nullish") {
27401
- if (node.optional) return { kind: "normal", hasValue: true, value: void 0 };
27497
+ if (member.kind === "nullish" || member.object === null || member.object === void 0) {
27498
+ if (member.kind === "nullish" && node.optional) return { kind: "normal", hasValue: true, value: void 0 };
27402
27499
  throw new TypeError("Cannot read properties of null or undefined.");
27403
27500
  }
27404
27501
  return {
27405
27502
  kind: "normal",
27406
27503
  hasValue: true,
27407
- value: getPropertyValue(member.object, member.property, context)
27504
+ value: getPropertyValue(member.object, await toPropertyKey(member.property, context.budget, createCoercionContext(context)), context)
27408
27505
  };
27409
27506
  }
27410
27507
  function getPropertyValue(target, property, context) {
@@ -27419,7 +27516,7 @@ function getPropertyValue(target, property, context) {
27419
27516
  if (isSandboxGenerator(target)) return getGeneratorMember(target, property, context.budget);
27420
27517
  if (isSandboxClosure(target)) return getClosureMemberValue(target, property, context);
27421
27518
  if (isSandboxPromise(target)) return getPromiseMember(property, context.budget);
27422
- if (isSandboxRegex(target)) return getRegexMember(target, property);
27519
+ if (isSandboxRegex(target)) return getRegexMember(target, property, context.budget);
27423
27520
  if (!isIndexableSandboxValue(target)) {
27424
27521
  throw new TypeError("Attempted to read a property from a non-object value.");
27425
27522
  }
@@ -27429,6 +27526,7 @@ function createPatternContext(context, scope = context.scope, evaluate = evaluat
27429
27526
  const evaluationContext = { ...context, scope };
27430
27527
  return {
27431
27528
  evaluate: (node) => evaluate(node, evaluationContext),
27529
+ toPropertyKey: (value) => toPropertyKey(value, context.budget, createCoercionContext(evaluationContext)),
27432
27530
  getProperty: (value, key) => getPropertyValue(value, key, evaluationContext),
27433
27531
  setProperty: (target, key, value) => setSandboxProperty(target, key, value, context.budget)
27434
27532
  };
@@ -27523,21 +27621,8 @@ async function evaluateMemberAccess(node, context) {
27523
27621
  kind: "nullish"
27524
27622
  };
27525
27623
  }
27526
- const property = node.computed ? await evaluateMemberProperty(node.property, context) : { ok: true, value: getStaticPropertyName2(node.property) };
27527
- if (!property.ok) {
27528
- return property.result.kind === "error" ? {
27529
- kind: "error",
27530
- error: property.result.error
27531
- } : {
27532
- kind: "completion",
27533
- result: property.result
27534
- };
27535
- }
27536
- if (object.value === null || object.value === void 0) {
27537
- return {
27538
- kind: "nullish"
27539
- };
27540
- }
27624
+ const property = node.computed ? await evaluateNode(node.property, context) : { kind: "normal", value: getStaticPropertyName2(node.property) };
27625
+ if (property.kind !== "normal") return { kind: "completion", result: property };
27541
27626
  return {
27542
27627
  kind: "resolved",
27543
27628
  object: object.value,
@@ -27552,13 +27637,10 @@ async function evaluateMemberProperty(node, context) {
27552
27637
  result: property
27553
27638
  };
27554
27639
  }
27555
- if (typeof property.value === "string" || typeof property.value === "number") {
27556
- return {
27557
- ok: true,
27558
- value: property.value
27559
- };
27560
- }
27561
- throw new TypeError("Computed property access requires a string or number key.");
27640
+ return {
27641
+ ok: true,
27642
+ value: await toPropertyKey(property.value, context.budget, createCoercionContext(context))
27643
+ };
27562
27644
  }
27563
27645
  async function evaluateObjectPropertyKey(node, context) {
27564
27646
  if (!node.computed) {
@@ -27582,15 +27664,15 @@ async function evaluateMemberCallExpression(node, context) {
27582
27664
  if (node.callee.type !== "MemberExpression") {
27583
27665
  throw new TypeError("Expected member call expression.");
27584
27666
  }
27585
- const member = await evaluateMemberAccess(node.callee, context);
27586
- if (member.kind === "error") {
27587
- return member;
27667
+ const reference = await evaluateMemberAccess(node.callee, context);
27668
+ if (reference.kind === "error") {
27669
+ return reference;
27588
27670
  }
27589
- if (member.kind === "completion") {
27590
- return member.result;
27671
+ if (reference.kind === "completion") {
27672
+ return reference.result;
27591
27673
  }
27592
- if (member.kind === "nullish") {
27593
- if (node.optional || node.callee.optional) {
27674
+ if (reference.kind === "nullish" || reference.object === null || reference.object === void 0) {
27675
+ if (reference.kind === "nullish") {
27594
27676
  return {
27595
27677
  kind: "normal",
27596
27678
  hasValue: true,
@@ -27599,6 +27681,10 @@ async function evaluateMemberCallExpression(node, context) {
27599
27681
  }
27600
27682
  throw new TypeError("Cannot read properties of null or undefined.");
27601
27683
  }
27684
+ const member = {
27685
+ ...reference,
27686
+ property: await toPropertyKey(reference.property, context.budget, createCoercionContext(context))
27687
+ };
27602
27688
  if (typeof member.object === "string" && isStringMethodName(member.property)) {
27603
27689
  return evaluateStringMethodCall(node, member.object, member.property, context);
27604
27690
  }
@@ -27695,7 +27781,7 @@ async function evaluateMemberCallExpression(node, context) {
27695
27781
  if (isSandboxRegex(member.object) && isRegexMethodName(member.property)) {
27696
27782
  return evaluateResolvedCallExpression(
27697
27783
  node,
27698
- getRegexMember(member.object, member.property),
27784
+ getRegexMember(member.object, member.property, context.budget),
27699
27785
  context,
27700
27786
  member.object
27701
27787
  );
@@ -27930,23 +28016,13 @@ function applyBinaryOperator(node, left, right, context) {
27930
28016
  return hasSandboxProperty(right, left, context);
27931
28017
  }
27932
28018
  }
27933
- async function toPropertyKey(value, context) {
27934
- if (isPlainSandboxObject(value) && !isSandboxDate(value) && !isFloat32Array(value) && !isSandboxGenerator(value) && !isGuestHostObject(value)) {
27935
- for (const name of ["toString", "valueOf"]) {
27936
- const method = getMemberValue(value, name, context);
27937
- if (!isSandboxClosure(method)) continue;
27938
- const primitive = await invokeSandboxClosure(method, [], context, context.callStack, void 0, value);
27939
- if (primitive === null || typeof primitive !== "object") {
27940
- return context.budget.allocateString(String(primitive));
27941
- }
27942
- }
27943
- throw new TypeError("Cannot convert object to primitive value.");
27944
- }
27945
- return sandboxString(value, context.budget, {
28019
+ function createCoercionContext(context) {
28020
+ return {
27946
28021
  stack: context.callStack,
27947
28022
  thisValue: void 0,
28023
+ compilation: context.compilation,
27948
28024
  invokeClosure: (closure, args, thisValue) => invokeSandboxClosure(closure, args, context, context.callStack, void 0, thisValue)
27949
- });
28025
+ };
27950
28026
  }
27951
28027
  function hasSandboxProperty(value, key, context) {
27952
28028
  let current = value;
@@ -32818,4 +32894,4 @@ export {
32818
32894
  FileSnapshotBackend,
32819
32895
  run
32820
32896
  };
32821
- //# sourceMappingURL=chunk-5J6BX3HD.js.map
32897
+ //# sourceMappingURL=chunk-774EXZKX.js.map