@mysten-incubation/devstack 0.1.1 → 0.2.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 (858) hide show
  1. package/README.md +6 -3
  2. package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
  3. package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
  4. package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
  5. package/dashboard-ui/index.html +2 -2
  6. package/dist/api/define-capabilities.d.mts +1 -20
  7. package/dist/api/define-capabilities.mjs +15 -22
  8. package/dist/api/define-capabilities.mjs.map +1 -1
  9. package/dist/api/define-devstack-with.d.mts +7 -1
  10. package/dist/api/define-devstack-with.mjs.map +1 -1
  11. package/dist/api/define-devstack.mjs.map +1 -1
  12. package/dist/api/define-plugin.d.mts +2 -1
  13. package/dist/api/inference-network.d.mts +31 -17
  14. package/dist/api/inference-network.mjs +40 -43
  15. package/dist/api/inference-network.mjs.map +1 -1
  16. package/dist/api/load-config.mjs +88 -0
  17. package/dist/api/load-config.mjs.map +1 -0
  18. package/dist/api/mode-narrowed-factory.d.mts +1 -1
  19. package/dist/api/mode-narrowed-factory.mjs.map +1 -1
  20. package/dist/api/run-stack-internal.mjs +202 -0
  21. package/dist/api/run-stack-internal.mjs.map +1 -0
  22. package/dist/api/run-stack.d.mts +82 -31
  23. package/dist/api/run-stack.mjs +22 -141
  24. package/dist/api/run-stack.mjs.map +1 -1
  25. package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
  26. package/dist/build-integrations/dapp-kit/index.mjs +58 -0
  27. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
  28. package/dist/build-integrations/playwright/config.d.mts +1 -30
  29. package/dist/build-integrations/playwright/config.mjs +1 -27
  30. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  31. package/dist/build-integrations/playwright/errors.d.mts +4 -7
  32. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  33. package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
  34. package/dist/build-integrations/playwright/global-setup.mjs +142 -218
  35. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
  36. package/dist/build-integrations/playwright/index.d.mts +2 -2
  37. package/dist/build-integrations/playwright/index.mjs +2 -2
  38. package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
  39. package/dist/build-integrations/playwright/stack-context.mjs +4 -2
  40. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
  41. package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
  42. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  43. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
  44. package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
  45. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  46. package/dist/build-integrations/runtime/discover.d.mts +6 -4
  47. package/dist/build-integrations/runtime/discover.mjs +15 -4
  48. package/dist/build-integrations/runtime/discover.mjs.map +1 -1
  49. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
  50. package/dist/build-integrations/runtime/errors.mjs.map +1 -1
  51. package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
  52. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
  53. package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
  54. package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
  55. package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
  56. package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
  57. package/dist/build-integrations/vite/index.d.mts +84 -19
  58. package/dist/build-integrations/vite/index.mjs +203 -28
  59. package/dist/build-integrations/vite/index.mjs.map +1 -1
  60. package/dist/build-integrations/vitest/config.d.mts +20 -2
  61. package/dist/build-integrations/vitest/config.mjs +16 -4
  62. package/dist/build-integrations/vitest/config.mjs.map +1 -1
  63. package/dist/build-integrations/vitest/env.d.mts +18 -10
  64. package/dist/build-integrations/vitest/env.mjs +11 -10
  65. package/dist/build-integrations/vitest/env.mjs.map +1 -1
  66. package/dist/build-integrations/vitest/errors.d.mts +7 -11
  67. package/dist/build-integrations/vitest/errors.mjs +3 -4
  68. package/dist/build-integrations/vitest/errors.mjs.map +1 -1
  69. package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
  70. package/dist/build-integrations/vitest/global-setup.mjs +156 -0
  71. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
  72. package/dist/build-integrations/vitest/index.d.mts +3 -2
  73. package/dist/build-integrations/vitest/index.mjs +3 -2
  74. package/dist/build-integrations/vitest/setup.mjs +2 -2
  75. package/dist/build-integrations/vitest/setup.mjs.map +1 -1
  76. package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
  77. package/dist/build-integrations/vitest/stack-context.mjs +3 -2
  78. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
  79. package/dist/cli/bail.mjs.map +1 -1
  80. package/dist/cli/doctor-probes.mjs +1 -3
  81. package/dist/cli/doctor-probes.mjs.map +1 -1
  82. package/dist/cli/main.d.mts +23 -1
  83. package/dist/cli/main.mjs +63 -8
  84. package/dist/cli/main.mjs.map +1 -1
  85. package/dist/cli/prune-direct.mjs.map +1 -1
  86. package/dist/cli/snapshot-reader.mjs.map +1 -1
  87. package/dist/cli/up-lifecycle.mjs.map +1 -1
  88. package/dist/cli/wirings/apply.mjs +28 -21
  89. package/dist/cli/wirings/apply.mjs.map +1 -1
  90. package/dist/cli/wirings/codegen.mjs +108 -0
  91. package/dist/cli/wirings/codegen.mjs.map +1 -0
  92. package/dist/cli/wirings/config-loader.mjs +12 -62
  93. package/dist/cli/wirings/config-loader.mjs.map +1 -1
  94. package/dist/cli/wirings/dump-ids.mjs +86 -0
  95. package/dist/cli/wirings/dump-ids.mjs.map +1 -0
  96. package/dist/cli/wirings/engine-command.mjs +1 -1
  97. package/dist/cli/wirings/engine-command.mjs.map +1 -1
  98. package/dist/cli/wirings/identity.mjs +2 -2
  99. package/dist/cli/wirings/identity.mjs.map +1 -1
  100. package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
  101. package/dist/cli/wirings/read-devstack-version.mjs +17 -0
  102. package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
  103. package/dist/cli/wirings/snapshot.mjs +27 -34
  104. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  105. package/dist/cli/wirings/up-ipc.mjs +147 -0
  106. package/dist/cli/wirings/up-ipc.mjs.map +1 -0
  107. package/dist/cli/wirings/up.mjs +218 -198
  108. package/dist/cli/wirings/up.mjs.map +1 -1
  109. package/dist/cli/wirings/wipe.mjs +1 -1
  110. package/dist/cli/wirings/wipe.mjs.map +1 -1
  111. package/dist/contracts/chain-probe.d.mts +1 -1
  112. package/dist/contracts/chain-probe.mjs +1 -1
  113. package/dist/contracts/chain-probe.mjs.map +1 -1
  114. package/dist/contracts/codegenable.d.mts +60 -6
  115. package/dist/contracts/codegenable.mjs +28 -0
  116. package/dist/contracts/codegenable.mjs.map +1 -0
  117. package/dist/contracts/config-bindings.mjs +162 -0
  118. package/dist/contracts/config-bindings.mjs.map +1 -0
  119. package/dist/contracts/container-runtime.d.mts +23 -17
  120. package/dist/contracts/plugin-expander.mjs.map +1 -1
  121. package/dist/contracts/snapshotable.d.mts +5 -7
  122. package/dist/contracts/wallet-protocol.d.mts +2 -5
  123. package/dist/contracts/wallet-protocol.mjs +2 -5
  124. package/dist/contracts/wallet-protocol.mjs.map +1 -1
  125. package/dist/index.d.mts +21 -26
  126. package/dist/index.mjs +8 -9
  127. package/dist/orchestrators/boot.d.mts +28 -0
  128. package/dist/orchestrators/boot.mjs +440 -0
  129. package/dist/orchestrators/boot.mjs.map +1 -0
  130. package/dist/orchestrators/codegen/bindings.d.mts +13 -1
  131. package/dist/orchestrators/codegen/bindings.mjs +23 -9
  132. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  133. package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
  134. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
  135. package/dist/orchestrators/codegen/emit.mjs +1 -1
  136. package/dist/orchestrators/codegen/emit.mjs.map +1 -1
  137. package/dist/orchestrators/codegen/errors.mjs +21 -1
  138. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  139. package/dist/orchestrators/codegen/format.mjs +2 -0
  140. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  141. package/dist/orchestrators/codegen/gitignore.mjs +30 -11
  142. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
  143. package/dist/orchestrators/codegen/id-config.mjs +107 -0
  144. package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
  145. package/dist/orchestrators/codegen/output-location.mjs +23 -32
  146. package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
  147. package/dist/orchestrators/codegen/paths.mjs +8 -1
  148. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  149. package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
  150. package/dist/orchestrators/codegen/service.mjs +286 -58
  151. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  152. package/dist/orchestrators/layers.mjs +31 -0
  153. package/dist/orchestrators/layers.mjs.map +1 -0
  154. package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
  155. package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
  156. package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
  157. package/dist/orchestrators/network-options.d.mts +52 -0
  158. package/dist/orchestrators/network-options.mjs +43 -0
  159. package/dist/orchestrators/network-options.mjs.map +1 -0
  160. package/dist/orchestrators/router/cleanup.mjs.map +1 -1
  161. package/dist/orchestrators/router/cors.mjs.map +1 -1
  162. package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
  163. package/dist/orchestrators/router/errors.mjs.map +1 -1
  164. package/dist/orchestrators/router/file-provider.mjs.map +1 -1
  165. package/dist/orchestrators/router/hostname.mjs.map +1 -1
  166. package/dist/orchestrators/router/profile.mjs +1 -1
  167. package/dist/orchestrators/router/profile.mjs.map +1 -1
  168. package/dist/orchestrators/router/service.d.mts +2 -2
  169. package/dist/orchestrators/router/service.mjs +12 -27
  170. package/dist/orchestrators/router/service.mjs.map +1 -1
  171. package/dist/orchestrators/router/traefik-container.mjs +1 -1
  172. package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
  173. package/dist/orchestrators/snapshot/capture.mjs +171 -195
  174. package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
  175. package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
  176. package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
  177. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
  178. package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
  179. package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
  180. package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
  181. package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
  182. package/dist/orchestrators/snapshot/index.mjs +1 -4
  183. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
  184. package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
  185. package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
  186. package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
  187. package/dist/orchestrators/snapshot/prune.mjs +40 -31
  188. package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
  189. package/dist/orchestrators/snapshot/restore.mjs +221 -196
  190. package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
  191. package/dist/orchestrators/snapshot/service.mjs +72 -62
  192. package/dist/orchestrators/snapshot/service.mjs.map +1 -1
  193. package/dist/orchestrators/snapshot/wipe.mjs +67 -56
  194. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
  195. package/dist/plugins/account/codegen.mjs +3 -0
  196. package/dist/plugins/account/codegen.mjs.map +1 -1
  197. package/dist/plugins/account/errors.d.mts +2 -2
  198. package/dist/plugins/account/errors.mjs +1 -4
  199. package/dist/plugins/account/errors.mjs.map +1 -1
  200. package/dist/plugins/account/funding.mjs +3 -27
  201. package/dist/plugins/account/funding.mjs.map +1 -1
  202. package/dist/plugins/account/index.d.mts +3 -8
  203. package/dist/plugins/account/index.mjs +71 -35
  204. package/dist/plugins/account/index.mjs.map +1 -1
  205. package/dist/plugins/account/keypair.d.mts +8 -7
  206. package/dist/plugins/account/keypair.mjs +5 -18
  207. package/dist/plugins/account/keypair.mjs.map +1 -1
  208. package/dist/plugins/account/lease.mjs.map +1 -1
  209. package/dist/plugins/account/registry.d.mts +1 -46
  210. package/dist/plugins/account/registry.mjs.map +1 -1
  211. package/dist/plugins/account/service.d.mts +43 -34
  212. package/dist/plugins/account/service.mjs +9 -54
  213. package/dist/plugins/account/service.mjs.map +1 -1
  214. package/dist/plugins/account/snapshot.mjs.map +1 -1
  215. package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
  216. package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
  217. package/dist/plugins/account/variants/signer.mjs.map +1 -1
  218. package/dist/plugins/action/discriminator.mjs.map +1 -1
  219. package/dist/plugins/action/errors.mjs +1 -4
  220. package/dist/plugins/action/errors.mjs.map +1 -1
  221. package/dist/plugins/action/execute.mjs +3 -4
  222. package/dist/plugins/action/execute.mjs.map +1 -1
  223. package/dist/plugins/action/index.d.mts +2 -2
  224. package/dist/plugins/action/index.mjs +7 -11
  225. package/dist/plugins/action/index.mjs.map +1 -1
  226. package/dist/plugins/action/service.d.mts +5 -7
  227. package/dist/plugins/action/service.mjs +2 -16
  228. package/dist/plugins/action/service.mjs.map +1 -1
  229. package/dist/plugins/coin/address-resolution.mjs.map +1 -1
  230. package/dist/plugins/coin/codegen.mjs +97 -16
  231. package/dist/plugins/coin/codegen.mjs.map +1 -1
  232. package/dist/plugins/coin/discovery.mjs.map +1 -1
  233. package/dist/plugins/coin/errors.mjs +1 -4
  234. package/dist/plugins/coin/errors.mjs.map +1 -1
  235. package/dist/plugins/coin/index.d.mts +4 -34
  236. package/dist/plugins/coin/index.mjs +47 -28
  237. package/dist/plugins/coin/index.mjs.map +1 -1
  238. package/dist/plugins/coin/metadata.d.mts +1 -0
  239. package/dist/plugins/coin/metadata.mjs +8 -9
  240. package/dist/plugins/coin/metadata.mjs.map +1 -1
  241. package/dist/plugins/coin/mint.mjs +7 -21
  242. package/dist/plugins/coin/mint.mjs.map +1 -1
  243. package/dist/plugins/coin/registry.mjs +33 -20
  244. package/dist/plugins/coin/registry.mjs.map +1 -1
  245. package/dist/plugins/coin/service.d.mts +1 -1
  246. package/dist/plugins/coin/service.mjs +1 -8
  247. package/dist/plugins/coin/service.mjs.map +1 -1
  248. package/dist/plugins/coin/snapshot.mjs.map +1 -1
  249. package/dist/plugins/coin/type-strings.mjs.map +1 -1
  250. package/dist/plugins/dashboard/domain.mjs +106 -167
  251. package/dist/plugins/dashboard/domain.mjs.map +1 -1
  252. package/dist/plugins/dashboard/index.mjs +13 -13
  253. package/dist/plugins/dashboard/index.mjs.map +1 -1
  254. package/dist/plugins/dashboard/origin-policy.mjs +3 -3
  255. package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
  256. package/dist/plugins/dashboard/routable.mjs.map +1 -1
  257. package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
  258. package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
  259. package/dist/plugins/dashboard/schema/root.mjs +23 -44
  260. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  261. package/dist/plugins/dashboard/schema/types.mjs +37 -91
  262. package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
  263. package/dist/plugins/dashboard/schema.mjs.map +1 -1
  264. package/dist/plugins/dashboard/server.mjs.map +1 -1
  265. package/dist/plugins/deepbook/codegen.d.mts +12 -11
  266. package/dist/plugins/deepbook/codegen.mjs +108 -11
  267. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  268. package/dist/plugins/deepbook/deploy.mjs +7 -14
  269. package/dist/plugins/deepbook/deploy.mjs.map +1 -1
  270. package/dist/plugins/deepbook/errors.mjs +4 -2
  271. package/dist/plugins/deepbook/errors.mjs.map +1 -1
  272. package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
  273. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
  274. package/dist/plugins/deepbook/hash.mjs.map +1 -1
  275. package/dist/plugins/deepbook/index.d.mts +38 -34
  276. package/dist/plugins/deepbook/index.mjs +133 -64
  277. package/dist/plugins/deepbook/index.mjs.map +1 -1
  278. package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
  279. package/dist/plugins/deepbook/pyth/index.mjs +4 -8
  280. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
  281. package/dist/plugins/deepbook/snapshot.mjs +0 -1
  282. package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
  283. package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
  284. package/dist/plugins/deepbook/types.d.mts +2 -1
  285. package/dist/plugins/deepbook/types.mjs.map +1 -1
  286. package/dist/plugins/faucet/dispatcher.d.mts +3 -3
  287. package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
  288. package/dist/plugins/faucet/errors.mjs.map +1 -1
  289. package/dist/plugins/faucet/http.mjs +2 -10
  290. package/dist/plugins/faucet/http.mjs.map +1 -1
  291. package/dist/plugins/faucet/index.mjs +0 -1
  292. package/dist/plugins/faucet/index.mjs.map +1 -1
  293. package/dist/plugins/host-service/errors.d.mts +1 -3
  294. package/dist/plugins/host-service/errors.mjs +1 -2
  295. package/dist/plugins/host-service/errors.mjs.map +1 -1
  296. package/dist/plugins/host-service/index.d.mts +1 -2
  297. package/dist/plugins/host-service/index.mjs +11 -11
  298. package/dist/plugins/host-service/index.mjs.map +1 -1
  299. package/dist/plugins/host-service/routable.mjs.map +1 -1
  300. package/dist/plugins/host-service/service.mjs +13 -13
  301. package/dist/plugins/host-service/service.mjs.map +1 -1
  302. package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
  303. package/dist/plugins/internal/codegen-helpers.mjs +2 -0
  304. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  305. package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
  306. package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
  307. package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
  308. package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
  309. package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
  310. package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
  311. package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
  312. package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
  313. package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
  314. package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
  315. package/dist/plugins/package/build.mjs +2 -2
  316. package/dist/plugins/package/build.mjs.map +1 -1
  317. package/dist/plugins/package/codegen.d.mts +7 -14
  318. package/dist/plugins/package/codegen.mjs +187 -59
  319. package/dist/plugins/package/codegen.mjs.map +1 -1
  320. package/dist/plugins/package/dep-resolution.mjs +51 -3
  321. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  322. package/dist/plugins/package/errors.mjs +1 -4
  323. package/dist/plugins/package/errors.mjs.map +1 -1
  324. package/dist/plugins/package/git-source.d.mts +18 -0
  325. package/dist/plugins/package/git-source.mjs +119 -0
  326. package/dist/plugins/package/git-source.mjs.map +1 -0
  327. package/dist/plugins/package/index.d.mts +28 -19
  328. package/dist/plugins/package/index.mjs +107 -32
  329. package/dist/plugins/package/index.mjs.map +1 -1
  330. package/dist/plugins/package/mode-known.mjs +2 -2
  331. package/dist/plugins/package/mode-known.mjs.map +1 -1
  332. package/dist/plugins/package/mode-local.mjs +18 -35
  333. package/dist/plugins/package/mode-local.mjs.map +1 -1
  334. package/dist/plugins/package/publish-executor.mjs +13 -8
  335. package/dist/plugins/package/publish-executor.mjs.map +1 -1
  336. package/dist/plugins/package/publish-output.d.mts +1 -11
  337. package/dist/plugins/package/publish-output.mjs +1 -9
  338. package/dist/plugins/package/publish-output.mjs.map +1 -1
  339. package/dist/plugins/package/registry.d.mts +1 -1
  340. package/dist/plugins/package/registry.mjs +26 -14
  341. package/dist/plugins/package/registry.mjs.map +1 -1
  342. package/dist/plugins/package/service.mjs.map +1 -1
  343. package/dist/plugins/package/snapshot.mjs.map +1 -1
  344. package/dist/plugins/router-entrypoints.mjs +1 -3
  345. package/dist/plugins/router-entrypoints.mjs.map +1 -1
  346. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
  347. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
  348. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
  349. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
  350. package/dist/plugins/seal/codegen.d.mts +1 -5
  351. package/dist/plugins/seal/codegen.mjs +83 -12
  352. package/dist/plugins/seal/codegen.mjs.map +1 -1
  353. package/dist/plugins/seal/config-render.mjs +2 -6
  354. package/dist/plugins/seal/config-render.mjs.map +1 -1
  355. package/dist/plugins/seal/deploy.mjs +18 -29
  356. package/dist/plugins/seal/deploy.mjs.map +1 -1
  357. package/dist/plugins/seal/errors.d.mts +4 -5
  358. package/dist/plugins/seal/errors.mjs +1 -8
  359. package/dist/plugins/seal/errors.mjs.map +1 -1
  360. package/dist/plugins/seal/index.d.mts +7 -28
  361. package/dist/plugins/seal/index.mjs +69 -47
  362. package/dist/plugins/seal/index.mjs.map +1 -1
  363. package/dist/plugins/seal/key-manager.mjs.map +1 -1
  364. package/dist/plugins/seal/key-server.mjs +1 -6
  365. package/dist/plugins/seal/key-server.mjs.map +1 -1
  366. package/dist/plugins/seal/keygen.mjs +2 -3
  367. package/dist/plugins/seal/keygen.mjs.map +1 -1
  368. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  369. package/dist/plugins/seal/mode/live.mjs +1 -1
  370. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  371. package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
  372. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  373. package/dist/plugins/seal/plugin-key.mjs.map +1 -1
  374. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  375. package/dist/plugins/seal/routable.mjs.map +1 -1
  376. package/dist/plugins/seal/service.mjs.map +1 -1
  377. package/dist/plugins/seal/snapshot.mjs +1 -2
  378. package/dist/plugins/seal/snapshot.mjs.map +1 -1
  379. package/dist/plugins/sui/auto-tick.mjs +5 -5
  380. package/dist/plugins/sui/auto-tick.mjs.map +1 -1
  381. package/dist/plugins/sui/chain-build-container.mjs +2 -2
  382. package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
  383. package/dist/plugins/sui/chain-probe.mjs +4 -4
  384. package/dist/plugins/sui/chain-probe.mjs.map +1 -1
  385. package/dist/plugins/sui/codegen.d.mts +9 -7
  386. package/dist/plugins/sui/codegen.mjs +49 -46
  387. package/dist/plugins/sui/codegen.mjs.map +1 -1
  388. package/dist/plugins/sui/errors.d.mts +1 -1
  389. package/dist/plugins/sui/errors.mjs +1 -9
  390. package/dist/plugins/sui/errors.mjs.map +1 -1
  391. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
  392. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
  393. package/dist/plugins/sui/exec/index.mjs.map +1 -0
  394. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
  395. package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
  396. package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
  397. package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
  398. package/dist/plugins/sui/fork-orchestration.mjs +13 -23
  399. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
  400. package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
  401. package/dist/plugins/sui/index.d.mts +34 -83
  402. package/dist/plugins/sui/index.mjs +200 -68
  403. package/dist/plugins/sui/index.mjs.map +1 -1
  404. package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
  405. package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
  406. package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
  407. package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
  408. package/dist/plugins/sui/log-attrs.mjs +11 -0
  409. package/dist/plugins/sui/log-attrs.mjs.map +1 -0
  410. package/dist/plugins/sui/mode/external.mjs +4 -12
  411. package/dist/plugins/sui/mode/external.mjs.map +1 -1
  412. package/dist/plugins/sui/mode/fork.mjs +19 -16
  413. package/dist/plugins/sui/mode/fork.mjs.map +1 -1
  414. package/dist/plugins/sui/mode/live.mjs +4 -17
  415. package/dist/plugins/sui/mode/live.mjs.map +1 -1
  416. package/dist/plugins/sui/mode/local.d.mts +1 -0
  417. package/dist/plugins/sui/mode/local.mjs +203 -61
  418. package/dist/plugins/sui/mode/local.mjs.map +1 -1
  419. package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
  420. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
  421. package/dist/plugins/sui/mode/shared.d.mts +6 -7
  422. package/dist/plugins/sui/mode/shared.mjs.map +1 -1
  423. package/dist/plugins/sui/mode/spec.d.mts +23 -6
  424. package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
  425. package/dist/plugins/sui/move/index.mjs.map +1 -0
  426. package/dist/plugins/sui/move-summary-runner.mjs +8 -4
  427. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
  428. package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
  429. package/dist/plugins/sui/network-resolver.d.mts +6 -6
  430. package/dist/plugins/sui/routable.mjs.map +1 -1
  431. package/dist/plugins/sui/service.mjs +10 -6
  432. package/dist/plugins/sui/service.mjs.map +1 -1
  433. package/dist/plugins/sui/snapshot.mjs +10 -5
  434. package/dist/plugins/sui/snapshot.mjs.map +1 -1
  435. package/dist/plugins/wallet/codegen.d.mts +8 -6
  436. package/dist/plugins/wallet/codegen.mjs +4 -10
  437. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  438. package/dist/plugins/wallet/errors.mjs +1 -4
  439. package/dist/plugins/wallet/errors.mjs.map +1 -1
  440. package/dist/plugins/wallet/index.d.mts +3 -6
  441. package/dist/plugins/wallet/index.mjs +16 -21
  442. package/dist/plugins/wallet/index.mjs.map +1 -1
  443. package/dist/plugins/wallet/origin-policy.mjs +3 -3
  444. package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
  445. package/dist/plugins/wallet/pairing.mjs +6 -24
  446. package/dist/plugins/wallet/pairing.mjs.map +1 -1
  447. package/dist/plugins/wallet/protocol.mjs.map +1 -1
  448. package/dist/plugins/wallet/routable.mjs.map +1 -1
  449. package/dist/plugins/wallet/server.mjs +17 -24
  450. package/dist/plugins/wallet/server.mjs.map +1 -1
  451. package/dist/plugins/wallet/service.d.mts +2 -2
  452. package/dist/plugins/wallet/service.mjs +4 -15
  453. package/dist/plugins/wallet/service.mjs.map +1 -1
  454. package/dist/plugins/wallet/snapshot.mjs.map +1 -1
  455. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
  456. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
  457. package/dist/plugins/walrus/codegen.d.mts +2 -13
  458. package/dist/plugins/walrus/codegen.mjs +93 -28
  459. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  460. package/dist/plugins/walrus/deploy-paths.mjs +2 -3
  461. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
  462. package/dist/plugins/walrus/deploy.mjs +26 -19
  463. package/dist/plugins/walrus/deploy.mjs.map +1 -1
  464. package/dist/plugins/walrus/errors.mjs +1 -8
  465. package/dist/plugins/walrus/errors.mjs.map +1 -1
  466. package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
  467. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
  468. package/dist/plugins/walrus/index.d.mts +13 -44
  469. package/dist/plugins/walrus/index.mjs +119 -122
  470. package/dist/plugins/walrus/index.mjs.map +1 -1
  471. package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
  472. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  473. package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
  474. package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
  475. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
  476. package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
  477. package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
  478. package/dist/plugins/walrus/routable.mjs.map +1 -1
  479. package/dist/plugins/walrus/service.mjs.map +1 -1
  480. package/dist/plugins/walrus/snapshot.mjs +3 -3
  481. package/dist/plugins/walrus/snapshot.mjs.map +1 -1
  482. package/dist/plugins/walrus/storage-nodes.mjs +53 -14
  483. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
  484. package/dist/plugins/walrus/wal-swap.mjs +4 -8
  485. package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
  486. package/dist/primitives/artifact-publisher.mjs.map +1 -1
  487. package/dist/primitives/cache.d.mts +1 -1
  488. package/dist/runtime/docker/client.mjs +47 -3
  489. package/dist/runtime/docker/client.mjs.map +1 -1
  490. package/dist/runtime/docker/container.mjs +37 -57
  491. package/dist/runtime/docker/container.mjs.map +1 -1
  492. package/dist/runtime/docker/errors.mjs.map +1 -1
  493. package/dist/runtime/docker/exec.mjs +2 -2
  494. package/dist/runtime/docker/exec.mjs.map +1 -1
  495. package/dist/runtime/docker/image.mjs +10 -11
  496. package/dist/runtime/docker/image.mjs.map +1 -1
  497. package/dist/runtime/docker/index.mjs +0 -1
  498. package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
  499. package/dist/runtime/docker/inventory.mjs +9 -9
  500. package/dist/runtime/docker/inventory.mjs.map +1 -1
  501. package/dist/runtime/docker/labels.mjs +12 -1
  502. package/dist/runtime/docker/labels.mjs.map +1 -1
  503. package/dist/runtime/docker/network.mjs +6 -6
  504. package/dist/runtime/docker/network.mjs.map +1 -1
  505. package/dist/runtime/docker/render-run-args.mjs.map +1 -1
  506. package/dist/runtime/docker/service.mjs +31 -45
  507. package/dist/runtime/docker/service.mjs.map +1 -1
  508. package/dist/runtime/docker/sweep.mjs +14 -64
  509. package/dist/runtime/docker/sweep.mjs.map +1 -1
  510. package/dist/runtime/docker/volume.mjs +1 -1
  511. package/dist/runtime/docker/volume.mjs.map +1 -1
  512. package/dist/runtime/docker/wrap.mjs +14 -2
  513. package/dist/runtime/docker/wrap.mjs.map +1 -1
  514. package/dist/substrate/brand.d.mts +2 -5
  515. package/dist/substrate/brand.mjs +3 -2
  516. package/dist/substrate/brand.mjs.map +1 -1
  517. package/dist/substrate/cross-process.mjs +2 -16
  518. package/dist/substrate/cross-process.mjs.map +1 -1
  519. package/dist/substrate/event-time.mjs +0 -2
  520. package/dist/substrate/event-time.mjs.map +1 -1
  521. package/dist/substrate/events.d.mts +46 -16
  522. package/dist/substrate/identity.d.mts +11 -5
  523. package/dist/substrate/manifest.d.mts +33 -26
  524. package/dist/substrate/manifest.mjs +8 -3
  525. package/dist/substrate/manifest.mjs.map +1 -1
  526. package/dist/substrate/options.d.mts +33 -4
  527. package/dist/substrate/plugin-ctx.d.mts +70 -0
  528. package/dist/substrate/plugin-ctx.mjs +66 -0
  529. package/dist/substrate/plugin-ctx.mjs.map +1 -0
  530. package/dist/substrate/plugin.d.mts +46 -38
  531. package/dist/substrate/plugin.mjs +13 -9
  532. package/dist/substrate/plugin.mjs.map +1 -1
  533. package/dist/substrate/projection.d.mts +1 -1
  534. package/dist/substrate/runtime/atomic-write.mjs +3 -4
  535. package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
  536. package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
  537. package/dist/substrate/runtime/cache/service.mjs +50 -20
  538. package/dist/substrate/runtime/cache/service.mjs.map +1 -1
  539. package/dist/substrate/runtime/config-validation.mjs.map +1 -1
  540. package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
  541. package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
  542. package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
  543. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
  544. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
  545. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
  546. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
  547. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
  548. package/dist/substrate/runtime/cross-process/index.mjs +0 -2
  549. package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
  550. package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
  551. package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
  552. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  553. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
  554. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
  555. package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
  556. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
  557. package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
  558. package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
  559. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
  560. package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
  561. package/dist/substrate/runtime/errors.mjs +1 -13
  562. package/dist/substrate/runtime/errors.mjs.map +1 -1
  563. package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
  564. package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
  565. package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
  566. package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
  567. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
  568. package/dist/substrate/runtime/http-probe.d.mts +1 -3
  569. package/dist/substrate/runtime/http-probe.mjs.map +1 -1
  570. package/dist/substrate/runtime/index.mjs +1 -6
  571. package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
  572. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
  573. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
  574. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
  575. package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
  576. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
  577. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
  578. package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
  579. package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
  580. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
  581. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
  582. package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
  583. package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
  584. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
  585. package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
  586. package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
  587. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
  588. package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
  589. package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
  590. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
  591. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
  592. package/dist/substrate/runtime/managed-container.d.mts +5 -1
  593. package/dist/substrate/runtime/managed-container.mjs +8 -10
  594. package/dist/substrate/runtime/managed-container.mjs.map +1 -1
  595. package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
  596. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  597. package/dist/substrate/runtime/mode-errors.d.mts +1 -2
  598. package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
  599. package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
  600. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
  601. package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
  602. package/dist/substrate/runtime/observability/index.d.mts +1 -1
  603. package/dist/substrate/runtime/observability/index.mjs +4 -6
  604. package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
  605. package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
  606. package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
  607. package/dist/substrate/runtime/observability/logger.mjs +3 -3
  608. package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
  609. package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
  610. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
  611. package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
  612. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
  613. package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
  614. package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
  615. package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
  616. package/dist/substrate/runtime/paths.mjs +27 -9
  617. package/dist/substrate/runtime/paths.mjs.map +1 -1
  618. package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
  619. package/dist/substrate/runtime/port-broker/service.mjs +10 -27
  620. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
  621. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
  622. package/dist/substrate/runtime/probes.d.mts +2 -3
  623. package/dist/substrate/runtime/probes.mjs.map +1 -1
  624. package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
  625. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
  626. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
  627. package/dist/substrate/runtime/projection/update.mjs +87 -11
  628. package/dist/substrate/runtime/projection/update.mjs.map +1 -1
  629. package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
  630. package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
  631. package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
  632. package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
  633. package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
  634. package/dist/substrate/runtime/reconcile/index.mjs +5 -0
  635. package/dist/substrate/runtime/reconcile/label.mjs +41 -0
  636. package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
  637. package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
  638. package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
  639. package/dist/substrate/runtime/retry-policy.d.mts +2 -3
  640. package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
  641. package/dist/substrate/runtime/routed-url.mjs.map +1 -1
  642. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
  643. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
  644. package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
  645. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
  646. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
  647. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
  648. package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
  649. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
  650. package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
  651. package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
  652. package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
  653. package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
  654. package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
  655. package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
  656. package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
  657. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
  658. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
  659. package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
  660. package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
  661. package/dist/substrate/runtime/supervisor/index.mjs +2 -0
  662. package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
  663. package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
  664. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
  665. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
  666. package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
  667. package/dist/substrate/runtime/supervisor/state.mjs +1 -1
  668. package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
  669. package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
  670. package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
  671. package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
  672. package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
  673. package/dist/substrate/runtime/tar/reader.mjs +216 -0
  674. package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
  675. package/dist/substrate/runtime/typed-env.mjs.map +1 -1
  676. package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
  677. package/dist/substrate/versioned-doc-sync.mjs +5 -5
  678. package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
  679. package/dist/surfaces/cli/command-tree.mjs +49 -7
  680. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  681. package/dist/surfaces/cli/commands/config.mjs +1 -1
  682. package/dist/surfaces/cli/commands/config.mjs.map +1 -1
  683. package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
  684. package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
  685. package/dist/surfaces/cli/commands/doctor.mjs +1 -1
  686. package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
  687. package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
  688. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
  689. package/dist/surfaces/cli/commands/prune.mjs +1 -1
  690. package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
  691. package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
  692. package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
  693. package/dist/surfaces/cli/commands/status.mjs +1 -1
  694. package/dist/surfaces/cli/commands/status.mjs.map +1 -1
  695. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
  696. package/dist/surfaces/cli/commands/wipe.mjs +3 -4
  697. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
  698. package/dist/surfaces/cli/envelope.mjs.map +1 -1
  699. package/dist/surfaces/cli/errors.mjs.map +1 -1
  700. package/dist/surfaces/cli/flags.mjs.map +1 -1
  701. package/dist/surfaces/cli/index.mjs +45 -14
  702. package/dist/surfaces/cli/index.mjs.map +1 -1
  703. package/dist/surfaces/cli/output.mjs.map +1 -1
  704. package/dist/surfaces/cli/sysexits.mjs.map +1 -1
  705. package/dist/surfaces/tui/app.mjs +0 -21
  706. package/dist/surfaces/tui/app.mjs.map +1 -1
  707. package/dist/surfaces/tui/dashboard.mjs +0 -48
  708. package/dist/surfaces/tui/dashboard.mjs.map +1 -1
  709. package/dist/surfaces/tui/display-derivation.mjs +80 -16
  710. package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
  711. package/dist/surfaces/tui/errors.mjs.map +1 -1
  712. package/dist/surfaces/tui/event-log.mjs +0 -9
  713. package/dist/surfaces/tui/event-log.mjs.map +1 -1
  714. package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
  715. package/dist/surfaces/tui/index.mjs +2 -2
  716. package/dist/surfaces/tui/index.mjs.map +1 -1
  717. package/dist/surfaces/tui/input.mjs.map +1 -1
  718. package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
  719. package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
  720. package/dist/surfaces/tui/plain-renderer.mjs +26 -19
  721. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  722. package/dist/surfaces/tui/resource-table.mjs +8 -10
  723. package/dist/surfaces/tui/resource-table.mjs.map +1 -1
  724. package/images/postgres/Dockerfile +0 -1
  725. package/images/sui/Dockerfile +27 -54
  726. package/images/sui/entrypoint.sh +17 -179
  727. package/package.json +23 -15
  728. package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
  729. package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
  730. package/dashboard-ui/assets/index-Deml9drg.css +0 -1
  731. package/dist/api/plugin-errors.d.mts +0 -7
  732. package/dist/api/plugin-errors.mjs +0 -10
  733. package/dist/api/plugin-errors.mjs.map +0 -1
  734. package/dist/cli/wirings/build-verb-layers.mjs +0 -42
  735. package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
  736. package/dist/contracts/capability-decl.d.mts +0 -40
  737. package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
  738. package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
  739. package/dist/orchestrators/run.mjs +0 -91
  740. package/dist/orchestrators/run.mjs.map +0 -1
  741. package/dist/orchestrators/runtime-composition.d.mts +0 -10
  742. package/dist/orchestrators/runtime-composition.mjs +0 -252
  743. package/dist/orchestrators/runtime-composition.mjs.map +0 -1
  744. package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
  745. package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
  746. package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
  747. package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
  748. package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
  749. package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
  750. package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
  751. package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
  752. package/dist/orchestrators/snapshot/state-document.mjs +0 -58
  753. package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
  754. package/dist/plugins/account/spans.mjs +0 -16
  755. package/dist/plugins/account/spans.mjs.map +0 -1
  756. package/dist/plugins/account/variants/env.mjs +0 -24
  757. package/dist/plugins/account/variants/env.mjs.map +0 -1
  758. package/dist/plugins/account/variants/inline.mjs +0 -13
  759. package/dist/plugins/account/variants/inline.mjs.map +0 -1
  760. package/dist/plugins/account/variants/keystore.mjs +0 -91
  761. package/dist/plugins/account/variants/keystore.mjs.map +0 -1
  762. package/dist/plugins/action/spans.mjs +0 -11
  763. package/dist/plugins/action/spans.mjs.map +0 -1
  764. package/dist/plugins/coin/spans.mjs +0 -20
  765. package/dist/plugins/coin/spans.mjs.map +0 -1
  766. package/dist/plugins/deepbook/spans.mjs +0 -18
  767. package/dist/plugins/deepbook/spans.mjs.map +0 -1
  768. package/dist/plugins/faucet/spans.mjs +0 -12
  769. package/dist/plugins/faucet/spans.mjs.map +0 -1
  770. package/dist/plugins/package/spans.mjs +0 -14
  771. package/dist/plugins/package/spans.mjs.map +0 -1
  772. package/dist/plugins/postgres/codegen.mjs +0 -42
  773. package/dist/plugins/postgres/codegen.mjs.map +0 -1
  774. package/dist/plugins/postgres/connection.d.mts +0 -33
  775. package/dist/plugins/postgres/connection.mjs.map +0 -1
  776. package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
  777. package/dist/plugins/postgres/errors.d.mts +0 -60
  778. package/dist/plugins/postgres/errors.mjs +0 -29
  779. package/dist/plugins/postgres/errors.mjs.map +0 -1
  780. package/dist/plugins/postgres/index.d.mts +0 -37
  781. package/dist/plugins/postgres/index.mjs +0 -68
  782. package/dist/plugins/postgres/index.mjs.map +0 -1
  783. package/dist/plugins/postgres/routable.mjs +0 -33
  784. package/dist/plugins/postgres/routable.mjs.map +0 -1
  785. package/dist/plugins/postgres/service.d.mts +0 -50
  786. package/dist/plugins/postgres/service.mjs +0 -179
  787. package/dist/plugins/postgres/service.mjs.map +0 -1
  788. package/dist/plugins/postgres/snapshot.mjs +0 -32
  789. package/dist/plugins/postgres/snapshot.mjs.map +0 -1
  790. package/dist/plugins/postgres/spans.mjs +0 -11
  791. package/dist/plugins/postgres/spans.mjs.map +0 -1
  792. package/dist/plugins/seal/spans.mjs +0 -18
  793. package/dist/plugins/seal/spans.mjs.map +0 -1
  794. package/dist/plugins/sui/spans.mjs +0 -17
  795. package/dist/plugins/sui/spans.mjs.map +0 -1
  796. package/dist/plugins/wallet/spans.mjs +0 -22
  797. package/dist/plugins/wallet/spans.mjs.map +0 -1
  798. package/dist/plugins/walrus/registry-publish.d.mts +0 -24
  799. package/dist/plugins/walrus/spans.mjs +0 -18
  800. package/dist/plugins/walrus/spans.mjs.map +0 -1
  801. package/dist/runtime/docker/logs.d.mts +0 -1
  802. package/dist/runtime/docker/logs.mjs +0 -34
  803. package/dist/runtime/docker/logs.mjs.map +0 -1
  804. package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
  805. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
  806. package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
  807. package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
  808. package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
  809. package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
  810. package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
  811. package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
  812. package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
  813. package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
  814. package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
  815. package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
  816. package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
  817. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
  818. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
  819. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
  820. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
  821. package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
  822. package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
  823. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
  824. package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
  825. package/dist/substrate/runtime/observability/span-store.mjs +0 -110
  826. package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
  827. package/dist/substrate/runtime/observability/spans.d.mts +0 -1
  828. package/dist/substrate/runtime/observability/spans.mjs +0 -87
  829. package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
  830. package/dist/substrate/runtime/projection/index.mjs +0 -4
  831. package/dist/substrate/runtime/projection/persisted.mjs +0 -213
  832. package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
  833. package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
  834. package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
  835. package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
  836. package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
  837. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
  838. package/dist/substrate/runtime/state-store/index.mjs +0 -3
  839. package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
  840. package/dist/substrate/runtime/state-store/schema.mjs +0 -41
  841. package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
  842. package/dist/substrate/runtime/state-store/service.d.mts +0 -1
  843. package/dist/substrate/runtime/state-store/service.mjs +0 -145
  844. package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
  845. package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
  846. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
  847. package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
  848. package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
  849. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
  850. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
  851. package/dist/substrate/state-store.d.mts +0 -1
  852. /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
  853. /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
  854. /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
  855. /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
  856. /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
  857. /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
  858. /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
@@ -1,4 +1,4 @@
1
- import { SpanAttr } from "../../substrate/runtime/observability/spans.mjs";
1
+ import { LogAttr } from "../../substrate/runtime/observability/log-attrs.mjs";
2
2
  import { observeProcessLines, readableToByteStream } from "../../substrate/runtime/observability/process-lines.mjs";
3
3
  import "../../substrate/runtime/observability/index.mjs";
4
4
  import { awaitManagedProcessReady, describeProcessExitStatus, nodeProcessSpawner, onceProcessError, onceProcessExit, terminateManagedProcess } from "../../substrate/runtime/process-supervisor.mjs";
@@ -189,7 +189,7 @@ const terminateChild = (child, timeoutMs, logger, pluginKey, tag) => terminateMa
189
189
  onEscalate: () => logger.log(tag, pluginKey, {
190
190
  level: "warn",
191
191
  message: "host service did not exit after SIGTERM; sending SIGKILL",
192
- fields: { [SpanAttr.event]: "process.shutdown.escalated" }
192
+ fields: { [LogAttr.event]: "process.shutdown.escalated" }
193
193
  })
194
194
  });
195
195
  const httpReady = (url, timeoutMs, intervalMs, exit, processError, error) => awaitManagedProcessReady({
@@ -292,8 +292,8 @@ const startHostProcess = (options, ctx, port) => Effect.gen(function* () {
292
292
  level: "warn",
293
293
  message: "host service readiness pattern has a nested-quantifier shape that may exhibit catastrophic backtracking on adversarial output; prefer anchored, non-nested patterns",
294
294
  fields: {
295
- [SpanAttr.serviceName]: options.serviceName,
296
- [SpanAttr.event]: "host-service.ready-pattern.redos-warning",
295
+ [LogAttr.serviceName]: options.serviceName,
296
+ [LogAttr.event]: "host-service.ready-pattern.redos-warning",
297
297
  "host-service.ready-pattern.source": options.ready.pattern.source
298
298
  }
299
299
  });
@@ -334,7 +334,7 @@ const startHostProcess = (options, ctx, port) => Effect.gen(function* () {
334
334
  logger: ctx.logger,
335
335
  pluginKey: ctx.pluginKey,
336
336
  tag,
337
- fields: { [SpanAttr.serviceName]: options.serviceName },
337
+ fields: { [LogAttr.serviceName]: options.serviceName },
338
338
  onLine: ({ line, stream }) => Effect.sync(() => {
339
339
  observeReadinessLine(line, stream);
340
340
  })
@@ -393,20 +393,20 @@ const startHostProcess = (options, ctx, port) => Effect.gen(function* () {
393
393
  level: "error",
394
394
  message: "host service exited after readiness",
395
395
  fields: {
396
- [SpanAttr.event]: "process.exited",
397
- [SpanAttr.serviceName]: options.serviceName,
398
- [SpanAttr.exitCode]: status.code,
399
- [SpanAttr.exitSignal]: status.signal,
400
- [SpanAttr.exitStatus]: describeProcessExitStatus(status)
396
+ [LogAttr.event]: "process.exited",
397
+ [LogAttr.serviceName]: options.serviceName,
398
+ [LogAttr.exitCode]: status.code,
399
+ [LogAttr.exitSignal]: status.signal,
400
+ [LogAttr.exitStatus]: describeProcessExitStatus(status)
401
401
  }
402
402
  }))));
403
403
  yield* Effect.forkScoped(Effect.promise(() => processError).pipe(Effect.flatMap((cause) => shuttingDown ? Effect.void : ctx.logger.log(tag, ctx.pluginKey, {
404
404
  level: "error",
405
405
  message: "host service process emitted an error after readiness",
406
406
  fields: {
407
- [SpanAttr.event]: "process.error",
408
- [SpanAttr.serviceName]: options.serviceName,
409
- [SpanAttr.errorCause]: cause
407
+ [LogAttr.event]: "process.error",
408
+ [LogAttr.serviceName]: options.serviceName,
409
+ [LogAttr.errorCause]: cause
410
410
  }
411
411
  }))));
412
412
  });
@@ -1 +1 @@
1
- {"version":3,"file":"service.mjs","names":[],"sources":["../../../src/plugins/host-service/service.ts"],"sourcesContent":["import { resolve } from 'node:path';\n\nimport { Effect, Exit, Ref } from 'effect';\nimport type { Scope } from 'effect';\n\nimport type { PluginKey } from '../../substrate/brand.ts';\nimport type { AnyResourceRef } from '../../api/define-plugin.ts';\nimport {\n\texpectNonEmptyString,\n\texpectOptionalPositiveInteger,\n} from '../../substrate/runtime/config-validation.ts';\nimport {\n\tobserveProcessLines,\n\treadableToByteStream,\n\tSpanAttr,\n\ttype LoggerShape,\n} from '../../substrate/runtime/observability/index.ts';\nimport { waitForHttpEndpoint } from '../../substrate/runtime/http-probe.ts';\nimport type { PortBrokerError } from '../../substrate/runtime/port-broker/index.ts';\nimport {\n\tawaitManagedProcessReady,\n\tdescribeProcessExitStatus,\n\tnodeProcessSpawner,\n\tonceProcessError,\n\tonceProcessExit,\n\tterminateManagedProcess,\n\ttype ManagedProcessChild,\n\ttype ManagedProcessSpawner,\n\ttype ManagedProcessSpawnOptions,\n} from '../../substrate/runtime/process-supervisor.ts';\n\nimport { HOST_SERVICE_DEFAULT_ENDPOINT_NAME } from './routable.ts';\nimport { hostServiceConfigError, HostServiceAcquireError } from './errors.ts';\n\nexport const HOST_SERVICE_PORT_TOKEN = '{port}' as const;\n\nexport type HostServiceReadyProbe =\n\t| {\n\t\t\treadonly kind: 'http';\n\t\t\treadonly url?: string;\n\t\t\treadonly timeoutMs?: number;\n\t\t\treadonly intervalMs?: number;\n\t }\n\t| {\n\t\t\treadonly kind: 'log';\n\t\t\t/** Pattern matched against each stdout/stderr line. `string` is a\n\t\t\t * fast substring match. `RegExp` is evaluated via `.test(line)`\n\t\t\t * per line and runs synchronously on the observer fiber —\n\t\t\t * AVOID catastrophic-backtracking shapes like `(a+)+b` or\n\t\t\t * `(a|a)*c` which can wedge the fiber on adversarial output.\n\t\t\t * Prefer anchored, non-nested-quantifier patterns. The\n\t\t\t * plugin emits a one-time warning at registration if it\n\t\t\t * detects nested-quantifier shapes. */\n\t\t\treadonly pattern: string | RegExp;\n\t\t\treadonly stream?: 'stdout' | 'stderr' | 'both';\n\t\t\treadonly timeoutMs?: number;\n\t };\n\ninterface HostServiceBaseOptions<After extends ReadonlyArray<AnyResourceRef>> {\n\treadonly name?: string;\n\treadonly endpointName?: string;\n\treadonly after?: After;\n\treadonly cwd?: string;\n\treadonly port?: number;\n\treadonly env?: Readonly<Record<string, string>>;\n\treadonly ready?: HostServiceReadyProbe;\n\treadonly shutdownGraceMs?: number;\n}\n\ninterface HostServiceCommandOptions<\n\tAfter extends ReadonlyArray<AnyResourceRef>,\n> extends HostServiceBaseOptions<After> {\n\treadonly command: string;\n\treadonly args?: ReadonlyArray<string>;\n\treadonly script?: never;\n}\n\ninterface HostServiceScriptOptions<\n\tAfter extends ReadonlyArray<AnyResourceRef>,\n> extends HostServiceBaseOptions<After> {\n\treadonly script: string;\n\treadonly command?: never;\n\treadonly args?: never;\n}\n\nexport type HostServiceOptions<\n\tAfter extends ReadonlyArray<AnyResourceRef> = ReadonlyArray<AnyResourceRef>,\n> = HostServiceCommandOptions<After> | HostServiceScriptOptions<After>;\n\nexport interface HostServiceResolvedOptions {\n\treadonly serviceName: string;\n\treadonly endpointName: string;\n\treadonly command: string;\n\treadonly args: ReadonlyArray<string>;\n\treadonly cwd: string;\n\treadonly preferredPort?: number;\n\treadonly env: Readonly<Record<string, string>>;\n\treadonly ready?: HostServiceReadyProbe;\n\treadonly shutdownGraceMs: number;\n}\n\nexport interface HostServiceValue {\n\treadonly name: string;\n\treadonly endpointName: string;\n\treadonly command: string;\n\treadonly args: ReadonlyArray<string>;\n\treadonly cwd: string;\n\t/** The real loopback port the child (Vite) binds. Always the bound\n\t * port, regardless of how `url` is shaped — readiness probes and\n\t * direct host tooling read this. */\n\treadonly port: number;\n\t/** Canonical URL for this service: the router-fronted routed origin\n\t * (`http://<endpoint>.<stack?>.<app>.localhost:5175`) when the\n\t * supervisor derived one, the raw `http://127.0.0.1:<port>` loopback\n\t * bind otherwise. The routed form is what the dev-wallet CORS\n\t * allowlist accepts, so any consumer that hands this URL to a browser\n\t * — `devstack up` output, an app or build integration holding the\n\t * resolved `HostServiceValue` — gets a working wallet pairing.\n\t * Consumers that need the bind target read `port`. Mirrors\n\t * `WalletValue.url` (\"router-fronted when available, loopback\n\t * otherwise\"). */\n\treadonly url: string;\n}\n\nexport interface PreparedHostService {\n\treadonly value: HostServiceValue;\n\treadonly start: Effect.Effect<void, HostServiceAcquireError, Scope.Scope>;\n}\n\nexport type HostProcessChild = ManagedProcessChild;\nexport type HostProcessSpawnOptions = ManagedProcessSpawnOptions;\nexport type HostProcessSpawner = ManagedProcessSpawner;\n\nexport interface HostServiceAcquireContext {\n\treadonly allocatePort: (\n\t\tpreferredPort: number | undefined,\n\t) => Effect.Effect<number, PortBrokerError, Scope.Scope>;\n\treadonly logger: LoggerShape;\n\treadonly pluginKey: PluginKey;\n\treadonly spawner?: HostProcessSpawner;\n\treadonly processEnv?: NodeJS.ProcessEnv;\n\t/**\n\t * Stack identity to publish into the spawned child's environment so\n\t * that in-process build integrations running INSIDE that child (the\n\t * `devstack` Vite plugin in particular) can re-discover the active\n\t * stack's manifest. `--stack` is a CLI flag, not an env var, and the\n\t * supervisor process does not mutate its own `process.env`, so without\n\t * this the child would inherit no `DEVSTACK_STACK` /\n\t * `DEVSTACK_RUNTIME_ROOT` and the Vite plugin's\n\t * `resolveDiscoveryEnv(process.env)` would fall back to the `main`\n\t * stack — aliasing `@generated` at the wrong stack's codegen output.\n\t *\n\t * `stack` is the effective stack name (`Identity.stack`); `runtimeRoot`\n\t * is the absolute on-disk runtime root (`RuntimeRoot.root`). The two\n\t * map directly onto the `<runtimeRoot>/stacks/<stack>/manifest.json`\n\t * path the supervisor writes and `discoverManifestPath` reads. Optional\n\t * so non-supervised callers (and tests) can omit them.\n\t */\n\treadonly discoveryIdentity?: {\n\t\treadonly stack: string;\n\t\treadonly runtimeRoot: string;\n\t};\n\t/**\n\t * Canonical router-fronted URL for this host-service's endpoint, e.g.\n\t * `http://dev.<stack>.<app>.localhost:5175`. When supplied it becomes\n\t * the published `HostServiceValue.url` so every consumer that reads\n\t * \"the host-service's URL\" (`devstack up` output, an app / build\n\t * integration holding the resolved value) is pointed at the URL that\n\t * actually works end-to-end — in particular the one whose Origin the\n\t * dev-wallet CORS allowlist accepts. The raw `http://127.0.0.1:<port>` loopback\n\t * bind is kept INTERNAL (Vite's listen + the readiness probe, which\n\t * derives its own loopback literal) and remains the fallback here when\n\t * no routed URL is available (router disabled, or a hostname-validation\n\t * failure in the caller's best-effort derivation). Optional + nullable\n\t * so non-supervised callers and tests fall back to loopback exactly as\n\t * before.\n\t *\n\t * Mirrors the wallet's own `WalletValue.url` rule (\"router-fronted URL\n\t * when available, loopback otherwise\") and the ARCHITECTURE.md\n\t * \"Host-service = endpoint-defaults bus\" intent that the ROUTED origin\n\t * is canonical.\n\t */\n\treadonly routedUrl?: string | null;\n}\n\nconst DEFAULT_SHUTDOWN_GRACE_MS = 5_000;\nconst DEFAULT_HTTP_READY_TIMEOUT_MS = 60_000;\nconst DEFAULT_HTTP_READY_INTERVAL_MS = 250;\nconst DEFAULT_LOG_READY_TIMEOUT_MS = 60_000;\nconst READY_STREAM_VALUES = ['stdout', 'stderr', 'both'] as const;\n\nconst shellInvocationFor = (script: string): { command: string; args: ReadonlyArray<string> } => {\n\tif (process.platform === 'win32') {\n\t\treturn {\n\t\t\tcommand: process.env.ComSpec ?? process.env.COMSPEC ?? 'cmd.exe',\n\t\t\targs: ['/d', '/s', '/c', script],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: '/bin/sh',\n\t\targs: ['-c', script],\n\t};\n};\n\nconst configErrorFor =\n\t(serviceName: string) => (issue: Parameters<typeof hostServiceConfigError>[1]) =>\n\t\thostServiceConfigError(serviceName, issue);\n\nconst normalizeReadyProbe = (\n\tserviceName: string,\n\tready: HostServiceReadyProbe | undefined,\n): HostServiceReadyProbe | undefined => {\n\tif (ready === undefined) return undefined;\n\tconst mkError = configErrorFor(serviceName);\n\tif (ready.kind === 'http') {\n\t\tif (ready.url !== undefined) {\n\t\t\texpectNonEmptyString(ready.url, { field: 'ready.url', mkError });\n\t\t}\n\t\texpectOptionalPositiveInteger(ready.timeoutMs, { field: 'ready.timeoutMs', mkError });\n\t\texpectOptionalPositiveInteger(ready.intervalMs, { field: 'ready.intervalMs', mkError });\n\t\treturn ready;\n\t}\n\tif (ready.kind === 'log') {\n\t\tif (typeof ready.pattern !== 'string' && !(ready.pattern instanceof RegExp)) {\n\t\t\tthrow mkError({ field: 'ready.pattern', message: 'must be a string or RegExp' });\n\t\t}\n\t\tif (ready.stream !== undefined && !READY_STREAM_VALUES.includes(ready.stream)) {\n\t\t\tthrow mkError({\n\t\t\t\tfield: 'ready.stream',\n\t\t\t\tmessage: \"must be one of 'stdout', 'stderr', 'both'\",\n\t\t\t});\n\t\t}\n\t\texpectOptionalPositiveInteger(ready.timeoutMs, { field: 'ready.timeoutMs', mkError });\n\t\treturn ready;\n\t}\n\tthrow mkError({ field: 'ready.kind', message: \"must be 'http' or 'log'\" });\n};\n\nexport const normalizeHostServiceOptions = (\n\toptions: HostServiceOptions,\n): HostServiceResolvedOptions => {\n\tconst endpointName = options.endpointName ?? HOST_SERVICE_DEFAULT_ENDPOINT_NAME;\n\tconst serviceName = options.name ?? endpointName;\n\tconst mkError = configErrorFor(serviceName);\n\texpectNonEmptyString(serviceName, { field: 'name', mkError });\n\texpectNonEmptyString(endpointName, { field: 'endpointName', mkError });\n\n\tconst rawCommand = (options as { readonly command?: unknown }).command;\n\tconst rawArgs = (options as { readonly args?: unknown }).args;\n\tconst rawScript = (options as { readonly script?: unknown }).script;\n\tif (rawCommand !== undefined && rawScript !== undefined) {\n\t\tthrow mkError({ field: 'command', message: 'use either command or script, not both' });\n\t}\n\tif (rawCommand === undefined && rawScript === undefined) {\n\t\tthrow mkError({ field: 'command', message: 'is required unless script is provided' });\n\t}\n\tif (rawScript !== undefined && rawArgs !== undefined) {\n\t\tthrow mkError({ field: 'args', message: 'args are only supported with command' });\n\t}\n\n\tif (\n\t\toptions.port !== undefined &&\n\t\t!(\n\t\t\ttypeof options.port === 'number' &&\n\t\t\tNumber.isInteger(options.port) &&\n\t\t\toptions.port > 0 &&\n\t\t\toptions.port <= 65_535\n\t\t)\n\t) {\n\t\tthrow mkError({ field: 'port', message: 'must be an integer between 1 and 65535' });\n\t}\n\tconst preferredPort = options.port;\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst rawEnv = options.env;\n\tif (rawEnv !== undefined) {\n\t\tif (typeof rawEnv !== 'object' || rawEnv === null || Array.isArray(rawEnv)) {\n\t\t\tthrow mkError({ field: 'env', message: 'must be an object of string values' });\n\t\t}\n\t\tfor (const [key, entry] of Object.entries(rawEnv)) {\n\t\t\tif (key.length === 0) {\n\t\t\t\tthrow mkError({ field: 'env', message: 'environment variable names must be non-empty' });\n\t\t\t}\n\t\t\tif (typeof entry !== 'string') {\n\t\t\t\tthrow mkError({ field: `env.${key}`, message: 'must be a string' });\n\t\t\t}\n\t\t}\n\t}\n\tconst env: Readonly<Record<string, string>> = rawEnv ?? {};\n\tconst shutdownGraceMs =\n\t\texpectOptionalPositiveInteger(options.shutdownGraceMs, {\n\t\t\tfield: 'shutdownGraceMs',\n\t\t\tmkError,\n\t\t}) ?? DEFAULT_SHUTDOWN_GRACE_MS;\n\tconst ready = normalizeReadyProbe(serviceName, options.ready);\n\tconst invocation =\n\t\trawScript !== undefined\n\t\t\t? shellInvocationFor(expectNonEmptyString(rawScript, { field: 'script', mkError }))\n\t\t\t: {\n\t\t\t\t\tcommand: expectNonEmptyString(rawCommand, { field: 'command', mkError }),\n\t\t\t\t\targs: options.args ?? [],\n\t\t\t\t};\n\n\treturn {\n\t\tserviceName,\n\t\tendpointName,\n\t\tcommand: invocation.command,\n\t\targs: invocation.args,\n\t\tcwd,\n\t\t...(preferredPort === undefined ? {} : { preferredPort }),\n\t\tenv,\n\t\t...(ready === undefined ? {} : { ready }),\n\t\tshutdownGraceMs,\n\t};\n};\n\nconst renderPortToken = (value: string, port: number): string =>\n\tvalue.replaceAll(HOST_SERVICE_PORT_TOKEN, String(port));\n\n/** Heuristic: catastrophic-backtracking patterns typically nest a\n * quantifier inside another quantifier (e.g. `(a+)+`, `(a*)*`,\n * `(a|a)*`). This is intentionally conservative — it flags clearly\n * risky shapes without trying to be a real ReDoS analyzer. The\n * guard runs once at host-service start and only emits a warning,\n * not a fail-stop. */\nconst looksRedosProne = (pattern: RegExp): boolean => {\n\tconst source = pattern.source;\n\t// `(...)<quant><quant>` — quantifier directly after a group's quantifier.\n\tif (/\\)[*+?](?:\\{[^}]*\\})?[*+?]/.test(source)) return true;\n\t// `(...<quant>...)<quant>` — quantifier inside a group that itself is quantified.\n\tif (/\\([^()]*[*+?][^()]*\\)[*+?]/.test(source)) return true;\n\t// `(a|a)*` style — alternation with overlapping branches under a quantifier.\n\tif (/\\([^()]*\\|[^()]*\\)[*+]/.test(source)) return true;\n\treturn false;\n};\n\nconst renderCommand = (\n\toptions: HostServiceResolvedOptions,\n\tport: number,\n): {\n\treadonly command: string;\n\treadonly args: ReadonlyArray<string>;\n\treadonly env: NodeJS.ProcessEnv;\n} => {\n\tconst renderedEnv: NodeJS.ProcessEnv = {};\n\tfor (const [key, value] of Object.entries(options.env)) {\n\t\trenderedEnv[key] = renderPortToken(value, port);\n\t}\n\treturn {\n\t\tcommand: renderPortToken(options.command, port),\n\t\targs: options.args.map((arg) => renderPortToken(arg, port)),\n\t\tenv: renderedEnv,\n\t};\n};\n\nconst hostServiceValue = (\n\toptions: HostServiceResolvedOptions,\n\tport: number,\n\trendered: { readonly command: string; readonly args: ReadonlyArray<string> },\n\troutedUrl: string | null,\n): HostServiceValue => ({\n\tname: options.serviceName,\n\tendpointName: options.endpointName,\n\tcommand: rendered.command,\n\targs: rendered.args,\n\tcwd: options.cwd,\n\tport,\n\t// Canonical routed URL when the supervisor derived one, raw loopback\n\t// otherwise. `port` above always stays the real bound loopback port —\n\t// callers that need the bind target (readiness, direct host tooling)\n\t// read `.port`, not `.url`.\n\turl: routedUrl ?? `http://127.0.0.1:${port}`,\n});\n\nconst terminateChild = (\n\tchild: HostProcessChild,\n\ttimeoutMs: number,\n\tlogger: LoggerShape,\n\tpluginKey: PluginKey,\n\ttag: string,\n): Effect.Effect<void> =>\n\tterminateManagedProcess(child, {\n\t\tgraceMs: timeoutMs,\n\t\tprocessGroup: true,\n\t\tonEscalate: () =>\n\t\t\tlogger.log(tag, pluginKey, {\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage: 'host service did not exit after SIGTERM; sending SIGKILL',\n\t\t\t\tfields: { [SpanAttr.event]: 'process.shutdown.escalated' },\n\t\t\t}),\n\t});\n\nconst httpReady = (\n\turl: string,\n\ttimeoutMs: number,\n\tintervalMs: number,\n\texit: Promise<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>,\n\tprocessError: Promise<unknown>,\n\terror: HostServiceAcquireError,\n): Effect.Effect<void, HostServiceAcquireError> =>\n\tawaitManagedProcessReady({\n\t\tready: waitForHttpEndpoint({\n\t\t\tendpoint: url,\n\t\t\ttimeoutMs,\n\t\t\tintervalMs,\n\t\t\t// HTTP readiness is a health check: require a 200 from the probed\n\t\t\t// `url` ITSELF. `redirect: 'manual'` means a 3xx is not followed —\n\t\t\t// it reads as `status 0`, so a server that 302s to a 200 login page\n\t\t\t// is NOT counted as ready off the redirect target. Point `url` at an\n\t\t\t// endpoint that returns 200 when the service is up (default: the\n\t\t\t// service root). Anything else — a still-compiling dev server, a\n\t\t\t// 5xx, a redirect — keeps polling until the readiness timeout. Use a\n\t\t\t// `log` probe instead when 200-at-a-URL isn't the right signal.\n\t\t\trequestInit: { redirect: 'manual' },\n\t\t\tvalidate: (response) => response.status === 200,\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t...error,\n\t\t\t\t\t\tphase: 'ready',\n\t\t\t\t\t\tmessage: `host service did not become ready at ${url} within ${timeoutMs}ms`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t\texit,\n\t\tprocessError,\n\t\tonExitBeforeReady: (status) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'exit',\n\t\t\t\tmessage: 'host service exited before readiness',\n\t\t\t\texitCode: status.code,\n\t\t\t\tsignal: status.signal,\n\t\t\t}),\n\t\tonProcessErrorBeforeReady: (cause) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'spawn',\n\t\t\t\tmessage: 'host service process failed before readiness',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nexport const logReady = (\n\tready: Extract<HostServiceReadyProbe, { readonly kind: 'log' }>,\n\treadySignal: Promise<void>,\n\texit: Promise<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>,\n\tprocessError: Promise<unknown>,\n\terror: HostServiceAcquireError,\n): Effect.Effect<void, HostServiceAcquireError> =>\n\tawaitManagedProcessReady({\n\t\tready: Effect.tryPromise({\n\t\t\ttry: () =>\n\t\t\t\tnew Promise<void>((resolveReady, rejectReady) => {\n\t\t\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t\t\trejectReady(\n\t\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\t\t...error,\n\t\t\t\t\t\t\t\tphase: 'ready',\n\t\t\t\t\t\t\t\tmessage: `host service did not emit readiness log within ${ready.timeoutMs ?? DEFAULT_LOG_READY_TIMEOUT_MS}ms`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}, ready.timeoutMs ?? DEFAULT_LOG_READY_TIMEOUT_MS);\n\t\t\t\t\treadySignal.then(\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\tresolveReady();\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// Thread a rejecting readiness signal through as the\n\t\t\t\t\t\t// inner-Promise rejection (a non-tagged cause). Without\n\t\t\t\t\t\t// this `onRejected` handler a rejected signal would be an\n\t\t\t\t\t\t// unhandled rejection and the `catch:` arm below could\n\t\t\t\t\t\t// never see it. The `catch` arm preserves this raw cause\n\t\t\t\t\t\t// on `HostServiceAcquireError.cause`.\n\t\t\t\t\t\t(cause: unknown) => {\n\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\trejectReady(cause);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\tcatch: (cause) =>\n\t\t\t\tcause instanceof HostServiceAcquireError\n\t\t\t\t\t? cause\n\t\t\t\t\t: new HostServiceAcquireError({\n\t\t\t\t\t\t\tserviceName: error.serviceName,\n\t\t\t\t\t\t\tcwd: error.cwd,\n\t\t\t\t\t\t\tcommand: error.command,\n\t\t\t\t\t\t\targs: error.args,\n\t\t\t\t\t\t\tphase: error.phase,\n\t\t\t\t\t\t\tmessage: error.message,\n\t\t\t\t\t\t\texitCode: error.exitCode,\n\t\t\t\t\t\t\tsignal: error.signal,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t}),\n\t\texit,\n\t\tprocessError,\n\t\tonExitBeforeReady: (status) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'exit',\n\t\t\t\tmessage: 'host service exited before readiness',\n\t\t\t\texitCode: status.code,\n\t\t\t\tsignal: status.signal,\n\t\t\t}),\n\t\tonProcessErrorBeforeReady: (cause) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'spawn',\n\t\t\t\tmessage: 'host service process failed before readiness',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nconst allocateHostPort = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n): Effect.Effect<number, HostServiceAcquireError, Scope.Scope> =>\n\tctx.allocatePort(options.preferredPort).pipe(\n\t\tEffect.mapError(\n\t\t\t(cause) =>\n\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\tserviceName: options.serviceName,\n\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\tcommand: options.command,\n\t\t\t\t\targs: options.args,\n\t\t\t\t\tphase: 'allocate-port',\n\t\t\t\t\tmessage: 'host service failed to allocate HTTP port',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t),\n\t);\n\nconst startHostProcess = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n\tport: number,\n): Effect.Effect<void, HostServiceAcquireError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst rendered = renderCommand(options, port);\n\t\t// Per-stack discovery identity for in-child build integrations\n\t\t// (the `devstack` Vite plugin). These are a LOW-precedence base\n\t\t// layer: the inherited process env and the user's explicit\n\t\t// `options.env` both spread on top, so a user-set\n\t\t// `DEVSTACK_STACK` / `DEVSTACK_RUNTIME_ROOT` always wins. The\n\t\t// literal var names + the `RUNTIME_ROOT`-over-`STATE_DIR`\n\t\t// preference mirror `resolveDiscoveryEnv` (the plugin's reader);\n\t\t// `runtimeRoot` is absolute, so `discoverManifestPath` resolves\n\t\t// `<runtimeRoot>/stacks/<stack>/manifest.json` directly — exactly\n\t\t// where the supervisor writes the manifest.\n\t\tconst discoveryEnv: NodeJS.ProcessEnv =\n\t\t\tctx.discoveryIdentity === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tDEVSTACK_STACK: ctx.discoveryIdentity.stack,\n\t\t\t\t\t\tDEVSTACK_RUNTIME_ROOT: ctx.discoveryIdentity.runtimeRoot,\n\t\t\t\t\t};\n\t\tconst env: NodeJS.ProcessEnv = {\n\t\t\t...discoveryEnv,\n\t\t\t...(ctx.processEnv ?? process.env),\n\t\t\t...rendered.env,\n\t\t\tPORT: String(port),\n\t\t};\n\t\tconst tag = `host-service/${options.serviceName}`;\n\t\t// One-time ReDoS-shape warning. The log observer runs `RegExp.test`\n\t\t// synchronously per stdout/stderr line; a catastrophic-backtracking\n\t\t// pattern would wedge the observer fiber on adversarial output.\n\t\tif (\n\t\t\toptions.ready?.kind === 'log' &&\n\t\t\toptions.ready.pattern instanceof RegExp &&\n\t\t\tlooksRedosProne(options.ready.pattern)\n\t\t) {\n\t\t\tyield* ctx.logger.log(tag, ctx.pluginKey, {\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage:\n\t\t\t\t\t'host service readiness pattern has a nested-quantifier shape that may exhibit catastrophic backtracking on adversarial output; prefer anchored, non-nested patterns',\n\t\t\t\tfields: {\n\t\t\t\t\t[SpanAttr.serviceName]: options.serviceName,\n\t\t\t\t\t[SpanAttr.event]: 'host-service.ready-pattern.redos-warning',\n\t\t\t\t\t// Namespaced diagnostic field (the offending pattern source),\n\t\t\t\t\t// consistent with the `event` name above. A bare `pattern`\n\t\t\t\t\t// key collides with the generic attribute vocabulary.\n\t\t\t\t\t'host-service.ready-pattern.source': options.ready.pattern.source,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tlet resolveLogReady: (() => void) | undefined;\n\t\tconst logReadySignal =\n\t\t\toptions.ready?.kind === 'log'\n\t\t\t\t? new Promise<void>((resolveReady) => {\n\t\t\t\t\t\tresolveLogReady = resolveReady;\n\t\t\t\t\t})\n\t\t\t\t: null;\n\t\tconst observeReadinessLine = (line: string, stream: 'stdout' | 'stderr'): void => {\n\t\t\tif (options.ready?.kind !== 'log') return;\n\t\t\tif (\n\t\t\t\toptions.ready.stream !== undefined &&\n\t\t\t\toptions.ready.stream !== 'both' &&\n\t\t\t\toptions.ready.stream !== stream\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst matches =\n\t\t\t\ttypeof options.ready.pattern === 'string'\n\t\t\t\t\t? line.includes(options.ready.pattern)\n\t\t\t\t\t: options.ready.pattern.test(line);\n\t\t\tif (matches) resolveLogReady?.();\n\t\t};\n\n\t\tconst spawnChild = ctx.spawner ?? nodeProcessSpawner;\n\t\t// Mutable cells declared before the setup block so the terminator\n\t\t// finalizer below can observe them.\n\t\tlet shuttingDown = false;\n\t\tlet exitStatus: {\n\t\t\treadonly code: number | null;\n\t\t\treadonly signal: NodeJS.Signals | null;\n\t\t} | null = null;\n\t\t// Atomic, deadlock-free process setup.\n\t\t//\n\t\t// Three things happen in one `Effect.uninterruptible` region — spawn,\n\t\t// fork the stdout/stderr line drains (`observeProcessLines`), and\n\t\t// register the kill finalizer — so that:\n\t\t//\n\t\t// 1. No interrupt can land between a successful spawn and the finalizer\n\t\t// registration. That gap was the original leak window: a SIGINT\n\t\t// mid-boot could orphan a detached child still holding its port.\n\t\t//\n\t\t// 2. The terminator finalizer is registered *after* the drain fibers,\n\t\t// so on scope close (LIFO) it runs *before* they are interrupted.\n\t\t// This ordering is load-bearing: the drains read the child's stdout/\n\t\t// stderr via `Stream.fromAsyncIterable`, whose `iterator.next()`\n\t\t// park is NON-interruptible — it only unblocks when the stream ends.\n\t\t// The child's streams end when the child is killed. So the\n\t\t// terminator must run first to kill the child (ending the streams),\n\t\t// which lets the drains drain-to-end and their interrupts complete.\n\t\t// Registering the terminator *before* the drains (e.g. via\n\t\t// `acquireRelease` at the top, or any pre-`observeProcessLines`\n\t\t// finalizer) inverts this and deadlocks scope close: the drain\n\t\t// interrupt can never complete because the terminator that would end\n\t\t// its stream is queued to run after it.\n\t\t//\n\t\t// The post-readiness `exited`/`processError` observers below are\n\t\t// registered later still, so they are interrupted before the terminator\n\t\t// runs — their `Effect.promise` waits are interruptible, so that unwinds\n\t\t// cleanly without needing the child to exit first.\n\t\tconst child = yield* Effect.uninterruptible(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst spawned = yield* Effect.try({\n\t\t\t\t\ttry: () =>\n\t\t\t\t\t\tspawnChild(rendered.command, rendered.args, {\n\t\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t\tenv,\n\t\t\t\t\t\t\tstdio: 'pipe',\n\t\t\t\t\t\t\tdetached: process.platform !== 'win32',\n\t\t\t\t\t\t}),\n\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\tserviceName: options.serviceName,\n\t\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t\tcommand: rendered.command,\n\t\t\t\t\t\t\targs: rendered.args,\n\t\t\t\t\t\t\tphase: 'spawn',\n\t\t\t\t\t\t\tmessage: 'host service spawn failed',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tyield* observeProcessLines(\n\t\t\t\t\t{\n\t\t\t\t\t\tstdout: readableToByteStream(\n\t\t\t\t\t\t\tspawned.stdout as unknown as AsyncIterable<Uint8Array> | null | undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tstderr: readableToByteStream(\n\t\t\t\t\t\t\tspawned.stderr as unknown as AsyncIterable<Uint8Array> | null | undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlogger: ctx.logger,\n\t\t\t\t\t\tpluginKey: ctx.pluginKey,\n\t\t\t\t\t\ttag,\n\t\t\t\t\t\tfields: { [SpanAttr.serviceName]: options.serviceName },\n\t\t\t\t\t\tonLine: ({ line, stream }) =>\n\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\tobserveReadinessLine(line, stream);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tyield* Effect.addFinalizer(() =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tshuttingDown = true;\n\t\t\t\t\t\tif (exitStatus !== null) return;\n\t\t\t\t\t\tyield* terminateChild(spawned, options.shutdownGraceMs, ctx.logger, ctx.pluginKey, tag);\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn spawned;\n\t\t\t}),\n\t\t);\n\t\tconst exited = onceProcessExit(child).then((status) => {\n\t\t\texitStatus = status;\n\t\t\treturn status;\n\t\t});\n\t\tconst processError = onceProcessError(child);\n\n\t\tconst baseError = new HostServiceAcquireError({\n\t\t\tserviceName: options.serviceName,\n\t\t\tcwd: options.cwd,\n\t\t\tcommand: rendered.command,\n\t\t\targs: rendered.args,\n\t\t\tphase: 'ready',\n\t\t\tmessage: 'host service readiness failed',\n\t\t});\n\t\tconst awaitReadiness = (() => {\n\t\t\tif (options.ready?.kind === 'http') {\n\t\t\t\tconst url = renderPortToken(options.ready.url ?? 'http://127.0.0.1:{port}', port);\n\t\t\t\treturn httpReady(\n\t\t\t\t\turl,\n\t\t\t\t\toptions.ready.timeoutMs ?? DEFAULT_HTTP_READY_TIMEOUT_MS,\n\t\t\t\t\toptions.ready.intervalMs ?? DEFAULT_HTTP_READY_INTERVAL_MS,\n\t\t\t\t\texited,\n\t\t\t\t\tprocessError,\n\t\t\t\t\tbaseError,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (options.ready?.kind === 'log' && logReadySignal !== null) {\n\t\t\t\treturn logReady(options.ready, logReadySignal, exited, processError, baseError);\n\t\t\t}\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* awaitManagedProcessReady({\n\t\t\t\t\tready: Effect.promise(\n\t\t\t\t\t\t() => new Promise<void>((resolveReady) => setTimeout(resolveReady, 0)),\n\t\t\t\t\t),\n\t\t\t\t\texit: exited,\n\t\t\t\t\tprocessError,\n\t\t\t\t\tonExitBeforeReady: (status) =>\n\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\t...baseError,\n\t\t\t\t\t\t\tphase: 'exit',\n\t\t\t\t\t\t\tmessage: 'host service exited before readiness',\n\t\t\t\t\t\t\texitCode: status.code,\n\t\t\t\t\t\t\tsignal: status.signal,\n\t\t\t\t\t\t}),\n\t\t\t\t\tonProcessErrorBeforeReady: (cause) =>\n\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\t...baseError,\n\t\t\t\t\t\t\tphase: 'spawn',\n\t\t\t\t\t\t\tmessage: 'host service process failed before readiness',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t});\n\t\t})();\n\t\tconst readinessExit = yield* Effect.exit(awaitReadiness);\n\t\tif (Exit.isFailure(readinessExit)) {\n\t\t\tshuttingDown = true;\n\t\t\tif (exitStatus === null) {\n\t\t\t\tyield* terminateChild(child, options.shutdownGraceMs, ctx.logger, ctx.pluginKey, tag);\n\t\t\t}\n\t\t\treturn yield* Effect.failCause(readinessExit.cause);\n\t\t}\n\n\t\t// Post-readiness observers. These previously used `void\n\t\t// promise.then(() => Effect.runPromise(...))` which could fire\n\t\t// AFTER the surrounding Scope had already closed (running logger\n\t\t// effects outside any scope, with `.catch(() => {})` swallowing\n\t\t// any failures). Fork into the Scope via `Effect.forkScoped` so\n\t\t// that scope-close interrupts the observer fiber cleanly — the\n\t\t// finalizer flips `shuttingDown` first, so expected-exit cases\n\t\t// still no-op as before. These observers are registered after the\n\t\t// terminator finalizer, so on scope close they are interrupted before\n\t\t// it runs; their `Effect.promise` waits are interruptible, so they\n\t\t// unwind cleanly without waiting on the child to exit.\n\t\tyield* Effect.forkScoped(\n\t\t\tEffect.promise(() => exited).pipe(\n\t\t\t\tEffect.flatMap((status) =>\n\t\t\t\t\tshuttingDown\n\t\t\t\t\t\t? Effect.void\n\t\t\t\t\t\t: ctx.logger.log(tag, ctx.pluginKey, {\n\t\t\t\t\t\t\t\tlevel: 'error',\n\t\t\t\t\t\t\t\tmessage: 'host service exited after readiness',\n\t\t\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\t\t\t[SpanAttr.event]: 'process.exited',\n\t\t\t\t\t\t\t\t\t[SpanAttr.serviceName]: options.serviceName,\n\t\t\t\t\t\t\t\t\t[SpanAttr.exitCode]: status.code,\n\t\t\t\t\t\t\t\t\t[SpanAttr.exitSignal]: status.signal,\n\t\t\t\t\t\t\t\t\t[SpanAttr.exitStatus]: describeProcessExitStatus(status),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tyield* Effect.forkScoped(\n\t\t\tEffect.promise(() => processError).pipe(\n\t\t\t\tEffect.flatMap((cause) =>\n\t\t\t\t\tshuttingDown\n\t\t\t\t\t\t? Effect.void\n\t\t\t\t\t\t: ctx.logger.log(tag, ctx.pluginKey, {\n\t\t\t\t\t\t\t\tlevel: 'error',\n\t\t\t\t\t\t\t\tmessage: 'host service process emitted an error after readiness',\n\t\t\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\t\t\t[SpanAttr.event]: 'process.error',\n\t\t\t\t\t\t\t\t\t[SpanAttr.serviceName]: options.serviceName,\n\t\t\t\t\t\t\t\t\t[SpanAttr.errorCause]: cause,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t});\n\nexport const prepareHostService = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n): Effect.Effect<PreparedHostService, HostServiceAcquireError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst port = yield* allocateHostPort(options, ctx);\n\t\tconst rendered = renderCommand(options, port);\n\t\tconst started = yield* Ref.make(false);\n\t\tconst start = Effect.gen(function* () {\n\t\t\tif (yield* Ref.get(started)) return;\n\t\t\tyield* startHostProcess(options, ctx, port);\n\t\t\tyield* Ref.set(started, true);\n\t\t});\n\n\t\treturn {\n\t\t\tvalue: hostServiceValue(options, port, rendered, ctx.routedUrl ?? null),\n\t\t\tstart,\n\t\t};\n\t});\n\nexport const acquireHostService = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n): Effect.Effect<HostServiceValue, HostServiceAcquireError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst prepared = yield* prepareHostService(options, ctx);\n\t\tyield* prepared.start;\n\t\treturn prepared.value;\n\t});\n"],"mappings":"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"}
1
+ {"version":3,"file":"service.mjs","names":[],"sources":["../../../src/plugins/host-service/service.ts"],"sourcesContent":["import { resolve } from 'node:path';\n\nimport { Effect, Exit, Ref } from 'effect';\nimport type { Scope } from 'effect';\n\nimport type { PluginKey } from '../../substrate/brand.ts';\nimport type { AnyResourceRef } from '../../api/define-plugin.ts';\nimport {\n\texpectNonEmptyString,\n\texpectOptionalPositiveInteger,\n} from '../../substrate/runtime/config-validation.ts';\nimport {\n\tobserveProcessLines,\n\treadableToByteStream,\n\tLogAttr,\n\ttype LoggerShape,\n} from '../../substrate/runtime/observability/index.ts';\nimport { waitForHttpEndpoint } from '../../substrate/runtime/http-probe.ts';\nimport type { PortBrokerError } from '../../substrate/runtime/port-broker/index.ts';\nimport {\n\tawaitManagedProcessReady,\n\tdescribeProcessExitStatus,\n\tnodeProcessSpawner,\n\tonceProcessError,\n\tonceProcessExit,\n\tterminateManagedProcess,\n\ttype ManagedProcessChild,\n\ttype ManagedProcessSpawner,\n\ttype ManagedProcessSpawnOptions,\n} from '../../substrate/runtime/process-supervisor.ts';\n\nimport { HOST_SERVICE_DEFAULT_ENDPOINT_NAME } from './routable.ts';\nimport { hostServiceConfigError, HostServiceAcquireError } from './errors.ts';\n\nexport const HOST_SERVICE_PORT_TOKEN = '{port}' as const;\n\nexport type HostServiceReadyProbe =\n\t| {\n\t\t\treadonly kind: 'http';\n\t\t\treadonly url?: string;\n\t\t\treadonly timeoutMs?: number;\n\t\t\treadonly intervalMs?: number;\n\t }\n\t| {\n\t\t\treadonly kind: 'log';\n\t\t\t/** Pattern matched against each stdout/stderr line. `string` is a\n\t\t\t * fast substring match. `RegExp` is evaluated via `.test(line)`\n\t\t\t * per line and runs synchronously on the observer fiber —\n\t\t\t * AVOID catastrophic-backtracking shapes like `(a+)+b` or\n\t\t\t * `(a|a)*c` which can wedge the fiber on adversarial output.\n\t\t\t * Prefer anchored, non-nested-quantifier patterns. The\n\t\t\t * plugin emits a one-time warning at registration if it\n\t\t\t * detects nested-quantifier shapes. */\n\t\t\treadonly pattern: string | RegExp;\n\t\t\treadonly stream?: 'stdout' | 'stderr' | 'both';\n\t\t\treadonly timeoutMs?: number;\n\t };\n\ninterface HostServiceBaseOptions<After extends ReadonlyArray<AnyResourceRef>> {\n\treadonly name?: string;\n\treadonly endpointName?: string;\n\treadonly after?: After;\n\treadonly cwd?: string;\n\treadonly port?: number;\n\treadonly env?: Readonly<Record<string, string>>;\n\treadonly ready?: HostServiceReadyProbe;\n\treadonly shutdownGraceMs?: number;\n}\n\ninterface HostServiceCommandOptions<\n\tAfter extends ReadonlyArray<AnyResourceRef>,\n> extends HostServiceBaseOptions<After> {\n\treadonly command: string;\n\treadonly args?: ReadonlyArray<string>;\n\treadonly script?: never;\n}\n\ninterface HostServiceScriptOptions<\n\tAfter extends ReadonlyArray<AnyResourceRef>,\n> extends HostServiceBaseOptions<After> {\n\treadonly script: string;\n\treadonly command?: never;\n\treadonly args?: never;\n}\n\nexport type HostServiceOptions<\n\tAfter extends ReadonlyArray<AnyResourceRef> = ReadonlyArray<AnyResourceRef>,\n> = HostServiceCommandOptions<After> | HostServiceScriptOptions<After>;\n\nexport interface HostServiceResolvedOptions {\n\treadonly serviceName: string;\n\treadonly endpointName: string;\n\treadonly command: string;\n\treadonly args: ReadonlyArray<string>;\n\treadonly cwd: string;\n\treadonly preferredPort?: number;\n\treadonly env: Readonly<Record<string, string>>;\n\treadonly ready?: HostServiceReadyProbe;\n\treadonly shutdownGraceMs: number;\n}\n\nexport interface HostServiceValue {\n\treadonly name: string;\n\treadonly endpointName: string;\n\treadonly command: string;\n\treadonly args: ReadonlyArray<string>;\n\treadonly cwd: string;\n\t/** The real loopback port the child (Vite) binds. Always the bound\n\t * port, regardless of how `url` is shaped — readiness probes and\n\t * direct host tooling read this. */\n\treadonly port: number;\n\t/** Canonical URL for this service: the router-fronted routed origin\n\t * (`http://<endpoint>.<stack?>.<app>.localhost:5175`) when the\n\t * supervisor derived one, the raw `http://127.0.0.1:<port>` loopback\n\t * bind otherwise. The routed form is what the dev-wallet CORS\n\t * allowlist accepts, so any consumer that hands this URL to a browser\n\t * — `devstack up` output, an app or build integration holding the\n\t * resolved `HostServiceValue` — gets a working wallet pairing.\n\t * Consumers that need the bind target read `port`. Mirrors\n\t * `WalletValue.url` (\"router-fronted when available, loopback\n\t * otherwise\"). */\n\treadonly url: string;\n}\n\nexport interface PreparedHostService {\n\treadonly value: HostServiceValue;\n\treadonly start: Effect.Effect<void, HostServiceAcquireError, Scope.Scope>;\n}\n\nexport type HostProcessChild = ManagedProcessChild;\nexport type HostProcessSpawnOptions = ManagedProcessSpawnOptions;\nexport type HostProcessSpawner = ManagedProcessSpawner;\n\nexport interface HostServiceAcquireContext {\n\treadonly allocatePort: (\n\t\tpreferredPort: number | undefined,\n\t) => Effect.Effect<number, PortBrokerError, Scope.Scope>;\n\treadonly logger: LoggerShape;\n\treadonly pluginKey: PluginKey;\n\treadonly spawner?: HostProcessSpawner;\n\treadonly processEnv?: NodeJS.ProcessEnv;\n\t/**\n\t * Stack identity to publish into the spawned child's environment so\n\t * that in-process build integrations running INSIDE that child (the\n\t * `devstack` Vite plugin in particular) can re-discover the active\n\t * stack's manifest. `--stack` is a CLI flag, not an env var, and the\n\t * supervisor process does not mutate its own `process.env`, so without\n\t * this the child would inherit no `DEVSTACK_STACK` /\n\t * `DEVSTACK_RUNTIME_ROOT` and the Vite plugin's\n\t * `resolveDiscoveryEnv(process.env)` would fall back to the `main`\n\t * stack — aliasing `@generated` at the wrong stack's codegen output.\n\t *\n\t * `stack` is the effective stack name (`Identity.stack`); `runtimeRoot`\n\t * is the absolute on-disk runtime root (`RuntimeRoot.root`). The two\n\t * map directly onto the `<runtimeRoot>/stacks/<stack>/manifest.json`\n\t * path the supervisor writes and `discoverManifestPath` reads. Optional\n\t * so non-supervised callers (and tests) can omit them.\n\t */\n\treadonly discoveryIdentity?: {\n\t\treadonly stack: string;\n\t\treadonly runtimeRoot: string;\n\t};\n\t/**\n\t * Canonical router-fronted URL for this host-service's endpoint, e.g.\n\t * `http://dev.<stack>.<app>.localhost:5175`. When supplied it becomes\n\t * the published `HostServiceValue.url` so every consumer that reads\n\t * \"the host-service's URL\" (`devstack up` output, an app / build\n\t * integration holding the resolved value) is pointed at the URL that\n\t * actually works end-to-end — in particular the one whose Origin the\n\t * dev-wallet CORS allowlist accepts. The raw `http://127.0.0.1:<port>` loopback\n\t * bind is kept INTERNAL (Vite's listen + the readiness probe, which\n\t * derives its own loopback literal) and remains the fallback here when\n\t * no routed URL is available (router disabled, or a hostname-validation\n\t * failure in the caller's best-effort derivation). Optional + nullable\n\t * so non-supervised callers and tests fall back to loopback exactly as\n\t * before.\n\t *\n\t * Mirrors the wallet's own `WalletValue.url` rule (\"router-fronted URL\n\t * when available, loopback otherwise\") and the ARCHITECTURE.md\n\t * \"Host-service = endpoint-defaults bus\" intent that the ROUTED origin\n\t * is canonical.\n\t */\n\treadonly routedUrl?: string | null;\n}\n\nconst DEFAULT_SHUTDOWN_GRACE_MS = 5_000;\nconst DEFAULT_HTTP_READY_TIMEOUT_MS = 60_000;\nconst DEFAULT_HTTP_READY_INTERVAL_MS = 250;\nconst DEFAULT_LOG_READY_TIMEOUT_MS = 60_000;\nconst READY_STREAM_VALUES = ['stdout', 'stderr', 'both'] as const;\n\nconst shellInvocationFor = (script: string): { command: string; args: ReadonlyArray<string> } => {\n\tif (process.platform === 'win32') {\n\t\treturn {\n\t\t\tcommand: process.env.ComSpec ?? process.env.COMSPEC ?? 'cmd.exe',\n\t\t\targs: ['/d', '/s', '/c', script],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: '/bin/sh',\n\t\targs: ['-c', script],\n\t};\n};\n\nconst configErrorFor =\n\t(serviceName: string) => (issue: Parameters<typeof hostServiceConfigError>[1]) =>\n\t\thostServiceConfigError(serviceName, issue);\n\nconst normalizeReadyProbe = (\n\tserviceName: string,\n\tready: HostServiceReadyProbe | undefined,\n): HostServiceReadyProbe | undefined => {\n\tif (ready === undefined) return undefined;\n\tconst mkError = configErrorFor(serviceName);\n\tif (ready.kind === 'http') {\n\t\tif (ready.url !== undefined) {\n\t\t\texpectNonEmptyString(ready.url, { field: 'ready.url', mkError });\n\t\t}\n\t\texpectOptionalPositiveInteger(ready.timeoutMs, { field: 'ready.timeoutMs', mkError });\n\t\texpectOptionalPositiveInteger(ready.intervalMs, { field: 'ready.intervalMs', mkError });\n\t\treturn ready;\n\t}\n\tif (ready.kind === 'log') {\n\t\tif (typeof ready.pattern !== 'string' && !(ready.pattern instanceof RegExp)) {\n\t\t\tthrow mkError({ field: 'ready.pattern', message: 'must be a string or RegExp' });\n\t\t}\n\t\tif (ready.stream !== undefined && !READY_STREAM_VALUES.includes(ready.stream)) {\n\t\t\tthrow mkError({\n\t\t\t\tfield: 'ready.stream',\n\t\t\t\tmessage: \"must be one of 'stdout', 'stderr', 'both'\",\n\t\t\t});\n\t\t}\n\t\texpectOptionalPositiveInteger(ready.timeoutMs, { field: 'ready.timeoutMs', mkError });\n\t\treturn ready;\n\t}\n\tthrow mkError({ field: 'ready.kind', message: \"must be 'http' or 'log'\" });\n};\n\nexport const normalizeHostServiceOptions = (\n\toptions: HostServiceOptions,\n): HostServiceResolvedOptions => {\n\tconst endpointName = options.endpointName ?? HOST_SERVICE_DEFAULT_ENDPOINT_NAME;\n\tconst serviceName = options.name ?? endpointName;\n\tconst mkError = configErrorFor(serviceName);\n\texpectNonEmptyString(serviceName, { field: 'name', mkError });\n\texpectNonEmptyString(endpointName, { field: 'endpointName', mkError });\n\n\tconst rawCommand = (options as { readonly command?: unknown }).command;\n\tconst rawArgs = (options as { readonly args?: unknown }).args;\n\tconst rawScript = (options as { readonly script?: unknown }).script;\n\tif (rawCommand !== undefined && rawScript !== undefined) {\n\t\tthrow mkError({ field: 'command', message: 'use either command or script, not both' });\n\t}\n\tif (rawCommand === undefined && rawScript === undefined) {\n\t\tthrow mkError({ field: 'command', message: 'is required unless script is provided' });\n\t}\n\tif (rawScript !== undefined && rawArgs !== undefined) {\n\t\tthrow mkError({ field: 'args', message: 'args are only supported with command' });\n\t}\n\n\tif (\n\t\toptions.port !== undefined &&\n\t\t!(\n\t\t\ttypeof options.port === 'number' &&\n\t\t\tNumber.isInteger(options.port) &&\n\t\t\toptions.port > 0 &&\n\t\t\toptions.port <= 65_535\n\t\t)\n\t) {\n\t\tthrow mkError({ field: 'port', message: 'must be an integer between 1 and 65535' });\n\t}\n\tconst preferredPort = options.port;\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst rawEnv = options.env;\n\tif (rawEnv !== undefined) {\n\t\tif (typeof rawEnv !== 'object' || rawEnv === null || Array.isArray(rawEnv)) {\n\t\t\tthrow mkError({ field: 'env', message: 'must be an object of string values' });\n\t\t}\n\t\tfor (const [key, entry] of Object.entries(rawEnv)) {\n\t\t\tif (key.length === 0) {\n\t\t\t\tthrow mkError({ field: 'env', message: 'environment variable names must be non-empty' });\n\t\t\t}\n\t\t\tif (typeof entry !== 'string') {\n\t\t\t\tthrow mkError({ field: `env.${key}`, message: 'must be a string' });\n\t\t\t}\n\t\t}\n\t}\n\tconst env: Readonly<Record<string, string>> = rawEnv ?? {};\n\tconst shutdownGraceMs =\n\t\texpectOptionalPositiveInteger(options.shutdownGraceMs, {\n\t\t\tfield: 'shutdownGraceMs',\n\t\t\tmkError,\n\t\t}) ?? DEFAULT_SHUTDOWN_GRACE_MS;\n\tconst ready = normalizeReadyProbe(serviceName, options.ready);\n\tconst invocation =\n\t\trawScript !== undefined\n\t\t\t? shellInvocationFor(expectNonEmptyString(rawScript, { field: 'script', mkError }))\n\t\t\t: {\n\t\t\t\t\tcommand: expectNonEmptyString(rawCommand, { field: 'command', mkError }),\n\t\t\t\t\targs: options.args ?? [],\n\t\t\t\t};\n\n\treturn {\n\t\tserviceName,\n\t\tendpointName,\n\t\tcommand: invocation.command,\n\t\targs: invocation.args,\n\t\tcwd,\n\t\t...(preferredPort === undefined ? {} : { preferredPort }),\n\t\tenv,\n\t\t...(ready === undefined ? {} : { ready }),\n\t\tshutdownGraceMs,\n\t};\n};\n\nconst renderPortToken = (value: string, port: number): string =>\n\tvalue.replaceAll(HOST_SERVICE_PORT_TOKEN, String(port));\n\n/** Heuristic: catastrophic-backtracking patterns typically nest a\n * quantifier inside another quantifier (e.g. `(a+)+`, `(a*)*`,\n * `(a|a)*`). This is intentionally conservative — it flags clearly\n * risky shapes without trying to be a real ReDoS analyzer. The\n * guard runs once at host-service start and only emits a warning,\n * not a fail-stop. */\nconst looksRedosProne = (pattern: RegExp): boolean => {\n\tconst source = pattern.source;\n\t// `(...)<quant><quant>` — quantifier directly after a group's quantifier.\n\tif (/\\)[*+?](?:\\{[^}]*\\})?[*+?]/.test(source)) return true;\n\t// `(...<quant>...)<quant>` — quantifier inside a group that itself is quantified.\n\tif (/\\([^()]*[*+?][^()]*\\)[*+?]/.test(source)) return true;\n\t// `(a|a)*` style — alternation with overlapping branches under a quantifier.\n\tif (/\\([^()]*\\|[^()]*\\)[*+]/.test(source)) return true;\n\treturn false;\n};\n\nconst renderCommand = (\n\toptions: HostServiceResolvedOptions,\n\tport: number,\n): {\n\treadonly command: string;\n\treadonly args: ReadonlyArray<string>;\n\treadonly env: NodeJS.ProcessEnv;\n} => {\n\tconst renderedEnv: NodeJS.ProcessEnv = {};\n\tfor (const [key, value] of Object.entries(options.env)) {\n\t\trenderedEnv[key] = renderPortToken(value, port);\n\t}\n\treturn {\n\t\tcommand: renderPortToken(options.command, port),\n\t\targs: options.args.map((arg) => renderPortToken(arg, port)),\n\t\tenv: renderedEnv,\n\t};\n};\n\nconst hostServiceValue = (\n\toptions: HostServiceResolvedOptions,\n\tport: number,\n\trendered: { readonly command: string; readonly args: ReadonlyArray<string> },\n\troutedUrl: string | null,\n): HostServiceValue => ({\n\tname: options.serviceName,\n\tendpointName: options.endpointName,\n\tcommand: rendered.command,\n\targs: rendered.args,\n\tcwd: options.cwd,\n\tport,\n\t// Canonical routed URL when the supervisor derived one, raw loopback\n\t// otherwise. `port` above always stays the real bound loopback port —\n\t// callers that need the bind target (readiness, direct host tooling)\n\t// read `.port`, not `.url`.\n\turl: routedUrl ?? `http://127.0.0.1:${port}`,\n});\n\nconst terminateChild = (\n\tchild: HostProcessChild,\n\ttimeoutMs: number,\n\tlogger: LoggerShape,\n\tpluginKey: PluginKey,\n\ttag: string,\n): Effect.Effect<void> =>\n\tterminateManagedProcess(child, {\n\t\tgraceMs: timeoutMs,\n\t\tprocessGroup: true,\n\t\tonEscalate: () =>\n\t\t\tlogger.log(tag, pluginKey, {\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage: 'host service did not exit after SIGTERM; sending SIGKILL',\n\t\t\t\tfields: { [LogAttr.event]: 'process.shutdown.escalated' },\n\t\t\t}),\n\t});\n\nconst httpReady = (\n\turl: string,\n\ttimeoutMs: number,\n\tintervalMs: number,\n\texit: Promise<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>,\n\tprocessError: Promise<unknown>,\n\terror: HostServiceAcquireError,\n): Effect.Effect<void, HostServiceAcquireError> =>\n\tawaitManagedProcessReady({\n\t\tready: waitForHttpEndpoint({\n\t\t\tendpoint: url,\n\t\t\ttimeoutMs,\n\t\t\tintervalMs,\n\t\t\t// HTTP readiness is a health check: require a 200 from the probed\n\t\t\t// `url` ITSELF. `redirect: 'manual'` means a 3xx is not followed —\n\t\t\t// it reads as `status 0`, so a server that 302s to a 200 login page\n\t\t\t// is NOT counted as ready off the redirect target. Point `url` at an\n\t\t\t// endpoint that returns 200 when the service is up (default: the\n\t\t\t// service root). Anything else — a still-compiling dev server, a\n\t\t\t// 5xx, a redirect — keeps polling until the readiness timeout. Use a\n\t\t\t// `log` probe instead when 200-at-a-URL isn't the right signal.\n\t\t\trequestInit: { redirect: 'manual' },\n\t\t\tvalidate: (response) => response.status === 200,\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause) =>\n\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t...error,\n\t\t\t\t\t\tphase: 'ready',\n\t\t\t\t\t\tmessage: `host service did not become ready at ${url} within ${timeoutMs}ms`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t\texit,\n\t\tprocessError,\n\t\tonExitBeforeReady: (status) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'exit',\n\t\t\t\tmessage: 'host service exited before readiness',\n\t\t\t\texitCode: status.code,\n\t\t\t\tsignal: status.signal,\n\t\t\t}),\n\t\tonProcessErrorBeforeReady: (cause) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'spawn',\n\t\t\t\tmessage: 'host service process failed before readiness',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nexport const logReady = (\n\tready: Extract<HostServiceReadyProbe, { readonly kind: 'log' }>,\n\treadySignal: Promise<void>,\n\texit: Promise<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>,\n\tprocessError: Promise<unknown>,\n\terror: HostServiceAcquireError,\n): Effect.Effect<void, HostServiceAcquireError> =>\n\tawaitManagedProcessReady({\n\t\tready: Effect.tryPromise({\n\t\t\ttry: () =>\n\t\t\t\tnew Promise<void>((resolveReady, rejectReady) => {\n\t\t\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t\t\trejectReady(\n\t\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\t\t...error,\n\t\t\t\t\t\t\t\tphase: 'ready',\n\t\t\t\t\t\t\t\tmessage: `host service did not emit readiness log within ${ready.timeoutMs ?? DEFAULT_LOG_READY_TIMEOUT_MS}ms`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}, ready.timeoutMs ?? DEFAULT_LOG_READY_TIMEOUT_MS);\n\t\t\t\t\treadySignal.then(\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\tresolveReady();\n\t\t\t\t\t\t},\n\t\t\t\t\t\t// Thread a rejecting readiness signal through as the\n\t\t\t\t\t\t// inner-Promise rejection (a non-tagged cause). Without\n\t\t\t\t\t\t// this `onRejected` handler a rejected signal would be an\n\t\t\t\t\t\t// unhandled rejection and the `catch:` arm below could\n\t\t\t\t\t\t// never see it. The `catch` arm preserves this raw cause\n\t\t\t\t\t\t// on `HostServiceAcquireError.cause`.\n\t\t\t\t\t\t(cause: unknown) => {\n\t\t\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\t\t\trejectReady(cause);\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\tcatch: (cause) =>\n\t\t\t\tcause instanceof HostServiceAcquireError\n\t\t\t\t\t? cause\n\t\t\t\t\t: new HostServiceAcquireError({\n\t\t\t\t\t\t\tserviceName: error.serviceName,\n\t\t\t\t\t\t\tcwd: error.cwd,\n\t\t\t\t\t\t\tcommand: error.command,\n\t\t\t\t\t\t\targs: error.args,\n\t\t\t\t\t\t\tphase: error.phase,\n\t\t\t\t\t\t\tmessage: error.message,\n\t\t\t\t\t\t\texitCode: error.exitCode,\n\t\t\t\t\t\t\tsignal: error.signal,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t}),\n\t\texit,\n\t\tprocessError,\n\t\tonExitBeforeReady: (status) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'exit',\n\t\t\t\tmessage: 'host service exited before readiness',\n\t\t\t\texitCode: status.code,\n\t\t\t\tsignal: status.signal,\n\t\t\t}),\n\t\tonProcessErrorBeforeReady: (cause) =>\n\t\t\tnew HostServiceAcquireError({\n\t\t\t\t...error,\n\t\t\t\tphase: 'spawn',\n\t\t\t\tmessage: 'host service process failed before readiness',\n\t\t\t\tcause,\n\t\t\t}),\n\t});\n\nconst allocateHostPort = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n): Effect.Effect<number, HostServiceAcquireError, Scope.Scope> =>\n\tctx.allocatePort(options.preferredPort).pipe(\n\t\tEffect.mapError(\n\t\t\t(cause) =>\n\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\tserviceName: options.serviceName,\n\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\tcommand: options.command,\n\t\t\t\t\targs: options.args,\n\t\t\t\t\tphase: 'allocate-port',\n\t\t\t\t\tmessage: 'host service failed to allocate HTTP port',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t),\n\t);\n\nconst startHostProcess = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n\tport: number,\n): Effect.Effect<void, HostServiceAcquireError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst rendered = renderCommand(options, port);\n\t\t// Per-stack discovery identity for in-child build integrations\n\t\t// (the `devstack` Vite plugin). These are a LOW-precedence base\n\t\t// layer: the inherited process env and the user's explicit\n\t\t// `options.env` both spread on top, so a user-set\n\t\t// `DEVSTACK_STACK` / `DEVSTACK_RUNTIME_ROOT` always wins. The\n\t\t// literal var names + the `RUNTIME_ROOT`-over-`STATE_DIR`\n\t\t// preference mirror `resolveDiscoveryEnv` (the plugin's reader);\n\t\t// `runtimeRoot` is absolute, so `discoverManifestPath` resolves\n\t\t// `<runtimeRoot>/stacks/<stack>/manifest.json` directly — exactly\n\t\t// where the supervisor writes the manifest.\n\t\tconst discoveryEnv: NodeJS.ProcessEnv =\n\t\t\tctx.discoveryIdentity === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tDEVSTACK_STACK: ctx.discoveryIdentity.stack,\n\t\t\t\t\t\tDEVSTACK_RUNTIME_ROOT: ctx.discoveryIdentity.runtimeRoot,\n\t\t\t\t\t};\n\t\tconst env: NodeJS.ProcessEnv = {\n\t\t\t...discoveryEnv,\n\t\t\t...(ctx.processEnv ?? process.env),\n\t\t\t...rendered.env,\n\t\t\tPORT: String(port),\n\t\t};\n\t\tconst tag = `host-service/${options.serviceName}`;\n\t\t// One-time ReDoS-shape warning. The log observer runs `RegExp.test`\n\t\t// synchronously per stdout/stderr line; a catastrophic-backtracking\n\t\t// pattern would wedge the observer fiber on adversarial output.\n\t\tif (\n\t\t\toptions.ready?.kind === 'log' &&\n\t\t\toptions.ready.pattern instanceof RegExp &&\n\t\t\tlooksRedosProne(options.ready.pattern)\n\t\t) {\n\t\t\tyield* ctx.logger.log(tag, ctx.pluginKey, {\n\t\t\t\tlevel: 'warn',\n\t\t\t\tmessage:\n\t\t\t\t\t'host service readiness pattern has a nested-quantifier shape that may exhibit catastrophic backtracking on adversarial output; prefer anchored, non-nested patterns',\n\t\t\t\tfields: {\n\t\t\t\t\t[LogAttr.serviceName]: options.serviceName,\n\t\t\t\t\t[LogAttr.event]: 'host-service.ready-pattern.redos-warning',\n\t\t\t\t\t// Namespaced diagnostic field (the offending pattern source),\n\t\t\t\t\t// consistent with the `event` name above. A bare `pattern`\n\t\t\t\t\t// key collides with the generic attribute vocabulary.\n\t\t\t\t\t'host-service.ready-pattern.source': options.ready.pattern.source,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t\tlet resolveLogReady: (() => void) | undefined;\n\t\tconst logReadySignal =\n\t\t\toptions.ready?.kind === 'log'\n\t\t\t\t? new Promise<void>((resolveReady) => {\n\t\t\t\t\t\tresolveLogReady = resolveReady;\n\t\t\t\t\t})\n\t\t\t\t: null;\n\t\tconst observeReadinessLine = (line: string, stream: 'stdout' | 'stderr'): void => {\n\t\t\tif (options.ready?.kind !== 'log') return;\n\t\t\tif (\n\t\t\t\toptions.ready.stream !== undefined &&\n\t\t\t\toptions.ready.stream !== 'both' &&\n\t\t\t\toptions.ready.stream !== stream\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst matches =\n\t\t\t\ttypeof options.ready.pattern === 'string'\n\t\t\t\t\t? line.includes(options.ready.pattern)\n\t\t\t\t\t: options.ready.pattern.test(line);\n\t\t\tif (matches) resolveLogReady?.();\n\t\t};\n\n\t\tconst spawnChild = ctx.spawner ?? nodeProcessSpawner;\n\t\t// Mutable cells declared before the setup block so the terminator\n\t\t// finalizer below can observe them.\n\t\tlet shuttingDown = false;\n\t\tlet exitStatus: {\n\t\t\treadonly code: number | null;\n\t\t\treadonly signal: NodeJS.Signals | null;\n\t\t} | null = null;\n\t\t// Atomic, deadlock-free process setup.\n\t\t//\n\t\t// Three things happen in one `Effect.uninterruptible` region — spawn,\n\t\t// fork the stdout/stderr line drains (`observeProcessLines`), and\n\t\t// register the kill finalizer — so that:\n\t\t//\n\t\t// 1. No interrupt can land between a successful spawn and the finalizer\n\t\t// registration. That gap was the original leak window: a SIGINT\n\t\t// mid-boot could orphan a detached child still holding its port.\n\t\t//\n\t\t// 2. The terminator finalizer is registered *after* the drain fibers,\n\t\t// so on scope close (LIFO) it runs *before* they are interrupted.\n\t\t// This ordering is load-bearing: the drains read the child's stdout/\n\t\t// stderr via `Stream.fromAsyncIterable`, whose `iterator.next()`\n\t\t// park is NON-interruptible — it only unblocks when the stream ends.\n\t\t// The child's streams end when the child is killed. So the\n\t\t// terminator must run first to kill the child (ending the streams),\n\t\t// which lets the drains drain-to-end and their interrupts complete.\n\t\t// Registering the terminator *before* the drains (e.g. via\n\t\t// `acquireRelease` at the top, or any pre-`observeProcessLines`\n\t\t// finalizer) inverts this and deadlocks scope close: the drain\n\t\t// interrupt can never complete because the terminator that would end\n\t\t// its stream is queued to run after it.\n\t\t//\n\t\t// The post-readiness `exited`/`processError` observers below are\n\t\t// registered later still, so they are interrupted before the terminator\n\t\t// runs — their `Effect.promise` waits are interruptible, so that unwinds\n\t\t// cleanly without needing the child to exit first.\n\t\tconst child = yield* Effect.uninterruptible(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst spawned = yield* Effect.try({\n\t\t\t\t\ttry: () =>\n\t\t\t\t\t\tspawnChild(rendered.command, rendered.args, {\n\t\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t\tenv,\n\t\t\t\t\t\t\tstdio: 'pipe',\n\t\t\t\t\t\t\tdetached: process.platform !== 'win32',\n\t\t\t\t\t\t}),\n\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\tserviceName: options.serviceName,\n\t\t\t\t\t\t\tcwd: options.cwd,\n\t\t\t\t\t\t\tcommand: rendered.command,\n\t\t\t\t\t\t\targs: rendered.args,\n\t\t\t\t\t\t\tphase: 'spawn',\n\t\t\t\t\t\t\tmessage: 'host service spawn failed',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tyield* observeProcessLines(\n\t\t\t\t\t{\n\t\t\t\t\t\tstdout: readableToByteStream(\n\t\t\t\t\t\t\tspawned.stdout as unknown as AsyncIterable<Uint8Array> | null | undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tstderr: readableToByteStream(\n\t\t\t\t\t\t\tspawned.stderr as unknown as AsyncIterable<Uint8Array> | null | undefined,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tlogger: ctx.logger,\n\t\t\t\t\t\tpluginKey: ctx.pluginKey,\n\t\t\t\t\t\ttag,\n\t\t\t\t\t\tfields: { [LogAttr.serviceName]: options.serviceName },\n\t\t\t\t\t\tonLine: ({ line, stream }) =>\n\t\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\t\tobserveReadinessLine(line, stream);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\tyield* Effect.addFinalizer(() =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tshuttingDown = true;\n\t\t\t\t\t\tif (exitStatus !== null) return;\n\t\t\t\t\t\tyield* terminateChild(spawned, options.shutdownGraceMs, ctx.logger, ctx.pluginKey, tag);\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn spawned;\n\t\t\t}),\n\t\t);\n\t\tconst exited = onceProcessExit(child).then((status) => {\n\t\t\texitStatus = status;\n\t\t\treturn status;\n\t\t});\n\t\tconst processError = onceProcessError(child);\n\n\t\tconst baseError = new HostServiceAcquireError({\n\t\t\tserviceName: options.serviceName,\n\t\t\tcwd: options.cwd,\n\t\t\tcommand: rendered.command,\n\t\t\targs: rendered.args,\n\t\t\tphase: 'ready',\n\t\t\tmessage: 'host service readiness failed',\n\t\t});\n\t\tconst awaitReadiness = (() => {\n\t\t\tif (options.ready?.kind === 'http') {\n\t\t\t\tconst url = renderPortToken(options.ready.url ?? 'http://127.0.0.1:{port}', port);\n\t\t\t\treturn httpReady(\n\t\t\t\t\turl,\n\t\t\t\t\toptions.ready.timeoutMs ?? DEFAULT_HTTP_READY_TIMEOUT_MS,\n\t\t\t\t\toptions.ready.intervalMs ?? DEFAULT_HTTP_READY_INTERVAL_MS,\n\t\t\t\t\texited,\n\t\t\t\t\tprocessError,\n\t\t\t\t\tbaseError,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (options.ready?.kind === 'log' && logReadySignal !== null) {\n\t\t\t\treturn logReady(options.ready, logReadySignal, exited, processError, baseError);\n\t\t\t}\n\t\t\treturn Effect.gen(function* () {\n\t\t\t\tyield* awaitManagedProcessReady({\n\t\t\t\t\tready: Effect.promise(\n\t\t\t\t\t\t() => new Promise<void>((resolveReady) => setTimeout(resolveReady, 0)),\n\t\t\t\t\t),\n\t\t\t\t\texit: exited,\n\t\t\t\t\tprocessError,\n\t\t\t\t\tonExitBeforeReady: (status) =>\n\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\t...baseError,\n\t\t\t\t\t\t\tphase: 'exit',\n\t\t\t\t\t\t\tmessage: 'host service exited before readiness',\n\t\t\t\t\t\t\texitCode: status.code,\n\t\t\t\t\t\t\tsignal: status.signal,\n\t\t\t\t\t\t}),\n\t\t\t\t\tonProcessErrorBeforeReady: (cause) =>\n\t\t\t\t\t\tnew HostServiceAcquireError({\n\t\t\t\t\t\t\t...baseError,\n\t\t\t\t\t\t\tphase: 'spawn',\n\t\t\t\t\t\t\tmessage: 'host service process failed before readiness',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t});\n\t\t})();\n\t\tconst readinessExit = yield* Effect.exit(awaitReadiness);\n\t\tif (Exit.isFailure(readinessExit)) {\n\t\t\tshuttingDown = true;\n\t\t\tif (exitStatus === null) {\n\t\t\t\tyield* terminateChild(child, options.shutdownGraceMs, ctx.logger, ctx.pluginKey, tag);\n\t\t\t}\n\t\t\treturn yield* Effect.failCause(readinessExit.cause);\n\t\t}\n\n\t\t// Post-readiness observers. Fork into the Scope via\n\t\t// `Effect.forkScoped` so that scope-close interrupts the observer\n\t\t// fiber cleanly — the finalizer flips `shuttingDown` first, so\n\t\t// expected-exit cases no-op. These observers are registered after the\n\t\t// terminator finalizer, so on scope close they are interrupted before\n\t\t// it runs; their `Effect.promise` waits are interruptible, so they\n\t\t// unwind cleanly without waiting on the child to exit.\n\t\tyield* Effect.forkScoped(\n\t\t\tEffect.promise(() => exited).pipe(\n\t\t\t\tEffect.flatMap((status) =>\n\t\t\t\t\tshuttingDown\n\t\t\t\t\t\t? Effect.void\n\t\t\t\t\t\t: ctx.logger.log(tag, ctx.pluginKey, {\n\t\t\t\t\t\t\t\tlevel: 'error',\n\t\t\t\t\t\t\t\tmessage: 'host service exited after readiness',\n\t\t\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\t\t\t[LogAttr.event]: 'process.exited',\n\t\t\t\t\t\t\t\t\t[LogAttr.serviceName]: options.serviceName,\n\t\t\t\t\t\t\t\t\t[LogAttr.exitCode]: status.code,\n\t\t\t\t\t\t\t\t\t[LogAttr.exitSignal]: status.signal,\n\t\t\t\t\t\t\t\t\t[LogAttr.exitStatus]: describeProcessExitStatus(status),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t\tyield* Effect.forkScoped(\n\t\t\tEffect.promise(() => processError).pipe(\n\t\t\t\tEffect.flatMap((cause) =>\n\t\t\t\t\tshuttingDown\n\t\t\t\t\t\t? Effect.void\n\t\t\t\t\t\t: ctx.logger.log(tag, ctx.pluginKey, {\n\t\t\t\t\t\t\t\tlevel: 'error',\n\t\t\t\t\t\t\t\tmessage: 'host service process emitted an error after readiness',\n\t\t\t\t\t\t\t\tfields: {\n\t\t\t\t\t\t\t\t\t[LogAttr.event]: 'process.error',\n\t\t\t\t\t\t\t\t\t[LogAttr.serviceName]: options.serviceName,\n\t\t\t\t\t\t\t\t\t[LogAttr.errorCause]: cause,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t});\n\nexport const prepareHostService = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n): Effect.Effect<PreparedHostService, HostServiceAcquireError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst port = yield* allocateHostPort(options, ctx);\n\t\tconst rendered = renderCommand(options, port);\n\t\tconst started = yield* Ref.make(false);\n\t\tconst start = Effect.gen(function* () {\n\t\t\tif (yield* Ref.get(started)) return;\n\t\t\tyield* startHostProcess(options, ctx, port);\n\t\t\tyield* Ref.set(started, true);\n\t\t});\n\n\t\treturn {\n\t\t\tvalue: hostServiceValue(options, port, rendered, ctx.routedUrl ?? null),\n\t\t\tstart,\n\t\t};\n\t});\n\nexport const acquireHostService = (\n\toptions: HostServiceResolvedOptions,\n\tctx: HostServiceAcquireContext,\n): Effect.Effect<HostServiceValue, HostServiceAcquireError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst prepared = yield* prepareHostService(options, ctx);\n\t\tyield* prepared.start;\n\t\treturn prepared.value;\n\t});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"acquire-on-chain-artifact.mjs","names":[],"sources":["../../../src/plugins/internal/acquire-on-chain-artifact.ts"],"sourcesContent":["// acquireOnChainArtifact — thin compactor over `ArtifactPublisher.publish`.\n//\n// Recurs across plugins that publish on-chain artifacts (coin/mint,\n// deepbook/pyth, deepbook/deploy, …). All three sites share:\n//\n// - the `register: () => Effect.void` no-op (these plugins keep no\n// in-process registry — the cached payload IS the resolved value),\n// - the `publish<Produced, Verified>({namespace, chain, contentHash,\n// verify, produce, register})` skeleton.\n//\n// The helper does NOT touch the `produce` body itself: the three\n// consumers' produce pipelines diverge meaningfully (coin/mint uses\n// `signAndDispatch` against the Account bus; deepbook/{pyth,deploy} use\n// `executeSuiTx` against the raw SDK client). Forcing a union over those\n// shapes would either widen the helper to the point of unhelpfulness or\n// regress one of the consumers. Each consumer continues to compose its\n// own `produce`; the helper centralises the surrounding boilerplate.\n//\n// For the rarer \"phase-preserving produce\" pattern (action plugin's\n// Ref-stash to recover typed-error phases across the substrate's\n// ArtifactPublishError wrap), see\n// `substrate/runtime/phase-preserving-produce.ts`.\n//\n// Boundary discipline: this module lives under `plugins/internal/`\n// because it consumes the public `ArtifactPublisher` surface AND the\n// public `ChainId`/`ContentHash` brands. No plugin-domain types leak in;\n// callers project the `Produced` payload to their resolved value\n// themselves.\n\nimport { Effect, type Scope } from 'effect';\n\nimport type { ChainId, ContentHash } from '../../substrate/brand.ts';\nimport {\n\ttype ArtifactPublishError,\n\ttype ArtifactPublisher,\n\ttype ArtifactSpec,\n} from '../../primitives/artifact-publisher.ts';\n\n/** Spec slice consumed by `acquireOnChainArtifact`. Mirrors\n * `ArtifactSpec<Produced, Verified>` minus the `register` field — the\n * helper supplies the universal `() => Effect.void` register for\n * artifact plugins with no in-process registry to feed. */\nexport interface AcquireOnChainArtifactSpec<Produced, Verified> {\n\treadonly namespace: string;\n\treadonly chain: ChainId;\n\treadonly contentHash: ContentHash;\n\treadonly verify: ArtifactSpec<Produced, Verified>['verify'];\n\treadonly produce: ArtifactSpec<Produced, Verified>['produce'];\n}\n\n/** Submit an on-chain artifact spec with the universal\n * `register: () => Effect.void` no-op baked in. Returns the substrate's\n * resolved `Produced` payload (decoded cached payload on verify-hit;\n * freshly produced payload on miss).\n *\n * Callers that need a non-void `register` (or a phase-preserving\n * produce wrap) should consume the underlying `publisher.publish`\n * surface directly. */\nexport const acquireOnChainArtifact = <Produced, Verified>(\n\tpublisher: ArtifactPublisher,\n\tspec: AcquireOnChainArtifactSpec<Produced, Verified>,\n): Effect.Effect<Produced, ArtifactPublishError, Scope.Scope> =>\n\tpublisher.publish<Produced, Verified>({\n\t\tnamespace: spec.namespace,\n\t\tchain: spec.chain,\n\t\tcontentHash: spec.contentHash,\n\t\tverify: spec.verify,\n\t\tproduce: spec.produce,\n\t\t// Register on EVERY cycle (hit AND miss) — substrate contract\n\t\t// (architecture §10). The on-chain-artifact plugins this helper\n\t\t// serves keep no in-process registry; the cached payload carries\n\t\t// everything callers need.\n\t\tregister: () => Effect.void,\n\t});\n"],"mappings":";;;;;;;;;;;AA0DA,MAAa,0BACZ,WACA,SAEA,UAAU,QAA4B;CACrC,WAAW,KAAK;CAChB,OAAO,KAAK;CACZ,aAAa,KAAK;CAClB,QAAQ,KAAK;CACb,SAAS,KAAK;CAKd,gBAAgB,OAAO;CACvB,CAAC"}
1
+ {"version":3,"file":"acquire-on-chain-artifact.mjs","names":[],"sources":["../../../src/plugins/internal/acquire-on-chain-artifact.ts"],"sourcesContent":["// acquireOnChainArtifact — thin compactor over `ArtifactPublisher.publish`.\n//\n// Recurs across plugins that publish on-chain artifacts (coin/mint,\n// deepbook/pyth, deepbook/deploy, …). All three sites share:\n//\n// - the `register: () => Effect.void` no-op (these plugins keep no\n// in-process registry — the cached payload IS the resolved value),\n// - the `publish<Produced, Verified>({namespace, chain, contentHash,\n// verify, produce, register})` skeleton.\n//\n// The helper does NOT touch the `produce` body itself: the three\n// consumers' produce pipelines diverge meaningfully (coin/mint uses\n// `signAndDispatch` against the Account bus; deepbook/{pyth,deploy} use\n// `executeSuiTx` against the raw SDK client). Forcing a union over those\n// shapes would either widen the helper to the point of unhelpfulness or\n// regress one of the consumers. Each consumer continues to compose its\n// own `produce`; the helper centralises the surrounding boilerplate.\n//\n// For the rarer \"phase-preserving produce\" pattern (action plugin's\n// Ref-stash to recover typed-error phases across the substrate's\n// ArtifactPublishError wrap), see\n// `substrate/runtime/phase-preserving-produce.ts`.\n//\n// Boundary discipline: this module lives under `plugins/internal/`\n// because it consumes the public `ArtifactPublisher` surface AND the\n// public `ContentHash` brand. No plugin-domain types leak in;\n// callers project the `Produced` payload to their resolved value\n// themselves.\n\nimport { Effect, type Scope } from 'effect';\n\nimport type { ContentHash } from '../../substrate/brand.ts';\nimport {\n\ttype ArtifactPublishError,\n\ttype ArtifactPublisher,\n\ttype ArtifactSpec,\n} from '../../primitives/artifact-publisher.ts';\n\n/** Spec slice consumed by `acquireOnChainArtifact`. Mirrors\n * `ArtifactSpec<Produced, Verified>` minus the `register` field — the\n * helper supplies the universal `() => Effect.void` register for\n * artifact plugins with no in-process registry to feed. */\nexport interface AcquireOnChainArtifactSpec<Produced, Verified> {\n\treadonly namespace: string;\n\treadonly chain: string;\n\treadonly contentHash: ContentHash;\n\treadonly verify: ArtifactSpec<Produced, Verified>['verify'];\n\treadonly produce: ArtifactSpec<Produced, Verified>['produce'];\n}\n\n/** Submit an on-chain artifact spec with the universal\n * `register: () => Effect.void` no-op baked in. Returns the substrate's\n * resolved `Produced` payload (decoded cached payload on verify-hit;\n * freshly produced payload on miss).\n *\n * Callers that need a non-void `register` (or a phase-preserving\n * produce wrap) should consume the underlying `publisher.publish`\n * surface directly. */\nexport const acquireOnChainArtifact = <Produced, Verified>(\n\tpublisher: ArtifactPublisher,\n\tspec: AcquireOnChainArtifactSpec<Produced, Verified>,\n): Effect.Effect<Produced, ArtifactPublishError, Scope.Scope> =>\n\tpublisher.publish<Produced, Verified>({\n\t\tnamespace: spec.namespace,\n\t\tchain: spec.chain,\n\t\tcontentHash: spec.contentHash,\n\t\tverify: spec.verify,\n\t\tproduce: spec.produce,\n\t\t// Register on EVERY cycle (hit AND miss) — substrate contract\n\t\t// (architecture §10). The on-chain-artifact plugins this helper\n\t\t// serves keep no in-process registry; the cached payload carries\n\t\t// everything callers need.\n\t\tregister: () => Effect.void,\n\t});\n"],"mappings":";;;;;;;;;;;AA0DA,MAAa,0BACZ,WACA,SAEA,UAAU,QAA4B;CACrC,WAAW,KAAK;CAChB,OAAO,KAAK;CACZ,aAAa,KAAK;CAClB,QAAQ,KAAK;CACb,SAAS,KAAK;CAKd,gBAAgB,OAAO;AACxB,CAAC"}
@@ -5,6 +5,8 @@ const defineSimpleConstExport = (spec) => ({
5
5
  emitterName: spec.emitterName,
6
6
  outputPath: spec.outputPath,
7
7
  sensitive: spec.sensitive ?? false,
8
+ ...spec.outputLocation ? { outputLocation: spec.outputLocation } : {},
9
+ ...spec.aggregateOnly ? { aggregateOnly: spec.aggregateOnly } : {},
8
10
  ...spec.aggregate ? { aggregate: spec.aggregate } : {},
9
11
  emit: (ctx) => Effect.gen(function* () {
10
12
  if (spec.preEmit) yield* spec.preEmit;
@@ -1 +1 @@
1
- {"version":3,"file":"codegen-helpers.mjs","names":[],"sources":["../../../src/plugins/internal/codegen-helpers.ts"],"sourcesContent":["// Internal plugin helpers — codegen shape factories.\n//\n// `defineSimpleConstExport` collapses the duplicated `CodegenableDecl`\n// boilerplate shared by `coin/codegen.ts`, `wallet/codegen.ts`, and\n// `account/codegen.ts`. Each of those plugins emits one file containing\n// exactly one `export const` from a resolved value record, optionally\n// joining a cross-decl aggregate bucket and optionally running a\n// pre-emit Effect (e.g. span annotation) before writing.\n//\n// Internal to this package — not re-exported from the root barrel.\n\nimport { Effect } from 'effect';\n\nimport type {\n\tAggregateContribution,\n\tCodegenableDecl,\n} from '../../contracts/codegenable.ts';\n\n/** Spec for a `CodegenableDecl` that emits a single `export const`.\n *\n * `Emitter` is preserved as a generic so plugins that template the\n * emitter name (e.g. `coin/${symbol}`, `account/${name}`) keep their\n * literal-typed emission identity. */\nexport interface SimpleConstExportSpec<Emitter extends string, Value> {\n\treadonly emitterName: Emitter;\n\treadonly outputPath: string;\n\treadonly exportName: string;\n\treadonly value: Value;\n\treadonly sensitive?: boolean;\n\treadonly aggregate?: AggregateContribution;\n\t/** Optional Effect run before the `exportConst` write — used by the\n\t * wallet plugin to annotate the current span with a redacted form\n\t * of the emitted value. Runs inside the emit Effect so the\n\t * annotation lands on the codegen span. */\n\treadonly preEmit?: Effect.Effect<void>;\n}\n\nexport const defineSimpleConstExport = <Emitter extends string, Value>(\n\tspec: SimpleConstExportSpec<Emitter, Value>,\n): CodegenableDecl<Emitter> => ({\n\tkind: 'codegenable',\n\temitterName: spec.emitterName,\n\toutputPath: spec.outputPath,\n\tsensitive: spec.sensitive ?? false,\n\t...(spec.aggregate ? { aggregate: spec.aggregate } : {}),\n\temit: (ctx) =>\n\t\tEffect.gen(function* () {\n\t\t\tif (spec.preEmit) {\n\t\t\t\tyield* spec.preEmit;\n\t\t\t}\n\t\t\tctx.exportConst(spec.exportName, spec.value);\n\t\t\treturn ctx.done();\n\t\t}),\n});\n"],"mappings":";;AAqCA,MAAa,2BACZ,UAC+B;CAC/B,MAAM;CACN,aAAa,KAAK;CAClB,YAAY,KAAK;CACjB,WAAW,KAAK,aAAa;CAC7B,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,WAAW,GAAG,EAAE;CACvD,OAAO,QACN,OAAO,IAAI,aAAa;AACvB,MAAI,KAAK,QACR,QAAO,KAAK;AAEb,MAAI,YAAY,KAAK,YAAY,KAAK,MAAM;AAC5C,SAAO,IAAI,MAAM;GAChB;CACH"}
1
+ {"version":3,"file":"codegen-helpers.mjs","names":[],"sources":["../../../src/plugins/internal/codegen-helpers.ts"],"sourcesContent":["// Internal plugin helpers — codegen shape factories.\n//\n// `defineSimpleConstExport` collapses the duplicated `CodegenableDecl`\n// boilerplate shared by the per-plugin `codegen.ts` modules. Each of\n// those plugins emits one file containing exactly one `export const`\n// from a resolved value record, optionally joining a cross-decl\n// aggregate bucket and optionally running a pre-emit Effect (e.g. span\n// annotation) before writing.\n//\n// Internal to this package — not re-exported from the root barrel.\n\nimport { Effect } from 'effect';\n\nimport type {\n\tAggregateContribution,\n\tCodegenableDecl,\n\tOutputLocation,\n} from '../../contracts/codegenable.ts';\n\n/** Spec for a `CodegenableDecl` that emits a single `export const`.\n *\n * `Emitter` is preserved as a generic so plugins that template the\n * emitter name (e.g. `coin/${symbol}`, `account/${name}`) keep their\n * literal-typed emission identity. */\nexport interface SimpleConstExportSpec<Emitter extends string, Value> {\n\treadonly emitterName: Emitter;\n\treadonly outputPath: string;\n\treadonly exportName: string;\n\treadonly value: Value;\n\treadonly sensitive?: boolean;\n\t/** Which codegen tree the standalone file lands in. Default\n\t * `'generated'`. */\n\treadonly outputLocation?: OutputLocation;\n\t/** Contribute only to the `aggregate` bucket — skip the standalone\n\t * file. Default `false`. */\n\treadonly aggregateOnly?: boolean;\n\treadonly aggregate?: AggregateContribution;\n\t/** Optional Effect run before the `exportConst` write — used by the\n\t * wallet plugin to annotate the current span with a redacted form\n\t * of the emitted value. Runs inside the emit Effect so the\n\t * annotation lands on the codegen span. */\n\treadonly preEmit?: Effect.Effect<void>;\n}\n\nexport const defineSimpleConstExport = <Emitter extends string, Value>(\n\tspec: SimpleConstExportSpec<Emitter, Value>,\n): CodegenableDecl<Emitter> => ({\n\tkind: 'codegenable',\n\temitterName: spec.emitterName,\n\toutputPath: spec.outputPath,\n\tsensitive: spec.sensitive ?? false,\n\t...(spec.outputLocation ? { outputLocation: spec.outputLocation } : {}),\n\t...(spec.aggregateOnly ? { aggregateOnly: spec.aggregateOnly } : {}),\n\t...(spec.aggregate ? { aggregate: spec.aggregate } : {}),\n\temit: (ctx) =>\n\t\tEffect.gen(function* () {\n\t\t\tif (spec.preEmit) {\n\t\t\t\tyield* spec.preEmit;\n\t\t\t}\n\t\t\tctx.exportConst(spec.exportName, spec.value);\n\t\t\treturn ctx.done();\n\t\t}),\n});\n"],"mappings":";;AA4CA,MAAa,2BACZ,UAC+B;CAC/B,MAAM;CACN,aAAa,KAAK;CAClB,YAAY,KAAK;CACjB,WAAW,KAAK,aAAa;CAC7B,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;CACrE,GAAI,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,IAAI,CAAC;CAClE,GAAI,KAAK,YAAY,EAAE,WAAW,KAAK,UAAU,IAAI,CAAC;CACtD,OAAO,QACN,OAAO,IAAI,aAAa;EACvB,IAAI,KAAK,SACR,OAAO,KAAK;EAEb,IAAI,YAAY,KAAK,YAAY,KAAK,KAAK;EAC3C,OAAO,IAAI,KAAK;CACjB,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"funding-failure-error.mjs","names":[],"sources":["../../../src/plugins/internal/funding-failure-error.ts"],"sourcesContent":["// Internal plugin helpers — funding-failure error envelope.\n//\n// `fundingFailureError` collapses the two near-identical\n// `accountAcquireError` builds in `plugins/account/funding.ts` that wrap\n// a strategy `request(...)` failure during funding:\n//\n// - `fund-default` — the ephemeral-account SUI faucet path\n// (the `wrapFaucetFailure` site).\n// - `fund-cross-cutting` — the per-coin cross-cutting path\n// (the `wrapCrossCuttingFailure` site).\n//\n// Both sites produced an `AccountAcquireError` with the same shape\n// (`phase`, `accountName`, `variant`, `cause`, `message`, `hint`), the\n// same `(tag=...)` suffix extracted from the cause, and a phase-specific\n// hint. This helper centralizes the tag extraction and the phase →\n// (message-template, hint) mapping so the call sites collapse to a\n// single line each.\n//\n// Internal to this package — not re-exported from the root barrel.\n\nimport {\n\taccountAcquireError,\n\ttype AccountAcquireError,\n\ttype AccountVariantKind,\n} from '../account/errors.ts';\n\n/** Discriminated spec for `fundingFailureError`. Each phase carries\n * the identifying fields it needs to preserve byte-identical message\n * output with the original inline builders in `funding.ts`. */\nexport type FundingFailureErrorSpec =\n\t| {\n\t\t\treadonly phase: 'fund-default';\n\t\t\treadonly accountName: string;\n\t\t\treadonly variant: AccountVariantKind;\n\t\t\t/** Chain id the faucet strategy was keyed on. */\n\t\t\treadonly chainId: string;\n\t\t\treadonly cause: { readonly _tag: string };\n\t }\n\t| {\n\t\t\treadonly phase: 'fund-cross-cutting';\n\t\t\treadonly accountName: string;\n\t\t\treadonly variant: AccountVariantKind;\n\t\t\t/** Strategy-registry key the request was routed through —\n\t\t\t * `faucet:request:<chainId>` for SUI entries or\n\t\t\t * `coinType:<fullCoinType>` for other entries. */\n\t\t\treadonly key: string;\n\t\t\treadonly amount: bigint;\n\t\t\treadonly cause: unknown;\n\t };\n\nconst extractTag = (cause: unknown): string =>\n\ttypeof cause === 'object' && cause !== null && '_tag' in cause\n\t\t? String((cause as { readonly _tag?: unknown })._tag)\n\t\t: 'unknown';\n\nconst FUND_DEFAULT_HINT =\n\t'See the cause chain — typical roots are the faucet container ' +\n\t'not yet ready (FaucetUnreachable), the wall-clock budget elapsed ' +\n\t'(FaucetExhausted), or the body returned Failure (FaucetBodyError).';\n\nconst FUND_CROSS_CUTTING_HINT =\n\t'Cross-cutting funding requires the matching strategy ' +\n\t'to be registered at the time of acquire — check the ' +\n\t'plugin that contributes this coin and any `via` dependency.';\n\n/** Build the `AccountAcquireError` for a funding strategy request that\n * failed. The message and hint are templated from `phase`; the tag is\n * extracted from the cause's `_tag` field (falling back to\n * `'unknown'`). */\nexport const fundingFailureError = (spec: FundingFailureErrorSpec): AccountAcquireError => {\n\tif (spec.phase === 'fund-default') {\n\t\treturn accountAcquireError({\n\t\t\tphase: 'fund-default',\n\t\t\taccountName: spec.accountName,\n\t\t\tvariant: spec.variant,\n\t\t\tmessage:\n\t\t\t\t`Account '${spec.accountName}': faucet strategy request failed ` +\n\t\t\t\t`for chain '${spec.chainId}' (tag=${spec.cause._tag}).`,\n\t\t\tcause: spec.cause,\n\t\t\thint: FUND_DEFAULT_HINT,\n\t\t});\n\t}\n\tconst tag = extractTag(spec.cause);\n\treturn accountAcquireError({\n\t\tphase: 'fund-cross-cutting',\n\t\taccountName: spec.accountName,\n\t\tvariant: spec.variant,\n\t\tmessage:\n\t\t\t`Account '${spec.accountName}': cross-cutting funding ` +\n\t\t\t`failed for coin (key='${spec.key}') amount=${spec.amount} ` +\n\t\t\t`(tag=${tag}).`,\n\t\tcause: spec.cause,\n\t\thint: FUND_CROSS_CUTTING_HINT,\n\t});\n};\n"],"mappings":";;AAkDA,MAAM,cAAc,UACnB,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,QACtD,OAAQ,MAAsC,KAAK,GACnD;AAEJ,MAAM,oBACL;AAID,MAAM,0BACL;;;;;AAQD,MAAa,uBAAuB,SAAuD;AAC1F,KAAI,KAAK,UAAU,eAClB,QAAO,oBAAoB;EAC1B,OAAO;EACP,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,SACC,YAAY,KAAK,YAAY,+CACf,KAAK,QAAQ,SAAS,KAAK,MAAM,KAAK;EACrD,OAAO,KAAK;EACZ,MAAM;EACN,CAAC;CAEH,MAAM,MAAM,WAAW,KAAK,MAAM;AAClC,QAAO,oBAAoB;EAC1B,OAAO;EACP,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,SACC,YAAY,KAAK,YAAY,iDACJ,KAAK,IAAI,YAAY,KAAK,OAAO,QAClD,IAAI;EACb,OAAO,KAAK;EACZ,MAAM;EACN,CAAC"}
1
+ {"version":3,"file":"funding-failure-error.mjs","names":[],"sources":["../../../src/plugins/internal/funding-failure-error.ts"],"sourcesContent":["// Internal plugin helpers — funding-failure error envelope.\n//\n// `fundingFailureError` collapses the two near-identical\n// `accountAcquireError` builds in `plugins/account/funding.ts` that wrap\n// a strategy `request(...)` failure during funding:\n//\n// - `fund-default` — the ephemeral-account SUI faucet path\n// (the `wrapFaucetFailure` site).\n// - `fund-cross-cutting` — the per-coin cross-cutting path\n// (the `wrapCrossCuttingFailure` site).\n//\n// Both sites produced an `AccountAcquireError` with the same shape\n// (`phase`, `accountName`, `variant`, `cause`, `message`, `hint`), the\n// same `(tag=...)` suffix extracted from the cause, and a phase-specific\n// hint. This helper centralizes the tag extraction and the phase →\n// (message-template, hint) mapping so the call sites collapse to a\n// single line each.\n//\n// Internal to this package — not re-exported from the root barrel.\n\nimport {\n\taccountAcquireError,\n\ttype AccountAcquireError,\n\ttype AccountVariantKind,\n} from '../account/errors.ts';\n\n/** Discriminated spec for `fundingFailureError`. Each phase carries\n * the identifying fields it needs to preserve byte-identical message\n * output with the original inline builders in `funding.ts`. */\nexport type FundingFailureErrorSpec =\n\t| {\n\t\t\treadonly phase: 'fund-default';\n\t\t\treadonly accountName: string;\n\t\t\treadonly variant: AccountVariantKind;\n\t\t\t/** Chain id the faucet strategy was keyed on. */\n\t\t\treadonly chainId: string;\n\t\t\treadonly cause: { readonly _tag: string };\n\t }\n\t| {\n\t\t\treadonly phase: 'fund-cross-cutting';\n\t\t\treadonly accountName: string;\n\t\t\treadonly variant: AccountVariantKind;\n\t\t\t/** Strategy-registry key the request was routed through —\n\t\t\t * `faucet:request:<chainId>` for SUI entries or\n\t\t\t * `coinType:<fullCoinType>` for other entries. */\n\t\t\treadonly key: string;\n\t\t\treadonly amount: bigint;\n\t\t\treadonly cause: unknown;\n\t };\n\nconst extractTag = (cause: unknown): string =>\n\ttypeof cause === 'object' && cause !== null && '_tag' in cause\n\t\t? String((cause as { readonly _tag?: unknown })._tag)\n\t\t: 'unknown';\n\nconst FUND_DEFAULT_HINT =\n\t'See the cause chain — typical roots are the faucet container ' +\n\t'not yet ready (FaucetUnreachable), the wall-clock budget elapsed ' +\n\t'(FaucetExhausted), or the body returned Failure (FaucetBodyError).';\n\nconst FUND_CROSS_CUTTING_HINT =\n\t'Cross-cutting funding requires the matching strategy ' +\n\t'to be registered at the time of acquire — check the ' +\n\t'plugin that contributes this coin and any `via` dependency.';\n\n/** Build the `AccountAcquireError` for a funding strategy request that\n * failed. The message and hint are templated from `phase`; the tag is\n * extracted from the cause's `_tag` field (falling back to\n * `'unknown'`). */\nexport const fundingFailureError = (spec: FundingFailureErrorSpec): AccountAcquireError => {\n\tif (spec.phase === 'fund-default') {\n\t\treturn accountAcquireError({\n\t\t\tphase: 'fund-default',\n\t\t\taccountName: spec.accountName,\n\t\t\tvariant: spec.variant,\n\t\t\tmessage:\n\t\t\t\t`Account '${spec.accountName}': faucet strategy request failed ` +\n\t\t\t\t`for chain '${spec.chainId}' (tag=${spec.cause._tag}).`,\n\t\t\tcause: spec.cause,\n\t\t\thint: FUND_DEFAULT_HINT,\n\t\t});\n\t}\n\tconst tag = extractTag(spec.cause);\n\treturn accountAcquireError({\n\t\tphase: 'fund-cross-cutting',\n\t\taccountName: spec.accountName,\n\t\tvariant: spec.variant,\n\t\tmessage:\n\t\t\t`Account '${spec.accountName}': cross-cutting funding ` +\n\t\t\t`failed for coin (key='${spec.key}') amount=${spec.amount} ` +\n\t\t\t`(tag=${tag}).`,\n\t\tcause: spec.cause,\n\t\thint: FUND_CROSS_CUTTING_HINT,\n\t});\n};\n"],"mappings":";;AAkDA,MAAM,cAAc,UACnB,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,QACtD,OAAQ,MAAsC,IAAI,IAClD;AAEJ,MAAM,oBACL;AAID,MAAM,0BACL;;;;;AAQD,MAAa,uBAAuB,SAAuD;CAC1F,IAAI,KAAK,UAAU,gBAClB,OAAO,oBAAoB;EAC1B,OAAO;EACP,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,SACC,YAAY,KAAK,YAAY,+CACf,KAAK,QAAQ,SAAS,KAAK,MAAM,KAAK;EACrD,OAAO,KAAK;EACZ,MAAM;CACP,CAAC;CAEF,MAAM,MAAM,WAAW,KAAK,KAAK;CACjC,OAAO,oBAAoB;EAC1B,OAAO;EACP,aAAa,KAAK;EAClB,SAAS,KAAK;EACd,SACC,YAAY,KAAK,YAAY,iDACJ,KAAK,IAAI,YAAY,KAAK,OAAO,QAClD,IAAI;EACb,OAAO,KAAK;EACZ,MAAM;CACP,CAAC;AACF"}
@@ -1,4 +1,4 @@
1
- //#region src/plugins/postgres/connection.ts
1
+ //#region src/plugins/internal/postgres-sidecar/connection.ts
2
2
  /** Build the credentialed URL.
3
3
  *
4
4
  * Caller convention: this URL MUST NOT be logged or persisted to
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.mjs","names":[],"sources":["../../../../src/plugins/internal/postgres-sidecar/connection.ts"],"sourcesContent":["// Internal Postgres sidecar connection-string builders.\n//\n// Distilled-doc § Postgres-specific concerns: two URL shapes must exit\n// the sidecar —\n//\n// 1. CREDENTIALED form (`postgres://<user>:<pw>@<host>:<port>`) for\n// in-process / in-stack dialers that need to issue real queries.\n// 2. PLAIN form (`postgres://<host>:<port>`) for the on-disk manifest\n// and for any non-secret display. NEVER carries the password.\n//\n// Both shapes can be extended with a database name segment via\n// `withDatabase`. The plain form's existence is the structural cure\n// for the \"credentialed URL leaks via console.log\" foot-gun called\n// out in the distilled doc's learnings.\n\n/** Components of a postgres connection. The plugin keeps these in\n * one record so URL construction is a single function call. */\nexport interface PostgresConnectionParts {\n\treadonly user: string;\n\treadonly password: string;\n\treadonly host: string;\n\treadonly port: number;\n}\n\n/** Build the credentialed URL.\n *\n * Caller convention: this URL MUST NOT be logged or persisted to\n * disk. The substrate's observability redactor strips it on best-\n * effort; the structural cure is to use `plainUrl` everywhere the\n * password isn't needed. */\nexport const credentialedUrl = (parts: PostgresConnectionParts): string => {\n\tconst { user, password, host, port } = parts;\n\treturn `postgres://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:${port}`;\n};\n\n/** Build the no-credentials URL. Manifest-safe by construction. */\nexport const plainUrl = (host: string, port: number): string => `postgres://${host}:${port}`;\n\n/** Compose a database segment onto a base URL. */\nexport const withDatabase = (baseUrl: string, db: string): string =>\n\t`${baseUrl}/${encodeURIComponent(db)}`;\n"],"mappings":";;;;;;;AA8BA,MAAa,mBAAmB,UAA2C;CAC1E,MAAM,EAAE,MAAM,UAAU,MAAM,SAAS;CACvC,OAAO,cAAc,mBAAmB,IAAI,EAAE,GAAG,mBAAmB,QAAQ,EAAE,GAAG,KAAK,GAAG;AAC1F;;AAGA,MAAa,YAAY,MAAc,SAAyB,cAAc,KAAK,GAAG;;AAGtF,MAAa,gBAAgB,SAAiB,OAC7C,GAAG,QAAQ,GAAG,mBAAmB,EAAE"}
@@ -1,15 +1,21 @@
1
- import { ProbeTimeoutError, exitCodeProbeResult, waitForProbe } from "../../substrate/runtime/probes.mjs";
1
+ import { ProbeTimeoutError, exitCodeProbeResult, waitForProbe } from "../../../substrate/runtime/probes.mjs";
2
2
  import { databaseCreateFailed, postgresConnectionTimeout } from "./errors.mjs";
3
- import { PostgresSpans } from "./spans.mjs";
4
3
  import { Effect } from "effect";
5
- //#region src/plugins/postgres/db-ensure.ts
4
+ //#region src/plugins/internal/postgres-sidecar/db-ensure.ts
6
5
  const READY_PROBE_INTERVAL_MS = 500;
7
- /** Wait until `pg_isready -U <user> -d <db>` exits zero or the
8
- * overall deadline elapses.
6
+ /** Wait until the server accepts a REAL query or the overall deadline
7
+ * elapses. Each attempt runs `pg_isready` THEN a `SELECT 1` against the
8
+ * always-present `postgres` maintenance DB; readiness requires BOTH.
9
9
  *
10
- * Distilled doc § "Postgres-specific concerns" — server-aware probe;
11
- * TCP-listener readiness alone is insufficient (postgres opens the
12
- * port before it accepts queries). */
10
+ * Distilled doc § "Postgres-specific concerns" — server-aware probe; TCP-
11
+ * listener readiness alone is insufficient (postgres opens the port
12
+ * before it accepts queries). The `SELECT 1` step closes a further gap:
13
+ * the official image bootstraps a TEMPORARY server for init, shuts it
14
+ * down, then starts the real one — `pg_isready` (and the first real
15
+ * query) can land in that restart window and see SQLSTATE 57P03
16
+ * ("shutting down" / "starting up"). Proving a query here makes EVERY
17
+ * downstream psql caller (chain-marker read, createdb) race-free without
18
+ * per-caller retries. */
13
19
  const awaitReady = (exec, user, database, timeoutMs) => Effect.gen(function* () {
14
20
  let attempts = 0;
15
21
  let lastResult;
@@ -20,15 +26,26 @@ const awaitReady = (exec, user, database, timeoutMs) => Effect.gen(function* ()
20
26
  intervalMs: READY_PROBE_INTERVAL_MS,
21
27
  probe: () => Effect.gen(function* () {
22
28
  attempts += 1;
23
- const result = yield* exec.run([
29
+ const isReady = yield* exec.run([
24
30
  "pg_isready",
25
31
  "-U",
26
32
  user,
27
33
  "-d",
28
34
  database
29
35
  ]);
30
- lastResult = result;
31
- return exitCodeProbeResult(result);
36
+ lastResult = isReady;
37
+ if (isReady.exitCode !== 0) return exitCodeProbeResult(isReady);
38
+ const query = yield* exec.run([
39
+ "psql",
40
+ "-U",
41
+ user,
42
+ "-d",
43
+ "postgres",
44
+ "-tAc",
45
+ "SELECT 1"
46
+ ]);
47
+ lastResult = query;
48
+ return exitCodeProbeResult(query);
32
49
  })
33
50
  }).pipe(Effect.mapError((cause) => {
34
51
  const lastError = cause instanceof ProbeTimeoutError ? cause.lastError : cause;
@@ -41,10 +58,7 @@ const awaitReady = (exec, user, database, timeoutMs) => Effect.gen(function* ()
41
58
  lastStderr: lastResult?.stderr,
42
59
  ...lastError === void 0 ? {} : { lastError }
43
60
  });
44
- }), Effect.withSpan("devstack.plugin.postgres.awaitReady", { attributes: {
45
- [PostgresSpans.database]: database,
46
- [PostgresSpans.timeoutMs]: timeoutMs
47
- } }));
61
+ }));
48
62
  });
49
63
  /** Idempotently ensure a logical database exists.
50
64
  *
@@ -94,7 +108,7 @@ const ensureDatabase = (exec, user, dbName) => Effect.gen(function* () {
94
108
  stdout: created.stdout,
95
109
  stderr: created.stderr
96
110
  }));
97
- }).pipe(Effect.withSpan("devstack.plugin.postgres.ensureDatabase", { attributes: { [PostgresSpans.database]: dbName } }));
111
+ });
98
112
  /** Sequentially ensure every non-bootstrap database exists. The
99
113
  * bootstrap (first entry) is created by `POSTGRES_DB` at image
100
114
  * entrypoint and MUST be skipped here. */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-ensure.mjs","names":[],"sources":["../../../../src/plugins/internal/postgres-sidecar/db-ensure.ts"],"sourcesContent":["// Internal Postgres sidecar — idempotent logical-database creation via\n// `docker exec ... psql`.\n//\n// Why exec, not a TS pg client:\n// - Production path keeps a zero-runtime-dep posture (distilled doc\n// § Postgres-specific concerns: \"avoids carrying a TS `pg` runtime\n// dependency in the production path\").\n// - The probe binary already lives inside the image; the dev\n// machine doesn't need a libpq install.\n// - The same machinery serves `pg_isready` (readiness probe) and\n// `psql` (existence check + createdb), so one exec primitive\n// covers both side-channels.\n//\n// Idempotency contract:\n// - The first database is bootstrapped by the upstream image's\n// entrypoint via `POSTGRES_DB`. The plugin's acquire body MUST\n// skip it here — passing it through `ensureDatabase` is harmless\n// (we short-circuit on existence) but wastes a round-trip.\n// - Subsequent databases land via SELECT 1 / createdb. SELECT 1\n// against `pg_database WHERE datname = '<name>'` returns \"1\\n\" on\n// hit; we treat any non-empty trimmed stdout as a hit so a\n// trailing newline doesn't trigger a duplicate-createdb path.\n//\n// The `ContainerExec` capability is consumed via the plugin's service\n// body (`service.ts:containerExec`), which thin-wraps the\n// `ContainerRuntime.exec` contract surface. Daemon-level failures (no\n// such container, daemon unreachable) map to a typed\n// `PostgresPluginError({phase: 'container-start'})` rather than a\n// fabricated non-zero `ExecResult`; `waitForProbe` treats that typed\n// failure as retryable and preserves the underlying cause on the\n// timeout error's `lastError` field.\n\nimport { Effect } from 'effect';\n\nimport {\n\tdatabaseCreateFailed,\n\tpostgresConnectionTimeout,\n\ttype DatabaseCreateFailed,\n\ttype PostgresConnectionTimeout,\n\ttype PostgresPluginError,\n} from './errors.ts';\nimport {\n\tProbeTimeoutError,\n\texitCodeProbeResult,\n\twaitForProbe,\n} from '../../../substrate/runtime/probes.ts';\n\n/** One captured exec invocation. Mirrors the shape returned by\n * `docker exec` (stdout + stderr + exit code), without naming docker\n * — any container runtime that supports an exec primitive can\n * satisfy this. */\nexport interface ExecResult {\n\treadonly exitCode: number;\n\treadonly stdout: string;\n\treadonly stderr: string;\n}\n\n/** Exec callable injected by the plugin's service body. Wraps\n * `ContainerRuntime.exec` (see contract) into the local seam shape so\n * the retry / existence-check loops here stay runtime-agnostic.\n *\n * Daemon-level failures surface as `PostgresPluginError`; non-zero\n * exit codes (eg `pg_isready` not ready yet) are returned in the\n * `ExecResult` for the caller to interpret. */\nexport interface ContainerExec {\n\treadonly run: (argv: ReadonlyArray<string>) => Effect.Effect<ExecResult, PostgresPluginError>;\n}\n\nconst READY_PROBE_INTERVAL_MS = 500;\n\n/** Wait until the server accepts a REAL query or the overall deadline\n * elapses. Each attempt runs `pg_isready` THEN a `SELECT 1` against the\n * always-present `postgres` maintenance DB; readiness requires BOTH.\n *\n * Distilled doc § \"Postgres-specific concerns\" — server-aware probe; TCP-\n * listener readiness alone is insufficient (postgres opens the port\n * before it accepts queries). The `SELECT 1` step closes a further gap:\n * the official image bootstraps a TEMPORARY server for init, shuts it\n * down, then starts the real one — `pg_isready` (and the first real\n * query) can land in that restart window and see SQLSTATE 57P03\n * (\"shutting down\" / \"starting up\"). Proving a query here makes EVERY\n * downstream psql caller (chain-marker read, createdb) race-free without\n * per-caller retries. */\nexport const awaitReady = (\n\texec: ContainerExec,\n\tuser: string,\n\tdatabase: string,\n\ttimeoutMs: number,\n): Effect.Effect<void, PostgresConnectionTimeout> =>\n\tEffect.gen(function* () {\n\t\tlet attempts = 0;\n\t\tlet lastResult: ExecResult | undefined;\n\t\tconst startedAt = Date.now();\n\n\t\treturn yield* waitForProbe({\n\t\t\tlabel: `postgres:${database}`,\n\t\t\ttimeoutMs,\n\t\t\tintervalMs: READY_PROBE_INTERVAL_MS,\n\t\t\tprobe: () =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tattempts += 1;\n\t\t\t\t\tconst isReady = yield* exec.run(['pg_isready', '-U', user, '-d', database]);\n\t\t\t\t\tlastResult = isReady;\n\t\t\t\t\tif (isReady.exitCode !== 0) return exitCodeProbeResult(isReady);\n\t\t\t\t\t// A real query against the maintenance DB — fails with 57P03\n\t\t\t\t\t// while the init temp-server is restarting, so it gates out the\n\t\t\t\t\t// connect-race window `pg_isready` alone would pass.\n\t\t\t\t\tconst query = yield* exec.run(['psql', '-U', user, '-d', 'postgres', '-tAc', 'SELECT 1']);\n\t\t\t\t\tlastResult = query;\n\t\t\t\t\treturn exitCodeProbeResult(query);\n\t\t\t\t}),\n\t\t}).pipe(\n\t\t\tEffect.mapError((cause) => {\n\t\t\t\tconst lastError = cause instanceof ProbeTimeoutError ? cause.lastError : (cause as unknown);\n\t\t\t\treturn postgresConnectionTimeout({\n\t\t\t\t\tdatabase,\n\t\t\t\t\tattempts: cause instanceof ProbeTimeoutError ? cause.attempts : attempts,\n\t\t\t\t\telapsedMs: Date.now() - startedAt,\n\t\t\t\t\tlastExitCode: lastResult?.exitCode,\n\t\t\t\t\tlastStdout: lastResult?.stdout,\n\t\t\t\t\tlastStderr: lastResult?.stderr,\n\t\t\t\t\t...(lastError === undefined ? {} : { lastError }),\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\t});\n\n/** Idempotently ensure a logical database exists.\n *\n * Algorithm:\n * 1. `psql -tAc \"SELECT 1 FROM pg_database WHERE datname = '<db>'\"`.\n * Exit 0 + non-empty stdout => exists, return.\n * Exit != 0 => DatabaseCreateFailed(exists-check).\n * 2. `createdb -U <user> <db>`.\n * Exit 0 => done.\n * Exit != 0 => DatabaseCreateFailed(createdb).\n *\n * Identifier quoting note: this implementation passes the database\n * name as a CLI argument (createdb) and as a SQL string literal\n * (the existence query). Postgres folds unquoted identifiers; if\n * the caller passes `MyDB`, postgres stores it as `mydb`. The\n * current plugin contract doesn't quote — distilled doc § Edge\n * cases flags this as a known foot-gun, and the recommended cure\n * is \"use lowercase names\". */\nexport const ensureDatabase = (\n\texec: ContainerExec,\n\tuser: string,\n\tdbName: string,\n): Effect.Effect<void, DatabaseCreateFailed | PostgresPluginError> =>\n\tEffect.gen(function* () {\n\t\t// Quote-escape per SQL literal rules (double single-quotes inside\n\t\t// the literal). The plugin's own contract restricts callers to\n\t\t// lowercase database identifiers (see distilled-doc § Edge cases\n\t\t// above), but the literal interpolation here is still a foot-\n\t\t// gun: a name containing `'` would break the WHERE clause and\n\t\t// either fail the existence check or, worse, alter its\n\t\t// semantics. Escaping locks the wire shape independent of the\n\t\t// upstream contract.\n\t\tconst escapedDbName = dbName.replace(/'/g, \"''\");\n\t\tconst exists = yield* exec.run([\n\t\t\t'psql',\n\t\t\t'-U',\n\t\t\tuser,\n\t\t\t'-tAc',\n\t\t\t`SELECT 1 FROM pg_database WHERE datname = '${escapedDbName}'`,\n\t\t]);\n\t\tif (exists.exitCode !== 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tdatabaseCreateFailed({\n\t\t\t\t\tdatabase: dbName,\n\t\t\t\t\top: 'exists-check',\n\t\t\t\t\texitCode: exists.exitCode,\n\t\t\t\t\tstdout: exists.stdout,\n\t\t\t\t\tstderr: exists.stderr,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (exists.stdout.trim().length > 0) {\n\t\t\treturn; // already present\n\t\t}\n\n\t\t// The `--` argv separator stops `createdb`'s flag parsing — a\n\t\t// `dbName` starting with `-` (e.g. `--help`) would otherwise be\n\t\t// interpreted as a flag rather than a positional database name.\n\t\t// Argv form already neutralizes shell-metacharacter injection;\n\t\t// the separator closes the remaining flag-shape gap.\n\t\tconst created = yield* exec.run(['createdb', '-U', user, '--', dbName]);\n\t\tif (created.exitCode !== 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tdatabaseCreateFailed({\n\t\t\t\t\tdatabase: dbName,\n\t\t\t\t\top: 'createdb',\n\t\t\t\t\texitCode: created.exitCode,\n\t\t\t\t\tstdout: created.stdout,\n\t\t\t\t\tstderr: created.stderr,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t});\n\n/** Sequentially ensure every non-bootstrap database exists. The\n * bootstrap (first entry) is created by `POSTGRES_DB` at image\n * entrypoint and MUST be skipped here. */\nexport const ensureDatabases = (\n\texec: ContainerExec,\n\tuser: string,\n\tdatabases: ReadonlyArray<string>,\n): Effect.Effect<void, DatabaseCreateFailed | PostgresPluginError> =>\n\tEffect.gen(function* () {\n\t\tfor (let i = 1; i < databases.length; i++) {\n\t\t\tyield* ensureDatabase(exec, user, databases[i]!);\n\t\t}\n\t});\n"],"mappings":";;;;AAoEA,MAAM,0BAA0B;;;;;;;;;;;;;;AAehC,MAAa,cACZ,MACA,MACA,UACA,cAEA,OAAO,IAAI,aAAa;CACvB,IAAI,WAAW;CACf,IAAI;CACJ,MAAM,YAAY,KAAK,IAAI;CAE3B,OAAO,OAAO,aAAa;EAC1B,OAAO,YAAY;EACnB;EACA,YAAY;EACZ,aACC,OAAO,IAAI,aAAa;GACvB,YAAY;GACZ,MAAM,UAAU,OAAO,KAAK,IAAI;IAAC;IAAc;IAAM;IAAM;IAAM;GAAQ,CAAC;GAC1E,aAAa;GACb,IAAI,QAAQ,aAAa,GAAG,OAAO,oBAAoB,OAAO;GAI9D,MAAM,QAAQ,OAAO,KAAK,IAAI;IAAC;IAAQ;IAAM;IAAM;IAAM;IAAY;IAAQ;GAAU,CAAC;GACxF,aAAa;GACb,OAAO,oBAAoB,KAAK;EACjC,CAAC;CACH,CAAC,CAAC,CAAC,KACF,OAAO,UAAU,UAAU;EAC1B,MAAM,YAAY,iBAAiB,oBAAoB,MAAM,YAAa;EAC1E,OAAO,0BAA0B;GAChC;GACA,UAAU,iBAAiB,oBAAoB,MAAM,WAAW;GAChE,WAAW,KAAK,IAAI,IAAI;GACxB,cAAc,YAAY;GAC1B,YAAY,YAAY;GACxB,YAAY,YAAY;GACxB,GAAI,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;EAChD,CAAC;CACF,CAAC,CACF;AACD,CAAC;;;;;;;;;;;;;;;;;;AAmBF,MAAa,kBACZ,MACA,MACA,WAEA,OAAO,IAAI,aAAa;CASvB,MAAM,gBAAgB,OAAO,QAAQ,MAAM,IAAI;CAC/C,MAAM,SAAS,OAAO,KAAK,IAAI;EAC9B;EACA;EACA;EACA;EACA,8CAA8C,cAAc;CAC7D,CAAC;CACD,IAAI,OAAO,aAAa,GACvB,OAAO,OAAO,OAAO,KACpB,qBAAqB;EACpB,UAAU;EACV,IAAI;EACJ,UAAU,OAAO;EACjB,QAAQ,OAAO;EACf,QAAQ,OAAO;CAChB,CAAC,CACF;CAED,IAAI,OAAO,OAAO,KAAK,CAAC,CAAC,SAAS,GACjC;CAQD,MAAM,UAAU,OAAO,KAAK,IAAI;EAAC;EAAY;EAAM;EAAM;EAAM;CAAM,CAAC;CACtE,IAAI,QAAQ,aAAa,GACxB,OAAO,OAAO,OAAO,KACpB,qBAAqB;EACpB,UAAU;EACV,IAAI;EACJ,UAAU,QAAQ;EAClB,QAAQ,QAAQ;EAChB,QAAQ,QAAQ;CACjB,CAAC,CACF;AAEF,CAAC;;;;AAKF,MAAa,mBACZ,MACA,MACA,cAEA,OAAO,IAAI,aAAa;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACrC,OAAO,eAAe,MAAM,MAAM,UAAU,EAAG;AAEjD,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { defineConfigError } from "../../../substrate/runtime/config-validation.mjs";
2
+ //#region src/plugins/internal/postgres-sidecar/errors.ts
3
+ const postgresPluginError = (phase, message, cause) => ({
4
+ _tag: "PostgresPluginError",
5
+ phase,
6
+ message,
7
+ cause
8
+ });
9
+ const postgresConfigError = defineConfigError("PostgresConfigError");
10
+ const postgresConnectionTimeout = (parts) => ({
11
+ _tag: "PostgresConnectionTimeout",
12
+ ...parts
13
+ });
14
+ const databaseCreateFailed = (parts) => ({
15
+ _tag: "DatabaseCreateFailed",
16
+ ...parts
17
+ });
18
+ //#endregion
19
+ export { databaseCreateFailed, postgresConfigError, postgresConnectionTimeout, postgresPluginError };
20
+
21
+ //# sourceMappingURL=errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../../../../src/plugins/internal/postgres-sidecar/errors.ts"],"sourcesContent":["// Internal Postgres sidecar — typed errors.\n//\n// These errors are not part of the public root barrel. They are raised by the\n// internal sidecar and wrapped by the owning plugin's error channel.\n//\n// Phase tags mirror the lifecycle states from the distilled doc\n// (10-postgres § Lifecycle states): one phase per failure boundary\n// so the cause walker / TUI / regression tests can pin behaviour by\n// label rather than by message-substring matching.\n//\n// Effect v4: errors are plain interfaces with a `_tag` discriminator.\n// `Effect.catchTag` / `catchTags` match on the `_tag` literal — we do\n// NOT subclass an Effect base class. See architecture § Effect.\n\nimport {\n\tdefineConfigError,\n\ttype ConfigIssue,\n} from '../../../substrate/runtime/config-validation.ts';\n\n/** Phases for `PostgresPluginError`. Closed sum — additions land in\n * the distilled-doc catalog first. */\nexport type PostgresPhase =\n\t| 'network-create'\n\t| 'image-build'\n\t| 'container-start'\n\t| 'ready-probe'\n\t| 'db-ensure'\n\t| 'unknown';\n\n/** Generic plugin error. Most failure surfaces collapse onto this\n * shape; specific failure modes that warrant their own catchable\n * tag (timeout, createdb-collision) get their own type below. */\nexport interface PostgresPluginError {\n\treadonly _tag: 'PostgresPluginError';\n\treadonly phase: PostgresPhase;\n\treadonly message: string;\n\treadonly cause?: unknown;\n}\n\nexport const postgresPluginError = (\n\tphase: PostgresPhase,\n\tmessage: string,\n\tcause?: unknown,\n): PostgresPluginError => ({ _tag: 'PostgresPluginError', phase, message, cause });\n\nexport interface PostgresConfigError extends ConfigIssue {\n\treadonly _tag: 'PostgresConfigError';\n}\n\nexport const postgresConfigError = defineConfigError('PostgresConfigError');\n\n/** `pg_isready` returned non-zero past the deadline. Carries the\n * database name + last exit code + captured streams so the cause\n * walker can render an actionable hint (slow disk, port mismatch,\n * perms on data dir).\n *\n * Distilled-doc § Edge cases: this is the most common \"what went\n * wrong\" failure during first boot of a freshly-built image; it\n * deserves its own tag so the renderer can show a slow-disk hint\n * before users guess. */\nexport interface PostgresConnectionTimeout {\n\treadonly _tag: 'PostgresConnectionTimeout';\n\treadonly database: string;\n\treadonly attempts: number;\n\treadonly elapsedMs: number;\n\treadonly lastExitCode?: number;\n\treadonly lastStdout?: string;\n\treadonly lastStderr?: string;\n\t/** Underlying typed error from the last probe attempt — populated\n\t * when the probe itself failed (eg daemon-level container-start\n\t * error) rather than `pg_isready` returning a non-zero exit. The\n\t * cause walker reads this to render the actionable hint. */\n\treadonly lastError?: unknown;\n}\n\nexport const postgresConnectionTimeout = (\n\tparts: Omit<PostgresConnectionTimeout, '_tag'>,\n): PostgresConnectionTimeout => ({ _tag: 'PostgresConnectionTimeout', ...parts });\n\n/** Logical-database creation failed. Distinct from a network /\n * container / probe failure because the typical root cause is\n * case-sensitivity collision in postgres identifier folding —\n * surfaced explicitly via its own tag so consumers can render a\n * \"quote the identifier\" hint. */\nexport interface DatabaseCreateFailed {\n\treadonly _tag: 'DatabaseCreateFailed';\n\treadonly database: string;\n\treadonly op: 'exists-check' | 'createdb';\n\treadonly exitCode?: number;\n\treadonly stdout?: string;\n\treadonly stderr?: string;\n\treadonly cause?: unknown;\n}\n\nexport const databaseCreateFailed = (\n\tparts: Omit<DatabaseCreateFailed, '_tag'>,\n): DatabaseCreateFailed => ({ _tag: 'DatabaseCreateFailed', ...parts });\n"],"mappings":";;AAuCA,MAAa,uBACZ,OACA,SACA,WAC0B;CAAE,MAAM;CAAuB;CAAO;CAAS;AAAM;AAMhF,MAAa,sBAAsB,kBAAkB,qBAAqB;AA0B1E,MAAa,6BACZ,WACgC;CAAE,MAAM;CAA6B,GAAG;AAAM;AAiB/E,MAAa,wBACZ,WAC2B;CAAE,MAAM;CAAwB,GAAG;AAAM"}
@@ -1,2 +1,3 @@
1
+ import "./connection.mjs";
1
2
  import "./service.mjs";
2
3
  export {};