@mysten-incubation/devstack 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (858) hide show
  1. package/README.md +6 -3
  2. package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
  3. package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
  4. package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
  5. package/dashboard-ui/index.html +2 -2
  6. package/dist/api/define-capabilities.d.mts +1 -20
  7. package/dist/api/define-capabilities.mjs +15 -22
  8. package/dist/api/define-capabilities.mjs.map +1 -1
  9. package/dist/api/define-devstack-with.d.mts +7 -1
  10. package/dist/api/define-devstack-with.mjs.map +1 -1
  11. package/dist/api/define-devstack.mjs.map +1 -1
  12. package/dist/api/define-plugin.d.mts +2 -1
  13. package/dist/api/inference-network.d.mts +31 -17
  14. package/dist/api/inference-network.mjs +40 -43
  15. package/dist/api/inference-network.mjs.map +1 -1
  16. package/dist/api/load-config.mjs +88 -0
  17. package/dist/api/load-config.mjs.map +1 -0
  18. package/dist/api/mode-narrowed-factory.d.mts +1 -1
  19. package/dist/api/mode-narrowed-factory.mjs.map +1 -1
  20. package/dist/api/run-stack-internal.mjs +202 -0
  21. package/dist/api/run-stack-internal.mjs.map +1 -0
  22. package/dist/api/run-stack.d.mts +82 -31
  23. package/dist/api/run-stack.mjs +22 -141
  24. package/dist/api/run-stack.mjs.map +1 -1
  25. package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
  26. package/dist/build-integrations/dapp-kit/index.mjs +58 -0
  27. package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
  28. package/dist/build-integrations/playwright/config.d.mts +1 -30
  29. package/dist/build-integrations/playwright/config.mjs +1 -27
  30. package/dist/build-integrations/playwright/config.mjs.map +1 -1
  31. package/dist/build-integrations/playwright/errors.d.mts +4 -7
  32. package/dist/build-integrations/playwright/errors.mjs.map +1 -1
  33. package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
  34. package/dist/build-integrations/playwright/global-setup.mjs +142 -218
  35. package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
  36. package/dist/build-integrations/playwright/index.d.mts +2 -2
  37. package/dist/build-integrations/playwright/index.mjs +2 -2
  38. package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
  39. package/dist/build-integrations/playwright/stack-context.mjs +4 -2
  40. package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
  41. package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
  42. package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
  43. package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
  44. package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
  45. package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
  46. package/dist/build-integrations/runtime/discover.d.mts +6 -4
  47. package/dist/build-integrations/runtime/discover.mjs +15 -4
  48. package/dist/build-integrations/runtime/discover.mjs.map +1 -1
  49. package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
  50. package/dist/build-integrations/runtime/errors.mjs.map +1 -1
  51. package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
  52. package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
  53. package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
  54. package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
  55. package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
  56. package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
  57. package/dist/build-integrations/vite/index.d.mts +84 -19
  58. package/dist/build-integrations/vite/index.mjs +203 -28
  59. package/dist/build-integrations/vite/index.mjs.map +1 -1
  60. package/dist/build-integrations/vitest/config.d.mts +20 -2
  61. package/dist/build-integrations/vitest/config.mjs +16 -4
  62. package/dist/build-integrations/vitest/config.mjs.map +1 -1
  63. package/dist/build-integrations/vitest/env.d.mts +18 -10
  64. package/dist/build-integrations/vitest/env.mjs +11 -10
  65. package/dist/build-integrations/vitest/env.mjs.map +1 -1
  66. package/dist/build-integrations/vitest/errors.d.mts +7 -11
  67. package/dist/build-integrations/vitest/errors.mjs +3 -4
  68. package/dist/build-integrations/vitest/errors.mjs.map +1 -1
  69. package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
  70. package/dist/build-integrations/vitest/global-setup.mjs +156 -0
  71. package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
  72. package/dist/build-integrations/vitest/index.d.mts +3 -2
  73. package/dist/build-integrations/vitest/index.mjs +3 -2
  74. package/dist/build-integrations/vitest/setup.mjs +2 -2
  75. package/dist/build-integrations/vitest/setup.mjs.map +1 -1
  76. package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
  77. package/dist/build-integrations/vitest/stack-context.mjs +3 -2
  78. package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
  79. package/dist/cli/bail.mjs.map +1 -1
  80. package/dist/cli/doctor-probes.mjs +1 -3
  81. package/dist/cli/doctor-probes.mjs.map +1 -1
  82. package/dist/cli/main.d.mts +23 -1
  83. package/dist/cli/main.mjs +63 -8
  84. package/dist/cli/main.mjs.map +1 -1
  85. package/dist/cli/prune-direct.mjs.map +1 -1
  86. package/dist/cli/snapshot-reader.mjs.map +1 -1
  87. package/dist/cli/up-lifecycle.mjs.map +1 -1
  88. package/dist/cli/wirings/apply.mjs +28 -21
  89. package/dist/cli/wirings/apply.mjs.map +1 -1
  90. package/dist/cli/wirings/codegen.mjs +108 -0
  91. package/dist/cli/wirings/codegen.mjs.map +1 -0
  92. package/dist/cli/wirings/config-loader.mjs +12 -62
  93. package/dist/cli/wirings/config-loader.mjs.map +1 -1
  94. package/dist/cli/wirings/dump-ids.mjs +86 -0
  95. package/dist/cli/wirings/dump-ids.mjs.map +1 -0
  96. package/dist/cli/wirings/engine-command.mjs +1 -1
  97. package/dist/cli/wirings/engine-command.mjs.map +1 -1
  98. package/dist/cli/wirings/identity.mjs +2 -2
  99. package/dist/cli/wirings/identity.mjs.map +1 -1
  100. package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
  101. package/dist/cli/wirings/read-devstack-version.mjs +17 -0
  102. package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
  103. package/dist/cli/wirings/snapshot.mjs +27 -34
  104. package/dist/cli/wirings/snapshot.mjs.map +1 -1
  105. package/dist/cli/wirings/up-ipc.mjs +147 -0
  106. package/dist/cli/wirings/up-ipc.mjs.map +1 -0
  107. package/dist/cli/wirings/up.mjs +218 -198
  108. package/dist/cli/wirings/up.mjs.map +1 -1
  109. package/dist/cli/wirings/wipe.mjs +1 -1
  110. package/dist/cli/wirings/wipe.mjs.map +1 -1
  111. package/dist/contracts/chain-probe.d.mts +1 -1
  112. package/dist/contracts/chain-probe.mjs +1 -1
  113. package/dist/contracts/chain-probe.mjs.map +1 -1
  114. package/dist/contracts/codegenable.d.mts +60 -6
  115. package/dist/contracts/codegenable.mjs +28 -0
  116. package/dist/contracts/codegenable.mjs.map +1 -0
  117. package/dist/contracts/config-bindings.mjs +162 -0
  118. package/dist/contracts/config-bindings.mjs.map +1 -0
  119. package/dist/contracts/container-runtime.d.mts +23 -17
  120. package/dist/contracts/plugin-expander.mjs.map +1 -1
  121. package/dist/contracts/snapshotable.d.mts +5 -7
  122. package/dist/contracts/wallet-protocol.d.mts +2 -5
  123. package/dist/contracts/wallet-protocol.mjs +2 -5
  124. package/dist/contracts/wallet-protocol.mjs.map +1 -1
  125. package/dist/index.d.mts +21 -26
  126. package/dist/index.mjs +8 -9
  127. package/dist/orchestrators/boot.d.mts +28 -0
  128. package/dist/orchestrators/boot.mjs +440 -0
  129. package/dist/orchestrators/boot.mjs.map +1 -0
  130. package/dist/orchestrators/codegen/bindings.d.mts +13 -1
  131. package/dist/orchestrators/codegen/bindings.mjs +23 -9
  132. package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
  133. package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
  134. package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
  135. package/dist/orchestrators/codegen/emit.mjs +1 -1
  136. package/dist/orchestrators/codegen/emit.mjs.map +1 -1
  137. package/dist/orchestrators/codegen/errors.mjs +21 -1
  138. package/dist/orchestrators/codegen/errors.mjs.map +1 -1
  139. package/dist/orchestrators/codegen/format.mjs +2 -0
  140. package/dist/orchestrators/codegen/format.mjs.map +1 -1
  141. package/dist/orchestrators/codegen/gitignore.mjs +30 -11
  142. package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
  143. package/dist/orchestrators/codegen/id-config.mjs +107 -0
  144. package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
  145. package/dist/orchestrators/codegen/output-location.mjs +23 -32
  146. package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
  147. package/dist/orchestrators/codegen/paths.mjs +8 -1
  148. package/dist/orchestrators/codegen/paths.mjs.map +1 -1
  149. package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
  150. package/dist/orchestrators/codegen/service.mjs +286 -58
  151. package/dist/orchestrators/codegen/service.mjs.map +1 -1
  152. package/dist/orchestrators/layers.mjs +31 -0
  153. package/dist/orchestrators/layers.mjs.map +1 -0
  154. package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
  155. package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
  156. package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
  157. package/dist/orchestrators/network-options.d.mts +52 -0
  158. package/dist/orchestrators/network-options.mjs +43 -0
  159. package/dist/orchestrators/network-options.mjs.map +1 -0
  160. package/dist/orchestrators/router/cleanup.mjs.map +1 -1
  161. package/dist/orchestrators/router/cors.mjs.map +1 -1
  162. package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
  163. package/dist/orchestrators/router/errors.mjs.map +1 -1
  164. package/dist/orchestrators/router/file-provider.mjs.map +1 -1
  165. package/dist/orchestrators/router/hostname.mjs.map +1 -1
  166. package/dist/orchestrators/router/profile.mjs +1 -1
  167. package/dist/orchestrators/router/profile.mjs.map +1 -1
  168. package/dist/orchestrators/router/service.d.mts +2 -2
  169. package/dist/orchestrators/router/service.mjs +12 -27
  170. package/dist/orchestrators/router/service.mjs.map +1 -1
  171. package/dist/orchestrators/router/traefik-container.mjs +1 -1
  172. package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
  173. package/dist/orchestrators/snapshot/capture.mjs +171 -195
  174. package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
  175. package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
  176. package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
  177. package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
  178. package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
  179. package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
  180. package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
  181. package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
  182. package/dist/orchestrators/snapshot/index.mjs +1 -4
  183. package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
  184. package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
  185. package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
  186. package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
  187. package/dist/orchestrators/snapshot/prune.mjs +40 -31
  188. package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
  189. package/dist/orchestrators/snapshot/restore.mjs +221 -196
  190. package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
  191. package/dist/orchestrators/snapshot/service.mjs +72 -62
  192. package/dist/orchestrators/snapshot/service.mjs.map +1 -1
  193. package/dist/orchestrators/snapshot/wipe.mjs +67 -56
  194. package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
  195. package/dist/plugins/account/codegen.mjs +3 -0
  196. package/dist/plugins/account/codegen.mjs.map +1 -1
  197. package/dist/plugins/account/errors.d.mts +2 -2
  198. package/dist/plugins/account/errors.mjs +1 -4
  199. package/dist/plugins/account/errors.mjs.map +1 -1
  200. package/dist/plugins/account/funding.mjs +3 -27
  201. package/dist/plugins/account/funding.mjs.map +1 -1
  202. package/dist/plugins/account/index.d.mts +3 -8
  203. package/dist/plugins/account/index.mjs +71 -35
  204. package/dist/plugins/account/index.mjs.map +1 -1
  205. package/dist/plugins/account/keypair.d.mts +8 -7
  206. package/dist/plugins/account/keypair.mjs +5 -18
  207. package/dist/plugins/account/keypair.mjs.map +1 -1
  208. package/dist/plugins/account/lease.mjs.map +1 -1
  209. package/dist/plugins/account/registry.d.mts +1 -46
  210. package/dist/plugins/account/registry.mjs.map +1 -1
  211. package/dist/plugins/account/service.d.mts +43 -34
  212. package/dist/plugins/account/service.mjs +9 -54
  213. package/dist/plugins/account/service.mjs.map +1 -1
  214. package/dist/plugins/account/snapshot.mjs.map +1 -1
  215. package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
  216. package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
  217. package/dist/plugins/account/variants/signer.mjs.map +1 -1
  218. package/dist/plugins/action/discriminator.mjs.map +1 -1
  219. package/dist/plugins/action/errors.mjs +1 -4
  220. package/dist/plugins/action/errors.mjs.map +1 -1
  221. package/dist/plugins/action/execute.mjs +3 -4
  222. package/dist/plugins/action/execute.mjs.map +1 -1
  223. package/dist/plugins/action/index.d.mts +2 -2
  224. package/dist/plugins/action/index.mjs +7 -11
  225. package/dist/plugins/action/index.mjs.map +1 -1
  226. package/dist/plugins/action/service.d.mts +5 -7
  227. package/dist/plugins/action/service.mjs +2 -16
  228. package/dist/plugins/action/service.mjs.map +1 -1
  229. package/dist/plugins/coin/address-resolution.mjs.map +1 -1
  230. package/dist/plugins/coin/codegen.mjs +97 -16
  231. package/dist/plugins/coin/codegen.mjs.map +1 -1
  232. package/dist/plugins/coin/discovery.mjs.map +1 -1
  233. package/dist/plugins/coin/errors.mjs +1 -4
  234. package/dist/plugins/coin/errors.mjs.map +1 -1
  235. package/dist/plugins/coin/index.d.mts +4 -34
  236. package/dist/plugins/coin/index.mjs +47 -28
  237. package/dist/plugins/coin/index.mjs.map +1 -1
  238. package/dist/plugins/coin/metadata.d.mts +1 -0
  239. package/dist/plugins/coin/metadata.mjs +8 -9
  240. package/dist/plugins/coin/metadata.mjs.map +1 -1
  241. package/dist/plugins/coin/mint.mjs +7 -21
  242. package/dist/plugins/coin/mint.mjs.map +1 -1
  243. package/dist/plugins/coin/registry.mjs +33 -20
  244. package/dist/plugins/coin/registry.mjs.map +1 -1
  245. package/dist/plugins/coin/service.d.mts +1 -1
  246. package/dist/plugins/coin/service.mjs +1 -8
  247. package/dist/plugins/coin/service.mjs.map +1 -1
  248. package/dist/plugins/coin/snapshot.mjs.map +1 -1
  249. package/dist/plugins/coin/type-strings.mjs.map +1 -1
  250. package/dist/plugins/dashboard/domain.mjs +106 -167
  251. package/dist/plugins/dashboard/domain.mjs.map +1 -1
  252. package/dist/plugins/dashboard/index.mjs +13 -13
  253. package/dist/plugins/dashboard/index.mjs.map +1 -1
  254. package/dist/plugins/dashboard/origin-policy.mjs +3 -3
  255. package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
  256. package/dist/plugins/dashboard/routable.mjs.map +1 -1
  257. package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
  258. package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
  259. package/dist/plugins/dashboard/schema/root.mjs +23 -44
  260. package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
  261. package/dist/plugins/dashboard/schema/types.mjs +37 -91
  262. package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
  263. package/dist/plugins/dashboard/schema.mjs.map +1 -1
  264. package/dist/plugins/dashboard/server.mjs.map +1 -1
  265. package/dist/plugins/deepbook/codegen.d.mts +12 -11
  266. package/dist/plugins/deepbook/codegen.mjs +108 -11
  267. package/dist/plugins/deepbook/codegen.mjs.map +1 -1
  268. package/dist/plugins/deepbook/deploy.mjs +7 -14
  269. package/dist/plugins/deepbook/deploy.mjs.map +1 -1
  270. package/dist/plugins/deepbook/errors.mjs +4 -2
  271. package/dist/plugins/deepbook/errors.mjs.map +1 -1
  272. package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
  273. package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
  274. package/dist/plugins/deepbook/hash.mjs.map +1 -1
  275. package/dist/plugins/deepbook/index.d.mts +38 -34
  276. package/dist/plugins/deepbook/index.mjs +133 -64
  277. package/dist/plugins/deepbook/index.mjs.map +1 -1
  278. package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
  279. package/dist/plugins/deepbook/pyth/index.mjs +4 -8
  280. package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
  281. package/dist/plugins/deepbook/snapshot.mjs +0 -1
  282. package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
  283. package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
  284. package/dist/plugins/deepbook/types.d.mts +2 -1
  285. package/dist/plugins/deepbook/types.mjs.map +1 -1
  286. package/dist/plugins/faucet/dispatcher.d.mts +3 -3
  287. package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
  288. package/dist/plugins/faucet/errors.mjs.map +1 -1
  289. package/dist/plugins/faucet/http.mjs +2 -10
  290. package/dist/plugins/faucet/http.mjs.map +1 -1
  291. package/dist/plugins/faucet/index.mjs +0 -1
  292. package/dist/plugins/faucet/index.mjs.map +1 -1
  293. package/dist/plugins/host-service/errors.d.mts +1 -3
  294. package/dist/plugins/host-service/errors.mjs +1 -2
  295. package/dist/plugins/host-service/errors.mjs.map +1 -1
  296. package/dist/plugins/host-service/index.d.mts +1 -2
  297. package/dist/plugins/host-service/index.mjs +11 -11
  298. package/dist/plugins/host-service/index.mjs.map +1 -1
  299. package/dist/plugins/host-service/routable.mjs.map +1 -1
  300. package/dist/plugins/host-service/service.mjs +13 -13
  301. package/dist/plugins/host-service/service.mjs.map +1 -1
  302. package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
  303. package/dist/plugins/internal/codegen-helpers.mjs +2 -0
  304. package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
  305. package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
  306. package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
  307. package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
  308. package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
  309. package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
  310. package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
  311. package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
  312. package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
  313. package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
  314. package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
  315. package/dist/plugins/package/build.mjs +2 -2
  316. package/dist/plugins/package/build.mjs.map +1 -1
  317. package/dist/plugins/package/codegen.d.mts +7 -14
  318. package/dist/plugins/package/codegen.mjs +187 -59
  319. package/dist/plugins/package/codegen.mjs.map +1 -1
  320. package/dist/plugins/package/dep-resolution.mjs +51 -3
  321. package/dist/plugins/package/dep-resolution.mjs.map +1 -1
  322. package/dist/plugins/package/errors.mjs +1 -4
  323. package/dist/plugins/package/errors.mjs.map +1 -1
  324. package/dist/plugins/package/git-source.d.mts +18 -0
  325. package/dist/plugins/package/git-source.mjs +119 -0
  326. package/dist/plugins/package/git-source.mjs.map +1 -0
  327. package/dist/plugins/package/index.d.mts +28 -19
  328. package/dist/plugins/package/index.mjs +107 -32
  329. package/dist/plugins/package/index.mjs.map +1 -1
  330. package/dist/plugins/package/mode-known.mjs +2 -2
  331. package/dist/plugins/package/mode-known.mjs.map +1 -1
  332. package/dist/plugins/package/mode-local.mjs +18 -35
  333. package/dist/plugins/package/mode-local.mjs.map +1 -1
  334. package/dist/plugins/package/publish-executor.mjs +13 -8
  335. package/dist/plugins/package/publish-executor.mjs.map +1 -1
  336. package/dist/plugins/package/publish-output.d.mts +1 -11
  337. package/dist/plugins/package/publish-output.mjs +1 -9
  338. package/dist/plugins/package/publish-output.mjs.map +1 -1
  339. package/dist/plugins/package/registry.d.mts +1 -1
  340. package/dist/plugins/package/registry.mjs +26 -14
  341. package/dist/plugins/package/registry.mjs.map +1 -1
  342. package/dist/plugins/package/service.mjs.map +1 -1
  343. package/dist/plugins/package/snapshot.mjs.map +1 -1
  344. package/dist/plugins/router-entrypoints.mjs +1 -3
  345. package/dist/plugins/router-entrypoints.mjs.map +1 -1
  346. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
  347. package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
  348. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
  349. package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
  350. package/dist/plugins/seal/codegen.d.mts +1 -5
  351. package/dist/plugins/seal/codegen.mjs +83 -12
  352. package/dist/plugins/seal/codegen.mjs.map +1 -1
  353. package/dist/plugins/seal/config-render.mjs +2 -6
  354. package/dist/plugins/seal/config-render.mjs.map +1 -1
  355. package/dist/plugins/seal/deploy.mjs +18 -29
  356. package/dist/plugins/seal/deploy.mjs.map +1 -1
  357. package/dist/plugins/seal/errors.d.mts +4 -5
  358. package/dist/plugins/seal/errors.mjs +1 -8
  359. package/dist/plugins/seal/errors.mjs.map +1 -1
  360. package/dist/plugins/seal/index.d.mts +7 -28
  361. package/dist/plugins/seal/index.mjs +69 -47
  362. package/dist/plugins/seal/index.mjs.map +1 -1
  363. package/dist/plugins/seal/key-manager.mjs.map +1 -1
  364. package/dist/plugins/seal/key-server.mjs +1 -6
  365. package/dist/plugins/seal/key-server.mjs.map +1 -1
  366. package/dist/plugins/seal/keygen.mjs +2 -3
  367. package/dist/plugins/seal/keygen.mjs.map +1 -1
  368. package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
  369. package/dist/plugins/seal/mode/live.mjs +1 -1
  370. package/dist/plugins/seal/mode/live.mjs.map +1 -1
  371. package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
  372. package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
  373. package/dist/plugins/seal/plugin-key.mjs.map +1 -1
  374. package/dist/plugins/seal/registry-publish.mjs.map +1 -1
  375. package/dist/plugins/seal/routable.mjs.map +1 -1
  376. package/dist/plugins/seal/service.mjs.map +1 -1
  377. package/dist/plugins/seal/snapshot.mjs +1 -2
  378. package/dist/plugins/seal/snapshot.mjs.map +1 -1
  379. package/dist/plugins/sui/auto-tick.mjs +5 -5
  380. package/dist/plugins/sui/auto-tick.mjs.map +1 -1
  381. package/dist/plugins/sui/chain-build-container.mjs +2 -2
  382. package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
  383. package/dist/plugins/sui/chain-probe.mjs +4 -4
  384. package/dist/plugins/sui/chain-probe.mjs.map +1 -1
  385. package/dist/plugins/sui/codegen.d.mts +9 -7
  386. package/dist/plugins/sui/codegen.mjs +49 -46
  387. package/dist/plugins/sui/codegen.mjs.map +1 -1
  388. package/dist/plugins/sui/errors.d.mts +1 -1
  389. package/dist/plugins/sui/errors.mjs +1 -9
  390. package/dist/plugins/sui/errors.mjs.map +1 -1
  391. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
  392. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
  393. package/dist/plugins/sui/exec/index.mjs.map +1 -0
  394. package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
  395. package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
  396. package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
  397. package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
  398. package/dist/plugins/sui/fork-orchestration.mjs +13 -23
  399. package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
  400. package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
  401. package/dist/plugins/sui/index.d.mts +34 -83
  402. package/dist/plugins/sui/index.mjs +200 -68
  403. package/dist/plugins/sui/index.mjs.map +1 -1
  404. package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
  405. package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
  406. package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
  407. package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
  408. package/dist/plugins/sui/log-attrs.mjs +11 -0
  409. package/dist/plugins/sui/log-attrs.mjs.map +1 -0
  410. package/dist/plugins/sui/mode/external.mjs +4 -12
  411. package/dist/plugins/sui/mode/external.mjs.map +1 -1
  412. package/dist/plugins/sui/mode/fork.mjs +19 -16
  413. package/dist/plugins/sui/mode/fork.mjs.map +1 -1
  414. package/dist/plugins/sui/mode/live.mjs +4 -17
  415. package/dist/plugins/sui/mode/live.mjs.map +1 -1
  416. package/dist/plugins/sui/mode/local.d.mts +1 -0
  417. package/dist/plugins/sui/mode/local.mjs +203 -61
  418. package/dist/plugins/sui/mode/local.mjs.map +1 -1
  419. package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
  420. package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
  421. package/dist/plugins/sui/mode/shared.d.mts +6 -7
  422. package/dist/plugins/sui/mode/shared.mjs.map +1 -1
  423. package/dist/plugins/sui/mode/spec.d.mts +23 -6
  424. package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
  425. package/dist/plugins/sui/move/index.mjs.map +1 -0
  426. package/dist/plugins/sui/move-summary-runner.mjs +8 -4
  427. package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
  428. package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
  429. package/dist/plugins/sui/network-resolver.d.mts +6 -6
  430. package/dist/plugins/sui/routable.mjs.map +1 -1
  431. package/dist/plugins/sui/service.mjs +10 -6
  432. package/dist/plugins/sui/service.mjs.map +1 -1
  433. package/dist/plugins/sui/snapshot.mjs +10 -5
  434. package/dist/plugins/sui/snapshot.mjs.map +1 -1
  435. package/dist/plugins/wallet/codegen.d.mts +8 -6
  436. package/dist/plugins/wallet/codegen.mjs +4 -10
  437. package/dist/plugins/wallet/codegen.mjs.map +1 -1
  438. package/dist/plugins/wallet/errors.mjs +1 -4
  439. package/dist/plugins/wallet/errors.mjs.map +1 -1
  440. package/dist/plugins/wallet/index.d.mts +3 -6
  441. package/dist/plugins/wallet/index.mjs +16 -21
  442. package/dist/plugins/wallet/index.mjs.map +1 -1
  443. package/dist/plugins/wallet/origin-policy.mjs +3 -3
  444. package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
  445. package/dist/plugins/wallet/pairing.mjs +6 -24
  446. package/dist/plugins/wallet/pairing.mjs.map +1 -1
  447. package/dist/plugins/wallet/protocol.mjs.map +1 -1
  448. package/dist/plugins/wallet/routable.mjs.map +1 -1
  449. package/dist/plugins/wallet/server.mjs +17 -24
  450. package/dist/plugins/wallet/server.mjs.map +1 -1
  451. package/dist/plugins/wallet/service.d.mts +2 -2
  452. package/dist/plugins/wallet/service.mjs +4 -15
  453. package/dist/plugins/wallet/service.mjs.map +1 -1
  454. package/dist/plugins/wallet/snapshot.mjs.map +1 -1
  455. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
  456. package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
  457. package/dist/plugins/walrus/codegen.d.mts +2 -13
  458. package/dist/plugins/walrus/codegen.mjs +93 -28
  459. package/dist/plugins/walrus/codegen.mjs.map +1 -1
  460. package/dist/plugins/walrus/deploy-paths.mjs +2 -3
  461. package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
  462. package/dist/plugins/walrus/deploy.mjs +26 -19
  463. package/dist/plugins/walrus/deploy.mjs.map +1 -1
  464. package/dist/plugins/walrus/errors.mjs +1 -8
  465. package/dist/plugins/walrus/errors.mjs.map +1 -1
  466. package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
  467. package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
  468. package/dist/plugins/walrus/index.d.mts +13 -44
  469. package/dist/plugins/walrus/index.mjs +119 -122
  470. package/dist/plugins/walrus/index.mjs.map +1 -1
  471. package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
  472. package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
  473. package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
  474. package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
  475. package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
  476. package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
  477. package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
  478. package/dist/plugins/walrus/routable.mjs.map +1 -1
  479. package/dist/plugins/walrus/service.mjs.map +1 -1
  480. package/dist/plugins/walrus/snapshot.mjs +3 -3
  481. package/dist/plugins/walrus/snapshot.mjs.map +1 -1
  482. package/dist/plugins/walrus/storage-nodes.mjs +53 -14
  483. package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
  484. package/dist/plugins/walrus/wal-swap.mjs +4 -8
  485. package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
  486. package/dist/primitives/artifact-publisher.mjs.map +1 -1
  487. package/dist/primitives/cache.d.mts +1 -1
  488. package/dist/runtime/docker/client.mjs +47 -3
  489. package/dist/runtime/docker/client.mjs.map +1 -1
  490. package/dist/runtime/docker/container.mjs +37 -57
  491. package/dist/runtime/docker/container.mjs.map +1 -1
  492. package/dist/runtime/docker/errors.mjs.map +1 -1
  493. package/dist/runtime/docker/exec.mjs +2 -2
  494. package/dist/runtime/docker/exec.mjs.map +1 -1
  495. package/dist/runtime/docker/image.mjs +10 -11
  496. package/dist/runtime/docker/image.mjs.map +1 -1
  497. package/dist/runtime/docker/index.mjs +0 -1
  498. package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
  499. package/dist/runtime/docker/inventory.mjs +9 -9
  500. package/dist/runtime/docker/inventory.mjs.map +1 -1
  501. package/dist/runtime/docker/labels.mjs +12 -1
  502. package/dist/runtime/docker/labels.mjs.map +1 -1
  503. package/dist/runtime/docker/network.mjs +6 -6
  504. package/dist/runtime/docker/network.mjs.map +1 -1
  505. package/dist/runtime/docker/render-run-args.mjs.map +1 -1
  506. package/dist/runtime/docker/service.mjs +31 -45
  507. package/dist/runtime/docker/service.mjs.map +1 -1
  508. package/dist/runtime/docker/sweep.mjs +14 -64
  509. package/dist/runtime/docker/sweep.mjs.map +1 -1
  510. package/dist/runtime/docker/volume.mjs +1 -1
  511. package/dist/runtime/docker/volume.mjs.map +1 -1
  512. package/dist/runtime/docker/wrap.mjs +14 -2
  513. package/dist/runtime/docker/wrap.mjs.map +1 -1
  514. package/dist/substrate/brand.d.mts +2 -5
  515. package/dist/substrate/brand.mjs +3 -2
  516. package/dist/substrate/brand.mjs.map +1 -1
  517. package/dist/substrate/cross-process.mjs +2 -16
  518. package/dist/substrate/cross-process.mjs.map +1 -1
  519. package/dist/substrate/event-time.mjs +0 -2
  520. package/dist/substrate/event-time.mjs.map +1 -1
  521. package/dist/substrate/events.d.mts +46 -16
  522. package/dist/substrate/identity.d.mts +11 -5
  523. package/dist/substrate/manifest.d.mts +33 -26
  524. package/dist/substrate/manifest.mjs +8 -3
  525. package/dist/substrate/manifest.mjs.map +1 -1
  526. package/dist/substrate/options.d.mts +33 -4
  527. package/dist/substrate/plugin-ctx.d.mts +70 -0
  528. package/dist/substrate/plugin-ctx.mjs +66 -0
  529. package/dist/substrate/plugin-ctx.mjs.map +1 -0
  530. package/dist/substrate/plugin.d.mts +46 -38
  531. package/dist/substrate/plugin.mjs +13 -9
  532. package/dist/substrate/plugin.mjs.map +1 -1
  533. package/dist/substrate/projection.d.mts +1 -1
  534. package/dist/substrate/runtime/atomic-write.mjs +3 -4
  535. package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
  536. package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
  537. package/dist/substrate/runtime/cache/service.mjs +50 -20
  538. package/dist/substrate/runtime/cache/service.mjs.map +1 -1
  539. package/dist/substrate/runtime/config-validation.mjs.map +1 -1
  540. package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
  541. package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
  542. package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
  543. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
  544. package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
  545. package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
  546. package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
  547. package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
  548. package/dist/substrate/runtime/cross-process/index.mjs +0 -2
  549. package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
  550. package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
  551. package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
  552. package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
  553. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
  554. package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
  555. package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
  556. package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
  557. package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
  558. package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
  559. package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
  560. package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
  561. package/dist/substrate/runtime/errors.mjs +1 -13
  562. package/dist/substrate/runtime/errors.mjs.map +1 -1
  563. package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
  564. package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
  565. package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
  566. package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
  567. package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
  568. package/dist/substrate/runtime/http-probe.d.mts +1 -3
  569. package/dist/substrate/runtime/http-probe.mjs.map +1 -1
  570. package/dist/substrate/runtime/index.mjs +1 -6
  571. package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
  572. package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
  573. package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
  574. package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
  575. package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
  576. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
  577. package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
  578. package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
  579. package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
  580. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
  581. package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
  582. package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
  583. package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
  584. package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
  585. package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
  586. package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
  587. package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
  588. package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
  589. package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
  590. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
  591. package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
  592. package/dist/substrate/runtime/managed-container.d.mts +5 -1
  593. package/dist/substrate/runtime/managed-container.mjs +8 -10
  594. package/dist/substrate/runtime/managed-container.mjs.map +1 -1
  595. package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
  596. package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
  597. package/dist/substrate/runtime/mode-errors.d.mts +1 -2
  598. package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
  599. package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
  600. package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
  601. package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
  602. package/dist/substrate/runtime/observability/index.d.mts +1 -1
  603. package/dist/substrate/runtime/observability/index.mjs +4 -6
  604. package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
  605. package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
  606. package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
  607. package/dist/substrate/runtime/observability/logger.mjs +3 -3
  608. package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
  609. package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
  610. package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
  611. package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
  612. package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
  613. package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
  614. package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
  615. package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
  616. package/dist/substrate/runtime/paths.mjs +27 -9
  617. package/dist/substrate/runtime/paths.mjs.map +1 -1
  618. package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
  619. package/dist/substrate/runtime/port-broker/service.mjs +10 -27
  620. package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
  621. package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
  622. package/dist/substrate/runtime/probes.d.mts +2 -3
  623. package/dist/substrate/runtime/probes.mjs.map +1 -1
  624. package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
  625. package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
  626. package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
  627. package/dist/substrate/runtime/projection/update.mjs +87 -11
  628. package/dist/substrate/runtime/projection/update.mjs.map +1 -1
  629. package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
  630. package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
  631. package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
  632. package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
  633. package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
  634. package/dist/substrate/runtime/reconcile/index.mjs +5 -0
  635. package/dist/substrate/runtime/reconcile/label.mjs +41 -0
  636. package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
  637. package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
  638. package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
  639. package/dist/substrate/runtime/retry-policy.d.mts +2 -3
  640. package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
  641. package/dist/substrate/runtime/routed-url.mjs.map +1 -1
  642. package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
  643. package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
  644. package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
  645. package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
  646. package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
  647. package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
  648. package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
  649. package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
  650. package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
  651. package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
  652. package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
  653. package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
  654. package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
  655. package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
  656. package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
  657. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
  658. package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
  659. package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
  660. package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
  661. package/dist/substrate/runtime/supervisor/index.mjs +2 -0
  662. package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
  663. package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
  664. package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
  665. package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
  666. package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
  667. package/dist/substrate/runtime/supervisor/state.mjs +1 -1
  668. package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
  669. package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
  670. package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
  671. package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
  672. package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
  673. package/dist/substrate/runtime/tar/reader.mjs +216 -0
  674. package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
  675. package/dist/substrate/runtime/typed-env.mjs.map +1 -1
  676. package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
  677. package/dist/substrate/versioned-doc-sync.mjs +5 -5
  678. package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
  679. package/dist/surfaces/cli/command-tree.mjs +49 -7
  680. package/dist/surfaces/cli/command-tree.mjs.map +1 -1
  681. package/dist/surfaces/cli/commands/config.mjs +1 -1
  682. package/dist/surfaces/cli/commands/config.mjs.map +1 -1
  683. package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
  684. package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
  685. package/dist/surfaces/cli/commands/doctor.mjs +1 -1
  686. package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
  687. package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
  688. package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
  689. package/dist/surfaces/cli/commands/prune.mjs +1 -1
  690. package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
  691. package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
  692. package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
  693. package/dist/surfaces/cli/commands/status.mjs +1 -1
  694. package/dist/surfaces/cli/commands/status.mjs.map +1 -1
  695. package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
  696. package/dist/surfaces/cli/commands/wipe.mjs +3 -4
  697. package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
  698. package/dist/surfaces/cli/envelope.mjs.map +1 -1
  699. package/dist/surfaces/cli/errors.mjs.map +1 -1
  700. package/dist/surfaces/cli/flags.mjs.map +1 -1
  701. package/dist/surfaces/cli/index.mjs +45 -14
  702. package/dist/surfaces/cli/index.mjs.map +1 -1
  703. package/dist/surfaces/cli/output.mjs.map +1 -1
  704. package/dist/surfaces/cli/sysexits.mjs.map +1 -1
  705. package/dist/surfaces/tui/app.mjs +0 -21
  706. package/dist/surfaces/tui/app.mjs.map +1 -1
  707. package/dist/surfaces/tui/dashboard.mjs +0 -48
  708. package/dist/surfaces/tui/dashboard.mjs.map +1 -1
  709. package/dist/surfaces/tui/display-derivation.mjs +80 -16
  710. package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
  711. package/dist/surfaces/tui/errors.mjs.map +1 -1
  712. package/dist/surfaces/tui/event-log.mjs +0 -9
  713. package/dist/surfaces/tui/event-log.mjs.map +1 -1
  714. package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
  715. package/dist/surfaces/tui/index.mjs +2 -2
  716. package/dist/surfaces/tui/index.mjs.map +1 -1
  717. package/dist/surfaces/tui/input.mjs.map +1 -1
  718. package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
  719. package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
  720. package/dist/surfaces/tui/plain-renderer.mjs +26 -19
  721. package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
  722. package/dist/surfaces/tui/resource-table.mjs +8 -10
  723. package/dist/surfaces/tui/resource-table.mjs.map +1 -1
  724. package/images/postgres/Dockerfile +0 -1
  725. package/images/sui/Dockerfile +27 -54
  726. package/images/sui/entrypoint.sh +17 -179
  727. package/package.json +23 -15
  728. package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
  729. package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
  730. package/dashboard-ui/assets/index-Deml9drg.css +0 -1
  731. package/dist/api/plugin-errors.d.mts +0 -7
  732. package/dist/api/plugin-errors.mjs +0 -10
  733. package/dist/api/plugin-errors.mjs.map +0 -1
  734. package/dist/cli/wirings/build-verb-layers.mjs +0 -42
  735. package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
  736. package/dist/contracts/capability-decl.d.mts +0 -40
  737. package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
  738. package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
  739. package/dist/orchestrators/run.mjs +0 -91
  740. package/dist/orchestrators/run.mjs.map +0 -1
  741. package/dist/orchestrators/runtime-composition.d.mts +0 -10
  742. package/dist/orchestrators/runtime-composition.mjs +0 -252
  743. package/dist/orchestrators/runtime-composition.mjs.map +0 -1
  744. package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
  745. package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
  746. package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
  747. package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
  748. package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
  749. package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
  750. package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
  751. package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
  752. package/dist/orchestrators/snapshot/state-document.mjs +0 -58
  753. package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
  754. package/dist/plugins/account/spans.mjs +0 -16
  755. package/dist/plugins/account/spans.mjs.map +0 -1
  756. package/dist/plugins/account/variants/env.mjs +0 -24
  757. package/dist/plugins/account/variants/env.mjs.map +0 -1
  758. package/dist/plugins/account/variants/inline.mjs +0 -13
  759. package/dist/plugins/account/variants/inline.mjs.map +0 -1
  760. package/dist/plugins/account/variants/keystore.mjs +0 -91
  761. package/dist/plugins/account/variants/keystore.mjs.map +0 -1
  762. package/dist/plugins/action/spans.mjs +0 -11
  763. package/dist/plugins/action/spans.mjs.map +0 -1
  764. package/dist/plugins/coin/spans.mjs +0 -20
  765. package/dist/plugins/coin/spans.mjs.map +0 -1
  766. package/dist/plugins/deepbook/spans.mjs +0 -18
  767. package/dist/plugins/deepbook/spans.mjs.map +0 -1
  768. package/dist/plugins/faucet/spans.mjs +0 -12
  769. package/dist/plugins/faucet/spans.mjs.map +0 -1
  770. package/dist/plugins/package/spans.mjs +0 -14
  771. package/dist/plugins/package/spans.mjs.map +0 -1
  772. package/dist/plugins/postgres/codegen.mjs +0 -42
  773. package/dist/plugins/postgres/codegen.mjs.map +0 -1
  774. package/dist/plugins/postgres/connection.d.mts +0 -33
  775. package/dist/plugins/postgres/connection.mjs.map +0 -1
  776. package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
  777. package/dist/plugins/postgres/errors.d.mts +0 -60
  778. package/dist/plugins/postgres/errors.mjs +0 -29
  779. package/dist/plugins/postgres/errors.mjs.map +0 -1
  780. package/dist/plugins/postgres/index.d.mts +0 -37
  781. package/dist/plugins/postgres/index.mjs +0 -68
  782. package/dist/plugins/postgres/index.mjs.map +0 -1
  783. package/dist/plugins/postgres/routable.mjs +0 -33
  784. package/dist/plugins/postgres/routable.mjs.map +0 -1
  785. package/dist/plugins/postgres/service.d.mts +0 -50
  786. package/dist/plugins/postgres/service.mjs +0 -179
  787. package/dist/plugins/postgres/service.mjs.map +0 -1
  788. package/dist/plugins/postgres/snapshot.mjs +0 -32
  789. package/dist/plugins/postgres/snapshot.mjs.map +0 -1
  790. package/dist/plugins/postgres/spans.mjs +0 -11
  791. package/dist/plugins/postgres/spans.mjs.map +0 -1
  792. package/dist/plugins/seal/spans.mjs +0 -18
  793. package/dist/plugins/seal/spans.mjs.map +0 -1
  794. package/dist/plugins/sui/spans.mjs +0 -17
  795. package/dist/plugins/sui/spans.mjs.map +0 -1
  796. package/dist/plugins/wallet/spans.mjs +0 -22
  797. package/dist/plugins/wallet/spans.mjs.map +0 -1
  798. package/dist/plugins/walrus/registry-publish.d.mts +0 -24
  799. package/dist/plugins/walrus/spans.mjs +0 -18
  800. package/dist/plugins/walrus/spans.mjs.map +0 -1
  801. package/dist/runtime/docker/logs.d.mts +0 -1
  802. package/dist/runtime/docker/logs.mjs +0 -34
  803. package/dist/runtime/docker/logs.mjs.map +0 -1
  804. package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
  805. package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
  806. package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
  807. package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
  808. package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
  809. package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
  810. package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
  811. package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
  812. package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
  813. package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
  814. package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
  815. package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
  816. package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
  817. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
  818. package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
  819. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
  820. package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
  821. package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
  822. package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
  823. package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
  824. package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
  825. package/dist/substrate/runtime/observability/span-store.mjs +0 -110
  826. package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
  827. package/dist/substrate/runtime/observability/spans.d.mts +0 -1
  828. package/dist/substrate/runtime/observability/spans.mjs +0 -87
  829. package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
  830. package/dist/substrate/runtime/projection/index.mjs +0 -4
  831. package/dist/substrate/runtime/projection/persisted.mjs +0 -213
  832. package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
  833. package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
  834. package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
  835. package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
  836. package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
  837. package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
  838. package/dist/substrate/runtime/state-store/index.mjs +0 -3
  839. package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
  840. package/dist/substrate/runtime/state-store/schema.mjs +0 -41
  841. package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
  842. package/dist/substrate/runtime/state-store/service.d.mts +0 -1
  843. package/dist/substrate/runtime/state-store/service.mjs +0 -145
  844. package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
  845. package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
  846. package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
  847. package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
  848. package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
  849. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
  850. package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
  851. package/dist/substrate/state-store.d.mts +0 -1
  852. /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
  853. /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
  854. /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
  855. /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
  856. /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
  857. /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
  858. /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
@@ -1,7 +1,4 @@
1
1
  import { defineSimpleConstExport } from "../internal/codegen-helpers.mjs";
2
- import { WalletSpans } from "./spans.mjs";
3
- import { redactToken } from "./pairing.mjs";
4
- import { Effect } from "effect";
5
2
  //#region src/plugins/wallet/codegen.ts
6
3
  /**
7
4
  * Construct the Codegenable contribution.
@@ -18,14 +15,11 @@ import { Effect } from "effect";
18
15
  */
19
16
  const makeWalletCodegen = (resolved) => defineSimpleConstExport({
20
17
  emitterName: "dapp-kit-config",
21
- outputPath: "dapp-kit/config.ts",
22
- exportName: "dappKitConfig",
18
+ outputPath: "dev-wallet.ts",
19
+ exportName: "devWallet",
23
20
  value: resolved,
24
- sensitive: true,
25
- preEmit: Effect.annotateCurrentSpan({
26
- [WalletSpans.codegenPairUrl]: redactToken(resolved.pairUrl),
27
- [WalletSpans.codegenWalletUrl]: resolved.walletUrl
28
- })
21
+ outputLocation: "generated-extras",
22
+ sensitive: true
29
23
  });
30
24
  //#endregion
31
25
  export { makeWalletCodegen };
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/wallet/codegen.ts"],"sourcesContent":["// Wallet plugin — Codegenable contribution.\n//\n// Architecture (15-wallet.md §\"Capabilities PRODUCED\" + §\"Codegen\n// emits a `dapp-kit-config.ts`\"):\n//\n// - The browser-side dev-wallet adapter is the cross-boundary\n// consumer. It reads a typed `dapp-kit-config` value at startup,\n// constructs a `DevstackSignerAdapter`, and registers it with\n// `@mysten/dapp-kit`'s wallet-standard surface (in user-app\n// bundle code — devstack itself NEVER imports dapp-kit).\n//\n// - The emitted file lives at `dapp-kit/config.ts` under the staging\n// dir. The generated module owns the exported config value's type.\n//\n// SENSITIVE FLAG (task requirement #5 — manifest-vs-token threat\n// surface):\n//\n// - The emitted file carries the unredacted pair URL (incl. the\n// `#token=<32-hex>` fragment) so the dev-wallet adapter can wire\n// itself up without a side-channel read.\n// - Therefore `sensitive: true`. The codegen orchestrator tightens\n// the file mode to `0o600` on emit AND injects the file path into\n// `.gitignore`.\n//\n// Distilled-doc tension absorbed (15-wallet.md \"Manifest carries\n// unredacted pair URL while token file is 0o600 — pick one\"):\n//\n// We pick \"tighten the emit perms\". The token still lives in a\n// `0o600` side-channel file (see `pairing.ts:tokenPath`), AND the\n// codegen emit is also `0o600` via the sensitive flag. The legacy\n// `.devstack/manifest.json` write that left the pair URL world-\n// readable is GONE the rewrite no longer emits an unredacted pair\n// URL into the manifest. Only the codegen file carries it, and that\n// file is tightened.\n//\n// See the report's §\"Architecture-doc revisions\" for the\n// architecture-doc note that needs to land alongside this.\n\nimport { Effect } from 'effect';\n\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\n\nimport { defineSimpleConstExport } from '../internal/codegen-helpers.ts';\n\nimport { redactToken } from './pairing.ts';\nimport { WalletSpans } from './spans.ts';\n\n// ----------------------------------------------------------------------\n// Emitted shape\n// ----------------------------------------------------------------------\n\n/** The typed shape `dapp-kit/config.ts` exports. Downstream consumers\n * (the user-app's dapp-kit boot code) import and consume this.\n *\n * Field shape mirrors what `DevstackSignerAdapter` needs:\n *\n * - `walletUrl` : the wallet HTTP server's URL (router-fronted\n * host form when available, direct-loopback\n * fallback otherwise).\n * - `pairUrl` : `walletUrl` + `/#token=<32-hex>` (single\n * source of truth for the token).\n * - `protocolPaths` : path constants the adapter reads. Mirrored\n * here so the adapter doesn't depend on a\n * separate import.\n * - `chain` : Sui chain id the wallet's accounts are\n * scoped to. Surfaced so dapp-kit can pin its\n * active chain.\n */\nexport interface DappKitConfigBindings {\n\treadonly walletUrl: string;\n\treadonly pairUrl: string;\n\treadonly chain: string;\n\treadonly protocolPaths: {\n\t\treadonly health: string;\n\t\treadonly accounts: string;\n\t\treadonly signTransaction: string;\n\t\treadonly signPersonalMessage: string;\n\t};\n}\n\n// ----------------------------------------------------------------------\n// Decl construction\n// ----------------------------------------------------------------------\n\n/**\n * Construct the Codegenable contribution.\n *\n * Emits `dapp-kit/config.ts` with `sensitive: true` → the orchestrator\n * writes the file with `0o600` and gitignores it. The emitted shape\n * carries the unredacted pair URL; the side-channel token file is\n * also `0o600`.\n *\n * The `resolved` arg is supplied AFTER acquire (the substrate's\n * \"resolve-once\" memo). At factory time the barrel passes a\n * placeholder so the type plumbing works; at codegen time the\n * substrate re-evaluates with the resolved values.\n */\nexport const makeWalletCodegen = (\n\tresolved: DappKitConfigBindings,\n): CodegenableDecl<'dapp-kit-config'> =>\n\tdefineSimpleConstExport({\n\t\temitterName: 'dapp-kit-config',\n\t\toutputPath: 'dapp-kit/config.ts',\n\t\texportName: 'dappKitConfig',\n\t\tvalue: resolved,\n\t\t// SENSITIVE: drives 0o600 + .gitignore. The architecture has\n\t\t// this hook (`SnapshotableDecl` mirrors it for the snapshot\n\t\t// subtree).\n\t\tsensitive: true,\n\t\t// Span annotation logs ONLY the redacted form — defense-in-\n\t\t// depth so any debug-mode span dump doesn't leak the token.\n\t\tpreEmit: Effect.annotateCurrentSpan({\n\t\t\t[WalletSpans.codegenPairUrl]: redactToken(resolved.pairUrl),\n\t\t\t[WalletSpans.codegenWalletUrl]: resolved.walletUrl,\n\t\t}),\n\t});\n"],"mappings":";;;;;;;;;;;;;;;;;;AAiGA,MAAa,qBACZ,aAEA,wBAAwB;CACvB,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,OAAO;CAIP,WAAW;CAGX,SAAS,OAAO,oBAAoB;GAClC,YAAY,iBAAiB,YAAY,SAAS,QAAQ;GAC1D,YAAY,mBAAmB,SAAS;EACzC,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"codegen.mjs","names":[],"sources":["../../../src/plugins/wallet/codegen.ts"],"sourcesContent":["// Wallet plugin — Codegenable contribution.\n//\n// Architecture (15-wallet.md §\"Capabilities PRODUCED\" + §\"Codegen\n// emits a `dapp-kit-config.ts`\"):\n//\n// - The browser-side dev-wallet adapter is the cross-boundary\n// consumer. It reads a typed `dapp-kit-config` value at startup,\n// constructs a `DevstackSignerAdapter`, and registers it with\n// `@mysten/dapp-kit`'s wallet-standard surface (in user-app\n// bundle code — devstack itself NEVER imports dapp-kit).\n//\n// - The emitted file lives at `dapp-kit/config.ts` under the staging\n// dir. The generated module owns the exported config value's type.\n//\n// SENSITIVE FLAG (manifest-vs-token threat surface):\n//\n// - The emitted file carries the unredacted pair URL (incl. the\n// `#token=<32-hex>` fragment) so the dev-wallet adapter can wire\n// itself up without a side-channel read.\n// - Therefore `sensitive: true`. The codegen orchestrator tightens\n// the file mode to `0o600` on emit AND injects the file path into\n// `.gitignore`.\n// - The token lives in a `0o600` side-channel file (see\n// `pairing.ts:tokenPath`) AND the codegen emit is `0o600` via the\n// sensitive flag. The unredacted pair URL is never written to a\n// world-readable manifest only the tightened codegen file carries\n// it.\n\nimport type { CodegenableDecl } from '../../contracts/codegenable.ts';\n\nimport { defineSimpleConstExport } from '../internal/codegen-helpers.ts';\n\n// ----------------------------------------------------------------------\n// Emitted shape\n// ----------------------------------------------------------------------\n\n/** The typed shape `dapp-kit/config.ts` exports. Downstream consumers\n * (the user-app's dapp-kit boot code) import and consume this.\n *\n * Field shape mirrors what `DevstackSignerAdapter` needs:\n *\n * - `walletUrl` : the wallet HTTP server's URL (router-fronted\n * host form when available, direct-loopback\n * fallback otherwise).\n * - `pairUrl` : `walletUrl` + `/#token=<32-hex>` (single\n * source of truth for the token).\n * - `protocolPaths` : path constants the adapter reads. Mirrored\n * here so the adapter doesn't depend on a\n * separate import.\n * - `network` : the network name the wallet's accounts are\n * scoped to (e.g. `localnet`). The dev wallet\n * derives the wallet-standard chain (`sui:<network>`)\n * from it at the wallet-standard boundary; devstack\n * itself never carries the `sui:`-prefixed form.\n */\nexport interface DevWalletConfig {\n\treadonly walletUrl: string;\n\treadonly pairUrl: string;\n\treadonly network: string;\n\treadonly protocolPaths: {\n\t\treadonly health: string;\n\t\treadonly accounts: string;\n\t\treadonly signTransaction: string;\n\t\treadonly signPersonalMessage: string;\n\t};\n}\n\n// ----------------------------------------------------------------------\n// Decl construction\n// ----------------------------------------------------------------------\n\n/**\n * Construct the Codegenable contribution.\n *\n * Emits `dapp-kit/config.ts` with `sensitive: true` → the orchestrator\n * writes the file with `0o600` and gitignores it. The emitted shape\n * carries the unredacted pair URL; the side-channel token file is\n * also `0o600`.\n *\n * The `resolved` arg is supplied AFTER acquire (the substrate's\n * \"resolve-once\" memo). At factory time the barrel passes a\n * placeholder so the type plumbing works; at codegen time the\n * substrate re-evaluates with the resolved values.\n */\nexport const makeWalletCodegen = (resolved: DevWalletConfig): CodegenableDecl<'dapp-kit-config'> =>\n\tdefineSimpleConstExport({\n\t\temitterName: 'dapp-kit-config',\n\t\toutputPath: 'dev-wallet.ts',\n\t\texportName: 'devWallet',\n\t\tvalue: resolved,\n\t\t// Dev-only + secret-bearing: lands in the gitignored\n\t\t// `generated-extras` tree (reached via `@devstack-dev`). The\n\t\t// token never enters the runtime `src/generated/` tree.\n\t\toutputLocation: 'generated-extras',\n\t\t// SENSITIVE: drives 0o600. The architecture has this hook\n\t\t// (`SnapshotableDecl` mirrors it for the snapshot subtree).\n\t\t// `generated-extras` is already gitignored at the `.devstack`\n\t\t// level, so the codegen `.gitignore` does not list it.\n\t\tsensitive: true,\n\t});\n"],"mappings":";;;;;;;;;;;;;;;AAoFA,MAAa,qBAAqB,aACjC,wBAAwB;CACvB,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,OAAO;CAIP,gBAAgB;CAKhB,WAAW;AACZ,CAAC"}
@@ -7,10 +7,7 @@ const walletRequestError = (parts) => ({
7
7
  _tag: "WalletRequestError",
8
8
  ...parts
9
9
  });
10
- /** Error tags this plugin contributes — surfaced to the cause walker
11
- * via `PluginErrorContribution`. */
12
- const WALLET_ERROR_TAGS = ["WalletBootError", "WalletRequestError"];
13
10
  //#endregion
14
- export { WALLET_ERROR_TAGS, walletBootError, walletRequestError };
11
+ export { walletBootError, walletRequestError };
15
12
 
16
13
  //# sourceMappingURL=errors.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../../../src/plugins/wallet/errors.ts"],"sourcesContent":["// Wallet plugin — typed errors.\n//\n// Distilled-doc finding (15-wallet.md \"Failure modes\"): the wallet's\n// failure surface separates BOOT-time errors from REQUEST-time errors.\n// Boot errors surface as `WalletBootError` (port allocation, listen\n// failure, token-file write); request errors surface as\n// `WalletRequestError` (auth, origin, route, body parse, sign-route\n// failure). The two channels never mix — request errors flow back to\n// the HTTP client as JSON envelopes, boot errors flow up the supervisor\n// scope.\n//\n// Effect v4: plain interface + `_tag` literal discriminator (no\n// subclassing). Per-plugin tagged-error convention — the cause walker\n// dispatches on `_tag`.\n\n/**\n * Phases for `WalletBootError`. Closed sum — adding a phase means\n * editing this list AND any cause-walker display tables.\n *\n * - `listen` : `http.Server.listen` rejected (typically\n * EADDRINUSE after port-broker forward-scan, or\n * EACCES on a privileged port).\n * - `allocate-port` : the supervisor's port broker could not yield\n * a free port near the preferred one.\n * - `read-token` : the on-disk pairing-token file existed but\n * could not be read (EACCES, EIO).\n * - `write-token` : the freshly-minted token file could not be\n * persisted (ENOSPC, EROFS).\n * - `bind-account` : a consumed account tag failed to resolve at\n * acquire time (re-thrown with a wallet phase).\n * - `route-url` : failed to construct the router-fronted URL\n * for the generated dapp-kit config.\n * - `no-accounts` : account inference resolved to an empty set.\n */\nexport type WalletBootPhase =\n\t| 'listen'\n\t| 'allocate-port'\n\t| 'read-token'\n\t| 'write-token'\n\t| 'bind-account'\n\t| 'route-url'\n\t| 'no-accounts';\n\n/** Boot-time wallet error — raised by the plugin's acquire body. */\nexport interface WalletBootError {\n\treadonly _tag: 'WalletBootError';\n\treadonly phase: WalletBootPhase;\n\treadonly message: string;\n\treadonly hint?: string;\n\treadonly cause?: unknown;\n}\n\nexport const walletBootError = (parts: Omit<WalletBootError, '_tag'>): WalletBootError => ({\n\t_tag: 'WalletBootError',\n\t...parts,\n});\n\n/**\n * Phases for `WalletRequestError`. Each maps to an HTTP status the\n * server emits (status code carried explicitly so renderers can keep\n * the mapping in one place rather than re-deriving it).\n *\n * - `origin-missing` : 403 — no Origin header on a protected\n * route (closes the curl/non-browser\n * bypass; mandatory by C12).\n * - `origin-forbidden` : 403 — Origin not in the stack-scoped\n * allowlist.\n * - `unauthorized` : 401 — bearer absent or did not survive\n * constant-time compare.\n * - `route-not-found` : 404 — `/api/v1/devstack/*` path with no\n * handler wired.\n * - `address-not-found` : 404 — sign request named an address the\n * wallet did not bind.\n * - `body-invalid` : 400 — JSON parse, missing required\n * field, non-base64 bytes, body >64 KiB.\n * - `sign-route-failed` : 500 — the routed `AccountValue` sign\n * closure raised an `AccountSignError`.\n */\nexport type WalletRequestPhase =\n\t| 'origin-missing'\n\t| 'origin-forbidden'\n\t| 'unauthorized'\n\t| 'route-not-found'\n\t| 'address-not-found'\n\t| 'body-invalid'\n\t| 'sign-route-failed';\n\n/** Request-time wallet error — raised by the in-process HTTP handlers.\n * Carries the HTTP status the server will write and an optional inner\n * cause (e.g. an `AccountSignError` for `sign-route-failed`). */\nexport interface WalletRequestError {\n\treadonly _tag: 'WalletRequestError';\n\treadonly phase: WalletRequestPhase;\n\treadonly httpStatus: number;\n\treadonly message: string;\n\treadonly cause?: unknown;\n}\n\nexport const walletRequestError = (\n\tparts: Omit<WalletRequestError, '_tag'>,\n): WalletRequestError => ({ _tag: 'WalletRequestError', ...parts });\n\n/** Union of every error a wallet caller may encounter. */\nexport type WalletError = WalletBootError | WalletRequestError;\n\n/** Error tags this plugin contributes surfaced to the cause walker\n * via `PluginErrorContribution`. */\nexport const WALLET_ERROR_TAGS: ReadonlyArray<WalletError['_tag']> = [\n\t'WalletBootError',\n\t'WalletRequestError',\n] as const;\n"],"mappings":";AAoDA,MAAa,mBAAmB,WAA2D;CAC1F,MAAM;CACN,GAAG;CACH;AA2CD,MAAa,sBACZ,WACyB;CAAE,MAAM;CAAsB,GAAG;CAAO;;;AAOlE,MAAa,oBAAwD,CACpE,mBACA,qBACA"}
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../../../src/plugins/wallet/errors.ts"],"sourcesContent":["// Wallet plugin — typed errors.\n//\n// Distilled-doc finding (15-wallet.md \"Failure modes\"): the wallet's\n// failure surface separates BOOT-time errors from REQUEST-time errors.\n// Boot errors surface as `WalletBootError` (port allocation, listen\n// failure, token-file write); request errors surface as\n// `WalletRequestError` (auth, origin, route, body parse, sign-route\n// failure). The two channels never mix — request errors flow back to\n// the HTTP client as JSON envelopes, boot errors flow up the supervisor\n// scope.\n//\n// Effect v4: plain interface + `_tag` literal discriminator (no\n// subclassing). Per-plugin tagged-error convention — the cause walker\n// dispatches on `_tag`.\n\n/**\n * Phases for `WalletBootError`. Closed sum — adding a phase means\n * editing this list AND any cause-walker display tables.\n *\n * - `listen` : `http.Server.listen` rejected (typically\n * EADDRINUSE after port-broker forward-scan, or\n * EACCES on a privileged port).\n * - `allocate-port` : the supervisor's port broker could not yield\n * a free port near the preferred one.\n * - `read-token` : the on-disk pairing-token file existed but\n * could not be read (EACCES, EIO).\n * - `write-token` : the freshly-minted token file could not be\n * persisted (ENOSPC, EROFS).\n * - `bind-account` : a consumed account tag failed to resolve at\n * acquire time (re-thrown with a wallet phase).\n * - `route-url` : failed to construct the router-fronted URL\n * for the generated dapp-kit config.\n * - `no-accounts` : account inference resolved to an empty set.\n */\nexport type WalletBootPhase =\n\t| 'listen'\n\t| 'allocate-port'\n\t| 'read-token'\n\t| 'write-token'\n\t| 'bind-account'\n\t| 'route-url'\n\t| 'no-accounts';\n\n/** Boot-time wallet error — raised by the plugin's acquire body. */\nexport interface WalletBootError {\n\treadonly _tag: 'WalletBootError';\n\treadonly phase: WalletBootPhase;\n\treadonly message: string;\n\treadonly hint?: string;\n\treadonly cause?: unknown;\n}\n\nexport const walletBootError = (parts: Omit<WalletBootError, '_tag'>): WalletBootError => ({\n\t_tag: 'WalletBootError',\n\t...parts,\n});\n\n/**\n * Phases for `WalletRequestError`. Each maps to an HTTP status the\n * server emits (status code carried explicitly so renderers can keep\n * the mapping in one place rather than re-deriving it).\n *\n * - `origin-missing` : 403 — no Origin header on a protected\n * route (closes the curl/non-browser\n * bypass; mandatory by C12).\n * - `origin-forbidden` : 403 — Origin not in the stack-scoped\n * allowlist.\n * - `unauthorized` : 401 — bearer absent or did not survive\n * constant-time compare.\n * - `route-not-found` : 404 — `/api/v1/devstack/*` path with no\n * handler wired.\n * - `address-not-found` : 404 — sign request named an address the\n * wallet did not bind.\n * - `body-invalid` : 400 — JSON parse, missing required\n * field, non-base64 bytes, body >64 KiB.\n * - `sign-route-failed` : 500 — the routed `AccountValue` sign\n * closure raised an `AccountSignError`.\n */\nexport type WalletRequestPhase =\n\t| 'origin-missing'\n\t| 'origin-forbidden'\n\t| 'unauthorized'\n\t| 'route-not-found'\n\t| 'address-not-found'\n\t| 'body-invalid'\n\t| 'sign-route-failed';\n\n/** Request-time wallet error — raised by the in-process HTTP handlers.\n * Carries the HTTP status the server will write and an optional inner\n * cause (e.g. an `AccountSignError` for `sign-route-failed`). */\nexport interface WalletRequestError {\n\treadonly _tag: 'WalletRequestError';\n\treadonly phase: WalletRequestPhase;\n\treadonly httpStatus: number;\n\treadonly message: string;\n\treadonly cause?: unknown;\n}\n\nexport const walletRequestError = (\n\tparts: Omit<WalletRequestError, '_tag'>,\n): WalletRequestError => ({ _tag: 'WalletRequestError', ...parts });\n\n/** Union of every error a wallet caller may encounter. */\nexport type WalletError = WalletBootError | WalletRequestError;\n\n/** The catchable error tags this plugin exposes. Pinned against the\n * user-facing error catalog by the error-catalog-parity test. */\nexport const WALLET_ERROR_TAGS: ReadonlyArray<WalletError['_tag']> = [\n\t'WalletBootError',\n\t'WalletRequestError',\n] as const;\n"],"mappings":";AAoDA,MAAa,mBAAmB,WAA2D;CAC1F,MAAM;CACN,GAAG;AACJ;AA2CA,MAAa,sBACZ,WACyB;CAAE,MAAM;CAAsB,GAAG;AAAM"}
@@ -1,11 +1,8 @@
1
1
  import { WALLET_AUTH_HEADER, WALLET_BEARER_PREFIX, WALLET_ENDPOINT_KEY, WALLET_ENDPOINT_NAME, WALLET_PROTOCOL_PREFIX, WALLET_TOKEN_FRAGMENT_KEY, WALLET_TOKEN_HEX_LENGTH, WalletHttpPath, WalletHttpPathValue } from "../../contracts/wallet-protocol.mjs";
2
- import { CodegenableDecl } from "../../contracts/codegenable.mjs";
3
- import { RoutableDecl } from "../../contracts/routable.mjs";
4
- import { SnapshotableDecl } from "../../contracts/snapshotable.mjs";
5
2
  import { Plugin, ResourceRef } from "../../substrate/plugin.mjs";
6
- import { SuiClient } from "../sui/mode/shared.mjs";
7
3
  import { SuiOptions } from "../sui/mode/spec.mjs";
8
- import { DappKitConfigBindings } from "./codegen.mjs";
4
+ import { SuiClient } from "../sui/mode/shared.mjs";
5
+ import { DevWalletConfig } from "./codegen.mjs";
9
6
  import { WalletBootError, WalletBootPhase, WalletError, WalletRequestError, WalletRequestPhase } from "./errors.mjs";
10
7
  import { PairingToken } from "./pairing.mjs";
11
8
  import { WalletServerHandle } from "./server.mjs";
@@ -55,7 +52,7 @@ declare function wallet(opts: Omit<WalletOptions, 'accounts'> & {
55
52
  declare function wallet(): ReturnType<typeof makeWalletMember<readonly []>>;
56
53
  declare function makeWalletMember<Accounts extends ReadonlyArray<WalletAccountMember>>(opts: WalletOptions, accounts: Accounts): Plugin<"wallet", WalletValue, readonly [ResourceRef<"sui", SuiClient & {
57
54
  readonly mode: SuiOptions["mode"];
58
- }>, ...Accounts], readonly [SnapshotableDecl, CodegenableDecl<"dapp-kit-config">, RoutableDecl]>;
55
+ }>, ...Accounts]>;
59
56
  //#endregion
60
57
  export { wallet };
61
58
  //# sourceMappingURL=index.d.mts.map
@@ -2,22 +2,21 @@ import { definePlugin, resource } from "../../substrate/plugin.mjs";
2
2
  import { attachPluginExpander } from "../../contracts/plugin-expander.mjs";
3
3
  import "../../api/define-plugin.mjs";
4
4
  import { IdentityContext, StackPathsService } from "../../substrate/runtime/paths.mjs";
5
+ import { PluginContext } from "../../substrate/plugin-ctx.mjs";
5
6
  import { DEFAULT_PORT_WINDOW, PortBrokerService } from "../../substrate/runtime/port-broker/service.mjs";
6
7
  import "../../substrate/runtime/port-broker/index.mjs";
7
8
  import { renderUrl, routedHostname } from "../../substrate/runtime/routed-url.mjs";
8
9
  import { HOST_SERVICE_DEFAULT_ENTRYPOINT_PORT } from "../host-service/routable.mjs";
9
10
  import "../../contracts/wallet-protocol.mjs";
10
11
  import { WALLET_ENTRYPOINT_PORT, makeWalletRoutable } from "./routable.mjs";
11
- import { pluginErrorContributions } from "../../api/plugin-errors.mjs";
12
12
  import { suiResource } from "../sui/index.mjs";
13
13
  import "../host-service/index.mjs";
14
- import { WALLET_ERROR_TAGS, walletBootError } from "./errors.mjs";
15
- import "./spans.mjs";
16
- import "./protocol.mjs";
17
- import "./pairing.mjs";
18
14
  import { makeWalletCodegen } from "./codegen.mjs";
15
+ import { walletBootError } from "./errors.mjs";
19
16
  import { makeWalletSnapshotable } from "./snapshot.mjs";
20
17
  import "./origin-policy.mjs";
18
+ import "./protocol.mjs";
19
+ import "./pairing.mjs";
21
20
  import "./server.mjs";
22
21
  import { acquireWallet } from "./service.mjs";
23
22
  import { Effect } from "effect";
@@ -45,7 +44,6 @@ const isAccountResourceMember = (member) => member.id.startsWith(ACCOUNT_RESOURC
45
44
  /** The wallet plugin's resource identity. ONE per stack (15-wallet.md
46
45
  * "singleton per stack"). The id is `'wallet'` (singular). */
47
46
  const walletResource = resource("wallet");
48
- const walletErrorContributions = pluginErrorContributions(WALLET_ERROR_TAGS);
49
47
  function wallet(opts) {
50
48
  const resolvedOpts = opts ?? { accounts: "all" };
51
49
  if (resolvedOpts.accounts === "all") {
@@ -74,6 +72,7 @@ function makeWalletMember(opts, accounts) {
74
72
  role: "service",
75
73
  section: "service",
76
74
  start: (deps) => Effect.gen(function* () {
75
+ const ctx = yield* PluginContext;
77
76
  const identity = yield* IdentityContext;
78
77
  const paths = yield* StackPathsService;
79
78
  const portBroker = yield* PortBrokerService;
@@ -96,10 +95,10 @@ function makeWalletMember(opts, accounts) {
96
95
  message: `wallet app-origin URL construction failed: ${err.detail}`,
97
96
  cause: err
98
97
  })));
99
- return yield* acquireWallet(resolvedOpts, {
98
+ const resolved = yield* acquireWallet(resolvedOpts, {
100
99
  app: identity.app,
101
100
  stack: identity.stack,
102
- chain: identity.chain,
101
+ network: identity.network,
103
102
  stateRoot: paths.stackRoot,
104
103
  allocatePort: (preferred, probeHost) => portBroker.allocate({
105
104
  owner: "wallet",
@@ -116,19 +115,15 @@ function makeWalletMember(opts, accounts) {
116
115
  routerFrontedUrl,
117
116
  routedAppOrigin
118
117
  });
119
- }),
120
- errorContributions: walletErrorContributions,
121
- capabilities: ({ value: resolved, runtime: acquireCtx }) => {
122
- return [
123
- makeWalletSnapshotable(),
124
- makeWalletCodegen(resolved.bindings),
125
- makeWalletRoutable({
126
- app: acquireCtx.identity.app,
127
- stack: acquireCtx.identity.stack,
128
- port: resolved.localPort
129
- })
130
- ];
131
- }
118
+ ctx.snapshotExtra(makeWalletSnapshotable());
119
+ ctx.codegen(makeWalletCodegen(resolved.bindings));
120
+ ctx.endpoint(makeWalletRoutable({
121
+ app: identity.app,
122
+ stack: identity.stack,
123
+ port: resolved.localPort
124
+ }));
125
+ return resolved;
126
+ })
132
127
  });
133
128
  }
134
129
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/wallet/index.ts"],"sourcesContent":["// Wallet plugin — barrel + `wallet(opts?)` factory.\n//\n// Architecture (15-wallet.md):\n//\n// The wallet bridges devstack (the supervisor host) and the\n// browser-side dev-wallet adapter (in the separate `dev-wallet`\n// package). Two parts:\n//\n// 1. The IN-PROCESS HTTP server. Owned here. Boot at acquire,\n// serve `/api/v1/devstack/*` routes (health, accounts,\n// sign-transaction, sign-personal-message).\n//\n// 2. The BROWSER-SIDE ADAPTER. Owned by `dev-wallet`. Reads the\n// codegen-emitted `dapp-kit/config.ts`, constructs a\n// `DevstackSignerAdapter`, registers it with `@mysten/dapp-\n// kit`'s wallet-standard surface.\n//\n// The HTTP protocol is the ONE cross-boundary contract. THIS PACKAGE\n// NEVER IMPORTS `@mysten/dapp-kit*` OR `@mysten/wallet-standard`.\n//\n// Capabilities emitted:\n//\n// 1. Snapshotable — pairing token under `wallet/token`.\n// 2. Codegenable — `dapp-kit-config` bindings (the dev-wallet\n// adapter consumes this). Sensitive flag set — 0o600 + gitignore.\n// 3. Routable — wallet UI URL on the stack-scoped router.\n\nimport { Effect } from 'effect';\n\nimport { definePlugin, resource } from '../../api/define-plugin.ts';\nimport { pluginErrorContributions } from '../../api/plugin-errors.ts';\nimport { attachPluginExpander } from '../../contracts/plugin-expander.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport {\n\tDEFAULT_PORT_WINDOW,\n\tPortBrokerService,\n} from '../../substrate/runtime/port-broker/index.ts';\nimport { renderUrl, routedHostname } from '../../substrate/runtime/routed-url.ts';\nimport { suiResource } from '../sui/index.ts';\nimport type { AccountResourceId } from '../account/index.ts';\nimport {\n\tHOST_SERVICE_DEFAULT_ENDPOINT_NAME,\n\tHOST_SERVICE_DEFAULT_ENTRYPOINT_PORT,\n} from '../host-service/index.ts';\n\nimport { makeWalletCodegen } from './codegen.ts';\nimport { WALLET_ERROR_TAGS, walletBootError } from './errors.ts';\nimport { makeWalletRoutable, WALLET_ENTRYPOINT_PORT, WALLET_ROUTE_ROLE } from './routable.ts';\nimport { makeWalletSnapshotable } from './snapshot.ts';\nimport {\n\tacquireWallet,\n\tWALLET_ACCOUNTS_ALL,\n\ttype WalletAcquireContext,\n\ttype WalletAccountMember,\n\ttype WalletOptions,\n\ttype WalletValue,\n} from './service.ts';\nimport type { AnyPlugin } from '../../substrate/plugin.ts';\n\n/** Wallet's expander contributes through the substrate-owned\n * `PluginExpander` contract (`contracts/plugin-expander.ts`). The\n * composer dispatches every member's expander uniformly — wallet has\n * no special-case wiring in `api/define-devstack.ts`.\n *\n * Compose-time symmetry: any plugin needing the \"rewrite this\n * placeholder once the full member tuple is known\" rewrite uses the\n * same `attachPluginExpander(...)` seam wallet uses below. */\n\nconst ACCOUNT_RESOURCE_ID_PREFIX = 'account/' as const;\n\n/** Type-narrowing predicate on a plugin's resource id. The account\n * plugin's `AccountResourceId<Name>` template-literal type IS the\n * substrate-owned discriminator (12-account.md \"resource id flows into\n * the on-disk path, the manifest key, container labels, and generated\n * TypeScript exports\") — every account member's `id` reduces to\n * `account/${Name}`. Probing through this typed predicate (vs. a bare\n * `startsWith` whose narrowing returns `string`) prevents misclassifying\n * a future plugin whose id happens to start with `account/` but is NOT\n * the account-plugin shape, AND surfaces a compile error if the\n * account-id prefix convention ever changes. */\nconst isAccountResourceMember = (\n\tmember: AnyPlugin,\n): member is AnyPlugin & { readonly id: AccountResourceId<string> } =>\n\tmember.id.startsWith(ACCOUNT_RESOURCE_ID_PREFIX);\n\n// ----------------------------------------------------------------------\n// Resource identity\n// ----------------------------------------------------------------------\n\n/** The wallet plugin's resource identity. ONE per stack (15-wallet.md\n * \"singleton per stack\"). The id is `'wallet'` (singular). */\nconst walletResource = resource<'wallet', WalletValue>('wallet');\nconst walletErrorContributions = pluginErrorContributions(WALLET_ERROR_TAGS);\n\n// ----------------------------------------------------------------------\n// User-facing factory\n// ----------------------------------------------------------------------\n\n/**\n * Construct the wallet plugin.\n *\n * Two parts of the wallet:\n *\n * - HERE: HTTP server + token + pairing protocol + codegen.\n * - DEV-WALLET PACKAGE: `@mysten/dapp-kit`-shaped adapter the\n * user-app's frontend bundle imports.\n *\n * Distilled-doc invariant (15-wallet.md \"Always explicit\"): the\n * composer NEVER auto-mounts the wallet. The user calls `wallet()`,\n * `wallet({ accounts: 'all' })`, or `wallet({ accounts: [alice, bob] })`\n * and passes the result to `defineDevstack(...)`.\n *\n * ### Security defaults\n *\n * - `bindAddress: '0.0.0.0'`. The router runs in Docker, so on\n * native Linux it reaches this host process through the Docker\n * host-gateway address instead of host loopback. The published\n * wallet URL remains stack-scoped through the router.\n *\n * - Origin allowlist is the router-fronted dev-server origin for\n * this stack plus any explicit `allowedOrigins`. The wallet does\n * not auto-allowlist a bare `http://localhost:<vite-port>` form —\n * `localhost` is not stack-scoped, so a sibling stack on the same\n * port could pair with this wallet. See `origin-policy.ts`.\n *\n * - Pairing token in URL fragment only (`#token=<32-hex>`). Never\n * in query params (would land in access logs / referrers).\n *\n * - Constant-time bearer compare on every request.\n *\n * - Token file `0o600`. Codegen output (`dapp-kit/config.ts`)\n * `0o600` + gitignored via `sensitive: true`.\n */\nexport function wallet<const Accounts extends ReadonlyArray<WalletAccountMember>>(\n\topts: Omit<WalletOptions, 'accounts'> & { readonly accounts: Accounts },\n): ReturnType<typeof makeWalletMember<Accounts>>;\nexport function wallet(\n\topts: Omit<WalletOptions, 'accounts'> & { readonly accounts: typeof WALLET_ACCOUNTS_ALL },\n): ReturnType<typeof makeWalletMember<readonly []>>;\nexport function wallet(): ReturnType<typeof makeWalletMember<readonly []>>;\nexport function wallet(opts?: WalletOptions): AnyPlugin {\n\tconst resolvedOpts: WalletOptions =\n\t\topts ?? ({ accounts: WALLET_ACCOUNTS_ALL } satisfies WalletOptions);\n\tif (resolvedOpts.accounts === WALLET_ACCOUNTS_ALL) {\n\t\t// Deferred placeholder. `dependsOn` carries only `[suiResource]` —\n\t\t// the composer rewrites the member once it knows which account\n\t\t// members are in the stack (api-surface-design §4 D6). Without\n\t\t// composer expansion, the wallet would race account funding;\n\t\t// WITH composer expansion, every per-account dependency edge is\n\t\t// in place by the time the dep-graph builds.\n\t\t//\n\t\t// Type-level: the placeholder's `dependsOn` is `[suiResource]`. A\n\t\t// wider `ReadonlyArray<account/${string}>` would widen the\n\t\t// stack-level `MissingProviders` check to the template literal\n\t\t// (which never reduces to any concrete `account/<name>`), so\n\t\t// the placeholder MUST stay narrow.\n\t\t//\n\t\t// Runtime: the symbol-keyed expander is attached as a value-\n\t\t// only property; the factory's declared return type\n\t\t// intentionally does NOT surface it (a `unique symbol`-keyed\n\t\t// member field would leak into the user's inferred Stack type\n\t\t// and trigger TS2742 \"type cannot be named without a reference\n\t\t// to ./node_modules/.../plugins/wallet\" at every example's\n\t\t// default export).\n\t\tconst placeholder = makeWalletMember(resolvedOpts, [] as const);\n\t\tattachPluginExpander(placeholder, (members) => {\n\t\t\t// Filter the full composed member tuple to the per-account\n\t\t\t// resource members the wallet would otherwise have to receive\n\t\t\t// at factory call. `isAccountResourceMember` narrows on the\n\t\t\t// `AccountResourceId<Name>` template-literal type — the typed\n\t\t\t// discriminator the account plugin's barrel exposes via\n\t\t\t// `AccountResourceId<Name>` — so a future plugin whose id\n\t\t\t// accidentally starts with `account/` cannot masquerade.\n\t\t\tconst accountMembers: Array<WalletAccountMember> = [];\n\t\t\tfor (const m of members) {\n\t\t\t\tif (isAccountResourceMember(m)) {\n\t\t\t\t\taccountMembers.push(m as unknown as WalletAccountMember);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn makeWalletMember({ ...resolvedOpts, accounts: accountMembers }, accountMembers);\n\t\t});\n\t\treturn placeholder;\n\t}\n\treturn makeWalletMember(resolvedOpts, resolvedOpts.accounts);\n}\n\nfunction makeWalletMember<Accounts extends ReadonlyArray<WalletAccountMember>>(\n\topts: WalletOptions,\n\taccounts: Accounts,\n) {\n\t// Dependencies MUST include every account ref (15-wallet.md\n\t// \"upstreamKeys MUST include suiResource.id + every account id\" — same\n\t// load-bearing invariant). The substrate's topological scheduler\n\t// uses `dependsOn` to drive build order; without including the\n\t// account refs here, the wallet would race account funding and the\n\t// first `signTransaction` would fail with `address-not-found`.\n\t//\n\tconst dependencies = [suiResource, ...accounts] as const;\n\n\t// The resolved-opts shape acquireWallet sees has accounts pinned to\n\t// the resolved tuple — `'all'` is purely a user-surface convenience\n\t// the composer never propagates to the supervisor.\n\tconst resolvedOpts: WalletOptions<Accounts> = { ...opts, accounts };\n\n\treturn definePlugin({\n\t\tid: walletResource.id,\n\t\tdependsOn: dependencies,\n\t\t// The HTTP server is a long-lived host process; per-request\n\t\t// handlers fork off the supervisor-context fiber but the server\n\t\t// itself lives for the stack's lifetime.\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Pull identity, the stack-paths bundle, and the port-\n\t\t\t\t// broker from the supervisor-provided substrate context.\n\t\t\t\t// `StackPathsService.stackRoot` is the on-disk root for\n\t\t\t\t// per-stack runtime artifacts (incl. `wallet/token`); the\n\t\t\t\t// port broker is per-stack (Layer-driven, one instance per\n\t\t\t\t// stack scope); the wallet's scope hangs off the\n\t\t\t\t// supervisor's `acquireScope`, so any release finalizer\n\t\t\t\t// installed by these primitives unwinds with the rest of\n\t\t\t\t// the plugin's resources on cycle / teardown.\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst paths = yield* StackPathsService;\n\t\t\t\tconst portBroker = yield* PortBrokerService;\n\n\t\t\t\t// The first dependency is the hard Sui ordering edge; the\n\t\t\t\t// remaining values mirror the explicit account tuple.\n\t\t\t\tconst [, ...resolvedAccounts] = deps;\n\t\t\t\tconst routerFrontedUrl = yield* routedHostname(identity, WALLET_ROUTE_ROLE).pipe(\n\t\t\t\t\tEffect.map((hostname) =>\n\t\t\t\t\t\trenderUrl({\n\t\t\t\t\t\t\tprotocol: 'http',\n\t\t\t\t\t\t\thostname,\n\t\t\t\t\t\t\tport: WALLET_ENTRYPOINT_PORT,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.mapError((err) =>\n\t\t\t\t\t\twalletBootError({\n\t\t\t\t\t\t\tphase: 'route-url',\n\t\t\t\t\t\t\tmessage: `wallet router URL construction failed: ${err.detail}`,\n\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tconst routedAppOrigin = yield* routedHostname(\n\t\t\t\t\tidentity,\n\t\t\t\t\tHOST_SERVICE_DEFAULT_ENDPOINT_NAME,\n\t\t\t\t).pipe(\n\t\t\t\t\tEffect.map((hostname) =>\n\t\t\t\t\t\trenderUrl({\n\t\t\t\t\t\t\tprotocol: 'http',\n\t\t\t\t\t\t\thostname,\n\t\t\t\t\t\t\tport: HOST_SERVICE_DEFAULT_ENTRYPOINT_PORT,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.mapError((err) =>\n\t\t\t\t\t\twalletBootError({\n\t\t\t\t\t\t\tphase: 'route-url',\n\t\t\t\t\t\t\tmessage: `wallet app-origin URL construction failed: ${err.detail}`,\n\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst acquireCtx: WalletAcquireContext = {\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tchain: identity.chain,\n\t\t\t\t\tstateRoot: paths.stackRoot,\n\t\t\t\t\tallocatePort: (preferred, probeHost) =>\n\t\t\t\t\t\tportBroker\n\t\t\t\t\t\t\t.allocate({\n\t\t\t\t\t\t\t\towner: 'wallet',\n\t\t\t\t\t\t\t\t// Pin the wallet's UX-meaningful range so the dev wallet\n\t\t\t\t\t\t\t\t// adapter's auto-connect-port heuristic keeps working even\n\t\t\t\t\t\t\t\t// after a fallback scan. The broker scan window is half-open\n\t\t\t\t\t\t\t\t// `[start, start + size)`, so `DEFAULT_PORT_WINDOW`\n\t\t\t\t\t\t\t\t// (start 39200, size 1000) covers 39200..40199 inclusive.\n\t\t\t\t\t\t\t\t// Reuse the broker's exported default rather than a local\n\t\t\t\t\t\t\t\t// literal so the two cannot silently drift (pinned by\n\t\t\t\t\t\t\t\t// `test/plugins/wallet/port-window-pin.test.ts`).\n\t\t\t\t\t\t\t\twindowHint: DEFAULT_PORT_WINDOW,\n\t\t\t\t\t\t\t\tpreferredPort: preferred,\n\t\t\t\t\t\t\t\t...(probeHost === undefined ? {} : { probeHost }),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\tEffect.map((alloc) => alloc.port),\n\t\t\t\t\t\t\t\tEffect.mapError((err) =>\n\t\t\t\t\t\t\t\t\twalletBootError({\n\t\t\t\t\t\t\t\t\t\tphase: 'allocate-port',\n\t\t\t\t\t\t\t\t\t\tmessage: `port-broker allocate failed: ${err.detail}`,\n\t\t\t\t\t\t\t\t\t\thint:\n\t\t\t\t\t\t\t\t\t\t\terr.reason === 'preferred-busy'\n\t\t\t\t\t\t\t\t\t\t\t\t? 'another plugin in this stack is using your preferred port; omit `port` to let the broker pick.'\n\t\t\t\t\t\t\t\t\t\t\t\t: err.reason === 'no-free-port'\n\t\t\t\t\t\t\t\t\t\t\t\t\t? 'the wallet port window is exhausted; check for stray devstack supervisors holding ports.'\n\t\t\t\t\t\t\t\t\t\t\t\t\t: 'bind-probe failed — likely a privileged port or jail restriction.',\n\t\t\t\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\tresolveAccounts: () => Effect.succeed(resolvedAccounts),\n\t\t\t\t\trouterFrontedUrl,\n\t\t\t\t\troutedAppOrigin,\n\t\t\t\t};\n\n\t\t\t\treturn yield* acquireWallet(resolvedOpts, acquireCtx);\n\t\t\t}),\n\t\terrorContributions: walletErrorContributions,\n\t\t// Dynamic capability factory — receives the resolved\n\t\t// `WalletValue` + acquire context. Stamps the real dapp-kit\n\t\t// bindings (walletUrl, pairUrl, chain id, paths) into the\n\t\t// codegen decl, and the real identity app/stack into the\n\t\t// routable decl.\n\t\tcapabilities: ({ value: resolved, runtime: acquireCtx }) => {\n\t\t\tconst snapshot = makeWalletSnapshotable();\n\t\t\tconst codegen = makeWalletCodegen(resolved.bindings);\n\t\t\tconst routable = makeWalletRoutable({\n\t\t\t\tapp: acquireCtx.identity.app,\n\t\t\t\tstack: acquireCtx.identity.stack,\n\t\t\t\tport: resolved.localPort,\n\t\t\t});\n\t\t\treturn [snapshot, codegen, routable] as const;\n\t\t},\n\t});\n}\n\n// ----------------------------------------------------------------------\n// Re-exports\n// ----------------------------------------------------------------------\n\nexport type {\n\tWalletOptions,\n\tWalletValue,\n\tWalletAccountMember,\n\tWalletAccountsAll,\n} from './service.ts';\nexport { WALLET_ACCOUNTS_ALL } from './service.ts';\nexport type { DappKitConfigBindings } from './codegen.ts';\nexport {\n\tWalletHttpPath,\n\tWALLET_PROTOCOL_PREFIX,\n\tWALLET_AUTH_HEADER,\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n\tSignRequestSchema,\n\tSignResponseSchema,\n\tHealthResponseSchema,\n\tAccountsResponseSchema,\n\tAccountSummarySchema,\n\tErrorResponseSchema,\n\tSuiAddressSchema,\n\tBase64Schema,\n\tSignatureSchemeSchema,\n\tAccountSourceSchema,\n\ttype WalletHttpPathValue,\n\ttype SignRequest,\n\ttype SignResponse,\n\ttype HealthResponse,\n\ttype AccountsResponse,\n\ttype AccountSummary,\n\ttype ErrorResponse,\n} from './protocol.ts';\nexport type {\n\tWalletError,\n\tWalletBootError,\n\tWalletBootPhase,\n\tWalletRequestError,\n\tWalletRequestPhase,\n} from './errors.ts';\nexport { WALLET_ERROR_TAGS } from './errors.ts';\nexport type { OriginPolicy, OriginPolicyInputs, OriginCheckResult } from './origin-policy.ts';\nexport { resolveOriginPolicy, checkOrigin, corsHeadersFor } from './origin-policy.ts';\nexport type { PairingToken } from './pairing.ts';\nexport {\n\tmintToken,\n\tacquirePairingToken,\n\ttokenPath,\n\tcomposePairUrl,\n\tparsePairUrl,\n\tparseBearerHeader,\n\tsafeBearerEquals,\n\tredactToken,\n} from './pairing.ts';\nexport { WALLET_ENDPOINT_NAME, WALLET_ENDPOINT_KEY, makeWalletRoutable } from './routable.ts';\nexport { WalletSpans } from './spans.ts';\nexport {\n\tdispatch,\n\tstartHttpServer,\n\tMAX_BODY_BYTES,\n\ttype WalletRequest,\n\ttype WalletResponse,\n\ttype WalletServerConfig,\n\ttype WalletServerHandle,\n} from './server.ts';\nexport { makeWalletCodegen } from './codegen.ts';\nexport { makeWalletSnapshotable } from './snapshot.ts';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,MAAM,6BAA6B;;;;;;;;;;;AAYnC,MAAM,2BACL,WAEA,OAAO,GAAG,WAAW,2BAA2B;;;AAQjD,MAAM,iBAAiB,SAAgC,SAAS;AAChE,MAAM,2BAA2B,yBAAyB,kBAAkB;AAgD5E,SAAgB,OAAO,MAAiC;CACvD,MAAM,eACL,QAAS,EAAE,UAAA,OAA+B;AAC3C,KAAI,aAAa,aAAA,OAAkC;EAqBlD,MAAM,cAAc,iBAAiB,cAAc,EAAE,CAAU;AAC/D,uBAAqB,cAAc,YAAY;GAQ9C,MAAM,iBAA6C,EAAE;AACrD,QAAK,MAAM,KAAK,QACf,KAAI,wBAAwB,EAAE,CAC7B,gBAAe,KAAK,EAAoC;AAG1D,UAAO,iBAAiB;IAAE,GAAG;IAAc,UAAU;IAAgB,EAAE,eAAe;IACrF;AACF,SAAO;;AAER,QAAO,iBAAiB,cAAc,aAAa,SAAS;;AAG7D,SAAS,iBACR,MACA,UACC;CAQD,MAAM,eAAe,CAAC,aAAa,GAAG,SAAS;CAK/C,MAAM,eAAwC;EAAE,GAAG;EAAM;EAAU;AAEnE,QAAO,aAAa;EACnB,IAAI,eAAe;EACnB,WAAW;EAIX,MAAM;EACN,SAAS;EACT,QAAQ,SACP,OAAO,IAAI,aAAa;GAUvB,MAAM,WAAW,OAAO;GACxB,MAAM,QAAQ,OAAO;GACrB,MAAM,aAAa,OAAO;GAI1B,MAAM,GAAG,GAAG,oBAAoB;GAChC,MAAM,mBAAmB,OAAO,eAAe,UAAA,MAA4B,CAAC,KAC3E,OAAO,KAAK,aACX,UAAU;IACT,UAAU;IACV;IACA,MAAM;IACN,CAAC,CACF,EACD,OAAO,UAAU,QAChB,gBAAgB;IACf,OAAO;IACP,SAAS,0CAA0C,IAAI;IACvD,OAAO;IACP,CAAC,CACF,CACD;GACD,MAAM,kBAAkB,OAAO,eAC9B,UAAA,MAEA,CAAC,KACD,OAAO,KAAK,aACX,UAAU;IACT,UAAU;IACV;IACA,MAAM;IACN,CAAC,CACF,EACD,OAAO,UAAU,QAChB,gBAAgB;IACf,OAAO;IACP,SAAS,8CAA8C,IAAI;IAC3D,OAAO;IACP,CAAC,CACF,CACD;AA4CD,UAAO,OAAO,cAAc,cAAc;IAzCzC,KAAK,SAAS;IACd,OAAO,SAAS;IAChB,OAAO,SAAS;IAChB,WAAW,MAAM;IACjB,eAAe,WAAW,cACzB,WACE,SAAS;KACT,OAAO;KASP,YAAY;KACZ,eAAe;KACf,GAAI,cAAc,KAAA,IAAY,EAAE,GAAG,EAAE,WAAW;KAChD,CAAC,CACD,KACA,OAAO,KAAK,UAAU,MAAM,KAAK,EACjC,OAAO,UAAU,QAChB,gBAAgB;KACf,OAAO;KACP,SAAS,gCAAgC,IAAI;KAC7C,MACC,IAAI,WAAW,mBACZ,mGACA,IAAI,WAAW,iBACd,6FACA;KACL,OAAO;KACP,CAAC,CACF,CACD;IACH,uBAAuB,OAAO,QAAQ,iBAAiB;IACvD;IACA;IAGmD,CAAC;IACpD;EACH,oBAAoB;EAMpB,eAAe,EAAE,OAAO,UAAU,SAAS,iBAAiB;AAQ3D,UAAO;IAPU,wBAOD;IANA,kBAAkB,SAAS,SAMlB;IALR,mBAAmB;KACnC,KAAK,WAAW,SAAS;KACzB,OAAO,WAAW,SAAS;KAC3B,MAAM,SAAS;KACf,CACkC;IAAC;;EAErC,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/wallet/index.ts"],"sourcesContent":["// Wallet plugin — barrel + `wallet(opts?)` factory.\n//\n// Architecture (15-wallet.md):\n//\n// The wallet bridges devstack (the supervisor host) and the\n// browser-side dev-wallet adapter (in the separate `dev-wallet`\n// package). Two parts:\n//\n// 1. The IN-PROCESS HTTP server. Owned here. Boot at acquire,\n// serve `/api/v1/devstack/*` routes (health, accounts,\n// sign-transaction, sign-personal-message).\n//\n// 2. The BROWSER-SIDE ADAPTER. Owned by `dev-wallet`. Reads the\n// codegen-emitted `dapp-kit/config.ts`, constructs a\n// `DevstackSignerAdapter`, registers it with `@mysten/dapp-\n// kit`'s wallet-standard surface.\n//\n// The HTTP protocol is the ONE cross-boundary contract. THIS PACKAGE\n// NEVER IMPORTS `@mysten/dapp-kit*` OR `@mysten/wallet-standard`.\n//\n// During `start`, the plugin emits (via the typed `ctx.*` verbs):\n//\n// 1. `ctx.snapshotExtra` — pairing token under `wallet/token`.\n// 2. `ctx.codegen` — `dapp-kit-config` bindings (the dev-wallet\n// adapter consumes this). Sensitive flag set — 0o600 + gitignore.\n// 3. `ctx.endpoint` — wallet UI URL on the stack-scoped router.\n\nimport { Effect } from 'effect';\n\nimport { definePlugin, resource } from '../../api/define-plugin.ts';\nimport { attachPluginExpander } from '../../contracts/plugin-expander.ts';\nimport { IdentityContext, StackPathsService } from '../../substrate/runtime/paths.ts';\nimport {\n\tDEFAULT_PORT_WINDOW,\n\tPortBrokerService,\n} from '../../substrate/runtime/port-broker/index.ts';\nimport { renderUrl, routedHostname } from '../../substrate/runtime/routed-url.ts';\nimport { suiResource } from '../sui/index.ts';\nimport type { AccountResourceId } from '../account/index.ts';\nimport {\n\tHOST_SERVICE_DEFAULT_ENDPOINT_NAME,\n\tHOST_SERVICE_DEFAULT_ENTRYPOINT_PORT,\n} from '../host-service/index.ts';\n\nimport { makeWalletCodegen } from './codegen.ts';\nimport { walletBootError } from './errors.ts';\nimport { makeWalletRoutable, WALLET_ENTRYPOINT_PORT, WALLET_ROUTE_ROLE } from './routable.ts';\nimport { makeWalletSnapshotable } from './snapshot.ts';\nimport {\n\tacquireWallet,\n\tWALLET_ACCOUNTS_ALL,\n\ttype WalletAcquireContext,\n\ttype WalletAccountMember,\n\ttype WalletOptions,\n\ttype WalletValue,\n} from './service.ts';\nimport type { AnyPlugin } from '../../substrate/plugin.ts';\nimport { PluginContext } from '../../substrate/plugin-ctx.ts';\n\n/** Wallet's expander contributes through the substrate-owned\n * `PluginExpander` contract (`contracts/plugin-expander.ts`). The\n * composer dispatches every member's expander uniformly — wallet has\n * no special-case wiring in `api/define-devstack.ts`.\n *\n * Compose-time symmetry: any plugin needing the \"rewrite this\n * placeholder once the full member tuple is known\" rewrite uses the\n * same `attachPluginExpander(...)` seam wallet uses below. */\n\nconst ACCOUNT_RESOURCE_ID_PREFIX = 'account/' as const;\n\n/** Type-narrowing predicate on a plugin's resource id. The account\n * plugin's `AccountResourceId<Name>` template-literal type IS the\n * substrate-owned discriminator (12-account.md \"resource id flows into\n * the on-disk path, the manifest key, container labels, and generated\n * TypeScript exports\") — every account member's `id` reduces to\n * `account/${Name}`. Probing through this typed predicate (vs. a bare\n * `startsWith` whose narrowing returns `string`) prevents misclassifying\n * a future plugin whose id happens to start with `account/` but is NOT\n * the account-plugin shape, AND surfaces a compile error if the\n * account-id prefix convention ever changes. */\nconst isAccountResourceMember = (\n\tmember: AnyPlugin,\n): member is AnyPlugin & { readonly id: AccountResourceId<string> } =>\n\tmember.id.startsWith(ACCOUNT_RESOURCE_ID_PREFIX);\n\n// ----------------------------------------------------------------------\n// Resource identity\n// ----------------------------------------------------------------------\n\n/** The wallet plugin's resource identity. ONE per stack (15-wallet.md\n * \"singleton per stack\"). The id is `'wallet'` (singular). */\nconst walletResource = resource<'wallet', WalletValue>('wallet');\n\n// ----------------------------------------------------------------------\n// User-facing factory\n// ----------------------------------------------------------------------\n\n/**\n * Construct the wallet plugin.\n *\n * Two parts of the wallet:\n *\n * - HERE: HTTP server + token + pairing protocol + codegen.\n * - DEV-WALLET PACKAGE: `@mysten/dapp-kit`-shaped adapter the\n * user-app's frontend bundle imports.\n *\n * Distilled-doc invariant (15-wallet.md \"Always explicit\"): the\n * composer NEVER auto-mounts the wallet. The user calls `wallet()`,\n * `wallet({ accounts: 'all' })`, or `wallet({ accounts: [alice, bob] })`\n * and passes the result to `defineDevstack(...)`.\n *\n * ### Security defaults\n *\n * - `bindAddress: '0.0.0.0'`. The router runs in Docker, so on\n * native Linux it reaches this host process through the Docker\n * host-gateway address instead of host loopback. The published\n * wallet URL remains stack-scoped through the router.\n *\n * - Origin allowlist is the router-fronted dev-server origin for\n * this stack plus any explicit `allowedOrigins`. The wallet does\n * not auto-allowlist a bare `http://localhost:<vite-port>` form —\n * `localhost` is not stack-scoped, so a sibling stack on the same\n * port could pair with this wallet. See `origin-policy.ts`.\n *\n * - Pairing token in URL fragment only (`#token=<32-hex>`). Never\n * in query params (would land in access logs / referrers).\n *\n * - Constant-time bearer compare on every request.\n *\n * - Token file `0o600`. Codegen output (`dapp-kit/config.ts`)\n * `0o600` + gitignored via `sensitive: true`.\n */\nexport function wallet<const Accounts extends ReadonlyArray<WalletAccountMember>>(\n\topts: Omit<WalletOptions, 'accounts'> & { readonly accounts: Accounts },\n): ReturnType<typeof makeWalletMember<Accounts>>;\nexport function wallet(\n\topts: Omit<WalletOptions, 'accounts'> & { readonly accounts: typeof WALLET_ACCOUNTS_ALL },\n): ReturnType<typeof makeWalletMember<readonly []>>;\nexport function wallet(): ReturnType<typeof makeWalletMember<readonly []>>;\nexport function wallet(opts?: WalletOptions): AnyPlugin {\n\tconst resolvedOpts: WalletOptions =\n\t\topts ?? ({ accounts: WALLET_ACCOUNTS_ALL } satisfies WalletOptions);\n\tif (resolvedOpts.accounts === WALLET_ACCOUNTS_ALL) {\n\t\t// Deferred placeholder. `dependsOn` carries only `[suiResource]` —\n\t\t// the composer rewrites the member once it knows which account\n\t\t// members are in the stack (api-surface-design §4 D6). Without\n\t\t// composer expansion, the wallet would race account funding;\n\t\t// WITH composer expansion, every per-account dependency edge is\n\t\t// in place by the time the dep-graph builds.\n\t\t//\n\t\t// Type-level: the placeholder's `dependsOn` is `[suiResource]`. A\n\t\t// wider `ReadonlyArray<account/${string}>` would widen the\n\t\t// stack-level `MissingProviders` check to the template literal\n\t\t// (which never reduces to any concrete `account/<name>`), so\n\t\t// the placeholder MUST stay narrow.\n\t\t//\n\t\t// Runtime: the symbol-keyed expander is attached as a value-\n\t\t// only property; the factory's declared return type\n\t\t// intentionally does NOT surface it (a `unique symbol`-keyed\n\t\t// member field would leak into the user's inferred Stack type\n\t\t// and trigger TS2742 \"type cannot be named without a reference\n\t\t// to ./node_modules/.../plugins/wallet\" at every example's\n\t\t// default export).\n\t\tconst placeholder = makeWalletMember(resolvedOpts, [] as const);\n\t\tattachPluginExpander(placeholder, (members) => {\n\t\t\t// Filter the full composed member tuple to the per-account\n\t\t\t// resource members the wallet would otherwise have to receive\n\t\t\t// at factory call. `isAccountResourceMember` narrows on the\n\t\t\t// `AccountResourceId<Name>` template-literal type — the typed\n\t\t\t// discriminator the account plugin's barrel exposes via\n\t\t\t// `AccountResourceId<Name>` — so a future plugin whose id\n\t\t\t// accidentally starts with `account/` cannot masquerade.\n\t\t\tconst accountMembers: Array<WalletAccountMember> = [];\n\t\t\tfor (const m of members) {\n\t\t\t\tif (isAccountResourceMember(m)) {\n\t\t\t\t\taccountMembers.push(m as unknown as WalletAccountMember);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn makeWalletMember({ ...resolvedOpts, accounts: accountMembers }, accountMembers);\n\t\t});\n\t\treturn placeholder;\n\t}\n\treturn makeWalletMember(resolvedOpts, resolvedOpts.accounts);\n}\n\nfunction makeWalletMember<Accounts extends ReadonlyArray<WalletAccountMember>>(\n\topts: WalletOptions,\n\taccounts: Accounts,\n) {\n\t// Dependencies MUST include every account ref (15-wallet.md\n\t// \"upstreamKeys MUST include suiResource.id + every account id\" — same\n\t// load-bearing invariant). The substrate's topological scheduler\n\t// uses `dependsOn` to drive build order; without including the\n\t// account refs here, the wallet would race account funding and the\n\t// first `signTransaction` would fail with `address-not-found`.\n\t//\n\tconst dependencies = [suiResource, ...accounts] as const;\n\n\t// The resolved-opts shape acquireWallet sees has accounts pinned to\n\t// the resolved tuple — `'all'` is purely a user-surface convenience\n\t// the composer never propagates to the supervisor.\n\tconst resolvedOpts: WalletOptions<Accounts> = { ...opts, accounts };\n\n\treturn definePlugin({\n\t\tid: walletResource.id,\n\t\tdependsOn: dependencies,\n\t\t// The HTTP server is a long-lived host process; per-request\n\t\t// handlers fork off the supervisor-context fiber but the server\n\t\t// itself lives for the stack's lifetime.\n\t\trole: 'service',\n\t\tsection: 'service',\n\t\t// `deps` auto-infers from the resolved `dependsOn`: the hard Sui\n\t\t// ordering edge (discarded) followed by the resolved account\n\t\t// values. `ctx` arrives via the `PluginContext` service.\n\t\tstart: (deps) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst ctx = yield* PluginContext;\n\t\t\t\t// Pull identity, the stack-paths bundle, and the port-\n\t\t\t\t// broker from the supervisor-provided substrate context.\n\t\t\t\t// `StackPathsService.stackRoot` is the on-disk root for\n\t\t\t\t// per-stack runtime artifacts (incl. `wallet/token`); the\n\t\t\t\t// port broker is per-stack (Layer-driven, one instance per\n\t\t\t\t// stack scope); the wallet's scope hangs off the\n\t\t\t\t// supervisor's `acquireScope`, so any release finalizer\n\t\t\t\t// installed by these primitives unwinds with the rest of\n\t\t\t\t// the plugin's resources on cycle / teardown.\n\t\t\t\tconst identity = yield* IdentityContext;\n\t\t\t\tconst paths = yield* StackPathsService;\n\t\t\t\tconst portBroker = yield* PortBrokerService;\n\n\t\t\t\t// The first dependency is the hard Sui ordering edge; the\n\t\t\t\t// remaining values mirror the explicit account tuple.\n\t\t\t\tconst [, ...resolvedAccounts] = deps;\n\t\t\t\tconst routerFrontedUrl = yield* routedHostname(identity, WALLET_ROUTE_ROLE).pipe(\n\t\t\t\t\tEffect.map((hostname) =>\n\t\t\t\t\t\trenderUrl({\n\t\t\t\t\t\t\tprotocol: 'http',\n\t\t\t\t\t\t\thostname,\n\t\t\t\t\t\t\tport: WALLET_ENTRYPOINT_PORT,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.mapError((err) =>\n\t\t\t\t\t\twalletBootError({\n\t\t\t\t\t\t\tphase: 'route-url',\n\t\t\t\t\t\t\tmessage: `wallet router URL construction failed: ${err.detail}`,\n\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tconst routedAppOrigin = yield* routedHostname(\n\t\t\t\t\tidentity,\n\t\t\t\t\tHOST_SERVICE_DEFAULT_ENDPOINT_NAME,\n\t\t\t\t).pipe(\n\t\t\t\t\tEffect.map((hostname) =>\n\t\t\t\t\t\trenderUrl({\n\t\t\t\t\t\t\tprotocol: 'http',\n\t\t\t\t\t\t\thostname,\n\t\t\t\t\t\t\tport: HOST_SERVICE_DEFAULT_ENTRYPOINT_PORT,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t\tEffect.mapError((err) =>\n\t\t\t\t\t\twalletBootError({\n\t\t\t\t\t\t\tphase: 'route-url',\n\t\t\t\t\t\t\tmessage: `wallet app-origin URL construction failed: ${err.detail}`,\n\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tconst acquireCtx: WalletAcquireContext = {\n\t\t\t\t\tapp: identity.app,\n\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\tnetwork: identity.network,\n\t\t\t\t\tstateRoot: paths.stackRoot,\n\t\t\t\t\tallocatePort: (preferred, probeHost) =>\n\t\t\t\t\t\tportBroker\n\t\t\t\t\t\t\t.allocate({\n\t\t\t\t\t\t\t\towner: 'wallet',\n\t\t\t\t\t\t\t\t// Pin the wallet's UX-meaningful range so the dev wallet\n\t\t\t\t\t\t\t\t// adapter's auto-connect-port heuristic keeps working even\n\t\t\t\t\t\t\t\t// after a fallback scan. The broker scan window is half-open\n\t\t\t\t\t\t\t\t// `[start, start + size)`, so `DEFAULT_PORT_WINDOW`\n\t\t\t\t\t\t\t\t// (start 39200, size 1000) covers 39200..40199 inclusive.\n\t\t\t\t\t\t\t\t// Reuse the broker's exported default rather than a local\n\t\t\t\t\t\t\t\t// literal so the two cannot silently drift (pinned by\n\t\t\t\t\t\t\t\t// `test/plugins/wallet/port-window-pin.test.ts`).\n\t\t\t\t\t\t\t\twindowHint: DEFAULT_PORT_WINDOW,\n\t\t\t\t\t\t\t\tpreferredPort: preferred,\n\t\t\t\t\t\t\t\t...(probeHost === undefined ? {} : { probeHost }),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\tEffect.map((alloc) => alloc.port),\n\t\t\t\t\t\t\t\tEffect.mapError((err) =>\n\t\t\t\t\t\t\t\t\twalletBootError({\n\t\t\t\t\t\t\t\t\t\tphase: 'allocate-port',\n\t\t\t\t\t\t\t\t\t\tmessage: `port-broker allocate failed: ${err.detail}`,\n\t\t\t\t\t\t\t\t\t\thint:\n\t\t\t\t\t\t\t\t\t\t\terr.reason === 'preferred-busy'\n\t\t\t\t\t\t\t\t\t\t\t\t? 'another plugin in this stack is using your preferred port; omit `port` to let the broker pick.'\n\t\t\t\t\t\t\t\t\t\t\t\t: err.reason === 'no-free-port'\n\t\t\t\t\t\t\t\t\t\t\t\t\t? 'the wallet port window is exhausted; check for stray devstack supervisors holding ports.'\n\t\t\t\t\t\t\t\t\t\t\t\t\t: 'bind-probe failed — likely a privileged port or jail restriction.',\n\t\t\t\t\t\t\t\t\t\tcause: err,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\tresolveAccounts: () => Effect.succeed(resolvedAccounts),\n\t\t\t\t\trouterFrontedUrl,\n\t\t\t\t\troutedAppOrigin,\n\t\t\t\t};\n\n\t\t\t\tconst resolved = yield* acquireWallet(resolvedOpts, acquireCtx);\n\n\t\t\t\t// Emit the wallet's contributions inline. `resolved` is the\n\t\t\t\t// just-acquired `WalletValue`; `runtime.identity.{app,stack}`\n\t\t\t\t// map to the `identity` already held here\n\t\t\t\t// (`yield* IdentityContext`). Emit each decl via its matching\n\t\t\t\t// buffered verb IN ORDER (snapshotable → `ctx.snapshotExtra`,\n\t\t\t\t// codegenable → `ctx.codegen`, routable → `ctx.endpoint`); decl\n\t\t\t\t// shapes are load-bearing. The verbs are void and buffer for the\n\t\t\t\t// supervisor's post-start replay.\n\t\t\t\tctx.snapshotExtra(makeWalletSnapshotable());\n\t\t\t\tctx.codegen(makeWalletCodegen(resolved.bindings));\n\t\t\t\tctx.endpoint(\n\t\t\t\t\tmakeWalletRoutable({\n\t\t\t\t\t\tapp: identity.app,\n\t\t\t\t\t\tstack: identity.stack,\n\t\t\t\t\t\tport: resolved.localPort,\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn resolved;\n\t\t\t}),\n\t});\n}\n\n// ----------------------------------------------------------------------\n// Re-exports\n// ----------------------------------------------------------------------\n\nexport type {\n\tWalletOptions,\n\tWalletValue,\n\tWalletAccountMember,\n\tWalletAccountsAll,\n} from './service.ts';\nexport { WALLET_ACCOUNTS_ALL } from './service.ts';\nexport type { DevWalletConfig } from './codegen.ts';\nexport {\n\tWalletHttpPath,\n\tWALLET_PROTOCOL_PREFIX,\n\tWALLET_AUTH_HEADER,\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n\tSignRequestSchema,\n\tSignResponseSchema,\n\tHealthResponseSchema,\n\tAccountsResponseSchema,\n\tAccountSummarySchema,\n\tErrorResponseSchema,\n\tSuiAddressSchema,\n\tBase64Schema,\n\tSignatureSchemeSchema,\n\tAccountSourceSchema,\n\ttype WalletHttpPathValue,\n\ttype SignRequest,\n\ttype SignResponse,\n\ttype HealthResponse,\n\ttype AccountsResponse,\n\ttype AccountSummary,\n\ttype ErrorResponse,\n} from './protocol.ts';\nexport type {\n\tWalletError,\n\tWalletBootError,\n\tWalletBootPhase,\n\tWalletRequestError,\n\tWalletRequestPhase,\n} from './errors.ts';\nexport type { OriginPolicy, OriginPolicyInputs, OriginCheckResult } from './origin-policy.ts';\nexport { resolveOriginPolicy, checkOrigin, corsHeadersFor } from './origin-policy.ts';\nexport type { PairingToken } from './pairing.ts';\nexport {\n\tmintToken,\n\tacquirePairingToken,\n\ttokenPath,\n\tcomposePairUrl,\n\tparsePairUrl,\n\tparseBearerHeader,\n\tsafeBearerEquals,\n\tredactToken,\n} from './pairing.ts';\nexport { WALLET_ENDPOINT_NAME, WALLET_ENDPOINT_KEY, makeWalletRoutable } from './routable.ts';\nexport {\n\tdispatch,\n\tstartHttpServer,\n\tMAX_BODY_BYTES,\n\ttype WalletRequest,\n\ttype WalletResponse,\n\ttype WalletServerConfig,\n\ttype WalletServerHandle,\n} from './server.ts';\nexport { makeWalletCodegen } from './codegen.ts';\nexport { makeWalletSnapshotable } from './snapshot.ts';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,MAAM,6BAA6B;;;;;;;;;;;AAYnC,MAAM,2BACL,WAEA,OAAO,GAAG,WAAW,0BAA0B;;;AAQhD,MAAM,iBAAiB,SAAgC,QAAQ;AAgD/D,SAAgB,OAAO,MAAiC;CACvD,MAAM,eACL,QAAS,EAAE,UAAA,MAA8B;CAC1C,IAAI,aAAa,aAAA,OAAkC;EAqBlD,MAAM,cAAc,iBAAiB,cAAc,CAAC,CAAU;EAC9D,qBAAqB,cAAc,YAAY;GAQ9C,MAAM,iBAA6C,CAAC;GACpD,KAAK,MAAM,KAAK,SACf,IAAI,wBAAwB,CAAC,GAC5B,eAAe,KAAK,CAAmC;GAGzD,OAAO,iBAAiB;IAAE,GAAG;IAAc,UAAU;GAAe,GAAG,cAAc;EACtF,CAAC;EACD,OAAO;CACR;CACA,OAAO,iBAAiB,cAAc,aAAa,QAAQ;AAC5D;AAEA,SAAS,iBACR,MACA,UACC;CAQD,MAAM,eAAe,CAAC,aAAa,GAAG,QAAQ;CAK9C,MAAM,eAAwC;EAAE,GAAG;EAAM;CAAS;CAElE,OAAO,aAAa;EACnB,IAAI,eAAe;EACnB,WAAW;EAIX,MAAM;EACN,SAAS;EAIT,QAAQ,SACP,OAAO,IAAI,aAAa;GACvB,MAAM,MAAM,OAAO;GAUnB,MAAM,WAAW,OAAO;GACxB,MAAM,QAAQ,OAAO;GACrB,MAAM,aAAa,OAAO;GAI1B,MAAM,GAAG,GAAG,oBAAoB;GAChC,MAAM,mBAAmB,OAAO,eAAe,UAAA,KAA2B,CAAC,CAAC,KAC3E,OAAO,KAAK,aACX,UAAU;IACT,UAAU;IACV;IACA,MAAM;GACP,CAAC,CACF,GACA,OAAO,UAAU,QAChB,gBAAgB;IACf,OAAO;IACP,SAAS,0CAA0C,IAAI;IACvD,OAAO;GACR,CAAC,CACF,CACD;GACA,MAAM,kBAAkB,OAAO,eAC9B,UAAA,KAED,CAAC,CAAC,KACD,OAAO,KAAK,aACX,UAAU;IACT,UAAU;IACV;IACA,MAAM;GACP,CAAC,CACF,GACA,OAAO,UAAU,QAChB,gBAAgB;IACf,OAAO;IACP,SAAS,8CAA8C,IAAI;IAC3D,OAAO;GACR,CAAC,CACF,CACD;GA4CA,MAAM,WAAW,OAAO,cAAc,cAAc;IAzCnD,KAAK,SAAS;IACd,OAAO,SAAS;IAChB,SAAS,SAAS;IAClB,WAAW,MAAM;IACjB,eAAe,WAAW,cACzB,WACE,SAAS;KACT,OAAO;KASP,YAAY;KACZ,eAAe;KACf,GAAI,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU;IAChD,CAAC,CAAC,CACD,KACA,OAAO,KAAK,UAAU,MAAM,IAAI,GAChC,OAAO,UAAU,QAChB,gBAAgB;KACf,OAAO;KACP,SAAS,gCAAgC,IAAI;KAC7C,MACC,IAAI,WAAW,mBACZ,mGACA,IAAI,WAAW,iBACd,6FACA;KACL,OAAO;IACR,CAAC,CACF,CACD;IACF,uBAAuB,OAAO,QAAQ,gBAAgB;IACtD;IACA;GAG4D,CAAC;GAU9D,IAAI,cAAc,uBAAuB,CAAC;GAC1C,IAAI,QAAQ,kBAAkB,SAAS,QAAQ,CAAC;GAChD,IAAI,SACH,mBAAmB;IAClB,KAAK,SAAS;IACd,OAAO,SAAS;IAChB,MAAM,SAAS;GAChB,CAAC,CACF;GAEA,OAAO;EACR,CAAC;CACH,CAAC;AACF"}
@@ -1,4 +1,4 @@
1
- import { SpanAttr } from "../../substrate/runtime/observability/spans.mjs";
1
+ import { LogAttr } from "../../substrate/runtime/observability/log-attrs.mjs";
2
2
  import { Effect } from "effect";
3
3
  //#region src/plugins/wallet/origin-policy.ts
4
4
  /**
@@ -23,8 +23,8 @@ const resolveOriginPolicy = (inputs) => Effect.gen(function* () {
23
23
  if (inputs.routedAppOrigin !== null) allowed.add(inputs.routedAppOrigin);
24
24
  for (const o of inputs.extraOrigins) allowed.add(o);
25
25
  if (allowed.size === 0) yield* Effect.logWarning("wallet origin allowlist is empty").pipe(Effect.annotateLogs({
26
- [SpanAttr.app]: inputs.app,
27
- [SpanAttr.stack]: inputs.stack
26
+ [LogAttr.app]: inputs.app,
27
+ [LogAttr.stack]: inputs.stack
28
28
  }));
29
29
  return { allowed };
30
30
  });
@@ -1 +1 @@
1
- {"version":3,"file":"origin-policy.mjs","names":[],"sources":["../../../src/plugins/wallet/origin-policy.ts"],"sourcesContent":["// Wallet plugin — CORS / origin allowlist policy.\n//\n// The allowlist is built from two real, substrate-wired sources: the\n// router-fronted dev-server origin for this stack (`routedAppOrigin`)\n// and any caller-supplied `extraOrigins`. Both are stack-scoped or\n// explicit, so neither opens the cross-stack pairing risk described in\n// 15-wallet.md.\n//\n// History (removed): an earlier design auto-allowlisted a vite-port-\n// derived origin (`http://dev.<stack>.<app>.localhost:<vite-port>`,\n// plus an opt-in `http://localhost:<vite-port>`). That branch was dead\n// AT THE TIME: there was no vite plugin and the port broker only\n// allocated ports for in-stack plugins with no reader/lookup API, so\n// `vitePortForThisStack` was always `null` at the only production call\n// site and the branch never fired. Per STYLE_GUIDE §5 (\"code either\n// works or doesn't exist\") the whole vite-origin path — and the\n// `allowLocalhostVite` opt-in it gated — was removed rather than left as\n// an unreachable allowlist seam.\n//\n// Note (no longer dead, but deliberately NOT re-added here): with the\n// `hostService(...)` plugin devstack now DOES own the dev server's bind\n// port (the broker allocates it; Vite binds it via `--port {port}`). So\n// the raw-loopback origin (`http://127.0.0.1:<port>` /\n// `http://localhost:<port>`) the dev sees in Vite's own console banner is\n// a real, knowable origin. The canonical fix lives on the host-service\n// side instead: it now publishes the ROUTED origin as its\n// `HostServiceValue.url`, so `devstack up` output (and any consumer\n// holding the resolved host-service value) point devs at the URL whose\n// Origin THIS allowlist already accepts (the routed `routedAppOrigin`).\n// Re-adding a raw-loopback branch\n// here is intentionally deferred — it would have to thread the\n// host-service's dynamic bind port into the wallet, which runs in the\n// OPPOSITE direction of the current dependency edge (host-service\n// `dependsOn` wallet), so the wallet has no view of that port at its own\n// boot. Devs who must load the raw Vite URL can pass it via\n// `allowedOrigins` (→ `extraOrigins`) until that plumbing is justified.\n//\n// Why \"origin + bearer together\": bearer alone leaves a non-browser-\n// tooling bypass — curl / fetch from a service worker can forge\n// `Authorization` from a leaked token. Browsers always send `Origin`;\n// non-browsers omit it. Demanding BOTH closes the bypass.\n\nimport { Effect } from 'effect';\n\nimport { SpanAttr } from '../../substrate/runtime/observability/spans.ts';\n\n// ----------------------------------------------------------------------\n// Policy shape\n// ----------------------------------------------------------------------\n\n/** Result of resolving the origin allowlist at boot. Captured into\n * the HTTP handler closure so per-request checks are pure-string\n * comparison. */\nexport interface OriginPolicy {\n\treadonly allowed: ReadonlySet<string>;\n}\n\n/** Per-stack inputs the policy resolver needs. Supplied by the\n * substrate at acquire time (identity + routed-url derivation); this\n * module doesn't reach into the broker itself. */\nexport interface OriginPolicyInputs {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly routedAppOrigin: string | null;\n\treadonly extraOrigins: ReadonlyArray<string>;\n}\n\n// ----------------------------------------------------------------------\n// Resolution\n// ----------------------------------------------------------------------\n\n/**\n * Resolve the per-stack origin allowlist.\n *\n * - Always allowlisted: the router-fronted dev-server origin for this\n * stack (`routedAppOrigin`), when the router derivation produced one.\n * - Always allowlisted: any explicit caller-supplied origins from\n * `extraOrigins`.\n *\n * Empty-allowlist policy (no `routedAppOrigin` AND no `extraOrigins`):\n * allowed. The wallet boots normally; with an empty allowlist the\n * per-request gate refuses every request (every Origin lands in\n * `forbidden`). This is the correct behavior for a stack composed\n * without any client UI (e.g. node-only smoke / e2e configs) — the\n * wallet's keypair + token are still useful for the host process, but\n * the HTTP surface is effectively closed. A `Effect.logWarning`\n * surfaces the configuration for operator visibility.\n */\nexport const resolveOriginPolicy = (inputs: OriginPolicyInputs): Effect.Effect<OriginPolicy> =>\n\tEffect.gen(function* () {\n\t\tconst allowed = new Set<string>();\n\n\t\tif (inputs.routedAppOrigin !== null) {\n\t\t\tallowed.add(inputs.routedAppOrigin);\n\t\t}\n\n\t\tfor (const o of inputs.extraOrigins) {\n\t\t\tallowed.add(o);\n\t\t}\n\n\t\tif (allowed.size === 0) {\n\t\t\tyield* Effect.logWarning('wallet origin allowlist is empty').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t[SpanAttr.app]: inputs.app,\n\t\t\t\t\t[SpanAttr.stack]: inputs.stack,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn { allowed } satisfies OriginPolicy;\n\t});\n\n// ----------------------------------------------------------------------\n// Per-request check\n// ----------------------------------------------------------------------\n\n/** Per-request origin gate. Returns `'missing'` for absent Origin,\n * `'forbidden'` for Origin not in the allowlist, `'ok'` for accepted.\n *\n * Distilled-doc invariant (C12): missing Origin is its OWN refusal\n * shape (closes the curl / non-browser bypass — bearer alone is not\n * enough). */\nexport type OriginCheckResult = 'missing' | 'forbidden' | 'ok';\n\nexport const checkOrigin = (\n\tpolicy: OriginPolicy,\n\theaderValue: string | undefined,\n): OriginCheckResult => {\n\tif (headerValue === undefined || headerValue.length === 0) return 'missing';\n\treturn policy.allowed.has(headerValue) ? 'ok' : 'forbidden';\n};\n\n/** Compose CORS headers for a successful request. Single-allowed-origin\n * echo (browsers don't honor wildcard with credentials, and we want\n * to keep `Access-Control-Allow-Credentials` open for fetch with\n * `credentials: 'include'` if a future codegen seam needs it). */\nexport const corsHeadersFor = (origin: string): Readonly<Record<string, string>> => ({\n\t'access-control-allow-origin': origin,\n\t'access-control-allow-methods': 'GET, POST, OPTIONS',\n\t'access-control-allow-headers': 'authorization, content-type',\n\t'access-control-allow-credentials': 'true',\n\tvary: 'origin',\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwFA,MAAa,uBAAuB,WACnC,OAAO,IAAI,aAAa;CACvB,MAAM,0BAAU,IAAI,KAAa;AAEjC,KAAI,OAAO,oBAAoB,KAC9B,SAAQ,IAAI,OAAO,gBAAgB;AAGpC,MAAK,MAAM,KAAK,OAAO,aACtB,SAAQ,IAAI,EAAE;AAGf,KAAI,QAAQ,SAAS,EACpB,QAAO,OAAO,WAAW,mCAAmC,CAAC,KAC5D,OAAO,aAAa;GAClB,SAAS,MAAM,OAAO;GACtB,SAAS,QAAQ,OAAO;EACzB,CAAC,CACF;AAGF,QAAO,EAAE,SAAS;EACjB;AAcH,MAAa,eACZ,QACA,gBACuB;AACvB,KAAI,gBAAgB,KAAA,KAAa,YAAY,WAAW,EAAG,QAAO;AAClE,QAAO,OAAO,QAAQ,IAAI,YAAY,GAAG,OAAO;;;;;;AAOjD,MAAa,kBAAkB,YAAsD;CACpF,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;CAChC,oCAAoC;CACpC,MAAM;CACN"}
1
+ {"version":3,"file":"origin-policy.mjs","names":[],"sources":["../../../src/plugins/wallet/origin-policy.ts"],"sourcesContent":["// Wallet plugin — CORS / origin allowlist policy.\n//\n// The allowlist is built from two real, substrate-wired sources: the\n// router-fronted dev-server origin for this stack (`routedAppOrigin`)\n// and any caller-supplied `extraOrigins`. Both are stack-scoped or\n// explicit, so neither opens the cross-stack pairing risk described in\n// 15-wallet.md.\n//\n// No raw-loopback origin: with the `hostService(...)` plugin devstack\n// owns the dev server's bind port (the broker allocates it; Vite binds\n// it via `--port {port}`), so the raw-loopback origin\n// (`http://127.0.0.1:<port>` / `http://localhost:<port>`) the dev sees\n// in Vite's own console banner is a real, knowable origin. The canonical\n// fix lives on the host-service side: it publishes the ROUTED origin as\n// its `HostServiceValue.url`, so `devstack up` output (and any consumer\n// holding the resolved host-service value) point devs at the URL whose\n// Origin THIS allowlist already accepts (the routed `routedAppOrigin`).\n// A raw-loopback allowlist branch would have to thread the host-service's\n// dynamic bind port into the wallet, which runs in the OPPOSITE direction\n// of the dependency edge (host-service `dependsOn` wallet), so the wallet\n// has no view of that port at its own boot. Devs who must load the raw\n// Vite URL pass it via `allowedOrigins` (→ `extraOrigins`).\n//\n// Why \"origin + bearer together\": bearer alone leaves a non-browser-\n// tooling bypass — curl / fetch from a service worker can forge\n// `Authorization` from a leaked token. Browsers always send `Origin`;\n// non-browsers omit it. Demanding BOTH closes the bypass.\n\nimport { Effect } from 'effect';\n\nimport { LogAttr } from '../../substrate/runtime/observability/log-attrs.ts';\n\n// ----------------------------------------------------------------------\n// Policy shape\n// ----------------------------------------------------------------------\n\n/** Result of resolving the origin allowlist at boot. Captured into\n * the HTTP handler closure so per-request checks are pure-string\n * comparison. */\nexport interface OriginPolicy {\n\treadonly allowed: ReadonlySet<string>;\n}\n\n/** Per-stack inputs the policy resolver needs. Supplied by the\n * substrate at acquire time (identity + routed-url derivation); this\n * module doesn't reach into the broker itself. */\nexport interface OriginPolicyInputs {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly routedAppOrigin: string | null;\n\treadonly extraOrigins: ReadonlyArray<string>;\n}\n\n// ----------------------------------------------------------------------\n// Resolution\n// ----------------------------------------------------------------------\n\n/**\n * Resolve the per-stack origin allowlist.\n *\n * - Always allowlisted: the router-fronted dev-server origin for this\n * stack (`routedAppOrigin`), when the router derivation produced one.\n * - Always allowlisted: any explicit caller-supplied origins from\n * `extraOrigins`.\n *\n * Empty-allowlist policy (no `routedAppOrigin` AND no `extraOrigins`):\n * allowed. The wallet boots normally; with an empty allowlist the\n * per-request gate refuses every request (every Origin lands in\n * `forbidden`). This is the correct behavior for a stack composed\n * without any client UI (e.g. node-only smoke / e2e configs) — the\n * wallet's keypair + token are still useful for the host process, but\n * the HTTP surface is effectively closed. A `Effect.logWarning`\n * surfaces the configuration for operator visibility.\n */\nexport const resolveOriginPolicy = (inputs: OriginPolicyInputs): Effect.Effect<OriginPolicy> =>\n\tEffect.gen(function* () {\n\t\tconst allowed = new Set<string>();\n\n\t\tif (inputs.routedAppOrigin !== null) {\n\t\t\tallowed.add(inputs.routedAppOrigin);\n\t\t}\n\n\t\tfor (const o of inputs.extraOrigins) {\n\t\t\tallowed.add(o);\n\t\t}\n\n\t\tif (allowed.size === 0) {\n\t\t\tyield* Effect.logWarning('wallet origin allowlist is empty').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t[LogAttr.app]: inputs.app,\n\t\t\t\t\t[LogAttr.stack]: inputs.stack,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\treturn { allowed } satisfies OriginPolicy;\n\t});\n\n// ----------------------------------------------------------------------\n// Per-request check\n// ----------------------------------------------------------------------\n\n/** Per-request origin gate. Returns `'missing'` for absent Origin,\n * `'forbidden'` for Origin not in the allowlist, `'ok'` for accepted.\n *\n * Distilled-doc invariant (C12): missing Origin is its OWN refusal\n * shape (closes the curl / non-browser bypass — bearer alone is not\n * enough). */\nexport type OriginCheckResult = 'missing' | 'forbidden' | 'ok';\n\nexport const checkOrigin = (\n\tpolicy: OriginPolicy,\n\theaderValue: string | undefined,\n): OriginCheckResult => {\n\tif (headerValue === undefined || headerValue.length === 0) return 'missing';\n\treturn policy.allowed.has(headerValue) ? 'ok' : 'forbidden';\n};\n\n/** Compose CORS headers for a successful request. Single-allowed-origin\n * echo (browsers don't honor wildcard with credentials, and we want\n * to keep `Access-Control-Allow-Credentials` open for fetch with\n * `credentials: 'include'` if a future codegen seam needs it). */\nexport const corsHeadersFor = (origin: string): Readonly<Record<string, string>> => ({\n\t'access-control-allow-origin': origin,\n\t'access-control-allow-methods': 'GET, POST, OPTIONS',\n\t'access-control-allow-headers': 'authorization, content-type',\n\t'access-control-allow-credentials': 'true',\n\tvary: 'origin',\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0EA,MAAa,uBAAuB,WACnC,OAAO,IAAI,aAAa;CACvB,MAAM,0BAAU,IAAI,IAAY;CAEhC,IAAI,OAAO,oBAAoB,MAC9B,QAAQ,IAAI,OAAO,eAAe;CAGnC,KAAK,MAAM,KAAK,OAAO,cACtB,QAAQ,IAAI,CAAC;CAGd,IAAI,QAAQ,SAAS,GACpB,OAAO,OAAO,WAAW,kCAAkC,CAAC,CAAC,KAC5D,OAAO,aAAa;GAClB,QAAQ,MAAM,OAAO;GACrB,QAAQ,QAAQ,OAAO;CACzB,CAAC,CACF;CAGD,OAAO,EAAE,QAAQ;AAClB,CAAC;AAcF,MAAa,eACZ,QACA,gBACuB;CACvB,IAAI,gBAAgB,KAAA,KAAa,YAAY,WAAW,GAAG,OAAO;CAClE,OAAO,OAAO,QAAQ,IAAI,WAAW,IAAI,OAAO;AACjD;;;;;AAMA,MAAa,kBAAkB,YAAsD;CACpF,+BAA+B;CAC/B,gCAAgC;CAChC,gCAAgC;CAChC,oCAAoC;CACpC,MAAM;AACP"}
@@ -1,13 +1,11 @@
1
- import { redactText } from "../../substrate/runtime/observability/redaction.mjs";
2
1
  import { atomicWriteFile } from "../../substrate/runtime/atomic-write.mjs";
3
2
  import "../../substrate/runtime/observability/index.mjs";
4
3
  import { WALLET_BEARER_PREFIX, WALLET_TOKEN_FRAGMENT_KEY } from "../../contracts/wallet-protocol.mjs";
5
4
  import { walletBootError } from "./errors.mjs";
6
- import { WalletSpans } from "./spans.mjs";
7
5
  import "./protocol.mjs";
8
6
  import { Effect } from "effect";
9
- import { randomBytes, timingSafeEqual } from "node:crypto";
10
7
  import { join } from "node:path";
8
+ import { randomBytes, timingSafeEqual } from "node:crypto";
11
9
  import { readFile } from "node:fs/promises";
12
10
  //#region src/plugins/wallet/pairing.ts
13
11
  /** Token-charset regex: lowercase hex, exactly 32 chars. Reject any
@@ -17,8 +15,9 @@ const asToken = (s) => s;
17
15
  /** Mint a fresh token. 16 random bytes → 32 hex chars. */
18
16
  const mintToken = () => Effect.sync(() => asToken(randomBytes(16).toString("hex")));
19
17
  /** Resolve the on-disk token path under a state root. The state root
20
- * is supplied by the substrate's identity / state-store config; this
21
- * helper centralises the layout convention.
18
+ * is the substrate path resolver's per-stack `StackPathsService.stackRoot`
19
+ * (derived from the runtime root + identity); this helper centralises
20
+ * the layout convention.
22
21
  *
23
22
  * Convention: `<stateRoot>/wallet/token` — one token per stack, lives
24
23
  * alongside other per-stack runtime artifacts. */
@@ -51,7 +50,7 @@ const acquirePairingToken = (path) => Effect.gen(function* () {
51
50
  if (existing !== null) {
52
51
  const trimmed = existing.trim();
53
52
  if (TOKEN_RE.test(trimmed)) return asToken(trimmed);
54
- yield* Effect.logWarning("wallet token file is malformed; re-minting").pipe(Effect.annotateLogs({ [WalletSpans.tokenFile]: path }));
53
+ yield* Effect.logWarning("wallet token file is malformed; re-minting").pipe(Effect.annotateLogs({ "wallet.tokenFile": path }));
55
54
  }
56
55
  const token = yield* mintToken();
57
56
  yield* atomicWriteFile(path, new TextEncoder().encode(token), { mode: 384 }).pipe(Effect.mapError((cause) => walletBootError({
@@ -104,24 +103,7 @@ const safeBearerEquals = (a, b) => {
104
103
  if (ab.length !== bb.length) return false;
105
104
  return timingSafeEqual(ab, bb);
106
105
  };
107
- const TOKEN_REDACTION_RULE = {
108
- kind: "pattern",
109
- pattern: /([#?&]token=)[A-Za-z0-9]+/g,
110
- replacement: "$1<redacted>"
111
- };
112
- /**
113
- * Redact the token fragment from any URL-shaped string for logging /
114
- * TUI rendering. Defense-in-depth — the engine's log sink should never
115
- * see the unredacted pair URL anyway, but this exists for callers that
116
- * accidentally pass `pairUrl` straight into a log line.
117
- *
118
- * Distilled-doc opportunity (15-wallet.md): the legacy redactor only
119
- * covered `#token=`. This regex covers BOTH the fragment form and a
120
- * hypothetical query form so a future config change doesn't silently
121
- * leak.
122
- */
123
- const redactToken = (s) => redactText(s, [TOKEN_REDACTION_RULE]);
124
106
  //#endregion
125
- export { acquirePairingToken, composePairUrl, mintToken, parseBearerHeader, redactToken, safeBearerEquals, tokenPath };
107
+ export { acquirePairingToken, composePairUrl, mintToken, parseBearerHeader, safeBearerEquals, tokenPath };
126
108
 
127
109
  //# sourceMappingURL=pairing.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"pairing.mjs","names":["joinPath"],"sources":["../../../src/plugins/wallet/pairing.ts"],"sourcesContent":["// Wallet plugin — pairing-token discipline.\n//\n// What this module owns (15-wallet.md \"Token comparison MUST be\n// constant-time\", \"Token MUST live in URL fragment (not query)\",\n// \"Token MUST NOT appear in log lines\", \"Token file MUST be mode\n// 0o600\"):\n//\n// 1. Token generation: 16 random bytes → 32 hex chars.\n// 2. Token persistence: file at `<stateRoot>/wallet/token`, mode\n// `0o600`, atomic write.\n// 3. Token rehydration: read-existing-or-mint so warm starts +\n// snapshot restore preserve the dev-wallet pairing.\n// 4. URL-fragment ↔ Authorization-header bridge: helpers that\n// compose the pair URL (token in fragment) and parse the\n// bearer-prefixed header back to the raw token.\n// 5. Constant-time bearer compare: timing-safe equality so a\n// remote attacker can't recover the token byte-by-byte via\n// response-time measurement.\n//\n// What this module does NOT own:\n//\n// - The HTTP server (see `server.ts`).\n// - The CORS / Origin allowlist (see `origin-policy.ts`).\n// - The codegen file (see `codegen.ts`).\n\nimport { Effect, FileSystem } from 'effect';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { join as joinPath } from 'node:path';\n\nimport { atomicWriteFile } from '../../substrate/runtime/atomic-write.ts';\nimport { redactText, type RedactionRule } from '../../substrate/runtime/observability/index.ts';\nimport { walletBootError, type WalletBootError } from './errors.ts';\nimport { WalletSpans } from './spans.ts';\nimport {\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n} from './protocol.ts';\n\n// ----------------------------------------------------------------------\n// Token shape\n// ----------------------------------------------------------------------\n\n/** A pairing token. Branded so it can't be confused with arbitrary\n * strings at the type level — only this module mints them. */\nexport type PairingToken = string & { readonly __pairingToken: unique symbol };\n\n/** Token-charset regex: lowercase hex, exactly 32 chars. Reject any\n * on-disk value that doesn't match (re-mint). */\nconst TOKEN_RE = /^[0-9a-f]{32}$/;\n\nconst asToken = (s: string): PairingToken => s as PairingToken;\n\n// ----------------------------------------------------------------------\n// Generation\n// ----------------------------------------------------------------------\n\n/** Mint a fresh token. 16 random bytes → 32 hex chars. */\nexport const mintToken = (): Effect.Effect<PairingToken> =>\n\tEffect.sync(() => asToken(randomBytes(16).toString('hex')));\n\n// ----------------------------------------------------------------------\n// Persistence\n// ----------------------------------------------------------------------\n\n/** Resolve the on-disk token path under a state root. The state root\n * is supplied by the substrate's identity / state-store config; this\n * helper centralises the layout convention.\n *\n * Convention: `<stateRoot>/wallet/token` — one token per stack, lives\n * alongside other per-stack runtime artifacts. */\nexport const tokenPath = (stateRoot: string): string => joinPath(stateRoot, 'wallet', 'token');\n\n/**\n * Read the on-disk token if it exists and is well-formed; otherwise\n * mint + persist a fresh one via the substrate's atomic-write primitive\n * (mkdir-parent → O_EXCL temp → write → fsync → rename, mode 0o600).\n * Warm starts and snapshot restores both land in the \"read existing\"\n * branch so a previously-paired dev-wallet keeps working without a\n * re-pair UX.\n */\nexport const acquirePairingToken = (\n\tpath: string,\n): Effect.Effect<PairingToken, WalletBootError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\t// Try to read an existing token.\n\t\tconst existing = yield* Effect.tryPromise({\n\t\t\ttry: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await readFile(path, 'utf8');\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return null;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcatch: (cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'read-token',\n\t\t\t\t\tmessage: `read of wallet token file failed at ${path}`,\n\t\t\t\t\thint: 'check filesystem permissions / disk availability',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\n\t\tif (existing !== null) {\n\t\t\tconst trimmed = existing.trim();\n\t\t\tif (TOKEN_RE.test(trimmed)) {\n\t\t\t\treturn asToken(trimmed);\n\t\t\t}\n\t\t\t// Malformed — fall through to mint + overwrite.\n\t\t\tyield* Effect.logWarning('wallet token file is malformed; re-minting').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t[WalletSpans.tokenFile]: path,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\t// Mint a new one + persist via substrate's atomic-write\n\t\t// (mode 0o600). The token survives partial-write failures: the\n\t\t// in-memory value is authoritative for the current cycle, and a\n\t\t// failed persist surfaces as `write-token` so callers can choose\n\t\t// to fail-fast or continue with a transient pairing.\n\t\tconst token = yield* mintToken();\n\t\tconst bytes = new TextEncoder().encode(token);\n\t\tyield* atomicWriteFile(path, bytes, { mode: 0o600 }).pipe(\n\t\t\tEffect.mapError((cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'write-token',\n\t\t\t\t\tmessage: `failed to persist wallet token at ${path}`,\n\t\t\t\t\thint: 'ENOSPC / EROFS / EACCES — boot continues with in-memory token; new pairing required next cycle',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\n\t\treturn token;\n\t});\n\n// ----------------------------------------------------------------------\n// Pair-URL composition (fragment-only)\n// ----------------------------------------------------------------------\n\n/**\n * Compose the pair URL the dev-wallet adapter reads.\n *\n * The token rides the URL FRAGMENT (`#token=...`), never a query\n * parameter. Fragments are not sent to servers, so the token can't\n * land in access logs / referrer headers / Sentry breadcrumbs.\n */\nexport const composePairUrl = (walletUrl: string, token: PairingToken): string =>\n\t`${walletUrl}/#${WALLET_TOKEN_FRAGMENT_KEY}=${token}`;\n\n/**\n * Inverse — parse the token out of a pair URL fragment. Used by tests +\n * by the dev-wallet adapter (mirrored there because of the workspace-\n * cycle constraint).\n */\nexport const parsePairUrl = (pairUrl: string): PairingToken | null => {\n\tconst hashIdx = pairUrl.indexOf('#');\n\tif (hashIdx < 0) return null;\n\tconst fragment = pairUrl.slice(hashIdx + 1);\n\tconst prefix = `${WALLET_TOKEN_FRAGMENT_KEY}=`;\n\tif (!fragment.startsWith(prefix)) return null;\n\tconst raw = fragment.slice(prefix.length);\n\treturn TOKEN_RE.test(raw) ? asToken(raw) : null;\n};\n\n// ----------------------------------------------------------------------\n// Authorization-header bridge\n// ----------------------------------------------------------------------\n\n/**\n * Parse a raw `Authorization` header value into the bearer token. The\n * dev-wallet adapter copies the token from `url.hash` into the\n * `Authorization: Bearer <token>` header on every request — this\n * helper is the symmetric inverse.\n *\n * Returns `null` on missing / malformed header so the caller can map\n * to the structured `unauthorized` request error.\n */\nexport const parseBearerHeader = (header: string | undefined): string | null => {\n\tif (header === undefined) return null;\n\tif (!header.startsWith(WALLET_BEARER_PREFIX)) return null;\n\tconst raw = header.slice(WALLET_BEARER_PREFIX.length);\n\t// Don't TOKEN_RE-test here — the constant-time compare against the\n\t// expected token covers shape mismatch (length-difference shortcut\n\t// is acceptable since token length is public knowledge).\n\treturn raw.length === WALLET_TOKEN_HEX_LENGTH ? raw : null;\n};\n\n// ----------------------------------------------------------------------\n// Constant-time compare\n// ----------------------------------------------------------------------\n\n/**\n * Constant-time bearer-token compare. The length-mismatch shortcut is\n * intentional — token length is public knowledge (always 32 hex\n * chars), so leaking \"wrong length\" is not a credential leak. The\n * shortcut also prevents `timingSafeEqual` from throwing on mismatched\n * buffer sizes.\n *\n * Invariant (15-wallet.md \"Token comparison MUST be constant-time\"):\n * NEVER `===` two tokens. `===` on strings short-circuits at the first\n * mismatching byte, leaking the prefix byte-by-byte via response-time\n * measurement to a remote attacker.\n */\nexport const safeBearerEquals = (a: string, b: PairingToken | string): boolean => {\n\tif (a.length !== b.length) return false;\n\t// `a` is attacker-controlled — a multi-byte UTF-8 codepoint in `a`\n\t// would inflate `ab.length` past `bb.length` even though\n\t// `a.length === b.length` passed (string length counts UTF-16 code\n\t// units, byte length counts UTF-8 bytes). The second length guard\n\t// stops `timingSafeEqual` from throwing in that case (its contract\n\t// requires equal-length buffers) and keeps the function total. For\n\t// the canonical case (`b` is a 32-hex `PairingToken`) the guard is\n\t// redundant; for the defensive case it prevents a malformed-input\n\t// throw from leaking up the dispatcher path.\n\tconst ab = Buffer.from(a, 'utf8');\n\tconst bb = Buffer.from(b, 'utf8');\n\tif (ab.length !== bb.length) return false;\n\treturn timingSafeEqual(ab, bb);\n};\n\n// ----------------------------------------------------------------------\n// Logging hygiene\n// ----------------------------------------------------------------------\n\nconst TOKEN_REDACTION_RULE: RedactionRule = {\n\tkind: 'pattern',\n\tpattern: /([#?&]token=)[A-Za-z0-9]+/g,\n\treplacement: '$1<redacted>',\n};\n\n/**\n * Redact the token fragment from any URL-shaped string for logging /\n * TUI rendering. Defense-in-depth — the engine's log sink should never\n * see the unredacted pair URL anyway, but this exists for callers that\n * accidentally pass `pairUrl` straight into a log line.\n *\n * Distilled-doc opportunity (15-wallet.md): the legacy redactor only\n * covered `#token=`. This regex covers BOTH the fragment form and a\n * hypothetical query form so a future config change doesn't silently\n * leak.\n */\nexport const redactToken = (s: string): string => redactText(s, [TOKEN_REDACTION_RULE]);\n"],"mappings":";;;;;;;;;;;;;;AAkDA,MAAM,WAAW;AAEjB,MAAM,WAAW,MAA4B;;AAO7C,MAAa,kBACZ,OAAO,WAAW,QAAQ,YAAY,GAAG,CAAC,SAAS,MAAM,CAAC,CAAC;;;;;;;AAY5D,MAAa,aAAa,cAA8BA,KAAS,WAAW,UAAU,QAAQ;;;;;;;;;AAU9F,MAAa,uBACZ,SAEA,OAAO,IAAI,aAAa;CAEvB,MAAM,WAAW,OAAO,OAAO,WAAW;EACzC,KAAK,YAAY;AAChB,OAAI;AACH,WAAO,MAAM,SAAS,MAAM,OAAO;YAC3B,KAAK;AACb,QAAK,KAA+B,SAAS,SAAU,QAAO;AAC9D,UAAM;;;EAGR,QAAQ,UACP,gBAAgB;GACf,OAAO;GACP,SAAS,uCAAuC;GAChD,MAAM;GACN;GACA,CAAC;EACH,CAAC;AAEF,KAAI,aAAa,MAAM;EACtB,MAAM,UAAU,SAAS,MAAM;AAC/B,MAAI,SAAS,KAAK,QAAQ,CACzB,QAAO,QAAQ,QAAQ;AAGxB,SAAO,OAAO,WAAW,6CAA6C,CAAC,KACtE,OAAO,aAAa,GAClB,YAAY,YAAY,MACzB,CAAC,CACF;;CAQF,MAAM,QAAQ,OAAO,WAAW;AAEhC,QAAO,gBAAgB,MADT,IAAI,aAAa,CAAC,OAAO,MACL,EAAE,EAAE,MAAM,KAAO,CAAC,CAAC,KACpD,OAAO,UAAU,UAChB,gBAAgB;EACf,OAAO;EACP,SAAS,qCAAqC;EAC9C,MAAM;EACN;EACA,CAAC,CACF,CACD;AAED,QAAO;EACN;;;;;;;;AAaH,MAAa,kBAAkB,WAAmB,UACjD,GAAG,UAAU,IAAI,0BAA0B,GAAG;;;;;;;;;;AA8B/C,MAAa,qBAAqB,WAA8C;AAC/E,KAAI,WAAW,KAAA,EAAW,QAAO;AACjC,KAAI,CAAC,OAAO,WAAA,UAAgC,CAAE,QAAO;CACrD,MAAM,MAAM,OAAO,MAAM,qBAAqB,OAAO;AAIrD,QAAO,IAAI,WAAA,KAAqC,MAAM;;;;;;;;;;;;;;AAmBvD,MAAa,oBAAoB,GAAW,MAAsC;AACjF,KAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;CAUlC,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;CACjC,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;AACjC,KAAI,GAAG,WAAW,GAAG,OAAQ,QAAO;AACpC,QAAO,gBAAgB,IAAI,GAAG;;AAO/B,MAAM,uBAAsC;CAC3C,MAAM;CACN,SAAS;CACT,aAAa;CACb;;;;;;;;;;;;AAaD,MAAa,eAAe,MAAsB,WAAW,GAAG,CAAC,qBAAqB,CAAC"}
1
+ {"version":3,"file":"pairing.mjs","names":["joinPath"],"sources":["../../../src/plugins/wallet/pairing.ts"],"sourcesContent":["// Wallet plugin — pairing-token discipline.\n//\n// What this module owns (15-wallet.md \"Token comparison MUST be\n// constant-time\", \"Token MUST live in URL fragment (not query)\",\n// \"Token MUST NOT appear in log lines\", \"Token file MUST be mode\n// 0o600\"):\n//\n// 1. Token generation: 16 random bytes → 32 hex chars.\n// 2. Token persistence: file at `<stateRoot>/wallet/token`, mode\n// `0o600`, atomic write.\n// 3. Token rehydration: read-existing-or-mint so warm starts +\n// snapshot restore preserve the dev-wallet pairing.\n// 4. URL-fragment ↔ Authorization-header bridge: helpers that\n// compose the pair URL (token in fragment) and parse the\n// bearer-prefixed header back to the raw token.\n// 5. Constant-time bearer compare: timing-safe equality so a\n// remote attacker can't recover the token byte-by-byte via\n// response-time measurement.\n//\n// What this module does NOT own:\n//\n// - The HTTP server (see `server.ts`).\n// - The CORS / Origin allowlist (see `origin-policy.ts`).\n// - The codegen file (see `codegen.ts`).\n\nimport { Effect, FileSystem } from 'effect';\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { readFile } from 'node:fs/promises';\nimport { join as joinPath } from 'node:path';\n\nimport { atomicWriteFile } from '../../substrate/runtime/atomic-write.ts';\nimport { redactText, type RedactionRule } from '../../substrate/runtime/observability/index.ts';\nimport { walletBootError, type WalletBootError } from './errors.ts';\nimport {\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n} from './protocol.ts';\n\n// ----------------------------------------------------------------------\n// Token shape\n// ----------------------------------------------------------------------\n\n/** A pairing token. Branded so it can't be confused with arbitrary\n * strings at the type level — only this module mints them. */\nexport type PairingToken = string & { readonly __pairingToken: unique symbol };\n\n/** Token-charset regex: lowercase hex, exactly 32 chars. Reject any\n * on-disk value that doesn't match (re-mint). */\nconst TOKEN_RE = /^[0-9a-f]{32}$/;\n\nconst asToken = (s: string): PairingToken => s as PairingToken;\n\n// ----------------------------------------------------------------------\n// Generation\n// ----------------------------------------------------------------------\n\n/** Mint a fresh token. 16 random bytes → 32 hex chars. */\nexport const mintToken = (): Effect.Effect<PairingToken> =>\n\tEffect.sync(() => asToken(randomBytes(16).toString('hex')));\n\n// ----------------------------------------------------------------------\n// Persistence\n// ----------------------------------------------------------------------\n\n/** Resolve the on-disk token path under a state root. The state root\n * is the substrate path resolver's per-stack `StackPathsService.stackRoot`\n * (derived from the runtime root + identity); this helper centralises\n * the layout convention.\n *\n * Convention: `<stateRoot>/wallet/token` — one token per stack, lives\n * alongside other per-stack runtime artifacts. */\nexport const tokenPath = (stateRoot: string): string => joinPath(stateRoot, 'wallet', 'token');\n\n/**\n * Read the on-disk token if it exists and is well-formed; otherwise\n * mint + persist a fresh one via the substrate's atomic-write primitive\n * (mkdir-parent → O_EXCL temp → write → fsync → rename, mode 0o600).\n * Warm starts and snapshot restores both land in the \"read existing\"\n * branch so a previously-paired dev-wallet keeps working without a\n * re-pair UX.\n */\nexport const acquirePairingToken = (\n\tpath: string,\n): Effect.Effect<PairingToken, WalletBootError, FileSystem.FileSystem> =>\n\tEffect.gen(function* () {\n\t\t// Try to read an existing token.\n\t\tconst existing = yield* Effect.tryPromise({\n\t\t\ttry: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await readFile(path, 'utf8');\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif ((err as NodeJS.ErrnoException)?.code === 'ENOENT') return null;\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcatch: (cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'read-token',\n\t\t\t\t\tmessage: `read of wallet token file failed at ${path}`,\n\t\t\t\t\thint: 'check filesystem permissions / disk availability',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\n\t\tif (existing !== null) {\n\t\t\tconst trimmed = existing.trim();\n\t\t\tif (TOKEN_RE.test(trimmed)) {\n\t\t\t\treturn asToken(trimmed);\n\t\t\t}\n\t\t\t// Malformed — fall through to mint + overwrite.\n\t\t\tyield* Effect.logWarning('wallet token file is malformed; re-minting').pipe(\n\t\t\t\tEffect.annotateLogs({\n\t\t\t\t\t'wallet.tokenFile': path,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\t// Mint a new one + persist via substrate's atomic-write\n\t\t// (mode 0o600). The token survives partial-write failures: the\n\t\t// in-memory value is authoritative for the current cycle, and a\n\t\t// failed persist surfaces as `write-token` so callers can choose\n\t\t// to fail-fast or continue with a transient pairing.\n\t\tconst token = yield* mintToken();\n\t\tconst bytes = new TextEncoder().encode(token);\n\t\tyield* atomicWriteFile(path, bytes, { mode: 0o600 }).pipe(\n\t\t\tEffect.mapError((cause) =>\n\t\t\t\twalletBootError({\n\t\t\t\t\tphase: 'write-token',\n\t\t\t\t\tmessage: `failed to persist wallet token at ${path}`,\n\t\t\t\t\thint: 'ENOSPC / EROFS / EACCES — boot continues with in-memory token; new pairing required next cycle',\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t\t),\n\t\t);\n\n\t\treturn token;\n\t});\n\n// ----------------------------------------------------------------------\n// Pair-URL composition (fragment-only)\n// ----------------------------------------------------------------------\n\n/**\n * Compose the pair URL the dev-wallet adapter reads.\n *\n * The token rides the URL FRAGMENT (`#token=...`), never a query\n * parameter. Fragments are not sent to servers, so the token can't\n * land in access logs / referrer headers / Sentry breadcrumbs.\n */\nexport const composePairUrl = (walletUrl: string, token: PairingToken): string =>\n\t`${walletUrl}/#${WALLET_TOKEN_FRAGMENT_KEY}=${token}`;\n\n/**\n * Inverse — parse the token out of a pair URL fragment. Used by tests +\n * by the dev-wallet adapter (mirrored there because of the workspace-\n * cycle constraint).\n */\nexport const parsePairUrl = (pairUrl: string): PairingToken | null => {\n\tconst hashIdx = pairUrl.indexOf('#');\n\tif (hashIdx < 0) return null;\n\tconst fragment = pairUrl.slice(hashIdx + 1);\n\tconst prefix = `${WALLET_TOKEN_FRAGMENT_KEY}=`;\n\tif (!fragment.startsWith(prefix)) return null;\n\tconst raw = fragment.slice(prefix.length);\n\treturn TOKEN_RE.test(raw) ? asToken(raw) : null;\n};\n\n// ----------------------------------------------------------------------\n// Authorization-header bridge\n// ----------------------------------------------------------------------\n\n/**\n * Parse a raw `Authorization` header value into the bearer token. The\n * dev-wallet adapter copies the token from `url.hash` into the\n * `Authorization: Bearer <token>` header on every request — this\n * helper is the symmetric inverse.\n *\n * Returns `null` on missing / malformed header so the caller can map\n * to the structured `unauthorized` request error.\n */\nexport const parseBearerHeader = (header: string | undefined): string | null => {\n\tif (header === undefined) return null;\n\tif (!header.startsWith(WALLET_BEARER_PREFIX)) return null;\n\tconst raw = header.slice(WALLET_BEARER_PREFIX.length);\n\t// Don't TOKEN_RE-test here — the constant-time compare against the\n\t// expected token covers shape mismatch (length-difference shortcut\n\t// is acceptable since token length is public knowledge).\n\treturn raw.length === WALLET_TOKEN_HEX_LENGTH ? raw : null;\n};\n\n// ----------------------------------------------------------------------\n// Constant-time compare\n// ----------------------------------------------------------------------\n\n/**\n * Constant-time bearer-token compare. The length-mismatch shortcut is\n * intentional — token length is public knowledge (always 32 hex\n * chars), so leaking \"wrong length\" is not a credential leak. The\n * shortcut also prevents `timingSafeEqual` from throwing on mismatched\n * buffer sizes.\n *\n * Invariant (15-wallet.md \"Token comparison MUST be constant-time\"):\n * NEVER `===` two tokens. `===` on strings short-circuits at the first\n * mismatching byte, leaking the prefix byte-by-byte via response-time\n * measurement to a remote attacker.\n */\nexport const safeBearerEquals = (a: string, b: PairingToken | string): boolean => {\n\tif (a.length !== b.length) return false;\n\t// `a` is attacker-controlled — a multi-byte UTF-8 codepoint in `a`\n\t// would inflate `ab.length` past `bb.length` even though\n\t// `a.length === b.length` passed (string length counts UTF-16 code\n\t// units, byte length counts UTF-8 bytes). The second length guard\n\t// stops `timingSafeEqual` from throwing in that case (its contract\n\t// requires equal-length buffers) and keeps the function total. For\n\t// the canonical case (`b` is a 32-hex `PairingToken`) the guard is\n\t// redundant; for the defensive case it prevents a malformed-input\n\t// throw from leaking up the dispatcher path.\n\tconst ab = Buffer.from(a, 'utf8');\n\tconst bb = Buffer.from(b, 'utf8');\n\tif (ab.length !== bb.length) return false;\n\treturn timingSafeEqual(ab, bb);\n};\n\n// ----------------------------------------------------------------------\n// Logging hygiene\n// ----------------------------------------------------------------------\n\nconst TOKEN_REDACTION_RULE: RedactionRule = {\n\tkind: 'pattern',\n\tpattern: /([#?&]token=)[A-Za-z0-9]+/g,\n\treplacement: '$1<redacted>',\n};\n\n/**\n * Redact the token fragment from any URL-shaped string for logging /\n * TUI rendering. Defense-in-depth — the engine's log sink should never\n * see the unredacted pair URL anyway, but this exists for callers that\n * accidentally pass `pairUrl` straight into a log line.\n *\n * This regex covers BOTH the fragment form (`#token=`) and a\n * hypothetical query form so a future config change doesn't silently\n * leak.\n */\nexport const redactToken = (s: string): string => redactText(s, [TOKEN_REDACTION_RULE]);\n"],"mappings":";;;;;;;;;;;;AAiDA,MAAM,WAAW;AAEjB,MAAM,WAAW,MAA4B;;AAO7C,MAAa,kBACZ,OAAO,WAAW,QAAQ,YAAY,EAAE,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC;;;;;;;;AAa3D,MAAa,aAAa,cAA8BA,KAAS,WAAW,UAAU,OAAO;;;;;;;;;AAU7F,MAAa,uBACZ,SAEA,OAAO,IAAI,aAAa;CAEvB,MAAM,WAAW,OAAO,OAAO,WAAW;EACzC,KAAK,YAAY;GAChB,IAAI;IACH,OAAO,MAAM,SAAS,MAAM,MAAM;GACnC,SAAS,KAAK;IACb,IAAK,KAA+B,SAAS,UAAU,OAAO;IAC9D,MAAM;GACP;EACD;EACA,QAAQ,UACP,gBAAgB;GACf,OAAO;GACP,SAAS,uCAAuC;GAChD,MAAM;GACN;EACD,CAAC;CACH,CAAC;CAED,IAAI,aAAa,MAAM;EACtB,MAAM,UAAU,SAAS,KAAK;EAC9B,IAAI,SAAS,KAAK,OAAO,GACxB,OAAO,QAAQ,OAAO;EAGvB,OAAO,OAAO,WAAW,4CAA4C,CAAC,CAAC,KACtE,OAAO,aAAa,EACnB,oBAAoB,KACrB,CAAC,CACF;CACD;CAOA,MAAM,QAAQ,OAAO,UAAU;CAE/B,OAAO,gBAAgB,MADT,IAAI,YAAY,CAAC,CAAC,OAAO,KACN,GAAG,EAAE,MAAM,IAAM,CAAC,CAAC,CAAC,KACpD,OAAO,UAAU,UAChB,gBAAgB;EACf,OAAO;EACP,SAAS,qCAAqC;EAC9C,MAAM;EACN;CACD,CAAC,CACF,CACD;CAEA,OAAO;AACR,CAAC;;;;;;;;AAaF,MAAa,kBAAkB,WAAmB,UACjD,GAAG,UAAU,IAAI,0BAA0B,GAAG;;;;;;;;;;AA8B/C,MAAa,qBAAqB,WAA8C;CAC/E,IAAI,WAAW,KAAA,GAAW,OAAO;CACjC,IAAI,CAAC,OAAO,WAAA,SAA+B,GAAG,OAAO;CACrD,MAAM,MAAM,OAAO,MAAM,qBAAqB,MAAM;CAIpD,OAAO,IAAI,WAAA,KAAqC,MAAM;AACvD;;;;;;;;;;;;;AAkBA,MAAa,oBAAoB,GAAW,MAAsC;CACjF,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAUlC,MAAM,KAAK,OAAO,KAAK,GAAG,MAAM;CAChC,MAAM,KAAK,OAAO,KAAK,GAAG,MAAM;CAChC,IAAI,GAAG,WAAW,GAAG,QAAQ,OAAO;CACpC,OAAO,gBAAgB,IAAI,EAAE;AAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.mjs","names":[],"sources":["../../../src/plugins/wallet/protocol.ts"],"sourcesContent":["// Wallet plugin — wire-level protocol.\n//\n// This file is the ONE cross-boundary contract between the devstack-\n// side HTTP server (this plugin) and the browser-side adapter (the\n// `dev-wallet` package). The browser-side adapter MUST be kept in\n// lock-step with these schemas; today that's enforced by a mirror in\n// `dev-wallet/src/adapters/devstack-paths.ts` + a byte-equality test.\n//\n// Distilled-doc opportunity (15-wallet.md \"Acyclic-edge duplication\"):\n// the duplication exists because devstack peer-deps on dev-wallet (for\n// codegen output) and a reverse edge would close a workspace cycle.\n// Per the task's architecture-revision flag: the long-term fix is to\n// hoist this file into a third tiny package (e.g.\n// `@mysten-incubation/devstack-wallet-protocol`) consumed by BOTH\n// sides. See `## Architecture-doc revisions` in the report.\n//\n// Canonical envelope choice (15-wallet.md \"Asymmetric sign-response\n// field names\" + \"Dual field-name acceptance\"):\n//\n// - Sign endpoints accept `{ address, bytes }` (always `bytes`, never\n// `txBytes` or `messageBytes`).\n// - Sign endpoints respond `{ bytes, signature }` (always those two\n// names; never `txBytes` / `suiSignature`).\n//\n// This mirrors `@mysten/sui`'s `Signer.signTransaction` /\n// `signPersonalMessage` return shape exactly, eliminating the asymmetry\n// the legacy server carried. Per the memory note \"no compat for\n// never-cases\" — devstack is unreleased, no migration burden.\n//\n// Effect v4 Schema is the validator. Each request/response is a\n// Schema.Struct; handlers `Schema.decodeUnknown(...)` the body and\n// `catchTag('ParseError', ...)` into a `body-invalid` request error.\n\nimport { Schema } from 'effect';\n\n// Pure wire constants live in the name-blind contract so L5 build\n// integrations can consume them without importing this L2 plugin\n// module; re-exported here so plugin-internal callers keep their\n// current import sites.\nexport {\n\tWalletHttpPath,\n\tWALLET_PROTOCOL_PREFIX,\n\tWALLET_AUTH_HEADER,\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n\ttype WalletHttpPathValue,\n} from '../../contracts/wallet-protocol.ts';\n\n// ----------------------------------------------------------------------\n// Shared primitives\n// ----------------------------------------------------------------------\n\n/**\n * Sui address — `0x` + 64 hex chars. Schema-validated so a typo or\n * truncated address surfaces as a structured `body-invalid` request\n * error rather than a confusing `address-not-found` (no account bound\n * at the address would be the same shape if we didn't validate).\n */\nexport const SuiAddressSchema = Schema.String.check(Schema.isPattern(/^0x[0-9a-fA-F]{64}$/));\n\n/** Base64-encoded bytes — string-typed at the wire (we keep base64 over\n * the cross-boundary; the server decodes with `Uint8Array.fromBase64`\n * or equivalent before handing to the Account sign closures). */\nexport const Base64Schema = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9+/]*={0,2}$/));\n\n/** Signature scheme discriminator surfaced on `/accounts`. Mirrors the\n * `AccountValue.scheme` shape from the account plugin. */\nexport const SignatureSchemeSchema = Schema.Union([\n\tSchema.Literal('ed25519'),\n\tSchema.Literal('secp256k1'),\n\tSchema.Literal('secp256r1'),\n]);\n\n/** Account-source discriminator. `'impersonate'` accounts cannot\n * satisfy `signTransaction` / `signPersonalMessage` — fork-admin\n * surfaces (not part of this protocol today) are the only sensible\n * consumers. */\nexport const AccountSourceSchema = Schema.Union([\n\tSchema.Literal('real'),\n\tSchema.Literal('impersonate'),\n]);\n\n// ----------------------------------------------------------------------\n// Response envelopes (200)\n// ----------------------------------------------------------------------\n\nexport const HealthResponseSchema = Schema.Struct({\n\tok: Schema.Literal(true),\n});\nexport type HealthResponse = Schema.Schema.Type<typeof HealthResponseSchema>;\n\nexport const AccountSummarySchema = Schema.Struct({\n\tname: Schema.String,\n\taddress: SuiAddressSchema,\n\tscheme: SignatureSchemeSchema,\n\t/** Base64-encoded `publicKey`. Impersonation accounts publish a\n\t * zero-length string here — consumers branch on `source`, not on\n\t * publicKey emptiness. */\n\tpublicKey: Base64Schema,\n\tsource: AccountSourceSchema,\n});\nexport type AccountSummary = Schema.Schema.Type<typeof AccountSummarySchema>;\n\nexport const AccountsResponseSchema = Schema.Struct({\n\taccounts: Schema.Array(AccountSummarySchema),\n});\nexport type AccountsResponse = Schema.Schema.Type<typeof AccountsResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Sign endpoints — request + response\n// ----------------------------------------------------------------------\n\n/** Canonical sign request — same shape for transaction and personal-\n * message routes. `bytes` is the only payload key (no `txBytes`,\n * `message`, or `messageBytes` aliases). */\nexport const SignRequestSchema = Schema.Struct({\n\taddress: SuiAddressSchema,\n\tbytes: Base64Schema,\n});\nexport type SignRequest = Schema.Schema.Type<typeof SignRequestSchema>;\n\n/** Canonical sign response — same shape for transaction and personal-\n * message routes. Matches `@mysten/sui`'s `Signer` return shape\n * byte-for-byte. */\nexport const SignResponseSchema = Schema.Struct({\n\tbytes: Base64Schema,\n\tsignature: Schema.String,\n});\nexport type SignResponse = Schema.Schema.Type<typeof SignResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Error envelope\n// ----------------------------------------------------------------------\n\n/** Error response body. The HTTP status carries the broad classification\n * (400/401/403/404/500); `code` carries the narrow phase so callers\n * can branch programmatically. */\nexport const ErrorResponseSchema = Schema.Struct({\n\terror: Schema.String,\n\tcode: Schema.String,\n});\nexport type ErrorResponse = Schema.Schema.Type<typeof ErrorResponseSchema>;\n\n// Header / token constants are re-exported above from\n// `../../contracts/wallet-protocol.ts`.\n"],"mappings":";;;;;;;;;AA2DA,MAAa,mBAAmB,OAAO,OAAO,MAAM,OAAO,UAAU,sBAAsB,CAAC;;;;AAK5F,MAAa,eAAe,OAAO,OAAO,MAAM,OAAO,UAAU,yBAAyB,CAAC;;;AAI3F,MAAa,wBAAwB,OAAO,MAAM;CACjD,OAAO,QAAQ,UAAU;CACzB,OAAO,QAAQ,YAAY;CAC3B,OAAO,QAAQ,YAAY;CAC3B,CAAC;;;;;AAMF,MAAa,sBAAsB,OAAO,MAAM,CAC/C,OAAO,QAAQ,OAAO,EACtB,OAAO,QAAQ,cAAc,CAC7B,CAAC;AAMkC,OAAO,OAAO,EACjD,IAAI,OAAO,QAAQ,KAAK,EACxB,CAAC;AAGF,MAAa,uBAAuB,OAAO,OAAO;CACjD,MAAM,OAAO;CACb,SAAS;CACT,QAAQ;;;;CAIR,WAAW;CACX,QAAQ;CACR,CAAC;AAGoC,OAAO,OAAO,EACnD,UAAU,OAAO,MAAM,qBAAqB,EAC5C,CAAC;;;;AAUF,MAAa,oBAAoB,OAAO,OAAO;CAC9C,SAAS;CACT,OAAO;CACP,CAAC;AAMgC,OAAO,OAAO;CAC/C,OAAO;CACP,WAAW,OAAO;CAClB,CAAC;AAUiC,OAAO,OAAO;CAChD,OAAO,OAAO;CACd,MAAM,OAAO;CACb,CAAC"}
1
+ {"version":3,"file":"protocol.mjs","names":[],"sources":["../../../src/plugins/wallet/protocol.ts"],"sourcesContent":["// Wallet plugin — wire-level protocol.\n//\n// This file is the ONE cross-boundary contract between the devstack-\n// side HTTP server (this plugin) and the browser-side adapter (the\n// `dev-wallet` package). The browser-side adapter MUST be kept in\n// lock-step with these schemas; today that's enforced by a mirror in\n// `dev-wallet/src/adapters/devstack-paths.ts` + a byte-equality test.\n//\n// Distilled-doc opportunity (15-wallet.md \"Acyclic-edge duplication\"):\n// the duplication exists because devstack peer-deps on dev-wallet (for\n// codegen output) and a reverse edge would close a workspace cycle.\n// The long-term fix is to hoist this file into a third tiny package\n// (e.g. `@mysten-incubation/devstack-wallet-protocol`) consumed by BOTH\n// sides.\n//\n// Canonical envelope choice (15-wallet.md \"Asymmetric sign-response\n// field names\" + \"Dual field-name acceptance\"):\n//\n// - Sign endpoints accept `{ address, bytes }` (always `bytes`, never\n// `txBytes` or `messageBytes`).\n// - Sign endpoints respond `{ bytes, signature }` (always those two\n// names; never `txBytes` / `suiSignature`).\n//\n// This mirrors `@mysten/sui`'s `Signer.signTransaction` /\n// `signPersonalMessage` return shape exactly, so the request/response\n// field names stay symmetric.\n//\n// Effect v4 Schema is the validator. Each request/response is a\n// Schema.Struct; handlers `Schema.decodeUnknown(...)` the body and\n// `catchTag('ParseError', ...)` into a `body-invalid` request error.\n\nimport { Schema } from 'effect';\n\n// Pure wire constants live in the name-blind contract so L5 build\n// integrations can consume them without importing this L2 plugin\n// module; re-exported here so plugin-internal callers keep their\n// current import sites.\nexport {\n\tWalletHttpPath,\n\tWALLET_PROTOCOL_PREFIX,\n\tWALLET_AUTH_HEADER,\n\tWALLET_BEARER_PREFIX,\n\tWALLET_TOKEN_FRAGMENT_KEY,\n\tWALLET_TOKEN_HEX_LENGTH,\n\ttype WalletHttpPathValue,\n} from '../../contracts/wallet-protocol.ts';\n\n// ----------------------------------------------------------------------\n// Shared primitives\n// ----------------------------------------------------------------------\n\n/**\n * Sui address — `0x` + 64 hex chars. Schema-validated so a typo or\n * truncated address surfaces as a structured `body-invalid` request\n * error rather than a confusing `address-not-found` (no account bound\n * at the address would be the same shape if we didn't validate).\n */\nexport const SuiAddressSchema = Schema.String.check(Schema.isPattern(/^0x[0-9a-fA-F]{64}$/));\n\n/** Base64-encoded bytes — string-typed at the wire (we keep base64 over\n * the cross-boundary; the server decodes with `Uint8Array.fromBase64`\n * or equivalent before handing to the Account sign closures). */\nexport const Base64Schema = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9+/]*={0,2}$/));\n\n/** Signature scheme discriminator surfaced on `/accounts`. Mirrors the\n * `AccountValue.scheme` shape from the account plugin. */\nexport const SignatureSchemeSchema = Schema.Union([\n\tSchema.Literal('ed25519'),\n\tSchema.Literal('secp256k1'),\n\tSchema.Literal('secp256r1'),\n]);\n\n/** Account-source discriminator. `'impersonate'` accounts cannot\n * satisfy `signTransaction` / `signPersonalMessage` — fork-admin\n * surfaces (not part of this protocol today) are the only sensible\n * consumers. */\nexport const AccountSourceSchema = Schema.Union([\n\tSchema.Literal('real'),\n\tSchema.Literal('impersonate'),\n]);\n\n// ----------------------------------------------------------------------\n// Response envelopes (200)\n// ----------------------------------------------------------------------\n\nexport const HealthResponseSchema = Schema.Struct({\n\tok: Schema.Literal(true),\n});\nexport type HealthResponse = Schema.Schema.Type<typeof HealthResponseSchema>;\n\nexport const AccountSummarySchema = Schema.Struct({\n\tname: Schema.String,\n\taddress: SuiAddressSchema,\n\tscheme: SignatureSchemeSchema,\n\t/** Base64-encoded `publicKey`. Impersonation accounts publish a\n\t * zero-length string here — consumers branch on `source`, not on\n\t * publicKey emptiness. */\n\tpublicKey: Base64Schema,\n\tsource: AccountSourceSchema,\n});\nexport type AccountSummary = Schema.Schema.Type<typeof AccountSummarySchema>;\n\nexport const AccountsResponseSchema = Schema.Struct({\n\taccounts: Schema.Array(AccountSummarySchema),\n});\nexport type AccountsResponse = Schema.Schema.Type<typeof AccountsResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Sign endpoints — request + response\n// ----------------------------------------------------------------------\n\n/** Canonical sign request — same shape for transaction and personal-\n * message routes. `bytes` is the only payload key (no `txBytes`,\n * `message`, or `messageBytes` aliases). */\nexport const SignRequestSchema = Schema.Struct({\n\taddress: SuiAddressSchema,\n\tbytes: Base64Schema,\n});\nexport type SignRequest = Schema.Schema.Type<typeof SignRequestSchema>;\n\n/** Canonical sign response — same shape for transaction and personal-\n * message routes. Matches `@mysten/sui`'s `Signer` return shape\n * byte-for-byte. */\nexport const SignResponseSchema = Schema.Struct({\n\tbytes: Base64Schema,\n\tsignature: Schema.String,\n});\nexport type SignResponse = Schema.Schema.Type<typeof SignResponseSchema>;\n\n// ----------------------------------------------------------------------\n// Error envelope\n// ----------------------------------------------------------------------\n\n/** Error response body. The HTTP status carries the broad classification\n * (400/401/403/404/500); `code` carries the narrow phase so callers\n * can branch programmatically. */\nexport const ErrorResponseSchema = Schema.Struct({\n\terror: Schema.String,\n\tcode: Schema.String,\n});\nexport type ErrorResponse = Schema.Schema.Type<typeof ErrorResponseSchema>;\n\n// Header / token constants are re-exported above from\n// `../../contracts/wallet-protocol.ts`.\n"],"mappings":";;;;;;;;;AAyDA,MAAa,mBAAmB,OAAO,OAAO,MAAM,OAAO,UAAU,qBAAqB,CAAC;;;;AAK3F,MAAa,eAAe,OAAO,OAAO,MAAM,OAAO,UAAU,wBAAwB,CAAC;;;AAI1F,MAAa,wBAAwB,OAAO,MAAM;CACjD,OAAO,QAAQ,SAAS;CACxB,OAAO,QAAQ,WAAW;CAC1B,OAAO,QAAQ,WAAW;AAC3B,CAAC;;;;;AAMD,MAAa,sBAAsB,OAAO,MAAM,CAC/C,OAAO,QAAQ,MAAM,GACrB,OAAO,QAAQ,aAAa,CAC7B,CAAC;AAMmC,OAAO,OAAO,EACjD,IAAI,OAAO,QAAQ,IAAI,EACxB,CAAC;AAGD,MAAa,uBAAuB,OAAO,OAAO;CACjD,MAAM,OAAO;CACb,SAAS;CACT,QAAQ;;;;CAIR,WAAW;CACX,QAAQ;AACT,CAAC;AAGqC,OAAO,OAAO,EACnD,UAAU,OAAO,MAAM,oBAAoB,EAC5C,CAAC;;;;AAUD,MAAa,oBAAoB,OAAO,OAAO;CAC9C,SAAS;CACT,OAAO;AACR,CAAC;AAMiC,OAAO,OAAO;CAC/C,OAAO;CACP,WAAW,OAAO;AACnB,CAAC;AAUkC,OAAO,OAAO;CAChD,OAAO,OAAO;CACd,MAAM,OAAO;AACd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"routable.mjs","names":[],"sources":["../../../src/plugins/wallet/routable.ts"],"sourcesContent":["// Wallet plugin — Routable contribution.\n//\n// The wallet's HTTP server is a HOST PROCESS (not a docker container)\n// listening on a loopback port the substrate's port broker hands us.\n// The router (Traefik) fronts the loopback port under a stack-scoped\n// hostname like `wallet.<app>.localhost:<router-port>`.\n//\n// This contribution is what tells the router about the upstream. The\n// router orchestrator reads the decl, mints the stack-scoped hostname,\n// and writes the file-provider YAML without ever naming the wallet\n// plugin.\n//\n// The wallet always emits this decl. The router is the standard app\n// and wallet entrypoint, while the loopback URL remains an internal\n// fallback for tests and direct host tooling.\n\nimport type { EntrypointDecl, RoutableDecl } from '../../contracts/routable.ts';\n\n// The routed-endpoint identity constants live in the name-blind\n// contract so L5 build integrations can consume them without importing\n// this L2 plugin module; re-exported here so plugin-internal callers\n// (and the conventional-routes alias table) keep one source of truth.\nexport {\n\tWALLET_ENDPOINT_NAME,\n\tWALLET_ENDPOINT_KEY,\n} from '../../contracts/wallet-protocol.ts';\n\nimport { WALLET_ENDPOINT_NAME } from '../../contracts/wallet-protocol.ts';\n\nexport const WALLET_ROUTE_ROLE = 'api' as const;\nexport const WALLET_ENTRYPOINT_PORT = 6173;\n\nexport const WALLET_ENTRYPOINTS: ReadonlyArray<EntrypointDecl> = [\n\t{ name: WALLET_ENDPOINT_NAME, port: WALLET_ENTRYPOINT_PORT, protocol: 'http' },\n];\n\n// ----------------------------------------------------------------------\n// Decl\n// ----------------------------------------------------------------------\n\n/** Construct the Routable decl for the stack-scoped wallet endpoint. */\nexport const makeWalletRoutable = (parts: {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly port: number;\n}): RoutableDecl => ({\n\tkind: 'routable',\n\tendpointName: WALLET_ENDPOINT_NAME,\n\tdispatchId: {\n\t\t// Convention: `<plugin>.<app>.<stack>` keeps dispatch-file\n\t\t// listings readable; the router still hashes the full\n\t\t// `(app, stack, serviceKey, role)` tuple for uniqueness.\n\t\tserviceKey: `wallet.${parts.app}.${parts.stack}`,\n\t\trole: WALLET_ROUTE_ROLE,\n\t},\n\tupstream: { type: 'host-loopback', port: parts.port },\n\tcors: true,\n\twireProtocol: 'http',\n});\n"],"mappings":";AA8BA,MAAa,yBAAyB;AAEtC,MAAa,qBAAoD,CAChE;CAAE,MAAM;CAAsB,MAAM;CAAwB,UAAU;CAAQ,CAC9E;;AAOD,MAAa,sBAAsB,WAId;CACpB,MAAM;CACN,cAAc;CACd,YAAY;EAIX,YAAY,UAAU,MAAM,IAAI,GAAG,MAAM;EACzC,MAAA;EACA;CACD,UAAU;EAAE,MAAM;EAAiB,MAAM,MAAM;EAAM;CACrD,MAAM;CACN,cAAc;CACd"}
1
+ {"version":3,"file":"routable.mjs","names":[],"sources":["../../../src/plugins/wallet/routable.ts"],"sourcesContent":["// Wallet plugin — Routable contribution.\n//\n// The wallet's HTTP server is a HOST PROCESS (not a docker container)\n// listening on a loopback port the substrate's port broker hands us.\n// The router (Traefik) fronts the loopback port under a stack-scoped\n// hostname like `wallet.<app>.localhost:<router-port>`.\n//\n// This contribution is what tells the router about the upstream. The\n// router orchestrator reads the decl, mints the stack-scoped hostname,\n// and writes the file-provider YAML without ever naming the wallet\n// plugin.\n//\n// The wallet always emits this decl. The router is the standard app\n// and wallet entrypoint, while the loopback URL remains an internal\n// fallback for tests and direct host tooling.\n\nimport type { EntrypointDecl, RoutableDecl } from '../../contracts/routable.ts';\n\n// The routed-endpoint identity constants live in the name-blind\n// contract so L5 build integrations can consume them without importing\n// this L2 plugin module; re-exported here so plugin-internal callers\n// (and the conventional-routes alias table) keep one source of truth.\nexport { WALLET_ENDPOINT_NAME, WALLET_ENDPOINT_KEY } from '../../contracts/wallet-protocol.ts';\n\nimport { WALLET_ENDPOINT_NAME } from '../../contracts/wallet-protocol.ts';\n\nexport const WALLET_ROUTE_ROLE = 'api' as const;\nexport const WALLET_ENTRYPOINT_PORT = 6173;\n\nexport const WALLET_ENTRYPOINTS: ReadonlyArray<EntrypointDecl> = [\n\t{ name: WALLET_ENDPOINT_NAME, port: WALLET_ENTRYPOINT_PORT, protocol: 'http' },\n];\n\n// ----------------------------------------------------------------------\n// Decl\n// ----------------------------------------------------------------------\n\n/** Construct the Routable decl for the stack-scoped wallet endpoint. */\nexport const makeWalletRoutable = (parts: {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly port: number;\n}): RoutableDecl => ({\n\tkind: 'routable',\n\tendpointName: WALLET_ENDPOINT_NAME,\n\tdispatchId: {\n\t\t// Convention: `<plugin>.<app>.<stack>` keeps dispatch-file\n\t\t// listings readable; the router still hashes the full\n\t\t// `(app, stack, serviceKey, role)` tuple for uniqueness.\n\t\tserviceKey: `wallet.${parts.app}.${parts.stack}`,\n\t\trole: WALLET_ROUTE_ROLE,\n\t},\n\tupstream: { type: 'host-loopback', port: parts.port },\n\tcors: true,\n\twireProtocol: 'http',\n});\n"],"mappings":";AA2BA,MAAa,yBAAyB;AAEtC,MAAa,qBAAoD,CAChE;CAAE,MAAM;CAAsB,MAAM;CAAwB,UAAU;AAAO,CAC9E;;AAOA,MAAa,sBAAsB,WAId;CACpB,MAAM;CACN,cAAc;CACd,YAAY;EAIX,YAAY,UAAU,MAAM,IAAI,GAAG,MAAM;EACzC,MAAA;CACD;CACA,UAAU;EAAE,MAAM;EAAiB,MAAM,MAAM;CAAK;CACpD,MAAM;CACN,cAAc;AACf"}