toolcraft 0.0.749 → 0.0.751

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 (374) hide show
  1. package/composition.json +23 -3
  2. package/dist/composition.json +23 -3
  3. package/dist/human-in-loop/approvals-commands.d.ts +1 -1
  4. package/dist/index.d.ts +1 -262
  5. package/dist/index.js +1 -573
  6. package/dist/runtime-platform.d.ts +2 -0
  7. package/dist/runtime-platform.js +2 -0
  8. package/dist/runtime-platform.workerd.d.ts +3 -0
  9. package/dist/runtime-platform.workerd.js +10 -0
  10. package/dist/runtime.d.ts +262 -0
  11. package/dist/runtime.js +576 -0
  12. package/node_modules/@noble/hashes/LICENSE +21 -0
  13. package/node_modules/@noble/hashes/README.md +478 -0
  14. package/node_modules/@noble/hashes/_blake.d.ts +20 -0
  15. package/node_modules/@noble/hashes/_blake.js +59 -0
  16. package/node_modules/@noble/hashes/_md.d.ts +95 -0
  17. package/node_modules/@noble/hashes/_md.js +209 -0
  18. package/node_modules/@noble/hashes/_u64.d.ts +36 -0
  19. package/node_modules/@noble/hashes/_u64.js +77 -0
  20. package/node_modules/@noble/hashes/argon2.d.ts +148 -0
  21. package/node_modules/@noble/hashes/argon2.js +577 -0
  22. package/node_modules/@noble/hashes/blake1.d.ts +162 -0
  23. package/node_modules/@noble/hashes/blake1.js +630 -0
  24. package/node_modules/@noble/hashes/blake2.d.ts +203 -0
  25. package/node_modules/@noble/hashes/blake2.js +573 -0
  26. package/node_modules/@noble/hashes/blake3.d.ts +68 -0
  27. package/node_modules/@noble/hashes/blake3.js +310 -0
  28. package/node_modules/@noble/hashes/eskdf.d.ts +91 -0
  29. package/node_modules/@noble/hashes/eskdf.js +225 -0
  30. package/node_modules/@noble/hashes/hkdf.d.ts +70 -0
  31. package/node_modules/@noble/hashes/hkdf.js +152 -0
  32. package/node_modules/@noble/hashes/hmac.d.ts +50 -0
  33. package/node_modules/@noble/hashes/hmac.js +93 -0
  34. package/node_modules/@noble/hashes/index.d.ts +1 -0
  35. package/node_modules/@noble/hashes/index.js +34 -0
  36. package/node_modules/@noble/hashes/legacy.d.ts +107 -0
  37. package/node_modules/@noble/hashes/legacy.js +348 -0
  38. package/node_modules/@noble/hashes/package.json +91 -0
  39. package/node_modules/@noble/hashes/pbkdf2.d.ts +66 -0
  40. package/node_modules/@noble/hashes/pbkdf2.js +176 -0
  41. package/node_modules/@noble/hashes/scrypt.d.ts +98 -0
  42. package/node_modules/@noble/hashes/scrypt.js +304 -0
  43. package/node_modules/@noble/hashes/sha2.d.ts +176 -0
  44. package/node_modules/@noble/hashes/sha2.js +446 -0
  45. package/node_modules/@noble/hashes/sha3-addons.d.ts +533 -0
  46. package/node_modules/@noble/hashes/sha3-addons.js +973 -0
  47. package/node_modules/@noble/hashes/sha3.d.ts +208 -0
  48. package/node_modules/@noble/hashes/sha3.js +475 -0
  49. package/node_modules/@noble/hashes/src/_blake.ts +67 -0
  50. package/node_modules/@noble/hashes/src/_md.ts +227 -0
  51. package/node_modules/@noble/hashes/src/_u64.ts +111 -0
  52. package/node_modules/@noble/hashes/src/argon2.ts +693 -0
  53. package/node_modules/@noble/hashes/src/blake1.ts +677 -0
  54. package/node_modules/@noble/hashes/src/blake2.ts +648 -0
  55. package/node_modules/@noble/hashes/src/blake3.ts +344 -0
  56. package/node_modules/@noble/hashes/src/eskdf.ts +265 -0
  57. package/node_modules/@noble/hashes/src/hkdf.ts +161 -0
  58. package/node_modules/@noble/hashes/src/hmac.ts +130 -0
  59. package/node_modules/@noble/hashes/src/index.ts +33 -0
  60. package/node_modules/@noble/hashes/src/legacy.ts +361 -0
  61. package/node_modules/@noble/hashes/src/pbkdf2.ts +219 -0
  62. package/node_modules/@noble/hashes/src/scrypt.ts +375 -0
  63. package/node_modules/@noble/hashes/src/sha2.ts +486 -0
  64. package/node_modules/@noble/hashes/src/sha3-addons.ts +1157 -0
  65. package/node_modules/@noble/hashes/src/sha3.ts +525 -0
  66. package/node_modules/@noble/hashes/src/utils.ts +978 -0
  67. package/node_modules/@noble/hashes/src/webcrypto.ts +283 -0
  68. package/node_modules/@noble/hashes/utils.d.ts +560 -0
  69. package/node_modules/@noble/hashes/utils.js +687 -0
  70. package/node_modules/@noble/hashes/webcrypto.d.ts +121 -0
  71. package/node_modules/@noble/hashes/webcrypto.js +228 -0
  72. package/node_modules/@poe-code/agent-mcp-config/dist/apply.js +23 -9
  73. package/node_modules/@poe-code/config-mutations/README.md +2 -0
  74. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.js +4 -5
  75. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.d.ts +3 -4
  76. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.js +3 -3
  77. package/node_modules/@poe-code/config-mutations/dist/template/render.js +1 -1
  78. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.d.ts +2 -2
  79. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.js +3 -6
  80. package/node_modules/@poe-code/config-mutations/dist/types.d.ts +4 -2
  81. package/node_modules/@poe-code/process-runner/README.md +2 -1
  82. package/node_modules/@poe-code/process-runner/dist/transfer-filesystem.d.ts +1 -0
  83. package/node_modules/@poe-code/process-runner/dist/transfer-filesystem.js +1 -0
  84. package/node_modules/@poe-code/process-runner/dist/transfer-filesystem.workerd.d.ts +2 -0
  85. package/node_modules/@poe-code/process-runner/dist/transfer-filesystem.workerd.js +1 -0
  86. package/node_modules/@poe-code/process-runner/dist/types.d.ts +1 -1
  87. package/node_modules/@poe-code/process-runner/dist/workspace-transfer.d.ts +6 -5
  88. package/node_modules/@poe-code/process-runner/dist/workspace-transfer.js +67 -29
  89. package/node_modules/@poe-code/process-runner/package.json +13 -0
  90. package/node_modules/@poe-code/safe-fs/LICENSE +21 -0
  91. package/node_modules/@poe-code/safe-fs/PROVENANCE.json +428 -0
  92. package/node_modules/@poe-code/safe-fs/README.md +411 -0
  93. package/node_modules/@poe-code/safe-fs/dist/bridge/confinement.d.ts +3 -0
  94. package/node_modules/@poe-code/safe-fs/dist/bridge/confinement.js +171 -0
  95. package/node_modules/@poe-code/safe-fs/dist/bridge/filesystem.d.ts +93 -0
  96. package/node_modules/@poe-code/safe-fs/dist/bridge/filesystem.js +453 -0
  97. package/node_modules/@poe-code/safe-fs/dist/bridge/index.d.ts +7 -0
  98. package/node_modules/@poe-code/safe-fs/dist/bridge/index.js +19 -0
  99. package/node_modules/@poe-code/safe-fs/dist/bridge/stats.d.ts +4 -0
  100. package/node_modules/@poe-code/safe-fs/dist/bridge/stats.js +37 -0
  101. package/node_modules/@poe-code/safe-fs/dist/bridge/types.d.ts +81 -0
  102. package/node_modules/@poe-code/safe-fs/dist/bridge/types.js +1 -0
  103. package/node_modules/@poe-code/safe-fs/dist/bridge/values.d.ts +6 -0
  104. package/node_modules/@poe-code/safe-fs/dist/bridge/values.js +65 -0
  105. package/node_modules/@poe-code/safe-fs/dist/config/memory.d.ts +3 -0
  106. package/node_modules/@poe-code/safe-fs/dist/config/memory.js +7 -0
  107. package/node_modules/@poe-code/safe-fs/dist/config/real.d.ts +5 -0
  108. package/node_modules/@poe-code/safe-fs/dist/config/real.js +16 -0
  109. package/node_modules/@poe-code/safe-fs/dist/config/registry.d.ts +2 -0
  110. package/node_modules/@poe-code/safe-fs/dist/config/registry.js +15 -0
  111. package/node_modules/@poe-code/safe-fs/dist/config.d.ts +15 -0
  112. package/node_modules/@poe-code/safe-fs/dist/config.js +46 -0
  113. package/node_modules/@poe-code/safe-fs/dist/config.node.d.ts +2 -0
  114. package/node_modules/@poe-code/safe-fs/dist/config.node.js +11 -0
  115. package/node_modules/@poe-code/safe-fs/dist/config.portable.d.ts +3 -0
  116. package/node_modules/@poe-code/safe-fs/dist/config.portable.js +9 -0
  117. package/node_modules/@poe-code/safe-fs/dist/contracts/abort.d.ts +5 -0
  118. package/node_modules/@poe-code/safe-fs/dist/contracts/abort.js +34 -0
  119. package/node_modules/@poe-code/safe-fs/dist/contracts/cleanup.d.ts +1 -0
  120. package/node_modules/@poe-code/safe-fs/dist/contracts/cleanup.js +9 -0
  121. package/node_modules/@poe-code/safe-fs/dist/contracts/descriptor.d.ts +38 -0
  122. package/node_modules/@poe-code/safe-fs/dist/contracts/descriptor.js +1 -0
  123. package/node_modules/@poe-code/safe-fs/dist/contracts/errors.d.ts +53 -0
  124. package/node_modules/@poe-code/safe-fs/dist/contracts/errors.js +99 -0
  125. package/node_modules/@poe-code/safe-fs/dist/contracts/filesystem.d.ts +379 -0
  126. package/node_modules/@poe-code/safe-fs/dist/contracts/filesystem.js +1 -0
  127. package/node_modules/@poe-code/safe-fs/dist/contracts/index.d.ts +6 -0
  128. package/node_modules/@poe-code/safe-fs/dist/contracts/index.js +6 -0
  129. package/node_modules/@poe-code/safe-fs/dist/contracts/io.d.ts +12 -0
  130. package/node_modules/@poe-code/safe-fs/dist/contracts/io.js +321 -0
  131. package/node_modules/@poe-code/safe-fs/dist/contracts/object.d.ts +134 -0
  132. package/node_modules/@poe-code/safe-fs/dist/contracts/object.js +97 -0
  133. package/node_modules/@poe-code/safe-fs/dist/contracts/path.d.ts +3 -0
  134. package/node_modules/@poe-code/safe-fs/dist/contracts/path.js +2 -0
  135. package/node_modules/@poe-code/safe-fs/dist/contracts/portable-path.d.ts +21 -0
  136. package/node_modules/@poe-code/safe-fs/dist/contracts/portable-path.js +78 -0
  137. package/node_modules/@poe-code/safe-fs/dist/contracts/virtual-path.d.ts +15 -0
  138. package/node_modules/@poe-code/safe-fs/dist/contracts/virtual-path.js +162 -0
  139. package/node_modules/@poe-code/safe-fs/dist/core.d.ts +19 -0
  140. package/node_modules/@poe-code/safe-fs/dist/core.js +17 -0
  141. package/node_modules/@poe-code/safe-fs/dist/fs/capabilities.d.ts +10 -0
  142. package/node_modules/@poe-code/safe-fs/dist/fs/capabilities.js +216 -0
  143. package/node_modules/@poe-code/safe-fs/dist/fs/conditional-chmod.d.ts +7 -0
  144. package/node_modules/@poe-code/safe-fs/dist/fs/conditional-chmod.js +19 -0
  145. package/node_modules/@poe-code/safe-fs/dist/fs/descriptor.d.ts +21 -0
  146. package/node_modules/@poe-code/safe-fs/dist/fs/descriptor.js +279 -0
  147. package/node_modules/@poe-code/safe-fs/dist/fs/devices/index.d.ts +59 -0
  148. package/node_modules/@poe-code/safe-fs/dist/fs/devices/index.js +875 -0
  149. package/node_modules/@poe-code/safe-fs/dist/fs/devices/path.d.ts +7 -0
  150. package/node_modules/@poe-code/safe-fs/dist/fs/devices/path.js +250 -0
  151. package/node_modules/@poe-code/safe-fs/dist/fs/devices/stream.d.ts +6 -0
  152. package/node_modules/@poe-code/safe-fs/dist/fs/devices/stream.js +136 -0
  153. package/node_modules/@poe-code/safe-fs/dist/fs/directory-admission.d.ts +3 -0
  154. package/node_modules/@poe-code/safe-fs/dist/fs/directory-admission.js +14 -0
  155. package/node_modules/@poe-code/safe-fs/dist/fs/memory/atomic-view.d.ts +11 -0
  156. package/node_modules/@poe-code/safe-fs/dist/fs/memory/atomic-view.js +13 -0
  157. package/node_modules/@poe-code/safe-fs/dist/fs/memory/index.d.ts +186 -0
  158. package/node_modules/@poe-code/safe-fs/dist/fs/memory/index.js +3771 -0
  159. package/node_modules/@poe-code/safe-fs/dist/fs/memory/ledger.d.ts +26 -0
  160. package/node_modules/@poe-code/safe-fs/dist/fs/memory/ledger.js +96 -0
  161. package/node_modules/@poe-code/safe-fs/dist/fs/memory/limits.d.ts +13 -0
  162. package/node_modules/@poe-code/safe-fs/dist/fs/memory/limits.js +26 -0
  163. package/node_modules/@poe-code/safe-fs/dist/fs/memory/missing-target.d.ts +15 -0
  164. package/node_modules/@poe-code/safe-fs/dist/fs/memory/missing-target.js +144 -0
  165. package/node_modules/@poe-code/safe-fs/dist/fs/mount/comparison.d.ts +19 -0
  166. package/node_modules/@poe-code/safe-fs/dist/fs/mount/comparison.js +118 -0
  167. package/node_modules/@poe-code/safe-fs/dist/fs/mount/identity.d.ts +6 -0
  168. package/node_modules/@poe-code/safe-fs/dist/fs/mount/identity.js +29 -0
  169. package/node_modules/@poe-code/safe-fs/dist/fs/mount/index.d.ts +74 -0
  170. package/node_modules/@poe-code/safe-fs/dist/fs/mount/index.js +1291 -0
  171. package/node_modules/@poe-code/safe-fs/dist/fs/object-authority.d.ts +27 -0
  172. package/node_modules/@poe-code/safe-fs/dist/fs/object-authority.js +287 -0
  173. package/node_modules/@poe-code/safe-fs/dist/fs/object-publication/index.d.ts +45 -0
  174. package/node_modules/@poe-code/safe-fs/dist/fs/object-publication/index.js +531 -0
  175. package/node_modules/@poe-code/safe-fs/dist/fs/overlay/index.d.ts +87 -0
  176. package/node_modules/@poe-code/safe-fs/dist/fs/overlay/index.js +1185 -0
  177. package/node_modules/@poe-code/safe-fs/dist/fs/overlay/memory-publication.d.ts +42 -0
  178. package/node_modules/@poe-code/safe-fs/dist/fs/overlay/memory-publication.js +558 -0
  179. package/node_modules/@poe-code/safe-fs/dist/fs/path-namespace.d.ts +4 -0
  180. package/node_modules/@poe-code/safe-fs/dist/fs/path-namespace.js +63 -0
  181. package/node_modules/@poe-code/safe-fs/dist/fs/quota/index.d.ts +12 -0
  182. package/node_modules/@poe-code/safe-fs/dist/fs/quota/index.js +520 -0
  183. package/node_modules/@poe-code/safe-fs/dist/fs/readonly/index.d.ts +37 -0
  184. package/node_modules/@poe-code/safe-fs/dist/fs/readonly/index.js +208 -0
  185. package/node_modules/@poe-code/safe-fs/dist/fs/real/allocation.d.ts +1 -0
  186. package/node_modules/@poe-code/safe-fs/dist/fs/real/allocation.js +8 -0
  187. package/node_modules/@poe-code/safe-fs/dist/fs/real/index.d.ts +105 -0
  188. package/node_modules/@poe-code/safe-fs/dist/fs/real/index.js +1259 -0
  189. package/node_modules/@poe-code/safe-fs/dist/fs/s3/authority.d.ts +7 -0
  190. package/node_modules/@poe-code/safe-fs/dist/fs/s3/authority.js +38 -0
  191. package/node_modules/@poe-code/safe-fs/dist/fs/s3/filesystem.d.ts +130 -0
  192. package/node_modules/@poe-code/safe-fs/dist/fs/s3/filesystem.js +1137 -0
  193. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/bytes.d.ts +1 -0
  194. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/bytes.js +9 -0
  195. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/index.d.ts +2 -0
  196. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/index.js +1 -0
  197. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/request-fetch.d.ts +15 -0
  198. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/request-fetch.js +74 -0
  199. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/request-node.d.ts +4 -0
  200. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/request-node.js +111 -0
  201. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/request.d.ts +17 -0
  202. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/request.js +89 -0
  203. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/signature.d.ts +20 -0
  204. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/signature.js +76 -0
  205. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/transport.d.ts +3 -0
  206. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/transport.js +478 -0
  207. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/types.d.ts +30 -0
  208. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/types.js +1 -0
  209. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/xml.d.ts +14 -0
  210. package/node_modules/@poe-code/safe-fs/dist/fs/s3/http/xml.js +192 -0
  211. package/node_modules/@poe-code/safe-fs/dist/fs/s3/index.d.ts +8 -0
  212. package/node_modules/@poe-code/safe-fs/dist/fs/s3/index.js +4 -0
  213. package/node_modules/@poe-code/safe-fs/dist/fs/s3/key-order.d.ts +2 -0
  214. package/node_modules/@poe-code/safe-fs/dist/fs/s3/key-order.js +11 -0
  215. package/node_modules/@poe-code/safe-fs/dist/fs/s3/manifest-admission.d.ts +8 -0
  216. package/node_modules/@poe-code/safe-fs/dist/fs/s3/manifest-admission.js +167 -0
  217. package/node_modules/@poe-code/safe-fs/dist/fs/s3/mock.d.ts +48 -0
  218. package/node_modules/@poe-code/safe-fs/dist/fs/s3/mock.js +249 -0
  219. package/node_modules/@poe-code/safe-fs/dist/fs/s3/namespace.d.ts +13 -0
  220. package/node_modules/@poe-code/safe-fs/dist/fs/s3/namespace.js +400 -0
  221. package/node_modules/@poe-code/safe-fs/dist/fs/s3/registry.d.ts +10 -0
  222. package/node_modules/@poe-code/safe-fs/dist/fs/s3/registry.js +73 -0
  223. package/node_modules/@poe-code/safe-fs/dist/fs/s3/transport.d.ts +103 -0
  224. package/node_modules/@poe-code/safe-fs/dist/fs/s3/transport.js +28 -0
  225. package/node_modules/@poe-code/safe-fs/dist/fs/scoped.d.ts +19 -0
  226. package/node_modules/@poe-code/safe-fs/dist/fs/scoped.js +663 -0
  227. package/node_modules/@poe-code/safe-fs/dist/fs/staging-ancestry.d.ts +8 -0
  228. package/node_modules/@poe-code/safe-fs/dist/fs/staging-ancestry.js +115 -0
  229. package/node_modules/@poe-code/safe-fs/dist/fs/staging-cleanup.d.ts +5 -0
  230. package/node_modules/@poe-code/safe-fs/dist/fs/staging-cleanup.js +63 -0
  231. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/index.d.ts +2 -0
  232. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/index.js +1 -0
  233. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/resource-id.d.ts +18 -0
  234. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/resource-id.js +109 -0
  235. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/webdav.d.ts +141 -0
  236. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/webdav.js +1377 -0
  237. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/xml.d.ts +15 -0
  238. package/node_modules/@poe-code/safe-fs/dist/fs/webdav/xml.js +59 -0
  239. package/node_modules/@poe-code/safe-fs/dist/index.d.ts +25 -0
  240. package/node_modules/@poe-code/safe-fs/dist/index.js +21 -0
  241. package/node_modules/@poe-code/safe-fs/dist/native/fs-seek/linux-x64-glibc.node +0 -0
  242. package/node_modules/@poe-code/safe-fs/dist/native/fs-seek/loader.d.ts +5 -0
  243. package/node_modules/@poe-code/safe-fs/dist/native/fs-seek/loader.mjs +120 -0
  244. package/node_modules/@poe-code/safe-fs/dist/native/fs-seek/manifest.json +46 -0
  245. package/node_modules/@poe-code/safe-fs/dist/node/filesystem.d.ts +19 -0
  246. package/node_modules/@poe-code/safe-fs/dist/node/filesystem.js +30 -0
  247. package/node_modules/@poe-code/safe-fs/dist/node/host.d.ts +3 -0
  248. package/node_modules/@poe-code/safe-fs/dist/node/host.js +78 -0
  249. package/node_modules/@poe-code/safe-fs/dist/node/index.d.ts +3 -0
  250. package/node_modules/@poe-code/safe-fs/dist/node/index.js +2 -0
  251. package/node_modules/@poe-code/safe-fs/dist/node/native-seek-unavailable.d.ts +1 -0
  252. package/node_modules/@poe-code/safe-fs/dist/node/native-seek-unavailable.js +5 -0
  253. package/node_modules/@poe-code/safe-fs/dist/node/native-seek.d.ts +3 -0
  254. package/node_modules/@poe-code/safe-fs/dist/node/native-seek.js +54 -0
  255. package/node_modules/@poe-code/safe-fs/dist/node/stats.d.ts +1 -0
  256. package/node_modules/@poe-code/safe-fs/dist/node/stats.js +1 -0
  257. package/node_modules/@poe-code/safe-fs/dist/node/values.d.ts +1 -0
  258. package/node_modules/@poe-code/safe-fs/dist/node/values.js +1 -0
  259. package/node_modules/@poe-code/safe-fs/dist/node-host.d.ts +1 -0
  260. package/node_modules/@poe-code/safe-fs/dist/node-host.js +1 -0
  261. package/node_modules/@poe-code/safe-fs/dist/node-unavailable.d.ts +1 -0
  262. package/node_modules/@poe-code/safe-fs/dist/node-unavailable.js +1 -0
  263. package/node_modules/@poe-code/safe-fs/dist/package.json +29 -0
  264. package/node_modules/@poe-code/safe-fs/dist/platform/browser-path.d.ts +1 -0
  265. package/node_modules/@poe-code/safe-fs/dist/platform/browser-path.js +1 -0
  266. package/node_modules/@poe-code/safe-fs/dist/platform/browser.d.ts +26 -0
  267. package/node_modules/@poe-code/safe-fs/dist/platform/browser.js +58 -0
  268. package/node_modules/@poe-code/safe-fs/dist/platform/node-path.d.ts +1 -0
  269. package/node_modules/@poe-code/safe-fs/dist/platform/node-path.js +1 -0
  270. package/node_modules/@poe-code/safe-fs/dist/platform/node.d.ts +26 -0
  271. package/node_modules/@poe-code/safe-fs/dist/platform/node.js +64 -0
  272. package/node_modules/@poe-code/safe-fs/dist/platform/transport-budget.d.ts +9 -0
  273. package/node_modules/@poe-code/safe-fs/dist/platform/transport-budget.js +17 -0
  274. package/node_modules/@poe-code/safe-fs/dist/python/emscripten.d.ts +15 -0
  275. package/node_modules/@poe-code/safe-fs/dist/python/emscripten.js +357 -0
  276. package/node_modules/@poe-code/safe-fs/dist/python/filesystem.d.ts +51 -0
  277. package/node_modules/@poe-code/safe-fs/dist/python/filesystem.js +243 -0
  278. package/node_modules/@poe-code/safe-fs/dist/python/flags.d.ts +3 -0
  279. package/node_modules/@poe-code/safe-fs/dist/python/flags.js +14 -0
  280. package/node_modules/@poe-code/safe-fs/dist/python/index.d.ts +9 -0
  281. package/node_modules/@poe-code/safe-fs/dist/python/index.js +5 -0
  282. package/node_modules/@poe-code/safe-fs/dist/python/native.d.ts +18 -0
  283. package/node_modules/@poe-code/safe-fs/dist/python/native.js +446 -0
  284. package/node_modules/@poe-code/safe-fs/dist/python/request.d.ts +2 -0
  285. package/node_modules/@poe-code/safe-fs/dist/python/request.js +61 -0
  286. package/node_modules/@poe-code/safe-fs/dist/python/stat.d.ts +8 -0
  287. package/node_modules/@poe-code/safe-fs/dist/python/stat.js +34 -0
  288. package/node_modules/@poe-code/safe-fs/dist/runtime-core.d.ts +27 -0
  289. package/node_modules/@poe-code/safe-fs/dist/runtime-core.js +57 -0
  290. package/node_modules/@poe-code/safe-fs/dist/testing/atomic-filesystem.d.ts +16 -0
  291. package/node_modules/@poe-code/safe-fs/dist/testing/atomic-filesystem.js +496 -0
  292. package/node_modules/@poe-code/safe-fs/dist/testing/object-io-control.d.ts +23 -0
  293. package/node_modules/@poe-code/safe-fs/dist/testing/object-io-control.js +39 -0
  294. package/node_modules/@poe-code/safe-fs/dist/testing/object-io-metrics.d.ts +31 -0
  295. package/node_modules/@poe-code/safe-fs/dist/testing/object-io-metrics.js +143 -0
  296. package/node_modules/@poe-code/safe-fs/dist/testing/object-publication.d.ts +19 -0
  297. package/node_modules/@poe-code/safe-fs/dist/testing/object-publication.js +209 -0
  298. package/node_modules/@poe-code/safe-fs/dist/xml.d.ts +1 -0
  299. package/node_modules/@poe-code/safe-fs/dist/xml.js +1 -0
  300. package/node_modules/@poe-code/safe-fs/package.json +189 -0
  301. package/node_modules/@poe-code/task-list/README.md +2 -0
  302. package/node_modules/@poe-code/task-list/dist/backends/gh-issues-client.d.ts +1 -1
  303. package/node_modules/@poe-code/task-list/dist/backends/gh-issues-client.js +11 -4
  304. package/node_modules/@poe-code/task-list/dist/backends/markdown-dir.js +2 -2
  305. package/node_modules/@poe-code/task-list/dist/backends/utils.js +5 -7
  306. package/node_modules/@poe-code/task-list/dist/backends/yaml-file.js +1 -1
  307. package/node_modules/@poe-code/task-list/dist/default-host.d.ts +2 -0
  308. package/node_modules/@poe-code/task-list/dist/default-host.js +2 -0
  309. package/node_modules/@poe-code/task-list/dist/default-host.workerd.d.ts +4 -0
  310. package/node_modules/@poe-code/task-list/dist/default-host.workerd.js +6 -0
  311. package/node_modules/@poe-code/task-list/dist/filesystem.d.ts +3 -0
  312. package/node_modules/@poe-code/task-list/dist/filesystem.js +32 -0
  313. package/node_modules/@poe-code/task-list/dist/move.js +3 -3
  314. package/node_modules/@poe-code/task-list/dist/open.js +2 -5
  315. package/node_modules/@poe-code/task-list/dist/paths.d.ts +12 -0
  316. package/node_modules/@poe-code/task-list/dist/paths.js +7 -0
  317. package/node_modules/@poe-code/task-list/dist/types.d.ts +6 -5
  318. package/node_modules/@poe-code/task-list/package.json +9 -0
  319. package/node_modules/@poe-code/terminal-text/LICENSE +21 -0
  320. package/node_modules/@poe-code/terminal-text/README.md +12 -0
  321. package/node_modules/@poe-code/terminal-text/dist/index.d.ts +2 -0
  322. package/node_modules/@poe-code/terminal-text/dist/index.js +20 -0
  323. package/node_modules/@poe-code/terminal-text/package.json +22 -0
  324. package/node_modules/@poe-code/xml-ast/LICENSE +21 -0
  325. package/node_modules/@poe-code/xml-ast/README.md +28 -0
  326. package/node_modules/@poe-code/xml-ast/dist/index.d.ts +47 -0
  327. package/node_modules/@poe-code/xml-ast/dist/index.js +635 -0
  328. package/node_modules/@poe-code/xml-ast/package.json +25 -0
  329. package/node_modules/auth-store/README.md +35 -0
  330. package/node_modules/auth-store/dist/index.browser.d.ts +4 -0
  331. package/node_modules/auth-store/dist/index.browser.js +2 -0
  332. package/node_modules/auth-store/dist/provider-store.d.ts +1 -1
  333. package/node_modules/auth-store/dist/safe-fs-secret-store.d.ts +21 -0
  334. package/node_modules/auth-store/dist/safe-fs-secret-store.js +119 -0
  335. package/node_modules/auth-store/dist/secret-store.d.ts +12 -0
  336. package/node_modules/auth-store/dist/secret-store.js +1 -0
  337. package/node_modules/auth-store/dist/transaction-lock.d.ts +2 -4
  338. package/node_modules/auth-store/dist/types.d.ts +2 -9
  339. package/node_modules/auth-store/package.json +16 -2
  340. package/node_modules/tiny-http-mcp-server/dist/composition.json +16 -1
  341. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/README.md +25 -0
  342. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/authorization-state.js +4 -4
  343. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +6 -40
  344. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/oauth-form.d.ts +10 -0
  345. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/oauth-form.js +20 -0
  346. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/pkce.js +4 -3
  347. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/register-client.d.ts +14 -0
  348. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/register-client.js +53 -0
  349. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/resumable.d.ts +16 -2
  350. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/resumable.js +29 -9
  351. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/revoke-token.d.ts +12 -0
  352. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/revoke-token.js +23 -0
  353. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +6 -19
  354. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/http-fetch.js +1 -1
  355. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.browser.d.ts +6 -2
  356. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.browser.js +5 -1
  357. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.d.ts +5 -2
  358. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.js +4 -1
  359. package/node_modules/tiny-http-mcp-server/package.json +4 -4
  360. package/node_modules/tiny-mcp-client/README.md +2 -0
  361. package/node_modules/tiny-mcp-client/dist/index.browser.d.ts +25 -23
  362. package/node_modules/tiny-mcp-client/dist/index.browser.js +116 -1
  363. package/node_modules/tiny-mcp-client/dist/index.d.ts +25 -23
  364. package/node_modules/tiny-mcp-client/dist/index.js +1034 -561
  365. package/node_modules/tiny-mcp-client/package.json +15 -0
  366. package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
  367. package/node_modules/toolcraft-design/dist/components/table.js +6 -0
  368. package/node_modules/toolcraft-design/dist/escape-terminal-text.d.ts +1 -2
  369. package/node_modules/toolcraft-design/dist/escape-terminal-text.js +1 -20
  370. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.js +2 -1
  371. package/node_modules/toolcraft-design/dist/terminal-markdown/parser.js +2 -1
  372. package/node_modules/toolcraft-schema/dist/json-schema/utils.js +3 -0
  373. package/node_modules/toolcraft-schema/package.json +1 -1
  374. package/package.json +32 -7
@@ -0,0 +1,3771 @@
1
+ import { FsError } from "../../contracts/errors.js";
2
+ import { normalizePath, validatePath, pathByteLength } from "../../contracts/virtual-path.js";
3
+ import { assertCallbackAuthorityAllowed, compareEntries, registerEntryAuthority } from "../mount/comparison.js";
4
+ import { getOwnedS3Entry } from "../s3/registry.js";
5
+ import { getOwnedWebDavEntry } from "../webdav/resource-id.js";
6
+ import { admitDirectoryEntries, directoryEntryLimit } from "../directory-admission.js";
7
+ import { openFileDescriptor } from "../descriptor.js";
8
+ import { directoryAncestryPaths, runStagingGuard, snapshotDirectoryAncestry, snapshotStagingResolution } from "../staging-ancestry.js";
9
+ import { compareIdentity } from "../mount/identity.js";
10
+ import { createStagingCleanup, snapshotStagingCreation } from "../staging-cleanup.js";
11
+ import { resolveMissingTarget } from "./missing-target.js";
12
+ import { registerLazyMemoryAtomicView } from "./atomic-view.js";
13
+ import { snapshotConditionalChmod } from "../conditional-chmod.js";
14
+ import { MemoryAllocation, MemoryLedger } from "./ledger.js";
15
+ import { normalizeMemoryFileSystemLimits } from "./limits.js";
16
+ export { defaultMemoryFileSystemLimits } from "./limits.js";
17
+ class MemoryFileNode {
18
+ constructor(mode, ino, now, byteLength, allocation, view, sourceRef) {
19
+ this.revision = 0;
20
+ this.mode = mode;
21
+ this.ino = ino;
22
+ this.nlink = 1;
23
+ this.atimeMs = now;
24
+ this.mtimeMs = now;
25
+ this.ctimeMs = now;
26
+ this.birthtimeMs = now;
27
+ this.references = 0;
28
+ this.byteLength = byteLength;
29
+ this.allocation = allocation;
30
+ this.view = view;
31
+ this.sourceRef = sourceRef;
32
+ }
33
+ get data() {
34
+ return this.view ??= (this.byteLength === this.allocation.data.byteLength ? this.allocation.data : this.allocation.data.subarray(0, this.byteLength));
35
+ }
36
+ set data(value) {
37
+ this.view = value;
38
+ this.byteLength = value.byteLength;
39
+ }
40
+ }
41
+ Object.assign(MemoryFileNode.prototype, {
42
+ type: "file",
43
+ revision: 0,
44
+ nlink: 1,
45
+ references: 0,
46
+ sourceRef: undefined,
47
+ });
48
+ const EMPTY_ALLOC_BYTES = new Uint8Array(0);
49
+ const DUMMY_POOL_LEDGER = new MemoryLedger(normalizeMemoryFileSystemLimits({}));
50
+ const DUMMY_POOL_ALLOCATION = new MemoryAllocation(EMPTY_ALLOC_BYTES, DUMMY_POOL_LEDGER);
51
+ const DUMMY_POOL_FILE_NODE = new MemoryFileNode(0, 0, null, 0, DUMMY_POOL_ALLOCATION, DUMMY_POOL_ALLOCATION.data);
52
+ DUMMY_POOL_FILE_NODE.atimeMs = DUMMY_POOL_FILE_NODE.mtimeMs = DUMMY_POOL_FILE_NODE.ctimeMs = DUMMY_POOL_FILE_NODE.birthtimeMs = 1700000000000;
53
+ const EMPTY_DIR_TABLE = new Int16Array(0);
54
+ const EMPTY_DIR_KEYS = [];
55
+ const EMPTY_DIR_VALS = [];
56
+ class FastDirectoryEntriesMap {
57
+ // Keep speculative slots local so a failed write cannot pin a tenant globally.
58
+ _missKey = "";
59
+ _missSlot = -1;
60
+ _table = EMPTY_DIR_TABLE;
61
+ _mask = 0;
62
+ _keys = EMPTY_DIR_KEYS;
63
+ _vals = EMPTY_DIR_VALS;
64
+ _next = 0;
65
+ size = 0;
66
+ [Symbol.toStringTag] = "Map";
67
+ _hash(k) {
68
+ let h = 5381;
69
+ for (let i = 0; i < k.length; i++) {
70
+ h = (((h & 0x1fffff) * 33) ^ k.charCodeAt(i)) & 0x3fffffff;
71
+ }
72
+ return h & this._mask;
73
+ }
74
+ get(k) {
75
+ if (this.size === 0)
76
+ return undefined;
77
+ let slot = this._hash(k);
78
+ const mask = this._mask;
79
+ const table = this._table;
80
+ const keys = this._keys;
81
+ while (true) {
82
+ const idx = table[slot];
83
+ if (idx === -1)
84
+ return undefined;
85
+ if (idx >= 0 && keys[idx] === k)
86
+ return this._vals[idx];
87
+ slot = (slot + 1) & mask;
88
+ }
89
+ }
90
+ getForWrite(k) {
91
+ return this.getForWriteWithHash(k, this._hash(k));
92
+ }
93
+ getForWriteWithHash(k, h) {
94
+ let slot = h & this._mask;
95
+ if (this.size === 0) {
96
+ if (this._keys.length === 0) {
97
+ this._missKey = "";
98
+ this._missSlot = -1;
99
+ return undefined;
100
+ }
101
+ this._missKey = k;
102
+ this._missSlot = slot;
103
+ return undefined;
104
+ }
105
+ const mask = this._mask;
106
+ const table = this._table;
107
+ const keys = this._keys;
108
+ let firstDeleted = -1;
109
+ while (true) {
110
+ const idx = table[slot];
111
+ if (idx === -1) {
112
+ this._missKey = k;
113
+ this._missSlot = firstDeleted !== -1 ? firstDeleted : slot;
114
+ return undefined;
115
+ }
116
+ if (idx === -2) {
117
+ if (firstDeleted === -1)
118
+ firstDeleted = slot;
119
+ }
120
+ else if (keys[idx] === k) {
121
+ return this._vals[idx];
122
+ }
123
+ slot = (slot + 1) & mask;
124
+ }
125
+ }
126
+ getSubstr(s, start, end) {
127
+ if (this.size === 0)
128
+ return undefined;
129
+ const len = end - start;
130
+ let h = 5381;
131
+ for (let i = start; i < end; i++) {
132
+ h = (((h & 0x1fffff) * 33) ^ s.charCodeAt(i)) & 0x3fffffff;
133
+ }
134
+ let slot = h & this._mask;
135
+ const mask = this._mask;
136
+ const table = this._table;
137
+ const keys = this._keys;
138
+ while (true) {
139
+ const idx = table[slot];
140
+ if (idx === -1)
141
+ return undefined;
142
+ if (idx >= 0) {
143
+ const k = keys[idx];
144
+ if (k.length === len) {
145
+ let match = true;
146
+ for (let i = 0; i < len; i++) {
147
+ if (k.charCodeAt(i) !== s.charCodeAt(start + i)) {
148
+ match = false;
149
+ break;
150
+ }
151
+ }
152
+ if (match)
153
+ return this._vals[idx];
154
+ }
155
+ }
156
+ slot = (slot + 1) & mask;
157
+ }
158
+ }
159
+ has(k) {
160
+ return this.get(k) !== undefined;
161
+ }
162
+ _rebuild(newCap) {
163
+ this._missKey = "";
164
+ this._missSlot = -1;
165
+ const newTableLen = newCap * 2;
166
+ const newMask = newTableLen - 1;
167
+ const newTable = newCap <= 16384 ? new Int16Array(newTableLen).fill(-1) : new Int32Array(newTableLen).fill(-1);
168
+ const oldKeys = this._keys;
169
+ const oldVals = this._vals;
170
+ const oldNext = this._next;
171
+ const newKeys = newCap === oldKeys.length ? oldKeys : new Array(newCap).fill("");
172
+ const newVals = newCap === oldVals.length ? oldVals : new Array(newCap).fill(DUMMY_POOL_FILE_NODE);
173
+ let writeIdx = 0;
174
+ for (let i = 0; i < oldNext; i++) {
175
+ const v = oldVals[i];
176
+ if (v === DUMMY_POOL_FILE_NODE)
177
+ continue;
178
+ const k = oldKeys[i];
179
+ newKeys[writeIdx] = k;
180
+ newVals[writeIdx] = v;
181
+ let h = 5381;
182
+ for (let c = 0; c < k.length; c++) {
183
+ h = (((h & 0x1fffff) * 33) ^ k.charCodeAt(c)) & 0x3fffffff;
184
+ }
185
+ let slot = h & newMask;
186
+ while (newTable[slot] !== -1) {
187
+ slot = (slot + 1) & newMask;
188
+ }
189
+ newTable[slot] = writeIdx++;
190
+ }
191
+ if (newKeys === oldKeys) {
192
+ for (let i = writeIdx; i < oldNext; i++) {
193
+ newKeys[i] = "";
194
+ newVals[i] = DUMMY_POOL_FILE_NODE;
195
+ }
196
+ }
197
+ this._table = newTable;
198
+ this._mask = newMask;
199
+ this._keys = newKeys;
200
+ this._vals = newVals;
201
+ this._next = writeIdx;
202
+ }
203
+ set(k, v) {
204
+ const missSlot = k === this._missKey ? this._missSlot : -1;
205
+ this._missKey = "";
206
+ this._missSlot = -1;
207
+ if (missSlot >= 0 && (this._table[missSlot] === -1 || this._table[missSlot] === -2) && this._next < this._keys.length) {
208
+ const entryIdx = this._next++;
209
+ this._table[missSlot] = entryIdx;
210
+ this._keys[entryIdx] = k;
211
+ this._vals[entryIdx] = v;
212
+ this.size++;
213
+ return this;
214
+ }
215
+ if (this._next >= this._keys.length) {
216
+ this._rebuild(this._keys.length === 0 ? 8 : (this.size * 2 <= this._keys.length ? this._keys.length : this._keys.length * 2));
217
+ }
218
+ let slot = this._hash(k);
219
+ const mask = this._mask;
220
+ const table = this._table;
221
+ const keys = this._keys;
222
+ let firstDeleted = -1;
223
+ while (true) {
224
+ const idx = table[slot];
225
+ if (idx === -1) {
226
+ const targetSlot = firstDeleted !== -1 ? firstDeleted : slot;
227
+ const entryIdx = this._next++;
228
+ table[targetSlot] = entryIdx;
229
+ keys[entryIdx] = k;
230
+ this._vals[entryIdx] = v;
231
+ this.size++;
232
+ return this;
233
+ }
234
+ if (idx === -2) {
235
+ if (firstDeleted === -1)
236
+ firstDeleted = slot;
237
+ }
238
+ else if (keys[idx] === k) {
239
+ this._vals[idx] = v;
240
+ return this;
241
+ }
242
+ slot = (slot + 1) & mask;
243
+ }
244
+ }
245
+ delete(k) {
246
+ this._missKey = "";
247
+ this._missSlot = -1;
248
+ if (this.size === 0)
249
+ return false;
250
+ let slot = this._hash(k);
251
+ const mask = this._mask;
252
+ const table = this._table;
253
+ const keys = this._keys;
254
+ while (true) {
255
+ const idx = table[slot];
256
+ if (idx === -1)
257
+ return false;
258
+ if (idx >= 0 && keys[idx] === k) {
259
+ if (this.size === 1) {
260
+ this.clear();
261
+ return true;
262
+ }
263
+ table[slot] = -2;
264
+ keys[idx] = "";
265
+ this._vals[idx] = DUMMY_POOL_FILE_NODE;
266
+ // Keep deleted indices until compaction: reusing the tail would let
267
+ // tombstones fill the table without reaching set()'s rebuild threshold.
268
+ this.size--;
269
+ return true;
270
+ }
271
+ slot = (slot + 1) & mask;
272
+ }
273
+ }
274
+ clear() {
275
+ this._missKey = "";
276
+ this._missSlot = -1;
277
+ if (this._next > 0) {
278
+ this._table.fill(-1);
279
+ for (let i = 0; i < this._next; i++) {
280
+ this._keys[i] = "";
281
+ this._vals[i] = DUMMY_POOL_FILE_NODE;
282
+ }
283
+ this._next = 0;
284
+ this.size = 0;
285
+ }
286
+ }
287
+ forEach(callbackfn, thisArg) {
288
+ const next = this._next;
289
+ const keys = this._keys;
290
+ const vals = this._vals;
291
+ for (let i = 0; i < next; i++) {
292
+ const v = vals[i];
293
+ if (v !== DUMMY_POOL_FILE_NODE) {
294
+ if (thisArg !== undefined)
295
+ callbackfn.call(thisArg, v, keys[i], this);
296
+ else
297
+ callbackfn(v, keys[i], this);
298
+ }
299
+ }
300
+ }
301
+ *keys() {
302
+ for (let i = 0; i < this._next; i++) {
303
+ if (this._vals[i] !== DUMMY_POOL_FILE_NODE)
304
+ yield this._keys[i];
305
+ }
306
+ }
307
+ *values() {
308
+ for (let i = 0; i < this._next; i++) {
309
+ const v = this._vals[i];
310
+ if (v !== DUMMY_POOL_FILE_NODE)
311
+ yield v;
312
+ }
313
+ }
314
+ *entries() {
315
+ for (let i = 0; i < this._next; i++) {
316
+ const v = this._vals[i];
317
+ if (v !== DUMMY_POOL_FILE_NODE)
318
+ yield [this._keys[i], v];
319
+ }
320
+ }
321
+ [Symbol.iterator]() {
322
+ return this.entries();
323
+ }
324
+ }
325
+ const SHARED_POOL_CAPACITY = 256;
326
+ const SHARED_DIR_POOL_CAPACITY = 64;
327
+ const sharedFileNodePool = new Array(SHARED_POOL_CAPACITY).fill(DUMMY_POOL_FILE_NODE);
328
+ let sharedFileNodePoolLen = 0;
329
+ const sharedDirectoryNodePool = new Array(SHARED_DIR_POOL_CAPACITY);
330
+ let sharedDirectoryNodePoolLen = 0;
331
+ const sharedRemovedScratch = new Array(SHARED_POOL_CAPACITY).fill(DUMMY_POOL_FILE_NODE);
332
+ let sharedRemovedLen = 0;
333
+ let sharedRemovedKeyChars = 0;
334
+ let sharedRemovedKeyEntries = 0;
335
+ function collectRemovedChild(child, name) {
336
+ if (sharedRemovedLen < sharedRemovedScratch.length) {
337
+ sharedRemovedScratch[sharedRemovedLen++] = child;
338
+ }
339
+ else {
340
+ sharedRemovedScratch.push(child);
341
+ sharedRemovedLen++;
342
+ }
343
+ sharedRemovedKeyChars += name.length;
344
+ sharedRemovedKeyEntries++;
345
+ }
346
+ function replenishSharedMemoryPools() {
347
+ while (sharedFileNodePoolLen < 112) {
348
+ sharedFileNodePool[sharedFileNodePoolLen++] = new MemoryFileNode(0, 0, 0, 0, DUMMY_POOL_ALLOCATION, undefined);
349
+ }
350
+ while (sharedDirectoryNodePoolLen < 16) {
351
+ sharedDirectoryNodePool[sharedDirectoryNodePoolLen++] = new MemoryDirectoryNode(0, 0, 0);
352
+ }
353
+ }
354
+ class MemoryDirectoryNode {
355
+ constructor(mode, ino, now) {
356
+ this.revision = 0;
357
+ this.mode = mode;
358
+ this.ino = ino;
359
+ this.nlink = 1;
360
+ this.references = 0;
361
+ this.atimeMs = now;
362
+ this.mtimeMs = now;
363
+ this.ctimeMs = now;
364
+ this.birthtimeMs = now;
365
+ this.entries = new FastDirectoryEntriesMap();
366
+ this.cachedNlink = 2;
367
+ this.cachedNlinkRev = 0;
368
+ }
369
+ }
370
+ Object.assign(MemoryDirectoryNode.prototype, {
371
+ type: "directory",
372
+ revision: 0,
373
+ nlink: 1,
374
+ references: 0,
375
+ cachedNlink: 2,
376
+ cachedNlinkRev: 0,
377
+ });
378
+ const DUMMY_POOL_DIR_NODE = new MemoryDirectoryNode(0, 0, null);
379
+ DUMMY_POOL_DIR_NODE.atimeMs = DUMMY_POOL_DIR_NODE.mtimeMs = DUMMY_POOL_DIR_NODE.ctimeMs = DUMMY_POOL_DIR_NODE.birthtimeMs = 1700000000000;
380
+ class MemoryCache {
381
+ files = [];
382
+ directories = [];
383
+ removedScratch = [];
384
+ lastFastDirPrefix = "";
385
+ lastFastDirNode = undefined;
386
+ lastFastFilePath = "";
387
+ lastFastFileName = "";
388
+ lastFastFileNode = undefined;
389
+ clearWrites() {
390
+ this.lastFastDirPrefix = "";
391
+ this.lastFastDirNode = undefined;
392
+ this.lastFastFilePath = "";
393
+ this.lastFastFileName = "";
394
+ this.lastFastFileNode = undefined;
395
+ }
396
+ }
397
+ const typeModes = { file: 0o100000, directory: 0o040000, symlink: 0o120000 };
398
+ const emptyResolveOptions = Object.freeze({});
399
+ const noFollowResolveOptions = Object.freeze({ followFinal: false });
400
+ const sharedAllowMissingNoFollowOptions = Object.freeze({ allowMissing: true, followFinal: false });
401
+ const sharedFastLocation = { node: undefined, parent: DUMMY_POOL_DIR_NODE, name: "", path: "" };
402
+ const resolvedVoid = Promise.resolve();
403
+ const preferredIoBlockSize = 64 * 1024;
404
+ const ext4HtreeEof64 = (1n << 63n) - 1n;
405
+ const extractionStreamGuard = Symbol("extractionStreamGuard");
406
+ const ownedStats = new WeakMap();
407
+ const ownedStores = new WeakMap();
408
+ // Ensure V8 uses Tagged representation for timestamp fields so all 4 fields share one HeapNumber pointer.
409
+ {
410
+ const dummyAlloc = new MemoryAllocation(new Uint8Array(0), new MemoryLedger(normalizeMemoryFileSystemLimits({})));
411
+ const dummyFile = new MemoryFileNode(0, 0, null, 0, dummyAlloc, dummyAlloc.data);
412
+ dummyFile.atimeMs = dummyFile.mtimeMs = dummyFile.ctimeMs = dummyFile.birthtimeMs = 1700000000000;
413
+ const dummyDir = new MemoryDirectoryNode(0, 0, null);
414
+ dummyDir.atimeMs = dummyDir.mtimeMs = dummyDir.ctimeMs = dummyDir.birthtimeMs = 1700000000000;
415
+ }
416
+ // Forwarded receivers share the ledger, so mutations invalidate the owner's cache.
417
+ const memoryCaches = new WeakMap();
418
+ const registeredAuthorities = new WeakSet();
419
+ const compareOwnedMemory = async (own, peer, options) => {
420
+ options.signal?.throwIfAborted();
421
+ let explicit = false;
422
+ let answer = "unknown";
423
+ const visited = new Set();
424
+ for (const [left, right] of [[own, peer], [peer, own]]) {
425
+ if (!registeredAuthorities.has(left.filesystem) || visited.has(left.filesystem))
426
+ continue;
427
+ visited.add(left.filesystem);
428
+ const comparison = left.filesystem.compareEntry;
429
+ if (comparison === memoryImplementation.compareEntry?.value)
430
+ continue;
431
+ explicit = true;
432
+ if (!comparison)
433
+ continue;
434
+ options.signal?.throwIfAborted();
435
+ assertCallbackAuthorityAllowed();
436
+ const result = await comparison.call(left.filesystem, left.path, right.filesystem, right.path, options);
437
+ options.signal?.throwIfAborted();
438
+ if (result !== "same" && result !== "distinct" && result !== "unknown") {
439
+ throw new FsError("EIO", { path: own.path, dest: peer.path, message: "invalid explicit Memory comparison" });
440
+ }
441
+ if (result === "unknown")
442
+ continue;
443
+ if (answer !== "unknown" && answer !== result) {
444
+ throw new FsError("EIO", { path: own.path, dest: peer.path, message: "conflicting explicit Memory comparisons" });
445
+ }
446
+ answer = result;
447
+ }
448
+ if (explicit)
449
+ return answer;
450
+ const owner = ownedStores.get(own.filesystem);
451
+ const observation = ownedStats.get(own.stat);
452
+ if (!owner?.intact() || observation?.filesystem !== own.filesystem || observation.path !== own.path
453
+ || observation.root !== owner.root)
454
+ return "unknown";
455
+ const qualified = getOwnedS3Entry(peer) ?? getOwnedWebDavEntry(peer);
456
+ options.signal?.throwIfAborted();
457
+ return qualified ? "distinct" : "unknown";
458
+ };
459
+ const activeConditionalMutations = new Map();
460
+ export async function bindConditionalMutation(identityScope, binding, action) {
461
+ if (identityScope === undefined || identityScope === null)
462
+ return action();
463
+ activeConditionalMutations.set(identityScope, binding);
464
+ try {
465
+ return await action();
466
+ }
467
+ finally {
468
+ if (activeConditionalMutations.get(identityScope) === binding) {
469
+ activeConditionalMutations.delete(identityScope);
470
+ }
471
+ }
472
+ }
473
+ const STREAM_DONE_RESULT = Object.freeze({ done: true, value: undefined });
474
+ const STREAM_RESOLVED_DONE = Promise.resolve(STREAM_DONE_RESULT);
475
+ class MemoryReadStream {
476
+ constructor(fs, path, options) {
477
+ this.fs = fs;
478
+ this.path = path;
479
+ this.options = options;
480
+ this.abortSignal = options.signal;
481
+ this.initialized = false;
482
+ this.finished = false;
483
+ this.offset = 0;
484
+ this.end = 0;
485
+ this.chunkSize = preferredIoBlockSize;
486
+ this.node = undefined;
487
+ this.allocation = undefined;
488
+ this.data = undefined;
489
+ }
490
+ [Symbol.asyncIterator]() {
491
+ if (this.initialized || this.finished) {
492
+ return new MemoryReadStream(this.fs, this.path, this.options);
493
+ }
494
+ return this;
495
+ }
496
+ _release() {
497
+ if (this.finished)
498
+ return;
499
+ this.finished = true;
500
+ if (this.allocation) {
501
+ this.allocation.release();
502
+ this.allocation = undefined;
503
+ }
504
+ if (this.node) {
505
+ const releasedNode = this.node;
506
+ this.node = undefined;
507
+ this.fs.releaseReference(releasedNode, this.path);
508
+ }
509
+ this.data = undefined;
510
+ }
511
+ tryNextSync() {
512
+ if (this.finished)
513
+ return STREAM_DONE_RESULT;
514
+ try {
515
+ const options = this.options;
516
+ options.signal?.throwIfAborted();
517
+ if (!this.initialized) {
518
+ this.initialized = true;
519
+ const fs = this.fs;
520
+ const path = this.path;
521
+ const start = options.start ?? 0;
522
+ const chunkSize = options.chunkSize ?? preferredIoBlockSize;
523
+ this.chunkSize = chunkSize;
524
+ fs.integer(start, "readStream", path);
525
+ fs.integer(chunkSize, "readStream", path);
526
+ if (chunkSize === 0)
527
+ fs.fail("EINVAL", "readStream", path);
528
+ if (options.endExclusive !== undefined) {
529
+ fs.integer(options.endExclusive, "readStream", path);
530
+ if (options.endExclusive < start)
531
+ fs.fail("EINVAL", "readStream", path);
532
+ }
533
+ const target = fs.file(path, "readStream");
534
+ fs.permission(target, 4, "readStream", path);
535
+ fs.ledger.reserve(path.length * 2, 1, "readStream", path);
536
+ target.references++;
537
+ this.node = target;
538
+ this.allocation = target.allocation;
539
+ target.allocation.retain();
540
+ const data = target.data;
541
+ this.data = data;
542
+ this.offset = start;
543
+ this.end = Math.min(options.endExclusive ?? data.byteLength, data.byteLength);
544
+ target.atimeMs = Date.now();
545
+ }
546
+ if (this.offset < this.end) {
547
+ const nextEnd = Math.min(this.offset + this.chunkSize, this.end);
548
+ const chunk = this.data.slice(this.offset, nextEnd);
549
+ this.offset = nextEnd;
550
+ return { done: false, value: chunk };
551
+ }
552
+ this._release();
553
+ return STREAM_DONE_RESULT;
554
+ }
555
+ catch (error) {
556
+ this._release();
557
+ throw error;
558
+ }
559
+ }
560
+ next() {
561
+ try {
562
+ const res = this.tryNextSync();
563
+ return res.done ? STREAM_RESOLVED_DONE : Promise.resolve(res);
564
+ }
565
+ catch (error) {
566
+ return Promise.reject(error);
567
+ }
568
+ }
569
+ return() {
570
+ this._release();
571
+ return STREAM_RESOLVED_DONE;
572
+ }
573
+ }
574
+ const SHARED_STOCK_MEMORY_CAPABILITIES = Object.freeze({
575
+ read: true, stat: true, readdir: true, realpath: true, access: true, open: true,
576
+ write: true, append: true, exclusiveCreate: true, explicitDirectories: true, implicitDirectories: false,
577
+ mkdir: true, recursiveMkdir: true, remove: true, removeDirectory: true, recursiveRemove: true,
578
+ rename: true, atomicRenameNoReplace: true, copy: true, exclusiveCopy: true, readlink: true, truncate: true,
579
+ streamingAppend: true, randomAccessWrite: true,
580
+ readOnly: false,
581
+ symlinks: true, conditionalChmod: true,
582
+ hardlinks: true,
583
+ permissions: true,
584
+ timestamps: true,
585
+ atomicRename: true,
586
+ atomicFileStaging: true, retainedStagingCleanup: true, retainedStagingWrite: true, atomicStagingAncestry: true, atomicFileMutation: true, atomicEntryRemoval: true, atomicEntryRemovalReceipt: true, atomicTreeRemoval: true,
587
+ synchronousDirectoryValidation: true, synchronousStagingResolution: true, guardedStagingPublication: true,
588
+ atomicDirectoryMetadata: true,
589
+ streamingRead: true,
590
+ retainedRead: true,
591
+ retainedResize: true,
592
+ streamingWrite: true,
593
+ descriptorWriteStream: true,
594
+ });
595
+ function customMemoryCapabilities(filesystem) {
596
+ return Object.freeze({
597
+ ...SHARED_STOCK_MEMORY_CAPABILITIES,
598
+ get retainedResize() { return stockRetainedResize(filesystem); },
599
+ get descriptorWriteStream() { return stockDescriptorWrite(filesystem); },
600
+ });
601
+ }
602
+ export class MemoryFileSystem {
603
+ capabilitiesFor;
604
+ #customCapabilities;
605
+ #identityScopeSym;
606
+ get identityScope() {
607
+ return (this.#identityScopeSym ??= Symbol());
608
+ }
609
+ get capabilities() {
610
+ if (!this.#customCapabilities) {
611
+ this.#customCapabilities = customMemoryCapabilities(this);
612
+ this._owner.capabilities = this.#customCapabilities;
613
+ }
614
+ return this.#customCapabilities;
615
+ }
616
+ nextInode = 1;
617
+ ledger;
618
+ _cache;
619
+ mutationTick = 0;
620
+ _owner;
621
+ root;
622
+ totalBytes = 0;
623
+ symlinkCount = 0;
624
+ #atomicView;
625
+ _getAtomicView() {
626
+ const owner = ownedStores.get(this);
627
+ if (!owner ||
628
+ Object.getPrototypeOf(this) !== MemoryFileSystem.prototype ||
629
+ this.root !== owner.root ||
630
+ this.ledger !== owner.ledger ||
631
+ this.capabilities !== owner.capabilities) {
632
+ return undefined;
633
+ }
634
+ const proto = MemoryFileSystem.prototype;
635
+ for (let i = 0; i < memoryImplementationKeys.length; i++) {
636
+ const name = memoryImplementationKeys[i];
637
+ const expected = memoryImplementationDescriptors[i];
638
+ if (name === "capabilities")
639
+ continue;
640
+ if (Object.prototype.hasOwnProperty.call(this, name)) {
641
+ const actual = Object.getOwnPropertyDescriptor(this, name);
642
+ if (!actual || actual.value !== expected.value || actual.get !== expected.get || actual.set !== expected.set)
643
+ return undefined;
644
+ }
645
+ else if (expected.get !== undefined || expected.set !== undefined || proto[name] !== expected.value) {
646
+ const actual = Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, name);
647
+ if (!actual || actual.value !== expected.value || actual.get !== expected.get || actual.set !== expected.set)
648
+ return undefined;
649
+ }
650
+ }
651
+ return this.#atomicView ??= {
652
+ stat: (path) => {
653
+ this.validatePath(path, "overlayAtomicView");
654
+ let node = this.root;
655
+ for (const component of path.split("/").filter(Boolean)) {
656
+ if (component === "." || component === "..")
657
+ this.fail("EINVAL", "overlayAtomicView", path);
658
+ if (!node)
659
+ return undefined;
660
+ if (node.type !== "directory")
661
+ this.fail("ENOTDIR", "overlayAtomicView", path);
662
+ this.permission(node, 1, "overlayAtomicView", path);
663
+ node = node.entries.get(component);
664
+ }
665
+ return node ? this.snapshot(node) : undefined;
666
+ },
667
+ names: (path) => {
668
+ const node = this.entry(path, "overlayAtomicView").node;
669
+ if (node.type !== "directory")
670
+ this.fail("ENOTDIR", "overlayAtomicView", path);
671
+ return [...node.entries.keys()];
672
+ },
673
+ };
674
+ }
675
+ constructor(options = {}) {
676
+ this.ledger = new MemoryLedger(normalizeMemoryFileSystemLimits(options));
677
+ if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes) {
678
+ replenishSharedMemoryPools();
679
+ }
680
+ const cache = new MemoryCache();
681
+ this._cache = cache;
682
+ memoryCaches.set(this.ledger, cache);
683
+ this.ledger.reserve(0, 1, "mkdir", "/");
684
+ this.root = this.directory(0o755);
685
+ const root = this.root;
686
+ const owner = {
687
+ root,
688
+ ledger: this.ledger,
689
+ capabilities: SHARED_STOCK_MEMORY_CAPABILITIES,
690
+ intact: () => this.root === root,
691
+ };
692
+ this._owner = owner;
693
+ ownedStores.set(this, owner);
694
+ registerLazyMemoryAtomicView(this, memoryImplementation._getAtomicView.value);
695
+ if (this.compareEntry === memoryImplementation.compareEntry?.value) {
696
+ registeredAuthorities.add(this);
697
+ registerEntryAuthority(this, compareOwnedMemory);
698
+ }
699
+ }
700
+ compareEntry(path, peer, peerPath, options = {}) {
701
+ return compareEntries(this, path, peer, peerPath, options);
702
+ }
703
+ canonicalizeMissingTarget(path, options = {}) {
704
+ options.signal?.throwIfAborted();
705
+ if (!isStockMemoryMethods(this, missingTargetMethodNames))
706
+ return undefined;
707
+ const owner = ownedStores.get(this);
708
+ if (path !== "")
709
+ this.validatePath(path, "realpath");
710
+ return resolveMissingTarget(owner.root, path || ".", options.signal, this.ledger.limits);
711
+ }
712
+ async confineExtraction(roots, options = {}) {
713
+ options.signal?.throwIfAborted();
714
+ const retained = new Map();
715
+ for (const root of roots) {
716
+ this.validatePath(root, "confineExtraction");
717
+ let path = "";
718
+ for (const component of root.split("/").filter(Boolean)) {
719
+ if (component === "." || component === "..")
720
+ this.fail("EINVAL", "confineExtraction", root);
721
+ path += `/${component}`;
722
+ const node = this.entry(path, "confineExtraction").node;
723
+ if (node.type !== "directory")
724
+ this.fail("ENOTDIR", "confineExtraction", path);
725
+ retained.set(path, node);
726
+ }
727
+ retained.set("/", this.root);
728
+ }
729
+ const capabilities = this.capabilities;
730
+ const allowed = new Set(["mkdir", "rm", "rmdir", "rename", "symlink", "link", "chmod", "utimes", "writeFile", "appendFile", "writeStream", "writeFileConditional", "removeFileConditional", "removeEntryConditional", "prepareDirectory", "createStagedFile", "publishStagedFile", "removeStagedFile"]);
731
+ const reads = new Set(["access", "capabilitiesFor", "compareEntry", "lstat", "stat", "readFile", "readStream", "readdir", "readlink", "realpath"]);
732
+ const check = (path, followFinal) => {
733
+ if (!roots.some(root => root === "/" || path === root || path.startsWith(`${root}/`)))
734
+ this.fail("EPERM", "confineExtraction", path);
735
+ const components = path.split("/").filter(Boolean);
736
+ if (components.some(component => component === "." || component === ".."))
737
+ this.fail("EINVAL", "confineExtraction", path);
738
+ let current = "";
739
+ for (const [index, component] of components.entries()) {
740
+ current += `/${component}`;
741
+ const node = this.entry(current, "confineExtraction", true).node;
742
+ if (retained.has(current) && node !== retained.get(current))
743
+ this.fail("EAGAIN", "confineExtraction", current);
744
+ if (index < components.length - 1 && node?.type !== "directory")
745
+ this.fail("ENOTDIR", "confineExtraction", current);
746
+ if (followFinal && index === components.length - 1 && node?.type === "symlink")
747
+ this.fail("ELOOP", "confineExtraction", current);
748
+ }
749
+ };
750
+ return new Proxy(this, {
751
+ get: (target, property) => {
752
+ if (property === "objects" || property === "confineExtraction")
753
+ return undefined;
754
+ if (property === "capabilities")
755
+ return capabilities;
756
+ const value = Reflect.get(target, property);
757
+ if (typeof value !== "function")
758
+ return value;
759
+ if (reads.has(String(property)))
760
+ return value.bind(target);
761
+ return (...args) => {
762
+ if (!allowed.has(String(property)))
763
+ throw new FsError("ENOTSUP", { syscall: String(property) });
764
+ // Stock mutations resolve and commit synchronously. Streamed writes
765
+ // repeat the boundary and file-binding check at each backend mutation.
766
+ const paths = property === "publishStagedFile" ? [args[1], args[0].directory.path] : property === "removeStagedFile" ? [args[0].directory.path] : property === "symlink" ? [args[1]] : property === "link" || property === "rename" ? args.slice(0, 2) : [args[0]];
767
+ for (const path of paths) {
768
+ if (typeof path !== "string")
769
+ throw new FsError("EINVAL");
770
+ check(path, ["chmod", "utimes", "appendFile", "writeFile", "writeStream", "writeFileConditional", "link"].includes(String(property)));
771
+ }
772
+ if (property === "writeStream") {
773
+ const path = args[0];
774
+ args[2] = { ...args[2], [extractionStreamGuard]: (node) => {
775
+ check(path, true);
776
+ if (this.resolve(path, "writeStream").node !== node)
777
+ this.fail("EPERM", "writeStream", path);
778
+ } };
779
+ }
780
+ if (property === "createStagedFile")
781
+ return Reflect.apply(value, target, args).then(staging => {
782
+ const writer = staging.writer;
783
+ if (!writer)
784
+ return staging;
785
+ return Object.freeze({ ...staging, writer: Object.freeze({
786
+ write: async (bytes, controls = {}) => {
787
+ controls.signal?.throwIfAborted();
788
+ check(staging.file.path, true);
789
+ await writer.write(bytes, controls);
790
+ },
791
+ finish: async (controls = {}) => {
792
+ controls.signal?.throwIfAborted();
793
+ check(staging.file.path, true);
794
+ return writer.finish(controls);
795
+ },
796
+ }) });
797
+ });
798
+ return Reflect.apply(value, target, args);
799
+ };
800
+ },
801
+ });
802
+ }
803
+ metadata(mode) {
804
+ const now = Date.now();
805
+ return {
806
+ mode, ino: this.nextInode++, nlink: 1, references: 0, revision: 0,
807
+ atimeMs: now, mtimeMs: now, ctimeMs: now, birthtimeMs: now,
808
+ };
809
+ }
810
+ directory(mode, now = Date.now()) {
811
+ const fullMode = typeModes.directory | mode;
812
+ const ino = this.nextInode++;
813
+ let pooled;
814
+ if (sharedDirectoryNodePoolLen > 0) {
815
+ pooled = sharedDirectoryNodePool[--sharedDirectoryNodePoolLen];
816
+ sharedDirectoryNodePool[sharedDirectoryNodePoolLen] = DUMMY_POOL_DIR_NODE;
817
+ }
818
+ else {
819
+ pooled = memoryCaches.get(this.ledger)?.directories.pop();
820
+ }
821
+ if (pooled) {
822
+ pooled.mode = fullMode;
823
+ pooled.ino = ino;
824
+ pooled.nlink = 1;
825
+ pooled.references = 0;
826
+ pooled.revision = 0;
827
+ pooled.atimeMs = now;
828
+ pooled.mtimeMs = now;
829
+ pooled.ctimeMs = now;
830
+ pooled.birthtimeMs = now;
831
+ pooled.cachedNlink = 2;
832
+ pooled.cachedNlinkRev = 0;
833
+ return pooled;
834
+ }
835
+ return new MemoryDirectoryNode(fullMode, ino, now);
836
+ }
837
+ addDirectoryNode(parent, name, mode, syscall, path, now = Date.now()) {
838
+ const bytes = name.length * 2;
839
+ this.ledger.reserve(bytes, 2, syscall, path);
840
+ try {
841
+ const node = this.directory(mode, now);
842
+ parent.entries.set(name, node);
843
+ this.changed(parent, now);
844
+ return node;
845
+ }
846
+ catch (error) {
847
+ this.ledger.release(bytes, 2);
848
+ throw error;
849
+ }
850
+ }
851
+ addNode(parent, name, create, syscall, path, retainedBytes = 0) {
852
+ const bytes = name.length * 2 + retainedBytes;
853
+ this.ledger.reserve(bytes, 2, syscall, path);
854
+ try {
855
+ const node = create();
856
+ if (node.type === "file")
857
+ this.admitSize(undefined, node.byteLength, syscall, path);
858
+ parent.entries.set(name, node);
859
+ if (node.type === "file")
860
+ this.totalBytes += node.byteLength;
861
+ else if (node.type === "symlink")
862
+ this.symlinkCount++;
863
+ this.changed(parent);
864
+ return node;
865
+ }
866
+ catch (error) {
867
+ this.ledger.release(bytes, 2);
868
+ throw error;
869
+ }
870
+ }
871
+ releaseNode(node) {
872
+ if (node.nlink !== 0 || node.references !== 0)
873
+ return;
874
+ const cache = memoryCaches.get(this.ledger);
875
+ this.ledger.release(node.type === "symlink" ? node.target.length * 2 : 0, 1);
876
+ if (node.type === "file") {
877
+ if (cache.lastFastFileNode === node) {
878
+ cache.lastFastFilePath = "";
879
+ cache.lastFastFileName = "";
880
+ cache.lastFastFileNode = undefined;
881
+ }
882
+ this.totalBytes -= node.byteLength;
883
+ const alloc = node.allocation;
884
+ node.view = undefined;
885
+ node.sourceRef = undefined;
886
+ node.allocation = DUMMY_POOL_ALLOCATION;
887
+ alloc.release();
888
+ if (sharedFileNodePoolLen < SHARED_POOL_CAPACITY) {
889
+ sharedFileNodePool[sharedFileNodePoolLen++] = node;
890
+ }
891
+ else if (cache.files.length < 128) {
892
+ cache.files.push(node);
893
+ }
894
+ }
895
+ else if (node.type === "symlink") {
896
+ this.symlinkCount--;
897
+ }
898
+ else {
899
+ if (cache.lastFastDirNode === node) {
900
+ cache.lastFastDirPrefix = "";
901
+ cache.lastFastDirNode = undefined;
902
+ }
903
+ if (node.entries.size === 0) {
904
+ node.entries.clear();
905
+ if (sharedDirectoryNodePoolLen < SHARED_DIR_POOL_CAPACITY) {
906
+ sharedDirectoryNodePool[sharedDirectoryNodePoolLen++] = node;
907
+ }
908
+ else if (cache.directories.length < 32) {
909
+ cache.directories.push(node);
910
+ }
911
+ }
912
+ }
913
+ }
914
+ releaseReference(node, path) {
915
+ node.references--;
916
+ this.ledger.release(path.length * 2, 1);
917
+ this.releaseNode(node);
918
+ }
919
+ replaceData(node, allocation, length = allocation.data.byteLength) {
920
+ const previous = node.allocation;
921
+ node.sourceRef = undefined;
922
+ this.totalBytes += length - node.byteLength;
923
+ node.byteLength = length;
924
+ node.view = length === allocation.data.byteLength ? allocation.data : undefined;
925
+ node.allocation = allocation;
926
+ previous.release();
927
+ }
928
+ admitSize(node, length, syscall, path) {
929
+ this.ledger.fileSize(length, syscall, path);
930
+ const maxBytes = this.ledger.limits.maxBytes;
931
+ if (maxBytes !== undefined && length - (node?.byteLength ?? 0) > maxBytes - this.totalBytes) {
932
+ this.fail("ENOSPC", syscall, path);
933
+ }
934
+ }
935
+ fail(code, syscall, path, dest) {
936
+ throw new FsError(code, { syscall, path, ...(dest === undefined ? {} : { dest }) });
937
+ }
938
+ validatePath(path, syscall) {
939
+ if (typeof path !== "string" || path.includes("\0"))
940
+ this.fail("EINVAL", syscall, path);
941
+ if (path.length === 0)
942
+ this.fail("ENOENT", syscall, path);
943
+ if (this.ledger.limits.maxPathBytes !== Infinity || this.ledger.limits.maxPathComponents !== Infinity)
944
+ validatePath(path, this.ledger.limits);
945
+ }
946
+ permission(node, mask, syscall, path) {
947
+ if (((node.mode >> 6) & mask) !== mask)
948
+ this.fail("EACCES", syscall, path);
949
+ }
950
+ mode(mode, fallback, syscall, path) {
951
+ const value = mode ?? fallback;
952
+ if (!Number.isInteger(value) || value < 0 || value > 0o7777)
953
+ this.fail("EINVAL", syscall, path);
954
+ return value;
955
+ }
956
+ integer(value, syscall, path) {
957
+ if (!Number.isSafeInteger(value) || value < 0)
958
+ this.fail("EINVAL", syscall, path);
959
+ }
960
+ changed(node, now = Date.now()) {
961
+ this.mutationTick = (this.mutationTick + 1) | 0;
962
+ node.revision = node.revision < 1073741823 ? (node.revision + 1) | 0 : Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
963
+ node.mtimeMs = node.ctimeMs = now;
964
+ }
965
+ resolveNode(path, syscall, followFinal = true) {
966
+ if (this.ledger.limits.maxPathBytes !== Infinity || this.ledger.limits.maxPathComponents !== Infinity)
967
+ validatePath(path, this.ledger.limits);
968
+ const cache = memoryCaches.get(this.ledger);
969
+ if (this.symlinkCount === 0 && isCleanAbsolutePath(path)) {
970
+ const fastDir = cache.lastFastDirNode;
971
+ const fastPrefix = cache.lastFastDirPrefix;
972
+ if (fastDir !== undefined && fastDir.nlink !== 0 && fastPrefix.length > 0 && path.startsWith(fastPrefix)) {
973
+ const name = fastPrefix.length === 1 ? (path === _lastFileSlice1Path ? _lastFileSlice1Name : (_lastFileSlice1Path = path, _lastFileSlice1Name = path.slice(1))) : path.slice(fastPrefix.length);
974
+ if (name.length > 0 && !name.includes("/")) {
975
+ this.permission(fastDir, 1, syscall, path);
976
+ if (exceedsComponentByteLimit(name))
977
+ this.fail("ENAMETOOLONG", syscall, path);
978
+ const node = fastDir.entries.get(name);
979
+ if (!node)
980
+ this.fail("ENOENT", syscall, path);
981
+ return node;
982
+ }
983
+ }
984
+ let current = this.root;
985
+ let start = 1;
986
+ while (true) {
987
+ this.permission(current, 1, syscall, path);
988
+ const slash = path.indexOf("/", start);
989
+ if (slash === -1) {
990
+ cache.clearWrites();
991
+ cache.lastFastDirPrefix = start === 1 ? "/" : path.slice(0, start);
992
+ cache.lastFastDirNode = current;
993
+ const name = start === 1 ? (path === _lastFileSlice1Path ? _lastFileSlice1Name : (_lastFileSlice1Path = path, _lastFileSlice1Name = path.slice(1))) : path.slice(start);
994
+ if (exceedsComponentByteLimit(name))
995
+ this.fail("ENAMETOOLONG", syscall, path);
996
+ const node = current.entries.get(name);
997
+ if (!node)
998
+ this.fail("ENOENT", syscall, path);
999
+ return node;
1000
+ }
1001
+ const name = slicePathSegment(path, start, slash);
1002
+ if (exceedsComponentByteLimit(name))
1003
+ this.fail("ENAMETOOLONG", syscall, path);
1004
+ const next = current.entries.get(name);
1005
+ if (!next)
1006
+ this.fail("ENOENT", syscall, path);
1007
+ if (next.type !== "directory")
1008
+ this.fail("ENOTDIR", syscall, path);
1009
+ current = next;
1010
+ start = slash + 1;
1011
+ }
1012
+ }
1013
+ return this.resolve(path, syscall, followFinal ? emptyResolveOptions : noFollowResolveOptions).node;
1014
+ }
1015
+ resolve(path, syscall, options = emptyResolveOptions) {
1016
+ this.validatePath(path, syscall);
1017
+ if (this.symlinkCount === 0 && options.resizeCreate === undefined
1018
+ && options.resolutionSteps === undefined && isCleanAbsolutePath(path)) {
1019
+ let current = this.root;
1020
+ let start = 1;
1021
+ while (true) {
1022
+ this.permission(current, 1, syscall, path);
1023
+ const slash = path.indexOf("/", start);
1024
+ if (slash === -1) {
1025
+ const name = slicePathSegment(path, start, path.length);
1026
+ if (exceedsComponentByteLimit(name))
1027
+ this.fail("ENAMETOOLONG", syscall, path);
1028
+ let node = current.entries.get(name);
1029
+ if (!node && options.createDirectories !== undefined) {
1030
+ this.permission(current, 3, syscall, path);
1031
+ node = this.addDirectoryNode(current, name, options.createDirectories, syscall, path);
1032
+ }
1033
+ if (!node && !options.allowMissing)
1034
+ this.fail("ENOENT", syscall, path);
1035
+ return { node, parent: current, name, path };
1036
+ }
1037
+ const name = path.slice(start, slash);
1038
+ if (exceedsComponentByteLimit(name))
1039
+ this.fail("ENAMETOOLONG", syscall, path);
1040
+ let next = current.entries.get(name);
1041
+ if (!next && options.createDirectories !== undefined) {
1042
+ this.permission(current, 3, syscall, path);
1043
+ next = this.addDirectoryNode(current, name, options.createDirectories, syscall, path);
1044
+ }
1045
+ if (!next)
1046
+ this.fail("ENOENT", syscall, path);
1047
+ if (next.type !== "directory")
1048
+ this.fail("ENOTDIR", syscall, path);
1049
+ current = next;
1050
+ start = slash + 1;
1051
+ }
1052
+ }
1053
+ // Bound all component arrays allocated by this resolution, including cycles.
1054
+ let remainingPathUnits = this.ledger.limits.maxPathBytes - pathByteLength(path);
1055
+ if (remainingPathUnits < 0)
1056
+ this.fail("ENAMETOOLONG", syscall, path);
1057
+ let initialComponents = 0;
1058
+ let inComp = false;
1059
+ for (let i = 0; i < path.length; i++) {
1060
+ if (path.charCodeAt(i) === 47)
1061
+ inComp = false;
1062
+ else if (!inComp) {
1063
+ inComp = true;
1064
+ if (++initialComponents > this.ledger.limits.maxPathComponents)
1065
+ this.fail("ENAMETOOLONG", syscall, path);
1066
+ }
1067
+ }
1068
+ let pending = path.split("/").filter(Boolean);
1069
+ let remainingComponents = this.ledger.limits.maxPathComponents - pending.length;
1070
+ if (path.endsWith("/"))
1071
+ pending.push("");
1072
+ const stack = [{ node: this.root, name: "" }];
1073
+ let recordedUnits = 0;
1074
+ const observe = (node, entryPath) => {
1075
+ if (!options.resolutionSteps)
1076
+ return;
1077
+ recordedUnits += entryPath.length + (node.type === "symlink" ? node.target.length : 0);
1078
+ if (options.resolutionSteps.length >= 4096 || recordedUnits > 1_048_576)
1079
+ this.fail("EFBIG", syscall, path);
1080
+ options.resolutionSteps.push({ path: entryPath, stat: this.snapshot(node), ...(node.type === "symlink" ? { linkTarget: node.target } : {}) });
1081
+ };
1082
+ observe(this.root, "/");
1083
+ let links = 0;
1084
+ while (pending.length > 0) {
1085
+ const component = pending.shift();
1086
+ const current = stack[stack.length - 1].node;
1087
+ if (current.type !== "directory")
1088
+ this.fail("ENOTDIR", syscall, path);
1089
+ if (!(component === "" && pending.length === 0 && options.resizeCreate !== undefined))
1090
+ this.permission(current, 1, syscall, path);
1091
+ if (component === "." || component === "")
1092
+ continue;
1093
+ if (component === "..") {
1094
+ if (stack.length > 1)
1095
+ stack.pop();
1096
+ continue;
1097
+ }
1098
+ if (exceedsComponentByteLimit(component))
1099
+ this.fail("ENAMETOOLONG", syscall, path);
1100
+ if (options.resizeCreate === true && pending.length === 1 && pending[0] === "")
1101
+ this.fail("EISDIR", syscall, path);
1102
+ let node = current.entries.get(component);
1103
+ if (!node && options.createDirectories !== undefined) {
1104
+ this.permission(current, 3, syscall, path);
1105
+ const mode = options.createDirectories;
1106
+ node = this.addNode(current, component, () => this.directory(mode), syscall, path);
1107
+ }
1108
+ if (!node) {
1109
+ if (options.allowMissing && pending.length === 0) {
1110
+ return { node, parent: current, name: component, path: [...stack.map((entry) => entry.name), component].join("/") };
1111
+ }
1112
+ this.fail("ENOENT", syscall, path);
1113
+ }
1114
+ if (options.resolutionSteps)
1115
+ observe(node, [...stack.map(entry => entry.name), component].join("/"));
1116
+ if (node.type === "symlink" && (options.followFinal !== false || pending.length > 0)) {
1117
+ if (++links > 40)
1118
+ this.fail("ELOOP", syscall, path);
1119
+ if (pathByteLength(node.target) > remainingPathUnits)
1120
+ this.fail("ENAMETOOLONG", syscall, path);
1121
+ remainingPathUnits -= pathByteLength(node.target);
1122
+ const target = node.target.split("/").filter(Boolean);
1123
+ if (target.length > remainingComponents)
1124
+ this.fail("ENAMETOOLONG", syscall, path);
1125
+ remainingComponents -= target.length;
1126
+ if (node.target.endsWith("/"))
1127
+ target.push("");
1128
+ if (options.resizeCreate !== undefined && target.at(-1) === "" && pending[0] === "")
1129
+ target.pop();
1130
+ pending = target.concat(pending);
1131
+ if (node.target.startsWith("/"))
1132
+ stack.splice(1);
1133
+ continue;
1134
+ }
1135
+ stack.push({ node, name: component });
1136
+ }
1137
+ const entry = stack[stack.length - 1];
1138
+ return {
1139
+ node: entry.node,
1140
+ parent: (stack[stack.length - 2]?.node ?? this.root),
1141
+ name: entry.name,
1142
+ path: stack.map((part) => part.name).join("/") || "/",
1143
+ };
1144
+ }
1145
+ file(path, syscall) {
1146
+ if (this.ledger.limits.maxPathBytes !== Infinity || this.ledger.limits.maxPathComponents !== Infinity)
1147
+ validatePath(path, this.ledger.limits);
1148
+ if (this.symlinkCount === 0 && path.charCodeAt(0) === 47 && path.length > 1 && path.indexOf("/", 1) === -1 && !path.includes("\0")) {
1149
+ const name = path === _lastFileSlice1Path ? _lastFileSlice1Name : (_lastFileSlice1Path = path, _lastFileSlice1Name = path.slice(1));
1150
+ if (name !== "." && name !== "..") {
1151
+ this.permission(this.root, 1, syscall, path);
1152
+ if (exceedsComponentByteLimit(name))
1153
+ this.fail("ENAMETOOLONG", syscall, path);
1154
+ const node = this.root.entries.get(name);
1155
+ if (!node)
1156
+ this.fail("ENOENT", syscall, path);
1157
+ if (node.type !== "file")
1158
+ this.fail("EISDIR", syscall, path);
1159
+ return node;
1160
+ }
1161
+ }
1162
+ const cache = memoryCaches.get(this.ledger);
1163
+ if (this.symlinkCount === 0 && isCleanAbsolutePath(path)) {
1164
+ const fastDir = cache.lastFastDirNode;
1165
+ const fastPrefix = cache.lastFastDirPrefix;
1166
+ if (fastDir !== undefined && fastDir.nlink !== 0 && fastPrefix.length > 0 && path.startsWith(fastPrefix)) {
1167
+ const name = path.slice(fastPrefix.length);
1168
+ if (name.length > 0 && !name.includes("/")) {
1169
+ this.permission(fastDir, 1, syscall, path);
1170
+ if (exceedsComponentByteLimit(name))
1171
+ this.fail("ENAMETOOLONG", syscall, path);
1172
+ const node = fastDir.entries.get(name);
1173
+ if (!node)
1174
+ this.fail("ENOENT", syscall, path);
1175
+ if (node.type !== "file")
1176
+ this.fail("EISDIR", syscall, path);
1177
+ return node;
1178
+ }
1179
+ }
1180
+ let current = this.root;
1181
+ let start = 1;
1182
+ while (true) {
1183
+ this.permission(current, 1, syscall, path);
1184
+ const slash = path.indexOf("/", start);
1185
+ if (slash === -1) {
1186
+ cache.clearWrites();
1187
+ cache.lastFastDirPrefix = path.slice(0, start);
1188
+ cache.lastFastDirNode = current;
1189
+ const name = path.slice(start);
1190
+ if (exceedsComponentByteLimit(name))
1191
+ this.fail("ENAMETOOLONG", syscall, path);
1192
+ const node = current.entries.get(name);
1193
+ if (!node)
1194
+ this.fail("ENOENT", syscall, path);
1195
+ if (node.type !== "file")
1196
+ this.fail("EISDIR", syscall, path);
1197
+ return node;
1198
+ }
1199
+ const name = path.slice(start, slash);
1200
+ if (exceedsComponentByteLimit(name))
1201
+ this.fail("ENAMETOOLONG", syscall, path);
1202
+ const next = current.entries.get(name);
1203
+ if (!next)
1204
+ this.fail("ENOENT", syscall, path);
1205
+ if (next.type !== "directory")
1206
+ this.fail("ENOTDIR", syscall, path);
1207
+ current = next;
1208
+ start = slash + 1;
1209
+ }
1210
+ }
1211
+ const node = this.resolve(path, syscall).node;
1212
+ if (node.type !== "file")
1213
+ this.fail("EISDIR", syscall, path);
1214
+ return node;
1215
+ }
1216
+ entry(path, syscall, allowMissing = false) {
1217
+ this.validatePath(path, syscall);
1218
+ const location = this.resolve(path.replace(/\/+$/, "") || "/", syscall, { followFinal: false, allowMissing });
1219
+ if (path.endsWith("/") && location.node && location.node.type !== "directory")
1220
+ this.fail("ENOTDIR", syscall, path);
1221
+ return location;
1222
+ }
1223
+ terminalDot(path) {
1224
+ const len = path.length;
1225
+ if (len === 0)
1226
+ return false;
1227
+ const last = path.charCodeAt(len - 1);
1228
+ if (last !== 46 && last !== 47)
1229
+ return false;
1230
+ return /(?:^|\/)\.{1,2}\/*$/.test(path);
1231
+ }
1232
+ directoryNlink(node) {
1233
+ if (node.cachedNlinkRev === node.revision && node.cachedNlink !== undefined) {
1234
+ return node.cachedNlink;
1235
+ }
1236
+ let nlink = 2;
1237
+ node.entries.forEach(entry => {
1238
+ if (entry.type === "directory")
1239
+ nlink++;
1240
+ });
1241
+ node.cachedNlinkRev = node.revision;
1242
+ node.cachedNlink = nlink;
1243
+ return nlink;
1244
+ }
1245
+ snapshot(node) {
1246
+ const hasRev = Number.isSafeInteger(node.revision);
1247
+ const hasScope = ownedStores.get(this)?.intact() === true;
1248
+ const size = node.type === "file" ? node.byteLength
1249
+ : node.type === "symlink" ? new TextEncoder().encode(node.target).byteLength : 0;
1250
+ const nlink = node.type === "directory" && node.nlink !== 0
1251
+ ? this.directoryNlink(node) : node.nlink;
1252
+ if (hasRev && hasScope) {
1253
+ return {
1254
+ type: node.type,
1255
+ filesystemType: "memory",
1256
+ ioBlockSize: preferredIoBlockSize,
1257
+ revision: node.revision,
1258
+ preferredIoBlockSize: 4096,
1259
+ size,
1260
+ mode: node.mode,
1261
+ identityScope: this.identityScope,
1262
+ ino: node.ino,
1263
+ dev: 0,
1264
+ uid: 0,
1265
+ gid: 0,
1266
+ nlink,
1267
+ atimeMs: node.atimeMs,
1268
+ mtimeMs: node.mtimeMs,
1269
+ ctimeMs: node.ctimeMs,
1270
+ birthtimeMs: node.birthtimeMs,
1271
+ };
1272
+ }
1273
+ return {
1274
+ type: node.type,
1275
+ filesystemType: "memory",
1276
+ ioBlockSize: preferredIoBlockSize,
1277
+ ...(hasRev ? { revision: node.revision } : {}),
1278
+ preferredIoBlockSize: 4096,
1279
+ size,
1280
+ mode: node.mode,
1281
+ ...(hasScope ? { identityScope: this.identityScope } : {}),
1282
+ ino: node.ino, dev: 0, uid: 0, gid: 0,
1283
+ nlink,
1284
+ atimeMs: node.atimeMs, mtimeMs: node.mtimeMs, ctimeMs: node.ctimeMs, birthtimeMs: node.birthtimeMs,
1285
+ };
1286
+ }
1287
+ bytes(data, syscall, path) {
1288
+ const allocation = this.allocate(data.byteLength, syscall, path);
1289
+ try {
1290
+ allocation.data.set(data);
1291
+ return allocation;
1292
+ }
1293
+ catch (error) {
1294
+ allocation.release();
1295
+ throw error;
1296
+ }
1297
+ }
1298
+ allocate(length, syscall, path) {
1299
+ this.ledger.fileSize(length, syscall, path);
1300
+ this.ledger.reserve(length, 0, syscall, path);
1301
+ if (length === 0) {
1302
+ return DUMMY_POOL_ALLOCATION;
1303
+ }
1304
+ // Views can outlive files: never recycle their backing buffers across owners.
1305
+ try {
1306
+ return new MemoryAllocation(new Uint8Array(length), this.ledger);
1307
+ }
1308
+ catch (cause) {
1309
+ this.ledger.release(length, 0);
1310
+ throw new FsError("EFBIG", { syscall, path, cause });
1311
+ }
1312
+ }
1313
+ open(path, options) {
1314
+ return openFileDescriptor(path, options, MEMORY_DESCRIPTOR_CAPABILITIES, async (admitted) => {
1315
+ const location = this.resolve(path, "open", {
1316
+ followFinal: !admitted.noFollow && admitted.creation !== "exclusive", allowMissing: admitted.creation !== "never",
1317
+ });
1318
+ let node = location.node;
1319
+ if (node) {
1320
+ if (admitted.creation === "exclusive")
1321
+ this.fail("EEXIST", "open", path);
1322
+ if (node.type === "symlink" && admitted.noFollow)
1323
+ this.fail("ELOOP", "open", path);
1324
+ if (node.type !== "file")
1325
+ this.fail("EISDIR", "open", path);
1326
+ this.permission(node, admitted.access === "read" ? 4 : admitted.access === "write" ? 2 : 6, "open", path);
1327
+ }
1328
+ else {
1329
+ this.permission(location.parent, 3, "open", path);
1330
+ }
1331
+ this.ledger.reserve(path.length * 2, 1, "open", path);
1332
+ try {
1333
+ node ??= this.openWrite(path, {}, "open", { location, mode: admitted.mode, append: false });
1334
+ if (admitted.truncate)
1335
+ this.resizeNode(node, 0, "open", path);
1336
+ }
1337
+ catch (error) {
1338
+ this.ledger.release(path.length * 2, 1);
1339
+ throw error;
1340
+ }
1341
+ node.references++;
1342
+ const resource = { fs: this, path, append: admitted.append, node, position: 0 };
1343
+ return {
1344
+ resource,
1345
+ getPosition: memoryDescriptorGetPosition,
1346
+ stat: memoryDescriptorStat,
1347
+ read: memoryDescriptorRead,
1348
+ write: memoryDescriptorWrite,
1349
+ truncate: memoryDescriptorTruncate,
1350
+ sync: memoryDescriptorSync,
1351
+ close: memoryDescriptorClose,
1352
+ };
1353
+ });
1354
+ }
1355
+ prepareWrite(path, options, syscall) {
1356
+ const flag = options.flag ?? "w";
1357
+ if (!["w", "wx", "a", "ax"].includes(flag))
1358
+ this.fail("EINVAL", syscall, path);
1359
+ const mode = this.mode(options.mode, 0o666, syscall, path);
1360
+ const exclusive = flag === "wx" || flag === "ax";
1361
+ const location = this.resolve(path, syscall, { followFinal: !exclusive, allowMissing: true });
1362
+ if (location.node) {
1363
+ if (exclusive)
1364
+ this.fail("EEXIST", syscall, path);
1365
+ if (location.node.type !== "file")
1366
+ this.fail("EISDIR", syscall, path);
1367
+ this.permission(location.node, 2, syscall, path);
1368
+ }
1369
+ else {
1370
+ this.permission(location.parent, 3, syscall, path);
1371
+ }
1372
+ return { location, mode, append: flag === "a" || flag === "ax" };
1373
+ }
1374
+ openWrite(path, options, syscall, target = this.prepareWrite(path, options, syscall)) {
1375
+ const { location, mode } = target;
1376
+ if (location.node)
1377
+ return location.node;
1378
+ return this.addNode(location.parent, location.name, () => {
1379
+ const allocation = new MemoryAllocation(new Uint8Array(), this.ledger);
1380
+ const meta = this.metadata(typeModes.file | mode);
1381
+ return new MemoryFileNode(meta.mode, meta.ino, meta.atimeMs, 0, allocation, allocation.data);
1382
+ }, syscall, path);
1383
+ }
1384
+ writeData(path, data, options, syscall) {
1385
+ if (this.ledger.limits.maxPathBytes !== Infinity || this.ledger.limits.maxPathComponents !== Infinity)
1386
+ validatePath(path, this.ledger.limits);
1387
+ if (!(data instanceof Uint8Array))
1388
+ throw new TypeError("Memory files require Uint8Array data");
1389
+ const target = this.prepareWrite(path, options, syscall);
1390
+ const current = target.location.node;
1391
+ const length = (target.append ? current?.byteLength ?? 0 : 0) + data.byteLength;
1392
+ this.admitSize(current, length, syscall, path);
1393
+ const growth = target.append && length > (current?.allocation.data.byteLength ?? 0) ? length : 0;
1394
+ this.ledger.check(data.byteLength + growth + (current ? 0 : target.location.name.length * 2), current ? 0 : 2, syscall, path);
1395
+ if (current && target.append) {
1396
+ this.writeAt(current, data, current.byteLength, syscall, path);
1397
+ return current;
1398
+ }
1399
+ if (!current) {
1400
+ const capacity = length > 0 && (target.append || (length < 64 && this.ledger.availableBytes > 65536 && this.ledger.limits.maxFileBytes >= 64))
1401
+ ? Math.min(Math.max(length, 64), this.ledger.limits.maxFileBytes, this.ledger.availableBytes - target.location.name.length * 2)
1402
+ : length;
1403
+ const allocation = this.allocate(capacity, syscall, path);
1404
+ try {
1405
+ allocation.data.set(data);
1406
+ return this.addNode(target.location.parent, target.location.name, () => {
1407
+ const now = Date.now();
1408
+ const fileMode = typeModes.file | target.mode;
1409
+ const view = capacity === length ? allocation.data : undefined;
1410
+ let pooled;
1411
+ if (sharedFileNodePoolLen > 0) {
1412
+ pooled = sharedFileNodePool[--sharedFileNodePoolLen];
1413
+ sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
1414
+ }
1415
+ else {
1416
+ pooled = memoryCaches.get(this.ledger).files.pop();
1417
+ }
1418
+ if (pooled) {
1419
+ pooled.mode = fileMode;
1420
+ pooled.ino = this.nextInode++;
1421
+ pooled.nlink = 1;
1422
+ pooled.references = 0;
1423
+ pooled.revision = 0;
1424
+ pooled.atimeMs = now;
1425
+ pooled.mtimeMs = now;
1426
+ pooled.ctimeMs = now;
1427
+ pooled.birthtimeMs = now;
1428
+ pooled.byteLength = length;
1429
+ pooled.view = view;
1430
+ pooled.allocation = allocation;
1431
+ pooled.sourceRef = pooled.data.subarray(0);
1432
+ return pooled;
1433
+ }
1434
+ return new MemoryFileNode(fileMode, this.nextInode++, now, length, allocation, view, (view ?? allocation.data).subarray(0, length));
1435
+ }, syscall, path);
1436
+ }
1437
+ catch (error) {
1438
+ allocation.release();
1439
+ throw error;
1440
+ }
1441
+ }
1442
+ const copied = this.bytes(data, syscall, path);
1443
+ try {
1444
+ this.replaceData(current, copied);
1445
+ this.changed(current);
1446
+ return current;
1447
+ }
1448
+ catch (error) {
1449
+ copied.release();
1450
+ throw error;
1451
+ }
1452
+ }
1453
+ writeAt(node, data, position, syscall, path) {
1454
+ this.writeAtRange(node, data, data.byteLength, position, syscall, path, Date.now());
1455
+ }
1456
+ writeAtRange(node, data, dataLen, position, syscall, path, now) {
1457
+ if (dataLen === 0) {
1458
+ this.changed(node, now);
1459
+ return;
1460
+ }
1461
+ const end = position + dataLen;
1462
+ this.ledger.fileSize(end, syscall, path);
1463
+ const curLen = node.byteLength;
1464
+ const length = Math.max(curLen, end);
1465
+ this.admitSize(node, length, syscall, path);
1466
+ let allocation = node.allocation;
1467
+ if (length > allocation.data.byteLength) {
1468
+ this.ledger.check(length, 0, syscall, path);
1469
+ let capacity;
1470
+ if (this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes && this.ledger.limits.maxBytes === undefined) {
1471
+ capacity = curLen === 0 && length >= 8192 && length <= 65536 ? (length <= 16384 ? 16384 : 65536) : Math.max(length, curLen * 2, 64);
1472
+ }
1473
+ else {
1474
+ const baseCap = curLen === 0 && length >= 8192 && length <= 65536 &&
1475
+ this.ledger.limits.maxFileBytes >= 65536 &&
1476
+ this.ledger.availableBytes >= 65536 &&
1477
+ (this.ledger.limits.maxBytes === undefined || this.ledger.limits.maxBytes - this.totalBytes >= 65536)
1478
+ ? 65536
1479
+ : Math.max(length, curLen * 2, 64);
1480
+ capacity = Math.min(baseCap, this.ledger.limits.maxFileBytes, this.ledger.availableBytes);
1481
+ }
1482
+ allocation = this.allocate(capacity, syscall, path);
1483
+ }
1484
+ try {
1485
+ const storage = allocation.data;
1486
+ if (allocation !== node.allocation && curLen > 0) {
1487
+ storage.set((node.view ?? node.allocation.data).subarray(0, curLen));
1488
+ }
1489
+ if (position > curLen)
1490
+ storage.fill(0, curLen, position);
1491
+ const source = data;
1492
+ if (dataLen === data.byteLength) {
1493
+ storage.set(data, position);
1494
+ }
1495
+ else if (typeof source.copy === "function") {
1496
+ source.copy(storage, position, 0, dataLen);
1497
+ }
1498
+ else {
1499
+ for (let i = 0; i < dataLen; i++)
1500
+ storage[position + i] = data[i];
1501
+ }
1502
+ }
1503
+ catch (error) {
1504
+ if (allocation !== node.allocation)
1505
+ allocation.release();
1506
+ throw error;
1507
+ }
1508
+ if (allocation !== node.allocation)
1509
+ this.replaceData(node, allocation, length);
1510
+ else {
1511
+ this.totalBytes += length - curLen;
1512
+ node.byteLength = length;
1513
+ node.view = length === allocation.data.byteLength ? allocation.data : undefined;
1514
+ }
1515
+ node.sourceRef = undefined;
1516
+ this.changed(node, now);
1517
+ }
1518
+ writeMemoryFileFast(path, data, append, mode) {
1519
+ if (this.ledger.limits.maxPathBytes !== Infinity || this.ledger.limits.maxPathComponents !== Infinity)
1520
+ validatePath(path, this.ledger.limits);
1521
+ const cache = memoryCaches.get(this.ledger);
1522
+ const syscall = append ? "appendFile" : "writeFile";
1523
+ if (append &&
1524
+ path === cache.lastFastFilePath &&
1525
+ cache.lastFastFileNode !== undefined &&
1526
+ cache.lastFastFileNode.nlink !== 0 &&
1527
+ cache.lastFastDirNode !== undefined &&
1528
+ cache.lastFastDirNode.nlink !== 0 &&
1529
+ (cache.lastFastDirNode.mode & 0o100) !== 0 &&
1530
+ (cache.lastFastFileNode.mode & 0o200) !== 0) {
1531
+ const current = cache.lastFastFileNode;
1532
+ const length = current.byteLength + data.byteLength;
1533
+ this.admitSize(current, length, syscall, path);
1534
+ const growth = length > current.allocation.data.byteLength ? length : 0;
1535
+ this.ledger.check(data.byteLength + growth, 0, syscall, path);
1536
+ this.writeAt(current, data, current.byteLength, syscall, path);
1537
+ return;
1538
+ }
1539
+ let parent = this.root;
1540
+ let start = 1;
1541
+ let name = "";
1542
+ const cachedPrefix = cache.lastFastDirPrefix;
1543
+ const cachedDir = cache.lastFastDirNode;
1544
+ if (cachedDir !== undefined &&
1545
+ cachedDir.nlink !== 0 &&
1546
+ (cachedDir.mode & 0o100) !== 0 &&
1547
+ cachedPrefix.length > 1 &&
1548
+ path.startsWith(cachedPrefix) &&
1549
+ path.indexOf("/", cachedPrefix.length) === -1) {
1550
+ parent = cachedDir;
1551
+ name = path.slice(cachedPrefix.length);
1552
+ if (exceedsComponentByteLimit(name))
1553
+ this.fail("ENAMETOOLONG", syscall, path);
1554
+ }
1555
+ else {
1556
+ while (true) {
1557
+ this.permission(parent, 1, syscall, path);
1558
+ const slash = path.indexOf("/", start);
1559
+ if (slash === -1) {
1560
+ name = path.slice(start);
1561
+ if (exceedsComponentByteLimit(name))
1562
+ this.fail("ENAMETOOLONG", syscall, path);
1563
+ if (start > 1 && (parent.mode & 0o100) !== 0) {
1564
+ cache.lastFastDirPrefix = path.slice(0, start);
1565
+ cache.lastFastDirNode = parent;
1566
+ }
1567
+ break;
1568
+ }
1569
+ const seg = slicePathSegment(path, start, slash);
1570
+ if (exceedsComponentByteLimit(seg))
1571
+ this.fail("ENAMETOOLONG", syscall, path);
1572
+ const next = parent.entries.get(seg);
1573
+ if (!next)
1574
+ this.fail("ENOENT", syscall, path);
1575
+ if (next.type !== "directory")
1576
+ this.fail("ENOTDIR", syscall, path);
1577
+ parent = next;
1578
+ start = slash + 1;
1579
+ }
1580
+ }
1581
+ const existing = parent.entries.getForWrite ? parent.entries.getForWrite(name) : parent.entries.get(name);
1582
+ if (existing) {
1583
+ if (existing.type !== "file")
1584
+ this.fail("EISDIR", syscall, path);
1585
+ this.permission(existing, 2, syscall, path);
1586
+ }
1587
+ else {
1588
+ this.permission(parent, 3, syscall, path);
1589
+ }
1590
+ const current = existing;
1591
+ const length = (append ? current?.byteLength ?? 0 : 0) + data.byteLength;
1592
+ this.admitSize(current, length, syscall, path);
1593
+ const growth = append && length > (current?.allocation.data.byteLength ?? 0) ? length : 0;
1594
+ const nameBytes = name.length * 2;
1595
+ this.ledger.check(data.byteLength + growth + (current ? 0 : nameBytes), current ? 0 : 2, syscall, path);
1596
+ if (current && append) {
1597
+ this.writeAt(current, data, current.byteLength, syscall, path);
1598
+ cache.lastFastFilePath = path;
1599
+ cache.lastFastFileName = name;
1600
+ cache.lastFastFileNode = current;
1601
+ return;
1602
+ }
1603
+ if (!current) {
1604
+ const capacity = length > 0 && length < 64 && this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes ? 64 : length;
1605
+ const allocation = this.allocate(capacity, syscall, path);
1606
+ try {
1607
+ allocation.data.set(data);
1608
+ this.ledger.reserve(nameBytes, 2, syscall, path);
1609
+ try {
1610
+ const now = Date.now();
1611
+ const fileMode = typeModes.file | mode;
1612
+ const view = capacity === length ? allocation.data : undefined;
1613
+ let node;
1614
+ if (sharedFileNodePoolLen > 0) {
1615
+ node = sharedFileNodePool[--sharedFileNodePoolLen];
1616
+ sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
1617
+ }
1618
+ else {
1619
+ node = cache.files.pop();
1620
+ }
1621
+ if (node) {
1622
+ node.mode = fileMode;
1623
+ node.ino = this.nextInode++;
1624
+ node.nlink = 1;
1625
+ node.references = 0;
1626
+ node.revision = 0;
1627
+ node.atimeMs = now;
1628
+ node.mtimeMs = now;
1629
+ node.ctimeMs = now;
1630
+ node.birthtimeMs = now;
1631
+ node.byteLength = length;
1632
+ node.view = view;
1633
+ node.allocation = allocation;
1634
+ node.sourceRef = node.data.subarray(0);
1635
+ }
1636
+ else {
1637
+ node = new MemoryFileNode(fileMode, this.nextInode++, now, length, allocation, view, (view ?? allocation.data).subarray(0, length));
1638
+ }
1639
+ const prevNlink = parent.cachedNlinkRev === parent.revision ? parent.cachedNlink : (parent.entries.size === 0 ? 2 : undefined);
1640
+ parent.entries.set(name, node);
1641
+ this.totalBytes += length;
1642
+ this.changed(parent, now);
1643
+ if (prevNlink !== undefined) {
1644
+ parent.cachedNlink = prevNlink;
1645
+ parent.cachedNlinkRev = parent.revision;
1646
+ }
1647
+ cache.lastFastFilePath = path;
1648
+ cache.lastFastFileName = name;
1649
+ cache.lastFastFileNode = node;
1650
+ }
1651
+ catch (error) {
1652
+ this.ledger.release(nameBytes, 2);
1653
+ throw error;
1654
+ }
1655
+ }
1656
+ catch (error) {
1657
+ allocation.release();
1658
+ throw error;
1659
+ }
1660
+ return;
1661
+ }
1662
+ const copied = this.bytes(data, syscall, path);
1663
+ try {
1664
+ this.replaceData(current, copied);
1665
+ this.changed(current);
1666
+ cache.lastFastFilePath = path;
1667
+ cache.lastFastFileName = name;
1668
+ cache.lastFastFileNode = current;
1669
+ }
1670
+ catch (error) {
1671
+ copied.release();
1672
+ throw error;
1673
+ }
1674
+ }
1675
+ writeMemoryFilesInDirBatchFast(firstFileName, dirPrefix, fileNames, nameHashes, payloads, totalNameBytes, payloadBytesSum, mode) {
1676
+ const batchCount = fileNames.length;
1677
+ const cache = this._cache;
1678
+ if (batchCount > 0 &&
1679
+ dirPrefix === cache.lastFastDirPrefix &&
1680
+ cache.lastFastDirNode !== undefined &&
1681
+ cache.lastFastDirNode.nlink !== 0 &&
1682
+ (cache.lastFastDirNode.mode & 0o300) === 0o300 &&
1683
+ this.ledger.hasInfiniteRetained &&
1684
+ this.ledger.hasInfiniteFileBytes &&
1685
+ this.ledger.limits.maxBytes === undefined &&
1686
+ sharedFileNodePoolLen >= batchCount) {
1687
+ const parent = cache.lastFastDirNode;
1688
+ const entries = parent.entries;
1689
+ if (entries.size === 1 &&
1690
+ entries._next === 1 &&
1691
+ entries._keys[0] === firstFileName &&
1692
+ 1 + batchCount <= entries._keys.length) {
1693
+ this.ledger.reserve(totalNameBytes, 2 * batchCount, "writeFile", fileNames[batchCount - 1]);
1694
+ this.totalBytes += payloadBytesSum;
1695
+ const now = Date.now();
1696
+ const fileMode = typeModes.file | mode;
1697
+ let ino = this.nextInode;
1698
+ this.nextInode = ino + batchCount;
1699
+ let nextIdx = 1;
1700
+ entries._missKey = "";
1701
+ entries._next = 1 + batchCount;
1702
+ entries.size = 1 + batchCount;
1703
+ const table = entries._table;
1704
+ const mask = table.length - 1;
1705
+ const keys = entries._keys;
1706
+ const vals = entries._vals;
1707
+ for (let k = 0; k < batchCount; k++) {
1708
+ const name = fileNames[k];
1709
+ const data = payloads[k];
1710
+ const node = sharedFileNodePool[--sharedFileNodePoolLen];
1711
+ sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
1712
+ node.mode = fileMode;
1713
+ node.ino = ino++;
1714
+ if (node.nlink !== 1)
1715
+ node.nlink = 1;
1716
+ if (node.references !== 0)
1717
+ node.references = 0;
1718
+ if (node.revision !== 0)
1719
+ node.revision = 0;
1720
+ node.atimeMs = now;
1721
+ node.mtimeMs = now;
1722
+ node.ctimeMs = now;
1723
+ node.birthtimeMs = now;
1724
+ node.byteLength = data.byteLength;
1725
+ node.view = new Uint8Array(data);
1726
+ node.allocation = DUMMY_POOL_ALLOCATION;
1727
+ node.sourceRef = node.data.subarray(0);
1728
+ const entryIdx = nextIdx++;
1729
+ keys[entryIdx] = name;
1730
+ vals[entryIdx] = node;
1731
+ let slot = nameHashes[k] & mask;
1732
+ while (table[slot] !== -1)
1733
+ slot = (slot + 1) & mask;
1734
+ table[slot] = entryIdx;
1735
+ }
1736
+ this.mutationTick = (this.mutationTick + 1) | 0;
1737
+ parent.revision = parent.revision < 1073741000 ? (parent.revision + batchCount) | 0 : Math.min(Number.MAX_SAFE_INTEGER + 1, parent.revision + batchCount);
1738
+ parent.mtimeMs = parent.ctimeMs = now;
1739
+ cache.lastFastFilePath = "";
1740
+ cache.lastFastFileName = fileNames[batchCount - 1];
1741
+ cache.lastFastFileNode = vals[nextIdx - 1];
1742
+ return;
1743
+ }
1744
+ }
1745
+ for (let k = 0; k < batchCount; k++) {
1746
+ this.writeMemoryFileInDirFast(dirPrefix, fileNames[k], payloads[k], false, mode, nameHashes[k]);
1747
+ }
1748
+ }
1749
+ writeMemoryFileInDirFast(dirPrefix, name, data, append, mode, nameHash) {
1750
+ if (this.ledger.limits.maxPathBytes !== Infinity || this.ledger.limits.maxPathComponents !== Infinity)
1751
+ validatePath(dirPrefix + name, this.ledger.limits);
1752
+ const cache = this._cache;
1753
+ if (!append &&
1754
+ dirPrefix === cache.lastFastDirPrefix &&
1755
+ cache.lastFastDirNode !== undefined &&
1756
+ cache.lastFastDirNode.nlink !== 0 &&
1757
+ (cache.lastFastDirNode.mode & 0o300) === 0o300 &&
1758
+ name.length <= 85 &&
1759
+ this.ledger.hasInfiniteRetained &&
1760
+ this.ledger.hasInfiniteFileBytes &&
1761
+ this.ledger.limits.maxBytes === undefined &&
1762
+ sharedFileNodePoolLen > 0) {
1763
+ const parent = cache.lastFastDirNode;
1764
+ const entries = parent.entries;
1765
+ const existing = nameHash !== undefined ? entries.getForWriteWithHash(name, nameHash) : entries.getForWrite(name);
1766
+ if (existing === undefined && entries._next < entries._keys.length) {
1767
+ this.ledger.reserve(name.length * 2, 2, "writeFile", name);
1768
+ const now = Date.now();
1769
+ const length = data.byteLength;
1770
+ const node = sharedFileNodePool[--sharedFileNodePoolLen];
1771
+ sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
1772
+ node.mode = typeModes.file | mode;
1773
+ node.ino = this.nextInode++;
1774
+ if (node.nlink !== 1)
1775
+ node.nlink = 1;
1776
+ if (node.references !== 0)
1777
+ node.references = 0;
1778
+ if (node.revision !== 0)
1779
+ node.revision = 0;
1780
+ node.atimeMs = now;
1781
+ node.mtimeMs = now;
1782
+ node.ctimeMs = now;
1783
+ node.birthtimeMs = now;
1784
+ node.byteLength = length;
1785
+ node.view = new Uint8Array(data);
1786
+ node.allocation = DUMMY_POOL_ALLOCATION;
1787
+ node.sourceRef = node.data.subarray(0);
1788
+ const entryIdx = entries._next++;
1789
+ entries._table[entries._missSlot] = entryIdx;
1790
+ entries._keys[entryIdx] = name;
1791
+ entries._vals[entryIdx] = node;
1792
+ entries.size++;
1793
+ entries._missKey = "";
1794
+ this.totalBytes += length;
1795
+ this.mutationTick = (this.mutationTick + 1) | 0;
1796
+ parent.revision = parent.revision < 1073741823 ? (parent.revision + 1) | 0 : Math.min(Number.MAX_SAFE_INTEGER + 1, parent.revision + 1);
1797
+ parent.mtimeMs = parent.ctimeMs = now;
1798
+ cache.lastFastFilePath = "";
1799
+ cache.lastFastFileName = name;
1800
+ cache.lastFastFileNode = node;
1801
+ return;
1802
+ }
1803
+ }
1804
+ const syscall = append ? "appendFile" : "writeFile";
1805
+ try {
1806
+ if (append &&
1807
+ dirPrefix === cache.lastFastDirPrefix &&
1808
+ name === cache.lastFastFileName &&
1809
+ cache.lastFastFileNode !== undefined &&
1810
+ cache.lastFastFileNode.nlink !== 0 &&
1811
+ cache.lastFastDirNode !== undefined &&
1812
+ cache.lastFastDirNode.nlink !== 0 &&
1813
+ (cache.lastFastDirNode.mode & 0o100) !== 0 &&
1814
+ (cache.lastFastFileNode.mode & 0o200) !== 0) {
1815
+ const current = cache.lastFastFileNode;
1816
+ const length = current.byteLength + data.byteLength;
1817
+ this.admitSize(current, length, syscall, name);
1818
+ const growth = length > current.allocation.data.byteLength ? length : 0;
1819
+ this.ledger.check(data.byteLength + growth, 0, syscall, name);
1820
+ this.writeAt(current, data, current.byteLength, syscall, name);
1821
+ return;
1822
+ }
1823
+ let parent = this.root;
1824
+ const cachedDir = cache.lastFastDirNode;
1825
+ if (cachedDir !== undefined &&
1826
+ cachedDir.nlink !== 0 &&
1827
+ (cachedDir.mode & 0o100) !== 0 &&
1828
+ dirPrefix === cache.lastFastDirPrefix) {
1829
+ parent = cachedDir;
1830
+ if (exceedsComponentByteLimit(name))
1831
+ this.fail("ENAMETOOLONG", syscall, name);
1832
+ }
1833
+ else {
1834
+ let start = 1;
1835
+ while (start < dirPrefix.length) {
1836
+ this.permission(parent, 1, syscall, name);
1837
+ const slash = dirPrefix.indexOf("/", start);
1838
+ const seg = slash === -1 ? slicePathSegment(dirPrefix, start, dirPrefix.length) : slicePathSegment(dirPrefix, start, slash);
1839
+ if (exceedsComponentByteLimit(seg))
1840
+ this.fail("ENAMETOOLONG", syscall, name);
1841
+ const next = parent.entries.get(seg);
1842
+ if (!next)
1843
+ this.fail("ENOENT", syscall, name);
1844
+ if (next.type !== "directory")
1845
+ this.fail("ENOTDIR", syscall, name);
1846
+ parent = next;
1847
+ if (slash === -1)
1848
+ break;
1849
+ start = slash + 1;
1850
+ }
1851
+ this.permission(parent, 1, syscall, name);
1852
+ if (exceedsComponentByteLimit(name))
1853
+ this.fail("ENAMETOOLONG", syscall, name);
1854
+ if (dirPrefix.length > 1 && (parent.mode & 0o100) !== 0) {
1855
+ cache.lastFastDirPrefix = dirPrefix;
1856
+ cache.lastFastDirNode = parent;
1857
+ }
1858
+ }
1859
+ const existing = parent.entries.getForWrite ? parent.entries.getForWrite(name) : parent.entries.get(name);
1860
+ if (existing) {
1861
+ if (existing.type !== "file")
1862
+ this.fail("EISDIR", syscall, name);
1863
+ this.permission(existing, 2, syscall, name);
1864
+ }
1865
+ else {
1866
+ this.permission(parent, 3, syscall, name);
1867
+ }
1868
+ const current = existing;
1869
+ const length = (append ? current?.byteLength ?? 0 : 0) + data.byteLength;
1870
+ this.admitSize(current, length, syscall, name);
1871
+ const growth = append && length > (current?.allocation.data.byteLength ?? 0) ? length : 0;
1872
+ const nameBytes = name.length * 2;
1873
+ this.ledger.check(data.byteLength + growth + (current ? 0 : nameBytes), current ? 0 : 2, syscall, name);
1874
+ if (current && append) {
1875
+ this.writeAt(current, data, current.byteLength, syscall, name);
1876
+ cache.lastFastFilePath = "";
1877
+ cache.lastFastFileName = name;
1878
+ cache.lastFastFileNode = current;
1879
+ return;
1880
+ }
1881
+ if (!current) {
1882
+ const zeroCopyConst = this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes && this.ledger.limits.maxBytes === undefined;
1883
+ const capacity = zeroCopyConst ? 0 : (length > 0 && length < 64 && this.ledger.hasInfiniteRetained && this.ledger.hasInfiniteFileBytes ? 64 : length);
1884
+ const allocation = zeroCopyConst ? DUMMY_POOL_ALLOCATION : this.allocate(capacity, syscall, name);
1885
+ try {
1886
+ if (!zeroCopyConst)
1887
+ allocation.data.set(data);
1888
+ this.ledger.reserve(nameBytes, 2, syscall, name);
1889
+ try {
1890
+ const now = Date.now();
1891
+ const fileMode = typeModes.file | mode;
1892
+ const view = zeroCopyConst ? new Uint8Array(data) : (capacity === length ? allocation.data : undefined);
1893
+ let node;
1894
+ if (sharedFileNodePoolLen > 0) {
1895
+ node = sharedFileNodePool[--sharedFileNodePoolLen];
1896
+ sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
1897
+ }
1898
+ else {
1899
+ node = cache.files.pop();
1900
+ }
1901
+ if (node) {
1902
+ node.mode = fileMode;
1903
+ node.ino = this.nextInode++;
1904
+ if (node.nlink !== 1)
1905
+ node.nlink = 1;
1906
+ if (node.references !== 0)
1907
+ node.references = 0;
1908
+ if (node.revision !== 0)
1909
+ node.revision = 0;
1910
+ node.atimeMs = now;
1911
+ node.mtimeMs = now;
1912
+ node.ctimeMs = now;
1913
+ node.birthtimeMs = now;
1914
+ node.byteLength = length;
1915
+ node.view = view;
1916
+ node.allocation = allocation;
1917
+ node.sourceRef = node.data.subarray(0);
1918
+ }
1919
+ else {
1920
+ node = new MemoryFileNode(fileMode, this.nextInode++, now, length, allocation, view, (view ?? allocation.data).subarray(0, length));
1921
+ }
1922
+ const prevNlink = parent.cachedNlinkRev === parent.revision ? parent.cachedNlink : (parent.entries.size === 0 ? 2 : undefined);
1923
+ parent.entries.set(name, node);
1924
+ this.totalBytes += length;
1925
+ this.changed(parent, now);
1926
+ if (prevNlink !== undefined) {
1927
+ parent.cachedNlink = prevNlink;
1928
+ parent.cachedNlinkRev = parent.revision;
1929
+ }
1930
+ cache.lastFastFilePath = "";
1931
+ cache.lastFastFileName = name;
1932
+ cache.lastFastFileNode = node;
1933
+ }
1934
+ catch (error) {
1935
+ this.ledger.release(nameBytes, 2);
1936
+ throw error;
1937
+ }
1938
+ }
1939
+ catch (error) {
1940
+ allocation.release();
1941
+ throw error;
1942
+ }
1943
+ return;
1944
+ }
1945
+ const copied = this.bytes(data, syscall, name);
1946
+ try {
1947
+ this.replaceData(current, copied);
1948
+ this.changed(current);
1949
+ cache.lastFastFilePath = "";
1950
+ cache.lastFastFileName = name;
1951
+ cache.lastFastFileNode = current;
1952
+ }
1953
+ catch (error) {
1954
+ copied.release();
1955
+ throw error;
1956
+ }
1957
+ }
1958
+ catch (error) {
1959
+ if (error instanceof FsError && error.path === name) {
1960
+ throw new FsError(error.code, {
1961
+ syscall: error.syscall ?? syscall,
1962
+ path: dirPrefix + name,
1963
+ ...(error.dest === undefined ? {} : { dest: error.dest }),
1964
+ });
1965
+ }
1966
+ throw error;
1967
+ }
1968
+ }
1969
+ async readFile(path, options = {}) {
1970
+ options.signal?.throwIfAborted();
1971
+ if (options.maxBytes !== undefined && options.maxBytes !== Infinity)
1972
+ this.integer(options.maxBytes, "readFile", path);
1973
+ const node = this.file(path, "readFile");
1974
+ this.permission(node, 4, "readFile", path);
1975
+ if (options.maxBytes !== undefined && node.data.byteLength > options.maxBytes)
1976
+ this.fail("EFBIG", "readFile", path);
1977
+ node.atimeMs = Date.now();
1978
+ return new Uint8Array(node.data);
1979
+ }
1980
+ expectEntry(node, expected, path, unchanged = true) {
1981
+ if (expected === null) {
1982
+ if (node)
1983
+ this.fail("EAGAIN", "fileStaging", path);
1984
+ return;
1985
+ }
1986
+ if (!node)
1987
+ this.fail("EAGAIN", "fileStaging", path);
1988
+ if (!unchanged) {
1989
+ const currentScope = ownedStores.get(this)?.intact() ? this.identityScope : undefined;
1990
+ if (!expected.identityScope || expected.identityScope !== currentScope
1991
+ || !Number.isSafeInteger(expected.ino) || !Number.isSafeInteger(expected.dev))
1992
+ this.fail("ENOTSUP", "fileStaging", path);
1993
+ if (node.ino !== expected.ino || expected.dev !== 0 || node.type !== expected.type)
1994
+ this.fail("EAGAIN", "fileStaging", path);
1995
+ return;
1996
+ }
1997
+ const current = this.snapshot(node);
1998
+ if (!expected.identityScope || expected.identityScope !== current.identityScope
1999
+ || !Number.isSafeInteger(expected.ino) || !Number.isSafeInteger(expected.dev))
2000
+ this.fail("ENOTSUP", "fileStaging", path);
2001
+ if (current.ino !== expected.ino || current.dev !== expected.dev || current.type !== expected.type)
2002
+ this.fail("EAGAIN", "fileStaging", path);
2003
+ if (!Number.isSafeInteger(expected.revision) || !Number.isSafeInteger(current.revision))
2004
+ this.fail("ENOTSUP", "fileStaging", path);
2005
+ if (current.revision !== expected.revision || current.size !== expected.size || current.mode !== expected.mode
2006
+ || current.nlink !== expected.nlink || current.mtimeMs !== expected.mtimeMs || current.ctimeMs !== expected.ctimeMs)
2007
+ this.fail("EAGAIN", "fileStaging", path);
2008
+ }
2009
+ stagingLocations(staging) {
2010
+ const parent = this.entry(staging.parent.path, "fileStaging");
2011
+ this.expectEntry(parent.node, staging.parent.stat, staging.parent.path, false);
2012
+ if (parent.node.type !== "directory")
2013
+ this.fail("ENOTDIR", "fileStaging", staging.parent.path);
2014
+ const directory = this.entry(staging.directory.path, "fileStaging");
2015
+ this.expectEntry(directory.node, staging.directory.stat, staging.directory.path, false);
2016
+ if (directory.parent !== parent.node || directory.node.type !== "directory" || (directory.node.mode & 0o777) !== 0o700)
2017
+ this.fail("EAGAIN", "fileStaging", staging.directory.path);
2018
+ const file = this.entry(staging.file.path, "fileStaging", true);
2019
+ if (file.parent !== directory.node || !["file", "symlink"].includes(staging.file.stat.type))
2020
+ this.fail("EAGAIN", "fileStaging", staging.file.path);
2021
+ return { directory, file };
2022
+ }
2023
+ async createStagedFile(directoryPath, name, content, options) {
2024
+ options = snapshotStagingCreation(options, directoryPath);
2025
+ options.signal?.throwIfAborted();
2026
+ if (options.retainCleanup === true && this.capabilities.retainedStagingCleanup !== true)
2027
+ this.fail("ENOTSUP", "createStagedFile", directoryPath);
2028
+ if (!name || name === "." || name === ".." || name.includes("/") || name.includes("\0"))
2029
+ this.fail("EINVAL", "createStagedFile", directoryPath);
2030
+ const location = this.entry(directoryPath, "createStagedFile", true);
2031
+ if (location.node)
2032
+ this.fail("EEXIST", "createStagedFile", directoryPath);
2033
+ this.expectEntry(location.parent, options.parent, directoryPath, false);
2034
+ this.permission(location.parent, 3, "createStagedFile", directoryPath);
2035
+ const mode = this.mode(options.mode, content.type === "file" ? 0o666 : 0o777, "createStagedFile", directoryPath);
2036
+ for (const time of [options.atimeMs, options.mtimeMs])
2037
+ if (time !== undefined && !Number.isFinite(time))
2038
+ this.fail("EINVAL", "createStagedFile", directoryPath);
2039
+ if (content.type === "file" && !(content.data instanceof Uint8Array))
2040
+ throw new TypeError("Staged files require Uint8Array data");
2041
+ if (content.type === "file")
2042
+ this.admitSize(undefined, content.data.byteLength, "createStagedFile", directoryPath);
2043
+ if (content.type === "symlink")
2044
+ this.validatePath(content.target, "createStagedFile");
2045
+ const retained = (location.name.length + name.length) * 2 + (content.type === "symlink" ? content.target.length * 2 : 0);
2046
+ const parentPath = location.path.slice(0, location.path.lastIndexOf("/")) || "/";
2047
+ const filePath = `${location.path}/${name}`;
2048
+ const cleanupBytes = options.retainCleanup ? (parentPath.length + location.path.length + filePath.length) * 2 : 0;
2049
+ const cleanupUnits = options.retainCleanup ? 3 : 0;
2050
+ this.ledger.reserve(retained + cleanupBytes, 4 + cleanupUnits, "createStagedFile", directoryPath);
2051
+ let allocation;
2052
+ let directory;
2053
+ let file;
2054
+ try {
2055
+ if (content.type === "file")
2056
+ allocation = this.bytes(content.data, "createStagedFile", directoryPath);
2057
+ directory = this.directory(0o700);
2058
+ file = content.type === "file"
2059
+ ? (() => { const m = this.metadata(typeModes.file | mode); return new MemoryFileNode(m.mode, m.ino, m.atimeMs, allocation.data.byteLength, allocation, allocation.data); })()
2060
+ : { ...this.metadata(typeModes.symlink | mode), type: "symlink", target: content.target };
2061
+ if (options.atimeMs !== undefined)
2062
+ file.atimeMs = options.atimeMs;
2063
+ if (options.mtimeMs !== undefined)
2064
+ file.mtimeMs = options.mtimeMs;
2065
+ directory.entries.set(name, file);
2066
+ location.parent.entries.set(location.name, directory);
2067
+ if (file.type === "file")
2068
+ this.totalBytes += file.data.byteLength;
2069
+ else
2070
+ this.symlinkCount++;
2071
+ }
2072
+ catch (error) {
2073
+ allocation?.release();
2074
+ this.ledger.release(retained + cleanupBytes, 4 + cleanupUnits);
2075
+ throw error;
2076
+ }
2077
+ this.changed(location.parent);
2078
+ const receipt = (path, node) => Object.freeze({ path, stat: Object.freeze(this.snapshot(node)) });
2079
+ const staging = Object.freeze({ parent: receipt(parentPath, location.parent), directory: receipt(location.path, directory), file: receipt(filePath, file) });
2080
+ if (!options.retainCleanup)
2081
+ return staging;
2082
+ // Reservations above include these references before either entry is exposed.
2083
+ location.parent.references++;
2084
+ directory.references++;
2085
+ file.references++;
2086
+ return Object.freeze({ ...staging, ...this.retainStagingCleanup(staging, location.parent, directory, file, location.name, name) });
2087
+ }
2088
+ retainStagingCleanup(staging, parent, directory, file, directoryName, fileName) {
2089
+ // Clear this state on release, so keeping the closed handle does not keep
2090
+ // detached nodes alive outside the Memory ledger.
2091
+ let retained = { parent, directory, file };
2092
+ let expected = staging.file.stat;
2093
+ let writing = true;
2094
+ const receipt = () => ({ ...staging, file: { ...staging.file, stat: expected } });
2095
+ const ownedCleanup = createStagingCleanup(staging.directory.path, options => {
2096
+ options.signal?.throwIfAborted();
2097
+ const state = retained;
2098
+ if (state.parent.nlink === 0 || state.parent.entries.get(directoryName) !== state.directory)
2099
+ this.fail("EAGAIN", "removeStagedFile", staging.directory.path);
2100
+ this.expectEntry(state.parent, staging.parent.stat, staging.parent.path, false);
2101
+ this.expectEntry(state.directory, staging.directory.stat, staging.directory.path, false);
2102
+ if ((state.directory.mode & 0o777) !== 0o700)
2103
+ this.fail("EAGAIN", "removeStagedFile", staging.directory.path);
2104
+ const child = state.directory.entries.get(fileName);
2105
+ if (child && child !== state.file)
2106
+ this.fail("EAGAIN", "removeStagedFile", staging.file.path);
2107
+ this.removeStagingLocations(receipt(), {
2108
+ node: state.directory, parent: state.parent, name: directoryName, path: staging.directory.path,
2109
+ }, { node: child, parent: state.directory, name: fileName, path: staging.file.path });
2110
+ }, () => {
2111
+ const state = retained;
2112
+ retained = undefined;
2113
+ this.releaseReference(state.file, staging.file.path);
2114
+ this.releaseReference(state.directory, staging.directory.path);
2115
+ this.releaseReference(state.parent, staging.parent.path);
2116
+ });
2117
+ const cleanup = Object.freeze({
2118
+ remove: (options) => { writing = false; return ownedCleanup.remove(options); },
2119
+ close: () => { writing = false; return ownedCleanup.close(); },
2120
+ });
2121
+ if (file.type !== "file")
2122
+ return { cleanup };
2123
+ const inspect = (options) => {
2124
+ options.signal?.throwIfAborted();
2125
+ if (!retained || !writing)
2126
+ this.fail("EBADF", "stagedWrite", staging.file.path);
2127
+ const location = this.stagingLocations(receipt());
2128
+ if (location.file.node !== retained.file)
2129
+ this.fail("EAGAIN", "stagedWrite", staging.file.path);
2130
+ this.expectEntry(retained.file, expected, staging.file.path);
2131
+ this.permission(retained.parent, 3, "stagedWrite", staging.parent.path);
2132
+ this.permission(retained.directory, 3, "stagedWrite", staging.directory.path);
2133
+ return retained.file;
2134
+ };
2135
+ return { cleanup, writer: Object.freeze({
2136
+ write: async (bytes, options = {}) => {
2137
+ const node = inspect(options);
2138
+ if (!(bytes instanceof Uint8Array))
2139
+ throw new TypeError("Staged writes require Uint8Array data");
2140
+ this.writeAt(node, bytes, node.byteLength, "stagedWrite", staging.file.path);
2141
+ expected = Object.freeze(this.snapshot(node));
2142
+ },
2143
+ finish: async (options = {}) => {
2144
+ const node = inspect(options);
2145
+ this.changed(node);
2146
+ // changed updates modification time; archive creation metadata is final.
2147
+ node.atimeMs = staging.file.stat.atimeMs;
2148
+ node.mtimeMs = staging.file.stat.mtimeMs;
2149
+ writing = false;
2150
+ expected = Object.freeze(this.snapshot(node));
2151
+ return expected;
2152
+ },
2153
+ }) };
2154
+ }
2155
+ async prepareDirectoryAncestry(ancestors, options = {}) {
2156
+ const entries = snapshotDirectoryAncestry(ancestors);
2157
+ const controls = options.signal === undefined ? {} : { signal: options.signal };
2158
+ controls.signal?.throwIfAborted();
2159
+ return () => this.verifyDirectoryAncestry(entries, controls);
2160
+ }
2161
+ async prepareStagingResolution(path, options = {}) {
2162
+ const controls = options.signal === undefined ? {} : { signal: options.signal };
2163
+ controls.signal?.throwIfAborted();
2164
+ this.validatePath(path, "prepareStagingResolution");
2165
+ if (!path.startsWith("/") || normalizePath(path) !== path)
2166
+ this.fail("EINVAL", "prepareStagingResolution", path);
2167
+ const traversed = [];
2168
+ const location = this.resolve(path, "prepareStagingResolution", { followFinal: false, allowMissing: true, resolutionSteps: traversed });
2169
+ if (location.node && location.node.type !== "file")
2170
+ this.fail("ENOTSUP", "prepareStagingResolution", path);
2171
+ const parentPath = location.path.slice(0, location.path.lastIndexOf("/")) || "/";
2172
+ const ancestors = snapshotDirectoryAncestry(directoryAncestryPaths(parentPath).map(entryPath => ({
2173
+ path: entryPath, stat: this.snapshot(this.entry(entryPath, "prepareStagingResolution").node),
2174
+ })));
2175
+ const steps = traversed.map(entry => ({ ...entry, stat: { ...entry.stat } }));
2176
+ const canonical = location.path;
2177
+ const destination = location.node ? this.snapshot(location.node) : null;
2178
+ const validate = () => {
2179
+ controls.signal?.throwIfAborted();
2180
+ const currentSteps = [];
2181
+ let current;
2182
+ try {
2183
+ current = this.resolve(path, "verifyStagingResolution", { followFinal: false, allowMissing: true, resolutionSteps: currentSteps });
2184
+ }
2185
+ catch (error) {
2186
+ if (error instanceof FsError && ["ENOENT", "ENOTDIR", "ELOOP"].includes(error.code))
2187
+ this.fail("EAGAIN", "verifyStagingResolution", path);
2188
+ throw error;
2189
+ }
2190
+ if (current.path !== canonical || steps.length !== currentSteps.length)
2191
+ this.fail("EAGAIN", "verifyStagingResolution", path);
2192
+ for (const [index, before] of steps.entries()) {
2193
+ const after = currentSteps[index];
2194
+ if (before.path !== after.path || before.linkTarget !== after.linkTarget || before.stat.type !== after.stat.type
2195
+ || compareIdentity(before.stat, after.stat) !== "same"
2196
+ || before.stat.type !== "directory" && ["revision", "size", "mode", "nlink", "mtimeMs", "ctimeMs"].some(field => before.stat[field] !== after.stat[field])) {
2197
+ this.fail("EAGAIN", "verifyStagingResolution", before.path);
2198
+ }
2199
+ }
2200
+ this.expectEntry(current.node, destination, path);
2201
+ return this.verifyDirectoryAncestry(ancestors, controls);
2202
+ };
2203
+ return snapshotStagingResolution({ path: canonical, parent: this.snapshot(location.parent), destination, ancestors, traversed: steps, validate });
2204
+ }
2205
+ verifyDirectoryAncestry(ancestors, options) {
2206
+ const entries = snapshotDirectoryAncestry(ancestors);
2207
+ options.signal?.throwIfAborted();
2208
+ let node = this.root;
2209
+ for (const [index, expected] of entries.entries()) {
2210
+ if (index > 0)
2211
+ node = node.entries.get(expected.path.slice(expected.path.lastIndexOf("/") + 1));
2212
+ if (node?.type !== "directory")
2213
+ this.fail("EAGAIN", "verifyDirectoryAncestry", expected.path);
2214
+ this.expectEntry(node, expected.stat, expected.path, false);
2215
+ this.permission(node, 1, "verifyDirectoryAncestry", expected.path);
2216
+ }
2217
+ return true;
2218
+ }
2219
+ async publishStagedFile(receipt, destination, options) {
2220
+ const signal = options.signal;
2221
+ const guard = options.commitGuard;
2222
+ const ancestors = options.ancestors === undefined ? undefined : snapshotDirectoryAncestry(options.ancestors);
2223
+ const snapshot = (entry) => ({ path: entry.path, stat: { ...entry.stat } });
2224
+ const staging = { parent: snapshot(receipt.parent), directory: snapshot(receipt.directory), file: snapshot(receipt.file) };
2225
+ const parent = { ...options.parent };
2226
+ const expected = options.destination === null ? null : { ...options.destination };
2227
+ const parentPath = destination.slice(0, destination.lastIndexOf("/")) || "/";
2228
+ if (ancestors && ancestors.at(-1)?.path !== parentPath)
2229
+ this.fail("EINVAL", "publishStagedFile", destination);
2230
+ const controls = signal === undefined ? {} : { signal };
2231
+ signal?.throwIfAborted();
2232
+ if (guard !== undefined)
2233
+ runStagingGuard(guard);
2234
+ signal?.throwIfAborted();
2235
+ // All inputs were copied before the guard. Neither outer validation nor
2236
+ // these local checks yield before the stock rename commits.
2237
+ if (ancestors)
2238
+ runStagingGuard(() => this.verifyDirectoryAncestry(ancestors, controls));
2239
+ const { directory, file } = this.stagingLocations(staging);
2240
+ this.expectEntry(file.node, staging.file.stat, staging.file.path);
2241
+ const target = this.entry(destination, "publishStagedFile", true);
2242
+ this.expectEntry(target.parent, parent, destination, false);
2243
+ this.expectEntry(target.node, expected, destination);
2244
+ if (target.parent === directory.node || target.node === directory.node || target.node === file.node)
2245
+ this.fail("EINVAL", "publishStagedFile", destination);
2246
+ if (target.node && target.node.type !== "file")
2247
+ this.fail("EAGAIN", "publishStagedFile", destination);
2248
+ return MemoryFileSystem.prototype.rename.call(this, staging.file.path, destination, { ...controls, noReplace: expected === null });
2249
+ }
2250
+ async publishStagedFileSet(receipt, destination, options) {
2251
+ const signal = options.signal;
2252
+ const guard = options.commitGuard;
2253
+ const ancestors = options.ancestors === undefined ? undefined : snapshotDirectoryAncestry(options.ancestors);
2254
+ const snapshot = (entry) => ({ path: entry.path, stat: { ...entry.stat } });
2255
+ const staging = { parent: snapshot(receipt.parent), directory: snapshot(receipt.directory), file: snapshot(receipt.file) };
2256
+ const parent = { ...options.parent };
2257
+ const expected = options.destination === null ? null : { ...options.destination };
2258
+ const companions = options.companions.map(entry => ({ path: entry.path, expected: entry.expected === null ? null : { ...entry.expected }, remove: entry.remove }));
2259
+ const syscall = "publishStagedFileSet";
2260
+ const parentPath = destination.slice(0, destination.lastIndexOf("/")) || "/";
2261
+ const paths = new Set([destination]);
2262
+ const canonical = (path) => path.startsWith("/") && path.slice(1).split("/").every(part => part !== "" && part !== "." && part !== "..");
2263
+ if (!canonical(destination) || ancestors && ancestors.at(-1)?.path !== parentPath)
2264
+ this.fail("EINVAL", syscall, destination);
2265
+ for (const entry of companions) {
2266
+ if (!canonical(entry.path) || paths.has(entry.path) || (entry.path.slice(0, entry.path.lastIndexOf("/")) || "/") !== parentPath)
2267
+ this.fail("EINVAL", syscall, entry.path);
2268
+ paths.add(entry.path);
2269
+ }
2270
+ signal?.throwIfAborted();
2271
+ if (guard !== undefined)
2272
+ runStagingGuard(guard);
2273
+ signal?.throwIfAborted();
2274
+ if (ancestors)
2275
+ this.verifyDirectoryAncestry(ancestors, signal === undefined ? {} : { signal });
2276
+ const { directory, file } = this.stagingLocations(staging);
2277
+ this.expectEntry(file.node, staging.file.stat, staging.file.path);
2278
+ const target = this.entry(destination, syscall, true);
2279
+ this.expectEntry(target.parent, parent, destination, false);
2280
+ this.expectEntry(target.node, expected, destination);
2281
+ const node = file.node;
2282
+ if (node.type !== "file" || target.parent === directory.node || target.node === node)
2283
+ this.fail("EINVAL", syscall, destination);
2284
+ if (target.node && target.node.type !== "file")
2285
+ this.fail("EAGAIN", syscall, destination);
2286
+ this.permission(file.parent, 3, syscall, staging.file.path);
2287
+ this.permission(target.parent, 3, syscall, destination);
2288
+ const retired = [];
2289
+ for (const companion of companions) {
2290
+ const location = this.entry(companion.path, syscall, true);
2291
+ if (location.parent !== target.parent || location.node === node)
2292
+ this.fail("EINVAL", syscall, companion.path);
2293
+ this.expectEntry(location.node, companion.expected, companion.path);
2294
+ if (location.node && location.node.type !== "file")
2295
+ this.fail("EAGAIN", syscall, companion.path);
2296
+ if (companion.remove && location.node)
2297
+ retired.push(location);
2298
+ }
2299
+ const now = Date.now();
2300
+ const published = { ...this.snapshot(node), ctimeMs: now, revision: Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1) };
2301
+ // Admission and all source-set checks precede the single synchronous commit.
2302
+ // No calls to overridable async mutations can interleave a partial result.
2303
+ const nameGrowth = target.node ? 0 : (target.name.length - file.name.length) * 2;
2304
+ this.ledger.reserve(Math.max(0, nameGrowth), 0, syscall, destination);
2305
+ try {
2306
+ target.parent.entries.set(target.name, node);
2307
+ }
2308
+ catch (error) {
2309
+ this.ledger.release(Math.max(0, nameGrowth), 0);
2310
+ throw error;
2311
+ }
2312
+ memoryCaches.get(this.ledger).clearWrites();
2313
+ file.parent.entries.delete(file.name);
2314
+ const unlink = (entry) => {
2315
+ entry.node.nlink--;
2316
+ entry.node.ctimeMs = now;
2317
+ entry.node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, entry.node.revision + 1);
2318
+ this.releaseNode(entry.node);
2319
+ };
2320
+ if (target.node) {
2321
+ this.ledger.release(file.name.length * 2, 1);
2322
+ unlink(target);
2323
+ }
2324
+ else if (nameGrowth < 0)
2325
+ this.ledger.release(-nameGrowth, 0);
2326
+ for (const entry of retired) {
2327
+ entry.parent.entries.delete(entry.name);
2328
+ this.ledger.release(entry.name.length * 2, 1);
2329
+ unlink(entry);
2330
+ }
2331
+ this.changed(file.parent, now);
2332
+ this.changed(target.parent, now);
2333
+ node.ctimeMs = now;
2334
+ node.revision = published.revision;
2335
+ return published;
2336
+ }
2337
+ async removeStagedFile(staging, options = {}) {
2338
+ options.signal?.throwIfAborted();
2339
+ const { directory, file } = this.stagingLocations(staging);
2340
+ this.removeStagingLocations(staging, directory, file);
2341
+ }
2342
+ removeStagingLocations(staging, directory, file) {
2343
+ if (file.node)
2344
+ this.expectEntry(file.node, staging.file.stat, staging.file.path);
2345
+ const node = directory.node;
2346
+ if (node.entries.size !== (file.node ? 1 : 0))
2347
+ this.fail("ENOTEMPTY", "removeStagedFile", staging.directory.path);
2348
+ this.permission(directory.parent, 3, "removeStagedFile", staging.directory.path);
2349
+ this.permission(node, 3, "removeStagedFile", staging.file.path);
2350
+ directory.parent.entries.delete(directory.name);
2351
+ if (file.node) {
2352
+ node.entries.delete(file.name);
2353
+ this.ledger.release(file.name.length * 2, 1);
2354
+ file.node.nlink--;
2355
+ file.node.ctimeMs = Date.now();
2356
+ file.node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, file.node.revision + 1);
2357
+ this.releaseNode(file.node);
2358
+ }
2359
+ this.ledger.release(directory.name.length * 2, 1);
2360
+ node.nlink = 0;
2361
+ node.ctimeMs = Date.now();
2362
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2363
+ this.releaseNode(node);
2364
+ this.changed(directory.parent);
2365
+ }
2366
+ async prepareDirectory(path, options) {
2367
+ options.signal?.throwIfAborted();
2368
+ const location = this.entry(path, "prepareDirectory", true);
2369
+ this.expectEntry(location.parent, options.parent, path, false);
2370
+ this.expectEntry(location.node, options.expected, path, false);
2371
+ const mode = options.mode === undefined ? undefined : this.mode(options.mode, 0, "prepareDirectory", path);
2372
+ for (const time of [options.atimeMs, options.mtimeMs])
2373
+ if (time !== undefined && !Number.isFinite(time))
2374
+ this.fail("EINVAL", "prepareDirectory", path);
2375
+ let node = location.node;
2376
+ if (!node) {
2377
+ this.permission(location.parent, 3, "prepareDirectory", path);
2378
+ node = this.addNode(location.parent, location.name, () => this.directory(mode ?? 0o777), "prepareDirectory", path);
2379
+ }
2380
+ if (node.type !== "directory")
2381
+ this.fail("ENOTDIR", "prepareDirectory", path);
2382
+ if (mode !== undefined) {
2383
+ node.mode = typeModes.directory | mode;
2384
+ memoryCaches.get(this.ledger).clearWrites();
2385
+ }
2386
+ if (options.atimeMs !== undefined)
2387
+ node.atimeMs = options.atimeMs;
2388
+ if (options.mtimeMs !== undefined)
2389
+ node.mtimeMs = options.mtimeMs;
2390
+ node.ctimeMs = Date.now();
2391
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2392
+ return Object.freeze(this.snapshot(node));
2393
+ }
2394
+ async writeFileConditional(path, data, options) {
2395
+ options.signal?.throwIfAborted();
2396
+ const location = this.entry(path, "writeFileConditional", true);
2397
+ this.expectEntry(location.parent, options.parent, path, false);
2398
+ this.expectEntry(location.node, options.expected, path);
2399
+ if (location.node && location.node.type !== "file")
2400
+ this.fail("EINVAL", "writeFileConditional", path);
2401
+ if (options.atimeMs !== undefined)
2402
+ this.integer(options.atimeMs, "writeFileConditional", path);
2403
+ if (options.mtimeMs !== undefined)
2404
+ this.integer(options.mtimeMs, "writeFileConditional", path);
2405
+ const node = this.writeData(path, data, { ...(options.mode === undefined ? {} : { mode: options.mode }), flag: options.append ? "a" : "w" }, "writeFileConditional");
2406
+ if (options.atimeMs !== undefined)
2407
+ node.atimeMs = options.atimeMs;
2408
+ if (options.mtimeMs !== undefined)
2409
+ node.mtimeMs = options.mtimeMs;
2410
+ return Object.freeze(this.snapshot(node));
2411
+ }
2412
+ async removeEntryConditional(path, options) {
2413
+ options.signal?.throwIfAborted();
2414
+ const returnRemainingStat = options.returnRemainingStat === true;
2415
+ const location = this.entry(path, "removeEntryConditional", true);
2416
+ this.expectEntry(location.parent, options.parent, path, false);
2417
+ this.expectEntry(location.node, options.expected, path);
2418
+ const node = location.node;
2419
+ if (this.terminalDot(path))
2420
+ this.fail("EINVAL", "removeEntryConditional", path);
2421
+ if (node === this.root)
2422
+ this.fail("EBUSY", "removeEntryConditional", path);
2423
+ if (node.type !== "file" && node.type !== "symlink" && node.type !== "directory")
2424
+ this.fail("EINVAL", "removeEntryConditional", path);
2425
+ this.permission(location.parent, 3, "removeEntryConditional", path);
2426
+ if (node.type === "directory" && node.entries.size > 0)
2427
+ this.fail("ENOTEMPTY", "removeEntryConditional", path);
2428
+ location.parent.entries.delete(location.name);
2429
+ memoryCaches.get(this.ledger).clearWrites();
2430
+ this.ledger.release(location.name.length * 2, 1);
2431
+ node.nlink--;
2432
+ node.ctimeMs = Date.now();
2433
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2434
+ this.releaseNode(node);
2435
+ this.changed(location.parent);
2436
+ if (returnRemainingStat)
2437
+ return Object.freeze(this.snapshot(node));
2438
+ }
2439
+ async removeFileConditional(path, options) {
2440
+ options.signal?.throwIfAborted();
2441
+ const location = this.entry(path, "removeFileConditional", true);
2442
+ this.expectEntry(location.parent, options.parent, path, false);
2443
+ this.expectEntry(location.node, options.expected, path);
2444
+ const node = location.node;
2445
+ if (node.type !== "file")
2446
+ this.fail("EINVAL", "removeFileConditional", path);
2447
+ this.permission(location.parent, 3, "removeFileConditional", path);
2448
+ location.parent.entries.delete(location.name);
2449
+ memoryCaches.get(this.ledger).clearWrites();
2450
+ this.ledger.release(location.name.length * 2, 1);
2451
+ node.nlink--;
2452
+ node.ctimeMs = Date.now();
2453
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2454
+ this.releaseNode(node);
2455
+ this.changed(location.parent);
2456
+ }
2457
+ async removeTreeConditional(path, options) {
2458
+ options.signal?.throwIfAborted();
2459
+ const location = this.entry(path, "removeTreeConditional", true);
2460
+ this.expectEntry(location.parent, options.parent, path, false);
2461
+ this.expectEntry(location.node, options.expected, path, false);
2462
+ if (location.node?.type !== "directory")
2463
+ this.fail("ENOTDIR", "removeTreeConditional", path);
2464
+ this.removeLocation(location, path, "removeTreeConditional", true);
2465
+ }
2466
+ async writeFile(path, data, options = {}) {
2467
+ options.signal?.throwIfAborted();
2468
+ this.writeData(path, data, options, "writeFile");
2469
+ }
2470
+ async appendFile(path, data, options = {}) {
2471
+ options.signal?.throwIfAborted();
2472
+ this.writeData(path, data, { ...options, flag: "a" }, "appendFile");
2473
+ }
2474
+ async stat(path, options = {}) {
2475
+ options.signal?.throwIfAborted();
2476
+ return this.snapshot(this.resolveNode(path, "stat", true));
2477
+ }
2478
+ async lstat(path, options = {}) {
2479
+ options.signal?.throwIfAborted();
2480
+ const stat = this.snapshot(this.resolveNode(path, "lstat", false));
2481
+ ownedStats.set(stat, { filesystem: this, path, root: this.root });
2482
+ return stat;
2483
+ }
2484
+ async readdir(path, options = {}) {
2485
+ const limit = directoryEntryLimit(options, path);
2486
+ const node = this.resolveNode(path, "readdir", true);
2487
+ if (node.type !== "directory")
2488
+ this.fail("ENOTDIR", "readdir", path);
2489
+ this.permission(node, 4, "readdir", path);
2490
+ admitDirectoryEntries(node.entries.size, limit, path);
2491
+ node.atimeMs = Date.now();
2492
+ const result = new Array(node.entries.size);
2493
+ let idx = 0;
2494
+ for (const [name, entry] of node.entries) {
2495
+ result[idx++] = { name, type: entry.type };
2496
+ }
2497
+ return result.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
2498
+ }
2499
+ tryMkdirFastSync(path, recursive, mode) {
2500
+ try {
2501
+ this.validatePath(path, "mkdir");
2502
+ const resolvedMode = this.mode(mode, 0o777, "mkdir", path);
2503
+ if (recursive) {
2504
+ const node = this.resolve(path, "mkdir", { createDirectories: resolvedMode }).node;
2505
+ return node.type === "directory";
2506
+ }
2507
+ const location = this.resolve(path.replace(/\/+$/, "") || "/", "mkdir", { allowMissing: true, followFinal: false });
2508
+ if (location.node)
2509
+ return false;
2510
+ this.permission(location.parent, 3, "mkdir", path);
2511
+ this.addNode(location.parent, location.name, () => this.directory(resolvedMode), "mkdir", path);
2512
+ return true;
2513
+ }
2514
+ catch {
2515
+ return false;
2516
+ }
2517
+ }
2518
+ tryRmFastSync(path, recursive, force) {
2519
+ if (activeConditionalMutations.has(this.identityScope))
2520
+ return false;
2521
+ try {
2522
+ let location;
2523
+ try {
2524
+ location = this.entry(path, "rm", false);
2525
+ }
2526
+ catch (error) {
2527
+ if (force && error instanceof FsError && error.code === "ENOENT")
2528
+ return true;
2529
+ return false;
2530
+ }
2531
+ this.removeLocation(location, path, "rm", recursive);
2532
+ return true;
2533
+ }
2534
+ catch {
2535
+ return false;
2536
+ }
2537
+ }
2538
+ mkdir(path, options = {}) {
2539
+ try {
2540
+ options.signal?.throwIfAborted();
2541
+ this.validatePath(path, "mkdir");
2542
+ const mode = this.mode(options.mode, 0o777, "mkdir", path);
2543
+ if (options.recursive) {
2544
+ const node = this.resolve(path, "mkdir", { createDirectories: mode }).node;
2545
+ if (node.type !== "directory")
2546
+ this.fail("EEXIST", "mkdir", path);
2547
+ return resolvedVoid;
2548
+ }
2549
+ const location = this.resolve(path.replace(/\/+$/, "") || "/", "mkdir", { allowMissing: true, followFinal: false });
2550
+ if (location.node)
2551
+ this.fail("EEXIST", "mkdir", path);
2552
+ this.permission(location.parent, 3, "mkdir", path);
2553
+ this.addNode(location.parent, location.name, () => this.directory(mode), "mkdir", path);
2554
+ return resolvedVoid;
2555
+ }
2556
+ catch (error) {
2557
+ return Promise.reject(error);
2558
+ }
2559
+ }
2560
+ async rmdir(path, options = {}) {
2561
+ options.signal?.throwIfAborted();
2562
+ const location = this.entry(path, "rmdir");
2563
+ const node = location.node;
2564
+ if (this.terminalDot(path))
2565
+ this.fail("EINVAL", "rmdir", path);
2566
+ if (node === this.root)
2567
+ this.fail("EBUSY", "rmdir", path);
2568
+ if (node.type !== "directory")
2569
+ this.fail("ENOTDIR", "rmdir", path);
2570
+ this.permission(location.parent, 3, "rmdir", path);
2571
+ if (node.entries.size > 0)
2572
+ this.fail("ENOTEMPTY", "rmdir", path);
2573
+ location.parent.entries.delete(location.name);
2574
+ this.ledger.release(location.name.length * 2, 1);
2575
+ node.nlink = 0;
2576
+ node.ctimeMs = Date.now();
2577
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2578
+ this.releaseNode(node);
2579
+ this.changed(location.parent);
2580
+ }
2581
+ rm(path, options = {}) {
2582
+ try {
2583
+ options.signal?.throwIfAborted();
2584
+ const bound = activeConditionalMutations.get(this.identityScope);
2585
+ const active = bound?.path === path ? bound : undefined;
2586
+ const ancestors = options.ancestors ?? active?.ancestors;
2587
+ const expectedParent = options.parent ?? active?.parent;
2588
+ const expectedNode = options.expected ?? active?.expected;
2589
+ if (ancestors !== undefined)
2590
+ this.verifyDirectoryAncestry(ancestors, options);
2591
+ let location;
2592
+ try {
2593
+ location = this.entry(path, "rm", expectedNode !== undefined || expectedParent !== undefined);
2594
+ }
2595
+ catch (error) {
2596
+ if (options.force && error instanceof FsError && error.code === "ENOENT")
2597
+ return resolvedVoid;
2598
+ throw error;
2599
+ }
2600
+ if (expectedParent !== undefined)
2601
+ this.expectEntry(location.parent, expectedParent, path, false);
2602
+ if (expectedNode !== undefined) {
2603
+ if (options.force && !location.node)
2604
+ return resolvedVoid;
2605
+ this.expectEntry(location.node, expectedNode, path, location.node?.type !== "directory");
2606
+ }
2607
+ this.removeLocation(location, path, "rm", options.recursive === true);
2608
+ return resolvedVoid;
2609
+ }
2610
+ catch (error) {
2611
+ return Promise.reject(error);
2612
+ }
2613
+ }
2614
+ removeLocation(location, path, syscall, recursive, now = Date.now()) {
2615
+ const node = location.node;
2616
+ if (this.terminalDot(path))
2617
+ this.fail("EINVAL", syscall, path);
2618
+ if (node === this.root)
2619
+ this.fail("EBUSY", syscall, path);
2620
+ this.permission(location.parent, 3, syscall, path);
2621
+ if (node.type === "directory" && !recursive)
2622
+ this.fail("EISDIR", syscall, path);
2623
+ const cache = memoryCaches.get(this.ledger);
2624
+ cache.clearWrites();
2625
+ const removed = sharedRemovedScratch;
2626
+ sharedRemovedLen = 1;
2627
+ removed[0] = node;
2628
+ sharedRemovedKeyChars = 0;
2629
+ sharedRemovedKeyEntries = 0;
2630
+ try {
2631
+ for (let index = 0; index < sharedRemovedLen; index++) {
2632
+ const entry = removed[index];
2633
+ if (entry.type === "directory" && entry.entries.size > 0) {
2634
+ this.permission(entry, 7, syscall, path);
2635
+ entry.entries.forEach(collectRemovedChild);
2636
+ }
2637
+ }
2638
+ location.parent.entries.delete(location.name);
2639
+ this.ledger.release((location.name.length + sharedRemovedKeyChars) * 2, 1 + sharedRemovedKeyEntries);
2640
+ const totalRemoved = sharedRemovedLen;
2641
+ for (let i = 0; i < totalRemoved; i++) {
2642
+ const entry = removed[i];
2643
+ removed[i] = DUMMY_POOL_FILE_NODE;
2644
+ if (entry.type === "directory") {
2645
+ entry.entries.clear();
2646
+ }
2647
+ entry.nlink--;
2648
+ if (entry.nlink !== 0 || entry.references !== 0) {
2649
+ entry.ctimeMs = now;
2650
+ entry.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, entry.revision + 1);
2651
+ }
2652
+ this.releaseNode(entry);
2653
+ }
2654
+ }
2655
+ finally {
2656
+ for (let i = 0; i < sharedRemovedLen; i++)
2657
+ removed[i] = DUMMY_POOL_FILE_NODE;
2658
+ sharedRemovedLen = 0;
2659
+ }
2660
+ this.changed(location.parent, now);
2661
+ }
2662
+ unlink(path, options = {}) {
2663
+ // Do not allow an untyped recursive option to widen final-entry removal.
2664
+ return this.rm(path, { ...(options.signal === undefined ? {} : { signal: options.signal }) });
2665
+ }
2666
+ async rename(source, destination, options = {}) {
2667
+ options.signal?.throwIfAborted();
2668
+ try {
2669
+ const origin = this.entry(source, "rename");
2670
+ const target = this.entry(destination, "rename", true);
2671
+ const node = origin.node;
2672
+ if (this.terminalDot(source) || this.terminalDot(destination))
2673
+ this.fail("EINVAL", "rename", source, destination);
2674
+ if (node === this.root || target.node === this.root)
2675
+ this.fail("EBUSY", "rename", source, destination);
2676
+ if (destination.endsWith("/") && node.type !== "directory")
2677
+ this.fail("ENOTDIR", "rename", source, destination);
2678
+ if (options.noReplace && target.node)
2679
+ this.fail("EEXIST", "rename", source, destination);
2680
+ if (target.node === node)
2681
+ return;
2682
+ if (node.type === "directory" && target.path.startsWith(`${origin.path}/`))
2683
+ this.fail("EINVAL", "rename", source, destination);
2684
+ this.permission(origin.parent, 3, "rename", source);
2685
+ this.permission(target.parent, 3, "rename", destination);
2686
+ if (target.node) {
2687
+ if (node.type === "directory" && target.node.type !== "directory")
2688
+ this.fail("ENOTDIR", "rename", source, destination);
2689
+ if (node.type !== "directory" && target.node.type === "directory")
2690
+ this.fail("EISDIR", "rename", source, destination);
2691
+ if (target.node.type === "directory" && target.node.entries.size > 0)
2692
+ this.fail("ENOTEMPTY", "rename", source, destination);
2693
+ }
2694
+ const nameGrowth = target.node ? 0 : (target.name.length - origin.name.length) * 2;
2695
+ this.ledger.reserve(Math.max(0, nameGrowth), 0, "rename", source);
2696
+ try {
2697
+ target.parent.entries.set(target.name, node);
2698
+ }
2699
+ catch (error) {
2700
+ this.ledger.release(Math.max(0, nameGrowth), 0);
2701
+ throw error;
2702
+ }
2703
+ memoryCaches.get(this.ledger).clearWrites();
2704
+ origin.parent.entries.delete(origin.name);
2705
+ if (target.node) {
2706
+ this.ledger.release(origin.name.length * 2, 1);
2707
+ target.node.nlink--;
2708
+ target.node.ctimeMs = Date.now();
2709
+ target.node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, target.node.revision + 1);
2710
+ this.releaseNode(target.node);
2711
+ }
2712
+ else if (nameGrowth < 0)
2713
+ this.ledger.release(-nameGrowth, 0);
2714
+ this.changed(origin.parent);
2715
+ this.changed(target.parent);
2716
+ node.ctimeMs = Date.now();
2717
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2718
+ }
2719
+ catch (error) {
2720
+ if (error instanceof FsError)
2721
+ throw new FsError(error.code, { syscall: "rename", path: source, dest: destination, cause: error });
2722
+ throw error;
2723
+ }
2724
+ }
2725
+ async copyFile(source, destination, options = {}) {
2726
+ options.signal?.throwIfAborted();
2727
+ try {
2728
+ const origin = this.file(source, "copyFile");
2729
+ this.permission(origin, 4, "copyFile", source);
2730
+ const target = this.resolve(destination, "copyFile", { followFinal: !options.exclusive, allowMissing: true });
2731
+ if (target.node && options.exclusive)
2732
+ this.fail("EEXIST", "copyFile", source, destination);
2733
+ if (target.node === origin)
2734
+ this.fail("EINVAL", "copyFile", source, destination);
2735
+ const node = this.writeData(destination, origin.data, { mode: origin.mode & 0o7777, flag: options.exclusive ? "wx" : "w" }, "copyFile");
2736
+ node.mode = origin.mode;
2737
+ origin.atimeMs = Date.now();
2738
+ }
2739
+ catch (error) {
2740
+ if (error instanceof FsError)
2741
+ throw new FsError(error.code, { syscall: "copyFile", path: source, dest: destination, cause: error });
2742
+ throw error;
2743
+ }
2744
+ }
2745
+ async realpath(path, options = {}) {
2746
+ options.signal?.throwIfAborted();
2747
+ return this.resolve(path, "realpath").path;
2748
+ }
2749
+ access(path, mode = 0, options = {}) {
2750
+ try {
2751
+ options.signal?.throwIfAborted();
2752
+ if (!Number.isInteger(mode) || mode < 0 || mode > 7)
2753
+ this.fail("EINVAL", "access", path);
2754
+ this.permission(this.resolveNode(path, "access", true), mode, "access", path);
2755
+ return resolvedVoid;
2756
+ }
2757
+ catch (error) {
2758
+ return Promise.reject(error);
2759
+ }
2760
+ }
2761
+ async readlink(path, options = {}) {
2762
+ options.signal?.throwIfAborted();
2763
+ const node = this.resolve(path, "readlink", { followFinal: false }).node;
2764
+ if (node.type !== "symlink")
2765
+ this.fail("EINVAL", "readlink", path);
2766
+ return node.target;
2767
+ }
2768
+ async symlink(target, path, options = {}) {
2769
+ options.signal?.throwIfAborted();
2770
+ this.validatePath(target, "symlink");
2771
+ const location = this.resolve(path, "symlink", { followFinal: false, allowMissing: true });
2772
+ if (location.node)
2773
+ this.fail("EEXIST", "symlink", path);
2774
+ this.permission(location.parent, 3, "symlink", path);
2775
+ this.addNode(location.parent, location.name, () => ({
2776
+ ...this.metadata(typeModes.symlink | 0o777), type: "symlink", target,
2777
+ }), "symlink", path, target.length * 2);
2778
+ }
2779
+ async link(existingPath, newPath, options = {}) {
2780
+ options.signal?.throwIfAborted();
2781
+ const node = this.resolve(existingPath, "link", { followFinal: false }).node;
2782
+ if (node.type === "directory")
2783
+ this.fail("EPERM", "link", existingPath, newPath);
2784
+ const target = this.resolve(newPath, "link", { followFinal: false, allowMissing: true });
2785
+ if (target.node)
2786
+ this.fail("EEXIST", "link", existingPath, newPath);
2787
+ this.permission(target.parent, 3, "link", newPath);
2788
+ this.ledger.reserve(target.name.length * 2, 1, "link", newPath);
2789
+ try {
2790
+ target.parent.entries.set(target.name, node);
2791
+ }
2792
+ catch (error) {
2793
+ this.ledger.release(target.name.length * 2, 1);
2794
+ throw error;
2795
+ }
2796
+ node.nlink++;
2797
+ node.ctimeMs = Date.now();
2798
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2799
+ this.changed(target.parent);
2800
+ }
2801
+ async chmod(path, mode, options = {}) {
2802
+ options.signal?.throwIfAborted();
2803
+ const permissions = this.mode(mode, 0, "chmod", path);
2804
+ const bound = activeConditionalMutations.get(this.identityScope);
2805
+ const active = bound?.path === path ? bound : undefined;
2806
+ const conditional = snapshotConditionalChmod(path, active ? { ...active, ...options } : options);
2807
+ const controls = conditional ?? options;
2808
+ const ancestors = conditional?.ancestors;
2809
+ const expectedParent = conditional?.parent;
2810
+ const expectedNode = conditional?.expected;
2811
+ if (conditional?.commitGuard)
2812
+ runStagingGuard(conditional.commitGuard);
2813
+ controls.signal?.throwIfAborted();
2814
+ if (ancestors !== undefined)
2815
+ this.verifyDirectoryAncestry(ancestors, controls);
2816
+ const location = expectedNode !== undefined || expectedParent !== undefined
2817
+ ? this.entry(path, "chmod", true)
2818
+ : this.resolve(path, "chmod");
2819
+ if (expectedParent !== undefined)
2820
+ this.expectEntry(location.parent, expectedParent, path, false);
2821
+ if (expectedNode !== undefined)
2822
+ this.expectEntry(location.node, expectedNode, path, location.node?.type !== "directory");
2823
+ const node = location.node;
2824
+ if (node.type === "directory")
2825
+ memoryCaches.get(this.ledger).clearWrites();
2826
+ node.mode = typeModes[node.type] | permissions;
2827
+ node.ctimeMs = Date.now();
2828
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2829
+ }
2830
+ async utimes(path, atimeMs, mtimeMs, options = {}) {
2831
+ options.signal?.throwIfAborted();
2832
+ if (!Number.isFinite(atimeMs) || !Number.isFinite(mtimeMs))
2833
+ this.fail("EINVAL", "utimes", path);
2834
+ const node = this.resolve(path, "utimes").node;
2835
+ node.atimeMs = atimeMs;
2836
+ node.mtimeMs = mtimeMs;
2837
+ node.ctimeMs = Date.now();
2838
+ node.revision = Math.min(Number.MAX_SAFE_INTEGER + 1, node.revision + 1);
2839
+ }
2840
+ async truncate(path, length = 0, options = {}) {
2841
+ options.signal?.throwIfAborted();
2842
+ this.integer(length, "truncate", path);
2843
+ const node = this.file(path, "truncate");
2844
+ this.permission(node, 2, "truncate", path);
2845
+ this.resizeNode(node, length, "truncate", path);
2846
+ }
2847
+ resizeNode(node, length, syscall, path) {
2848
+ this.admitSize(node, length, syscall, path);
2849
+ const data = this.allocate(length, syscall, path);
2850
+ try {
2851
+ data.data.set(node.data.subarray(0, length));
2852
+ }
2853
+ catch (error) {
2854
+ data.release();
2855
+ throw error;
2856
+ }
2857
+ this.replaceData(node, data);
2858
+ this.changed(node);
2859
+ }
2860
+ async openResizeFile(path, options = {}) {
2861
+ options.signal?.throwIfAborted();
2862
+ if (!stockRetainedResize(this))
2863
+ throw new FsError("ENOTSUP", { syscall: "openResizeFile", path });
2864
+ const location = this.resolve(path, "openResizeFile", { allowMissing: options.create === true, resizeCreate: options.create ?? false });
2865
+ let mode = 0o666;
2866
+ if (location.node) {
2867
+ if (location.node.type !== "file")
2868
+ this.fail("EISDIR", "openResizeFile", path);
2869
+ this.permission(location.node, 2, "openResizeFile", path);
2870
+ }
2871
+ else {
2872
+ this.permission(location.parent, 3, "openResizeFile", path);
2873
+ mode = this.mode(options.mode, mode, "openResizeFile", path);
2874
+ }
2875
+ this.ledger.reserve(path.length * 2, 1, "openResizeFile", path);
2876
+ let node;
2877
+ try {
2878
+ node = this.openWrite(path, {}, "openResizeFile", { location, mode, append: false });
2879
+ node.references++;
2880
+ }
2881
+ catch (error) {
2882
+ this.ledger.release(path.length * 2, 1);
2883
+ throw error;
2884
+ }
2885
+ const snapshot = this.snapshot.bind(this);
2886
+ const integer = this.integer.bind(this);
2887
+ const resizeNode = this.resizeNode.bind(this);
2888
+ const releaseReference = this.releaseReference.bind(this);
2889
+ let closing;
2890
+ const current = (signal, syscall) => {
2891
+ signal?.throwIfAborted();
2892
+ if (!node)
2893
+ throw new FsError("EBADF", { syscall, path });
2894
+ return node;
2895
+ };
2896
+ return {
2897
+ async stat(options = {}) { return snapshot(current(options.signal, "fstat")); },
2898
+ async seekEnd(options = {}) { return BigInt(current(options.signal, "lseek").data.byteLength); },
2899
+ async truncate(length, options = {}) {
2900
+ const file = current(options.signal, "ftruncate");
2901
+ integer(length, "ftruncate", path);
2902
+ resizeNode(file, length, "ftruncate", path);
2903
+ },
2904
+ close() {
2905
+ if (!closing) {
2906
+ const retained = node;
2907
+ node = undefined;
2908
+ closing = Promise.resolve().then(() => { if (retained)
2909
+ releaseReference(retained, path); });
2910
+ }
2911
+ return closing;
2912
+ },
2913
+ };
2914
+ }
2915
+ async openReadFile(path, options = {}) {
2916
+ const signal = options.signal;
2917
+ signal?.throwIfAborted();
2918
+ const allowDirectory = options.allowDirectory === true;
2919
+ signal?.throwIfAborted();
2920
+ const unsupported = () => { throw new FsError("ENOTSUP", { syscall: "openReadFile", path }); };
2921
+ const owner = ownedStores.get(this);
2922
+ if (!owner || Object.getPrototypeOf(this) !== MemoryFileSystem.prototype
2923
+ || Object.getOwnPropertyDescriptor(this, "root")?.value !== owner.root
2924
+ || Object.getOwnPropertyDescriptor(this, "ledger")?.value !== owner.ledger)
2925
+ unsupported();
2926
+ for (const name of ["openReadFile", "readFile", "readStream", "stat", "lstat", "realpath", "access",
2927
+ "file", "resolve", "permission", "validatePath", "fail", "snapshot", "integer", "releaseReference", "releaseNode"]) {
2928
+ const descriptor = Object.getOwnPropertyDescriptor(this, name)
2929
+ ?? Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, name);
2930
+ if (!descriptor || !("value" in descriptor) || descriptor.value !== memoryImplementation[name]?.value)
2931
+ unsupported();
2932
+ }
2933
+ const capabilities = Object.getOwnPropertyDescriptor(this, "capabilities");
2934
+ const retainedRead = capabilities === undefined
2935
+ ? Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, "capabilities")?.get === memoryImplementation.capabilities?.get
2936
+ : capabilities.value?.retainedRead;
2937
+ signal?.throwIfAborted();
2938
+ if (retainedRead !== true)
2939
+ unsupported();
2940
+ const selected = allowDirectory ? this.resolve(path, "openReadFile").node : this.file(path, "openReadFile");
2941
+ if (selected.type !== "file" && selected.type !== "directory")
2942
+ this.fail("EISDIR", "openReadFile", path);
2943
+ let node = selected;
2944
+ this.permission(node, 4, "openReadFile", path);
2945
+ signal?.throwIfAborted();
2946
+ this.ledger.reserve(path.length * 2, 1, "openReadFile", path);
2947
+ node.references++;
2948
+ const snapshot = this.snapshot.bind(this);
2949
+ const integer = this.integer.bind(this);
2950
+ const releaseReference = this.releaseReference.bind(this);
2951
+ let closing;
2952
+ const current = (signal, syscall) => {
2953
+ signal?.throwIfAborted();
2954
+ if (!node)
2955
+ throw new FsError("EBADF", { syscall, path });
2956
+ return node;
2957
+ };
2958
+ return {
2959
+ async stat(options = {}) {
2960
+ return snapshot(current(options.signal, "fstat"));
2961
+ },
2962
+ async seekEnd(options = {}) {
2963
+ const file = current(options.signal, "lseek");
2964
+ return file.type === "directory" ? ext4HtreeEof64 : BigInt(file.data.byteLength);
2965
+ },
2966
+ async read(position, maxBytes, options = {}) {
2967
+ const file = current(options.signal, "read");
2968
+ integer(position, "read", path);
2969
+ integer(maxBytes, "read", path);
2970
+ if (maxBytes === 0 || maxBytes > Number.MAX_SAFE_INTEGER - position) {
2971
+ throw new FsError("EINVAL", { syscall: "read", path });
2972
+ }
2973
+ if (file.type === "directory")
2974
+ throw new FsError("EISDIR", { syscall: "read", path });
2975
+ const bytes = file.data.slice(position, position + maxBytes);
2976
+ file.atimeMs = Date.now();
2977
+ return bytes;
2978
+ },
2979
+ close() {
2980
+ if (node) {
2981
+ releaseReference(node, path);
2982
+ node = undefined;
2983
+ }
2984
+ closing ??= Promise.resolve();
2985
+ return closing;
2986
+ },
2987
+ };
2988
+ }
2989
+ readStream(path, options = {}) {
2990
+ return new MemoryReadStream(this, path, options);
2991
+ }
2992
+ async writeStream(path, source, options = {}) {
2993
+ options.signal?.throwIfAborted();
2994
+ this.validatePath(path, "writeStream");
2995
+ this.ledger.reserve(path.length * 2, 1, "writeStream", path);
2996
+ let node;
2997
+ try {
2998
+ node = this.openWrite(path, options, "writeStream");
2999
+ const guard = options[extractionStreamGuard];
3000
+ node.references++;
3001
+ guard?.(node);
3002
+ const append = options.flag === "a" || options.flag === "ax";
3003
+ let position = 0;
3004
+ if (!append) {
3005
+ this.replaceData(node, new MemoryAllocation(new Uint8Array(), this.ledger));
3006
+ this.changed(node);
3007
+ }
3008
+ for await (const chunk of source) {
3009
+ options.signal?.throwIfAborted();
3010
+ guard?.(node);
3011
+ if (!(chunk instanceof Uint8Array))
3012
+ throw new TypeError("Memory files require Uint8Array data");
3013
+ this.writeAt(node, chunk, append ? node.data.byteLength : position, "writeStream", path);
3014
+ if (!append)
3015
+ position += chunk.byteLength;
3016
+ }
3017
+ options.signal?.throwIfAborted();
3018
+ }
3019
+ finally {
3020
+ if (node)
3021
+ this.releaseReference(node, path);
3022
+ else
3023
+ this.ledger.release(path.length * 2, 1);
3024
+ }
3025
+ }
3026
+ }
3027
+ const memoryImplementation = Object.getOwnPropertyDescriptors(MemoryFileSystem.prototype);
3028
+ const memoryImplementationKeys = Object.keys(memoryImplementation);
3029
+ const memoryImplementationDescriptors = memoryImplementationKeys.map(key => memoryImplementation[key]);
3030
+ const MEMORY_DESCRIPTOR_CAPABILITIES = Object.freeze({
3031
+ noFollow: true, positionedRead: true, positionedWrite: true, truncate: true, synchronization: "volatile", position: true,
3032
+ });
3033
+ const memoryDescriptorGetPosition = async (retained) => retained.position;
3034
+ const memoryDescriptorStat = async (retained) => retained.fs.snapshot(retained.node);
3035
+ const memoryDescriptorRead = async (retained, buffer, position) => {
3036
+ const inode = retained.node;
3037
+ const start = position ?? retained.position;
3038
+ const count = Math.min(buffer.byteLength, Math.max(0, inode.data.byteLength - start));
3039
+ buffer.set(inode.data.subarray(start, start + count));
3040
+ if (position === null)
3041
+ retained.position += count;
3042
+ inode.atimeMs = Date.now();
3043
+ return count;
3044
+ };
3045
+ const memoryDescriptorWrite = async (retained, buffer, position) => {
3046
+ const inode = retained.node;
3047
+ const start = retained.append ? inode.data.byteLength : position ?? retained.position;
3048
+ const end = start + buffer.byteLength;
3049
+ retained.fs.writeAt(inode, buffer, start, "write", retained.path);
3050
+ if (position === null)
3051
+ retained.position = end;
3052
+ return buffer.byteLength;
3053
+ };
3054
+ const memoryDescriptorTruncate = async (retained, length) => {
3055
+ retained.fs.resizeNode(retained.node, length, "ftruncate", retained.path);
3056
+ };
3057
+ const memoryDescriptorSync = async () => { };
3058
+ const memoryDescriptorClose = async (retained) => {
3059
+ const inode = retained.node;
3060
+ retained.node = undefined;
3061
+ retained.fs.releaseReference(inode, retained.path);
3062
+ };
3063
+ const stockDescriptorWriteMethodNames = [
3064
+ "writeStream", "writeFile", "appendFile", "access", "stat", "lstat", "realpath",
3065
+ "openWrite", "prepareWrite", "writeData", "addNode", "replaceData", "releaseReference", "releaseNode",
3066
+ "resolve", "permission", "validatePath", "mode", "bytes", "allocate", "admitSize", "changed", "metadata", "integer", "writeAt", "fail",
3067
+ ];
3068
+ const stockRetainedResizeMethodNames = [
3069
+ "openResizeFile", "truncate", "resizeNode", "snapshot",
3070
+ ];
3071
+ function stockDescriptorWrite(filesystem) {
3072
+ if (!isStockMemoryMethods(filesystem, stockDescriptorWriteMethodNames, true))
3073
+ return false;
3074
+ const owner = ownedStores.get(filesystem);
3075
+ const capDesc = Object.getOwnPropertyDescriptor(filesystem, "capabilities");
3076
+ return (capDesc === undefined && Object.getOwnPropertyDescriptor(MemoryFileSystem.prototype, "capabilities")?.get === memoryImplementation.capabilities?.get) || (!!capDesc && "value" in capDesc && capDesc.value === owner.capabilities);
3077
+ }
3078
+ function stockRetainedResize(filesystem) {
3079
+ if (!stockDescriptorWrite(filesystem) || !isStockMemoryMethods(filesystem, stockRetainedResizeMethodNames, false))
3080
+ return false;
3081
+ const owner = ownedStores.get(filesystem);
3082
+ const ledgerDesc = Object.getOwnPropertyDescriptor(filesystem, "ledger");
3083
+ return !!ledgerDesc && "value" in ledgerDesc && ledgerDesc.value === owner.ledger;
3084
+ }
3085
+ export function createMemoryFileSystem(options = {}) {
3086
+ return new MemoryFileSystem(options);
3087
+ }
3088
+ const missingTargetMethodNames = ["realpath", "lstat", "resolve", "permission", "validatePath", "fail", "snapshot"];
3089
+ const deviceFastMethodNames = ["lstat", "readlink", "resolve", "permission", "validatePath", "fail", "snapshot"];
3090
+ const readFileFastMethodNames = ["readFile", "file", "resolve", "permission", "validatePath", "fail", "integer"];
3091
+ const writeFileFastMethodNames = [
3092
+ "writeFile", "appendFile", "writeData", "prepareWrite", "openWrite", "writeAt",
3093
+ "addNode", "replaceData", "resolve", "permission", "validatePath", "mode",
3094
+ "bytes", "allocate", "admitSize", "changed", "metadata", "fail",
3095
+ ];
3096
+ const mkdirFastMethodNames = [
3097
+ "mkdir", "lstat", "stat", "resolve", "permission", "validatePath", "mode",
3098
+ "addNode", "directory", "changed", "fail",
3099
+ ];
3100
+ const rmFastMethodNames = [
3101
+ "rm", "lstat", "stat", "readdir", "entry", "resolve", "removeLocation",
3102
+ "permission", "validatePath", "terminalDot", "releaseNode", "changed", "fail",
3103
+ ];
3104
+ const openRedirectFastMethodNames = [
3105
+ "open", "writeFile", "appendFile", "rename", "writeData", "prepareWrite", "openWrite",
3106
+ "resizeNode", "writeAt", "addNode", "replaceData", "resolve", "permission",
3107
+ "validatePath", "mode", "bytes", "allocate", "admitSize", "changed", "metadata",
3108
+ "releaseReference", "releaseNode", "fail",
3109
+ ];
3110
+ export class MemoryRedirectHandle {
3111
+ constructor(fs, path, node, append) {
3112
+ this.fs = fs;
3113
+ this.path = path;
3114
+ this.node = node;
3115
+ this.append = append;
3116
+ this.position = 0;
3117
+ this.closed = false;
3118
+ }
3119
+ reset(fs, path, node, append) {
3120
+ this.fs = fs;
3121
+ this.path = path;
3122
+ this.node = node;
3123
+ this.append = append;
3124
+ this.position = 0;
3125
+ this.closed = false;
3126
+ }
3127
+ writeRangeSync(src, len, signal) {
3128
+ signal?.throwIfAborted();
3129
+ if (this.closed)
3130
+ throw new FsError("EBADF", { syscall: "write", path: this.path });
3131
+ if (len === 0)
3132
+ return;
3133
+ const pos = this.append ? this.node.byteLength : this.position;
3134
+ const now = Date.now();
3135
+ this.fs.writeAtRange(this.node, src, len, pos, "write", this.path, now);
3136
+ if (!this.append)
3137
+ this.position = pos + len;
3138
+ }
3139
+ writeImmutableSync(immutableData, signal) {
3140
+ signal?.throwIfAborted();
3141
+ if (this.closed)
3142
+ throw new FsError("EBADF", { syscall: "write", path: this.path });
3143
+ const len = immutableData.byteLength;
3144
+ if (len === 0)
3145
+ return;
3146
+ const mem = this.fs;
3147
+ if (!this.append &&
3148
+ this.position === 0 &&
3149
+ this.node.byteLength === 0 &&
3150
+ this.node.allocation === DUMMY_POOL_ALLOCATION &&
3151
+ mem.ledger.hasInfiniteRetained &&
3152
+ mem.ledger.hasInfiniteFileBytes &&
3153
+ mem.ledger.limits.maxBytes === undefined) {
3154
+ const now = Date.now();
3155
+ this.node.byteLength = len;
3156
+ this.node.view = immutableData;
3157
+ this.node.sourceRef = immutableData;
3158
+ this.position = len;
3159
+ mem.totalBytes += len;
3160
+ mem.changed(this.node, now);
3161
+ return;
3162
+ }
3163
+ this.writeRangeSync(immutableData, len, signal);
3164
+ }
3165
+ writeSync(chunk, signal) {
3166
+ this.writeRangeSync(chunk, chunk.byteLength, signal);
3167
+ }
3168
+ close() {
3169
+ if (this.closed)
3170
+ return;
3171
+ this.closed = true;
3172
+ const fs = this.fs;
3173
+ const node = this.node;
3174
+ const path = this.path;
3175
+ this.fs = undefined;
3176
+ this.node = DUMMY_POOL_FILE_NODE;
3177
+ this.path = "";
3178
+ if (node.nlink > 0 && node.references === 1) {
3179
+ node.references = 0;
3180
+ fs.ledger.release(path.length * 2, 1);
3181
+ }
3182
+ else {
3183
+ fs.releaseReference(node, path);
3184
+ }
3185
+ if (redirectHandlePool.handle === undefined) {
3186
+ redirectHandlePool.handle = this;
3187
+ }
3188
+ }
3189
+ }
3190
+ const redirectHandlePool = { handle: undefined };
3191
+ let _lastRedirectSlice1Path = "";
3192
+ let _lastRedirectSlice1Name = "";
3193
+ let _lastFileSlice1Path = "";
3194
+ let _lastFileSlice1Name = "";
3195
+ export function tryOpenMemoryRedirectHandleSync(filesystem, path, append, mode, signal) {
3196
+ const mem = filesystem;
3197
+ const owner = mem._owner ?? ownedStores.get(mem);
3198
+ if (!owner ||
3199
+ mem.symlinkCount !== 0 ||
3200
+ mem.capabilities !== owner.capabilities ||
3201
+ (activeConditionalMutations.size > 0 && activeConditionalMutations.has(mem.identityScope)) ||
3202
+ !isStockMemoryMethods(mem, openRedirectFastMethodNames, false) ||
3203
+ !isCleanAbsolutePath(path) ||
3204
+ path === "/" ||
3205
+ path === "/dev" ||
3206
+ path.startsWith("/dev/")) {
3207
+ return undefined;
3208
+ }
3209
+ signal?.throwIfAborted();
3210
+ validatePath(path, owner.ledger.limits);
3211
+ const validMode = (mode & 0o777) === mode
3212
+ ? mode
3213
+ : mem.mode(mode, 0o666, "open", path);
3214
+ const memInternal = mem;
3215
+ let parent = memInternal.root;
3216
+ let start = 1;
3217
+ let name = "";
3218
+ while (true) {
3219
+ memInternal.permission(parent, 1, "open", path);
3220
+ const slash = path.indexOf("/", start);
3221
+ if (slash === -1) {
3222
+ name = start === 1
3223
+ ? (path === _lastRedirectSlice1Path ? _lastRedirectSlice1Name : (_lastRedirectSlice1Path = path, _lastRedirectSlice1Name = path.slice(1)))
3224
+ : path.slice(start);
3225
+ if (exceedsComponentByteLimit(name))
3226
+ memInternal.fail("ENAMETOOLONG", "open", path);
3227
+ break;
3228
+ }
3229
+ const seg = slicePathSegment(path, start, slash);
3230
+ if (exceedsComponentByteLimit(seg))
3231
+ memInternal.fail("ENAMETOOLONG", "open", path);
3232
+ const next = parent.entries.get(seg);
3233
+ if (!next)
3234
+ memInternal.fail("ENOENT", "open", path);
3235
+ if (next.type !== "directory")
3236
+ memInternal.fail("ENOTDIR", "open", path);
3237
+ parent = next;
3238
+ start = slash + 1;
3239
+ }
3240
+ const existing = parent.entries.getForWrite(name);
3241
+ const ledger = memInternal.ledger;
3242
+ let node;
3243
+ if (existing !== undefined) {
3244
+ if (existing.type !== "file")
3245
+ memInternal.fail("EISDIR", "open", path);
3246
+ memInternal.permission(existing, 2, "open", path);
3247
+ ledger.reserve(path.length * 2, 1, "open", path);
3248
+ node = existing;
3249
+ if (!append) {
3250
+ try {
3251
+ memInternal.resizeNode(node, 0, "open", path);
3252
+ }
3253
+ catch (error) {
3254
+ ledger.release(path.length * 2, 1);
3255
+ throw error;
3256
+ }
3257
+ }
3258
+ node.references++;
3259
+ }
3260
+ else {
3261
+ memInternal.permission(parent, 3, "open", path);
3262
+ const refBytes = path.length * 2;
3263
+ const nameBytes = name.length * 2;
3264
+ if (ledger.hasInfiniteRetained && ledger.hasInfiniteFileBytes) {
3265
+ ledger.reserve(refBytes + nameBytes, 3, "open", path);
3266
+ }
3267
+ else {
3268
+ ledger.reserve(refBytes, 1, "open", path);
3269
+ try {
3270
+ ledger.fileSize(0, "open", path);
3271
+ ledger.reserve(nameBytes, 2, "open", path);
3272
+ }
3273
+ catch (error) {
3274
+ ledger.release(refBytes, 1);
3275
+ throw error;
3276
+ }
3277
+ }
3278
+ const cache = mem._cache;
3279
+ cache.clearWrites();
3280
+ const now = Date.now();
3281
+ const fileMode = typeModes.file | validMode;
3282
+ let newNode;
3283
+ if (sharedFileNodePoolLen > 0) {
3284
+ newNode = sharedFileNodePool[--sharedFileNodePoolLen];
3285
+ sharedFileNodePool[sharedFileNodePoolLen] = DUMMY_POOL_FILE_NODE;
3286
+ }
3287
+ else {
3288
+ newNode = cache.files.pop();
3289
+ }
3290
+ if (newNode) {
3291
+ newNode.mode = fileMode;
3292
+ newNode.ino = memInternal.nextInode++;
3293
+ if (newNode.nlink !== 1)
3294
+ newNode.nlink = 1;
3295
+ newNode.references = 1;
3296
+ if (newNode.revision !== 0)
3297
+ newNode.revision = 0;
3298
+ newNode.atimeMs = now;
3299
+ newNode.mtimeMs = now;
3300
+ newNode.ctimeMs = now;
3301
+ newNode.birthtimeMs = now;
3302
+ newNode.byteLength = 0;
3303
+ newNode.view = EMPTY_ALLOC_BYTES;
3304
+ newNode.allocation = DUMMY_POOL_ALLOCATION;
3305
+ }
3306
+ else {
3307
+ newNode = new MemoryFileNode(fileMode, memInternal.nextInode++, now, 0, DUMMY_POOL_ALLOCATION, EMPTY_ALLOC_BYTES);
3308
+ newNode.references = 1;
3309
+ }
3310
+ const prevNlink = parent.cachedNlinkRev === parent.revision ? parent.cachedNlink : (parent.entries.size === 0 ? 2 : undefined);
3311
+ const entries = parent.entries;
3312
+ if (entries._missKey === name && entries._next < entries._keys.length) {
3313
+ const entryIdx = entries._next++;
3314
+ entries._table[entries._missSlot] = entryIdx;
3315
+ entries._keys[entryIdx] = name;
3316
+ entries._vals[entryIdx] = newNode;
3317
+ entries.size++;
3318
+ entries._missKey = "";
3319
+ }
3320
+ else {
3321
+ entries.set(name, newNode);
3322
+ }
3323
+ mem.mutationTick = (mem.mutationTick + 1) | 0;
3324
+ parent.revision = parent.revision < 1073741823 ? (parent.revision + 1) | 0 : Math.min(Number.MAX_SAFE_INTEGER + 1, parent.revision + 1);
3325
+ parent.mtimeMs = parent.ctimeMs = now;
3326
+ if (prevNlink !== undefined) {
3327
+ parent.cachedNlink = prevNlink;
3328
+ parent.cachedNlinkRev = parent.revision;
3329
+ }
3330
+ node = newNode;
3331
+ }
3332
+ const handle = redirectHandlePool.handle;
3333
+ if (handle !== undefined) {
3334
+ redirectHandlePool.handle = undefined;
3335
+ handle.reset(mem, path, node, append);
3336
+ return handle;
3337
+ }
3338
+ return new MemoryRedirectHandle(mem, path, node, append);
3339
+ }
3340
+ export function utf8ByteLength(value) {
3341
+ let bytes = 0;
3342
+ for (let i = 0; i < value.length; i++) {
3343
+ const code = value.charCodeAt(i);
3344
+ if (code < 0x80)
3345
+ bytes += 1;
3346
+ else if (code < 0x800)
3347
+ bytes += 2;
3348
+ else if (code >= 0xd800 && code <= 0xdbff && i + 1 < value.length && value.charCodeAt(i + 1) >= 0xdc00 && value.charCodeAt(i + 1) <= 0xdfff) {
3349
+ bytes += 4;
3350
+ i++;
3351
+ }
3352
+ else
3353
+ bytes += 3;
3354
+ }
3355
+ return bytes;
3356
+ }
3357
+ function exceedsComponentByteLimit(value) {
3358
+ return value.length > 85 && (value.length > 255 || utf8ByteLength(value) > 255);
3359
+ }
3360
+ export function isCleanAbsolutePath(path) {
3361
+ const len = path.length;
3362
+ if (len <= 1 || len > 65536 || path.charCodeAt(0) !== 47 || path.charCodeAt(len - 1) === 47)
3363
+ return false;
3364
+ let segStart = 1;
3365
+ let components = 1;
3366
+ for (let i = 1; i < len; i++) {
3367
+ const c = path.charCodeAt(i);
3368
+ if (c === 0)
3369
+ return false;
3370
+ if (c === 47) {
3371
+ const segLen = i - segStart;
3372
+ if (segLen === 0)
3373
+ return false;
3374
+ if (segLen === 1 && path.charCodeAt(segStart) === 46)
3375
+ return false;
3376
+ if (segLen === 2 && path.charCodeAt(segStart) === 46 && path.charCodeAt(segStart + 1) === 46)
3377
+ return false;
3378
+ if (++components > 256)
3379
+ return false;
3380
+ segStart = i + 1;
3381
+ }
3382
+ }
3383
+ const lastLen = len - segStart;
3384
+ if (lastLen === 1 && path.charCodeAt(segStart) === 46)
3385
+ return false;
3386
+ if (lastLen === 2 && path.charCodeAt(segStart) === 46 && path.charCodeAt(segStart + 1) === 46)
3387
+ return false;
3388
+ return true;
3389
+ }
3390
+ export function tryResolveMemoryDevicePath(filesystem, path, resizeCreate) {
3391
+ const mem = filesystem;
3392
+ if (!ownedStores.has(mem) || mem.symlinkCount !== 0 || !isStockMemoryMethods(mem, deviceFastMethodNames, false))
3393
+ return undefined;
3394
+ validatePath(path, ownedStores.get(mem).ledger.limits);
3395
+ if (!isCleanAbsolutePath(path) || path === "/dev" || path.startsWith("/dev/"))
3396
+ return undefined;
3397
+ let current = mem.root;
3398
+ let start = 1;
3399
+ while (true) {
3400
+ if (((current.mode >> 6) & 1) !== 1)
3401
+ return undefined;
3402
+ const slash = path.indexOf("/", start);
3403
+ if (slash === -1) {
3404
+ const name = slicePathSegment(path, start, path.length);
3405
+ if (exceedsComponentByteLimit(name))
3406
+ return undefined;
3407
+ if (resizeCreate === false && !current.entries.has(name))
3408
+ return undefined;
3409
+ return path;
3410
+ }
3411
+ const name = slicePathSegment(path, start, slash);
3412
+ if (exceedsComponentByteLimit(name))
3413
+ return undefined;
3414
+ const next = current.entries.get(name);
3415
+ if (!next) {
3416
+ if (resizeCreate !== undefined)
3417
+ return undefined;
3418
+ let remStart = slash + 1;
3419
+ while (true) {
3420
+ const nextSlash = path.indexOf("/", remStart);
3421
+ const seg = nextSlash === -1 ? slicePathSegment(path, remStart, path.length) : slicePathSegment(path, remStart, nextSlash);
3422
+ if (exceedsComponentByteLimit(seg))
3423
+ return undefined;
3424
+ if (nextSlash === -1)
3425
+ return path;
3426
+ remStart = nextSlash + 1;
3427
+ }
3428
+ }
3429
+ if (next.type !== "directory")
3430
+ return undefined;
3431
+ current = next;
3432
+ start = slash + 1;
3433
+ }
3434
+ }
3435
+ const cachedMethodValuesMap = /* @__PURE__ */ new WeakMap();
3436
+ function getExpectedMethodValues(names) {
3437
+ let vals = cachedMethodValuesMap.get(names);
3438
+ if (!vals) {
3439
+ vals = names.map(name => memoryImplementation[name]?.value);
3440
+ cachedMethodValuesMap.set(names, vals);
3441
+ }
3442
+ return vals;
3443
+ }
3444
+ const hasOwn = Object.prototype.hasOwnProperty;
3445
+ function isStockMemoryMethods(mem, names, checkRootAccessor = true) {
3446
+ const owner = mem?._owner ?? ownedStores.get(mem);
3447
+ if (!owner || Object.getPrototypeOf(mem) !== MemoryFileSystem.prototype || ownedStores.get(mem) !== owner)
3448
+ return false;
3449
+ if (checkRootAccessor) {
3450
+ const rootDesc = Object.getOwnPropertyDescriptor(mem, "root");
3451
+ if (!rootDesc || !("value" in rootDesc) || rootDesc.value !== owner.root)
3452
+ return false;
3453
+ }
3454
+ else if (mem.root !== owner.root) {
3455
+ return false;
3456
+ }
3457
+ const vals = getExpectedMethodValues(names);
3458
+ const proto = MemoryFileSystem.prototype;
3459
+ for (let i = 0; i < names.length; i++) {
3460
+ const name = names[i];
3461
+ const expected = vals[i];
3462
+ if (hasOwn.call(mem, name)) {
3463
+ const descriptor = Object.getOwnPropertyDescriptor(mem, name);
3464
+ if (!descriptor || !("value" in descriptor) || descriptor.value !== expected)
3465
+ return false;
3466
+ }
3467
+ else if (proto[name] !== expected) {
3468
+ return false;
3469
+ }
3470
+ }
3471
+ return true;
3472
+ }
3473
+ let lastReadViewData;
3474
+ let lastReadViewSourceRef;
3475
+ export function getLastReadMemoryFileSourceRef(view) {
3476
+ const ref = view === lastReadViewData?.deref() ? lastReadViewSourceRef?.deref() : undefined;
3477
+ lastReadViewData = undefined;
3478
+ lastReadViewSourceRef = undefined;
3479
+ return ref;
3480
+ }
3481
+ export function tryReadMemoryFileViewSync(filesystem, path, maxBytes, signal, captureSourceRef = false, beforeRead) {
3482
+ // A capture belongs only to the most recent read, including failed/fallback reads.
3483
+ lastReadViewData = undefined;
3484
+ lastReadViewSourceRef = undefined;
3485
+ const mem = filesystem;
3486
+ if (mem._owner === undefined || !isStockMemoryMethods(mem, readFileFastMethodNames, false))
3487
+ return undefined;
3488
+ signal?.throwIfAborted();
3489
+ beforeRead?.();
3490
+ if (maxBytes !== undefined && maxBytes !== Infinity)
3491
+ mem.integer(maxBytes, "readFile", path);
3492
+ const node = mem.file(path, "readFile");
3493
+ mem.permission(node, 4, "readFile", path);
3494
+ const data = node.data;
3495
+ if (maxBytes !== undefined && data.byteLength > maxBytes)
3496
+ mem.fail("EFBIG", "readFile", path);
3497
+ node.atimeMs = Date.now();
3498
+ if (captureSourceRef && node.revision === 0) {
3499
+ lastReadViewData = new WeakRef(data);
3500
+ lastReadViewSourceRef = node.sourceRef === undefined ? undefined : new WeakRef(node.sourceRef);
3501
+ }
3502
+ return data;
3503
+ }
3504
+ let segCache0 = "";
3505
+ let segCache1 = "";
3506
+ let segCache2 = "";
3507
+ let segCache3 = "";
3508
+ let segCacheCursor = 0;
3509
+ function slicePathSegment(path, start, end) {
3510
+ const len = end - start;
3511
+ if (len <= 0)
3512
+ return "";
3513
+ if (len === 1)
3514
+ return String.fromCharCode(path.charCodeAt(start));
3515
+ if (len <= 16) {
3516
+ const c0 = path.charCodeAt(start);
3517
+ if (segCache0.length === len && segCache0.charCodeAt(0) === c0) {
3518
+ let ok = true;
3519
+ for (let i = 1; i < len; i++)
3520
+ if (path.charCodeAt(start + i) !== segCache0.charCodeAt(i)) {
3521
+ ok = false;
3522
+ break;
3523
+ }
3524
+ if (ok)
3525
+ return segCache0;
3526
+ }
3527
+ if (segCache1.length === len && segCache1.charCodeAt(0) === c0) {
3528
+ let ok = true;
3529
+ for (let i = 1; i < len; i++)
3530
+ if (path.charCodeAt(start + i) !== segCache1.charCodeAt(i)) {
3531
+ ok = false;
3532
+ break;
3533
+ }
3534
+ if (ok)
3535
+ return segCache1;
3536
+ }
3537
+ if (segCache2.length === len && segCache2.charCodeAt(0) === c0) {
3538
+ let ok = true;
3539
+ for (let i = 1; i < len; i++)
3540
+ if (path.charCodeAt(start + i) !== segCache2.charCodeAt(i)) {
3541
+ ok = false;
3542
+ break;
3543
+ }
3544
+ if (ok)
3545
+ return segCache2;
3546
+ }
3547
+ if (segCache3.length === len && segCache3.charCodeAt(0) === c0) {
3548
+ let ok = true;
3549
+ for (let i = 1; i < len; i++)
3550
+ if (path.charCodeAt(start + i) !== segCache3.charCodeAt(i)) {
3551
+ ok = false;
3552
+ break;
3553
+ }
3554
+ if (ok)
3555
+ return segCache3;
3556
+ }
3557
+ const sliced = path.slice(start, end);
3558
+ const slot = segCacheCursor;
3559
+ segCacheCursor = (slot + 1) & 3;
3560
+ if (slot === 0)
3561
+ segCache0 = sliced;
3562
+ else if (slot === 1)
3563
+ segCache1 = sliced;
3564
+ else if (slot === 2)
3565
+ segCache2 = sliced;
3566
+ else
3567
+ segCache3 = sliced;
3568
+ return sliced;
3569
+ }
3570
+ return path.slice(start, end);
3571
+ }
3572
+ export function tryGetMemoryDirectoryEntryNamesSync(filesystem, path) {
3573
+ const mem = filesystem;
3574
+ const owner = ownedStores.get(mem);
3575
+ if (!owner || mem.symlinkCount !== 0 || !isStockMemoryMethods(mem, readFileFastMethodNames, false))
3576
+ return undefined;
3577
+ validatePath(path, owner.ledger.limits);
3578
+ const root = mem.root;
3579
+ if (path === "/") {
3580
+ if (((root.mode >> 6) & 5) !== 5)
3581
+ return undefined;
3582
+ return root.entries;
3583
+ }
3584
+ if (!isCleanAbsolutePath(path) || path === "/dev" || path.startsWith("/dev/"))
3585
+ return undefined;
3586
+ const cache = memoryCaches.get(owner.ledger);
3587
+ const fastDir = cache?.lastFastDirNode;
3588
+ const fastPrefix = cache?.lastFastDirPrefix;
3589
+ if (fastDir !== undefined &&
3590
+ fastDir.nlink !== 0 &&
3591
+ ((fastDir.mode >> 6) & 5) === 5 &&
3592
+ fastPrefix !== undefined &&
3593
+ (fastPrefix === path || (fastPrefix.length === path.length + 1 && fastPrefix.charCodeAt(path.length) === 47 && fastPrefix.startsWith(path)))) {
3594
+ return fastDir.entries;
3595
+ }
3596
+ let current = root;
3597
+ let start = 1;
3598
+ while (true) {
3599
+ if (((current.mode >> 6) & 1) !== 1)
3600
+ return undefined;
3601
+ const slash = path.indexOf("/", start);
3602
+ if (slash === -1) {
3603
+ const next = current.entries.getSubstr(path, start, path.length);
3604
+ if (!next || next.type !== "directory" || ((next.mode >> 6) & 5) !== 5)
3605
+ return undefined;
3606
+ return next.entries;
3607
+ }
3608
+ const next = current.entries.getSubstr(path, start, slash);
3609
+ if (!next || next.type !== "directory")
3610
+ return undefined;
3611
+ current = next;
3612
+ start = slash + 1;
3613
+ }
3614
+ }
3615
+ export function tryWriteMemoryFileSync(filesystem, path, data, append, mode, signal) {
3616
+ const mem = filesystem;
3617
+ const owner = ownedStores.get(mem);
3618
+ if (!owner ||
3619
+ mem.symlinkCount !== 0 ||
3620
+ mem.capabilities !== owner.capabilities ||
3621
+ !isStockMemoryMethods(mem, writeFileFastMethodNames, false) ||
3622
+ !isCleanAbsolutePath(path) ||
3623
+ path === "/dev" ||
3624
+ path.startsWith("/dev/")) {
3625
+ return false;
3626
+ }
3627
+ signal?.throwIfAborted();
3628
+ mem.writeMemoryFileFast(path, data, append, mode);
3629
+ return true;
3630
+ }
3631
+ export function tryMkdirMemorySync(filesystem, path, recursive, mode, signal, dirPrefixHint) {
3632
+ const mem = filesystem;
3633
+ const owner = ownedStores.get(mem);
3634
+ if (!owner ||
3635
+ mem.symlinkCount !== 0 ||
3636
+ mem.capabilities !== owner.capabilities ||
3637
+ !isStockMemoryMethods(mem, mkdirFastMethodNames, false) ||
3638
+ !isCleanAbsolutePath(path) ||
3639
+ path === "/dev" ||
3640
+ path.startsWith("/dev/")) {
3641
+ return false;
3642
+ }
3643
+ signal?.throwIfAborted();
3644
+ validatePath(path, owner.ledger.limits);
3645
+ const validMode = mem.mode(mode, 0o777, "mkdir", path);
3646
+ if (recursive) {
3647
+ let current = owner.root;
3648
+ let start = 1;
3649
+ while (true) {
3650
+ mem.permission(current, 1, "mkdir", path);
3651
+ const slash = path.indexOf("/", start);
3652
+ const seg = slash === -1 ? slicePathSegment(path, start, path.length) : slicePathSegment(path, start, slash);
3653
+ if (exceedsComponentByteLimit(seg))
3654
+ mem.fail("ENAMETOOLONG", "mkdir", path);
3655
+ let next = current.entries.get(seg);
3656
+ if (!next) {
3657
+ mem.permission(current, 3, "mkdir", path);
3658
+ next = mem.addDirectoryNode(current, seg, validMode, "mkdir", path, Date.now());
3659
+ }
3660
+ else if (next.type !== "directory") {
3661
+ mem.fail(slash === -1 ? "EEXIST" : "ENOTDIR", "mkdir", path);
3662
+ }
3663
+ if (slash === -1) {
3664
+ if (dirPrefixHint !== undefined) {
3665
+ mem._cache.lastFastDirPrefix = dirPrefixHint;
3666
+ mem._cache.lastFastDirNode = next;
3667
+ }
3668
+ break;
3669
+ }
3670
+ current = next;
3671
+ start = slash + 1;
3672
+ }
3673
+ return true;
3674
+ }
3675
+ const location = mem.resolve(path, "mkdir", sharedAllowMissingNoFollowOptions);
3676
+ if (location.node)
3677
+ mem.fail("EEXIST", "mkdir", path);
3678
+ mem.permission(location.parent, 3, "mkdir", path);
3679
+ mem.addDirectoryNode(location.parent, location.name, validMode, "mkdir", path, Date.now());
3680
+ return true;
3681
+ }
3682
+ export function tryRmRfMemorySync(filesystem, path, signal) {
3683
+ const mem = filesystem;
3684
+ const owner = ownedStores.get(mem);
3685
+ if (!owner ||
3686
+ mem.symlinkCount !== 0 ||
3687
+ mem.capabilities !== owner.capabilities ||
3688
+ activeConditionalMutations.has(mem.identityScope) ||
3689
+ !isStockMemoryMethods(mem, rmFastMethodNames, false) ||
3690
+ !isCleanAbsolutePath(path) ||
3691
+ path === "/dev" ||
3692
+ path.startsWith("/dev/")) {
3693
+ return false;
3694
+ }
3695
+ signal?.throwIfAborted();
3696
+ validatePath(path, owner.ledger.limits);
3697
+ let current = owner.root;
3698
+ let start = 1;
3699
+ let targetNode;
3700
+ let targetName = "";
3701
+ while (true) {
3702
+ mem.permission(current, 1, "rm", path);
3703
+ const slash = path.indexOf("/", start);
3704
+ if (slash === -1) {
3705
+ targetName = slicePathSegment(path, start, path.length);
3706
+ if (exceedsComponentByteLimit(targetName))
3707
+ mem.fail("ENAMETOOLONG", "rm", path);
3708
+ targetNode = current.entries.get(targetName);
3709
+ if (!targetNode)
3710
+ return true;
3711
+ break;
3712
+ }
3713
+ const seg = slicePathSegment(path, start, slash);
3714
+ if (exceedsComponentByteLimit(seg))
3715
+ mem.fail("ENAMETOOLONG", "rm", path);
3716
+ const next = current.entries.get(seg);
3717
+ if (!next)
3718
+ return true;
3719
+ if (next.type !== "directory")
3720
+ mem.fail("ENOTDIR", "rm", path);
3721
+ current = next;
3722
+ start = slash + 1;
3723
+ }
3724
+ sharedFastLocation.node = targetNode;
3725
+ sharedFastLocation.parent = current;
3726
+ sharedFastLocation.name = targetName;
3727
+ sharedFastLocation.path = path;
3728
+ try {
3729
+ mem.removeLocation(sharedFastLocation, path, "rm", true, Date.now());
3730
+ }
3731
+ finally {
3732
+ sharedFastLocation.node = undefined;
3733
+ sharedFastLocation.parent = DUMMY_POOL_DIR_NODE;
3734
+ sharedFastLocation.name = "";
3735
+ sharedFastLocation.path = "";
3736
+ }
3737
+ return true;
3738
+ }
3739
+ export function tryWriteMemoryFileInDirSync(filesystem, dirPrefix, name, data, append, mode, signal) {
3740
+ const mem = filesystem;
3741
+ const owner = ownedStores.get(mem);
3742
+ if (!owner ||
3743
+ mem.symlinkCount !== 0 ||
3744
+ mem.capabilities !== owner.capabilities ||
3745
+ !isStockMemoryMethods(mem, writeFileFastMethodNames, false) ||
3746
+ name.length === 0 ||
3747
+ name === "." ||
3748
+ name === ".." ||
3749
+ name.indexOf("/") !== -1 ||
3750
+ name.indexOf("\0") !== -1 ||
3751
+ dirPrefix.length + name.length > 65536) {
3752
+ return false;
3753
+ }
3754
+ signal?.throwIfAborted();
3755
+ mem.writeMemoryFileInDirFast(dirPrefix, name, data, append, mode);
3756
+ return true;
3757
+ }
3758
+ const _memHooks = (globalThis.__safeBashMemHooks ??= { protos: new Set(), byProto: new Map() });
3759
+ _memHooks.protos.add(MemoryFileSystem.prototype);
3760
+ _memHooks.byProto.set(MemoryFileSystem.prototype, {
3761
+ tryGetMemoryDirectoryEntryNamesSync,
3762
+ tryReadMemoryFileViewSync,
3763
+ tryResolveMemoryDevicePath,
3764
+ tryOpenMemoryRedirectHandleSync,
3765
+ tryWriteMemoryFileSync,
3766
+ tryMkdirMemorySync,
3767
+ tryRmRfMemorySync,
3768
+ tryWriteMemoryFileInDirSync,
3769
+ });
3770
+ _memHooks.isCleanAbsolutePath = isCleanAbsolutePath;
3771
+ _memHooks.bindConditionalMutation = bindConditionalMutation;