@poe-platform/safe-bash 0.1.656 → 0.1.658

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 (129) hide show
  1. package/dist/safe-bash/chunks/{chunk-43HWIHXB.js → chunk-Z4UKD5FF.js} +192 -61
  2. package/dist/safe-bash/chunks/chunk-Z4UKD5FF.js.map +7 -0
  3. package/dist/safe-bash/chunks/{xz-U4QDTPZL.js → xz-4V5FXSPG.js} +555 -514
  4. package/dist/safe-bash/chunks/xz-4V5FXSPG.js.map +7 -0
  5. package/dist/safe-bash/commands/archive/index.d.ts +1 -1
  6. package/dist/safe-bash/commands/archive/index.d.ts.map +1 -1
  7. package/dist/safe-bash/commands/archive/internal.d.ts +32 -0
  8. package/dist/safe-bash/commands/archive/internal.d.ts.map +1 -1
  9. package/dist/safe-bash/commands/archive/internal.js.map +1 -1
  10. package/dist/safe-bash/commands/archive/unzip/arguments.d.ts +3 -0
  11. package/dist/safe-bash/commands/archive/unzip/arguments.d.ts.map +1 -1
  12. package/dist/safe-bash/commands/archive/unzip/arguments.js +31 -5
  13. package/dist/safe-bash/commands/archive/unzip/arguments.js.map +1 -1
  14. package/dist/safe-bash/commands/archive/unzip/safety.d.ts +4 -0
  15. package/dist/safe-bash/commands/archive/unzip/safety.d.ts.map +1 -1
  16. package/dist/safe-bash/commands/archive/unzip/safety.js +3 -0
  17. package/dist/safe-bash/commands/archive/unzip/safety.js.map +1 -1
  18. package/dist/safe-bash/commands/archive/unzip.d.ts.map +1 -1
  19. package/dist/safe-bash/commands/archive/unzip.js +159 -112
  20. package/dist/safe-bash/commands/archive/unzip.js.map +1 -1
  21. package/dist/safe-bash/commands/archive/zip/aes-primitives-unavailable.d.ts +2 -0
  22. package/dist/safe-bash/commands/archive/zip/aes-primitives-unavailable.d.ts.map +1 -0
  23. package/dist/safe-bash/commands/archive/zip/aes-primitives-unavailable.js +3 -0
  24. package/dist/safe-bash/commands/archive/zip/aes-primitives-unavailable.js.map +1 -0
  25. package/dist/safe-bash/commands/archive/zip/aes-primitives.d.ts +2 -0
  26. package/dist/safe-bash/commands/archive/zip/aes-primitives.d.ts.map +1 -0
  27. package/dist/safe-bash/commands/archive/zip/aes-primitives.js +3 -0
  28. package/dist/safe-bash/commands/archive/zip/aes-primitives.js.map +1 -0
  29. package/dist/safe-bash/commands/archive/zip/aes.d.ts +18 -0
  30. package/dist/safe-bash/commands/archive/zip/aes.d.ts.map +1 -0
  31. package/dist/safe-bash/commands/archive/zip/aes.js +157 -0
  32. package/dist/safe-bash/commands/archive/zip/aes.js.map +1 -0
  33. package/dist/safe-bash/commands/archive/zip/crypto.d.ts +16 -0
  34. package/dist/safe-bash/commands/archive/zip/crypto.d.ts.map +1 -1
  35. package/dist/safe-bash/commands/archive/zip/crypto.js +85 -0
  36. package/dist/safe-bash/commands/archive/zip/crypto.js.map +1 -1
  37. package/dist/safe-bash/commands/archive/zip/grow.d.ts +4 -0
  38. package/dist/safe-bash/commands/archive/zip/grow.d.ts.map +1 -0
  39. package/dist/safe-bash/commands/archive/zip/grow.js +3 -0
  40. package/dist/safe-bash/commands/archive/zip/grow.js.map +1 -0
  41. package/dist/safe-bash/commands/archive/zip/help.d.ts +4 -2
  42. package/dist/safe-bash/commands/archive/zip/help.d.ts.map +1 -1
  43. package/dist/safe-bash/commands/archive/zip/help.js +98 -3
  44. package/dist/safe-bash/commands/archive/zip/help.js.map +1 -1
  45. package/dist/safe-bash/commands/archive/zip/line-endings.d.ts +1 -0
  46. package/dist/safe-bash/commands/archive/zip/line-endings.d.ts.map +1 -1
  47. package/dist/safe-bash/commands/archive/zip/line-endings.js +158 -0
  48. package/dist/safe-bash/commands/archive/zip/line-endings.js.map +1 -1
  49. package/dist/safe-bash/commands/archive/zip/log.d.ts +23 -0
  50. package/dist/safe-bash/commands/archive/zip/log.d.ts.map +1 -0
  51. package/dist/safe-bash/commands/archive/zip/log.js +159 -0
  52. package/dist/safe-bash/commands/archive/zip/log.js.map +1 -0
  53. package/dist/safe-bash/commands/archive/zip/lzma.d.ts +10 -0
  54. package/dist/safe-bash/commands/archive/zip/lzma.d.ts.map +1 -0
  55. package/dist/safe-bash/commands/archive/zip/lzma.js +41 -0
  56. package/dist/safe-bash/commands/archive/zip/lzma.js.map +1 -0
  57. package/dist/safe-bash/commands/archive/zip/names.d.ts +3 -0
  58. package/dist/safe-bash/commands/archive/zip/names.d.ts.map +1 -0
  59. package/dist/safe-bash/commands/archive/zip/names.js +34 -0
  60. package/dist/safe-bash/commands/archive/zip/names.js.map +1 -0
  61. package/dist/safe-bash/commands/archive/zip/options.d.ts +7 -0
  62. package/dist/safe-bash/commands/archive/zip/options.d.ts.map +1 -1
  63. package/dist/safe-bash/commands/archive/zip/options.js +88 -17
  64. package/dist/safe-bash/commands/archive/zip/options.js.map +1 -1
  65. package/dist/safe-bash/commands/archive/zip/repair.d.ts +11 -0
  66. package/dist/safe-bash/commands/archive/zip/repair.d.ts.map +1 -0
  67. package/dist/safe-bash/commands/archive/zip/repair.js +392 -0
  68. package/dist/safe-bash/commands/archive/zip/repair.js.map +1 -0
  69. package/dist/safe-bash/commands/archive/zip/safety.d.ts +23 -4
  70. package/dist/safe-bash/commands/archive/zip/safety.d.ts.map +1 -1
  71. package/dist/safe-bash/commands/archive/zip/safety.js +73 -23
  72. package/dist/safe-bash/commands/archive/zip/safety.js.map +1 -1
  73. package/dist/safe-bash/commands/archive/zip/sfx.d.ts +5 -0
  74. package/dist/safe-bash/commands/archive/zip/sfx.d.ts.map +1 -0
  75. package/dist/safe-bash/commands/archive/zip/sfx.js +56 -0
  76. package/dist/safe-bash/commands/archive/zip/sfx.js.map +1 -0
  77. package/dist/safe-bash/commands/archive/zip/test-command.d.ts +6 -0
  78. package/dist/safe-bash/commands/archive/zip/test-command.d.ts.map +1 -0
  79. package/dist/safe-bash/commands/archive/zip/test-command.js +101 -0
  80. package/dist/safe-bash/commands/archive/zip/test-command.js.map +1 -0
  81. package/dist/safe-bash/commands/archive/zip/volumes.d.ts +22 -0
  82. package/dist/safe-bash/commands/archive/zip/volumes.d.ts.map +1 -0
  83. package/dist/safe-bash/commands/archive/zip/volumes.js +265 -0
  84. package/dist/safe-bash/commands/archive/zip/volumes.js.map +1 -0
  85. package/dist/safe-bash/commands/archive/zip/zip64.d.ts +20 -1
  86. package/dist/safe-bash/commands/archive/zip/zip64.d.ts.map +1 -1
  87. package/dist/safe-bash/commands/archive/zip/zip64.js +127 -17
  88. package/dist/safe-bash/commands/archive/zip/zip64.js.map +1 -1
  89. package/dist/safe-bash/commands/archive/zip-format.d.ts +30 -5
  90. package/dist/safe-bash/commands/archive/zip-format.d.ts.map +1 -1
  91. package/dist/safe-bash/commands/archive/zip-format.js +489 -91
  92. package/dist/safe-bash/commands/archive/zip-format.js.map +1 -1
  93. package/dist/safe-bash/commands/archive/zip.d.ts.map +1 -1
  94. package/dist/safe-bash/commands/archive/zip.js +729 -128
  95. package/dist/safe-bash/commands/archive/zip.js.map +1 -1
  96. package/dist/safe-bash/commands/bytes/compression/bounded-codec.d.ts +7 -0
  97. package/dist/safe-bash/commands/bytes/compression/bounded-codec.d.ts.map +1 -1
  98. package/dist/safe-bash/commands/bytes/compression/bounded-codec.js.map +1 -1
  99. package/dist/safe-bash/commands/bytes/compression/codec-loader.d.ts.map +1 -1
  100. package/dist/safe-bash/commands/bytes/compression/codec-loader.js +8 -1
  101. package/dist/safe-bash/commands/bytes/compression/codec-loader.js.map +1 -1
  102. package/dist/safe-bash/commands/bytes/compression/native/generated/xz.mjs +1 -1
  103. package/dist/safe-bash/commands/bytes/compression/native/sources.json +2 -2
  104. package/dist/safe-bash/commands/bytes/compression/native/types.d.ts +1 -0
  105. package/dist/safe-bash/commands/bytes/compression/native/types.d.ts.map +1 -1
  106. package/dist/safe-bash/commands/python/cache.d.ts +11 -0
  107. package/dist/safe-bash/commands/python/cache.d.ts.map +1 -0
  108. package/dist/safe-bash/commands/python/cache.js +41 -0
  109. package/dist/safe-bash/commands/python/cache.js.map +1 -0
  110. package/dist/safe-bash/commands/python/index.browser.js +7 -1
  111. package/dist/safe-bash/commands/python/index.d.ts +6 -2
  112. package/dist/safe-bash/commands/python/index.d.ts.map +1 -1
  113. package/dist/safe-bash/commands/python/index.js +16 -10
  114. package/dist/safe-bash/commands/python/index.js.map +1 -1
  115. package/dist/safe-bash/commands/python/manifest.d.ts +23 -0
  116. package/dist/safe-bash/commands/python/manifest.d.ts.map +1 -0
  117. package/dist/safe-bash/commands/python/manifest.js +48 -0
  118. package/dist/safe-bash/commands/python/manifest.js.map +1 -0
  119. package/dist/safe-bash/commands/python/provisioning.d.ts +17 -13
  120. package/dist/safe-bash/commands/python/provisioning.d.ts.map +1 -1
  121. package/dist/safe-bash/commands/python/provisioning.js +88 -46
  122. package/dist/safe-bash/commands/python/provisioning.js.map +1 -1
  123. package/dist/safe-bash/commands/text.js +1 -1
  124. package/dist/safe-bash/commands/text.js.map +1 -1
  125. package/dist/safe-bash/core.browser.js +3113 -718
  126. package/dist/safe-bash/core.browser.js.map +4 -4
  127. package/package.json +11 -3
  128. package/dist/safe-bash/chunks/chunk-43HWIHXB.js.map +0 -7
  129. package/dist/safe-bash/chunks/xz-U4QDTPZL.js.map +0 -7
@@ -917,6 +917,96 @@ var sha384 = /* @__PURE__ */ createHasher(
917
917
  /* @__PURE__ */ oidNist(2)
918
918
  );
919
919
 
920
+ // packages/safe-bash/src/commands/python/manifest.ts
921
+ init_platform();
922
+ var PythonPackageConflictError = class extends Error {
923
+ code = "EPACKAGECONFLICT";
924
+ retryable = true;
925
+ constructor() {
926
+ super("Python package environment changed during installation; retry the command");
927
+ this.name = "PythonPackageConflictError";
928
+ }
929
+ };
930
+ function createPythonPackageManifestStore(options = {}) {
931
+ const maxBytes = options.maxBytes ?? 1048576;
932
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new RangeError("Python manifest maxBytes must be a positive integer");
933
+ const manifests = /* @__PURE__ */ new Map();
934
+ let retainedBytes = 0;
935
+ let revision = 0;
936
+ let disposed = false;
937
+ const check = (scope, signal) => {
938
+ signal.throwIfAborted();
939
+ if (disposed) throw new Error("Python manifest store is disposed");
940
+ if (typeof scope !== "string" || !scope || scope.length > 1024) throw new TypeError("Invalid Python manifest scope");
941
+ };
942
+ return {
943
+ async get(scope, { signal }) {
944
+ check(scope, signal);
945
+ const value = manifests.get(scope);
946
+ return value ? { revision: value.revision, bytes: value.bytes.slice() } : void 0;
947
+ },
948
+ async compareAndSet(scope, expected, bytes, { signal }) {
949
+ check(scope, signal);
950
+ const current = manifests.get(scope);
951
+ if (current?.revision !== expected) return false;
952
+ if (!(bytes instanceof Uint8Array)) throw new TypeError("Python manifest must contain bytes");
953
+ const nextBytes = retainedBytes - (current?.bytes.length ?? 0) + bytes.length;
954
+ if (nextBytes > maxBytes || !current && manifests.size >= 1024 || revision >= Number.MAX_SAFE_INTEGER) {
955
+ throw new RangeError("Python manifest store budget exhausted");
956
+ }
957
+ manifests.set(scope, { revision: String(++revision), bytes: Uint8Array.from(bytes) });
958
+ retainedBytes = nextBytes;
959
+ return true;
960
+ },
961
+ dispose() {
962
+ disposed = true;
963
+ manifests.clear();
964
+ retainedBytes = 0;
965
+ }
966
+ };
967
+ }
968
+
969
+ // packages/safe-bash/src/commands/python/cache.ts
970
+ init_platform();
971
+ var pythonPackageRuntimeKey = "pyodide-314.0.6-cp314-emscripten-wasm32-v1";
972
+ function createPythonPackageCache(options = {}) {
973
+ const maxBytes = options.maxBytes ?? 128 * 1024 * 1024;
974
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new RangeError("Python cache maxBytes must be a positive integer");
975
+ const values = /* @__PURE__ */ new Map();
976
+ const manifestKey = pythonPackageRuntimeKey + "-environment";
977
+ let retainedBytes = 0;
978
+ let disposed = false;
979
+ return {
980
+ async get(key) {
981
+ if (disposed) throw new Error("Python package cache is disposed");
982
+ return values.get(key)?.slice();
983
+ },
984
+ async set(key, bytes) {
985
+ if (disposed) throw new Error("Python package cache is disposed");
986
+ if (key === manifestKey && bytes.length > maxBytes) throw new RangeError("Python package manifest exceeds maxCacheBytes");
987
+ const previous = values.get(key);
988
+ if (previous) {
989
+ retainedBytes -= previous.length;
990
+ values.delete(key);
991
+ }
992
+ if (bytes.length > maxBytes) return;
993
+ while (values.size && (retainedBytes + bytes.length > maxBytes || values.size >= 1024)) {
994
+ const oldest = [...values.keys()].find((entry) => entry !== manifestKey);
995
+ if (oldest === void 0) return;
996
+ retainedBytes -= values.get(oldest).length;
997
+ values.delete(oldest);
998
+ }
999
+ values.set(key, Uint8Array.from(bytes));
1000
+ retainedBytes += bytes.length;
1001
+ },
1002
+ dispose() {
1003
+ disposed = true;
1004
+ values.clear();
1005
+ retainedBytes = 0;
1006
+ }
1007
+ };
1008
+ }
1009
+
920
1010
  // packages/safe-bash/src/commands/python/provisioning.ts
921
1011
  var pythonDocumentPackages = Object.freeze([
922
1012
  "lxml==6.0.2",
@@ -933,12 +1023,11 @@ var pythonDocumentPackages = Object.freeze([
933
1023
  ]);
934
1024
  var encoder = new TextEncoder();
935
1025
  var decoder = new TextDecoder();
936
- var runtimeKey = "pyodide-314.0.6-cp314-emscripten-wasm32-v1";
937
1026
  function digest(value) {
938
1027
  return Array.from(sha256(value), (byte) => byte.toString(16).padStart(2, "0")).join("");
939
1028
  }
940
- function failure(message) {
941
- return Object.assign(new Error(message), { code: "EPACKAGE" });
1029
+ function failure(message, cause) {
1030
+ return Object.assign(new Error(message, { cause }), { code: "EPACKAGE" });
942
1031
  }
943
1032
  function missing(error) {
944
1033
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
@@ -955,42 +1044,43 @@ function checkSession(session) {
955
1044
  }
956
1045
  function createPythonPackageEnvironment(options = {}) {
957
1046
  if (options.cache && options.cacheDirectory) throw new TypeError("Choose package cache or cacheDirectory, not both");
1047
+ if (options.manifestStore && (typeof options.scope !== "string" || !options.scope.trim() || options.scope.length > 1024)) throw new TypeError("Shared Python manifests require an explicit nonempty scope");
1048
+ if (options.scope !== void 0 && !options.manifestStore) throw new TypeError("Python scope requires a manifestStore");
1049
+ const manifestKey = options.manifestStore ? pythonPackageRuntimeKey + "-environment-" + digest(encoder.encode(JSON.stringify(options.scope))) : pythonPackageRuntimeKey + "-environment";
958
1050
  if (options.profile !== void 0 && options.profile !== "documents") throw new TypeError("Unknown Python package profile");
959
1051
  const maxBytes = options.maxDownloadBytes ?? 64 * 1024 * 1024;
960
1052
  if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) throw new RangeError("maxDownloadBytes must be a positive integer");
961
1053
  const maxCacheBytes = options.maxCacheBytes ?? 128 * 1024 * 1024;
962
1054
  if (!Number.isSafeInteger(maxCacheBytes) || maxCacheBytes < 1) throw new RangeError("maxCacheBytes must be a positive integer");
963
- const memory = /* @__PURE__ */ new Map();
964
- let memoryBytes = 0;
965
- const defaultCache = {
966
- async get(key) {
967
- return memory.get(key)?.slice();
968
- },
969
- async set(key, value) {
970
- const manifestKey = runtimeKey + "-environment";
971
- if (key === manifestKey && value.length > maxCacheBytes) throw failure("Python package manifest exceeds maxCacheBytes");
972
- const previous = memory.get(key);
973
- if (previous) {
974
- memoryBytes -= previous.length;
975
- memory.delete(key);
976
- }
977
- if (value.length > maxCacheBytes) return;
978
- while (memory.size && (memoryBytes + value.length > maxCacheBytes || memory.size >= 1024)) {
979
- const oldest = Array.from(memory.keys()).find((entry) => entry !== manifestKey);
980
- if (oldest === void 0) return;
981
- memoryBytes -= memory.get(oldest).length;
982
- memory.delete(oldest);
983
- }
984
- memory.set(key, value.slice());
985
- memoryBytes += value.length;
986
- }
987
- };
1055
+ const defaultCache = createPythonPackageCache({ maxBytes: maxCacheBytes });
988
1056
  const sessions = /* @__PURE__ */ new Map();
1057
+ const controller = new AbortController();
1058
+ const pending = /* @__PURE__ */ new Set();
1059
+ let disposed = false;
1060
+ let disposing;
1061
+ const admit = (operation) => (...args) => {
1062
+ if (disposed) return Promise.reject(failure("Python package environment is disposed"));
1063
+ const work = Promise.resolve().then(() => {
1064
+ if (disposed) throw failure("Python package environment is disposed");
1065
+ return operation(...args);
1066
+ });
1067
+ pending.add(work);
1068
+ void work.then(() => {
1069
+ pending.delete(work);
1070
+ }, () => {
1071
+ pending.delete(work);
1072
+ });
1073
+ return work;
1074
+ };
989
1075
  let counter = 0;
990
1076
  let committing = Promise.resolve();
991
- async function prepare(context) {
1077
+ async function prepare(input) {
1078
+ const invocation = new AbortController();
1079
+ const signal = AbortSignal.any([input.signal, controller.signal, invocation.signal]);
1080
+ inheritYieldCheckpoint(input.signal, signal);
1081
+ const context = { ...input, signal };
992
1082
  context.signal.throwIfAborted();
993
- const directory = options.cacheDirectory === void 0 ? void 0 : resolvePath(context.cwd, options.cacheDirectory, runtimeKey);
1083
+ const directory = options.cacheDirectory === void 0 ? void 0 : resolvePath(context.cwd, options.cacheDirectory, pythonPackageRuntimeKey);
994
1084
  const cache = options.cache ?? (directory === void 0 ? defaultCache : {
995
1085
  async get(key) {
996
1086
  try {
@@ -1005,7 +1095,20 @@ function createPythonPackageEnvironment(options = {}) {
1005
1095
  await context.fs.writeFile(resolvePath(directory, key), bytes, { signal: context.signal });
1006
1096
  }
1007
1097
  });
1008
- const stored = await cache.get(runtimeKey + "-environment");
1098
+ const manifestCache = options.cacheDirectory === void 0 ? defaultCache : cache;
1099
+ let snapshot;
1100
+ if (options.manifestStore) {
1101
+ try {
1102
+ snapshot = await options.manifestStore.get(manifestKey, context);
1103
+ } catch (error) {
1104
+ context.signal.throwIfAborted();
1105
+ throw failure("Cannot read Python package environment manifest", error);
1106
+ }
1107
+ }
1108
+ context.signal.throwIfAborted();
1109
+ 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");
1110
+ const manifestRevision = snapshot?.revision;
1111
+ const stored = options.manifestStore ? snapshot?.bytes : await manifestCache.get(manifestKey);
1009
1112
  context.signal.throwIfAborted();
1010
1113
  if (stored && stored.length > maxBytes) throw failure("Python package manifest exceeds maxDownloadBytes");
1011
1114
  const manifest = stored === void 0 ? "" : decoder.decode(stored);
@@ -1045,7 +1148,7 @@ function createPythonPackageEnvironment(options = {}) {
1045
1148
  }
1046
1149
  sessions.delete(session);
1047
1150
  };
1048
- sessions.set(session, { ...context, cache, offline: context.offline ?? options.offline ?? false, requirements: unique, opened: /* @__PURE__ */ new Map(), opening: false, closed: false, manifest, aborted });
1151
+ sessions.set(session, { ...context, cache, manifestCache, manifestRevision, controller: invocation, offline: context.offline ?? options.offline ?? false, requirements: unique, opened: /* @__PURE__ */ new Map(), opening: false, closed: false, manifest, aborted });
1049
1152
  context.signal.addEventListener("abort", aborted, { once: true });
1050
1153
  return { session, requirements: unique, offline: context.offline ?? options.offline ?? false };
1051
1154
  }
@@ -1062,11 +1165,18 @@ function createPythonPackageEnvironment(options = {}) {
1062
1165
  if (manifestBytes.length > maxBytes) throw failure("Python package manifest exceeds maxDownloadBytes");
1063
1166
  const commit = committing.then(async () => {
1064
1167
  checkSession(session);
1065
- const current = await session.cache.get(runtimeKey + "-environment");
1066
- checkSession(session);
1067
- if (current && current.length > maxBytes) throw failure("Python package manifest exceeds maxDownloadBytes");
1068
- if ((current === void 0 ? "" : decoder.decode(current)) !== session.manifest) throw failure("Python package environment changed during installation; retry the command");
1069
- await session.cache.set(runtimeKey + "-environment", manifestBytes);
1168
+ if (options.manifestStore) {
1169
+ const committed = await options.manifestStore.compareAndSet(manifestKey, session.manifestRevision, manifestBytes, { signal: session.signal });
1170
+ checkSession(session);
1171
+ if (typeof committed !== "boolean") throw failure("Invalid Python package manifest publication result");
1172
+ if (!committed) throw new PythonPackageConflictError();
1173
+ } else {
1174
+ const current = await session.manifestCache.get(manifestKey);
1175
+ checkSession(session);
1176
+ if (current && current.length > maxBytes) throw failure("Python package manifest exceeds maxDownloadBytes");
1177
+ if ((current === void 0 ? "" : decoder.decode(current)) !== session.manifest) throw new PythonPackageConflictError();
1178
+ await session.manifestCache.set(manifestKey, manifestBytes);
1179
+ }
1070
1180
  checkSession(session);
1071
1181
  });
1072
1182
  committing = commit.catch(() => {
@@ -1094,8 +1204,9 @@ function createPythonPackageEnvironment(options = {}) {
1094
1204
  const url = args[1];
1095
1205
  const expected = args[2];
1096
1206
  if (expected !== void 0 && expected !== null && (typeof expected !== "string" || expected.length !== 64 || Array.from(expected).some((c) => !"0123456789abcdef".includes(c)))) throw failure("Invalid SHA-256 package integrity value");
1097
- const address = runtimeKey + "-url-" + digest(encoder.encode(url));
1098
- const metadata = await session.cache.get(address);
1207
+ const address = pythonPackageRuntimeKey + "-url-" + digest(encoder.encode(url));
1208
+ const canonicalWheel = url.startsWith("file:") || url.startsWith("emfs:");
1209
+ const metadata = canonicalWheel ? void 0 : await session.cache.get(address);
1099
1210
  checkSession(session);
1100
1211
  let bytes;
1101
1212
  let headers = [];
@@ -1108,7 +1219,7 @@ function createPythonPackageEnvironment(options = {}) {
1108
1219
  throw failure(`Invalid package cache metadata: ${url}`);
1109
1220
  }
1110
1221
  if (typeof record !== "object" || record === null || typeof record.digest !== "string" || record.digest.length !== 64 || Array.from(record.digest).some((char) => !"0123456789abcdef".includes(char)) || !Array.isArray(record.headers) || record.headers.some((pair) => !Array.isArray(pair) || pair.length !== 2 || pair.some((value) => typeof value !== "string"))) throw failure(`Invalid package cache metadata: ${url}`);
1111
- bytes = await session.cache.get(runtimeKey + "-sha256-" + record.digest);
1222
+ bytes = await session.cache.get(pythonPackageRuntimeKey + "-sha256-" + record.digest);
1112
1223
  headers = record.headers;
1113
1224
  checkSession(session);
1114
1225
  if (bytes && bytes.length > maxBytes) throw failure("Cached package exceeds maxDownloadBytes");
@@ -1117,7 +1228,7 @@ function createPythonPackageEnvironment(options = {}) {
1117
1228
  if (bytes) options.onProgress?.({ phase: "cached", url, bytes: bytes.length });
1118
1229
  }
1119
1230
  if (!bytes) {
1120
- if (url.startsWith("file:") || url.startsWith("emfs:")) {
1231
+ if (canonicalWheel) {
1121
1232
  const path = new URL(url);
1122
1233
  if (path.host && path.host !== "localhost") throw failure("Local wheels must use the canonical filesystem");
1123
1234
  try {
@@ -1186,9 +1297,9 @@ function createPythonPackageEnvironment(options = {}) {
1186
1297
  const hash = digest(bytes);
1187
1298
  const metadataBytes = encoder.encode(JSON.stringify({ digest: hash, headers }));
1188
1299
  if (metadataBytes.length > maxBytes) throw failure("Python package cache metadata exceeds maxDownloadBytes");
1189
- await session.cache.set(runtimeKey + "-sha256-" + hash, Uint8Array.from(bytes));
1300
+ await session.cache.set(pythonPackageRuntimeKey + "-sha256-" + hash, Uint8Array.from(bytes));
1190
1301
  checkSession(session);
1191
- await session.cache.set(address, metadataBytes);
1302
+ if (!canonicalWheel) await session.cache.set(address, metadataBytes);
1192
1303
  checkSession(session);
1193
1304
  }
1194
1305
  checkSession(session);
@@ -1200,15 +1311,31 @@ function createPythonPackageEnvironment(options = {}) {
1200
1311
  session.opening = false;
1201
1312
  }
1202
1313
  }
1203
- return { prepare, dispatch, finish(start) {
1204
- const session = sessions.get(start.session);
1205
- if (session) {
1206
- session.closed = true;
1207
- session.opened.clear();
1208
- session.signal.removeEventListener("abort", session.aborted);
1314
+ return {
1315
+ prepare: admit(prepare),
1316
+ dispatch: admit(dispatch),
1317
+ finish(start) {
1318
+ const session = sessions.get(start.session);
1319
+ if (session) {
1320
+ session.closed = true;
1321
+ session.opened.clear();
1322
+ session.signal.removeEventListener("abort", session.aborted);
1323
+ session.controller.abort(failure("Python package session is closed"));
1324
+ }
1325
+ sessions.delete(start.session);
1326
+ },
1327
+ dispose() {
1328
+ if (!disposing) {
1329
+ disposed = true;
1330
+ controller.abort(failure("Python package environment is disposed"));
1331
+ disposing = Promise.allSettled([...pending]).then(() => {
1332
+ sessions.clear();
1333
+ defaultCache.dispose();
1334
+ });
1335
+ }
1336
+ return disposing;
1209
1337
  }
1210
- sessions.delete(start.session);
1211
- } };
1338
+ };
1212
1339
  }
1213
1340
 
1214
1341
  // packages/safe-bash/src/commands/python/index.ts
@@ -1217,6 +1344,7 @@ var PythonInputChunkError = class extends RangeError {
1217
1344
  function createPythonCommands(options) {
1218
1345
  if (typeof options?.createWorker !== "function") throw new PythonFailure("executor-unavailable");
1219
1346
  if (options.onDiagnostic !== void 0 && typeof options.onDiagnostic !== "function") throw new TypeError("Python onDiagnostic must be a function");
1347
+ if (options.environment && options.provisioning) throw new TypeError("A borrowed Python environment cannot be combined with provisioning options");
1220
1348
  const maxTransferBytes = options.maxTransferBytes ?? 65536;
1221
1349
  const maxOpenFiles = options.maxOpenFiles ?? 256;
1222
1350
  const maxConcurrentWorkers = options.maxConcurrentWorkers ?? 4;
@@ -1227,12 +1355,7 @@ function createPythonCommands(options) {
1227
1355
  for (const size of [maxTransferBytes, maxOpenFiles]) if (!Number.isSafeInteger(size) || size < 1 || size > 1048576) throw new RangeError("Invalid Python resource limit");
1228
1356
  const runtimeMount = options.runtimeMount ?? "/.pyodide-runtime";
1229
1357
  if (!runtimeMount.startsWith("/") || runtimeMount === "/" || runtimeMount.slice(1).includes("/") || runtimeMount.includes("\0") || runtimeMount.split("/").some((part) => part === ".." || part === ".")) throw new TypeError("Python runtime mount must be an absolute top-level canonical path");
1230
- const environment = createPythonPackageEnvironment({
1231
- ...options.provisioning,
1232
- requirements: [...options.provisioning?.requirements ?? [], ...options.packages ?? []],
1233
- requirementFiles: [...options.provisioning?.requirementFiles ?? [], ...options.requirements ?? []],
1234
- ...options.packageProfile ? { profile: options.packageProfile } : {}
1235
- });
1358
+ const environment = options.environment ?? createPythonPackageEnvironment(options.provisioning);
1236
1359
  const execute = async (context) => {
1237
1360
  let installation;
1238
1361
  try {
@@ -1388,7 +1511,8 @@ function createPythonCommands(options) {
1388
1511
  fs: context.fs,
1389
1512
  cwd: context.cwd,
1390
1513
  signal,
1391
- ...installation ? { requirements: installation.packages, requirementFiles: installation.requirements } : {}
1514
+ requirements: [...options.packages ?? [], ...options.packageProfile ? pythonDocumentPackages : [], ...installation?.packages ?? []],
1515
+ requirementFiles: [...options.requirements ?? [], ...installation?.requirements ?? []]
1392
1516
  }).then((value) => {
1393
1517
  packages = value;
1394
1518
  });
@@ -1540,8 +1664,12 @@ function createPythonCommands(options) {
1540
1664
  return ["python", "python3"].map((name) => ({ name, description: "Python with an explicit synchronous interpreter worker and canonical filesystem", execute }));
1541
1665
  }
1542
1666
  function pythonCommands(options) {
1543
- const commands = createPythonCommands(options);
1544
- return { name: "python-commands", setup(host) {
1667
+ if (typeof options?.createWorker !== "function") throw new PythonFailure("executor-unavailable");
1668
+ if (options?.environment && options.provisioning) throw new TypeError("A borrowed Python environment cannot be combined with provisioning options");
1669
+ const { provisioning, ...configuration } = options;
1670
+ const environment = options.environment ?? createPythonPackageEnvironment(provisioning);
1671
+ const commands = createPythonCommands({ ...configuration, environment });
1672
+ return { name: "python-commands", ...options.environment ? {} : { dispose: environment.dispose }, setup(host) {
1545
1673
  if (!options.replace) {
1546
1674
  for (const command of commands) if (host.commands.has(command.name)) throw new Error(`Command already registered: ${command.name}`);
1547
1675
  }
@@ -1561,9 +1689,12 @@ export {
1561
1689
  sha224,
1562
1690
  sha512,
1563
1691
  sha384,
1692
+ PythonPackageConflictError,
1693
+ createPythonPackageManifestStore,
1694
+ createPythonPackageCache,
1564
1695
  pythonDocumentPackages,
1565
1696
  createPythonPackageEnvironment,
1566
1697
  createPythonCommands,
1567
1698
  pythonCommands
1568
1699
  };
1569
- //# sourceMappingURL=chunk-43HWIHXB.js.map
1700
+ //# sourceMappingURL=chunk-Z4UKD5FF.js.map