@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,6 +1,5 @@
|
|
|
1
1
|
import { defaultRuntime } from "../../runtime.js";
|
|
2
2
|
import { resolveAgentDir, resolveDefaultAgentId, resolveSessionAgentId } from "../../agents/agent-scope.js";
|
|
3
|
-
import { listProviderBrandManifests } from "../../providers/registry.js";
|
|
4
3
|
import { DEFAULT_PROVIDER } from "../../agents/defaults.js";
|
|
5
4
|
import { normalizeSecretInput } from "../../utils/normalize-secret-input.js";
|
|
6
5
|
import { normalizeProviderId } from "../../agents/provider-id.js";
|
|
@@ -11,6 +10,7 @@ import { loadConfig, writeConfigFile } from "../../config/io.js";
|
|
|
11
10
|
import "../../config/config.js";
|
|
12
11
|
import { resolveProfileUnusableUntilForDisplay } from "../../agents/auth-profiles/usage.js";
|
|
13
12
|
import "../../agents/auth-profiles.js";
|
|
13
|
+
import { listProviderBrandManifests } from "../../providers/registry.js";
|
|
14
14
|
import { ensureFasedModelsJson } from "../../agents/models-config.js";
|
|
15
15
|
import { deriveModelMetadata } from "../../agents/model-metadata.js";
|
|
16
16
|
import { ErrorCodes, errorShape } from "../protocol/schema/error-codes.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { logMutatingAdminRpcAudit } from "./mutating-admin-rpc-audit.js";
|
|
2
|
+
import { ErrorCodes, errorShape } from "../protocol/schema/error-codes.js";
|
|
3
|
+
import "../protocol/index.js";
|
|
4
|
+
import { sanitizeGatewaySecretsRuntimeError } from "../server-secrets-runtime.js";
|
|
5
|
+
|
|
6
|
+
//#region src/gateway/server-methods/secrets.ts
|
|
7
|
+
function createSecretsHandlers(params) {
|
|
8
|
+
return { "secrets.reload": async ({ respond, client, context }) => {
|
|
9
|
+
try {
|
|
10
|
+
const result = await params.reloadSecrets();
|
|
11
|
+
logMutatingAdminRpcAudit({
|
|
12
|
+
context,
|
|
13
|
+
client,
|
|
14
|
+
method: "secrets.reload",
|
|
15
|
+
outcome: "succeeded",
|
|
16
|
+
details: { warningCount: result.warningCount }
|
|
17
|
+
});
|
|
18
|
+
respond(true, {
|
|
19
|
+
ok: true,
|
|
20
|
+
warningCount: result.warningCount
|
|
21
|
+
});
|
|
22
|
+
} catch (err) {
|
|
23
|
+
const safe = sanitizeGatewaySecretsRuntimeError(err);
|
|
24
|
+
logMutatingAdminRpcAudit({
|
|
25
|
+
context,
|
|
26
|
+
client,
|
|
27
|
+
method: "secrets.reload",
|
|
28
|
+
outcome: "failed",
|
|
29
|
+
details: { code: safe.code }
|
|
30
|
+
});
|
|
31
|
+
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, safe.message, {
|
|
32
|
+
retryable: true,
|
|
33
|
+
details: { code: safe.code }
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
36
|
+
} };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { createSecretsHandlers };
|
|
@@ -55,10 +55,9 @@ const CONTROL_PLANE_WRITE_METHODS = new Set([
|
|
|
55
55
|
]);
|
|
56
56
|
const SAT_MINING_MUTATION_METHODS = new Set([
|
|
57
57
|
"sat.openCycle",
|
|
58
|
-
"sat.
|
|
58
|
+
"sat.topUpRegistryReserve",
|
|
59
59
|
"sat.refillRegistryReserveFromTreasury",
|
|
60
60
|
"sat.runProtocolMaintenanceOnce",
|
|
61
|
-
"sat.setProtocolRecipients",
|
|
62
61
|
"sat.claimProtocolTreasury",
|
|
63
62
|
"sat.claimProtocolDistributorSat",
|
|
64
63
|
"sat.initMinerCapital",
|
|
@@ -19,76 +19,201 @@ function shouldInvalidateGatewayModelCatalog(changedPaths) {
|
|
|
19
19
|
return changedPaths.some((path) => path === "models" || path.startsWith("models.") || path === "agents.defaults.model" || path.startsWith("agents.defaults.model.") || path === "agents.defaults.models" || path.startsWith("agents.defaults.models."));
|
|
20
20
|
}
|
|
21
21
|
function createGatewayReloadHandlers(params) {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
22
|
+
const createHotReloadTransaction = (plan) => {
|
|
23
|
+
const originalState = params.getState();
|
|
24
|
+
let workingState = { ...originalState };
|
|
25
|
+
let policyMutated = false;
|
|
26
|
+
let heartbeatMutated = false;
|
|
27
|
+
let cronMutated = false;
|
|
28
|
+
let browserMutated = false;
|
|
29
|
+
let gmailMutated = false;
|
|
30
|
+
let concurrencyMutated = false;
|
|
31
|
+
const channelsMutated = [];
|
|
32
|
+
let applyStarted = false;
|
|
33
|
+
let rollbackStarted = false;
|
|
34
|
+
const publishState = () => {
|
|
35
|
+
params.setState({ ...workingState });
|
|
36
|
+
};
|
|
37
|
+
const startGmailWatcherForReload = async (config, phase) => {
|
|
38
|
+
let failed = false;
|
|
39
|
+
await startGmailWatcherWithLogs({
|
|
40
|
+
cfg: config,
|
|
41
|
+
log: {
|
|
42
|
+
info: (message) => params.logHooks.info(message),
|
|
43
|
+
warn: () => params.logHooks.warn(`gmail watcher ${phase} did not start`),
|
|
44
|
+
error: () => {
|
|
45
|
+
failed = true;
|
|
46
|
+
params.logHooks.error(`gmail watcher ${phase} failed to start`);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
onSkipped: () => params.logHooks.info(`skipping gmail watcher ${phase} (FASED_SKIP_GMAIL_WATCHER=1)`)
|
|
46
50
|
});
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (plan.restartBrowserControl) {
|
|
50
|
-
if (state.browserControl) {
|
|
51
|
-
await state.browserControl.stop().catch(() => {});
|
|
51
|
+
if (failed) {
|
|
52
|
+
throw new Error(`gmail watcher ${phase} failed`);
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
};
|
|
55
|
+
const apply = async (nextConfig) => {
|
|
56
|
+
if (applyStarted) {
|
|
57
|
+
throw new Error("hot reload transaction already started");
|
|
57
58
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
59
|
+
applyStarted = true;
|
|
60
|
+
policyMutated = true;
|
|
61
|
+
setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(nextConfig) });
|
|
62
|
+
if (plan.reloadHooks) {
|
|
63
|
+
workingState.hooksConfig = resolveHooksConfig(nextConfig);
|
|
64
|
+
}
|
|
65
|
+
if (plan.restartHeartbeat) {
|
|
66
|
+
heartbeatMutated = true;
|
|
67
|
+
workingState.heartbeatRunner.updateConfig(nextConfig);
|
|
68
|
+
}
|
|
69
|
+
resetDirectoryCache();
|
|
70
|
+
if (shouldInvalidateGatewayModelCatalog(plan.changedPaths)) {
|
|
71
|
+
markGatewayModelCatalogStaleForReload();
|
|
72
|
+
}
|
|
73
|
+
if (plan.restartCron) {
|
|
74
|
+
cronMutated = true;
|
|
75
|
+
workingState.cronState.cron.stop();
|
|
76
|
+
workingState.cronState = buildGatewayCronService({
|
|
77
|
+
cfg: nextConfig,
|
|
78
|
+
deps: params.deps,
|
|
79
|
+
broadcast: params.broadcast
|
|
80
|
+
});
|
|
81
|
+
publishState();
|
|
82
|
+
await workingState.cronState.cron.start();
|
|
83
|
+
}
|
|
84
|
+
if (plan.restartBrowserControl) {
|
|
85
|
+
browserMutated = true;
|
|
86
|
+
try {
|
|
87
|
+
await workingState.browserControl?.stop();
|
|
88
|
+
} finally {
|
|
89
|
+
workingState.browserControl = null;
|
|
90
|
+
publishState();
|
|
78
91
|
}
|
|
92
|
+
workingState.browserControl = await startBrowserControlServerIfEnabled();
|
|
93
|
+
publishState();
|
|
79
94
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
if (plan.restartGmailWatcher) {
|
|
96
|
+
gmailMutated = true;
|
|
97
|
+
await stopGmailWatcher();
|
|
98
|
+
await startGmailWatcherForReload(nextConfig, "apply");
|
|
99
|
+
}
|
|
100
|
+
if (plan.restartChannels.size > 0) {
|
|
101
|
+
if (isTruthyEnvValue(process.env.FASED_SKIP_CHANNELS) || isTruthyEnvValue(process.env.FASED_SKIP_PROVIDERS)) {
|
|
102
|
+
params.logChannels.info("skipping channel reload (FASED_SKIP_CHANNELS=1 or FASED_SKIP_PROVIDERS=1)");
|
|
103
|
+
} else {
|
|
104
|
+
for (const channel of plan.restartChannels) {
|
|
105
|
+
channelsMutated.push(channel);
|
|
106
|
+
params.logChannels.info(`restarting ${channel} channel`);
|
|
107
|
+
await params.stopChannel(channel);
|
|
108
|
+
await params.startChannel(channel);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
concurrencyMutated = true;
|
|
113
|
+
setCommandLaneConcurrency(CommandLane.Cron, nextConfig.cron?.maxConcurrentRuns ?? 1);
|
|
114
|
+
setCommandLaneConcurrency(CommandLane.Main, resolveAgentMaxConcurrent(nextConfig));
|
|
115
|
+
setCommandLaneConcurrency(CommandLane.Subagent, resolveSubagentMaxConcurrent(nextConfig));
|
|
116
|
+
if (plan.hotReasons.length > 0) {
|
|
117
|
+
params.logReload.info(`config hot reload applied (${plan.hotReasons.join(", ")})`);
|
|
118
|
+
} else if (plan.noopPaths.length > 0) {
|
|
119
|
+
params.logReload.info(`config change applied (dynamic reads: ${plan.noopPaths.join(", ")})`);
|
|
120
|
+
}
|
|
121
|
+
publishState();
|
|
122
|
+
};
|
|
123
|
+
const rollback = async (previousConfig) => {
|
|
124
|
+
if (!applyStarted || rollbackStarted) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
rollbackStarted = true;
|
|
128
|
+
const failures = [];
|
|
129
|
+
const capture = async (operation) => {
|
|
130
|
+
try {
|
|
131
|
+
await operation();
|
|
132
|
+
return true;
|
|
133
|
+
} catch (error) {
|
|
134
|
+
failures.push(error);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
if (concurrencyMutated) {
|
|
139
|
+
await capture(() => {
|
|
140
|
+
setCommandLaneConcurrency(CommandLane.Cron, previousConfig.cron?.maxConcurrentRuns ?? 1);
|
|
141
|
+
setCommandLaneConcurrency(CommandLane.Main, resolveAgentMaxConcurrent(previousConfig));
|
|
142
|
+
setCommandLaneConcurrency(CommandLane.Subagent, resolveSubagentMaxConcurrent(previousConfig));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
for (const channel of channelsMutated.toReversed()) {
|
|
146
|
+
const stopped = await capture(async () => await params.stopChannel(channel));
|
|
147
|
+
if (stopped) {
|
|
148
|
+
await capture(async () => await params.startChannel(channel));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (gmailMutated) {
|
|
152
|
+
const stopped = await capture(async () => await stopGmailWatcher());
|
|
153
|
+
if (stopped) {
|
|
154
|
+
await capture(async () => await startGmailWatcherForReload(previousConfig, "rollback"));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (browserMutated) {
|
|
158
|
+
const candidateBrowser = workingState.browserControl;
|
|
159
|
+
const candidateStopped = await capture(async () => await candidateBrowser?.stop());
|
|
160
|
+
workingState.browserControl = null;
|
|
161
|
+
publishState();
|
|
162
|
+
if (candidateStopped) {
|
|
163
|
+
let restoredBrowser = null;
|
|
164
|
+
const restored = await capture(async () => {
|
|
165
|
+
restoredBrowser = await startBrowserControlServerIfEnabled();
|
|
166
|
+
});
|
|
167
|
+
if (restored) {
|
|
168
|
+
workingState.browserControl = restoredBrowser;
|
|
169
|
+
publishState();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (cronMutated) {
|
|
174
|
+
await capture(() => workingState.cronState.cron.stop());
|
|
175
|
+
workingState.cronState = originalState.cronState;
|
|
176
|
+
publishState();
|
|
177
|
+
await capture(async () => await originalState.cronState.cron.start());
|
|
178
|
+
}
|
|
179
|
+
if (heartbeatMutated) {
|
|
180
|
+
const restored = await capture(() => workingState.heartbeatRunner.updateConfig(previousConfig));
|
|
181
|
+
if (!restored) {
|
|
182
|
+
await capture(() => workingState.heartbeatRunner.stop());
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
workingState.hooksConfig = originalState.hooksConfig;
|
|
186
|
+
if (policyMutated) {
|
|
187
|
+
await capture(() => setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(previousConfig) }));
|
|
188
|
+
}
|
|
189
|
+
resetDirectoryCache();
|
|
190
|
+
if (shouldInvalidateGatewayModelCatalog(plan.changedPaths)) {
|
|
191
|
+
markGatewayModelCatalogStaleForReload();
|
|
192
|
+
}
|
|
193
|
+
publishState();
|
|
194
|
+
if (failures.length > 0) {
|
|
195
|
+
throw new Error(`hot reload rollback incomplete (${failures.length} component failure(s))`);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
return {
|
|
199
|
+
apply,
|
|
200
|
+
rollback
|
|
201
|
+
};
|
|
202
|
+
};
|
|
203
|
+
const applyHotReload = async (plan, nextConfig) => {
|
|
204
|
+
await createHotReloadTransaction(plan).apply(nextConfig);
|
|
90
205
|
};
|
|
91
206
|
let restartPending = false;
|
|
207
|
+
let restartDeferral = null;
|
|
208
|
+
const cancelPendingGatewayRestart = () => {
|
|
209
|
+
const cancelled = restartDeferral?.cancel() ?? false;
|
|
210
|
+
restartDeferral = null;
|
|
211
|
+
restartPending = false;
|
|
212
|
+
if (cancelled) {
|
|
213
|
+
params.logReload.info("cancelled deferred config restart before evaluating the latest revision");
|
|
214
|
+
}
|
|
215
|
+
return cancelled;
|
|
216
|
+
};
|
|
92
217
|
const requestGatewayRestart = (plan, nextConfig) => {
|
|
93
218
|
setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(nextConfig) });
|
|
94
219
|
const reasons = plan.restartReasons.length ? plan.restartReasons.join(", ") : plan.changedPaths.join(", ");
|
|
@@ -123,30 +248,33 @@ function createGatewayReloadHandlers(params) {
|
|
|
123
248
|
const active = getActiveCounts();
|
|
124
249
|
if (active.totalActive > 0) {
|
|
125
250
|
if (restartPending) {
|
|
126
|
-
|
|
127
|
-
return;
|
|
251
|
+
cancelPendingGatewayRestart();
|
|
128
252
|
}
|
|
129
253
|
restartPending = true;
|
|
130
254
|
const initialDetails = formatActiveDetails(active);
|
|
131
255
|
params.logReload.warn(`config change requires gateway restart (${reasons}) — deferring until ${initialDetails.join(", ")} complete`);
|
|
132
|
-
deferGatewayRestartUntilIdle({
|
|
256
|
+
const deferral = deferGatewayRestartUntilIdle({
|
|
133
257
|
getPendingCount: () => getActiveCounts().totalActive,
|
|
134
258
|
hooks: {
|
|
135
259
|
onReady: () => {
|
|
136
260
|
restartPending = false;
|
|
261
|
+
restartDeferral = null;
|
|
137
262
|
params.logReload.info("all operations and replies completed; restarting gateway now");
|
|
138
263
|
},
|
|
139
264
|
onTimeout: (_pending, elapsedMs) => {
|
|
140
265
|
const remaining = formatActiveDetails(getActiveCounts());
|
|
141
266
|
restartPending = false;
|
|
267
|
+
restartDeferral = null;
|
|
142
268
|
params.logReload.warn(`restart timeout after ${elapsedMs}ms with ${remaining.join(", ")} still active; restarting anyway`);
|
|
143
269
|
},
|
|
144
270
|
onCheckError: (err) => {
|
|
145
271
|
restartPending = false;
|
|
272
|
+
restartDeferral = null;
|
|
146
273
|
params.logReload.warn(`restart deferral check failed (${String(err)}); restarting gateway now`);
|
|
147
274
|
}
|
|
148
275
|
}
|
|
149
276
|
});
|
|
277
|
+
restartDeferral = deferral.isPending() ? deferral : null;
|
|
150
278
|
} else {
|
|
151
279
|
params.logReload.warn(`config change requires gateway restart (${reasons})`);
|
|
152
280
|
const emitted = emitGatewayRestart();
|
|
@@ -157,6 +285,8 @@ function createGatewayReloadHandlers(params) {
|
|
|
157
285
|
};
|
|
158
286
|
return {
|
|
159
287
|
applyHotReload,
|
|
288
|
+
cancelPendingGatewayRestart,
|
|
289
|
+
createHotReloadTransaction,
|
|
160
290
|
requestGatewayRestart
|
|
161
291
|
};
|
|
162
292
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isLoopbackHost, isTrustedProxyAddress, isValidIPv4, resolveGatewayBindHost } from "./net.js";
|
|
2
2
|
import { resolveWalletRuntimeConfig } from "../wallet/wallet-runtime-config.js";
|
|
3
|
-
import { resolveWalletApprovalAuthMode } from "../wallet/wallet-approval-auth.js";
|
|
4
3
|
import { normalizeControlUiBasePath } from "./control-ui-shared.js";
|
|
4
|
+
import { resolveWalletApprovalAuthMode } from "../wallet/wallet-approval-auth.js";
|
|
5
5
|
import { resolveHooksConfig } from "./hooks.js";
|
|
6
6
|
import { assertGatewayAuthConfigured, resolveGatewayAuth } from "./auth.js";
|
|
7
7
|
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { resolveMainSessionKeyFromConfig } from "../config/sessions/main-session.js";
|
|
2
|
+
import "../config/sessions.js";
|
|
3
|
+
import { enqueueSystemEvent } from "../infra/system-events.js";
|
|
4
|
+
import { activateSecretsRuntimeSnapshot, clearSecretsRuntimeSnapshot, getActiveSecretsRuntimeSnapshot, prepareSecretsRuntimeSnapshot } from "../secrets/runtime.js";
|
|
5
|
+
import { buildGatewayReloadPlan, diffConfigPaths, resolveGatewayReloadSettings } from "./config-reload.js";
|
|
6
|
+
import { isDeepStrictEqual } from "node:util";
|
|
7
|
+
|
|
8
|
+
//#region src/gateway/server-secrets-runtime.ts
|
|
9
|
+
var GatewaySecretsRuntimeError = class extends Error {
|
|
10
|
+
constructor(code, message, options) {
|
|
11
|
+
super(message, options);
|
|
12
|
+
this.name = "GatewaySecretsRuntimeError";
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function sanitizeGatewaySecretsRuntimeError(error) {
|
|
17
|
+
if (error instanceof GatewaySecretsRuntimeError) {
|
|
18
|
+
return {
|
|
19
|
+
code: error.code,
|
|
20
|
+
message: error.message
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
code: "SECRETS_RELOAD_FAILED",
|
|
25
|
+
message: "Secret reload failed without changing the active runtime snapshot. Run `fased secrets audit --check` for local diagnostics."
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function runtimeError(code, message, cause) {
|
|
29
|
+
return new GatewaySecretsRuntimeError(code, message, cause === undefined ? undefined : { cause });
|
|
30
|
+
}
|
|
31
|
+
function normalizeRuntimeError(error, fallbackCode, fallbackMessage) {
|
|
32
|
+
return error instanceof GatewaySecretsRuntimeError ? error : runtimeError(fallbackCode, fallbackMessage, error);
|
|
33
|
+
}
|
|
34
|
+
function invalidSnapshotError(snapshot) {
|
|
35
|
+
const paths = [...new Set(snapshot.issues.map((issue) => issue.path.trim() || "<root>"))].slice(0, 8);
|
|
36
|
+
const suffix = paths.length > 0 ? ` Invalid paths: ${paths.join(", ")}.` : "";
|
|
37
|
+
return runtimeError("SECRETS_CONFIG_INVALID", `Secret reload refused an invalid Gateway config.${suffix} Run \`fased doctor\` locally before retrying.`);
|
|
38
|
+
}
|
|
39
|
+
function missingSnapshotError() {
|
|
40
|
+
return runtimeError("SECRETS_CONFIG_MISSING", "Secret reload refused to replace the active snapshot because the Gateway config file is missing.");
|
|
41
|
+
}
|
|
42
|
+
function staleSourceError() {
|
|
43
|
+
return runtimeError("SECRETS_SOURCE_STALE", "Secret reload discarded a stale config revision; retry after the current config change finishes.");
|
|
44
|
+
}
|
|
45
|
+
function cloneConfig(config) {
|
|
46
|
+
return structuredClone(config);
|
|
47
|
+
}
|
|
48
|
+
function sameSourceSnapshot(left, right) {
|
|
49
|
+
if (left.exists !== right.exists || left.valid !== right.valid) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (left.hash && right.hash) {
|
|
53
|
+
return left.hash === right.hash;
|
|
54
|
+
}
|
|
55
|
+
return isDeepStrictEqual(left.config, right.config);
|
|
56
|
+
}
|
|
57
|
+
function planNeedsHotApply(plan) {
|
|
58
|
+
return plan.hotReasons.length > 0 || plan.reloadHooks || plan.restartGmailWatcher || plan.restartBrowserControl || plan.restartCron || plan.restartHeartbeat || plan.restartChannels.size > 0;
|
|
59
|
+
}
|
|
60
|
+
function assertManualSourceChangeAllowed(params) {
|
|
61
|
+
const changedPaths = diffConfigPaths(params.previous, params.next);
|
|
62
|
+
if (changedPaths.length === 0) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const plan = buildGatewayReloadPlan(changedPaths);
|
|
66
|
+
const settings = resolveGatewayReloadSettings(params.next);
|
|
67
|
+
if (settings.mode === "restart" || plan.restartGateway) {
|
|
68
|
+
throw runtimeError("SECRETS_SOURCE_RESTART_REQUIRED", "Secret reload refused config changes that require a Gateway restart. Let the config reloader restart the Gateway, then retry.");
|
|
69
|
+
}
|
|
70
|
+
if (planNeedsHotApply(plan)) {
|
|
71
|
+
throw runtimeError("SECRETS_SOURCE_HOT_RELOAD_REQUIRED", "Secret reload refused config changes that require live component reconfiguration. Let the config reloader apply them, then retry.");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function createGatewaySecretsRuntimeController(params) {
|
|
75
|
+
const prepareSnapshot = params.prepareSnapshot ?? prepareSecretsRuntimeSnapshot;
|
|
76
|
+
const activateSnapshot = params.activateSnapshot ?? activateSecretsRuntimeSnapshot;
|
|
77
|
+
const getActiveSnapshot = params.getActiveSnapshot ?? getActiveSecretsRuntimeSnapshot;
|
|
78
|
+
const clearSnapshot = params.clearSnapshot ?? clearSecretsRuntimeSnapshot;
|
|
79
|
+
let activeSourceConfig = null;
|
|
80
|
+
let degraded = false;
|
|
81
|
+
let closed = false;
|
|
82
|
+
let latestGeneration = 0;
|
|
83
|
+
let operationTail = Promise.resolve();
|
|
84
|
+
let shutdownPromise = null;
|
|
85
|
+
const runExclusive = (operation) => {
|
|
86
|
+
const result = operationTail.then(operation, operation);
|
|
87
|
+
operationTail = result.then(() => undefined, () => undefined);
|
|
88
|
+
return result;
|
|
89
|
+
};
|
|
90
|
+
const runTracked = (operation) => {
|
|
91
|
+
const generation = ++latestGeneration;
|
|
92
|
+
return runExclusive(async () => await operation(generation));
|
|
93
|
+
};
|
|
94
|
+
const assertCurrent = (generation) => {
|
|
95
|
+
if (closed) {
|
|
96
|
+
throw runtimeError("SECRETS_RUNTIME_CLOSED", "Secret reload was cancelled because the Gateway is shutting down.");
|
|
97
|
+
}
|
|
98
|
+
if (generation !== latestGeneration) {
|
|
99
|
+
throw staleSourceError();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
const emitTransition = (code) => {
|
|
103
|
+
if (params.emitTransition) {
|
|
104
|
+
params.emitTransition(code);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const text = code === "SECRETS_RELOADER_DEGRADED" ? `[${code}] Secret reload failed; the Gateway kept its last-known-good runtime snapshot.` : `[${code}] Secret references recovered and the Gateway activated a new runtime snapshot.`;
|
|
108
|
+
enqueueSystemEvent(text, {
|
|
109
|
+
sessionKey: resolveMainSessionKeyFromConfig(),
|
|
110
|
+
contextKey: "gateway-secrets-runtime",
|
|
111
|
+
trusted: true
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
const recordReloadFailure = (error) => {
|
|
115
|
+
const safe = sanitizeGatewaySecretsRuntimeError(error);
|
|
116
|
+
params.log.warn(`[SECRETS_RELOADER_DEGRADED] secret reload failed; keeping last-known-good runtime snapshot (${safe.code}): ${safe.message}`);
|
|
117
|
+
if (degraded || closed) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
degraded = true;
|
|
121
|
+
emitTransition("SECRETS_RELOADER_DEGRADED");
|
|
122
|
+
};
|
|
123
|
+
const recordReloadSuccess = () => {
|
|
124
|
+
if (!degraded) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
degraded = false;
|
|
128
|
+
params.log.info("[SECRETS_RELOADER_RECOVERED] secret runtime snapshot recovered");
|
|
129
|
+
emitTransition("SECRETS_RELOADER_RECOVERED");
|
|
130
|
+
};
|
|
131
|
+
const logWarnings = (prepared) => {
|
|
132
|
+
for (const warning of prepared.warnings) {
|
|
133
|
+
params.log.warn(`[${warning.code}] ${warning.message}`);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const prepareSafely = async (config) => {
|
|
137
|
+
try {
|
|
138
|
+
return await prepareSnapshot({ config });
|
|
139
|
+
} catch (error) {
|
|
140
|
+
throw normalizeRuntimeError(error, "SECRETS_RESOLUTION_FAILED", "One or more required secret references could not be resolved. Run `fased secrets audit --check` locally before retrying.");
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const requireReloadableSnapshot = (snapshot) => {
|
|
144
|
+
if (!snapshot.exists) {
|
|
145
|
+
throw missingSnapshotError();
|
|
146
|
+
}
|
|
147
|
+
if (!snapshot.valid) {
|
|
148
|
+
throw invalidSnapshotError(snapshot);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
const assertSnapshotStillCurrent = async (expected) => {
|
|
152
|
+
const current = await params.readConfigSnapshot();
|
|
153
|
+
requireReloadableSnapshot(current);
|
|
154
|
+
if (!sameSourceSnapshot(expected, current)) {
|
|
155
|
+
throw staleSourceError();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const restoreSnapshot = (previous) => {
|
|
159
|
+
try {
|
|
160
|
+
if (previous) {
|
|
161
|
+
activateSnapshot(previous);
|
|
162
|
+
} else {
|
|
163
|
+
clearSnapshot();
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
clearSnapshot();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
const activateStartup = (snapshot) => runTracked(async (generation) => {
|
|
170
|
+
if (!snapshot.valid) {
|
|
171
|
+
throw invalidSnapshotError(snapshot);
|
|
172
|
+
}
|
|
173
|
+
assertCurrent(generation);
|
|
174
|
+
const prepared = await prepareSafely(snapshot.config);
|
|
175
|
+
assertCurrent(generation);
|
|
176
|
+
activateSnapshot(prepared);
|
|
177
|
+
activeSourceConfig = cloneConfig(snapshot.config);
|
|
178
|
+
logWarnings(prepared);
|
|
179
|
+
return prepared;
|
|
180
|
+
});
|
|
181
|
+
const activateHotReload = (snapshot, transaction) => runTracked(async (generation) => {
|
|
182
|
+
try {
|
|
183
|
+
requireReloadableSnapshot(snapshot);
|
|
184
|
+
assertCurrent(generation);
|
|
185
|
+
await assertSnapshotStillCurrent(snapshot);
|
|
186
|
+
assertCurrent(generation);
|
|
187
|
+
const prepared = await prepareSafely(snapshot.config);
|
|
188
|
+
assertCurrent(generation);
|
|
189
|
+
await assertSnapshotStillCurrent(snapshot);
|
|
190
|
+
assertCurrent(generation);
|
|
191
|
+
const previous = getActiveSnapshot();
|
|
192
|
+
activateSnapshot(prepared);
|
|
193
|
+
try {
|
|
194
|
+
await transaction.apply(prepared.config);
|
|
195
|
+
assertCurrent(generation);
|
|
196
|
+
await assertSnapshotStillCurrent(snapshot);
|
|
197
|
+
assertCurrent(generation);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
restoreSnapshot(previous);
|
|
200
|
+
if (previous) {
|
|
201
|
+
try {
|
|
202
|
+
await transaction.rollback(previous.config);
|
|
203
|
+
} catch (rollbackError) {
|
|
204
|
+
throw runtimeError("SECRETS_HOT_APPLY_FAILED", "Gateway hot reload failed. The last-known-good secret snapshot was restored, but one or more live components could not be restored and remain stopped.", rollbackError);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
throw normalizeRuntimeError(error, "SECRETS_HOT_APPLY_FAILED", "Gateway hot reload failed; the last-known-good secret snapshot and live component state were restored.");
|
|
208
|
+
}
|
|
209
|
+
activeSourceConfig = cloneConfig(snapshot.config);
|
|
210
|
+
logWarnings(prepared);
|
|
211
|
+
recordReloadSuccess();
|
|
212
|
+
return prepared;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
const safe = normalizeRuntimeError(error, "SECRETS_RELOAD_FAILED", "Secret reload failed without changing the active runtime snapshot.");
|
|
215
|
+
recordReloadFailure(safe);
|
|
216
|
+
throw safe;
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
const validateRestart = (snapshot) => runTracked(async (generation) => {
|
|
220
|
+
try {
|
|
221
|
+
requireReloadableSnapshot(snapshot);
|
|
222
|
+
assertCurrent(generation);
|
|
223
|
+
await assertSnapshotStillCurrent(snapshot);
|
|
224
|
+
assertCurrent(generation);
|
|
225
|
+
const prepared = await prepareSafely(snapshot.config);
|
|
226
|
+
assertCurrent(generation);
|
|
227
|
+
await assertSnapshotStillCurrent(snapshot);
|
|
228
|
+
assertCurrent(generation);
|
|
229
|
+
logWarnings(prepared);
|
|
230
|
+
return { warningCount: prepared.warnings.length };
|
|
231
|
+
} catch (error) {
|
|
232
|
+
const safe = normalizeRuntimeError(error, "SECRETS_RELOAD_FAILED", "Secret validation failed; the Gateway restart was not scheduled.");
|
|
233
|
+
recordReloadFailure(safe);
|
|
234
|
+
throw safe;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
const reloadFromConfig = () => runTracked(async (generation) => {
|
|
238
|
+
try {
|
|
239
|
+
assertCurrent(generation);
|
|
240
|
+
const snapshot = await params.readConfigSnapshot();
|
|
241
|
+
requireReloadableSnapshot(snapshot);
|
|
242
|
+
if (!activeSourceConfig) {
|
|
243
|
+
throw runtimeError("SECRETS_RELOAD_FAILED", "Secret reload is unavailable before the startup snapshot is active.");
|
|
244
|
+
}
|
|
245
|
+
assertManualSourceChangeAllowed({
|
|
246
|
+
previous: activeSourceConfig,
|
|
247
|
+
next: snapshot.config
|
|
248
|
+
});
|
|
249
|
+
const prepared = await prepareSafely(snapshot.config);
|
|
250
|
+
assertCurrent(generation);
|
|
251
|
+
await assertSnapshotStillCurrent(snapshot);
|
|
252
|
+
assertCurrent(generation);
|
|
253
|
+
activateSnapshot(prepared);
|
|
254
|
+
activeSourceConfig = cloneConfig(snapshot.config);
|
|
255
|
+
logWarnings(prepared);
|
|
256
|
+
recordReloadSuccess();
|
|
257
|
+
return { warningCount: prepared.warnings.length };
|
|
258
|
+
} catch (error) {
|
|
259
|
+
const safe = normalizeRuntimeError(error, "SECRETS_RELOAD_FAILED", "Secret reload failed without changing the active runtime snapshot.");
|
|
260
|
+
recordReloadFailure(safe);
|
|
261
|
+
throw safe;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
const shutdown = () => {
|
|
265
|
+
if (shutdownPromise) {
|
|
266
|
+
return shutdownPromise;
|
|
267
|
+
}
|
|
268
|
+
closed = true;
|
|
269
|
+
latestGeneration += 1;
|
|
270
|
+
shutdownPromise = (async () => {
|
|
271
|
+
await operationTail;
|
|
272
|
+
activeSourceConfig = null;
|
|
273
|
+
degraded = false;
|
|
274
|
+
clearSnapshot();
|
|
275
|
+
})();
|
|
276
|
+
return shutdownPromise;
|
|
277
|
+
};
|
|
278
|
+
return {
|
|
279
|
+
activateStartup,
|
|
280
|
+
activateHotReload,
|
|
281
|
+
validateRestart,
|
|
282
|
+
reloadFromConfig,
|
|
283
|
+
shutdown
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
//#endregion
|
|
288
|
+
export { createGatewaySecretsRuntimeController, sanitizeGatewaySecretsRuntimeError };
|