@mysten-incubation/devstack 0.1.0 → 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 +7 -4
  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 -31
  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 +1 @@
1
- {"version":3,"file":"local.mjs","names":["sharedFetchChainId"],"sources":["../../../../src/plugins/sui/mode/local.ts"],"sourcesContent":["// Sui plugin — local-container mode.\n//\n// In-stack Sui validator + faucet, running in the supervised docker\n// stack. Used during normal dev loops when the developer wants fresh,\n// fast, throwaway chain state with a working faucet.\n//\n// Boot sequence (load-bearing order):\n//\n// 1. Resolve image — vendored Dockerfile build via the\n// ContainerRuntime contract (caller `image` override honoured for\n// `{build}`; `{pull}` is deferred — see stub list in the README).\n// 2. Allocate + ensure container — `sui start --with-faucet=0.0.0.0:9123\n// --with-graphql=0.0.0.0:9125` with direct host port-publishing\n// for internal boot probes. User-facing URLs are router-fronted\n// named hosts; the direct host ports intentionally live in the\n// high private windows so they do not collide with router\n// entrypoints.\n// RecreatePolicy is `on-failure` so the writable layer (chain\n// state at `/root/.sui`) survives clean stop/start cycles, but an\n// unclean SIGKILL/137 exit recreates instead of resuming a suspect\n// RocksDB/checkpoint state. The image's entrypoint forwards SIGINT\n// to a non-PID-1 sui child so clean shutdown (RocksDB checkpoint\n// drain → exit 0/130) is the normal case.\n// 3. Ready probe — RPC `getChainIdentifier`, faucet `GET /`, and\n// GraphQL HTTP liveness. Per-fetch deadline + outer deadline.\n// 4. Fetch chain id from the now-responsive client (bounded timeout).\n// 5. Build `waitForTransactionsReady` — `Effect.cached` against a\n// real faucet funding tx; first failure caches for the scope.\n// Manual `invalidate` clears the memo.\n// 6. Return resolved `SuiClient`. Auto-tick is the no-op advancer\n// (localnet drives its own consensus).\n//\n// Faucet socket-level readiness does NOT imply funds-transferability.\n// The first `waitForTransactionsReady.wait` POSTs a real funding tx,\n// retrying on body-level `{Failure}` responses during the post-RPC /\n// pre-fund window.\n//\n// What this body deliberately defers:\n// - Postgres indexer sidecar — GraphQL is enabled by `sui start` and\n// routed as a first-class endpoint, but no separate postgres\n// lifecycle is supervised here.\n// - Snapshot capture — the framework exists in the plugin's\n// snapshot.ts; this body produces the running container that the\n// orchestrator captures.\n\nimport { Duration, Effect, type Scope } from 'effect';\n\nimport { SuiGrpcClient } from '@mysten/sui/grpc';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tContainerRuntimeError,\n\tImageRef,\n\tContainerPortPublish,\n\tPortBindingReconciliation,\n} from '../../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple } from '../../../contracts/snapshotable.ts';\nimport type { Identity } from '../../../substrate/identity.ts';\nimport type { AllocatedPort, PortBroker } from '../../../substrate/runtime/port-broker/index.ts';\nimport { waitForHttpEndpoint } from '../../../substrate/runtime/http-probe.ts';\nimport { setCurrentPluginPhase } from '../../../substrate/runtime/current-plugin.ts';\nimport { ensureManagedContainer } from '../../../substrate/runtime/managed-container.ts';\nimport { SpanAttr } from '../../../substrate/runtime/observability/spans.ts';\nimport { renderUrl, routedHostname } from '../../../substrate/runtime/routed-url.ts';\nimport {\n\tDEFAULT_SUI_CLI_VERSION,\n\tsuiCliImageBuildContext,\n} from '../../../substrate/runtime/sui-move-build/index.ts';\nimport { suiPluginError, type SuiConfigError, type SuiPluginError } from '../errors.ts';\nimport { formatUnknownError } from '../../../substrate/runtime/format-unknown-error.ts';\nimport type { ResolvedSuiNetwork } from '../network-resolver.ts';\nimport { SuiSpans } from '../spans.ts';\nimport {\n\tSUI_FAUCET_ENTRYPOINT_PORT,\n\tSUI_FAUCET_ENDPOINT_NAME,\n\tSUI_GRAPHQL_ENDPOINT_NAME,\n\tSUI_GRAPHQL_ENTRYPOINT_PORT,\n\tSUI_RPC_ENDPOINT_NAME,\n\tSUI_RPC_ENTRYPOINT_PORT,\n} from '../routable.ts';\nimport type { SuiClient } from './shared.ts';\nimport { toDockerHostGatewayUrl } from './shared.ts';\nimport {\n\tassembleSuiClient,\n\tbuildWaitForTransactionsReady,\n\tfetchChainId as sharedFetchChainId,\n\tmakeResolvedNetwork,\n} from './shared-boot.ts';\nimport type { SuiLocalOptions } from './spec.ts';\n\n/** Default ready-probe timeout for localnet. The validator's cold\n * start runs genesis + faucet bootstrap; 60 s is the documented\n * ceiling. */\nexport const DEFAULT_LOCAL_READY_TIMEOUT = Duration.seconds(60);\n\n/** Default sui validator binary version pinned by the vendored\n * `images/sui/` Dockerfile. The build arg `SUI_VERSION` is threaded\n * through to the release-tarball URL. Bump in lockstep with matching\n * Walrus / Seal versions (else the Move package ABIs drift). */\nexport const DEFAULT_SUI_VERSION = DEFAULT_SUI_CLI_VERSION;\n\n// In-container ports the sui binary binds on. These match the router\n// entrypoint ports; direct host publishes below use different high\n// ports so Traefik owns the public listener ports.\nconst CONTAINER_RPC_PORT = SUI_RPC_ENTRYPOINT_PORT;\nconst CONTAINER_FAUCET_PORT = SUI_FAUCET_ENTRYPOINT_PORT;\nconst CONTAINER_GRAPHQL_PORT = SUI_GRAPHQL_ENTRYPOINT_PORT;\n\n// Default host ports. Without `opts.ports`, these are preferences\n// brokered against the kernel before Docker publishes them.\nexport const DEFAULT_HOST_RPC_PORT = 51000;\nexport const DEFAULT_HOST_FAUCET_PORT = 50000;\nexport const DEFAULT_HOST_GRAPHQL_PORT = 51001;\nconst DOCKER_PUBLISH_HOST = '0.0.0.0' as const;\nexport const MAX_DOCKER_PUBLISH_PORT_RETRIES = 3;\nexport const LOCAL_VALIDATOR_STOP_GRACE_SECONDS = 30;\n\n/** Per-fetch deadline for the ready-probe HTTP calls. Without it a\n * hung fetch would block the outer ready deadline with no signal\n * about which probe wedged. */\nconst PROBE_FETCH_TIMEOUT_MS = 3000;\n\n/** Resolved local-mode boot artifacts. */\nexport interface LocalModeBootResult {\n\treadonly resolved: ResolvedSuiNetwork;\n\treadonly client: SuiClient;\n}\n\n/**\n * Build the local-mode boot Effect.\n *\n * `identity` is threaded in by the caller (the plugin barrel's acquire\n * body, which has access to the substrate's `IdentityContext` via the\n * outer composition layer); the body uses it to stamp the canonical\n * container label tuple so sweep / inventory are name-blind.\n *\n * `{pull}`, `{build}`, and vendored-build image branches are wired.\n */\nexport const bootLocalMode = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n\tportBroker: PortBroker,\n\topts: SuiLocalOptions,\n): Effect.Effect<LocalModeBootResult, SuiPluginError | SuiConfigError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\t// ----- 1. Resolve image ---------------------------------------------\n\t\tyield* setCurrentPluginPhase('resolving Sui local image');\n\t\tconst image = yield* resolveImage(runtime, identity, opts);\n\n\t\t// ----- 2. Allocate ports + ensure container --------------------------\n\t\tyield* setCurrentPluginPhase('creating Sui validator container');\n\t\tconst labels: ContainerLabelTuple = {\n\t\t\tapp: identity.app,\n\t\t\tstack: identity.stack,\n\t\t\tplugin: 'sui',\n\t\t\trole: 'validator',\n\t\t};\n\t\tconst containerName = `devstack-${identity.app}-${identity.stack}-sui-validator`;\n\t\tconst { handle, ports } = yield* ensureLocalValidatorContainer(\n\t\t\truntime,\n\t\t\tportBroker,\n\t\t\timage,\n\t\t\tlabels,\n\t\t\tcontainerName,\n\t\t\topts,\n\t\t);\n\n\t\t// ----- 3. Ready probes ----------------------------------------------\n\t\tconst publishedPorts = resolvePublishedPortMapping(ports, handle.ports);\n\t\tconst directRpcUrl = `http://127.0.0.1:${publishedPorts[0]!.hostPort}`;\n\t\tconst directFaucetUrl = `http://127.0.0.1:${publishedPorts[1]!.hostPort}`;\n\t\tconst directGraphqlUrl = `http://127.0.0.1:${publishedPorts[2]!.hostPort}`;\n\t\tconst rpcUrl = yield* routedSuiUrl(identity, SUI_RPC_ENDPOINT_NAME, SUI_RPC_ENTRYPOINT_PORT);\n\t\tconst faucetUrl = yield* routedSuiUrl(\n\t\t\tidentity,\n\t\t\tSUI_FAUCET_ENDPOINT_NAME,\n\t\t\tSUI_FAUCET_ENTRYPOINT_PORT,\n\t\t);\n\t\tconst graphqlUrl = yield* routedSuiUrl(\n\t\t\tidentity,\n\t\t\tSUI_GRAPHQL_ENDPOINT_NAME,\n\t\t\tSUI_GRAPHQL_ENTRYPOINT_PORT,\n\t\t);\n\t\tconst readyTimeout = opts.readyTimeout ?? DEFAULT_LOCAL_READY_TIMEOUT;\n\n\t\tyield* setCurrentPluginPhase('waiting for Sui RPC, faucet, and GraphQL');\n\t\tyield* waitForReady(directRpcUrl, directFaucetUrl, directGraphqlUrl, readyTimeout).pipe(\n\t\t\tEffect.annotateLogs({ [SuiSpans.container]: handle.name }),\n\t\t);\n\n\t\tconst sdkClient = new SuiGrpcClient({ baseUrl: directRpcUrl, network: 'localnet' });\n\n\t\t// ----- 4. Resolve chain id ------------------------------------------\n\t\tyield* setCurrentPluginPhase('fetching Sui chain id');\n\t\tconst chain = yield* sharedFetchChainId(sdkClient, {\n\t\t\tspan: 'devstack.plugin.sui.local.fetchChainId',\n\t\t});\n\n\t\t// ----- 5. waitForTransactionsReady (memoised) -----------------------\n\t\tyield* setCurrentPluginPhase('preparing Sui funds-ready gate');\n\t\tconst waitForTransactionsReady = yield* buildWaitForTransactionsReady(directFaucetUrl);\n\n\t\t// ----- 6. Assemble resolved SuiClient -------------------------------\n\t\t// Surface `buildImage` so package's path-(b) `docker run --rm`\n\t\t// build path can spawn a one-shot sui-cli container using the\n\t\t// SAME image we built/resolved here. Without this the package\n\t\t// plugin would have to re-resolve the image, doubling the\n\t\t// build-context hash work and risking digest drift.\n\t\tconst { client } = yield* assembleSuiClient({\n\t\t\tsdkClient,\n\t\t\tchain,\n\t\t\trpcUrl,\n\t\t\tfaucetUrl,\n\t\t\tfundingFaucetUrl: directFaucetUrl,\n\t\t\tgraphqlUrl,\n\t\t\twaitForTransactionsReady,\n\t\t\tbuildImage: image,\n\t\t\thostGateway: {\n\t\t\t\trpcUrl: toDockerHostGatewayUrl(directRpcUrl),\n\t\t\t\tfaucetUrl: toDockerHostGatewayUrl(directFaucetUrl),\n\t\t\t\tgraphqlUrl: toDockerHostGatewayUrl(directGraphqlUrl),\n\t\t\t},\n\t\t});\n\t\tconst resolved = makeResolvedNetwork({\n\t\t\tmode: 'local',\n\t\t\tchain,\n\t\t\trpc: rpcUrl,\n\t\t\tfaucet: faucetUrl,\n\t\t\tgraphql: graphqlUrl,\n\t\t\tsource: 'default',\n\t\t});\n\t\treturn {\n\t\t\tresolved,\n\t\t\tclient,\n\t\t};\n\t}).pipe(\n\t\tEffect.withSpan('devstack.plugin.sui.local.boot', { attributes: { [SpanAttr.plugin]: 'sui' } }),\n\t);\n\n// ---------------------------------------------------------------------------\n// Image resolution — vendored Dockerfile build via `ContainerRuntime`\n// ---------------------------------------------------------------------------\n\nexport const resolveImage = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n\topts: SuiLocalOptions,\n): Effect.Effect<ImageRef, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tif (opts.image && 'pull' in opts.image) {\n\t\t\tconst pullRef = opts.image.pull;\n\t\t\tif (runtime.pullImage === undefined) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'image-build',\n\t\t\t\t\t\t`sui local mode cannot pull image '${pullRef}' because the configured container runtime does not expose image pulls.`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn yield* runtime\n\t\t\t\t.pullImage(pullRef)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t\t'image-build',\n\t\t\t\t\t\t\t`sui local mode failed to pull image '${pullRef}': ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t}\n\t\tconst version = opts.version ?? DEFAULT_SUI_VERSION;\n\t\tconst owner = {\n\t\t\tapp: identity.app,\n\t\t\tstack: identity.stack,\n\t\t\tplugin: 'sui',\n\t\t\trole: 'validator',\n\t\t} as const;\n\t\tconst buildCtx =\n\t\t\topts.image && 'build' in opts.image\n\t\t\t\t? {\n\t\t\t\t\t\tcontextPath: opts.image.build.context,\n\t\t\t\t\t\tdockerfile: opts.image.build.dockerfile ?? 'Dockerfile',\n\t\t\t\t\t\tbuildArgs: { SUI_VERSION: version },\n\t\t\t\t\t\towner,\n\t\t\t\t\t}\n\t\t\t\t: { ...suiCliImageBuildContext(version), owner };\n\t\treturn yield* runtime\n\t\t\t.ensureImage(buildCtx)\n\t\t\t.pipe(\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'image-build',\n\t\t\t\t\t\t`sui image build failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t}).pipe(Effect.withSpan('devstack.plugin.sui.local.resolveImage'));\n\ninterface LocalValidatorContainerResult {\n\treadonly handle: ContainerHandle;\n\treadonly ports: ReadonlyArray<ContainerPortPublish>;\n}\n\ninterface ResolvedPortMapping {\n\treadonly ports: ReadonlyArray<ContainerPortPublish>;\n\treadonly release: Effect.Effect<void>;\n}\n\nexport const ensureLocalValidatorContainer = (\n\truntime: ContainerRuntime,\n\tportBroker: PortBroker,\n\timage: ImageRef,\n\tlabels: ContainerLabelTuple,\n\tcontainerName: string,\n\topts: SuiLocalOptions,\n): Effect.Effect<LocalValidatorContainerResult, SuiPluginError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst reusablePorts =\n\t\t\topts.ports === undefined\n\t\t\t\t? yield* findReusablePortMapping(runtime, labels, containerName)\n\t\t\t\t: undefined;\n\t\tif (reusablePorts !== undefined) {\n\t\t\treturn yield* ensureLocalValidatorContainerAttempt({\n\t\t\t\truntime,\n\t\t\t\tportBroker,\n\t\t\t\timage,\n\t\t\t\tlabels,\n\t\t\t\tcontainerName,\n\t\t\t\topts,\n\t\t\t\tports: reusablePorts,\n\t\t\t\tattempt: 0,\n\t\t\t\treconciliation: 'adopt-existing',\n\t\t\t});\n\t\t}\n\t\treturn yield* ensureLocalValidatorContainerWithFreshPorts({\n\t\t\truntime,\n\t\t\tportBroker,\n\t\t\timage,\n\t\t\tlabels,\n\t\t\tcontainerName,\n\t\t\topts,\n\t\t\tattempt: 0,\n\t\t\treconciliation: opts.ports ? 'exact' : 'adopt-existing',\n\t\t});\n\t});\n\ninterface EnsureLocalValidatorContainerBase {\n\treadonly runtime: ContainerRuntime;\n\treadonly portBroker: PortBroker;\n\treadonly image: ImageRef;\n\treadonly labels: ContainerLabelTuple;\n\treadonly containerName: string;\n\treadonly opts: SuiLocalOptions;\n}\n\nconst ensureLocalValidatorContainerWithFreshPorts = (\n\tparams: EnsureLocalValidatorContainerBase & {\n\t\treadonly attempt: number;\n\t\treadonly reconciliation: PortBindingReconciliation;\n\t},\n): Effect.Effect<LocalValidatorContainerResult, SuiPluginError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst mapping = yield* resolvePortMappingWithRelease(params.portBroker, params.opts.ports);\n\t\treturn yield* ensureLocalValidatorContainerAttempt({\n\t\t\t...params,\n\t\t\tports: mapping.ports,\n\t\t\treleasePorts: mapping.release,\n\t\t});\n\t});\n\nconst ensureLocalValidatorContainerAttempt = (\n\tparams: EnsureLocalValidatorContainerBase & {\n\t\treadonly ports: ReadonlyArray<ContainerPortPublish>;\n\t\treadonly releasePorts?: Effect.Effect<void>;\n\t\treadonly attempt: number;\n\t\treadonly reconciliation: PortBindingReconciliation;\n\t},\n): Effect.Effect<LocalValidatorContainerResult, SuiPluginError, Scope.Scope> =>\n\tensureManagedContainer({\n\t\truntime: params.runtime,\n\t\tlabels: params.labels,\n\t\tspec: {\n\t\t\tname: params.containerName,\n\t\t\timage: params.image,\n\t\t\t// Keep the writable layer only after clean exits. If Docker\n\t\t\t// escalates a previous stop to SIGKILL (137), resume can hang\n\t\t\t// in RocksDB/checkpoint recovery with no RPC/faucet probes.\n\t\t\t// `on-failure` routes that stale layer to recreate while still\n\t\t\t// warm-resuming normal exit 0 / 130 stops. The longer grace\n\t\t\t// gives the entrypoint's SIGINT forwarding time to drain.\n\t\t\trecreate: 'on-failure',\n\t\t\tstopGraceSeconds: LOCAL_VALIDATOR_STOP_GRACE_SECONDS,\n\t\t\tports: params.ports,\n\t\t\tportBindingReconciliation: params.reconciliation,\n\t\t},\n\t\tmapError: (cause) => cause,\n\t}).pipe(\n\t\tEffect.map((handle) => ({ handle, ports: params.ports })),\n\t\tEffect.catch((cause: ContainerRuntimeError) => {\n\t\t\tif (\n\t\t\t\tparams.opts.ports === undefined &&\n\t\t\t\tcause.reason === 'publish-port-conflict' &&\n\t\t\t\tparams.attempt < MAX_DOCKER_PUBLISH_PORT_RETRIES\n\t\t\t) {\n\t\t\t\treturn (params.releasePorts ?? Effect.void).pipe(\n\t\t\t\t\tEffect.andThen(\n\t\t\t\t\t\tensureLocalValidatorContainerWithFreshPorts({\n\t\t\t\t\t\t\t...params,\n\t\t\t\t\t\t\tattempt: params.attempt + 1,\n\t\t\t\t\t\t\treconciliation: 'exact',\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn Effect.fail(\n\t\t\t\tsuiPluginError(\n\t\t\t\t\t'container-start',\n\t\t\t\t\t`sui-validator container failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\tcause,\n\t\t\t\t),\n\t\t\t);\n\t\t}),\n\t);\n\n// ---------------------------------------------------------------------------\n// Port mapping — host:container pairs\n// ---------------------------------------------------------------------------\n\n// Exported test entry point: resolves the host:container port pairs\n// without surfacing the release handle (the live boot path uses\n// `resolvePortMappingWithRelease` directly to retain the release).\nexport const resolvePortMapping = (\n\tportBroker: PortBroker,\n\toverride: Readonly<Record<number, number>> | undefined,\n): Effect.Effect<ReadonlyArray<ContainerPortPublish>, SuiPluginError, Scope.Scope> =>\n\tresolvePortMappingWithRelease(portBroker, override).pipe(Effect.map((mapping) => mapping.ports));\n\nconst resolvePortMappingWithRelease = (\n\tportBroker: PortBroker,\n\toverride: Readonly<Record<number, number>> | undefined,\n): Effect.Effect<ResolvedPortMapping, SuiPluginError, Scope.Scope> => {\n\tconst pick = (containerPort: number, fallback: number): number => {\n\t\tif (!override) return fallback;\n\t\tconst hit = override[containerPort];\n\t\treturn typeof hit === 'number' ? hit : fallback;\n\t};\n\tif (override) {\n\t\treturn Effect.succeed({\n\t\t\tports: [\n\t\t\t\tportPublish(CONTAINER_RPC_PORT, pick(CONTAINER_RPC_PORT, DEFAULT_HOST_RPC_PORT)),\n\t\t\t\tportPublish(CONTAINER_FAUCET_PORT, pick(CONTAINER_FAUCET_PORT, DEFAULT_HOST_FAUCET_PORT)),\n\t\t\t\tportPublish(\n\t\t\t\t\tCONTAINER_GRAPHQL_PORT,\n\t\t\t\t\tpick(CONTAINER_GRAPHQL_PORT, DEFAULT_HOST_GRAPHQL_PORT),\n\t\t\t\t),\n\t\t\t],\n\t\t\trelease: Effect.void,\n\t\t});\n\t}\n\treturn Effect.gen(function* () {\n\t\tconst rpc = yield* allocatePort(portBroker, 'sui:rpc', DEFAULT_HOST_RPC_PORT, 'rpc');\n\t\tconst faucet = yield* allocatePort(\n\t\t\tportBroker,\n\t\t\t'sui:faucet',\n\t\t\tDEFAULT_HOST_FAUCET_PORT,\n\t\t\t'faucet',\n\t\t);\n\t\tconst graphql = yield* allocatePort(\n\t\t\tportBroker,\n\t\t\t'sui:graphql',\n\t\t\tDEFAULT_HOST_GRAPHQL_PORT,\n\t\t\t'graphql',\n\t\t);\n\t\treturn {\n\t\t\tports: [\n\t\t\t\tportPublish(CONTAINER_RPC_PORT, rpc.port),\n\t\t\t\tportPublish(CONTAINER_FAUCET_PORT, faucet.port),\n\t\t\t\tportPublish(CONTAINER_GRAPHQL_PORT, graphql.port),\n\t\t\t],\n\t\t\trelease: Effect.all([rpc.release, faucet.release, graphql.release], { discard: true }),\n\t\t};\n\t});\n};\n\nexport const resolvePublishedPortMapping = (\n\trequested: ReadonlyArray<ContainerPortPublish>,\n\tactual: ReadonlyArray<ContainerPortPublish> | undefined,\n): ReadonlyArray<ContainerPortPublish> => [\n\tpickPublishedPort(requested, actual, CONTAINER_RPC_PORT, DEFAULT_HOST_RPC_PORT),\n\tpickPublishedPort(requested, actual, CONTAINER_FAUCET_PORT, DEFAULT_HOST_FAUCET_PORT),\n\tpickPublishedPort(requested, actual, CONTAINER_GRAPHQL_PORT, DEFAULT_HOST_GRAPHQL_PORT),\n];\n\nconst pickPublishedPort = (\n\trequested: ReadonlyArray<ContainerPortPublish>,\n\tactual: ReadonlyArray<ContainerPortPublish> | undefined,\n\tcontainerPort: number,\n\tfallbackHostPort: number,\n): ContainerPortPublish =>\n\tactual?.find((port) => port.containerPort === containerPort) ??\n\trequested.find((port) => port.containerPort === containerPort) ??\n\tportPublish(containerPort, fallbackHostPort);\n\nexport const selectReusablePortMapping = (\n\thandles: ReadonlyArray<ContainerHandle>,\n\tcontainerName: string,\n): ReadonlyArray<ContainerPortPublish> | undefined => {\n\tconst ports = handles.find((handle) => handle.name === containerName)?.ports;\n\tif (!hasSuiPortMapping(ports)) return undefined;\n\treturn resolvePublishedPortMapping([], ports);\n};\n\nconst findReusablePortMapping = (\n\truntime: ContainerRuntime,\n\tlabels: ContainerLabelTuple,\n\tcontainerName: string,\n): Effect.Effect<ReadonlyArray<ContainerPortPublish> | undefined, SuiPluginError> =>\n\truntime.inspectByLabels(labels).pipe(\n\t\tEffect.map((handles) => selectReusablePortMapping(handles, containerName)),\n\t\tEffect.mapError((cause) =>\n\t\t\tsuiPluginError(\n\t\t\t\t'container-start',\n\t\t\t\t`sui local mode: failed to inspect existing validator container: ${cause.reason}: ${cause.detail}`,\n\t\t\t\tcause,\n\t\t\t),\n\t\t),\n\t);\n\nconst hasSuiPortMapping = (\n\tports: ReadonlyArray<ContainerPortPublish> | undefined,\n): ports is ReadonlyArray<ContainerPortPublish> =>\n\tports !== undefined &&\n\tports.some((port) => port.containerPort === CONTAINER_RPC_PORT) &&\n\tports.some((port) => port.containerPort === CONTAINER_FAUCET_PORT) &&\n\tports.some((port) => port.containerPort === CONTAINER_GRAPHQL_PORT);\n\nconst portPublish = (containerPort: number, hostPort: number): ContainerPortPublish => ({\n\tcontainerPort,\n\thostPort,\n\thostIp: DOCKER_PUBLISH_HOST,\n});\n\nconst allocatePort = (\n\tportBroker: PortBroker,\n\towner: string,\n\tpreferredPort: number | undefined,\n\tlabel: 'rpc' | 'faucet' | 'graphql',\n): Effect.Effect<AllocatedPort, SuiPluginError, Scope.Scope> => {\n\tconst allocate = (\n\t\thint: number | undefined,\n\t): Effect.Effect<AllocatedPort, SuiPluginError, Scope.Scope> =>\n\t\tportBroker\n\t\t\t.allocate({\n\t\t\t\towner,\n\t\t\t\t...(hint === undefined ? {} : { preferredPort: hint }),\n\t\t\t\tprobeHost: DOCKER_PUBLISH_HOST,\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catchTag('PortBrokerError', (cause) =>\n\t\t\t\t\thint !== undefined && cause.reason === 'preferred-busy'\n\t\t\t\t\t\t? portBroker.allocate({ owner, probeHost: DOCKER_PUBLISH_HOST })\n\t\t\t\t\t\t: Effect.fail(cause),\n\t\t\t\t),\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'port-allocate',\n\t\t\t\t\t\t`sui local mode: failed to allocate ${label} host port ` +\n\t\t\t\t\t\t\t`(preferred ${hint ?? 'auto'}): ${cause.detail}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\treturn allocate(preferredPort);\n};\n\n// ---------------------------------------------------------------------------\n// Ready-probe coordination\n// ---------------------------------------------------------------------------\n\n/** Coordinated readiness gate. Both RPC + faucet must respond within\n * the outer deadline; each probe has its own per-fetch deadline so a\n * wedged endpoint surfaces by name. */\nconst waitForReady = (\n\trpcUrl: string,\n\tfaucetUrl: string,\n\tgraphqlUrl: string,\n\treadyTimeout: Duration.Duration,\n): Effect.Effect<void, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tconst readyTimeoutMs = Duration.toMillis(readyTimeout);\n\t\tconst rpcProbe: Effect.Effect<void, SuiPluginError> = waitForHttpEndpoint({\n\t\t\tendpoint: rpcUrl,\n\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\tintervalMs: 1_000,\n\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\trequestInit: {\n\t\t\t\tmethod: 'POST',\n\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tjsonrpc: '2.0',\n\t\t\t\t\tid: 1,\n\t\t\t\t\tmethod: 'sui_getLatestCheckpointSequenceNumber',\n\t\t\t\t\tparams: [],\n\t\t\t\t}),\n\t\t\t},\n\t\t\tvalidate: async (response) => {\n\t\t\t\tif (!response.ok) return false;\n\t\t\t\tconst body = (await response.json()) as { readonly result?: unknown };\n\t\t\t\treturn typeof body.result === 'string' || typeof body.result === 'number';\n\t\t\t},\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'rpc-probe',\n\t\t\t\t\t\t`sui local mode: RPC endpoint ${rpcUrl} did not become ready within ` +\n\t\t\t\t\t\t\t`${readyTimeoutMs}ms: ${formatUnknownError(cause)}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t),\n\t\t\tEffect.withSpan('devstack.plugin.sui.local.probe.rpc'),\n\t\t);\n\n\t\t// Faucet socket-level liveness — `GET /` returns \"OK\" as soon as\n\t\t// the HTTP server is bound. We do NOT POST `/v2/gas` here; that's\n\t\t// the funds-ready probe, which is paid for lazily on first call.\n\t\tconst faucetProbe: Effect.Effect<void, SuiPluginError> = waitForHttpEndpoint({\n\t\t\tendpoint: faucetUrl,\n\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\tintervalMs: 1_000,\n\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\tvalidate: (response) => response.status < 500,\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'faucet-probe',\n\t\t\t\t\t\t`sui local mode: faucet endpoint ${faucetUrl} did not become ready within ` +\n\t\t\t\t\t\t\t`${readyTimeoutMs}ms: ${formatUnknownError(cause)}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t),\n\t\t\tEffect.withSpan('devstack.plugin.sui.local.probe.faucet'),\n\t\t);\n\n\t\tconst graphqlProbe: Effect.Effect<void, SuiPluginError> = waitForHttpEndpoint({\n\t\t\tendpoint: graphqlUrl,\n\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\tintervalMs: 1_000,\n\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\tvalidate: (response) => response.status < 500,\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'graphql-probe',\n\t\t\t\t\t\t`sui local mode: GraphQL endpoint ${graphqlUrl} did not become ready within ` +\n\t\t\t\t\t\t\t`${readyTimeoutMs}ms: ${formatUnknownError(cause)}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t),\n\t\t\tEffect.withSpan('devstack.plugin.sui.local.probe.graphql'),\n\t\t);\n\n\t\tyield* Effect.all([rpcProbe, faucetProbe, graphqlProbe], { concurrency: 'unbounded' }).pipe(\n\t\t\tEffect.asVoid,\n\t\t);\n\t}).pipe(Effect.withSpan('devstack.plugin.sui.local.waitForReady'));\n\n// Chain-id fetch + waitForTransactionsReady builders live in\n// `shared-boot.ts` — see imports at the top of this file.\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst routedSuiUrl = (\n\tidentity: Identity,\n\tendpointName: string,\n\tport: number,\n): Effect.Effect<string, SuiPluginError> =>\n\troutedHostname(identity, endpointName).pipe(\n\t\tEffect.map((hostname) => renderUrl({ protocol: 'http', hostname, port })),\n\t\tEffect.mapError((cause) =>\n\t\t\tsuiPluginError(\n\t\t\t\t'container-start',\n\t\t\t\t`sui local mode: failed to construct router URL for ${endpointName}: ${cause.detail}`,\n\t\t\t\tcause,\n\t\t\t),\n\t\t),\n\t);\n"],"mappings":"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"}
1
+ {"version":3,"file":"local.mjs","names":["sharedFetchChainId"],"sources":["../../../../src/plugins/sui/mode/local.ts"],"sourcesContent":["// Sui plugin — local-container mode.\n//\n// In-stack Sui validator + faucet, running in the supervised docker\n// stack. Used during normal dev loops when the developer wants fresh,\n// fast, throwaway chain state with a working faucet.\n//\n// Boot sequence (load-bearing order):\n//\n// 1. Resolve image — vendored Dockerfile build via the\n// ContainerRuntime contract (caller `image` override honoured for\n// `{build}`; `{pull}` is deferred — see stub list in the README).\n// 2. Allocate + ensure container — `sui start --with-faucet=0.0.0.0:9123\n// --with-graphql=0.0.0.0:9125` with direct host port-publishing\n// for internal boot probes. User-facing URLs are router-fronted\n// named hosts; the direct host ports intentionally live in the\n// high private windows so they do not collide with router\n// entrypoints.\n// RecreatePolicy is `on-failure` so the writable layer (chain\n// state at `/root/.sui`) survives clean stop/start cycles, but an\n// unclean SIGKILL/137 exit recreates instead of resuming a suspect\n// RocksDB/checkpoint state. The runtime stops the container with\n// SIGINT so sui runs its ctrl-c shutdown path.\n// 3. Ready probe — gRPC service info, faucet `GET /`, and GraphQL\n// HTTP liveness. Per-fetch deadline + outer deadline.\n// 4. Fetch chain id from the now-responsive client (bounded timeout).\n// 5. Build `waitForTransactionsReady` — `Effect.cached` against a\n// real faucet funding tx; first failure caches for the scope.\n// Manual `invalidate` clears the memo.\n// 6. Return resolved `SuiClient`. Auto-tick is the no-op advancer\n// (localnet drives its own consensus).\n//\n// Faucet socket-level readiness does NOT imply funds-transferability.\n// The first `waitForTransactionsReady.wait` POSTs a real funding tx,\n// retrying on body-level `{Failure}` responses during the post-RPC /\n// pre-fund window.\n//\n// GraphQL indexer (on by default):\n// - The sui-tools base ships no embedded Postgres, so `--with-graphql`\n// reads from a separate DB. By default the sui plugin OWNS that DB as\n// a postgres SIDECAR (provisioned in the barrel before this body\n// runs); the caller can instead BYO a Postgres, or opt out entirely.\n// Either way this body receives a resolved `{ url, network }`\n// (`undefined` when indexer is off), attaches the validator to that\n// network, and passes the DSN in via `DEVSTACK_SUI_INDEXER_URL` so\n// the entrypoint appends `--with-graphql` + `--with-indexer=<dsn>`.\n//\n// What this body deliberately defers:\n// - Snapshot capture — the framework exists in the plugin's\n// snapshot.ts; this body produces the running container that the\n// orchestrator captures.\n\nimport { Duration, Effect, type Scope } from 'effect';\n\nimport { SuiGrpcClient } from '@mysten/sui/grpc';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tContainerRuntimeError,\n\tImageRef,\n\tContainerPortPublish,\n\tPortBindingReconciliation,\n} from '../../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple } from '../../../contracts/snapshotable.ts';\nimport type { Identity } from '../../../substrate/identity.ts';\nimport type { AllocatedPort, PortBroker } from '../../../substrate/runtime/port-broker/index.ts';\nimport { waitForHttpEndpoint } from '../../../substrate/runtime/http-probe.ts';\nimport { waitForProbe } from '../../../substrate/runtime/probes.ts';\nimport { setCurrentPluginPhase } from '../../../substrate/runtime/current-plugin.ts';\nimport { ensureManagedContainer } from '../../../substrate/runtime/managed-container.ts';\nimport { renderUrl, routedHostname } from '../../../substrate/runtime/routed-url.ts';\nimport { suiCliImageBuildContext } from '../move/index.ts';\nimport { suiPluginError, type SuiConfigError, type SuiPluginError } from '../errors.ts';\nimport { formatUnknownError } from '../../../substrate/runtime/format-unknown-error.ts';\nimport type { ResolvedSuiNetwork } from '../network-resolver.ts';\nimport { SuiLogAttr } from '../log-attrs.ts';\nimport {\n\tSUI_FAUCET_ENTRYPOINT_PORT,\n\tSUI_FAUCET_ENDPOINT_NAME,\n\tSUI_GRAPHQL_ENDPOINT_NAME,\n\tSUI_GRAPHQL_ENTRYPOINT_PORT,\n\tSUI_RPC_ENDPOINT_NAME,\n\tSUI_RPC_ENTRYPOINT_PORT,\n} from '../routable.ts';\nimport type { SuiClient } from './shared.ts';\nimport { toDockerHostGatewayUrl } from './shared.ts';\nimport {\n\tassembleSuiClient,\n\tbuildWaitForTransactionsReady,\n\tfetchChainId as sharedFetchChainId,\n\tmakeResolvedNetwork,\n} from './shared-boot.ts';\nimport type { SuiLocalOptions } from './spec.ts';\n\n/** Default ready-probe timeout for localnet.\n *\n * The pinned sui-tools image carries the embedded-fullnode resume fix\n * (sui #26884), so BOTH the validator AND the embedded fullnode resume\n * from their persisted dbs on every `sui start` — there is no per-boot\n * genesis re-sync. (Pre-#26884, each `sui start` minted the fullnode a\n * fresh key + empty db and it re-synced the whole chain from seq=0 at\n * ~50x realtime; that band no longer exists.) So both bands satisfy the\n * catch-up gate almost immediately:\n *\n * - cold boot — genesis + faucet bootstrap; empty store, live cadence\n * from the first sample.\n * - warm restart / snapshot restore — both nodes resume from disk;\n * the head is already at the persisted tip, so it stabilizes at\n * once.\n *\n * 180s is therefore generous headroom, not a re-sync budget: the gate\n * satisfies in a couple of polls on a healthy boot, and the timeout only\n * bounds a genuinely wedged boot (gRPC bound but head never stabilizing\n * → typed `grpc-probe` error). */\nexport const DEFAULT_LOCAL_READY_TIMEOUT = Duration.seconds(180);\n\n// In-container ports the sui binary binds on. These match the router\n// entrypoint ports; direct host publishes below use different high\n// ports so Traefik owns the public listener ports.\nconst CONTAINER_RPC_PORT = SUI_RPC_ENTRYPOINT_PORT;\nconst CONTAINER_FAUCET_PORT = SUI_FAUCET_ENTRYPOINT_PORT;\nconst CONTAINER_GRAPHQL_PORT = SUI_GRAPHQL_ENTRYPOINT_PORT;\n\n// Default host ports. Without `opts.ports`, these are preferences\n// brokered against the kernel before Docker publishes them.\nexport const DEFAULT_HOST_RPC_PORT = 51000;\nexport const DEFAULT_HOST_FAUCET_PORT = 50000;\nexport const DEFAULT_HOST_GRAPHQL_PORT = 51001;\nconst DOCKER_PUBLISH_HOST = '0.0.0.0' as const;\nexport const MAX_DOCKER_PUBLISH_PORT_RETRIES = 3;\nexport const LOCAL_VALIDATOR_STOP_GRACE_SECONDS = 30;\n\n/** Per-fetch deadline for the ready-probe HTTP calls. Without it a\n * hung fetch would block the outer ready deadline with no signal\n * about which probe wedged. */\nconst PROBE_FETCH_TIMEOUT_MS = 3000;\n\n/** Role label for sui's owned GraphQL-indexer postgres sidecar. Shared\n * const so the container label (in `bootPostgresSidecar`'s caller) and\n * the snapshotable capture tuple agree exactly. */\nexport const SUI_INDEXER_DB_ROLE = 'indexer-db' as const;\n\n/** Resolved indexer wiring for local mode. The URL is the PostgreSQL DSN\n * (sui-owned sidecar by default, or the caller's BYO DB); `network` is\n * the container network the validator joins to reach it.\n *\n * A chain re-genesis resets the sui-owned sidecar DB before boot:\n * absent or SIGKILLed validators cause the sidecar container to be\n * removed, while validator image identity is folded into the sidecar\n * `configHash` for image-driven re-genesis. Clean restarts resume it. */\nexport interface LocalIndexer {\n\treadonly url: string;\n\treadonly network: string;\n}\n\n/** Resolved local-mode boot artifacts. */\nexport interface LocalModeBootResult {\n\treadonly resolved: ResolvedSuiNetwork;\n\treadonly client: SuiClient;\n}\n\n/**\n * Build the local-mode boot Effect.\n *\n * `identity` is threaded in by the caller (the plugin barrel's acquire\n * body, which has access to the substrate's `IdentityContext` via the\n * outer composition layer); the body uses it to stamp the canonical\n * container label tuple so sweep / inventory are name-blind.\n *\n * `{pull}`, `{build}`, and vendored-build image branches are wired.\n */\nexport const bootLocalMode = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n\tportBroker: PortBroker,\n\topts: SuiLocalOptions,\n\tindexer: LocalIndexer | undefined,\n\t// Pre-resolved validator image. The barrel resolves it BEFORE the\n\t// indexer-db sidecar is provisioned (so the sidecar's `configHash` can\n\t// fold the validator's image ref — see `provisionLocalIndexer`) and\n\t// hands the SAME `ImageRef` here. Single source: the image the sidecar\n\t// hashed and the image this container runs are byte-identical, so they\n\t// cannot drift. `undefined` (the `indexer: false` / no-sidecar path)\n\t// resolves it inline.\n\tprebuiltImage?: ImageRef,\n): Effect.Effect<LocalModeBootResult, SuiPluginError | SuiConfigError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\t// ----- 1. Resolve image ---------------------------------------------\n\t\tyield* setCurrentPluginPhase('resolving Sui local image');\n\t\tconst image = prebuiltImage ?? (yield* resolveImage(runtime, identity, opts));\n\n\t\t// ----- 2. Allocate ports + ensure container --------------------------\n\t\tyield* setCurrentPluginPhase('creating Sui validator container');\n\t\tconst labels: ContainerLabelTuple = {\n\t\t\tapp: identity.app,\n\t\t\tstack: identity.stack,\n\t\t\tplugin: 'sui',\n\t\t\trole: 'validator',\n\t\t};\n\t\tconst containerName = `devstack-${identity.app}-${identity.stack}-sui-validator`;\n\t\tconst { handle, ports } = yield* ensureLocalValidatorContainer(\n\t\t\truntime,\n\t\t\tportBroker,\n\t\t\timage,\n\t\t\tlabels,\n\t\t\tcontainerName,\n\t\t\topts,\n\t\t\tindexer,\n\t\t);\n\n\t\t// GraphQL is gated on a resolved indexer DB (on by default via the\n\t\t// sui-owned sidecar; off when `indexer: false`). Without `indexer`\n\t\t// the entrypoint omits `--with-graphql`, so we skip its routed URL +\n\t\t// probe and resolve a graphql-less client.\n\t\tconst graphqlEnabled = indexer !== undefined;\n\n\t\t// ----- 3. Ready probes ----------------------------------------------\n\t\tconst publishedPorts = resolvePublishedPortMapping(ports, handle.ports);\n\t\tconst directRpcUrl = `http://127.0.0.1:${publishedPorts[0]!.hostPort}`;\n\t\tconst directFaucetUrl = `http://127.0.0.1:${publishedPorts[1]!.hostPort}`;\n\t\tconst directGraphqlUrl = `http://127.0.0.1:${publishedPorts[2]!.hostPort}`;\n\t\tconst rpcUrl = yield* routedSuiUrl(identity, SUI_RPC_ENDPOINT_NAME, SUI_RPC_ENTRYPOINT_PORT);\n\t\tconst faucetUrl = yield* routedSuiUrl(\n\t\t\tidentity,\n\t\t\tSUI_FAUCET_ENDPOINT_NAME,\n\t\t\tSUI_FAUCET_ENTRYPOINT_PORT,\n\t\t);\n\t\tconst graphqlUrl = graphqlEnabled\n\t\t\t? yield* routedSuiUrl(identity, SUI_GRAPHQL_ENDPOINT_NAME, SUI_GRAPHQL_ENTRYPOINT_PORT)\n\t\t\t: undefined;\n\t\tconst readyTimeout = opts.readyTimeout ?? DEFAULT_LOCAL_READY_TIMEOUT;\n\t\tconst sdkClient = new SuiGrpcClient({ baseUrl: directRpcUrl, network: 'localnet' });\n\n\t\tyield* setCurrentPluginPhase(\n\t\t\tgraphqlEnabled\n\t\t\t\t? 'waiting for Sui gRPC, faucet, and GraphQL'\n\t\t\t\t: 'waiting for Sui gRPC and faucet',\n\t\t);\n\t\tyield* waitForReady(\n\t\t\tsdkClient,\n\t\t\tdirectRpcUrl,\n\t\t\tdirectFaucetUrl,\n\t\t\tgraphqlEnabled ? directGraphqlUrl : undefined,\n\t\t\treadyTimeout,\n\t\t).pipe(Effect.annotateLogs({ [SuiLogAttr.container]: handle.name }));\n\n\t\t// Head-stabilization gate. `waitForReady` only proves the RPC\n\t\t// listener is BOUND, not that it serves the committed head. With the\n\t\t// #26884 resume fix both the validator and the embedded fullnode\n\t\t// resume from their persisted dbs (see DEFAULT_LOCAL_READY_TIMEOUT),\n\t\t// so there is no genesis re-sync — this gate is now a FAST safety\n\t\t// check, not a long wait: it polls the checkpoint head until it\n\t\t// stabilizes to live cadence, satisfying in a couple of polls on both\n\t\t// warm-restart and cold boot. Kept because it is cheap and closes a\n\t\t// real correctness window: it guarantees the RPC serves the persisted\n\t\t// head BEFORE downstream deploy-verify probes read object ids —\n\t\t// without it a probe firing into a still-settling head could read a\n\t\t// committed id as not-found and spuriously re-deploy with fresh ids.\n\t\tyield* setCurrentPluginPhase('waiting for Sui checkpoint head to stabilize');\n\t\tyield* waitForCheckpointCatchUp(sdkClient, directRpcUrl, readyTimeout).pipe(\n\t\t\tEffect.annotateLogs({ [SuiLogAttr.container]: handle.name }),\n\t\t);\n\n\t\t// ----- 4. Resolve chain id ------------------------------------------\n\t\tyield* setCurrentPluginPhase('fetching Sui chain id');\n\t\tconst chainId = yield* sharedFetchChainId(sdkClient);\n\n\t\t// ----- 5. waitForTransactionsReady (memoised) -----------------------\n\t\tyield* setCurrentPluginPhase('preparing Sui funds-ready gate');\n\t\tconst waitForTransactionsReady = yield* buildWaitForTransactionsReady(directFaucetUrl);\n\n\t\t// ----- 6. Assemble resolved SuiClient -------------------------------\n\t\t// Surface `buildImage` so package's path-(b) `docker run --rm`\n\t\t// build path can spawn a one-shot sui-cli container using the\n\t\t// SAME image we built/resolved here. Without this the package\n\t\t// plugin would have to re-resolve the image, doubling the\n\t\t// build-context hash work and risking digest drift.\n\t\tconst { client } = yield* assembleSuiClient({\n\t\t\tsdkClient,\n\t\t\tchainId,\n\t\t\trpcUrl,\n\t\t\tfaucetUrl,\n\t\t\tfundingFaucetUrl: directFaucetUrl,\n\t\t\t...(graphqlUrl !== undefined ? { graphqlUrl } : {}),\n\t\t\twaitForTransactionsReady,\n\t\t\tbuildImage: image,\n\t\t\thostGateway: {\n\t\t\t\trpcUrl: toDockerHostGatewayUrl(directRpcUrl),\n\t\t\t\tfaucetUrl: toDockerHostGatewayUrl(directFaucetUrl),\n\t\t\t\tgraphqlUrl: graphqlEnabled ? toDockerHostGatewayUrl(directGraphqlUrl) : null,\n\t\t\t},\n\t\t});\n\t\tconst resolved = makeResolvedNetwork({\n\t\t\tmode: 'local',\n\t\t\tchainId,\n\t\t\trpc: rpcUrl,\n\t\t\tfaucet: faucetUrl,\n\t\t\t...(graphqlUrl !== undefined ? { graphql: graphqlUrl } : {}),\n\t\t\tsource: 'default',\n\t\t});\n\t\treturn {\n\t\t\tresolved,\n\t\t\tclient,\n\t\t};\n\t});\n\n// ---------------------------------------------------------------------------\n// Image resolution — vendored Dockerfile build via `ContainerRuntime`\n// ---------------------------------------------------------------------------\n\nexport const resolveImage = (\n\truntime: ContainerRuntime,\n\tidentity: Identity,\n\topts: SuiLocalOptions,\n): Effect.Effect<ImageRef, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tif (opts.image && 'pull' in opts.image) {\n\t\t\tconst pullRef = opts.image.pull;\n\t\t\tif (runtime.pullImage === undefined) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'image-build',\n\t\t\t\t\t\t`sui local mode cannot pull image '${pullRef}' because the configured container runtime does not expose image pulls.`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn yield* runtime\n\t\t\t\t.pullImage(pullRef)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t\t'image-build',\n\t\t\t\t\t\t\t`sui local mode failed to pull image '${pullRef}': ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t}\n\t\tconst owner = {\n\t\t\tapp: identity.app,\n\t\t\tstack: identity.stack,\n\t\t\tplugin: 'sui',\n\t\t\trole: 'validator',\n\t\t} as const;\n\t\tconst vendored = suiCliImageBuildContext();\n\t\tconst buildCtx =\n\t\t\topts.image && 'build' in opts.image\n\t\t\t\t? {\n\t\t\t\t\t\tcontextPath: opts.image.build.context,\n\t\t\t\t\t\tdockerfile: opts.image.build.dockerfile ?? 'Dockerfile',\n\t\t\t\t\t\tbuildArgs: vendored.buildArgs,\n\t\t\t\t\t\towner,\n\t\t\t\t\t}\n\t\t\t\t: { ...vendored, owner };\n\t\treturn yield* runtime\n\t\t\t.ensureImage(buildCtx)\n\t\t\t.pipe(\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'image-build',\n\t\t\t\t\t\t`sui image build failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t});\n\ninterface LocalValidatorContainerResult {\n\treadonly handle: ContainerHandle;\n\treadonly ports: ReadonlyArray<ContainerPortPublish>;\n}\n\ninterface ResolvedPortMapping {\n\treadonly ports: ReadonlyArray<ContainerPortPublish>;\n\treadonly release: Effect.Effect<void>;\n}\n\nexport const ensureLocalValidatorContainer = (\n\truntime: ContainerRuntime,\n\tportBroker: PortBroker,\n\timage: ImageRef,\n\tlabels: ContainerLabelTuple,\n\tcontainerName: string,\n\topts: SuiLocalOptions,\n\tindexer: LocalIndexer | undefined,\n): Effect.Effect<LocalValidatorContainerResult, SuiPluginError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst reusablePorts =\n\t\t\topts.ports === undefined\n\t\t\t\t? yield* findReusablePortMapping(runtime, labels, containerName)\n\t\t\t\t: undefined;\n\t\tif (reusablePorts !== undefined) {\n\t\t\treturn yield* ensureLocalValidatorContainerAttempt({\n\t\t\t\truntime,\n\t\t\t\tportBroker,\n\t\t\t\timage,\n\t\t\t\tlabels,\n\t\t\t\tcontainerName,\n\t\t\t\topts,\n\t\t\t\tindexer,\n\t\t\t\tports: reusablePorts,\n\t\t\t\tattempt: 0,\n\t\t\t\treconciliation: 'adopt-existing',\n\t\t\t});\n\t\t}\n\t\treturn yield* ensureLocalValidatorContainerWithFreshPorts({\n\t\t\truntime,\n\t\t\tportBroker,\n\t\t\timage,\n\t\t\tlabels,\n\t\t\tcontainerName,\n\t\t\topts,\n\t\t\tindexer,\n\t\t\tattempt: 0,\n\t\t\treconciliation: opts.ports ? 'exact' : 'adopt-existing',\n\t\t});\n\t});\n\ninterface EnsureLocalValidatorContainerBase {\n\treadonly runtime: ContainerRuntime;\n\treadonly portBroker: PortBroker;\n\treadonly image: ImageRef;\n\treadonly labels: ContainerLabelTuple;\n\treadonly containerName: string;\n\treadonly opts: SuiLocalOptions;\n\treadonly indexer: LocalIndexer | undefined;\n}\n\nconst ensureLocalValidatorContainerWithFreshPorts = (\n\tparams: EnsureLocalValidatorContainerBase & {\n\t\treadonly attempt: number;\n\t\treadonly reconciliation: PortBindingReconciliation;\n\t},\n): Effect.Effect<LocalValidatorContainerResult, SuiPluginError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst mapping = yield* resolvePortMappingWithRelease(params.portBroker, params.opts.ports);\n\t\treturn yield* ensureLocalValidatorContainerAttempt({\n\t\t\t...params,\n\t\t\tports: mapping.ports,\n\t\t\treleasePorts: mapping.release,\n\t\t});\n\t});\n\nconst ensureLocalValidatorContainerAttempt = (\n\tparams: EnsureLocalValidatorContainerBase & {\n\t\treadonly ports: ReadonlyArray<ContainerPortPublish>;\n\t\treadonly releasePorts?: Effect.Effect<void>;\n\t\treadonly attempt: number;\n\t\treadonly reconciliation: PortBindingReconciliation;\n\t},\n): Effect.Effect<LocalValidatorContainerResult, SuiPluginError, Scope.Scope> =>\n\tensureManagedContainer({\n\t\truntime: params.runtime,\n\t\tlabels: params.labels,\n\t\tspec: {\n\t\t\tname: params.containerName,\n\t\t\timage: params.image,\n\t\t\t// Keep the writable layer only after clean exits. If Docker\n\t\t\t// escalates stop to SIGKILL (137), recreate on the next boot\n\t\t\t// instead of resuming suspect RocksDB/checkpoint state.\n\t\t\trecreate: 'on-failure',\n\t\t\tstopGraceSeconds: LOCAL_VALIDATOR_STOP_GRACE_SECONDS,\n\t\t\tstopSignal: 'SIGINT',\n\t\t\tports: params.ports,\n\t\t\tportBindingReconciliation: params.reconciliation,\n\t\t\t// Indexer (when on): join the indexer DB's network + hand the\n\t\t\t// entrypoint the DSN so it enables `--with-graphql` against it\n\t\t\t// (sui-owned sidecar by default, or a BYO DB). Omitted = RPC +\n\t\t\t// faucet only.\n\t\t\t//\n\t\t\t// The DSN is a credentialed env var, so it (and the sidecar's\n\t\t\t// POSTGRES_PASSWORD) bakes into the `docker commit` snapshot\n\t\t\t// image. Deliberate and accepted: the password is a deterministic\n\t\t\t// localnet credential (derived per app/stack/stackRoot) with no\n\t\t\t// production exposure.\n\t\t\t...(params.indexer !== undefined\n\t\t\t\t? {\n\t\t\t\t\t\tnetworkAttach: [params.indexer.network],\n\t\t\t\t\t\tenv: { DEVSTACK_SUI_INDEXER_URL: params.indexer.url },\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t},\n\t\tmapError: (cause) => cause,\n\t}).pipe(\n\t\tEffect.map((handle) => ({ handle, ports: params.ports })),\n\t\tEffect.catch((cause: ContainerRuntimeError) => {\n\t\t\tif (\n\t\t\t\tparams.opts.ports === undefined &&\n\t\t\t\tcause.reason === 'publish-port-conflict' &&\n\t\t\t\tparams.attempt < MAX_DOCKER_PUBLISH_PORT_RETRIES\n\t\t\t) {\n\t\t\t\treturn (params.releasePorts ?? Effect.void).pipe(\n\t\t\t\t\tEffect.andThen(\n\t\t\t\t\t\tensureLocalValidatorContainerWithFreshPorts({\n\t\t\t\t\t\t\t...params,\n\t\t\t\t\t\t\tattempt: params.attempt + 1,\n\t\t\t\t\t\t\treconciliation: 'exact',\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn Effect.fail(\n\t\t\t\tsuiPluginError(\n\t\t\t\t\t'container-start',\n\t\t\t\t\t`sui-validator container failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\tcause,\n\t\t\t\t),\n\t\t\t);\n\t\t}),\n\t);\n\n// ---------------------------------------------------------------------------\n// Port mapping — host:container pairs\n// ---------------------------------------------------------------------------\n\n// Exported test entry point: resolves the host:container port pairs\n// without surfacing the release handle (the live boot path uses\n// `resolvePortMappingWithRelease` directly to retain the release).\nexport const resolvePortMapping = (\n\tportBroker: PortBroker,\n\toverride: Readonly<Record<number, number>> | undefined,\n): Effect.Effect<ReadonlyArray<ContainerPortPublish>, SuiPluginError, Scope.Scope> =>\n\tresolvePortMappingWithRelease(portBroker, override).pipe(Effect.map((mapping) => mapping.ports));\n\nconst resolvePortMappingWithRelease = (\n\tportBroker: PortBroker,\n\toverride: Readonly<Record<number, number>> | undefined,\n): Effect.Effect<ResolvedPortMapping, SuiPluginError, Scope.Scope> => {\n\tconst pick = (containerPort: number, fallback: number): number => {\n\t\tif (!override) return fallback;\n\t\tconst hit = override[containerPort];\n\t\treturn typeof hit === 'number' ? hit : fallback;\n\t};\n\tif (override) {\n\t\treturn Effect.succeed({\n\t\t\tports: [\n\t\t\t\tportPublish(CONTAINER_RPC_PORT, pick(CONTAINER_RPC_PORT, DEFAULT_HOST_RPC_PORT)),\n\t\t\t\tportPublish(CONTAINER_FAUCET_PORT, pick(CONTAINER_FAUCET_PORT, DEFAULT_HOST_FAUCET_PORT)),\n\t\t\t\tportPublish(\n\t\t\t\t\tCONTAINER_GRAPHQL_PORT,\n\t\t\t\t\tpick(CONTAINER_GRAPHQL_PORT, DEFAULT_HOST_GRAPHQL_PORT),\n\t\t\t\t),\n\t\t\t],\n\t\t\trelease: Effect.void,\n\t\t});\n\t}\n\treturn Effect.gen(function* () {\n\t\tconst rpc = yield* allocatePort(portBroker, 'sui:rpc', DEFAULT_HOST_RPC_PORT, 'rpc');\n\t\tconst faucet = yield* allocatePort(\n\t\t\tportBroker,\n\t\t\t'sui:faucet',\n\t\t\tDEFAULT_HOST_FAUCET_PORT,\n\t\t\t'faucet',\n\t\t);\n\t\tconst graphql = yield* allocatePort(\n\t\t\tportBroker,\n\t\t\t'sui:graphql',\n\t\t\tDEFAULT_HOST_GRAPHQL_PORT,\n\t\t\t'graphql',\n\t\t);\n\t\treturn {\n\t\t\tports: [\n\t\t\t\tportPublish(CONTAINER_RPC_PORT, rpc.port),\n\t\t\t\tportPublish(CONTAINER_FAUCET_PORT, faucet.port),\n\t\t\t\tportPublish(CONTAINER_GRAPHQL_PORT, graphql.port),\n\t\t\t],\n\t\t\trelease: Effect.all([rpc.release, faucet.release, graphql.release], { discard: true }),\n\t\t};\n\t});\n};\n\nexport const resolvePublishedPortMapping = (\n\trequested: ReadonlyArray<ContainerPortPublish>,\n\tactual: ReadonlyArray<ContainerPortPublish> | undefined,\n): ReadonlyArray<ContainerPortPublish> => [\n\tpickPublishedPort(requested, actual, CONTAINER_RPC_PORT, DEFAULT_HOST_RPC_PORT),\n\tpickPublishedPort(requested, actual, CONTAINER_FAUCET_PORT, DEFAULT_HOST_FAUCET_PORT),\n\tpickPublishedPort(requested, actual, CONTAINER_GRAPHQL_PORT, DEFAULT_HOST_GRAPHQL_PORT),\n];\n\nconst pickPublishedPort = (\n\trequested: ReadonlyArray<ContainerPortPublish>,\n\tactual: ReadonlyArray<ContainerPortPublish> | undefined,\n\tcontainerPort: number,\n\tfallbackHostPort: number,\n): ContainerPortPublish =>\n\tactual?.find((port) => port.containerPort === containerPort) ??\n\trequested.find((port) => port.containerPort === containerPort) ??\n\tportPublish(containerPort, fallbackHostPort);\n\nexport const selectReusablePortMapping = (\n\thandles: ReadonlyArray<ContainerHandle>,\n\tcontainerName: string,\n): ReadonlyArray<ContainerPortPublish> | undefined => {\n\tconst ports = handles.find((handle) => handle.name === containerName)?.ports;\n\tif (!hasSuiPortMapping(ports)) return undefined;\n\treturn resolvePublishedPortMapping([], ports);\n};\n\nconst findReusablePortMapping = (\n\truntime: ContainerRuntime,\n\tlabels: ContainerLabelTuple,\n\tcontainerName: string,\n): Effect.Effect<ReadonlyArray<ContainerPortPublish> | undefined, SuiPluginError> =>\n\truntime.inspectByLabels(labels).pipe(\n\t\tEffect.map((handles) => selectReusablePortMapping(handles, containerName)),\n\t\tEffect.mapError((cause) =>\n\t\t\tsuiPluginError(\n\t\t\t\t'container-start',\n\t\t\t\t`sui local mode: failed to inspect existing validator container: ${cause.reason}: ${cause.detail}`,\n\t\t\t\tcause,\n\t\t\t),\n\t\t),\n\t);\n\nconst hasSuiPortMapping = (\n\tports: ReadonlyArray<ContainerPortPublish> | undefined,\n): ports is ReadonlyArray<ContainerPortPublish> =>\n\tports !== undefined &&\n\tports.some((port) => port.containerPort === CONTAINER_RPC_PORT) &&\n\tports.some((port) => port.containerPort === CONTAINER_FAUCET_PORT) &&\n\tports.some((port) => port.containerPort === CONTAINER_GRAPHQL_PORT);\n\nconst portPublish = (containerPort: number, hostPort: number): ContainerPortPublish => ({\n\tcontainerPort,\n\thostPort,\n\thostIp: DOCKER_PUBLISH_HOST,\n});\n\nconst allocatePort = (\n\tportBroker: PortBroker,\n\towner: string,\n\tpreferredPort: number | undefined,\n\tlabel: 'rpc' | 'faucet' | 'graphql',\n): Effect.Effect<AllocatedPort, SuiPluginError, Scope.Scope> => {\n\tconst allocate = (\n\t\thint: number | undefined,\n\t): Effect.Effect<AllocatedPort, SuiPluginError, Scope.Scope> =>\n\t\tportBroker\n\t\t\t.allocate({\n\t\t\t\towner,\n\t\t\t\t...(hint === undefined ? {} : { preferredPort: hint }),\n\t\t\t\tprobeHost: DOCKER_PUBLISH_HOST,\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catchTag('PortBrokerError', (cause) =>\n\t\t\t\t\thint !== undefined && cause.reason === 'preferred-busy'\n\t\t\t\t\t\t? portBroker.allocate({ owner, probeHost: DOCKER_PUBLISH_HOST })\n\t\t\t\t\t\t: Effect.fail(cause),\n\t\t\t\t),\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'port-allocate',\n\t\t\t\t\t\t`sui local mode: failed to allocate ${label} host port ` +\n\t\t\t\t\t\t\t`(preferred ${hint ?? 'auto'}): ${cause.detail}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\treturn allocate(preferredPort);\n};\n\n// ---------------------------------------------------------------------------\n// Ready-probe coordination\n// ---------------------------------------------------------------------------\n\n/** Coordinated readiness gate. RPC + faucet must respond within the\n * outer deadline; GraphQL is probed only when enabled (gated on the\n * external indexer). Each probe has its own per-fetch deadline so a\n * wedged endpoint surfaces by name. */\nconst waitForReady = (\n\tsdkClient: SuiGrpcClient,\n\trpcUrl: string,\n\tfaucetUrl: string,\n\tgraphqlUrl: string | undefined,\n\treadyTimeout: Duration.Duration,\n): Effect.Effect<void, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tconst readyTimeoutMs = Duration.toMillis(readyTimeout);\n\t\tconst grpcProbe: Effect.Effect<void, SuiPluginError> = waitForProbe({\n\t\t\tlabel: `${rpcUrl} (gRPC service info)`,\n\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\tintervalMs: 1_000,\n\t\t\tattemptTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\tprobe: () =>\n\t\t\t\tfetchServiceInfo(sdkClient, PROBE_FETCH_TIMEOUT_MS).pipe(\n\t\t\t\t\tEffect.map((info) =>\n\t\t\t\t\t\tinfo.chainId !== undefined || info.checkpointHeight !== undefined\n\t\t\t\t\t\t\t? true\n\t\t\t\t\t\t\t: { ready: false, detail: { reason: 'missing-service-info' } },\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'grpc-probe',\n\t\t\t\t\t\t`sui local mode: gRPC endpoint ${rpcUrl} did not become ready within ` +\n\t\t\t\t\t\t\t`${readyTimeoutMs}ms: ${formatUnknownError(cause)}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\t// Faucet socket-level liveness — `GET /` returns \"OK\" as soon as\n\t\t// the HTTP server is bound. We do NOT POST `/v2/gas` here; that's\n\t\t// the funds-ready probe, which is paid for lazily on first call.\n\t\tconst faucetProbe: Effect.Effect<void, SuiPluginError> = waitForHttpEndpoint({\n\t\t\tendpoint: faucetUrl,\n\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\tintervalMs: 1_000,\n\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\tvalidate: (response) => response.status < 500,\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'faucet-probe',\n\t\t\t\t\t\t`sui local mode: faucet endpoint ${faucetUrl} did not become ready within ` +\n\t\t\t\t\t\t\t`${readyTimeoutMs}ms: ${formatUnknownError(cause)}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t),\n\t\t);\n\n\t\tconst graphqlProbe: ReadonlyArray<Effect.Effect<void, SuiPluginError>> =\n\t\t\tgraphqlUrl === undefined\n\t\t\t\t? []\n\t\t\t\t: [\n\t\t\t\t\t\twaitForHttpEndpoint({\n\t\t\t\t\t\t\tendpoint: graphqlUrl,\n\t\t\t\t\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\t\t\t\t\tintervalMs: 1_000,\n\t\t\t\t\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\t\t\t\t\tvalidate: (response) => response.status < 500,\n\t\t\t\t\t\t}).pipe(\n\t\t\t\t\t\t\tEffect.mapError(\n\t\t\t\t\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t\t\t\t\t'graphql-probe',\n\t\t\t\t\t\t\t\t\t\t`sui local mode: GraphQL endpoint ${graphqlUrl} did not become ready within ` +\n\t\t\t\t\t\t\t\t\t\t\t`${readyTimeoutMs}ms: ${formatUnknownError(cause)}`,\n\t\t\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t];\n\n\t\tyield* Effect.all([grpcProbe, faucetProbe, ...graphqlProbe], { concurrency: 'unbounded' }).pipe(\n\t\t\tEffect.asVoid,\n\t\t);\n\t});\n\n// ---------------------------------------------------------------------------\n// Caught-up-to-head gate\n// ---------------------------------------------------------------------------\n\n/** Poll interval for the head-stabilization gate. With the #26884 resume\n * fix there is no routine re-sync, but a 1s interval still samples a wide\n * enough window to tell any transient fast burst (hundreds/poll) apart\n * from live cadence (a handful/poll) before declaring the head stable. */\nconst CATCH_UP_POLL_INTERVAL_MS = 1_000;\n\n/** Per-poll delta at or below which the head is considered to be moving\n * at LIVE cadence rather than fast-replay cadence. Localnet's narwhal/\n * bullshark consensus produces only a few checkpoints per second when\n * idle; replay produces hundreds per `CATCH_UP_POLL_INTERVAL_MS`. A\n * threshold of 25 sits well above live idle cadence and far below the\n * replay rate, so it cannot mistake live ticking for replay. */\nconst CATCH_UP_LIVE_CADENCE_DELTA = 25;\n\n/** Number of CONSECUTIVE live-cadence polls required before declaring\n * caught-up. Two consecutive small deltas rules out the moment replay\n * briefly stalls (e.g. a GC pause) from being read as caught-up: a\n * paused replay shows one small delta then resumes with a large one,\n * so it never strings two together. A genuinely caught-up validator\n * holds small deltas indefinitely. */\nconst CATCH_UP_STABLE_POLLS_REQUIRED = 2;\n\ninterface SuiServiceInfo {\n\treadonly chainId?: string;\n\treadonly checkpointHeight?: bigint;\n}\n\nconst fetchServiceInfo = (\n\tsdkClient: SuiGrpcClient,\n\ttimeoutMs: number,\n): Effect.Effect<SuiServiceInfo, unknown> =>\n\tEffect.tryPromise({\n\t\ttry: (signal) =>\n\t\t\tsdkClient.ledgerService.getServiceInfo({}, { abort: signal, timeout: timeoutMs }).response,\n\t\tcatch: (cause) => cause,\n\t});\n\n/** Fetch the latest checkpoint height via the gRPC service-info surface.\n * Returns the number, or `undefined` when the listener answered but did\n * not include a safely numeric checkpoint height. */\nconst fetchLatestCheckpoint = (\n\tsdkClient: SuiGrpcClient,\n): Effect.Effect<number | undefined, unknown> =>\n\tfetchServiceInfo(sdkClient, PROBE_FETCH_TIMEOUT_MS).pipe(\n\t\tEffect.map((body) => {\n\t\t\tif (body.checkpointHeight === undefined) return undefined;\n\t\t\tconst checkpoint = Number(body.checkpointHeight);\n\t\t\treturn Number.isSafeInteger(checkpoint) ? checkpoint : undefined;\n\t\t}),\n\t);\n\n/** One poll's verdict from the catch-up cadence evaluator. */\nexport type CatchUpVerdict =\n\t| { readonly caughtUp: true }\n\t| { readonly caughtUp: false; readonly detail: unknown };\n\n/** Build the stateful cadence evaluator the catch-up gate feeds samples\n * into. Pure + injectable so the cadence logic is unit-testable without\n * a live validator. Each `step(sample)` consumes one\n * gRPC service-info checkpoint-height reading:\n *\n * - `undefined` (listener answered, result unparseable) resets the\n * stability streak.\n * - the FIRST numeric sample only establishes a baseline (its delta is\n * `+Infinity`), so the gate always takes at least two samples before\n * it can declare caught-up — cheap on cold boot, correct on restore.\n * - a NEGATIVE delta (the head regressed — mid-re-sync / reset) resets\n * the streak; it is NOT counted as live cadence even though it is\n * `<= CATCH_UP_LIVE_CADENCE_DELTA`.\n * - a delta in `[0, CATCH_UP_LIVE_CADENCE_DELTA]` counts toward the\n * live-cadence streak; a larger delta (fast replay) resets it.\n * - `CATCH_UP_STABLE_POLLS_REQUIRED` consecutive live-cadence deltas →\n * caught-up. */\nexport const makeCatchUpEvaluator = (opts?: {\n\treadonly liveCadenceDelta?: number;\n\treadonly stablePollsRequired?: number;\n}): {\n\treadonly step: (sample: number | undefined) => CatchUpVerdict;\n\treadonly last: () => number | undefined;\n} => {\n\tconst liveCadenceDelta = opts?.liveCadenceDelta ?? CATCH_UP_LIVE_CADENCE_DELTA;\n\tconst stablePollsRequired = opts?.stablePollsRequired ?? CATCH_UP_STABLE_POLLS_REQUIRED;\n\tlet previous: number | undefined;\n\tlet stablePolls = 0;\n\treturn {\n\t\tstep: (sample) => {\n\t\t\tif (sample === undefined) {\n\t\t\t\tstablePolls = 0;\n\t\t\t\treturn { caughtUp: false, detail: { reason: 'unparseable-checkpoint' } };\n\t\t\t}\n\t\t\tconst delta = previous === undefined ? Number.POSITIVE_INFINITY : sample - previous;\n\t\t\tprevious = sample;\n\t\t\t// A NEGATIVE delta means the checkpoint sequence REGRESSED (the head\n\t\t\t// went backwards — e.g. an RPC reading a node mid-re-sync, or a\n\t\t\t// reset). That is NOT live cadence: a regression satisfies\n\t\t\t// `<= liveCadenceDelta`, so counting it toward the streak could\n\t\t\t// falsely declare caught-up while the store is still settling. Reset\n\t\t\t// the streak and keep waiting for forward, live-cadence progress.\n\t\t\tif (delta < 0) {\n\t\t\t\tstablePolls = 0;\n\t\t\t\treturn {\n\t\t\t\t\tcaughtUp: false,\n\t\t\t\t\tdetail: { current: sample, delta, stablePolls, regressed: true },\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (delta <= liveCadenceDelta) {\n\t\t\t\tstablePolls += 1;\n\t\t\t} else {\n\t\t\t\tstablePolls = 0;\n\t\t\t}\n\t\t\tif (stablePolls >= stablePollsRequired) return { caughtUp: true };\n\t\t\treturn { caughtUp: false, detail: { current: sample, delta, stablePolls } };\n\t\t},\n\t\tlast: () => previous,\n\t};\n};\n\n/** Head-stabilization gate.\n *\n * Polls the gRPC service-info checkpoint height and treats the head as\n * stable once the per-poll delta is at live cadence (`<= CATCH_UP_LIVE_\n * CADENCE_DELTA`/poll) and HOLDS there for `CATCH_UP_STABLE_POLLS_\n * REQUIRED` consecutive polls. With the #26884 resume fix both nodes\n * resume from disk, so there is no genesis re-sync to wait out: cold and\n * warm/restore boots alike are at live cadence from the first samples\n * and satisfy in a couple of polls. The fast-replay reset branch in the\n * evaluator is retained as a cheap guard for any transient burst rather\n * than a routine restart band.\n *\n * A wedged boot (gRPC bound but head never stabilizing) lapses the outer\n * deadline → typed `grpc-probe` error rather than hanging forever. */\nconst waitForCheckpointCatchUp = (\n\tsdkClient: SuiGrpcClient,\n\trpcUrl: string,\n\treadyTimeout: Duration.Duration,\n): Effect.Effect<void, SuiPluginError> =>\n\tEffect.gen(function* () {\n\t\tconst readyTimeoutMs = Duration.toMillis(readyTimeout);\n\t\tconst evaluator = makeCatchUpEvaluator();\n\n\t\treturn yield* waitForProbe({\n\t\t\tlabel: `${rpcUrl} (checkpoint catch-up)`,\n\t\t\ttimeoutMs: readyTimeoutMs,\n\t\t\tintervalMs: CATCH_UP_POLL_INTERVAL_MS,\n\t\t\tattemptTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\tprobe: () =>\n\t\t\t\tfetchLatestCheckpoint(sdkClient).pipe(\n\t\t\t\t\tEffect.map((current) => {\n\t\t\t\t\t\tconst verdict = evaluator.step(current);\n\t\t\t\t\t\treturn verdict.caughtUp ? true : { ready: false, detail: verdict.detail };\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t}).pipe(\n\t\t\tEffect.mapError(\n\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'grpc-probe',\n\t\t\t\t\t\t`sui local mode: checkpoint head did not stabilize within ` +\n\t\t\t\t\t\t\t`${readyTimeoutMs}ms (last seq=${evaluator.last() ?? 'n/a'}). With the #26884 ` +\n\t\t\t\t\t\t\t`resume fix both nodes resume from disk, so the head should reach live cadence ` +\n\t\t\t\t\t\t\t`almost immediately; a stall here points to a wedged boot, not a re-sync: ` +\n\t\t\t\t\t\t\t`${formatUnknownError(cause)}`,\n\t\t\t\t\t\tcause,\n\t\t\t\t\t),\n\t\t\t),\n\t\t);\n\t});\n\n// Chain-id fetch + waitForTransactionsReady builders live in\n// `shared-boot.ts` — see imports at the top of this file.\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst routedSuiUrl = (\n\tidentity: Identity,\n\tendpointName: string,\n\tport: number,\n): Effect.Effect<string, SuiPluginError> =>\n\troutedHostname(identity, endpointName).pipe(\n\t\tEffect.map((hostname) => renderUrl({ protocol: 'http', hostname, port })),\n\t\tEffect.mapError((cause) =>\n\t\t\tsuiPluginError(\n\t\t\t\t'container-start',\n\t\t\t\t`sui local mode: failed to construct router URL for ${endpointName}: ${cause.detail}`,\n\t\t\t\tcause,\n\t\t\t),\n\t\t),\n\t);\n"],"mappings":"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"}
@@ -1,18 +1,16 @@
1
- import { chainId } from "../../../substrate/brand.mjs";
2
1
  import { waitForHttpEndpoint } from "../../../substrate/runtime/http-probe.mjs";
3
2
  import { suiConfigError, suiPluginError } from "../errors.mjs";
4
3
  import { formatUnknownError } from "../../../substrate/runtime/format-unknown-error.mjs";
5
- import { SuiSpans } from "../spans.mjs";
6
- import { makeSuiChainProbe } from "../chain-probe.mjs";
7
4
  import { toDockerHostGatewayUrl } from "./shared.mjs";
5
+ import { makeSuiChainProbe } from "../chain-probe.mjs";
8
6
  import { Duration, Effect, SynchronizedRef } from "effect";
9
7
  //#region src/plugins/sui/mode/shared-boot.ts
10
8
  /** Default chain-id fetch timeout. The wire latency is the dominant
11
9
  * cost on real RPCs; 30 s is the documented ceiling. */
12
10
  const DEFAULT_CHAIN_ID_TIMEOUT = Duration.seconds(30);
13
11
  /** Fetch the chain identifier off a constructed grpc client. The
14
- * result is the bare string that downstream cache layers fold into
15
- * their state-store keys. */
12
+ * result is the bare string that the substrate's content-addressed
13
+ * cache folds into its keys (`(namespace, chainId, contentHash)`). */
16
14
  const fetchChainId = (sdkClient, opts) => {
17
15
  const timeout = opts?.timeout ?? DEFAULT_CHAIN_ID_TIMEOUT;
18
16
  const timeoutMs = Duration.toMillis(timeout);
@@ -28,12 +26,11 @@ const fetchChainId = (sdkClient, opts) => {
28
26
  }).pipe(Effect.timeoutOrElse({
29
27
  duration: timeout,
30
28
  orElse: () => Effect.fail(suiPluginError("chain-id-fetch", `sui chain-id fetch did not respond within ${timeoutMs}ms`))
31
- }), Effect.tap((id) => Effect.annotateCurrentSpan({ [SuiSpans.chain]: id })), Effect.withSpan(opts?.span ?? "devstack.plugin.sui.fetchChainId"));
29
+ }));
32
30
  };
33
31
  /** Per-attempt and total budget for the `waitForTransactionsReady`
34
32
  * retry loop. The 2 s spacing matches the upstream sui-faucet's
35
- * internal cadence; the 90 s ceiling matches the v3 service's
36
- * documented wall-clock. */
33
+ * internal cadence; the 90 s ceiling is the wall-clock budget. */
37
34
  const FUNDS_READY_RETRY_SPACING = Duration.seconds(2);
38
35
  const FUNDS_READY_TIMEOUT = Duration.seconds(90);
39
36
  /** Per-fetch deadline for the faucet probe POST. Bounded short so
@@ -114,26 +111,25 @@ const makeSdkShim = (sdkClient) => ({
114
111
  * `fork: null` discriminator is invariant for non-fork modes; the
115
112
  * fork builder constructs its own client with the admin surface.
116
113
  *
117
- * `chain` is accepted as a bare string and branded to `ChainId` at
118
- * this single boundary every consumer downstream reads the
119
- * branded shape so capability-key constructors (`chainProbe…`,
120
- * `faucet…`) accept it without a cast.
114
+ * `chainId` is a plain string value every consumer downstream reads
115
+ * it directly and capability-key constructors (`chainProbe…`,
116
+ * `faucet…`) key on the string.
121
117
  *
122
- * Returns an `Effect` on the `SuiConfigError` channel: the empty-chain
118
+ * Returns an `Effect` on the `SuiConfigError` channel: the empty-chainId
123
119
  * guard must surface as a typed, `catchTag`-able failure. Calling it
124
120
  * un-yielded as a sync function (as it once was) turned a thrown
125
121
  * `SuiConfigError` into a DEFECT inside the mode-boot `Effect.gen`
126
122
  * bodies — a hidden crash the channel could never recover (mirrors the
127
123
  * fix already applied to `auto-tick.ts`; STYLE_GUIDE §2). */
128
124
  const assembleSuiClient = (parts) => Effect.gen(function* () {
129
- if (typeof parts.chain !== "string" || parts.chain.length === 0) return yield* Effect.fail(suiConfigError({
130
- field: "chain",
125
+ if (typeof parts.chainId !== "string" || parts.chainId.length === 0) return yield* Effect.fail(suiConfigError({
126
+ field: "chainId",
131
127
  message: "sui.assembleSuiClient: chain id must be a non-empty string",
132
128
  hint: "check fetchChainId / network resolver returned a real chain id"
133
129
  }));
134
- const chain = parts.chain;
130
+ const chainId = parts.chainId;
135
131
  const sdkShim = makeSdkShim(parts.sdkClient);
136
- const chainProbe = makeSuiChainProbe(sdkShim, chain);
132
+ const chainProbe = makeSuiChainProbe(sdkShim, chainId);
137
133
  return {
138
134
  client: {
139
135
  sdk: sdkShim,
@@ -146,7 +142,7 @@ const assembleSuiClient = (parts) => Effect.gen(function* () {
146
142
  faucetUrl: parts.faucetUrl === void 0 ? null : toDockerHostGatewayUrl(parts.faucetUrl),
147
143
  graphqlUrl: parts.graphqlUrl === void 0 ? null : toDockerHostGatewayUrl(parts.graphqlUrl)
148
144
  },
149
- chain: chainId(chain),
145
+ chainId,
150
146
  waitForTransactionsReady: parts.waitForTransactionsReady,
151
147
  chainProbe,
152
148
  fork: null,
@@ -157,13 +153,12 @@ const assembleSuiClient = (parts) => Effect.gen(function* () {
157
153
  };
158
154
  });
159
155
  /** Shape the resolved network record the boot builders all hand
160
- * back. The substrate-network mapping is uniform per mode. Brands
161
- * the raw chain string at this boundary so consumers downstream
162
- * (codegen, capabilities, walrus/seal deps) read a `ChainId` and
163
- * don't re-wrap. */
156
+ * back. The substrate-network mapping is uniform per mode. The raw
157
+ * chainId string flows through verbatim consumers downstream (codegen,
158
+ * capabilities, walrus/seal deps) read it as a plain string value. */
164
159
  const makeResolvedNetwork = (parts) => ({
165
160
  mode: parts.mode,
166
- chain: chainId(parts.chain),
161
+ chainId: parts.chainId,
167
162
  rpc: parts.rpc,
168
163
  source: parts.source,
169
164
  ...parts.faucet !== void 0 ? { faucet: parts.faucet } : {},
@@ -1 +1 @@
1
- {"version":3,"file":"shared-boot.mjs","names":["brandChainId"],"sources":["../../../../src/plugins/sui/mode/shared-boot.ts"],"sourcesContent":["// Sui plugin — boot helpers shared across local / external / live modes.\n//\n// What lives here (and why):\n//\n// - `fetchChainId(client, opts?)` — bounded chain-id probe. The\n// only readiness sentinel for external + live; local treats it\n// as the chain-id capture step after the multi-probe gate has\n// succeeded.\n// - `buildWaitForTransactionsReady(faucetUrl, opts?)` — memoised\n// funds-ready gate for faucet-bearing networks. `Effect.cached`\n// with a manual-invalidation surface (the distilled-doc\n// opportunity called out in `mode/shared.ts`).\n// - `noopWaitForTransactionsReady` — trivially-succeeding gate for\n// faucet-less networks (live mainnet, fork).\n// - `assembleSuiClient(...)` — collapses the boilerplate that\n// local/local-rpc/live all repeat (sdk shim + chainProbe + the\n// `fork: null` discriminator).\n//\n// Why not jam this into `mode/local.ts`: external + live can't\n// import from `local.ts` without dragging the container-runtime\n// import path along; the helpers below are wire-only and have NO\n// substrate-context dependencies.\n\nimport { Duration, Effect, SynchronizedRef, type Scope } from 'effect';\n\nimport type { SuiGrpcClient } from '@mysten/sui/grpc';\n\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport { chainId as brandChainId } from '../../../substrate/brand.ts';\nimport { waitForHttpEndpoint } from '../../../substrate/runtime/http-probe.ts';\nimport { makeSuiChainProbe, type SuiSdkShim, type SuiProbeKey } from '../chain-probe.ts';\nimport {\n\tsuiConfigError,\n\tsuiPluginError,\n\ttype SuiConfigError,\n\ttype SuiPluginError,\n} from '../errors.ts';\nimport { formatUnknownError } from '../../../substrate/runtime/format-unknown-error.ts';\nimport type { ResolvedSuiNetwork } from '../network-resolver.ts';\nimport { SuiSpans } from '../spans.ts';\nimport { toDockerHostGatewayUrl, type SuiClient, type WaitForTransactionsReady } from './shared.ts';\n\n// ---------------------------------------------------------------------------\n// Chain-id fetch — bounded, typed-error\n// ---------------------------------------------------------------------------\n\n/** Default chain-id fetch timeout. The wire latency is the dominant\n * cost on real RPCs; 30 s is the documented ceiling. */\nexport const DEFAULT_CHAIN_ID_TIMEOUT = Duration.seconds(30);\n\n/** Fetch the chain identifier off a constructed grpc client. The\n * result is the bare string that downstream cache layers fold into\n * their state-store keys. */\nexport const fetchChainId = (\n\tsdkClient: SuiGrpcClient,\n\topts?: { readonly timeout?: Duration.Duration; readonly span?: string },\n): Effect.Effect<string, SuiPluginError> => {\n\tconst timeout = opts?.timeout ?? DEFAULT_CHAIN_ID_TIMEOUT;\n\tconst timeoutMs = Duration.toMillis(timeout);\n\treturn Effect.tryPromise({\n\t\ttry: (signal) =>\n\t\t\tsdkClient.ledgerService\n\t\t\t\t.getServiceInfo({}, { abort: signal, timeout: timeoutMs })\n\t\t\t\t.response.then((response) => {\n\t\t\t\t\tif (!response.chainId) {\n\t\t\t\t\t\tthrow new Error('Chain identifier not found in service info');\n\t\t\t\t\t}\n\t\t\t\t\treturn response.chainId;\n\t\t\t\t}),\n\t\tcatch: (cause): SuiPluginError =>\n\t\t\tsuiPluginError(\n\t\t\t\t'chain-id-fetch',\n\t\t\t\t`sui chain-id fetch failed: ${formatUnknownError(cause)}`,\n\t\t\t\tcause,\n\t\t\t),\n\t}).pipe(\n\t\tEffect.timeoutOrElse({\n\t\t\tduration: timeout,\n\t\t\torElse: (): Effect.Effect<string, SuiPluginError> =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'chain-id-fetch',\n\t\t\t\t\t\t`sui chain-id fetch did not respond within ${timeoutMs}ms`,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t}),\n\t\tEffect.tap((id: string) => Effect.annotateCurrentSpan({ [SuiSpans.chain]: id })),\n\t\tEffect.withSpan(opts?.span ?? 'devstack.plugin.sui.fetchChainId'),\n\t);\n};\n\n// ---------------------------------------------------------------------------\n// waitForTransactionsReady — memoised, with manual invalidation\n// ---------------------------------------------------------------------------\n\n/** Per-attempt and total budget for the `waitForTransactionsReady`\n * retry loop. The 2 s spacing matches the upstream sui-faucet's\n * internal cadence; the 90 s ceiling matches the v3 service's\n * documented wall-clock. */\nconst FUNDS_READY_RETRY_SPACING = Duration.seconds(2);\nconst FUNDS_READY_TIMEOUT = Duration.seconds(90);\n\n/** Per-fetch deadline for the faucet probe POST. Bounded short so\n * the outer retry loop hammers quickly. */\nconst PROBE_FETCH_TIMEOUT_MS = 3000;\n\n/** Probe recipient for the faucet funds-ready check. A literal\n * zero-balance address so the real call doesn't pollute caller wallets;\n * any well-formed address works. */\nconst FAUCET_PROBE_RECIPIENT = '0x0000000000000000000000000000000000000000000000000000000000000001';\n\n/**\n * Build the funds-transferable gate against a real HTTP faucet.\n * Memoised — first successful resolution sticks for the scope; the\n * manual `invalidate` surface clears the memo so long-running\n * supervisors can re-probe without a full restart.\n */\nexport const buildWaitForTransactionsReady = (\n\tfaucetUrl: string,\n\topts?: {\n\t\treadonly retrySpacing?: Duration.Duration;\n\t\treadonly timeout?: Duration.Duration;\n\t},\n): Effect.Effect<WaitForTransactionsReady, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst retrySpacing = opts?.retrySpacing ?? FUNDS_READY_RETRY_SPACING;\n\t\tconst timeout = opts?.timeout ?? FUNDS_READY_TIMEOUT;\n\t\t// SynchronizedRef serialises the get-or-init transition so two\n\t\t// concurrent callers can't both observe `null` and both build\n\t\t// their own `Effect.cached` instance (CAS-style guard against\n\t\t// the build-once race).\n\t\tconst ref = yield* SynchronizedRef.make<Effect.Effect<void, SuiPluginError> | null>(null);\n\n\t\tconst makeProbe = (): Effect.Effect<void, SuiPluginError> =>\n\t\t\twaitForHttpEndpoint({\n\t\t\t\tendpoint: `${faucetUrl}/v2/gas`,\n\t\t\t\ttimeoutMs: Duration.toMillis(timeout),\n\t\t\t\tintervalMs: Duration.toMillis(retrySpacing),\n\t\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\t\trequestInit: {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tFixedAmountRequest: { recipient: FAUCET_PROBE_RECIPIENT },\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tvalidate: async (response) => {\n\t\t\t\t\tif (!response.ok) throw new Error(`faucet HTTP ${response.status}`);\n\t\t\t\t\tconst body = (await response.json()) as { status?: unknown };\n\t\t\t\t\tconst status = body.status;\n\t\t\t\t\tif (typeof status === 'object' && status !== null && 'Failure' in status) {\n\t\t\t\t\t\tconst failure = (status as { Failure: unknown }).Failure;\n\t\t\t\t\t\tthrow new Error(`faucet body: Failure ${JSON.stringify(failure)}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t}).pipe(\n\t\t\t\tEffect.mapError(\n\t\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t\t'wait-funds-ready',\n\t\t\t\t\t\t\t`sui faucet at ${faucetUrl} did not become funds-transferable within ` +\n\t\t\t\t\t\t\t\t`${Duration.toMillis(timeout)}ms (still returning body-level Failure or 5xx): ` +\n\t\t\t\t\t\t\t\tformatUnknownError(cause),\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\n\t\t// `modifyEffect` atomically observes-then-updates inside a\n\t\t// serialised critical section: at most one fiber builds the\n\t\t// memoised probe, every other caller reads it back. This\n\t\t// closes the read-build-write race the plain Ref had.\n\t\tconst getOrInit: Effect.Effect<Effect.Effect<void, SuiPluginError>> =\n\t\t\tSynchronizedRef.modifyEffect(ref, (existing) =>\n\t\t\t\texisting !== null\n\t\t\t\t\t? Effect.succeed([existing, existing] as const)\n\t\t\t\t\t: Effect.cached(makeProbe()).pipe(Effect.map((cached) => [cached, cached] as const)),\n\t\t\t);\n\n\t\treturn {\n\t\t\twait: getOrInit.pipe(Effect.flatMap((eff) => eff)),\n\t\t\tinvalidate: SynchronizedRef.set(ref, null),\n\t\t};\n\t});\n\n/** Trivially-succeeding gate. Used by faucet-less networks (live\n * mainnet, fork — fork funds via impersonation, not HTTP). */\nexport const noopWaitForTransactionsReady: WaitForTransactionsReady = {\n\twait: Effect.void,\n\tinvalidate: Effect.void,\n};\n\n// ---------------------------------------------------------------------------\n// SuiClient assembly — collapses the per-mode boilerplate\n// ---------------------------------------------------------------------------\n\n/** Build the `SuiSdkShim` over a constructed grpc client.\n * Account/Coin/Wallet read through this seam, so we expose\n * `executeTransaction` + `waitForTransaction` in addition to the\n * read methods needed by the chain probe.\n *\n * Every read/write goes through `sdkClient.core.*` — the gRPC\n * TransportMethods surface from `@mysten/sui`. JSON-RPC is\n * deprecated; do not reintroduce it. */\nexport const makeSdkShim = (sdkClient: SuiGrpcClient): SuiSdkShim => ({\n\tcore: {\n\t\tgetObject: (args) => sdkClient.core.getObject(args),\n\t\tgetTransaction: (args) => sdkClient.core.getTransaction(args),\n\t\tgetBalance: (args) => sdkClient.core.getBalance(args),\n\t\tlistCoins: (args) => sdkClient.core.listCoins(args),\n\t\t// Extended surfaces — used by the account plugin's sign + execute\n\t\t// closure. Routes through `client.core.*` (the cross-transport\n\t\t// canonical surface per STYLE_GUIDE §16). The SDK accepts a\n\t\t// mutable `signatures: string[]`; the shim's readonly signature\n\t\t// is widened with a copy at the boundary.\n\t\texecuteTransaction: (args) =>\n\t\t\tsdkClient.core.executeTransaction({\n\t\t\t\ttransaction: args.transaction,\n\t\t\t\tsignatures: [...args.signatures],\n\t\t\t\t...(args.include !== undefined ? { include: args.include } : {}),\n\t\t\t}),\n\t\twaitForTransaction: (args) =>\n\t\t\tsdkClient.core.waitForTransaction({\n\t\t\t\tdigest: args.digest,\n\t\t\t\t...(args.timeout !== undefined ? { timeout: args.timeout } : {}),\n\t\t\t}),\n\t},\n\t// Client passthrough — Package's publish-tx builder hands this to\n\t// `Transaction.build({ client })`; sibling plugins reach\n\t// `client.core.*` directly through this slot. Typed as\n\t// ClientWithCoreApi via SuiSdkShim.client.\n\tclient: sdkClient,\n});\n\n/** Assemble a `SuiClient` from the per-mode building blocks. The\n * `fork: null` discriminator is invariant for non-fork modes; the\n * fork builder constructs its own client with the admin surface.\n *\n * `chain` is accepted as a bare string and branded to `ChainId` at\n * this single boundary — every consumer downstream reads the\n * branded shape so capability-key constructors (`chainProbe…`,\n * `faucet…`) accept it without a cast.\n *\n * Returns an `Effect` on the `SuiConfigError` channel: the empty-chain\n * guard must surface as a typed, `catchTag`-able failure. Calling it\n * un-yielded as a sync function (as it once was) turned a thrown\n * `SuiConfigError` into a DEFECT inside the mode-boot `Effect.gen`\n * bodies — a hidden crash the channel could never recover (mirrors the\n * fix already applied to `auto-tick.ts`; STYLE_GUIDE §2). */\nexport const assembleSuiClient = (parts: {\n\treadonly sdkClient: SuiGrpcClient;\n\treadonly chain: string;\n\treadonly rpcUrl: string;\n\treadonly faucetUrl?: string;\n\treadonly fundingFaucetUrl?: string;\n\treadonly graphqlUrl?: string;\n\treadonly waitForTransactionsReady: WaitForTransactionsReady;\n\t/** Image ref consumed by package's path (b) (`docker run --rm`)\n\t * build path. `null` for modes that have no in-stack image\n\t * (external + live). */\n\treadonly buildImage?: import('../../../contracts/container-runtime.ts').ImageRef | null;\n\t/** Container-reachable mirrors. Local mode resolves public URLs\n\t * through the router but sibling containers still need direct\n\t * host-gateway URLs during boot. */\n\treadonly hostGateway?: SuiClient['hostGateway'];\n}): Effect.Effect<\n\t{\n\t\treadonly client: SuiClient;\n\t\treadonly sdkShim: SuiSdkShim;\n\t\treadonly chainProbe: ChainProbe<SuiProbeKey>;\n\t},\n\tSuiConfigError\n> =>\n\tEffect.gen(function* () {\n\t\t// Defense-in-depth — `fetchChainId` should never resolve to an\n\t\t// empty string (RPC rejects that earlier), but a branded empty\n\t\t// string would silently fold into every downstream cache key. A\n\t\t// caller-pinned `chain: ''` (e.g. `.live.custom({ chain: '' })`)\n\t\t// reaches here, so fail on the typed channel rather than throw.\n\t\tif (typeof parts.chain !== 'string' || parts.chain.length === 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tsuiConfigError({\n\t\t\t\t\tfield: 'chain',\n\t\t\t\t\tmessage: 'sui.assembleSuiClient: chain id must be a non-empty string',\n\t\t\t\t\thint: 'check fetchChainId / network resolver returned a real chain id',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst chain = parts.chain;\n\t\tconst sdkShim = makeSdkShim(parts.sdkClient);\n\t\tconst chainProbe = makeSuiChainProbe(sdkShim, chain);\n\t\tconst client: SuiClient = {\n\t\t\tsdk: sdkShim,\n\t\t\trpcUrl: parts.rpcUrl,\n\t\t\tfaucetUrl: parts.faucetUrl ?? null,\n\t\t\tfundingFaucetUrl: parts.fundingFaucetUrl ?? parts.faucetUrl ?? null,\n\t\t\tgraphqlUrl: parts.graphqlUrl ?? null,\n\t\t\thostGateway: parts.hostGateway ?? {\n\t\t\t\trpcUrl: toDockerHostGatewayUrl(parts.rpcUrl),\n\t\t\t\tfaucetUrl: parts.faucetUrl === undefined ? null : toDockerHostGatewayUrl(parts.faucetUrl),\n\t\t\t\tgraphqlUrl:\n\t\t\t\t\tparts.graphqlUrl === undefined ? null : toDockerHostGatewayUrl(parts.graphqlUrl),\n\t\t\t},\n\t\t\tchain: brandChainId(chain),\n\t\t\twaitForTransactionsReady: parts.waitForTransactionsReady,\n\t\t\tchainProbe,\n\t\t\tfork: null,\n\t\t\tbuildImage: parts.buildImage ?? null,\n\t\t};\n\t\treturn { client, sdkShim, chainProbe };\n\t});\n\n/** Shape the resolved network record the boot builders all hand\n * back. The substrate-network mapping is uniform per mode. Brands\n * the raw chain string at this boundary so consumers downstream\n * (codegen, capabilities, walrus/seal deps) read a `ChainId` and\n * don't re-wrap. */\nexport const makeResolvedNetwork = (parts: {\n\treadonly mode: ResolvedSuiNetwork['mode'];\n\treadonly chain: string;\n\treadonly rpc: string;\n\treadonly faucet?: string;\n\treadonly graphql?: string;\n\treadonly source: ResolvedSuiNetwork['source'];\n\treadonly checkpoint?: string;\n\treadonly forkUpstream?: ResolvedSuiNetwork['forkUpstream'];\n}): ResolvedSuiNetwork => ({\n\tmode: parts.mode,\n\tchain: brandChainId(parts.chain),\n\trpc: parts.rpc,\n\tsource: parts.source,\n\t...(parts.faucet !== undefined ? { faucet: parts.faucet } : {}),\n\t...(parts.graphql !== undefined ? { graphql: parts.graphql } : {}),\n\t...(parts.checkpoint !== undefined ? { checkpoint: parts.checkpoint } : {}),\n\t...(parts.forkUpstream !== undefined ? { forkUpstream: parts.forkUpstream } : {}),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-boot.mjs","names":[],"sources":["../../../../src/plugins/sui/mode/shared-boot.ts"],"sourcesContent":["// Sui plugin — boot helpers shared across local / external / live modes.\n//\n// What lives here (and why):\n//\n// - `fetchChainId(client, opts?)` — bounded chain-id probe. The\n// only readiness sentinel for external + live; local treats it\n// as the chain-id capture step after the multi-probe gate has\n// succeeded.\n// - `buildWaitForTransactionsReady(faucetUrl, opts?)` — memoised\n// funds-ready gate for faucet-bearing networks. `Effect.cached`\n// with a manual-invalidation surface (the distilled-doc\n// opportunity called out in `mode/shared.ts`).\n// - `noopWaitForTransactionsReady` — trivially-succeeding gate for\n// faucet-less networks (live mainnet, fork).\n// - `assembleSuiClient(...)` — collapses the boilerplate that\n// local/local-rpc/live all repeat (sdk shim + chainProbe + the\n// `fork: null` discriminator).\n//\n// Why not jam this into `mode/local.ts`: external + live can't\n// import from `local.ts` without dragging the container-runtime\n// import path along; the helpers below are wire-only and have NO\n// substrate-context dependencies.\n\nimport { Duration, Effect, SynchronizedRef, type Scope } from 'effect';\n\nimport type { SuiGrpcClient } from '@mysten/sui/grpc';\n\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport { waitForHttpEndpoint } from '../../../substrate/runtime/http-probe.ts';\nimport { makeSuiChainProbe, type SuiSdkShim, type SuiProbeKey } from '../chain-probe.ts';\nimport {\n\tsuiConfigError,\n\tsuiPluginError,\n\ttype SuiConfigError,\n\ttype SuiPluginError,\n} from '../errors.ts';\nimport { formatUnknownError } from '../../../substrate/runtime/format-unknown-error.ts';\nimport type { ResolvedSuiNetwork } from '../network-resolver.ts';\nimport { toDockerHostGatewayUrl, type SuiClient, type WaitForTransactionsReady } from './shared.ts';\n\n// ---------------------------------------------------------------------------\n// Chain-id fetch — bounded, typed-error\n// ---------------------------------------------------------------------------\n\n/** Default chain-id fetch timeout. The wire latency is the dominant\n * cost on real RPCs; 30 s is the documented ceiling. */\nexport const DEFAULT_CHAIN_ID_TIMEOUT = Duration.seconds(30);\n\n/** Fetch the chain identifier off a constructed grpc client. The\n * result is the bare string that the substrate's content-addressed\n * cache folds into its keys (`(namespace, chainId, contentHash)`). */\nexport const fetchChainId = (\n\tsdkClient: SuiGrpcClient,\n\topts?: { readonly timeout?: Duration.Duration },\n): Effect.Effect<string, SuiPluginError> => {\n\tconst timeout = opts?.timeout ?? DEFAULT_CHAIN_ID_TIMEOUT;\n\tconst timeoutMs = Duration.toMillis(timeout);\n\treturn Effect.tryPromise({\n\t\ttry: (signal) =>\n\t\t\tsdkClient.ledgerService\n\t\t\t\t.getServiceInfo({}, { abort: signal, timeout: timeoutMs })\n\t\t\t\t.response.then((response) => {\n\t\t\t\t\tif (!response.chainId) {\n\t\t\t\t\t\tthrow new Error('Chain identifier not found in service info');\n\t\t\t\t\t}\n\t\t\t\t\treturn response.chainId;\n\t\t\t\t}),\n\t\tcatch: (cause): SuiPluginError =>\n\t\t\tsuiPluginError(\n\t\t\t\t'chain-id-fetch',\n\t\t\t\t`sui chain-id fetch failed: ${formatUnknownError(cause)}`,\n\t\t\t\tcause,\n\t\t\t),\n\t}).pipe(\n\t\tEffect.timeoutOrElse({\n\t\t\tduration: timeout,\n\t\t\torElse: (): Effect.Effect<string, SuiPluginError> =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t'chain-id-fetch',\n\t\t\t\t\t\t`sui chain-id fetch did not respond within ${timeoutMs}ms`,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t}),\n\t);\n};\n\n// ---------------------------------------------------------------------------\n// waitForTransactionsReady — memoised, with manual invalidation\n// ---------------------------------------------------------------------------\n\n/** Per-attempt and total budget for the `waitForTransactionsReady`\n * retry loop. The 2 s spacing matches the upstream sui-faucet's\n * internal cadence; the 90 s ceiling is the wall-clock budget. */\nconst FUNDS_READY_RETRY_SPACING = Duration.seconds(2);\nconst FUNDS_READY_TIMEOUT = Duration.seconds(90);\n\n/** Per-fetch deadline for the faucet probe POST. Bounded short so\n * the outer retry loop hammers quickly. */\nconst PROBE_FETCH_TIMEOUT_MS = 3000;\n\n/** Probe recipient for the faucet funds-ready check. A literal\n * zero-balance address so the real call doesn't pollute caller wallets;\n * any well-formed address works. */\nconst FAUCET_PROBE_RECIPIENT = '0x0000000000000000000000000000000000000000000000000000000000000001';\n\n/**\n * Build the funds-transferable gate against a real HTTP faucet.\n * Memoised — first successful resolution sticks for the scope; the\n * manual `invalidate` surface clears the memo so long-running\n * supervisors can re-probe without a full restart.\n */\nexport const buildWaitForTransactionsReady = (\n\tfaucetUrl: string,\n\topts?: {\n\t\treadonly retrySpacing?: Duration.Duration;\n\t\treadonly timeout?: Duration.Duration;\n\t},\n): Effect.Effect<WaitForTransactionsReady, never, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst retrySpacing = opts?.retrySpacing ?? FUNDS_READY_RETRY_SPACING;\n\t\tconst timeout = opts?.timeout ?? FUNDS_READY_TIMEOUT;\n\t\t// SynchronizedRef serialises the get-or-init transition so two\n\t\t// concurrent callers can't both observe `null` and both build\n\t\t// their own `Effect.cached` instance (CAS-style guard against\n\t\t// the build-once race).\n\t\tconst ref = yield* SynchronizedRef.make<Effect.Effect<void, SuiPluginError> | null>(null);\n\n\t\tconst makeProbe = (): Effect.Effect<void, SuiPluginError> =>\n\t\t\twaitForHttpEndpoint({\n\t\t\t\tendpoint: `${faucetUrl}/v2/gas`,\n\t\t\t\ttimeoutMs: Duration.toMillis(timeout),\n\t\t\t\tintervalMs: Duration.toMillis(retrySpacing),\n\t\t\t\trequestTimeoutMs: PROBE_FETCH_TIMEOUT_MS,\n\t\t\t\trequestInit: {\n\t\t\t\t\tmethod: 'POST',\n\t\t\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\t\tFixedAmountRequest: { recipient: FAUCET_PROBE_RECIPIENT },\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tvalidate: async (response) => {\n\t\t\t\t\tif (!response.ok) throw new Error(`faucet HTTP ${response.status}`);\n\t\t\t\t\tconst body = (await response.json()) as { status?: unknown };\n\t\t\t\t\tconst status = body.status;\n\t\t\t\t\tif (typeof status === 'object' && status !== null && 'Failure' in status) {\n\t\t\t\t\t\tconst failure = (status as { Failure: unknown }).Failure;\n\t\t\t\t\t\tthrow new Error(`faucet body: Failure ${JSON.stringify(failure)}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t}).pipe(\n\t\t\t\tEffect.mapError(\n\t\t\t\t\t(cause): SuiPluginError =>\n\t\t\t\t\t\tsuiPluginError(\n\t\t\t\t\t\t\t'wait-funds-ready',\n\t\t\t\t\t\t\t`sui faucet at ${faucetUrl} did not become funds-transferable within ` +\n\t\t\t\t\t\t\t\t`${Duration.toMillis(timeout)}ms (still returning body-level Failure or 5xx): ` +\n\t\t\t\t\t\t\t\tformatUnknownError(cause),\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\n\t\t// `modifyEffect` atomically observes-then-updates inside a\n\t\t// serialised critical section: at most one fiber builds the\n\t\t// memoised probe, every other caller reads it back. This\n\t\t// closes the read-build-write race the plain Ref had.\n\t\tconst getOrInit: Effect.Effect<Effect.Effect<void, SuiPluginError>> =\n\t\t\tSynchronizedRef.modifyEffect(ref, (existing) =>\n\t\t\t\texisting !== null\n\t\t\t\t\t? Effect.succeed([existing, existing] as const)\n\t\t\t\t\t: Effect.cached(makeProbe()).pipe(Effect.map((cached) => [cached, cached] as const)),\n\t\t\t);\n\n\t\treturn {\n\t\t\twait: getOrInit.pipe(Effect.flatMap((eff) => eff)),\n\t\t\tinvalidate: SynchronizedRef.set(ref, null),\n\t\t};\n\t});\n\n/** Trivially-succeeding gate. Used by faucet-less networks (live\n * mainnet, fork — fork funds via impersonation, not HTTP). */\nexport const noopWaitForTransactionsReady: WaitForTransactionsReady = {\n\twait: Effect.void,\n\tinvalidate: Effect.void,\n};\n\n// ---------------------------------------------------------------------------\n// SuiClient assembly — collapses the per-mode boilerplate\n// ---------------------------------------------------------------------------\n\n/** Build the `SuiSdkShim` over a constructed grpc client.\n * Account/Coin/Wallet read through this seam, so we expose\n * `executeTransaction` + `waitForTransaction` in addition to the\n * read methods needed by the chain probe.\n *\n * Every read/write goes through `sdkClient.core.*` — the gRPC\n * TransportMethods surface from `@mysten/sui`. JSON-RPC is\n * deprecated; do not reintroduce it. */\nexport const makeSdkShim = (sdkClient: SuiGrpcClient): SuiSdkShim => ({\n\tcore: {\n\t\tgetObject: (args) => sdkClient.core.getObject(args),\n\t\tgetTransaction: (args) => sdkClient.core.getTransaction(args),\n\t\tgetBalance: (args) => sdkClient.core.getBalance(args),\n\t\tlistCoins: (args) => sdkClient.core.listCoins(args),\n\t\t// Extended surfaces — used by the account plugin's sign + execute\n\t\t// closure. Routes through `client.core.*` (the cross-transport\n\t\t// canonical surface per STYLE_GUIDE §16). The SDK accepts a\n\t\t// mutable `signatures: string[]`; the shim's readonly signature\n\t\t// is widened with a copy at the boundary.\n\t\texecuteTransaction: (args) =>\n\t\t\tsdkClient.core.executeTransaction({\n\t\t\t\ttransaction: args.transaction,\n\t\t\t\tsignatures: [...args.signatures],\n\t\t\t\t...(args.include !== undefined ? { include: args.include } : {}),\n\t\t\t}),\n\t\twaitForTransaction: (args) =>\n\t\t\tsdkClient.core.waitForTransaction({\n\t\t\t\tdigest: args.digest,\n\t\t\t\t...(args.timeout !== undefined ? { timeout: args.timeout } : {}),\n\t\t\t}),\n\t},\n\t// Client passthrough — Package's publish-tx builder hands this to\n\t// `Transaction.build({ client })`; sibling plugins reach\n\t// `client.core.*` directly through this slot. Typed as\n\t// ClientWithCoreApi via SuiSdkShim.client.\n\tclient: sdkClient,\n});\n\n/** Assemble a `SuiClient` from the per-mode building blocks. The\n * `fork: null` discriminator is invariant for non-fork modes; the\n * fork builder constructs its own client with the admin surface.\n *\n * `chainId` is a plain string value — every consumer downstream reads\n * it directly and capability-key constructors (`chainProbe…`,\n * `faucet…`) key on the string.\n *\n * Returns an `Effect` on the `SuiConfigError` channel: the empty-chainId\n * guard must surface as a typed, `catchTag`-able failure. Calling it\n * un-yielded as a sync function (as it once was) turned a thrown\n * `SuiConfigError` into a DEFECT inside the mode-boot `Effect.gen`\n * bodies — a hidden crash the channel could never recover (mirrors the\n * fix already applied to `auto-tick.ts`; STYLE_GUIDE §2). */\nexport const assembleSuiClient = (parts: {\n\treadonly sdkClient: SuiGrpcClient;\n\treadonly chainId: string;\n\treadonly rpcUrl: string;\n\treadonly faucetUrl?: string;\n\treadonly fundingFaucetUrl?: string;\n\treadonly graphqlUrl?: string;\n\treadonly waitForTransactionsReady: WaitForTransactionsReady;\n\t/** Image ref consumed by package's path (b) (`docker run --rm`)\n\t * build path. `null` for modes that have no in-stack image\n\t * (external + live). */\n\treadonly buildImage?: import('../../../contracts/container-runtime.ts').ImageRef | null;\n\t/** Container-reachable mirrors. Local mode resolves public URLs\n\t * through the router but sibling containers still need direct\n\t * host-gateway URLs during boot. */\n\treadonly hostGateway?: SuiClient['hostGateway'];\n}): Effect.Effect<\n\t{\n\t\treadonly client: SuiClient;\n\t\treadonly sdkShim: SuiSdkShim;\n\t\treadonly chainProbe: ChainProbe<SuiProbeKey>;\n\t},\n\tSuiConfigError\n> =>\n\tEffect.gen(function* () {\n\t\t// Defense-in-depth — `fetchChainId` should never resolve to an\n\t\t// empty string (RPC rejects that earlier), but a branded empty\n\t\t// string would silently fold into every downstream cache key. A\n\t\t// caller-pinned `chainId: ''` (e.g. `.live.custom({ chainId: '' })`)\n\t\t// reaches here, so fail on the typed channel rather than throw.\n\t\tif (typeof parts.chainId !== 'string' || parts.chainId.length === 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tsuiConfigError({\n\t\t\t\t\tfield: 'chainId',\n\t\t\t\t\tmessage: 'sui.assembleSuiClient: chain id must be a non-empty string',\n\t\t\t\t\thint: 'check fetchChainId / network resolver returned a real chain id',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst chainId = parts.chainId;\n\t\tconst sdkShim = makeSdkShim(parts.sdkClient);\n\t\tconst chainProbe = makeSuiChainProbe(sdkShim, chainId);\n\t\tconst client: SuiClient = {\n\t\t\tsdk: sdkShim,\n\t\t\trpcUrl: parts.rpcUrl,\n\t\t\tfaucetUrl: parts.faucetUrl ?? null,\n\t\t\tfundingFaucetUrl: parts.fundingFaucetUrl ?? parts.faucetUrl ?? null,\n\t\t\tgraphqlUrl: parts.graphqlUrl ?? null,\n\t\t\thostGateway: parts.hostGateway ?? {\n\t\t\t\trpcUrl: toDockerHostGatewayUrl(parts.rpcUrl),\n\t\t\t\tfaucetUrl: parts.faucetUrl === undefined ? null : toDockerHostGatewayUrl(parts.faucetUrl),\n\t\t\t\tgraphqlUrl:\n\t\t\t\t\tparts.graphqlUrl === undefined ? null : toDockerHostGatewayUrl(parts.graphqlUrl),\n\t\t\t},\n\t\t\tchainId,\n\t\t\twaitForTransactionsReady: parts.waitForTransactionsReady,\n\t\t\tchainProbe,\n\t\t\tfork: null,\n\t\t\tbuildImage: parts.buildImage ?? null,\n\t\t};\n\t\treturn { client, sdkShim, chainProbe };\n\t});\n\n/** Shape the resolved network record the boot builders all hand\n * back. The substrate-network mapping is uniform per mode. The raw\n * chainId string flows through verbatim — consumers downstream (codegen,\n * capabilities, walrus/seal deps) read it as a plain string value. */\nexport const makeResolvedNetwork = (parts: {\n\treadonly mode: ResolvedSuiNetwork['mode'];\n\treadonly chainId: string;\n\treadonly rpc: string;\n\treadonly faucet?: string;\n\treadonly graphql?: string;\n\treadonly source: ResolvedSuiNetwork['source'];\n\treadonly checkpoint?: string;\n\treadonly forkUpstream?: ResolvedSuiNetwork['forkUpstream'];\n}): ResolvedSuiNetwork => ({\n\tmode: parts.mode,\n\tchainId: parts.chainId,\n\trpc: parts.rpc,\n\tsource: parts.source,\n\t...(parts.faucet !== undefined ? { faucet: parts.faucet } : {}),\n\t...(parts.graphql !== undefined ? { graphql: parts.graphql } : {}),\n\t...(parts.checkpoint !== undefined ? { checkpoint: parts.checkpoint } : {}),\n\t...(parts.forkUpstream !== undefined ? { forkUpstream: parts.forkUpstream } : {}),\n});\n"],"mappings":"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"}
@@ -1,4 +1,3 @@
1
- import { ChainId } from "../../../substrate/brand.mjs";
2
1
  import { ImageRef } from "../../../contracts/container-runtime.mjs";
3
2
  import { ChainProbe } from "../../../contracts/chain-probe.mjs";
4
3
  import { SuiProbeKey, SuiSdkShim } from "../chain-probe.mjs";
@@ -70,12 +69,12 @@ interface SuiClient {
70
69
  readonly faucetUrl: string | null;
71
70
  readonly graphqlUrl: string | null;
72
71
  };
73
- /** Chain identitydownstream cache primitives fold this into
74
- * their state-store keys so on-chain artifacts re-derive when
75
- * the chain is wiped. Branded so consumers can hand it directly
76
- * to `chainProbeCapabilityKey(chain)` / `faucetCapabilityKey(chain)`
77
- * without a cast. */
78
- readonly chain: ChainId;
72
+ /** Genesis-digest chain identifier the substrate's content-addressed
73
+ * cache folds this into its keys (`(namespace, chainId, contentHash)`)
74
+ * so on-chain artifacts re-derive when the chain is wiped. A plain
75
+ * string value handed directly to `chainProbeCapabilityKey(chainId)`
76
+ * / `faucetCapabilityKey(chainId)`. NOT the network name. */
77
+ readonly chainId: string;
79
78
  /** Mode-aware funds-transferable gate; trivially-succeeding on
80
79
  * faucet-less networks. */
81
80
  readonly waitForTransactionsReady: WaitForTransactionsReady;
@@ -1 +1 @@
1
- {"version":3,"file":"shared.mjs","names":[],"sources":["../../../../src/plugins/sui/mode/shared.ts"],"sourcesContent":["// Shared shapes across mode builders.\n//\n// `SuiClient` is the resolved-value the plugin's `provides` tag\n// publishes — every consumer (Account, Coin, Wallet, Faucet,\n// Package, Codegen, Walrus/Seal/Deepbook fork variants) reads\n// THIS shape.\n//\n// Why one shape: distilled-doc finding — Sui's factory + builder\n// file is ~2000 LOC because the four per-network builders share\n// boilerplate (publish endpoints + fetch chain id + publish state)\n// but their bodies diverge in mode-specific ways. The redesign\n// bakes the seam in: the resolved value is uniform, the boot path\n// is mode-specific, and the admin surfaces narrow at the type\n// level (fork has `Sui.fork.advanceClock`; live does not).\n\nimport { Effect } from 'effect';\n\nimport type { SuiPluginError } from '../errors.ts';\nimport type { SuiSdkShim } from '../chain-probe.ts';\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport type { ImageRef } from '../../../contracts/container-runtime.ts';\nimport type { SuiProbeKey } from '../chain-probe.ts';\nimport type { ChainId } from '../../../substrate/brand.ts';\n\n/** Funds-ready strategy contributed by Sui. Mode-aware:\n *\n * - local container — first call POSTs a real funding tx against\n * the faucet, retrying on body-level {Failure} during the\n * post-RPC / pre-fund window. Memoised after first success.\n * - external w/ faucet — same as local container.\n * - live testnet — same, but no retry needed (the public faucet\n * is rate-limited differently).\n * - live mainnet / faucet-less — trivially-succeeding no-op.\n * (Architecture: \"no-faucet network has a trivially-succeeding\n * funds-ready gate\" is a first-class property of the mode.)\n * - fork — trivially-succeeding (impersonation funds, not\n * faucet).\n *\n * Distilled-doc opportunity: `Effect.cached` caches the first-call\n * failure for the whole scope; add a manual-invalidation surface\n * so a fork restart can re-probe. The shape below leaves room for\n * that knob. */\nexport interface WaitForTransactionsReady {\n\treadonly wait: Effect.Effect<void, SuiPluginError>;\n\t/** Manual invalidation — clears the memoised result. The default\n\t * built-in invalidates on plugin restart; this surface lets\n\t * long-running supervisors invalidate without a full restart. */\n\treadonly invalidate: Effect.Effect<void>;\n}\n\n/** Fork admin surface — mode-narrowed. Only the fork-mode factory's\n * resolved value carries this; local/local-rpc/live values have a\n * type-level `null`. */\nexport interface ForkAdminSurface {\n\treadonly status: Effect.Effect<\n\t\t{ readonly checkpoint: string; readonly clock: number },\n\t\tSuiPluginError\n\t>;\n\treadonly advanceClock: (intervalMs: number) => Effect.Effect<void, SuiPluginError>;\n\treadonly advanceCheckpoint: Effect.Effect<void, SuiPluginError>;\n\treadonly impersonate: (\n\t\tsender: string,\n\t\ttx: unknown,\n\t) => Effect.Effect<\n\t\t{ readonly digest: string; readonly success: boolean; readonly raw: unknown },\n\t\tSuiPluginError\n\t>;\n}\n\n/** The resolved value Sui publishes via its resource id. */\nexport interface SuiClient {\n\t/** The SDK shim. Fork mode wraps this with the property-access\n\t * blocklist (`fork-orchestration.wrapWithForkGuard`). */\n\treadonly sdk: SuiSdkShim;\n\t/** Host-reachable RPC URL for this resolved network. Local mode\n\t * surfaces the router-fronted URL; direct boot/probe ports are\n\t * available through `hostGateway` for sibling containers. */\n\treadonly rpcUrl: string;\n\t/** Host-reachable faucet base URL when this network has a faucet. */\n\treadonly faucetUrl: string | null;\n\t/** Faucet URL used by account funding strategies. Local mode keeps\n\t * this on the direct validator port used by the funds-ready gate. */\n\treadonly fundingFaucetUrl: string | null;\n\t/** Host-reachable GraphQL URL when the mode exposes one. */\n\treadonly graphqlUrl: string | null;\n\t/** Container-reachable mirrors of the host URLs. Loopback hosts are\n\t * rewritten to `host.docker.internal`; public URLs pass through. */\n\treadonly hostGateway: {\n\t\treadonly rpcUrl: string;\n\t\treadonly faucetUrl: string | null;\n\t\treadonly graphqlUrl: string | null;\n\t};\n\t/** Chain identitydownstream cache primitives fold this into\n\t * their state-store keys so on-chain artifacts re-derive when\n\t * the chain is wiped. Branded so consumers can hand it directly\n\t * to `chainProbeCapabilityKey(chain)` / `faucetCapabilityKey(chain)`\n\t * without a cast. */\n\treadonly chain: ChainId;\n\t/** Mode-aware funds-transferable gate; trivially-succeeding on\n\t * faucet-less networks. */\n\treadonly waitForTransactionsReady: WaitForTransactionsReady;\n\t/** Schema-validated read surface. Folded into every consumer's\n\t * context via `chain-probe:<chainId>` strategy lookup. */\n\treadonly chainProbe: ChainProbe<SuiProbeKey>;\n\t/** Fork-mode-only admin sub-surface. `null` for non-fork\n\t * modes; the mode-narrowed factory namespace narrows this at\n\t * the type level so consumers don't have to nullcheck. */\n\treadonly fork: ForkAdminSurface | null;\n\t/** Container image ref the Sui plugin built/pulled for its\n\t * validator. Surfaced so cross-service consumers (Package's\n\t * Move build, codegen's `summary` invocation) can spawn a\n\t * one-shot container running the SAME sui binary without\n\t * re-resolving the image. `null` for modes that have no\n\t * in-stack container (external + live). */\n\treadonly buildImage: ImageRef | null;\n}\n\nexport const toDockerHostGatewayUrl = (url: string): string => {\n\tconst parsed = new URL(url);\n\tif (\n\t\tparsed.hostname === '127.0.0.1' ||\n\t\tparsed.hostname === 'localhost' ||\n\t\tparsed.hostname === '0.0.0.0' ||\n\t\tparsed.hostname === '::1' ||\n\t\tparsed.hostname === '[::1]'\n\t) {\n\t\tparsed.hostname = 'host.docker.internal';\n\t}\n\tconst rendered = parsed.toString();\n\treturn parsed.pathname === '/' && parsed.search === '' && parsed.hash === ''\n\t\t? rendered.slice(0, -1)\n\t\t: rendered;\n};\n"],"mappings":";;AAqHA,MAAa,0BAA0B,QAAwB;CAC9D,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,KACC,OAAO,aAAa,eACpB,OAAO,aAAa,eACpB,OAAO,aAAa,aACpB,OAAO,aAAa,SACpB,OAAO,aAAa,QAEpB,QAAO,WAAW;CAEnB,MAAM,WAAW,OAAO,UAAU;AAClC,QAAO,OAAO,aAAa,OAAO,OAAO,WAAW,MAAM,OAAO,SAAS,KACvE,SAAS,MAAM,GAAG,GAAG,GACrB"}
1
+ {"version":3,"file":"shared.mjs","names":[],"sources":["../../../../src/plugins/sui/mode/shared.ts"],"sourcesContent":["// Shared shapes across mode builders.\n//\n// `SuiClient` is the resolved-value the plugin's `provides` tag\n// publishes — every consumer (Account, Coin, Wallet, Faucet,\n// Package, Codegen, Walrus/Seal/Deepbook fork variants) reads\n// THIS shape.\n//\n// Why one shape: distilled-doc finding — Sui's factory + builder\n// file is ~2000 LOC because the four per-network builders share\n// boilerplate (publish endpoints + fetch chain id + publish state)\n// but their bodies diverge in mode-specific ways. The redesign\n// bakes the seam in: the resolved value is uniform, the boot path\n// is mode-specific, and the admin surfaces narrow at the type\n// level (fork has `Sui.fork.advanceClock`; live does not).\n\nimport { Effect } from 'effect';\n\nimport type { SuiPluginError } from '../errors.ts';\nimport type { SuiSdkShim } from '../chain-probe.ts';\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport type { ImageRef } from '../../../contracts/container-runtime.ts';\nimport type { SuiProbeKey } from '../chain-probe.ts';\n\n/** Funds-ready strategy contributed by Sui. Mode-aware:\n *\n * - local container — first call POSTs a real funding tx against\n * the faucet, retrying on body-level {Failure} during the\n * post-RPC / pre-fund window. Memoised after first success.\n * - external w/ faucet — same as local container.\n * - live testnet — same, but no retry needed (the public faucet\n * is rate-limited differently).\n * - live mainnet / faucet-less — trivially-succeeding no-op.\n * (Architecture: \"no-faucet network has a trivially-succeeding\n * funds-ready gate\" is a first-class property of the mode.)\n * - fork — trivially-succeeding (impersonation funds, not\n * faucet).\n *\n * Distilled-doc opportunity: `Effect.cached` caches the first-call\n * failure for the whole scope; add a manual-invalidation surface\n * so a fork restart can re-probe. The shape below leaves room for\n * that knob. */\nexport interface WaitForTransactionsReady {\n\treadonly wait: Effect.Effect<void, SuiPluginError>;\n\t/** Manual invalidation — clears the memoised result. The default\n\t * built-in invalidates on plugin restart; this surface lets\n\t * long-running supervisors invalidate without a full restart. */\n\treadonly invalidate: Effect.Effect<void>;\n}\n\n/** Fork admin surface — mode-narrowed. Only the fork-mode factory's\n * resolved value carries this; local/local-rpc/live values have a\n * type-level `null`. */\nexport interface ForkAdminSurface {\n\treadonly status: Effect.Effect<\n\t\t{ readonly checkpoint: string; readonly clock: number },\n\t\tSuiPluginError\n\t>;\n\treadonly advanceClock: (intervalMs: number) => Effect.Effect<void, SuiPluginError>;\n\treadonly advanceCheckpoint: Effect.Effect<void, SuiPluginError>;\n\treadonly impersonate: (\n\t\tsender: string,\n\t\ttx: unknown,\n\t) => Effect.Effect<\n\t\t{ readonly digest: string; readonly success: boolean; readonly raw: unknown },\n\t\tSuiPluginError\n\t>;\n}\n\n/** The resolved value Sui publishes via its resource id. */\nexport interface SuiClient {\n\t/** The SDK shim. Fork mode wraps this with the property-access\n\t * blocklist (`fork-orchestration.wrapWithForkGuard`). */\n\treadonly sdk: SuiSdkShim;\n\t/** Host-reachable RPC URL for this resolved network. Local mode\n\t * surfaces the router-fronted URL; direct boot/probe ports are\n\t * available through `hostGateway` for sibling containers. */\n\treadonly rpcUrl: string;\n\t/** Host-reachable faucet base URL when this network has a faucet. */\n\treadonly faucetUrl: string | null;\n\t/** Faucet URL used by account funding strategies. Local mode keeps\n\t * this on the direct validator port used by the funds-ready gate. */\n\treadonly fundingFaucetUrl: string | null;\n\t/** Host-reachable GraphQL URL when the mode exposes one. */\n\treadonly graphqlUrl: string | null;\n\t/** Container-reachable mirrors of the host URLs. Loopback hosts are\n\t * rewritten to `host.docker.internal`; public URLs pass through. */\n\treadonly hostGateway: {\n\t\treadonly rpcUrl: string;\n\t\treadonly faucetUrl: string | null;\n\t\treadonly graphqlUrl: string | null;\n\t};\n\t/** Genesis-digest chain identifier the substrate's content-addressed\n\t * cache folds this into its keys (`(namespace, chainId, contentHash)`)\n\t * so on-chain artifacts re-derive when the chain is wiped. A plain\n\t * string value handed directly to `chainProbeCapabilityKey(chainId)`\n\t * / `faucetCapabilityKey(chainId)`. NOT the network name. */\n\treadonly chainId: string;\n\t/** Mode-aware funds-transferable gate; trivially-succeeding on\n\t * faucet-less networks. */\n\treadonly waitForTransactionsReady: WaitForTransactionsReady;\n\t/** Schema-validated read surface. Folded into every consumer's\n\t * context via `chain-probe:<chainId>` strategy lookup. */\n\treadonly chainProbe: ChainProbe<SuiProbeKey>;\n\t/** Fork-mode-only admin sub-surface. `null` for non-fork\n\t * modes; the mode-narrowed factory namespace narrows this at\n\t * the type level so consumers don't have to nullcheck. */\n\treadonly fork: ForkAdminSurface | null;\n\t/** Container image ref the Sui plugin built/pulled for its\n\t * validator. Surfaced so cross-service consumers (Package's\n\t * Move build, codegen's `summary` invocation) can spawn a\n\t * one-shot container running the SAME sui binary without\n\t * re-resolving the image. `null` for modes that have no\n\t * in-stack container (external + live). */\n\treadonly buildImage: ImageRef | null;\n}\n\nexport const toDockerHostGatewayUrl = (url: string): string => {\n\tconst parsed = new URL(url);\n\tif (\n\t\tparsed.hostname === '127.0.0.1' ||\n\t\tparsed.hostname === 'localhost' ||\n\t\tparsed.hostname === '0.0.0.0' ||\n\t\tparsed.hostname === '::1' ||\n\t\tparsed.hostname === '[::1]'\n\t) {\n\t\tparsed.hostname = 'host.docker.internal';\n\t}\n\tconst rendered = parsed.toString();\n\treturn parsed.pathname === '/' && parsed.search === '' && parsed.hash === ''\n\t\t? rendered.slice(0, -1)\n\t\t: rendered;\n};\n"],"mappings":";;AAoHA,MAAa,0BAA0B,QAAwB;CAC9D,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,IACC,OAAO,aAAa,eACpB,OAAO,aAAa,eACpB,OAAO,aAAa,aACpB,OAAO,aAAa,SACpB,OAAO,aAAa,SAEpB,OAAO,WAAW;CAEnB,MAAM,WAAW,OAAO,SAAS;CACjC,OAAO,OAAO,aAAa,OAAO,OAAO,WAAW,MAAM,OAAO,SAAS,KACvE,SAAS,MAAM,GAAG,EAAE,IACpB;AACJ"}
@@ -12,8 +12,13 @@ interface SuiCommonOptions {
12
12
  /** Ready-probe timeout. Per-mode defaults are mode-specific. */
13
13
  readonly readyTimeout?: Duration.Duration;
14
14
  }
15
- /** Local container mode — in-stack validator + faucet + GraphQL +
16
- * postgres indexer. */
15
+ /** Local container mode — in-stack validator + faucet + GraphQL. GraphQL,
16
+ * its indexer, and a Postgres are ON BY DEFAULT: the sui plugin OWNS a
17
+ * postgres sidecar container (labelled under sui) and auto-creates its
18
+ * `sui_indexer` DB, so a bare `sui()` boots the full GraphQL surface with
19
+ * no cross-plugin wiring. Two escape hatches: `indexer: false` opts out
20
+ * (RPC + faucet only, no sidecar), and `indexerDb` points GraphQL at a
21
+ * Postgres the caller already runs (no sidecar). */
17
22
  interface SuiLocalOptions extends SuiCommonOptions {
18
23
  readonly mode: 'local';
19
24
  /** Image override — `{pull}` skips the build; `{build}` uses
@@ -26,8 +31,20 @@ interface SuiLocalOptions extends SuiCommonOptions {
26
31
  readonly dockerfile?: string;
27
32
  };
28
33
  };
29
- /** Sui binary version (default in mode/local.ts). */
30
- readonly version?: string;
34
+ /** GraphQL/indexer/Postgres on-off. Default `true` sui owns a
35
+ * postgres sidecar and runs `--with-graphql` against it. `false` ⇒
36
+ * RPC + faucet only, no sidecar, no GraphQL. */
37
+ readonly indexer?: boolean;
38
+ /** BYO indexer Postgres (value-based escape hatch). When set, GraphQL
39
+ * reads from the caller's own DB and NO sidecar is provisioned. `url`
40
+ * is a PostgreSQL DSN reachable from the validator on `network`;
41
+ * `database` (default `'sui_indexer'`) is appended to the DSN if it
42
+ * carries no path segment. */
43
+ readonly indexerDb?: {
44
+ readonly url: string;
45
+ readonly network: string;
46
+ readonly database?: string;
47
+ };
31
48
  /** Optional direct host port mapping keyed by container port. When
32
49
  * supplied, the mapping is exact: Sui does not reassign missing
33
50
  * or busy host ports through the PortBroker. Omit this field to
@@ -45,7 +62,7 @@ interface SuiLocalRpcOptions extends SuiCommonOptions {
45
62
  readonly graphqlUrl?: string;
46
63
  /** Optional chain id pin for caller-owned endpoints. Omit to
47
64
  * probe the RPC endpoint. */
48
- readonly chain?: string;
65
+ readonly chainId?: string;
49
66
  }
50
67
  /** Live testnet / mainnet / custom-RPC mode. */
51
68
  interface SuiLiveOptions extends SuiCommonOptions {
@@ -58,7 +75,7 @@ interface SuiLiveOptions extends SuiCommonOptions {
58
75
  readonly graphqlUrl?: string;
59
76
  /** Optional chain id pin for custom/caller-owned live endpoints.
60
77
  * Omit to probe the RPC endpoint. */
61
- readonly chain?: string;
78
+ readonly chainId?: string;
62
79
  }
63
80
  /** Fork-mode faucet config. Funds test accounts by impersonating a
64
81
  * large-reserve "whale" address on the forked upstream and transferring