@poe-platform/safe-bash 0.1.530 → 0.1.531

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 (52) hide show
  1. package/dist/safe-bash/chunks/chunk-2GV4WO7O.js +136 -0
  2. package/dist/safe-bash/chunks/chunk-2GV4WO7O.js.map +7 -0
  3. package/dist/safe-bash/chunks/chunk-54Z5EUCW.js +340 -0
  4. package/dist/safe-bash/chunks/chunk-54Z5EUCW.js.map +7 -0
  5. package/dist/safe-bash/chunks/{chunk-NYHAKXQ7.js → chunk-6MHYEBAJ.js} +16 -140
  6. package/dist/safe-bash/chunks/chunk-6MHYEBAJ.js.map +7 -0
  7. package/dist/safe-bash/chunks/{chunk-5MSOBYRG.js → chunk-IKATLB4I.js} +5 -3
  8. package/dist/safe-bash/chunks/{chunk-5MSOBYRG.js.map → chunk-IKATLB4I.js.map} +1 -1
  9. package/dist/safe-bash/chunks/{chunk-5OCQTFXT.js → chunk-LUJYX5H5.js} +6 -332
  10. package/dist/safe-bash/chunks/{chunk-5OCQTFXT.js.map → chunk-LUJYX5H5.js.map} +4 -4
  11. package/dist/safe-bash/chunks/chunk-UGMUVHIY.js +1603 -0
  12. package/dist/safe-bash/chunks/chunk-UGMUVHIY.js.map +7 -0
  13. package/dist/safe-bash/commands/network/args.d.ts +3 -0
  14. package/dist/safe-bash/commands/network/args.d.ts.map +1 -1
  15. package/dist/safe-bash/commands/network/args.js +1 -1
  16. package/dist/safe-bash/commands/network/args.js.map +1 -1
  17. package/dist/safe-bash/commands/network/body.js +2 -2
  18. package/dist/safe-bash/commands/network/body.js.map +1 -1
  19. package/dist/safe-bash/commands/network/curl.d.ts +12 -2
  20. package/dist/safe-bash/commands/network/curl.d.ts.map +1 -1
  21. package/dist/safe-bash/commands/network/curl.js +46 -27
  22. package/dist/safe-bash/commands/network/curl.js.map +1 -1
  23. package/dist/safe-bash/commands/network/index.browser.js +29 -0
  24. package/dist/safe-bash/commands/network/index.browser.js.map +7 -0
  25. package/dist/safe-bash/commands/network/index.d.ts +1 -10
  26. package/dist/safe-bash/commands/network/index.d.ts.map +1 -1
  27. package/dist/safe-bash/commands/network/index.js +1 -22
  28. package/dist/safe-bash/commands/network/index.js.map +1 -1
  29. package/dist/safe-bash/commands/network/platform.d.ts +4 -0
  30. package/dist/safe-bash/commands/network/platform.d.ts.map +1 -0
  31. package/dist/safe-bash/commands/network/platform.js +4 -0
  32. package/dist/safe-bash/commands/network/platform.js.map +1 -0
  33. package/dist/safe-bash/commands/network/public.d.ts +12 -0
  34. package/dist/safe-bash/commands/network/public.d.ts.map +1 -0
  35. package/dist/safe-bash/commands/network/public.js +27 -0
  36. package/dist/safe-bash/commands/network/public.js.map +1 -0
  37. package/dist/safe-bash/commands/network/shared.js +1 -1
  38. package/dist/safe-bash/commands/network/shared.js.map +1 -1
  39. package/dist/safe-bash/commands/network/wget.d.ts +4 -0
  40. package/dist/safe-bash/commands/network/wget.d.ts.map +1 -0
  41. package/dist/safe-bash/commands/network/wget.js +155 -0
  42. package/dist/safe-bash/commands/network/wget.js.map +1 -0
  43. package/dist/safe-bash/commands/xml/index.browser.js +3 -2
  44. package/dist/safe-bash/commands/yq/index.browser.js +4 -2
  45. package/dist/safe-bash/core.browser.js +42 -366
  46. package/dist/safe-bash/core.browser.js.map +4 -4
  47. package/dist/safe-bash/core.d.ts +1 -5
  48. package/dist/safe-bash/core.d.ts.map +1 -1
  49. package/dist/safe-bash/core.js +1 -3
  50. package/dist/safe-bash/core.js.map +1 -1
  51. package/package.json +9 -3
  52. package/dist/safe-bash/chunks/chunk-NYHAKXQ7.js.map +0 -7
@@ -0,0 +1,1603 @@
1
+ import {
2
+ createOutputOperation
3
+ } from "./chunk-2GV4WO7O.js";
4
+ import {
5
+ FsError,
6
+ __toESM,
7
+ collectBytes,
8
+ createBytePipe,
9
+ getCommandArguments,
10
+ import_buffer,
11
+ init_platform,
12
+ normalizePath,
13
+ outputFailure,
14
+ pathOf,
15
+ posixPath,
16
+ readBytes,
17
+ require_buffer,
18
+ shellValueByteLength,
19
+ shellValueBytes,
20
+ toByteSource,
21
+ writeBytes,
22
+ writeDiagnostic,
23
+ yieldTurn
24
+ } from "./chunk-LUJYX5H5.js";
25
+
26
+ // packages/safe-bash/src/commands/network/public.ts
27
+ init_platform();
28
+
29
+ // packages/safe-bash/src/commands/network/wget.ts
30
+ init_platform();
31
+
32
+ // packages/safe-bash/src/commands/network/curl.ts
33
+ init_platform();
34
+
35
+ // packages/safe-bash/src/commands/network/aggregate.ts
36
+ init_platform();
37
+
38
+ // packages/safe-bash/src/commands/network/shared.ts
39
+ init_platform();
40
+
41
+ // packages/safe-bash/src/commands/network/types.ts
42
+ init_platform();
43
+ var defaultNetworkLimits = Object.freeze({
44
+ maxUploadBytes: 64 * 1024 * 1024,
45
+ maxDownloadBytes: 64 * 1024 * 1024,
46
+ maxBufferBytes: 8 * 1024 * 1024,
47
+ maxHeaderBytes: 64 * 1024,
48
+ maxRedirects: 10,
49
+ maxRetries: 5,
50
+ maxUrls: 32,
51
+ maxTimeMs: 12e4,
52
+ maxTotalTimeMs: 12e4
53
+ });
54
+ var cloudflareWorkerNetworkLimits = Object.freeze({
55
+ maxUploadBytes: 4 * 1024 * 1024,
56
+ maxDownloadBytes: 4 * 1024 * 1024,
57
+ maxBufferBytes: 1024 * 1024,
58
+ maxHeaderBytes: 32 * 1024,
59
+ maxRedirects: 2,
60
+ maxRetries: 1,
61
+ maxUrls: 8,
62
+ maxTimeMs: 1e4,
63
+ maxTotalTimeMs: 1e4
64
+ });
65
+ var CurlError = class extends Error {
66
+ constructor(exitCode, message) {
67
+ super(message);
68
+ this.exitCode = exitCode;
69
+ this.name = "CurlError";
70
+ }
71
+ exitCode;
72
+ };
73
+
74
+ // packages/safe-bash/src/commands/network/shared.ts
75
+ var encode = (text) => new TextEncoder().encode(text);
76
+ function limitsFor(overrides = {}) {
77
+ const result = { ...defaultNetworkLimits, ...overrides };
78
+ for (const [name, value] of Object.entries(result)) {
79
+ const minimum = name === "maxRedirects" || name === "maxRetries" ? 0 : 1;
80
+ if (!Number.isSafeInteger(value) || value < minimum || name === "maxTimeMs" && value > 2147483647) {
81
+ throw new RangeError(`Invalid network limit: ${name}`);
82
+ }
83
+ }
84
+ return Object.freeze(result);
85
+ }
86
+ async function withSignal(operation, signal) {
87
+ signal.throwIfAborted();
88
+ return new Promise((resolve, reject) => {
89
+ const onAbort = () => {
90
+ cleanup();
91
+ reject(signal.reason);
92
+ };
93
+ const cleanup = () => signal.removeEventListener("abort", onAbort);
94
+ signal.addEventListener("abort", onAbort, { once: true });
95
+ Promise.resolve().then(operation).then((value) => {
96
+ cleanup();
97
+ resolve(value);
98
+ }, (error) => {
99
+ cleanup();
100
+ reject(error);
101
+ });
102
+ });
103
+ }
104
+ async function delay(milliseconds, signal) {
105
+ let timer;
106
+ try {
107
+ await withSignal(() => new Promise((resolve) => {
108
+ timer = setTimeout(resolve, milliseconds);
109
+ }), signal);
110
+ } finally {
111
+ clearTimeout(timer);
112
+ }
113
+ }
114
+ function header(headers, name) {
115
+ return headers.find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
116
+ }
117
+ function networkError(error) {
118
+ if (error instanceof CurlError) return error;
119
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
120
+ if (["ENOTFOUND", "EAI_AGAIN"].includes(code)) return new CurlError(6, "Could not resolve host");
121
+ if (["ECONNREFUSED", "ENETUNREACH", "EHOSTUNREACH"].includes(code)) return new CurlError(7, "Failed to connect");
122
+ if (/CERT|SELF_SIGNED|UNABLE_TO_VERIFY/.test(code)) return new CurlError(60, "TLS certificate verification failed");
123
+ if (/TLS|SSL/.test(code)) return new CurlError(35, "TLS handshake failed");
124
+ return new CurlError(56, "Network transfer failed");
125
+ }
126
+ async function diagnostic(context, error) {
127
+ await writeDiagnostic(context.stderr, `${context.command}: (${error.exitCode}) ${error.message}
128
+ `, context.signal);
129
+ }
130
+
131
+ // packages/safe-bash/src/commands/network/aggregate.ts
132
+ function createDeadlineOutput(context, destination, remaining) {
133
+ const lifetime = new AbortController();
134
+ const signal = AbortSignal.any([context.signal, lifetime.signal]);
135
+ const operation = createOutputOperation({ ...context, signal }, destination);
136
+ if (operation.signal.aborted) return operation;
137
+ let timer;
138
+ operation.registerCleanup(() => {
139
+ clearTimeout(timer);
140
+ timer = void 0;
141
+ });
142
+ timer = setTimeout(() => lifetime.abort(new CurlError(28, "Operation timed out")), Math.max(0, remaining));
143
+ return operation;
144
+ }
145
+ async function deadlineDiagnostic(context, error, remaining) {
146
+ const operation = createDeadlineOutput(context, context.stderr, remaining);
147
+ try {
148
+ await diagnostic({ ...context, stderr: operation.output, signal: operation.signal }, error);
149
+ } finally {
150
+ await operation.close();
151
+ }
152
+ }
153
+
154
+ // packages/safe-bash/src/commands/network/args.ts
155
+ init_platform();
156
+
157
+ // packages/safe-bash/browser/network.mjs
158
+ init_platform();
159
+ var import_buffer2 = __toESM(require_buffer(), 1);
160
+ function createDefaultHttpTransport() {
161
+ throw new TypeError("Portable network commands require an explicit HTTP transport; inject createFetchTransport() or a host transport");
162
+ }
163
+ function randomBytes(length) {
164
+ const bytes = new Uint8Array(length);
165
+ globalThis.crypto.getRandomValues(bytes);
166
+ return import_buffer2.Buffer.from(bytes);
167
+ }
168
+ function validateHeaderName(name) {
169
+ if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) throw new TypeError("Invalid HTTP header name");
170
+ }
171
+ function validateHeaderValue(_name, value) {
172
+ if (/[^\t\x20-\x7e\x80-\xff]/.test(value)) throw new TypeError("Invalid HTTP header value");
173
+ }
174
+
175
+ // packages/safe-bash/src/commands/network/args.ts
176
+ var values = {
177
+ X: "request",
178
+ d: "data",
179
+ H: "header",
180
+ u: "user",
181
+ A: "user-agent",
182
+ e: "referer",
183
+ o: "output",
184
+ D: "dump-header",
185
+ w: "write-out",
186
+ T: "upload-file",
187
+ m: "max-time",
188
+ F: "form"
189
+ };
190
+ var flags = {
191
+ L: "location",
192
+ I: "head",
193
+ i: "include",
194
+ f: "fail",
195
+ s: "silent",
196
+ S: "show-error",
197
+ G: "get",
198
+ O: "remote-name",
199
+ v: "verbose",
200
+ q: "disable",
201
+ N: "no-buffer",
202
+ g: "globoff",
203
+ h: "help",
204
+ V: "version"
205
+ };
206
+ var longValues = /* @__PURE__ */ new Set([
207
+ ...Object.values(values),
208
+ "data-ascii",
209
+ "data-raw",
210
+ "data-binary",
211
+ "data-urlencode",
212
+ "json",
213
+ "form-string",
214
+ "url",
215
+ "oauth2-bearer",
216
+ "max-redirs",
217
+ "max-filesize",
218
+ "retry",
219
+ "retry-delay"
220
+ ]);
221
+ function number(value, integral = false) {
222
+ if (!(integral ? /^\d+$/ : /^\d+(?:\.\d+)?$/).test(value)) throw new CurlError(2, "Invalid numeric option");
223
+ const parsed = Number(value);
224
+ if (!Number.isFinite(parsed) || parsed < 0 || parsed > Number.MAX_SAFE_INTEGER) throw new CurlError(2, "Invalid numeric option");
225
+ return parsed;
226
+ }
227
+ function addHeader(result, raw) {
228
+ const colon = raw.indexOf(":");
229
+ const semicolon = colon < 0 && raw.endsWith(";");
230
+ if (colon < 1 && !semicolon) throw new CurlError(2, "Invalid HTTP header");
231
+ const name = semicolon ? raw.slice(0, -1) : raw.slice(0, colon);
232
+ const value = semicolon ? "" : raw.slice(colon + 1).trim();
233
+ try {
234
+ validateHeaderName(name);
235
+ validateHeaderValue(name, value);
236
+ } catch {
237
+ throw new CurlError(2, "Invalid HTTP header");
238
+ }
239
+ if (["host", "content-length", "transfer-encoding", "connection", "proxy-authorization", "upgrade", "expect"].includes(name.toLowerCase())) {
240
+ throw new CurlError(2, "Transport-controlled HTTP header is not supported");
241
+ }
242
+ result.headers.push([name, value === "" && !semicolon ? null : value]);
243
+ }
244
+ function parseArguments(args, limits) {
245
+ const result = {
246
+ urls: [],
247
+ data: [],
248
+ headers: [],
249
+ include: false,
250
+ head: false,
251
+ get: false,
252
+ location: false,
253
+ remoteName: false,
254
+ fail: false,
255
+ failWithBody: false,
256
+ silent: false,
257
+ showError: false,
258
+ verbose: false,
259
+ globoff: false,
260
+ help: false,
261
+ version: false,
262
+ retries: 0,
263
+ retryDelayMs: 0,
264
+ maxTimeMs: limits.maxTimeMs,
265
+ maxRedirects: limits.maxRedirects,
266
+ maxFileSize: limits.maxDownloadBytes
267
+ };
268
+ const apply = (option, value) => {
269
+ switch (option) {
270
+ case "request":
271
+ if (!value || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(value) || ["CONNECT", "TRACE"].includes(value.toUpperCase())) {
272
+ throw new CurlError(2, "Invalid or unsupported HTTP method");
273
+ }
274
+ result.method = value;
275
+ break;
276
+ case "header":
277
+ addHeader(result, value);
278
+ break;
279
+ case "user-agent":
280
+ addHeader(result, `User-Agent: ${value}`);
281
+ break;
282
+ case "referer":
283
+ addHeader(result, `Referer: ${value}`);
284
+ break;
285
+ case "user":
286
+ if (!value.includes(":")) throw new CurlError(2, "Basic authentication requires user:password; prompting is unsupported");
287
+ result.user = value;
288
+ break;
289
+ case "oauth2-bearer":
290
+ result.bearer = value;
291
+ break;
292
+ case "data":
293
+ case "data-ascii":
294
+ result.data.push({ kind: "data", value });
295
+ break;
296
+ case "data-raw":
297
+ result.data.push({ kind: "raw", value });
298
+ break;
299
+ case "data-binary":
300
+ result.data.push({ kind: "binary", value });
301
+ break;
302
+ case "data-urlencode":
303
+ result.data.push({ kind: "urlencode", value });
304
+ break;
305
+ case "json":
306
+ case "form":
307
+ case "form-string":
308
+ result.data.push({ kind: option, value });
309
+ break;
310
+ case "output":
311
+ result.output = value;
312
+ result.remoteName = false;
313
+ break;
314
+ case "remote-name":
315
+ result.remoteName = true;
316
+ delete result.output;
317
+ break;
318
+ case "dump-header":
319
+ result.dumpHeader = value;
320
+ break;
321
+ case "write-out":
322
+ result.writeOut = value;
323
+ break;
324
+ case "upload-file":
325
+ result.upload = value;
326
+ break;
327
+ case "url":
328
+ result.urls.push(value);
329
+ break;
330
+ case "max-time": {
331
+ const milliseconds = number(value) * 1e3;
332
+ result.maxTimeMs = milliseconds === 0 ? limits.maxTimeMs : Math.min(milliseconds, limits.maxTimeMs);
333
+ break;
334
+ }
335
+ case "max-filesize":
336
+ result.maxFileSize = Math.min(number(value, true), limits.maxDownloadBytes);
337
+ break;
338
+ case "max-redirs":
339
+ result.maxRedirects = Math.min(number(value, true), limits.maxRedirects);
340
+ break;
341
+ case "retry":
342
+ result.retries = Math.min(number(value, true), limits.maxRetries);
343
+ break;
344
+ case "retry-delay":
345
+ result.retryDelayMs = Math.min(number(value) * 1e3, limits.maxTimeMs);
346
+ break;
347
+ case "location":
348
+ result.location = true;
349
+ break;
350
+ case "head":
351
+ result.head = true;
352
+ break;
353
+ case "include":
354
+ case "show-headers":
355
+ result.include = true;
356
+ break;
357
+ case "get":
358
+ result.get = true;
359
+ break;
360
+ case "fail":
361
+ result.fail = true;
362
+ break;
363
+ case "fail-with-body":
364
+ result.failWithBody = true;
365
+ break;
366
+ case "silent":
367
+ result.silent = true;
368
+ break;
369
+ case "show-error":
370
+ result.showError = true;
371
+ break;
372
+ case "verbose":
373
+ result.verbose = true;
374
+ break;
375
+ case "globoff":
376
+ result.globoff = true;
377
+ break;
378
+ case "help":
379
+ result.help = true;
380
+ break;
381
+ case "version":
382
+ result.version = true;
383
+ break;
384
+ case "disable":
385
+ case "no-buffer":
386
+ case "no-progress-meter":
387
+ case "basic":
388
+ break;
389
+ default:
390
+ throw new CurlError(2, "Unsupported curl option");
391
+ }
392
+ };
393
+ let ended = false;
394
+ for (let index = 0; index < args.length; index++) {
395
+ const argument = args[index];
396
+ if (ended || !argument.startsWith("-") || argument === "-") {
397
+ result.urls.push(argument);
398
+ continue;
399
+ }
400
+ if (argument === "--") {
401
+ ended = true;
402
+ continue;
403
+ }
404
+ if (argument.startsWith("--")) {
405
+ const equals = argument.indexOf("=");
406
+ const name = argument.slice(2, equals < 0 ? void 0 : equals);
407
+ let value = equals < 0 ? void 0 : argument.slice(equals + 1);
408
+ if (longValues.has(name)) {
409
+ value ??= args[++index];
410
+ if (value === void 0) throw new CurlError(2, "Option requires an argument");
411
+ } else if (value !== void 0) throw new CurlError(2, "Unexpected option argument");
412
+ apply(name, value);
413
+ } else {
414
+ for (let offset = 1; offset < argument.length; offset++) {
415
+ const name = argument[offset];
416
+ if (values[name]) {
417
+ const value = argument.slice(offset + 1) || args[++index];
418
+ if (value === void 0) throw new CurlError(2, "Option requires an argument");
419
+ apply(values[name], value);
420
+ break;
421
+ }
422
+ if (!flags[name]) throw new CurlError(2, "Unsupported curl option");
423
+ apply(flags[name]);
424
+ }
425
+ }
426
+ }
427
+ if (!result.help && !result.version && !result.urls.length) throw new CurlError(2, "No URL specified");
428
+ if (result.urls.length > limits.maxUrls) throw new CurlError(2, "URL count exceeds host limit");
429
+ if (result.fail && result.failWithBody) throw new CurlError(2, "--fail and --fail-with-body are mutually exclusive");
430
+ const form = result.data.some((part) => part.kind === "form" || part.kind === "form-string");
431
+ if (result.upload !== void 0 && result.data.length || form && result.data.some((part) => !part.kind.startsWith("form")) || result.get && (form || result.upload !== void 0) || result.head && (result.upload !== void 0 || result.data.length > 0) && !result.get) {
432
+ throw new CurlError(2, "Incompatible request body options");
433
+ }
434
+ if (result.data.some((part) => part.kind === "json") && result.data.some((part) => part.kind !== "json")) {
435
+ throw new CurlError(2, "Mixing JSON and other data modes is unsupported");
436
+ }
437
+ return result;
438
+ }
439
+
440
+ // packages/safe-bash/src/commands/network/body.ts
441
+ init_platform();
442
+ function percent(bytes) {
443
+ let output = "";
444
+ for (const byte of bytes) output += byte >= 65 && byte <= 90 || byte >= 97 && byte <= 122 || byte >= 48 && byte <= 57 || [45, 46, 95, 126].includes(byte) ? String.fromCharCode(byte) : byte === 32 ? "+" : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
445
+ return encode(output);
446
+ }
447
+ function dataPart(argument) {
448
+ const value = argument.value;
449
+ if (argument.kind === "urlencode") {
450
+ const equals = value.indexOf("=");
451
+ if (equals >= 0) return [{ bytes: encode(equals ? `${value.slice(0, equals)}=` : "") }, { bytes: encode(value.slice(equals + 1)), urlencode: true }];
452
+ const at = value.indexOf("@");
453
+ if (at >= 0) return [{ bytes: encode(at ? `${value.slice(0, at)}=` : "") }, { file: value.slice(at + 1), urlencode: true }];
454
+ return [{ bytes: encode(value), urlencode: true }];
455
+ }
456
+ if (argument.kind !== "raw" && value.startsWith("@")) return [{ file: value.slice(1), strip: argument.kind === "data" }];
457
+ return [{ bytes: encode(value) }];
458
+ }
459
+ function quoted(value) {
460
+ if (/[\r\n\0]/.test(value)) throw new CurlError(2, "Invalid multipart field metadata");
461
+ return value.replace(/["\\]/g, "\\$&");
462
+ }
463
+ function multipart(argument, boundary) {
464
+ const equals = argument.value.indexOf("=");
465
+ if (equals < 1) throw new CurlError(2, "Multipart form requires name=value");
466
+ const name = quoted(argument.value.slice(0, equals));
467
+ let value = argument.value.slice(equals + 1);
468
+ let type;
469
+ let filename;
470
+ if (argument.kind === "form") {
471
+ const fields = value.split(";");
472
+ value = fields.shift();
473
+ for (const field of fields) {
474
+ if (field.startsWith("type=")) type = field.slice(5);
475
+ else if (field.startsWith("filename=")) filename = field.slice(9);
476
+ else throw new CurlError(2, "Unsupported multipart form attribute");
477
+ }
478
+ }
479
+ const isFile = argument.kind === "form" && /^[<@]/.test(value);
480
+ if (isFile && (value.slice(1).includes(",") || !value.slice(1))) throw new CurlError(2, "Unsupported multipart file list");
481
+ if (isFile && value.startsWith("@")) filename ??= posixPath.basename(value.slice(1));
482
+ if (type !== void 0 && !/^[\w!#$&^_.+-]+\/[\w!#$&^_.+-]+$/.test(type)) throw new CurlError(2, "Invalid multipart content type");
483
+ let preamble = `--${boundary}\r
484
+ Content-Disposition: form-data; name="${name}"`;
485
+ if (filename !== void 0) preamble += `; filename="${quoted(filename)}"`;
486
+ preamble += "\r\n";
487
+ if (type || filename !== void 0) preamble += `Content-Type: ${type ?? "application/octet-stream"}\r
488
+ `;
489
+ preamble += "\r\n";
490
+ return [{ bytes: encode(preamble) }, isFile ? { file: value.slice(1) } : { bytes: encode(value) }, { bytes: encode("\r\n") }];
491
+ }
492
+ function createBody(context, args, limits) {
493
+ if (!args.data.length && args.upload === void 0) return void 0;
494
+ const parts = [];
495
+ let contentType;
496
+ const form = args.data.some((part) => part.kind.startsWith("form"));
497
+ if (form) {
498
+ const boundary = `virtual-bash-${randomBytes(18).toString("hex")}`;
499
+ contentType = `multipart/form-data; boundary=${boundary}`;
500
+ for (const argument of args.data) parts.push(...multipart(argument, boundary));
501
+ parts.push({ bytes: encode(`--${boundary}--\r
502
+ `) });
503
+ } else if (args.upload !== void 0) parts.push({ file: args.upload });
504
+ else {
505
+ const json = args.data[0]?.kind === "json";
506
+ contentType = json ? "application/json" : "application/x-www-form-urlencoded";
507
+ args.data.forEach((argument, index) => {
508
+ if (index && !json) parts.push({ bytes: encode("&") });
509
+ parts.push(...dataPart(argument));
510
+ });
511
+ }
512
+ const hasStdin = parts.some((part) => part.file === "-");
513
+ let opened = false;
514
+ let replayComplete = false;
515
+ let replayable = true;
516
+ let cachedBytes = 0;
517
+ let cache = [];
518
+ let stdinUsed = false;
519
+ const source = async function* (part, signal) {
520
+ if (part.bytes !== void 0) {
521
+ yield part.bytes;
522
+ return;
523
+ }
524
+ if (part.file === "-") {
525
+ if (!stdinUsed) {
526
+ stdinUsed = true;
527
+ yield* readBytes(context.stdin, signal);
528
+ }
529
+ return;
530
+ }
531
+ try {
532
+ const path = pathOf(context, part.file);
533
+ const capabilities = await context.fs.capabilitiesFor?.(path, { signal }) ?? context.fs.capabilities;
534
+ signal.throwIfAborted();
535
+ if (context.fs.readStream && capabilities.streamingRead !== false) yield* readBytes(context.fs.readStream(path, { signal }), signal);
536
+ else yield await context.fs.readFile(path, { signal, maxBytes: Math.min(limits.maxBufferBytes, limits.maxUploadBytes) });
537
+ } catch (error) {
538
+ signal.throwIfAborted();
539
+ if (error instanceof CurlError) throw error;
540
+ throw new CurlError(26, "Failed to read virtual upload file");
541
+ }
542
+ };
543
+ return {
544
+ ...contentType === void 0 ? {} : { contentType },
545
+ open(signal) {
546
+ return (async function* () {
547
+ if (hasStdin && opened) {
548
+ if (!replayComplete || !replayable) throw new CurlError(65, "Cannot replay stdin upload within the host buffer limit");
549
+ for (const chunk of cache) {
550
+ signal.throwIfAborted();
551
+ yield chunk.slice();
552
+ }
553
+ return;
554
+ }
555
+ opened = true;
556
+ let count = 0;
557
+ let chunks = 0;
558
+ for (const part of parts) for await (const raw of source(part, signal)) {
559
+ if (++chunks % 256 === 0) await yieldTurn(signal);
560
+ for (let offset = 0; offset < raw.length; offset += 16 * 1024) {
561
+ signal.throwIfAborted();
562
+ let chunk = raw.subarray(offset, offset + 16 * 1024);
563
+ if (part.strip) chunk = chunk.filter((byte) => byte !== 0 && byte !== 10 && byte !== 13);
564
+ if (part.urlencode) chunk = percent(chunk);
565
+ count += chunk.length;
566
+ if (count > limits.maxUploadBytes) throw new CurlError(63, "Upload exceeds host byte limit");
567
+ if (hasStdin && replayable) {
568
+ cachedBytes += chunk.length;
569
+ if (cachedBytes > limits.maxBufferBytes) {
570
+ replayable = false;
571
+ cache = [];
572
+ } else cache.push(new Uint8Array(chunk));
573
+ }
574
+ if (chunk.length) yield chunk;
575
+ }
576
+ }
577
+ replayComplete = true;
578
+ })();
579
+ }
580
+ };
581
+ }
582
+ async function queryData(body, signal, limits) {
583
+ try {
584
+ return import_buffer.Buffer.from(await collectBytes(body.open(signal), { signal, maxBytes: limits.maxBufferBytes })).toString("utf8");
585
+ } catch (error) {
586
+ signal.throwIfAborted();
587
+ if (error instanceof CurlError) throw error;
588
+ throw new CurlError(63, "Query data exceeds host buffer limit");
589
+ }
590
+ }
591
+
592
+ // packages/safe-bash/src/commands/network/output.ts
593
+ init_platform();
594
+
595
+ // packages/safe-bash/src/contracts/filesystem-output.ts
596
+ init_platform();
597
+ var filesystemOutputBudgets = /* @__PURE__ */ new WeakMap();
598
+ function bindFileOutputBudget(context, budget) {
599
+ if (!context.registerCleanup) throw new TypeError("Shell output budgets require invocation cleanup ownership");
600
+ filesystemOutputBudgets.set(context.registerCleanup, budget);
601
+ }
602
+ async function writeFileOutput(context, bytes, write) {
603
+ context.signal.throwIfAborted();
604
+ const budget = context.registerCleanup && filesystemOutputBudgets.get(context.registerCleanup);
605
+ let pending;
606
+ const destination = { write(chunk) {
607
+ context.signal.throwIfAborted();
608
+ return pending = (async () => {
609
+ await write(chunk);
610
+ })();
611
+ } };
612
+ try {
613
+ await (budget?.(destination) ?? destination).write(bytes);
614
+ } catch (error) {
615
+ await pending?.catch(() => {
616
+ });
617
+ context.signal.throwIfAborted();
618
+ throw error;
619
+ }
620
+ context.signal.throwIfAborted();
621
+ }
622
+ async function openFileOutput(context, path, flag, incremental) {
623
+ let pipe;
624
+ let task;
625
+ let completed = false;
626
+ let ended = false;
627
+ let closing = false;
628
+ let failure;
629
+ const consumer = new AbortController();
630
+ let writes = Promise.resolve();
631
+ let acknowledge;
632
+ const acknowledgeWrite = () => {
633
+ const accepted = acknowledge;
634
+ acknowledge = void 0;
635
+ accepted?.();
636
+ };
637
+ let ready;
638
+ const opened = new Promise((resolve) => {
639
+ ready = resolve;
640
+ });
641
+ const destination = {
642
+ [outputFailure]: (reason) => operation.abort(reason),
643
+ async write(chunk) {
644
+ if (closing) throw new FsError("EBADF", { path, syscall: "write" });
645
+ const writing = writes.then(async () => {
646
+ for (let offset = 0; offset < chunk.byteLength; offset += 64 * 1024) {
647
+ const accepted = new Promise((resolve) => {
648
+ acknowledge = resolve;
649
+ });
650
+ await pipe.writable.write(chunk.subarray(offset, offset + 64 * 1024));
651
+ await accepted;
652
+ if (failure) throw failure.reason;
653
+ operation.signal.throwIfAborted();
654
+ }
655
+ });
656
+ writes = writing.catch(() => {
657
+ });
658
+ await writing;
659
+ }
660
+ };
661
+ const budget = context.registerCleanup && filesystemOutputBudgets.get(context.registerCleanup);
662
+ const operation = createOutputOperation(context, budget?.(destination) ?? destination);
663
+ operation.registerCleanup(async () => {
664
+ closing = true;
665
+ if (!completed) {
666
+ void operation.abort(operation.signal.aborted ? operation.signal.reason : new FsError("ECANCELED", { path, syscall: "write" }));
667
+ await pipe?.abort(operation.signal.reason);
668
+ }
669
+ await task?.catch(() => {
670
+ });
671
+ await writes;
672
+ });
673
+ try {
674
+ pipe = createBytePipe({ highWaterMark: 1, signal: operation.signal });
675
+ let reading = false;
676
+ const source = {
677
+ [Symbol.asyncIterator]() {
678
+ return (async function* () {
679
+ reading = true;
680
+ ready();
681
+ for await (const chunk of pipe.readable) {
682
+ yield chunk;
683
+ acknowledgeWrite();
684
+ }
685
+ operation.signal.throwIfAborted();
686
+ ended = true;
687
+ })();
688
+ }
689
+ };
690
+ task = (async () => {
691
+ const { fs } = context;
692
+ const signal = operation.signal;
693
+ signal.throwIfAborted();
694
+ const capabilities = await fs.capabilitiesFor?.(path, { signal }) ?? fs.capabilities;
695
+ if (capabilities.readOnly === true) throw new FsError("EROFS", { path, syscall: "write" });
696
+ try {
697
+ await fs.access(path, 2, { signal });
698
+ } catch (error) {
699
+ signal.throwIfAborted();
700
+ if (!(error instanceof FsError) || error.code !== "ENOENT" && error.code !== "ENOTSUP") throw error;
701
+ }
702
+ signal.throwIfAborted();
703
+ const streaming = flag === "a" ? capabilities.streamingAppend ?? capabilities.streamingWrite : capabilities.streamingWrite;
704
+ if ((!incremental || capabilities.descriptorWriteStream === true) && streaming !== false && fs.writeStream) {
705
+ try {
706
+ await fs.writeStream(path, source, { flag, signal });
707
+ if (!ended) throw new FsError("EIO", { path, message: "Streaming writer returned before consuming output" });
708
+ return;
709
+ } catch (error) {
710
+ signal.throwIfAborted();
711
+ if (reading || !(error instanceof FsError) || error.code !== "ENOTSUP") throw error;
712
+ }
713
+ }
714
+ if (flag === "w" && capabilities.write === false) throw new FsError("ENOTSUP", { path, syscall: "writeFile" });
715
+ if ((!incremental || flag === "a") && capabilities.append === false) throw new FsError("ENOTSUP", { path, syscall: "appendFile" });
716
+ const sink = incremental ? await incremental() : await (async () => {
717
+ if (flag === "a") await fs.appendFile(path, new Uint8Array(), { signal });
718
+ else await fs.writeFile(path, new Uint8Array(), { flag, signal });
719
+ return { write: (chunk) => fs.appendFile(path, chunk, { signal }) };
720
+ })();
721
+ for await (const chunk of source) {
722
+ signal.throwIfAborted();
723
+ await sink.write(chunk);
724
+ }
725
+ })();
726
+ void task.then(acknowledgeWrite, (error) => {
727
+ failure = { reason: error };
728
+ acknowledgeWrite();
729
+ if (!operation.signal.aborted) consumer.abort(error);
730
+ void operation.abort(error).catch(() => {
731
+ });
732
+ });
733
+ await Promise.race([opened, task]);
734
+ operation.signal.throwIfAborted();
735
+ const write = async (chunk) => {
736
+ try {
737
+ await operation.output.write(chunk);
738
+ } catch (error) {
739
+ throw failure ? failure.reason : error;
740
+ }
741
+ };
742
+ return {
743
+ signal: operation.signal,
744
+ sink: {
745
+ [outputFailure]: destination[outputFailure],
746
+ ownedOutput: { consumerClosed: consumer.signal, write },
747
+ write
748
+ },
749
+ async finish() {
750
+ closing = true;
751
+ try {
752
+ await writes;
753
+ await pipe.close();
754
+ await task;
755
+ operation.signal.throwIfAborted();
756
+ completed = true;
757
+ } catch (error) {
758
+ throw failure ? failure.reason : error;
759
+ } finally {
760
+ await operation.close();
761
+ }
762
+ },
763
+ abort: (reason) => operation.abort(reason)
764
+ };
765
+ } catch (error) {
766
+ await operation.abort(error);
767
+ throw error;
768
+ }
769
+ }
770
+
771
+ // packages/safe-bash/src/commands/network/output.ts
772
+ function responseHeaders(response, maxBytes) {
773
+ if (!Number.isInteger(response.status) || response.status < 100 || response.status > 599 || /[\r\n]/.test(response.statusText)) {
774
+ throw new CurlError(56, "Invalid HTTP response status");
775
+ }
776
+ const version = response.httpVersion ?? "1.1";
777
+ if (!/^\d(?:\.\d)?$/.test(version)) throw new CurlError(56, "Invalid HTTP response version");
778
+ let text = `HTTP/${version} ${response.status} ${response.statusText}\r
779
+ `;
780
+ for (const [name, value] of response.headers) {
781
+ if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name) || /[\r\n\0]/.test(value)) throw new CurlError(56, "Invalid HTTP response header");
782
+ text += `${name}: ${value}\r
783
+ `;
784
+ if (import_buffer.Buffer.byteLength(text, "latin1") > maxBytes) throw new CurlError(63, "Response headers exceed host byte limit");
785
+ }
786
+ return new Uint8Array(import_buffer.Buffer.from(`${text}\r
787
+ `, "latin1"));
788
+ }
789
+ async function writeOutput(context, path, source, signal) {
790
+ if (path === void 0 || path === "-") {
791
+ try {
792
+ for await (const chunk of readBytes(source, signal)) {
793
+ try {
794
+ await writeBytes(context.stdout, chunk, signal);
795
+ } catch {
796
+ signal.throwIfAborted();
797
+ throw new CurlError(23, "Failed writing output");
798
+ }
799
+ }
800
+ } catch (error) {
801
+ await context.stdout[outputFailure]?.(error);
802
+ throw error;
803
+ }
804
+ return;
805
+ }
806
+ try {
807
+ const target = await openFileOutput({ ...context, signal }, pathOf(context, path), "w");
808
+ try {
809
+ for await (const chunk of readBytes(source, target.signal)) await target.sink.write(chunk);
810
+ await target.finish();
811
+ } catch (error) {
812
+ await target.abort(error);
813
+ throw error;
814
+ }
815
+ } catch (error) {
816
+ signal.throwIfAborted();
817
+ if (error instanceof CurlError) throw error;
818
+ throw new CurlError(23, "Failed writing virtual output file");
819
+ }
820
+ }
821
+ async function dumpHeaders(context, path, bytes, append, signal) {
822
+ try {
823
+ if (path === "-") await writeBytes(context.stdout, bytes, signal);
824
+ else {
825
+ const target = await openFileOutput({ ...context, signal }, pathOf(context, path), append ? "a" : "w");
826
+ try {
827
+ await target.sink.write(bytes);
828
+ await target.finish();
829
+ } catch (error) {
830
+ await target.abort(error);
831
+ throw error;
832
+ }
833
+ }
834
+ } catch {
835
+ signal.throwIfAborted();
836
+ throw new CurlError(23, "Failed writing response headers");
837
+ }
838
+ }
839
+ function writeOutFormat(format, values2) {
840
+ let result = "";
841
+ for (let index = 0; index < format.length; index++) {
842
+ const character = format[index];
843
+ if (character === "\\") {
844
+ const next = format[++index];
845
+ result += next === "n" ? "\n" : next === "r" ? "\r" : next === "t" ? " " : next === void 0 ? "\\" : `\\${next}`;
846
+ } else if (character === "%" && format[index + 1] === "%") {
847
+ result += "%";
848
+ index++;
849
+ } else if (character === "%" && format[index + 1] === "{") {
850
+ const end = format.indexOf("}", index + 2);
851
+ if (end < 0) throw new CurlError(2, "Invalid write-out format");
852
+ const name = format.slice(index + 2, end);
853
+ if (!Object.hasOwn(values2, name)) throw new CurlError(2, "Unsupported write-out variable");
854
+ result += values2[name];
855
+ index = end;
856
+ } else result += character;
857
+ }
858
+ return encode(result);
859
+ }
860
+
861
+ // packages/safe-bash/src/commands/network/curl.ts
862
+ var retryStatuses = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
863
+ var redirectStatuses = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
864
+ var writeOutDefaults = Object.freeze({
865
+ http_code: "000",
866
+ response_code: "000",
867
+ url_effective: "",
868
+ redirect_url: "",
869
+ content_type: "",
870
+ size_download: "0",
871
+ size_upload: "0",
872
+ num_redirects: "0",
873
+ num_retries: "0",
874
+ time_total: "0.000000",
875
+ exitcode: "0",
876
+ errormsg: "",
877
+ filename_effective: "",
878
+ method: "GET",
879
+ http_version: ""
880
+ });
881
+ function parseUrl(text, globoff, redirect = false) {
882
+ if (/[\s\x00-\x1f\x7f]/.test(text)) throw new CurlError(3, "Malformed URL");
883
+ let url;
884
+ try {
885
+ url = new URL(text);
886
+ } catch {
887
+ throw new CurlError(3, "Malformed URL; explicit HTTP(S) scheme required");
888
+ }
889
+ if (!["http:", "https:"].includes(url.protocol)) throw new CurlError(1, "Only HTTP and HTTPS are supported");
890
+ if (!url.hostname) throw new CurlError(3, "Malformed URL");
891
+ if (!globoff && /[{}\[\]]/.test(url.pathname + url.search)) throw new CurlError(2, "URL glob expansion is unsupported; use --globoff for a literal URL");
892
+ let user;
893
+ if (url.username || url.password) {
894
+ if (redirect) throw new CurlError(3, "Redirect URLs may not supply credentials");
895
+ try {
896
+ user = `${decodeURIComponent(url.username)}:${decodeURIComponent(url.password)}`;
897
+ } catch {
898
+ throw new CurlError(3, "Malformed URL credentials");
899
+ }
900
+ url.username = "";
901
+ url.password = "";
902
+ }
903
+ url.hash = "";
904
+ return { url, ...user === void 0 ? {} : { user } };
905
+ }
906
+ function requestHeaders(args, contentType, user, scoped, maxBytes) {
907
+ const defaults = [["Accept", args.data[0]?.kind === "json" ? "application/json" : "*/*"], ["User-Agent", args.agent ?? "virtual-bash-curl/0.0"]];
908
+ if (contentType !== void 0) defaults.push(["Content-Type", contentType]);
909
+ if (scoped && user !== void 0) defaults.push(["Authorization", `Basic ${import_buffer.Buffer.from(user).toString("base64")}`]);
910
+ if (scoped && args.bearer !== void 0) {
911
+ if (/[\r\n\0]/.test(args.bearer)) throw new CurlError(2, "Invalid bearer token");
912
+ defaults.push(["Authorization", `Bearer ${args.bearer}`]);
913
+ }
914
+ const custom = scoped ? args.headers : [];
915
+ const names = new Set(custom.map(([name]) => name.toLowerCase()));
916
+ const result = [
917
+ ...defaults.filter(([name]) => !names.has(name.toLowerCase())),
918
+ ...custom.filter((entry) => entry[1] !== null)
919
+ ];
920
+ if (result.reduce((size, [name, value]) => size + import_buffer.Buffer.byteLength(name + value) + 4, 0) > maxBytes) {
921
+ throw new CurlError(63, "Request headers exceed host byte limit");
922
+ }
923
+ return result;
924
+ }
925
+ async function stop(response, signal) {
926
+ if (!response) return;
927
+ const cleanup = Promise.resolve().then(() => response.dispose());
928
+ void cleanup.catch(() => {
929
+ });
930
+ if (!signal.aborted) await withSignal(() => cleanup, signal).catch(() => {
931
+ });
932
+ }
933
+ function pipeClosed(error) {
934
+ return error instanceof Error && "code" in error && error.code === "EPIPE";
935
+ }
936
+ function remoteFilename(url) {
937
+ const name = posixPath.basename(url.pathname);
938
+ if (!name || name === "/" || name === "." || name === "..") throw new CurlError(23, "URL has no safe remote filename");
939
+ return name;
940
+ }
941
+ function createCurlCommand(options) {
942
+ return createTransferCommand(options, {
943
+ name: "curl",
944
+ help: "Usage: curl [HTTP(S) URL] [-X METHOD] [-H HEADER] [-d DATA] [-L] [-o VFSFILE]\nExplicit host authorization is required. See network/README.md for supported flags and limits.\n",
945
+ version: "virtual-bash curl 0.0 (HTTP HTTPS; Node streaming transport)\n",
946
+ parse: (context, limits) => parseArguments(context.args, limits),
947
+ status: (code) => code
948
+ });
949
+ }
950
+ function createTransferCommand(options, profile) {
951
+ if (typeof options?.authorize !== "function") throw new TypeError(`${profile.name} requires an explicit network authorizer`);
952
+ const limits = limitsFor(options.limits);
953
+ const transport = options.transport ?? createDefaultHttpTransport({ maxHeaderBytes: limits.maxHeaderBytes });
954
+ if (typeof transport !== "function") throw new TypeError("Invalid HTTP transport");
955
+ const authorize = options.authorize;
956
+ const executions = /* @__PURE__ */ new WeakMap();
957
+ return {
958
+ name: profile.name,
959
+ async execute(context) {
960
+ context.signal.throwIfAborted();
961
+ let args;
962
+ try {
963
+ if (context.args.reduce((size, value) => size + import_buffer.Buffer.byteLength(value), 0) > limits.maxBufferBytes) throw new CurlError(2, "Arguments exceed host buffer limit");
964
+ args = await profile.parse(context, limits);
965
+ if (args.help || args.version) {
966
+ await writeBytes(context.stdout, encode(args.version ? profile.version : profile.help), context.signal);
967
+ return { exitCode: 0 };
968
+ }
969
+ for (const url of args.urls) parseUrl(url, args.globoff);
970
+ if (args.urls.length > 1 && (args.output !== void 0 || args.remoteName || args.dumpHeader !== void 0)) {
971
+ throw new CurlError(2, "Multiple URLs with file/header outputs are unsupported");
972
+ }
973
+ } catch (error) {
974
+ context.signal.throwIfAborted();
975
+ const failure = error instanceof CurlError ? error : new CurlError(2, `Invalid ${profile.name} arguments`);
976
+ await diagnostic(context, new CurlError(profile.status(failure.exitCode), failure.message));
977
+ return { exitCode: profile.status(failure.exitCode) };
978
+ }
979
+ const scope = context.executionScope ?? {};
980
+ let started = executions.get(scope);
981
+ if (started === void 0) {
982
+ started = performance.now();
983
+ executions.set(scope, started);
984
+ }
985
+ let exitCode = 0;
986
+ for (const url of args.urls) {
987
+ context.signal.throwIfAborted();
988
+ if (performance.now() - started >= limits.maxTotalTimeMs) {
989
+ const failure = new CurlError(28, "Operation timed out");
990
+ if (!args.silent || args.showError) {
991
+ try {
992
+ await deadlineDiagnostic(context, failure, 0);
993
+ } catch (error) {
994
+ context.signal.throwIfAborted();
995
+ if (!(error instanceof CurlError)) throw error;
996
+ }
997
+ }
998
+ return { exitCode: profile.status(failure.exitCode) };
999
+ }
1000
+ exitCode = await transfer(context, args, url, limits, transport, authorize, started, profile.status);
1001
+ }
1002
+ return { exitCode };
1003
+ }
1004
+ };
1005
+ }
1006
+ async function transfer(context, args, input, limits, transport, authorize, started, status) {
1007
+ const start = performance.now();
1008
+ const remaining = () => Math.min(args.maxTimeMs - (performance.now() - start), limits.maxTotalTimeMs - (performance.now() - started));
1009
+ const hasFileOutput = args.remoteName || args.output !== void 0 && args.output !== "-" || args.dumpHeader !== void 0 && args.dumpHeader !== "-";
1010
+ const operation = createDeadlineOutput(context, hasFileOutput ? { write: (chunk) => context.stdout.write(chunk) } : context.stdout, remaining());
1011
+ const signal = operation.signal;
1012
+ const borrowed = context.stdout.ownedOutput ? { [Symbol.asyncIterator]() {
1013
+ const iterator = context.stdin[Symbol.asyncIterator]();
1014
+ return { next: () => iterator.next() };
1015
+ } } : context.stdin;
1016
+ let response;
1017
+ let failure;
1018
+ const values2 = { ...writeOutDefaults };
1019
+ let format = args.writeOut;
1020
+ let formatReady = false;
1021
+ let dumped = false;
1022
+ let downloaded = 0;
1023
+ let uploaded = 0;
1024
+ let included = [];
1025
+ let closedOutput = false;
1026
+ const publish = async (bytes) => {
1027
+ const writing = createDeadlineOutput(context, context.stdout, remaining());
1028
+ try {
1029
+ await writeBytes(writing.output, bytes, writing.signal);
1030
+ } catch (error) {
1031
+ context.signal.throwIfAborted();
1032
+ if (!pipeClosed(error)) throw error;
1033
+ closedOutput = true;
1034
+ } finally {
1035
+ await writing.close();
1036
+ }
1037
+ };
1038
+ try {
1039
+ if (format?.startsWith("@")) {
1040
+ try {
1041
+ const bytes = format === "@-" ? await collectBytes(borrowed, { signal, maxBytes: limits.maxBufferBytes }) : await withSignal(() => context.fs.readFile(pathOf(context, format.slice(1)), { signal, maxBytes: limits.maxBufferBytes }), signal);
1042
+ format = import_buffer.Buffer.from(bytes).toString("utf8");
1043
+ } catch {
1044
+ signal.throwIfAborted();
1045
+ throw new CurlError(26, "Failed reading write-out format");
1046
+ }
1047
+ }
1048
+ if (format !== void 0) {
1049
+ writeOutFormat(format, values2);
1050
+ formatReady = true;
1051
+ }
1052
+ const parsed = parseUrl(input, args.globoff);
1053
+ const initial = parsed.url;
1054
+ let body = createBody({ ...context, stdin: borrowed }, args, limits);
1055
+ if (args.get && body) {
1056
+ const query = await queryData(body, signal, limits);
1057
+ if (/[^\x21-\x7e]/.test(query)) throw new CurlError(3, "GET data must be URL encoded");
1058
+ initial.search += `${initial.search ? "&" : "?"}${query.replace(/%[0-9a-f]{2}/gi, (escape) => escape.toLowerCase())}`;
1059
+ body = void 0;
1060
+ }
1061
+ const output = args.remoteName ? args.directoryIndex && initial.pathname.endsWith("/") ? args.directoryIndex : remoteFilename(initial) : args.output;
1062
+ values2.filename_effective = output && output !== "-" ? output : "";
1063
+ if (output && output !== "-" && args.dumpHeader && args.dumpHeader !== "-" && normalizePath(pathOf(context, output)) === normalizePath(pathOf(context, args.dumpHeader))) {
1064
+ throw new CurlError(23, "Body and header output files must differ");
1065
+ }
1066
+ const initialMethod = args.method ?? (args.head ? "HEAD" : args.get ? "GET" : args.upload !== void 0 ? "PUT" : body ? "POST" : "GET");
1067
+ requestHeaders(args, body?.contentType, args.user ?? parsed.user, true, limits.maxHeaderBytes);
1068
+ attempts: for (let attempt = 0; attempt <= args.retries; attempt++) {
1069
+ values2.num_retries = String(attempt);
1070
+ downloaded = 0;
1071
+ failure = void 0;
1072
+ let current = new URL(initial);
1073
+ let method = initialMethod;
1074
+ let currentBody = body;
1075
+ let credentialsInScope = true;
1076
+ let previous;
1077
+ let redirects = 0;
1078
+ included = [];
1079
+ let headerBytes = 0;
1080
+ while (true) {
1081
+ signal.throwIfAborted();
1082
+ if (remaining() <= 0) throw new CurlError(28, "Operation timed out");
1083
+ values2.url_effective = current.href;
1084
+ values2.method = method;
1085
+ let denyPrivateNetworks = false;
1086
+ let allowed;
1087
+ try {
1088
+ allowed = await withSignal(() => authorize({
1089
+ url: current.href,
1090
+ method,
1091
+ attempt,
1092
+ signal,
1093
+ requirePrivateNetworkDeny() {
1094
+ denyPrivateNetworks = true;
1095
+ },
1096
+ ...previous === void 0 ? {} : { redirectFrom: previous }
1097
+ }), signal);
1098
+ } catch {
1099
+ signal.throwIfAborted();
1100
+ throw new CurlError(7, "Network authorization failed");
1101
+ }
1102
+ if (remaining() <= 0) throw new CurlError(28, "Operation timed out");
1103
+ if (allowed !== true) throw new CurlError(7, "Network access denied by host policy");
1104
+ const policy = denyPrivateNetworks ? { denyPrivateNetworks: true } : {};
1105
+ if (policy.denyPrivateNetworks && transport.supportsPrivateNetworkDeny !== true) {
1106
+ throw new CurlError(7, "Transport cannot enforce private network policy");
1107
+ }
1108
+ const headers = requestHeaders(args, currentBody?.contentType, args.user ?? parsed.user, credentialsInScope, limits.maxHeaderBytes);
1109
+ if (args.verbose) await writeBytes(context.stderr, encode(`> ${method} ${current.origin}
1110
+ ${headers.map(([name]) => `> ${name}: [redacted]
1111
+ `).join("")}`), signal);
1112
+ const upload = currentBody && (async function* () {
1113
+ for await (const chunk of currentBody.open(signal)) {
1114
+ uploaded += chunk.length;
1115
+ yield chunk;
1116
+ }
1117
+ })();
1118
+ try {
1119
+ response = await operation.acquire(async () => {
1120
+ const acquired = await transport({
1121
+ url: current.href,
1122
+ method,
1123
+ headers,
1124
+ signal,
1125
+ registerCleanup: operation.registerCleanup,
1126
+ ...policy,
1127
+ ...upload ? { body: upload } : {}
1128
+ });
1129
+ let cleanup;
1130
+ return { ...acquired, dispose() {
1131
+ cleanup ??= Promise.resolve().then(() => acquired.dispose());
1132
+ return cleanup;
1133
+ } };
1134
+ }, (result) => result.dispose());
1135
+ } catch (error) {
1136
+ signal.throwIfAborted();
1137
+ const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
1138
+ if (args.retryTransport && (code === "ECONNRESET" || code === "ETIMEDOUT" || code === "EPIPE") && attempt < args.retries) {
1139
+ await delay(args.retryDelayMs || Math.min(1e3 * 2 ** attempt, 6e5), signal);
1140
+ continue attempts;
1141
+ }
1142
+ throw error;
1143
+ }
1144
+ const block = responseHeaders(response, limits.maxHeaderBytes);
1145
+ headerBytes += block.length;
1146
+ if (headerBytes > limits.maxHeaderBytes) throw new CurlError(63, "Combined response headers exceed host byte limit");
1147
+ values2.http_code = values2.response_code = String(response.status).padStart(3, "0");
1148
+ values2.content_type = header(response.headers, "content-type") ?? "";
1149
+ values2.http_version = response.httpVersion ?? "1.1";
1150
+ if (args.verbose) await writeBytes(context.stderr, encode(`< HTTP ${response.status}
1151
+ `), signal);
1152
+ if (args.dumpHeader !== void 0) {
1153
+ if (args.dumpHeader === "-") await publish(block);
1154
+ else await dumpHeaders(context, args.dumpHeader, block, dumped, signal);
1155
+ dumped = true;
1156
+ }
1157
+ if (args.head || args.include) included.push(block);
1158
+ const location = header(response.headers, "location");
1159
+ if (redirectStatuses.has(response.status) && location !== void 0) {
1160
+ let target;
1161
+ try {
1162
+ target = parseUrl(new URL(location, current).href, true, true).url;
1163
+ } catch (error) {
1164
+ if (error instanceof CurlError) throw error;
1165
+ throw new CurlError(3, "Malformed redirect URL");
1166
+ }
1167
+ values2.redirect_url = target.href;
1168
+ if (args.location) {
1169
+ if (redirects++ >= args.maxRedirects) throw new CurlError(47, "Maximum redirects exceeded");
1170
+ if (current.protocol === "https:" && target.protocol === "http:") throw new CurlError(1, "HTTPS-to-HTTP redirects are disabled");
1171
+ if (target.origin !== current.origin) credentialsInScope = false;
1172
+ if (response.status === 303 && method !== "HEAD" || [301, 302].includes(response.status) && method === "POST") {
1173
+ currentBody = void 0;
1174
+ if (args.method === void 0) method = "GET";
1175
+ }
1176
+ previous = current.href;
1177
+ current = target;
1178
+ values2.num_redirects = String(redirects);
1179
+ await stop(response, signal);
1180
+ response = void 0;
1181
+ continue;
1182
+ }
1183
+ }
1184
+ break;
1185
+ }
1186
+ if (!response) throw new CurlError(56, "No HTTP response");
1187
+ if (response.status >= 400 && (args.fail || args.failWithBody)) failure = new CurlError(22, `HTTP response status ${response.status}`);
1188
+ const suppressBody = args.fail && failure !== void 0;
1189
+ let published = 0;
1190
+ if (!suppressBody || included.length) {
1191
+ const length = header(response.headers, "content-length");
1192
+ if (!args.head && !suppressBody && length && /^\d+$/.test(length) && Number(length) > args.maxFileSize) throw new CurlError(63, "Response exceeds download byte limit");
1193
+ const final = response;
1194
+ const writing = output === void 0 || output === "-" ? createOutputOperation({ ...context, signal }, context.stdout) : void 0;
1195
+ const bodySignal = writing?.signal ?? signal;
1196
+ const source = (async function* () {
1197
+ for (const bytes of included) {
1198
+ published += bytes.length;
1199
+ yield bytes;
1200
+ }
1201
+ if (!args.head && !suppressBody) {
1202
+ let chunks = 0;
1203
+ try {
1204
+ for await (const chunk of readBytes(final.body, bodySignal)) {
1205
+ if (++chunks % 256 === 0) {
1206
+ await yieldTurn(context.signal);
1207
+ bodySignal.throwIfAborted();
1208
+ }
1209
+ downloaded += chunk.length;
1210
+ if (downloaded > args.maxFileSize) throw new CurlError(63, "Response exceeds download byte limit");
1211
+ published += chunk.length;
1212
+ yield chunk;
1213
+ }
1214
+ if (length && /^\d+$/.test(length) && downloaded !== Number(length)) throw new CurlError(18, "Partial HTTP response body");
1215
+ } catch (error) {
1216
+ bodySignal.throwIfAborted();
1217
+ if (!(error instanceof CurlError) && length && /^\d+$/.test(length) && downloaded < Number(length)) throw new CurlError(18, "Partial HTTP response body");
1218
+ throw networkError(error);
1219
+ }
1220
+ }
1221
+ })();
1222
+ try {
1223
+ await writeOutput(writing ? { ...context, stdout: writing.output } : context, output, source, bodySignal);
1224
+ } catch (error) {
1225
+ context.signal.throwIfAborted();
1226
+ if (!pipeClosed(error)) throw error;
1227
+ closedOutput = true;
1228
+ } finally {
1229
+ await writing?.close();
1230
+ }
1231
+ }
1232
+ if (retryStatuses.has(response.status) && attempt < args.retries) {
1233
+ if (failure && (!args.silent || args.showError)) await deadlineDiagnostic(context, new CurlError(status(failure.exitCode), failure.message), remaining());
1234
+ const after = header(response.headers, "retry-after");
1235
+ let wait = args.retryDelayMs || Math.min(1e3 * 2 ** attempt, 6e5);
1236
+ if (after !== void 0) {
1237
+ const parsed2 = /^\d+$/.test(after) ? Number(after) * 1e3 : Date.parse(after) - Date.now();
1238
+ if (Number.isFinite(parsed2)) wait = Math.max(wait, parsed2);
1239
+ }
1240
+ await stop(response, signal);
1241
+ response = void 0;
1242
+ if (published && output !== void 0 && output !== "-") await writeOutput(context, output, toByteSource(""), signal);
1243
+ await delay(Math.min(wait, limits.maxTimeMs), signal);
1244
+ continue;
1245
+ }
1246
+ break;
1247
+ }
1248
+ } catch (error) {
1249
+ if (context.signal.aborted) throw context.signal.reason;
1250
+ if (pipeClosed(error)) closedOutput = true;
1251
+ else if (!hasFileOutput && context.stdout.ownedOutput?.consumerClosed.aborted) failure = new CurlError(23, "Failed writing output");
1252
+ else failure = signal.aborted && signal.reason instanceof CurlError ? signal.reason : networkError(error);
1253
+ } finally {
1254
+ try {
1255
+ await operation.close();
1256
+ } finally {
1257
+ context.signal.throwIfAborted();
1258
+ }
1259
+ }
1260
+ values2.size_download = String(downloaded);
1261
+ values2.size_upload = String(uploaded);
1262
+ values2.time_total = ((performance.now() - start) / 1e3).toFixed(6);
1263
+ values2.exitcode = String(failure?.exitCode ?? 0);
1264
+ values2.errormsg = failure?.message ?? "";
1265
+ if (format !== void 0 && formatReady) {
1266
+ try {
1267
+ await publish(writeOutFormat(format, values2));
1268
+ } catch (error) {
1269
+ context.signal.throwIfAborted();
1270
+ failure = error instanceof CurlError ? error : new CurlError(23, "Failed writing write-out result");
1271
+ }
1272
+ }
1273
+ if (failure && (!args.silent || args.showError)) {
1274
+ try {
1275
+ await deadlineDiagnostic(context, new CurlError(status(failure.exitCode), failure.message), remaining());
1276
+ } catch (error) {
1277
+ context.signal.throwIfAborted();
1278
+ if (!(error instanceof CurlError)) throw error;
1279
+ failure = error;
1280
+ }
1281
+ }
1282
+ return failure ? status(failure.exitCode) : closedOutput ? 141 : 0;
1283
+ }
1284
+
1285
+ // packages/safe-bash/src/commands/network/wget.ts
1286
+ async function parseWget(context, limits) {
1287
+ const carrier = getCommandArguments(context);
1288
+ let argumentBytes = 0;
1289
+ for (const value of carrier.values) {
1290
+ if (typeof value === "string" && value.length > limits.maxBufferBytes) throw new CurlError(2, "Arguments exceed host buffer limit");
1291
+ argumentBytes += shellValueByteLength(value);
1292
+ if (argumentBytes > limits.maxBufferBytes) throw new CurlError(2, "Arguments exceed host buffer limit");
1293
+ if (typeof value === "string") {
1294
+ for (let index = 0; index < value.length; index++) {
1295
+ if (index % 1024 === 0) await yieldTurn(context.signal);
1296
+ const code = value.charCodeAt(index);
1297
+ if (code >= 55296 && code <= 56319) {
1298
+ const next = value.charCodeAt(++index);
1299
+ if (!(next >= 56320 && next <= 57343)) throw new CurlError(2, "Arguments must be valid UTF-8");
1300
+ } else if (code >= 56320 && code <= 57343) throw new CurlError(2, "Arguments must be valid UTF-8");
1301
+ }
1302
+ continue;
1303
+ }
1304
+ const bytes = shellValueBytes(value);
1305
+ const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
1306
+ for (let offset = 0; offset < bytes.length; offset += 1024) {
1307
+ await yieldTurn(context.signal);
1308
+ try {
1309
+ decoder.decode(bytes.subarray(offset, offset + 1024), { stream: offset + 1024 < bytes.length });
1310
+ } catch (error) {
1311
+ context.signal.throwIfAborted();
1312
+ if (!(error instanceof TypeError) || "code" in error && error.code !== "ERR_ENCODING_INVALID_ENCODED_DATA") throw error;
1313
+ throw new CurlError(2, "Arguments must be valid UTF-8");
1314
+ }
1315
+ }
1316
+ }
1317
+ const result = {
1318
+ urls: [],
1319
+ data: [],
1320
+ headers: [],
1321
+ include: false,
1322
+ head: false,
1323
+ get: false,
1324
+ location: true,
1325
+ remoteName: true,
1326
+ fail: true,
1327
+ failWithBody: false,
1328
+ silent: false,
1329
+ showError: false,
1330
+ verbose: false,
1331
+ globoff: true,
1332
+ help: false,
1333
+ version: false,
1334
+ retries: Math.min(19, limits.maxRetries),
1335
+ retryDelayMs: 0,
1336
+ maxTimeMs: limits.maxTimeMs,
1337
+ maxRedirects: limits.maxRedirects,
1338
+ maxFileSize: limits.maxDownloadBytes,
1339
+ agent: "virtual-bash-wget/0.0",
1340
+ retryTransport: true,
1341
+ directoryIndex: "index.html"
1342
+ };
1343
+ const number2 = (value, integral) => {
1344
+ if (!(integral ? /^\d+$/u : /^\d+(?:\.\d+)?$/u).test(value)) throw new CurlError(2, "Invalid numeric option");
1345
+ const parsed = Number(value);
1346
+ if (!Number.isFinite(parsed) || parsed < 0 || parsed > Number.MAX_SAFE_INTEGER) throw new CurlError(2, "Invalid numeric option");
1347
+ return parsed;
1348
+ };
1349
+ let ended = false;
1350
+ for (let index = 0; index < context.args.length; index++) {
1351
+ if (index % 128 === 0) await yieldTurn(context.signal);
1352
+ const argument = context.args[index];
1353
+ if (ended || !argument.startsWith("-") || argument === "-") {
1354
+ result.urls.push(argument);
1355
+ continue;
1356
+ }
1357
+ if (argument === "--") {
1358
+ ended = true;
1359
+ continue;
1360
+ }
1361
+ if (!argument.startsWith("--")) {
1362
+ for (let position = 1; position < argument.length; position++) {
1363
+ if (position % 1024 === 0) await yieldTurn(context.signal);
1364
+ const flag2 = argument[position];
1365
+ if (flag2 === "q") result.silent = true;
1366
+ else if (flag2 === "n" && argument[position + 1] === "v") position++;
1367
+ else if (flag2 === "h") result.help = true;
1368
+ else if (flag2 === "r") throw new CurlError(2, "Recursive mirroring is unsupported");
1369
+ else if (flag2 === "O") {
1370
+ const output = position + 1 < argument.length ? argument.slice(position + 1) : context.args[++index];
1371
+ if (!output) throw new CurlError(2, "-O requires a nonempty output filename");
1372
+ result.output = output;
1373
+ result.remoteName = false;
1374
+ break;
1375
+ } else throw new CurlError(2, `Unsupported option: -${flag2}`);
1376
+ }
1377
+ continue;
1378
+ }
1379
+ if (argument === "--quiet") {
1380
+ result.silent = true;
1381
+ continue;
1382
+ }
1383
+ if (argument === "--no-verbose") continue;
1384
+ if (argument === "--help") {
1385
+ result.help = true;
1386
+ continue;
1387
+ }
1388
+ if (argument === "--version") {
1389
+ result.version = true;
1390
+ continue;
1391
+ }
1392
+ if (argument === "--recursive") throw new CurlError(2, "Recursive mirroring is unsupported");
1393
+ const equal = argument.indexOf("=");
1394
+ const flag = equal < 0 ? argument : argument.slice(0, equal);
1395
+ let operand;
1396
+ let option;
1397
+ if (["--output-document", "--timeout", "--tries"].includes(flag)) {
1398
+ option = flag === "--output-document" ? "output" : flag === "--timeout" ? "timeout" : "tries";
1399
+ operand = equal < 0 ? context.args[++index] : argument.slice(equal + 1);
1400
+ } else throw new CurlError(2, `Unsupported option: ${argument}`);
1401
+ if (operand === void 0) throw new CurlError(2, `${flag} requires an argument`);
1402
+ if (option === "output") {
1403
+ if (!operand) throw new CurlError(2, "Output filename must not be empty");
1404
+ result.output = operand;
1405
+ result.remoteName = false;
1406
+ } else if (option === "timeout") {
1407
+ const seconds = number2(operand, false);
1408
+ result.maxTimeMs = seconds === 0 ? limits.maxTimeMs : Math.min(seconds * 1e3, limits.maxTimeMs);
1409
+ } else {
1410
+ const tries = number2(operand, true);
1411
+ result.retries = tries === 0 ? limits.maxRetries : Math.min(tries - 1, limits.maxRetries);
1412
+ }
1413
+ }
1414
+ if (!result.help && !result.version && result.urls.length !== 1) throw new CurlError(2, "Exactly one HTTP(S) URL is required");
1415
+ return result;
1416
+ }
1417
+ function createWgetCommand(options) {
1418
+ return createTransferCommand(options, {
1419
+ name: "wget",
1420
+ parse: parseWget,
1421
+ help: "Usage: wget [-O FILE|-] [-q|-nv] [--timeout SECONDS] [--tries COUNT] URL\nVFS downloads require explicit host authorization. Recursive mirroring is unsupported.\nTimeout is aggregate and host-capped; --tries=0 remains host-capped.\n",
1422
+ version: "virtual-bash wget 0.0 (bounded HTTP HTTPS)\n",
1423
+ status: (code) => code === 0 ? 0 : [1, 2, 3].includes(code) ? 2 : [23, 26].includes(code) ? 3 : code === 60 ? 5 : code === 22 ? 8 : 4
1424
+ });
1425
+ }
1426
+
1427
+ // packages/safe-bash/src/commands/network/fetch-transport.ts
1428
+ init_platform();
1429
+ function requestBody(source, signal) {
1430
+ if (!source) return void 0;
1431
+ const iterator = source[Symbol.asyncIterator]();
1432
+ return new ReadableStream({
1433
+ async pull(controller) {
1434
+ try {
1435
+ signal.throwIfAborted();
1436
+ const next = await iterator.next();
1437
+ if (next.done) controller.close();
1438
+ else controller.enqueue(next.value);
1439
+ } catch (error) {
1440
+ controller.error(error);
1441
+ }
1442
+ },
1443
+ async cancel(reason) {
1444
+ await iterator.return?.(reason);
1445
+ }
1446
+ });
1447
+ }
1448
+ function createFetchTransport(options = {}) {
1449
+ const fetchRequest = options.fetch ?? globalThis.fetch;
1450
+ if (typeof fetchRequest !== "function") throw new TypeError("Fetch is unavailable");
1451
+ return async (input) => {
1452
+ input.signal.throwIfAborted();
1453
+ const url = new URL(input.url);
1454
+ if (url.protocol !== "http:" && url.protocol !== "https:") throw new CurlError(1, "Unsupported protocol");
1455
+ if (input.denyPrivateNetworks === true) throw new CurlError(7, "Fetch transport cannot enforce private-network denial");
1456
+ const stopped = new AbortController();
1457
+ const signal = AbortSignal.any([input.signal, stopped.signal]);
1458
+ const body = requestBody(input.body, signal);
1459
+ const headers = new Headers();
1460
+ for (const [name, value] of input.headers) headers.append(name, value);
1461
+ const request = new Request(url, {
1462
+ method: input.method,
1463
+ headers,
1464
+ body,
1465
+ credentials: "omit",
1466
+ redirect: "manual",
1467
+ signal,
1468
+ ...body ? { duplex: "half" } : {}
1469
+ });
1470
+ let response;
1471
+ const dispose = async () => {
1472
+ stopped.abort();
1473
+ if (response?.body) await response.body.cancel().catch(() => void 0);
1474
+ };
1475
+ input.registerCleanup?.(dispose);
1476
+ response = await fetchRequest(request);
1477
+ const reader = response.body?.getReader();
1478
+ const responseBody = reader ? (async function* () {
1479
+ try {
1480
+ while (true) {
1481
+ input.signal.throwIfAborted();
1482
+ const next = await reader.read();
1483
+ if (next.done) return;
1484
+ yield next.value;
1485
+ }
1486
+ } finally {
1487
+ reader.releaseLock();
1488
+ }
1489
+ })() : (async function* () {
1490
+ })();
1491
+ return {
1492
+ status: response.status,
1493
+ statusText: response.statusText,
1494
+ headers: [...response.headers.entries()],
1495
+ body: responseBody,
1496
+ dispose
1497
+ };
1498
+ };
1499
+ }
1500
+
1501
+ // packages/safe-bash/src/commands/network/authorizer.ts
1502
+ init_platform();
1503
+
1504
+ // packages/safe-bash/src/commands/network/private-address.ts
1505
+ init_platform();
1506
+ function privateIPv4(first, second) {
1507
+ return first === 10 || first === 127 || first === 0 || first === 169 && second === 254 || first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31 || first === 100 && second >= 64 && second <= 127 || first === 198 && second >= 18 && second <= 19 || first >= 224;
1508
+ }
1509
+ function privateHostname(input) {
1510
+ const hostname = input.toLowerCase().replace(/\.$/u, "").replace(/^\[|\]$/gu, "");
1511
+ if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname === "::1") return true;
1512
+ if (hostname.includes(":")) {
1513
+ const [prefix, suffix] = hostname.split("::");
1514
+ const leading = prefix ? prefix.split(":") : [];
1515
+ const trailing = suffix ? suffix.split(":") : [];
1516
+ const hextets = new Array(8).fill(0);
1517
+ for (let index = 0; index < leading.length; index++) hextets[index] = Number.parseInt(leading[index], 16);
1518
+ for (let index = 0; index < trailing.length; index++) hextets[8 - trailing.length + index] = Number.parseInt(trailing[index], 16);
1519
+ if (hextets.every((value) => value === 0)) return true;
1520
+ const mappedIPv4 = hextets.slice(0, 5).every((value) => value === 0) && hextets[5] === 65535;
1521
+ const translatedIPv4 = hextets.slice(0, 4).every((value) => value === 0) && hextets[4] === 65535 && hextets[5] === 0;
1522
+ const nat64IPv4 = hextets[0] === 100 && hextets[1] === 65435 && hextets.slice(2, 6).every((value) => value === 0);
1523
+ const compatibleIPv4 = hextets.slice(0, 6).every((value) => value === 0);
1524
+ if (mappedIPv4 || translatedIPv4 || nat64IPv4 || compatibleIPv4) {
1525
+ return privateIPv4(hextets[6] >>> 8, hextets[6] & 255);
1526
+ }
1527
+ if (hextets[0] === 8194) return privateIPv4(hextets[1] >>> 8, hextets[1] & 255);
1528
+ return (hextets[0] & 65024) === 64512 || (hextets[0] & 65472) === 65152 || (hextets[0] & 65472) === 65216 || (hextets[0] & 65280) === 65280 || hextets[0] === 100 && hextets[1] === 65435 && hextets[2] === 1;
1529
+ }
1530
+ const parts = hostname.split(".");
1531
+ if (parts.length !== 4 || parts.some((part) => !part || Array.from(part).some((character) => character < "0" || character > "9"))) return false;
1532
+ const octets = parts.map(Number);
1533
+ if (octets.some((value) => value < 0 || value > 255)) return false;
1534
+ const [first, second] = octets;
1535
+ return privateIPv4(first, second);
1536
+ }
1537
+
1538
+ // packages/safe-bash/src/commands/network/authorizer.ts
1539
+ function createOriginAuthorizer(allowlist = "*", options = {}) {
1540
+ const denyPrivateNetworks = options.denyPrivateNetworks === true;
1541
+ const origins = /* @__PURE__ */ new Set();
1542
+ const hosts = /* @__PURE__ */ new Set();
1543
+ for (const entry of allowlist === "*" ? [] : allowlist) {
1544
+ const value = entry.trim();
1545
+ if (!value) throw new TypeError("Origin allowlist entries must not be empty");
1546
+ if (value.includes("://")) {
1547
+ const url = new URL(value);
1548
+ if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) {
1549
+ throw new TypeError(`Origin allowlist entry must be an origin: ${entry}`);
1550
+ }
1551
+ origins.add(url.origin);
1552
+ } else {
1553
+ if (value.includes("/") || value.includes("@")) throw new TypeError(`Invalid hostname allowlist entry: ${entry}`);
1554
+ hosts.add(value.toLowerCase().replace(/\.$/u, ""));
1555
+ }
1556
+ }
1557
+ return (request) => {
1558
+ const url = new URL(request.url);
1559
+ const hostname = url.hostname.toLowerCase().replace(/\.$/u, "");
1560
+ if (denyPrivateNetworks) {
1561
+ request.requirePrivateNetworkDeny?.();
1562
+ if (privateHostname(hostname)) return false;
1563
+ }
1564
+ return allowlist === "*" || origins.has(url.origin) || hosts.has(hostname);
1565
+ };
1566
+ }
1567
+
1568
+ // packages/safe-bash/src/commands/network/public.ts
1569
+ function createNetworkCommands(options) {
1570
+ return [createCurlCommand(options), createWgetCommand(options)];
1571
+ }
1572
+ function networkCommands(options) {
1573
+ const definitions = createNetworkCommands(options);
1574
+ return {
1575
+ name: "network-commands",
1576
+ setup(host) {
1577
+ if (!options.replace) {
1578
+ for (const definition of definitions) if (host.commands.has(definition.name)) throw new Error(`Command already registered: ${definition.name}`);
1579
+ }
1580
+ for (const definition of definitions) host.commands.register(definition, { replace: options.replace ?? false });
1581
+ }
1582
+ };
1583
+ }
1584
+ var createCurlCommands = createNetworkCommands;
1585
+ var curlCommands = networkCommands;
1586
+
1587
+ export {
1588
+ bindFileOutputBudget,
1589
+ writeFileOutput,
1590
+ openFileOutput,
1591
+ defaultNetworkLimits,
1592
+ cloudflareWorkerNetworkLimits,
1593
+ CurlError,
1594
+ createCurlCommand,
1595
+ createWgetCommand,
1596
+ createFetchTransport,
1597
+ createOriginAuthorizer,
1598
+ createNetworkCommands,
1599
+ networkCommands,
1600
+ createCurlCommands,
1601
+ curlCommands
1602
+ };
1603
+ //# sourceMappingURL=chunk-UGMUVHIY.js.map