@poe-platform/safe-bash 0.1.50 → 0.1.52

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.
@@ -4822,47 +4822,62 @@ function evaluateArithmetic(program, variables) {
4822
4822
  throw new Error(`Unsupported arithmetic operator ${operator}`);
4823
4823
  }
4824
4824
  };
4825
- const evaluate = (node) => {
4826
- if (++steps > 1e4) throw new Error("Arithmetic operation limit exceeded");
4827
- let value2;
4828
- if (node.kind === "literal") return node.value;
4829
- if (node.kind === "name") {
4830
- if (visiting.has(node.name) || visiting.size >= 64) throw new Error("Arithmetic variable recursion");
4831
- visiting.add(node.name);
4832
- try {
4833
- return evaluate(parseArithmetic(variables[node.name] ?? "0"));
4834
- } finally {
4835
- visiting.delete(node.name);
4836
- }
4837
- }
4838
- if (node.kind === "conditional") return evaluate(evaluate(node.condition) ? node.yes : node.no);
4839
- if (node.kind === "unary") {
4840
- const operand = evaluate(node.operand);
4841
- if (node.operator === "+") value2 = operand;
4842
- else if (node.operator === "-") value2 = -operand;
4843
- else if (node.operator === "!") value2 = BigInt(!operand);
4844
- else if (node.operator === "~") value2 = ~operand;
4845
- else {
4846
- value2 = BigInt.asIntN(64, operand + (node.operator === "++" ? 1n : -1n));
4847
- variables[node.operand.name] = String(value2);
4848
- if (node.postfix) value2 = operand;
4849
- }
4850
- } else {
4851
- if (node.operator === "=") value2 = evaluate(node.right);
4852
- else {
4853
- const left = evaluate(node.left);
4854
- if (node.operator === "&&") return left ? BigInt(evaluate(node.right) !== 0n) : 0n;
4855
- if (node.operator === "||") return left ? 1n : BigInt(evaluate(node.right) !== 0n);
4856
- if (node.operator === ",") return evaluate(node.right);
4857
- value2 = binary(precedence[node.operator] === 2 ? node.operator.slice(0, -1) : node.operator, left, evaluate(node.right), node.right.start ?? 0);
4858
- }
4859
- if (precedence[node.operator] === 2) variables[node.left.name] = String(BigInt.asIntN(64, value2));
4860
- }
4861
- return BigInt.asIntN(64, value2);
4862
- };
4863
4825
  try {
4864
4826
  if (program.error) throw program.error;
4865
- return evaluate(program.tree);
4827
+ const pending = [{ kind: "evaluate", node: program.tree }];
4828
+ let value2 = 0n;
4829
+ while (pending.length) {
4830
+ const frame = pending.pop();
4831
+ if (frame.kind === "evaluate") {
4832
+ if (++steps > 1e4) throw new Error("Arithmetic operation limit exceeded");
4833
+ const node = frame.node;
4834
+ if (node.kind === "literal") value2 = node.value;
4835
+ else if (node.kind === "name") {
4836
+ if (visiting.has(node.name) || visiting.size >= 64) throw new Error("Arithmetic variable recursion");
4837
+ visiting.add(node.name);
4838
+ pending.push({ kind: "variable", name: node.name }, { kind: "evaluate", node: parseArithmetic(variables[node.name] ?? "0") });
4839
+ } else if (node.kind === "conditional") {
4840
+ pending.push({ kind: "conditional", node }, { kind: "evaluate", node: node.condition });
4841
+ } else if (node.kind === "unary") {
4842
+ pending.push({ kind: "unary", node }, { kind: "evaluate", node: node.operand });
4843
+ } else if (node.operator === "=") {
4844
+ pending.push({ kind: "right", node }, { kind: "evaluate", node: node.right });
4845
+ } else {
4846
+ pending.push({ kind: "left", node }, { kind: "evaluate", node: node.left });
4847
+ }
4848
+ } else if (frame.kind === "variable") visiting.delete(frame.name);
4849
+ else if (frame.kind === "conditional") {
4850
+ pending.push({ kind: "evaluate", node: value2 ? frame.node.yes : frame.node.no });
4851
+ } else if (frame.kind === "unary") {
4852
+ const { node } = frame;
4853
+ const operand = value2;
4854
+ if (node.operator === "+") value2 = operand;
4855
+ else if (node.operator === "-") value2 = -operand;
4856
+ else if (node.operator === "!") value2 = BigInt(!operand);
4857
+ else if (node.operator === "~") value2 = ~operand;
4858
+ else {
4859
+ value2 = BigInt.asIntN(64, operand + (node.operator === "++" ? 1n : -1n));
4860
+ variables[node.operand.name] = String(value2);
4861
+ if (node.postfix) value2 = operand;
4862
+ }
4863
+ value2 = BigInt.asIntN(64, value2);
4864
+ } else if (frame.kind === "left") {
4865
+ const { node } = frame;
4866
+ if (node.operator === "&&" || node.operator === "||") {
4867
+ if (node.operator === "&&" ? value2 === 0n : value2 !== 0n) value2 = BigInt(value2 !== 0n);
4868
+ else pending.push({ kind: "logical" }, { kind: "evaluate", node: node.right });
4869
+ } else {
4870
+ if (node.operator !== ",") pending.push({ kind: "right", node, left: value2 });
4871
+ pending.push({ kind: "evaluate", node: node.right });
4872
+ }
4873
+ } else if (frame.kind === "right") {
4874
+ const { node } = frame;
4875
+ if (node.operator !== "=") value2 = binary(precedence[node.operator] === 2 ? node.operator.slice(0, -1) : node.operator, frame.left, value2, node.right.start ?? 0);
4876
+ if (precedence[node.operator] === 2) variables[node.left.name] = String(BigInt.asIntN(64, value2));
4877
+ value2 = BigInt.asIntN(64, value2);
4878
+ } else value2 = BigInt(value2 !== 0n);
4879
+ }
4880
+ return value2;
4866
4881
  } catch (error) {
4867
4882
  if (error instanceof ArithmeticFailure) throw new Error(`${program.source.trimStart()}: ${error.message} (error token is "${program.source.slice(error.offset)}")`);
4868
4883
  if (error instanceof ShellSyntaxError) {
@@ -9513,6 +9528,7 @@ var defaultLimits = {
9513
9528
  maxInputBytes: 32 * 1024 * 1024,
9514
9529
  maxOutputBytes: 16 * 1024 * 1024,
9515
9530
  maxCommands: 1e4,
9531
+ maxPipelineStages: 64,
9516
9532
  maxLoopIterations: 1e4,
9517
9533
  maxSubstitutionDepth: 64,
9518
9534
  maxSourceBytes: 1024 * 1024,
@@ -9612,6 +9628,7 @@ var Budget = class {
9612
9628
  signal;
9613
9629
  #wallClockTimer;
9614
9630
  #wallClockDeadline = 0;
9631
+ #pipelineStages = 0;
9615
9632
  #cpuStarted = monotonicNow();
9616
9633
  #armWallClock() {
9617
9634
  const remaining = this.#wallClockDeadline - Date.now();
@@ -9641,6 +9658,17 @@ var Budget = class {
9641
9658
  this.signal.throwIfAborted();
9642
9659
  if (++this.commands > this.limits.maxCommands) this.fail("maxCommands");
9643
9660
  }
9661
+ reservePipelineStages(count) {
9662
+ this.signal.throwIfAborted();
9663
+ if (count > this.limits.maxPipelineStages - this.#pipelineStages) this.fail("maxPipelineStages");
9664
+ this.#pipelineStages += count;
9665
+ let released = false;
9666
+ return () => {
9667
+ if (released) return;
9668
+ released = true;
9669
+ this.#pipelineStages -= count;
9670
+ };
9671
+ }
9644
9672
  loop() {
9645
9673
  this.signal.throwIfAborted();
9646
9674
  if (++this.iterations > this.limits.maxLoopIterations) this.fail("maxLoopIterations");
@@ -11136,119 +11164,142 @@ var Runtime = class _Runtime {
11136
11164
  let status;
11137
11165
  if (pipeline.commands.length === 1) status = await this.command(pipeline.commands[0], state, io, false, pipeline.negate);
11138
11166
  else {
11139
- const pipes = pipeline.commands.slice(1).map(() => createBytePipe({
11140
- highWaterMark: this.budget.limits.pipeHighWaterMark,
11141
- signal: this.signal
11142
- }));
11143
- const controllers = pipeline.commands.map(() => new AbortController());
11167
+ const release = this.budget.reservePipelineStages(pipeline.commands.length);
11168
+ const retained = /* @__PURE__ */ new Set();
11169
+ let setupClosed = false;
11170
+ const retain = (work) => {
11171
+ retained.add(work);
11172
+ const settled = () => {
11173
+ retained.delete(work);
11174
+ if (setupClosed && !retained.size) release();
11175
+ };
11176
+ void work.then(settled, settled);
11177
+ };
11178
+ const pipes = [];
11179
+ const controllers = [];
11144
11180
  const written = /* @__PURE__ */ new Set();
11145
11181
  const completed = /* @__PURE__ */ new Set();
11146
11182
  const closing = /* @__PURE__ */ new Set();
11147
- const tasks = pipeline.commands.map(async (command, index) => {
11148
- const incoming = pipes[index - 1];
11149
- const outgoing = pipes[index];
11150
- const childDepth = this.cancellationDepth + 1;
11151
- const controls = [
11152
- { role: "pipeline-control", signal: controllers[index].signal }
11153
- ];
11154
- const prepared = prepareChildCancellation(
11155
- this.cancellation,
11156
- void 0,
11157
- this.cancellationAdmission(childDepth, controls.length),
11158
- controls
11159
- );
11160
- const owner = new InvocationCancellationOwner(io[invocationScope], prepared, this.cancellationState);
11161
- let boundary;
11162
- try {
11163
- boundary = owner.activate();
11164
- } catch (error) {
11165
- await owner.abandon(Promise.resolve());
11166
- throw error;
11167
- }
11168
- const signal = AbortSignal.any([boundary.deliverySignal, io[invocationScope].signal]);
11169
- const frame = {};
11170
- const runtime = new _Runtime(
11171
- this.fs,
11172
- this.commands,
11173
- this.middleware,
11174
- this.budget,
11175
- signal,
11176
- this.fileWrites,
11177
- this.outputFiles,
11178
- boundary.deliverySignal,
11179
- boundary,
11180
- this.cancellationState,
11181
- owner,
11182
- childDepth,
11183
- this.cancellationMaxDepth,
11184
- frame
11185
- );
11186
- const input2 = new ShellInput(incoming?.readable ?? io.stdin, this.budget, signal);
11187
- const pipeOutput = outgoing && { ownedOutput: outgoing.writable.ownedOutput, write: async (chunk) => {
11183
+ let statuses;
11184
+ try {
11185
+ for (let index = 1; index < pipeline.commands.length; index++) pipes.push(createBytePipe({
11186
+ highWaterMark: this.budget.limits.pipeHighWaterMark,
11187
+ signal: this.signal
11188
+ }));
11189
+ for (let index = 0; index < pipeline.commands.length; index++) controllers.push(new AbortController());
11190
+ const tasks = pipeline.commands.map(async (command, index) => {
11191
+ const incoming = pipes[index - 1];
11192
+ const outgoing = pipes[index];
11193
+ const childDepth = this.cancellationDepth + 1;
11194
+ const controls = [
11195
+ { role: "pipeline-control", signal: controllers[index].signal }
11196
+ ];
11197
+ const prepared = prepareChildCancellation(
11198
+ this.cancellation,
11199
+ void 0,
11200
+ this.cancellationAdmission(childDepth, controls.length),
11201
+ controls
11202
+ );
11203
+ const owner = new InvocationCancellationOwner(io[invocationScope], prepared, this.cancellationState);
11204
+ let boundary;
11188
11205
  try {
11189
- await outgoing.writable.write(chunk);
11190
- if (chunk.byteLength) written.add(index);
11206
+ boundary = owner.activate();
11191
11207
  } catch (error) {
11192
- if (errorCode(error) === "EPIPE") {
11193
- const closed = new PipelineClosed();
11194
- controllers[index].abort(closed);
11195
- throw closed;
11196
- }
11208
+ await owner.abandon(Promise.resolve());
11197
11209
  throw error;
11198
11210
  }
11199
- } };
11200
- const executeStage = async () => {
11201
- try {
11202
- let exitCode;
11211
+ const signal = AbortSignal.any([boundary.deliverySignal, io[invocationScope].signal]);
11212
+ const frame = {};
11213
+ const runtime = new _Runtime(
11214
+ this.fs,
11215
+ this.commands,
11216
+ this.middleware,
11217
+ this.budget,
11218
+ signal,
11219
+ this.fileWrites,
11220
+ this.outputFiles,
11221
+ boundary.deliverySignal,
11222
+ boundary,
11223
+ this.cancellationState,
11224
+ owner,
11225
+ childDepth,
11226
+ this.cancellationMaxDepth,
11227
+ frame
11228
+ );
11229
+ const input2 = new ShellInput(incoming?.readable ?? io.stdin, this.budget, signal);
11230
+ const pipeOutput = outgoing && { ownedOutput: outgoing.writable.ownedOutput, write: async (chunk) => {
11203
11231
  try {
11204
- const child = await cloneState(state, this.signal);
11205
- child.isolated = true;
11206
- exitCode = await interruptible(runtime.runCommandIsolated(command, child, {
11207
- ...isolateIO(io),
11208
- stdin: input2,
11209
- ...incoming ? { stdinIsDefault: false } : {},
11210
- stdout: pipeOutput ? this.budget.sink(pipeOutput, signal) : signalSink(io.stdout, signal),
11211
- stderr: signalSink(io.stderr, signal)
11212
- }).finally(() => stateMonitor(child)?.closeValues()), signal);
11232
+ await outgoing.writable.write(chunk);
11233
+ if (chunk.byteLength) written.add(index);
11213
11234
  } catch (error) {
11214
- if (!(error instanceof PipelineClosed)) throw error;
11215
- exitCode = 141;
11235
+ if (errorCode(error) === "EPIPE") {
11236
+ const closed = new PipelineClosed();
11237
+ controllers[index].abort(closed);
11238
+ throw closed;
11239
+ }
11240
+ throw error;
11216
11241
  }
11217
- return { exitCode };
11218
- } finally {
11219
- completed.add(index);
11220
- if (incoming) {
11221
- const upstream = index - 1;
11222
- const close = scheduleTurn(() => {
11223
- closing.delete(close);
11224
- if (written.has(upstream) && !completed.has(upstream)) controllers[upstream].abort(new PipelineClosed());
11242
+ } };
11243
+ const executeStage = async () => {
11244
+ try {
11245
+ let exitCode;
11246
+ try {
11247
+ const child = await cloneState(state, this.signal);
11248
+ child.isolated = true;
11249
+ const work = runtime.runCommandIsolated(command, child, {
11250
+ ...isolateIO(io),
11251
+ stdin: input2,
11252
+ ...incoming ? { stdinIsDefault: false } : {},
11253
+ stdout: pipeOutput ? this.budget.sink(pipeOutput, signal) : signalSink(io.stdout, signal),
11254
+ stderr: signalSink(io.stderr, signal)
11255
+ }).finally(() => stateMonitor(child)?.closeValues());
11256
+ retain(work);
11257
+ exitCode = await interruptible(work, signal);
11258
+ } catch (error) {
11259
+ if (!(error instanceof PipelineClosed)) throw error;
11260
+ exitCode = 141;
11261
+ }
11262
+ return { exitCode };
11263
+ } finally {
11264
+ completed.add(index);
11265
+ if (incoming) {
11266
+ const upstream = index - 1;
11267
+ const close = scheduleTurn(() => {
11268
+ closing.delete(close);
11269
+ if (written.has(upstream) && !completed.has(upstream)) controllers[upstream].abort(new PipelineClosed());
11270
+ });
11271
+ closing.add(close);
11272
+ await incoming.abort();
11273
+ }
11274
+ await input2.close().catch((error) => {
11275
+ if (!(error instanceof PipelineClosed)) throw error;
11225
11276
  });
11226
- closing.add(close);
11227
- await incoming.abort();
11277
+ if (outgoing) await outgoing.close().catch(() => void 0);
11228
11278
  }
11229
- await input2.close().catch((error) => {
11230
- if (!(error instanceof PipelineClosed)) throw error;
11231
- });
11232
- if (outgoing) await outgoing.close().catch(() => void 0);
11279
+ };
11280
+ let captured;
11281
+ try {
11282
+ captured = { kind: "return", value: await executeStage() };
11283
+ } catch (reason) {
11284
+ captured = frame.report && Object.is(frame.report.origin.signal.reason, reason) ? { kind: "throw", reason, report: frame.report } : { kind: "throw", reason };
11233
11285
  }
11234
- };
11235
- let captured;
11236
- try {
11237
- captured = { kind: "return", value: await executeStage() };
11238
- } catch (reason) {
11239
- captured = frame.report && Object.is(frame.report.origin.signal.reason, reason) ? { kind: "throw", reason, report: frame.report } : { kind: "throw", reason };
11240
- }
11241
- const selection = await owner.finish(Promise.resolve(), captured);
11242
- if (selection.outcome.kind === "throw") throw selection.outcome.reason;
11243
- return selection.outcome.value.exitCode;
11244
- });
11245
- let statuses;
11246
- try {
11286
+ const selection = await owner.finish(Promise.resolve(), captured);
11287
+ if (selection.outcome.kind === "throw") throw selection.outcome.reason;
11288
+ return selection.outcome.value.exitCode;
11289
+ });
11290
+ for (const task of tasks) retain(task);
11247
11291
  statuses = await interruptible(Promise.all(tasks), this.signal);
11248
11292
  } finally {
11249
- for (const close of closing) cancelTurn(close);
11250
- for (const [index, controller] of controllers.entries()) if (!completed.has(index) || written.has(index)) controller.abort(new PipelineClosed());
11251
- await Promise.all(pipes.map((pipe) => pipe.abort()));
11293
+ try {
11294
+ for (const close of closing) cancelTurn(close);
11295
+ for (const [index, controller] of controllers.entries()) if (!completed.has(index) || written.has(index)) controller.abort(new PipelineClosed());
11296
+ const aborts = pipes.map((pipe) => pipe.abort());
11297
+ for (const abort of aborts) retain(abort);
11298
+ await Promise.all(aborts);
11299
+ } finally {
11300
+ setupClosed = true;
11301
+ if (!retained.size) release();
11302
+ }
11252
11303
  }
11253
11304
  await this.publishStatus(state, statuses, io);
11254
11305
  status = state.pipefail ? statuses.findLast((status2) => status2 !== 0) ?? 0 : statuses.at(-1);
@@ -15154,6 +15205,7 @@ var cloudflareWorkerLimits = Object.freeze({
15154
15205
  maxInputBytes: 4 * 1024 * 1024,
15155
15206
  maxOutputBytes: 4 * 1024 * 1024,
15156
15207
  maxCommands: 1e3,
15208
+ maxPipelineStages: 64,
15157
15209
  maxLoopIterations: 1e3,
15158
15210
  maxSubstitutionDepth: 16,
15159
15211
  maxSourceBytes: 256 * 1024,