@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.
- package/CHANGELOG.md +32 -0
- package/README.md +38 -30
- package/config/dependency-ownership.json +1 -1
- package/config/signer-policies/README.md +49 -0
- package/config/signer-policies/agent.json.template +32 -0
- package/config/signer-policies/mining.json.template +69 -0
- package/config/signer-policies/network.json.template +5 -0
- package/config/signer-policies/vault.json.template +70 -0
- package/config/signer-protocol-v2.json +76 -0
- package/config/typescript-noemit-baseline.json +680 -0
- package/dist/agents/auth-profiles/store.js +267 -31
- package/dist/agents/bash-tools.exec.js +10 -4
- package/dist/agents/current-model-catalog.js +3 -3
- package/dist/agents/memory-search.js +7 -1
- package/dist/agents/model-catalog-access.js +1 -2
- package/dist/agents/model-catalog-snapshot.js +1 -1
- package/dist/agents/model-catalog-source.js +1 -1
- package/dist/agents/model-metadata.js +1 -1
- package/dist/agents/model-selection.js +2 -28
- package/dist/agents/models-config.providers.js +6 -6
- package/dist/agents/pi-embedded-runner/compact.js +15 -7
- package/dist/agents/pi-embedded-runner/model.js +1 -1
- package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
- package/dist/agents/pi-embedded-runner/run.js +2 -0
- package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
- package/dist/agents/pi-tool-definition-adapter.js +16 -1
- package/dist/agents/pi-tools.js +2 -1
- package/dist/agents/sandbox/config.js +1 -1
- package/dist/agents/sandbox/context.js +27 -2
- package/dist/agents/skills/env-overrides.js +38 -28
- package/dist/agents/skills/trust.js +93 -0
- package/dist/agents/skills/workspace.js +128 -0
- package/dist/agents/skills-clawhub.js +36 -11
- package/dist/agents/skills-marketplace-scan.js +49 -0
- package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
- package/dist/agents/tools/mining-tool.js +1 -1
- package/dist/agents/tools/session-status-tool.js +1 -1
- package/dist/agents/tools/wallet-action-tool.js +172 -36
- package/dist/agents/tools/wallet-skill-policy.js +65 -23
- package/dist/agents/tools/wallet-tool.js +7 -11
- package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
- package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
- package/dist/auto-reply/reply/directive-handling.model.js +2 -1
- package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
- package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
- package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
- package/dist/auto-reply/reply/model-selection.js +7 -4
- package/dist/auto-reply/reply/session-reset-model.js +4 -4
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/channel-web.js +2 -2
- package/dist/cli/gateway-cli/run.js +8 -0
- package/dist/cli/program/command-registry.js +1 -1
- package/dist/cli/program/register.onboard.js +2 -3
- package/dist/cli/program/register.wallet.js +16 -123
- package/dist/cli/providers-cli.js +1 -1
- package/dist/cli/sat-cli.js +129 -2
- package/dist/cli/update-cli/update-command.js +260 -11
- package/dist/commands/auth-choice.apply.api-providers.js +3 -3
- package/dist/commands/doctor-config-flow.js +1 -1
- package/dist/commands/doctor-legacy-config.js +2 -13
- package/dist/commands/model-picker.js +6 -6
- package/dist/commands/models/auth.js +1 -1
- package/dist/commands/onboard-auth.config-gateways.js +1 -1
- package/dist/commands/onboard-auth.credentials.js +32 -8
- package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
- package/dist/commands/onboard-non-interactive/local.js +5 -1
- package/dist/commands/wallet.js +568 -1911
- package/dist/config/config.js +2 -2
- package/dist/config/io.js +64 -2
- package/dist/config/schema.help.js +8 -7
- package/dist/config/schema.labels.js +5 -4
- package/dist/config/zod-schema.agent-runtime.js +1 -0
- package/dist/config/zod-schema.js +5 -0
- package/dist/control-ui/assets/{app-DLil9VO1.js → app-bR-fO5ty.js} +1511 -1555
- package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
- package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
- package/dist/control-ui/assets/{index-DdE_NIXo.js → index-ckCxHwjy.js} +3 -3
- package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
- package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
- package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
- package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
- package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/daemon/systemd-system.js +56 -50
- package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
- package/dist/extensions/sat-mining/src/rpc-read.js +235 -67
- package/dist/extensions/sat-mining/src/sat-bond-layout.js +5 -2
- package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
- package/dist/extensions/sat-mining/src/solana-submit.js +1038 -397
- package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
- package/dist/federation/auto-connect.js +98 -8
- package/dist/federation/marketplace-capability-adapter.js +33 -7
- package/dist/federation/marketplace-delivery-outbox.js +196 -0
- package/dist/federation/marketplace-delivery.js +351 -215
- package/dist/federation/marketplace-direct-payment.js +272 -141
- package/dist/federation/marketplace-escrow.js +607 -249
- package/dist/federation/marketplace-settlement-ledger.js +352 -0
- package/dist/federation/offers.js +9 -7
- package/dist/federation/peer-auth-v2.js +529 -0
- package/dist/gateway/a2a-http.js +425 -96
- package/dist/gateway/a2a-settlement.js +259 -153
- package/dist/gateway/a2a-task-store.js +524 -0
- package/dist/gateway/auth.js +38 -2
- package/dist/gateway/config-reload.js +46 -33
- package/dist/gateway/durable-capacity.js +31 -0
- package/dist/gateway/federation-http.js +540 -135
- package/dist/gateway/federation-marketplace-run-store.js +397 -0
- package/dist/gateway/federation-marketplace.js +535 -230
- package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
- package/dist/gateway/security-path.js +1 -1
- package/dist/gateway/server-http.js +1084 -1205
- package/dist/gateway/server-methods/models.js +1 -1
- package/dist/gateway/server-methods/secrets.js +40 -0
- package/dist/gateway/server-methods.js +1 -2
- package/dist/gateway/server-reload-handlers.js +196 -66
- package/dist/gateway/server-runtime-config.js +1 -1
- package/dist/gateway/server-secrets-runtime.js +288 -0
- package/dist/gateway/server.impl.js +73 -42
- package/dist/gateway/sessions-patch.js +3 -5
- package/dist/index.js +4 -2
- package/dist/infra/fasedhub.js +64 -1
- package/dist/infra/local-source-paired-update.js +538 -0
- package/dist/infra/restart.js +41 -10
- package/dist/infra/update-runner.js +96 -0
- package/dist/light-update-status.js +11 -11
- package/dist/memory/backend-config.js +2 -1
- package/dist/memory/session-files.js +16 -2
- package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
- package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
- package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Bwi2Oq03.js → audio-preflight-BYxAt775.js} +27 -27
- package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
- package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
- package/dist/plugin-sdk/channel-plugin-common.js +4 -4
- package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-DzT4L4Ty.js → chunk-items-DIRHG2gJ.js} +1 -1
- package/dist/plugin-sdk/command-status.d.ts +2 -2
- package/dist/plugin-sdk/command-status.js +27 -27
- package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
- package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
- package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
- package/dist/plugin-sdk/{config-schema-BrkmtFxB.js → config-schema-BOT7kHb6.js} +6779 -3696
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +6 -6
- package/dist/plugin-sdk/discord.js +19 -19
- package/dist/plugin-sdk/file-lock.js +35 -4
- package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
- package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
- package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
- package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
- package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
- package/dist/plugin-sdk/index.d.ts +21 -39
- package/dist/plugin-sdk/index.js +29 -29
- package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
- package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
- package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
- package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
- package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
- package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
- package/dist/plugin-sdk/{monitor-M_ta2lMc.js → monitor-BCFDaqJ-.js} +31 -31
- package/dist/plugin-sdk/{monitor-wYVncM9w.js → monitor-BgbjRiPM.js} +32 -32
- package/dist/plugin-sdk/{openresponses-http-B2GmeSt4.js → openresponses-http-DFf87SMM.js} +27 -27
- package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
- package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3bHYGaw.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
- package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
- package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
- package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
- package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
- package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
- package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
- package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
- package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
- package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
- package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
- package/dist/plugin-sdk/sat-runtime.d.ts +549 -309
- package/dist/plugin-sdk/sat-runtime.js +29 -29
- package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
- package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
- package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
- package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
- package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
- package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
- package/dist/plugin-sdk/{slack-CxE1mfzj.js → slack-BUTt8cxK.js} +39 -39
- package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
- package/dist/plugin-sdk/slack.d.ts +6 -6
- package/dist/plugin-sdk/slack.js +9 -9
- package/dist/plugin-sdk/{sticker-cache-CGzGWu00.js → sticker-cache-D0wHVqjt.js} +3 -3
- package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
- package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-DaEcYQ8r.js → telegram-actions-CC_qN4v0.js} +30 -30
- package/dist/plugin-sdk/telegram.d.ts +6 -6
- package/dist/plugin-sdk/telegram.js +8 -8
- package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
- package/dist/plugin-sdk/tmp-fased-dir-xOTGlzBE.d.ts +486 -0
- package/dist/plugin-sdk/{types-vcJrC_uv.d.ts → types-C3avNytw.d.ts} +3 -4
- package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
- package/dist/plugin-sdk/{types-DFAW-n1J.d.ts → types-DWfbSAaM.d.ts} +2 -2
- package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
- package/dist/plugin-sdk/{web-CInY-lCv.js → web-BXsJ1vqe.js} +32 -32
- package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
- package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +13 -13
- package/dist/plugin-sdk/whatsapp.js +12 -12
- package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
- package/dist/plugin-sdk/{zod-schema.providers-core-BEbNizPe.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
- package/dist/providers/refresh.js +1 -1
- package/dist/providers/registry.js +1 -1
- package/dist/secrets/apply.js +1 -1
- package/dist/secrets/runtime.js +1 -1
- package/dist/wallet/external-submission-ledger.js +376 -0
- package/dist/wallet/legacy-embedded-keystore.js +40 -0
- package/dist/wallet/local-socket-signer-archive.js +30 -0
- package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
- package/dist/wallet/local-socket-signer-policy.js +166 -0
- package/dist/wallet/local-socket-signer-protocol.js +561 -118
- package/dist/wallet/native-signer-wallet-id.js +25 -0
- package/dist/wallet/providers/alchemy-adapter.js +3 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +380 -105
- package/dist/wallet/providers/turnkey-adapter.js +292 -34
- package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
- package/dist/wallet/signer-network-admin.js +184 -0
- package/dist/wallet/signer-protocol-v2.generated.js +90 -0
- package/dist/wallet/solana-bond-signing.js +157 -69
- package/dist/wallet/solana-reviewed-transaction.js +375 -0
- package/dist/wallet/solana-swap.js +520 -64
- package/dist/wallet/solana-transaction-inspection.js +106 -4
- package/dist/wallet/solana-trigger.js +658 -320
- package/dist/wallet/turnkey-reviewed-state.js +370 -0
- package/dist/wallet/wallet-approval-auth.js +17 -28
- package/dist/wallet/wallet-atomic-state.js +53 -0
- package/dist/wallet/wallet-canary.js +0 -1
- package/dist/wallet/wallet-inbound-events.js +16 -11
- package/dist/wallet/wallet-policy-simulation.js +1 -1
- package/dist/wallet/wallet-policy.js +90 -36
- package/dist/wallet/wallet-provider-capabilities.js +28 -4
- package/dist/wallet/wallet-provider-registry.js +57 -44
- package/dist/wallet/wallet-provider-resolver.js +62 -63
- package/dist/wallet/wallet-runtime-config.js +28 -41
- package/dist/wallet/wallet-secrets-store.js +22 -0
- package/dist/wallet/wallet-send-approvals.js +1891 -589
- package/dist/wallet/wallet-send-execution-ledger.js +292 -0
- package/dist/wallet/wallet-settlement-links.js +14 -13
- package/dist/wallet/wallet-standard-review.js +353 -0
- package/dist/wallet/wallet-status.js +0 -9
- package/dist/wallet/wallet-task-ledger.js +16 -2
- package/dist/web/auto-reply/heartbeat-runner.js +1 -1
- package/dist/web/auto-reply/monitor.js +2 -2
- package/dist/wizard/host-security-capability.js +14 -23
- package/dist/wizard/onboarding.finalize.js +63 -184
- package/dist/wizard/onboarding.host-security.js +117 -1367
- package/dist/wizard/onboarding.js +172 -217
- package/dist/wizard/onboarding.wallet.js +232 -785
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +12 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +12 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +12 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/index.ts +498 -153
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
- package/extensions/sat-mining/src/audit-store.ts +50 -5
- package/extensions/sat-mining/src/claim-service.ts +85 -14
- package/extensions/sat-mining/src/config.ts +9 -0
- package/extensions/sat-mining/src/cycle-progress.ts +16 -8
- package/extensions/sat-mining/src/epoch-service.ts +9 -5
- package/extensions/sat-mining/src/gateway-runner.ts +21 -1
- package/extensions/sat-mining/src/protocol-contract.ts +45 -1
- package/extensions/sat-mining/src/recovery-service.ts +312 -0
- package/extensions/sat-mining/src/round-watcher.ts +391 -81
- package/extensions/sat-mining/src/rpc-read.ts +330 -89
- package/extensions/sat-mining/src/runtime.ts +14 -0
- package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
- package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
- package/extensions/sat-mining/src/solana-submit.ts +1199 -428
- package/extensions/sat-mining/src/submission-ledger.ts +433 -0
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +12 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +12 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +12 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +12 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +4955 -0
- package/package.json +23 -5
- package/scripts/fased-host-updater.mjs +1421 -0
- package/scripts/fased-host-updaterctl.mjs +186 -0
- package/scripts/fased-managed-service.sh +36 -0
- package/scripts/fased-managed-updater.mjs +3065 -156
- package/scripts/fased-signer-enroll-hosting.sh +275 -0
- package/scripts/fased-signer-network-hosting.sh +143 -0
- package/scripts/fased-signer-owner-policy.mjs +1430 -0
- package/scripts/fased-signer-policy-hosting.sh +50 -0
- package/scripts/fased-signer-policy-local.sh +26 -0
- package/scripts/hosted-release-manifest.mjs +185 -0
- package/scripts/install-fased-signerd.sh +183 -108
- package/scripts/install-managed-runtime.mjs +212 -10
- package/scripts/managed-runtime-layout.mjs +75 -3
- package/scripts/migrate-hosted-signer-v2.mjs +58 -0
- package/scripts/start-managed.sh +169 -360
- package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
- package/dist/plugin-sdk/tmp-fased-dir-CS6zsYEE.d.ts +0 -77
- package/dist/wallet/local-socket-signer-broker.js +0 -224
- package/dist/wallet/local-socket-signer-custody.js +0 -42
- package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
- package/dist/wallet/providers/privy-adapter.js +0 -80
- 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
|
-
|
|
375
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
});
|