@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":"index.mjs","names":[],"sources":["../../../src/plugins/seal/index.ts"],"sourcesContent":["// Seal plugin — barrel + factories.\n//\n// Architecture (07-seal.md): Seal is a local or known service plugin.\n// Three operative modes:\n//\n// - `local-keygen` — localnet, owns the master key. Heavy boot.\n// - `live` — testnet / mainnet, read-only handle to a\n// known deployment.\n// - `fork-known` — `*-fork` networks; routes to the wrapped\n// upstream's known deployment.\n//\n// Plus one type-level refusal:\n//\n// - `fork-localkeygen-refused` — local-keygen ON `*-fork` is a\n// synchronous throw at factory time (distilled-doc invariant #8).\n//\n// Public surface:\n//\n// - `seal(opts)` — explicit mode selection.\n// - `sealFor(network).<mode>` — mode-narrowed factory namespace.\n// Mode-narrowing makes `sealFor(forkNetwork).localKeygen(...)`\n// a COMPILE-time refusal (architecture Tension 11 + type-prototype\n// finding #4).\n//\n// Capability decls emitted:\n//\n// 1. Snapshotable — local-keygen contributes secret material\n// subtree; known modes contribute the\n// empty shape.\n// 2. Codegenable — `seal-key-server` bindings (server\n// configs + URL + objectId).\n// 3. Routable — `seal-key-server` endpoint, local-keygen\n// only (known modes route to a remote URL\n// outside Traefik's purview).\n\nimport { Effect, FileSystem, Path } from 'effect';\n\nimport { definePlugin, type ResourceRef } from '../../api/define-plugin.ts';\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { pluginErrorContributions } from '../../api/plugin-errors.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { ArtifactPublisherService } from '../../substrate/runtime/artifact-publisher/index.ts';\nimport { chainProbeFor } from '../../substrate/runtime/strategy-registry/index.ts';\nimport type { AccountResourceId, AccountValue } from '../account/index.ts';\nimport { suiResource } from '../sui/index.ts';\n\nimport type { SealObjectProbeKey } from './deploy.ts';\nimport { sealPluginKey } from './plugin-key.ts';\nimport { makeSealCodegenable, type SealBindings } from './codegen.ts';\nimport { sealError, SEAL_ERROR_TAGS, type SealError } from './errors.ts';\nimport { validateForkKnownInputs, type ForkUpstream } from './mode/fork-known.ts';\nimport type { KnownNetwork } from './mode/live.ts';\nimport { validateLiveInputs } from './mode/live.ts';\nimport {\n\tbuildSealNetworkName,\n\tDEFAULT_KEY_SERVER_PORT,\n\tderiveSealSubnetPrefix,\n} from './key-server.ts';\nimport { withSubnetAddressing } from '../../substrate/runtime/subnet-broker.ts';\nimport {\n\tbootLocalKeygen,\n\tresolveLocalKeygenOptions,\n\ttype LocalKeygenDeps,\n} from './mode/local-keygen.ts';\nimport {\n\tmakeSealResource,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResolved,\n} from './registry-publish.ts';\nimport { buildSealKeyServerPublicRoute, makeSealRoutable } from './routable.ts';\nimport { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from './snapshot.ts';\nimport { bootSealService, type SealMode } from './service.ts';\nimport { DEFAULT_SEAL_VERSION } from './bootstrap-assets/source-fetch.ts';\n\nconst sealErrorContributions = pluginErrorContributions(SEAL_ERROR_TAGS);\n\n// ---------------------------------------------------------------------------\n// Resource exports — distilled-doc §\"TypeScript exports consumed elsewhere\"\n// ---------------------------------------------------------------------------\n\nexport {\n\tmakeSealResource,\n\tsealResourceId,\n\ttype SealKeyServer,\n\ttype SealKeyServerEntry,\n\ttype SealResolved,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResourceId,\n} from './registry-publish.ts';\nexport type { SealKeyManager } from './key-manager.ts';\nexport {\n\ttype SealError,\n\ttype SealAnyError,\n\ttype SealConfigError,\n\tSEAL_ERROR_TAGS,\n} from './errors.ts';\nexport type { SealBindings } from './codegen.ts';\nexport { SealSpans } from './spans.ts';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Common options shared across all three modes. */\nexport interface SealCommonOptions {\n\treadonly name?: string;\n}\n\n/** A user-supplied signer account ref. The user passes the result of\n * `account('publisher')` — NOT a magic-string token. Generic over the\n * literal account name so the seal dependency edge preserves the\n * per-account resource id. */\nexport type SealSignerMember<Name extends string = string> = ResourceRef<\n\tAccountResourceId<Name>,\n\tAccountValue\n>;\n\n/** Local-keygen mode options. The `signer` field is REQUIRED — the\n * Move publish + on-chain register both need it. The mode-narrowed\n * factory's TypeScript shape enforces this (no `signer?` here). */\nexport interface SealLocalKeygenOptions<\n\tSigner extends SealSignerMember = SealSignerMember,\n> extends SealCommonOptions {\n\t/** Signer for the seal Move publish + on-chain key-server register.\n\t * Pass the result of `account('publisher')` — the same plugin/resource\n\t * ref used elsewhere in the stack. The ref is threaded through\n\t * `dependsOn` so the publish tx waits for the account's acquire\n\t * (keypair mint + funding) to complete. */\n\treadonly signer: Signer;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n\treadonly image?: { readonly pull: string } | { readonly build: { readonly context: string } };\n}\n\n/** Live-mode options (testnet / mainnet). */\nexport interface SealLiveOptions extends SealCommonOptions {\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n/** Fork-known-mode options. */\nexport interface SealForkKnownOptions extends SealCommonOptions {\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\nexport type SealOptions<Signer extends SealSignerMember = SealSignerMember> =\n\t| ({ readonly mode: 'local-keygen' } & SealLocalKeygenOptions<Signer>)\n\t| ({ readonly mode: 'live' } & SealLiveOptions)\n\t| ({ readonly mode: 'fork-known' } & SealForkKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction\n// ---------------------------------------------------------------------------\n\n/** Constants + shared knobs for the buildXyz helpers below. */\nconst DEFAULT_NAME = 'seal';\n\n/** Build the local-keygen-mode plugin. The service contributes\n * Snapshotable (secret) + Codegenable + Routable.\n *\n * Architecture mirror (walrus): `ContainerRuntimeService` +\n * `IdentityContext` wired via the supervisor's plugin runtime context,\n * artifact publisher publisher + chain probe yielded inside `acquire`. */\nconst buildLocalKeygenPlugin = <const Signer extends SealSignerMember>(\n\topts: SealLocalKeygenOptions<Signer>,\n) => {\n\t// Synchronous factory-time defaults. Localnet-signer-required is\n\t// enforced by the typed `signer:` field on\n\t// SealLocalKeygenOptions.\n\tconst resolved = resolveLocalKeygenOptions(opts, DEFAULT_SEAL_VERSION);\n\n\tconst sealResource = makeSealResource(resolved.name);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\tdependsOn: { sui: suiResource, signer: opts.signer },\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tpluginKey: sealPluginKey(resolved.name),\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst { sui, signer: signerAccount } = deps;\n\t\t\t\t// Substrate-context primitives:\n\t\t\t\t// - `ContainerRuntimeService` + `IdentityContext` arrive\n\t\t\t\t// via the supervisor's plugin runtime context.\n\t\t\t\t// - `ArtifactPublisher` is the substrate-level\n\t\t\t\t// publisher (cache → verify → produce → register cycle).\n\t\t\t\t// - Chain probe is looked up via the\n\t\t\t\t// StrategyRegistry under `chain-probe:<chainId>`; the\n\t\t\t\t// Sui plugin registered it during its own acquire.\n\t\t\t\t// The probe is yielded eagerly so the dep edge fails\n\t\t\t\t// fast if sui's chain-probe registration is missing,\n\t\t\t\t// matching walrus's pattern.\n\t\t\t\t// - `StackPathsService` resolves the per-stack on-disk\n\t\t\t\t// root so the key-server config + master-key.env\n\t\t\t\t// bind-mount sources are real paths (not the\n\t\t\t\t// `<runtime>/...` template).\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst publisher = yield* ArtifactPublisherService;\n\t\t\t\tconst stackPaths = yield* StackPathsService;\n\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\tconst path = yield* Path.Path;\n\t\t\t\tconst probe = yield* chainProbeFor<SealObjectProbeKey>(sui.chain);\n\n\t\t\t\t// Resolve the seal service dir from the per-stack paths\n\t\t\t\t// bundle. The dir must exist before the key-server's\n\t\t\t\t// bind-mounts (config yaml + master-key env-file).\n\t\t\t\tconst servicePath = path.join(stackPaths.stackRoot, 'seal', resolved.name);\n\t\t\t\tyield* fs.makeDirectory(servicePath, { recursive: true }).pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\tsealError('config-render', {\n\t\t\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\t\t\tmessage: `seal.config-render: failed to create service directory at ${servicePath} — downstream config + master-key writes would all fail; surfacing the underlying filesystem error.`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Cross-container DNS: seal's key-server dials sui RPC via\n\t\t\t\t// `host.docker.internal`. The sui plugin binds a brokered\n\t\t\t\t// host port; the SDK publish/register path runs from the host\n\t\t\t\t// process and does not need the container network.\n\t\t\t\t//\n\t\t\t\t// Architectural decision (B5): seal owns its OWN docker\n\t\t\t\t// network for the key-server's network attachment;\n\t\t\t\t// sui-side hops go through the host gateway. Mirrors\n\t\t\t\t// walrus's pattern (see plugins/walrus/index.ts §B5).\n\t\t\t\tconst sealNetworkName = buildSealNetworkName(identity.app, identity.stack, resolved.name);\n\t\t\t\tconst suiRpcUrlInNetwork = sui.hostGateway.rpcUrl;\n\t\t\t\tconst routed = buildSealKeyServerPublicRoute({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tport: DEFAULT_KEY_SERVER_PORT,\n\t\t\t\t});\n\n\t\t\t\t// Idempotent network create — the long-running key-server\n\t\t\t\t// attaches to this name. The seal boot pipeline doesn't own\n\t\t\t\t// the create (unlike walrus's local-cluster which calls\n\t\t\t\t// `ensureNetwork` from its mode body); we call it here\n\t\t\t\t// because the substrate's `acquire` is the only seam that\n\t\t\t\t// holds both the runtime + the identity needed for the\n\t\t\t\t// per-stack label tuple.\n\t\t\t\tconst sealSubnetPrefix = deriveSealSubnetPrefix({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tsealName: resolved.name,\n\t\t\t\t});\n\t\t\t\tyield* runtime.ensureNetwork(\n\t\t\t\t\twithSubnetAddressing(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: sealNetworkName,\n\t\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsealSubnetPrefix,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst localKeygenDeps: LocalKeygenDeps = {\n\t\t\t\t\truntime,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tsigner: signerAccount,\n\t\t\t\t\tsdk: sui.sdk,\n\t\t\t\t\t...(sui.buildImage !== null ? { buildImage: sui.buildImage } : {}),\n\t\t\t\t\tchainProbe: probe,\n\t\t\t\t\tchain: sui.chain,\n\t\t\t\t\tservicePath,\n\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\tlabels: {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tplugin: 'seal',\n\t\t\t\t\t\trole: 'key-server',\n\t\t\t\t\t},\n\t\t\t\t\tsuiNetworkName: sealNetworkName,\n\t\t\t\t\tsuiRpcUrlInNetwork,\n\t\t\t\t\troutedHostname: routed.hostname,\n\t\t\t\t\troutedUrl: routed.url,\n\t\t\t\t};\n\n\t\t\t\tconst boot = (yield* bootLocalKeygen(\n\t\t\t\t\tlocalKeygenDeps,\n\t\t\t\t\tresolved,\n\t\t\t\t)) satisfies SealLocalKeygenResolved;\n\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...boot.keyServer,\n\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\tmanager: boot.keyManager,\n\t\t\t\t};\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t\t// Dynamic capability factory — receives the resolved\n\t\t// `SealKeyServer` + acquire context. Stamps the REAL\n\t\t// objectId / keyServerUrl into codegen bindings and the\n\t\t// real identity app/stack into the snapshot decl.\n\t\tcapabilities: ({ value: resolvedKs, runtime: acquireCtx }) => {\n\t\t\tconst bindings: SealBindings = {\n\t\t\t\tname: resolved.name,\n\t\t\t\tobjectId: resolvedKs.objectId,\n\t\t\t\tkeyServerUrl: resolvedKs.keyServerUrl,\n\t\t\t\tserverConfigs: resolvedKs.serverConfigs,\n\t\t\t\tmode: 'local-keygen',\n\t\t\t};\n\t\t\tconst snap = makeLocalKeygenSnapshotable({\n\t\t\t\tname: resolved.name,\n\t\t\t\tapp: acquireCtx.identity.app,\n\t\t\t\tstack: acquireCtx.identity.stack,\n\t\t\t});\n\t\t\tconst codegen = makeSealCodegenable(bindings);\n\t\t\tconst routable = makeSealRoutable({\n\t\t\t\tname: resolved.name,\n\t\t\t\tcontainerName: `devstack-${acquireCtx.identity.app}-${acquireCtx.identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t});\n\t\t\treturn [snap, codegen, routable] as const;\n\t\t},\n\t\terrorContributions: sealErrorContributions,\n\t});\n};\n\n/** Build the live-mode plugin. No Routable (URL is remote). */\nconst buildLivePlugin = (opts: SealLiveOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work.\n\tconst validated = validateLiveInputs({ name, ...opts });\n\tconst bindings: SealBindings = {\n\t\tname,\n\t\tobjectId: validated.objectId,\n\t\tkeyServerUrl: validated.keyServerUrl,\n\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\tmode: 'live',\n\t};\n\tconst snap = makeKnownSnapshotable({ name });\n\tconst codegen = makeSealCodegenable(bindings);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst mode: SealMode = { mode: 'live', name, resolved: validated };\n\t\t\t\tconst publisher = yield* ArtifactPublisherService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\treturn {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'live',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t\tcapabilities: [snap, codegen] as const,\n\t\terrorContributions: sealErrorContributions,\n\t});\n};\n\n/** Build the fork-known-mode plugin. Structurally symmetric with\n * `buildLivePlugin` — both resolve their `{objectId, keyServerUrl}`\n * tuple at factory time via `validateLiveInputs` (the fork-known\n * side maps `upstream → KnownNetwork` first via\n * `validateForkKnownInputs`) and thread it through SealMode's\n * `resolved:` envelope.\n *\n * Capabilities are kept on the dynamic shape (callback form)\n * rather than precomputed — leaves room for a future on-acquire\n * override path (e.g. the substrate dynamically rewrites the\n * bindings) without restructuring the factory. Not load-bearing\n * today; static capabilities would also work. */\nconst buildForkKnownPlugin = (opts: SealForkKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work — symmetric with\n\t// `buildLivePlugin`'s factory-boundary `validateLiveInputs` call.\n\t// `validateForkKnownInputs` maps the upstream alias to a\n\t// `KnownNetwork` and runs the same validation pipeline as live mode.\n\tconst validated = validateForkKnownInputs({ name, ...opts });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Symmetric with the live branch's `{ mode, name, resolved }`\n\t\t\t\t// envelope. `upstream` rides through for downstream\n\t\t\t\t// span attribution; `resolved` carries the validated\n\t\t\t\t// `{objectId, keyServerUrl}` tuple.\n\t\t\t\tconst mode: SealMode = {\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tname,\n\t\t\t\t\tupstream: opts.upstream,\n\t\t\t\t\tresolved: validated,\n\t\t\t\t};\n\t\t\t\tconst publisher = yield* ArtifactPublisherService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\treturn {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t\tcapabilities: ({ value: resolvedKs }) => {\n\t\t\tconst bindings: SealBindings = {\n\t\t\t\tname,\n\t\t\t\tobjectId: resolvedKs.objectId,\n\t\t\t\tkeyServerUrl: resolvedKs.keyServerUrl,\n\t\t\t\tserverConfigs: resolvedKs.serverConfigs,\n\t\t\t\tmode: 'fork-known',\n\t\t\t};\n\t\t\treturn [snap, makeSealCodegenable(bindings)] as const;\n\t\t},\n\t\terrorContributions: sealErrorContributions,\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Explicit Seal factory. `local-keygen` requires a signer; live and\n * fork-known modes must be selected directly or through `sealFor`. */\nexport const seal = <const Signer extends SealSignerMember = SealSignerMember>(\n\topts: SealOptions<Signer>,\n) => {\n\tswitch (opts.mode) {\n\t\tcase 'local-keygen':\n\t\t\treturn buildLocalKeygenPlugin(opts);\n\t\tcase 'live':\n\t\t\treturn buildLivePlugin(opts);\n\t\tcase 'fork-known':\n\t\t\treturn buildForkKnownPlugin(opts);\n\t}\n};\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local' } as const;\n * sealFor(local).localKeygen({signer}) // OK\n * sealFor(local).forkKnown(...) // type error: not in 'local' branch\n *\n * const fork = { mode: 'fork' } as const;\n * sealFor(fork).forkKnown({upstream}) // OK\n * sealFor(fork).localKeygen({signer}) // type error: not in 'fork' branch\n * // (distilled-doc invariant #8)\n *\n * Distilled-doc invariant #8 (fork-localkeygen-refused): the\n * fork-mode branch has NO `localKeygen` entry — that's the\n * type-level refusal. */\nexport const sealFor = defineModeNamespace({\n\tlocal: {\n\t\tlocalKeygen: <const Signer extends SealSignerMember>(opts: SealLocalKeygenOptions<Signer>) =>\n\t\t\tbuildLocalKeygenPlugin(opts),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'mainnet', ...opts }),\n\t\tcustom: (\n\t\t\topts: Required<Pick<SealLiveOptions, 'objectId' | 'keyServerUrl'>> & SealLiveOptions,\n\t\t) => buildLivePlugin(opts),\n\t},\n\tfork: {\n\t\tforkKnown: (opts: SealForkKnownOptions) => buildForkKnownPlugin(opts),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Type-only error re-export\n// ---------------------------------------------------------------------------\n\nexport type { SealError as SealAcquireError };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/seal/index.ts"],"sourcesContent":["// Seal plugin — barrel + factories.\n//\n// Architecture (07-seal.md): Seal is a local or known service plugin.\n// Three operative modes:\n//\n// - `local-keygen` — localnet, owns the master key. Heavy boot.\n// - `live` — testnet / mainnet, read-only handle to a\n// known deployment.\n// - `fork-known` — `*-fork` networks; routes to the wrapped\n// upstream's known deployment.\n//\n// Plus one type-level refusal:\n//\n// - `fork-localkeygen-refused` — local-keygen ON `*-fork` is a\n// synchronous throw at factory time (distilled-doc invariant #8).\n//\n// Public surface:\n//\n// - `seal(opts)` — explicit mode selection.\n// - `sealFor(network).<mode>` — mode-narrowed factory namespace.\n// Mode-narrowing makes `sealFor(forkNetwork).localKeygen(...)`\n// a COMPILE-time refusal (architecture Tension 11 + type-prototype\n// finding #4).\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.snapshotExtra` — local-keygen contributes secret material\n// subtree; known modes contribute the\n// empty shape.\n// 2. `ctx.codegen` — `seal-key-server` bindings (server\n// configs + URL + objectId).\n// 3. `ctx.endpoint` — `seal-key-server` endpoint, local-keygen\n// only (known modes route to a remote URL\n// outside Traefik's purview).\n\nimport { Effect, FileSystem, Path } from 'effect';\n\nimport { definePlugin, type ResourceRef } from '../../api/define-plugin.ts';\nimport { defineModeNamespace } from '../../api/mode-narrowed-factory.ts';\nimport { ContainerRuntimeService } from '../../runtime/docker/service.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\nimport { CacheService } from '../../substrate/runtime/cache/index.ts';\nimport { chainProbeFor } from '../../substrate/runtime/strategy-registry/index.ts';\nimport type { AccountResourceId, AccountValue } from '../account/index.ts';\nimport { suiResource } from '../sui/index.ts';\n\nimport type { SealObjectProbeKey } from './deploy.ts';\nimport { sealPluginKey } from './plugin-key.ts';\nimport { makeSealCodegenable, makeSealStaticCodegen, type SealBindings } from './codegen.ts';\nimport { sealError, type SealError } from './errors.ts';\nimport { validateForkKnownInputs, type ForkUpstream } from './mode/fork-known.ts';\nimport type { KnownNetwork } from './mode/live.ts';\nimport { validateLiveInputs } from './mode/live.ts';\nimport {\n\tbuildSealNetworkName,\n\tDEFAULT_KEY_SERVER_PORT,\n\tderiveSealSubnetPrefix,\n} from './key-server.ts';\nimport { withSubnetAddressing } from '../../substrate/runtime/subnet-broker.ts';\nimport {\n\tbootLocalKeygen,\n\tresolveLocalKeygenOptions,\n\ttype LocalKeygenDeps,\n} from './mode/local-keygen.ts';\nimport {\n\tmakeSealResource,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResolved,\n} from './registry-publish.ts';\nimport { buildSealKeyServerPublicRoute, makeSealRoutable } from './routable.ts';\nimport { makeKnownSnapshotable, makeLocalKeygenSnapshotable } from './snapshot.ts';\nimport { bootSealService, type SealMode } from './service.ts';\nimport { DEFAULT_SEAL_VERSION } from './bootstrap-assets/source-fetch.ts';\n\n// ---------------------------------------------------------------------------\n// Resource exports — distilled-doc §\"TypeScript exports consumed elsewhere\"\n// ---------------------------------------------------------------------------\n\nexport {\n\tmakeSealResource,\n\tsealResourceId,\n\ttype SealKeyServer,\n\ttype SealKeyServerEntry,\n\ttype SealResolved,\n\ttype SealLocalKeygenResolved,\n\ttype SealKnownResolved,\n\ttype SealResourceId,\n} from './registry-publish.ts';\nexport type { SealKeyManager } from './key-manager.ts';\nexport { type SealError, type SealAnyError, type SealConfigError } from './errors.ts';\nexport type { SealBindings } from './codegen.ts';\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** Common options shared across all three modes. */\nexport interface SealCommonOptions {\n\treadonly name?: string;\n}\n\n/** A user-supplied signer account ref. The user passes the result of\n * `account('publisher')` — NOT a magic-string token. Generic over the\n * literal account name so the seal dependency edge preserves the\n * per-account resource id. */\nexport type SealSignerMember<Name extends string = string> = ResourceRef<\n\tAccountResourceId<Name>,\n\tAccountValue\n>;\n\n/** Local-keygen mode options. The `signer` field is REQUIRED — the\n * Move publish + on-chain register both need it. The mode-narrowed\n * factory's TypeScript shape enforces this (no `signer?` here). */\nexport interface SealLocalKeygenOptions<\n\tSigner extends SealSignerMember = SealSignerMember,\n> extends SealCommonOptions {\n\t/** Signer for the seal Move publish + on-chain key-server register.\n\t * Pass the result of `account('publisher')` — the same plugin/resource\n\t * ref used elsewhere in the stack. The ref is threaded through\n\t * `dependsOn` so the publish tx waits for the account's acquire\n\t * (keypair mint + funding) to complete. */\n\treadonly signer: Signer;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n\treadonly image?: { readonly pull: string } | { readonly build: { readonly context: string } };\n}\n\n/** Live-mode options (testnet / mainnet). */\nexport interface SealLiveOptions extends SealCommonOptions {\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n/** Fork-known-mode options. */\nexport interface SealForkKnownOptions extends SealCommonOptions {\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\nexport type SealOptions<Signer extends SealSignerMember = SealSignerMember> =\n\t| ({ readonly mode: 'local-keygen' } & SealLocalKeygenOptions<Signer>)\n\t| ({ readonly mode: 'live' } & SealLiveOptions)\n\t| ({ readonly mode: 'fork-known' } & SealForkKnownOptions);\n\n// ---------------------------------------------------------------------------\n// Plugin construction\n// ---------------------------------------------------------------------------\n\n/** Constants + shared knobs for the buildXyz helpers below. */\nconst DEFAULT_NAME = 'seal';\n\n// ---------------------------------------------------------------------------\n// The three seal `start` bodies emit their contributions inline via the typed\n// `ctx` verbs after resolving the value. The decl shapes + emit ORDER are\n// load-bearing.\n//\n// ⚠ ID-STABILITY: the snapshotable decl captures the seal vault / master-key\n// secret material subtree; its shape (subtree paths, container label tuple,\n// secretMaterial / missingTolerance flags) MUST stay byte-identical.\n// ---------------------------------------------------------------------------\n\n/** Build the local-keygen-mode plugin. The service contributes\n * Snapshotable (secret) + Codegenable + Routable.\n *\n * Architecture mirror (walrus): `ContainerRuntimeService` +\n * `IdentityContext` wired via the supervisor's plugin runtime context,\n * artifact publisher publisher + chain probe yielded inside `acquire`. */\nconst buildLocalKeygenPlugin = <const Signer extends SealSignerMember>(\n\topts: SealLocalKeygenOptions<Signer>,\n) => {\n\t// Synchronous factory-time defaults. Localnet-signer-required is\n\t// enforced by the typed `signer:` field on\n\t// SealLocalKeygenOptions.\n\tconst resolved = resolveLocalKeygenOptions(opts, DEFAULT_SEAL_VERSION);\n\n\tconst sealResource = makeSealResource(resolved.name);\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\tdependsOn: { sui: suiResource, signer: opts.signer },\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tpluginKey: sealPluginKey(resolved.name),\n\t\t// Stack-free codegen: the key-server object id / URL / committee are\n\t\t// LOADED CONFIG DATA -- the committed `seal.ts` stub emits\n\t\t// `resolveValue('seal:<name>', '<key>')`, never a baked object id.\n\t\tstaticCodegen: () => [makeSealStaticCodegen({ name: resolved.name, mode: 'local-keygen' })],\n\t\t// `deps` auto-infers the resolved `{ sui, signer }` dependency\n\t\t// object from seal's `dependsOn: { sui: suiResource, signer:\n\t\t// opts.signer }`. `ctx` is the typed plugin-authoring surface the\n\t\t// contribution emission below drives; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst { sui, signer: signerAccount } = deps;\n\t\t\t\t// Substrate-context primitives:\n\t\t\t\t// - `ContainerRuntimeService` + `IdentityContext` arrive\n\t\t\t\t// via the supervisor's plugin runtime context.\n\t\t\t\t// - `ArtifactPublisher` is the substrate-level\n\t\t\t\t// publisher (cache → verify → produce → register cycle).\n\t\t\t\t// - Chain probe is looked up via the\n\t\t\t\t// StrategyRegistry under `chain-probe:<chainId>`; the\n\t\t\t\t// Sui plugin registered it during its own acquire.\n\t\t\t\t// The probe is yielded eagerly so the dep edge fails\n\t\t\t\t// fast if sui's chain-probe registration is missing,\n\t\t\t\t// matching walrus's pattern.\n\t\t\t\t// - `StackPathsService` resolves the per-stack on-disk\n\t\t\t\t// root so the key-server config + master-key.env\n\t\t\t\t// bind-mount sources are real paths (not the\n\t\t\t\t// `<runtime>/...` template).\n\t\t\t\tconst runtime = yield* ContainerRuntimeService;\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst stackPaths = yield* StackPathsService;\n\t\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\t\tconst path = yield* Path.Path;\n\t\t\t\tconst probe = yield* chainProbeFor<SealObjectProbeKey>(sui.chainId);\n\n\t\t\t\t// Resolve the seal service dir from the per-stack paths\n\t\t\t\t// bundle. The dir must exist before the key-server's\n\t\t\t\t// bind-mounts (config yaml + master-key env-file).\n\t\t\t\tconst servicePath = path.join(stackPaths.stackRoot, 'seal', resolved.name);\n\t\t\t\tyield* fs.makeDirectory(servicePath, { recursive: true }).pipe(\n\t\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\t\tsealError('config-render', {\n\t\t\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\t\t\tmessage: `seal.config-render: failed to create service directory at ${servicePath} — downstream config + master-key writes would all fail; surfacing the underlying filesystem error.`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// Cross-container DNS: seal's key-server dials sui RPC via\n\t\t\t\t// `host.docker.internal`. The sui plugin binds a brokered\n\t\t\t\t// host port; the SDK publish/register path runs from the host\n\t\t\t\t// process and does not need the container network.\n\t\t\t\t//\n\t\t\t\t// Architectural decision (B5): seal owns its OWN docker\n\t\t\t\t// network for the key-server's network attachment;\n\t\t\t\t// sui-side hops go through the host gateway. Mirrors\n\t\t\t\t// walrus's pattern (see plugins/walrus/index.ts §B5).\n\t\t\t\tconst sealNetworkName = buildSealNetworkName(identity.app, identity.stack, resolved.name);\n\t\t\t\tconst suiRpcUrlInNetwork = sui.hostGateway.rpcUrl;\n\t\t\t\tconst routed = buildSealKeyServerPublicRoute({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tport: DEFAULT_KEY_SERVER_PORT,\n\t\t\t\t});\n\n\t\t\t\t// Idempotent network create — the long-running key-server\n\t\t\t\t// attaches to this name. The seal boot pipeline doesn't own\n\t\t\t\t// the create (unlike walrus's local-cluster which calls\n\t\t\t\t// `ensureNetwork` from its mode body); we call it here\n\t\t\t\t// because the substrate's `acquire` is the only seam that\n\t\t\t\t// holds both the runtime + the identity needed for the\n\t\t\t\t// per-stack label tuple.\n\t\t\t\tconst sealSubnetPrefix = deriveSealSubnetPrefix({\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tsealName: resolved.name,\n\t\t\t\t});\n\t\t\t\tyield* runtime.ensureNetwork(\n\t\t\t\t\twithSubnetAddressing(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tname: sealNetworkName,\n\t\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsealSubnetPrefix,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst localKeygenDeps: LocalKeygenDeps = {\n\t\t\t\t\truntime,\n\t\t\t\t\tpublisher,\n\t\t\t\t\tsigner: signerAccount,\n\t\t\t\t\tsdk: sui.sdk,\n\t\t\t\t\t...(sui.buildImage !== null ? { buildImage: sui.buildImage } : {}),\n\t\t\t\t\tchainProbe: probe,\n\t\t\t\t\tchainId: sui.chainId,\n\t\t\t\t\tservicePath,\n\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\tlabels: {\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tplugin: 'seal',\n\t\t\t\t\t\trole: 'key-server',\n\t\t\t\t\t},\n\t\t\t\t\tsuiNetworkName: sealNetworkName,\n\t\t\t\t\tsuiRpcUrlInNetwork,\n\t\t\t\t\troutedHostname: routed.hostname,\n\t\t\t\t\troutedUrl: routed.url,\n\t\t\t\t};\n\n\t\t\t\tconst boot = (yield* bootLocalKeygen(\n\t\t\t\t\tlocalKeygenDeps,\n\t\t\t\t\tresolved,\n\t\t\t\t)) satisfies SealLocalKeygenResolved;\n\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...boot.keyServer,\n\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\tmanager: boot.keyManager,\n\t\t\t\t};\n\t\t\t\t// Emit the resolved contributions inline: snapshot (seal vault /\n\t\t\t\t// master-key secret-material subtree) → codegen → routable (key\n\t\t\t\t// server). `resolvedValue` is the just-resolved `SealResolved`;\n\t\t\t\t// `identity` (from `IdentityContext`) stamps the snapshot +\n\t\t\t\t// routable container name. The codegen bindings carry the REAL\n\t\t\t\t// objectId / keyServerUrl / serverConfigs.\n\t\t\t\tctx.snapshotExtra(\n\t\t\t\t\tmakeLocalKeygenSnapshotable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tobjectId: resolvedValue.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolvedValue.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolvedValue.serverConfigs,\n\t\t\t\t\t\tmode: 'local-keygen',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tctx.endpoint(\n\t\t\t\t\tmakeSealRoutable({\n\t\t\t\t\t\tname: resolved.name,\n\t\t\t\t\t\tcontainerName: `devstack-${identity.app}-${identity.stack}-seal-${resolved.name}-key-server`,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n/** Build the live-mode plugin. No Routable (URL is remote). */\nconst buildLivePlugin = (opts: SealLiveOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work.\n\tconst validated = validateLiveInputs({ name, ...opts });\n\tconst bindings: SealBindings = {\n\t\tname,\n\t\tobjectId: validated.objectId,\n\t\tkeyServerUrl: validated.keyServerUrl,\n\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\tmode: 'live',\n\t};\n\tconst snap = makeKnownSnapshotable({ name });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Live mode resolves its `{objectId, keyServerUrl, serverConfigs}` tuple\n\t\t// at factory time (DECLARED config) — bake them as literals in the\n\t\t// committed `seal.ts` (mirrors `knownPackage`).\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'live',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: bindings.objectId,\n\t\t\t\t\tkeyServerUrl: bindings.keyServerUrl,\n\t\t\t\t\tserverConfigs: bindings.serverConfigs,\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Live mode has no `dependsOn`, so `start` is zero-arg. `ctx`\n\t\t// drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\tconst mode: SealMode = { mode: 'live', name, resolved: validated };\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\t// Emit inline: snapshot → codegen. `snap` + `bindings` are\n\t\t\t\t// resolved at FACTORY time for live mode (validated\n\t\t\t\t// `{objectId, keyServerUrl}`), so the emit reuses the same\n\t\t\t\t// precomputed values.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(makeSealCodegenable(bindings));\n\t\t\t\treturn {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'live',\n\t\t\t\t\tmanager: null,\n\t\t\t\t} satisfies SealResolved;\n\t\t\t}),\n\t});\n};\n\n/** Build the fork-known-mode plugin. Structurally symmetric with\n * `buildLivePlugin` — both resolve their `{objectId, keyServerUrl}`\n * tuple at factory time via `validateLiveInputs` (the fork-known\n * side maps `upstream → KnownNetwork` first via\n * `validateForkKnownInputs`) and thread it through SealMode's\n * `resolved:` envelope.\n *\n * Capabilities are kept on the dynamic shape (callback form)\n * rather than precomputed — leaves room for a future on-acquire\n * override path (e.g. the substrate dynamically rewrites the\n * bindings) without restructuring the factory. Not load-bearing\n * today; static capabilities would also work. */\nconst buildForkKnownPlugin = (opts: SealForkKnownOptions) => {\n\tconst name = opts.name ?? DEFAULT_NAME;\n\tconst sealResource = makeSealResource(name);\n\tconst snap = makeKnownSnapshotable({ name });\n\t// Validate inputs at factory time so misconfigurations fail\n\t// before any plugin row starts work — symmetric with\n\t// `buildLivePlugin`'s factory-boundary `validateLiveInputs` call.\n\t// `validateForkKnownInputs` maps the upstream alias to a\n\t// `KnownNetwork` and runs the same validation pipeline as live mode.\n\tconst validated = validateForkKnownInputs({ name, ...opts });\n\n\treturn definePlugin({\n\t\tid: sealResource.id,\n\t\trole: 'task',\n\t\tsection: 'service',\n\t\t// Fork-known mode resolves its `{objectId, keyServerUrl}` tuple at\n\t\t// factory time (DECLARED config, via `validateForkKnownInputs`) — bake\n\t\t// them as literals in the committed `seal.ts` (mirrors `knownPackage`).\n\t\t// The committee `serverConfigs` is the single declared key-server (the\n\t\t// same shape `acquireLive` derives), so it is declared config too.\n\t\tstaticCodegen: () => [\n\t\t\tmakeSealStaticCodegen({\n\t\t\t\tname,\n\t\t\t\tmode: 'fork-known',\n\t\t\t\tknown: {\n\t\t\t\t\tobjectId: validated.objectId,\n\t\t\t\t\tkeyServerUrl: validated.keyServerUrl,\n\t\t\t\t\tserverConfigs: [{ objectId: validated.objectId, weight: 1 }],\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t\t// Fork-known mode has no `dependsOn`, so `start` is zero-arg.\n\t\t// `ctx` drives the contribution emission below; it arrives via the\n\t\t// `PluginContext` service.\n\t\tstart: () =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Symmetric with the live branch's `{ mode, name, resolved }`\n\t\t\t\t// envelope. `upstream` rides through for downstream\n\t\t\t\t// span attribution; `resolved` carries the validated\n\t\t\t\t// `{objectId, keyServerUrl}` tuple.\n\t\t\t\tconst mode: SealMode = {\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tname,\n\t\t\t\t\tupstream: opts.upstream,\n\t\t\t\t\tresolved: validated,\n\t\t\t\t};\n\t\t\t\tconst publisher = yield* CacheService;\n\t\t\t\tconst resolved = (yield* bootSealService(publisher, mode)) as SealKnownResolved;\n\t\t\t\tconst resolvedValue: SealResolved = {\n\t\t\t\t\t...resolved.keyServer,\n\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\tmanager: null,\n\t\t\t\t};\n\t\t\t\t// Emit inline: snapshot → codegen. `bindings` is built from the\n\t\t\t\t// post-acquire `resolved.keyServer` (`{objectId, keyServerUrl,\n\t\t\t\t// serverConfigs}`); `snap` is factory-scoped.\n\t\t\t\tctx.snapshotExtra(snap);\n\t\t\t\tctx.codegen(\n\t\t\t\t\tmakeSealCodegenable({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tobjectId: resolved.keyServer.objectId,\n\t\t\t\t\t\tkeyServerUrl: resolved.keyServer.keyServerUrl,\n\t\t\t\t\t\tserverConfigs: resolved.keyServer.serverConfigs,\n\t\t\t\t\t\tmode: 'fork-known',\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\treturn resolvedValue;\n\t\t\t}),\n\t});\n};\n\n// ---------------------------------------------------------------------------\n// User-facing factories\n// ---------------------------------------------------------------------------\n\n/** Explicit Seal factory. `local-keygen` requires a signer; live and\n * fork-known modes must be selected directly or through `sealFor`. */\nexport const seal = <const Signer extends SealSignerMember = SealSignerMember>(\n\topts: SealOptions<Signer>,\n) => {\n\tswitch (opts.mode) {\n\t\tcase 'local-keygen':\n\t\t\treturn buildLocalKeygenPlugin(opts);\n\t\tcase 'live':\n\t\t\treturn buildLivePlugin(opts);\n\t\tcase 'fork-known':\n\t\t\treturn buildForkKnownPlugin(opts);\n\t}\n};\n\n/** Mode-narrowed factory namespace.\n *\n * Usage:\n * const local = { mode: 'local' } as const;\n * sealFor(local).localKeygen({signer}) // OK\n * sealFor(local).forkKnown(...) // type error: not in 'local' branch\n *\n * const fork = { mode: 'fork' } as const;\n * sealFor(fork).forkKnown({upstream}) // OK\n * sealFor(fork).localKeygen({signer}) // type error: not in 'fork' branch\n * // (distilled-doc invariant #8)\n *\n * Distilled-doc invariant #8 (fork-localkeygen-refused): the\n * fork-mode branch has NO `localKeygen` entry — that's the\n * type-level refusal. */\nexport const sealFor = defineModeNamespace({\n\tlocal: {\n\t\tlocalKeygen: <const Signer extends SealSignerMember>(opts: SealLocalKeygenOptions<Signer>) =>\n\t\t\tbuildLocalKeygenPlugin(opts),\n\t},\n\tlive: {\n\t\ttestnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'testnet', ...opts }),\n\t\tmainnet: (opts: Omit<SealLiveOptions, 'network'> = {}) =>\n\t\t\tbuildLivePlugin({ network: 'mainnet', ...opts }),\n\t\tcustom: (\n\t\t\topts: Required<Pick<SealLiveOptions, 'objectId' | 'keyServerUrl'>> & SealLiveOptions,\n\t\t) => buildLivePlugin(opts),\n\t},\n\tfork: {\n\t\tforkKnown: (opts: SealForkKnownOptions) => buildForkKnownPlugin(opts),\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// Type-only error re-export\n// ---------------------------------------------------------------------------\n\nexport type { SealError as SealAcquireError };\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"key-manager.mjs","names":[],"sources":["../../../src/plugins/seal/key-manager.ts"],"sourcesContent":["// Seal plugin — master-key staging.\n\n// ---------------------------------------------------------------------------\n// User-facing shape — distilled doc §\"SealKeyManager interface\"\n// ---------------------------------------------------------------------------\n\n/** Local-only admin handle. Produced by the `localKeygen` mode ONLY\n * (distilled-doc invariant #15 — known-deployment modes do NOT\n * produce a manager, since we don't own the master key).\n *\n * Fields:\n * - `masterKeyEnvFile` — absolute path to the 0o600 env-file\n * (snapshot-survived). */\nexport interface SealKeyManager {\n\treadonly masterKeyEnvFile: string;\n}\n\n// ---------------------------------------------------------------------------\n// makeKeyManager — pre-provides the substrate services\n// ---------------------------------------------------------------------------\n\n/** Inputs the manager closes over. The caller (mode/local-keygen.ts)\n * has already captured the substrate services AND the per-instance\n * context (name, signer, image, etc.); this helper just assembles\n * the consumer-facing shape. */\nexport interface MakeKeyManagerInputs {\n\treadonly masterKeyEnvFile: string;\n}\n\nexport const makeKeyManager = (inputs: MakeKeyManagerInputs): SealKeyManager => ({\n\tmasterKeyEnvFile: inputs.masterKeyEnvFile,\n});\n"],"mappings":";AA6BA,MAAa,kBAAkB,YAAkD,EAChF,kBAAkB,OAAO,kBACzB"}
1
+ {"version":3,"file":"key-manager.mjs","names":[],"sources":["../../../src/plugins/seal/key-manager.ts"],"sourcesContent":["// Seal plugin — master-key staging.\n\n// ---------------------------------------------------------------------------\n// User-facing shape — distilled doc §\"SealKeyManager interface\"\n// ---------------------------------------------------------------------------\n\n/** Local-only admin handle. Produced by the `localKeygen` mode ONLY\n * (distilled-doc invariant #15 — known-deployment modes do NOT\n * produce a manager, since we don't own the master key).\n *\n * Fields:\n * - `masterKeyEnvFile` — absolute path to the 0o600 env-file\n * (snapshot-survived). */\nexport interface SealKeyManager {\n\treadonly masterKeyEnvFile: string;\n}\n\n// ---------------------------------------------------------------------------\n// makeKeyManager — pre-provides the substrate services\n// ---------------------------------------------------------------------------\n\n/** Inputs the manager closes over. The caller (mode/local-keygen.ts)\n * has already captured the substrate services AND the per-instance\n * context (name, signer, image, etc.); this helper just assembles\n * the consumer-facing shape. */\nexport interface MakeKeyManagerInputs {\n\treadonly masterKeyEnvFile: string;\n}\n\nexport const makeKeyManager = (inputs: MakeKeyManagerInputs): SealKeyManager => ({\n\tmasterKeyEnvFile: inputs.masterKeyEnvFile,\n});\n"],"mappings":";AA6BA,MAAa,kBAAkB,YAAkD,EAChF,kBAAkB,OAAO,iBAC1B"}
@@ -4,7 +4,6 @@ import { DEFAULT_KEY_SERVER_PORT, SEAL_KEY_SERVER_ENDPOINT_NAME } from "./routab
4
4
  import { ensureManagedContainer } from "../../substrate/runtime/managed-container.mjs";
5
5
  import { deriveSubnetPrefix } from "../../substrate/runtime/subnet-broker.mjs";
6
6
  import { isSealError, sealError } from "./errors.mjs";
7
- import { SealSpans } from "./spans.mjs";
8
7
  import { KEY_SERVER_CONFIG_BASENAME, MASTER_KEY_ENVFILE_BASENAME } from "./keygen.mjs";
9
8
  import { Effect } from "effect";
10
9
  import { basename, dirname, relative } from "node:path";
@@ -165,11 +164,7 @@ const startKeyServer = (runtime, spec, name) => Effect.gen(function* () {
165
164
  });
166
165
  }));
167
166
  return { containerName: spec.containerName };
168
- }).pipe(Effect.withSpan("devstack.plugin.seal.keyServer.start", { attributes: {
169
- [SealSpans.name]: name,
170
- [SealSpans.containerName]: spec.containerName,
171
- [SealSpans.routedUrl]: spec.routedUrl
172
- } }));
167
+ });
173
168
  //#endregion
174
169
  export { buildKeyServerSpec, buildSealNetworkName, deriveSealSubnetPrefix, startKeyServer };
175
170
 
@@ -1 +1 @@
1
- {"version":3,"file":"key-server.mjs","names":[],"sources":["../../../src/plugins/seal/key-server.ts"],"sourcesContent":["// Seal plugin — long-running key-server container lifecycle.\n//\n// Distilled-doc invariants pinned by this file:\n//\n// #1 (KeyServer.url == routed hostname): the URL handed to the\n// on-chain Move call MUST equal the routed hostname stamped on\n// the `seal-key-server` route. We resolve the URL ONCE via the\n// router (see `routable.ts`) and pipe the same value into both\n// the Move register pass (`deploy.ts` + `registry-publish.ts`)\n// and this file's container spec.\n//\n// #3 (env-file not -e MASTER_KEY=…): the container is launched\n// with `envFiles: [<masterKeyEnvFile>]` and a `env:` map that\n// does NOT contain `MASTER_KEY`. Distilled doc §Hard\n// requirements #3 — the inline form surfaces the key in host\n// process env + docker inspect output.\n//\n// IMPLEMENTATION CONSTRAINT: the L1 `EnsureContainerSpec`\n// contract today does NOT expose an `envFiles:` slot — only\n// `env:`. We work around this by bind-mounting the env-file\n// into the container under a stack-root bind mount; the cargo\n// image's entrypoint shell (see Hard requirement #7) is\n// responsible for `set -a; . \"$MASTER_KEY_ENVFILE\"; set +a`\n// BEFORE exec'ing the daemon, so the secret never appears in\n// `docker inspect`. ARCHITECTURE REVISION TRACKED: add `envFiles`\n// to `EnsureContainerSpec`.\n//\n// #5 (NO host-port publish): the `ports:` field is INTENTIONALLY\n// absent from the `EnsureContainerSpec` we pass to the runtime.\n// Traefik dispatches by Host: header from the well-known router\n// entrypoint `seal-key-server`.\n//\n// #7 (signal-forwarding entrypoint shell): the cargo-built image\n// embeds the entrypoint shell that traps SIGTERM and forwards\n// SIGTERM to the key-server child. Distilled doc §Hard\n// requirements #21. The image declares the right entrypoint;\n// this file does NOT re-declare it.\n\nimport { Effect, type Scope } from 'effect';\nimport { basename, dirname, relative } from 'node:path';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tEnsureContainerSpec,\n\tImageRef,\n} from '../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport {\n\tProbeTimeoutError,\n\texitCodeProbeResult,\n\twaitForProbe,\n} from '../../substrate/runtime/probes.ts';\nimport { ensureManagedContainer } from '../../substrate/runtime/managed-container.ts';\nimport { HOST_GATEWAY_EXTRA_HOSTS } from '../../substrate/runtime/host-gateway.ts';\nimport { deriveSubnetPrefix } from '../../substrate/runtime/subnet-broker.ts';\nimport { isSealError, sealError, type SealError } from './errors.ts';\nimport { KEY_SERVER_CONFIG_BASENAME, MASTER_KEY_ENVFILE_BASENAME } from './keygen.ts';\nimport { DEFAULT_KEY_SERVER_PORT, SEAL_KEY_SERVER_ENDPOINT_NAME } from './routable.ts';\nimport { SealSpans } from './spans.ts';\n\nexport { DEFAULT_KEY_SERVER_PORT } from './routable.ts';\n\n// ---------------------------------------------------------------------------\n// Constants — mirror v3 `seal/internal.ts:102-103`\n// ---------------------------------------------------------------------------\n\n/** Default `/health` probe timeout. */\nexport const DEFAULT_READY_TIMEOUT_MS = 60_000 as const;\n\n/** Inside-container config path. The binary reads `CONFIG_PATH` to\n * locate the rendered yaml. */\nexport const INSIDE_CONFIG_PATH = '/etc/seal/key-server-config.yaml' as const;\n\n/** Inside-container master-key env-file path. The entrypoint shell\n * sources this before exec'ing the daemon (Hard requirement #3 +\n * #7). */\nexport const INSIDE_MASTER_KEY_ENVFILE = '/etc/seal/master-key.env' as const;\n\nconst INSIDE_RUNTIME_ROOT = '/devstack/runtime' as const;\n\n/** Container-side env defaults. NB: `MASTER_KEY` is NOT here — it\n * flows via the bind-mounted env-file sourced by the entrypoint\n * shell. Distilled-doc invariant #3. */\nexport const CONTAINER_ENV: Readonly<Record<string, string>> = {\n\tCONFIG_PATH: INSIDE_CONFIG_PATH,\n\tMASTER_KEY_ENVFILE: INSIDE_MASTER_KEY_ENVFILE,\n\tRUST_LOG: 'info',\n};\n\nexport { HOST_GATEWAY_EXTRA_HOSTS };\n\nexport const buildSealNetworkName = (app: string, stack: string, sealName: string): string =>\n\t`devstack-${app}-${stack}-seal-${sealName}-net`;\n\nexport interface SealNetworkIdentity {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly sealName: string;\n}\n\n/** Seal's key-server network gets a deterministic /24 so repeated\n * local runs do not consume Docker's default bridge address pools.\n * Seal claims the `10.128.*` – `10.191.*` band; see\n * substrate/runtime/subnet-broker.ts for the algorithm and band\n * coordination with walrus. */\nexport const deriveSealSubnetPrefix = (identity: SealNetworkIdentity): string =>\n\tderiveSubnetPrefix(`${identity.app}\\0${identity.stack}\\0${identity.sealName}\\0seal`, 128);\n\n/** Per-probe interval inside the bounded retry. */\nconst READY_PROBE_INTERVAL_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Spec shape\n// ---------------------------------------------------------------------------\n\n/** The container spec produced for the long-running key-server. This\n * is the substrate-blind value the ContainerRuntime adapter\n * consumes. */\nexport interface KeyServerContainerSpec {\n\t/** Image ref from the Seal image resolver. */\n\treadonly image: ImageRef;\n\t/** Composed container name (substrate folds `<app>-<stack>-…`). */\n\treadonly containerName: string;\n\t/** Label tuple — drives the snapshot orchestrator's filter +\n\t * `inspectByLabels`. */\n\treadonly labels: ContainerLabelTuple;\n\t/** Mount source on host. Docker Desktop can reject freshly-created\n\t * nested file/leaf-directory bind sources even when a parent mount\n\t * can see them, so key-server mounts the stack root and points the\n\t * entrypoint at the config/envfile inside that mount.\n\t *\n\t * The rendered config + master-key envfile do not appear as their\n\t * own fields on this spec — they live under `servicePath` inside\n\t * `runtimeRootHostPath`. The single host mount publishes both into\n\t * the container; `configContainerPath` /\n\t * `masterKeyEnvFileContainerPath` give the entrypoint shell the\n\t * inside-container locations. The spec-builder asserts the\n\t * relationship between `servicePath` and `runtimeRootHostPath`. */\n\treadonly runtimeRootHostPath: string;\n\treadonly configContainerPath: string;\n\treadonly masterKeyEnvFileContainerPath: string;\n\t/** Fingerprint of config contents that affect key-server boot. */\n\treadonly configFingerprint: string;\n\t/** Inner docker network for sui DNS resolution. */\n\treadonly network: string;\n\t/** Router routing spec — Traefik file-provider stamped per\n\t * container. Distilled-doc invariant #5 (no host-port publish). */\n\treadonly routing: ReadonlyArray<{\n\t\treadonly name: string;\n\t\treadonly entrypoint: string;\n\t\treadonly servicePort: number;\n\t}>;\n\t/** Routed URL — `<routedUrl>/health` is what the ready probe\n\t * would hit if/when an HTTP probe contract lands. Today we use\n\t * an exec-based probe (see `startKeyServer`). */\n\treadonly routedUrl: string;\n\t/** Timeout for the ready probe. */\n\treadonly readyTimeoutMs: number;\n\t/** Graceful stop deadline. Distilled-doc invariant #21 — the\n\t * entrypoint shell forwards Docker's SIGTERM to the key-server. */\n\treadonly stopGraceSeconds: number;\n\t/** In-container port the daemon binds. */\n\treadonly containerPort: number;\n}\n\n// ---------------------------------------------------------------------------\n// Spec builder\n// ---------------------------------------------------------------------------\n\n/** Inputs to assemble the container spec. */\nexport interface KeyServerSpecInputs {\n\treadonly name: string;\n\treadonly image: ImageRef;\n\treadonly containerName: string;\n\treadonly labels: ContainerLabelTuple;\n\treadonly suiNetwork: string;\n\treadonly servicePath: string;\n\treadonly configFingerprint: string;\n\treadonly routedHostname: string;\n\treadonly routedUrl: string;\n\treadonly readyTimeoutMs?: number;\n}\n\n/** Build the container spec. Distilled-doc invariants #1, #3, #5\n * encoded here:\n *\n * - `routedUrl` is the SAME value the on-chain Move call registers.\n * - `env` is `CONTAINER_ENV` (no MASTER_KEY); the bind-mounted env-file\n * at `<servicePath>/master-key.env` (sourced by the entrypoint shell)\n * carries the secret.\n * - `routing[]` lists the seal-key-server entrypoint; the spec returned has\n * NO `ports:` field (it's not modelled).\n *\n * Asserts at spec-build time that the substrate-provided `servicePath`\n * lives under the derived `runtimeRootHostPath`. The single host\n * mount publishes the entire `runtimeRootHostPath` subtree; if the\n * caller ever drifts `servicePath` outside that subtree, the\n * rendered config + master-key envfile silently would not reach the\n * container — surface that drift here instead. */\nexport const buildKeyServerSpec = (inputs: KeyServerSpecInputs): KeyServerContainerSpec => {\n\tconst runtimeRootHostPath = dirname(dirname(inputs.servicePath));\n\tconst rel = relative(runtimeRootHostPath, inputs.servicePath);\n\tif (rel.length === 0 || rel.startsWith('..') || runtimeRootHostPath === '/') {\n\t\t// `runtimeRootHostPath === '/'` catches the degenerate case\n\t\t// where the `dirname(dirname(...))` walk-up collapses to the\n\t\t// host root (e.g. servicePath shorter than 3 segments) — that\n\t\t// would bind-mount the entire host into the container. Same\n\t\t// family of bug as the walrus deploy-paths walk-up.\n\t\tthrow new Error(\n\t\t\t`buildKeyServerSpec: servicePath (${inputs.servicePath}) must be a descendant of ` +\n\t\t\t\t`runtimeRootHostPath (${runtimeRootHostPath}) AND runtimeRootHostPath must not ` +\n\t\t\t\t`collapse to '/'. The single bind-mount publishes runtimeRootHostPath into the ` +\n\t\t\t\t`container — if servicePath drifts outside it, the rendered config + master-key ` +\n\t\t\t\t`envfile would silently not reach the container; if the root collapses to '/', the ` +\n\t\t\t\t`bind would publish the host root. Cross-check the substrate's seal servicePath layout.`,\n\t\t);\n\t}\n\tconst serviceDirName = basename(inputs.servicePath);\n\tconst configContainerPath = `${INSIDE_RUNTIME_ROOT}/seal/${serviceDirName}/${KEY_SERVER_CONFIG_BASENAME}`;\n\tconst masterKeyEnvFileContainerPath = `${INSIDE_RUNTIME_ROOT}/seal/${serviceDirName}/${MASTER_KEY_ENVFILE_BASENAME}`;\n\tvoid inputs.routedHostname; // flows through routedUrl\n\treturn {\n\t\timage: inputs.image,\n\t\tcontainerName: inputs.containerName,\n\t\tlabels: inputs.labels,\n\t\truntimeRootHostPath,\n\t\tconfigContainerPath,\n\t\tmasterKeyEnvFileContainerPath,\n\t\tconfigFingerprint: inputs.configFingerprint,\n\t\tnetwork: inputs.suiNetwork,\n\t\trouting: [\n\t\t\t{\n\t\t\t\tname: SEAL_KEY_SERVER_ENDPOINT_NAME,\n\t\t\t\tentrypoint: SEAL_KEY_SERVER_ENDPOINT_NAME,\n\t\t\t\tservicePort: DEFAULT_KEY_SERVER_PORT,\n\t\t\t},\n\t\t],\n\t\troutedUrl: inputs.routedUrl,\n\t\treadyTimeoutMs: inputs.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n\t\tstopGraceSeconds: 15,\n\t\tcontainerPort: DEFAULT_KEY_SERVER_PORT,\n\t};\n};\n\nexport const buildKeyServerEnsureContainerSpec = (\n\tspec: KeyServerContainerSpec,\n): EnsureContainerSpec => ({\n\tname: spec.containerName,\n\timage: spec.image,\n\tlabels: spec.labels,\n\trecreate: 'on-config-change',\n\tconfigHash: [\n\t\t'seal-key-server',\n\t\t`runtime=${spec.runtimeRootHostPath}`,\n\t\t`config=${spec.configContainerPath}`,\n\t\t`master=${spec.masterKeyEnvFileContainerPath}`,\n\t\t`content=${spec.configFingerprint}`,\n\t\t`network=${spec.network}`,\n\t].join('|'),\n\t// Distilled-doc invariant #3 — MASTER_KEY is NOT here.\n\t// The bind-mounted env-file is sourced by the entrypoint\n\t// shell BEFORE the daemon exec. See file header on the\n\t// L1 `envFiles:` gap.\n\tenv: {\n\t\t...CONTAINER_ENV,\n\t\tCONFIG_PATH: spec.configContainerPath,\n\t\tMASTER_KEY_ENVFILE: spec.masterKeyEnvFileContainerPath,\n\t},\n\tstopGraceSeconds: spec.stopGraceSeconds,\n\tnetworkAttach: [spec.network],\n\t// Distilled-doc invariant #5 — `ports` intentionally absent.\n\textraHosts: HOST_GATEWAY_EXTRA_HOSTS,\n\tmounts: [\n\t\t{\n\t\t\tsource: spec.runtimeRootHostPath,\n\t\t\ttarget: INSIDE_RUNTIME_ROOT,\n\t\t\treadonly: true,\n\t\t},\n\t],\n});\n\n// ---------------------------------------------------------------------------\n// Start procedure — real ContainerRuntime wiring\n// ---------------------------------------------------------------------------\n\n/** Start the long-running key-server container.\n *\n * Wiring:\n *\n * 1. `runtime.ensureContainer` — content-addressed image, label\n * tuple, recreate-on-config-change. Two bind mounts: the\n * rendered yaml (read-only) + the master-key env-file\n * (read-only). NO `ports:` — Traefik dispatches by Host:\n * header on the well-known `seal-key-server` entrypoint port.\n * 2. In-container ready probe via `runtime.exec` — issues an\n * HTTP GET against `http://127.0.0.1:2024/health`. Bounded\n * retries until `readyTimeoutMs`. We shell out to `curl`\n * (present in the vendored `debian:bookworm-slim` base) +\n * fall back to `nc -z` for the stub image which doesn't\n * carry curl. Both probes hit the same socket; curl\n * additionally confirms the binary has parsed CONFIG_PATH\n * and is serving the upstream's `/health` route (returns\n * `{name,version,status:\"up\"}` once boot completes —\n * distilled-doc §\"Container start + ready\").\n *\n * Stop semantics: scope-close runs `ensureContainer`'s finalizer\n * which calls `docker stop` with the Seal-specific grace window. */\nexport const startKeyServer = (\n\truntime: ContainerRuntime,\n\tspec: KeyServerContainerSpec,\n\tname: string,\n): Effect.Effect<{ readonly containerName: string }, SealError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst ensureSpec = buildKeyServerEnsureContainerSpec(spec);\n\t\tconst { labels, ...containerSpec } = ensureSpec;\n\t\tconst handle: ContainerHandle = yield* ensureManagedContainer({\n\t\t\truntime,\n\t\t\tlabels,\n\t\t\tspec: containerSpec,\n\t\t\tmapError: (cause) =>\n\t\t\t\tsealError('container', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal key-server (name=${spec.containerName}) ensureContainer failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\n\t\t// Exec-based ready probe — distilled-doc §\"Container start +\n\t\t// ready\". The vendored debian:bookworm-slim base ships\n\t\t// `curl`; the e2e stub image (alpine) ships busybox `nc`. We\n\t\t// probe with curl first (real `/health` round-trip — confirms\n\t\t// the daemon parsed CONFIG_PATH AND bound the listener) and\n\t\t// fall back to `nc -z` (TCP-only — confirms only the socket\n\t\t// is listening). One of the two MUST succeed on a healthy\n\t\t// container.\n\t\t//\n\t\t// `/health` returns `{name, version, status: \"up\"}` once the\n\t\t// binary finishes config + master-key load. Pre-boot we\n\t\t// expect connection-refused → curl returns non-zero, retry.\n\t\tconst directProbeUrl = `http://127.0.0.1:${spec.containerPort}/health`;\n\t\tyield* waitForProbe({\n\t\t\tlabel: `seal.key-server.${name}`,\n\t\t\ttimeoutMs: spec.readyTimeoutMs,\n\t\t\tintervalMs: READY_PROBE_INTERVAL_MS,\n\t\t\tprobe: () =>\n\t\t\t\truntime\n\t\t\t\t\t.exec(handle, [\n\t\t\t\t\t\t'sh',\n\t\t\t\t\t\t'-c',\n\t\t\t\t\t\t`(command -v curl >/dev/null 2>&1 && ` +\n\t\t\t\t\t\t\t`curl -fsS -m 2 ${directProbeUrl} >/dev/null) ` +\n\t\t\t\t\t\t\t`|| nc -z 127.0.0.1 ${spec.containerPort} ` +\n\t\t\t\t\t\t\t`|| exit 1`,\n\t\t\t\t\t])\n\t\t\t\t\t.pipe(Effect.map(exitCodeProbeResult)),\n\t\t}).pipe(\n\t\t\tEffect.mapError((cause) => {\n\t\t\t\tif (cause instanceof ProbeTimeoutError) {\n\t\t\t\t\t// Unwrap so we don't double-wrap an inner `SealError`:\n\t\t\t\t\t// if `lastError` was itself a `SealError` (e.g. an\n\t\t\t\t\t// upstream probe site that already promoted to typed),\n\t\t\t\t\t// re-wrapping inside `sealError('ready', …)` would\n\t\t\t\t\t// leave the cause walker chasing two layers. The\n\t\t\t\t\t// outer `passthroughOrWrap.for<SealError>` in\n\t\t\t\t\t// `index.ts` strips one such layer, but the direct\n\t\t\t\t\t// `sealError('ready', …)` path doesn't — collapse\n\t\t\t\t\t// here at the source.\n\t\t\t\t\tconst inner = cause.lastError ?? cause.lastNotReady ?? cause;\n\t\t\t\t\tif (isSealError(inner)) {\n\t\t\t\t\t\treturn inner;\n\t\t\t\t\t}\n\t\t\t\t\treturn sealError('ready', {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`seal key-server never became ready within ${spec.readyTimeoutMs}ms ` +\n\t\t\t\t\t\t\t`(directProbeUrl=${directProbeUrl}, routedUrl=${spec.routedUrl})`,\n\t\t\t\t\t\tcause: inner,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn sealError('ready', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal key-server ready-probe exec failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\tcause,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\n\t\treturn { containerName: spec.containerName };\n\t}).pipe(\n\t\tEffect.withSpan('devstack.plugin.seal.keyServer.start', {\n\t\t\tattributes: {\n\t\t\t\t[SealSpans.name]: name,\n\t\t\t\t[SealSpans.containerName]: spec.containerName,\n\t\t\t\t[SealSpans.routedUrl]: spec.routedUrl,\n\t\t\t},\n\t\t}),\n\t);\n"],"mappings":"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"}
1
+ {"version":3,"file":"key-server.mjs","names":[],"sources":["../../../src/plugins/seal/key-server.ts"],"sourcesContent":["// Seal plugin — long-running key-server container lifecycle.\n//\n// Distilled-doc invariants pinned by this file:\n//\n// #1 (KeyServer.url == routed hostname): the URL handed to the\n// on-chain Move call MUST equal the routed hostname stamped on\n// the `seal-key-server` route. We resolve the URL ONCE via the\n// router (see `routable.ts`) and pipe the same value into both\n// the Move register pass (`deploy.ts` + `registry-publish.ts`)\n// and this file's container spec.\n//\n// #3 (env-file not -e MASTER_KEY=…): the container is launched\n// with `envFiles: [<masterKeyEnvFile>]` and a `env:` map that\n// does NOT contain `MASTER_KEY`. Distilled doc §Hard\n// requirements #3 — the inline form surfaces the key in host\n// process env + docker inspect output.\n//\n// IMPLEMENTATION CONSTRAINT: the L1 `EnsureContainerSpec`\n// contract today does NOT expose an `envFiles:` slot — only\n// `env:`. We work around this by bind-mounting the env-file\n// into the container under a stack-root bind mount; the cargo\n// image's entrypoint shell (see Hard requirement #7) is\n// responsible for `set -a; . \"$MASTER_KEY_ENVFILE\"; set +a`\n// BEFORE exec'ing the daemon, so the secret never appears in\n// `docker inspect`. ARCHITECTURE REVISION TRACKED: add `envFiles`\n// to `EnsureContainerSpec`.\n//\n// #5 (NO host-port publish): the `ports:` field is INTENTIONALLY\n// absent from the `EnsureContainerSpec` we pass to the runtime.\n// Traefik dispatches by Host: header from the well-known router\n// entrypoint `seal-key-server`.\n//\n// #7 (signal-forwarding entrypoint shell): the cargo-built image\n// embeds the entrypoint shell that traps SIGTERM and forwards\n// SIGTERM to the key-server child. Distilled doc §Hard\n// requirements #21. The image declares the right entrypoint;\n// this file does NOT re-declare it.\n\nimport { Effect, type Scope } from 'effect';\nimport { basename, dirname, relative } from 'node:path';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tEnsureContainerSpec,\n\tImageRef,\n} from '../../contracts/container-runtime.ts';\nimport type { ContainerLabelTuple } from '../../contracts/snapshotable.ts';\nimport {\n\tProbeTimeoutError,\n\texitCodeProbeResult,\n\twaitForProbe,\n} from '../../substrate/runtime/probes.ts';\nimport { ensureManagedContainer } from '../../substrate/runtime/managed-container.ts';\nimport { HOST_GATEWAY_EXTRA_HOSTS } from '../../substrate/runtime/host-gateway.ts';\nimport { deriveSubnetPrefix } from '../../substrate/runtime/subnet-broker.ts';\nimport { isSealError, sealError, type SealError } from './errors.ts';\nimport { KEY_SERVER_CONFIG_BASENAME, MASTER_KEY_ENVFILE_BASENAME } from './keygen.ts';\nimport { DEFAULT_KEY_SERVER_PORT, SEAL_KEY_SERVER_ENDPOINT_NAME } from './routable.ts';\n\nexport { DEFAULT_KEY_SERVER_PORT } from './routable.ts';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Default `/health` probe timeout. */\nexport const DEFAULT_READY_TIMEOUT_MS = 60_000 as const;\n\n/** Inside-container config path. The binary reads `CONFIG_PATH` to\n * locate the rendered yaml. */\nexport const INSIDE_CONFIG_PATH = '/etc/seal/key-server-config.yaml' as const;\n\n/** Inside-container master-key env-file path. The entrypoint shell\n * sources this before exec'ing the daemon (Hard requirement #3 +\n * #7). */\nexport const INSIDE_MASTER_KEY_ENVFILE = '/etc/seal/master-key.env' as const;\n\nconst INSIDE_RUNTIME_ROOT = '/devstack/runtime' as const;\n\n/** Container-side env defaults. NB: `MASTER_KEY` is NOT here — it\n * flows via the bind-mounted env-file sourced by the entrypoint\n * shell. Distilled-doc invariant #3. */\nexport const CONTAINER_ENV: Readonly<Record<string, string>> = {\n\tCONFIG_PATH: INSIDE_CONFIG_PATH,\n\tMASTER_KEY_ENVFILE: INSIDE_MASTER_KEY_ENVFILE,\n\tRUST_LOG: 'info',\n};\n\nexport { HOST_GATEWAY_EXTRA_HOSTS };\n\nexport const buildSealNetworkName = (app: string, stack: string, sealName: string): string =>\n\t`devstack-${app}-${stack}-seal-${sealName}-net`;\n\nexport interface SealNetworkIdentity {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly sealName: string;\n}\n\n/** Seal's key-server network gets a deterministic /24 so repeated\n * local runs do not consume Docker's default bridge address pools.\n * Seal claims the `10.128.*` – `10.191.*` band; see\n * substrate/runtime/subnet-broker.ts for the algorithm and band\n * coordination with walrus. */\nexport const deriveSealSubnetPrefix = (identity: SealNetworkIdentity): string =>\n\tderiveSubnetPrefix(`${identity.app}\\0${identity.stack}\\0${identity.sealName}\\0seal`, 128);\n\n/** Per-probe interval inside the bounded retry. */\nconst READY_PROBE_INTERVAL_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Spec shape\n// ---------------------------------------------------------------------------\n\n/** The container spec produced for the long-running key-server. This\n * is the substrate-blind value the ContainerRuntime adapter\n * consumes. */\nexport interface KeyServerContainerSpec {\n\t/** Image ref from the Seal image resolver. */\n\treadonly image: ImageRef;\n\t/** Composed container name (substrate folds `<app>-<stack>-…`). */\n\treadonly containerName: string;\n\t/** Label tuple — drives the snapshot orchestrator's filter +\n\t * `inspectByLabels`. */\n\treadonly labels: ContainerLabelTuple;\n\t/** Mount source on host. Docker Desktop can reject freshly-created\n\t * nested file/leaf-directory bind sources even when a parent mount\n\t * can see them, so key-server mounts the stack root and points the\n\t * entrypoint at the config/envfile inside that mount.\n\t *\n\t * The rendered config + master-key envfile do not appear as their\n\t * own fields on this spec — they live under `servicePath` inside\n\t * `runtimeRootHostPath`. The single host mount publishes both into\n\t * the container; `configContainerPath` /\n\t * `masterKeyEnvFileContainerPath` give the entrypoint shell the\n\t * inside-container locations. The spec-builder asserts the\n\t * relationship between `servicePath` and `runtimeRootHostPath`. */\n\treadonly runtimeRootHostPath: string;\n\treadonly configContainerPath: string;\n\treadonly masterKeyEnvFileContainerPath: string;\n\t/** Fingerprint of config contents that affect key-server boot. */\n\treadonly configFingerprint: string;\n\t/** Inner docker network for sui DNS resolution. */\n\treadonly network: string;\n\t/** Router routing spec — Traefik file-provider stamped per\n\t * container. Distilled-doc invariant #5 (no host-port publish). */\n\treadonly routing: ReadonlyArray<{\n\t\treadonly name: string;\n\t\treadonly entrypoint: string;\n\t\treadonly servicePort: number;\n\t}>;\n\t/** Routed URL — `<routedUrl>/health` is what the ready probe\n\t * would hit if/when an HTTP probe contract lands. Today we use\n\t * an exec-based probe (see `startKeyServer`). */\n\treadonly routedUrl: string;\n\t/** Timeout for the ready probe. */\n\treadonly readyTimeoutMs: number;\n\t/** Graceful stop deadline. Distilled-doc invariant #21 — the\n\t * entrypoint shell forwards Docker's SIGTERM to the key-server. */\n\treadonly stopGraceSeconds: number;\n\t/** In-container port the daemon binds. */\n\treadonly containerPort: number;\n}\n\n// ---------------------------------------------------------------------------\n// Spec builder\n// ---------------------------------------------------------------------------\n\n/** Inputs to assemble the container spec. */\nexport interface KeyServerSpecInputs {\n\treadonly name: string;\n\treadonly image: ImageRef;\n\treadonly containerName: string;\n\treadonly labels: ContainerLabelTuple;\n\treadonly suiNetwork: string;\n\treadonly servicePath: string;\n\treadonly configFingerprint: string;\n\treadonly routedHostname: string;\n\treadonly routedUrl: string;\n\treadonly readyTimeoutMs?: number;\n}\n\n/** Build the container spec. Distilled-doc invariants #1, #3, #5\n * encoded here:\n *\n * - `routedUrl` is the SAME value the on-chain Move call registers.\n * - `env` is `CONTAINER_ENV` (no MASTER_KEY); the bind-mounted env-file\n * at `<servicePath>/master-key.env` (sourced by the entrypoint shell)\n * carries the secret.\n * - `routing[]` lists the seal-key-server entrypoint; the spec returned has\n * NO `ports:` field (it's not modelled).\n *\n * Asserts at spec-build time that the substrate-provided `servicePath`\n * lives under the derived `runtimeRootHostPath`. The single host\n * mount publishes the entire `runtimeRootHostPath` subtree; if the\n * caller ever drifts `servicePath` outside that subtree, the\n * rendered config + master-key envfile silently would not reach the\n * container — surface that drift here instead. */\nexport const buildKeyServerSpec = (inputs: KeyServerSpecInputs): KeyServerContainerSpec => {\n\tconst runtimeRootHostPath = dirname(dirname(inputs.servicePath));\n\tconst rel = relative(runtimeRootHostPath, inputs.servicePath);\n\tif (rel.length === 0 || rel.startsWith('..') || runtimeRootHostPath === '/') {\n\t\t// `runtimeRootHostPath === '/'` catches the degenerate case\n\t\t// where the `dirname(dirname(...))` walk-up collapses to the\n\t\t// host root (e.g. servicePath shorter than 3 segments) — that\n\t\t// would bind-mount the entire host into the container. Same\n\t\t// family of bug as the walrus deploy-paths walk-up.\n\t\tthrow new Error(\n\t\t\t`buildKeyServerSpec: servicePath (${inputs.servicePath}) must be a descendant of ` +\n\t\t\t\t`runtimeRootHostPath (${runtimeRootHostPath}) AND runtimeRootHostPath must not ` +\n\t\t\t\t`collapse to '/'. The single bind-mount publishes runtimeRootHostPath into the ` +\n\t\t\t\t`container — if servicePath drifts outside it, the rendered config + master-key ` +\n\t\t\t\t`envfile would silently not reach the container; if the root collapses to '/', the ` +\n\t\t\t\t`bind would publish the host root. Cross-check the substrate's seal servicePath layout.`,\n\t\t);\n\t}\n\tconst serviceDirName = basename(inputs.servicePath);\n\tconst configContainerPath = `${INSIDE_RUNTIME_ROOT}/seal/${serviceDirName}/${KEY_SERVER_CONFIG_BASENAME}`;\n\tconst masterKeyEnvFileContainerPath = `${INSIDE_RUNTIME_ROOT}/seal/${serviceDirName}/${MASTER_KEY_ENVFILE_BASENAME}`;\n\tvoid inputs.routedHostname; // flows through routedUrl\n\treturn {\n\t\timage: inputs.image,\n\t\tcontainerName: inputs.containerName,\n\t\tlabels: inputs.labels,\n\t\truntimeRootHostPath,\n\t\tconfigContainerPath,\n\t\tmasterKeyEnvFileContainerPath,\n\t\tconfigFingerprint: inputs.configFingerprint,\n\t\tnetwork: inputs.suiNetwork,\n\t\trouting: [\n\t\t\t{\n\t\t\t\tname: SEAL_KEY_SERVER_ENDPOINT_NAME,\n\t\t\t\tentrypoint: SEAL_KEY_SERVER_ENDPOINT_NAME,\n\t\t\t\tservicePort: DEFAULT_KEY_SERVER_PORT,\n\t\t\t},\n\t\t],\n\t\troutedUrl: inputs.routedUrl,\n\t\treadyTimeoutMs: inputs.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n\t\tstopGraceSeconds: 15,\n\t\tcontainerPort: DEFAULT_KEY_SERVER_PORT,\n\t};\n};\n\nexport const buildKeyServerEnsureContainerSpec = (\n\tspec: KeyServerContainerSpec,\n): EnsureContainerSpec => ({\n\tname: spec.containerName,\n\timage: spec.image,\n\tlabels: spec.labels,\n\trecreate: 'on-config-change',\n\tconfigHash: [\n\t\t'seal-key-server',\n\t\t`runtime=${spec.runtimeRootHostPath}`,\n\t\t`config=${spec.configContainerPath}`,\n\t\t`master=${spec.masterKeyEnvFileContainerPath}`,\n\t\t`content=${spec.configFingerprint}`,\n\t\t`network=${spec.network}`,\n\t].join('|'),\n\t// Distilled-doc invariant #3 — MASTER_KEY is NOT here.\n\t// The bind-mounted env-file is sourced by the entrypoint\n\t// shell BEFORE the daemon exec. See file header on the\n\t// L1 `envFiles:` gap.\n\tenv: {\n\t\t...CONTAINER_ENV,\n\t\tCONFIG_PATH: spec.configContainerPath,\n\t\tMASTER_KEY_ENVFILE: spec.masterKeyEnvFileContainerPath,\n\t},\n\tstopGraceSeconds: spec.stopGraceSeconds,\n\tnetworkAttach: [spec.network],\n\t// Distilled-doc invariant #5 — `ports` intentionally absent.\n\textraHosts: HOST_GATEWAY_EXTRA_HOSTS,\n\tmounts: [\n\t\t{\n\t\t\tsource: spec.runtimeRootHostPath,\n\t\t\ttarget: INSIDE_RUNTIME_ROOT,\n\t\t\treadonly: true,\n\t\t},\n\t],\n});\n\n// ---------------------------------------------------------------------------\n// Start procedure — real ContainerRuntime wiring\n// ---------------------------------------------------------------------------\n\n/** Start the long-running key-server container.\n *\n * Wiring:\n *\n * 1. `runtime.ensureContainer` — content-addressed image, label\n * tuple, recreate-on-config-change. Two bind mounts: the\n * rendered yaml (read-only) + the master-key env-file\n * (read-only). NO `ports:` — Traefik dispatches by Host:\n * header on the well-known `seal-key-server` entrypoint port.\n * 2. In-container ready probe via `runtime.exec` — issues an\n * HTTP GET against `http://127.0.0.1:2024/health`. Bounded\n * retries until `readyTimeoutMs`. We shell out to `curl`\n * (present in the vendored `debian:bookworm-slim` base) +\n * fall back to `nc -z` for the stub image which doesn't\n * carry curl. Both probes hit the same socket; curl\n * additionally confirms the binary has parsed CONFIG_PATH\n * and is serving the upstream's `/health` route (returns\n * `{name,version,status:\"up\"}` once boot completes —\n * distilled-doc §\"Container start + ready\").\n *\n * Stop semantics: scope-close runs `ensureContainer`'s finalizer\n * which calls `docker stop` with the Seal-specific grace window. */\nexport const startKeyServer = (\n\truntime: ContainerRuntime,\n\tspec: KeyServerContainerSpec,\n\tname: string,\n): Effect.Effect<{ readonly containerName: string }, SealError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst ensureSpec = buildKeyServerEnsureContainerSpec(spec);\n\t\tconst { labels, ...containerSpec } = ensureSpec;\n\t\tconst handle: ContainerHandle = yield* ensureManagedContainer({\n\t\t\truntime,\n\t\t\tlabels,\n\t\t\tspec: containerSpec,\n\t\t\tmapError: (cause) =>\n\t\t\t\tsealError('container', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal key-server (name=${spec.containerName}) ensureContainer failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\n\t\t// Exec-based ready probe — distilled-doc §\"Container start +\n\t\t// ready\". The vendored debian:bookworm-slim base ships\n\t\t// `curl`; the e2e stub image (alpine) ships busybox `nc`. We\n\t\t// probe with curl first (real `/health` round-trip — confirms\n\t\t// the daemon parsed CONFIG_PATH AND bound the listener) and\n\t\t// fall back to `nc -z` (TCP-only — confirms only the socket\n\t\t// is listening). One of the two MUST succeed on a healthy\n\t\t// container.\n\t\t//\n\t\t// `/health` returns `{name, version, status: \"up\"}` once the\n\t\t// binary finishes config + master-key load. Pre-boot we\n\t\t// expect connection-refused → curl returns non-zero, retry.\n\t\tconst directProbeUrl = `http://127.0.0.1:${spec.containerPort}/health`;\n\t\tyield* waitForProbe({\n\t\t\tlabel: `seal.key-server.${name}`,\n\t\t\ttimeoutMs: spec.readyTimeoutMs,\n\t\t\tintervalMs: READY_PROBE_INTERVAL_MS,\n\t\t\tprobe: () =>\n\t\t\t\truntime\n\t\t\t\t\t.exec(handle, [\n\t\t\t\t\t\t'sh',\n\t\t\t\t\t\t'-c',\n\t\t\t\t\t\t`(command -v curl >/dev/null 2>&1 && ` +\n\t\t\t\t\t\t\t`curl -fsS -m 2 ${directProbeUrl} >/dev/null) ` +\n\t\t\t\t\t\t\t`|| nc -z 127.0.0.1 ${spec.containerPort} ` +\n\t\t\t\t\t\t\t`|| exit 1`,\n\t\t\t\t\t])\n\t\t\t\t\t.pipe(Effect.map(exitCodeProbeResult)),\n\t\t}).pipe(\n\t\t\tEffect.mapError((cause) => {\n\t\t\t\tif (cause instanceof ProbeTimeoutError) {\n\t\t\t\t\t// Unwrap so we don't double-wrap an inner `SealError`:\n\t\t\t\t\t// if `lastError` was itself a `SealError` (e.g. an\n\t\t\t\t\t// upstream probe site that already promoted to typed),\n\t\t\t\t\t// re-wrapping inside `sealError('ready', …)` would\n\t\t\t\t\t// leave the cause walker chasing two layers. The\n\t\t\t\t\t// outer `passthroughOrWrap.for<SealError>` in\n\t\t\t\t\t// `index.ts` strips one such layer, but the direct\n\t\t\t\t\t// `sealError('ready', …)` path doesn't — collapse\n\t\t\t\t\t// here at the source.\n\t\t\t\t\tconst inner = cause.lastError ?? cause.lastNotReady ?? cause;\n\t\t\t\t\tif (isSealError(inner)) {\n\t\t\t\t\t\treturn inner;\n\t\t\t\t\t}\n\t\t\t\t\treturn sealError('ready', {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`seal key-server never became ready within ${spec.readyTimeoutMs}ms ` +\n\t\t\t\t\t\t\t`(directProbeUrl=${directProbeUrl}, routedUrl=${spec.routedUrl})`,\n\t\t\t\t\t\tcause: inner,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn sealError('ready', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal key-server ready-probe exec failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\tcause,\n\t\t\t\t});\n\t\t\t}),\n\t\t);\n\n\t\treturn { containerName: spec.containerName };\n\t});\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { redactText } from "../../substrate/runtime/observability/redaction.mjs";
2
2
  import "../../substrate/runtime/observability/index.mjs";
3
3
  import { sealError } from "./errors.mjs";
4
- import { SealSpans } from "./spans.mjs";
5
4
  import { Duration, Effect } from "effect";
6
5
  //#region src/plugins/seal/keygen.ts
7
6
  /** Entrypoint binary inside the seal image. */
@@ -82,8 +81,8 @@ const runSealKeygen = (runtime, name, image) => Effect.gen(function* () {
82
81
  stderr: redactMasterKey(result.stderr)
83
82
  }));
84
83
  return yield* parseSealKeygenOutput(result.stdout, name);
85
- }).pipe(Effect.withSpan("devstack.plugin.seal.keygen.oneShot", { attributes: { [SealSpans.name]: name } }), Effect.timeoutOrElse({
86
- duration: Duration.millis(KEYGEN_TIMEOUT_MS + 5e3),
84
+ }).pipe(Effect.timeoutOrElse({
85
+ duration: Duration.millis(35e3),
87
86
  orElse: () => Effect.fail(sealError("keygen", {
88
87
  name,
89
88
  message: `seal.keygen: outer timeout ${KEYGEN_TIMEOUT_MS}ms exceeded`
@@ -1 +1 @@
1
- {"version":3,"file":"keygen.mjs","names":[],"sources":["../../../src/plugins/seal/keygen.ts"],"sourcesContent":["// Seal plugin — BLS12-381 keygen helpers + master-key redactor.\n//\n// Distilled-doc invariant (07-seal.md §\"Generic artifact-publisher-publish\"\n// + §Hard requirements #16): the master-key MUST be redacted from any\n// stdout/stderr that may surface in a SealError. The redactor lives\n// here as the single owner so call sites (`mode/local-keygen.ts`,\n// `key-manager.ts`) all funnel through one regex.\n//\n// The keygen pipeline is REAL — `runtime.runOneShot` against the cargo\n// image runs `seal-cli genkey`, captures stdout, parses the BLS hex\n// pair. The image itself is the seam (`SEAL_CARGO_IMAGE_OVERRIDE` env\n// — see `bootstrap-assets/cargo-image.ts`).\n\nimport { Duration, Effect, type Scope } from 'effect';\n\nimport type { ContainerRuntime, ImageRef } from '../../contracts/container-runtime.ts';\nimport { redactText, type RedactionRule } from '../../substrate/runtime/observability/index.ts';\nimport { sealError, type SealError } from './errors.ts';\nimport { SealSpans } from './spans.ts';\n\n// ---------------------------------------------------------------------------\n// Constants — mirror v3 (`seal/internal.ts:115-149`)\n// ---------------------------------------------------------------------------\n\n/** Entrypoint binary inside the seal image. */\nexport const SEAL_KEYGEN_ENTRYPOINT = 'seal-cli';\n\n/** Args for the keygen one-shot. */\nexport const SEAL_KEYGEN_ARGS = ['genkey'] as const;\n\n/** Default master-key env-file basename inside `runtime/seal/`. */\nexport const MASTER_KEY_ENVFILE_BASENAME = 'master-key.env';\n\n/** Default key-server config yaml basename inside `runtime/seal/`. */\nexport const KEY_SERVER_CONFIG_BASENAME = 'key-server-config.yaml';\n\n/** Wall-clock timeout for the keygen one-shot. BLS12-381 keygen is\n * small — under 1s. 30s ceiling absorbs container startup overhead\n * on slow CI runners. */\nconst KEYGEN_TIMEOUT_MS = 30_000;\n\n// ---------------------------------------------------------------------------\n// PersistedBlsKeypair — the cache-stored shape\n// ---------------------------------------------------------------------------\n\n/** Two hex blobs round-tripped through the substrate StateStore. The\n * master key is the secret; the public key is on-chain in the\n * registered `KeyServer` object. Distilled-doc §\"Persistence model\"\n * + §Hard requirements #5 — chainId is folded into the cache key by\n * the ArtifactPublisher substrate. */\nexport interface PersistedBlsKeypair {\n\treadonly masterKey: string;\n\treadonly publicKey: string;\n}\n\n// ---------------------------------------------------------------------------\n// Redaction — distilled-doc invariant #16\n// ---------------------------------------------------------------------------\n\n/** Case-insensitive line-level pattern matching any `master[_-]?key`\n * mention. Mirrors v3's `MASTER_KEY_LINE_RE` (`seal/internal.ts:1343`). */\nconst MASTER_KEY_LINE_RE = /^.*master[_\\- ]?key.*$/gim;\n\n/** Defense-in-depth: any contiguous hex run of 64+ chars is treated as\n * a possible BLS12-381 master key (32 bytes = 64 hex chars). The\n * label-based pass catches the canonical `Master key: 0x…` format;\n * this pass catches stray hex emissions that drop the label (e.g. a\n * `log::info!(\"{}\", master)` call site upstream that prints only the\n * hex). Bounded at 64+ to avoid false-positives on shorter hex like\n * 4-byte chain ids or 8-byte object-id prefixes; legitimate Sui\n * object ids are 32 bytes (64 hex chars) and would also trip the\n * rule — acceptable, since a redacted object id is a tractable\n * diagnostic regression while a leaked master key is not.\n *\n * Boundary shape: negative lookbehind/lookahead against the hex class\n * itself (NOT `\\b`). The `\\b` form had a known gap — `0x<hex>` and\n * `<word-prefix>0x<hex>` failed to match because `0` and `x` are\n * both `\\w` characters, so `\\b` couldn't anchor at the start of the\n * hex run. The lookbehind form starts the match anywhere not\n * preceded by a hex character, so an adversarial concat like\n * `...key0xdeadbeef…` redacts the hex run starting right after the\n * non-hex `x`. */\nconst HIGH_ENTROPY_HEX_RE = /(?<![0-9a-fA-F])[0-9a-fA-F]{64,}(?![0-9a-fA-F])/g;\n\nconst MASTER_KEY_REDACTION_RULES: ReadonlyArray<RedactionRule> = [\n\t// Order matters: redact the labeled line first (replaces the whole\n\t// line including the hex), then the standalone-hex pass picks up\n\t// anything left over. Because the first pass replaces the full line\n\t// with a fixed literal containing no hex, the second pass cannot\n\t// double-replace.\n\t{\n\t\tkind: 'pattern',\n\t\tpattern: MASTER_KEY_LINE_RE,\n\t\treplacement: '[REDACTED master key]',\n\t},\n\t{\n\t\tkind: 'pattern',\n\t\tpattern: HIGH_ENTROPY_HEX_RE,\n\t\treplacement: '<REDACTED-HEX-RUN>',\n\t},\n];\n\n/** Replace any line containing `master_key` / `master-key` / `masterkey`\n * (case-insensitive) with `[REDACTED master key]`, AND any standalone\n * hex run of 64+ chars with `<REDACTED-HEX-RUN>`. Used at every site\n * that may surface stdout/stderr from `seal-cli`. */\nexport const redactMasterKey = (s: string): string => redactText(s, MASTER_KEY_REDACTION_RULES);\n\n// ---------------------------------------------------------------------------\n// Output parser — distilled-doc §\"Helpers\"\n// ---------------------------------------------------------------------------\n\n/** Parse `Master key:` / `Public key:` hex lines from `seal-cli genkey`\n * stdout. Hex prefix may or may not include `0x` (we strip it).\n *\n * Returns a typed `PersistedBlsKeypair` on success, or fails with a\n * `SealError({phase: 'keygen'})` carrying the REDACTED tail of the\n * stdout so a parser drift doesn't leak the master key into logs. */\nexport const parseSealKeygenOutput = (\n\tstdout: string,\n\tname: string,\n): Effect.Effect<PersistedBlsKeypair, SealError> => {\n\tconst stripHex = (s: string): string => (s.startsWith('0x') ? s.slice(2) : s);\n\t// Bounded widths — BLS12-381 master is 32 bytes (64 hex chars);\n\t// public key is 96 bytes uncompressed G2 (192 hex chars). The\n\t// trailing `\\b` prevents a greedy slurp if the upstream binary\n\t// ever prints adjacent hex on the same line.\n\tconst masterMatch = stdout.match(/Master key:\\s*(0x)?([0-9a-fA-F]{64})\\b/);\n\tconst publicMatch = stdout.match(/Public key:\\s*(0x)?([0-9a-fA-F]{192})\\b/);\n\tif (!masterMatch || !publicMatch) {\n\t\treturn Effect.fail(\n\t\t\tsealError('keygen', {\n\t\t\t\tname,\n\t\t\t\tmessage:\n\t\t\t\t\t'seal.keygen: could not parse seal-cli genkey output (Master key: / Public key: lines missing)',\n\t\t\t\tstdout: redactMasterKey(stdout),\n\t\t\t}),\n\t\t);\n\t}\n\treturn Effect.succeed({\n\t\tmasterKey: stripHex(masterMatch[2]!),\n\t\tpublicKey: stripHex(publicMatch[2]!),\n\t} satisfies PersistedBlsKeypair);\n};\n\n// ---------------------------------------------------------------------------\n// Real keygen one-shot\n// ---------------------------------------------------------------------------\n\n/** Run `seal-cli genkey` inside the cargo-built seal image and\n * parse the BLS12-381 master + public keys.\n *\n * Implementation:\n * 1. `runtime.runOneShot({ image, entrypoint: 'seal-cli', argv:\n * ['genkey'], timeoutMillis: 30s })` — fresh `docker run --rm`.\n * 2. Promote non-zero exit to typed SealError with REDACTED tails.\n * 3. Parse stdout via `parseSealKeygenOutput`.\n *\n * Distilled-doc invariant #16 — every stdout/stderr capture site\n * passes through `redactMasterKey` BEFORE landing in the error. The\n * parser handles the success-path; the failure path does its own\n * redact at the raise site. */\nexport const runSealKeygen = (\n\truntime: ContainerRuntime,\n\tname: string,\n\timage: ImageRef,\n): Effect.Effect<PersistedBlsKeypair, SealError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst result = yield* runtime\n\t\t\t.runOneShot({\n\t\t\t\timage,\n\t\t\t\tentrypoint: SEAL_KEYGEN_ENTRYPOINT,\n\t\t\t\targv: SEAL_KEYGEN_ARGS,\n\t\t\t\ttimeoutMillis: KEYGEN_TIMEOUT_MS,\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\tsealError('keygen', {\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tmessage: `seal-cli genkey one-shot failed: ${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\t);\n\n\t\tif (result.exitCode !== 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tsealError('keygen', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal-cli genkey exited with code ${result.exitCode}`,\n\t\t\t\t\texitCode: result.exitCode,\n\t\t\t\t\t// Defense-in-depth — the redactor handles success-path\n\t\t\t\t\t// output (where the key is the parsed value) but the\n\t\t\t\t\t// failure path's stdout MAY also carry the key, e.g.\n\t\t\t\t\t// when stderr says \"wrote master key to <log>\".\n\t\t\t\t\tstdout: redactMasterKey(result.stdout),\n\t\t\t\t\tstderr: redactMasterKey(result.stderr),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn yield* parseSealKeygenOutput(result.stdout, name);\n\t}).pipe(\n\t\tEffect.withSpan('devstack.plugin.seal.keygen.oneShot', {\n\t\t\tattributes: { [SealSpans.name]: name },\n\t\t}),\n\t\tEffect.timeoutOrElse({\n\t\t\tduration: Duration.millis(KEYGEN_TIMEOUT_MS + 5_000),\n\t\t\torElse: () =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\tsealError('keygen', {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tmessage: `seal.keygen: outer timeout ${KEYGEN_TIMEOUT_MS}ms exceeded`,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t}),\n\t);\n"],"mappings":";;;;;;;AAyBA,MAAa,yBAAyB;;AAGtC,MAAa,mBAAmB,CAAC,SAAS;;AAG1C,MAAa,8BAA8B;;AAG3C,MAAa,6BAA6B;;;;AAK1C,MAAM,oBAAoB;AA6C1B,MAAM,6BAA2D,CAMhE;CACC,MAAM;CACN,SAAS;CACT,aAAa;CACb,EACD;CACC,MAAM;CACN,SAAS;CACT,aAAa;CACb,CACD;;;;;AAMD,MAAa,mBAAmB,MAAsB,WAAW,GAAG,2BAA2B;;;;;;;AAY/F,MAAa,yBACZ,QACA,SACmD;CACnD,MAAM,YAAY,MAAuB,EAAE,WAAW,KAAK,GAAG,EAAE,MAAM,EAAE,GAAG;CAK3E,MAAM,cAAc,OAAO,MAAM,yCAAyC;CAC1E,MAAM,cAAc,OAAO,MAAM,0CAA0C;AAC3E,KAAI,CAAC,eAAe,CAAC,YACpB,QAAO,OAAO,KACb,UAAU,UAAU;EACnB;EACA,SACC;EACD,QAAQ,gBAAgB,OAAO;EAC/B,CAAC,CACF;AAEF,QAAO,OAAO,QAAQ;EACrB,WAAW,SAAS,YAAY,GAAI;EACpC,WAAW,SAAS,YAAY,GAAI;EACpC,CAA+B;;;;;;;;;;;;;;;AAoBjC,MAAa,iBACZ,SACA,MACA,UAEA,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO,QACpB,WAAW;EACX;EACA,YAAY;EACZ,MAAM;EACN,eAAe;EACf,CAAC,CACD,KACA,OAAO,OAAO,UACb,OAAO,KACN,UAAU,UAAU;EACnB;EACA,SAAS,oCAAoC,MAAM,OAAO,IAAI,MAAM;EACpE;EACA,CAAC,CACF,CACD,CACD;AAEF,KAAI,OAAO,aAAa,EACvB,QAAO,OAAO,OAAO,KACpB,UAAU,UAAU;EACnB;EACA,SAAS,oCAAoC,OAAO;EACpD,UAAU,OAAO;EAKjB,QAAQ,gBAAgB,OAAO,OAAO;EACtC,QAAQ,gBAAgB,OAAO,OAAO;EACtC,CAAC,CACF;AAGF,QAAO,OAAO,sBAAsB,OAAO,QAAQ,KAAK;EACvD,CAAC,KACF,OAAO,SAAS,uCAAuC,EACtD,YAAY,GAAG,UAAU,OAAO,MAAM,EACtC,CAAC,EACF,OAAO,cAAc;CACpB,UAAU,SAAS,OAAO,oBAAoB,IAAM;CACpD,cACC,OAAO,KACN,UAAU,UAAU;EACnB;EACA,SAAS,8BAA8B,kBAAkB;EACzD,CAAC,CACF;CACF,CAAC,CACF"}
1
+ {"version":3,"file":"keygen.mjs","names":[],"sources":["../../../src/plugins/seal/keygen.ts"],"sourcesContent":["// Seal plugin — BLS12-381 keygen helpers + master-key redactor.\n//\n// Distilled-doc invariant (07-seal.md §\"Generic artifact-publisher-publish\"\n// + §Hard requirements #16): the master-key MUST be redacted from any\n// stdout/stderr that may surface in a SealError. The redactor lives\n// here as the single owner so call sites (`mode/local-keygen.ts`,\n// `key-manager.ts`) all funnel through one regex.\n//\n// The keygen pipeline is REAL — `runtime.runOneShot` against the cargo\n// image runs `seal-cli genkey`, captures stdout, parses the BLS hex\n// pair. The image itself is the seam (`SEAL_CARGO_IMAGE_OVERRIDE` env\n// — see `bootstrap-assets/cargo-image.ts`).\n\nimport { Duration, Effect, type Scope } from 'effect';\n\nimport type { ContainerRuntime, ImageRef } from '../../contracts/container-runtime.ts';\nimport { redactText, type RedactionRule } from '../../substrate/runtime/observability/index.ts';\nimport { sealError, type SealError } from './errors.ts';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Entrypoint binary inside the seal image. */\nexport const SEAL_KEYGEN_ENTRYPOINT = 'seal-cli';\n\n/** Args for the keygen one-shot. */\nexport const SEAL_KEYGEN_ARGS = ['genkey'] as const;\n\n/** Default master-key env-file basename inside `runtime/seal/`. */\nexport const MASTER_KEY_ENVFILE_BASENAME = 'master-key.env';\n\n/** Default key-server config yaml basename inside `runtime/seal/`. */\nexport const KEY_SERVER_CONFIG_BASENAME = 'key-server-config.yaml';\n\n/** Wall-clock timeout for the keygen one-shot. BLS12-381 keygen is\n * small — under 1s. 30s ceiling absorbs container startup overhead\n * on slow CI runners. */\nconst KEYGEN_TIMEOUT_MS = 30_000;\n\n// ---------------------------------------------------------------------------\n// PersistedBlsKeypair — the cache-stored shape\n// ---------------------------------------------------------------------------\n\n/** Two hex blobs round-tripped through the substrate's content-addressed\n * cache (via the ArtifactPublisher). The master key is the secret; the\n * public key is on-chain in the registered `KeyServer` object.\n * Distilled-doc §\"Persistence model\" + §Hard requirements #5 — chainId\n * is folded into the cache key by the ArtifactPublisher substrate. */\nexport interface PersistedBlsKeypair {\n\treadonly masterKey: string;\n\treadonly publicKey: string;\n}\n\n// ---------------------------------------------------------------------------\n// Redaction — distilled-doc invariant #16\n// ---------------------------------------------------------------------------\n\n/** Case-insensitive line-level pattern matching any `master[_-]?key`\n * mention. */\nconst MASTER_KEY_LINE_RE = /^.*master[_\\- ]?key.*$/gim;\n\n/** Defense-in-depth: any contiguous hex run of 64+ chars is treated as\n * a possible BLS12-381 master key (32 bytes = 64 hex chars). The\n * label-based pass catches the canonical `Master key: 0x…` format;\n * this pass catches stray hex emissions that drop the label (e.g. a\n * `log::info!(\"{}\", master)` call site upstream that prints only the\n * hex). Bounded at 64+ to avoid false-positives on shorter hex like\n * 4-byte chain ids or 8-byte object-id prefixes; legitimate Sui\n * object ids are 32 bytes (64 hex chars) and would also trip the\n * rule — acceptable, since a redacted object id is a tractable\n * diagnostic regression while a leaked master key is not.\n *\n * Boundary shape: negative lookbehind/lookahead against the hex class\n * itself (NOT `\\b`). The `\\b` form had a known gap — `0x<hex>` and\n * `<word-prefix>0x<hex>` failed to match because `0` and `x` are\n * both `\\w` characters, so `\\b` couldn't anchor at the start of the\n * hex run. The lookbehind form starts the match anywhere not\n * preceded by a hex character, so an adversarial concat like\n * `...key0xdeadbeef…` redacts the hex run starting right after the\n * non-hex `x`. */\nconst HIGH_ENTROPY_HEX_RE = /(?<![0-9a-fA-F])[0-9a-fA-F]{64,}(?![0-9a-fA-F])/g;\n\nconst MASTER_KEY_REDACTION_RULES: ReadonlyArray<RedactionRule> = [\n\t// Order matters: redact the labeled line first (replaces the whole\n\t// line including the hex), then the standalone-hex pass picks up\n\t// anything left over. Because the first pass replaces the full line\n\t// with a fixed literal containing no hex, the second pass cannot\n\t// double-replace.\n\t{\n\t\tkind: 'pattern',\n\t\tpattern: MASTER_KEY_LINE_RE,\n\t\treplacement: '[REDACTED master key]',\n\t},\n\t{\n\t\tkind: 'pattern',\n\t\tpattern: HIGH_ENTROPY_HEX_RE,\n\t\treplacement: '<REDACTED-HEX-RUN>',\n\t},\n];\n\n/** Replace any line containing `master_key` / `master-key` / `masterkey`\n * (case-insensitive) with `[REDACTED master key]`, AND any standalone\n * hex run of 64+ chars with `<REDACTED-HEX-RUN>`. Used at every site\n * that may surface stdout/stderr from `seal-cli`. */\nexport const redactMasterKey = (s: string): string => redactText(s, MASTER_KEY_REDACTION_RULES);\n\n// ---------------------------------------------------------------------------\n// Output parser — distilled-doc §\"Helpers\"\n// ---------------------------------------------------------------------------\n\n/** Parse `Master key:` / `Public key:` hex lines from `seal-cli genkey`\n * stdout. Hex prefix may or may not include `0x` (we strip it).\n *\n * Returns a typed `PersistedBlsKeypair` on success, or fails with a\n * `SealError({phase: 'keygen'})` carrying the REDACTED tail of the\n * stdout so a parser drift doesn't leak the master key into logs. */\nexport const parseSealKeygenOutput = (\n\tstdout: string,\n\tname: string,\n): Effect.Effect<PersistedBlsKeypair, SealError> => {\n\tconst stripHex = (s: string): string => (s.startsWith('0x') ? s.slice(2) : s);\n\t// Bounded widths — BLS12-381 master is 32 bytes (64 hex chars);\n\t// public key is 96 bytes uncompressed G2 (192 hex chars). The\n\t// trailing `\\b` prevents a greedy slurp if the upstream binary\n\t// ever prints adjacent hex on the same line.\n\tconst masterMatch = stdout.match(/Master key:\\s*(0x)?([0-9a-fA-F]{64})\\b/);\n\tconst publicMatch = stdout.match(/Public key:\\s*(0x)?([0-9a-fA-F]{192})\\b/);\n\tif (!masterMatch || !publicMatch) {\n\t\treturn Effect.fail(\n\t\t\tsealError('keygen', {\n\t\t\t\tname,\n\t\t\t\tmessage:\n\t\t\t\t\t'seal.keygen: could not parse seal-cli genkey output (Master key: / Public key: lines missing)',\n\t\t\t\tstdout: redactMasterKey(stdout),\n\t\t\t}),\n\t\t);\n\t}\n\treturn Effect.succeed({\n\t\tmasterKey: stripHex(masterMatch[2]!),\n\t\tpublicKey: stripHex(publicMatch[2]!),\n\t} satisfies PersistedBlsKeypair);\n};\n\n// ---------------------------------------------------------------------------\n// Real keygen one-shot\n// ---------------------------------------------------------------------------\n\n/** Run `seal-cli genkey` inside the cargo-built seal image and\n * parse the BLS12-381 master + public keys.\n *\n * Implementation:\n * 1. `runtime.runOneShot({ image, entrypoint: 'seal-cli', argv:\n * ['genkey'], timeoutMillis: 30s })` — fresh `docker run --rm`.\n * 2. Promote non-zero exit to typed SealError with REDACTED tails.\n * 3. Parse stdout via `parseSealKeygenOutput`.\n *\n * Distilled-doc invariant #16 — every stdout/stderr capture site\n * passes through `redactMasterKey` BEFORE landing in the error. The\n * parser handles the success-path; the failure path does its own\n * redact at the raise site. */\nexport const runSealKeygen = (\n\truntime: ContainerRuntime,\n\tname: string,\n\timage: ImageRef,\n): Effect.Effect<PersistedBlsKeypair, SealError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst result = yield* runtime\n\t\t\t.runOneShot({\n\t\t\t\timage,\n\t\t\t\tentrypoint: SEAL_KEYGEN_ENTRYPOINT,\n\t\t\t\targv: SEAL_KEYGEN_ARGS,\n\t\t\t\ttimeoutMillis: KEYGEN_TIMEOUT_MS,\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\tsealError('keygen', {\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tmessage: `seal-cli genkey one-shot failed: ${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\t);\n\n\t\tif (result.exitCode !== 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tsealError('keygen', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal-cli genkey exited with code ${result.exitCode}`,\n\t\t\t\t\texitCode: result.exitCode,\n\t\t\t\t\t// Defense-in-depth — the redactor handles success-path\n\t\t\t\t\t// output (where the key is the parsed value) but the\n\t\t\t\t\t// failure path's stdout MAY also carry the key, e.g.\n\t\t\t\t\t// when stderr says \"wrote master key to <log>\".\n\t\t\t\t\tstdout: redactMasterKey(result.stdout),\n\t\t\t\t\tstderr: redactMasterKey(result.stderr),\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn yield* parseSealKeygenOutput(result.stdout, name);\n\t}).pipe(\n\t\tEffect.timeoutOrElse({\n\t\t\tduration: Duration.millis(KEYGEN_TIMEOUT_MS + 5_000),\n\t\t\torElse: () =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\tsealError('keygen', {\n\t\t\t\t\t\tname,\n\t\t\t\t\t\tmessage: `seal.keygen: outer timeout ${KEYGEN_TIMEOUT_MS}ms exceeded`,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t}),\n\t);\n"],"mappings":";;;;;;AAwBA,MAAa,yBAAyB;;AAGtC,MAAa,mBAAmB,CAAC,QAAQ;;AAGzC,MAAa,8BAA8B;;AAG3C,MAAa,6BAA6B;;;;AAK1C,MAAM,oBAAoB;AA6C1B,MAAM,6BAA2D,CAMhE;CACC,MAAM;CACN,SAAS;CACT,aAAa;AACd,GACA;CACC,MAAM;CACN,SAAS;CACT,aAAa;AACd,CACD;;;;;AAMA,MAAa,mBAAmB,MAAsB,WAAW,GAAG,0BAA0B;;;;;;;AAY9F,MAAa,yBACZ,QACA,SACmD;CACnD,MAAM,YAAY,MAAuB,EAAE,WAAW,IAAI,IAAI,EAAE,MAAM,CAAC,IAAI;CAK3E,MAAM,cAAc,OAAO,MAAM,wCAAwC;CACzE,MAAM,cAAc,OAAO,MAAM,yCAAyC;CAC1E,IAAI,CAAC,eAAe,CAAC,aACpB,OAAO,OAAO,KACb,UAAU,UAAU;EACnB;EACA,SACC;EACD,QAAQ,gBAAgB,MAAM;CAC/B,CAAC,CACF;CAED,OAAO,OAAO,QAAQ;EACrB,WAAW,SAAS,YAAY,EAAG;EACnC,WAAW,SAAS,YAAY,EAAG;CACpC,CAA+B;AAChC;;;;;;;;;;;;;;AAmBA,MAAa,iBACZ,SACA,MACA,UAEA,OAAO,IAAI,aAAa;CACvB,MAAM,SAAS,OAAO,QACpB,WAAW;EACX;EACA,YAAY;EACZ,MAAM;EACN,eAAe;CAChB,CAAC,CAAC,CACD,KACA,OAAO,OAAO,UACb,OAAO,KACN,UAAU,UAAU;EACnB;EACA,SAAS,oCAAoC,MAAM,OAAO,IAAI,MAAM;EACpE;CACD,CAAC,CACF,CACD,CACD;CAED,IAAI,OAAO,aAAa,GACvB,OAAO,OAAO,OAAO,KACpB,UAAU,UAAU;EACnB;EACA,SAAS,oCAAoC,OAAO;EACpD,UAAU,OAAO;EAKjB,QAAQ,gBAAgB,OAAO,MAAM;EACrC,QAAQ,gBAAgB,OAAO,MAAM;CACtC,CAAC,CACF;CAGD,OAAO,OAAO,sBAAsB,OAAO,QAAQ,IAAI;AACxD,CAAC,CAAC,CAAC,KACF,OAAO,cAAc;CACpB,UAAU,SAAS,OAAO,IAAyB;CACnD,cACC,OAAO,KACN,UAAU,UAAU;EACnB;EACA,SAAS,8BAA8B,kBAAkB;CAC1D,CAAC,CACF;AACF,CAAC,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"fork-known.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/fork-known.ts"],"sourcesContent":["// Seal fork-known mode — *-fork networks route to the wrapped\n// upstream's known key-server deployment.\n//\n// Distilled-doc §\"Startup — `sealKnownKeyServer` (testnet / mainnet\n// / fork)\": structurally IDENTICAL to live mode. The only difference\n// is the network resolver step at the barrel — `*-fork` networks\n// route to the wrapped upstream (mainnet-fork → mainnet,\n// testnet-fork → testnet, devnet-fork → devnet) BEFORE the\n// known-deployment lookup fires.\n//\n// Distilled-doc invariant #13: `Seal()` on `*-fork` MUST route to\n// `sealKnownKeyServer` with the wrapped upstream's deployment. The\n// barrel (`index.ts`) enforces this via `resolveDeploymentNetwork`;\n// this file's mode body simply consumes the resolved network the\n// barrel passed.\n//\n// The mode body re-uses `acquireLive` since the boot pipeline is\n// identical. We expose a distinct factory only so the mode-narrowed\n// factory namespace (`sealFor(network).forkKnown(opts)`) can\n// route by mode without leaking the live-mode internals.\n\nimport { Effect } from 'effect';\n\nimport { acquireLive, validateLiveInputs, type KnownNetwork } from './live.ts';\nimport type { SealError } from '../errors.ts';\nimport type { SealKnownResolved } from '../registry-publish.ts';\n\n// ---------------------------------------------------------------------------\n// Fork → upstream network mapping\n// ---------------------------------------------------------------------------\n\n/** Map a fork upstream to its known-deployment lookup target. */\nexport type ForkUpstream = 'mainnet' | 'testnet' | 'devnet';\n\n/** Resolve the wrapped upstream's known deployment key. Distilled-\n * doc invariant #13. */\nexport const resolveDeploymentNetwork = (upstream: ForkUpstream): KnownNetwork => upstream;\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** Pre-validated fork-known inputs. Symmetric with the live mode's\n * `{ name, resolved }` shape — the barrel resolves\n * `upstream → KnownNetwork → validated tuple` synchronously at\n * factory time so both branches reach `acquireLive` with the same\n * structural envelope. */\nexport interface ForkKnownInputs {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly resolved: { readonly objectId: string; readonly keyServerUrl: string };\n}\n\n/** Resolve the fork-known overrides + upstream-derived defaults into\n * a validated tuple. Pure synchronous projection — mirrors the\n * factory-boundary `validateLiveInputs` call in `index.ts` for the\n * live branch. Throws on missing fields after fallback (matches the\n * live branch's behaviour — see `validateLiveInputs`). */\nexport const validateForkKnownInputs = (inputs: {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}): { readonly objectId: string; readonly keyServerUrl: string } => {\n\ttry {\n\t\treturn validateLiveInputs({\n\t\t\tname: inputs.name,\n\t\t\tnetwork: resolveDeploymentNetwork(inputs.upstream),\n\t\t\tobjectId: inputs.objectId,\n\t\t\tkeyServerUrl: inputs.keyServerUrl,\n\t\t});\n\t} catch (err) {\n\t\t// Re-throw the original tagged error so downstream\n\t\t// `Effect.catchTag('SealConfigError', …)` still matches.\n\t\t// Wrapping in `new Error(…)` would strip the `_tag` and turn\n\t\t// the typed refusal into an untyped runtime crash. Prepend the\n\t\t// upstream context to the message in-place instead.\n\t\tif (isSealConfigError(err)) {\n\t\t\tthrow {\n\t\t\t\t...err,\n\t\t\t\tmessage: `seal.fork-known (upstream=${inputs.upstream}): ${err.message}`,\n\t\t\t};\n\t\t}\n\t\tthrow err;\n\t}\n};\n\nconst isSealConfigError = (\n\tvalue: unknown,\n): value is { readonly _tag: 'SealConfigError'; readonly message: string; [k: string]: unknown } =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\t(value as { _tag?: unknown })._tag === 'SealConfigError' &&\n\ttypeof (value as { message?: unknown }).message === 'string';\n\n// ---------------------------------------------------------------------------\n// Mode acquire\n// ---------------------------------------------------------------------------\n\n/** Acquire body for the fork-known mode. Inputs already pre-validated\n * by the barrel via `validateForkKnownInputs`; delegates the\n * read-side projection to live mode. The `upstream` field rides\n * through for downstream span attribution.\n *\n * Error channel kept typed as `SealError` for forward-compatibility\n * with any future fallible work this body needs to do (currently\n * `acquireLive` is `Effect.sync` so the channel is effectively\n * `never`). */\nexport const acquireForkKnown = (\n\tinputs: ForkKnownInputs,\n): Effect.Effect<SealKnownResolved, SealError> =>\n\tacquireLive({ name: inputs.name, resolved: inputs.resolved });\n"],"mappings":";;;;;AAoCA,MAAa,4BAA4B,aAAyC;;;;;;AAsBlF,MAAa,2BAA2B,WAK4B;AACnE,KAAI;AACH,SAAO,mBAAmB;GACzB,MAAM,OAAO;GACb,SAAS,yBAAyB,OAAO,SAAS;GAClD,UAAU,OAAO;GACjB,cAAc,OAAO;GACrB,CAAC;UACM,KAAK;AAMb,MAAI,kBAAkB,IAAI,CACzB,OAAM;GACL,GAAG;GACH,SAAS,6BAA6B,OAAO,SAAS,KAAK,IAAI;GAC/D;AAEF,QAAM;;;AAIR,MAAM,qBACL,UAEA,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,qBACvC,OAAQ,MAAgC,YAAY;;;;;;;;;;AAerD,MAAa,oBACZ,WAEA,YAAY;CAAE,MAAM,OAAO;CAAM,UAAU,OAAO;CAAU,CAAC"}
1
+ {"version":3,"file":"fork-known.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/fork-known.ts"],"sourcesContent":["// Seal fork-known mode — *-fork networks route to the wrapped\n// upstream's known key-server deployment.\n//\n// Distilled-doc §\"Startup — `sealKnownKeyServer` (testnet / mainnet\n// / fork)\": structurally IDENTICAL to live mode. The only difference\n// is the network resolver step at the barrel — `*-fork` networks\n// route to the wrapped upstream (mainnet-fork → mainnet,\n// testnet-fork → testnet, devnet-fork → devnet) BEFORE the\n// known-deployment lookup fires.\n//\n// Distilled-doc invariant #13: `Seal()` on `*-fork` MUST route to\n// `sealKnownKeyServer` with the wrapped upstream's deployment. The\n// barrel (`index.ts`) enforces this via `resolveDeploymentNetwork`;\n// this file's mode body simply consumes the resolved network the\n// barrel passed.\n//\n// The mode body re-uses `acquireLive` since the boot pipeline is\n// identical. We expose a distinct factory only so the mode-narrowed\n// factory namespace (`sealFor(network).forkKnown(opts)`) can\n// route by mode without leaking the live-mode internals.\n\nimport { Effect } from 'effect';\n\nimport { acquireLive, validateLiveInputs, type KnownNetwork } from './live.ts';\nimport type { SealError } from '../errors.ts';\nimport type { SealKnownResolved } from '../registry-publish.ts';\n\n// ---------------------------------------------------------------------------\n// Fork → upstream network mapping\n// ---------------------------------------------------------------------------\n\n/** Map a fork upstream to its known-deployment lookup target. */\nexport type ForkUpstream = 'mainnet' | 'testnet' | 'devnet';\n\n/** Resolve the wrapped upstream's known deployment key. Distilled-\n * doc invariant #13. */\nexport const resolveDeploymentNetwork = (upstream: ForkUpstream): KnownNetwork => upstream;\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** Pre-validated fork-known inputs. Symmetric with the live mode's\n * `{ name, resolved }` shape — the barrel resolves\n * `upstream → KnownNetwork → validated tuple` synchronously at\n * factory time so both branches reach `acquireLive` with the same\n * structural envelope. */\nexport interface ForkKnownInputs {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly resolved: { readonly objectId: string; readonly keyServerUrl: string };\n}\n\n/** Resolve the fork-known overrides + upstream-derived defaults into\n * a validated tuple. Pure synchronous projection — mirrors the\n * factory-boundary `validateLiveInputs` call in `index.ts` for the\n * live branch. Throws on missing fields after fallback (matches the\n * live branch's behaviour — see `validateLiveInputs`). */\nexport const validateForkKnownInputs = (inputs: {\n\treadonly name: string;\n\treadonly upstream: ForkUpstream;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}): { readonly objectId: string; readonly keyServerUrl: string } => {\n\ttry {\n\t\treturn validateLiveInputs({\n\t\t\tname: inputs.name,\n\t\t\tnetwork: resolveDeploymentNetwork(inputs.upstream),\n\t\t\tobjectId: inputs.objectId,\n\t\t\tkeyServerUrl: inputs.keyServerUrl,\n\t\t});\n\t} catch (err) {\n\t\t// Re-throw the original tagged error so downstream\n\t\t// `Effect.catchTag('SealConfigError', …)` still matches.\n\t\t// Wrapping in `new Error(…)` would strip the `_tag` and turn\n\t\t// the typed refusal into an untyped runtime crash. Prepend the\n\t\t// upstream context to the message in-place instead.\n\t\tif (isSealConfigError(err)) {\n\t\t\tthrow {\n\t\t\t\t...err,\n\t\t\t\tmessage: `seal.fork-known (upstream=${inputs.upstream}): ${err.message}`,\n\t\t\t};\n\t\t}\n\t\tthrow err;\n\t}\n};\n\nconst isSealConfigError = (\n\tvalue: unknown,\n): value is { readonly _tag: 'SealConfigError'; readonly message: string; [k: string]: unknown } =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\t(value as { _tag?: unknown })._tag === 'SealConfigError' &&\n\ttypeof (value as { message?: unknown }).message === 'string';\n\n// ---------------------------------------------------------------------------\n// Mode acquire\n// ---------------------------------------------------------------------------\n\n/** Acquire body for the fork-known mode. Inputs already pre-validated\n * by the barrel via `validateForkKnownInputs`; delegates the\n * read-side projection to live mode. The `upstream` field rides\n * through for downstream span attribution.\n *\n * Error channel kept typed as `SealError` for forward-compatibility\n * with any future fallible work this body needs to do (currently\n * `acquireLive` is `Effect.sync` so the channel is effectively\n * `never`). */\nexport const acquireForkKnown = (\n\tinputs: ForkKnownInputs,\n): Effect.Effect<SealKnownResolved, SealError> =>\n\tacquireLive({ name: inputs.name, resolved: inputs.resolved });\n"],"mappings":";;;;;AAoCA,MAAa,4BAA4B,aAAyC;;;;;;AAsBlF,MAAa,2BAA2B,WAK4B;CACnE,IAAI;EACH,OAAO,mBAAmB;GACzB,MAAM,OAAO;GACb,SAAS,yBAAyB,OAAO,QAAQ;GACjD,UAAU,OAAO;GACjB,cAAc,OAAO;EACtB,CAAC;CACF,SAAS,KAAK;EAMb,IAAI,kBAAkB,GAAG,GACxB,MAAM;GACL,GAAG;GACH,SAAS,6BAA6B,OAAO,SAAS,KAAK,IAAI;EAChE;EAED,MAAM;CACP;AACD;AAEA,MAAM,qBACL,UAEA,OAAO,UAAU,YACjB,UAAU,QACT,MAA6B,SAAS,qBACvC,OAAQ,MAAgC,YAAY;;;;;;;;;;AAerD,MAAa,oBACZ,WAEA,YAAY;CAAE,MAAM,OAAO;CAAM,UAAU,OAAO;AAAS,CAAC"}
@@ -17,7 +17,7 @@ const KNOWN_DEPLOYMENTS = {
17
17
  };
18
18
  /** Validate the inputs at the factory boundary. Pure synchronous
19
19
  * function. The plugin `start` body is reserved for Effect-flavored
20
- * work; the throw here matches v3's pattern (distilled-doc
20
+ * work; this validation throws synchronously (distilled-doc
21
21
  * §Failure modes). */
22
22
  const validateLiveInputs = (inputs) => {
23
23
  const fromNetwork = inputs.network && KNOWN_DEPLOYMENTS[inputs.network] ? KNOWN_DEPLOYMENTS[inputs.network] : null;
@@ -1 +1 @@
1
- {"version":3,"file":"live.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/live.ts"],"sourcesContent":["// Seal live mode — testnet / mainnet known key server.\n//\n// Distilled-doc §\"Startup — `sealKnownKeyServer`\": far simpler than\n// the local-keygen path.\n//\n// 1. Look up the known deployment (or accept explicit overrides).\n// 2. Publish the endpoint + state-store entry to the substrate\n// registries (the codegen + manifest emitters consume these).\n// 3. Return the read-side handle.\n//\n// NO chain interactions, NO docker, NO state-store writes, NO\n// keygen. Distilled-doc invariant #15 — the manager tag is NOT\n// produced (we don't own the master key for a remote deployment).\n//\n// Known-deployment lookup: distilled-doc §\"Adjacent Seal references\"\n// → `engine/known-deployments.ts:153-157` carries the\n// `mysten-testnet-1` Open-mode independent server. `mainnet`\n// intentionally empty (Mysten doesn't ship a public default key\n// server on mainnet — production is via Enoki). `devnet`\n// intentionally empty.\n\nimport { Effect } from 'effect';\n\nimport { expectNonEmptyString } from '../../../substrate/runtime/config-validation.ts';\nimport { sealConfigError } from '../errors.ts';\nimport type { SealKeyServerEntry, SealKnownResolved } from '../registry-publish.ts';\n\n// ---------------------------------------------------------------------------\n// Known-deployment table — distilled-doc reference\n// ---------------------------------------------------------------------------\n\n/** Closed set of known deployments. `mainnet` + `devnet` intentionally\n * null (no public default key server). `testnet` carries the public\n * key-server URL but `keyServerObjectId` is `null` until a real id is\n * sourced — `validateLiveInputs` forces the caller to supply\n * `objectId` explicitly in that case. */\nexport const KNOWN_DEPLOYMENTS: {\n\treadonly testnet: {\n\t\treadonly keyServerObjectId: string | null;\n\t\treadonly keyServerUrl: string;\n\t};\n\treadonly mainnet: null;\n\treadonly devnet: null;\n} = {\n\ttestnet: {\n\t\tkeyServerObjectId: null,\n\t\tkeyServerUrl: 'https://seal-keyserver.testnet.mystenlabs.com',\n\t},\n\tmainnet: null,\n\tdevnet: null,\n};\n\nexport type KnownNetwork = keyof typeof KNOWN_DEPLOYMENTS;\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** Live-mode inputs. Either `network` resolves to a known deployment\n * OR the user supplies explicit `objectId` + `keyServerUrl`\n * overrides. Distilled-doc §\"Configuration\" — the factory throws\n * synchronously if neither path produces a usable tuple. */\nexport interface LiveModeInputs {\n\treadonly name: string;\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Resolved\n// ---------------------------------------------------------------------------\n\n/** Validate the inputs at the factory boundary. Pure synchronous\n * function. The plugin `start` body is reserved for Effect-flavored\n * work; the throw here matches v3's pattern (distilled-doc\n * §Failure modes). */\nexport const validateLiveInputs = (\n\tinputs: LiveModeInputs,\n): {\n\treadonly objectId: string;\n\treadonly keyServerUrl: string;\n} => {\n\tconst fromNetwork =\n\t\tinputs.network && KNOWN_DEPLOYMENTS[inputs.network] ? KNOWN_DEPLOYMENTS[inputs.network] : null;\n\tconst objectId = inputs.objectId ?? fromNetwork?.keyServerObjectId;\n\tconst keyServerUrl = inputs.keyServerUrl ?? fromNetwork?.keyServerUrl;\n\tconst message = `seal.live: missing required fields. Pass network ('testnet') or set objectId + keyServerUrl explicitly (got network=${String(\n\t\tinputs.network,\n\t)}, objectId=${String(inputs.objectId)}, keyServerUrl=${String(inputs.keyServerUrl)}).`;\n\treturn {\n\t\tobjectId: expectNonEmptyString(objectId, {\n\t\t\tfield: 'objectId',\n\t\t\tmessage,\n\t\t\tmkError: sealConfigError,\n\t\t}),\n\t\tkeyServerUrl: expectNonEmptyString(keyServerUrl, {\n\t\t\tfield: 'keyServerUrl',\n\t\t\tmessage,\n\t\t\tmkError: sealConfigError,\n\t\t}),\n\t};\n};\n\n// ---------------------------------------------------------------------------\n// Mode acquire\n// ---------------------------------------------------------------------------\n\n/** Acquire body for the live mode. Validation already ran at the\n * factory boundary (see `index.ts:buildLivePlugin`); this projects\n * the validated bundle into the resolved shape. Returns the\n * read-side handle ONLY (no manager tag — distilled-doc invariant #15). */\nexport const acquireLive = (inputs: {\n\treadonly name: string;\n\treadonly resolved: { readonly objectId: string; readonly keyServerUrl: string };\n}): Effect.Effect<SealKnownResolved> =>\n\tEffect.sync(() => {\n\t\tconst serverConfigs: ReadonlyArray<SealKeyServerEntry> = [\n\t\t\t{ objectId: inputs.resolved.objectId, weight: 1 },\n\t\t];\n\t\treturn {\n\t\t\tkeyServer: {\n\t\t\t\tserverConfigs,\n\t\t\t\tkeyServerUrl: inputs.resolved.keyServerUrl,\n\t\t\t\tobjectId: inputs.resolved.objectId,\n\t\t\t},\n\t\t} satisfies SealKnownResolved;\n\t});\n"],"mappings":";;;;;;;;;AAoCA,MAAa,oBAOT;CACH,SAAS;EACR,mBAAmB;EACnB,cAAc;EACd;CACD,SAAS;CACT,QAAQ;CACR;;;;;AA2BD,MAAa,sBACZ,WAII;CACJ,MAAM,cACL,OAAO,WAAW,kBAAkB,OAAO,WAAW,kBAAkB,OAAO,WAAW;CAC3F,MAAM,WAAW,OAAO,YAAY,aAAa;CACjD,MAAM,eAAe,OAAO,gBAAgB,aAAa;CACzD,MAAM,UAAU,uHAAuH,OACtI,OAAO,QACP,CAAC,aAAa,OAAO,OAAO,SAAS,CAAC,iBAAiB,OAAO,OAAO,aAAa,CAAC;AACpF,QAAO;EACN,UAAU,qBAAqB,UAAU;GACxC,OAAO;GACP;GACA,SAAS;GACT,CAAC;EACF,cAAc,qBAAqB,cAAc;GAChD,OAAO;GACP;GACA,SAAS;GACT,CAAC;EACF;;;;;;AAWF,MAAa,eAAe,WAI3B,OAAO,WAAW;AAIjB,QAAO,EACN,WAAW;EACV,eAAA,CAJD;GAAE,UAAU,OAAO,SAAS;GAAU,QAAQ;GAAG,CAInC;EACb,cAAc,OAAO,SAAS;EAC9B,UAAU,OAAO,SAAS;EAC1B,EACD;EACA"}
1
+ {"version":3,"file":"live.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/live.ts"],"sourcesContent":["// Seal live mode — testnet / mainnet known key server.\n//\n// Distilled-doc §\"Startup — `sealKnownKeyServer`\": far simpler than\n// the local-keygen path.\n//\n// 1. Look up the known deployment (or accept explicit overrides).\n// 2. Publish the resolved key-server endpoint as the plugin's\n// resource (the codegen + manifest emitters consume it).\n// 3. Return the read-side handle.\n//\n// NO chain interactions, NO docker, NO on-disk persistence, NO\n// keygen. Distilled-doc invariant #15 — the manager tag is NOT\n// produced (we don't own the master key for a remote deployment).\n//\n// Known-deployment lookup: distilled-doc §\"Adjacent Seal references\"\n// → `engine/known-deployments.ts:153-157` carries the\n// `mysten-testnet-1` Open-mode independent server. `mainnet`\n// intentionally empty (Mysten doesn't ship a public default key\n// server on mainnet — production is via Enoki). `devnet`\n// intentionally empty.\n\nimport { Effect } from 'effect';\n\nimport { expectNonEmptyString } from '../../../substrate/runtime/config-validation.ts';\nimport { sealConfigError } from '../errors.ts';\nimport type { SealKeyServerEntry, SealKnownResolved } from '../registry-publish.ts';\n\n// ---------------------------------------------------------------------------\n// Known-deployment table — distilled-doc reference\n// ---------------------------------------------------------------------------\n\n/** Closed set of known deployments. `mainnet` + `devnet` intentionally\n * null (no public default key server). `testnet` carries the public\n * key-server URL but `keyServerObjectId` is `null` until a real id is\n * sourced — `validateLiveInputs` forces the caller to supply\n * `objectId` explicitly in that case. */\nexport const KNOWN_DEPLOYMENTS: {\n\treadonly testnet: {\n\t\treadonly keyServerObjectId: string | null;\n\t\treadonly keyServerUrl: string;\n\t};\n\treadonly mainnet: null;\n\treadonly devnet: null;\n} = {\n\ttestnet: {\n\t\tkeyServerObjectId: null,\n\t\tkeyServerUrl: 'https://seal-keyserver.testnet.mystenlabs.com',\n\t},\n\tmainnet: null,\n\tdevnet: null,\n};\n\nexport type KnownNetwork = keyof typeof KNOWN_DEPLOYMENTS;\n\n// ---------------------------------------------------------------------------\n// Inputs\n// ---------------------------------------------------------------------------\n\n/** Live-mode inputs. Either `network` resolves to a known deployment\n * OR the user supplies explicit `objectId` + `keyServerUrl`\n * overrides. Distilled-doc §\"Configuration\" — the factory throws\n * synchronously if neither path produces a usable tuple. */\nexport interface LiveModeInputs {\n\treadonly name: string;\n\treadonly network?: KnownNetwork;\n\treadonly objectId?: string;\n\treadonly keyServerUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Resolved\n// ---------------------------------------------------------------------------\n\n/** Validate the inputs at the factory boundary. Pure synchronous\n * function. The plugin `start` body is reserved for Effect-flavored\n * work; this validation throws synchronously (distilled-doc\n * §Failure modes). */\nexport const validateLiveInputs = (\n\tinputs: LiveModeInputs,\n): {\n\treadonly objectId: string;\n\treadonly keyServerUrl: string;\n} => {\n\tconst fromNetwork =\n\t\tinputs.network && KNOWN_DEPLOYMENTS[inputs.network] ? KNOWN_DEPLOYMENTS[inputs.network] : null;\n\tconst objectId = inputs.objectId ?? fromNetwork?.keyServerObjectId;\n\tconst keyServerUrl = inputs.keyServerUrl ?? fromNetwork?.keyServerUrl;\n\tconst message = `seal.live: missing required fields. Pass network ('testnet') or set objectId + keyServerUrl explicitly (got network=${String(\n\t\tinputs.network,\n\t)}, objectId=${String(inputs.objectId)}, keyServerUrl=${String(inputs.keyServerUrl)}).`;\n\treturn {\n\t\tobjectId: expectNonEmptyString(objectId, {\n\t\t\tfield: 'objectId',\n\t\t\tmessage,\n\t\t\tmkError: sealConfigError,\n\t\t}),\n\t\tkeyServerUrl: expectNonEmptyString(keyServerUrl, {\n\t\t\tfield: 'keyServerUrl',\n\t\t\tmessage,\n\t\t\tmkError: sealConfigError,\n\t\t}),\n\t};\n};\n\n// ---------------------------------------------------------------------------\n// Mode acquire\n// ---------------------------------------------------------------------------\n\n/** Acquire body for the live mode. Validation already ran at the\n * factory boundary (see `index.ts:buildLivePlugin`); this projects\n * the validated bundle into the resolved shape. Returns the\n * read-side handle ONLY (no manager tag — distilled-doc invariant #15). */\nexport const acquireLive = (inputs: {\n\treadonly name: string;\n\treadonly resolved: { readonly objectId: string; readonly keyServerUrl: string };\n}): Effect.Effect<SealKnownResolved> =>\n\tEffect.sync(() => {\n\t\tconst serverConfigs: ReadonlyArray<SealKeyServerEntry> = [\n\t\t\t{ objectId: inputs.resolved.objectId, weight: 1 },\n\t\t];\n\t\treturn {\n\t\t\tkeyServer: {\n\t\t\t\tserverConfigs,\n\t\t\t\tkeyServerUrl: inputs.resolved.keyServerUrl,\n\t\t\t\tobjectId: inputs.resolved.objectId,\n\t\t\t},\n\t\t} satisfies SealKnownResolved;\n\t});\n"],"mappings":";;;;;;;;;AAoCA,MAAa,oBAOT;CACH,SAAS;EACR,mBAAmB;EACnB,cAAc;CACf;CACA,SAAS;CACT,QAAQ;AACT;;;;;AA2BA,MAAa,sBACZ,WAII;CACJ,MAAM,cACL,OAAO,WAAW,kBAAkB,OAAO,WAAW,kBAAkB,OAAO,WAAW;CAC3F,MAAM,WAAW,OAAO,YAAY,aAAa;CACjD,MAAM,eAAe,OAAO,gBAAgB,aAAa;CACzD,MAAM,UAAU,uHAAuH,OACtI,OAAO,OACR,EAAE,aAAa,OAAO,OAAO,QAAQ,EAAE,iBAAiB,OAAO,OAAO,YAAY,EAAE;CACpF,OAAO;EACN,UAAU,qBAAqB,UAAU;GACxC,OAAO;GACP;GACA,SAAS;EACV,CAAC;EACD,cAAc,qBAAqB,cAAc;GAChD,OAAO;GACP;GACA,SAAS;EACV,CAAC;CACF;AACD;;;;;AAUA,MAAa,eAAe,WAI3B,OAAO,WAAW;CAIjB,OAAO,EACN,WAAW;EACV,eAAA,CAJD;GAAE,UAAU,OAAO,SAAS;GAAU,QAAQ;EAAE,CAInC;EACZ,cAAc,OAAO,SAAS;EAC9B,UAAU,OAAO,SAAS;CAC3B,EACD;AACD,CAAC"}
@@ -1,9 +1,7 @@
1
- import { SpanAttr } from "../../../substrate/runtime/observability/spans.mjs";
1
+ import { decodeJsonText } from "../../../substrate/runtime/runtime-decode.mjs";
2
2
  import { versionedDocSchema } from "../../../substrate/versioned-doc-schema.mjs";
3
3
  import { atomicWriteFile } from "../../../substrate/runtime/atomic-write.mjs";
4
- import { decodeJsonText } from "../../../substrate/runtime/runtime-decode.mjs";
5
4
  import { sealError } from "../errors.mjs";
6
- import { SealSpans } from "../spans.mjs";
7
5
  import { MASTER_KEY_ENVFILE_BASENAME, runSealKeygen } from "../keygen.mjs";
8
6
  import { buildKeyServerSpec, startKeyServer } from "../key-server.mjs";
9
7
  import { parseMasterKeyEnvFile, renderSealKeyServerConfig, stageSealConfig } from "../config-render.mjs";
@@ -106,7 +104,7 @@ const ensureLocalKeygenArtifacts = (deps, opts, publicKey) => Effect.gen(functio
106
104
  const movePackagePath = yield* resolveMovePackagePath(deps, opts);
107
105
  const { packageId } = yield* publishSealPackage(deps.publisher, {
108
106
  name: opts.name,
109
- chain: deps.chain,
107
+ chainId: deps.chainId,
110
108
  movePackagePath,
111
109
  signer: deps.signer,
112
110
  sdk: deps.sdk,
@@ -116,7 +114,7 @@ const ensureLocalKeygenArtifacts = (deps, opts, publicKey) => Effect.gen(functio
116
114
  });
117
115
  const { objectId: keyServerObjectId } = yield* registerKeyServer(deps.publisher, {
118
116
  name: opts.name,
119
- chain: deps.chain,
117
+ chainId: deps.chainId,
120
118
  keyServerUrl: deps.routedUrl,
121
119
  sealPackageId: packageId,
122
120
  publicKeyHex: publicKey,
@@ -205,11 +203,7 @@ const bootLocalKeygen = (deps, opts) => Effect.gen(function* () {
205
203
  name: opts.name,
206
204
  message: `seal.local-keygen: on-chain artifact failure (${err.reason}): ${err.detail}`,
207
205
  cause: err
208
- }))), Effect.withSpan("devstack.plugin.seal.localKeygen.boot", { attributes: {
209
- [SpanAttr.plugin]: "seal",
210
- [SealSpans.name]: opts.name,
211
- [SealSpans.version]: opts.version
212
- } }));
206
+ }))));
213
207
  //#endregion
214
208
  export { bootLocalKeygen, resolveLocalKeygenOptions };
215
209
 
@@ -1 +1 @@
1
- {"version":3,"file":"local-keygen.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/local-keygen.ts"],"sourcesContent":["// Seal local-keygen mode — the full localnet path.\n//\n// Distilled-doc reference (07-seal.md §\"Lifecycle / Startup —\n// `sealLocalKeygen`\"). Eight ordered phases:\n//\n// 0. Yield deps (Sui, Identity, ContainerRuntime, artifact publisher publisher).\n// 1. Image build (bootstrap asset — parallel with sui's boot).\n// 1a. Move source resolve (bootstrap asset, conditional).\n// 2. BLS keygen one-shot (real `runtime.runOneShot` against cargo\n// image; output parsed via regex).\n// 3. Publish seal Move package (via artifact publisher primitive).\n// 4. Register on-chain KeyServer (via artifact publisher primitive).\n// 5. Render config yaml + stage master-key env-file (atomic\n// FileSystem\n// writes).\n// 6. Start long-running key-server container (real\n// `runtime.ensureContainer`\n// + exec-based ready\n// probe).\n// 7. Project the plugin's aggregate value.\n//\n// Distilled-doc invariants pinned by this file:\n//\n// #1 KeyServer.url == routed hostname — single mint point\n// (`routedUrl` passed\n// identically into\n// `registerKeyServer`\n// and `buildKeyServerSpec`).\n// #2 Boot order keygen → publish → register → config → container.\n// #4 env-file for secret loading (not -e MASTER_KEY=…).\n// #5 No host-port publish.\n// #6 Keypair B8 verify cascade (deploy.ts:buildKeypairVerify).\n// #7 Signal-forwarding entrypoint shell (image-side).\n// #8 Fork incompatibility throw — handled at the barrel\n// (`index.ts`), NOT here.\n// #9 Peer-dep structural assignability (compile-time check\n// lives in registry-publish.ts).\n//\n// This is the substrate-name-LEAK boundary. Inside this file we can\n// say \"seal\"; outside `src/plugins/seal/`, the substrate doesn't\n// know seal exists.\n\nimport { Effect, FileSystem, Path, Schema, type Scope } from 'effect';\n\nimport { decodeJsonText } from '../../../substrate/runtime/runtime-decode.ts';\n\nimport type { ChainId } from '../../../substrate/brand.ts';\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport type { ContainerLabelTuple } from '../../../contracts/snapshotable.ts';\nimport type { ContainerRuntime, ImageRef } from '../../../contracts/container-runtime.ts';\nimport type {\n\tArtifactPublishError,\n\tArtifactPublisher,\n} from '../../../primitives/artifact-publisher.ts';\nimport type { AccountValue } from '../../account/index.ts';\nimport {\n\tparseMasterKeyEnvFile,\n\trenderSealKeyServerConfig,\n\tstageSealConfig,\n} from '../config-render.ts';\nimport {\n\tpublishSealPackage,\n\tregisterKeyServer,\n\ttype SealObjectProbeKey,\n\ttype SealSuiSdk,\n} from '../deploy.ts';\nimport { sealError, type SealError } from '../errors.ts';\nimport { SealSpans } from '../spans.ts';\nimport { SpanAttr } from '../../../substrate/runtime/observability/spans.ts';\nimport { MASTER_KEY_ENVFILE_BASENAME, runSealKeygen, type PersistedBlsKeypair } from '../keygen.ts';\nimport { makeKeyManager } from '../key-manager.ts';\nimport { buildKeyServerSpec, startKeyServer, type KeyServerContainerSpec } from '../key-server.ts';\nimport type { SealKeyServerEntry, SealLocalKeygenResolved } from '../registry-publish.ts';\nimport { resolveDefaultSealCargoImage } from '../bootstrap-assets/cargo-image.ts';\nimport { resolveDefaultSealSource } from '../bootstrap-assets/source-fetch.ts';\nimport { atomicWriteFile } from '../../../substrate/runtime/atomic-write.ts';\nimport { versionedDocSchema } from '../../../substrate/versioned-doc-schema.ts';\n\n// ---------------------------------------------------------------------------\n// Options (factory-time)\n// ---------------------------------------------------------------------------\n\n/** Options the local-keygen mode accepts. Mirrors v3\n * `SealLocalKeygenOptions` (07-seal.md §\"Configuration\"). The\n * barrel (`index.ts`) folds the typed `SealLocalKeygenOptions`\n * surface into this internal shape after default resolution. */\nexport interface LocalKeygenOptions {\n\treadonly name?: string;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n}\n\n/** Resolved options after defaults are applied. */\nexport interface ResolvedLocalKeygenOptions {\n\treadonly name: string;\n\treadonly version: string;\n\treadonly readyTimeoutMs: number;\n\treadonly keyServerName: string;\n\treadonly movePackagePath?: string;\n}\n\nconst DEFAULT_READY_TIMEOUT_MS = 60_000;\nconst DEFAULT_KEY_SERVER_NAME = 'devstack-local';\n\n/** Synchronous factory-time defaults application. Pure — no\n * validation throws because the localnet signer requirement is\n * enforced one layer up in the barrel (the type-narrowed\n * `sealFor(local).localKeygen({signer})` makes signer required). */\nexport const resolveLocalKeygenOptions = (\n\topts: LocalKeygenOptions,\n\tdefaultVersion: string,\n): ResolvedLocalKeygenOptions => ({\n\tname: opts.name ?? 'seal',\n\tversion: opts.version ?? defaultVersion,\n\treadyTimeoutMs: opts.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n\tkeyServerName: opts.keyServerName ?? DEFAULT_KEY_SERVER_NAME,\n\tmovePackagePath: opts.movePackagePath,\n});\n\n// ---------------------------------------------------------------------------\n// Inputs to the boot pipeline (acquire-time)\n// ---------------------------------------------------------------------------\n\n/** Acquire-time deps the boot pipeline consumes. Sourced by the\n * barrel (`index.ts`) from a mix of:\n *\n * - substrate-resolved values (`IdentityContext`,\n * `ContainerRuntimeService`, `ArtifactPublisher`);\n * - substrate-derived identifiers (chainId, servicePath,\n * subnet, etc.);\n * - router-resolved URL (single mint — distilled-doc invariant #1).\n *\n * The barrel composes these from substrate services\n * (ContainerRuntime, IdentityContext, ArtifactPublisher,\n * StackPathsService) at acquire-time. */\nexport interface LocalKeygenDeps {\n\treadonly runtime: ContainerRuntime;\n\treadonly publisher: ArtifactPublisher;\n\treadonly signer: AccountValue;\n\treadonly sdk: SealSuiSdk;\n\treadonly buildImage?: ImageRef;\n\treadonly chainProbe: ChainProbe<SealObjectProbeKey>;\n\treadonly chain: ChainId;\n\t/** Per-stack on-disk dir under `runtime/seal/`. Host path for the\n\t * config yaml + master-key env-file. */\n\treadonly servicePath: string;\n\t/** Container name composed by the substrate (app + stack + name +\n\t * role). */\n\treadonly containerName: string;\n\t/** Label tuple driving snapshot/inspect by labels. */\n\treadonly labels: ContainerLabelTuple;\n\t/** Seal's per-stack docker network — the key-server daemon attaches\n\t * to this network. */\n\treadonly suiNetworkName: string;\n\t/** In-network sui RPC URL — the daemon's CONFIG_PATH yaml carries\n\t * this. */\n\treadonly suiRpcUrlInNetwork: string;\n\t/** Router-resolved single mint (distilled-doc invariant #1). */\n\treadonly routedHostname: string;\n\treadonly routedUrl: string;\n}\n\ninterface PersistedLocalKeygenKeyMaterial {\n\treadonly masterKey: string;\n\treadonly publicKey: string;\n\treadonly masterKeyEnvFile: string;\n}\n\ninterface PersistedLocalKeygenState extends PersistedLocalKeygenKeyMaterial {\n\treadonly packageId: string;\n\treadonly keyServerObjectId: string;\n}\n\nconst LOCAL_KEYGEN_STATE_VERSION = 1;\nconst LOCAL_KEYGEN_STATE_BASENAME = 'local-keygen-state.v1.json';\n\nconst PersistedLocalKeygenMetadataSchema = versionedDocSchema(LOCAL_KEYGEN_STATE_VERSION, {\n\tpublicKey: Schema.String,\n});\n\ntype PersistedLocalKeygenMetadata = Schema.Schema.Type<typeof PersistedLocalKeygenMetadataSchema>;\n\nconst localKeygenMetadataPath = (servicePath: string): string =>\n\t`${servicePath}/${LOCAL_KEYGEN_STATE_BASENAME}`;\n\nconst readPersistedLocalKeygenMetadata = (\n\tservicePath: string,\n): Effect.Effect<PersistedLocalKeygenMetadata | null, never, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst path = localKeygenMetadataPath(servicePath);\n\t\tconst raw = yield* fs.readFileString(path).pipe(Effect.catch(() => Effect.succeed(null)));\n\t\tif (raw === null) return null;\n\t\t// Parse + decode failures here mean \"no usable persisted metadata\"\n\t\t// and the caller treats this as a miss; the typed\n\t\t// `RuntimeDecodeIssue` carries the parse/decode diagnostic for\n\t\t// debugging but is collapsed to `null` so the boot loop falls\n\t\t// through to a fresh keygen.\n\t\treturn yield* decodeJsonText(PersistedLocalKeygenMetadataSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) => issue,\n\t\t}).pipe(Effect.catch(() => Effect.succeed(null)));\n\t});\n\nconst stagePersistedLocalKeygenMetadata = (\n\tservicePath: string,\n\tname: string,\n\tmetadata: PersistedLocalKeygenMetadata,\n): Effect.Effect<void, SealError, FileSystem.FileSystem> =>\n\tatomicWriteFile(\n\t\tlocalKeygenMetadataPath(servicePath),\n\t\tnew TextEncoder().encode(`${JSON.stringify(metadata, null, 2)}\\n`),\n\t\t{\n\t\t\tmode: 0o644,\n\t\t\tparentMode: 0o700,\n\t\t},\n\t).pipe(\n\t\tEffect.catch((cause) =>\n\t\t\tEffect.fail(\n\t\t\t\tsealError('config-render', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal.config-render: failed to write ${LOCAL_KEYGEN_STATE_BASENAME} (${cause.stage})`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n\nconst readPersistedLocalKeygenState = (\n\tservicePath: string,\n): Effect.Effect<PersistedLocalKeygenKeyMaterial | null, never, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst masterKeyEnvFile = `${servicePath}/${MASTER_KEY_ENVFILE_BASENAME}`;\n\t\tconst masterKeyBody = yield* fs\n\t\t\t.readFileString(masterKeyEnvFile)\n\t\t\t.pipe(Effect.catch(() => Effect.succeed(null)));\n\t\tif (masterKeyBody === null) return null;\n\t\tconst masterKey = parseMasterKeyEnvFile(masterKeyBody);\n\t\tif (masterKey === null) return null;\n\t\tconst metadata = yield* readPersistedLocalKeygenMetadata(servicePath);\n\t\tif (metadata === null) return null;\n\n\t\treturn {\n\t\t\tmasterKey,\n\t\t\tpublicKey: metadata.publicKey,\n\t\t\tmasterKeyEnvFile,\n\t\t};\n\t});\n\n/** BLS12-381 master key — 32 bytes, persisted as 64 hex chars. */\nconst BLS_MASTER_KEY_HEX_LEN = 64;\n/** BLS12-381 G2 uncompressed public key — 96 bytes, persisted as 192 hex chars. */\nconst BLS_PUBLIC_KEY_HEX_LEN = 192;\nconst HEX_ONLY_RE = /^[0-9a-fA-F]+$/;\n\n/** Stricter decode than the JSON-shape Schema alone — verifies the\n * persisted master key + public key are well-formed BLS12-381 hex of\n * the expected widths. The Schema validation alone accepts any\n * string, so a corrupt-on-disk JSON whose `publicKey` was overwritten\n * to a shorter / wrong-width value would otherwise be silently\n * reused on boot — leading to a master-key / KeyServer mismatch\n * (the master-key.env carries one key, the registered KeyServer's\n * on-chain `publicKey` carries a different one). Distilled-doc\n * invariant #6 (keypair B8 verify cascade) covers the on-chain\n * side; this is the on-disk side.\n *\n * We cannot in-process re-derive the G2 public key from the master\n * scalar without bundling a BLS12-381 implementation (the keygen\n * binary owns this in cargo-land). The width invariant is the\n * cheapest defense that catches the realistic corruption modes:\n * truncated writes, hand-edited JSON, stale persistence from an\n * older devstack version. */\nconst validatePersistedKeyMaterialShape = (\n\tmaterial: PersistedLocalKeygenKeyMaterial,\n\tname: string,\n): Effect.Effect<void, SealError> => {\n\tif (material.masterKey.length !== BLS_MASTER_KEY_HEX_LEN || !HEX_ONLY_RE.test(material.masterKey)) {\n\t\treturn Effect.fail(\n\t\t\tsealError('config-render', {\n\t\t\t\tname,\n\t\t\t\tmessage:\n\t\t\t\t\t`seal.local-keygen: persisted master key in ${MASTER_KEY_ENVFILE_BASENAME} ` +\n\t\t\t\t\t`is not ${BLS_MASTER_KEY_HEX_LEN}-char hex (got ${material.masterKey.length} chars). ` +\n\t\t\t\t\t'The on-disk state is corrupt; delete the seal service directory and ' +\n\t\t\t\t\t're-boot to regenerate, or restore from a known-good snapshot.',\n\t\t\t}),\n\t\t);\n\t}\n\tif (\n\t\tmaterial.publicKey.length !== BLS_PUBLIC_KEY_HEX_LEN ||\n\t\t!HEX_ONLY_RE.test(material.publicKey)\n\t) {\n\t\treturn Effect.fail(\n\t\t\tsealError('config-render', {\n\t\t\t\tname,\n\t\t\t\tmessage:\n\t\t\t\t\t`seal.local-keygen: persisted publicKey in ${LOCAL_KEYGEN_STATE_BASENAME} ` +\n\t\t\t\t\t`is not ${BLS_PUBLIC_KEY_HEX_LEN}-char hex (got ${material.publicKey.length} chars). ` +\n\t\t\t\t\t'The on-disk state is corrupt; reusing it would publish a KeyServer ' +\n\t\t\t\t\t'whose on-chain publicKey diverges from the local master key. ' +\n\t\t\t\t\t'Delete the seal service directory and re-boot to regenerate.',\n\t\t\t}),\n\t\t);\n\t}\n\treturn Effect.void;\n};\n\nconst sealConfigFingerprint = (parts: {\n\treadonly packageId: string;\n\treadonly keyServerObjectId: string;\n\treadonly nodeUrl: string;\n}): string =>\n\t[\n\t\t`package=${parts.packageId}`,\n\t\t`keyServer=${parts.keyServerObjectId}`,\n\t\t`nodeUrl=${parts.nodeUrl}`,\n\t].join('|');\n\nconst resolveMovePackagePath = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n): Effect.Effect<string, SealError, Scope.Scope | FileSystem.FileSystem | Path.Path> =>\n\topts.movePackagePath\n\t\t? Effect.succeed(opts.movePackagePath)\n\t\t: resolveDefaultSealSource(deps.runtime).pipe(Effect.map((s) => s.path));\n\nconst ensureLocalKeygenArtifacts = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n\tpublicKey: string,\n): Effect.Effect<\n\t{\n\t\treadonly packageId: string;\n\t\treadonly keyServerObjectId: string;\n\t},\n\tSealError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> =>\n\tEffect.gen(function* () {\n\t\tconst movePackagePath = yield* resolveMovePackagePath(deps, opts);\n\t\tconst { packageId } = yield* publishSealPackage(deps.publisher, {\n\t\t\tname: opts.name,\n\t\t\tchain: deps.chain,\n\t\t\tmovePackagePath,\n\t\t\tsigner: deps.signer,\n\t\t\tsdk: deps.sdk,\n\t\t\truntime: deps.runtime,\n\t\t\tchainProbe: deps.chainProbe,\n\t\t\t...(deps.buildImage !== undefined ? { buildImage: deps.buildImage } : {}),\n\t\t});\n\t\tconst { objectId: keyServerObjectId } = yield* registerKeyServer(deps.publisher, {\n\t\t\tname: opts.name,\n\t\t\tchain: deps.chain,\n\t\t\tkeyServerUrl: deps.routedUrl,\n\t\t\tsealPackageId: packageId,\n\t\t\tpublicKeyHex: publicKey,\n\t\t\tkeyServerName: opts.keyServerName,\n\t\t\tsigner: deps.signer,\n\t\t\tsdk: deps.sdk,\n\t\t\tchainProbe: deps.chainProbe,\n\t\t});\n\t\treturn { packageId, keyServerObjectId };\n\t});\n\nconst stageResolvedLocalKeygenState = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n\tartifacts: {\n\t\treadonly packageId: string;\n\t\treadonly keyServerObjectId: string;\n\t},\n\tkeypair: Pick<PersistedBlsKeypair, 'masterKey' | 'publicKey'>,\n): Effect.Effect<PersistedLocalKeygenState, SealError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst yaml = renderSealKeyServerConfig({\n\t\t\tsealPackageId: artifacts.packageId,\n\t\t\tnodeUrl: deps.suiRpcUrlInNetwork,\n\t\t\tkeyServerObjectId: artifacts.keyServerObjectId,\n\t\t});\n\t\tconst { masterKeyEnvFile } = yield* stageSealConfig(\n\t\t\tyaml,\n\t\t\tkeypair.masterKey,\n\t\t\tdeps.servicePath,\n\t\t\topts.name,\n\t\t);\n\t\tyield* stagePersistedLocalKeygenMetadata(deps.servicePath, opts.name, {\n\t\t\tversion: LOCAL_KEYGEN_STATE_VERSION,\n\t\t\tpublicKey: keypair.publicKey,\n\t\t});\n\t\treturn {\n\t\t\tpackageId: artifacts.packageId,\n\t\t\tkeyServerObjectId: artifacts.keyServerObjectId,\n\t\t\tmasterKey: keypair.masterKey,\n\t\t\tpublicKey: keypair.publicKey,\n\t\t\tmasterKeyEnvFile,\n\t\t};\n\t});\n\nconst startLocalKeygenContainer = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n\tcargoImage: ImageRef,\n\tstate: PersistedLocalKeygenState,\n): Effect.Effect<SealLocalKeygenResolved, SealError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst spec: KeyServerContainerSpec = buildKeyServerSpec({\n\t\t\tname: opts.name,\n\t\t\timage: cargoImage,\n\t\t\tcontainerName: deps.containerName,\n\t\t\tlabels: deps.labels,\n\t\t\tsuiNetwork: deps.suiNetworkName,\n\t\t\tservicePath: deps.servicePath,\n\t\t\tconfigFingerprint: sealConfigFingerprint({\n\t\t\t\tpackageId: state.packageId,\n\t\t\t\tkeyServerObjectId: state.keyServerObjectId,\n\t\t\t\tnodeUrl: deps.suiRpcUrlInNetwork,\n\t\t\t}),\n\t\t\troutedHostname: deps.routedHostname,\n\t\t\troutedUrl: deps.routedUrl,\n\t\t\treadyTimeoutMs: opts.readyTimeoutMs,\n\t\t});\n\t\tconst { containerName } = yield* startKeyServer(deps.runtime, spec, opts.name);\n\t\tvoid containerName;\n\n\t\tconst serverConfigs: ReadonlyArray<SealKeyServerEntry> = [\n\t\t\t{ objectId: state.keyServerObjectId, weight: 1 },\n\t\t];\n\t\tconst keyManager = makeKeyManager({\n\t\t\tmasterKeyEnvFile: state.masterKeyEnvFile,\n\t\t});\n\t\treturn {\n\t\t\tkeyServer: {\n\t\t\t\tserverConfigs,\n\t\t\t\tkeyServerUrl: deps.routedUrl,\n\t\t\t\tobjectId: state.keyServerObjectId,\n\t\t\t},\n\t\t\tkeyManager,\n\t\t\tpackageId: state.packageId,\n\t\t} satisfies SealLocalKeygenResolved;\n\t});\n\n// ---------------------------------------------------------------------------\n// Boot pipeline\n// ---------------------------------------------------------------------------\n\n/** The plugin's aggregate acquire body. Calls each phase in\n * order; failures surface as typed `SealError` /\n * `ArtifactPublishError` through the Effect's error channel.\n *\n * Distilled-doc invariant #2 — phase order is keygen → publish →\n * register → config-render → container. Any phase failure short-\n * circuits before downstream phases (cheap on warm restart because\n * the ArtifactPublisher cache + verify covers steps 3-4). */\nexport const bootLocalKeygen = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n): Effect.Effect<\n\tSealLocalKeygenResolved,\n\tSealError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> =>\n\tEffect.gen(function* () {\n\t\t// ---- cargo image (bootstrap asset) -----------------------\n\t\t// The cargo image's resolver honors `SEAL_CARGO_IMAGE_OVERRIDE`\n\t\t// for the pre-baked path; falls back to a documented seam error\n\t\t// pointing at the override hatch.\n\t\tconst cargoImage: ImageRef = yield* resolveDefaultSealCargoImage(deps.runtime, {\n\t\t\tapp: deps.labels.app,\n\t\t\tstack: deps.labels.stack,\n\t\t});\n\n\t\tconst persisted = yield* readPersistedLocalKeygenState(deps.servicePath);\n\t\tif (persisted !== null) {\n\t\t\t// Defensive invariant — if the on-disk publicKey or master key\n\t\t\t// has the wrong shape, the ArtifactPublisher cache might\n\t\t\t// happily reuse a stale on-chain KeyServer whose registered\n\t\t\t// publicKey no longer matches the master key the daemon\n\t\t\t// loads at boot. Refuse to proceed so the operator gets a\n\t\t\t// clear typed error instead of a silently-broken stack.\n\t\t\tyield* validatePersistedKeyMaterialShape(persisted, opts.name);\n\t\t\tconst artifacts = yield* ensureLocalKeygenArtifacts(deps, opts, persisted.publicKey);\n\t\t\tconst refreshed = yield* stageResolvedLocalKeygenState(deps, opts, artifacts, persisted);\n\t\t\treturn yield* startLocalKeygenContainer(deps, opts, cargoImage, refreshed);\n\t\t}\n\n\t\t// ---- keygen (BLS12-381 master + public) -----------------\n\t\t// The keypair flows into publish + register inputs. The\n\t\t// artifact publisher still owns the on-chain artifacts; this\n\t\t// local state only persists key material.\n\t\tconst keypair: PersistedBlsKeypair = yield* runSealKeygen(deps.runtime, opts.name, cargoImage);\n\n\t\t// ---- render config + stage master-key -------------------\n\t\t// Distilled-doc invariant #19 — `network: !Devnet` is hardcoded\n\t\t// by `renderSealKeyServerConfig`. Invariant #4 — `master-key.env`\n\t\t// MUST NOT be unlinked on scope close. `stageSealConfig` does\n\t\t// NOT register a finalizer.\n\t\tconst artifacts = yield* ensureLocalKeygenArtifacts(deps, opts, keypair.publicKey);\n\t\tconst state = yield* stageResolvedLocalKeygenState(deps, opts, artifacts, keypair);\n\t\treturn yield* startLocalKeygenContainer(deps, opts, cargoImage, state);\n\t}).pipe(\n\t\tEffect.catchTag('ArtifactPublishError', (err) =>\n\t\t\tEffect.fail(\n\t\t\t\tsealError('seal', {\n\t\t\t\t\tname: opts.name,\n\t\t\t\t\tmessage: `seal.local-keygen: on-chain artifact failure (${err.reason}): ${err.detail}`,\n\t\t\t\t\tcause: err,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t\tEffect.withSpan('devstack.plugin.seal.localKeygen.boot', {\n\t\t\tattributes: {\n\t\t\t\t[SpanAttr.plugin]: 'seal',\n\t\t\t\t[SealSpans.name]: opts.name,\n\t\t\t\t[SealSpans.version]: opts.version,\n\t\t\t},\n\t\t}),\n\t);\n"],"mappings":"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"}
1
+ {"version":3,"file":"local-keygen.mjs","names":[],"sources":["../../../../src/plugins/seal/mode/local-keygen.ts"],"sourcesContent":["// Seal local-keygen mode — the full localnet path.\n//\n// Distilled-doc reference (07-seal.md §\"Lifecycle / Startup —\n// `sealLocalKeygen`\"). Eight ordered phases:\n//\n// 0. Yield deps (Sui, Identity, ContainerRuntime, artifact publisher publisher).\n// 1. Image build (bootstrap asset — parallel with sui's boot).\n// 1a. Move source resolve (bootstrap asset, conditional).\n// 2. BLS keygen one-shot (real `runtime.runOneShot` against cargo\n// image; output parsed via regex).\n// 3. Publish seal Move package (via artifact publisher primitive).\n// 4. Register on-chain KeyServer (via artifact publisher primitive).\n// 5. Render config yaml + stage master-key env-file (atomic\n// FileSystem\n// writes).\n// 6. Start long-running key-server container (real\n// `runtime.ensureContainer`\n// + exec-based ready\n// probe).\n// 7. Project the plugin's aggregate value.\n//\n// Distilled-doc invariants pinned by this file:\n//\n// #1 KeyServer.url == routed hostname — single mint point\n// (`routedUrl` passed\n// identically into\n// `registerKeyServer`\n// and `buildKeyServerSpec`).\n// #2 Boot order keygen → publish → register → config → container.\n// #4 env-file for secret loading (not -e MASTER_KEY=…).\n// #5 No host-port publish.\n// #6 Keypair B8 verify cascade (deploy.ts:buildKeypairVerify).\n// #7 Signal-forwarding entrypoint shell (image-side).\n// #8 Fork incompatibility throw — handled at the barrel\n// (`index.ts`), NOT here.\n// #9 Peer-dep structural assignability (compile-time check\n// lives in registry-publish.ts).\n//\n// This is the substrate-name-LEAK boundary. Inside this file we can\n// say \"seal\"; outside `src/plugins/seal/`, the substrate doesn't\n// know seal exists.\n\nimport { Effect, FileSystem, Path, Schema, type Scope } from 'effect';\n\nimport { decodeJsonText } from '../../../substrate/runtime/runtime-decode.ts';\n\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport type { ContainerLabelTuple } from '../../../contracts/snapshotable.ts';\nimport type { ContainerRuntime, ImageRef } from '../../../contracts/container-runtime.ts';\nimport type {\n\tArtifactPublishError,\n\tArtifactPublisher,\n} from '../../../primitives/artifact-publisher.ts';\nimport type { AccountValue } from '../../account/index.ts';\nimport {\n\tparseMasterKeyEnvFile,\n\trenderSealKeyServerConfig,\n\tstageSealConfig,\n} from '../config-render.ts';\nimport {\n\tpublishSealPackage,\n\tregisterKeyServer,\n\ttype SealObjectProbeKey,\n\ttype SealSuiSdk,\n} from '../deploy.ts';\nimport { sealError, type SealError } from '../errors.ts';\nimport { MASTER_KEY_ENVFILE_BASENAME, runSealKeygen, type PersistedBlsKeypair } from '../keygen.ts';\nimport { makeKeyManager } from '../key-manager.ts';\nimport { buildKeyServerSpec, startKeyServer, type KeyServerContainerSpec } from '../key-server.ts';\nimport type { SealKeyServerEntry, SealLocalKeygenResolved } from '../registry-publish.ts';\nimport { resolveDefaultSealCargoImage } from '../bootstrap-assets/cargo-image.ts';\nimport { resolveDefaultSealSource } from '../bootstrap-assets/source-fetch.ts';\nimport { atomicWriteFile } from '../../../substrate/runtime/atomic-write.ts';\nimport { versionedDocSchema } from '../../../substrate/versioned-doc-schema.ts';\n\n// ---------------------------------------------------------------------------\n// Options (factory-time)\n// ---------------------------------------------------------------------------\n\n/** Options the local-keygen mode accepts (07-seal.md\n * §\"Configuration\"). The\n * barrel (`index.ts`) folds the typed `SealLocalKeygenOptions`\n * surface into this internal shape after default resolution. */\nexport interface LocalKeygenOptions {\n\treadonly name?: string;\n\treadonly version?: string;\n\treadonly movePackagePath?: string;\n\treadonly readyTimeoutMs?: number;\n\treadonly keyServerName?: string;\n}\n\n/** Resolved options after defaults are applied. */\nexport interface ResolvedLocalKeygenOptions {\n\treadonly name: string;\n\treadonly version: string;\n\treadonly readyTimeoutMs: number;\n\treadonly keyServerName: string;\n\treadonly movePackagePath?: string;\n}\n\nconst DEFAULT_READY_TIMEOUT_MS = 60_000;\nconst DEFAULT_KEY_SERVER_NAME = 'devstack-local';\n\n/** Synchronous factory-time defaults application. Pure — no\n * validation throws because the localnet signer requirement is\n * enforced one layer up in the barrel (the type-narrowed\n * `sealFor(local).localKeygen({signer})` makes signer required). */\nexport const resolveLocalKeygenOptions = (\n\topts: LocalKeygenOptions,\n\tdefaultVersion: string,\n): ResolvedLocalKeygenOptions => ({\n\tname: opts.name ?? 'seal',\n\tversion: opts.version ?? defaultVersion,\n\treadyTimeoutMs: opts.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS,\n\tkeyServerName: opts.keyServerName ?? DEFAULT_KEY_SERVER_NAME,\n\tmovePackagePath: opts.movePackagePath,\n});\n\n// ---------------------------------------------------------------------------\n// Inputs to the boot pipeline (acquire-time)\n// ---------------------------------------------------------------------------\n\n/** Acquire-time deps the boot pipeline consumes. Sourced by the\n * barrel (`index.ts`) from a mix of:\n *\n * - substrate-resolved values (`IdentityContext`,\n * `ContainerRuntimeService`, `ArtifactPublisher`);\n * - substrate-derived identifiers (chainId, servicePath,\n * subnet, etc.);\n * - router-resolved URL (single mint — distilled-doc invariant #1).\n *\n * The barrel composes these from substrate services\n * (ContainerRuntime, IdentityContext, ArtifactPublisher,\n * StackPathsService) at acquire-time. */\nexport interface LocalKeygenDeps {\n\treadonly runtime: ContainerRuntime;\n\treadonly publisher: ArtifactPublisher;\n\treadonly signer: AccountValue;\n\treadonly sdk: SealSuiSdk;\n\treadonly buildImage?: ImageRef;\n\treadonly chainProbe: ChainProbe<SealObjectProbeKey>;\n\treadonly chainId: string;\n\t/** Per-stack on-disk dir under `runtime/seal/`. Host path for the\n\t * config yaml + master-key env-file. */\n\treadonly servicePath: string;\n\t/** Container name composed by the substrate (app + stack + name +\n\t * role). */\n\treadonly containerName: string;\n\t/** Label tuple driving snapshot/inspect by labels. */\n\treadonly labels: ContainerLabelTuple;\n\t/** Seal's per-stack docker network — the key-server daemon attaches\n\t * to this network. */\n\treadonly suiNetworkName: string;\n\t/** In-network sui RPC URL — the daemon's CONFIG_PATH yaml carries\n\t * this. */\n\treadonly suiRpcUrlInNetwork: string;\n\t/** Router-resolved single mint (distilled-doc invariant #1). */\n\treadonly routedHostname: string;\n\treadonly routedUrl: string;\n}\n\ninterface PersistedLocalKeygenKeyMaterial {\n\treadonly masterKey: string;\n\treadonly publicKey: string;\n\treadonly masterKeyEnvFile: string;\n}\n\ninterface PersistedLocalKeygenState extends PersistedLocalKeygenKeyMaterial {\n\treadonly packageId: string;\n\treadonly keyServerObjectId: string;\n}\n\nconst LOCAL_KEYGEN_STATE_VERSION = 1;\nconst LOCAL_KEYGEN_STATE_BASENAME = 'local-keygen-state.v1.json';\n\nconst PersistedLocalKeygenMetadataSchema = versionedDocSchema(LOCAL_KEYGEN_STATE_VERSION, {\n\tpublicKey: Schema.String,\n});\n\ntype PersistedLocalKeygenMetadata = Schema.Schema.Type<typeof PersistedLocalKeygenMetadataSchema>;\n\nconst localKeygenMetadataPath = (servicePath: string): string =>\n\t`${servicePath}/${LOCAL_KEYGEN_STATE_BASENAME}`;\n\nconst readPersistedLocalKeygenMetadata = (\n\tservicePath: string,\n): Effect.Effect<PersistedLocalKeygenMetadata | null, never, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst path = localKeygenMetadataPath(servicePath);\n\t\tconst raw = yield* fs.readFileString(path).pipe(Effect.catch(() => Effect.succeed(null)));\n\t\tif (raw === null) return null;\n\t\t// Parse + decode failures here mean \"no usable persisted metadata\"\n\t\t// and the caller treats this as a miss; the typed\n\t\t// `RuntimeDecodeIssue` carries the parse/decode diagnostic for\n\t\t// debugging but is collapsed to `null` so the boot loop falls\n\t\t// through to a fresh keygen.\n\t\treturn yield* decodeJsonText(PersistedLocalKeygenMetadataSchema, raw, {\n\t\t\tsource: path,\n\t\t\tmkError: (issue) => issue,\n\t\t}).pipe(Effect.catch(() => Effect.succeed(null)));\n\t});\n\nconst stagePersistedLocalKeygenMetadata = (\n\tservicePath: string,\n\tname: string,\n\tmetadata: PersistedLocalKeygenMetadata,\n): Effect.Effect<void, SealError, FileSystem.FileSystem> =>\n\tatomicWriteFile(\n\t\tlocalKeygenMetadataPath(servicePath),\n\t\tnew TextEncoder().encode(`${JSON.stringify(metadata, null, 2)}\\n`),\n\t\t{\n\t\t\tmode: 0o644,\n\t\t\tparentMode: 0o700,\n\t\t},\n\t).pipe(\n\t\tEffect.catch((cause) =>\n\t\t\tEffect.fail(\n\t\t\t\tsealError('config-render', {\n\t\t\t\t\tname,\n\t\t\t\t\tmessage: `seal.config-render: failed to write ${LOCAL_KEYGEN_STATE_BASENAME} (${cause.stage})`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n\nconst readPersistedLocalKeygenState = (\n\tservicePath: string,\n): Effect.Effect<PersistedLocalKeygenKeyMaterial | null, never, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst masterKeyEnvFile = `${servicePath}/${MASTER_KEY_ENVFILE_BASENAME}`;\n\t\tconst masterKeyBody = yield* fs\n\t\t\t.readFileString(masterKeyEnvFile)\n\t\t\t.pipe(Effect.catch(() => Effect.succeed(null)));\n\t\tif (masterKeyBody === null) return null;\n\t\tconst masterKey = parseMasterKeyEnvFile(masterKeyBody);\n\t\tif (masterKey === null) return null;\n\t\tconst metadata = yield* readPersistedLocalKeygenMetadata(servicePath);\n\t\tif (metadata === null) return null;\n\n\t\treturn {\n\t\t\tmasterKey,\n\t\t\tpublicKey: metadata.publicKey,\n\t\t\tmasterKeyEnvFile,\n\t\t};\n\t});\n\n/** BLS12-381 master key — 32 bytes, persisted as 64 hex chars. */\nconst BLS_MASTER_KEY_HEX_LEN = 64;\n/** BLS12-381 G2 uncompressed public key — 96 bytes, persisted as 192 hex chars. */\nconst BLS_PUBLIC_KEY_HEX_LEN = 192;\nconst HEX_ONLY_RE = /^[0-9a-fA-F]+$/;\n\n/** Stricter decode than the JSON-shape Schema alone — verifies the\n * persisted master key + public key are well-formed BLS12-381 hex of\n * the expected widths. The Schema validation alone accepts any\n * string, so a corrupt-on-disk JSON whose `publicKey` was overwritten\n * to a shorter / wrong-width value would otherwise be silently\n * reused on boot — leading to a master-key / KeyServer mismatch\n * (the master-key.env carries one key, the registered KeyServer's\n * on-chain `publicKey` carries a different one). Distilled-doc\n * invariant #6 (keypair B8 verify cascade) covers the on-chain\n * side; this is the on-disk side.\n *\n * We cannot in-process re-derive the G2 public key from the master\n * scalar without bundling a BLS12-381 implementation (the keygen\n * binary owns this in cargo-land). The width invariant is the\n * cheapest defense that catches the realistic corruption modes:\n * truncated writes, hand-edited JSON, stale persistence from an\n * older devstack version. */\nconst validatePersistedKeyMaterialShape = (\n\tmaterial: PersistedLocalKeygenKeyMaterial,\n\tname: string,\n): Effect.Effect<void, SealError> => {\n\tif (\n\t\tmaterial.masterKey.length !== BLS_MASTER_KEY_HEX_LEN ||\n\t\t!HEX_ONLY_RE.test(material.masterKey)\n\t) {\n\t\treturn Effect.fail(\n\t\t\tsealError('config-render', {\n\t\t\t\tname,\n\t\t\t\tmessage:\n\t\t\t\t\t`seal.local-keygen: persisted master key in ${MASTER_KEY_ENVFILE_BASENAME} ` +\n\t\t\t\t\t`is not ${BLS_MASTER_KEY_HEX_LEN}-char hex (got ${material.masterKey.length} chars). ` +\n\t\t\t\t\t'The on-disk state is corrupt; delete the seal service directory and ' +\n\t\t\t\t\t're-boot to regenerate, or restore from a known-good snapshot.',\n\t\t\t}),\n\t\t);\n\t}\n\tif (\n\t\tmaterial.publicKey.length !== BLS_PUBLIC_KEY_HEX_LEN ||\n\t\t!HEX_ONLY_RE.test(material.publicKey)\n\t) {\n\t\treturn Effect.fail(\n\t\t\tsealError('config-render', {\n\t\t\t\tname,\n\t\t\t\tmessage:\n\t\t\t\t\t`seal.local-keygen: persisted publicKey in ${LOCAL_KEYGEN_STATE_BASENAME} ` +\n\t\t\t\t\t`is not ${BLS_PUBLIC_KEY_HEX_LEN}-char hex (got ${material.publicKey.length} chars). ` +\n\t\t\t\t\t'The on-disk state is corrupt; reusing it would publish a KeyServer ' +\n\t\t\t\t\t'whose on-chain publicKey diverges from the local master key. ' +\n\t\t\t\t\t'Delete the seal service directory and re-boot to regenerate.',\n\t\t\t}),\n\t\t);\n\t}\n\treturn Effect.void;\n};\n\nconst sealConfigFingerprint = (parts: {\n\treadonly packageId: string;\n\treadonly keyServerObjectId: string;\n\treadonly nodeUrl: string;\n}): string =>\n\t[\n\t\t`package=${parts.packageId}`,\n\t\t`keyServer=${parts.keyServerObjectId}`,\n\t\t`nodeUrl=${parts.nodeUrl}`,\n\t].join('|');\n\nconst resolveMovePackagePath = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n): Effect.Effect<string, SealError, Scope.Scope | FileSystem.FileSystem | Path.Path> =>\n\topts.movePackagePath\n\t\t? Effect.succeed(opts.movePackagePath)\n\t\t: resolveDefaultSealSource(deps.runtime).pipe(Effect.map((s) => s.path));\n\nconst ensureLocalKeygenArtifacts = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n\tpublicKey: string,\n): Effect.Effect<\n\t{\n\t\treadonly packageId: string;\n\t\treadonly keyServerObjectId: string;\n\t},\n\tSealError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> =>\n\tEffect.gen(function* () {\n\t\tconst movePackagePath = yield* resolveMovePackagePath(deps, opts);\n\t\tconst { packageId } = yield* publishSealPackage(deps.publisher, {\n\t\t\tname: opts.name,\n\t\t\tchainId: deps.chainId,\n\t\t\tmovePackagePath,\n\t\t\tsigner: deps.signer,\n\t\t\tsdk: deps.sdk,\n\t\t\truntime: deps.runtime,\n\t\t\tchainProbe: deps.chainProbe,\n\t\t\t...(deps.buildImage !== undefined ? { buildImage: deps.buildImage } : {}),\n\t\t});\n\t\tconst { objectId: keyServerObjectId } = yield* registerKeyServer(deps.publisher, {\n\t\t\tname: opts.name,\n\t\t\tchainId: deps.chainId,\n\t\t\tkeyServerUrl: deps.routedUrl,\n\t\t\tsealPackageId: packageId,\n\t\t\tpublicKeyHex: publicKey,\n\t\t\tkeyServerName: opts.keyServerName,\n\t\t\tsigner: deps.signer,\n\t\t\tsdk: deps.sdk,\n\t\t\tchainProbe: deps.chainProbe,\n\t\t});\n\t\treturn { packageId, keyServerObjectId };\n\t});\n\nconst stageResolvedLocalKeygenState = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n\tartifacts: {\n\t\treadonly packageId: string;\n\t\treadonly keyServerObjectId: string;\n\t},\n\tkeypair: Pick<PersistedBlsKeypair, 'masterKey' | 'publicKey'>,\n): Effect.Effect<PersistedLocalKeygenState, SealError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\tconst yaml = renderSealKeyServerConfig({\n\t\t\tsealPackageId: artifacts.packageId,\n\t\t\tnodeUrl: deps.suiRpcUrlInNetwork,\n\t\t\tkeyServerObjectId: artifacts.keyServerObjectId,\n\t\t});\n\t\tconst { masterKeyEnvFile } = yield* stageSealConfig(\n\t\t\tyaml,\n\t\t\tkeypair.masterKey,\n\t\t\tdeps.servicePath,\n\t\t\topts.name,\n\t\t);\n\t\tyield* stagePersistedLocalKeygenMetadata(deps.servicePath, opts.name, {\n\t\t\tversion: LOCAL_KEYGEN_STATE_VERSION,\n\t\t\tpublicKey: keypair.publicKey,\n\t\t});\n\t\treturn {\n\t\t\tpackageId: artifacts.packageId,\n\t\t\tkeyServerObjectId: artifacts.keyServerObjectId,\n\t\t\tmasterKey: keypair.masterKey,\n\t\t\tpublicKey: keypair.publicKey,\n\t\t\tmasterKeyEnvFile,\n\t\t};\n\t});\n\nconst startLocalKeygenContainer = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n\tcargoImage: ImageRef,\n\tstate: PersistedLocalKeygenState,\n): Effect.Effect<SealLocalKeygenResolved, SealError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tconst spec: KeyServerContainerSpec = buildKeyServerSpec({\n\t\t\tname: opts.name,\n\t\t\timage: cargoImage,\n\t\t\tcontainerName: deps.containerName,\n\t\t\tlabels: deps.labels,\n\t\t\tsuiNetwork: deps.suiNetworkName,\n\t\t\tservicePath: deps.servicePath,\n\t\t\tconfigFingerprint: sealConfigFingerprint({\n\t\t\t\tpackageId: state.packageId,\n\t\t\t\tkeyServerObjectId: state.keyServerObjectId,\n\t\t\t\tnodeUrl: deps.suiRpcUrlInNetwork,\n\t\t\t}),\n\t\t\troutedHostname: deps.routedHostname,\n\t\t\troutedUrl: deps.routedUrl,\n\t\t\treadyTimeoutMs: opts.readyTimeoutMs,\n\t\t});\n\t\tconst { containerName } = yield* startKeyServer(deps.runtime, spec, opts.name);\n\t\tvoid containerName;\n\n\t\tconst serverConfigs: ReadonlyArray<SealKeyServerEntry> = [\n\t\t\t{ objectId: state.keyServerObjectId, weight: 1 },\n\t\t];\n\t\tconst keyManager = makeKeyManager({\n\t\t\tmasterKeyEnvFile: state.masterKeyEnvFile,\n\t\t});\n\t\treturn {\n\t\t\tkeyServer: {\n\t\t\t\tserverConfigs,\n\t\t\t\tkeyServerUrl: deps.routedUrl,\n\t\t\t\tobjectId: state.keyServerObjectId,\n\t\t\t},\n\t\t\tkeyManager,\n\t\t\tpackageId: state.packageId,\n\t\t} satisfies SealLocalKeygenResolved;\n\t});\n\n// ---------------------------------------------------------------------------\n// Boot pipeline\n// ---------------------------------------------------------------------------\n\n/** The plugin's aggregate acquire body. Calls each phase in\n * order; failures surface as typed `SealError` /\n * `ArtifactPublishError` through the Effect's error channel.\n *\n * Distilled-doc invariant #2 — phase order is keygen → publish →\n * register → config-render → container. Any phase failure short-\n * circuits before downstream phases (cheap on warm restart because\n * the ArtifactPublisher cache + verify covers steps 3-4). */\nexport const bootLocalKeygen = (\n\tdeps: LocalKeygenDeps,\n\topts: ResolvedLocalKeygenOptions,\n): Effect.Effect<\n\tSealLocalKeygenResolved,\n\tSealError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> =>\n\tEffect.gen(function* () {\n\t\t// ---- cargo image (bootstrap asset) -----------------------\n\t\t// The cargo image's resolver honors `SEAL_CARGO_IMAGE_OVERRIDE`\n\t\t// for the pre-baked path; falls back to a documented seam error\n\t\t// pointing at the override hatch.\n\t\tconst cargoImage: ImageRef = yield* resolveDefaultSealCargoImage(deps.runtime, {\n\t\t\tapp: deps.labels.app,\n\t\t\tstack: deps.labels.stack,\n\t\t});\n\n\t\tconst persisted = yield* readPersistedLocalKeygenState(deps.servicePath);\n\t\tif (persisted !== null) {\n\t\t\t// Defensive invariant — if the on-disk publicKey or master key\n\t\t\t// has the wrong shape, the ArtifactPublisher cache might\n\t\t\t// happily reuse a stale on-chain KeyServer whose registered\n\t\t\t// publicKey no longer matches the master key the daemon\n\t\t\t// loads at boot. Refuse to proceed so the operator gets a\n\t\t\t// clear typed error instead of a silently-broken stack.\n\t\t\tyield* validatePersistedKeyMaterialShape(persisted, opts.name);\n\t\t\tconst artifacts = yield* ensureLocalKeygenArtifacts(deps, opts, persisted.publicKey);\n\t\t\tconst refreshed = yield* stageResolvedLocalKeygenState(deps, opts, artifacts, persisted);\n\t\t\treturn yield* startLocalKeygenContainer(deps, opts, cargoImage, refreshed);\n\t\t}\n\n\t\t// ---- keygen (BLS12-381 master + public) -----------------\n\t\t// The keypair flows into publish + register inputs. The\n\t\t// artifact publisher still owns the on-chain artifacts; this\n\t\t// local state only persists key material.\n\t\tconst keypair: PersistedBlsKeypair = yield* runSealKeygen(deps.runtime, opts.name, cargoImage);\n\n\t\t// ---- render config + stage master-key -------------------\n\t\t// Distilled-doc invariant #19 — `network: !Devnet` is hardcoded\n\t\t// by `renderSealKeyServerConfig`. Invariant #4 — `master-key.env`\n\t\t// MUST NOT be unlinked on scope close. `stageSealConfig` does\n\t\t// NOT register a finalizer.\n\t\tconst artifacts = yield* ensureLocalKeygenArtifacts(deps, opts, keypair.publicKey);\n\t\tconst state = yield* stageResolvedLocalKeygenState(deps, opts, artifacts, keypair);\n\t\treturn yield* startLocalKeygenContainer(deps, opts, cargoImage, state);\n\t}).pipe(\n\t\tEffect.catchTag('ArtifactPublishError', (err) =>\n\t\t\tEffect.fail(\n\t\t\t\tsealError('seal', {\n\t\t\t\t\tname: opts.name,\n\t\t\t\t\tmessage: `seal.local-keygen: on-chain artifact failure (${err.reason}): ${err.detail}`,\n\t\t\t\t\tcause: err,\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t);\n"],"mappings":"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"}