@fased/fased 0.1.61 → 0.1.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/README.md +38 -30
- package/config/dependency-ownership.json +1 -1
- package/config/signer-policies/README.md +49 -0
- package/config/signer-policies/agent.json.template +32 -0
- package/config/signer-policies/mining.json.template +69 -0
- package/config/signer-policies/network.json.template +5 -0
- package/config/signer-policies/vault.json.template +70 -0
- package/config/signer-protocol-v2.json +76 -0
- package/config/typescript-noemit-baseline.json +680 -0
- package/dist/acp/client.js +2 -2
- package/dist/acp/secret-file.js +2 -2
- package/dist/agents/agent-scope.js +2 -2
- package/dist/agents/apply-patch.js +8 -8
- package/dist/agents/auth-profiles/paths.js +2 -2
- package/dist/agents/auth-profiles/store.js +269 -33
- package/dist/agents/bash-tools.exec.js +10 -4
- package/dist/agents/bash-tools.shared.js +2 -2
- package/dist/agents/cli-credentials.js +4 -4
- package/dist/agents/current-model-catalog.js +3 -3
- package/dist/agents/docs-path.js +3 -3
- package/dist/agents/embedded-pi-mcp.js +4 -4
- package/dist/agents/identity-avatar.js +3 -3
- package/dist/agents/identity-file.js +2 -2
- package/dist/agents/memory-search.js +7 -1
- package/dist/agents/model-catalog-access.js +1 -2
- package/dist/agents/model-catalog-snapshot.js +1 -1
- package/dist/agents/model-catalog-source.js +1 -1
- package/dist/agents/model-metadata.js +1 -1
- package/dist/agents/model-selection.js +2 -28
- package/dist/agents/models-config.providers.js +6 -6
- package/dist/agents/openai-codex-app-server.js +5 -5
- package/dist/agents/pi-embedded-runner/compact.js +15 -7
- package/dist/agents/pi-embedded-runner/model.js +1 -1
- package/dist/agents/pi-embedded-runner/run/attempt.js +24 -13
- package/dist/agents/pi-embedded-runner/run.js +2 -0
- package/dist/agents/pi-embedded-runner/tool-split.js +40 -2
- package/dist/agents/pi-embedded-subscribe.raw-stream.js +3 -3
- package/dist/agents/pi-extensions/compaction-safeguard.js +3 -3
- package/dist/agents/pi-model-discovery.js +6 -6
- package/dist/agents/pi-project-settings.js +3 -3
- package/dist/agents/pi-tool-definition-adapter.js +16 -1
- package/dist/agents/pi-tools.js +2 -1
- package/dist/agents/sandbox/config.js +1 -1
- package/dist/agents/sandbox/context.js +27 -2
- package/dist/agents/sandbox/fs-bridge.js +2 -2
- package/dist/agents/session-dirs.js +4 -4
- package/dist/agents/session-write-lock.js +13 -13
- package/dist/agents/shell-utils.js +5 -5
- package/dist/agents/skills/bundled-dir.js +4 -4
- package/dist/agents/skills/env-overrides.js +38 -28
- package/dist/agents/skills/local-loader.js +6 -6
- package/dist/agents/skills/plugin-skills.js +2 -2
- package/dist/agents/skills/trust.js +93 -0
- package/dist/agents/skills/workspace.js +141 -13
- package/dist/agents/skills-clawhub.js +36 -11
- package/dist/agents/skills-install-download.js +7 -7
- package/dist/agents/skills-install-plan.js +2 -2
- package/dist/agents/skills-install.js +2 -2
- package/dist/agents/skills-marketplace-scan.js +49 -0
- package/dist/agents/skills-status.js +2 -2
- package/dist/agents/subagent-depth.js +2 -2
- package/dist/agents/system-prompt-params.js +2 -2
- package/dist/agents/tools/marketplace-offer-draft-tool.js +1 -1
- package/dist/agents/tools/mining-tool.js +1 -1
- package/dist/agents/tools/session-status-tool.js +1 -1
- package/dist/agents/tools/wallet-action-tool.js +172 -36
- package/dist/agents/tools/wallet-skill-policy.js +65 -23
- package/dist/agents/tools/wallet-tool.js +7 -11
- package/dist/agents/workspace.js +22 -22
- package/dist/auto-reply/reply/agent-runner-execution.js +2 -2
- package/dist/auto-reply/reply/agent-runner.js +2 -2
- package/dist/auto-reply/reply/commands-export-session.js +7 -7
- package/dist/auto-reply/reply/directive-handling.fast-lane.js +2 -1
- package/dist/auto-reply/reply/directive-handling.impl.js +2 -1
- package/dist/auto-reply/reply/directive-handling.model.js +2 -1
- package/dist/auto-reply/reply/directive-handling.persist.js +2 -2
- package/dist/auto-reply/reply/get-reply-directives-apply.js +2 -0
- package/dist/auto-reply/reply/get-reply-inline-actions.js +25 -1
- package/dist/auto-reply/reply/model-selection.js +7 -4
- package/dist/auto-reply/reply/post-compaction-audit.js +3 -3
- package/dist/auto-reply/reply/post-compaction-context.js +3 -3
- package/dist/auto-reply/reply/session-reset-model.js +4 -4
- package/dist/auto-reply/reply/session.js +3 -3
- package/dist/auto-reply/skill-commands.js +3 -3
- package/dist/auto-reply/status.js +6 -6
- package/dist/brand.js +1 -1
- package/dist/browser/chrome.executables.js +3 -3
- package/dist/browser/chrome.js +3 -3
- package/dist/browser/chrome.profile-decoration.js +6 -6
- package/dist/browser/profiles-service.js +2 -2
- package/dist/browser/server-context.js +2 -2
- package/dist/browser/trash.js +4 -4
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/canvas-host/server.js +4 -4
- package/dist/capabilities/catalog.js +3 -3
- package/dist/channel-web.js +2 -2
- package/dist/channels/plugins/catalog.js +3 -3
- package/dist/cli/browser-cli-extension.js +6 -6
- package/dist/cli/command-format.js +2 -2
- package/dist/cli/cron-cli/register.cron-simple.js +2 -2
- package/dist/cli/dns-cli.js +9 -9
- package/dist/cli/gateway-cli/dev.js +5 -5
- package/dist/cli/gateway-cli/run.js +10 -2
- package/dist/cli/hooks-cli.js +5 -5
- package/dist/cli/lightweight/gateway-runtime-probe.js +2 -2
- package/dist/cli/memory-cli.js +7 -7
- package/dist/cli/nodes-media-utils.js +2 -2
- package/dist/cli/plugins-cli.js +2 -2
- package/dist/cli/program/command-registry.js +1 -1
- package/dist/cli/program/register.onboard.js +2 -3
- package/dist/cli/program/register.wallet.js +16 -123
- package/dist/cli/providers-cli.js +1 -1
- package/dist/cli/sat-cli.js +129 -2
- package/dist/cli/secrets-cli.js +3 -3
- package/dist/cli/update-cli/update-command.js +260 -11
- package/dist/cli/windows-argv.js +2 -2
- package/dist/commands/auth-choice.apply.api-providers.js +3 -3
- package/dist/commands/dashboard-link.js +3 -3
- package/dist/commands/doctor-config-flow.js +1 -1
- package/dist/commands/doctor-install.js +5 -5
- package/dist/commands/doctor-legacy-config.js +2 -13
- package/dist/commands/doctor-memory-search.js +2 -2
- package/dist/commands/doctor-platform-notes.js +2 -2
- package/dist/commands/doctor-sandbox.js +2 -2
- package/dist/commands/doctor-state-integrity.js +23 -23
- package/dist/commands/doctor-workspace.js +3 -3
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/managed-up.js +2 -2
- package/dist/commands/model-picker.js +6 -6
- package/dist/commands/models/auth.js +1 -1
- package/dist/commands/onboard-auth.config-gateways.js +1 -1
- package/dist/commands/onboard-auth.credentials.js +35 -11
- package/dist/commands/onboard-non-interactive/local/wallet-config.js +28 -27
- package/dist/commands/onboard-non-interactive/local.js +5 -1
- package/dist/commands/onboarding/plugin-install.js +2 -2
- package/dist/commands/sessions-cleanup.js +2 -2
- package/dist/commands/signal-install.js +6 -6
- package/dist/commands/status-all/channels.js +2 -2
- package/dist/commands/wallet.js +570 -1913
- package/dist/config/cache-utils.js +2 -2
- package/dist/config/config.js +2 -2
- package/dist/config/includes.js +5 -5
- package/dist/config/io.js +66 -4
- package/dist/config/paths.js +3 -3
- package/dist/config/sat-runtime-ids.js +3 -3
- package/dist/config/schema.help.js +8 -7
- package/dist/config/schema.labels.js +5 -4
- package/dist/config/sessions/disk-budget.js +6 -6
- package/dist/config/sessions/paths.js +2 -2
- package/dist/config/sessions/store.js +17 -17
- package/dist/config/sessions/transcript.js +4 -4
- package/dist/config/talk.js +2 -2
- package/dist/config/zod-schema.agent-runtime.js +1 -0
- package/dist/config/zod-schema.js +5 -0
- package/dist/control-ui/assets/{app-BXA4gPvN.js → app-bR-fO5ty.js} +1511 -1555
- package/dist/control-ui/assets/{config-CU5Zi8Dh.js → config-LeImukCW.js} +10 -10
- package/dist/control-ui/assets/{federation-D10Q4eP_.js → federation-DgA9e-Pn.js} +364 -422
- package/dist/control-ui/assets/{index-D2QbJhVg.js → index-ckCxHwjy.js} +3 -3
- package/dist/control-ui/assets/{mining-BdhMn18r.js → mining-BgHFh0ei.js} +134 -114
- package/dist/control-ui/assets/mining-commit-DFpB_4JN.js +2 -0
- package/dist/control-ui/assets/{open-external-url-DwSiwMPl.js → open-external-url-ulF1B-sA.js} +3 -3
- package/dist/control-ui/assets/{providers-QMn4w2_f.js → providers-CIx9fxc6.js} +2 -2
- package/dist/control-ui/assets/{wallet-C2g294QT.js → wallet-DvStR_AT.js} +259 -377
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/cron/service/store.js +2 -2
- package/dist/cron/store.js +6 -6
- package/dist/daemon/systemd-system.js +60 -54
- package/dist/discord/monitor/thread-bindings.state.js +2 -2
- package/dist/extensions/sat-mining/src/protocol-contract.js +43 -3
- package/dist/extensions/sat-mining/src/rpc-read.js +235 -67
- package/dist/extensions/sat-mining/src/sat-bond-layout.js +14 -11
- package/dist/extensions/sat-mining/src/signer-codec-manifest.js +406 -0
- package/dist/extensions/sat-mining/src/solana-submit.js +1038 -397
- package/dist/extensions/sat-mining/src/submission-ledger.js +349 -0
- package/dist/federation/auto-connect.js +98 -8
- package/dist/federation/marketplace-capability-adapter.js +33 -7
- package/dist/federation/marketplace-delivery-outbox.js +196 -0
- package/dist/federation/marketplace-delivery.js +351 -215
- package/dist/federation/marketplace-direct-payment.js +272 -141
- package/dist/federation/marketplace-escrow.js +607 -249
- package/dist/federation/marketplace-settlement-ledger.js +352 -0
- package/dist/federation/offers.js +9 -7
- package/dist/federation/peer-auth-v2.js +529 -0
- package/dist/gateway/a2a-http.js +425 -96
- package/dist/gateway/a2a-settlement.js +259 -153
- package/dist/gateway/a2a-task-store.js +524 -0
- package/dist/gateway/auth.js +38 -2
- package/dist/gateway/config-reload.js +46 -33
- package/dist/gateway/control-ui-boot-check.js +6 -6
- package/dist/gateway/control-ui-login.js +7 -7
- package/dist/gateway/control-ui.js +9 -9
- package/dist/gateway/durable-capacity.js +31 -0
- package/dist/gateway/federation-http.js +540 -135
- package/dist/gateway/federation-marketplace-run-store.js +397 -0
- package/dist/gateway/federation-marketplace.js +535 -230
- package/dist/gateway/hooks-mapping.js +4 -4
- package/dist/gateway/mutating-admin-rpc-rate-limit.js +5 -0
- package/dist/gateway/security-path.js +1 -1
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +1088 -1209
- package/dist/gateway/server-methods/chat.js +3 -3
- package/dist/gateway/server-methods/models.js +1 -1
- package/dist/gateway/server-methods/secrets.js +40 -0
- package/dist/gateway/server-methods/sessions.js +6 -6
- package/dist/gateway/server-methods/usage.js +2 -2
- package/dist/gateway/server-methods.js +1 -2
- package/dist/gateway/server-reload-handlers.js +196 -66
- package/dist/gateway/server-runtime-config.js +1 -1
- package/dist/gateway/server-secrets-runtime.js +288 -0
- package/dist/gateway/server.impl.js +73 -42
- package/dist/gateway/session-compaction-checkpoints.js +4 -4
- package/dist/gateway/session-utils.fs.js +24 -24
- package/dist/gateway/session-utils.js +6 -6
- package/dist/gateway/sessions-patch.js +3 -5
- package/dist/hooks/bundled-dir.js +4 -4
- package/dist/hooks/gmail-setup-utils.js +6 -6
- package/dist/hooks/import-url.js +2 -2
- package/dist/hooks/loader.js +4 -4
- package/dist/hooks/workspace.js +7 -7
- package/dist/index.js +4 -2
- package/dist/infra/archive.js +17 -17
- package/dist/infra/boundary-file-read.js +2 -2
- package/dist/infra/boundary-path.js +15 -15
- package/dist/infra/brew.js +2 -2
- package/dist/infra/control-ui-assets.js +14 -14
- package/dist/infra/device-auth-store.js +8 -8
- package/dist/infra/device-identity.js +8 -8
- package/dist/infra/dotenv.js +2 -2
- package/dist/infra/exec-approvals.js +8 -8
- package/dist/infra/exec-command-resolution.js +4 -4
- package/dist/infra/exec-safe-bin-trust.js +2 -2
- package/dist/infra/fased-root.js +5 -5
- package/dist/infra/fasedhub.js +64 -1
- package/dist/infra/fs-safe.js +14 -14
- package/dist/infra/gateway-lock.js +11 -11
- package/dist/infra/git-commit.js +5 -5
- package/dist/infra/git-root.js +4 -4
- package/dist/infra/hosted-runtime-artifact.js +3 -3
- package/dist/infra/is-main.js +2 -2
- package/dist/infra/json-file.js +7 -7
- package/dist/infra/local-source-paired-update.js +538 -0
- package/dist/infra/managed-runtime-bootstrap.js +6 -6
- package/dist/infra/outbound/delivery-queue.js +16 -16
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/ports-lsof.js +4 -4
- package/dist/infra/provider-usage.auth.js +3 -3
- package/dist/infra/restart.js +41 -10
- package/dist/infra/safe-open-sync.js +2 -2
- package/dist/infra/session-cost-usage.js +9 -9
- package/dist/infra/shell-env.js +2 -2
- package/dist/infra/state-migrations.fs.js +6 -6
- package/dist/infra/state-migrations.js +23 -23
- package/dist/infra/tmp-fased-dir.js +6 -6
- package/dist/infra/update-runner.js +96 -0
- package/dist/infra/widearea-dns.js +3 -3
- package/dist/infra/wsl.js +2 -2
- package/dist/light-update-status.js +11 -11
- package/dist/line/accounts.js +2 -2
- package/dist/line/download.js +2 -2
- package/dist/logging/config.js +3 -3
- package/dist/logging/logger.js +7 -7
- package/dist/managed/federation.js +3 -3
- package/dist/managed/tunnel.js +3 -3
- package/dist/media/store.js +13 -13
- package/dist/media-understanding/runner.js +3 -3
- package/dist/memory/backend-config.js +2 -1
- package/dist/memory/embeddings.js +2 -2
- package/dist/memory/internal.js +10 -10
- package/dist/memory/manager-sync-ops.js +7 -7
- package/dist/memory/repair-executor.js +17 -17
- package/dist/memory/session-files.js +16 -2
- package/dist/node-host/invoke-system-run-plan.js +8 -8
- package/dist/node-host/invoke.js +2 -2
- package/dist/node-host/runner.js +3 -3
- package/dist/pairing/pairing-store.js +3 -3
- package/dist/plugin-sdk/{accounts-DxblobYM.js → accounts-Brn3-uWN.js} +1 -1
- package/dist/plugin-sdk/{actions-D4UNimWa.js → actions-DRu135h0.js} +2 -2
- package/dist/plugin-sdk/{active-listener-CFuy106s.js → active-listener-B_NMtgPL.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-Bv0hUOWL.js → audio-preflight-BYxAt775.js} +27 -27
- package/dist/plugin-sdk/{audit-Cs0K7LBp.js → audit-C5d2z5U1.js} +1 -1
- package/dist/plugin-sdk/{channel-access-D5aHoTY8.js → channel-access-CcFRdRPO.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-Dvch9mMQ.js → channel-access-configure-DaI5wevh.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +3 -3
- package/dist/plugin-sdk/channel-plugin-common.js +4 -4
- package/dist/plugin-sdk/{chunk-B0FUGc5A.js → chunk-CyoyqpbG.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-Bk--NU3E.js → chunk-items-DIRHG2gJ.js} +1 -1
- package/dist/plugin-sdk/command-status.d.ts +2 -2
- package/dist/plugin-sdk/command-status.js +27 -27
- package/dist/plugin-sdk/{commands-registry-DmDRhRAU.js → commands-registry-BfqdEWdF.js} +2 -2
- package/dist/plugin-sdk/{common-CfUOowOp.js → common-HCcXU-NR.js} +1 -1
- package/dist/plugin-sdk/{config-mxULv0fQ.js → config-DlWVeLFB.js} +7113 -6877
- package/dist/plugin-sdk/{config-schema-CGW6J3Pv.js → config-schema-BOT7kHb6.js} +6779 -3696
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/discord.d.ts +5 -5
- package/dist/plugin-sdk/discord.js +19 -19
- package/dist/plugin-sdk/file-lock.js +35 -4
- package/dist/plugin-sdk/{filesystem-manager-ZoHU8oA7.js → filesystem-manager-DoI8IBNF.js} +1 -1
- package/dist/plugin-sdk/{group-mentions-BHRff6j8.d.ts → group-mentions-q3hUTCt7.d.ts} +1 -1
- package/dist/plugin-sdk/{handle-action-DbVCF9HZ.js → handle-action-hvwapMKg.js} +13 -13
- package/dist/plugin-sdk/{helpers-BXbdgs5H.js → helpers-DMBU4oTo.js} +1 -1
- package/dist/plugin-sdk/{image-ops-D7jPxaph.js → image-ops-DQi0n_Tt.js} +1 -1
- package/dist/plugin-sdk/index.d.ts +9 -27
- package/dist/plugin-sdk/index.js +29 -29
- package/dist/plugin-sdk/json-store.js +6 -6
- package/dist/plugin-sdk/{login-BRxww6nv.js → login-Ca583Okc.js} +3 -3
- package/dist/plugin-sdk/{login-qr-DJXsk9XH.js → login-qr-CGciBSNP.js} +3 -3
- package/dist/plugin-sdk/{manager-Y2S_5IlI.js → manager-BegWxNYX.js} +4 -4
- package/dist/plugin-sdk/{markdown-tables-DHLFQqaF.js → markdown-tables-DCOXEUfZ.js} +1 -1
- package/dist/plugin-sdk/{media-Czo4carg.js → media-CAdQF5TG.js} +47 -47
- package/dist/plugin-sdk/{memory-search-DTjIMw8J.js → memory-search-CrFPOeTH.js} +4 -1
- package/dist/plugin-sdk/{monitor-B9Cmt_Je.js → monitor-BCFDaqJ-.js} +31 -31
- package/dist/plugin-sdk/{monitor-B71iwAgC.js → monitor-BgbjRiPM.js} +32 -32
- package/dist/plugin-sdk/{openresponses-http-Du4GMmwo.js → openresponses-http-DFf87SMM.js} +27 -27
- package/dist/plugin-sdk/{optional-runtime-dependency-DdMbxS24.js → optional-runtime-dependency-0dznm3ZO.js} +1 -1
- package/dist/plugin-sdk/{outbound-Db8mRN6P.js → outbound-BgVDdHxx.js} +6 -6
- package/dist/plugin-sdk/{outbound-attachment-BqFjcypb.js → outbound-attachment-QqTnIhZL.js} +2 -2
- package/dist/plugin-sdk/{pairing-message-BMkkS038.d.ts → pairing-message-CS-9BHug.d.ts} +2 -2
- package/dist/plugin-sdk/{pairing-message-B3GC_7CD.js → pairing-message-D0CoLHRJ.js} +1 -1
- package/dist/plugin-sdk/{pairing-store-CQikgIbw.js → pairing-store-BChahgI2.js} +2 -2
- package/dist/plugin-sdk/{pi-model-discovery-CY3m5zJP.js → pi-model-discovery-BX_JLcEJ.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DSh1T2pn.js → pi-model-discovery-runtime-DxTMz_XF.js} +2 -2
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +2 -2
- package/dist/plugin-sdk/{pw-ai-AFUqn-tQ.js → pw-ai-natjh3rm.js} +3 -3
- package/dist/plugin-sdk/{qmd-manager-DSyx77KY.js → qmd-manager-CgRaTxUq.js} +1 -1
- package/dist/plugin-sdk/{query-expansion-CAI2kKLQ.js → query-expansion-BG3FgzF7.js} +14 -3
- package/dist/plugin-sdk/{replies-Fzh9PhXl.js → replies-ChYo5ZQM.js} +2 -2
- package/dist/plugin-sdk/{resolve-outbound-target-KpF3co6T.js → resolve-outbound-target-D-KGgHJZ.js} +1 -1
- package/dist/plugin-sdk/{resolve-route-CDl74O19.js → resolve-route-C8tvQm8Z.js} +1 -1
- package/dist/plugin-sdk/{retry-policy-D4uiqUOG.js → retry-policy-C6SjKjQA.js} +1 -1
- package/dist/plugin-sdk/{runtime-Bb6KRnCC.js → runtime-2B9_WKoI.js} +8 -3
- package/dist/plugin-sdk/{runtime-dependency-DLDmB94f.js → runtime-dependency-DczkvPxn.js} +2 -2
- package/dist/plugin-sdk/sat-runtime.d.ts +549 -309
- package/dist/plugin-sdk/sat-runtime.js +29 -29
- package/dist/plugin-sdk/{send-C4k4JuJN.js → send-B6KkGKZD.js} +6 -6
- package/dist/plugin-sdk/{send-D-uDKGIq.js → send-CFzGKJXo.js} +6 -6
- package/dist/plugin-sdk/{send-Du8ykP1k.js → send-DCO441U7.js} +8 -8
- package/dist/plugin-sdk/{send-5nFktR1n.js → send-gDoGA-7e.js} +5 -5
- package/dist/plugin-sdk/{send-Bfzf11VY.js → send-q9HXrSwK.js} +7 -7
- package/dist/plugin-sdk/{session-CS-Td9EM.js → session-DHD4ZKyG.js} +2 -2
- package/dist/plugin-sdk/{skill-commands-CFAlXWHk.js → skill-commands-FKEPLS7T.js} +201 -26
- package/dist/plugin-sdk/{slack-D_bbE6Yd.js → slack-BUTt8cxK.js} +39 -39
- package/dist/plugin-sdk/{slack-actions-BcMkNv1Z.js → slack-actions-DhbMcp8M.js} +11 -11
- package/dist/plugin-sdk/slack.d.ts +5 -5
- package/dist/plugin-sdk/slack.js +9 -9
- package/dist/plugin-sdk/{sticker-cache-Dqo9nRhi.js → sticker-cache-D0wHVqjt.js} +3 -3
- package/dist/plugin-sdk/{tables-bFXyRpkx.js → tables-B3jr0Pvq.js} +1 -1
- package/dist/plugin-sdk/{targets-DH7a9lKB.js → targets-CtSbTxYX.js} +1 -1
- package/dist/plugin-sdk/{telegram-actions-Cnag7JTH.js → telegram-actions-CC_qN4v0.js} +30 -30
- package/dist/plugin-sdk/telegram.d.ts +5 -5
- package/dist/plugin-sdk/telegram.js +8 -8
- package/dist/plugin-sdk/{thread-bindings.lifecycle-CgOvvdw8.js → thread-bindings.lifecycle-QbkNl-m6.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-CQpk44Hq.js → thread-bindings.state-D9hg_M1c.js} +2 -2
- package/dist/plugin-sdk/tmp-fased-dir-xOTGlzBE.d.ts +486 -0
- package/dist/plugin-sdk/{types-CLIvQaVg.d.ts → types-C3avNytw.d.ts} +3 -4
- package/dist/plugin-sdk/{types-DyhXnYUr.d.ts → types-D0kDG8l0.d.ts} +3 -2
- package/dist/plugin-sdk/{types-BYDL6dQj.d.ts → types-DWfbSAaM.d.ts} +2 -2
- package/dist/plugin-sdk/{types.plugin-_fbu40Re.d.ts → types.plugin-BcSBq42x.d.ts} +8 -3
- package/dist/plugin-sdk/{web-BInKQkc4.js → web-BXsJ1vqe.js} +32 -32
- package/dist/plugin-sdk/{whatsapp-actions-BtSc2CBv.js → whatsapp-actions-Bj_rOncr.js} +13 -13
- package/dist/plugin-sdk/{whatsapp-heartbeat-Bg9TuYzl.js → whatsapp-heartbeat-B1WHkJIg.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +5 -5
- package/dist/plugin-sdk/whatsapp.js +12 -12
- package/dist/plugin-sdk/{wsl-C4DGFkOd.js → wsl-J-HscWxS.js} +3 -3
- package/dist/plugins/bundled-dir.js +3 -3
- package/dist/plugins/discovery.js +11 -11
- package/dist/plugins/loader.js +13 -13
- package/dist/plugins/manifest-registry.js +2 -2
- package/dist/plugins/manifest.js +4 -4
- package/dist/plugins/path-safety.js +3 -3
- package/dist/plugins/status-cache.js +9 -9
- package/dist/plugins/update.js +3 -3
- package/dist/plugins/web-search-install-catalog.js +3 -3
- package/dist/providers/refresh.js +1 -1
- package/dist/providers/registry.js +1 -1
- package/dist/secrets/apply.js +17 -17
- package/dist/secrets/audit.js +11 -11
- package/dist/secrets/runtime.js +1 -1
- package/dist/secrets/shared.js +9 -9
- package/dist/security/scan-paths.js +2 -2
- package/dist/shared/config-eval.js +2 -2
- package/dist/shared/pid-alive.js +2 -2
- package/dist/tasks/standing-orders.js +5 -5
- package/dist/tasks/task-flow-registry.js +5 -5
- package/dist/tasks/task-registry.js +5 -5
- package/dist/tasks/workflow-definitions.js +6 -6
- package/dist/telegram/token.js +5 -5
- package/dist/utils.js +5 -5
- package/dist/wallet/external-submission-ledger.js +376 -0
- package/dist/wallet/legacy-embedded-keystore.js +40 -0
- package/dist/wallet/local-socket-signer-archive.js +30 -0
- package/dist/wallet/local-socket-signer-lifecycle.js +97 -0
- package/dist/wallet/local-socket-signer-policy.js +166 -0
- package/dist/wallet/local-socket-signer-protocol.js +561 -118
- package/dist/wallet/native-signer-wallet-id.js +25 -0
- package/dist/wallet/providers/alchemy-adapter.js +3 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +382 -107
- package/dist/wallet/providers/turnkey-adapter.js +292 -34
- package/dist/wallet/providers/wallet-standard-adapter.js +100 -0
- package/dist/wallet/signer-network-admin.js +184 -0
- package/dist/wallet/signer-protocol-v2.generated.js +90 -0
- package/dist/wallet/solana-bond-signing.js +157 -69
- package/dist/wallet/solana-reviewed-transaction.js +375 -0
- package/dist/wallet/solana-swap.js +520 -64
- package/dist/wallet/solana-transaction-inspection.js +106 -4
- package/dist/wallet/solana-trigger.js +658 -320
- package/dist/wallet/turnkey-reviewed-state.js +370 -0
- package/dist/wallet/wallet-approval-auth.js +20 -31
- package/dist/wallet/wallet-atomic-state.js +53 -0
- package/dist/wallet/wallet-audit-log.js +5 -5
- package/dist/wallet/wallet-canary.js +0 -1
- package/dist/wallet/wallet-inbound-events.js +19 -14
- package/dist/wallet/wallet-observability.js +5 -5
- package/dist/wallet/wallet-policy-simulation.js +1 -1
- package/dist/wallet/wallet-policy.js +95 -41
- package/dist/wallet/wallet-provider-capabilities.js +28 -4
- package/dist/wallet/wallet-provider-registry.js +64 -51
- package/dist/wallet/wallet-provider-resolver.js +62 -63
- package/dist/wallet/wallet-runtime-config.js +31 -44
- package/dist/wallet/wallet-secrets-store.js +44 -22
- package/dist/wallet/wallet-send-approvals.js +1894 -592
- package/dist/wallet/wallet-send-execution-ledger.js +292 -0
- package/dist/wallet/wallet-settlement-links.js +17 -16
- package/dist/wallet/wallet-standard-review.js +353 -0
- package/dist/wallet/wallet-status.js +0 -9
- package/dist/wallet/wallet-task-ledger.js +16 -2
- package/dist/web/accounts.js +3 -3
- package/dist/web/auth-store.js +18 -18
- package/dist/web/auto-reply/heartbeat-runner.js +1 -1
- package/dist/web/auto-reply/monitor.js +2 -2
- package/dist/web/session.js +4 -4
- package/dist/wizard/host-security-capability.js +15 -24
- package/dist/wizard/onboarding.finalize.js +63 -184
- package/dist/wizard/onboarding.host-security.js +118 -1368
- package/dist/wizard/onboarding.js +180 -242
- package/dist/wizard/onboarding.wallet.js +323 -829
- package/extensions/acpx/package.json +1 -1
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/fased-federation/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +18 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +2 -2
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +18 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +18 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/sat-mining/index.ts +498 -153
- package/extensions/sat-mining/package.json +1 -1
- package/extensions/sat-mining/signer-codec-schema.v1.json +374 -0
- package/extensions/sat-mining/src/audit-store.ts +50 -5
- package/extensions/sat-mining/src/claim-service.ts +85 -14
- package/extensions/sat-mining/src/config.ts +9 -0
- package/extensions/sat-mining/src/cycle-progress.ts +16 -8
- package/extensions/sat-mining/src/epoch-service.ts +9 -5
- package/extensions/sat-mining/src/gateway-runner.ts +21 -1
- package/extensions/sat-mining/src/protocol-contract.ts +45 -1
- package/extensions/sat-mining/src/recovery-service.ts +312 -0
- package/extensions/sat-mining/src/round-watcher.ts +391 -81
- package/extensions/sat-mining/src/rpc-read.ts +330 -89
- package/extensions/sat-mining/src/runtime.ts +14 -0
- package/extensions/sat-mining/src/sat-bond-layout.ts +6 -0
- package/extensions/sat-mining/src/signer-codec-manifest.ts +429 -0
- package/extensions/sat-mining/src/solana-submit.ts +1199 -428
- package/extensions/sat-mining/src/submission-ledger.ts +433 -0
- package/extensions/signal/package.json +1 -1
- package/extensions/synology-chat/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +18 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +18 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +18 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +18 -0
- package/extensions/zalouser/package.json +1 -1
- package/install.sh +4955 -0
- package/package.json +24 -5
- package/scripts/fased-host-updater.mjs +1421 -0
- package/scripts/fased-host-updaterctl.mjs +186 -0
- package/scripts/fased-managed-service.sh +36 -0
- package/scripts/fased-managed-updater.mjs +3065 -156
- package/scripts/fased-signer-enroll-hosting.sh +275 -0
- package/scripts/fased-signer-network-hosting.sh +143 -0
- package/scripts/fased-signer-owner-policy.mjs +1430 -0
- package/scripts/fased-signer-policy-hosting.sh +50 -0
- package/scripts/fased-signer-policy-local.sh +26 -0
- package/scripts/hosted-release-manifest.mjs +185 -0
- package/scripts/install-fased-signerd.sh +217 -0
- package/scripts/install-managed-runtime.mjs +212 -10
- package/scripts/managed-runtime-layout.mjs +75 -3
- package/scripts/migrate-hosted-signer-v2.mjs +58 -0
- package/scripts/start-managed.sh +169 -360
- package/dist/control-ui/assets/mining-commit-R-6nu87p.js +0 -2
- package/dist/plugin-sdk/tmp-fased-dir-BdFQvrvw.d.ts +0 -77
- package/dist/wallet/local-socket-signer-broker.js +0 -224
- package/dist/wallet/local-socket-signer-custody.js +0 -42
- package/dist/wallet/providers/embedded-keystore-adapter.js +0 -402
- package/dist/wallet/providers/privy-adapter.js +0 -80
- package/dist/wallet/wallet-custody.js +0 -1836
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { withFileLock } from "../plugin-sdk/file-lock.js";
|
|
2
|
+
import "../infra/file-lock.js";
|
|
3
|
+
import { ensureWalletStateDir } from "./wallet-runtime-config.js";
|
|
4
|
+
import { WalletProviderError } from "./wallet-provider-adapter.js";
|
|
5
|
+
import { broadcastReviewedSolanaTransaction, buildReviewedSolanaTransaction, computeReviewedSolanaRequestDigest, reconcileReviewedSolanaTransaction, validateReviewedSolanaSignedTransaction } from "./solana-reviewed-transaction.js";
|
|
6
|
+
import syncFs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
9
|
+
|
|
10
|
+
//#region src/wallet/turnkey-reviewed-state.ts
|
|
11
|
+
const STATE_FILE_NAME = "turnkey-reviews.v1.json";
|
|
12
|
+
const REVIEW_TTL_MS = 2 * 60 * 1e3;
|
|
13
|
+
const STATE_FILE_MODE = 384;
|
|
14
|
+
const MAX_REVIEW_RECORDS = 1e4;
|
|
15
|
+
const MAX_RETAINED_TERMINAL_REVIEWS = 5e3;
|
|
16
|
+
const TERMINAL_REVIEW_RETENTION_MS = 30 * 24 * 60 * 6e4;
|
|
17
|
+
const REVIEW_LOCK_OPTIONS = {
|
|
18
|
+
retries: {
|
|
19
|
+
retries: 80,
|
|
20
|
+
factor: 1.15,
|
|
21
|
+
minTimeout: 20,
|
|
22
|
+
maxTimeout: 200,
|
|
23
|
+
randomize: true
|
|
24
|
+
},
|
|
25
|
+
stale: 3e4
|
|
26
|
+
};
|
|
27
|
+
let reviewStateLock = Promise.resolve();
|
|
28
|
+
function statePath(env) {
|
|
29
|
+
return path.join(ensureWalletStateDir(env).rootDir, STATE_FILE_NAME);
|
|
30
|
+
}
|
|
31
|
+
function readFile(env) {
|
|
32
|
+
const filePath = statePath(env);
|
|
33
|
+
if (!syncFs.existsSync(filePath)) {
|
|
34
|
+
return {
|
|
35
|
+
version: 1,
|
|
36
|
+
reviews: []
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const parsed = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
|
|
41
|
+
if (parsed.version === 1 && Array.isArray(parsed.reviews)) {
|
|
42
|
+
return parsed;
|
|
43
|
+
}
|
|
44
|
+
} catch {}
|
|
45
|
+
throw new WalletProviderError({
|
|
46
|
+
code: "wallet_provider_unavailable",
|
|
47
|
+
message: "Turnkey reviewed transaction state is invalid; repair it before signing",
|
|
48
|
+
retryable: false
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function saveFile(file, env) {
|
|
52
|
+
const filePath = statePath(env);
|
|
53
|
+
const temporary = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
54
|
+
let descriptor;
|
|
55
|
+
try {
|
|
56
|
+
descriptor = syncFs.openSync(temporary, "wx", STATE_FILE_MODE);
|
|
57
|
+
syncFs.writeFileSync(descriptor, `${JSON.stringify(file, null, 2)}\n`, "utf8");
|
|
58
|
+
syncFs.fsyncSync(descriptor);
|
|
59
|
+
syncFs.closeSync(descriptor);
|
|
60
|
+
descriptor = undefined;
|
|
61
|
+
syncFs.renameSync(temporary, filePath);
|
|
62
|
+
try {
|
|
63
|
+
syncFs.chmodSync(filePath, STATE_FILE_MODE);
|
|
64
|
+
} catch {}
|
|
65
|
+
try {
|
|
66
|
+
const directory = syncFs.openSync(path.dirname(filePath), "r");
|
|
67
|
+
try {
|
|
68
|
+
syncFs.fsyncSync(directory);
|
|
69
|
+
} finally {
|
|
70
|
+
syncFs.closeSync(directory);
|
|
71
|
+
}
|
|
72
|
+
} catch {}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (descriptor !== undefined) {
|
|
75
|
+
syncFs.closeSync(descriptor);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
syncFs.unlinkSync(temporary);
|
|
79
|
+
} catch {}
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function secureEqual(left, right) {
|
|
84
|
+
const leftBytes = Buffer.from(left, "utf8");
|
|
85
|
+
const rightBytes = Buffer.from(right, "utf8");
|
|
86
|
+
return leftBytes.length === rightBytes.length && timingSafeEqual(leftBytes, rightBytes);
|
|
87
|
+
}
|
|
88
|
+
function compactReviewState(file, nowMs = Date.now()) {
|
|
89
|
+
const terminal = file.reviews.filter((review) => review.status === "broadcast" || review.status === "failed").toSorted((left, right) => Date.parse(left.createdAt) - Date.parse(right.createdAt));
|
|
90
|
+
const removable = new Set(terminal.filter((review, index) => nowMs - Date.parse(review.createdAt) > TERMINAL_REVIEW_RETENTION_MS || terminal.length - index > MAX_RETAINED_TERMINAL_REVIEWS).map((review) => review.preparedId));
|
|
91
|
+
return {
|
|
92
|
+
version: 1,
|
|
93
|
+
reviews: file.reviews.filter((review) => !removable.has(review.preparedId))
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function requireReviewCapacity(file) {
|
|
97
|
+
if (file.reviews.length >= MAX_REVIEW_RECORDS) {
|
|
98
|
+
throw new WalletProviderError({
|
|
99
|
+
code: "wallet_provider_unavailable",
|
|
100
|
+
message: "Turnkey review state reached its durable safety limit; reconcile unresolved reviews",
|
|
101
|
+
retryable: false
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function digest(value) {
|
|
106
|
+
return createHash("sha256").update(value, "utf8").digest("base64url");
|
|
107
|
+
}
|
|
108
|
+
function normalizedRpcUrlDigest(rpcUrl) {
|
|
109
|
+
let normalized;
|
|
110
|
+
try {
|
|
111
|
+
const parsed = new URL(rpcUrl.trim());
|
|
112
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
113
|
+
throw new Error("unsupported protocol");
|
|
114
|
+
}
|
|
115
|
+
normalized = parsed.toString();
|
|
116
|
+
} catch {
|
|
117
|
+
throw new WalletProviderError({
|
|
118
|
+
code: "wallet_provider_invalid_config",
|
|
119
|
+
message: "Turnkey review requires a valid HTTP(S) Solana RPC URL"
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return digest(normalized);
|
|
123
|
+
}
|
|
124
|
+
function preparedIdentity(params) {
|
|
125
|
+
return digest([
|
|
126
|
+
"fased-turnkey-reviewed-v1",
|
|
127
|
+
params.approvalRequestId,
|
|
128
|
+
params.requestDigest,
|
|
129
|
+
params.rpcUrlDigest,
|
|
130
|
+
params.authorizationContextDigest
|
|
131
|
+
].join("\0"));
|
|
132
|
+
}
|
|
133
|
+
function toPrepareResult(record) {
|
|
134
|
+
return {
|
|
135
|
+
preparedId: record.preparedId,
|
|
136
|
+
signer: record.signer,
|
|
137
|
+
unsignedTxBase64: record.unsignedTxBase64,
|
|
138
|
+
messageBase64: record.messageBase64,
|
|
139
|
+
intentDigest: record.intentDigest,
|
|
140
|
+
expiresAt: record.expiresAt,
|
|
141
|
+
recentBlockhash: record.recentBlockhash,
|
|
142
|
+
lastValidBlockHeight: record.lastValidBlockHeight,
|
|
143
|
+
simulation: {
|
|
144
|
+
ok: true,
|
|
145
|
+
...typeof record.simulationUnitsConsumed === "number" && Number.isFinite(record.simulationUnitsConsumed) ? { unitsConsumed: record.simulationUnitsConsumed } : {}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function withReviewLock(env, task) {
|
|
150
|
+
const run = async () => await withFileLock(statePath(env), REVIEW_LOCK_OPTIONS, async () => await task());
|
|
151
|
+
const current = reviewStateLock.then(run, run);
|
|
152
|
+
reviewStateLock = current.then(() => undefined, () => undefined);
|
|
153
|
+
return await current;
|
|
154
|
+
}
|
|
155
|
+
async function prepareTurnkeyReviewedTransaction(params) {
|
|
156
|
+
const env = params.env ?? process.env;
|
|
157
|
+
const approvalRequestId = params.request.requestId?.trim();
|
|
158
|
+
if (!approvalRequestId) {
|
|
159
|
+
throw new WalletProviderError({
|
|
160
|
+
code: "wallet_provider_invalid_config",
|
|
161
|
+
message: "Turnkey preparation requires a stable approval request ID"
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const requestDigest = computeReviewedSolanaRequestDigest({
|
|
165
|
+
request: params.request,
|
|
166
|
+
signer: params.signerAddress.trim()
|
|
167
|
+
});
|
|
168
|
+
const expectedRpcUrlDigest = normalizedRpcUrlDigest(params.rpcUrl);
|
|
169
|
+
const expectedAuthorizationContextDigest = digest(params.authorizationContext);
|
|
170
|
+
const preparedId = preparedIdentity({
|
|
171
|
+
approvalRequestId,
|
|
172
|
+
requestDigest,
|
|
173
|
+
rpcUrlDigest: expectedRpcUrlDigest,
|
|
174
|
+
authorizationContextDigest: expectedAuthorizationContextDigest
|
|
175
|
+
});
|
|
176
|
+
return await withReviewLock(env, async () => {
|
|
177
|
+
const file = compactReviewState(readFile(env));
|
|
178
|
+
const existing = file.reviews.find((review) => review.approvalRequestId === approvalRequestId || review.preparedId === preparedId);
|
|
179
|
+
if (existing) {
|
|
180
|
+
const sameImmutableRequest = existing.approvalRequestId === approvalRequestId && secureEqual(existing.preparedId, preparedId) && secureEqual(existing.signer, params.signerAddress.trim()) && secureEqual(existing.requestDigest, requestDigest) && secureEqual(existing.rpcUrlDigest, expectedRpcUrlDigest) && secureEqual(existing.authorizationContextDigest, expectedAuthorizationContextDigest);
|
|
181
|
+
if (!sameImmutableRequest) {
|
|
182
|
+
throw new WalletProviderError({
|
|
183
|
+
code: "wallet_provider_invalid_config",
|
|
184
|
+
message: "Turnkey approval request ID is already bound to a different immutable transaction",
|
|
185
|
+
retryable: false
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
if (existing.status === "failed") {
|
|
189
|
+
throw new WalletProviderError({
|
|
190
|
+
code: "wallet_provider_unavailable",
|
|
191
|
+
message: `${existing.failureReason ?? "Turnkey reviewed transaction failed"}; create a new approval request`,
|
|
192
|
+
retryable: false
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
if (existing.status === "prepared" && Date.parse(existing.expiresAt) <= Date.now()) {
|
|
196
|
+
throw new WalletProviderError({
|
|
197
|
+
code: "wallet_provider_invalid_config",
|
|
198
|
+
message: "Turnkey prepared review expired; create a new approval request",
|
|
199
|
+
retryable: false
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return toPrepareResult(existing);
|
|
203
|
+
}
|
|
204
|
+
requireReviewCapacity(file);
|
|
205
|
+
const prepared = await buildReviewedSolanaTransaction({
|
|
206
|
+
request: params.request,
|
|
207
|
+
signerAddress: params.signerAddress,
|
|
208
|
+
rpcUrl: params.rpcUrl
|
|
209
|
+
});
|
|
210
|
+
if (!secureEqual(prepared.signer, params.signerAddress.trim())) {
|
|
211
|
+
throw new WalletProviderError({
|
|
212
|
+
code: "wallet_provider_unavailable",
|
|
213
|
+
message: "Turnkey transaction builder returned a different signer"
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const now = Date.now();
|
|
217
|
+
const record = {
|
|
218
|
+
approvalRequestId,
|
|
219
|
+
preparedId,
|
|
220
|
+
createdAt: new Date(now).toISOString(),
|
|
221
|
+
expiresAt: new Date(now + REVIEW_TTL_MS).toISOString(),
|
|
222
|
+
status: "prepared",
|
|
223
|
+
signer: prepared.signer,
|
|
224
|
+
requestDigest,
|
|
225
|
+
intentDigest: prepared.intentDigest,
|
|
226
|
+
unsignedTxBase64: prepared.unsignedTxBase64,
|
|
227
|
+
messageBase64: prepared.messageBase64,
|
|
228
|
+
recentBlockhash: prepared.recentBlockhash,
|
|
229
|
+
lastValidBlockHeight: prepared.lastValidBlockHeight,
|
|
230
|
+
rpcUrlDigest: expectedRpcUrlDigest,
|
|
231
|
+
authorizationContextDigest: expectedAuthorizationContextDigest,
|
|
232
|
+
simulationUnitsConsumed: prepared.simulation.unitsConsumed
|
|
233
|
+
};
|
|
234
|
+
file.reviews.push(record);
|
|
235
|
+
saveFile(file, env);
|
|
236
|
+
return toPrepareResult(record);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
async function executeTurnkeyReviewedTransaction(params) {
|
|
240
|
+
const env = params.env ?? process.env;
|
|
241
|
+
const preparedId = params.preparedId.trim();
|
|
242
|
+
if (!preparedId) {
|
|
243
|
+
throw new WalletProviderError({
|
|
244
|
+
code: "wallet_provider_invalid_config",
|
|
245
|
+
message: "Turnkey send requires a prepared review ID"
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return await withReviewLock(env, async () => {
|
|
249
|
+
const file = readFile(env);
|
|
250
|
+
const review = file.reviews.find((record) => record.preparedId === preparedId);
|
|
251
|
+
if (!review) {
|
|
252
|
+
throw new WalletProviderError({
|
|
253
|
+
code: "wallet_provider_invalid_config",
|
|
254
|
+
message: "Turnkey prepared review is unknown; prepare and review the transaction again"
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
if (review.status === "broadcast" && review.txHash) {
|
|
258
|
+
return {
|
|
259
|
+
txHash: review.txHash,
|
|
260
|
+
signer: review.signer,
|
|
261
|
+
intentDigest: review.intentDigest,
|
|
262
|
+
idempotent: true
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (review.status === "broadcasting" || review.status === "unknown") {
|
|
266
|
+
if (!review.txHash) {
|
|
267
|
+
throw new WalletProviderError({
|
|
268
|
+
code: "wallet_provider_ambiguous",
|
|
269
|
+
message: "Turnkey broadcast is in progress or unknown; do not submit it again",
|
|
270
|
+
retryable: false
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
let reconciled;
|
|
274
|
+
try {
|
|
275
|
+
reconciled = await reconcileReviewedSolanaTransaction({
|
|
276
|
+
rpcUrl: params.rpcUrl,
|
|
277
|
+
expectedTxHash: review.txHash,
|
|
278
|
+
lastValidBlockHeight: review.lastValidBlockHeight
|
|
279
|
+
});
|
|
280
|
+
} catch {
|
|
281
|
+
throw new WalletProviderError({
|
|
282
|
+
code: "wallet_provider_ambiguous",
|
|
283
|
+
message: `Turnkey broadcast remains unknown; reconcile signature ${review.txHash} before any new send`,
|
|
284
|
+
retryable: false
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
if (reconciled.state === "landed") {
|
|
288
|
+
review.status = "broadcast";
|
|
289
|
+
saveFile(file, env);
|
|
290
|
+
return {
|
|
291
|
+
txHash: review.txHash,
|
|
292
|
+
signer: review.signer,
|
|
293
|
+
intentDigest: review.intentDigest,
|
|
294
|
+
idempotent: true
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (reconciled.state === "failed" || reconciled.state === "expired") {
|
|
298
|
+
review.status = "failed";
|
|
299
|
+
review.failureReason = reconciled.state === "failed" ? reconciled.reason : `reviewed transaction expired at block height ${review.lastValidBlockHeight} without landing`;
|
|
300
|
+
saveFile(file, env);
|
|
301
|
+
throw new WalletProviderError({
|
|
302
|
+
code: "wallet_provider_unavailable",
|
|
303
|
+
message: `${review.failureReason}; prepare and review a new transaction`,
|
|
304
|
+
retryable: false
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
throw new WalletProviderError({
|
|
308
|
+
code: "wallet_provider_ambiguous",
|
|
309
|
+
message: `Turnkey broadcast remains pending; reconcile signature ${review.txHash} before any new send`,
|
|
310
|
+
retryable: false
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
if (review.status === "failed") {
|
|
314
|
+
throw new WalletProviderError({
|
|
315
|
+
code: "wallet_provider_unavailable",
|
|
316
|
+
message: `${review.failureReason ?? "Turnkey reviewed transaction failed"}; prepare and review a new transaction`,
|
|
317
|
+
retryable: false
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (Date.parse(review.expiresAt) <= Date.now()) {
|
|
321
|
+
throw new WalletProviderError({
|
|
322
|
+
code: "wallet_provider_invalid_config",
|
|
323
|
+
message: "Turnkey prepared review expired; prepare and review a new transaction"
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
const expectedRequestDigest = computeReviewedSolanaRequestDigest({
|
|
327
|
+
request: params.request,
|
|
328
|
+
signer: params.signerAddress
|
|
329
|
+
});
|
|
330
|
+
if (review.approvalRequestId !== undefined && !secureEqual(review.approvalRequestId, params.request.requestId?.trim() ?? "") || !secureEqual(review.signer, params.signerAddress) || !secureEqual(review.requestDigest, expectedRequestDigest) || !secureEqual(review.rpcUrlDigest, normalizedRpcUrlDigest(params.rpcUrl)) || !secureEqual(review.authorizationContextDigest, digest(params.authorizationContext))) {
|
|
331
|
+
throw new WalletProviderError({
|
|
332
|
+
code: "wallet_provider_invalid_config",
|
|
333
|
+
message: "Turnkey execution context does not match the immutable prepared review"
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
const signedTxBase64 = await params.sign(review.unsignedTxBase64);
|
|
337
|
+
const verified = validateReviewedSolanaSignedTransaction({
|
|
338
|
+
unsignedTxBase64: review.unsignedTxBase64,
|
|
339
|
+
signedTxBase64,
|
|
340
|
+
signerAddress: review.signer
|
|
341
|
+
});
|
|
342
|
+
review.status = "broadcasting";
|
|
343
|
+
review.txHash = verified.txHash;
|
|
344
|
+
review.signedTxBase64 = verified.signedBytes.toString("base64");
|
|
345
|
+
saveFile(file, env);
|
|
346
|
+
try {
|
|
347
|
+
const txHash = await broadcastReviewedSolanaTransaction({
|
|
348
|
+
rpcUrl: params.rpcUrl,
|
|
349
|
+
signedTxBase64: review.signedTxBase64,
|
|
350
|
+
expectedTxHash: verified.txHash
|
|
351
|
+
});
|
|
352
|
+
review.status = "broadcast";
|
|
353
|
+
review.txHash = txHash;
|
|
354
|
+
saveFile(file, env);
|
|
355
|
+
return {
|
|
356
|
+
txHash,
|
|
357
|
+
signer: review.signer,
|
|
358
|
+
intentDigest: review.intentDigest,
|
|
359
|
+
idempotent: false
|
|
360
|
+
};
|
|
361
|
+
} catch (error) {
|
|
362
|
+
review.status = "unknown";
|
|
363
|
+
saveFile(file, env);
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
//#endregion
|
|
370
|
+
export { executeTurnkeyReviewedTransaction, prepareTurnkeyReviewedTransaction };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ensureWalletStateDir } from "./wallet-runtime-config.js";
|
|
2
|
-
import
|
|
2
|
+
import { serializeWalletState, writeWalletStateFileAtomically } from "./wallet-atomic-state.js";
|
|
3
|
+
import syncFs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { createHash, createPublicKey, randomBytes, timingSafeEqual, verify } from "node:crypto";
|
|
5
6
|
|
|
@@ -73,22 +74,12 @@ function rpIdFromHost(host) {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
function normalizeState(input) {
|
|
76
|
-
if (!input || typeof input !== "object") {
|
|
77
|
-
|
|
78
|
-
version: 2,
|
|
79
|
-
passkeys: [],
|
|
80
|
-
challenges: [],
|
|
81
|
-
grants: []
|
|
82
|
-
};
|
|
77
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
78
|
+
throw new Error("wallet approval auth state must be an object");
|
|
83
79
|
}
|
|
84
80
|
const parsed = input;
|
|
85
|
-
if (parsed.version !== 2) {
|
|
86
|
-
|
|
87
|
-
version: 2,
|
|
88
|
-
passkeys: [],
|
|
89
|
-
challenges: [],
|
|
90
|
-
grants: []
|
|
91
|
-
};
|
|
81
|
+
if (parsed.version !== 2 || !Array.isArray(parsed.passkeys) || !Array.isArray(parsed.challenges) || !Array.isArray(parsed.grants)) {
|
|
82
|
+
throw new Error("wallet approval auth state has an unsupported shape");
|
|
92
83
|
}
|
|
93
84
|
const passkeys = Array.isArray(parsed.passkeys) ? parsed.passkeys.map((entry) => {
|
|
94
85
|
if (!entry || typeof entry !== "object") {
|
|
@@ -109,6 +100,9 @@ function normalizeState(input) {
|
|
|
109
100
|
transports: Array.isArray(value.transports) ? value.transports.map((v) => String(v)) : undefined
|
|
110
101
|
};
|
|
111
102
|
}).filter((entry) => entry !== null) : [];
|
|
103
|
+
if (passkeys.length !== parsed.passkeys.length) {
|
|
104
|
+
throw new Error("wallet approval auth state contains an invalid passkey");
|
|
105
|
+
}
|
|
112
106
|
const challenges = Array.isArray(parsed.challenges) ? parsed.challenges.map((entry) => {
|
|
113
107
|
if (!entry || typeof entry !== "object") {
|
|
114
108
|
return null;
|
|
@@ -137,6 +131,9 @@ function normalizeState(input) {
|
|
|
137
131
|
status: value.status
|
|
138
132
|
};
|
|
139
133
|
}).filter((entry) => entry !== null) : [];
|
|
134
|
+
if (challenges.length !== parsed.challenges.length || challenges.some((entry) => !entry.id || !entry.challenge || !entry.host || !entry.rpId)) {
|
|
135
|
+
throw new Error("wallet approval auth state contains an invalid challenge");
|
|
136
|
+
}
|
|
140
137
|
const grants = Array.isArray(parsed.grants) ? parsed.grants.map((entry) => {
|
|
141
138
|
if (!entry || typeof entry !== "object") {
|
|
142
139
|
return null;
|
|
@@ -154,6 +151,9 @@ function normalizeState(input) {
|
|
|
154
151
|
expiresAt: value.expiresAt
|
|
155
152
|
};
|
|
156
153
|
}).filter((entry) => entry !== null) : [];
|
|
154
|
+
if (grants.length !== parsed.grants.length || grants.some((entry) => !entry.host)) {
|
|
155
|
+
throw new Error("wallet approval auth state contains an invalid grant");
|
|
156
|
+
}
|
|
157
157
|
return {
|
|
158
158
|
version: 2,
|
|
159
159
|
passkeys,
|
|
@@ -163,7 +163,7 @@ function normalizeState(input) {
|
|
|
163
163
|
}
|
|
164
164
|
function loadState(env = process.env) {
|
|
165
165
|
const statePath = resolveStatePath(env);
|
|
166
|
-
if (!
|
|
166
|
+
if (!syncFs.existsSync(statePath)) {
|
|
167
167
|
return {
|
|
168
168
|
version: 2,
|
|
169
169
|
passkeys: [],
|
|
@@ -172,26 +172,15 @@ function loadState(env = process.env) {
|
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
174
|
try {
|
|
175
|
-
const raw =
|
|
175
|
+
const raw = syncFs.readFileSync(statePath, "utf8");
|
|
176
176
|
return normalizeState(JSON.parse(raw));
|
|
177
|
-
} catch {
|
|
178
|
-
|
|
179
|
-
version: 2,
|
|
180
|
-
passkeys: [],
|
|
181
|
-
challenges: [],
|
|
182
|
-
grants: []
|
|
183
|
-
};
|
|
177
|
+
} catch (error) {
|
|
178
|
+
throw new Error("wallet approval auth state is unreadable; refusing to reset credentials", { cause: error });
|
|
184
179
|
}
|
|
185
180
|
}
|
|
186
181
|
function saveState(state, env = process.env) {
|
|
187
182
|
const statePath = resolveStatePath(env);
|
|
188
|
-
|
|
189
|
-
encoding: "utf8",
|
|
190
|
-
mode: 384
|
|
191
|
-
});
|
|
192
|
-
try {
|
|
193
|
-
fs.chmodSync(statePath, 384);
|
|
194
|
-
} catch {}
|
|
183
|
+
writeWalletStateFileAtomically(statePath, serializeWalletState(state));
|
|
195
184
|
}
|
|
196
185
|
function pruneState(state) {
|
|
197
186
|
const now = nowMs();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import syncFs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
|
|
5
|
+
//#region src/wallet/wallet-atomic-state.ts
|
|
6
|
+
const WALLET_STATE_FILE_MODE = 384;
|
|
7
|
+
/**
|
|
8
|
+
* Replace a wallet state file durably without ever exposing a partially-written
|
|
9
|
+
* destination. Callers remain responsible for validating the full document
|
|
10
|
+
* before trusting it and for serializing read/modify/write operations.
|
|
11
|
+
*/
|
|
12
|
+
function writeWalletStateFileAtomically(filePath, contents) {
|
|
13
|
+
const directoryPath = path.dirname(filePath);
|
|
14
|
+
const temporaryPath = path.join(directoryPath, `.${path.basename(filePath)}.${process.pid}.${randomBytes(8).toString("hex")}.tmp`);
|
|
15
|
+
let descriptor;
|
|
16
|
+
let renamed = false;
|
|
17
|
+
try {
|
|
18
|
+
descriptor = syncFs.openSync(temporaryPath, "wx", WALLET_STATE_FILE_MODE);
|
|
19
|
+
syncFs.writeFileSync(descriptor, contents, { encoding: "utf8" });
|
|
20
|
+
syncFs.fsyncSync(descriptor);
|
|
21
|
+
syncFs.closeSync(descriptor);
|
|
22
|
+
descriptor = undefined;
|
|
23
|
+
syncFs.renameSync(temporaryPath, filePath);
|
|
24
|
+
renamed = true;
|
|
25
|
+
try {
|
|
26
|
+
syncFs.chmodSync(filePath, WALLET_STATE_FILE_MODE);
|
|
27
|
+
} catch {}
|
|
28
|
+
const directoryDescriptor = syncFs.openSync(directoryPath, "r");
|
|
29
|
+
try {
|
|
30
|
+
syncFs.fsyncSync(directoryDescriptor);
|
|
31
|
+
} finally {
|
|
32
|
+
syncFs.closeSync(directoryDescriptor);
|
|
33
|
+
}
|
|
34
|
+
} catch (error) {
|
|
35
|
+
if (descriptor !== undefined) {
|
|
36
|
+
try {
|
|
37
|
+
syncFs.closeSync(descriptor);
|
|
38
|
+
} catch {}
|
|
39
|
+
}
|
|
40
|
+
if (!renamed) {
|
|
41
|
+
try {
|
|
42
|
+
syncFs.unlinkSync(temporaryPath);
|
|
43
|
+
} catch {}
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function serializeWalletState(value) {
|
|
49
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { serializeWalletState, writeWalletStateFileAtomically };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ensureWalletStateDir } from "./wallet-runtime-config.js";
|
|
2
|
-
import
|
|
2
|
+
import syncFs from "node:fs";
|
|
3
3
|
import { randomBytes } from "node:crypto";
|
|
4
4
|
|
|
5
5
|
//#region src/wallet/wallet-audit-log.ts
|
|
@@ -15,22 +15,22 @@ function appendWalletAuditEntry(params) {
|
|
|
15
15
|
actor: params.actor?.trim() || "system",
|
|
16
16
|
details: params.details ?? {}
|
|
17
17
|
};
|
|
18
|
-
|
|
18
|
+
syncFs.appendFileSync(paths.auditLogPath, `${JSON.stringify(entry)}\n`, {
|
|
19
19
|
encoding: "utf8",
|
|
20
20
|
mode: 384
|
|
21
21
|
});
|
|
22
22
|
try {
|
|
23
|
-
|
|
23
|
+
syncFs.chmodSync(paths.auditLogPath, 384);
|
|
24
24
|
} catch {}
|
|
25
25
|
return entry;
|
|
26
26
|
}
|
|
27
27
|
function readWalletAuditEntries(params) {
|
|
28
28
|
const paths = ensureWalletStateDir(params?.env ?? process.env);
|
|
29
|
-
if (!
|
|
29
|
+
if (!syncFs.existsSync(paths.auditLogPath)) {
|
|
30
30
|
return [];
|
|
31
31
|
}
|
|
32
32
|
const limit = Math.max(1, Math.min(500, params?.limit ?? 100));
|
|
33
|
-
const raw =
|
|
33
|
+
const raw = syncFs.readFileSync(paths.auditLogPath, "utf8");
|
|
34
34
|
const lines = raw.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
35
35
|
const out = [];
|
|
36
36
|
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ensureWalletStateDir } from "./wallet-runtime-config.js";
|
|
2
2
|
import { readWalletProviderRegistry, resolveWalletSelection } from "./wallet-provider-registry.js";
|
|
3
|
+
import { serializeWalletState, writeWalletStateFileAtomically } from "./wallet-atomic-state.js";
|
|
3
4
|
import { buildWalletProviderCapabilityMatrix, providerSupportsChainOperation } from "./wallet-provider-capabilities.js";
|
|
4
5
|
import { walletDiagnosticErrorString } from "./wallet-redaction.js";
|
|
5
6
|
import { createWalletProviderAdapter, resolveWalletProviderId } from "./wallet-provider-resolver.js";
|
|
6
7
|
import { appendWalletAuditEntry, readWalletAuditEntries } from "./wallet-audit-log.js";
|
|
7
|
-
import
|
|
8
|
+
import syncFs from "node:fs";
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import { randomBytes } from "node:crypto";
|
|
10
11
|
|
|
@@ -26,6 +27,7 @@ function normalizeProviderId(value) {
|
|
|
26
27
|
case "local-socket-signer":
|
|
27
28
|
case "alchemy":
|
|
28
29
|
case "turnkey":
|
|
30
|
+
case "wallet-standard":
|
|
29
31
|
case "privy": return value;
|
|
30
32
|
default: return null;
|
|
31
33
|
}
|
|
@@ -115,9 +117,12 @@ function defaultLedger() {
|
|
|
115
117
|
}
|
|
116
118
|
function normalizeLedger(raw) {
|
|
117
119
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
118
|
-
|
|
120
|
+
throw new Error("wallet inbound ledger must be an object");
|
|
119
121
|
}
|
|
120
122
|
const value = raw;
|
|
123
|
+
if (value.version !== 1 || !Array.isArray(value.snapshots) || !Array.isArray(value.events) || typeof value.updatedAt !== "string") {
|
|
124
|
+
throw new Error("wallet inbound ledger has an unsupported shape");
|
|
125
|
+
}
|
|
121
126
|
const snapshots = Array.isArray(value.snapshots) ? value.snapshots.filter((entry) => {
|
|
122
127
|
if (!entry || typeof entry !== "object") {
|
|
123
128
|
return false;
|
|
@@ -134,6 +139,9 @@ function normalizeLedger(raw) {
|
|
|
134
139
|
unit: entry.unit,
|
|
135
140
|
updatedAt: entry.updatedAt
|
|
136
141
|
})) : [];
|
|
142
|
+
if (snapshots.length !== value.snapshots.length) {
|
|
143
|
+
throw new Error("wallet inbound ledger contains an invalid balance snapshot");
|
|
144
|
+
}
|
|
137
145
|
const events = Array.isArray(value.events) ? value.events.filter((entry) => {
|
|
138
146
|
if (!entry || typeof entry !== "object") {
|
|
139
147
|
return false;
|
|
@@ -164,24 +172,27 @@ function normalizeLedger(raw) {
|
|
|
164
172
|
} : undefined,
|
|
165
173
|
metadata: entry.metadata && typeof entry.metadata === "object" ? entry.metadata : undefined
|
|
166
174
|
})) : [];
|
|
175
|
+
if (events.length !== value.events.length) {
|
|
176
|
+
throw new Error("wallet inbound ledger contains an invalid event");
|
|
177
|
+
}
|
|
167
178
|
return {
|
|
168
179
|
version: 1,
|
|
169
180
|
snapshots,
|
|
170
181
|
events,
|
|
171
|
-
updatedAt:
|
|
182
|
+
updatedAt: value.updatedAt,
|
|
172
183
|
lastReconciledAt: typeof value.lastReconciledAt === "string" ? value.lastReconciledAt : undefined
|
|
173
184
|
};
|
|
174
185
|
}
|
|
175
186
|
function readLedger(env = process.env) {
|
|
176
187
|
const filePath = inboundLedgerPath(env);
|
|
177
|
-
if (!
|
|
188
|
+
if (!syncFs.existsSync(filePath)) {
|
|
178
189
|
return defaultLedger();
|
|
179
190
|
}
|
|
180
191
|
try {
|
|
181
|
-
const parsed = JSON.parse(
|
|
192
|
+
const parsed = JSON.parse(syncFs.readFileSync(filePath, "utf8"));
|
|
182
193
|
return normalizeLedger(parsed);
|
|
183
|
-
} catch {
|
|
184
|
-
|
|
194
|
+
} catch (error) {
|
|
195
|
+
throw new Error("wallet inbound ledger is unreadable; refusing to reset event history", { cause: error });
|
|
185
196
|
}
|
|
186
197
|
}
|
|
187
198
|
function writeLedger(ledger, env = process.env) {
|
|
@@ -191,13 +202,7 @@ function writeLedger(ledger, env = process.env) {
|
|
|
191
202
|
version: 1,
|
|
192
203
|
updatedAt: nowIso()
|
|
193
204
|
};
|
|
194
|
-
|
|
195
|
-
encoding: "utf8",
|
|
196
|
-
mode: 384
|
|
197
|
-
});
|
|
198
|
-
try {
|
|
199
|
-
fs.chmodSync(filePath, 384);
|
|
200
|
-
} catch {}
|
|
205
|
+
writeWalletStateFileAtomically(filePath, serializeWalletState(payload));
|
|
201
206
|
}
|
|
202
207
|
function findWalletById(env, walletId) {
|
|
203
208
|
if (!walletId) {
|