@mysten-incubation/devstack 0.0.0

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 (833) hide show
  1. package/LICENSE +189 -0
  2. package/README.md +94 -0
  3. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  4. package/dist/api/define-capabilities.d.mts +25 -0
  5. package/dist/api/define-capabilities.mjs +19 -0
  6. package/dist/api/define-capabilities.mjs.map +1 -0
  7. package/dist/api/define-devstack-with.d.mts +41 -0
  8. package/dist/api/define-devstack-with.mjs +24 -0
  9. package/dist/api/define-devstack-with.mjs.map +1 -0
  10. package/dist/api/define-devstack.d.mts +62 -0
  11. package/dist/api/define-devstack.mjs +108 -0
  12. package/dist/api/define-devstack.mjs.map +1 -0
  13. package/dist/api/define-plugin.d.mts +1 -0
  14. package/dist/api/inference-network.mjs +122 -0
  15. package/dist/api/inference-network.mjs.map +1 -0
  16. package/dist/api/mode-narrowed-factory.d.mts +26 -0
  17. package/dist/api/mode-narrowed-factory.mjs +8 -0
  18. package/dist/api/mode-narrowed-factory.mjs.map +1 -0
  19. package/dist/api/plugin-errors.mjs +10 -0
  20. package/dist/api/plugin-errors.mjs.map +1 -0
  21. package/dist/api/run-stack.d.mts +82 -0
  22. package/dist/api/run-stack.mjs +127 -0
  23. package/dist/api/run-stack.mjs.map +1 -0
  24. package/dist/build-integrations/playwright/config.d.mts +92 -0
  25. package/dist/build-integrations/playwright/config.mjs +71 -0
  26. package/dist/build-integrations/playwright/config.mjs.map +1 -0
  27. package/dist/build-integrations/playwright/errors.d.mts +82 -0
  28. package/dist/build-integrations/playwright/errors.mjs +43 -0
  29. package/dist/build-integrations/playwright/errors.mjs.map +1 -0
  30. package/dist/build-integrations/playwright/global-setup.d.mts +64 -0
  31. package/dist/build-integrations/playwright/global-setup.mjs +44 -0
  32. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -0
  33. package/dist/build-integrations/playwright/index.d.mts +6 -0
  34. package/dist/build-integrations/playwright/index.mjs +6 -0
  35. package/dist/build-integrations/playwright/stack-context.d.mts +95 -0
  36. package/dist/build-integrations/playwright/stack-context.mjs +277 -0
  37. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -0
  38. package/dist/build-integrations/playwright/wallet-context.d.mts +87 -0
  39. package/dist/build-integrations/playwright/wallet-context.mjs +148 -0
  40. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -0
  41. package/dist/build-integrations/runtime/cold-start-url.d.mts +67 -0
  42. package/dist/build-integrations/runtime/cold-start-url.mjs +56 -0
  43. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -0
  44. package/dist/build-integrations/runtime/dapp-kit-slot.mjs +10 -0
  45. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -0
  46. package/dist/build-integrations/runtime/discover.d.mts +78 -0
  47. package/dist/build-integrations/runtime/discover.mjs +124 -0
  48. package/dist/build-integrations/runtime/discover.mjs.map +1 -0
  49. package/dist/build-integrations/runtime/endpoint-registry.d.mts +26 -0
  50. package/dist/build-integrations/runtime/endpoint-registry.mjs +41 -0
  51. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -0
  52. package/dist/build-integrations/runtime/errors.d.mts +64 -0
  53. package/dist/build-integrations/runtime/errors.mjs +51 -0
  54. package/dist/build-integrations/runtime/errors.mjs.map +1 -0
  55. package/dist/build-integrations/runtime/index.d.mts +7 -0
  56. package/dist/build-integrations/runtime/index.mjs +6 -0
  57. package/dist/build-integrations/runtime/read-stack-context.d.mts +38 -0
  58. package/dist/build-integrations/runtime/read-stack-context.mjs +130 -0
  59. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -0
  60. package/dist/build-integrations/runtime/stack-context.d.mts +53 -0
  61. package/dist/build-integrations/vitest/config.d.mts +62 -0
  62. package/dist/build-integrations/vitest/config.mjs +80 -0
  63. package/dist/build-integrations/vitest/config.mjs.map +1 -0
  64. package/dist/build-integrations/vitest/env.d.mts +48 -0
  65. package/dist/build-integrations/vitest/env.mjs +50 -0
  66. package/dist/build-integrations/vitest/env.mjs.map +1 -0
  67. package/dist/build-integrations/vitest/errors.d.mts +44 -0
  68. package/dist/build-integrations/vitest/errors.mjs +18 -0
  69. package/dist/build-integrations/vitest/errors.mjs.map +1 -0
  70. package/dist/build-integrations/vitest/index.d.mts +6 -0
  71. package/dist/build-integrations/vitest/index.mjs +6 -0
  72. package/dist/build-integrations/vitest/setup.d.mts +53 -0
  73. package/dist/build-integrations/vitest/setup.mjs +56 -0
  74. package/dist/build-integrations/vitest/setup.mjs.map +1 -0
  75. package/dist/build-integrations/vitest/stack-context.d.mts +58 -0
  76. package/dist/build-integrations/vitest/stack-context.mjs +67 -0
  77. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -0
  78. package/dist/cli/main.d.mts +5 -0
  79. package/dist/cli/main.mjs +586 -0
  80. package/dist/cli/main.mjs.map +1 -0
  81. package/dist/cli/prune-direct.mjs +216 -0
  82. package/dist/cli/prune-direct.mjs.map +1 -0
  83. package/dist/cli/snapshot-reader.mjs +73 -0
  84. package/dist/cli/snapshot-reader.mjs.map +1 -0
  85. package/dist/cli/up-lifecycle.mjs +28 -0
  86. package/dist/cli/up-lifecycle.mjs.map +1 -0
  87. package/dist/contracts/capability-decl.d.mts +42 -0
  88. package/dist/contracts/chain-probe.d.mts +26 -0
  89. package/dist/contracts/chain-probe.mjs +8 -0
  90. package/dist/contracts/chain-probe.mjs.map +1 -0
  91. package/dist/contracts/codegenable.d.mts +43 -0
  92. package/dist/contracts/container-runtime.d.mts +245 -0
  93. package/dist/contracts/liveness-classifier.d.mts +19 -0
  94. package/dist/contracts/network-resolver.d.mts +15 -0
  95. package/dist/contracts/network-resolver.mjs +7 -0
  96. package/dist/contracts/network-resolver.mjs.map +1 -0
  97. package/dist/contracts/projection.d.mts +15 -0
  98. package/dist/contracts/routable.d.mts +53 -0
  99. package/dist/contracts/snapshotable.d.mts +39 -0
  100. package/dist/contracts/strategy-contributor.d.mts +26 -0
  101. package/dist/index.d.mts +89 -0
  102. package/dist/index.mjs +37 -0
  103. package/dist/orchestrators/codegen/bindings.d.mts +2 -0
  104. package/dist/orchestrators/codegen/bindings.mjs +340 -0
  105. package/dist/orchestrators/codegen/bindings.mjs.map +1 -0
  106. package/dist/orchestrators/codegen/emit.mjs +56 -0
  107. package/dist/orchestrators/codegen/emit.mjs.map +1 -0
  108. package/dist/orchestrators/codegen/errors.d.mts +1 -0
  109. package/dist/orchestrators/codegen/errors.mjs +66 -0
  110. package/dist/orchestrators/codegen/errors.mjs.map +1 -0
  111. package/dist/orchestrators/codegen/extras.mjs +16 -0
  112. package/dist/orchestrators/codegen/extras.mjs.map +1 -0
  113. package/dist/orchestrators/codegen/format.mjs +109 -0
  114. package/dist/orchestrators/codegen/format.mjs.map +1 -0
  115. package/dist/orchestrators/codegen/gitignore.mjs +67 -0
  116. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -0
  117. package/dist/orchestrators/codegen/paths.d.mts +1 -0
  118. package/dist/orchestrators/codegen/paths.mjs +33 -0
  119. package/dist/orchestrators/codegen/paths.mjs.map +1 -0
  120. package/dist/orchestrators/codegen/permissions.mjs +6 -0
  121. package/dist/orchestrators/codegen/permissions.mjs.map +1 -0
  122. package/dist/orchestrators/codegen/service.d.mts +1 -0
  123. package/dist/orchestrators/codegen/service.mjs +276 -0
  124. package/dist/orchestrators/codegen/service.mjs.map +1 -0
  125. package/dist/orchestrators/router/cleanup.mjs +58 -0
  126. package/dist/orchestrators/router/cleanup.mjs.map +1 -0
  127. package/dist/orchestrators/router/cors.mjs +31 -0
  128. package/dist/orchestrators/router/cors.mjs.map +1 -0
  129. package/dist/orchestrators/router/entrypoints.d.mts +1 -0
  130. package/dist/orchestrators/router/entrypoints.mjs +80 -0
  131. package/dist/orchestrators/router/entrypoints.mjs.map +1 -0
  132. package/dist/orchestrators/router/errors.d.mts +1 -0
  133. package/dist/orchestrators/router/errors.mjs +103 -0
  134. package/dist/orchestrators/router/errors.mjs.map +1 -0
  135. package/dist/orchestrators/router/file-provider.d.mts +1 -0
  136. package/dist/orchestrators/router/file-provider.mjs +320 -0
  137. package/dist/orchestrators/router/file-provider.mjs.map +1 -0
  138. package/dist/orchestrators/router/hostname.d.mts +1 -0
  139. package/dist/orchestrators/router/hostname.mjs +107 -0
  140. package/dist/orchestrators/router/hostname.mjs.map +1 -0
  141. package/dist/orchestrators/router/index.d.mts +1 -0
  142. package/dist/orchestrators/router/profile.d.mts +1 -0
  143. package/dist/orchestrators/router/profile.mjs +109 -0
  144. package/dist/orchestrators/router/profile.mjs.map +1 -0
  145. package/dist/orchestrators/router/service.d.mts +3 -0
  146. package/dist/orchestrators/router/service.mjs +421 -0
  147. package/dist/orchestrators/router/service.mjs.map +1 -0
  148. package/dist/orchestrators/router/traefik-container.d.mts +1 -0
  149. package/dist/orchestrators/router/traefik-container.mjs +229 -0
  150. package/dist/orchestrators/router/traefik-container.mjs.map +1 -0
  151. package/dist/orchestrators/runtime-composition.d.mts +10 -0
  152. package/dist/orchestrators/runtime-composition.mjs +168 -0
  153. package/dist/orchestrators/runtime-composition.mjs.map +1 -0
  154. package/dist/orchestrators/snapshot/capture.d.mts +1 -0
  155. package/dist/orchestrators/snapshot/capture.mjs +350 -0
  156. package/dist/orchestrators/snapshot/capture.mjs.map +1 -0
  157. package/dist/orchestrators/snapshot/descriptor.d.mts +1 -0
  158. package/dist/orchestrators/snapshot/descriptor.mjs +109 -0
  159. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -0
  160. package/dist/orchestrators/snapshot/identity-guard.d.mts +1 -0
  161. package/dist/orchestrators/snapshot/identity-guard.mjs +132 -0
  162. package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -0
  163. package/dist/orchestrators/snapshot/image-bundle-tags.mjs +207 -0
  164. package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -0
  165. package/dist/orchestrators/snapshot/index.d.mts +1 -0
  166. package/dist/orchestrators/snapshot/integrity.d.mts +1 -0
  167. package/dist/orchestrators/snapshot/integrity.mjs +74 -0
  168. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -0
  169. package/dist/orchestrators/snapshot/prune.d.mts +1 -0
  170. package/dist/orchestrators/snapshot/prune.mjs +110 -0
  171. package/dist/orchestrators/snapshot/prune.mjs.map +1 -0
  172. package/dist/orchestrators/snapshot/restore.d.mts +1 -0
  173. package/dist/orchestrators/snapshot/restore.mjs +404 -0
  174. package/dist/orchestrators/snapshot/restore.mjs.map +1 -0
  175. package/dist/orchestrators/snapshot/service.d.mts +1 -0
  176. package/dist/orchestrators/snapshot/service.mjs +296 -0
  177. package/dist/orchestrators/snapshot/service.mjs.map +1 -0
  178. package/dist/orchestrators/snapshot/state-document.mjs +18 -0
  179. package/dist/orchestrators/snapshot/state-document.mjs.map +1 -0
  180. package/dist/orchestrators/snapshot/wipe.d.mts +1 -0
  181. package/dist/orchestrators/snapshot/wipe.mjs +59 -0
  182. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -0
  183. package/dist/plugins/account/codegen.d.mts +12 -0
  184. package/dist/plugins/account/codegen.mjs +22 -0
  185. package/dist/plugins/account/codegen.mjs.map +1 -0
  186. package/dist/plugins/account/errors.d.mts +44 -0
  187. package/dist/plugins/account/errors.mjs +16 -0
  188. package/dist/plugins/account/errors.mjs.map +1 -0
  189. package/dist/plugins/account/funding.d.mts +94 -0
  190. package/dist/plugins/account/funding.mjs +199 -0
  191. package/dist/plugins/account/funding.mjs.map +1 -0
  192. package/dist/plugins/account/index.d.mts +54 -0
  193. package/dist/plugins/account/index.mjs +151 -0
  194. package/dist/plugins/account/index.mjs.map +1 -0
  195. package/dist/plugins/account/keypair.d.mts +32 -0
  196. package/dist/plugins/account/keypair.mjs +99 -0
  197. package/dist/plugins/account/keypair.mjs.map +1 -0
  198. package/dist/plugins/account/lease.mjs +21 -0
  199. package/dist/plugins/account/lease.mjs.map +1 -0
  200. package/dist/plugins/account/registry.d.mts +33 -0
  201. package/dist/plugins/account/registry.mjs +36 -0
  202. package/dist/plugins/account/registry.mjs.map +1 -0
  203. package/dist/plugins/account/service.d.mts +104 -0
  204. package/dist/plugins/account/service.mjs +405 -0
  205. package/dist/plugins/account/service.mjs.map +1 -0
  206. package/dist/plugins/account/snapshot.mjs +33 -0
  207. package/dist/plugins/account/snapshot.mjs.map +1 -0
  208. package/dist/plugins/account/variants/env.mjs +24 -0
  209. package/dist/plugins/account/variants/env.mjs.map +1 -0
  210. package/dist/plugins/account/variants/ephemeral.mjs +72 -0
  211. package/dist/plugins/account/variants/ephemeral.mjs.map +1 -0
  212. package/dist/plugins/account/variants/impersonate.d.mts +16 -0
  213. package/dist/plugins/account/variants/impersonate.mjs +48 -0
  214. package/dist/plugins/account/variants/impersonate.mjs.map +1 -0
  215. package/dist/plugins/account/variants/inline.mjs +13 -0
  216. package/dist/plugins/account/variants/inline.mjs.map +1 -0
  217. package/dist/plugins/account/variants/keystore.mjs +93 -0
  218. package/dist/plugins/account/variants/keystore.mjs.map +1 -0
  219. package/dist/plugins/account/variants/signer.mjs +31 -0
  220. package/dist/plugins/account/variants/signer.mjs.map +1 -0
  221. package/dist/plugins/action/build-context.d.mts +41 -0
  222. package/dist/plugins/action/discriminator.d.mts +20 -0
  223. package/dist/plugins/action/discriminator.mjs +13 -0
  224. package/dist/plugins/action/discriminator.mjs.map +1 -0
  225. package/dist/plugins/action/errors.d.mts +31 -0
  226. package/dist/plugins/action/errors.mjs +13 -0
  227. package/dist/plugins/action/errors.mjs.map +1 -0
  228. package/dist/plugins/action/execute.d.mts +2 -0
  229. package/dist/plugins/action/execute.mjs +145 -0
  230. package/dist/plugins/action/execute.mjs.map +1 -0
  231. package/dist/plugins/action/index.d.mts +56 -0
  232. package/dist/plugins/action/index.mjs +82 -0
  233. package/dist/plugins/action/index.mjs.map +1 -0
  234. package/dist/plugins/action/service.d.mts +26 -0
  235. package/dist/plugins/action/service.mjs +84 -0
  236. package/dist/plugins/action/service.mjs.map +1 -0
  237. package/dist/plugins/coin/address-resolution.d.mts +34 -0
  238. package/dist/plugins/coin/address-resolution.mjs +80 -0
  239. package/dist/plugins/coin/address-resolution.mjs.map +1 -0
  240. package/dist/plugins/coin/codegen.d.mts +16 -0
  241. package/dist/plugins/coin/codegen.mjs +21 -0
  242. package/dist/plugins/coin/codegen.mjs.map +1 -0
  243. package/dist/plugins/coin/discovery.d.mts +26 -0
  244. package/dist/plugins/coin/discovery.mjs +112 -0
  245. package/dist/plugins/coin/discovery.mjs.map +1 -0
  246. package/dist/plugins/coin/errors.d.mts +48 -0
  247. package/dist/plugins/coin/errors.mjs +13 -0
  248. package/dist/plugins/coin/errors.mjs.map +1 -0
  249. package/dist/plugins/coin/index.d.mts +95 -0
  250. package/dist/plugins/coin/index.mjs +172 -0
  251. package/dist/plugins/coin/index.mjs.map +1 -0
  252. package/dist/plugins/coin/metadata.d.mts +15 -0
  253. package/dist/plugins/coin/metadata.mjs +99 -0
  254. package/dist/plugins/coin/metadata.mjs.map +1 -0
  255. package/dist/plugins/coin/mint.d.mts +34 -0
  256. package/dist/plugins/coin/mint.mjs +164 -0
  257. package/dist/plugins/coin/mint.mjs.map +1 -0
  258. package/dist/plugins/coin/registry.d.mts +1 -0
  259. package/dist/plugins/coin/registry.mjs +37 -0
  260. package/dist/plugins/coin/registry.mjs.map +1 -0
  261. package/dist/plugins/coin/service.d.mts +47 -0
  262. package/dist/plugins/coin/service.mjs +51 -0
  263. package/dist/plugins/coin/service.mjs.map +1 -0
  264. package/dist/plugins/coin/snapshot.mjs +19 -0
  265. package/dist/plugins/coin/snapshot.mjs.map +1 -0
  266. package/dist/plugins/coin/type-strings.mjs +49 -0
  267. package/dist/plugins/coin/type-strings.mjs.map +1 -0
  268. package/dist/plugins/deepbook/codegen.d.mts +39 -0
  269. package/dist/plugins/deepbook/codegen.mjs +15 -0
  270. package/dist/plugins/deepbook/codegen.mjs.map +1 -0
  271. package/dist/plugins/deepbook/deploy.mjs +437 -0
  272. package/dist/plugins/deepbook/deploy.mjs.map +1 -0
  273. package/dist/plugins/deepbook/errors.d.mts +29 -0
  274. package/dist/plugins/deepbook/errors.mjs +26 -0
  275. package/dist/plugins/deepbook/errors.mjs.map +1 -0
  276. package/dist/plugins/deepbook/faucet-strategy.d.mts +8 -0
  277. package/dist/plugins/deepbook/faucet-strategy.mjs +81 -0
  278. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -0
  279. package/dist/plugins/deepbook/index.d.mts +171 -0
  280. package/dist/plugins/deepbook/index.mjs +359 -0
  281. package/dist/plugins/deepbook/index.mjs.map +1 -0
  282. package/dist/plugins/deepbook/plugin-key.mjs +7 -0
  283. package/dist/plugins/deepbook/plugin-key.mjs.map +1 -0
  284. package/dist/plugins/deepbook/pyth/index.mjs +226 -0
  285. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -0
  286. package/dist/plugins/deepbook/routable.mjs +21 -0
  287. package/dist/plugins/deepbook/routable.mjs.map +1 -0
  288. package/dist/plugins/deepbook/snapshot.mjs +49 -0
  289. package/dist/plugins/deepbook/snapshot.mjs.map +1 -0
  290. package/dist/plugins/deepbook/types.d.mts +125 -0
  291. package/dist/plugins/deepbook/types.mjs +12 -0
  292. package/dist/plugins/deepbook/types.mjs.map +1 -0
  293. package/dist/plugins/faucet/dispatcher.d.mts +9 -0
  294. package/dist/plugins/faucet/dispatcher.mjs +13 -0
  295. package/dist/plugins/faucet/dispatcher.mjs.map +1 -0
  296. package/dist/plugins/faucet/errors.d.mts +86 -0
  297. package/dist/plugins/faucet/errors.mjs +19 -0
  298. package/dist/plugins/faucet/errors.mjs.map +1 -0
  299. package/dist/plugins/faucet/http.mjs +127 -0
  300. package/dist/plugins/faucet/http.mjs.map +1 -0
  301. package/dist/plugins/faucet/index.d.mts +43 -0
  302. package/dist/plugins/faucet/index.mjs +42 -0
  303. package/dist/plugins/faucet/index.mjs.map +1 -0
  304. package/dist/plugins/faucet/service.d.mts +20 -0
  305. package/dist/plugins/faucet/strategies/sui-local.d.mts +23 -0
  306. package/dist/plugins/faucet/strategies/sui-local.mjs +29 -0
  307. package/dist/plugins/faucet/strategies/sui-local.mjs.map +1 -0
  308. package/dist/plugins/host-service/errors.d.mts +27 -0
  309. package/dist/plugins/host-service/errors.mjs +14 -0
  310. package/dist/plugins/host-service/errors.mjs.map +1 -0
  311. package/dist/plugins/host-service/index.d.mts +10 -0
  312. package/dist/plugins/host-service/index.mjs +48 -0
  313. package/dist/plugins/host-service/index.mjs.map +1 -0
  314. package/dist/plugins/host-service/routable.mjs +24 -0
  315. package/dist/plugins/host-service/routable.mjs.map +1 -0
  316. package/dist/plugins/host-service/service.d.mts +49 -0
  317. package/dist/plugins/host-service/service.mjs +375 -0
  318. package/dist/plugins/host-service/service.mjs.map +1 -0
  319. package/dist/plugins/package/build.d.mts +1 -0
  320. package/dist/plugins/package/build.mjs +24 -0
  321. package/dist/plugins/package/build.mjs.map +1 -0
  322. package/dist/plugins/package/codegen.d.mts +19 -0
  323. package/dist/plugins/package/codegen.mjs +41 -0
  324. package/dist/plugins/package/codegen.mjs.map +1 -0
  325. package/dist/plugins/package/dep-resolution.mjs +10 -0
  326. package/dist/plugins/package/dep-resolution.mjs.map +1 -0
  327. package/dist/plugins/package/errors.d.mts +34 -0
  328. package/dist/plugins/package/errors.mjs +13 -0
  329. package/dist/plugins/package/errors.mjs.map +1 -0
  330. package/dist/plugins/package/index.d.mts +109 -0
  331. package/dist/plugins/package/index.mjs +207 -0
  332. package/dist/plugins/package/index.mjs.map +1 -0
  333. package/dist/plugins/package/mode-known.mjs +41 -0
  334. package/dist/plugins/package/mode-known.mjs.map +1 -0
  335. package/dist/plugins/package/mode-local.d.mts +1 -0
  336. package/dist/plugins/package/mode-local.mjs +183 -0
  337. package/dist/plugins/package/mode-local.mjs.map +1 -0
  338. package/dist/plugins/package/publish-executor.mjs +202 -0
  339. package/dist/plugins/package/publish-executor.mjs.map +1 -0
  340. package/dist/plugins/package/publish-output.d.mts +28 -0
  341. package/dist/plugins/package/publish-output.mjs +45 -0
  342. package/dist/plugins/package/publish-output.mjs.map +1 -0
  343. package/dist/plugins/package/registry.d.mts +25 -0
  344. package/dist/plugins/package/registry.mjs +30 -0
  345. package/dist/plugins/package/registry.mjs.map +1 -0
  346. package/dist/plugins/package/service.mjs +20 -0
  347. package/dist/plugins/package/service.mjs.map +1 -0
  348. package/dist/plugins/package/snapshot.mjs +25 -0
  349. package/dist/plugins/package/snapshot.mjs.map +1 -0
  350. package/dist/plugins/postgres/codegen.mjs +42 -0
  351. package/dist/plugins/postgres/codegen.mjs.map +1 -0
  352. package/dist/plugins/postgres/connection.d.mts +33 -0
  353. package/dist/plugins/postgres/connection.mjs +19 -0
  354. package/dist/plugins/postgres/connection.mjs.map +1 -0
  355. package/dist/plugins/postgres/db-ensure.mjs +100 -0
  356. package/dist/plugins/postgres/db-ensure.mjs.map +1 -0
  357. package/dist/plugins/postgres/errors.d.mts +55 -0
  358. package/dist/plugins/postgres/errors.mjs +29 -0
  359. package/dist/plugins/postgres/errors.mjs.map +1 -0
  360. package/dist/plugins/postgres/index.d.mts +37 -0
  361. package/dist/plugins/postgres/index.mjs +75 -0
  362. package/dist/plugins/postgres/index.mjs.map +1 -0
  363. package/dist/plugins/postgres/routable.mjs +33 -0
  364. package/dist/plugins/postgres/routable.mjs.map +1 -0
  365. package/dist/plugins/postgres/service.d.mts +50 -0
  366. package/dist/plugins/postgres/service.mjs +145 -0
  367. package/dist/plugins/postgres/service.mjs.map +1 -0
  368. package/dist/plugins/postgres/snapshot.d.mts +1 -0
  369. package/dist/plugins/postgres/snapshot.mjs +32 -0
  370. package/dist/plugins/postgres/snapshot.mjs.map +1 -0
  371. package/dist/plugins/router-entrypoints.mjs +21 -0
  372. package/dist/plugins/router-entrypoints.mjs.map +1 -0
  373. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +59 -0
  374. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -0
  375. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +132 -0
  376. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -0
  377. package/dist/plugins/seal/codegen.d.mts +19 -0
  378. package/dist/plugins/seal/codegen.mjs +16 -0
  379. package/dist/plugins/seal/codegen.mjs.map +1 -0
  380. package/dist/plugins/seal/config-render.mjs +82 -0
  381. package/dist/plugins/seal/config-render.mjs.map +1 -0
  382. package/dist/plugins/seal/deploy.mjs +198 -0
  383. package/dist/plugins/seal/deploy.mjs.map +1 -0
  384. package/dist/plugins/seal/errors.d.mts +52 -0
  385. package/dist/plugins/seal/errors.mjs +19 -0
  386. package/dist/plugins/seal/errors.mjs.map +1 -0
  387. package/dist/plugins/seal/index.d.mts +161 -0
  388. package/dist/plugins/seal/index.mjs +235 -0
  389. package/dist/plugins/seal/index.mjs.map +1 -0
  390. package/dist/plugins/seal/key-manager.d.mts +22 -0
  391. package/dist/plugins/seal/key-manager.mjs +22 -0
  392. package/dist/plugins/seal/key-manager.mjs.map +1 -0
  393. package/dist/plugins/seal/key-server.mjs +175 -0
  394. package/dist/plugins/seal/key-server.mjs.map +1 -0
  395. package/dist/plugins/seal/keygen.mjs +96 -0
  396. package/dist/plugins/seal/keygen.mjs.map +1 -0
  397. package/dist/plugins/seal/mode/fork-known.d.mts +8 -0
  398. package/dist/plugins/seal/mode/fork-known.mjs +23 -0
  399. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -0
  400. package/dist/plugins/seal/mode/live.d.mts +18 -0
  401. package/dist/plugins/seal/mode/live.mjs +64 -0
  402. package/dist/plugins/seal/mode/live.mjs.map +1 -0
  403. package/dist/plugins/seal/mode/local-keygen.mjs +180 -0
  404. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -0
  405. package/dist/plugins/seal/plugin-key.mjs +7 -0
  406. package/dist/plugins/seal/plugin-key.mjs.map +1 -0
  407. package/dist/plugins/seal/registry-publish.d.mts +43 -0
  408. package/dist/plugins/seal/registry-publish.mjs +9 -0
  409. package/dist/plugins/seal/registry-publish.mjs.map +1 -0
  410. package/dist/plugins/seal/routable.mjs +57 -0
  411. package/dist/plugins/seal/routable.mjs.map +1 -0
  412. package/dist/plugins/seal/service.mjs +17 -0
  413. package/dist/plugins/seal/service.mjs.map +1 -0
  414. package/dist/plugins/seal/snapshot.mjs +51 -0
  415. package/dist/plugins/seal/snapshot.mjs.map +1 -0
  416. package/dist/plugins/sui/auto-tick.mjs +45 -0
  417. package/dist/plugins/sui/auto-tick.mjs.map +1 -0
  418. package/dist/plugins/sui/chain-build-container.d.mts +1 -0
  419. package/dist/plugins/sui/chain-probe.d.mts +85 -0
  420. package/dist/plugins/sui/chain-probe.mjs +104 -0
  421. package/dist/plugins/sui/chain-probe.mjs.map +1 -0
  422. package/dist/plugins/sui/codegen.d.mts +14 -0
  423. package/dist/plugins/sui/codegen.mjs +26 -0
  424. package/dist/plugins/sui/codegen.mjs.map +1 -0
  425. package/dist/plugins/sui/errors.d.mts +74 -0
  426. package/dist/plugins/sui/errors.mjs +28 -0
  427. package/dist/plugins/sui/errors.mjs.map +1 -0
  428. package/dist/plugins/sui/fork-orchestration.mjs +24 -0
  429. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -0
  430. package/dist/plugins/sui/fork-transaction.mjs +96 -0
  431. package/dist/plugins/sui/fork-transaction.mjs.map +1 -0
  432. package/dist/plugins/sui/index.d.mts +318 -0
  433. package/dist/plugins/sui/index.mjs +182 -0
  434. package/dist/plugins/sui/index.mjs.map +1 -0
  435. package/dist/plugins/sui/mode/external.mjs +60 -0
  436. package/dist/plugins/sui/mode/external.mjs.map +1 -0
  437. package/dist/plugins/sui/mode/fork.mjs +283 -0
  438. package/dist/plugins/sui/mode/fork.mjs.map +1 -0
  439. package/dist/plugins/sui/mode/live.mjs +103 -0
  440. package/dist/plugins/sui/mode/live.mjs.map +1 -0
  441. package/dist/plugins/sui/mode/local.mjs +293 -0
  442. package/dist/plugins/sui/mode/local.mjs.map +1 -0
  443. package/dist/plugins/sui/mode/shared-boot.mjs +254 -0
  444. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -0
  445. package/dist/plugins/sui/mode/shared.d.mts +103 -0
  446. package/dist/plugins/sui/mode/shared.mjs +12 -0
  447. package/dist/plugins/sui/mode/shared.mjs.map +1 -0
  448. package/dist/plugins/sui/mode/spec.d.mts +94 -0
  449. package/dist/plugins/sui/network-resolver.d.mts +23 -0
  450. package/dist/plugins/sui/routable.mjs +88 -0
  451. package/dist/plugins/sui/routable.mjs.map +1 -0
  452. package/dist/plugins/sui/seed-objects.d.mts +18 -0
  453. package/dist/plugins/sui/seed-objects.mjs +25 -0
  454. package/dist/plugins/sui/seed-objects.mjs.map +1 -0
  455. package/dist/plugins/sui/service.mjs +38 -0
  456. package/dist/plugins/sui/service.mjs.map +1 -0
  457. package/dist/plugins/sui/snapshot.mjs +53 -0
  458. package/dist/plugins/sui/snapshot.mjs.map +1 -0
  459. package/dist/plugins/wallet/codegen.d.mts +33 -0
  460. package/dist/plugins/wallet/codegen.mjs +34 -0
  461. package/dist/plugins/wallet/codegen.mjs.map +1 -0
  462. package/dist/plugins/wallet/errors.d.mts +66 -0
  463. package/dist/plugins/wallet/errors.mjs +16 -0
  464. package/dist/plugins/wallet/errors.mjs.map +1 -0
  465. package/dist/plugins/wallet/index.d.mts +63 -0
  466. package/dist/plugins/wallet/index.mjs +126 -0
  467. package/dist/plugins/wallet/index.mjs.map +1 -0
  468. package/dist/plugins/wallet/origin-policy.d.mts +1 -0
  469. package/dist/plugins/wallet/origin-policy.mjs +65 -0
  470. package/dist/plugins/wallet/origin-policy.mjs.map +1 -0
  471. package/dist/plugins/wallet/pairing.d.mts +11 -0
  472. package/dist/plugins/wallet/pairing.mjs +125 -0
  473. package/dist/plugins/wallet/pairing.mjs.map +1 -0
  474. package/dist/plugins/wallet/protocol.d.mts +1 -0
  475. package/dist/plugins/wallet/protocol.mjs +96 -0
  476. package/dist/plugins/wallet/protocol.mjs.map +1 -0
  477. package/dist/plugins/wallet/routable.mjs +32 -0
  478. package/dist/plugins/wallet/routable.mjs.map +1 -0
  479. package/dist/plugins/wallet/server.d.mts +12 -0
  480. package/dist/plugins/wallet/server.mjs +317 -0
  481. package/dist/plugins/wallet/server.mjs.map +1 -0
  482. package/dist/plugins/wallet/service.d.mts +68 -0
  483. package/dist/plugins/wallet/service.mjs +97 -0
  484. package/dist/plugins/wallet/service.mjs.map +1 -0
  485. package/dist/plugins/wallet/snapshot.d.mts +1 -0
  486. package/dist/plugins/wallet/snapshot.mjs +14 -0
  487. package/dist/plugins/wallet/snapshot.mjs.map +1 -0
  488. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +42 -0
  489. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -0
  490. package/dist/plugins/walrus/codegen.d.mts +38 -0
  491. package/dist/plugins/walrus/codegen.mjs +34 -0
  492. package/dist/plugins/walrus/codegen.mjs.map +1 -0
  493. package/dist/plugins/walrus/deploy-paths.mjs +14 -0
  494. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -0
  495. package/dist/plugins/walrus/deploy.d.mts +1 -0
  496. package/dist/plugins/walrus/deploy.mjs +224 -0
  497. package/dist/plugins/walrus/deploy.mjs.map +1 -0
  498. package/dist/plugins/walrus/errors.d.mts +38 -0
  499. package/dist/plugins/walrus/errors.mjs +26 -0
  500. package/dist/plugins/walrus/errors.mjs.map +1 -0
  501. package/dist/plugins/walrus/faucet-strategy.d.mts +12 -0
  502. package/dist/plugins/walrus/faucet-strategy.mjs +62 -0
  503. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -0
  504. package/dist/plugins/walrus/index.d.mts +177 -0
  505. package/dist/plugins/walrus/index.mjs +284 -0
  506. package/dist/plugins/walrus/index.mjs.map +1 -0
  507. package/dist/plugins/walrus/mode/known-deploy.d.mts +25 -0
  508. package/dist/plugins/walrus/mode/known-deploy.mjs +71 -0
  509. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -0
  510. package/dist/plugins/walrus/mode/local-cluster.d.mts +34 -0
  511. package/dist/plugins/walrus/mode/local-cluster.mjs +153 -0
  512. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -0
  513. package/dist/plugins/walrus/plugin-key.mjs +7 -0
  514. package/dist/plugins/walrus/plugin-key.mjs.map +1 -0
  515. package/dist/plugins/walrus/registry-publish.d.mts +24 -0
  516. package/dist/plugins/walrus/registry-publish.mjs +7 -0
  517. package/dist/plugins/walrus/registry-publish.mjs.map +1 -0
  518. package/dist/plugins/walrus/routable.mjs +99 -0
  519. package/dist/plugins/walrus/routable.mjs.map +1 -0
  520. package/dist/plugins/walrus/service.mjs +20 -0
  521. package/dist/plugins/walrus/service.mjs.map +1 -0
  522. package/dist/plugins/walrus/snapshot.mjs +53 -0
  523. package/dist/plugins/walrus/snapshot.mjs.map +1 -0
  524. package/dist/plugins/walrus/storage-nodes.d.mts +15 -0
  525. package/dist/plugins/walrus/storage-nodes.mjs +154 -0
  526. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -0
  527. package/dist/plugins/walrus/wal-swap.d.mts +2 -0
  528. package/dist/plugins/walrus/wal-swap.mjs +58 -0
  529. package/dist/plugins/walrus/wal-swap.mjs.map +1 -0
  530. package/dist/primitives/artifact-publisher.d.mts +12 -0
  531. package/dist/primitives/cache.d.mts +1 -0
  532. package/dist/runtime/built-in-plugin-layers.mjs +49 -0
  533. package/dist/runtime/built-in-plugin-layers.mjs.map +1 -0
  534. package/dist/runtime/docker/client.d.mts +2 -0
  535. package/dist/runtime/docker/client.mjs +54 -0
  536. package/dist/runtime/docker/client.mjs.map +1 -0
  537. package/dist/runtime/docker/container.d.mts +1 -0
  538. package/dist/runtime/docker/container.mjs +562 -0
  539. package/dist/runtime/docker/container.mjs.map +1 -0
  540. package/dist/runtime/docker/errors.d.mts +1 -0
  541. package/dist/runtime/docker/errors.mjs +187 -0
  542. package/dist/runtime/docker/errors.mjs.map +1 -0
  543. package/dist/runtime/docker/exec.d.mts +1 -0
  544. package/dist/runtime/docker/exec.mjs +63 -0
  545. package/dist/runtime/docker/exec.mjs.map +1 -0
  546. package/dist/runtime/docker/image.d.mts +1 -0
  547. package/dist/runtime/docker/image.mjs +278 -0
  548. package/dist/runtime/docker/image.mjs.map +1 -0
  549. package/dist/runtime/docker/index.d.mts +1 -0
  550. package/dist/runtime/docker/inventory.d.mts +1 -0
  551. package/dist/runtime/docker/inventory.mjs +167 -0
  552. package/dist/runtime/docker/inventory.mjs.map +1 -0
  553. package/dist/runtime/docker/labels.d.mts +1 -0
  554. package/dist/runtime/docker/labels.mjs +97 -0
  555. package/dist/runtime/docker/labels.mjs.map +1 -0
  556. package/dist/runtime/docker/logs.d.mts +1 -0
  557. package/dist/runtime/docker/logs.mjs +34 -0
  558. package/dist/runtime/docker/logs.mjs.map +1 -0
  559. package/dist/runtime/docker/network.d.mts +1 -0
  560. package/dist/runtime/docker/network.mjs +168 -0
  561. package/dist/runtime/docker/network.mjs.map +1 -0
  562. package/dist/runtime/docker/service.d.mts +9 -0
  563. package/dist/runtime/docker/service.mjs +266 -0
  564. package/dist/runtime/docker/service.mjs.map +1 -0
  565. package/dist/runtime/docker/sweep.d.mts +1 -0
  566. package/dist/runtime/docker/sweep.mjs +220 -0
  567. package/dist/runtime/docker/sweep.mjs.map +1 -0
  568. package/dist/runtime/docker/volume.d.mts +1 -0
  569. package/dist/runtime/docker/volume.mjs +24 -0
  570. package/dist/runtime/docker/volume.mjs.map +1 -0
  571. package/dist/runtime/docker/wrap.d.mts +1 -0
  572. package/dist/runtime/docker/wrap.mjs +131 -0
  573. package/dist/runtime/docker/wrap.mjs.map +1 -0
  574. package/dist/substrate/brand.d.mts +24 -0
  575. package/dist/substrate/brand.mjs +14 -0
  576. package/dist/substrate/brand.mjs.map +1 -0
  577. package/dist/substrate/cross-process.d.mts +1 -0
  578. package/dist/substrate/cross-process.mjs +28 -0
  579. package/dist/substrate/cross-process.mjs.map +1 -0
  580. package/dist/substrate/events.d.mts +117 -0
  581. package/dist/substrate/identity.d.mts +13 -0
  582. package/dist/substrate/lifecycle.d.mts +12 -0
  583. package/dist/substrate/manifest.d.mts +39 -0
  584. package/dist/substrate/manifest.mjs +33 -0
  585. package/dist/substrate/manifest.mjs.map +1 -0
  586. package/dist/substrate/network.d.mts +34 -0
  587. package/dist/substrate/options.d.mts +23 -0
  588. package/dist/substrate/plugin.d.mts +101 -0
  589. package/dist/substrate/plugin.mjs +61 -0
  590. package/dist/substrate/plugin.mjs.map +1 -0
  591. package/dist/substrate/projection.d.mts +100 -0
  592. package/dist/substrate/runtime/artifact-publisher/index.mjs +76 -0
  593. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +1 -0
  594. package/dist/substrate/runtime/atomic-write.mjs +106 -0
  595. package/dist/substrate/runtime/atomic-write.mjs.map +1 -0
  596. package/dist/substrate/runtime/cache/index.d.mts +1 -0
  597. package/dist/substrate/runtime/cache/schema.d.mts +1 -0
  598. package/dist/substrate/runtime/cache/schema.mjs +22 -0
  599. package/dist/substrate/runtime/cache/schema.mjs.map +1 -0
  600. package/dist/substrate/runtime/cache/service.d.mts +1 -0
  601. package/dist/substrate/runtime/cache/service.mjs +89 -0
  602. package/dist/substrate/runtime/cache/service.mjs.map +1 -0
  603. package/dist/substrate/runtime/capability-sinks/index.d.mts +1 -0
  604. package/dist/substrate/runtime/capability-sinks/layer.d.mts +1 -0
  605. package/dist/substrate/runtime/capability-sinks/layer.mjs +31 -0
  606. package/dist/substrate/runtime/capability-sinks/layer.mjs.map +1 -0
  607. package/dist/substrate/runtime/capability-sinks/service.d.mts +36 -0
  608. package/dist/substrate/runtime/capability-sinks/service.mjs +74 -0
  609. package/dist/substrate/runtime/capability-sinks/service.mjs.map +1 -0
  610. package/dist/substrate/runtime/config-validation.d.mts +38 -0
  611. package/dist/substrate/runtime/config-validation.mjs +137 -0
  612. package/dist/substrate/runtime/config-validation.mjs.map +1 -0
  613. package/dist/substrate/runtime/context-helpers.mjs +32 -0
  614. package/dist/substrate/runtime/context-helpers.mjs.map +1 -0
  615. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +128 -0
  616. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -0
  617. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs +136 -0
  618. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -0
  619. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs +49 -0
  620. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -0
  621. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs +9 -0
  622. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -0
  623. package/dist/substrate/runtime/cross-process/liveness.mjs +119 -0
  624. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -0
  625. package/dist/substrate/runtime/cross-process/roster.mjs +275 -0
  626. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -0
  627. package/dist/substrate/runtime/cross-process/snapshot-reservation.d.mts +1 -0
  628. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +117 -0
  629. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +1 -0
  630. package/dist/substrate/runtime/cross-process/stack-lock.d.mts +1 -0
  631. package/dist/substrate/runtime/cross-process/stack-lock.mjs +142 -0
  632. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -0
  633. package/dist/substrate/runtime/current-plugin.mjs +15 -0
  634. package/dist/substrate/runtime/current-plugin.mjs.map +1 -0
  635. package/dist/substrate/runtime/errors.d.mts +1 -0
  636. package/dist/substrate/runtime/errors.mjs +76 -0
  637. package/dist/substrate/runtime/errors.mjs.map +1 -0
  638. package/dist/substrate/runtime/host-tree-tar/index.mjs +364 -0
  639. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -0
  640. package/dist/substrate/runtime/http-probe.d.mts +35 -0
  641. package/dist/substrate/runtime/http-probe.mjs +65 -0
  642. package/dist/substrate/runtime/http-probe.mjs.map +1 -0
  643. package/dist/substrate/runtime/lease-broker/index.d.mts +1 -0
  644. package/dist/substrate/runtime/lease-broker/service.d.mts +64 -0
  645. package/dist/substrate/runtime/lease-broker/service.mjs +155 -0
  646. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -0
  647. package/dist/substrate/runtime/lifecycle/dep-graph.d.mts +1 -0
  648. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +138 -0
  649. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -0
  650. package/dist/substrate/runtime/lifecycle/index.d.mts +1 -0
  651. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +31 -0
  652. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +1 -0
  653. package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -0
  654. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +133 -0
  655. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -0
  656. package/dist/substrate/runtime/lifecycle/ready-gate.d.mts +1 -0
  657. package/dist/substrate/runtime/lifecycle/ready-gate.mjs +34 -0
  658. package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -0
  659. package/dist/substrate/runtime/lifecycle/selective-restart.d.mts +1 -0
  660. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +43 -0
  661. package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -0
  662. package/dist/substrate/runtime/lifecycle/signals.d.mts +1 -0
  663. package/dist/substrate/runtime/lifecycle/signals.mjs +64 -0
  664. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -0
  665. package/dist/substrate/runtime/lifecycle/state-machine.d.mts +1 -0
  666. package/dist/substrate/runtime/lifecycle/state-machine.mjs +38 -0
  667. package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -0
  668. package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -0
  669. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +27 -0
  670. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -0
  671. package/dist/substrate/runtime/managed-container.d.mts +30 -0
  672. package/dist/substrate/runtime/managed-container.mjs +32 -0
  673. package/dist/substrate/runtime/managed-container.mjs.map +1 -0
  674. package/dist/substrate/runtime/manifest/manifest.mjs +73 -0
  675. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -0
  676. package/dist/substrate/runtime/mode-errors.d.mts +36 -0
  677. package/dist/substrate/runtime/observability/cascade-formatter.d.mts +1 -0
  678. package/dist/substrate/runtime/observability/cascade-formatter.mjs +135 -0
  679. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -0
  680. package/dist/substrate/runtime/observability/formatter-registry.d.mts +1 -0
  681. package/dist/substrate/runtime/observability/formatter-registry.mjs +65 -0
  682. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +1 -0
  683. package/dist/substrate/runtime/observability/index.d.mts +3 -0
  684. package/dist/substrate/runtime/observability/logger.d.mts +58 -0
  685. package/dist/substrate/runtime/observability/logger.mjs +89 -0
  686. package/dist/substrate/runtime/observability/logger.mjs.map +1 -0
  687. package/dist/substrate/runtime/observability/pretty-error.d.mts +1 -0
  688. package/dist/substrate/runtime/observability/pretty-error.mjs +119 -0
  689. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -0
  690. package/dist/substrate/runtime/observability/process-lines.d.mts +31 -0
  691. package/dist/substrate/runtime/observability/process-lines.mjs +40 -0
  692. package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -0
  693. package/dist/substrate/runtime/observability/redaction.d.mts +28 -0
  694. package/dist/substrate/runtime/observability/redaction.mjs +45 -0
  695. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -0
  696. package/dist/substrate/runtime/observability/spans.d.mts +1 -0
  697. package/dist/substrate/runtime/observability/spans.mjs +87 -0
  698. package/dist/substrate/runtime/observability/spans.mjs.map +1 -0
  699. package/dist/substrate/runtime/observability/subprocess-capture.d.mts +2 -0
  700. package/dist/substrate/runtime/observability/subprocess-capture.mjs +82 -0
  701. package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -0
  702. package/dist/substrate/runtime/paths.d.mts +17 -0
  703. package/dist/substrate/runtime/paths.mjs +61 -0
  704. package/dist/substrate/runtime/paths.mjs.map +1 -0
  705. package/dist/substrate/runtime/port-broker/index.d.mts +1 -0
  706. package/dist/substrate/runtime/port-broker/service.d.mts +1 -0
  707. package/dist/substrate/runtime/port-broker/service.mjs +319 -0
  708. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -0
  709. package/dist/substrate/runtime/post-acquire-tasks.d.mts +1 -0
  710. package/dist/substrate/runtime/post-acquire-tasks.mjs +34 -0
  711. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -0
  712. package/dist/substrate/runtime/probes.d.mts +51 -0
  713. package/dist/substrate/runtime/probes.mjs +84 -0
  714. package/dist/substrate/runtime/probes.mjs.map +1 -0
  715. package/dist/substrate/runtime/process-supervisor.d.mts +57 -0
  716. package/dist/substrate/runtime/process-supervisor.mjs +73 -0
  717. package/dist/substrate/runtime/process-supervisor.mjs.map +1 -0
  718. package/dist/substrate/runtime/projection/operational-endpoints.mjs +44 -0
  719. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -0
  720. package/dist/substrate/runtime/projection/persisted.mjs +195 -0
  721. package/dist/substrate/runtime/projection/persisted.mjs.map +1 -0
  722. package/dist/substrate/runtime/projection/state-ref.mjs +48 -0
  723. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -0
  724. package/dist/substrate/runtime/projection/update.mjs +200 -0
  725. package/dist/substrate/runtime/projection/update.mjs.map +1 -0
  726. package/dist/substrate/runtime/retry-policy.d.mts +18 -0
  727. package/dist/substrate/runtime/retry-policy.mjs +16 -0
  728. package/dist/substrate/runtime/retry-policy.mjs.map +1 -0
  729. package/dist/substrate/runtime/run.mjs +86 -0
  730. package/dist/substrate/runtime/run.mjs.map +1 -0
  731. package/dist/substrate/runtime/runtime-decode.d.mts +32 -0
  732. package/dist/substrate/runtime/runtime-decode.mjs +53 -0
  733. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -0
  734. package/dist/substrate/runtime/scoped-http-server.mjs +36 -0
  735. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -0
  736. package/dist/substrate/runtime/scoped-ref-map/service.mjs +83 -0
  737. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +1 -0
  738. package/dist/substrate/runtime/stage-and-swap/index.d.mts +1 -0
  739. package/dist/substrate/runtime/stage-and-swap/index.mjs +131 -0
  740. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -0
  741. package/dist/substrate/runtime/state-store/schema.mjs +36 -0
  742. package/dist/substrate/runtime/state-store/schema.mjs.map +1 -0
  743. package/dist/substrate/runtime/strategy-registry/chain-probe-for.d.mts +1 -0
  744. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs +22 -0
  745. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -0
  746. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.d.mts +1 -0
  747. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs +30 -0
  748. package/dist/substrate/runtime/strategy-registry/faucet-capability-for.mjs.map +1 -0
  749. package/dist/substrate/runtime/strategy-registry/index.d.mts +1 -0
  750. package/dist/substrate/runtime/strategy-registry/service.d.mts +1 -0
  751. package/dist/substrate/runtime/strategy-registry/service.mjs +67 -0
  752. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -0
  753. package/dist/substrate/runtime/sui-execute/index.d.mts +11 -0
  754. package/dist/substrate/runtime/sui-execute/index.mjs +144 -0
  755. package/dist/substrate/runtime/sui-execute/index.mjs.map +1 -0
  756. package/dist/substrate/runtime/sui-move-build/index.d.mts +1 -0
  757. package/dist/substrate/runtime/sui-move-build/index.mjs +283 -0
  758. package/dist/substrate/runtime/sui-move-build/index.mjs.map +1 -0
  759. package/dist/substrate/runtime/supervisor.d.mts +1 -0
  760. package/dist/substrate/runtime/supervisor.mjs +831 -0
  761. package/dist/substrate/runtime/supervisor.mjs.map +1 -0
  762. package/dist/surfaces/cli/command-tree.mjs +276 -0
  763. package/dist/surfaces/cli/command-tree.mjs.map +1 -0
  764. package/dist/surfaces/cli/commands/config.mjs +31 -0
  765. package/dist/surfaces/cli/commands/config.mjs.map +1 -0
  766. package/dist/surfaces/cli/commands/confirm-node.mjs +26 -0
  767. package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -0
  768. package/dist/surfaces/cli/commands/confirm.mjs +26 -0
  769. package/dist/surfaces/cli/commands/confirm.mjs.map +1 -0
  770. package/dist/surfaces/cli/commands/doctor-probes.mjs +452 -0
  771. package/dist/surfaces/cli/commands/doctor-probes.mjs.map +1 -0
  772. package/dist/surfaces/cli/commands/doctor.mjs +38 -0
  773. package/dist/surfaces/cli/commands/doctor.mjs.map +1 -0
  774. package/dist/surfaces/cli/commands/prune-picker.mjs +347 -0
  775. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -0
  776. package/dist/surfaces/cli/commands/prune.mjs +178 -0
  777. package/dist/surfaces/cli/commands/prune.mjs.map +1 -0
  778. package/dist/surfaces/cli/commands/snapshot.mjs +141 -0
  779. package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -0
  780. package/dist/surfaces/cli/commands/status.mjs +95 -0
  781. package/dist/surfaces/cli/commands/status.mjs.map +1 -0
  782. package/dist/surfaces/cli/commands/supervisor-presence.mjs +33 -0
  783. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -0
  784. package/dist/surfaces/cli/commands/wipe.mjs +28 -0
  785. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -0
  786. package/dist/surfaces/cli/envelope.mjs +43 -0
  787. package/dist/surfaces/cli/envelope.mjs.map +1 -0
  788. package/dist/surfaces/cli/errors.mjs +110 -0
  789. package/dist/surfaces/cli/errors.mjs.map +1 -0
  790. package/dist/surfaces/cli/flags.mjs +56 -0
  791. package/dist/surfaces/cli/flags.mjs.map +1 -0
  792. package/dist/surfaces/cli/index.mjs +418 -0
  793. package/dist/surfaces/cli/index.mjs.map +1 -0
  794. package/dist/surfaces/cli/output.mjs +115 -0
  795. package/dist/surfaces/cli/output.mjs.map +1 -0
  796. package/dist/surfaces/cli/sysexits.mjs +139 -0
  797. package/dist/surfaces/cli/sysexits.mjs.map +1 -0
  798. package/dist/surfaces/tui/app.mjs +104 -0
  799. package/dist/surfaces/tui/app.mjs.map +1 -0
  800. package/dist/surfaces/tui/dashboard.mjs +261 -0
  801. package/dist/surfaces/tui/dashboard.mjs.map +1 -0
  802. package/dist/surfaces/tui/display-derivation.mjs +395 -0
  803. package/dist/surfaces/tui/display-derivation.mjs.map +1 -0
  804. package/dist/surfaces/tui/errors.mjs +11 -0
  805. package/dist/surfaces/tui/errors.mjs.map +1 -0
  806. package/dist/surfaces/tui/event-log.mjs +155 -0
  807. package/dist/surfaces/tui/event-log.mjs.map +1 -0
  808. package/dist/surfaces/tui/heartbeat.mjs +33 -0
  809. package/dist/surfaces/tui/heartbeat.mjs.map +1 -0
  810. package/dist/surfaces/tui/index.mjs +50 -0
  811. package/dist/surfaces/tui/index.mjs.map +1 -0
  812. package/dist/surfaces/tui/input.mjs +104 -0
  813. package/dist/surfaces/tui/input.mjs.map +1 -0
  814. package/dist/surfaces/tui/mode-detect.mjs +32 -0
  815. package/dist/surfaces/tui/mode-detect.mjs.map +1 -0
  816. package/dist/surfaces/tui/mount-ink.mjs +31 -0
  817. package/dist/surfaces/tui/mount-ink.mjs.map +1 -0
  818. package/dist/surfaces/tui/plain-renderer.mjs +170 -0
  819. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -0
  820. package/dist/surfaces/tui/resource-table.mjs +507 -0
  821. package/dist/surfaces/tui/resource-table.mjs.map +1 -0
  822. package/images/_shared/signal-forward.sh +77 -0
  823. package/images/postgres/Dockerfile +32 -0
  824. package/images/seal/Dockerfile +68 -0
  825. package/images/seal/entrypoint.sh +65 -0
  826. package/images/sui/Dockerfile +73 -0
  827. package/images/sui/entrypoint.sh +244 -0
  828. package/images/sui-fork/Dockerfile +53 -0
  829. package/images/sui-fork/entrypoint.sh +51 -0
  830. package/images/walrus/Dockerfile +122 -0
  831. package/images/walrus/deploy-walrus.sh +305 -0
  832. package/images/walrus/run-walrus.sh +53 -0
  833. package/package.json +94 -0
@@ -0,0 +1,119 @@
1
+ import { Data, Effect } from "effect";
2
+ import { execFileSync } from "node:child_process";
3
+ import { hostname } from "node:os";
4
+ Data.TaggedError("StartTimeProbeError");
5
+ /** Cheap "send signal 0" pid liveness. ESRCH → dead; EPERM → alive
6
+ * (foreign-user pid on shared dev hosts). Any other errno is
7
+ * conservatively treated as dead so we don't refuse cleanup on exotic
8
+ * platforms. */
9
+ const isPidAlive = (pid) => {
10
+ if (!Number.isFinite(pid) || pid <= 0) return false;
11
+ try {
12
+ process.kill(pid, 0);
13
+ return true;
14
+ } catch (err) {
15
+ return err.code === "EPERM";
16
+ }
17
+ };
18
+ /** Best-effort start-time stamp for `pid`. Returns `null` when the
19
+ * process is gone OR the platform can't produce a time. The stamp
20
+ * itself is opaque text — its only contract is bytewise equality with
21
+ * a previously-recorded sibling stamp.
22
+ *
23
+ * Architecture § Cross-process safety protocol §3 — `ps -o lstart` on
24
+ * macOS/Linux, `tasklist` confirmation on Windows. */
25
+ const processStartTime = (pid) => {
26
+ if (!Number.isFinite(pid) || pid <= 0) return null;
27
+ if (process.platform === "win32") try {
28
+ const out = execFileSync("tasklist", [
29
+ "/fi",
30
+ `PID eq ${pid}`,
31
+ "/fo",
32
+ "csv",
33
+ "/nh"
34
+ ], {
35
+ encoding: "utf8",
36
+ timeout: 2e3,
37
+ stdio: [
38
+ "ignore",
39
+ "pipe",
40
+ "ignore"
41
+ ]
42
+ });
43
+ return out.trim().startsWith("\"") ? hashStartTimeStamp(out.trim()) : null;
44
+ } catch {
45
+ return null;
46
+ }
47
+ try {
48
+ const trimmed = execFileSync("ps", [
49
+ "-o",
50
+ "lstart=",
51
+ "-p",
52
+ String(pid)
53
+ ], {
54
+ encoding: "utf8",
55
+ timeout: 2e3,
56
+ stdio: [
57
+ "ignore",
58
+ "pipe",
59
+ "ignore"
60
+ ]
61
+ }).trim();
62
+ return trimmed.length > 0 ? hashStartTimeStamp(trimmed) : null;
63
+ } catch {
64
+ return null;
65
+ }
66
+ };
67
+ /** Stable hash of a start-time string. Reduces the textual `ps -o
68
+ * lstart=` output to a single number so the roster carries a fixed-
69
+ * width integer (the architecture's `startTime` field is `number`).
70
+ *
71
+ * FNV-1a 32-bit; collisions are negligible at the (pid, host, second)
72
+ * granularity we ever compare. */
73
+ const hashStartTimeStamp = (stamp) => {
74
+ let h = 2166136261;
75
+ for (let i = 0; i < stamp.length; i++) {
76
+ h ^= stamp.charCodeAt(i);
77
+ h = h * 16777619 >>> 0;
78
+ }
79
+ return h >>> 0;
80
+ };
81
+ /** Liveness probe for a roster holder. Used by the claim-protocol
82
+ * sweep AND the snapshot-reservation orphan check.
83
+ *
84
+ * Discipline:
85
+ * - Foreign-host (`hostname` differs from our own) → ALWAYS alive
86
+ * (NFS-safe default; cross-host pid comparisons are meaningless).
87
+ * - Same-host: pid must be live AND start-time must match.
88
+ *
89
+ * Returns `'alive' | 'dead'`. Never throws. Effect-wrapped so callers
90
+ * compose under spans. */
91
+ const checkHolderLiveness = Effect.fn("cross-process.liveness.checkHolderLiveness")(function* (holder, ownHost = hostname()) {
92
+ if (holder.hostname !== ownHost) return "alive";
93
+ yield* Effect.annotateCurrentSpan({
94
+ "devstack.holder.pid": holder.pid,
95
+ "devstack.holder.host": holder.hostname
96
+ });
97
+ if (!isPidAlive(holder.pid)) return "dead";
98
+ const probedStart = processStartTime(holder.pid);
99
+ if (probedStart === null) return "alive";
100
+ return probedStart === holder.startTime ? "alive" : "dead";
101
+ });
102
+ /** Build a holder snapshot for THIS process. The intent defaults to
103
+ * `'normal'`; the snapshot-reservation flow flips it to `'snapshot'`
104
+ * under the stack lock and back when the reservation releases. */
105
+ const ownHolder = (intent = "normal") => {
106
+ const pid = process.pid;
107
+ return {
108
+ pid,
109
+ startTime: processStartTime(pid) ?? 0,
110
+ hostname: hostname(),
111
+ claimedAt: Date.now(),
112
+ heartbeatAt: Date.now(),
113
+ intent
114
+ };
115
+ };
116
+ //#endregion
117
+ export { checkHolderLiveness, isPidAlive, ownHolder, processStartTime };
118
+
119
+ //# sourceMappingURL=liveness.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveness.mjs","names":["nodeHostname"],"sources":["../../../../src/substrate/runtime/cross-process/liveness.ts"],"sourcesContent":["// PID + start-time liveness check.\n//\n// Architecture § Cross-process safety protocol § Claim protocol step 3:\n// \"process exists AND its start-time (as read from `/proc/<pid>/stat` on\n// Linux, `ps -o lstart` on macOS, or equivalent) matches the recorded\n// `startTime`.\"\n//\n// Foreign-host entries are treated as alive (NFS-safe conservative\n// default). On the same host, two checks combine: `kill(pid, 0)`\n// determines pid-in-use; `ps -o lstart` confirms it's the SAME process\n// (defending against pid reuse on long-uptime machines).\n//\n// This module is the ONLY place in the substrate that calls into\n// `process.kill` and shells out for start times. Roster/snapshot\n// reservation/stack-lock all consult it through the typed predicates.\n\nimport { execFileSync } from 'node:child_process';\nimport { hostname as nodeHostname } from 'node:os';\n\nimport { Data, Effect } from 'effect';\n\nimport type { RosterHolder } from '../../cross-process.ts';\n\n/** Tagged failure when the start-time probe itself errored unexpectedly\n * (timeout, missing utility, etc.). Distinguished from \"pid absent\",\n * which is signaled by `processStartTime` returning `null`. */\nexport class StartTimeProbeError extends Data.TaggedError('StartTimeProbeError')<{\n\treadonly pid: number;\n\treadonly cause: unknown;\n}> {}\n\n/** Cheap \"send signal 0\" pid liveness. ESRCH → dead; EPERM → alive\n * (foreign-user pid on shared dev hosts). Any other errno is\n * conservatively treated as dead so we don't refuse cleanup on exotic\n * platforms. */\nexport const isPidAlive = (pid: number): boolean => {\n\tif (!Number.isFinite(pid) || pid <= 0) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (err) {\n\t\tconst code = (err as NodeJS.ErrnoException).code;\n\t\treturn code === 'EPERM';\n\t}\n};\n\n/** Best-effort start-time stamp for `pid`. Returns `null` when the\n * process is gone OR the platform can't produce a time. The stamp\n * itself is opaque text — its only contract is bytewise equality with\n * a previously-recorded sibling stamp.\n *\n * Architecture § Cross-process safety protocol §3 — `ps -o lstart` on\n * macOS/Linux, `tasklist` confirmation on Windows. */\nexport const processStartTime = (pid: number): number | null => {\n\tif (!Number.isFinite(pid) || pid <= 0) return null;\n\tif (process.platform === 'win32') {\n\t\ttry {\n\t\t\tconst out = execFileSync('tasklist', ['/fi', `PID eq ${pid}`, '/fo', 'csv', '/nh'], {\n\t\t\t\tencoding: 'utf8',\n\t\t\t\ttimeout: 2000,\n\t\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t\t});\n\t\t\t// Windows path: just hash the line. Windows PID reuse on uptime\n\t\t\t// is a known v1 trade-off; the architecture says the protocol\n\t\t\t// stays POSIX-first.\n\t\t\treturn out.trim().startsWith('\"') ? hashStartTimeStamp(out.trim()) : null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\ttry {\n\t\tconst out = execFileSync('ps', ['-o', 'lstart=', '-p', String(pid)], {\n\t\t\tencoding: 'utf8',\n\t\t\ttimeout: 2000,\n\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t});\n\t\tconst trimmed = out.trim();\n\t\treturn trimmed.length > 0 ? hashStartTimeStamp(trimmed) : null;\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n/** Stable hash of a start-time string. Reduces the textual `ps -o\n * lstart=` output to a single number so the roster carries a fixed-\n * width integer (the architecture's `startTime` field is `number`).\n *\n * FNV-1a 32-bit; collisions are negligible at the (pid, host, second)\n * granularity we ever compare. */\nconst hashStartTimeStamp = (stamp: string): number => {\n\tlet h = 2166136261;\n\tfor (let i = 0; i < stamp.length; i++) {\n\t\th ^= stamp.charCodeAt(i);\n\t\th = (h * 16777619) >>> 0;\n\t}\n\t// Stay inside Number.MAX_SAFE_INTEGER's positive 32-bit range so the\n\t// number round-trips through JSON without precision loss.\n\treturn h >>> 0;\n};\n\n/** Liveness probe for a roster holder. Used by the claim-protocol\n * sweep AND the snapshot-reservation orphan check.\n *\n * Discipline:\n * - Foreign-host (`hostname` differs from our own) → ALWAYS alive\n * (NFS-safe default; cross-host pid comparisons are meaningless).\n * - Same-host: pid must be live AND start-time must match.\n *\n * Returns `'alive' | 'dead'`. Never throws. Effect-wrapped so callers\n * compose under spans. */\nexport const checkHolderLiveness = Effect.fn('cross-process.liveness.checkHolderLiveness')(\n\tfunction* (holder: RosterHolder, ownHost: string = nodeHostname()) {\n\t\t// Foreign-host: NFS-safe — we can't verify, assume alive.\n\t\tif (holder.hostname !== ownHost) {\n\t\t\treturn 'alive' as const;\n\t\t}\n\t\tyield* Effect.annotateCurrentSpan({\n\t\t\t'devstack.holder.pid': holder.pid,\n\t\t\t'devstack.holder.host': holder.hostname,\n\t\t});\n\t\tif (!isPidAlive(holder.pid)) return 'dead' as const;\n\t\tconst probedStart = processStartTime(holder.pid);\n\t\t// pid alive but no stamp probable → conservative: ALIVE\n\t\t// (we have nothing to dispute the recorded startTime with).\n\t\tif (probedStart === null) return 'alive' as const;\n\t\treturn probedStart === holder.startTime ? ('alive' as const) : ('dead' as const);\n\t},\n);\n\n/** Build a holder snapshot for THIS process. The intent defaults to\n * `'normal'`; the snapshot-reservation flow flips it to `'snapshot'`\n * under the stack lock and back when the reservation releases. */\nexport const ownHolder = (intent: 'normal' | 'snapshot' = 'normal'): RosterHolder => {\n\tconst pid = process.pid;\n\tconst startTime = processStartTime(pid) ?? 0;\n\treturn {\n\t\tpid,\n\t\tstartTime,\n\t\thostname: nodeHostname(),\n\t\tclaimedAt: Date.now(),\n\t\theartbeatAt: Date.now(),\n\t\tintent,\n\t};\n};\n"],"mappings":";;;AA0ByC,KAAK,YAAY,sBAAsB;;;;;AAShF,MAAa,cAAc,QAAyB;AACnD,KAAI,CAAC,OAAO,SAAS,IAAI,IAAI,OAAO,EAAG,QAAO;AAC9C,KAAI;AACH,UAAQ,KAAK,KAAK,EAAE;AACpB,SAAO;UACC,KAAK;AAEb,SADc,IAA8B,SAC5B;;;;;;;;;;AAWlB,MAAa,oBAAoB,QAA+B;AAC/D,KAAI,CAAC,OAAO,SAAS,IAAI,IAAI,OAAO,EAAG,QAAO;AAC9C,KAAI,QAAQ,aAAa,QACxB,KAAI;EACH,MAAM,MAAM,aAAa,YAAY;GAAC;GAAO,UAAU;GAAO;GAAO;GAAO;GAAM,EAAE;GACnF,UAAU;GACV,SAAS;GACT,OAAO;IAAC;IAAU;IAAQ;IAAS;GACnC,CAAC;AAIF,SAAO,IAAI,MAAM,CAAC,WAAW,KAAI,GAAG,mBAAmB,IAAI,MAAM,CAAC,GAAG;SAC9D;AACP,SAAO;;AAGT,KAAI;EAMH,MAAM,UALM,aAAa,MAAM;GAAC;GAAM;GAAW;GAAM,OAAO,IAAI;GAAC,EAAE;GACpE,UAAU;GACV,SAAS;GACT,OAAO;IAAC;IAAU;IAAQ;IAAS;GACnC,CACkB,CAAC,MAAM;AAC1B,SAAO,QAAQ,SAAS,IAAI,mBAAmB,QAAQ,GAAG;SACnD;AACP,SAAO;;;;;;;;;AAUT,MAAM,sBAAsB,UAA0B;CACrD,IAAI,IAAI;AACR,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACtC,OAAK,MAAM,WAAW,EAAE;AACxB,MAAK,IAAI,aAAc;;AAIxB,QAAO,MAAM;;;;;;;;;;;;AAad,MAAa,sBAAsB,OAAO,GAAG,6CAA6C,CACzF,WAAW,QAAsB,UAAkBA,UAAc,EAAE;AAElE,KAAI,OAAO,aAAa,QACvB,QAAO;AAER,QAAO,OAAO,oBAAoB;EACjC,uBAAuB,OAAO;EAC9B,wBAAwB,OAAO;EAC/B,CAAC;AACF,KAAI,CAAC,WAAW,OAAO,IAAI,CAAE,QAAO;CACpC,MAAM,cAAc,iBAAiB,OAAO,IAAI;AAGhD,KAAI,gBAAgB,KAAM,QAAO;AACjC,QAAO,gBAAgB,OAAO,YAAa,UAAqB;EAEjE;;;;AAKD,MAAa,aAAa,SAAgC,aAA2B;CACpF,MAAM,MAAM,QAAQ;AAEpB,QAAO;EACN;EACA,WAHiB,iBAAiB,IAAI,IAAI;EAI1C,UAAUA,UAAc;EACxB,WAAW,KAAK,KAAK;EACrB,aAAa,KAAK,KAAK;EACvB;EACA"}
@@ -0,0 +1,275 @@
1
+ import { DEFAULT_SWEEP_POLICY, RosterDocumentSchema } from "../../cross-process.mjs";
2
+ import { checkHolderLiveness, isPidAlive, ownHolder, processStartTime } from "./liveness.mjs";
3
+ import { decodeJsonText } from "../runtime-decode.mjs";
4
+ import { atomicWriteJsonSync } from "../atomic-write.mjs";
5
+ import { SpanAttr } from "../observability/spans.mjs";
6
+ import { acquireStackLock } from "./stack-lock.mjs";
7
+ import { Data, Effect, Schema } from "effect";
8
+ import { existsSync, readFileSync } from "node:fs";
9
+ import { dirname } from "node:path";
10
+ import { hostname } from "node:os";
11
+ //#region src/substrate/runtime/cross-process/roster.ts
12
+ var RosterCorruptError = class extends Data.TaggedError("RosterCorruptError") {};
13
+ var RosterIoError = class extends Data.TaggedError("RosterIoError") {};
14
+ const EMPTY_ROSTER = {
15
+ version: 1,
16
+ holders: []
17
+ };
18
+ /** Read the roster from disk. Returns the empty document if absent.
19
+ * Tolerates a missing file but NOT a malformed file (a malformed
20
+ * roster surfaces a typed error so callers can decide whether to
21
+ * abandon or rewrite). */
22
+ const readRoster = (path) => Effect.gen(function* () {
23
+ if (!existsSync(path)) return EMPTY_ROSTER;
24
+ const raw = yield* Effect.try({
25
+ try: () => readFileSync(path, "utf8"),
26
+ catch: (cause) => new RosterIoError({
27
+ path,
28
+ cause
29
+ })
30
+ });
31
+ return yield* decodeJsonText(RosterDocumentSchema, raw, {
32
+ source: path,
33
+ mkError: (issue) => new RosterCorruptError({
34
+ path,
35
+ raw,
36
+ cause: issue.cause ?? issue
37
+ })
38
+ });
39
+ }).pipe(Effect.withSpan("cross-process.roster.read"));
40
+ /** Atomic write: route through the canonical sync primitive. The
41
+ * roster's mutations are all under `stack.lock`, so the non-yielding
42
+ * sync surface is correct here — and it shares ONE owner of the
43
+ * tempfile dance with state-store, cache, and manifest. */
44
+ const atomicWriteRoster = (path, doc) => Effect.try({
45
+ try: () => atomicWriteJsonSync(path, doc),
46
+ catch: (cause) => new RosterIoError({
47
+ path,
48
+ cause
49
+ })
50
+ });
51
+ /** Walk the roster's holders and drop those that fail the liveness
52
+ * test AND whose heartbeats are older than `staleAfterMillis`.
53
+ *
54
+ * Architecture § Claim protocol step 3 — "Holders whose
55
+ * `heartbeatAt` is older than 3× the heartbeat interval AND who fail
56
+ * the PID liveness check are evicted."
57
+ *
58
+ * A live holder with a stale heartbeat is NOT evicted — heartbeat
59
+ * staleness alone is allowed (slow peer). The conjunction matters. */
60
+ const sweepStaleHolders = Effect.fn("cross-process.roster.sweep")(function* (doc, policy = DEFAULT_SWEEP_POLICY, now = Date.now()) {
61
+ const survivors = [];
62
+ const evicted = [];
63
+ for (const holder of doc.holders) {
64
+ if (!(now - holder.heartbeatAt > policy.staleAfterMillis)) {
65
+ survivors.push(holder);
66
+ continue;
67
+ }
68
+ if ((yield* checkHolderLiveness(holder).pipe(Effect.catch(() => Effect.succeed("alive")))) === "dead") evicted.push(holder);
69
+ else survivors.push(holder);
70
+ }
71
+ return {
72
+ swept: {
73
+ version: doc.version,
74
+ holders: survivors
75
+ },
76
+ evicted
77
+ };
78
+ });
79
+ const withStackLock = (paths, body) => Effect.scoped(Effect.gen(function* () {
80
+ yield* acquireStackLock(paths.stackLockFile);
81
+ return yield* body;
82
+ }));
83
+ /**
84
+ * Claim protocol — architecture § Claim protocol.
85
+ *
86
+ * Under the exclusive lock:
87
+ * 1. Read the roster (or initialize empty if missing).
88
+ * 2. Sweep stale holders (PID liveness + heartbeat age).
89
+ * 3. Append this process's entry.
90
+ * 4. Atomic write the result.
91
+ *
92
+ * Returns the swept document, our holder entry, and any evicted peers.
93
+ */
94
+ const claim = (paths, intent = "normal", policy = DEFAULT_SWEEP_POLICY) => withStackLock(paths, Effect.gen(function* () {
95
+ yield* Effect.annotateCurrentSpan({
96
+ "devstack.roster.path": paths.rosterFile,
97
+ "devstack.roster.intent": intent
98
+ });
99
+ const { swept, evicted } = yield* sweepStaleHolders(yield* readRoster(paths.rosterFile).pipe(Effect.catchTag("RosterCorruptError", () => Effect.succeed(EMPTY_ROSTER))), policy);
100
+ const self = { ...ownHolder(intent) };
101
+ const next = {
102
+ version: 1,
103
+ holders: [...swept.holders, self]
104
+ };
105
+ yield* atomicWriteRoster(paths.rosterFile, next);
106
+ return {
107
+ self,
108
+ roster: next,
109
+ evicted,
110
+ soleHolder: swept.holders.length === 0
111
+ };
112
+ })).pipe(Effect.withSpan("cross-process.roster.claim"));
113
+ /**
114
+ * Heartbeat protocol — refresh this process's `heartbeatAt`. Under the
115
+ * stack lock to keep mutation atomic. Architecture § Heartbeat
116
+ * protocol.
117
+ */
118
+ const heartbeat = (paths, ownPid = process.pid) => withStackLock(paths, Effect.gen(function* () {
119
+ const current = yield* readRoster(paths.rosterFile).pipe(Effect.catchTag("RosterCorruptError", () => Effect.succeed(EMPTY_ROSTER)));
120
+ const now = Date.now();
121
+ const ownHost = hostname();
122
+ let touched = false;
123
+ const next = {
124
+ version: 1,
125
+ holders: current.holders.map((h) => {
126
+ if (h.pid === ownPid && h.hostname === ownHost) {
127
+ touched = true;
128
+ return {
129
+ ...h,
130
+ heartbeatAt: now
131
+ };
132
+ }
133
+ return h;
134
+ })
135
+ };
136
+ if (touched) yield* atomicWriteRoster(paths.rosterFile, next);
137
+ })).pipe(Effect.withSpan("cross-process.roster.heartbeat"));
138
+ /**
139
+ * Release protocol — architecture § Release protocol.
140
+ *
141
+ * Removes this process's holder. Returns whether this was the
142
+ * last-leaver (caller runs the stop finalizer if so).
143
+ */
144
+ const release = (paths, ownPid = process.pid) => withStackLock(paths, Effect.gen(function* () {
145
+ const current = yield* readRoster(paths.rosterFile).pipe(Effect.catchTag("RosterCorruptError", () => Effect.succeed(EMPTY_ROSTER)));
146
+ const ownHost = hostname();
147
+ const remaining = current.holders.filter((h) => !(h.pid === ownPid && h.hostname === ownHost));
148
+ const next = {
149
+ version: 1,
150
+ holders: remaining
151
+ };
152
+ yield* atomicWriteRoster(paths.rosterFile, next);
153
+ return {
154
+ roster: next,
155
+ lastLeaver: remaining.length === 0
156
+ };
157
+ })).pipe(Effect.withSpan("cross-process.roster.release"));
158
+ /** Background heartbeat fiber. Wakes every `intervalMillis` (default
159
+ * matches `DEFAULT_SWEEP_POLICY.heartbeatIntervalMillis`) and refreshes
160
+ * this process's `heartbeatAt`.
161
+ *
162
+ * Returns an Effect that runs forever in its Scope — the supervisor
163
+ * forks it via `Effect.forkScoped` so it tears down with the stack. */
164
+ const heartbeatFiber = (paths, intervalMillis = DEFAULT_SWEEP_POLICY.heartbeatIntervalMillis) => Effect.gen(function* () {
165
+ while (true) {
166
+ yield* Effect.sleep(`${intervalMillis} millis`);
167
+ yield* heartbeat(paths).pipe(Effect.catch((err) => Effect.logWarning("roster heartbeat failed").pipe(Effect.annotateLogs({
168
+ [SpanAttr.rosterHeartbeatIntervalMs]: intervalMillis,
169
+ [SpanAttr.errorCause]: String(err)
170
+ }))));
171
+ }
172
+ }).pipe(Effect.withSpan("cross-process.roster.heartbeatFiber"));
173
+ const ContainerClaimSchema = Schema.Struct({
174
+ containerKey: Schema.String,
175
+ pid: Schema.Number,
176
+ startTime: Schema.optional(Schema.Number),
177
+ hostname: Schema.String,
178
+ claimedAt: Schema.Number
179
+ });
180
+ const ContainerClaimDocumentSchema = Schema.Struct({
181
+ version: Schema.Literal(1),
182
+ claims: Schema.Array(ContainerClaimSchema)
183
+ });
184
+ const EMPTY_CLAIMS = {
185
+ version: 1,
186
+ claims: []
187
+ };
188
+ const claimsPath = (rosterFile) => `${dirname(rosterFile)}/container-claims.json`;
189
+ const isContainerClaimLive = (claim, ownHost = hostname()) => {
190
+ if (claim.hostname !== ownHost) return true;
191
+ if (!isPidAlive(claim.pid)) return false;
192
+ if (claim.startTime === void 0) return true;
193
+ const probedStart = processStartTime(claim.pid);
194
+ if (probedStart === null) return true;
195
+ return probedStart === claim.startTime;
196
+ };
197
+ const liveContainerClaims = (doc) => ({
198
+ version: 1,
199
+ claims: doc.claims.filter((claim) => isContainerClaimLive(claim))
200
+ });
201
+ const writeClaims = (path, doc) => Effect.try({
202
+ try: () => atomicWriteJsonSync(path, doc),
203
+ catch: (cause) => new RosterIoError({
204
+ path,
205
+ cause
206
+ })
207
+ });
208
+ /** Read the container-claim ledger. */
209
+ const readClaims = (paths) => Effect.gen(function* () {
210
+ const path = claimsPath(paths.rosterFile);
211
+ if (!existsSync(path)) return EMPTY_CLAIMS;
212
+ const raw = yield* Effect.try({
213
+ try: () => readFileSync(path, "utf8"),
214
+ catch: (cause) => new RosterIoError({
215
+ path,
216
+ cause
217
+ })
218
+ });
219
+ return yield* decodeJsonText(ContainerClaimDocumentSchema, raw, {
220
+ source: path,
221
+ mkError: (issue) => new RosterCorruptError({
222
+ path,
223
+ raw,
224
+ cause: issue.cause ?? issue
225
+ })
226
+ });
227
+ }).pipe(Effect.withSpan("cross-process.roster.readClaims"));
228
+ /** Record that this process now claims `containerKey`. No-op if
229
+ * already claimed by this process. */
230
+ const addClaim = (paths, containerKey) => withStackLock(paths, Effect.gen(function* () {
231
+ const path = claimsPath(paths.rosterFile);
232
+ const current = yield* readClaims(paths).pipe(Effect.catchTag("RosterCorruptError", () => Effect.succeed(EMPTY_CLAIMS)));
233
+ const live = liveContainerClaims(current);
234
+ const ownPid = process.pid;
235
+ const ownStartTime = processStartTime(ownPid) ?? void 0;
236
+ const ownHost = hostname();
237
+ if (live.claims.some((c) => c.containerKey === containerKey && c.pid === ownPid && c.hostname === ownHost)) {
238
+ if (live.claims.length !== current.claims.length) yield* writeClaims(path, live);
239
+ return;
240
+ }
241
+ yield* writeClaims(path, {
242
+ version: 1,
243
+ claims: [...live.claims, {
244
+ containerKey,
245
+ pid: ownPid,
246
+ ...ownStartTime === void 0 ? {} : { startTime: ownStartTime },
247
+ hostname: ownHost,
248
+ claimedAt: Date.now()
249
+ }]
250
+ });
251
+ })).pipe(Effect.withSpan("cross-process.roster.addClaim"));
252
+ /** Release this process's claim on `containerKey`. Returns whether
253
+ * the container has zero remaining claims AFTER this release — the
254
+ * "last-leaver" signal that authorizes a teardown.
255
+ *
256
+ * Architecture § Cross-process safety protocol: "when a process
257
+ * releases its last claim and confirms no other process holds the
258
+ * container, it may tear down." */
259
+ const removeClaim = (paths, containerKey) => withStackLock(paths, Effect.gen(function* () {
260
+ const path = claimsPath(paths.rosterFile);
261
+ const live = liveContainerClaims(yield* readClaims(paths).pipe(Effect.catchTag("RosterCorruptError", () => Effect.succeed(EMPTY_CLAIMS))));
262
+ const ownPid = process.pid;
263
+ const ownHost = hostname();
264
+ const remaining = live.claims.filter((c) => !(c.containerKey === containerKey && c.pid === ownPid && c.hostname === ownHost));
265
+ const stillClaimedByPeer = remaining.some((c) => c.containerKey === containerKey);
266
+ yield* writeClaims(path, {
267
+ version: 1,
268
+ claims: remaining
269
+ });
270
+ return { lastClaimReleased: !stillClaimedByPeer };
271
+ })).pipe(Effect.withSpan("cross-process.roster.removeClaim"));
272
+ //#endregion
273
+ export { addClaim, claim, heartbeatFiber, readClaims, readRoster, release, removeClaim };
274
+
275
+ //# sourceMappingURL=roster.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roster.mjs","names":["nodeHostname"],"sources":["../../../../src/substrate/runtime/cross-process/roster.ts"],"sourcesContent":["// `roster.json` — authoritative cross-process holder record.\n//\n// Architecture § Cross-process safety protocol § Roster:\n// \"the authoritative cross-process record of which OS processes are\n// currently 'in' this stack.\"\n//\n// Mutated only under `stack.lock`. Schema-validated on every read so a\n// truncated/forward-version write never corrupts a peer's view. Stale\n// entries reaped during step-3 sweep on the next claim.\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { hostname as nodeHostname } from 'node:os';\nimport { dirname } from 'node:path';\n\nimport { Data, Effect, Schema } from 'effect';\n\nimport {\n\tDEFAULT_SWEEP_POLICY,\n\ttype RosterDocument,\n\tRosterDocumentSchema,\n\ttype RosterHolder,\n\ttype RosterSweepPolicy,\n} from '../../cross-process.ts';\nimport { atomicWriteJsonSync } from '../atomic-write.ts';\nimport { SpanAttr } from '../observability/spans.ts';\nimport { decodeJsonText } from '../runtime-decode.ts';\nimport { acquireStackLock } from './stack-lock.ts';\nimport { checkHolderLiveness, isPidAlive, ownHolder, processStartTime } from './liveness.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\nexport class RosterCorruptError extends Data.TaggedError('RosterCorruptError')<{\n\treadonly path: string;\n\treadonly raw: string;\n\treadonly cause: unknown;\n}> {}\n\nexport class RosterIoError extends Data.TaggedError('RosterIoError')<{\n\treadonly path: string;\n\treadonly cause: unknown;\n}> {}\n\nexport type RosterError = RosterCorruptError | RosterIoError;\n\n// -----------------------------------------------------------------------------\n// Read / write\n// -----------------------------------------------------------------------------\n\nconst EMPTY_ROSTER: RosterDocument = { version: 1, holders: [] };\n\n/** Read the roster from disk. Returns the empty document if absent.\n * Tolerates a missing file but NOT a malformed file (a malformed\n * roster surfaces a typed error so callers can decide whether to\n * abandon or rewrite). */\nexport const readRoster = (path: string): Effect.Effect<RosterDocument, RosterError> =>\n\tEffect.gen(function* () {\n\t\tif (!existsSync(path)) return EMPTY_ROSTER;\n\t\tconst raw = yield* Effect.try({\n\t\t\ttry: () => readFileSync(path, 'utf8'),\n\t\t\tcatch: (cause) => new RosterIoError({ path, cause }),\n\t\t});\n\t\tconst decoded = yield* decodeJsonText(RosterDocumentSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) => new RosterCorruptError({ path, raw, cause: issue.cause ?? issue }),\n\t\t});\n\t\treturn decoded;\n\t}).pipe(Effect.withSpan('cross-process.roster.read'));\n\n/** Atomic write: route through the canonical sync primitive. The\n * roster's mutations are all under `stack.lock`, so the non-yielding\n * sync surface is correct here — and it shares ONE owner of the\n * tempfile dance with state-store, cache, and manifest. */\nconst atomicWriteRoster = (path: string, doc: RosterDocument): Effect.Effect<void, RosterIoError> =>\n\tEffect.try({\n\t\ttry: () => atomicWriteJsonSync(path, doc),\n\t\tcatch: (cause) => new RosterIoError({ path, cause }),\n\t});\n\n// -----------------------------------------------------------------------------\n// Sweep\n// -----------------------------------------------------------------------------\n\n/** Walk the roster's holders and drop those that fail the liveness\n * test AND whose heartbeats are older than `staleAfterMillis`.\n *\n * Architecture § Claim protocol step 3 — \"Holders whose\n * `heartbeatAt` is older than 3× the heartbeat interval AND who fail\n * the PID liveness check are evicted.\"\n *\n * A live holder with a stale heartbeat is NOT evicted — heartbeat\n * staleness alone is allowed (slow peer). The conjunction matters. */\nexport const sweepStaleHolders = Effect.fn('cross-process.roster.sweep')(function* (\n\tdoc: RosterDocument,\n\tpolicy: RosterSweepPolicy = DEFAULT_SWEEP_POLICY,\n\tnow: number = Date.now(),\n) {\n\tconst survivors: RosterHolder[] = [];\n\tconst evicted: RosterHolder[] = [];\n\tfor (const holder of doc.holders) {\n\t\tconst heartbeatStale = now - holder.heartbeatAt > policy.staleAfterMillis;\n\t\tif (!heartbeatStale) {\n\t\t\tsurvivors.push(holder);\n\t\t\tcontinue;\n\t\t}\n\t\tconst liveness = yield* checkHolderLiveness(holder).pipe(\n\t\t\tEffect.catch(() => Effect.succeed('alive' as const)),\n\t\t);\n\t\tif (liveness === 'dead') {\n\t\t\tevicted.push(holder);\n\t\t} else {\n\t\t\tsurvivors.push(holder);\n\t\t}\n\t}\n\treturn {\n\t\tswept: { version: doc.version, holders: survivors } satisfies RosterDocument,\n\t\tevicted: evicted as ReadonlyArray<RosterHolder>,\n\t};\n});\n\n// -----------------------------------------------------------------------------\n// Claim / release / heartbeat\n// -----------------------------------------------------------------------------\n\n/** Outcome of a claim: the holder this process registered, the swept\n * document, and whether this process is now the sole holder. */\nexport interface ClaimResult {\n\treadonly self: RosterHolder;\n\treadonly roster: RosterDocument;\n\treadonly evicted: ReadonlyArray<RosterHolder>;\n\treadonly soleHolder: boolean;\n}\n\n/** Outcome of a release: the swept document and whether this process\n * was the last leaver (no peers remain after removal). Architecture §\n * Release protocol step 4. */\nexport interface ReleaseResult {\n\treadonly roster: RosterDocument;\n\treadonly lastLeaver: boolean;\n}\n\ninterface RosterPaths {\n\treadonly stackLockFile: string;\n\treadonly rosterFile: string;\n}\n\nconst withStackLock = <A, E, R>(\n\tpaths: RosterPaths,\n\tbody: Effect.Effect<A, E, R>,\n): Effect.Effect<A, E | import('./stack-lock.ts').StackLockError, R> =>\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tyield* acquireStackLock(paths.stackLockFile);\n\t\t\treturn yield* body;\n\t\t}),\n\t);\n\n/**\n * Claim protocol — architecture § Claim protocol.\n *\n * Under the exclusive lock:\n * 1. Read the roster (or initialize empty if missing).\n * 2. Sweep stale holders (PID liveness + heartbeat age).\n * 3. Append this process's entry.\n * 4. Atomic write the result.\n *\n * Returns the swept document, our holder entry, and any evicted peers.\n */\nexport const claim = (\n\tpaths: RosterPaths,\n\tintent: 'normal' | 'snapshot' = 'normal',\n\tpolicy: RosterSweepPolicy = DEFAULT_SWEEP_POLICY,\n): Effect.Effect<ClaimResult, RosterError | import('./stack-lock.ts').StackLockError> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tyield* Effect.annotateCurrentSpan({\n\t\t\t\t'devstack.roster.path': paths.rosterFile,\n\t\t\t\t'devstack.roster.intent': intent,\n\t\t\t});\n\t\t\tconst initial = yield* readRoster(paths.rosterFile).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_ROSTER)),\n\t\t\t);\n\t\t\tconst { swept, evicted } = yield* sweepStaleHolders(initial, policy);\n\t\t\tconst self: RosterHolder = { ...ownHolder(intent) };\n\t\t\tconst next: RosterDocument = {\n\t\t\t\tversion: 1,\n\t\t\t\tholders: [...swept.holders, self],\n\t\t\t};\n\t\t\tyield* atomicWriteRoster(paths.rosterFile, next);\n\t\t\treturn {\n\t\t\t\tself,\n\t\t\t\troster: next,\n\t\t\t\tevicted,\n\t\t\t\tsoleHolder: swept.holders.length === 0,\n\t\t\t};\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.claim'));\n\n/**\n * Heartbeat protocol — refresh this process's `heartbeatAt`. Under the\n * stack lock to keep mutation atomic. Architecture § Heartbeat\n * protocol.\n */\nexport const heartbeat = (\n\tpaths: RosterPaths,\n\townPid: number = process.pid,\n): Effect.Effect<void, RosterError | import('./stack-lock.ts').StackLockError> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tconst current = yield* readRoster(paths.rosterFile).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_ROSTER)),\n\t\t\t);\n\t\t\tconst now = Date.now();\n\t\t\tconst ownHost = nodeHostname();\n\t\t\tlet touched = false;\n\t\t\tconst next: RosterDocument = {\n\t\t\t\tversion: 1,\n\t\t\t\tholders: current.holders.map((h) => {\n\t\t\t\t\tif (h.pid === ownPid && h.hostname === ownHost) {\n\t\t\t\t\t\ttouched = true;\n\t\t\t\t\t\treturn { ...h, heartbeatAt: now };\n\t\t\t\t\t}\n\t\t\t\t\treturn h;\n\t\t\t\t}),\n\t\t\t};\n\t\t\tif (touched) yield* atomicWriteRoster(paths.rosterFile, next);\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.heartbeat'));\n\n/**\n * Release protocol — architecture § Release protocol.\n *\n * Removes this process's holder. Returns whether this was the\n * last-leaver (caller runs the stop finalizer if so).\n */\nexport const release = (\n\tpaths: RosterPaths,\n\townPid: number = process.pid,\n): Effect.Effect<ReleaseResult, RosterError | import('./stack-lock.ts').StackLockError> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tconst current = yield* readRoster(paths.rosterFile).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_ROSTER)),\n\t\t\t);\n\t\t\tconst ownHost = nodeHostname();\n\t\t\tconst remaining = current.holders.filter(\n\t\t\t\t(h) => !(h.pid === ownPid && h.hostname === ownHost),\n\t\t\t);\n\t\t\tconst next: RosterDocument = { version: 1, holders: remaining };\n\t\t\tyield* atomicWriteRoster(paths.rosterFile, next);\n\t\t\treturn {\n\t\t\t\troster: next,\n\t\t\t\tlastLeaver: remaining.length === 0,\n\t\t\t};\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.release'));\n\n/**\n * Set this process's `intent` (`normal` ↔ `snapshot`) under the\n * exclusive lock. Architecture § Concurrent snapshot step 2 / 5.\n */\nexport const setIntent = (\n\tpaths: RosterPaths,\n\tintent: 'normal' | 'snapshot',\n\townPid: number = process.pid,\n): Effect.Effect<void, RosterError | import('./stack-lock.ts').StackLockError> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tconst current = yield* readRoster(paths.rosterFile).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_ROSTER)),\n\t\t\t);\n\t\t\tconst ownHost = nodeHostname();\n\t\t\tconst next: RosterDocument = {\n\t\t\t\tversion: 1,\n\t\t\t\tholders: current.holders.map((h) =>\n\t\t\t\t\th.pid === ownPid && h.hostname === ownHost ? { ...h, intent } : h,\n\t\t\t\t),\n\t\t\t};\n\t\t\tyield* atomicWriteRoster(paths.rosterFile, next);\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.setIntent'));\n\n/** Background heartbeat fiber. Wakes every `intervalMillis` (default\n * matches `DEFAULT_SWEEP_POLICY.heartbeatIntervalMillis`) and refreshes\n * this process's `heartbeatAt`.\n *\n * Returns an Effect that runs forever in its Scope — the supervisor\n * forks it via `Effect.forkScoped` so it tears down with the stack. */\nexport const heartbeatFiber = (\n\tpaths: RosterPaths,\n\tintervalMillis: number = DEFAULT_SWEEP_POLICY.heartbeatIntervalMillis,\n): Effect.Effect<never> =>\n\tEffect.gen(function* () {\n\t\twhile (true) {\n\t\t\tyield* Effect.sleep(`${intervalMillis} millis`);\n\t\t\tyield* heartbeat(paths).pipe(\n\t\t\t\t// A heartbeat failure is non-fatal — the next peer's sweep\n\t\t\t\t// would otherwise evict us, but the architecture treats this\n\t\t\t\t// as \"the dev didn't get to flush a heartbeat in time;\n\t\t\t\t// recover by retrying next interval.\" Log via Effect's\n\t\t\t\t// logger; do not propagate.\n\t\t\t\tEffect.catch((err) =>\n\t\t\t\t\tEffect.logWarning('roster heartbeat failed').pipe(\n\t\t\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t\t\t[SpanAttr.rosterHeartbeatIntervalMs]: intervalMillis,\n\t\t\t\t\t\t\t[SpanAttr.errorCause]: String(err),\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}).pipe(Effect.withSpan('cross-process.roster.heartbeatFiber'));\n\n// -----------------------------------------------------------------------------\n// Container-claim ledger\n// -----------------------------------------------------------------------------\n//\n// Architecture § Cross-process safety protocol: roster \"Records claimed\n// containers per process. Last-leaver semantics: when a process\n// releases its last claim and confirms no other process holds the\n// container, it may tear down.\"\n//\n// The roster document carries holders only — the per-container claim\n// ledger lives in an EXTENSION file at `<stackRoot>/container-claims.json`\n// so the architecture-mandated `RosterDocument` shape doesn't widen.\n// Same atomicity discipline: mutate under `stack.lock`.\n\nexport interface ContainerClaim {\n\treadonly containerKey: string;\n\treadonly pid: number;\n\treadonly startTime?: number;\n\treadonly hostname: string;\n\treadonly claimedAt: number;\n}\n\nexport interface ContainerClaimDocument {\n\treadonly version: 1;\n\treadonly claims: ReadonlyArray<ContainerClaim>;\n}\n\nconst ContainerClaimSchema = Schema.Struct({\n\tcontainerKey: Schema.String,\n\tpid: Schema.Number,\n\tstartTime: Schema.optional(Schema.Number),\n\thostname: Schema.String,\n\tclaimedAt: Schema.Number,\n});\n\nconst ContainerClaimDocumentSchema = Schema.Struct({\n\tversion: Schema.Literal(1),\n\tclaims: Schema.Array(ContainerClaimSchema),\n});\n\nconst EMPTY_CLAIMS: ContainerClaimDocument = { version: 1, claims: [] };\n\nconst claimsPath = (rosterFile: string): string => `${dirname(rosterFile)}/container-claims.json`;\n\nconst isContainerClaimLive = (claim: ContainerClaim, ownHost: string = nodeHostname()): boolean => {\n\tif (claim.hostname !== ownHost) return true;\n\tif (!isPidAlive(claim.pid)) return false;\n\tif (claim.startTime === undefined) return true;\n\tconst probedStart = processStartTime(claim.pid);\n\tif (probedStart === null) return true;\n\treturn probedStart === claim.startTime;\n};\n\nconst liveContainerClaims = (doc: ContainerClaimDocument): ContainerClaimDocument => ({\n\tversion: 1,\n\tclaims: doc.claims.filter((claim) => isContainerClaimLive(claim)),\n});\n\nconst writeClaims = (\n\tpath: string,\n\tdoc: ContainerClaimDocument,\n): Effect.Effect<void, RosterIoError> =>\n\tEffect.try({\n\t\ttry: () => atomicWriteJsonSync(path, doc),\n\t\tcatch: (cause) => new RosterIoError({ path, cause }),\n\t});\n\n/** Read the container-claim ledger. */\nexport const readClaims = (\n\tpaths: RosterPaths,\n): Effect.Effect<ContainerClaimDocument, RosterError> =>\n\tEffect.gen(function* () {\n\t\tconst path = claimsPath(paths.rosterFile);\n\t\tif (!existsSync(path)) return EMPTY_CLAIMS;\n\t\tconst raw = yield* Effect.try({\n\t\t\ttry: () => readFileSync(path, 'utf8'),\n\t\t\tcatch: (cause) => new RosterIoError({ path, cause }),\n\t\t});\n\t\treturn yield* decodeJsonText(ContainerClaimDocumentSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) => new RosterCorruptError({ path, raw, cause: issue.cause ?? issue }),\n\t\t});\n\t}).pipe(Effect.withSpan('cross-process.roster.readClaims'));\n\n/** Prune stale same-host claims. This is the recovery path for an\n * interrupted process that could not run its scope finalizer. */\nexport const pruneStaleClaims = (\n\tpaths: RosterPaths,\n): Effect.Effect<ContainerClaimDocument, RosterError | import('./stack-lock.ts').StackLockError> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tconst path = claimsPath(paths.rosterFile);\n\t\t\tconst current = yield* readClaims(paths).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_CLAIMS)),\n\t\t\t);\n\t\t\tconst next = liveContainerClaims(current);\n\t\t\tif (next.claims.length !== current.claims.length) {\n\t\t\t\tyield* writeClaims(path, next);\n\t\t\t}\n\t\t\treturn next;\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.pruneStaleClaims'));\n\n/** Record that this process now claims `containerKey`. No-op if\n * already claimed by this process. */\nexport const addClaim = (\n\tpaths: RosterPaths,\n\tcontainerKey: string,\n): Effect.Effect<void, RosterError | import('./stack-lock.ts').StackLockError> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tconst path = claimsPath(paths.rosterFile);\n\t\t\tconst current = yield* readClaims(paths).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_CLAIMS)),\n\t\t\t);\n\t\t\tconst live = liveContainerClaims(current);\n\t\t\tconst ownPid = process.pid;\n\t\t\tconst ownStartTime = processStartTime(ownPid) ?? undefined;\n\t\t\tconst ownHost = nodeHostname();\n\t\t\tif (\n\t\t\t\tlive.claims.some(\n\t\t\t\t\t(c) => c.containerKey === containerKey && c.pid === ownPid && c.hostname === ownHost,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tif (live.claims.length !== current.claims.length) yield* writeClaims(path, live);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst next: ContainerClaimDocument = {\n\t\t\t\tversion: 1,\n\t\t\t\tclaims: [\n\t\t\t\t\t...live.claims,\n\t\t\t\t\t{\n\t\t\t\t\t\tcontainerKey,\n\t\t\t\t\t\tpid: ownPid,\n\t\t\t\t\t\t...(ownStartTime === undefined ? {} : { startTime: ownStartTime }),\n\t\t\t\t\t\thostname: ownHost,\n\t\t\t\t\t\tclaimedAt: Date.now(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t};\n\t\t\tyield* writeClaims(path, next);\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.addClaim'));\n\n/** Release this process's claim on `containerKey`. Returns whether\n * the container has zero remaining claims AFTER this release — the\n * \"last-leaver\" signal that authorizes a teardown.\n *\n * Architecture § Cross-process safety protocol: \"when a process\n * releases its last claim and confirms no other process holds the\n * container, it may tear down.\" */\nexport const removeClaim = (\n\tpaths: RosterPaths,\n\tcontainerKey: string,\n): Effect.Effect<\n\t{ readonly lastClaimReleased: boolean },\n\tRosterError | import('./stack-lock.ts').StackLockError\n> =>\n\twithStackLock(\n\t\tpaths,\n\t\tEffect.gen(function* () {\n\t\t\tconst path = claimsPath(paths.rosterFile);\n\t\t\tconst current = yield* readClaims(paths).pipe(\n\t\t\t\tEffect.catchTag('RosterCorruptError', () => Effect.succeed(EMPTY_CLAIMS)),\n\t\t\t);\n\t\t\tconst live = liveContainerClaims(current);\n\t\t\tconst ownPid = process.pid;\n\t\t\tconst ownHost = nodeHostname();\n\t\t\tconst remaining = live.claims.filter(\n\t\t\t\t(c) => !(c.containerKey === containerKey && c.pid === ownPid && c.hostname === ownHost),\n\t\t\t);\n\t\t\tconst stillClaimedByPeer = remaining.some((c) => c.containerKey === containerKey);\n\t\t\tconst next: ContainerClaimDocument = { version: 1, claims: remaining };\n\t\t\tyield* writeClaims(path, next);\n\t\t\treturn { lastClaimReleased: !stillClaimedByPeer };\n\t\t}),\n\t).pipe(Effect.withSpan('cross-process.roster.removeClaim'));\n"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ import { Effect, Scope } from "effect";
@@ -0,0 +1,117 @@
1
+ import { SnapshotReservationSchema } from "../../cross-process.mjs";
2
+ import { checkHolderLiveness } from "./liveness.mjs";
3
+ import { decodeJsonTextSync } from "../runtime-decode.mjs";
4
+ import { Data, Effect } from "effect";
5
+ import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
6
+ //#region src/substrate/runtime/cross-process/snapshot-reservation.ts
7
+ var SnapshotReservationHeldError = class extends Data.TaggedError("SnapshotReservationHeldError") {};
8
+ var SnapshotReservationIoError = class extends Data.TaggedError("SnapshotReservationIoError") {};
9
+ const parseReservation = (raw) => {
10
+ try {
11
+ return decodeJsonTextSync(SnapshotReservationSchema, raw, {
12
+ source: "snapshot.reservation",
13
+ mkError: (issue) => issue
14
+ });
15
+ } catch {
16
+ return null;
17
+ }
18
+ };
19
+ const ownReservation = (startTime) => ({
20
+ creatorPid: process.pid,
21
+ creatorStartTime: startTime,
22
+ createdAt: Date.now()
23
+ });
24
+ /**
25
+ * Sweep an orphaned reservation. If the file exists AND its creator is
26
+ * dead, unlink it. Returns whether a sweep happened so callers can
27
+ * observe / report.
28
+ *
29
+ * Architecture § Concurrent snapshot last paragraph:
30
+ * "If the snapshotting process crashes mid-snapshot, the reservation
31
+ * file persists. The next process's claim-protocol sweep detects an
32
+ * orphan reservation (the holder whose pid matches the
33
+ * reservation's creator entry is dead) and unlinks it."
34
+ */
35
+ const sweepOrphan = (path) => Effect.gen(function* () {
36
+ yield* Effect.annotateCurrentSpan({ "devstack.snapshot-reservation.path": path });
37
+ if (!existsSync(path)) return { swept: false };
38
+ const reservation = parseReservation(yield* Effect.try({
39
+ try: () => readFileSync(path, "utf8"),
40
+ catch: (cause) => new SnapshotReservationIoError({
41
+ path,
42
+ cause
43
+ })
44
+ }));
45
+ if (reservation === null) {
46
+ yield* Effect.try({
47
+ try: () => unlinkSync(path),
48
+ catch: (cause) => new SnapshotReservationIoError({
49
+ path,
50
+ cause
51
+ })
52
+ });
53
+ return { swept: true };
54
+ }
55
+ if ((yield* checkHolderLiveness({
56
+ pid: reservation.creatorPid,
57
+ startTime: reservation.creatorStartTime,
58
+ hostname: "",
59
+ claimedAt: reservation.createdAt,
60
+ heartbeatAt: reservation.createdAt,
61
+ intent: "snapshot"
62
+ }, "").pipe(Effect.catch(() => Effect.succeed("alive")))) === "alive") return { swept: false };
63
+ yield* Effect.try({
64
+ try: () => unlinkSync(path),
65
+ catch: (cause) => new SnapshotReservationIoError({
66
+ path,
67
+ cause
68
+ })
69
+ });
70
+ return { swept: true };
71
+ }).pipe(Effect.withSpan("cross-process.snapshot-reservation.sweepOrphan"));
72
+ /**
73
+ * Acquire the snapshot reservation as a scoped resource. The
74
+ * reservation is unlinked when the surrounding Scope closes.
75
+ *
76
+ * Architecture § Concurrent snapshot step 1: O_EXCL create, no retry.
77
+ * Callers that fail with `SnapshotReservationHeldError` propagate the
78
+ * structured "snapshot in progress" error to the user — the typical
79
+ * `Effect.catchTag` shape.
80
+ *
81
+ * `startTime` is the same value the roster carries for THIS process so
82
+ * the orphan sweep's pid-startTime check resolves identically.
83
+ */
84
+ const acquireReservation = (path, startTime) => Effect.gen(function* () {
85
+ yield* Effect.annotateCurrentSpan({ "devstack.snapshot-reservation.path": path });
86
+ yield* sweepOrphan(path);
87
+ const body = ownReservation(startTime);
88
+ yield* Effect.try({
89
+ try: () => writeFileSync(path, JSON.stringify(body), { flag: "wx" }),
90
+ catch: (cause) => {
91
+ if (cause.code === "EEXIST") {
92
+ let holder = null;
93
+ try {
94
+ holder = parseReservation(readFileSync(path, "utf8"));
95
+ } catch {}
96
+ return new SnapshotReservationHeldError({
97
+ path,
98
+ holder
99
+ });
100
+ }
101
+ return new SnapshotReservationIoError({
102
+ path,
103
+ cause
104
+ });
105
+ }
106
+ });
107
+ yield* Effect.addFinalizer(() => Effect.sync(() => {
108
+ try {
109
+ unlinkSync(path);
110
+ } catch {}
111
+ }));
112
+ return body;
113
+ }).pipe(Effect.withSpan("cross-process.snapshot-reservation.acquire"));
114
+ //#endregion
115
+ export { acquireReservation };
116
+
117
+ //# sourceMappingURL=snapshot-reservation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-reservation.mjs","names":[],"sources":["../../../../src/substrate/runtime/cross-process/snapshot-reservation.ts"],"sourcesContent":["// `snapshot.reservation` — presence-or-absence semaphore.\n//\n// Architecture § Cross-process safety protocol § Concurrent snapshot:\n// \"Snapshot requires exclusive control of the stack's container set\n// (pause-around-commit means peer processes' ready-probes would fail\n// if uncoordinated). The snapshotting process acquires\n// `snapshot.reservation` via O_EXCL create. If creation fails (peer\n// holds it), the snapshot refuses with a structured 'snapshot in\n// progress by peer pid X' error.\"\n//\n// Discipline:\n// - Acquire is atomic O_EXCL create with a JSON body carrying\n// `{ creatorPid, creatorStartTime, createdAt }`.\n// - Release is `unlink`.\n// - Orphan sweep: on the next claim, if the body's creator pid is\n// dead (PID + start-time check), the reservation is unlinked. This\n// mirrors the roster's stale-PID reclaim.\n// - Acquire DOES NOT retry — snapshot is a one-shot intent; the\n// caller surfaces the structured error to the user immediately.\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\n\nimport { Data, Effect, Scope } from 'effect';\n\nimport { type SnapshotReservation, SnapshotReservationSchema } from '../../cross-process.ts';\nimport { decodeJsonTextSync } from '../runtime-decode.ts';\nimport { checkHolderLiveness } from './liveness.ts';\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\nexport class SnapshotReservationHeldError extends Data.TaggedError('SnapshotReservationHeldError')<{\n\treadonly path: string;\n\treadonly holder: SnapshotReservation | null;\n}> {}\n\nexport class SnapshotReservationIoError extends Data.TaggedError('SnapshotReservationIoError')<{\n\treadonly path: string;\n\treadonly cause: unknown;\n}> {}\n\nexport type SnapshotReservationError = SnapshotReservationHeldError | SnapshotReservationIoError;\n\n// -----------------------------------------------------------------------------\n// Codec\n// -----------------------------------------------------------------------------\n\nconst parseReservation = (raw: string): SnapshotReservation | null => {\n\ttry {\n\t\treturn decodeJsonTextSync(SnapshotReservationSchema, raw, {\n\t\t\tsource: 'snapshot.reservation',\n\t\t\tmkError: (issue) => issue,\n\t\t});\n\t} catch {\n\t\treturn null;\n\t}\n};\n\n// -----------------------------------------------------------------------------\n// Acquire / release\n// -----------------------------------------------------------------------------\n\nconst ownReservation = (startTime: number): SnapshotReservation => ({\n\tcreatorPid: process.pid,\n\tcreatorStartTime: startTime,\n\tcreatedAt: Date.now(),\n});\n\n/**\n * Sweep an orphaned reservation. If the file exists AND its creator is\n * dead, unlink it. Returns whether a sweep happened so callers can\n * observe / report.\n *\n * Architecture § Concurrent snapshot last paragraph:\n * \"If the snapshotting process crashes mid-snapshot, the reservation\n * file persists. The next process's claim-protocol sweep detects an\n * orphan reservation (the holder whose pid matches the\n * reservation's creator entry is dead) and unlinks it.\"\n */\nexport const sweepOrphan = (\n\tpath: string,\n): Effect.Effect<{ readonly swept: boolean }, SnapshotReservationError> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.annotateCurrentSpan({ 'devstack.snapshot-reservation.path': path });\n\t\tif (!existsSync(path)) return { swept: false };\n\t\tconst raw = yield* Effect.try({\n\t\t\ttry: () => readFileSync(path, 'utf8'),\n\t\t\tcatch: (cause) => new SnapshotReservationIoError({ path, cause }),\n\t\t});\n\t\tconst reservation = parseReservation(raw);\n\t\tif (reservation === null) {\n\t\t\t// Malformed body — the creator wrote a half-written file then\n\t\t\t// died. Treat as orphan: unlink it so future acquires don't\n\t\t\t// fail forever.\n\t\t\tyield* Effect.try({\n\t\t\t\ttry: () => unlinkSync(path),\n\t\t\t\tcatch: (cause) => new SnapshotReservationIoError({ path, cause }),\n\t\t\t});\n\t\t\treturn { swept: true };\n\t\t}\n\t\t// PID-liveness check: synthesize a roster-shaped holder so the\n\t\t// shared liveness predicate applies.\n\t\tconst liveness = yield* checkHolderLiveness(\n\t\t\t{\n\t\t\t\tpid: reservation.creatorPid,\n\t\t\t\tstartTime: reservation.creatorStartTime,\n\t\t\t\thostname: '',\n\t\t\t\tclaimedAt: reservation.createdAt,\n\t\t\t\theartbeatAt: reservation.createdAt,\n\t\t\t\tintent: 'snapshot',\n\t\t\t},\n\t\t\t'',\n\t\t).pipe(Effect.catch(() => Effect.succeed('alive' as const)));\n\t\tif (liveness === 'alive') return { swept: false };\n\t\tyield* Effect.try({\n\t\t\ttry: () => unlinkSync(path),\n\t\t\tcatch: (cause) => new SnapshotReservationIoError({ path, cause }),\n\t\t});\n\t\treturn { swept: true };\n\t}).pipe(Effect.withSpan('cross-process.snapshot-reservation.sweepOrphan'));\n\n/**\n * Acquire the snapshot reservation as a scoped resource. The\n * reservation is unlinked when the surrounding Scope closes.\n *\n * Architecture § Concurrent snapshot step 1: O_EXCL create, no retry.\n * Callers that fail with `SnapshotReservationHeldError` propagate the\n * structured \"snapshot in progress\" error to the user — the typical\n * `Effect.catchTag` shape.\n *\n * `startTime` is the same value the roster carries for THIS process so\n * the orphan sweep's pid-startTime check resolves identically.\n */\nexport const acquireReservation = (\n\tpath: string,\n\tstartTime: number,\n): Effect.Effect<SnapshotReservation, SnapshotReservationError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.annotateCurrentSpan({ 'devstack.snapshot-reservation.path': path });\n\t\t// One-shot orphan sweep before our O_EXCL attempt. The sweep is\n\t\t// idempotent: if a peer just wrote the reservation while we ran\n\t\t// the sweep, the O_EXCL create fails below and we surface the\n\t\t// structured \"held\" error.\n\t\tyield* sweepOrphan(path);\n\t\tconst body = ownReservation(startTime);\n\t\tyield* Effect.try({\n\t\t\ttry: () => writeFileSync(path, JSON.stringify(body), { flag: 'wx' }),\n\t\t\tcatch: (cause) => {\n\t\t\t\tconst code = (cause as NodeJS.ErrnoException).code;\n\t\t\t\tif (code === 'EEXIST') {\n\t\t\t\t\tlet holder: SnapshotReservation | null = null;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tholder = parseReservation(readFileSync(path, 'utf8'));\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Body unreadable; leave holder as null.\n\t\t\t\t\t}\n\t\t\t\t\treturn new SnapshotReservationHeldError({ path, holder });\n\t\t\t\t}\n\t\t\t\treturn new SnapshotReservationIoError({ path, cause });\n\t\t\t},\n\t\t});\n\t\t// Finalizer: best-effort unlink on scope close. Architecture §\n\t\t// Concurrent snapshot step 5: \"It unlinks `snapshot.reservation`.\"\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.sync(() => {\n\t\t\t\ttry {\n\t\t\t\t\tunlinkSync(path);\n\t\t\t\t} catch {\n\t\t\t\t\t// Already gone — ok. A peer's sweep may have unlinked our\n\t\t\t\t\t// stale reservation if we somehow lost the process between\n\t\t\t\t\t// acquire and the finalizer fire.\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t\treturn body;\n\t}).pipe(Effect.withSpan('cross-process.snapshot-reservation.acquire'));\n\n/** Inspect (without acquiring) the current reservation. Returns the\n * parsed body or `null` if absent / malformed. Used by the supervisor\n * to decide whether to apply the \"snapshot-in-progress\" tolerance\n * window to ready probes. Architecture § Concurrent snapshot step 3. */\nexport const peekReservation = (\n\tpath: string,\n): Effect.Effect<SnapshotReservation | null, SnapshotReservationError> =>\n\tEffect.gen(function* () {\n\t\tif (!existsSync(path)) return null;\n\t\tconst raw = yield* Effect.try({\n\t\t\ttry: () => readFileSync(path, 'utf8'),\n\t\t\tcatch: (cause) => new SnapshotReservationIoError({ path, cause }),\n\t\t});\n\t\treturn parseReservation(raw);\n\t}).pipe(Effect.withSpan('cross-process.snapshot-reservation.peek'));\n"],"mappings":";;;;;;AAgCA,IAAa,+BAAb,cAAkD,KAAK,YAAY,+BAA+B,CAG/F;AAEH,IAAa,6BAAb,cAAgD,KAAK,YAAY,6BAA6B,CAG3F;AAQH,MAAM,oBAAoB,QAA4C;AACrE,KAAI;AACH,SAAO,mBAAmB,2BAA2B,KAAK;GACzD,QAAQ;GACR,UAAU,UAAU;GACpB,CAAC;SACK;AACP,SAAO;;;AAQT,MAAM,kBAAkB,eAA4C;CACnE,YAAY,QAAQ;CACpB,kBAAkB;CAClB,WAAW,KAAK,KAAK;CACrB;;;;;;;;;;;;AAaD,MAAa,eACZ,SAEA,OAAO,IAAI,aAAa;AACvB,QAAO,OAAO,oBAAoB,EAAE,sCAAsC,MAAM,CAAC;AACjF,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO,EAAE,OAAO,OAAO;CAK9C,MAAM,cAAc,iBAAiB,OAJlB,OAAO,IAAI;EAC7B,WAAW,aAAa,MAAM,OAAO;EACrC,QAAQ,UAAU,IAAI,2BAA2B;GAAE;GAAM;GAAO,CAAC;EACjE,CAAC,CACuC;AACzC,KAAI,gBAAgB,MAAM;AAIzB,SAAO,OAAO,IAAI;GACjB,WAAW,WAAW,KAAK;GAC3B,QAAQ,UAAU,IAAI,2BAA2B;IAAE;IAAM;IAAO,CAAC;GACjE,CAAC;AACF,SAAO,EAAE,OAAO,MAAM;;AAevB,MAAI,OAXoB,oBACvB;EACC,KAAK,YAAY;EACjB,WAAW,YAAY;EACvB,UAAU;EACV,WAAW,YAAY;EACvB,aAAa,YAAY;EACzB,QAAQ;EACR,EACD,GACA,CAAC,KAAK,OAAO,YAAY,OAAO,QAAQ,QAAiB,CAAC,CAAC,MAC3C,QAAS,QAAO,EAAE,OAAO,OAAO;AACjD,QAAO,OAAO,IAAI;EACjB,WAAW,WAAW,KAAK;EAC3B,QAAQ,UAAU,IAAI,2BAA2B;GAAE;GAAM;GAAO,CAAC;EACjE,CAAC;AACF,QAAO,EAAE,OAAO,MAAM;EACrB,CAAC,KAAK,OAAO,SAAS,iDAAiD,CAAC;;;;;;;;;;;;;AAc3E,MAAa,sBACZ,MACA,cAEA,OAAO,IAAI,aAAa;AACvB,QAAO,OAAO,oBAAoB,EAAE,sCAAsC,MAAM,CAAC;AAKjF,QAAO,YAAY,KAAK;CACxB,MAAM,OAAO,eAAe,UAAU;AACtC,QAAO,OAAO,IAAI;EACjB,WAAW,cAAc,MAAM,KAAK,UAAU,KAAK,EAAE,EAAE,MAAM,MAAM,CAAC;EACpE,QAAQ,UAAU;AAEjB,OADc,MAAgC,SACjC,UAAU;IACtB,IAAI,SAAqC;AACzC,QAAI;AACH,cAAS,iBAAiB,aAAa,MAAM,OAAO,CAAC;YAC9C;AAGR,WAAO,IAAI,6BAA6B;KAAE;KAAM;KAAQ,CAAC;;AAE1D,UAAO,IAAI,2BAA2B;IAAE;IAAM;IAAO,CAAC;;EAEvD,CAAC;AAGF,QAAO,OAAO,mBACb,OAAO,WAAW;AACjB,MAAI;AACH,cAAW,KAAK;UACT;GAKP,CACF;AACD,QAAO;EACN,CAAC,KAAK,OAAO,SAAS,6CAA6C,CAAC"}
@@ -0,0 +1 @@
1
+ import { Effect, Scope } from "effect";