@fased/fased 0.1.61 → 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 +43 -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/acp/client.js +2 -2
- package/dist/acp/secret-file.js +2 -2
- package/dist/agents/agent-scope.js +2 -2
- package/dist/agents/apply-patch.js +8 -8
- package/dist/agents/auth-profiles/paths.js +2 -2
- package/dist/agents/auth-profiles/store.js +269 -33
- package/dist/agents/bash-tools.exec.js +10 -4
- package/dist/agents/bash-tools.shared.js +2 -2
- package/dist/agents/cli-credentials.js +4 -4
- package/dist/agents/current-model-catalog.js +3 -3
- package/dist/agents/docs-path.js +3 -3
- package/dist/agents/embedded-pi-mcp.js +4 -4
- package/dist/agents/identity-avatar.js +3 -3
- package/dist/agents/identity-file.js +2 -2
- 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/openai-codex-app-server.js +5 -5
- 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-embedded-subscribe.raw-stream.js +3 -3
- package/dist/agents/pi-extensions/compaction-safeguard.js +3 -3
- package/dist/agents/pi-model-discovery.js +6 -6
- package/dist/agents/pi-project-settings.js +3 -3
- 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/sandbox/fs-bridge.js +2 -2
- package/dist/agents/session-dirs.js +4 -4
- package/dist/agents/session-write-lock.js +13 -13
- package/dist/agents/shell-utils.js +5 -5
- package/dist/agents/skills/bundled-dir.js +4 -4
- package/dist/agents/skills/env-overrides.js +38 -28
- package/dist/agents/skills/local-loader.js +6 -6
- package/dist/agents/skills/plugin-skills.js +2 -2
- package/dist/agents/skills/trust.js +93 -0
- package/dist/agents/skills/workspace.js +141 -13
- package/dist/agents/skills-clawhub.js +36 -11
- package/dist/agents/skills-install-download.js +7 -7
- package/dist/agents/skills-install-plan.js +2 -2
- package/dist/agents/skills-install.js +2 -2
- package/dist/agents/skills-marketplace-scan.js +49 -0
- package/dist/agents/skills-status.js +2 -2
- package/dist/agents/subagent-depth.js +2 -2
- package/dist/agents/system-prompt-params.js +2 -2
- 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/agents/workspace.js +22 -22
- package/dist/auto-reply/reply/agent-runner-execution.js +2 -2
- package/dist/auto-reply/reply/agent-runner.js +2 -2
- package/dist/auto-reply/reply/commands-export-session.js +7 -7
- 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/post-compaction-audit.js +3 -3
- package/dist/auto-reply/reply/post-compaction-context.js +3 -3
- package/dist/auto-reply/reply/session-reset-model.js +4 -4
- package/dist/auto-reply/reply/session.js +3 -3
- package/dist/auto-reply/skill-commands.js +3 -3
- package/dist/auto-reply/status.js +6 -6
- package/dist/brand.js +1 -1
- package/dist/browser/chrome.executables.js +3 -3
- package/dist/browser/chrome.js +3 -3
- package/dist/browser/chrome.profile-decoration.js +6 -6
- package/dist/browser/profiles-service.js +2 -2
- package/dist/browser/server-context.js +2 -2
- package/dist/browser/trash.js +4 -4
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/canvas-host/server.js +4 -4
- package/dist/capabilities/catalog.js +3 -3
- package/dist/channel-web.js +2 -2
- package/dist/channels/plugins/catalog.js +3 -3
- package/dist/cli/browser-cli-extension.js +6 -6
- package/dist/cli/command-format.js +2 -2
- package/dist/cli/cron-cli/register.cron-simple.js +2 -2
- package/dist/cli/dns-cli.js +9 -9
- package/dist/cli/gateway-cli/dev.js +5 -5
- package/dist/cli/gateway-cli/run.js +10 -2
- package/dist/cli/hooks-cli.js +5 -5
- package/dist/cli/lightweight/gateway-runtime-probe.js +2 -2
- package/dist/cli/memory-cli.js +7 -7
- package/dist/cli/nodes-media-utils.js +2 -2
- package/dist/cli/plugins-cli.js +2 -2
- 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/secrets-cli.js +3 -3
- package/dist/cli/update-cli/update-command.js +260 -11
- package/dist/cli/windows-argv.js +2 -2
- package/dist/commands/auth-choice.apply.api-providers.js +3 -3
- package/dist/commands/dashboard-link.js +3 -3
- package/dist/commands/doctor-config-flow.js +1 -1
- package/dist/commands/doctor-install.js +5 -5
- package/dist/commands/doctor-legacy-config.js +2 -13
- package/dist/commands/doctor-memory-search.js +2 -2
- package/dist/commands/doctor-platform-notes.js +2 -2
- package/dist/commands/doctor-sandbox.js +2 -2
- package/dist/commands/doctor-state-integrity.js +23 -23
- package/dist/commands/doctor-workspace.js +3 -3
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/managed-up.js +2 -2
- 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 +35 -11
- 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/onboarding/plugin-install.js +2 -2
- package/dist/commands/sessions-cleanup.js +2 -2
- package/dist/commands/signal-install.js +6 -6
- package/dist/commands/status-all/channels.js +2 -2
- package/dist/commands/wallet.js +570 -1913
- package/dist/config/cache-utils.js +2 -2
- package/dist/config/config.js +2 -2
- package/dist/config/includes.js +5 -5
- package/dist/config/io.js +66 -4
- package/dist/config/paths.js +3 -3
- package/dist/config/sat-runtime-ids.js +3 -3
- package/dist/config/schema.help.js +8 -7
- package/dist/config/schema.labels.js +5 -4
- package/dist/config/sessions/disk-budget.js +6 -6
- package/dist/config/sessions/paths.js +2 -2
- package/dist/config/sessions/store.js +17 -17
- package/dist/config/sessions/transcript.js +4 -4
- package/dist/config/talk.js +2 -2
- package/dist/config/zod-schema.agent-runtime.js +1 -0
- package/dist/config/zod-schema.js +5 -0
- package/dist/control-ui/assets/{app-BXA4gPvN.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-D2QbJhVg.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/cron/service/store.js +2 -2
- package/dist/cron/store.js +6 -6
- package/dist/daemon/systemd-system.js +60 -54
- package/dist/discord/monitor/thread-bindings.state.js +2 -2
- 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 +14 -11
- 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/control-ui-boot-check.js +6 -6
- package/dist/gateway/control-ui-login.js +7 -7
- package/dist/gateway/control-ui.js +9 -9
- 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/hooks-mapping.js +4 -4
- package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
- package/dist/gateway/security-path.js +1 -1
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +1088 -1209
- package/dist/gateway/server-methods/chat.js +3 -3
- package/dist/gateway/server-methods/models.js +1 -1
- package/dist/gateway/server-methods/secrets.js +40 -0
- package/dist/gateway/server-methods/sessions.js +6 -6
- package/dist/gateway/server-methods/usage.js +2 -2
- 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/session-compaction-checkpoints.js +4 -4
- package/dist/gateway/session-utils.fs.js +24 -24
- package/dist/gateway/session-utils.js +6 -6
- package/dist/gateway/sessions-patch.js +3 -5
- package/dist/hooks/bundled-dir.js +4 -4
- package/dist/hooks/gmail-setup-utils.js +6 -6
- package/dist/hooks/import-url.js +2 -2
- package/dist/hooks/loader.js +4 -4
- package/dist/hooks/workspace.js +7 -7
- package/dist/index.js +4 -2
- package/dist/infra/archive.js +17 -17
- package/dist/infra/boundary-file-read.js +2 -2
- package/dist/infra/boundary-path.js +15 -15
- package/dist/infra/brew.js +2 -2
- package/dist/infra/control-ui-assets.js +14 -14
- package/dist/infra/device-auth-store.js +8 -8
- package/dist/infra/device-identity.js +8 -8
- package/dist/infra/dotenv.js +2 -2
- package/dist/infra/exec-approvals.js +8 -8
- package/dist/infra/exec-command-resolution.js +4 -4
- package/dist/infra/exec-safe-bin-trust.js +2 -2
- package/dist/infra/fased-root.js +5 -5
- package/dist/infra/fasedhub.js +64 -1
- package/dist/infra/fs-safe.js +14 -14
- package/dist/infra/gateway-lock.js +11 -11
- package/dist/infra/git-commit.js +5 -5
- package/dist/infra/git-root.js +4 -4
- package/dist/infra/hosted-runtime-artifact.js +3 -3
- package/dist/infra/is-main.js +2 -2
- package/dist/infra/json-file.js +7 -7
- package/dist/infra/local-source-paired-update.js +538 -0
- package/dist/infra/managed-runtime-bootstrap.js +6 -6
- package/dist/infra/outbound/delivery-queue.js +16 -16
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/ports-lsof.js +4 -4
- package/dist/infra/provider-usage.auth.js +3 -3
- package/dist/infra/restart.js +41 -10
- package/dist/infra/safe-open-sync.js +2 -2
- package/dist/infra/session-cost-usage.js +9 -9
- package/dist/infra/shell-env.js +2 -2
- package/dist/infra/state-migrations.fs.js +6 -6
- package/dist/infra/state-migrations.js +23 -23
- package/dist/infra/tmp-fased-dir.js +6 -6
- package/dist/infra/update-runner.js +96 -0
- package/dist/infra/widearea-dns.js +3 -3
- package/dist/infra/wsl.js +2 -2
- package/dist/light-update-status.js +11 -11
- package/dist/line/accounts.js +2 -2
- package/dist/line/download.js +2 -2
- package/dist/logging/config.js +3 -3
- package/dist/logging/logger.js +7 -7
- package/dist/managed/federation.js +3 -3
- package/dist/managed/tunnel.js +3 -3
- package/dist/media/store.js +13 -13
- package/dist/media-understanding/runner.js +3 -3
- package/dist/memory/backend-config.js +2 -1
- package/dist/memory/embeddings.js +2 -2
- package/dist/memory/internal.js +10 -10
- package/dist/memory/manager-sync-ops.js +7 -7
- package/dist/memory/repair-executor.js +17 -17
- package/dist/memory/session-files.js +16 -2
- package/dist/node-host/invoke-system-run-plan.js +8 -8
- package/dist/node-host/invoke.js +2 -2
- package/dist/node-host/runner.js +3 -3
- package/dist/pairing/pairing-store.js +3 -3
- 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-Bv0hUOWL.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-Bk--NU3E.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-CGW6J3Pv.js → config-schema-BOT7kHb6.js} +6779 -3696
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +5 -5
- 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 +9 -27
- package/dist/plugin-sdk/index.js +29 -29
- package/dist/plugin-sdk/json-store.js +6 -6
- 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-B9Cmt_Je.js → monitor-BCFDaqJ-.js} +31 -31
- package/dist/plugin-sdk/{monitor-B71iwAgC.js → monitor-BgbjRiPM.js} +32 -32
- package/dist/plugin-sdk/{openresponses-http-Du4GMmwo.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-BMkkS038.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-D_bbE6Yd.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 +5 -5
- package/dist/plugin-sdk/slack.js +9 -9
- package/dist/plugin-sdk/{sticker-cache-Dqo9nRhi.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-Cnag7JTH.js → telegram-actions-CC_qN4v0.js} +30 -30
- package/dist/plugin-sdk/telegram.d.ts +5 -5
- 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-CLIvQaVg.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-BYDL6dQj.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-BInKQkc4.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 +5 -5
- package/dist/plugin-sdk/whatsapp.js +12 -12
- package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
- package/dist/plugins/bundled-dir.js +3 -3
- package/dist/plugins/discovery.js +11 -11
- package/dist/plugins/loader.js +13 -13
- package/dist/plugins/manifest-registry.js +2 -2
- package/dist/plugins/manifest.js +4 -4
- package/dist/plugins/path-safety.js +3 -3
- package/dist/plugins/status-cache.js +9 -9
- package/dist/plugins/update.js +3 -3
- package/dist/plugins/web-search-install-catalog.js +3 -3
- package/dist/providers/refresh.js +1 -1
- package/dist/providers/registry.js +1 -1
- package/dist/secrets/apply.js +17 -17
- package/dist/secrets/audit.js +11 -11
- package/dist/secrets/runtime.js +1 -1
- package/dist/secrets/shared.js +9 -9
- package/dist/security/scan-paths.js +2 -2
- package/dist/shared/config-eval.js +2 -2
- package/dist/shared/pid-alive.js +2 -2
- package/dist/tasks/standing-orders.js +5 -5
- package/dist/tasks/task-flow-registry.js +5 -5
- package/dist/tasks/task-registry.js +5 -5
- package/dist/tasks/workflow-definitions.js +6 -6
- package/dist/telegram/token.js +5 -5
- package/dist/utils.js +5 -5
- 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 +382 -107
- 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 +20 -31
- package/dist/wallet/wallet-atomic-state.js +53 -0
- package/dist/wallet/wallet-audit-log.js +5 -5
- package/dist/wallet/wallet-canary.js +0 -1
- package/dist/wallet/wallet-inbound-events.js +19 -14
- package/dist/wallet/wallet-observability.js +5 -5
- package/dist/wallet/wallet-policy-simulation.js +1 -1
- package/dist/wallet/wallet-policy.js +95 -41
- package/dist/wallet/wallet-provider-capabilities.js +28 -4
- package/dist/wallet/wallet-provider-registry.js +64 -51
- package/dist/wallet/wallet-provider-resolver.js +62 -63
- package/dist/wallet/wallet-runtime-config.js +31 -44
- package/dist/wallet/wallet-secrets-store.js +44 -22
- package/dist/wallet/wallet-send-approvals.js +1894 -592
- package/dist/wallet/wallet-send-execution-ledger.js +292 -0
- package/dist/wallet/wallet-settlement-links.js +17 -16
- 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/accounts.js +3 -3
- package/dist/web/auth-store.js +18 -18
- package/dist/web/auto-reply/heartbeat-runner.js +1 -1
- package/dist/web/auto-reply/monitor.js +2 -2
- package/dist/web/session.js +4 -4
- package/dist/wizard/host-security-capability.js +15 -24
- package/dist/wizard/onboarding.finalize.js +63 -184
- package/dist/wizard/onboarding.host-security.js +118 -1368
- package/dist/wizard/onboarding.js +180 -242
- package/dist/wizard/onboarding.wallet.js +323 -829
- 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 +18 -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 +18 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +18 -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 +18 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +18 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +18 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +18 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +4955 -0
- package/package.json +24 -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 +217 -0
- 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-BdFQvrvw.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,529 @@
|
|
|
1
|
+
import { resolveStateDir } from "../config/paths.js";
|
|
2
|
+
import { withFileLock } from "../plugin-sdk/file-lock.js";
|
|
3
|
+
import "../infra/file-lock.js";
|
|
4
|
+
import { isLoopbackHost } from "../gateway/net.js";
|
|
5
|
+
import { createAuthRateLimiter } from "../gateway/auth-rate-limit.js";
|
|
6
|
+
import { deriveDeviceIdFromPublicKey, loadOrCreateDeviceIdentity, normalizeDevicePublicKeyBase64Url, publicKeyRawBase64UrlFromPem, signDevicePayload, verifyDeviceSignature } from "../infra/device-identity.js";
|
|
7
|
+
import { readResponseWithLimit } from "../media/read-response-with-limit.js";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import fs from "node:fs/promises";
|
|
10
|
+
import crypto from "node:crypto";
|
|
11
|
+
|
|
12
|
+
//#region src/federation/peer-auth-v2.ts
|
|
13
|
+
const FEDERATION_PEER_PROTOCOL_VERSION = "2";
|
|
14
|
+
const FEDERATION_PEER_PROTOCOL_DOMAIN = "fased:federation-peer-request:v2";
|
|
15
|
+
const FEDERATION_PEER_MAX_CLOCK_SKEW_MS = 2 * 6e4;
|
|
16
|
+
const FEDERATION_MARKETPLACE_ORDER_PATH = "/api/federation/marketplace/orders";
|
|
17
|
+
const FEDERATION_MARKETPLACE_DELIVERY_PATH = "/api/federation/marketplace/deliveries";
|
|
18
|
+
const FEDERATION_A2A_RPC_PATH = "/a2a";
|
|
19
|
+
const FEDERATION_PEER_HEADERS = {
|
|
20
|
+
protocolVersion: "x-fased-protocol-version",
|
|
21
|
+
senderHandle: "x-fased-sender-handle",
|
|
22
|
+
recipientHandle: "x-fased-recipient-handle",
|
|
23
|
+
timestamp: "x-fased-request-ts",
|
|
24
|
+
nonce: "x-fased-request-nonce",
|
|
25
|
+
bodySha256: "x-fased-content-sha256",
|
|
26
|
+
publicKey: "x-fased-device-public-key",
|
|
27
|
+
signature: "x-fased-request-signature"
|
|
28
|
+
};
|
|
29
|
+
const DEFAULT_REPLAY_TTL_MS = 10 * 6e4;
|
|
30
|
+
const MAX_REPLAY_RESERVATIONS = 1e4;
|
|
31
|
+
const MAX_DIRECTORY_RESPONSE_BYTES = 256 * 1024;
|
|
32
|
+
const DIRECTORY_TIMEOUT_MS = 5e3;
|
|
33
|
+
const INGRESS_RATE_LIMIT_SCOPE = "federation-peer-v2";
|
|
34
|
+
const DEFAULT_INGRESS_RATE_LIMITER = createAuthRateLimiter({
|
|
35
|
+
maxAttempts: 60,
|
|
36
|
+
windowMs: 6e4,
|
|
37
|
+
lockoutMs: 6e4,
|
|
38
|
+
exemptLoopback: false
|
|
39
|
+
});
|
|
40
|
+
let replayReservationQueue = Promise.resolve();
|
|
41
|
+
function normalizeHandle(value) {
|
|
42
|
+
return value.trim().toLowerCase();
|
|
43
|
+
}
|
|
44
|
+
function isTrustedFederationPeerUrl(url) {
|
|
45
|
+
if (url.username || url.password) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return url.protocol === "https:" || url.protocol === "http:" && isLoopbackHost(url.hostname);
|
|
49
|
+
}
|
|
50
|
+
function serializeCanonicalJson(value) {
|
|
51
|
+
if (value === null || typeof value !== "object") {
|
|
52
|
+
return JSON.stringify(value);
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(value)) {
|
|
55
|
+
return `[${value.map((entry) => serializeCanonicalJson(entry)).join(",")}]`;
|
|
56
|
+
}
|
|
57
|
+
return `{${Object.keys(value).toSorted().map((key) => `${JSON.stringify(key)}:${serializeCanonicalJson(value[key])}`).join(",")}}`;
|
|
58
|
+
}
|
|
59
|
+
function canonicalizeFederationPeerJson(value) {
|
|
60
|
+
const json = JSON.stringify(value);
|
|
61
|
+
if (json === undefined) {
|
|
62
|
+
throw new Error("federation peer request body must be JSON-serializable");
|
|
63
|
+
}
|
|
64
|
+
return serializeCanonicalJson(JSON.parse(json));
|
|
65
|
+
}
|
|
66
|
+
function sha256Hex(value) {
|
|
67
|
+
return crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
68
|
+
}
|
|
69
|
+
function buildSignaturePayload(params) {
|
|
70
|
+
return canonicalizeFederationPeerJson({
|
|
71
|
+
protocol: FEDERATION_PEER_PROTOCOL_DOMAIN,
|
|
72
|
+
version: FEDERATION_PEER_PROTOCOL_VERSION,
|
|
73
|
+
sender: normalizeHandle(params.senderHandle),
|
|
74
|
+
recipient: normalizeHandle(params.recipientHandle),
|
|
75
|
+
method: params.method.trim().toUpperCase(),
|
|
76
|
+
path: params.path,
|
|
77
|
+
timestamp: params.timestampMs,
|
|
78
|
+
nonce: params.nonce,
|
|
79
|
+
bodySha256: params.bodySha256,
|
|
80
|
+
publicKey: params.publicKey
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function resolveIdentity(env, identity) {
|
|
84
|
+
return identity ?? loadOrCreateDeviceIdentity(path.join(resolveStateDir(env), "identity", "device.json"));
|
|
85
|
+
}
|
|
86
|
+
function buildSignedFederationPeerRequest(params) {
|
|
87
|
+
const senderHandle = normalizeHandle(params.senderHandle);
|
|
88
|
+
const recipientHandle = normalizeHandle(params.recipientHandle);
|
|
89
|
+
if (!senderHandle || senderHandle.length > 256) {
|
|
90
|
+
throw new Error("federation peer sender handle is required");
|
|
91
|
+
}
|
|
92
|
+
if (!recipientHandle || recipientHandle.length > 256) {
|
|
93
|
+
throw new Error("federation peer recipient handle is required");
|
|
94
|
+
}
|
|
95
|
+
const method = params.method ?? "POST";
|
|
96
|
+
const timestampMs = params.nowMs ?? Date.now();
|
|
97
|
+
if (!Number.isSafeInteger(timestampMs) || timestampMs <= 0) {
|
|
98
|
+
throw new Error("federation peer request timestamp is invalid");
|
|
99
|
+
}
|
|
100
|
+
const nonce = params.nonce?.trim() || crypto.randomUUID();
|
|
101
|
+
if (!/^[A-Za-z0-9_-]{16,128}$/u.test(nonce)) {
|
|
102
|
+
throw new Error("federation peer request nonce is invalid");
|
|
103
|
+
}
|
|
104
|
+
const body = canonicalizeFederationPeerJson(params.body);
|
|
105
|
+
const bodySha256 = sha256Hex(body);
|
|
106
|
+
const identity = resolveIdentity(params.env ?? process.env, params.identity);
|
|
107
|
+
const publicKey = publicKeyRawBase64UrlFromPem(identity.publicKeyPem);
|
|
108
|
+
const signature = signDevicePayload(identity.privateKeyPem, buildSignaturePayload({
|
|
109
|
+
senderHandle,
|
|
110
|
+
recipientHandle,
|
|
111
|
+
method,
|
|
112
|
+
path: params.path,
|
|
113
|
+
timestampMs,
|
|
114
|
+
nonce,
|
|
115
|
+
bodySha256,
|
|
116
|
+
publicKey
|
|
117
|
+
}));
|
|
118
|
+
return {
|
|
119
|
+
body,
|
|
120
|
+
headers: {
|
|
121
|
+
[FEDERATION_PEER_HEADERS.protocolVersion]: FEDERATION_PEER_PROTOCOL_VERSION,
|
|
122
|
+
[FEDERATION_PEER_HEADERS.senderHandle]: senderHandle,
|
|
123
|
+
[FEDERATION_PEER_HEADERS.recipientHandle]: recipientHandle,
|
|
124
|
+
[FEDERATION_PEER_HEADERS.timestamp]: String(timestampMs),
|
|
125
|
+
[FEDERATION_PEER_HEADERS.nonce]: nonce,
|
|
126
|
+
[FEDERATION_PEER_HEADERS.bodySha256]: bodySha256,
|
|
127
|
+
[FEDERATION_PEER_HEADERS.publicKey]: publicKey,
|
|
128
|
+
[FEDERATION_PEER_HEADERS.signature]: signature
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function readSingleHeader(req, name) {
|
|
133
|
+
const value = req.headers[name];
|
|
134
|
+
return typeof value === "string" ? value.trim() : "";
|
|
135
|
+
}
|
|
136
|
+
function directoryEntryCandidates(body) {
|
|
137
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
const record = body;
|
|
141
|
+
return [
|
|
142
|
+
record,
|
|
143
|
+
record.entry,
|
|
144
|
+
record.record,
|
|
145
|
+
record.directory,
|
|
146
|
+
record.node
|
|
147
|
+
].filter((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry)));
|
|
148
|
+
}
|
|
149
|
+
function readStringArray(value) {
|
|
150
|
+
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string").map((entry) => entry.trim()) : [];
|
|
151
|
+
}
|
|
152
|
+
function supportsFederationPeerProtocolV2(entry) {
|
|
153
|
+
const advertised = [
|
|
154
|
+
typeof entry.protocolVersion === "string" ? entry.protocolVersion : "",
|
|
155
|
+
typeof entry.peerProtocolVersion === "string" ? entry.peerProtocolVersion : "",
|
|
156
|
+
typeof entry.federationPeerProtocolVersion === "string" ? entry.federationPeerProtocolVersion : "",
|
|
157
|
+
...readStringArray(entry.protocolVersions),
|
|
158
|
+
...readStringArray(entry.supportedProtocols),
|
|
159
|
+
...readStringArray(entry.capabilities)
|
|
160
|
+
].map((value) => value.trim().toLowerCase());
|
|
161
|
+
return advertised.some((value) => value === "2" || value === "v2" || value === "protocol-v2" || value === "federation-peer-v2" || value === FEDERATION_PEER_PROTOCOL_DOMAIN);
|
|
162
|
+
}
|
|
163
|
+
function readDirectoryIdentity(body) {
|
|
164
|
+
for (const entry of directoryEntryCandidates(body)) {
|
|
165
|
+
const statusValue = typeof entry.trustState === "string" ? entry.trustState : typeof entry.status === "string" ? entry.status : "";
|
|
166
|
+
const nodeId = typeof entry.nodeId === "string" ? entry.nodeId.trim() : "";
|
|
167
|
+
if (!statusValue.trim() || !nodeId) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
status: statusValue.trim().toLowerCase(),
|
|
172
|
+
nodeId,
|
|
173
|
+
handle: typeof entry.handle === "string" ? normalizeHandle(entry.handle) : undefined,
|
|
174
|
+
nodeEndpoint: typeof entry.nodeEndpoint === "string" ? entry.nodeEndpoint.trim() : typeof entry.endpoint === "string" ? entry.endpoint.trim() : typeof entry.publicUrl === "string" ? entry.publicUrl.trim() : undefined,
|
|
175
|
+
bondTier: entry.bondTier === "none" || entry.bondTier === "basic-bond" || entry.bondTier === "operator-bond" ? entry.bondTier : undefined,
|
|
176
|
+
supportsProtocolV2: supportsFederationPeerProtocolV2(entry)
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
const lookupFederationPeerDirectory = async (params) => {
|
|
182
|
+
let url;
|
|
183
|
+
try {
|
|
184
|
+
url = new URL(`/api/federation/directory/${encodeURIComponent(params.senderHandle)}`, params.baseUrl);
|
|
185
|
+
} catch {
|
|
186
|
+
throw new Error("federation directory URL is invalid");
|
|
187
|
+
}
|
|
188
|
+
if (!isTrustedFederationPeerUrl(url)) {
|
|
189
|
+
throw new Error("federation directory must use HTTPS (plain HTTP is allowed only for an explicit loopback URL)");
|
|
190
|
+
}
|
|
191
|
+
const headers = { accept: "application/json" };
|
|
192
|
+
const apiToken = params.apiToken?.trim();
|
|
193
|
+
if (apiToken) {
|
|
194
|
+
headers.authorization = apiToken.toLowerCase().startsWith("bearer ") ? apiToken : `Bearer ${apiToken}`;
|
|
195
|
+
}
|
|
196
|
+
const response = await params.fetchImpl(url, {
|
|
197
|
+
method: "GET",
|
|
198
|
+
headers,
|
|
199
|
+
redirect: "error",
|
|
200
|
+
signal: AbortSignal.timeout(DIRECTORY_TIMEOUT_MS)
|
|
201
|
+
});
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
throw new Error(`federation directory lookup failed with HTTP ${response.status}`);
|
|
204
|
+
}
|
|
205
|
+
const responseText = (await readResponseWithLimit(response, MAX_DIRECTORY_RESPONSE_BYTES, { onOverflow: () => new Error("federation directory response is too large") })).toString("utf8");
|
|
206
|
+
let body;
|
|
207
|
+
try {
|
|
208
|
+
body = JSON.parse(responseText);
|
|
209
|
+
} catch {
|
|
210
|
+
throw new Error("federation directory response is not valid JSON");
|
|
211
|
+
}
|
|
212
|
+
const identity = readDirectoryIdentity(body);
|
|
213
|
+
if (!identity) {
|
|
214
|
+
throw new Error("federation directory response is missing status or nodeId");
|
|
215
|
+
}
|
|
216
|
+
return identity;
|
|
217
|
+
};
|
|
218
|
+
function resolveReplayStatePath(env) {
|
|
219
|
+
const explicit = env.FASED_FEDERATION_REPLAY_STATE_PATH?.trim();
|
|
220
|
+
return explicit || path.join(resolveStateDir(env), "federation", "peer-replay-v2.json");
|
|
221
|
+
}
|
|
222
|
+
async function readReplayState(statePath) {
|
|
223
|
+
try {
|
|
224
|
+
const raw = await fs.readFile(statePath, "utf8");
|
|
225
|
+
const value = JSON.parse(raw);
|
|
226
|
+
if (value.version !== 2 || !value.reservations || typeof value.reservations !== "object" || Array.isArray(value.reservations)) {
|
|
227
|
+
throw new Error("invalid replay state schema");
|
|
228
|
+
}
|
|
229
|
+
const reservations = {};
|
|
230
|
+
for (const [key, expiresAtMs] of Object.entries(value.reservations)) {
|
|
231
|
+
if (!/^[a-f0-9]{64}$/u.test(key) || !Number.isSafeInteger(expiresAtMs)) {
|
|
232
|
+
throw new Error("invalid replay reservation");
|
|
233
|
+
}
|
|
234
|
+
reservations[key] = expiresAtMs;
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
version: 2,
|
|
238
|
+
reservations
|
|
239
|
+
};
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error.code === "ENOENT") {
|
|
242
|
+
return {
|
|
243
|
+
version: 2,
|
|
244
|
+
reservations: {}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async function syncDirectory(directoryPath) {
|
|
251
|
+
try {
|
|
252
|
+
const handle = await fs.open(directoryPath, "r");
|
|
253
|
+
try {
|
|
254
|
+
await handle.sync();
|
|
255
|
+
} finally {
|
|
256
|
+
await handle.close();
|
|
257
|
+
}
|
|
258
|
+
} catch {}
|
|
259
|
+
}
|
|
260
|
+
async function writeReplayState(statePath, state) {
|
|
261
|
+
const directory = path.dirname(statePath);
|
|
262
|
+
await fs.mkdir(directory, {
|
|
263
|
+
recursive: true,
|
|
264
|
+
mode: 448
|
|
265
|
+
});
|
|
266
|
+
await fs.chmod(directory, 448).catch(() => undefined);
|
|
267
|
+
const tmpPath = `${statePath}.tmp-${process.pid}-${crypto.randomUUID()}`;
|
|
268
|
+
const handle = await fs.open(tmpPath, "wx", 384);
|
|
269
|
+
try {
|
|
270
|
+
await handle.writeFile(`${JSON.stringify(state)}\n`, "utf8");
|
|
271
|
+
await handle.sync();
|
|
272
|
+
} finally {
|
|
273
|
+
await handle.close();
|
|
274
|
+
}
|
|
275
|
+
try {
|
|
276
|
+
await fs.rename(tmpPath, statePath);
|
|
277
|
+
await fs.chmod(statePath, 384);
|
|
278
|
+
await syncDirectory(directory);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
await fs.rm(tmpPath, { force: true }).catch(() => undefined);
|
|
281
|
+
throw error;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async function inReplayReservationQueue(fn) {
|
|
285
|
+
const previous = replayReservationQueue;
|
|
286
|
+
let release;
|
|
287
|
+
replayReservationQueue = new Promise((resolve) => {
|
|
288
|
+
release = resolve;
|
|
289
|
+
});
|
|
290
|
+
await previous.catch(() => undefined);
|
|
291
|
+
try {
|
|
292
|
+
return await fn();
|
|
293
|
+
} finally {
|
|
294
|
+
release?.();
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const reserveFederationPeerReplay = async (params) => {
|
|
298
|
+
const reservationKey = sha256Hex(canonicalizeFederationPeerJson({
|
|
299
|
+
protocol: FEDERATION_PEER_PROTOCOL_DOMAIN,
|
|
300
|
+
sender: normalizeHandle(params.senderHandle),
|
|
301
|
+
nodeId: params.nodeId.toLowerCase(),
|
|
302
|
+
nonce: params.nonce
|
|
303
|
+
}));
|
|
304
|
+
const statePath = resolveReplayStatePath(params.env);
|
|
305
|
+
try {
|
|
306
|
+
return await inReplayReservationQueue(async () => await withFileLock(statePath, {
|
|
307
|
+
retries: {
|
|
308
|
+
retries: 20,
|
|
309
|
+
factor: 1.25,
|
|
310
|
+
minTimeout: 10,
|
|
311
|
+
maxTimeout: 100,
|
|
312
|
+
randomize: true
|
|
313
|
+
},
|
|
314
|
+
stale: 3e4
|
|
315
|
+
}, async () => {
|
|
316
|
+
const state = await readReplayState(statePath);
|
|
317
|
+
const reservations = Object.fromEntries(Object.entries(state.reservations).filter(([, expiresAtMs]) => Number.isSafeInteger(expiresAtMs) && expiresAtMs > params.nowMs));
|
|
318
|
+
if (reservations[reservationKey]) {
|
|
319
|
+
return {
|
|
320
|
+
ok: false,
|
|
321
|
+
reason: "replay"
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (Object.keys(reservations).length >= MAX_REPLAY_RESERVATIONS) {
|
|
325
|
+
return {
|
|
326
|
+
ok: false,
|
|
327
|
+
reason: "unavailable"
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
reservations[reservationKey] = Math.max(params.nowMs, params.timestampMs) + DEFAULT_REPLAY_TTL_MS;
|
|
331
|
+
await writeReplayState(statePath, {
|
|
332
|
+
version: 2,
|
|
333
|
+
reservations
|
|
334
|
+
});
|
|
335
|
+
return { ok: true };
|
|
336
|
+
}));
|
|
337
|
+
} catch {
|
|
338
|
+
return {
|
|
339
|
+
ok: false,
|
|
340
|
+
reason: "unavailable"
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
function rejectInvalid(reason) {
|
|
345
|
+
return {
|
|
346
|
+
ok: false,
|
|
347
|
+
statusCode: 401,
|
|
348
|
+
code: "peer_auth_invalid",
|
|
349
|
+
reason
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
function checkFederationPeerIngressBudget(params) {
|
|
353
|
+
const rateLimiter = params.rateLimiter ?? DEFAULT_INGRESS_RATE_LIMITER;
|
|
354
|
+
const rateLimit = rateLimiter.check(params.clientIp, INGRESS_RATE_LIMIT_SCOPE);
|
|
355
|
+
if (!rateLimit.allowed) {
|
|
356
|
+
return {
|
|
357
|
+
ok: false,
|
|
358
|
+
statusCode: 429,
|
|
359
|
+
code: "peer_auth_rate_limited",
|
|
360
|
+
reason: "federation peer authentication rate limit exceeded",
|
|
361
|
+
retryAfterMs: rateLimit.retryAfterMs
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
rateLimiter.recordFailure(params.clientIp, INGRESS_RATE_LIMIT_SCOPE);
|
|
365
|
+
return { ok: true };
|
|
366
|
+
}
|
|
367
|
+
async function reserveAuthorizedFederationPeerRequest(params) {
|
|
368
|
+
const nowMs = params.deps?.now?.() ?? Date.now();
|
|
369
|
+
const replay = await (params.deps?.reserveReplay ?? reserveFederationPeerReplay)({
|
|
370
|
+
senderHandle: params.authorization.senderHandle,
|
|
371
|
+
nodeId: params.authorization.nodeId,
|
|
372
|
+
nonce: params.authorization.nonce,
|
|
373
|
+
timestampMs: params.authorization.timestampMs,
|
|
374
|
+
nowMs,
|
|
375
|
+
env: params.env ?? process.env
|
|
376
|
+
});
|
|
377
|
+
if (replay.ok) {
|
|
378
|
+
return params.authorization;
|
|
379
|
+
}
|
|
380
|
+
if (replay.reason === "replay") {
|
|
381
|
+
return {
|
|
382
|
+
ok: false,
|
|
383
|
+
statusCode: 409,
|
|
384
|
+
code: "peer_auth_replay",
|
|
385
|
+
reason: "federation peer request nonce was already used"
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
ok: false,
|
|
390
|
+
statusCode: 503,
|
|
391
|
+
code: "peer_auth_replay_unavailable",
|
|
392
|
+
reason: "federation peer replay state is unavailable"
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
async function authorizeFederationPeerRequestV2(params) {
|
|
396
|
+
const env = params.env ?? process.env;
|
|
397
|
+
const nowMs = params.deps?.now?.() ?? Date.now();
|
|
398
|
+
const clientIp = params.clientIp ?? params.req.socket?.remoteAddress;
|
|
399
|
+
if (!params.ingressBudgetApplied) {
|
|
400
|
+
const ingressBudget = checkFederationPeerIngressBudget({
|
|
401
|
+
clientIp,
|
|
402
|
+
rateLimiter: params.deps?.rateLimiter
|
|
403
|
+
});
|
|
404
|
+
if (!ingressBudget.ok) {
|
|
405
|
+
return ingressBudget;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (params.req.method !== "POST" || params.req.url !== params.expectedPath) {
|
|
409
|
+
return rejectInvalid("federation peer request method or canonical path is invalid");
|
|
410
|
+
}
|
|
411
|
+
const protocolVersion = readSingleHeader(params.req, FEDERATION_PEER_HEADERS.protocolVersion);
|
|
412
|
+
const senderHandle = normalizeHandle(readSingleHeader(params.req, FEDERATION_PEER_HEADERS.senderHandle));
|
|
413
|
+
const recipientHandle = normalizeHandle(readSingleHeader(params.req, FEDERATION_PEER_HEADERS.recipientHandle));
|
|
414
|
+
const timestampRaw = readSingleHeader(params.req, FEDERATION_PEER_HEADERS.timestamp);
|
|
415
|
+
const nonce = readSingleHeader(params.req, FEDERATION_PEER_HEADERS.nonce);
|
|
416
|
+
const claimedBodySha256 = readSingleHeader(params.req, FEDERATION_PEER_HEADERS.bodySha256);
|
|
417
|
+
const publicKeyRaw = readSingleHeader(params.req, FEDERATION_PEER_HEADERS.publicKey);
|
|
418
|
+
const signature = readSingleHeader(params.req, FEDERATION_PEER_HEADERS.signature);
|
|
419
|
+
if (protocolVersion !== FEDERATION_PEER_PROTOCOL_VERSION) {
|
|
420
|
+
return rejectInvalid("signed federation peer protocol v2 is required");
|
|
421
|
+
}
|
|
422
|
+
if (!senderHandle || senderHandle.length > 256) {
|
|
423
|
+
return rejectInvalid("federation peer sender handle is invalid");
|
|
424
|
+
}
|
|
425
|
+
if (!recipientHandle || recipientHandle.length > 256) {
|
|
426
|
+
return rejectInvalid("federation peer recipient handle is invalid");
|
|
427
|
+
}
|
|
428
|
+
if (recipientHandle !== normalizeHandle(params.recipientHandle)) {
|
|
429
|
+
return rejectInvalid("federation peer recipient does not match this node");
|
|
430
|
+
}
|
|
431
|
+
if (!/^[0-9]{13}$/u.test(timestampRaw)) {
|
|
432
|
+
return rejectInvalid("federation peer timestamp is invalid");
|
|
433
|
+
}
|
|
434
|
+
const timestampMs = Number(timestampRaw);
|
|
435
|
+
if (!Number.isSafeInteger(timestampMs) || Math.abs(nowMs - timestampMs) > FEDERATION_PEER_MAX_CLOCK_SKEW_MS) {
|
|
436
|
+
return {
|
|
437
|
+
ok: false,
|
|
438
|
+
statusCode: 401,
|
|
439
|
+
code: "peer_auth_stale",
|
|
440
|
+
reason: "federation peer request timestamp is outside the allowed clock skew"
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
if (!/^[A-Za-z0-9_-]{16,128}$/u.test(nonce)) {
|
|
444
|
+
return rejectInvalid("federation peer nonce is invalid");
|
|
445
|
+
}
|
|
446
|
+
if (!/^[a-f0-9]{64}$/u.test(claimedBodySha256)) {
|
|
447
|
+
return rejectInvalid("federation peer body digest is invalid");
|
|
448
|
+
}
|
|
449
|
+
const canonicalBody = canonicalizeFederationPeerJson(params.body);
|
|
450
|
+
const actualBodySha256 = sha256Hex(canonicalBody);
|
|
451
|
+
if (claimedBodySha256 !== actualBodySha256) {
|
|
452
|
+
return rejectInvalid("federation peer body digest does not match the request");
|
|
453
|
+
}
|
|
454
|
+
const publicKey = normalizeDevicePublicKeyBase64Url(publicKeyRaw);
|
|
455
|
+
if (!publicKey || publicKey.length > 128 || !signature || signature.length > 128) {
|
|
456
|
+
return rejectInvalid("federation peer signing key or signature is invalid");
|
|
457
|
+
}
|
|
458
|
+
const nodeId = deriveDeviceIdFromPublicKey(publicKey);
|
|
459
|
+
if (!nodeId) {
|
|
460
|
+
return rejectInvalid("federation peer signing key is invalid");
|
|
461
|
+
}
|
|
462
|
+
const signaturePayload = buildSignaturePayload({
|
|
463
|
+
senderHandle,
|
|
464
|
+
recipientHandle,
|
|
465
|
+
method: "POST",
|
|
466
|
+
path: params.expectedPath,
|
|
467
|
+
timestampMs,
|
|
468
|
+
nonce,
|
|
469
|
+
bodySha256: claimedBodySha256,
|
|
470
|
+
publicKey
|
|
471
|
+
});
|
|
472
|
+
if (!verifyDeviceSignature(publicKey, signaturePayload, signature)) {
|
|
473
|
+
return rejectInvalid("federation peer request signature is invalid");
|
|
474
|
+
}
|
|
475
|
+
const directoryBaseUrl = params.directoryBaseUrl.trim();
|
|
476
|
+
if (!directoryBaseUrl) {
|
|
477
|
+
return {
|
|
478
|
+
ok: false,
|
|
479
|
+
statusCode: 503,
|
|
480
|
+
code: "peer_auth_directory_unavailable",
|
|
481
|
+
reason: "federation directory is not configured"
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
let directoryIdentity;
|
|
485
|
+
try {
|
|
486
|
+
directoryIdentity = await (params.deps?.directoryLookup ?? lookupFederationPeerDirectory)({
|
|
487
|
+
senderHandle,
|
|
488
|
+
baseUrl: directoryBaseUrl,
|
|
489
|
+
apiToken: params.directoryApiToken,
|
|
490
|
+
fetchImpl: params.deps?.fetchImpl ?? fetch
|
|
491
|
+
});
|
|
492
|
+
} catch (error) {
|
|
493
|
+
return {
|
|
494
|
+
ok: false,
|
|
495
|
+
statusCode: 503,
|
|
496
|
+
code: "peer_auth_directory_unavailable",
|
|
497
|
+
reason: error instanceof Error ? error.message : "federation directory lookup failed"
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
if (directoryIdentity.status.trim().toLowerCase() !== "verified" || directoryIdentity.nodeId.trim().toLowerCase() !== nodeId.toLowerCase() || directoryIdentity.handle && normalizeHandle(directoryIdentity.handle) !== senderHandle) {
|
|
501
|
+
return {
|
|
502
|
+
ok: false,
|
|
503
|
+
statusCode: 401,
|
|
504
|
+
code: "peer_auth_unverified",
|
|
505
|
+
reason: "federation peer identity is not verified by the directory"
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
const authorization = {
|
|
509
|
+
ok: true,
|
|
510
|
+
senderHandle,
|
|
511
|
+
recipientHandle,
|
|
512
|
+
nodeId,
|
|
513
|
+
nonce,
|
|
514
|
+
timestampMs,
|
|
515
|
+
bodySha256: claimedBodySha256,
|
|
516
|
+
...directoryIdentity.bondTier ? { bondTier: directoryIdentity.bondTier } : {}
|
|
517
|
+
};
|
|
518
|
+
if (params.deferReplayReservation) {
|
|
519
|
+
return authorization;
|
|
520
|
+
}
|
|
521
|
+
return await reserveAuthorizedFederationPeerRequest({
|
|
522
|
+
authorization,
|
|
523
|
+
env,
|
|
524
|
+
deps: params.deps
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
//#endregion
|
|
529
|
+
export { FEDERATION_A2A_RPC_PATH, FEDERATION_MARKETPLACE_DELIVERY_PATH, FEDERATION_MARKETPLACE_ORDER_PATH, FEDERATION_PEER_HEADERS, authorizeFederationPeerRequestV2, buildSignedFederationPeerRequest, checkFederationPeerIngressBudget, isTrustedFederationPeerUrl, lookupFederationPeerDirectory, reserveAuthorizedFederationPeerRequest };
|