@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,349 @@
1
+ import { resolveStateDir } from "../../../config/paths.js";
2
+ import { withFileLock } from "../../../plugin-sdk/file-lock.js";
3
+ import "../../../plugin-sdk/sat-runtime.js";
4
+ import path from "node:path";
5
+ import fs from "node:fs/promises";
6
+ import { createHash, randomUUID } from "node:crypto";
7
+
8
+ //#region extensions/sat-mining/src/submission-ledger.ts
9
+ const DEFAULT_LOCK_OPTIONS = {
10
+ retries: {
11
+ retries: 120,
12
+ factor: 1.15,
13
+ minTimeout: 10,
14
+ maxTimeout: 100,
15
+ randomize: true
16
+ },
17
+ stale: 12e4
18
+ };
19
+ const localLedgerWriteChains = new Map();
20
+ async function withSatSubmissionLedgerLock(filePath, task) {
21
+ const previous = localLedgerWriteChains.get(filePath) ?? Promise.resolve();
22
+ let releaseLocal;
23
+ const localGate = new Promise((resolve) => {
24
+ releaseLocal = resolve;
25
+ });
26
+ const current = previous.catch(() => undefined).then(async () => await localGate);
27
+ localLedgerWriteChains.set(filePath, current);
28
+ await previous.catch(() => undefined);
29
+ try {
30
+ return await withFileLock(filePath, DEFAULT_LOCK_OPTIONS, task);
31
+ } finally {
32
+ releaseLocal();
33
+ void current.finally(() => {
34
+ if (localLedgerWriteChains.get(filePath) === current) {
35
+ localLedgerWriteChains.delete(filePath);
36
+ }
37
+ });
38
+ }
39
+ }
40
+ function sha256(value) {
41
+ return createHash("sha256").update(value).digest("hex");
42
+ }
43
+ function canonicalize(value) {
44
+ if (Array.isArray(value)) {
45
+ return value.map((entry) => canonicalize(entry));
46
+ }
47
+ if (value && typeof value === "object") {
48
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonicalize(entry)]));
49
+ }
50
+ if (typeof value === "bigint") {
51
+ return value.toString();
52
+ }
53
+ return value;
54
+ }
55
+ function digestSatSubmissionIntent(value) {
56
+ return `sha256:${sha256(JSON.stringify(canonicalize(value)))}`;
57
+ }
58
+ function buildSatSubmissionOperationKey(intent) {
59
+ const action = typeof intent.action === "string" && intent.action.trim() ? intent.action.trim() : "sat";
60
+ const accountShape = Array.isArray(intent.instructions) ? intent.instructions.map((instruction) => {
61
+ const candidate = instruction;
62
+ return {
63
+ action: candidate.action,
64
+ keys: candidate.keys
65
+ };
66
+ }) : intent.keys;
67
+ return `${action}:${sha256(JSON.stringify(canonicalize(accountShape))).slice(0, 24)}`;
68
+ }
69
+ function normalizeStateKey(value) {
70
+ const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "_");
71
+ return normalized || "unattached";
72
+ }
73
+ function resolveSatSubmissionLedgerPath(params) {
74
+ const env = params.env ?? process.env;
75
+ return path.join(resolveStateDir(env), "sat-mining", "wallets", normalizeStateKey(params.walletId), "submission-ledger.json");
76
+ }
77
+ function emptyLedger() {
78
+ return {
79
+ version: 1,
80
+ records: {}
81
+ };
82
+ }
83
+ function normalizeRecord(value) {
84
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
85
+ return null;
86
+ }
87
+ const record = value;
88
+ if (typeof record.requestId !== "string" || typeof record.workflowId !== "string" || typeof record.operationKey !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(String(record.intentDigest ?? "")) || typeof record.walletId !== "string" || typeof record.action !== "string" || ![
89
+ "prepared",
90
+ "reserved",
91
+ "broadcast",
92
+ "confirmed",
93
+ "failed",
94
+ "unknown"
95
+ ].includes(String(record.state ?? ""))) {
96
+ return null;
97
+ }
98
+ return record;
99
+ }
100
+ async function readLedger(filePath) {
101
+ try {
102
+ const parsed = JSON.parse(await fs.readFile(filePath, "utf8"));
103
+ if (parsed.version !== 1 || !parsed.records || typeof parsed.records !== "object") {
104
+ throw new Error(`invalid SAT submission ledger format at ${filePath}`);
105
+ }
106
+ const records = {};
107
+ for (const [requestId, raw] of Object.entries(parsed.records)) {
108
+ const record = normalizeRecord(raw);
109
+ if (!record || record.requestId !== requestId) {
110
+ throw new Error(`invalid SAT submission ledger record ${requestId}`);
111
+ }
112
+ records[requestId] = record;
113
+ }
114
+ return {
115
+ version: 1,
116
+ records
117
+ };
118
+ } catch (error) {
119
+ if (error.code === "ENOENT") {
120
+ return emptyLedger();
121
+ }
122
+ throw error;
123
+ }
124
+ }
125
+ async function writeLedger(filePath, ledger) {
126
+ await fs.mkdir(path.dirname(filePath), {
127
+ recursive: true,
128
+ mode: 448
129
+ });
130
+ const tempPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
131
+ const handle = await fs.open(tempPath, "wx", 384);
132
+ try {
133
+ await handle.writeFile(`${JSON.stringify(ledger, null, 2)}\n`, "utf8");
134
+ await handle.sync();
135
+ } finally {
136
+ await handle.close();
137
+ }
138
+ try {
139
+ await fs.rename(tempPath, filePath);
140
+ const directory = await fs.open(path.dirname(filePath), "r");
141
+ try {
142
+ await directory.sync();
143
+ } finally {
144
+ await directory.close();
145
+ }
146
+ } catch (error) {
147
+ await fs.rm(tempPath, { force: true }).catch(() => undefined);
148
+ throw error;
149
+ }
150
+ }
151
+ function leaseDurationMs(env) {
152
+ const configured = Number(env.FASED_SAT_SUBMISSION_LEASE_MS ?? "");
153
+ if (Number.isFinite(configured) && configured >= 50 && configured <= 3e5) {
154
+ return Math.floor(configured);
155
+ }
156
+ return 6e4;
157
+ }
158
+ function isPidAlive(pid) {
159
+ if (!Number.isSafeInteger(pid) || pid <= 0) {
160
+ return false;
161
+ }
162
+ try {
163
+ process.kill(pid, 0);
164
+ return true;
165
+ } catch (error) {
166
+ return error.code === "EPERM";
167
+ }
168
+ }
169
+ function leaseIsLive(lease, now = Date.now()) {
170
+ if (!lease || Date.parse(lease.expiresAt) <= now) {
171
+ return false;
172
+ }
173
+ return lease.pid === process.pid || isPidAlive(lease.pid);
174
+ }
175
+ function assertStateTransition(requestId, current, next) {
176
+ const allowed = {
177
+ prepared: new Set([
178
+ "prepared",
179
+ "reserved",
180
+ "broadcast",
181
+ "confirmed",
182
+ "failed",
183
+ "unknown"
184
+ ]),
185
+ reserved: new Set([
186
+ "reserved",
187
+ "broadcast",
188
+ "confirmed",
189
+ "failed",
190
+ "unknown"
191
+ ]),
192
+ broadcast: new Set([
193
+ "broadcast",
194
+ "confirmed",
195
+ "failed",
196
+ "unknown"
197
+ ]),
198
+ unknown: new Set([
199
+ "broadcast",
200
+ "confirmed",
201
+ "failed",
202
+ "unknown"
203
+ ]),
204
+ confirmed: new Set(["confirmed"]),
205
+ failed: new Set(["failed"])
206
+ };
207
+ if (!allowed[current].has(next)) {
208
+ throw new Error(`SAT submission ${requestId} cannot move from ${current} back to ${next}`);
209
+ }
210
+ }
211
+ function buildSatSubmissionRequestId(params) {
212
+ const digest = sha256(JSON.stringify([
213
+ "fased-sat-submission-v1",
214
+ params.walletId,
215
+ params.workflowId,
216
+ params.operationKey
217
+ ]));
218
+ return `sat-v2-${digest.slice(0, 48)}`;
219
+ }
220
+ async function claimSatSubmission(params) {
221
+ const env = params.env ?? process.env;
222
+ const filePath = resolveSatSubmissionLedgerPath({
223
+ walletId: params.walletId,
224
+ env
225
+ });
226
+ const requestId = buildSatSubmissionRequestId(params);
227
+ const owner = params.owner ?? `${process.pid}:${randomUUID()}`;
228
+ return await withSatSubmissionLedgerLock(filePath, async () => {
229
+ const ledger = await readLedger(filePath);
230
+ const existing = ledger.records[requestId];
231
+ if (existing) {
232
+ if (existing.intentDigest !== params.intentDigest || existing.walletId !== params.walletId || existing.workflowId !== params.workflowId || existing.operationKey !== params.operationKey) {
233
+ throw new Error(`SAT idempotency collision for ${requestId}: the workflow key is already bound to a different immutable intent digest`);
234
+ }
235
+ if (leaseIsLive(existing.lease) && existing.lease?.owner !== owner) {
236
+ return {
237
+ record: existing,
238
+ created: false,
239
+ claimed: false,
240
+ owner
241
+ };
242
+ }
243
+ const now = new Date().toISOString();
244
+ existing.lease = {
245
+ owner,
246
+ pid: process.pid,
247
+ acquiredAt: now,
248
+ expiresAt: new Date(Date.now() + leaseDurationMs(env)).toISOString()
249
+ };
250
+ existing.attempts += 1;
251
+ existing.updatedAt = now;
252
+ await writeLedger(filePath, ledger);
253
+ return {
254
+ record: existing,
255
+ created: false,
256
+ claimed: true,
257
+ owner
258
+ };
259
+ }
260
+ const now = new Date().toISOString();
261
+ const record = {
262
+ requestId,
263
+ workflowId: params.workflowId,
264
+ operationKey: params.operationKey,
265
+ intentDigest: params.intentDigest,
266
+ walletId: params.walletId,
267
+ action: params.action,
268
+ state: "prepared",
269
+ attempts: 1,
270
+ createdAt: now,
271
+ updatedAt: now,
272
+ lease: {
273
+ owner,
274
+ pid: process.pid,
275
+ acquiredAt: now,
276
+ expiresAt: new Date(Date.now() + leaseDurationMs(env)).toISOString()
277
+ }
278
+ };
279
+ ledger.records[requestId] = record;
280
+ await writeLedger(filePath, ledger);
281
+ return {
282
+ record,
283
+ created: true,
284
+ claimed: true,
285
+ owner
286
+ };
287
+ });
288
+ }
289
+ async function readSatSubmission(params) {
290
+ const filePath = resolveSatSubmissionLedgerPath(params);
291
+ return await withSatSubmissionLedgerLock(filePath, async () => {
292
+ const ledger = await readLedger(filePath);
293
+ return ledger.records[params.requestId] ?? null;
294
+ });
295
+ }
296
+ async function updateSatSubmission(params) {
297
+ const filePath = resolveSatSubmissionLedgerPath(params);
298
+ return await withSatSubmissionLedgerLock(filePath, async () => {
299
+ const ledger = await readLedger(filePath);
300
+ const record = ledger.records[params.requestId];
301
+ if (!record) {
302
+ throw new Error(`SAT submission ${params.requestId} is missing from its durable ledger`);
303
+ }
304
+ if (record.intentDigest !== params.intentDigest) {
305
+ throw new Error(`SAT submission ${params.requestId} intent digest changed during execution`);
306
+ }
307
+ if (params.owner && record.lease?.owner !== params.owner) {
308
+ throw new Error(`SAT submission ${params.requestId} lease ownership changed during execution`);
309
+ }
310
+ if (record.signature && params.signature && record.signature !== params.signature) {
311
+ throw new Error(`SAT submission ${params.requestId} returned a different transaction signature`);
312
+ }
313
+ assertStateTransition(params.requestId, record.state, params.state);
314
+ record.state = params.state;
315
+ if (params.signature !== undefined) {
316
+ record.signature = params.signature;
317
+ }
318
+ if (params.error !== undefined) {
319
+ record.error = params.error;
320
+ } else if (params.state === "confirmed") {
321
+ delete record.error;
322
+ }
323
+ if (params.releaseLease) {
324
+ delete record.lease;
325
+ }
326
+ record.updatedAt = new Date().toISOString();
327
+ await writeLedger(filePath, ledger);
328
+ return record;
329
+ });
330
+ }
331
+ async function waitForSatSubmissionLease(params) {
332
+ const timeoutAt = Date.now() + Math.max(100, params.timeoutMs ?? 65e3);
333
+ for (;;) {
334
+ const record = await readSatSubmission(params);
335
+ if (!record) {
336
+ throw new Error(`SAT submission ${params.requestId} disappeared while waiting for its lease`);
337
+ }
338
+ if (!leaseIsLive(record.lease)) {
339
+ return record;
340
+ }
341
+ if (Date.now() >= timeoutAt) {
342
+ throw new Error(`SAT submission ${params.requestId} is already executing in another process; retry the same idempotency key`);
343
+ }
344
+ await new Promise((resolve) => setTimeout(resolve, 25));
345
+ }
346
+ }
347
+
348
+ //#endregion
349
+ export { buildSatSubmissionOperationKey, claimSatSubmission, digestSatSubmissionIntent, updateSatSubmission, waitForSatSubmissionLease };
@@ -1,7 +1,7 @@
1
1
  import { resolveStateDir } from "../config/paths.js";
2
2
  import { isTruthyEnvValue } from "../infra/env.js";
3
3
  import { resolveAgentPublicOrigin, resolveFederationBaseUrl, resolveFederationBondWalletId, resolveFederationHandle } from "./runtime.js";
4
- import { resolveFederationBondWallet, signFederationBondChallenge } from "../wallet/solana-bond-signing.js";
4
+ import { FEDERATION_BOND_SIGNATURE_DOMAIN, federationBondSigningMessageBase64, resolveFederationBondWallet, signFederationBondChallenge } from "../wallet/solana-bond-signing.js";
5
5
  import { buildAttestation } from "./attestation.js";
6
6
  import path from "node:path";
7
7
  import fs from "node:fs/promises";
@@ -116,7 +116,7 @@ async function loadPersistedFederationBondProof(env) {
116
116
  try {
117
117
  const raw = await fs.readFile(proofPath, "utf-8");
118
118
  const parsed = JSON.parse(raw);
119
- if (typeof parsed.challengeId !== "string" || typeof parsed.bondId !== "string" || typeof parsed.walletId !== "string" || typeof parsed.walletAddress !== "string" || typeof parsed.handle !== "string" || typeof parsed.nodeId !== "string" || typeof parsed.federationBaseUrl !== "string" || typeof parsed.expiresAt !== "string" || typeof parsed.payload !== "string" || typeof parsed.payloadBase64 !== "string" || typeof parsed.signatureBase64 !== "string" || typeof parsed.signedAt !== "string") {
119
+ if (typeof parsed.challengeId !== "string" || typeof parsed.bondId !== "string" || typeof parsed.walletId !== "string" || typeof parsed.walletAddress !== "string" || typeof parsed.handle !== "string" || typeof parsed.nodeId !== "string" || typeof parsed.federationBaseUrl !== "string" || typeof parsed.expiresAt !== "string" || typeof parsed.payload !== "string" || typeof parsed.payloadBase64 !== "string" || parsed.signatureDomain !== FEDERATION_BOND_SIGNATURE_DOMAIN || typeof parsed.signedMessageBase64 !== "string" || typeof parsed.signatureBase64 !== "string" || typeof parsed.signedAt !== "string") {
120
120
  return null;
121
121
  }
122
122
  return {
@@ -130,6 +130,8 @@ async function loadPersistedFederationBondProof(env) {
130
130
  expiresAt: parsed.expiresAt,
131
131
  payload: parsed.payload,
132
132
  payloadBase64: parsed.payloadBase64,
133
+ signatureDomain: FEDERATION_BOND_SIGNATURE_DOMAIN,
134
+ signedMessageBase64: parsed.signedMessageBase64,
133
135
  signatureBase64: parsed.signatureBase64,
134
136
  signedAt: parsed.signedAt,
135
137
  verifiedAt: typeof parsed.verifiedAt === "string" ? parsed.verifiedAt : undefined,
@@ -371,12 +373,38 @@ async function createFederationBondProof(opts) {
371
373
  const challengeBody = challenge.json ?? {};
372
374
  const challengeId = challengeBody.challengeId?.trim();
373
375
  const expiresAt = challengeBody.expiresAt?.trim();
374
- const payload = challengeBody.payload?.trim() || (challengeBody.payloadBase64 ? Buffer.from(challengeBody.payloadBase64, "base64").toString("utf-8") : "");
375
- if (!challengeId || !expiresAt || !payload) {
376
+ let payloadBase64 = challengeBody.payloadBase64?.trim() ?? "";
377
+ let payload = challengeBody.payload ?? "";
378
+ if (payloadBase64) {
379
+ const decoded = Buffer.from(payloadBase64, "base64");
380
+ if (decoded.toString("base64") !== payloadBase64) {
381
+ throw new Error("federation bond challenge failed: payloadBase64 is not canonical");
382
+ }
383
+ const decodedPayload = decoded.toString("utf-8");
384
+ if (payload && payload !== decodedPayload) {
385
+ throw new Error("federation bond challenge failed: payload encodings disagree");
386
+ }
387
+ payload = decodedPayload;
388
+ } else if (payload) {
389
+ payloadBase64 = Buffer.from(payload, "utf-8").toString("base64");
390
+ }
391
+ if (!challengeId || !expiresAt || !payload || !payloadBase64) {
376
392
  throw new Error("federation bond challenge failed: incomplete challenge payload");
377
393
  }
394
+ if (!opts?.tier) {
395
+ throw new Error("federation bond challenge requires the locally reviewed bond tier");
396
+ }
378
397
  const signedWallet = await signFederationBondChallenge({
379
- payload,
398
+ challengeId,
399
+ federationOrigin: baseUrl,
400
+ payloadBase64,
401
+ handle: federationToken.handle,
402
+ nodeId: federationToken.nodeId,
403
+ tokenId: federationToken.tokenId,
404
+ bondId,
405
+ tier: opts.tier,
406
+ ...opts.amountRaw?.trim() ? { amountRaw: opts.amountRaw.trim() } : {},
407
+ expiresAt,
380
408
  env,
381
409
  cfg: opts?.cfg,
382
410
  walletId: resolvedWallet.walletId
@@ -391,14 +419,74 @@ async function createFederationBondProof(opts) {
391
419
  federationBaseUrl: baseUrl,
392
420
  expiresAt,
393
421
  payload,
394
- payloadBase64: challengeBody.payloadBase64?.trim() || Buffer.from(payload, "utf-8").toString("base64"),
422
+ payloadBase64,
423
+ signatureDomain: FEDERATION_BOND_SIGNATURE_DOMAIN,
424
+ signedMessageBase64: federationBondSigningMessageBase64({
425
+ challengeId,
426
+ federationOrigin: baseUrl,
427
+ payloadBase64
428
+ }),
395
429
  signatureBase64: signedWallet.signatureBase64,
396
- signedAt: new Date().toISOString()
430
+ signedAt: new Date().toISOString(),
431
+ ...opts?.amountRaw?.trim() ? { bondAmountRaw: opts.amountRaw.trim() } : {},
432
+ ...opts?.tier ? { bondTier: opts.tier } : {}
397
433
  };
398
434
  await persistFederationBondProof(env, proof);
399
435
  opts?.log?.info?.(`federation bond proof prepared (${proof.handle} -> ${proof.walletAddress}, bond=${proof.bondId})`);
400
436
  return proof;
401
437
  }
438
+ async function persistFederationBondProofFromSignerReview(params) {
439
+ const env = params.env ?? process.env;
440
+ const review = params.review;
441
+ if (review.state !== "signed" || review.intentType !== "federation.bondChallenge" || review.semanticIntent.type !== "federation.bondChallenge" || review.artifactKind !== "domain-separated-message" || review.asset !== "federation:bond-challenge" || review.amount !== "1" || review.policyOperation !== "federation.bondChallenge" || review.requiredRole !== "vault" || review.requiredPrograms.length !== 1 || review.requiredPrograms[0] !== "domain:fased:federation-bond-challenge-v1") {
442
+ throw new Error("signed signer review is not an exact federation bond challenge");
443
+ }
444
+ const federation = review.semanticIntent.federation;
445
+ const signedMessageBase64 = federationBondSigningMessageBase64(federation);
446
+ if (!review.walletPublicKey || review.destination !== review.walletPublicKey || review.messageBase64 !== signedMessageBase64 || review.signature !== params.signatureBase64) {
447
+ throw new Error("signed federation review artifact does not match its wallet or payload");
448
+ }
449
+ const signature = Buffer.from(params.signatureBase64, "base64");
450
+ if (signature.length !== 64 || signature.toString("base64") !== params.signatureBase64) {
451
+ throw new Error("signed federation review returned a non-canonical Ed25519 signature");
452
+ }
453
+ const payloadBytes = Buffer.from(federation.payloadBase64, "base64");
454
+ if (payloadBytes.toString("base64") !== federation.payloadBase64) {
455
+ throw new Error("signed federation review payload is not canonical base64");
456
+ }
457
+ const payload = payloadBytes.toString("utf8");
458
+ if (!Buffer.from(payload, "utf8").equals(payloadBytes)) {
459
+ throw new Error("signed federation review payload is not valid UTF-8");
460
+ }
461
+ const challengeExpiresAt = Date.parse(federation.expiresAt);
462
+ if (!Number.isFinite(challengeExpiresAt) || challengeExpiresAt <= Date.now()) {
463
+ throw new Error("signed federation review challenge has expired");
464
+ }
465
+ const token = await loadPersistedFederationToken(env, { includeExpired: true });
466
+ if (!token || token.tokenId !== federation.tokenId || token.nodeId !== federation.nodeId || token.handle !== federation.handle) {
467
+ throw new Error("signed federation review does not match the persisted federation identity");
468
+ }
469
+ const configuredOrigin = resolveFederationBaseUrl(env);
470
+ if (!configuredOrigin || new URL(configuredOrigin).origin !== federation.federationOrigin) {
471
+ throw new Error("signed federation review does not match the configured federation origin");
472
+ }
473
+ return await persistFederationBondProof(env, {
474
+ challengeId: federation.challengeId,
475
+ bondId: federation.bondId,
476
+ walletId: params.walletId,
477
+ walletAddress: review.walletPublicKey,
478
+ handle: federation.handle,
479
+ nodeId: federation.nodeId,
480
+ federationBaseUrl: federation.federationOrigin,
481
+ expiresAt: federation.expiresAt,
482
+ payload,
483
+ payloadBase64: federation.payloadBase64,
484
+ signatureDomain: FEDERATION_BOND_SIGNATURE_DOMAIN,
485
+ signedMessageBase64,
486
+ signatureBase64: params.signatureBase64,
487
+ signedAt: review.updatedAt
488
+ });
489
+ }
402
490
  async function submitFederationBondProof(opts) {
403
491
  const env = opts?.env ?? process.env;
404
492
  const proof = opts?.proof ?? await loadPersistedFederationBondProof(env);
@@ -415,6 +503,8 @@ async function submitFederationBondProof(opts) {
415
503
  body: {
416
504
  challengeId: proof.challengeId,
417
505
  payloadBase64: proof.payloadBase64,
506
+ signatureDomain: proof.signatureDomain,
507
+ signedMessageBase64: proof.signedMessageBase64,
418
508
  signatureBase64: proof.signatureBase64
419
509
  }
420
510
  });
@@ -713,4 +803,4 @@ function startFederationAutoConnect(opts) {
713
803
  }
714
804
 
715
805
  //#endregion
716
- export { createAndSubmitFederationBondProof, loadPersistedFederationBondProof, runFederationAutoConnectOnce, startFederationAutoConnect };
806
+ export { createAndSubmitFederationBondProof, loadPersistedFederationBondProof, persistFederationBondProofFromSignerReview, runFederationAutoConnectOnce, startFederationAutoConnect, submitFederationBondProof };
@@ -1,3 +1,4 @@
1
+ import { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
1
2
  import { isMarketplaceAutomatedAdapterServiceKind } from "./marketplace-service-kinds.js";
2
3
  import { listLocalMarketplaceDeliveryTargets, listLocalMarketplaceOrders, upsertMarketplaceOrderConfig } from "./offers.js";
3
4
 
@@ -168,14 +169,36 @@ async function postWebhookDelivery(params) {
168
169
  };
169
170
  }
170
171
  try {
171
- const response = await params.fetchImpl(url, {
172
- method: "POST",
173
- headers: {
174
- "content-type": "application/json",
175
- "x-fased-marketplace-delivery": "capability"
176
- },
177
- body: JSON.stringify(params.payload)
172
+ if (new URL(url).protocol !== "https:") {
173
+ return {
174
+ ok: false,
175
+ reason: "webhook delivery requires HTTPS"
176
+ };
177
+ }
178
+ } catch {
179
+ return {
180
+ ok: false,
181
+ reason: "webhook delivery target has an invalid URL"
182
+ };
183
+ }
184
+ let guarded;
185
+ try {
186
+ guarded = await fetchWithSsrFGuard({
187
+ url,
188
+ fetchImpl: params.fetchImpl,
189
+ lookupFn: params.ssrfLookupFn,
190
+ timeoutMs: 1e4,
191
+ auditContext: "marketplace-capability-webhook",
192
+ init: {
193
+ method: "POST",
194
+ headers: {
195
+ "content-type": "application/json",
196
+ "x-fased-marketplace-delivery": "capability"
197
+ },
198
+ body: JSON.stringify(params.payload)
199
+ }
178
200
  });
201
+ const response = guarded.response;
179
202
  if (!response.ok) {
180
203
  return {
181
204
  ok: false,
@@ -188,6 +211,8 @@ async function postWebhookDelivery(params) {
188
211
  ok: false,
189
212
  reason: error instanceof Error ? error.message : String(error)
190
213
  };
214
+ } finally {
215
+ await guarded?.release();
191
216
  }
192
217
  }
193
218
  function resolveSubscriptionUpdate(params) {
@@ -279,6 +304,7 @@ async function runMarketplaceCapabilityAdapter(params) {
279
304
  } else if (targetKind === "webhook") {
280
305
  const webhookResult = await postWebhookDelivery({
281
306
  fetchImpl: deps.fetchImpl,
307
+ ssrfLookupFn: deps.ssrfLookupFn,
282
308
  target,
283
309
  payload: deliveryPayload
284
310
  });