@poe-platform/safe-bash 0.1.41 → 0.1.42

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 (134) hide show
  1. package/README.md +11 -2
  2. package/dist/safe-bash/browser.d.ts +5 -0
  3. package/dist/safe-bash/browser.d.ts.map +1 -1
  4. package/dist/safe-bash/browser.js +878 -122
  5. package/dist/safe-bash/browser.js.map +4 -4
  6. package/dist/safe-bash/commands/apply-patch/shared.js +2 -2
  7. package/dist/safe-bash/commands/apply-patch/shared.js.map +1 -1
  8. package/dist/safe-bash/commands/archive/internal.d.ts.map +1 -1
  9. package/dist/safe-bash/commands/archive/internal.js +3 -2
  10. package/dist/safe-bash/commands/archive/internal.js.map +1 -1
  11. package/dist/safe-bash/commands/bytes/checksums/index.d.ts.map +1 -1
  12. package/dist/safe-bash/commands/bytes/checksums/index.js +3 -2
  13. package/dist/safe-bash/commands/bytes/checksums/index.js.map +1 -1
  14. package/dist/safe-bash/commands/bytes/compression/gunzip.js +2 -2
  15. package/dist/safe-bash/commands/bytes/compression/gunzip.js.map +1 -1
  16. package/dist/safe-bash/commands/bytes/compression/stream.js +2 -2
  17. package/dist/safe-bash/commands/bytes/compression/stream.js.map +1 -1
  18. package/dist/safe-bash/commands/bytes/encoding/shared.js +3 -3
  19. package/dist/safe-bash/commands/bytes/encoding/shared.js.map +1 -1
  20. package/dist/safe-bash/commands/column/internal.d.ts.map +1 -1
  21. package/dist/safe-bash/commands/column/internal.js +2 -1
  22. package/dist/safe-bash/commands/column/internal.js.map +1 -1
  23. package/dist/safe-bash/commands/diff-patch/shared.js +2 -2
  24. package/dist/safe-bash/commands/diff-patch/shared.js.map +1 -1
  25. package/dist/safe-bash/commands/du/budget.d.ts.map +1 -1
  26. package/dist/safe-bash/commands/du/budget.js +3 -2
  27. package/dist/safe-bash/commands/du/budget.js.map +1 -1
  28. package/dist/safe-bash/commands/env-split.d.ts.map +1 -1
  29. package/dist/safe-bash/commands/env-split.js +2 -1
  30. package/dist/safe-bash/commands/env-split.js.map +1 -1
  31. package/dist/safe-bash/commands/expr/internal.d.ts.map +1 -1
  32. package/dist/safe-bash/commands/expr/internal.js +2 -1
  33. package/dist/safe-bash/commands/expr/internal.js.map +1 -1
  34. package/dist/safe-bash/commands/file/shared.d.ts.map +1 -1
  35. package/dist/safe-bash/commands/file/shared.js +3 -2
  36. package/dist/safe-bash/commands/file/shared.js.map +1 -1
  37. package/dist/safe-bash/commands/find.d.ts.map +1 -1
  38. package/dist/safe-bash/commands/find.js +12 -31
  39. package/dist/safe-bash/commands/find.js.map +1 -1
  40. package/dist/safe-bash/commands/html-to-markdown/budget.js +2 -2
  41. package/dist/safe-bash/commands/html-to-markdown/budget.js.map +1 -1
  42. package/dist/safe-bash/commands/metadata/internal.d.ts.map +1 -1
  43. package/dist/safe-bash/commands/metadata/internal.js +2 -1
  44. package/dist/safe-bash/commands/metadata/internal.js.map +1 -1
  45. package/dist/safe-bash/commands/move.d.ts.map +1 -1
  46. package/dist/safe-bash/commands/move.js +2 -1
  47. package/dist/safe-bash/commands/move.js.map +1 -1
  48. package/dist/safe-bash/commands/network/authorizer.d.ts +7 -0
  49. package/dist/safe-bash/commands/network/authorizer.d.ts.map +1 -0
  50. package/dist/safe-bash/commands/network/authorizer.js +48 -0
  51. package/dist/safe-bash/commands/network/authorizer.js.map +1 -0
  52. package/dist/safe-bash/commands/network/body.js +2 -2
  53. package/dist/safe-bash/commands/network/body.js.map +1 -1
  54. package/dist/safe-bash/commands/network/curl.js +2 -2
  55. package/dist/safe-bash/commands/network/curl.js.map +1 -1
  56. package/dist/safe-bash/commands/network/fetch-transport.d.ts +6 -0
  57. package/dist/safe-bash/commands/network/fetch-transport.d.ts.map +1 -0
  58. package/dist/safe-bash/commands/network/fetch-transport.js +80 -0
  59. package/dist/safe-bash/commands/network/fetch-transport.js.map +1 -0
  60. package/dist/safe-bash/commands/network/index.d.ts +2 -0
  61. package/dist/safe-bash/commands/network/index.d.ts.map +1 -1
  62. package/dist/safe-bash/commands/network/index.js +2 -0
  63. package/dist/safe-bash/commands/network/index.js.map +1 -1
  64. package/dist/safe-bash/commands/network/types.d.ts +1 -0
  65. package/dist/safe-bash/commands/network/types.d.ts.map +1 -1
  66. package/dist/safe-bash/commands/network/types.js +10 -0
  67. package/dist/safe-bash/commands/network/types.js.map +1 -1
  68. package/dist/safe-bash/commands/regex-execution/ere/limits.js +2 -2
  69. package/dist/safe-bash/commands/regex-execution/ere/limits.js.map +1 -1
  70. package/dist/safe-bash/commands/safejs/io.js +2 -2
  71. package/dist/safe-bash/commands/safejs/io.js.map +1 -1
  72. package/dist/safe-bash/commands/search/shared.js +2 -2
  73. package/dist/safe-bash/commands/search/shared.js.map +1 -1
  74. package/dist/safe-bash/commands/split/io.js +2 -2
  75. package/dist/safe-bash/commands/split/io.js.map +1 -1
  76. package/dist/safe-bash/commands/stream-format/shared.d.ts.map +1 -1
  77. package/dist/safe-bash/commands/stream-format/shared.js +2 -1
  78. package/dist/safe-bash/commands/stream-format/shared.js.map +1 -1
  79. package/dist/safe-bash/commands/stream-inspection/shared.d.ts.map +1 -1
  80. package/dist/safe-bash/commands/stream-inspection/shared.js +2 -1
  81. package/dist/safe-bash/commands/stream-inspection/shared.js.map +1 -1
  82. package/dist/safe-bash/commands/structured/limits.js +2 -2
  83. package/dist/safe-bash/commands/structured/limits.js.map +1 -1
  84. package/dist/safe-bash/commands/table-text/internal.d.ts.map +1 -1
  85. package/dist/safe-bash/commands/table-text/internal.js +2 -1
  86. package/dist/safe-bash/commands/table-text/internal.js.map +1 -1
  87. package/dist/safe-bash/commands/text-programs/shared.js +2 -2
  88. package/dist/safe-bash/commands/text-programs/shared.js.map +1 -1
  89. package/dist/safe-bash/commands/tree/io.js +2 -2
  90. package/dist/safe-bash/commands/tree/io.js.map +1 -1
  91. package/dist/safe-bash/contracts/yield.d.ts +13 -0
  92. package/dist/safe-bash/contracts/yield.d.ts.map +1 -0
  93. package/dist/safe-bash/contracts/yield.js +41 -0
  94. package/dist/safe-bash/contracts/yield.js.map +1 -0
  95. package/dist/safe-bash/shell/arithmetic.js +1 -1
  96. package/dist/safe-bash/shell/arithmetic.js.map +1 -1
  97. package/dist/safe-bash/shell/arrays/ledger.d.ts.map +1 -1
  98. package/dist/safe-bash/shell/arrays/ledger.js +2 -9
  99. package/dist/safe-bash/shell/arrays/ledger.js.map +1 -1
  100. package/dist/safe-bash/shell/conditional.d.ts.map +1 -1
  101. package/dist/safe-bash/shell/conditional.js +2 -1
  102. package/dist/safe-bash/shell/conditional.js.map +1 -1
  103. package/dist/safe-bash/shell/env-warning.d.ts +2 -0
  104. package/dist/safe-bash/shell/env-warning.d.ts.map +1 -0
  105. package/dist/safe-bash/shell/env-warning.js +18 -0
  106. package/dist/safe-bash/shell/env-warning.js.map +1 -0
  107. package/dist/safe-bash/shell/index.d.ts +1 -0
  108. package/dist/safe-bash/shell/index.d.ts.map +1 -1
  109. package/dist/safe-bash/shell/index.js +1 -0
  110. package/dist/safe-bash/shell/index.js.map +1 -1
  111. package/dist/safe-bash/shell/input.d.ts.map +1 -1
  112. package/dist/safe-bash/shell/input.js +4 -3
  113. package/dist/safe-bash/shell/input.js.map +1 -1
  114. package/dist/safe-bash/shell/parser.d.ts.map +1 -1
  115. package/dist/safe-bash/shell/parser.js +15 -1
  116. package/dist/safe-bash/shell/parser.js.map +1 -1
  117. package/dist/safe-bash/shell/pattern.d.ts.map +1 -1
  118. package/dist/safe-bash/shell/pattern.js +3 -2
  119. package/dist/safe-bash/shell/pattern.js.map +1 -1
  120. package/dist/safe-bash/shell/runtime.d.ts +3 -2
  121. package/dist/safe-bash/shell/runtime.d.ts.map +1 -1
  122. package/dist/safe-bash/shell/runtime.js +57 -55
  123. package/dist/safe-bash/shell/runtime.js.map +1 -1
  124. package/dist/safe-bash/shell/shell.d.ts.map +1 -1
  125. package/dist/safe-bash/shell/shell.js +4 -1
  126. package/dist/safe-bash/shell/shell.js.map +1 -1
  127. package/dist/safe-bash/shell/types.d.ts +2 -0
  128. package/dist/safe-bash/shell/types.d.ts.map +1 -1
  129. package/dist/safe-bash/shell/types.js.map +1 -1
  130. package/dist/safe-bash/shell/worker-limits.d.ts +3 -0
  131. package/dist/safe-bash/shell/worker-limits.d.ts.map +1 -0
  132. package/dist/safe-bash/shell/worker-limits.js +14 -0
  133. package/dist/safe-bash/shell/worker-limits.js.map +1 -0
  134. package/package.json +2 -2
@@ -1,3 +1,4 @@
1
+ import { cancelTurn, monotonicNow, registerYieldCheckpoint, scheduleTurn, yieldTurn } from "../contracts/yield.js";
1
2
  import { ACCESS_MODES, FsError, composeMiddleware, createBytePipe, pipeBytes, resolvePath, toByteSource, validateExitCode, writeText, } from "../contracts/index.js";
2
3
  import { concatShellValues, shellValueByteLength, shellValueBytes, shellValueFromBytes, shellValueText } from "../contracts/value.js";
3
4
  import { createCommandArguments, getCommandArguments } from "../contracts/command.js";
@@ -20,9 +21,10 @@ import { ArrayFailure, ArrayOwner, exactSum } from "./arrays/ledger.js";
20
21
  import { controlNames, IndexedBinding, textToken } from "./arrays/bindings.js";
21
22
  import { arrayStore, guestArrays, requireArrays, snapshotState, stateMonitor, trackState } from "./arrays/state.js";
22
23
  import { publishPipelineStatus } from "./pipestatus.js";
23
- import { EreTransportRoot } from "../commands/regex-execution/ere/transport/root.js";
24
- import { EreTransportProfileLimitError, EreTransportSemanticError } from "../commands/regex-execution/ere/transport/protocol.js";
25
- import { EreProfileLimitError, EreUnsupportedError } from "../commands/regex-execution/ere/errors.js";
24
+ import { EreProfileLimitError, EreSyntaxError, EreUnsupportedError } from "../commands/regex-execution/ere/errors.js";
25
+ import { EreLedger } from "../commands/regex-execution/ere/limits.js";
26
+ import { compileEre } from "../commands/regex-execution/ere/syntax.js";
27
+ import { matchEre } from "../commands/regex-execution/ere/matcher.js";
26
28
  export const defaultLimits = {
27
29
  maxInputBytes: 32 * 1024 * 1024,
28
30
  maxOutputBytes: 16 * 1024 * 1024,
@@ -32,6 +34,8 @@ export const defaultLimits = {
32
34
  maxSourceBytes: 1024 * 1024,
33
35
  maxExpansionFields: 10_000,
34
36
  maxExpansionBytes: 16 * 1024 * 1024,
37
+ maxWallClockMs: 30_000,
38
+ maxCpuMs: 30_000,
35
39
  pipeHighWaterMark: 64 * 1024,
36
40
  };
37
41
  const shellBuiltinNames = new Set([
@@ -64,17 +68,43 @@ export class Budget {
64
68
  sourceBytes = 0;
65
69
  controller = new AbortController();
66
70
  signal;
71
+ #wallClockTimer;
72
+ #wallClockDeadline = 0;
73
+ #cpuStarted = monotonicNow();
67
74
  constructor(limits, signal) {
68
75
  this.limits = limits;
69
76
  this.signal = signal ? AbortSignal.any([signal, this.controller.signal]) : this.controller.signal;
70
77
  this.values = new ValueArena(limits.maxExpansionBytes, limits.maxExpansionFields, () => this.signal.throwIfAborted(), limit => this.fail(limit));
78
+ this.#wallClockDeadline = Date.now() + limits.maxWallClockMs;
79
+ this.#armWallClock();
80
+ }
81
+ #armWallClock() {
82
+ const remaining = this.#wallClockDeadline - Date.now();
83
+ if (remaining <= 0) {
84
+ this.controller.abort(new ShellLimitError("maxWallClockMs"));
85
+ return;
86
+ }
87
+ this.#wallClockTimer = setTimeout(() => this.#armWallClock(), Math.min(remaining, 2_147_483_647));
88
+ const timer = this.#wallClockTimer;
89
+ timer.unref?.();
90
+ }
91
+ close() {
92
+ if (this.#wallClockTimer !== undefined)
93
+ clearTimeout(this.#wallClockTimer);
94
+ this.#wallClockTimer = undefined;
71
95
  }
72
96
  fail(limit) {
73
97
  const error = new ShellLimitError(limit);
74
98
  this.controller.abort(error);
75
99
  throw error;
76
100
  }
101
+ cpuCheckpoint() {
102
+ this.signal.throwIfAborted();
103
+ if (monotonicNow() - this.#cpuStarted > this.limits.maxCpuMs)
104
+ this.fail("maxCpuMs");
105
+ }
77
106
  tick() {
107
+ this.cpuCheckpoint();
78
108
  this.signal.throwIfAborted();
79
109
  if (++this.commands > this.limits.maxCommands)
80
110
  this.fail("maxCommands");
@@ -493,7 +523,7 @@ class CdLookup {
493
523
  amount -= step;
494
524
  if (this.spent % 128 === 0) {
495
525
  this.signal.throwIfAborted();
496
- await interruptible(new Promise(resolve => setImmediate(resolve)), this.signal);
526
+ await yieldTurn(this.signal);
497
527
  this.signal.throwIfAborted();
498
528
  }
499
529
  }
@@ -602,7 +632,7 @@ class DirectoryStackWork {
602
632
  this.signal.throwIfAborted();
603
633
  if (this.flushed === this.spent)
604
634
  return;
605
- await interruptible(new Promise(resolve => setImmediate(resolve)), this.signal);
635
+ await yieldTurn(this.signal);
606
636
  this.signal.throwIfAborted();
607
637
  this.flushed = this.spent;
608
638
  }
@@ -939,20 +969,6 @@ export class Runtime {
939
969
  cancellationDepth;
940
970
  cancellationMaxDepth;
941
971
  outcomeFrame;
942
- static #ereRoots = new WeakMap();
943
- static registerEreRoot(budget, scope) {
944
- const entry = { closed: false };
945
- scope.register(async () => {
946
- entry.closed = true;
947
- try {
948
- await entry.cleanup?.();
949
- }
950
- finally {
951
- Runtime.#ereRoots.delete(budget);
952
- }
953
- });
954
- Runtime.#ereRoots.set(budget, entry);
955
- }
956
972
  constructor(fs, commands, middleware, budget, signal = budget.signal, fileWrites = new Map(), outputFiles = new Map(), commandSignal = signal, cancellation, cancellationState, cancellationOwner, cancellationDepth, cancellationMaxDepth, outcomeFrame = undefined) {
957
973
  this.fs = fs;
958
974
  this.commands = commands;
@@ -968,6 +984,7 @@ export class Runtime {
968
984
  this.cancellationDepth = cancellationDepth;
969
985
  this.cancellationMaxDepth = cancellationMaxDepth;
970
986
  this.outcomeFrame = outcomeFrame;
987
+ registerYieldCheckpoint(this.signal, () => this.budget.cpuCheckpoint());
971
988
  }
972
989
  async ereDiagnostic(io, detail) {
973
990
  try {
@@ -1021,40 +1038,23 @@ export class Runtime {
1021
1038
  await textToken(operation, subject, this.signal);
1022
1039
  const name = "BASH_REMATCH";
1023
1040
  const watch = await store.watch(name, operation, this.signal);
1024
- const entry = Runtime.#ereRoots.get(this.budget);
1025
- if (!entry || entry.closed)
1026
- throw new Error("ERE invocation owner is closed");
1027
- if (!entry.root)
1028
- entry.root = new EreTransportRoot({ maxExpansionBytes: this.budget.limits.maxExpansionBytes, maxExpansionFields: this.budget.limits.maxExpansionFields }, cleanup => {
1029
- scope.assertOpen();
1030
- if (entry.closed)
1031
- throw new Error("ERE invocation owner is closed");
1032
- entry.cleanup = cleanup;
1033
- });
1034
- const session = entry.root.openSession(cleanup => scope.register(cleanup));
1041
+ const ledger = new EreLedger({
1042
+ maxExpansionBytes: this.budget.limits.maxExpansionBytes,
1043
+ maxExpansionFields: this.budget.limits.maxExpansionFields,
1044
+ });
1035
1045
  let result;
1036
- let sessionEscaping = false;
1037
1046
  try {
1038
- result = await session.execute({ pattern: fragments, subject }, this.signal);
1047
+ const program = await compileEre(fragments, ledger, this.signal);
1048
+ result = await matchEre(program, subject, ledger, this.signal);
1039
1049
  }
1040
1050
  catch (error) {
1041
- sessionEscaping = true;
1042
1051
  this.signal.throwIfAborted();
1043
- if (error instanceof EreTransportSemanticError || error instanceof EreUnsupportedError) {
1052
+ if (error instanceof EreSyntaxError || error instanceof EreUnsupportedError) {
1044
1053
  await this.ereDiagnostic(io, `[[ ${error.message}`);
1045
- sessionEscaping = false;
1046
1054
  return 2;
1047
1055
  }
1048
1056
  throw error;
1049
1057
  }
1050
- finally {
1051
- await session.close().catch(error => {
1052
- if (sessionEscaping)
1053
- scope.failures.push(error);
1054
- else
1055
- throw new NounsetDiagnosticFailure(error);
1056
- });
1057
- }
1058
1058
  const status = result.matched ? 0 : 1;
1059
1059
  this.signal.throwIfAborted();
1060
1060
  scope.assertOpen();
@@ -1071,8 +1071,8 @@ export class Runtime {
1071
1071
  const prepared = await store.prepareName(name, operation, this.signal);
1072
1072
  staged = IndexedBinding.create(store.owner);
1073
1073
  if (result.matched)
1074
- for (let index = 0; index < result.spans.length; index++) {
1075
- const span = result.spans[index];
1074
+ for (let index = 0; index < result.captures.length; index++) {
1075
+ const span = result.captures[index];
1076
1076
  const size = span === null ? 0 : span.end - span.start;
1077
1077
  operation.reserve({ payload: size, metadata: 32, work: size + 2 });
1078
1078
  const value = span === null ? "" : subject.slice(span.start, span.end);
@@ -1235,6 +1235,8 @@ export class Runtime {
1235
1235
  throw new ArrayFailure(origin === "arithmetic" ? "indexed arithmetic is unsupported" : "indexed write requires prepared publication");
1236
1236
  if (state.readonlyVariables?.has(name))
1237
1237
  throw new Error(`${name}: readonly variable`);
1238
+ if (shellValueByteLength(value) > this.budget.limits.maxExpansionBytes)
1239
+ this.budget.fail("maxExpansionBytes");
1238
1240
  if (name === "OPTIND" && state.getopts?.integer && origin !== "arithmetic") {
1239
1241
  try {
1240
1242
  value = String(evaluateArithmetic(prepareArithmetic(shellValueText(value) || "0"), this.arithmeticVariables(state)));
@@ -1801,7 +1803,7 @@ export class Runtime {
1801
1803
  completed.add(index);
1802
1804
  if (incoming) {
1803
1805
  const upstream = index - 1;
1804
- const close = setImmediate(() => {
1806
+ const close = scheduleTurn(() => {
1805
1807
  closing.delete(close);
1806
1808
  if (written.has(upstream) && !completed.has(upstream))
1807
1809
  controllers[upstream].abort(new PipelineClosed());
@@ -1835,7 +1837,7 @@ export class Runtime {
1835
1837
  }
1836
1838
  finally {
1837
1839
  for (const close of closing)
1838
- clearImmediate(close);
1840
+ cancelTurn(close);
1839
1841
  for (const [index, controller] of controllers.entries())
1840
1842
  if (!completed.has(index) || written.has(index))
1841
1843
  controller.abort(new PipelineClosed());
@@ -1911,7 +1913,7 @@ export class Runtime {
1911
1913
  originalIO = isolateIO(originalIO);
1912
1914
  this.budget.tick();
1913
1915
  if (this.budget.commands % 128 === 0)
1914
- await interruptible(new Promise((resolve) => setImmediate(resolve)), this.signal);
1916
+ await yieldTurn(this.signal);
1915
1917
  this.signal.throwIfAborted();
1916
1918
  const inputs = new Set();
1917
1919
  const outputs = new Set();
@@ -1961,7 +1963,7 @@ export class Runtime {
1961
1963
  diagnosticFailure = error;
1962
1964
  throw error;
1963
1965
  }
1964
- if (error instanceof EreProfileLimitError || error instanceof EreTransportProfileLimitError) {
1966
+ if (error instanceof EreProfileLimitError) {
1965
1967
  try {
1966
1968
  await this.diagnostic(io, `[[ ${error.message}`);
1967
1969
  }
@@ -2039,7 +2041,7 @@ export class Runtime {
2039
2041
  if (!matched)
2040
2042
  for (const word of clause.patterns) {
2041
2043
  if (++patterns % 128 === 0)
2042
- await interruptible(new Promise((resolve) => setImmediate(resolve)), this.signal);
2044
+ await yieldTurn(this.signal);
2043
2045
  const pattern = (await this.word(word, state, io, false, true)).join("");
2044
2046
  if (await matchesPattern(pattern, subject, work)) {
2045
2047
  matched = true;
@@ -2185,7 +2187,7 @@ export class Runtime {
2185
2187
  for (const warning of warnings.splice(0))
2186
2188
  await writeText(io.stderr, `shell: warning: ${warning}\n`);
2187
2189
  if (++words % 128 === 0)
2188
- await interruptible(new Promise((resolve) => setImmediate(resolve)), this.signal);
2190
+ await yieldTurn(this.signal);
2189
2191
  const part = (await this.word(word, state, io, false)).join("");
2190
2192
  size += Buffer.byteLength(part);
2191
2193
  if (size > this.budget.limits.maxExpansionBytes)
@@ -3168,7 +3170,7 @@ export class Runtime {
3168
3170
  let lines = 0;
3169
3171
  while (true) {
3170
3172
  if (++lines % 32 === 0)
3171
- await interruptible(new Promise(resolve => setImmediate(resolve)), this.signal);
3173
+ await yieldTurn(this.signal);
3172
3174
  this.signal.throwIfAborted();
3173
3175
  const bytes = await input.sourceLine();
3174
3176
  const eof = bytes === undefined;
@@ -3807,7 +3809,7 @@ export class Runtime {
3807
3809
  };
3808
3810
  const checkpoint = async () => {
3809
3811
  this.signal.throwIfAborted();
3810
- await interruptible(new Promise(resolve => setImmediate(resolve)), this.signal);
3812
+ await yieldTurn(this.signal);
3811
3813
  this.signal.throwIfAborted();
3812
3814
  };
3813
3815
  const { args } = context;
@@ -3863,7 +3865,7 @@ export class Runtime {
3863
3865
  };
3864
3866
  const checkpoint = async () => {
3865
3867
  this.signal.throwIfAborted();
3866
- await interruptible(new Promise(resolve => setImmediate(resolve)), this.signal);
3868
+ await yieldTurn(this.signal);
3867
3869
  this.signal.throwIfAborted();
3868
3870
  };
3869
3871
  if (!Array.isArray(context.args))
@@ -5008,7 +5010,7 @@ export class Runtime {
5008
5010
  if (work.remaining < 0)
5009
5011
  work.exhausted();
5010
5012
  if (++attempts % 256 === 0)
5011
- await new Promise(resolve => setImmediate(resolve));
5013
+ await yieldTurn(this.signal);
5012
5014
  this.signal.throwIfAborted();
5013
5015
  if (owner)
5014
5016
  await owner.ledger.checkpoint(this.signal, end - start + 1);