@fased/fased 0.1.62 → 0.1.64

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 (341) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +38 -30
  3. package/config/dependency-ownership.json +1 -1
  4. package/config/signer-policies/README.md +49 -0
  5. package/config/signer-policies/agent.json.template +32 -0
  6. package/config/signer-policies/mining.json.template +69 -0
  7. package/config/signer-policies/network.json.template +5 -0
  8. package/config/signer-policies/vault.json.template +70 -0
  9. package/config/signer-protocol-v2.json +76 -0
  10. package/config/typescript-noemit-baseline.json +680 -0
  11. package/dist/agents/auth-profiles/store.js +267 -31
  12. package/dist/agents/bash-tools.exec.js +10 -4
  13. package/dist/agents/current-model-catalog.js +3 -3
  14. package/dist/agents/memory-search.js +7 -1
  15. package/dist/agents/model-catalog-access.js +1 -2
  16. package/dist/agents/model-catalog-snapshot.js +1 -1
  17. package/dist/agents/model-catalog-source.js +1 -1
  18. package/dist/agents/model-metadata.js +1 -1
  19. package/dist/agents/model-selection.js +2 -28
  20. package/dist/agents/models-config.providers.js +6 -6
  21. package/dist/agents/pi-embedded-runner/compact.js +15 -7
  22. package/dist/agents/pi-embedded-runner/model.js +1 -1
  23. package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
  24. package/dist/agents/pi-embedded-runner/run.js +2 -0
  25. package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
  26. package/dist/agents/pi-tool-definition-adapter.js +16 -1
  27. package/dist/agents/pi-tools.js +2 -1
  28. package/dist/agents/sandbox/config.js +1 -1
  29. package/dist/agents/sandbox/context.js +27 -2
  30. package/dist/agents/skills/env-overrides.js +38 -28
  31. package/dist/agents/skills/trust.js +93 -0
  32. package/dist/agents/skills/workspace.js +128 -0
  33. package/dist/agents/skills-clawhub.js +36 -11
  34. package/dist/agents/skills-marketplace-scan.js +49 -0
  35. package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
  36. package/dist/agents/tools/mining-tool.js +1 -1
  37. package/dist/agents/tools/session-status-tool.js +1 -1
  38. package/dist/agents/tools/wallet-action-tool.js +172 -36
  39. package/dist/agents/tools/wallet-skill-policy.js +65 -23
  40. package/dist/agents/tools/wallet-tool.js +7 -11
  41. package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
  42. package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
  43. package/dist/auto-reply/reply/directive-handling.model.js +2 -1
  44. package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
  45. package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
  46. package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
  47. package/dist/auto-reply/reply/model-selection.js +7 -4
  48. package/dist/auto-reply/reply/session-reset-model.js +4 -4
  49. package/dist/brand.js +1 -1
  50. package/dist/build-info.json +3 -3
  51. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  52. package/dist/channel-web.js +2 -2
  53. package/dist/cli/gateway-cli/run.js +8 -0
  54. package/dist/cli/program/command-registry.js +1 -1
  55. package/dist/cli/program/register.onboard.js +2 -3
  56. package/dist/cli/program/register.wallet.js +16 -123
  57. package/dist/cli/providers-cli.js +1 -1
  58. package/dist/cli/sat-cli.js +129 -2
  59. package/dist/cli/update-cli/update-command.js +260 -11
  60. package/dist/commands/auth-choice.apply.api-providers.js +3 -3
  61. package/dist/commands/doctor-config-flow.js +1 -1
  62. package/dist/commands/doctor-legacy-config.js +2 -13
  63. package/dist/commands/model-picker.js +6 -6
  64. package/dist/commands/models/auth.js +1 -1
  65. package/dist/commands/onboard-auth.config-gateways.js +1 -1
  66. package/dist/commands/onboard-auth.credentials.js +32 -8
  67. package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
  68. package/dist/commands/onboard-non-interactive/local.js +5 -1
  69. package/dist/commands/wallet.js +568 -1911
  70. package/dist/config/config.js +2 -2
  71. package/dist/config/io.js +64 -2
  72. package/dist/config/schema.help.js +8 -7
  73. package/dist/config/schema.labels.js +5 -4
  74. package/dist/config/zod-schema.agent-runtime.js +1 -0
  75. package/dist/config/zod-schema.js +5 -0
  76. package/dist/control-ui/assets/{app-DLil9VO1.js → app-bR-fO5ty.js} +1511 -1555
  77. package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
  78. package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
  79. package/dist/control-ui/assets/{index-DdE_NIXo.js → index-ckCxHwjy.js} +3 -3
  80. package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
  81. package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
  82. package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
  83. package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
  84. package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
  85. package/dist/control-ui/index.html +1 -1
  86. package/dist/control-ui/version.json +1 -1
  87. package/dist/daemon/systemd-system.js +56 -50
  88. package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
  89. package/dist/extensions/sat-mining/src/rpc-read.js +235 -67
  90. package/dist/extensions/sat-mining/src/sat-bond-layout.js +5 -2
  91. package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
  92. package/dist/extensions/sat-mining/src/solana-submit.js +1038 -397
  93. package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
  94. package/dist/federation/auto-connect.js +98 -8
  95. package/dist/federation/marketplace-capability-adapter.js +33 -7
  96. package/dist/federation/marketplace-delivery-outbox.js +196 -0
  97. package/dist/federation/marketplace-delivery.js +351 -215
  98. package/dist/federation/marketplace-direct-payment.js +272 -141
  99. package/dist/federation/marketplace-escrow.js +607 -249
  100. package/dist/federation/marketplace-settlement-ledger.js +352 -0
  101. package/dist/federation/offers.js +9 -7
  102. package/dist/federation/peer-auth-v2.js +529 -0
  103. package/dist/gateway/a2a-http.js +425 -96
  104. package/dist/gateway/a2a-settlement.js +259 -153
  105. package/dist/gateway/a2a-task-store.js +524 -0
  106. package/dist/gateway/auth.js +38 -2
  107. package/dist/gateway/config-reload.js +46 -33
  108. package/dist/gateway/durable-capacity.js +31 -0
  109. package/dist/gateway/federation-http.js +540 -135
  110. package/dist/gateway/federation-marketplace-run-store.js +397 -0
  111. package/dist/gateway/federation-marketplace.js +535 -230
  112. package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
  113. package/dist/gateway/security-path.js +1 -1
  114. package/dist/gateway/server-http.js +1084 -1205
  115. package/dist/gateway/server-methods/models.js +1 -1
  116. package/dist/gateway/server-methods/secrets.js +40 -0
  117. package/dist/gateway/server-methods.js +1 -2
  118. package/dist/gateway/server-reload-handlers.js +196 -66
  119. package/dist/gateway/server-runtime-config.js +1 -1
  120. package/dist/gateway/server-secrets-runtime.js +288 -0
  121. package/dist/gateway/server.impl.js +73 -42
  122. package/dist/gateway/sessions-patch.js +3 -5
  123. package/dist/index.js +4 -2
  124. package/dist/infra/fasedhub.js +64 -1
  125. package/dist/infra/local-source-paired-update.js +538 -0
  126. package/dist/infra/restart.js +41 -10
  127. package/dist/infra/update-runner.js +96 -0
  128. package/dist/light-update-status.js +11 -11
  129. package/dist/memory/backend-config.js +2 -1
  130. package/dist/memory/session-files.js +16 -2
  131. package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
  132. package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
  133. package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
  134. package/dist/plugin-sdk/{audio-preflight-Bwi2Oq03.js → audio-preflight-BYxAt775.js} +27 -27
  135. package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
  136. package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
  137. package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
  138. package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
  139. package/dist/plugin-sdk/channel-plugin-common.js +4 -4
  140. package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
  141. package/dist/plugin-sdk/{chunk-items-DzT4L4Ty.js → chunk-items-DIRHG2gJ.js} +1 -1
  142. package/dist/plugin-sdk/command-status.d.ts +2 -2
  143. package/dist/plugin-sdk/command-status.js +27 -27
  144. package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
  145. package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
  146. package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
  147. package/dist/plugin-sdk/{config-schema-BrkmtFxB.js → config-schema-BOT7kHb6.js} +6779 -3696
  148. package/dist/plugin-sdk/device-pair.d.ts +1 -1
  149. package/dist/plugin-sdk/discord.d.ts +6 -6
  150. package/dist/plugin-sdk/discord.js +19 -19
  151. package/dist/plugin-sdk/file-lock.js +35 -4
  152. package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
  153. package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
  154. package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
  155. package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
  156. package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
  157. package/dist/plugin-sdk/index.d.ts +21 -39
  158. package/dist/plugin-sdk/index.js +29 -29
  159. package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
  160. package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
  161. package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
  162. package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
  163. package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
  164. package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
  165. package/dist/plugin-sdk/{monitor-M_ta2lMc.js → monitor-BCFDaqJ-.js} +31 -31
  166. package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-BgbjRiPM.js} +32 -32
  167. package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DFf87SMM.js} +27 -27
  168. package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
  169. package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
  170. package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
  171. package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
  172. package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
  173. package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
  174. package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
  175. package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
  176. package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
  177. package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
  178. package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
  179. package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
  180. package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
  181. package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
  182. package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
  183. package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
  184. package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
  185. package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
  186. package/dist/plugin-sdk/sat-runtime.d.ts +549 -309
  187. package/dist/plugin-sdk/sat-runtime.js +29 -29
  188. package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
  189. package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
  190. package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
  191. package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
  192. package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
  193. package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
  194. package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
  195. package/dist/plugin-sdk/{slack-CxE1mfzj.js → slack-BUTt8cxK.js} +39 -39
  196. package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
  197. package/dist/plugin-sdk/slack.d.ts +6 -6
  198. package/dist/plugin-sdk/slack.js +9 -9
  199. package/dist/plugin-sdk/{sticker-cache-CGzGWu00.js → sticker-cache-D0wHVqjt.js} +3 -3
  200. package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
  201. package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
  202. package/dist/plugin-sdk/{telegram-actions-DaEcYQ8r.js → telegram-actions-CC_qN4v0.js} +30 -30
  203. package/dist/plugin-sdk/telegram.d.ts +6 -6
  204. package/dist/plugin-sdk/telegram.js +8 -8
  205. package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
  206. package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
  207. package/dist/plugin-sdk/tmp-fased-dir-xOTGlzBE.d.ts +486 -0
  208. package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-C3avNytw.d.ts} +3 -4
  209. package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
  210. package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-DWfbSAaM.d.ts} +2 -2
  211. package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
  212. package/dist/plugin-sdk/{web-CInY-lCv.js → web-BXsJ1vqe.js} +32 -32
  213. package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
  214. package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
  215. package/dist/plugin-sdk/whatsapp.d.ts +13 -13
  216. package/dist/plugin-sdk/whatsapp.js +12 -12
  217. package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
  218. package/dist/plugin-sdk/{zod-schema.providers-core-BEbNizPe.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
  219. package/dist/providers/refresh.js +1 -1
  220. package/dist/providers/registry.js +1 -1
  221. package/dist/secrets/apply.js +1 -1
  222. package/dist/secrets/runtime.js +1 -1
  223. package/dist/wallet/external-submission-ledger.js +376 -0
  224. package/dist/wallet/legacy-embedded-keystore.js +40 -0
  225. package/dist/wallet/local-socket-signer-archive.js +30 -0
  226. package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
  227. package/dist/wallet/local-socket-signer-policy.js +166 -0
  228. package/dist/wallet/local-socket-signer-protocol.js +561 -118
  229. package/dist/wallet/native-signer-wallet-id.js +25 -0
  230. package/dist/wallet/providers/alchemy-adapter.js +3 -0
  231. package/dist/wallet/providers/local-socket-signer-adapter.js +380 -105
  232. package/dist/wallet/providers/turnkey-adapter.js +292 -34
  233. package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
  234. package/dist/wallet/signer-network-admin.js +184 -0
  235. package/dist/wallet/signer-protocol-v2.generated.js +90 -0
  236. package/dist/wallet/solana-bond-signing.js +157 -69
  237. package/dist/wallet/solana-reviewed-transaction.js +375 -0
  238. package/dist/wallet/solana-swap.js +520 -64
  239. package/dist/wallet/solana-transaction-inspection.js +106 -4
  240. package/dist/wallet/solana-trigger.js +658 -320
  241. package/dist/wallet/turnkey-reviewed-state.js +370 -0
  242. package/dist/wallet/wallet-approval-auth.js +17 -28
  243. package/dist/wallet/wallet-atomic-state.js +53 -0
  244. package/dist/wallet/wallet-canary.js +0 -1
  245. package/dist/wallet/wallet-inbound-events.js +16 -11
  246. package/dist/wallet/wallet-policy-simulation.js +1 -1
  247. package/dist/wallet/wallet-policy.js +90 -36
  248. package/dist/wallet/wallet-provider-capabilities.js +28 -4
  249. package/dist/wallet/wallet-provider-registry.js +57 -44
  250. package/dist/wallet/wallet-provider-resolver.js +62 -63
  251. package/dist/wallet/wallet-runtime-config.js +28 -41
  252. package/dist/wallet/wallet-secrets-store.js +22 -0
  253. package/dist/wallet/wallet-send-approvals.js +1891 -589
  254. package/dist/wallet/wallet-send-execution-ledger.js +292 -0
  255. package/dist/wallet/wallet-settlement-links.js +14 -13
  256. package/dist/wallet/wallet-standard-review.js +353 -0
  257. package/dist/wallet/wallet-status.js +0 -9
  258. package/dist/wallet/wallet-task-ledger.js +16 -2
  259. package/dist/web/auto-reply/heartbeat-runner.js +1 -1
  260. package/dist/web/auto-reply/monitor.js +2 -2
  261. package/dist/wizard/host-security-capability.js +14 -23
  262. package/dist/wizard/onboarding.finalize.js +63 -184
  263. package/dist/wizard/onboarding.host-security.js +117 -1367
  264. package/dist/wizard/onboarding.js +172 -217
  265. package/dist/wizard/onboarding.wallet.js +232 -785
  266. package/extensions/acpx/package.json +1 -1
  267. package/extensions/bluebubbles/package.json +1 -1
  268. package/extensions/copilot-proxy/package.json +1 -1
  269. package/extensions/diagnostics-otel/package.json +1 -1
  270. package/extensions/fased-federation/package.json +1 -1
  271. package/extensions/google-gemini-cli-auth/package.json +1 -1
  272. package/extensions/imessage/package.json +1 -1
  273. package/extensions/irc/package.json +1 -1
  274. package/extensions/line/package.json +1 -1
  275. package/extensions/llm-task/package.json +1 -1
  276. package/extensions/lobster/package.json +1 -1
  277. package/extensions/matrix/CHANGELOG.md +12 -0
  278. package/extensions/matrix/package.json +1 -1
  279. package/extensions/mattermost/package.json +1 -1
  280. package/extensions/memory-core/package.json +2 -2
  281. package/extensions/memory-lancedb/package.json +1 -1
  282. package/extensions/minimax-portal-auth/package.json +1 -1
  283. package/extensions/msteams/CHANGELOG.md +12 -0
  284. package/extensions/msteams/package.json +1 -1
  285. package/extensions/nextcloud-talk/package.json +1 -1
  286. package/extensions/nostr/CHANGELOG.md +12 -0
  287. package/extensions/nostr/package.json +1 -1
  288. package/extensions/open-prose/package.json +1 -1
  289. package/extensions/sat-mining/index.ts +498 -153
  290. package/extensions/sat-mining/package.json +1 -1
  291. package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
  292. package/extensions/sat-mining/src/audit-store.ts +50 -5
  293. package/extensions/sat-mining/src/claim-service.ts +85 -14
  294. package/extensions/sat-mining/src/config.ts +9 -0
  295. package/extensions/sat-mining/src/cycle-progress.ts +16 -8
  296. package/extensions/sat-mining/src/epoch-service.ts +9 -5
  297. package/extensions/sat-mining/src/gateway-runner.ts +21 -1
  298. package/extensions/sat-mining/src/protocol-contract.ts +45 -1
  299. package/extensions/sat-mining/src/recovery-service.ts +312 -0
  300. package/extensions/sat-mining/src/round-watcher.ts +391 -81
  301. package/extensions/sat-mining/src/rpc-read.ts +330 -89
  302. package/extensions/sat-mining/src/runtime.ts +14 -0
  303. package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
  304. package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
  305. package/extensions/sat-mining/src/solana-submit.ts +1199 -428
  306. package/extensions/sat-mining/src/submission-ledger.ts +433 -0
  307. package/extensions/signal/package.json +1 -1
  308. package/extensions/synology-chat/package.json +1 -1
  309. package/extensions/tlon/package.json +1 -1
  310. package/extensions/twitch/CHANGELOG.md +12 -0
  311. package/extensions/twitch/package.json +1 -1
  312. package/extensions/voice-call/CHANGELOG.md +12 -0
  313. package/extensions/voice-call/package.json +1 -1
  314. package/extensions/zalo/CHANGELOG.md +12 -0
  315. package/extensions/zalo/package.json +1 -1
  316. package/extensions/zalouser/CHANGELOG.md +12 -0
  317. package/extensions/zalouser/package.json +1 -1
  318. package/install.sh +4955 -0
  319. package/package.json +23 -5
  320. package/scripts/fased-host-updater.mjs +1421 -0
  321. package/scripts/fased-host-updaterctl.mjs +186 -0
  322. package/scripts/fased-managed-service.sh +36 -0
  323. package/scripts/fased-managed-updater.mjs +3065 -156
  324. package/scripts/fased-signer-enroll-hosting.sh +275 -0
  325. package/scripts/fased-signer-network-hosting.sh +143 -0
  326. package/scripts/fased-signer-owner-policy.mjs +1430 -0
  327. package/scripts/fased-signer-policy-hosting.sh +50 -0
  328. package/scripts/fased-signer-policy-local.sh +26 -0
  329. package/scripts/hosted-release-manifest.mjs +185 -0
  330. package/scripts/install-fased-signerd.sh +183 -108
  331. package/scripts/install-managed-runtime.mjs +212 -10
  332. package/scripts/managed-runtime-layout.mjs +75 -3
  333. package/scripts/migrate-hosted-signer-v2.mjs +58 -0
  334. package/scripts/start-managed.sh +169 -360
  335. package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
  336. package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
  337. package/dist/wallet/local-socket-signer-broker.js +0 -224
  338. package/dist/wallet/local-socket-signer-custody.js +0 -42
  339. package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
  340. package/dist/wallet/providers/privy-adapter.js +0 -80
  341. package/dist/wallet/wallet-custody.js +0 -1836
@@ -0,0 +1,292 @@
1
+ import { resolveProcessScopedMap } from "../shared/process-scoped-map.js";
2
+ import { acquireFileLock, withFileLock } from "../plugin-sdk/file-lock.js";
3
+ import "../infra/file-lock.js";
4
+ import { ensureWalletStateDir } from "./wallet-runtime-config.js";
5
+ import { serializeWalletState, writeWalletStateFileAtomically } from "./wallet-atomic-state.js";
6
+ import syncFs from "node:fs";
7
+ import path from "node:path";
8
+ import { createHash } from "node:crypto";
9
+
10
+ //#region src/wallet/wallet-send-execution-ledger.ts
11
+ const STATES = new Set([
12
+ "reserved",
13
+ "approval_pending",
14
+ "executing",
15
+ "unknown",
16
+ "executed",
17
+ "failed"
18
+ ]);
19
+ const TRANSITIONS = {
20
+ reserved: new Set([
21
+ "reserved",
22
+ "approval_pending",
23
+ "executing",
24
+ "unknown",
25
+ "failed"
26
+ ]),
27
+ approval_pending: new Set([
28
+ "approval_pending",
29
+ "executed",
30
+ "unknown",
31
+ "failed"
32
+ ]),
33
+ executing: new Set([
34
+ "executing",
35
+ "unknown",
36
+ "executed",
37
+ "failed"
38
+ ]),
39
+ unknown: new Set([
40
+ "unknown",
41
+ "executed",
42
+ "failed"
43
+ ]),
44
+ executed: new Set(["executed"]),
45
+ failed: new Set(["failed"])
46
+ };
47
+ const MUTATION_LOCK_OPTIONS = {
48
+ retries: {
49
+ retries: 100,
50
+ factor: 1.15,
51
+ minTimeout: 10,
52
+ maxTimeout: 200,
53
+ randomize: true
54
+ },
55
+ stale: 3e4
56
+ };
57
+ const EXECUTION_LOCK_OPTIONS = {
58
+ retries: {
59
+ retries: 1,
60
+ factor: 1,
61
+ minTimeout: 10,
62
+ maxTimeout: 10,
63
+ randomize: false
64
+ },
65
+ stale: 3e4
66
+ };
67
+ const MUTATION_QUEUES = resolveProcessScopedMap(Symbol.for("fased.wallet.sendExecution.mutationQueues"));
68
+ const ACTIVE_EXECUTIONS = resolveProcessScopedMap(Symbol.for("fased.wallet.sendExecution.activeExecutions"));
69
+ function containsControlCharacter(value) {
70
+ for (let index = 0; index < value.length; index += 1) {
71
+ if (value.charCodeAt(index) <= 31) {
72
+ return true;
73
+ }
74
+ }
75
+ return false;
76
+ }
77
+ function canonicalJson(value) {
78
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
79
+ return JSON.stringify(value);
80
+ }
81
+ if (typeof value === "number") {
82
+ if (!Number.isFinite(value)) {
83
+ throw new Error("wallet send intent contains a non-finite number");
84
+ }
85
+ return JSON.stringify(value);
86
+ }
87
+ if (Array.isArray(value)) {
88
+ return `[${value.map((entry) => canonicalJson(entry)).join(",")}]`;
89
+ }
90
+ if (value && typeof value === "object") {
91
+ const record = value;
92
+ return `{${Object.keys(record).filter((key) => record[key] !== undefined).toSorted().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
93
+ }
94
+ throw new Error("wallet send intent contains an unsupported value");
95
+ }
96
+ function walletSendIntentDigest(intent) {
97
+ return `sha256:${createHash("sha256").update(canonicalJson(intent)).digest("hex")}`;
98
+ }
99
+ function walletSendRequestId(executionIntentId) {
100
+ const normalized = executionIntentId.trim();
101
+ if (!normalized || normalized.length > 240 || containsControlCharacter(normalized)) {
102
+ throw new Error("wallet send executionIntentId is invalid");
103
+ }
104
+ return `wallet-send-${createHash("sha256").update(normalized).digest("hex")}`;
105
+ }
106
+ function ledgerPath(env) {
107
+ return path.join(ensureWalletStateDir(env).rootDir, "wallet-send-executions.json");
108
+ }
109
+ function executionLockTarget(executionIntentId, env) {
110
+ return path.join(path.dirname(ledgerPath(env)), ".wallet-send-executions", createHash("sha256").update(executionIntentId).digest("hex"));
111
+ }
112
+ function isRecord(value) {
113
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
114
+ }
115
+ function validateResult(value) {
116
+ if (value === undefined) {
117
+ return undefined;
118
+ }
119
+ if (!isRecord(value) || value.chain !== "solana" || typeof value.txHash !== "string" || !value.txHash.trim() || value.signer !== undefined && typeof value.signer !== "string" || value.metadata !== undefined && !isRecord(value.metadata)) {
120
+ throw new Error("wallet send execution ledger contains an invalid result");
121
+ }
122
+ return value;
123
+ }
124
+ function validateEntry(value) {
125
+ if (!isRecord(value)) {
126
+ throw new Error("wallet send execution ledger contains an invalid entry");
127
+ }
128
+ if (typeof value.executionIntentId !== "string" || !value.executionIntentId.trim() || typeof value.intentDigest !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(value.intentDigest) || typeof value.requestId !== "string" || !value.requestId.trim() || typeof value.walletId !== "string" || !value.walletId.trim() || typeof value.providerId !== "string" || !value.providerId.trim() || typeof value.state !== "string" || !STATES.has(value.state) || typeof value.createdAt !== "string" || typeof value.updatedAt !== "string") {
129
+ throw new Error("wallet send execution ledger contains an invalid entry");
130
+ }
131
+ for (const field of [
132
+ "approvalRequestId",
133
+ "signature",
134
+ "reason"
135
+ ]) {
136
+ if (value[field] !== undefined && typeof value[field] !== "string") {
137
+ throw new Error(`wallet send execution ledger contains an invalid ${field}`);
138
+ }
139
+ }
140
+ const expectedRequestId = walletSendRequestId(value.executionIntentId);
141
+ if (value.requestId !== expectedRequestId) {
142
+ throw new Error("wallet send execution ledger contains a mismatched request ID");
143
+ }
144
+ const result = validateResult(value.result);
145
+ if (value.state === "executed" && (!result || typeof value.signature !== "string" || value.signature !== result.txHash)) {
146
+ throw new Error("wallet send execution ledger contains an incomplete executed result");
147
+ }
148
+ return value;
149
+ }
150
+ function loadLedger(env) {
151
+ const filePath = ledgerPath(env);
152
+ if (!syncFs.existsSync(filePath)) {
153
+ return {
154
+ version: 1,
155
+ entries: []
156
+ };
157
+ }
158
+ try {
159
+ const parsed = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
160
+ if (parsed.version !== 1 || !Array.isArray(parsed.entries)) {
161
+ throw new Error("unsupported shape");
162
+ }
163
+ const entries = parsed.entries.map(validateEntry);
164
+ if (new Set(entries.map((entry) => entry.executionIntentId)).size !== entries.length || new Set(entries.map((entry) => entry.requestId)).size !== entries.length) {
165
+ throw new Error("duplicate execution identity");
166
+ }
167
+ return {
168
+ version: 1,
169
+ entries
170
+ };
171
+ } catch (error) {
172
+ throw new Error("wallet send execution ledger is unreadable; refusing to reset it", { cause: error });
173
+ }
174
+ }
175
+ function saveLedger(file, env) {
176
+ writeWalletStateFileAtomically(ledgerPath(env), serializeWalletState(file));
177
+ }
178
+ async function withMutationLock(env, task) {
179
+ const filePath = ledgerPath(env);
180
+ const previous = MUTATION_QUEUES.get(filePath) ?? Promise.resolve();
181
+ let releaseQueue;
182
+ const turn = new Promise((resolve) => {
183
+ releaseQueue = resolve;
184
+ });
185
+ const queued = previous.then(() => turn, () => turn);
186
+ MUTATION_QUEUES.set(filePath, queued);
187
+ await previous.catch(() => undefined);
188
+ try {
189
+ return await withFileLock(filePath, MUTATION_LOCK_OPTIONS, async () => await task());
190
+ } finally {
191
+ releaseQueue();
192
+ if (MUTATION_QUEUES.get(filePath) === queued) {
193
+ MUTATION_QUEUES.delete(filePath);
194
+ }
195
+ }
196
+ }
197
+ function getWalletSendExecution(params) {
198
+ const executionIntentId = params.executionIntentId.trim();
199
+ if (!executionIntentId) {
200
+ return undefined;
201
+ }
202
+ return loadLedger(params.env ?? process.env).entries.find((entry) => entry.executionIntentId === executionIntentId);
203
+ }
204
+ async function beginWalletSendExecution(params) {
205
+ const env = params.env ?? process.env;
206
+ const executionIntentId = params.executionIntentId.trim();
207
+ const walletId = params.walletId.trim();
208
+ const providerId = params.providerId.trim();
209
+ const requestId = walletSendRequestId(executionIntentId);
210
+ if (!walletId || !providerId || !/^sha256:[0-9a-f]{64}$/u.test(params.intentDigest)) {
211
+ throw new Error("wallet send execution identity is incomplete");
212
+ }
213
+ return await withMutationLock(env, () => {
214
+ const file = loadLedger(env);
215
+ const existing = file.entries.find((entry) => entry.executionIntentId === executionIntentId);
216
+ if (existing) {
217
+ if (existing.intentDigest !== params.intentDigest || existing.walletId !== walletId || existing.providerId !== providerId || existing.requestId !== requestId) {
218
+ throw new Error("wallet send executionIntentId is already bound to a different immutable intent");
219
+ }
220
+ return {
221
+ entry: existing,
222
+ created: false
223
+ };
224
+ }
225
+ const now = new Date().toISOString();
226
+ const entry = {
227
+ executionIntentId,
228
+ intentDigest: params.intentDigest,
229
+ requestId,
230
+ walletId,
231
+ providerId,
232
+ state: "reserved",
233
+ createdAt: now,
234
+ updatedAt: now
235
+ };
236
+ file.entries.push(entry);
237
+ saveLedger(file, env);
238
+ return {
239
+ entry,
240
+ created: true
241
+ };
242
+ });
243
+ }
244
+ async function updateWalletSendExecution(params) {
245
+ const env = params.env ?? process.env;
246
+ return await withMutationLock(env, () => {
247
+ const file = loadLedger(env);
248
+ const entry = file.entries.find((candidate) => candidate.executionIntentId === params.executionIntentId.trim());
249
+ if (!entry) {
250
+ throw new Error("wallet send execution entry not found");
251
+ }
252
+ if (!params.expectedStates.includes(entry.state)) {
253
+ throw new Error(`wallet send execution is ${entry.state}; expected ${params.expectedStates.join(" or ")}`);
254
+ }
255
+ if (!TRANSITIONS[entry.state].has(params.state)) {
256
+ throw new Error(`wallet send execution cannot transition from ${entry.state} to ${params.state}`);
257
+ }
258
+ Object.assign(entry, params.patch ?? {});
259
+ entry.state = params.state;
260
+ entry.updatedAt = new Date().toISOString();
261
+ saveLedger(file, env);
262
+ return entry;
263
+ });
264
+ }
265
+ async function claimWalletSendExecution(executionIntentIdRaw, env = process.env) {
266
+ const executionIntentId = executionIntentIdRaw.trim();
267
+ walletSendRequestId(executionIntentId);
268
+ const executionKey = `${ledgerPath(env)}\0${executionIntentId}`;
269
+ if (ACTIVE_EXECUTIONS.has(executionKey)) {
270
+ throw new Error("wallet send execution is already in progress");
271
+ }
272
+ ACTIVE_EXECUTIONS.set(executionKey, true);
273
+ let lock;
274
+ try {
275
+ lock = await acquireFileLock(executionLockTarget(executionIntentId, env), EXECUTION_LOCK_OPTIONS);
276
+ } catch (error) {
277
+ ACTIVE_EXECUTIONS.delete(executionKey);
278
+ throw new Error("wallet send execution is already in progress", { cause: error });
279
+ }
280
+ let released = false;
281
+ return async () => {
282
+ if (released) {
283
+ return;
284
+ }
285
+ released = true;
286
+ ACTIVE_EXECUTIONS.delete(executionKey);
287
+ await lock.release();
288
+ };
289
+ }
290
+
291
+ //#endregion
292
+ export { beginWalletSendExecution, claimWalletSendExecution, getWalletSendExecution, updateWalletSendExecution, walletSendIntentDigest, walletSendRequestId };
@@ -1,4 +1,5 @@
1
1
  import { ensureWalletStateDir } from "./wallet-runtime-config.js";
2
+ import { serializeWalletState, writeWalletStateFileAtomically } from "./wallet-atomic-state.js";
2
3
  import syncFs from "node:fs";
3
4
  import path from "node:path";
4
5
 
@@ -6,6 +7,13 @@ import path from "node:path";
6
7
  function linksFilePath(env = process.env) {
7
8
  return path.join(ensureWalletStateDir(env).rootDir, "wallet-settlement-links.json");
8
9
  }
10
+ function isWalletSettlementLink(value) {
11
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
12
+ return false;
13
+ }
14
+ const entry = value;
15
+ return typeof entry.requestId === "string" && Boolean(entry.requestId.trim()) && typeof entry.taskId === "string" && Boolean(entry.taskId.trim()) && (entry.mode === "manual" || entry.mode === "autonomous") && (entry.status === "pending" || entry.status === "unknown" || entry.status === "executed" || entry.status === "failed" || entry.status === "rejected") && typeof entry.createdAt === "string" && Boolean(entry.createdAt) && typeof entry.updatedAt === "string" && Boolean(entry.updatedAt);
16
+ }
9
17
  function loadFile(env = process.env) {
10
18
  const filePath = linksFilePath(env);
11
19
  if (!syncFs.existsSync(filePath)) {
@@ -16,27 +24,20 @@ function loadFile(env = process.env) {
16
24
  }
17
25
  try {
18
26
  const parsed = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
19
- if (parsed?.version === 1 && Array.isArray(parsed.links)) {
27
+ if (parsed?.version === 1 && Array.isArray(parsed.links) && parsed.links.every(isWalletSettlementLink)) {
20
28
  return {
21
29
  version: 1,
22
30
  links: parsed.links
23
31
  };
24
32
  }
25
- } catch {}
26
- return {
27
- version: 1,
28
- links: []
29
- };
33
+ } catch (error) {
34
+ throw new Error("wallet settlement state is unreadable; refusing to reset request links", { cause: error });
35
+ }
36
+ throw new Error("wallet settlement state has an unsupported shape; refusing to reset links");
30
37
  }
31
38
  function saveFile(file, env = process.env) {
32
39
  const filePath = linksFilePath(env);
33
- syncFs.writeFileSync(filePath, `${JSON.stringify(file, null, 2)}\n`, {
34
- encoding: "utf8",
35
- mode: 384
36
- });
37
- try {
38
- syncFs.chmodSync(filePath, 384);
39
- } catch {}
40
+ writeWalletStateFileAtomically(filePath, serializeWalletState(file));
40
41
  }
41
42
  function upsertWalletSettlementLink(params) {
42
43
  const env = params.env ?? process.env;
@@ -0,0 +1,353 @@
1
+ import { withFileLock } from "../plugin-sdk/file-lock.js";
2
+ import "../infra/file-lock.js";
3
+ import { ensureWalletStateDir } from "./wallet-runtime-config.js";
4
+ import { fetchSolanaRpc } from "./solana-assets.js";
5
+ import { WalletProviderError } from "./wallet-provider-adapter.js";
6
+ import { broadcastReviewedSolanaTransaction, buildReviewedSolanaTransaction, computeReviewedSolanaRequestDigest, reconcileReviewedSolanaTransaction, validateReviewedSolanaSignedTransaction } from "./solana-reviewed-transaction.js";
7
+ import syncFs from "node:fs";
8
+ import path from "node:path";
9
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
10
+
11
+ //#region src/wallet/wallet-standard-review.ts
12
+ const REVIEW_FILE_NAME = "wallet-standard-reviews.v1.json";
13
+ const REVIEW_TTL_MS = 2 * 60 * 1e3;
14
+ const REVIEW_FILE_MODE = 384;
15
+ const MAX_REVIEW_RECORDS = 1e4;
16
+ const MAX_RETAINED_TERMINAL_REVIEWS = 5e3;
17
+ const TERMINAL_REVIEW_RETENTION_MS = 30 * 24 * 60 * 6e4;
18
+ const REVIEW_LOCK_OPTIONS = {
19
+ retries: {
20
+ retries: 80,
21
+ factor: 1.15,
22
+ minTimeout: 20,
23
+ maxTimeout: 200,
24
+ randomize: true
25
+ },
26
+ stale: 3e4
27
+ };
28
+ const SOLANA_MAINNET_GENESIS_HASH = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
29
+ const SOLANA_DEVNET_GENESIS_HASH = "EtWTRABZaYq6iMfeYKouRu166VU2xqa1";
30
+ let reviewStateLock = Promise.resolve();
31
+ function reviewPath(env) {
32
+ return path.join(ensureWalletStateDir(env).rootDir, REVIEW_FILE_NAME);
33
+ }
34
+ function readFile(env) {
35
+ const filePath = reviewPath(env);
36
+ if (!syncFs.existsSync(filePath)) {
37
+ return {
38
+ version: 1,
39
+ reviews: []
40
+ };
41
+ }
42
+ try {
43
+ const parsed = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
44
+ if (parsed.version === 1 && Array.isArray(parsed.reviews)) {
45
+ return parsed;
46
+ }
47
+ } catch {}
48
+ throw new WalletProviderError({
49
+ code: "wallet_provider_unavailable",
50
+ message: "Wallet Standard review state is invalid; repair it before approving Vault sends",
51
+ retryable: false
52
+ });
53
+ }
54
+ function saveFile(file, env) {
55
+ const filePath = reviewPath(env);
56
+ const temporary = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
57
+ let descriptor;
58
+ try {
59
+ descriptor = syncFs.openSync(temporary, "wx", REVIEW_FILE_MODE);
60
+ syncFs.writeFileSync(descriptor, `${JSON.stringify(file, null, 2)}\n`, "utf8");
61
+ syncFs.fsyncSync(descriptor);
62
+ syncFs.closeSync(descriptor);
63
+ descriptor = undefined;
64
+ syncFs.renameSync(temporary, filePath);
65
+ try {
66
+ syncFs.chmodSync(filePath, REVIEW_FILE_MODE);
67
+ } catch {}
68
+ try {
69
+ const directory = syncFs.openSync(path.dirname(filePath), "r");
70
+ try {
71
+ syncFs.fsyncSync(directory);
72
+ } finally {
73
+ syncFs.closeSync(directory);
74
+ }
75
+ } catch {}
76
+ } catch (error) {
77
+ if (descriptor !== undefined) {
78
+ syncFs.closeSync(descriptor);
79
+ }
80
+ try {
81
+ syncFs.unlinkSync(temporary);
82
+ } catch {}
83
+ throw error;
84
+ }
85
+ }
86
+ function compactReviewState(file, nowMs = Date.now()) {
87
+ const terminal = file.reviews.filter((review) => review.status === "broadcast" || review.status === "failed").toSorted((left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt));
88
+ const removable = new Set(terminal.filter((review, index) => nowMs - Date.parse(review.createdAt) > TERMINAL_REVIEW_RETENTION_MS || terminal.length - index > MAX_RETAINED_TERMINAL_REVIEWS).map((review) => review.requestId));
89
+ return {
90
+ version: 1,
91
+ reviews: file.reviews.filter((review) => !removable.has(review.requestId))
92
+ };
93
+ }
94
+ function requireReviewCapacity(file) {
95
+ if (file.reviews.length >= MAX_REVIEW_RECORDS) {
96
+ throw new WalletProviderError({
97
+ code: "wallet_provider_unavailable",
98
+ message: "Wallet Standard review state reached its durable safety limit; reconcile unresolved reviews",
99
+ retryable: false
100
+ });
101
+ }
102
+ }
103
+ function secureEqual(left, right) {
104
+ const leftBytes = Buffer.from(left, "utf8");
105
+ const rightBytes = Buffer.from(right, "utf8");
106
+ return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);
107
+ }
108
+ function rpcUrlDigest(rpcUrl) {
109
+ let normalized;
110
+ try {
111
+ const parsed = new URL(rpcUrl.trim());
112
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
113
+ throw new Error("unsupported protocol");
114
+ }
115
+ normalized = parsed.toString();
116
+ } catch {
117
+ throw new WalletProviderError({
118
+ code: "wallet_provider_invalid_config",
119
+ message: "Wallet Standard review requires a valid HTTP(S) Solana RPC URL"
120
+ });
121
+ }
122
+ return createHash("sha256").update(normalized, "utf8").digest("base64url");
123
+ }
124
+ async function resolveWalletStandardChain(rpcUrl) {
125
+ const genesisHash = await fetchSolanaRpc(rpcUrl, "getGenesisHash", []);
126
+ if (genesisHash === SOLANA_MAINNET_GENESIS_HASH) {
127
+ return "solana:mainnet";
128
+ }
129
+ if (genesisHash === SOLANA_DEVNET_GENESIS_HASH) {
130
+ return "solana:devnet";
131
+ }
132
+ throw new WalletProviderError({
133
+ code: "wallet_provider_invalid_config",
134
+ message: "Hardware Vault supports only verified Solana mainnet or devnet RPC endpoints"
135
+ });
136
+ }
137
+ async function withReviewLock(env, task) {
138
+ const run = async () => await withFileLock(reviewPath(env), REVIEW_LOCK_OPTIONS, async () => await task());
139
+ const current = reviewStateLock.then(run, run);
140
+ reviewStateLock = current.then(() => undefined, () => undefined);
141
+ return await current;
142
+ }
143
+ function toPrepareResult(record) {
144
+ return {
145
+ requestId: record.requestId,
146
+ preparedId: record.preparedId,
147
+ signer: record.signer,
148
+ unsignedTxBase64: record.unsignedTxBase64,
149
+ messageBase64: record.messageBase64,
150
+ intentDigest: record.intentDigest,
151
+ expiresAt: record.expiresAt,
152
+ chain: record.chain,
153
+ simulation: {
154
+ ok: true,
155
+ ...typeof record.simulationUnitsConsumed === "number" && Number.isFinite(record.simulationUnitsConsumed) ? { unitsConsumed: record.simulationUnitsConsumed } : {}
156
+ }
157
+ };
158
+ }
159
+ async function prepareWalletStandardReview(params) {
160
+ const env = params.env ?? process.env;
161
+ const requestId = params.requestId.trim();
162
+ if (!requestId) {
163
+ throw new WalletProviderError({
164
+ code: "wallet_provider_invalid_config",
165
+ message: "Wallet Standard review requires an approval request ID"
166
+ });
167
+ }
168
+ return await withReviewLock(env, async () => {
169
+ const requestDigest = computeReviewedSolanaRequestDigest({
170
+ request: params.payload,
171
+ signer: params.signerAddress.trim()
172
+ });
173
+ const expectedRpcUrlDigest = rpcUrlDigest(params.rpcUrl);
174
+ const file = compactReviewState(readFile(env));
175
+ const existing = file.reviews.find((review) => review.requestId === requestId);
176
+ if (existing) {
177
+ const sameRequest = Boolean(existing.requestDigest) && secureEqual(existing.requestDigest, requestDigest);
178
+ const sameRpc = Boolean(existing.rpcUrlDigest) && secureEqual(existing.rpcUrlDigest, expectedRpcUrlDigest);
179
+ if (sameRequest && sameRpc && existing.status === "prepared" && Date.parse(existing.expiresAt) > Date.now()) {
180
+ return toPrepareResult(existing);
181
+ }
182
+ throw new WalletProviderError({
183
+ code: existing.status === "broadcasting" || existing.status === "unknown" ? "wallet_provider_ambiguous" : "wallet_provider_invalid_config",
184
+ message: "This approval request ID already has an immutable Wallet Standard review; create a new approval request",
185
+ retryable: false
186
+ });
187
+ }
188
+ requireReviewCapacity(file);
189
+ const chain = await resolveWalletStandardChain(params.rpcUrl);
190
+ const prepared = await buildReviewedSolanaTransaction({
191
+ request: params.payload,
192
+ signerAddress: params.signerAddress,
193
+ rpcUrl: params.rpcUrl
194
+ });
195
+ const now = Date.now();
196
+ const record = {
197
+ requestId,
198
+ preparedId: randomBytes(32).toString("base64url"),
199
+ createdAt: new Date(now).toISOString(),
200
+ expiresAt: new Date(now + REVIEW_TTL_MS).toISOString(),
201
+ status: "prepared",
202
+ signer: prepared.signer,
203
+ requestDigest,
204
+ intentDigest: prepared.intentDigest,
205
+ unsignedTxBase64: prepared.unsignedTxBase64,
206
+ messageBase64: prepared.messageBase64,
207
+ recentBlockhash: prepared.recentBlockhash,
208
+ lastValidBlockHeight: prepared.lastValidBlockHeight,
209
+ chain,
210
+ rpcUrlDigest: expectedRpcUrlDigest,
211
+ simulationUnitsConsumed: prepared.simulation.unitsConsumed
212
+ };
213
+ file.reviews.push(record);
214
+ saveFile(file, env);
215
+ return toPrepareResult(record);
216
+ });
217
+ }
218
+ async function executeLocked(params) {
219
+ const file = readFile(params.env);
220
+ const review = file.reviews.find((entry) => entry.requestId === params.requestId);
221
+ if (!review || !secureEqual(review.preparedId, params.preparedId)) {
222
+ throw new WalletProviderError({
223
+ code: "wallet_provider_invalid_config",
224
+ message: "Wallet Standard review is missing or does not match this approval"
225
+ });
226
+ }
227
+ if (!secureEqual(review.intentDigest, params.intentDigest)) {
228
+ throw new WalletProviderError({
229
+ code: "wallet_provider_invalid_config",
230
+ message: "Wallet Standard intent digest does not match the approved transaction"
231
+ });
232
+ }
233
+ if (!review.rpcUrlDigest || !secureEqual(review.rpcUrlDigest, rpcUrlDigest(params.rpcUrl))) {
234
+ throw new WalletProviderError({
235
+ code: "wallet_provider_invalid_config",
236
+ message: "Solana RPC configuration changed after review; approve again"
237
+ });
238
+ }
239
+ if (review.status === "broadcast" && review.txHash) {
240
+ return {
241
+ ok: true,
242
+ txHash: review.txHash,
243
+ signer: review.signer,
244
+ idempotent: true
245
+ };
246
+ }
247
+ if (review.status === "broadcasting" || review.status === "unknown") {
248
+ if (!review.txHash) {
249
+ throw new WalletProviderError({
250
+ code: "wallet_provider_ambiguous",
251
+ message: "Hardware-wallet broadcast is already in progress or unknown; do not submit it again",
252
+ retryable: false
253
+ });
254
+ }
255
+ let reconciled;
256
+ try {
257
+ reconciled = await reconcileReviewedSolanaTransaction({
258
+ rpcUrl: params.rpcUrl,
259
+ expectedTxHash: review.txHash,
260
+ lastValidBlockHeight: review.lastValidBlockHeight
261
+ });
262
+ } catch {
263
+ throw new WalletProviderError({
264
+ code: "wallet_provider_ambiguous",
265
+ message: `Hardware-wallet broadcast remains unknown; reconcile signature ${review.txHash} before any new send`,
266
+ retryable: false
267
+ });
268
+ }
269
+ if (reconciled.state === "landed") {
270
+ review.status = "broadcast";
271
+ saveFile(file, params.env);
272
+ return {
273
+ ok: true,
274
+ txHash: review.txHash,
275
+ signer: review.signer,
276
+ idempotent: true
277
+ };
278
+ }
279
+ if (reconciled.state === "failed" || reconciled.state === "expired") {
280
+ review.status = "failed";
281
+ review.failureReason = reconciled.state === "failed" ? reconciled.reason : `reviewed transaction expired at block height ${review.lastValidBlockHeight} without landing`;
282
+ saveFile(file, params.env);
283
+ throw new WalletProviderError({
284
+ code: "wallet_provider_unavailable",
285
+ message: `${review.failureReason}; create and approve a new Wallet Standard review`,
286
+ retryable: false
287
+ });
288
+ }
289
+ throw new WalletProviderError({
290
+ code: "wallet_provider_ambiguous",
291
+ message: `Hardware-wallet broadcast remains pending; reconcile signature ${review.txHash} before any new send`,
292
+ retryable: false
293
+ });
294
+ }
295
+ if (review.status === "failed") {
296
+ throw new WalletProviderError({
297
+ code: "wallet_provider_unavailable",
298
+ message: `${review.failureReason ?? "Wallet Standard transaction failed"}; create and approve a new Wallet Standard review`,
299
+ retryable: false
300
+ });
301
+ }
302
+ if (Date.parse(review.expiresAt) <= Date.now()) {
303
+ throw new WalletProviderError({
304
+ code: "wallet_provider_invalid_config",
305
+ message: "Hardware-wallet review expired; approve again to receive a fresh blockhash"
306
+ });
307
+ }
308
+ const verified = validateReviewedSolanaSignedTransaction({
309
+ unsignedTxBase64: review.unsignedTxBase64,
310
+ signedTxBase64: params.signedTxBase64,
311
+ signerAddress: review.signer
312
+ });
313
+ review.status = "broadcasting";
314
+ review.txHash = verified.txHash;
315
+ review.signedTxBase64 = verified.signedBytes.toString("base64");
316
+ saveFile(file, params.env);
317
+ try {
318
+ const txHash = await broadcastReviewedSolanaTransaction({
319
+ rpcUrl: params.rpcUrl,
320
+ signedTxBase64: review.signedTxBase64,
321
+ expectedTxHash: verified.txHash
322
+ });
323
+ review.status = "broadcast";
324
+ review.txHash = txHash;
325
+ saveFile(file, params.env);
326
+ return {
327
+ ok: true,
328
+ txHash,
329
+ signer: review.signer,
330
+ idempotent: false
331
+ };
332
+ } catch (error) {
333
+ review.status = "unknown";
334
+ saveFile(file, params.env);
335
+ throw error;
336
+ }
337
+ }
338
+ async function executeWalletStandardReview(params) {
339
+ const env = params.env ?? process.env;
340
+ const requestId = params.requestId.trim();
341
+ return await withReviewLock(env, async () => await executeLocked({
342
+ ...params,
343
+ requestId,
344
+ env
345
+ }));
346
+ }
347
+ function readWalletStandardReviewTxHash(params) {
348
+ const file = readFile(params.env ?? process.env);
349
+ return file.reviews.find((review) => review.requestId === params.requestId.trim())?.txHash;
350
+ }
351
+
352
+ //#endregion
353
+ export { executeWalletStandardReview, prepareWalletStandardReview, readWalletStandardReviewTxHash };