@poe-platform/safe-bash 0.1.825 → 0.1.827

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 (155) hide show
  1. package/dist/image-ast/index.js +39 -18
  2. package/dist/pdf-ast/image.js +1 -1
  3. package/dist/pdf-ast/index.js +1 -1
  4. package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +9 -3
  5. package/dist/safe-bash/chunks/{chunk-AGHV53VF.js → chunk-M6XFU6LQ.js} +3 -1
  6. package/dist/safe-bash/chunks/{chunk-363QOIDR.js → chunk-T6FHWSHM.js} +3 -1
  7. package/dist/safe-bash/command-chunks/{chunk-ZPBL7TYJ.js → chunk-2JRHCVMQ.js} +1 -1
  8. package/dist/safe-bash/command-chunks/{chunk-FMGNXOMV.js → chunk-2L3NMRLG.js} +7 -3
  9. package/dist/safe-bash/command-chunks/{chunk-DAQO64WC.js → chunk-2YKOJPIW.js} +1 -1
  10. package/dist/safe-bash/command-chunks/{chunk-EPYJSPOY.js → chunk-3QCW4VQF.js} +12 -8
  11. package/dist/safe-bash/command-chunks/{chunk-YRBFNT5B.js → chunk-3YL2TMLA.js} +10 -1
  12. package/dist/safe-bash/command-chunks/{chunk-5H7ZHP7F.js → chunk-43NDRBKY.js} +1 -1
  13. package/dist/safe-bash/command-chunks/{chunk-BBOYR6LV.js → chunk-46GA576V.js} +3 -3
  14. package/dist/safe-bash/command-chunks/{chunk-WPT2FCHH.js → chunk-4SLPM2WM.js} +1 -1
  15. package/dist/safe-bash/command-chunks/{chunk-7ZQVMPSB.js → chunk-5CAXR62E.js} +1 -1
  16. package/dist/safe-bash/command-chunks/{chunk-3DTHX5UU.js → chunk-66653AEZ.js} +40 -14
  17. package/dist/safe-bash/command-chunks/{chunk-ETFJ4L7F.js → chunk-6OLE6CLV.js} +1 -1
  18. package/dist/safe-bash/command-chunks/{chunk-ZIDESNHW.js → chunk-7M3M6FKC.js} +1 -1
  19. package/dist/safe-bash/command-chunks/{chunk-2KMNVJB7.js → chunk-A7PKUIJT.js} +1 -1
  20. package/dist/safe-bash/command-chunks/{chunk-AVSINNZ6.js → chunk-DEQ47SBQ.js} +5 -5
  21. package/dist/safe-bash/command-chunks/{chunk-EV7A5FNN.js → chunk-FFFRLPXU.js} +2 -2
  22. package/dist/safe-bash/command-chunks/{chunk-4MVQE6CT.js → chunk-FYTBEGSY.js} +1 -1
  23. package/dist/safe-bash/command-chunks/{chunk-LFTGMUAV.js → chunk-HQIZR6EU.js} +192 -489
  24. package/dist/safe-bash/command-chunks/chunk-HS2L7I4N.js +219 -0
  25. package/dist/safe-bash/command-chunks/{chunk-WKS2PAZL.js → chunk-HUGKO4ZE.js} +10 -1
  26. package/dist/safe-bash/command-chunks/chunk-IGXH5W5Z.js +111 -0
  27. package/dist/safe-bash/command-chunks/{chunk-CMJBRGU2.js → chunk-IHQZKUBS.js} +1 -1
  28. package/dist/safe-bash/command-chunks/chunk-JADJ4BMN.js +1519 -0
  29. package/dist/safe-bash/command-chunks/{chunk-5AQAWIYK.js → chunk-JEZC5V3B.js} +4 -0
  30. package/dist/safe-bash/command-chunks/{chunk-YB5TNDY6.js → chunk-K5VJ4NNL.js} +39 -5
  31. package/dist/safe-bash/command-chunks/{chunk-7RQGRFHJ.js → chunk-KHWDEAE4.js} +2 -2
  32. package/dist/safe-bash/command-chunks/chunk-L54KVUSY.js +604 -0
  33. package/dist/safe-bash/command-chunks/{chunk-3NJETNC2.js → chunk-MBXNG6C3.js} +2 -2
  34. package/dist/safe-bash/command-chunks/{chunk-HCPEYQKT.js → chunk-N4SH6QY5.js} +285 -302
  35. package/dist/safe-bash/command-chunks/{chunk-3DID6MQY.js → chunk-OWTQYLID.js} +2 -2
  36. package/dist/safe-bash/command-chunks/{chunk-4EA7WI3L.js → chunk-QOOQD6BD.js} +42 -33
  37. package/dist/safe-bash/command-chunks/{chunk-RQTFK7AV.js → chunk-QZYEI4N6.js} +1 -1
  38. package/dist/safe-bash/command-chunks/{chunk-R3SLT3ZX.js → chunk-R6GON4H3.js} +11 -1
  39. package/dist/safe-bash/command-chunks/{chunk-2GILUQJY.js → chunk-R7ZGDHME.js} +3 -3
  40. package/dist/safe-bash/command-chunks/{chunk-HNEWGADJ.js → chunk-RUXOFW5G.js} +7 -6
  41. package/dist/safe-bash/command-chunks/{chunk-LKAFLJ5L.js → chunk-RWQKX44L.js} +1 -1
  42. package/dist/safe-bash/command-chunks/{chunk-PKH57OIC.js → chunk-SG2KOOD4.js} +2 -2
  43. package/dist/safe-bash/command-chunks/chunk-T4TGJYFV.js +60 -0
  44. package/dist/safe-bash/command-chunks/chunk-TGSNVLFZ.js +105 -0
  45. package/dist/safe-bash/command-chunks/{chunk-NXCJNPL3.js → chunk-UCE77LYV.js} +2 -1
  46. package/dist/safe-bash/command-chunks/{chunk-EWECMOQ5.js → chunk-UIHPHIKI.js} +1 -1
  47. package/dist/safe-bash/command-chunks/{chunk-XSZNL3GV.js → chunk-UJPWPRVB.js} +191 -146
  48. package/dist/safe-bash/command-chunks/{chunk-E5CDHXFA.js → chunk-VOR6YDZC.js} +26 -1
  49. package/dist/safe-bash/command-chunks/chunk-VSNVYOK2.js +30 -0
  50. package/dist/safe-bash/command-chunks/{chunk-4XYGJB24.js → chunk-VTH4AORO.js} +3 -3
  51. package/dist/safe-bash/command-chunks/{chunk-W5LH7D23.js → chunk-WKKJJBJQ.js} +8 -8
  52. package/dist/safe-bash/command-chunks/{chunk-OLXMWQJ5.js → chunk-WRO3PB2M.js} +1 -1
  53. package/dist/safe-bash/command-chunks/{chunk-RUAGHZNF.js → chunk-X5ODTF3E.js} +7 -5
  54. package/dist/safe-bash/command-chunks/{chunk-LH4VBNF6.js → chunk-XGTSP2CP.js} +84 -16
  55. package/dist/safe-bash/command-chunks/{chunk-K576GZED.js → chunk-XTHKXCF2.js} +2 -2
  56. package/dist/safe-bash/command-chunks/{chunk-J3VS55K4.js → chunk-YHRESVJ7.js} +9 -3
  57. package/dist/safe-bash/command-chunks/{chunk-UWIDPTOB.js → chunk-YSCKOUQP.js} +1 -1
  58. package/dist/safe-bash/command-chunks/{chunk-UYNJF5QN.js → chunk-ZALAWNOE.js} +76 -122
  59. package/dist/safe-bash/command-chunks/{chunk-OT75C5YS.js → chunk-ZYXKW2K7.js} +1 -1
  60. package/dist/safe-bash/command-chunks/{pdf-renderer-346WYKSZ.js → pdf-renderer-5QWOVFA4.js} +1 -1
  61. package/dist/safe-bash/command-chunks/{prompt-tool-debug-3POFNRYP.js → prompt-tool-debug-G7ATE7D5.js} +6 -4
  62. package/dist/safe-bash/commands/llm/index.browser.js +5 -1
  63. package/dist/safe-bash/commands/llm/index.js +1 -1
  64. package/dist/safe-bash/commands/python/executor.browser.js +3 -1
  65. package/dist/safe-bash/commands/python/executor.js +1 -1
  66. package/dist/safe-bash/commands/python/index.browser.js +5 -1
  67. package/dist/safe-bash/commands/python/index.js +1 -1
  68. package/dist/safe-bash/core.browser.js +2 -2
  69. package/dist/safe-bash/full-core.browser.js +10 -2
  70. package/dist/safe-bash-command-awk/awk-runtime.js +2 -2
  71. package/dist/safe-bash-command-awk/awk-syntax.js +1 -1
  72. package/dist/safe-bash-command-awk/awk.js +3 -3
  73. package/dist/safe-bash-command-awk/index.js +3 -3
  74. package/dist/safe-bash-command-gpg/index.js +11 -3
  75. package/dist/safe-bash-command-imagemagick/index.js +2 -2
  76. package/dist/safe-bash-command-llm/collections.js +6 -4
  77. package/dist/safe-bash-command-llm/command.js +4 -4
  78. package/dist/safe-bash-command-llm/import-json-document.d.ts +9 -2
  79. package/dist/safe-bash-command-llm/index.d.ts +2 -1
  80. package/dist/safe-bash-command-llm/index.js +10 -4
  81. package/dist/safe-bash-command-llm/loader-provider.d.ts +5 -0
  82. package/dist/safe-bash-command-mcp/index.js +10 -13
  83. package/dist/safe-bash-command-pdftoppm/index.js +2 -2
  84. package/dist/safe-bash-command-playwright-cli/index.js +2 -2
  85. package/dist/safe-bash-command-playwright-cli/playwright/ability-execution.d.ts +1 -0
  86. package/dist/safe-bash-command-playwright-cli/playwright/ability-execution.js +1 -1
  87. package/dist/safe-bash-command-playwright-cli/playwright/controller.d.ts +2 -0
  88. package/dist/safe-bash-command-playwright-cli/playwright/controller.js +2 -2
  89. package/dist/safe-bash-command-playwright-cli/playwright/index.js +2 -2
  90. package/dist/safe-bash-command-python/build-backend.d.ts +2 -0
  91. package/dist/safe-bash-command-python/cache.d.ts +1 -1
  92. package/dist/safe-bash-command-python/executor.d.ts +5 -2
  93. package/dist/safe-bash-command-python/executor.js +11 -6
  94. package/dist/safe-bash-command-python/host-capabilities.js +1 -1
  95. package/dist/safe-bash-command-python/index.js +11 -6
  96. package/dist/safe-bash-command-python/jspi.js +5 -3
  97. package/dist/safe-bash-command-python/manifest-file.d.ts +44 -0
  98. package/dist/safe-bash-command-python/manifest.d.ts +45 -0
  99. package/dist/safe-bash-command-python/provisioning.d.ts +20 -1
  100. package/dist/safe-bash-command-python/provisioning.js +3 -2
  101. package/dist/safe-bash-command-python/reply.js +7 -11
  102. package/dist/safe-bash-command-python/source-archive.js +2 -2
  103. package/dist/safe-bash-command-python/source-zip.js +2 -2
  104. package/dist/safe-bash-command-python/worker.js +34 -21
  105. package/dist/safe-bash-command-sqlite3/engine.d.ts +4 -0
  106. package/dist/safe-bash-command-sqlite3/index.js +174 -18
  107. package/dist/safe-bash-command-svgo/index.js +1 -1
  108. package/dist/safe-bash-command-tar/create.js +3 -3
  109. package/dist/safe-bash-command-tar/extract.js +3 -3
  110. package/dist/safe-bash-command-tar/index.js +5 -5
  111. package/dist/safe-bash-command-tar/modes.js +5 -5
  112. package/dist/safe-bash-command-tar/options.d.ts +1 -1
  113. package/dist/safe-bash-command-tar/options.js +1 -1
  114. package/dist/safe-bash-command-tar/stream.js +1 -1
  115. package/dist/safe-bash-command-wkhtmltopdf/index.js +1 -1
  116. package/dist/safe-bash-command-xan/argv.js +1 -1
  117. package/dist/safe-bash-command-xan/commands.js +3 -3
  118. package/dist/safe-bash-command-xan/index.js +3 -3
  119. package/dist/safe-bash-command-xan/io.js +2 -2
  120. package/dist/safe-bash-compression-engine/bounded-codec.js +3 -3
  121. package/dist/safe-bash-compression-engine/codec-loader.js +2 -2
  122. package/dist/safe-bash-compression-engine/files.js +6 -6
  123. package/dist/safe-bash-compression-engine/index.js +5 -5
  124. package/dist/safe-bash-compression-engine/operand.js +6 -6
  125. package/dist/safe-bash-compression-engine/options.js +1 -1
  126. package/dist/safe-bash-compression-engine/stream.js +5 -5
  127. package/dist/safe-bash-compression-engine/zstd-decode.js +4 -4
  128. package/dist/safe-bash-contracts/filesystem-descriptor.js +1 -1
  129. package/dist/safe-bash-contracts/filesystem-output.js +1 -1
  130. package/dist/safe-bash-csv-engine/index.js +6 -6
  131. package/dist/safe-bash-csv-engine/python-codec-aliases.js +1 -1
  132. package/dist/safe-bash-csv-engine/python-codepages.js +3 -3
  133. package/dist/safe-bash-csv-engine/python-file-codepages.js +2 -2
  134. package/dist/safe-bash-csv-engine/python-utf16.js +4 -4
  135. package/dist/safe-bash-csv-engine/text-decoder.js +6 -6
  136. package/dist/safe-bash-graphviz-engine/index.js +1 -1
  137. package/dist/safe-bash-pager-engine/index.js +2 -2
  138. package/dist/safe-bash-query-engine/capture.js +3 -3
  139. package/dist/safe-bash-query-engine/delpaths.js +3 -3
  140. package/dist/safe-bash-query-engine/formats.js +2 -2
  141. package/dist/safe-bash-query-engine/index.js +10 -10
  142. package/dist/safe-bash-query-engine/indices.js +3 -3
  143. package/dist/safe-bash-query-engine/input.d.ts +3 -3
  144. package/dist/safe-bash-query-engine/input.js +1 -1
  145. package/dist/safe-bash-query-engine/interpreter.js +9 -9
  146. package/dist/safe-bash-query-engine/query-core.js +10 -10
  147. package/dist/safe-bash-query-engine/regex.js +4 -4
  148. package/dist/safe-bash-query-engine/splits.js +5 -5
  149. package/dist/safe-bash-query-engine/values.js +2 -2
  150. package/package.json +2 -2
  151. package/dist/safe-bash/command-chunks/chunk-OOYVZAWL.js +0 -90
  152. package/dist/safe-bash/command-chunks/chunk-RZOHZGEZ.js +0 -772
  153. package/dist/safe-bash/command-chunks/chunk-WIUEM7HP.js +0 -58
  154. package/dist/safe-bash/command-chunks/chunk-WY6THI6J.js +0 -673
  155. package/dist/safe-bash/command-chunks/chunk-ZERCTWUI.js +0 -467
@@ -1,772 +0,0 @@
1
- import {
2
- openPythonPackageFile
3
- } from "./chunk-NXCJNPL3.js";
4
-
5
- // packages/safe-bash-command-python/src/build-wheel.ts
6
- import { FsError as FsError2 } from "../../safe-bash-contracts/index.js";
7
- import { resolvePath as resolvePath2, basename } from "../../safe-bash-contracts/path.js";
8
-
9
- // packages/safe-bash-command-python/src/package-download.ts
10
- import { FsError } from "../../safe-bash-contracts/index.js";
11
- import { resolvePath } from "../../safe-bash-contracts/path.js";
12
- import { interruptible } from "../../safe-bash-contracts/runtime-control.js";
13
- import { yieldTurn } from "../../safe-bash-contracts/yield.js";
14
- var serial = 0;
15
- async function stagePythonPackage(context, directory, body, maxBytes, progress, verify, publish) {
16
- const { fs, signal } = context, settings = { signal };
17
- const caps = await fs.capabilitiesFor?.(directory, settings) ?? fs.capabilities;
18
- if (!caps.retainedStagingWrite || !caps.retainedStagingCleanup || !caps.retainedRead || !fs.createStagedFile || !fs.openReadFile || publish && (!caps.atomicFileStaging || !fs.publishStagedFile)) return void 0;
19
- const parent = await fs.stat(directory, settings);
20
- let stage;
21
- for (let attempt = 0; attempt < 16; attempt++) {
22
- try {
23
- stage = await fs.createStagedFile(resolvePath(directory, ".python-package-" + ++serial), "wheel", { type: "file", data: new Uint8Array(0) }, { parent, mode: 384, retainCleanup: true, signal });
24
- break;
25
- } catch (error) {
26
- signal.throwIfAborted();
27
- if (!(error instanceof FsError) || error.code !== "EEXIST") throw error;
28
- }
29
- }
30
- if (!stage) throw new Error("Python package staging names exhausted");
31
- const owner = stage;
32
- let artifact;
33
- let closing;
34
- const close = () => closing ??= (async () => {
35
- try {
36
- await artifact?.close();
37
- } finally {
38
- try {
39
- await owner.cleanup?.remove();
40
- } finally {
41
- await owner.cleanup?.close();
42
- }
43
- }
44
- })();
45
- try {
46
- if (!owner.cleanup || !owner.writer) throw new Error("Python package staging handles missing");
47
- let count = 0;
48
- const iterator = body[Symbol.asyncIterator]();
49
- let ended = false;
50
- try {
51
- while (true) {
52
- const next = await interruptible(Promise.resolve().then(() => {
53
- signal.throwIfAborted();
54
- return iterator.next();
55
- }), signal);
56
- signal.throwIfAborted();
57
- if (next.done) {
58
- ended = true;
59
- break;
60
- }
61
- const bytes = next.value;
62
- if (!(bytes instanceof Uint8Array)) throw new TypeError("Python package body must yield bytes");
63
- if (count + bytes.length > maxBytes) throw new Error("Package download exceeds maxDownloadBytes");
64
- for (let offset = 0; offset < bytes.length; offset += 65536) {
65
- const chunk = Uint8Array.from(bytes.subarray(offset, offset + 65536));
66
- await owner.writer.write(chunk, settings);
67
- count += chunk.length;
68
- await yieldTurn(signal);
69
- }
70
- if (bytes.length) progress(count);
71
- }
72
- } finally {
73
- if (!ended) {
74
- const returned = Promise.resolve().then(() => iterator.return?.());
75
- if (signal.aborted) void returned.catch(() => {
76
- });
77
- else await interruptible(returned, signal);
78
- }
79
- }
80
- const stat = await owner.writer.finish(settings);
81
- if (stat.size !== count) throw new Error("Python package staging size mismatch");
82
- artifact = await openPythonPackageFile(context, owner.file.path, maxBytes, stat);
83
- if (!artifact) throw new Error("Python package retained reads unavailable");
84
- verify(artifact.key);
85
- if (publish) {
86
- const key = artifact.key, path = publish(key);
87
- await artifact.close();
88
- artifact = void 0;
89
- let destination = null;
90
- try {
91
- destination = await fs.lstat(path, settings);
92
- } catch (error) {
93
- if (!(error instanceof FsError) || error.code !== "ENOENT") throw error;
94
- }
95
- await fs.publishStagedFile({ ...owner, file: { ...owner.file, stat } }, path, { parent, destination, signal });
96
- artifact = await openPythonPackageFile(context, path, maxBytes);
97
- if (!artifact || artifact.key !== key) throw new Error("Published Python package integrity mismatch");
98
- }
99
- return { ...artifact, close };
100
- } catch (error) {
101
- try {
102
- await close();
103
- } catch (cleanup) {
104
- throw new AggregateError([error, cleanup], error instanceof Error ? error.message : "Python package download failed");
105
- }
106
- throw error;
107
- }
108
- }
109
-
110
- // packages/safe-bash-command-python/src/build-wheel.ts
111
- async function publishPythonBuildWheel(source, directory, maxBytes, context) {
112
- const { fs, signal } = context, settings = { signal };
113
- let artifact = typeof source === "string" ? void 0 : source.artifact;
114
- let reading;
115
- try {
116
- signal.throwIfAborted();
117
- if (maxBytes !== Infinity && (!Number.isSafeInteger(maxBytes) || maxBytes < 0)) throw new RangeError("Invalid Python wheel size limit");
118
- const filename = typeof source === "string" ? basename(source) : source.filename;
119
- if (basename(filename) !== filename || !filename.endsWith(".whl") || filename.includes("\\") || filename.includes("\0")) throw new TypeError("Invalid Python build wheel filename");
120
- const root = await fs.realpath(resolvePath2(context.cwd, directory), settings);
121
- const caps = await fs.capabilitiesFor?.(root, settings) ?? fs.capabilities;
122
- if (!fs.confineExtraction || !fs.prepareDirectory || !caps.retainedStagingWrite || !caps.retainedStagingCleanup || !caps.retainedRead || !caps.atomicFileStaging) throw new Error("Python wheel publication requires confined retained atomic staging");
123
- if (typeof source === "string") artifact = await openPythonPackageFile(context, resolvePath2(context.cwd, source), maxBytes);
124
- if (!artifact) throw new Error("Python wheel publication requires retained source reads");
125
- if (artifact.size > maxBytes) throw new Error("Canonical package exceeds maxDownloadBytes");
126
- const retained = artifact;
127
- const confined = await fs.confineExtraction([root], settings);
128
- const destination = new Proxy(confined, { get(target, key) {
129
- const owner = key === "openReadFile" ? fs : target, value = Reflect.get(owner, key);
130
- return typeof value === "function" ? value.bind(owner) : value;
131
- } });
132
- const parent = await destination.stat(root, settings), path = resolvePath2(root, artifact.key);
133
- try {
134
- await destination.prepareDirectory(path, { parent, expected: null, mode: 448, signal });
135
- } catch (error) {
136
- if (!(error instanceof FsError2) || !["EEXIST", "EAGAIN"].includes(error.code)) throw error;
137
- }
138
- if ((await destination.lstat(path, settings)).type !== "directory") throw new Error("Python wheel publication directory changed");
139
- const output = resolvePath2(path, filename);
140
- const body = async function* () {
141
- for (let offset = 0; offset < retained.size; ) {
142
- const bytes = await (reading = Promise.resolve(retained.read(offset, Math.min(65536, retained.size - offset))));
143
- if (!bytes.length || bytes.length > Math.min(65536, retained.size - offset)) throw new Error("Invalid Python wheel read");
144
- offset += bytes.length;
145
- yield bytes;
146
- }
147
- };
148
- const published = await stagePythonPackage({ ...context, fs: destination }, path, body(), maxBytes, () => {
149
- }, (key) => {
150
- if (key !== retained.key) throw new Error("Built Python wheel integrity mismatch");
151
- }, () => output);
152
- if (!published) throw new Error("Python wheel publication requires retained atomic staging");
153
- try {
154
- return { url: "file://" + output.split("/").map(encodeURIComponent).join("/"), digest: published.key, size: published.size };
155
- } finally {
156
- await published.close();
157
- }
158
- } finally {
159
- try {
160
- await reading?.catch(() => {
161
- });
162
- } finally {
163
- await artifact?.close?.();
164
- }
165
- }
166
- }
167
-
168
- // packages/safe-bash-command-python/src/provisioning.ts
169
- import { sha256 } from "@noble/hashes/sha2.js";
170
- import { resolvePath as resolve, dirname, basename as basename2 } from "../../safe-bash-contracts/path.js";
171
- import { inheritYieldCheckpoint } from "../../safe-bash-contracts/yield.js";
172
-
173
- // packages/safe-bash-command-python/src/manifest.ts
174
- function readPackageManifest(value) {
175
- const strings = (values) => Array.isArray(values) && values.every((item) => typeof item === "string");
176
- if (Array.isArray(value)) return strings(value) ? value : void 0;
177
- if (!value || typeof value !== "object") return;
178
- const record = value, version = record.version;
179
- if (![1, 2, 3].includes(version) || Object.keys(value).length !== (version === 1 ? 2 : 3)) return;
180
- if (version !== 1 && (!Array.isArray(record.records) || !record.records.every((row) => Array.isArray(row) && row.length === version + 3 && row.every((part, index) => index > 2 && index < 5 ? strings(part) : typeof part === "string" || index === 5 && part === null)))) return;
181
- return strings(record.installed) ? record.installed : void 0;
182
- }
183
- var PythonPackageConflictError = class extends Error {
184
- code = "EPACKAGECONFLICT";
185
- retryable = true;
186
- constructor() {
187
- super("Python package environment changed during installation; retry the command");
188
- this.name = "PythonPackageConflictError";
189
- }
190
- };
191
- function createPythonPackageManifestStore(options = {}) {
192
- const maxBytes = options.maxBytes ?? Infinity;
193
- const maxEntries = options.maxEntries ?? Infinity;
194
- const maxScopeLength = options.maxScopeLength ?? Infinity;
195
- for (const [name, value] of Object.entries({ maxBytes, maxEntries, maxScopeLength })) {
196
- if (value !== Infinity && (!Number.isSafeInteger(value) || value < 1)) {
197
- throw new RangeError(`Python manifest ${name} must be a positive safe integer or Infinity`);
198
- }
199
- }
200
- const manifests = /* @__PURE__ */ new Map();
201
- let retainedBytes = 0;
202
- let revision = 0n;
203
- let disposed = false;
204
- const check = (scope, signal) => {
205
- signal.throwIfAborted();
206
- if (disposed) throw new Error("Python manifest store is disposed");
207
- if (typeof scope !== "string" || !scope) throw new TypeError("Invalid Python manifest scope");
208
- if (scope.length > maxScopeLength) throw new RangeError("Python manifest scope budget exhausted");
209
- };
210
- return {
211
- async get(scope, { signal }) {
212
- check(scope, signal);
213
- const value = manifests.get(scope);
214
- return value ? { revision: value.revision, bytes: value.bytes.slice() } : void 0;
215
- },
216
- async compareAndSet(scope, expected, bytes, { signal }) {
217
- check(scope, signal);
218
- const current = manifests.get(scope);
219
- if (current?.revision !== expected) return false;
220
- if (!(bytes instanceof Uint8Array)) throw new TypeError("Python manifest must contain bytes");
221
- const nextBytes = retainedBytes - (current?.bytes.length ?? 0) + bytes.length;
222
- if (nextBytes > maxBytes || !current && manifests.size >= maxEntries) {
223
- throw new RangeError("Python manifest store budget exhausted");
224
- }
225
- manifests.set(scope, { revision: String(++revision), bytes: Uint8Array.from(bytes) });
226
- retainedBytes = nextBytes;
227
- return true;
228
- },
229
- dispose() {
230
- disposed = true;
231
- manifests.clear();
232
- retainedBytes = 0;
233
- }
234
- };
235
- }
236
-
237
- // packages/safe-bash-command-python/src/cache.ts
238
- var pythonPackageRuntimeKey = "pyodide-314.0.6-cp314-emscripten-wasm32-v1";
239
- function createPythonPackageCache(options = {}) {
240
- const maxBytes = options.maxBytes ?? Infinity;
241
- if (options.maxBytes !== void 0 && (!Number.isSafeInteger(maxBytes) || maxBytes < 1)) throw new RangeError("Python cache maxBytes must be a positive integer");
242
- const values = /* @__PURE__ */ new Map();
243
- const manifestKey = pythonPackageRuntimeKey + "-environment";
244
- let retainedBytes = 0;
245
- let disposed = false;
246
- return {
247
- async get(key) {
248
- if (disposed) throw new Error("Python package cache is disposed");
249
- return values.get(key)?.slice();
250
- },
251
- async set(key, bytes) {
252
- if (disposed) throw new Error("Python package cache is disposed");
253
- if (key === manifestKey && bytes.length > maxBytes) throw new RangeError("Python package manifest exceeds maxCacheBytes");
254
- const previous = values.get(key);
255
- if (previous) {
256
- retainedBytes -= previous.length;
257
- values.delete(key);
258
- }
259
- if (bytes.length > maxBytes) return;
260
- while (values.size && retainedBytes + bytes.length > maxBytes) {
261
- const oldest = [...values.keys()].find((entry) => entry !== manifestKey);
262
- if (oldest === void 0) return;
263
- retainedBytes -= values.get(oldest).length;
264
- values.delete(oldest);
265
- }
266
- values.set(key, Uint8Array.from(bytes));
267
- retainedBytes += bytes.length;
268
- },
269
- dispose() {
270
- disposed = true;
271
- values.clear();
272
- retainedBytes = 0;
273
- }
274
- };
275
- }
276
-
277
- // packages/safe-bash-command-python/src/provisioning.ts
278
- var pythonDocumentPackages = Object.freeze([
279
- "lxml==6.0.2",
280
- "pillow==12.2.0",
281
- "python-docx==1.2.0",
282
- "openpyxl==3.1.5",
283
- "XlsxWriter==3.2.9",
284
- "pypdf==6.18.1",
285
- "fpdf2==2.8.8",
286
- "fonttools==4.65.0",
287
- "defusedxml==0.7.1",
288
- "et-xmlfile==2.0.0",
289
- "typing-extensions==4.16.0"
290
- ]);
291
- var encoder = new TextEncoder();
292
- var decoder = new TextDecoder();
293
- function digest(value) {
294
- return Array.from(sha256(value), (byte) => byte.toString(16).padStart(2, "0")).join("");
295
- }
296
- function validDigest(value) {
297
- if (typeof value !== "string" || value.length !== 64) return false;
298
- for (const char of value) if (!"0123456789abcdef".includes(char)) return false;
299
- return true;
300
- }
301
- function failure(message, cause) {
302
- return Object.assign(new Error(message, { cause }), { code: "EPACKAGE" });
303
- }
304
- function missing(error) {
305
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
306
- }
307
- function normalizeRequirement(value, cwd) {
308
- const requirement = value.trim();
309
- if (!requirement || requirement.startsWith("-")) throw failure(`Unsupported requirement: ${value}`);
310
- if (requirement.endsWith(".whl") && !requirement.includes("://")) return "file://" + resolve(cwd, requirement).split("/").map(encodeURIComponent).join("/");
311
- return requirement;
312
- }
313
- function checkSession(session) {
314
- session.signal.throwIfAborted();
315
- if (session.closed) throw failure("Python package session is closed");
316
- }
317
- function createPythonPackageEnvironment(options = {}) {
318
- if (options.cache && options.cacheDirectory) throw new TypeError("Choose package cache or cacheDirectory, not both");
319
- if (options.manifestStore && (typeof options.scope !== "string" || !options.scope.trim())) throw new TypeError("Shared Python manifests require an explicit nonempty scope");
320
- if (options.scope !== void 0 && !options.manifestStore) throw new TypeError("Python scope requires a manifestStore");
321
- const manifestKey = options.manifestStore ? pythonPackageRuntimeKey + "-environment-" + digest(encoder.encode(JSON.stringify(options.scope))) : pythonPackageRuntimeKey + "-environment";
322
- if (options.profile !== void 0 && options.profile !== "documents") throw new TypeError("Unknown Python package profile");
323
- const maxBytes = options.maxDownloadBytes ?? Infinity;
324
- const maxManifestBytes = options.maxManifestBytes ?? Infinity;
325
- const maxMetadataBytes = options.maxMetadataBytes ?? Infinity;
326
- for (const name of ["maxDownloadBytes", "maxManifestBytes", "maxMetadataBytes", "maxRequirementBytes", "maxCacheBytes"]) {
327
- const value = options[name];
328
- if (value !== void 0 && (!Number.isSafeInteger(value) || value < 1)) throw new RangeError(`${name} must be a positive integer`);
329
- }
330
- const cacheRecord = (key, headers, url) => {
331
- const bytes = encoder.encode(JSON.stringify({ digest: key, headers, url }));
332
- if (bytes.length > maxMetadataBytes) throw failure("Python package cache metadata exceeds maxMetadataBytes");
333
- return bytes;
334
- };
335
- const maxCacheBytes = options.maxCacheBytes;
336
- const defaultCache = createPythonPackageCache(maxCacheBytes === void 0 ? {} : { maxBytes: maxCacheBytes });
337
- const sessions = /* @__PURE__ */ new Map();
338
- const controller = new AbortController();
339
- const pending = /* @__PURE__ */ new Set();
340
- let cleanupFailure;
341
- const track = (work, cleanup = false) => {
342
- pending.add(work);
343
- void work.then(() => pending.delete(work), (error) => {
344
- if (cleanup) cleanupFailure ??= { error };
345
- pending.delete(work);
346
- });
347
- return work;
348
- };
349
- function release(session, all = false) {
350
- const artifacts = all ? [...session.retained.values()] : [];
351
- if (all) session.retained.clear();
352
- if (session.opened) {
353
- artifacts.push(session.opened);
354
- session.opened = void 0;
355
- }
356
- if (!artifacts.length) return session.retiring ?? Promise.resolve();
357
- return track(session.retiring = Promise.allSettled([session.retiring, ...artifacts.map((artifact) => Promise.resolve().then(() => artifact.close?.()))]).then((results) => {
358
- for (const result of results) if (result.status === "rejected") throw result.reason;
359
- }), true);
360
- }
361
- let disposed = false;
362
- let disposing;
363
- const admit = (operation) => (...args) => track(Promise.resolve().then(() => {
364
- if (disposed) throw failure("Python package environment is disposed");
365
- return operation(...args);
366
- }));
367
- let counter = 0;
368
- let committing = Promise.resolve();
369
- async function prepare(input) {
370
- const invocation = new AbortController();
371
- const signal = AbortSignal.any([input.signal, controller.signal, invocation.signal]);
372
- inheritYieldCheckpoint(input.signal, signal);
373
- const context = { ...input, signal };
374
- signal.throwIfAborted();
375
- const directory = options.cacheDirectory === void 0 ? void 0 : resolve(context.cwd, options.cacheDirectory, pythonPackageRuntimeKey);
376
- const noCache = context.noCache ?? options.noCache ?? false;
377
- const artifactDirectory = directory ?? (!options.cache && !noCache ? resolve(context.cwd, ".python-packages", "cache", pythonPackageRuntimeKey) : void 0);
378
- const cache = options.cache ?? (artifactDirectory === void 0 ? defaultCache : {
379
- async get(key) {
380
- try {
381
- return await context.fs.readFile(resolve(artifactDirectory, key), { signal });
382
- } catch (error) {
383
- if (missing(error)) return void 0;
384
- throw error;
385
- }
386
- },
387
- async set(key, bytes) {
388
- await context.fs.mkdir(artifactDirectory, { recursive: true, signal });
389
- await context.fs.writeFile(resolve(artifactDirectory, key), bytes, { signal });
390
- }
391
- });
392
- const manifestCache = options.cacheDirectory === void 0 ? defaultCache : cache;
393
- let snapshot;
394
- if (options.manifestStore) {
395
- try {
396
- snapshot = await options.manifestStore.get(manifestKey, context);
397
- } catch (error) {
398
- signal.throwIfAborted();
399
- throw failure("Cannot read Python package environment manifest", error);
400
- }
401
- }
402
- signal.throwIfAborted();
403
- if (snapshot !== void 0 && (typeof snapshot !== "object" || snapshot === null || typeof snapshot.revision !== "string" || !snapshot.revision || snapshot.revision.length > 1024 || !(snapshot.bytes instanceof Uint8Array))) throw failure("Invalid Python package manifest snapshot");
404
- const manifestRevision = snapshot?.revision;
405
- const stored = options.manifestStore ? snapshot?.bytes : await manifestCache.get(manifestKey);
406
- signal.throwIfAborted();
407
- if (stored && stored.length > maxManifestBytes) throw failure("Python package manifest exceeds maxManifestBytes");
408
- const manifest = stored === void 0 ? "" : decoder.decode(stored);
409
- let previous;
410
- try {
411
- previous = stored === void 0 ? [] : JSON.parse(manifest);
412
- } catch {
413
- throw failure("Invalid Python package environment manifest");
414
- }
415
- const saved = readPackageManifest(previous);
416
- if (!saved) throw failure("Invalid Python package environment manifest");
417
- const legacy = Array.isArray(previous);
418
- const restore = saved.map((value) => normalizeRequirement(value, context.cwd));
419
- const requirements = [...options.profile === "documents" ? pythonDocumentPackages : [], ...options.requirements ?? [], ...context.requirements ?? []].map((value) => normalizeRequirement(value, context.cwd));
420
- for (const file of [...options.requirementFiles ?? [], ...context.requirementFiles ?? []]) {
421
- const path = resolve(context.cwd, file);
422
- let source;
423
- try {
424
- source = decoder.decode(await context.fs.readFile(path, { signal, ...options.maxRequirementBytes === void 0 ? {} : { maxBytes: options.maxRequirementBytes } }));
425
- } catch (error) {
426
- signal.throwIfAborted();
427
- throw failure(`Cannot read Python requirements ${path}: ${error instanceof Error ? error.message : String(error)}`);
428
- }
429
- for (const line of source.split("\n")) {
430
- let comment = line.indexOf("#");
431
- while (comment > 0 && line[comment - 1].trim()) comment = line.indexOf("#", comment + 1);
432
- const text = (comment < 0 ? line : line.slice(0, comment)).trim();
433
- if (!text) continue;
434
- if (text.endsWith("\\")) throw failure(`Unsupported requirements continuation in ${path}: ${text}`);
435
- requirements.push(text[0] === "-" && options.prepareRequirements ? text : normalizeRequirement(text, dirname(path)));
436
- }
437
- }
438
- if ((options.editable?.length || context.editable?.length) && !options.prepareRequirements) throw failure("Editable packages require a source package environment");
439
- const requested = [...new Set(await options.prepareRequirements?.(requirements, context) ?? requirements)];
440
- signal.throwIfAborted();
441
- const session = String(++counter);
442
- const unique = [.../* @__PURE__ */ new Set([...restore, ...requested])];
443
- const aborted = () => {
444
- const current = sessions.get(session);
445
- if (current) {
446
- current.closed = true;
447
- void release(current, true);
448
- }
449
- };
450
- const offline = context.offline ?? options.offline ?? false;
451
- sessions.set(session, { ...context, cacheDirectory: directory, artifactDirectory, noCache, cache, manifestCache, manifestRevision, controller: invocation, offline, requirements: unique, opening: false, retained: /* @__PURE__ */ new Map(), closed: false, manifest, aborted });
452
- signal.addEventListener("abort", aborted, { once: true });
453
- const controls = {};
454
- for (const key of ["pre", "upgrade", "forceReinstall"]) if (context[key] ?? options[key]) controls[key] = true;
455
- return { session, requirements: unique, restore, requested, legacy, records: previous.records, ...controls, ...input.uninstall ? { uninstall: input.uninstall } : {}, offline };
456
- }
457
- async function dispatch(op, args, _context) {
458
- _context.signal.throwIfAborted();
459
- const session = sessions.get(String(args[0]));
460
- if (!session) throw failure("Python package session is closed");
461
- checkSession(session);
462
- if (op === "package-commit") {
463
- await release(session, true);
464
- checkSession(session);
465
- const pinned = args[1];
466
- const saved = readPackageManifest(pinned);
467
- if (!saved) throw failure("Invalid installed package manifest");
468
- const state = Array.isArray(pinned) ? [.../* @__PURE__ */ new Set([...session.requirements, ...saved])] : { ...pinned, installed: [...new Set(saved)] };
469
- const manifestBytes = encoder.encode(JSON.stringify(state));
470
- if (manifestBytes.length > maxManifestBytes) throw failure("Python package manifest exceeds maxManifestBytes");
471
- const commit = committing.then(async () => {
472
- checkSession(session);
473
- if (options.manifestStore) {
474
- const committed = await options.manifestStore.compareAndSet(manifestKey, session.manifestRevision, manifestBytes, { signal: session.signal });
475
- checkSession(session);
476
- if (typeof committed !== "boolean") throw failure("Invalid Python package manifest publication result");
477
- if (!committed) throw new PythonPackageConflictError();
478
- } else {
479
- const current = await session.manifestCache.get(manifestKey);
480
- checkSession(session);
481
- if (current && current.length > maxManifestBytes) throw failure("Python package manifest exceeds maxManifestBytes");
482
- if ((current === void 0 ? "" : decoder.decode(current)) !== session.manifest) throw new PythonPackageConflictError();
483
- await session.manifestCache.set(manifestKey, manifestBytes);
484
- }
485
- checkSession(session);
486
- });
487
- committing = commit.catch(() => {
488
- });
489
- await commit;
490
- options.onProgress?.({ phase: "installed" });
491
- return null;
492
- }
493
- if (op === "package-read" || op === "package-read-retained") {
494
- const artifact = op === "package-read" ? session.opened : session.retained.get(String(args[1])), offset = args[2], length = args[3];
495
- if (!artifact || op === "package-read" && artifact.key !== String(args[1]) || !Number.isSafeInteger(offset) || !Number.isSafeInteger(length) || offset < 0 || length < 1 || length > 65536) throw failure("Invalid package chunk request");
496
- const bytes = await artifact.read(offset, length);
497
- checkSession(session);
498
- return Array.from(bytes);
499
- }
500
- if (op === "package-retain") {
501
- let artifact = session.opened;
502
- if (!artifact || artifact.key !== String(args[1])) throw failure("Invalid package retention request");
503
- if (artifact.url && artifact.close) {
504
- const source = artifact;
505
- const retaining = (async () => {
506
- const path = decodeURIComponent(new URL(source.url).pathname);
507
- const directory = resolve(session.cacheDirectory ?? resolve(session.cwd, ".python-packages"), "installed");
508
- const capabilities = await session.fs.capabilitiesFor?.(directory, { signal: session.signal }) ?? session.fs.capabilities;
509
- if (!session.fs.confineExtraction || !session.fs.prepareDirectory || !capabilities.retainedStagingWrite || !capabilities.retainedStagingCleanup || !capabilities.retainedRead || !capabilities.atomicFileStaging) return;
510
- const target = resolve(directory, source.key, basename2(path));
511
- if (path !== target) {
512
- await session.fs.mkdir(directory, { recursive: true, signal: session.signal });
513
- checkSession(session);
514
- session.opened = void 0;
515
- const published = await publishPythonBuildWheel({ filename: basename2(path), artifact: source }, directory, maxBytes, session);
516
- artifact = await openPythonPackageFile(session, decodeURIComponent(new URL(published.url).pathname), maxBytes);
517
- if (!artifact) throw failure("Installed Python wheels require retained reads");
518
- if (artifact.key !== published.digest) {
519
- await artifact.close?.();
520
- throw failure("Installed Python wheel changed");
521
- }
522
- session.opened = artifact;
523
- artifact.url = published.url;
524
- try {
525
- checkSession(session);
526
- } catch (error) {
527
- await release(session);
528
- throw error;
529
- }
530
- }
531
- const durable = new URL(artifact.url);
532
- durable.hash = "sha256=" + artifact.key;
533
- artifact.url = durable.href;
534
- })();
535
- session.retaining = retaining;
536
- try {
537
- await retaining;
538
- } finally {
539
- session.retaining = void 0;
540
- }
541
- }
542
- checkSession(session);
543
- if (!artifact) throw failure("Installed Python wheel unavailable");
544
- const token = String(++counter);
545
- session.retained.set(token, artifact);
546
- session.opened = void 0;
547
- return { token, key: artifact.key, size: artifact.size, ...artifact.url ? { url: artifact.url } : {} };
548
- }
549
- if (op === "package-close") {
550
- if (session.opened?.key === String(args[1])) await release(session);
551
- return null;
552
- }
553
- if (op !== "package-open" || typeof args[1] !== "string") throw failure("Invalid package operation");
554
- if (session.opening || session.retaining) throw failure("Package download already in progress");
555
- session.opening = true;
556
- try {
557
- await release(session);
558
- checkSession(session);
559
- const url = args[1], { artifactDirectory: cacheDirectory, noCache } = session;
560
- const expected = args[2];
561
- let responseUrl = url;
562
- const verifyIntegrity = (key2) => {
563
- if (expected && key2 !== expected) throw failure(`Package integrity mismatch: ${url}`);
564
- };
565
- if (expected !== void 0 && expected !== null && !validDigest(expected)) throw failure("Invalid SHA-256 package integrity value");
566
- const address = pythonPackageRuntimeKey + "-url-" + digest(encoder.encode(url));
567
- const canonicalWheel = url.startsWith("file:") || url.startsWith("emfs:");
568
- const metadata = canonicalWheel || noCache || args[3] === "metadata" && !session.offline ? void 0 : await session.cache.get(address);
569
- checkSession(session);
570
- let key = "", bytes;
571
- let headers = [];
572
- const adopt = async (artifact, ready) => {
573
- session.opened = artifact;
574
- if (canonicalWheel) artifact.url = url;
575
- try {
576
- checkSession(session);
577
- await ready();
578
- checkSession(session);
579
- return { key: artifact.key, size: artifact.size, headers, url: responseUrl };
580
- } catch (error) {
581
- await release(session);
582
- throw error;
583
- }
584
- };
585
- if (metadata) {
586
- if (metadata.length > maxMetadataBytes) throw failure("Python package cache metadata exceeds maxMetadataBytes");
587
- let record;
588
- try {
589
- record = JSON.parse(decoder.decode(metadata));
590
- } catch {
591
- }
592
- if (typeof record !== "object" || record === null || !validDigest(record.digest) || record.url !== void 0 && typeof record.url !== "string" || !Array.isArray(record.headers) || record.headers.some((pair) => !Array.isArray(pair) || pair.length !== 2 || pair.some((value2) => typeof value2 !== "string"))) throw failure(`Invalid package cache metadata: ${url}`);
593
- headers = record.headers;
594
- responseUrl = record.url ?? url;
595
- let absent = false;
596
- if (cacheDirectory) {
597
- let artifact;
598
- try {
599
- artifact = await openPythonPackageFile(session, resolve(cacheDirectory, pythonPackageRuntimeKey + "-sha256-" + record.digest), maxBytes);
600
- } catch (error) {
601
- if (!missing(error)) throw error;
602
- absent = true;
603
- }
604
- if (artifact) {
605
- return await adopt(artifact, () => {
606
- if (artifact.key !== record.digest) throw failure(`Package cache integrity mismatch: ${url}`);
607
- verifyIntegrity(artifact.key);
608
- options.onProgress?.({ phase: "cached", url, bytes: artifact.size });
609
- });
610
- }
611
- }
612
- bytes = absent ? void 0 : await session.cache.get(pythonPackageRuntimeKey + "-sha256-" + record.digest);
613
- checkSession(session);
614
- if (bytes && bytes.length > maxBytes) throw failure("Cached package exceeds maxDownloadBytes");
615
- if (bytes) bytes = Uint8Array.from(bytes);
616
- if (bytes && (key = digest(bytes)) !== record.digest) throw failure(`Package cache integrity mismatch: ${url}`);
617
- if (bytes) options.onProgress?.({ phase: "cached", url, bytes: bytes.length });
618
- }
619
- if (!bytes) {
620
- if (canonicalWheel) {
621
- const path = new URL(url);
622
- if (path.host && path.host !== "localhost") throw failure("Local wheels must use the canonical filesystem");
623
- try {
624
- const artifact = await openPythonPackageFile(session, decodeURIComponent(path.pathname), maxBytes);
625
- if (artifact) {
626
- return await adopt(artifact, () => verifyIntegrity(artifact.key));
627
- }
628
- bytes = Uint8Array.from(await session.fs.readFile(decodeURIComponent(path.pathname), { signal: session.signal, ...Number.isFinite(maxBytes) ? { maxBytes } : {} }));
629
- } catch (error) {
630
- checkSession(session);
631
- throw failure(`Cannot read canonical Python wheel ${path.pathname}: ${error instanceof Error ? error.message : String(error)}`);
632
- }
633
- } else {
634
- if (session.offline) throw failure(`Offline package cache miss: ${url}`);
635
- if (!options.transport || !options.authorize) throw failure("Python package download requires configured transport and authorization");
636
- let current = new URL(url);
637
- let redirectFrom;
638
- for (let redirect = 0; ; redirect++) {
639
- if (current.protocol !== "https:" && current.protocol !== "http:") throw failure(`Unsupported package transport protocol: ${current.protocol}`);
640
- if (current.username || current.password) throw failure("Package URLs with credentials are unsupported");
641
- let denyPrivate = false;
642
- const allowed = await options.authorize({ url: current.href, method: "GET", attempt: 0, signal: session.signal, ...redirectFrom === void 0 ? {} : { redirectFrom }, requirePrivateNetworkDeny() {
643
- denyPrivate = true;
644
- } });
645
- checkSession(session);
646
- if (!allowed) throw failure(`Python package download authorization denied: ${current.href}`);
647
- if (denyPrivate && !options.transport.supportsPrivateNetworkDeny) throw failure("Package transport cannot enforce private network denial");
648
- checkSession(session);
649
- const response = await options.transport({ url: current.href, method: "GET", headers: [["accept", "application/vnd.pypi.simple.v1+json, application/json;q=0.9, */*;q=0.1"]], signal: session.signal, ...denyPrivate ? { denyPrivateNetworks: true } : {} });
650
- try {
651
- checkSession(session);
652
- if ([301, 302, 303, 307, 308].includes(response.status)) {
653
- if (redirect >= 5) throw failure("Too many package redirects");
654
- const location = response.headers.find(([key2]) => key2.toLowerCase() === "location")?.[1];
655
- if (!location) throw failure("Package redirect has no location");
656
- redirectFrom = current.href;
657
- current = new URL(location, current);
658
- continue;
659
- }
660
- if (response.status < 200 || response.status >= 300) throw failure(`Package download failed: HTTP ${response.status} ${current.href}`);
661
- headers = response.headers;
662
- responseUrl = current.href;
663
- const encoding = headers.find(([key2]) => key2.toLowerCase() === "content-encoding")?.[1].trim().toLowerCase();
664
- const length = headers.find(([key2]) => key2.toLowerCase() === "content-length")?.[1];
665
- const total = length === void 0 || encoding !== void 0 && encoding !== "identity" ? void 0 : Number(length);
666
- if (total !== void 0 && Number.isFinite(total) && total > maxBytes) throw failure("Package download exceeds maxDownloadBytes");
667
- const progress = (count2) => options.onProgress?.({ phase: "download", url, bytes: count2, ...typeof total === "number" && Number.isSafeInteger(total) ? { totalBytes: total } : {} });
668
- if (cacheDirectory || noCache) {
669
- const directory = cacheDirectory ?? session.cwd;
670
- if (cacheDirectory) await session.fs.mkdir(directory, { recursive: true, signal: session.signal });
671
- let metadataBytes;
672
- const artifact = await stagePythonPackage(
673
- session,
674
- directory,
675
- response.body,
676
- maxBytes,
677
- progress,
678
- (key2) => {
679
- verifyIntegrity(key2);
680
- if (!noCache) metadataBytes = cacheRecord(key2, headers, responseUrl);
681
- },
682
- noCache ? void 0 : (key2) => resolve(directory, pythonPackageRuntimeKey + "-sha256-" + key2)
683
- );
684
- if (artifact) {
685
- return await adopt(artifact, async () => {
686
- if (!noCache) await session.cache.set(address, metadataBytes);
687
- });
688
- }
689
- }
690
- const chunks = [];
691
- let count = 0;
692
- for await (const chunk of response.body) {
693
- checkSession(session);
694
- if (chunk.length === 0) continue;
695
- count += chunk.length;
696
- if (count > maxBytes) throw failure("Package download exceeds maxDownloadBytes");
697
- chunks.push(Uint8Array.from(chunk));
698
- progress(count);
699
- }
700
- bytes = new Uint8Array(count);
701
- let offset = 0;
702
- for (const chunk of chunks) {
703
- bytes.set(chunk, offset);
704
- offset += chunk.length;
705
- }
706
- break;
707
- } finally {
708
- await response.dispose();
709
- }
710
- }
711
- }
712
- checkSession(session);
713
- verifyIntegrity(key = digest(bytes));
714
- if (!noCache) {
715
- const metadataBytes = cacheRecord(key, headers, responseUrl);
716
- await session.cache.set(pythonPackageRuntimeKey + "-sha256-" + key, Uint8Array.from(bytes));
717
- checkSession(session);
718
- if (!canonicalWheel) await session.cache.set(address, metadataBytes);
719
- }
720
- }
721
- checkSession(session);
722
- verifyIntegrity(key);
723
- const value = bytes;
724
- session.opened = { key, size: bytes.length, ...canonicalWheel ? { url } : {}, read: (offset, length) => value.subarray(offset, offset + length) };
725
- return { key, size: bytes.length, headers, url: responseUrl };
726
- } finally {
727
- session.opening = false;
728
- }
729
- }
730
- return {
731
- prepare: admit(prepare),
732
- dispatch: admit(dispatch),
733
- finish(start) {
734
- const session = sessions.get(start.session);
735
- if (session) {
736
- session.closed = true;
737
- session.signal.removeEventListener("abort", session.aborted);
738
- session.controller.abort(failure("Python package session is closed"));
739
- sessions.delete(start.session);
740
- const retired = release(session, true);
741
- return Promise.allSettled([session.retaining, retired]).then(async () => {
742
- try {
743
- await retired;
744
- } finally {
745
- await release(session, true);
746
- }
747
- });
748
- }
749
- },
750
- dispose() {
751
- if (!disposing) {
752
- disposed = true;
753
- controller.abort(failure("Python package environment is disposed"));
754
- disposing = Promise.allSettled([...pending]).then(() => {
755
- sessions.clear();
756
- defaultCache.dispose();
757
- if (cleanupFailure) throw cleanupFailure.error;
758
- });
759
- }
760
- return disposing;
761
- }
762
- };
763
- }
764
-
765
- export {
766
- publishPythonBuildWheel,
767
- PythonPackageConflictError,
768
- createPythonPackageManifestStore,
769
- createPythonPackageCache,
770
- pythonDocumentPackages,
771
- createPythonPackageEnvironment
772
- };