@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
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { loadConfig, readConfigFileSnapshotForWrite, writeConfigFile } from "../config/io.js";
|
|
1
|
+
import { loadConfig, readConfigFileSnapshotForWrite, updateConfigFile, writeConfigFile } from "../config/io.js";
|
|
2
2
|
import "../config/config.js";
|
|
3
3
|
import { deleteManualFederationOfferConfig, deleteMarketplaceOrderConfig, deleteMarketplaceRequestConfig, listLocalFederationOffers, listLocalMarketplaceOrders, listLocalMarketplaceRequests, resolveOfferPaymentDefaults, upsertManualFederationOfferConfig, upsertMarketplaceOrderConfig, upsertMarketplaceRequestConfig, validateMarketplaceDeliveryTargetConfig } from "../federation/offers.js";
|
|
4
4
|
import { resolveAgentPublicOrigin, resolveFederationBaseUrl, resolveFederationHandle } from "../federation/runtime.js";
|
|
5
5
|
import { loadFederationBearerToken, persistFederationAccessToken } from "../federation/access-token.js";
|
|
6
|
+
import { readResponseWithLimit } from "../media/read-response-with-limit.js";
|
|
6
7
|
import { buildAttestation } from "../federation/attestation.js";
|
|
8
|
+
import { FEDERATION_MARKETPLACE_DELIVERY_PATH, FEDERATION_MARKETPLACE_ORDER_PATH, authorizeFederationPeerRequestV2, buildSignedFederationPeerRequest, checkFederationPeerIngressBudget, isTrustedFederationPeerUrl, reserveAuthorizedFederationPeerRequest } from "../federation/peer-auth-v2.js";
|
|
7
9
|
import { runMarketplaceCapabilityAdapter } from "../federation/marketplace-capability-adapter.js";
|
|
8
10
|
import { deliverMarketplaceContentSummarizeResult } from "../federation/marketplace-delivery.js";
|
|
9
11
|
import { payMarketplaceOrderDirect } from "../federation/marketplace-direct-payment.js";
|
|
@@ -11,6 +13,7 @@ import { cancelMarketplaceSolanaEscrow, fundMarketplaceSolanaEscrow, refundMarke
|
|
|
11
13
|
import os from "node:os";
|
|
12
14
|
import path from "node:path";
|
|
13
15
|
import { readFile, readdir } from "node:fs/promises";
|
|
16
|
+
import crypto from "node:crypto";
|
|
14
17
|
|
|
15
18
|
//#region src/gateway/federation-http.ts
|
|
16
19
|
const OPERATOR_ECONOMY_FEE_LANES = [
|
|
@@ -20,6 +23,8 @@ const OPERATOR_ECONOMY_FEE_LANES = [
|
|
|
20
23
|
"routing"
|
|
21
24
|
];
|
|
22
25
|
const DEFAULT_OPERATOR_ECONOMY_DISABLED_REASON = "fee collection is disabled until the multi-day measurement history threshold is met";
|
|
26
|
+
const FEDERATION_PEER_RESPONSE_MAX_BYTES = 512 * 1024;
|
|
27
|
+
const FEDERATION_PEER_REQUEST_TIMEOUT_MS = 1e4;
|
|
23
28
|
function pathLooksSimulated(candidate) {
|
|
24
29
|
return typeof candidate === "string" && /operator-economy-simulated|simulated/u.test(candidate);
|
|
25
30
|
}
|
|
@@ -64,6 +69,16 @@ function sendJson(res, status, body) {
|
|
|
64
69
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
65
70
|
res.end(JSON.stringify(body));
|
|
66
71
|
}
|
|
72
|
+
function sendPeerAuthRejection(res, result) {
|
|
73
|
+
if (result.retryAfterMs && result.retryAfterMs > 0) {
|
|
74
|
+
res.setHeader("Retry-After", String(Math.max(1, Math.ceil(result.retryAfterMs / 1e3))));
|
|
75
|
+
}
|
|
76
|
+
sendJson(res, result.statusCode, {
|
|
77
|
+
status: "rejected",
|
|
78
|
+
code: result.code,
|
|
79
|
+
reason: result.reason
|
|
80
|
+
});
|
|
81
|
+
}
|
|
67
82
|
function asObject(value) {
|
|
68
83
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
69
84
|
}
|
|
@@ -136,6 +151,18 @@ function safeConfigIdSegment(value) {
|
|
|
136
151
|
function safeMarketplaceOrderIdSegment(value) {
|
|
137
152
|
return safeConfigIdSegment(value).replace(/[._:]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 96);
|
|
138
153
|
}
|
|
154
|
+
function collisionResistantInboundOrderId(params) {
|
|
155
|
+
const senderHandle = normalizeComparableValue(params.senderHandle);
|
|
156
|
+
const remoteOrderId = params.remoteOrderId.trim();
|
|
157
|
+
const senderSegment = safeMarketplaceOrderIdSegment(senderHandle).slice(0, 40) || "federation";
|
|
158
|
+
const orderSegment = safeMarketplaceOrderIdSegment(remoteOrderId).slice(0, 40) || "order";
|
|
159
|
+
const digest = crypto.createHash("sha256").update(JSON.stringify([
|
|
160
|
+
params.kind,
|
|
161
|
+
senderHandle,
|
|
162
|
+
remoteOrderId
|
|
163
|
+
]), "utf8").digest("hex").slice(0, 32);
|
|
164
|
+
return `inbound-${params.kind}-${senderSegment}-${orderSegment}-${digest}`;
|
|
165
|
+
}
|
|
139
166
|
function toPositiveInteger(value) {
|
|
140
167
|
const numeric = Number(value);
|
|
141
168
|
return Number.isFinite(numeric) && numeric > 0 ? Math.floor(numeric) : 0;
|
|
@@ -444,12 +471,12 @@ async function readJsonBody(req, maxBytes) {
|
|
|
444
471
|
});
|
|
445
472
|
});
|
|
446
473
|
}
|
|
447
|
-
function
|
|
448
|
-
const
|
|
449
|
-
if (
|
|
450
|
-
return
|
|
474
|
+
function resolveFederationAuthorization(apiToken) {
|
|
475
|
+
const token = apiToken?.trim() ?? "";
|
|
476
|
+
if (!token) {
|
|
477
|
+
return undefined;
|
|
451
478
|
}
|
|
452
|
-
return
|
|
479
|
+
return token.toLowerCase().startsWith("bearer ") ? token : `Bearer ${token}`;
|
|
453
480
|
}
|
|
454
481
|
function resolveLocalOffersOrigin(req) {
|
|
455
482
|
const configured = resolveAgentPublicOrigin(process.env).trim();
|
|
@@ -636,6 +663,12 @@ function validateMarketplaceOrderBody(value) {
|
|
|
636
663
|
function normalizeComparableValue(value) {
|
|
637
664
|
return String(value ?? "").trim().toLowerCase();
|
|
638
665
|
}
|
|
666
|
+
function findCorrelatedMarketplaceBuyerOrder(params) {
|
|
667
|
+
const sellerHandle = normalizeComparableValue(params.sellerHandle);
|
|
668
|
+
const sellerOrderId = params.sellerOrderId.trim();
|
|
669
|
+
const serviceKind = normalizeComparableValue(params.serviceKind);
|
|
670
|
+
return listLocalMarketplaceOrders(params.config).find((entry) => entry.source === "local" && normalizeComparableValue(entry.order.sellerHandle) === sellerHandle && entry.order.sellerOrderId?.trim() === sellerOrderId && normalizeComparableValue(entry.order.serviceKind) === serviceKind) ?? null;
|
|
671
|
+
}
|
|
639
672
|
function pricingMatches(expected, actual) {
|
|
640
673
|
const expectedCurrency = normalizeComparableValue(expected?.currency || "USDC");
|
|
641
674
|
const actualCurrency = normalizeComparableValue(actual?.currency || "USDC");
|
|
@@ -692,6 +725,14 @@ function validateSellerMarketplaceOrderIntake(params) {
|
|
|
692
725
|
reason: "seller cannot intake an order from itself"
|
|
693
726
|
};
|
|
694
727
|
}
|
|
728
|
+
const requestedBuyer = params.order.buyerHandle?.trim() || "";
|
|
729
|
+
if (requestedBuyer && normalizeComparableValue(requestedBuyer) !== normalizeComparableValue(params.senderHandle)) {
|
|
730
|
+
return {
|
|
731
|
+
ok: false,
|
|
732
|
+
status: 409,
|
|
733
|
+
reason: "order buyerHandle does not match signed sender"
|
|
734
|
+
};
|
|
735
|
+
}
|
|
695
736
|
const requestedSeller = params.order.sellerHandle?.trim() || "";
|
|
696
737
|
if (requestedSeller && normalizeComparableValue(requestedSeller) !== normalizeComparableValue(params.localHandle)) {
|
|
697
738
|
return {
|
|
@@ -721,6 +762,38 @@ function validateSellerMarketplaceOrderIntake(params) {
|
|
|
721
762
|
reason: "local seller offer not found"
|
|
722
763
|
};
|
|
723
764
|
}
|
|
765
|
+
const requiredTier = normalizeComparableValue(localOffer.offer.requiredTrustOrBondTier || "verified");
|
|
766
|
+
const peerTier = params.peerBondTier ?? "none";
|
|
767
|
+
const peerTierRank = peerTier === "operator-bond" ? 2 : peerTier === "basic-bond" ? 1 : 0;
|
|
768
|
+
const requiredTierRank = requiredTier === "verified" || requiredTier === "none" ? 0 : requiredTier === "basic-bond" ? 1 : requiredTier === "operator-bond" ? 2 : -1;
|
|
769
|
+
if (requiredTierRank < 0) {
|
|
770
|
+
return {
|
|
771
|
+
ok: false,
|
|
772
|
+
status: 409,
|
|
773
|
+
reason: `local seller offer requires unsupported trust tier ${localOffer.offer.requiredTrustOrBondTier}`
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
if (peerTierRank < requiredTierRank) {
|
|
777
|
+
return {
|
|
778
|
+
ok: false,
|
|
779
|
+
status: 403,
|
|
780
|
+
reason: `seller offer requires ${requiredTier}; verified peer has ${peerTier}`
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
if (localOffer.offer.automation?.allowed === true && localOffer.offer.automation.humanApprovalRequired !== true) {
|
|
784
|
+
return {
|
|
785
|
+
ok: false,
|
|
786
|
+
status: 409,
|
|
787
|
+
reason: "seller offer requests unreviewed automation, which is unavailable until its policy is enforced"
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
if (!localOffer.offer.paymentDefaults?.payee.address.trim()) {
|
|
791
|
+
return {
|
|
792
|
+
ok: false,
|
|
793
|
+
status: 409,
|
|
794
|
+
reason: "local seller offer has no wallet-backed payment destination"
|
|
795
|
+
};
|
|
796
|
+
}
|
|
724
797
|
if (normalizeComparableValue(localOffer.offer.visibility) === "private") {
|
|
725
798
|
return {
|
|
726
799
|
ok: false,
|
|
@@ -771,59 +844,87 @@ function validateSellerMarketplaceOrderIntake(params) {
|
|
|
771
844
|
}
|
|
772
845
|
function buildSellerMarketplaceOrderInput(params) {
|
|
773
846
|
const now = new Date().toISOString();
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
const
|
|
777
|
-
const
|
|
847
|
+
const pricing = params.offer.offer.pricing;
|
|
848
|
+
const paymentDefaults = params.offer.offer.paymentDefaults;
|
|
849
|
+
const currency = pricing.currency || paymentDefaults?.currency || "USDC";
|
|
850
|
+
const paymentChain = paymentDefaults?.chain ?? paymentDefaults?.payee?.chain;
|
|
778
851
|
return {
|
|
779
|
-
...params.order,
|
|
780
852
|
id: params.inboundOrderId,
|
|
781
853
|
source: "federation",
|
|
782
|
-
status:
|
|
854
|
+
status: "accepted",
|
|
783
855
|
offerId: params.offer.offer.id,
|
|
856
|
+
...params.order.requestId?.trim() ? { requestId: params.order.requestId.trim() } : {},
|
|
784
857
|
buyerHandle: params.buyerHandle,
|
|
785
858
|
sellerHandle: params.localHandle,
|
|
859
|
+
peerNodeId: params.peerNodeId,
|
|
860
|
+
peerRemoteOrderId: params.peerRemoteOrderId,
|
|
861
|
+
peerRequestDigest: params.peerRequestDigest,
|
|
786
862
|
sellerOrderId: params.inboundOrderId,
|
|
787
863
|
sellerSyncStatus: "accepted",
|
|
788
864
|
sellerSyncedAt: now,
|
|
789
|
-
sellerAcceptedAt:
|
|
865
|
+
sellerAcceptedAt: now,
|
|
790
866
|
serviceKind: params.offer.offer.serviceKind,
|
|
791
867
|
title: params.offer.offer.title,
|
|
792
868
|
pricing,
|
|
793
|
-
fulfillmentMode: params.offer.offer.fulfillmentMode
|
|
794
|
-
receiptRules: params.offer.offer.receiptRules
|
|
869
|
+
fulfillmentMode: params.offer.offer.fulfillmentMode === "human" ? "human" : "agent-approval",
|
|
870
|
+
receiptRules: params.offer.offer.receiptRules,
|
|
795
871
|
paymentIntent: {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
amount: pricing?.amount ?? params.order.paymentIntent?.amount,
|
|
872
|
+
status: "requires_payment",
|
|
873
|
+
amount: pricing.amount,
|
|
799
874
|
currency,
|
|
800
|
-
unit: pricing
|
|
801
|
-
method:
|
|
802
|
-
|
|
875
|
+
unit: pricing.unit,
|
|
876
|
+
method: "agent-wallet",
|
|
877
|
+
chain: paymentChain,
|
|
878
|
+
assetKind: paymentDefaults?.asset?.kind,
|
|
879
|
+
assetAddress: paymentDefaults?.asset?.address,
|
|
880
|
+
assetDecimals: paymentDefaults?.assetDecimals,
|
|
881
|
+
acceptedAssets: params.offer.offer.acceptedAssets ?? params.offer.offer.paymentRails ?? [currency],
|
|
803
882
|
payeeHandle: params.localHandle,
|
|
804
|
-
payeeAddress:
|
|
883
|
+
payeeAddress: paymentDefaults?.payee.address
|
|
805
884
|
},
|
|
806
885
|
settlement: {
|
|
807
|
-
|
|
808
|
-
status:
|
|
809
|
-
amount: pricing
|
|
886
|
+
mode: "direct",
|
|
887
|
+
status: "requires_payment",
|
|
888
|
+
amount: pricing.amount,
|
|
810
889
|
currency,
|
|
811
|
-
|
|
812
|
-
|
|
890
|
+
chain: paymentChain,
|
|
891
|
+
assetKind: paymentDefaults?.asset?.kind,
|
|
892
|
+
assetAddress: paymentDefaults?.asset?.address,
|
|
893
|
+
assetDecimals: paymentDefaults?.assetDecimals,
|
|
894
|
+
payeeAddress: paymentDefaults?.payee.address,
|
|
895
|
+
escrow: {
|
|
896
|
+
status: "not_applicable",
|
|
897
|
+
holdPolicy: "none",
|
|
898
|
+
releaseRequired: false,
|
|
899
|
+
updatedAt: now
|
|
900
|
+
},
|
|
901
|
+
notes: "Peer-reported payment evidence awaits independent local chain verification."
|
|
813
902
|
},
|
|
814
903
|
delivery: {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
904
|
+
status: "pending",
|
|
905
|
+
fulfillmentMode: params.offer.offer.fulfillmentMode === "human" ? "human" : "agent-approval",
|
|
906
|
+
inputShape: params.offer.offer.inputShape,
|
|
907
|
+
deliveryShape: params.offer.offer.deliveryShape,
|
|
908
|
+
target: {
|
|
909
|
+
targetId: `${params.inboundOrderId}-buyer-federation`,
|
|
910
|
+
source: "order",
|
|
911
|
+
owner: "buyer",
|
|
912
|
+
kind: "federation",
|
|
913
|
+
status: "ready",
|
|
914
|
+
label: "Buyer federation node",
|
|
915
|
+
descriptor: params.buyerHandle,
|
|
916
|
+
maskedTarget: params.buyerHandle,
|
|
917
|
+
scope: {
|
|
918
|
+
orderId: params.inboundOrderId,
|
|
919
|
+
serviceKind: params.offer.offer.serviceKind
|
|
920
|
+
},
|
|
921
|
+
federation: { handle: params.buyerHandle }
|
|
922
|
+
},
|
|
821
923
|
updatedAt: now
|
|
822
924
|
},
|
|
823
925
|
receipt: {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
notes: params.order.receipt?.notes ?? "Awaiting payment proof and delivery evidence."
|
|
926
|
+
status: "pending",
|
|
927
|
+
notes: "Awaiting independently verified payment proof and delivery evidence."
|
|
827
928
|
}
|
|
828
929
|
};
|
|
829
930
|
}
|
|
@@ -833,7 +934,8 @@ function buildSellerMarketplaceOrderEndpoint(endpoint) {
|
|
|
833
934
|
return null;
|
|
834
935
|
}
|
|
835
936
|
try {
|
|
836
|
-
|
|
937
|
+
const url = new URL("/api/federation/marketplace/orders", raw);
|
|
938
|
+
return isTrustedFederationPeerUrl(url) ? url : null;
|
|
837
939
|
} catch {
|
|
838
940
|
return null;
|
|
839
941
|
}
|
|
@@ -849,10 +951,13 @@ async function forwardRequest(params) {
|
|
|
849
951
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
850
952
|
const targetPath = overridePath ?? url.pathname + url.search;
|
|
851
953
|
const target = new URL(targetPath, baseUrl);
|
|
954
|
+
if (!isTrustedFederationPeerUrl(target)) {
|
|
955
|
+
throw new Error("federation upstream must use HTTPS or an explicit loopback HTTP URL");
|
|
956
|
+
}
|
|
852
957
|
const headers = new Headers();
|
|
853
|
-
const authorization =
|
|
958
|
+
const authorization = resolveFederationAuthorization(apiToken) || (fallbackFederationToken ? resolveFederationAuthorization(await loadFederationBearerToken(process.env)) : undefined);
|
|
854
959
|
if (authorization) {
|
|
855
|
-
headers.set("Authorization", authorization
|
|
960
|
+
headers.set("Authorization", authorization);
|
|
856
961
|
}
|
|
857
962
|
let bodyPayload;
|
|
858
963
|
if (body !== undefined) {
|
|
@@ -862,9 +967,11 @@ async function forwardRequest(params) {
|
|
|
862
967
|
const upstream = await fetch(target, {
|
|
863
968
|
method: req.method,
|
|
864
969
|
headers,
|
|
865
|
-
body: bodyPayload
|
|
970
|
+
body: bodyPayload,
|
|
971
|
+
redirect: "error",
|
|
972
|
+
signal: AbortSignal.timeout(FEDERATION_PEER_REQUEST_TIMEOUT_MS)
|
|
866
973
|
});
|
|
867
|
-
const text = await upstream.
|
|
974
|
+
const text = (await readResponseWithLimit(upstream, FEDERATION_PEER_RESPONSE_MAX_BYTES, { onOverflow: () => new Error("federation upstream response exceeded the size limit") })).toString("utf8");
|
|
868
975
|
if (upstream.ok && persistFederationToken) {
|
|
869
976
|
await persistFederationTokenResponse(text);
|
|
870
977
|
}
|
|
@@ -879,20 +986,25 @@ async function forwardOperatorEconomyFeeRequest(params) {
|
|
|
879
986
|
const { req, res, baseUrl, apiToken, fallbackFederationToken } = params;
|
|
880
987
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
881
988
|
const target = new URL(url.pathname + url.search, baseUrl);
|
|
989
|
+
if (!isTrustedFederationPeerUrl(target)) {
|
|
990
|
+
throw new Error("federation upstream must use HTTPS or an explicit loopback HTTP URL");
|
|
991
|
+
}
|
|
882
992
|
const headers = new Headers();
|
|
883
|
-
const authorization =
|
|
993
|
+
const authorization = resolveFederationAuthorization(apiToken) || (fallbackFederationToken ? resolveFederationAuthorization(await loadFederationBearerToken(process.env)) : undefined);
|
|
884
994
|
if (authorization) {
|
|
885
|
-
headers.set("Authorization", authorization
|
|
995
|
+
headers.set("Authorization", authorization);
|
|
886
996
|
}
|
|
887
997
|
try {
|
|
888
998
|
const upstream = await fetch(target, {
|
|
889
999
|
method: req.method,
|
|
890
|
-
headers
|
|
1000
|
+
headers,
|
|
1001
|
+
redirect: "error",
|
|
1002
|
+
signal: AbortSignal.timeout(FEDERATION_PEER_REQUEST_TIMEOUT_MS)
|
|
891
1003
|
});
|
|
892
1004
|
if (upstream.status === 404 && await tryServeLocalOperatorEconomyFeeFallback(req, res)) {
|
|
893
1005
|
return;
|
|
894
1006
|
}
|
|
895
|
-
const text = await upstream.
|
|
1007
|
+
const text = (await readResponseWithLimit(upstream, FEDERATION_PEER_RESPONSE_MAX_BYTES, { onOverflow: () => new Error("federation upstream response exceeded the size limit") })).toString("utf8");
|
|
896
1008
|
res.statusCode = upstream.status;
|
|
897
1009
|
const contentType = upstream.headers.get("content-type");
|
|
898
1010
|
if (contentType) {
|
|
@@ -1394,7 +1506,7 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1394
1506
|
if (!endpoint) {
|
|
1395
1507
|
sendJson(res, 400, {
|
|
1396
1508
|
status: "rejected",
|
|
1397
|
-
reason: "seller endpoint is
|
|
1509
|
+
reason: "seller endpoint must use HTTPS (plain HTTP is allowed only for an explicit loopback URL)"
|
|
1398
1510
|
});
|
|
1399
1511
|
return true;
|
|
1400
1512
|
}
|
|
@@ -1403,6 +1515,14 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1403
1515
|
env: process.env,
|
|
1404
1516
|
fallbackDomain: federationBase ? new URL(federationBase).hostname : "localhost"
|
|
1405
1517
|
});
|
|
1518
|
+
const sellerHandle = currentOrder.order.sellerHandle?.trim() || "";
|
|
1519
|
+
if (!sellerHandle) {
|
|
1520
|
+
sendJson(res, 409, {
|
|
1521
|
+
status: "rejected",
|
|
1522
|
+
reason: "seller handle is required for signed marketplace order intake"
|
|
1523
|
+
});
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1406
1526
|
const orderPayload = {
|
|
1407
1527
|
...currentOrder.order,
|
|
1408
1528
|
delivery: {
|
|
@@ -1411,15 +1531,24 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1411
1531
|
}
|
|
1412
1532
|
};
|
|
1413
1533
|
try {
|
|
1534
|
+
const signedRequest = buildSignedFederationPeerRequest({
|
|
1535
|
+
senderHandle: localHandle,
|
|
1536
|
+
recipientHandle: sellerHandle,
|
|
1537
|
+
path: FEDERATION_MARKETPLACE_ORDER_PATH,
|
|
1538
|
+
body: orderPayload,
|
|
1539
|
+
env: process.env
|
|
1540
|
+
});
|
|
1414
1541
|
const upstream = await fetch(endpoint, {
|
|
1415
1542
|
method: "POST",
|
|
1416
1543
|
headers: {
|
|
1417
1544
|
"Content-Type": "application/json",
|
|
1418
|
-
|
|
1545
|
+
...signedRequest.headers
|
|
1419
1546
|
},
|
|
1420
|
-
body:
|
|
1547
|
+
body: signedRequest.body,
|
|
1548
|
+
redirect: "error",
|
|
1549
|
+
signal: AbortSignal.timeout(FEDERATION_PEER_REQUEST_TIMEOUT_MS)
|
|
1421
1550
|
});
|
|
1422
|
-
const text = await upstream.
|
|
1551
|
+
const text = (await readResponseWithLimit(upstream, FEDERATION_PEER_RESPONSE_MAX_BYTES, { onOverflow: () => new Error("seller intake response exceeded the size limit") })).toString("utf8");
|
|
1423
1552
|
let upstreamBody = text;
|
|
1424
1553
|
if (text.trim()) {
|
|
1425
1554
|
try {
|
|
@@ -1635,7 +1764,8 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1635
1764
|
const delivered = await deliverMarketplaceContentSummarizeResult({
|
|
1636
1765
|
config: snapshot.config,
|
|
1637
1766
|
orderId,
|
|
1638
|
-
result: resultPayload
|
|
1767
|
+
result: resultPayload,
|
|
1768
|
+
deps: opts.marketplaceDeliverySsrfLookupFn ? { ssrfLookupFn: opts.marketplaceDeliverySsrfLookupFn } : undefined
|
|
1639
1769
|
});
|
|
1640
1770
|
if ("error" in delivered) {
|
|
1641
1771
|
sendJson(res, delivered.statusCode, {
|
|
@@ -1691,6 +1821,14 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1691
1821
|
res.end("Method Not Allowed");
|
|
1692
1822
|
return true;
|
|
1693
1823
|
}
|
|
1824
|
+
const ingressBudget = checkFederationPeerIngressBudget({
|
|
1825
|
+
clientIp: opts.peerAuthClientIp ?? req.socket?.remoteAddress,
|
|
1826
|
+
rateLimiter: opts.peerAuthDeps?.rateLimiter
|
|
1827
|
+
});
|
|
1828
|
+
if (!ingressBudget.ok) {
|
|
1829
|
+
sendPeerAuthRejection(res, ingressBudget);
|
|
1830
|
+
return true;
|
|
1831
|
+
}
|
|
1694
1832
|
const body = await readJsonBody(req, maxBodyBytes);
|
|
1695
1833
|
if (!body.ok) {
|
|
1696
1834
|
sendJson(res, 400, {
|
|
@@ -1699,6 +1837,28 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1699
1837
|
});
|
|
1700
1838
|
return true;
|
|
1701
1839
|
}
|
|
1840
|
+
const federationBase = resolveFederationBaseUrl(process.env);
|
|
1841
|
+
const localHandle = resolveFederationHandle({
|
|
1842
|
+
env: process.env,
|
|
1843
|
+
fallbackDomain: federationBase ? new URL(federationBase).hostname : "localhost"
|
|
1844
|
+
});
|
|
1845
|
+
const peerAuth = await authorizeFederationPeerRequestV2({
|
|
1846
|
+
req,
|
|
1847
|
+
body: body.value,
|
|
1848
|
+
recipientHandle: localHandle,
|
|
1849
|
+
expectedPath: FEDERATION_MARKETPLACE_ORDER_PATH,
|
|
1850
|
+
directoryBaseUrl: federationBase,
|
|
1851
|
+
directoryApiToken: apiToken,
|
|
1852
|
+
clientIp: opts.peerAuthClientIp,
|
|
1853
|
+
env: process.env,
|
|
1854
|
+
deps: opts.peerAuthDeps,
|
|
1855
|
+
ingressBudgetApplied: true,
|
|
1856
|
+
deferReplayReservation: true
|
|
1857
|
+
});
|
|
1858
|
+
if (!peerAuth.ok) {
|
|
1859
|
+
sendPeerAuthRejection(res, peerAuth);
|
|
1860
|
+
return true;
|
|
1861
|
+
}
|
|
1702
1862
|
const parsed = validateMarketplaceOrderBody(body.value);
|
|
1703
1863
|
if (!parsed.ok) {
|
|
1704
1864
|
sendJson(res, 400, {
|
|
@@ -1707,48 +1867,138 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1707
1867
|
});
|
|
1708
1868
|
return true;
|
|
1709
1869
|
}
|
|
1710
|
-
const federationBase = resolveFederationBaseUrl(process.env);
|
|
1711
|
-
const localHandle = resolveFederationHandle({
|
|
1712
|
-
env: process.env,
|
|
1713
|
-
fallbackDomain: federationBase ? new URL(federationBase).hostname : "localhost"
|
|
1714
|
-
});
|
|
1715
1870
|
const origin = resolveLocalOffersOrigin(req);
|
|
1716
|
-
const senderHandle =
|
|
1717
|
-
const
|
|
1718
|
-
const
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
order: parsed.value
|
|
1871
|
+
const senderHandle = peerAuth.senderHandle;
|
|
1872
|
+
const buyerHandle = senderHandle || parsed.value.buyerHandle?.trim() || "";
|
|
1873
|
+
const remoteOrderId = parsed.value.id || parsed.value.offerId || parsed.value.title || "order";
|
|
1874
|
+
const inboundOrderId = collisionResistantInboundOrderId({
|
|
1875
|
+
kind: "order",
|
|
1876
|
+
senderHandle: buyerHandle,
|
|
1877
|
+
remoteOrderId
|
|
1724
1878
|
});
|
|
1725
|
-
|
|
1726
|
-
|
|
1879
|
+
const transaction = await updateConfigFile(async (currentConfig) => {
|
|
1880
|
+
const validation = validateSellerMarketplaceOrderIntake({
|
|
1881
|
+
config: currentConfig,
|
|
1882
|
+
origin,
|
|
1883
|
+
localHandle,
|
|
1884
|
+
senderHandle,
|
|
1885
|
+
peerBondTier: peerAuth.bondTier,
|
|
1886
|
+
order: parsed.value
|
|
1887
|
+
});
|
|
1888
|
+
if (!validation.ok) {
|
|
1889
|
+
return {
|
|
1890
|
+
config: currentConfig,
|
|
1891
|
+
result: {
|
|
1892
|
+
kind: "rejected",
|
|
1893
|
+
status: validation.status,
|
|
1894
|
+
reason: validation.reason
|
|
1895
|
+
},
|
|
1896
|
+
write: false
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
const existingInboundOrder = listLocalMarketplaceOrders(currentConfig).find((entry) => entry.configId === inboundOrderId);
|
|
1900
|
+
if (existingInboundOrder) {
|
|
1901
|
+
const ownershipMatches = existingInboundOrder.source === "federation" && normalizeComparableValue(existingInboundOrder.order.buyerHandle) === normalizeComparableValue(buyerHandle) && normalizeComparableValue(existingInboundOrder.order.sellerHandle) === normalizeComparableValue(localHandle) && normalizeComparableValue(existingInboundOrder.order.offerId) === normalizeComparableValue(validation.value.offer.offer.id) && existingInboundOrder.order.peerNodeId?.trim().toLowerCase() === peerAuth.nodeId.toLowerCase() && existingInboundOrder.order.peerRemoteOrderId === remoteOrderId;
|
|
1902
|
+
if (!ownershipMatches) {
|
|
1903
|
+
return {
|
|
1904
|
+
config: currentConfig,
|
|
1905
|
+
result: {
|
|
1906
|
+
kind: "rejected",
|
|
1907
|
+
status: 409,
|
|
1908
|
+
reason: "federation order identity conflicts with an existing local order"
|
|
1909
|
+
},
|
|
1910
|
+
write: false
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
if (existingInboundOrder.order.peerRequestDigest !== peerAuth.bodySha256) {
|
|
1914
|
+
return {
|
|
1915
|
+
config: currentConfig,
|
|
1916
|
+
result: {
|
|
1917
|
+
kind: "rejected",
|
|
1918
|
+
status: 409,
|
|
1919
|
+
reason: "federation order is immutable after its first accepted request"
|
|
1920
|
+
},
|
|
1921
|
+
write: false
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
const replay = await reserveAuthorizedFederationPeerRequest({
|
|
1925
|
+
authorization: peerAuth,
|
|
1926
|
+
env: process.env,
|
|
1927
|
+
deps: opts.peerAuthDeps
|
|
1928
|
+
});
|
|
1929
|
+
if (!replay.ok) {
|
|
1930
|
+
return {
|
|
1931
|
+
config: currentConfig,
|
|
1932
|
+
result: {
|
|
1933
|
+
kind: "auth-rejected",
|
|
1934
|
+
rejection: replay
|
|
1935
|
+
},
|
|
1936
|
+
write: false
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
return {
|
|
1940
|
+
config: currentConfig,
|
|
1941
|
+
result: {
|
|
1942
|
+
kind: "accepted",
|
|
1943
|
+
created: false,
|
|
1944
|
+
order: existingInboundOrder
|
|
1945
|
+
},
|
|
1946
|
+
write: false
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
const replay = await reserveAuthorizedFederationPeerRequest({
|
|
1950
|
+
authorization: peerAuth,
|
|
1951
|
+
env: process.env,
|
|
1952
|
+
deps: opts.peerAuthDeps
|
|
1953
|
+
});
|
|
1954
|
+
if (!replay.ok) {
|
|
1955
|
+
return {
|
|
1956
|
+
config: currentConfig,
|
|
1957
|
+
result: {
|
|
1958
|
+
kind: "auth-rejected",
|
|
1959
|
+
rejection: replay
|
|
1960
|
+
},
|
|
1961
|
+
write: false
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
const upserted = upsertMarketplaceOrderConfig({
|
|
1965
|
+
config: currentConfig,
|
|
1966
|
+
input: buildSellerMarketplaceOrderInput({
|
|
1967
|
+
order: parsed.value,
|
|
1968
|
+
localHandle,
|
|
1969
|
+
buyerHandle,
|
|
1970
|
+
inboundOrderId,
|
|
1971
|
+
peerNodeId: peerAuth.nodeId,
|
|
1972
|
+
peerRemoteOrderId: remoteOrderId,
|
|
1973
|
+
peerRequestDigest: peerAuth.bodySha256,
|
|
1974
|
+
offer: validation.value.offer
|
|
1975
|
+
})
|
|
1976
|
+
});
|
|
1977
|
+
return {
|
|
1978
|
+
config: upserted.config,
|
|
1979
|
+
result: {
|
|
1980
|
+
kind: "accepted",
|
|
1981
|
+
created: upserted.created,
|
|
1982
|
+
order: listLocalMarketplaceOrders(upserted.config).find((entry) => entry.configId === upserted.order.id)
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
});
|
|
1986
|
+
if (transaction.result.kind === "rejected") {
|
|
1987
|
+
sendJson(res, transaction.result.status, {
|
|
1727
1988
|
status: "rejected",
|
|
1728
|
-
reason:
|
|
1989
|
+
reason: transaction.result.reason
|
|
1729
1990
|
});
|
|
1730
1991
|
return true;
|
|
1731
1992
|
}
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
const result = upsertMarketplaceOrderConfig({
|
|
1737
|
-
config: snapshot.config,
|
|
1738
|
-
input: buildSellerMarketplaceOrderInput({
|
|
1739
|
-
order: parsed.value,
|
|
1740
|
-
localHandle,
|
|
1741
|
-
buyerHandle,
|
|
1742
|
-
inboundOrderId,
|
|
1743
|
-
offer: validation.value.offer
|
|
1744
|
-
})
|
|
1745
|
-
});
|
|
1746
|
-
await writeConfigFile(result.config, writeOptions);
|
|
1993
|
+
if (transaction.result.kind === "auth-rejected") {
|
|
1994
|
+
sendPeerAuthRejection(res, transaction.result.rejection);
|
|
1995
|
+
return true;
|
|
1996
|
+
}
|
|
1747
1997
|
sendJson(res, 200, {
|
|
1748
1998
|
ok: true,
|
|
1749
1999
|
accepted: true,
|
|
1750
|
-
created: result.created,
|
|
1751
|
-
order:
|
|
2000
|
+
created: transaction.result.created,
|
|
2001
|
+
order: transaction.result.order
|
|
1752
2002
|
});
|
|
1753
2003
|
return true;
|
|
1754
2004
|
}
|
|
@@ -1760,6 +2010,14 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1760
2010
|
res.end("Method Not Allowed");
|
|
1761
2011
|
return true;
|
|
1762
2012
|
}
|
|
2013
|
+
const ingressBudget = checkFederationPeerIngressBudget({
|
|
2014
|
+
clientIp: opts.peerAuthClientIp ?? req.socket?.remoteAddress,
|
|
2015
|
+
rateLimiter: opts.peerAuthDeps?.rateLimiter
|
|
2016
|
+
});
|
|
2017
|
+
if (!ingressBudget.ok) {
|
|
2018
|
+
sendPeerAuthRejection(res, ingressBudget);
|
|
2019
|
+
return true;
|
|
2020
|
+
}
|
|
1763
2021
|
const body = await readJsonBody(req, maxBodyBytes);
|
|
1764
2022
|
if (!body.ok) {
|
|
1765
2023
|
sendJson(res, 400, {
|
|
@@ -1768,6 +2026,28 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1768
2026
|
});
|
|
1769
2027
|
return true;
|
|
1770
2028
|
}
|
|
2029
|
+
const federationBase = resolveFederationBaseUrl(process.env);
|
|
2030
|
+
const localHandle = resolveFederationHandle({
|
|
2031
|
+
env: process.env,
|
|
2032
|
+
fallbackDomain: federationBase ? new URL(federationBase).hostname : "localhost"
|
|
2033
|
+
});
|
|
2034
|
+
const peerAuth = await authorizeFederationPeerRequestV2({
|
|
2035
|
+
req,
|
|
2036
|
+
body: body.value,
|
|
2037
|
+
recipientHandle: localHandle,
|
|
2038
|
+
expectedPath: FEDERATION_MARKETPLACE_DELIVERY_PATH,
|
|
2039
|
+
directoryBaseUrl: federationBase,
|
|
2040
|
+
directoryApiToken: apiToken,
|
|
2041
|
+
clientIp: opts.peerAuthClientIp,
|
|
2042
|
+
env: process.env,
|
|
2043
|
+
deps: opts.peerAuthDeps,
|
|
2044
|
+
ingressBudgetApplied: true,
|
|
2045
|
+
deferReplayReservation: true
|
|
2046
|
+
});
|
|
2047
|
+
if (!peerAuth.ok) {
|
|
2048
|
+
sendPeerAuthRejection(res, peerAuth);
|
|
2049
|
+
return true;
|
|
2050
|
+
}
|
|
1771
2051
|
const parsed = validateMarketplaceDeliveryInboxBody(body.value);
|
|
1772
2052
|
if (!parsed.ok) {
|
|
1773
2053
|
sendJson(res, 400, {
|
|
@@ -1776,67 +2056,181 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1776
2056
|
});
|
|
1777
2057
|
return true;
|
|
1778
2058
|
}
|
|
1779
|
-
const
|
|
1780
|
-
const
|
|
1781
|
-
|
|
1782
|
-
|
|
2059
|
+
const senderHandle = peerAuth.senderHandle;
|
|
2060
|
+
const inboundOrderId = collisionResistantInboundOrderId({
|
|
2061
|
+
kind: "delivery",
|
|
2062
|
+
senderHandle,
|
|
2063
|
+
remoteOrderId: parsed.value.orderId
|
|
1783
2064
|
});
|
|
1784
|
-
const senderHandle = (typeof req.headers["x-fased-sender-handle"] === "string" ? req.headers["x-fased-sender-handle"].trim() : "") || (typeof req.headers["x-fased-federation-sender"] === "string" ? req.headers["x-fased-federation-sender"].trim() : "");
|
|
1785
|
-
const senderSegment = safeMarketplaceOrderIdSegment(senderHandle || "federation");
|
|
1786
|
-
const orderSegment = safeMarketplaceOrderIdSegment(parsed.value.orderId);
|
|
1787
|
-
const inboundOrderId = `inbound-${senderSegment || "federation"}-${orderSegment || "order"}`;
|
|
1788
2065
|
const deliveredAt = parsed.value.deliveredAt || new Date().toISOString();
|
|
1789
2066
|
const payment = parsed.value.payment;
|
|
1790
|
-
const
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
2067
|
+
const transaction = await updateConfigFile(async (currentConfig) => {
|
|
2068
|
+
const buyerOrder = findCorrelatedMarketplaceBuyerOrder({
|
|
2069
|
+
config: currentConfig,
|
|
2070
|
+
sellerHandle: senderHandle,
|
|
2071
|
+
sellerOrderId: parsed.value.orderId,
|
|
2072
|
+
serviceKind: parsed.value.serviceKind
|
|
2073
|
+
});
|
|
2074
|
+
if (!buyerOrder) {
|
|
2075
|
+
return {
|
|
2076
|
+
config: currentConfig,
|
|
2077
|
+
result: {
|
|
2078
|
+
kind: "rejected",
|
|
2079
|
+
status: 409,
|
|
2080
|
+
reason: "federation delivery does not match an existing local buyer order"
|
|
2081
|
+
},
|
|
2082
|
+
write: false
|
|
2083
|
+
};
|
|
2084
|
+
}
|
|
2085
|
+
if (buyerOrder.order.offerId?.trim() && parsed.value.offerId.trim() && buyerOrder.order.offerId.trim() !== parsed.value.offerId.trim()) {
|
|
2086
|
+
return {
|
|
2087
|
+
config: currentConfig,
|
|
2088
|
+
result: {
|
|
2089
|
+
kind: "rejected",
|
|
2090
|
+
status: 409,
|
|
2091
|
+
reason: "federation delivery offer does not match the local buyer order"
|
|
2092
|
+
},
|
|
2093
|
+
write: false
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
const existingInboundDelivery = listLocalMarketplaceOrders(currentConfig).find((entry) => entry.configId === inboundOrderId);
|
|
2097
|
+
if (existingInboundDelivery) {
|
|
2098
|
+
const ownershipMatches = existingInboundDelivery.source === "federation" && normalizeComparableValue(existingInboundDelivery.order.sellerHandle) === normalizeComparableValue(senderHandle) && existingInboundDelivery.order.sellerOrderId?.trim() === parsed.value.orderId && normalizeComparableValue(existingInboundDelivery.order.buyerHandle) === normalizeComparableValue(localHandle) && existingInboundDelivery.order.peerNodeId?.trim().toLowerCase() === peerAuth.nodeId.toLowerCase() && existingInboundDelivery.order.peerRemoteOrderId === parsed.value.orderId;
|
|
2099
|
+
if (!ownershipMatches) {
|
|
2100
|
+
return {
|
|
2101
|
+
config: currentConfig,
|
|
2102
|
+
result: {
|
|
2103
|
+
kind: "rejected",
|
|
2104
|
+
status: 409,
|
|
2105
|
+
reason: "federation delivery identity conflicts with an existing local order"
|
|
2106
|
+
},
|
|
2107
|
+
write: false
|
|
2108
|
+
};
|
|
2109
|
+
}
|
|
2110
|
+
if (existingInboundDelivery.order.peerDeliveryDigest !== peerAuth.bodySha256) {
|
|
2111
|
+
return {
|
|
2112
|
+
config: currentConfig,
|
|
2113
|
+
result: {
|
|
2114
|
+
kind: "rejected",
|
|
2115
|
+
status: 409,
|
|
2116
|
+
reason: "federation delivery is immutable after its first accepted request"
|
|
2117
|
+
},
|
|
2118
|
+
write: false
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
const replay = await reserveAuthorizedFederationPeerRequest({
|
|
2122
|
+
authorization: peerAuth,
|
|
2123
|
+
env: process.env,
|
|
2124
|
+
deps: opts.peerAuthDeps
|
|
2125
|
+
});
|
|
2126
|
+
if (!replay.ok) {
|
|
2127
|
+
return {
|
|
2128
|
+
config: currentConfig,
|
|
2129
|
+
result: {
|
|
2130
|
+
kind: "auth-rejected",
|
|
2131
|
+
rejection: replay
|
|
2132
|
+
},
|
|
2133
|
+
write: false
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
return {
|
|
2137
|
+
config: currentConfig,
|
|
2138
|
+
result: {
|
|
2139
|
+
kind: "accepted",
|
|
2140
|
+
delivery: existingInboundDelivery
|
|
2141
|
+
},
|
|
2142
|
+
write: false
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
const replay = await reserveAuthorizedFederationPeerRequest({
|
|
2146
|
+
authorization: peerAuth,
|
|
2147
|
+
env: process.env,
|
|
2148
|
+
deps: opts.peerAuthDeps
|
|
2149
|
+
});
|
|
2150
|
+
if (!replay.ok) {
|
|
2151
|
+
return {
|
|
2152
|
+
config: currentConfig,
|
|
2153
|
+
result: {
|
|
2154
|
+
kind: "auth-rejected",
|
|
2155
|
+
rejection: replay
|
|
2156
|
+
},
|
|
2157
|
+
write: false
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
const upserted = upsertMarketplaceOrderConfig({
|
|
2161
|
+
config: currentConfig,
|
|
2162
|
+
input: {
|
|
2163
|
+
id: inboundOrderId,
|
|
2164
|
+
source: "federation",
|
|
1807
2165
|
status: "delivered",
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
2166
|
+
offerId: parsed.value.offerId,
|
|
2167
|
+
buyerHandle: localHandle,
|
|
2168
|
+
...senderHandle ? { sellerHandle: senderHandle } : {},
|
|
2169
|
+
sellerOrderId: parsed.value.orderId,
|
|
2170
|
+
peerNodeId: peerAuth.nodeId,
|
|
2171
|
+
peerRemoteOrderId: parsed.value.orderId,
|
|
2172
|
+
peerDeliveryDigest: peerAuth.bodySha256,
|
|
2173
|
+
title: "Federated content summary",
|
|
2174
|
+
serviceKind: "content.summarize",
|
|
2175
|
+
paymentIntent: {
|
|
2176
|
+
status: "submitted",
|
|
2177
|
+
...payment?.txRef ? { txRef: payment.txRef } : {}
|
|
2178
|
+
},
|
|
2179
|
+
settlement: {
|
|
2180
|
+
mode: "direct",
|
|
2181
|
+
status: "submitted",
|
|
2182
|
+
...payment?.invoiceId ? { invoiceId: payment.invoiceId } : {},
|
|
2183
|
+
...payment?.receiptId ? { receiptId: payment.receiptId } : {},
|
|
2184
|
+
...payment?.txRef ? { txRef: payment.txRef } : {},
|
|
2185
|
+
notes: "Peer-reported payment evidence has not been locally chain-verified.",
|
|
2186
|
+
updatedAt: deliveredAt
|
|
2187
|
+
},
|
|
2188
|
+
delivery: {
|
|
2189
|
+
status: "delivered",
|
|
2190
|
+
fulfillmentMode: "agent",
|
|
2191
|
+
deliveryShape: "summary-v0",
|
|
2192
|
+
targetKind: "federation",
|
|
2193
|
+
targetStatus: "ready",
|
|
2194
|
+
targetLabel: senderHandle ? "Federation sender" : "Federation",
|
|
2195
|
+
targetMasked: senderHandle || "federation",
|
|
2196
|
+
resultRef: parsed.value.resultRef,
|
|
2197
|
+
...parsed.value.artifactRef ? { artifactRef: parsed.value.artifactRef } : {},
|
|
2198
|
+
notes: `Received content.summarize result over federation: ${parsed.value.resultSummary}`,
|
|
2199
|
+
deliveredAt,
|
|
2200
|
+
updatedAt: deliveredAt
|
|
2201
|
+
},
|
|
2202
|
+
receipt: {
|
|
2203
|
+
status: "pending",
|
|
2204
|
+
resultRef: parsed.value.resultRef,
|
|
2205
|
+
notes: "Federation delivery stored as a read-only Marketplace inbox item; no local receipt has been issued and peer payment evidence remains unverified."
|
|
2206
|
+
},
|
|
2207
|
+
resultRef: parsed.value.resultRef
|
|
1827
2208
|
},
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
2209
|
+
now: deliveredAt
|
|
2210
|
+
});
|
|
2211
|
+
return {
|
|
2212
|
+
config: upserted.config,
|
|
2213
|
+
result: {
|
|
2214
|
+
kind: "accepted",
|
|
2215
|
+
delivery: listLocalMarketplaceOrders(upserted.config).find((entry) => entry.configId === upserted.order.id)
|
|
2216
|
+
}
|
|
2217
|
+
};
|
|
1834
2218
|
});
|
|
1835
|
-
|
|
2219
|
+
if (transaction.result.kind === "rejected") {
|
|
2220
|
+
sendJson(res, transaction.result.status, {
|
|
2221
|
+
status: "rejected",
|
|
2222
|
+
reason: transaction.result.reason
|
|
2223
|
+
});
|
|
2224
|
+
return true;
|
|
2225
|
+
}
|
|
2226
|
+
if (transaction.result.kind === "auth-rejected") {
|
|
2227
|
+
sendPeerAuthRejection(res, transaction.result.rejection);
|
|
2228
|
+
return true;
|
|
2229
|
+
}
|
|
1836
2230
|
sendJson(res, 200, {
|
|
1837
2231
|
ok: true,
|
|
1838
2232
|
accepted: true,
|
|
1839
|
-
delivery:
|
|
2233
|
+
delivery: transaction.result.delivery
|
|
1840
2234
|
});
|
|
1841
2235
|
return true;
|
|
1842
2236
|
}
|
|
@@ -1848,6 +2242,17 @@ async function handleFederationHttpRequest(req, res, opts) {
|
|
|
1848
2242
|
});
|
|
1849
2243
|
return true;
|
|
1850
2244
|
}
|
|
2245
|
+
try {
|
|
2246
|
+
if (!isTrustedFederationPeerUrl(new URL("/", baseUrl))) {
|
|
2247
|
+
throw new Error("untrusted transport");
|
|
2248
|
+
}
|
|
2249
|
+
} catch {
|
|
2250
|
+
sendJson(res, 503, {
|
|
2251
|
+
status: "unavailable",
|
|
2252
|
+
reason: "federation base URL must use HTTPS (plain HTTP is allowed only for an explicit loopback URL)"
|
|
2253
|
+
});
|
|
2254
|
+
return true;
|
|
2255
|
+
}
|
|
1851
2256
|
const shouldUseLocalFederationReadAuth = segments[0] === "operator-economy" && segments[1] === "fees";
|
|
1852
2257
|
if (req.method === "GET" && shouldUseLocalFederationReadAuth) {
|
|
1853
2258
|
const operatorEconomySubPath = segments[2] ?? "";
|