@fased/fased 0.1.66 → 0.1.68
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 +18 -0
- package/README.md +4 -0
- package/config/signer-protocol-v2.json +4 -0
- package/dist/brand.js +1 -1
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/cli/program/register.wallet.js +33 -2
- package/dist/commands/onboard.js +0 -8
- package/dist/commands/wallet.js +485 -58
- package/dist/control-ui/assets/{app-DYxADzeH.js → app-DyPTS0oM.js} +1526 -1526
- package/dist/control-ui/assets/{index-vw_10Zeo.js → index-Cu13yYHr.js} +3 -3
- package/dist/control-ui/assets/{wallet-DvStR_AT.js → wallet-ByKBcYhm.js} +272 -188
- package/dist/control-ui/index.html +1 -1
- package/dist/control-ui/version.json +1 -1
- package/dist/gateway/server-http.js +349 -47
- package/dist/infra/runtime-guard.js +16 -0
- package/dist/plugin-sdk/{actions-DRu135h0.js → actions-B-Vwj64K.js} +3 -3
- package/dist/plugin-sdk/{allow-list-DyAxs4yw.js → allow-list-Bf45HfoP.js} +1 -1
- package/dist/plugin-sdk/{audio-preflight-BFLoas5R.js → audio-preflight-_FVQjR1r.js} +26 -25
- package/dist/plugin-sdk/{audit-C5d2z5U1.js → audit-CUULWG22.js} +1 -1
- package/dist/plugin-sdk/{channel-access-configure-DaI5wevh.js → channel-access-configure-BoUsC-Ys.js} +1 -1
- package/dist/plugin-sdk/{channel-adapters.discord-BS4S4Svh.js → channel-adapters.discord-DSiR4X2Y.js} +1 -1
- package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
- package/dist/plugin-sdk/channel-plugin-common.js +1 -1
- package/dist/plugin-sdk/{chunk-CyoyqpbG.js → chunk-CBpl-AiQ.js} +1 -1
- package/dist/plugin-sdk/{chunk-items-TErs62MC.js → chunk-items-LH4uKSnh.js} +1 -1
- package/dist/plugin-sdk/command-status.js +26 -25
- package/dist/plugin-sdk/{commands-registry-BfqdEWdF.js → commands-registry-G5KXSi_y.js} +1 -1
- package/dist/plugin-sdk/{config-schema-BPnaDBwZ.js → config-schema-DjU_uD-6.js} +192 -94
- package/dist/plugin-sdk/device-pair.d.ts +1 -1
- package/dist/plugin-sdk/{diagnostic-DLL_zekv.js → diagnostic-sYs6Agr-.js} +1 -1
- package/dist/plugin-sdk/{directory-live-CSuYxdwk.js → directory-live-BXMpuYAF.js} +1 -1
- package/dist/plugin-sdk/{directory-live-Dw7ZgC9_.js → directory-live-Rn1BzPof.js} +1 -1
- package/dist/plugin-sdk/discord.d.ts +4 -4
- package/dist/plugin-sdk/discord.js +20 -20
- package/dist/plugin-sdk/{draft-stream-controls-BqchW1vi.js → draft-stream-controls-CMNdKSx-.js} +1 -1
- package/dist/plugin-sdk/{guilds-CDhRIX57.js → guilds-Dkwl0yHv.js} +1 -1
- package/dist/plugin-sdk/{handle-action-hvwapMKg.js → handle-action-CRdM6B-8.js} +15 -15
- package/dist/plugin-sdk/index.d.ts +16 -16
- package/dist/plugin-sdk/index.js +28 -27
- package/dist/plugin-sdk/{login-Ca583Okc.js → login-D7WnK8-P.js} +1 -1
- package/dist/plugin-sdk/{login-qr-CGciBSNP.js → login-qr-CRueOKZK.js} +2 -114
- package/dist/plugin-sdk/{markdown-tables-DCOXEUfZ.js → markdown-tables-d7GlUs5R.js} +1 -1
- package/dist/plugin-sdk/{media-CAdQF5TG.js → media-BAoaxCrt.js} +1 -1
- package/dist/plugin-sdk/{monitor-FuBPk-AL.js → monitor-DUMMbG4h.js} +34 -33
- package/dist/plugin-sdk/{monitor-sW6dQdX1.js → monitor-DXIM16Hj.js} +44 -43
- package/dist/plugin-sdk/{openresponses-http-CVZq0H-P.js → openresponses-http-C8lKwta1.js} +26 -25
- package/dist/plugin-sdk/{outbound-attachment-QqTnIhZL.js → outbound-attachment-CyXM3cAv.js} +1 -1
- package/dist/plugin-sdk/{outbound-BgVDdHxx.js → outbound-zB6llMGW.js} +6 -6
- package/dist/plugin-sdk/{pairing-message-L6L6L2YF.d.ts → pairing-message-mKO92L-M.d.ts} +1 -1
- package/dist/plugin-sdk/{pairing-store-BChahgI2.js → pairing-store-B6J2C0vP.js} +1 -1
- package/dist/plugin-sdk/{pi-model-discovery-runtime-DxTMz_XF.js → pi-model-discovery-runtime-6JzLw9Gk.js} +1 -1
- package/dist/plugin-sdk/{probe-CJb5uR8B.js → probe-BM7Oe40M.js} +2 -2
- package/dist/plugin-sdk/{probe-l_whvGLY.js → probe-CMPksimh.js} +1 -1
- package/dist/plugin-sdk/{probe-BFroeK3g.js → probe-oVp12D6L.js} +1 -1
- package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
- package/dist/plugin-sdk/{pw-ai-natjh3rm.js → pw-ai-DJ_gTc4M.js} +1 -1
- package/dist/plugin-sdk/qr-image-B4MlMG4N.js +115 -0
- package/dist/plugin-sdk/{replies-ChYo5ZQM.js → replies-CY-V0Zob.js} +3 -3
- package/dist/plugin-sdk/{resolve-channels-87LZrFk_.js → resolve-channels-1HtDcMqh.js} +2 -2
- package/dist/plugin-sdk/{resolve-channels-_-nV-EK2.js → resolve-channels-CU72Qh2j.js} +1 -1
- package/dist/plugin-sdk/{resolve-outbound-target-D-KGgHJZ.js → resolve-outbound-target-nQSBVYz9.js} +2 -2
- package/dist/plugin-sdk/{resolve-route-C8tvQm8Z.js → resolve-route-Dufnu2cT.js} +1 -1
- package/dist/plugin-sdk/{resolve-users-DN9VQBwv.js → resolve-users-Bk_ss2vC.js} +1 -1
- package/dist/plugin-sdk/{resolve-users-V6dHh_2B.js → resolve-users-IevCOk4W.js} +2 -2
- package/dist/plugin-sdk/{runtime-2B9_WKoI.js → runtime-CXSQwMaR.js} +1 -1
- package/dist/plugin-sdk/{runtime-dependency-DczkvPxn.js → runtime-dependency-nup8niQL.js} +9 -9
- package/dist/plugin-sdk/sat-runtime.d.ts +18 -2
- package/dist/plugin-sdk/sat-runtime.js +26 -25
- package/dist/plugin-sdk/{send-DCO441U7.js → send-BXBS_mRK.js} +8 -8
- package/dist/plugin-sdk/{send-CFzGKJXo.js → send-D-HfKQZm.js} +4 -4
- package/dist/plugin-sdk/{send-B6KkGKZD.js → send-D1j12ZgX.js} +5 -5
- package/dist/plugin-sdk/{send-q9HXrSwK.js → send-DWKm6yay.js} +10 -10
- package/dist/plugin-sdk/{send-gDoGA-7e.js → send-Di1Jit3L.js} +7 -7
- package/dist/plugin-sdk/{skill-commands-FKEPLS7T.js → skill-commands-iJtvpqgb.js} +2 -2
- package/dist/plugin-sdk/{slack-BZISDxDd.js → slack-B-nOOLM0.js} +45 -44
- package/dist/plugin-sdk/{slack-actions-DhbMcp8M.js → slack-actions-BzUEszJa.js} +10 -10
- package/dist/plugin-sdk/slack.d.ts +4 -4
- package/dist/plugin-sdk/slack.js +6 -6
- package/dist/plugin-sdk/{sticker-cache-B0aPv6Lg.js → sticker-cache-BLiId8Em.js} +2 -2
- package/dist/plugin-sdk/{tables-B3jr0Pvq.js → tables-_1W36GII.js} +2 -2
- package/dist/plugin-sdk/{targets-CtSbTxYX.js → targets-DDbNnLnB.js} +2 -2
- package/dist/plugin-sdk/{telegram-actions-H3gePEn6.js → telegram-actions-1X9A32Dn.js} +30 -29
- package/dist/plugin-sdk/telegram.d.ts +4 -4
- package/dist/plugin-sdk/telegram.js +3 -3
- package/dist/plugin-sdk/{thread-bindings.lifecycle-QbkNl-m6.js → thread-bindings.lifecycle-Y9T3CQGf.js} +3 -3
- package/dist/plugin-sdk/{thread-bindings.state-D9hg_M1c.js → thread-bindings.state-D2oOWDpv.js} +1 -1
- package/dist/plugin-sdk/{tmp-fased-dir-d1CmFAnJ.d.ts → tmp-fased-dir-BkpWlGUe.d.ts} +7 -1
- package/dist/plugin-sdk/{types-DUjYaWB2.d.ts → types-B-zL9gSv.d.ts} +1 -1
- package/dist/plugin-sdk/{types-xWjHXl1z.d.ts → types-DtCOO_hW.d.ts} +1 -1
- package/dist/plugin-sdk/{web-JwP9PAZR.js → web-BvjNyYBz.js} +33 -32
- package/dist/plugin-sdk/{whatsapp-actions-Bj_rOncr.js → whatsapp-actions-Blu9-eX-.js} +9 -9
- package/dist/plugin-sdk/{whatsapp-heartbeat-B1WHkJIg.js → whatsapp-heartbeat-DjmQM7hq.js} +2 -2
- package/dist/plugin-sdk/whatsapp.d.ts +9 -9
- package/dist/plugin-sdk/whatsapp.js +7 -7
- package/dist/plugin-sdk/{wsl-J-HscWxS.js → wsl-CTvIWvZz.js} +1 -1
- package/dist/plugin-sdk/{zod-schema.providers-core-CIzCjXH9.d.ts → zod-schema.providers-core-BCDlgtls.d.ts} +63 -63
- package/dist/wallet/local-socket-signer-lifecycle.js +29 -1
- package/dist/wallet/local-socket-signer-protocol.js +27 -0
- package/dist/wallet/providers/local-socket-signer-adapter.js +8 -0
- package/dist/wallet/signer-network-admin.js +11 -118
- package/dist/wallet/signer-protocol-v2.generated.js +4 -0
- package/dist/wallet/solana-assets.js +9 -3
- package/dist/wallet/solana-rpc-read-fetch.js +65 -0
- package/dist/wallet/wallet-status.js +7 -0
- package/dist/web/login-qr.js +1 -1
- package/dist/wizard/onboarding.js +61 -61
- 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/package.json +1 -1
- 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/fased.mjs +14 -1
- package/install.sh +16 -10
- package/package.json +6 -1
- package/scripts/fased-managed-updater.mjs +10 -2
- package/scripts/fased-signer-wallet-import-hosting.sh +78 -0
- package/scripts/install-managed-runtime.mjs +10 -7
- /package/dist/plugin-sdk/{active-listener-B_NMtgPL.js → active-listener-p9Ooc1qj.js} +0 -0
- /package/dist/plugin-sdk/{blocks-input-Bg-8S2pl.js → blocks-input-DiZaqaN7.js} +0 -0
- /package/dist/plugin-sdk/{channel-access-CcFRdRPO.js → channel-access-B0aZBSd2.js} +0 -0
- /package/dist/plugin-sdk/{channel-activity-DBDMQ3yI.js → channel-activity-F07DjroV.js} +0 -0
- /package/dist/plugin-sdk/{channel-core-CFRs8LPy.js → channel-core-DoF4X04L.js} +0 -0
- /package/dist/plugin-sdk/{client-pI228AVT.js → client-DLY-kWF_.js} +0 -0
- /package/dist/plugin-sdk/{command-poll-backoff-yJU83wEq.js → command-poll-backoff-NAePk3eL.js} +0 -0
- /package/dist/plugin-sdk/{date-time-uUevHscU.js → date-time-ChY_tHoG.js} +0 -0
- /package/dist/plugin-sdk/{draft-stream-loop-CrOPfV3F.js → draft-stream-loop-DMBwjjd1.js} +0 -0
- /package/dist/plugin-sdk/{fetch-BtmoPIlf.js → fetch-B0v6OTUZ.js} +0 -0
- /package/dist/plugin-sdk/{filesystem-manager-DoI8IBNF.js → filesystem-manager-BzuIJ9K9.js} +0 -0
- /package/dist/plugin-sdk/{gateway-registry-DZDsqicG.js → gateway-registry-Bgl2GFgy.js} +0 -0
- /package/dist/plugin-sdk/{inbound-context-DrAcXE0y.js → inbound-context-CQnfFFQ9.js} +0 -0
- /package/dist/plugin-sdk/{pi-model-discovery-BX_JLcEJ.js → pi-model-discovery-BHNVyRny.js} +0 -0
- /package/dist/plugin-sdk/{polls-DKQXVfJp.js → polls-DXd67TD8.js} +0 -0
- /package/dist/plugin-sdk/{proxy-DWpYcsvR.js → proxy-CLRUdShp.js} +0 -0
- /package/dist/plugin-sdk/{qmd-manager-CgRaTxUq.js → qmd-manager-B8Vnu0ND.js} +0 -0
- /package/dist/plugin-sdk/{render-e7fENCYH.js → render-DrBfVs0u.js} +0 -0
- /package/dist/plugin-sdk/{reply-reference-Bqk-7HXE.js → reply-reference-BnAk5Wjb.js} +0 -0
- /package/dist/plugin-sdk/{retry-policy-C6SjKjQA.js → retry-policy-CXh1owkc.js} +0 -0
- /package/dist/plugin-sdk/{sandbox-paths-Dx2lUqCu.js → sandbox-paths-Bzh1CuZc.js} +0 -0
- /package/dist/plugin-sdk/{session-DHD4ZKyG.js → session-iuGR_rdi.js} +0 -0
- /package/dist/plugin-sdk/{shared-CBgp_GBw.js → shared-D1AD2Ejn.js} +0 -0
- /package/dist/plugin-sdk/{target-errors-Ckufe179.js → target-errors-DfS1sLR9.js} +0 -0
- /package/dist/plugin-sdk/{tool-loop-detection-Bp8bPJLs.js → tool-loop-detection-sDZl27w7.js} +0 -0
- /package/dist/plugin-sdk/{ui-Be8cLHIS.js → ui-GQDYm_jw.js} +0 -0
- /package/dist/plugin-sdk/{with-timeout-ckWB8rTo.js → with-timeout-CVV8tytk.js} +0 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32.png" />
|
|
15
15
|
<link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon.png" />
|
|
16
16
|
<script data-fased-boot-watchdog src="./boot-watchdog.js" defer></script>
|
|
17
|
-
<script type="module" crossorigin src="./assets/index-
|
|
17
|
+
<script type="module" crossorigin src="./assets/index-Cu13yYHr.js"></script>
|
|
18
18
|
<link rel="stylesheet" crossorigin href="./assets/index-RwVraC3c.css">
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.1.
|
|
1
|
+
{"version":"0.1.68"}
|
|
@@ -11,6 +11,7 @@ import { resolveLocalSignerSocketPath, resolveWalletRuntimeConfig } from "../wal
|
|
|
11
11
|
import { WALLET_PROVIDER_IDS, checkNamedWalletDeletionSafety, deleteNamedWallet, normalizeWalletUserRole, readWalletProviderRegistry, resolveWalletSelection, resolveWalletUserRole, setAgentWalletAssignment, setDefaultWallet, setNamedWalletRole, setWalletProviderEnabled, upsertNamedWallet } from "../wallet/wallet-provider-registry.js";
|
|
12
12
|
import { resolveAgentPublicOrigin, resolveFederationBaseUrl, resolveFederationBondWalletId, resolveFederationHandle } from "../federation/runtime.js";
|
|
13
13
|
import { isValidSolanaAddress } from "../wallet/solana-address.js";
|
|
14
|
+
import { fetchPinnedSolanaRpcRead } from "../wallet/solana-rpc-read-fetch.js";
|
|
14
15
|
import { fetchSolanaMintInfoViaRpc, fetchSolanaNativeBalanceViaRpc, fetchSolanaTokenBalanceViaRpc, fetchSolanaWalletAssetsViaRpc, invalidateSolanaAssetRpcCaches, summarizeSolanaAssetRpcMetrics } from "../wallet/solana-assets.js";
|
|
15
16
|
import { tryResolveSatRuntimeIds } from "../config/sat-runtime-ids.js";
|
|
16
17
|
import { commitWalletPolicyConfigUpdate, prepareWalletPolicyConfigUpdate, resolveWalletPolicyConfig, resolveWalletRecurringTransferPolicy } from "../wallet/wallet-policy.js";
|
|
@@ -35,12 +36,15 @@ import { digestSatSubmissionIntent } from "../extensions/sat-mining/src/submissi
|
|
|
35
36
|
import { runWithSatSubmissionWorkflow, submitSatCancelBondUnlock, submitSatClaimBondStakingRewards, submitSatFinalizeBondUnlock, submitSatIncreaseBondPosition, submitSatOpenBondPosition, submitSatRequestBondUnlock, submitSatSyncBondStakingPosition, submitSatSyncBondStakingRewards } from "../extensions/sat-mining/src/solana-submit.js";
|
|
36
37
|
import { resolveAgentAvatar } from "../agents/identity-avatar.js";
|
|
37
38
|
import { resolveNativeSignerWalletId } from "../wallet/native-signer-wallet-id.js";
|
|
39
|
+
import { configureSignerOwnedWalletNetwork } from "../wallet/signer-network-admin.js";
|
|
38
40
|
import { listWalletInboundEvents, pollWalletInboundEvents, reconcileWalletInboundEvents, recordWalletInboundWebhookEvent } from "../wallet/wallet-inbound-events.js";
|
|
39
41
|
import { walletSetupCommand } from "../commands/wallet.js";
|
|
40
42
|
import { getDiagnosticStabilitySnapshot } from "../logging/diagnostic-stability.js";
|
|
41
43
|
import { resolveManagedFederationPublicUrl } from "../managed/federation.js";
|
|
44
|
+
import { lockSignerOwnedWalletForArchive } from "../wallet/local-socket-signer-archive.js";
|
|
42
45
|
import { LocalSignerPolicyAdminRequiredError, buildLocalSignerPolicyTightening, localSignerPolicyState } from "../wallet/local-socket-signer-policy.js";
|
|
43
46
|
import { executeWalletStandardReview, prepareWalletStandardReview, readWalletStandardReviewTxHash } from "../wallet/wallet-standard-review.js";
|
|
47
|
+
import { renderQrPngBase64 } from "../web/qr-image.js";
|
|
44
48
|
import { createA2aHandler } from "./a2a-http.js";
|
|
45
49
|
import { CONTROL_UI_BOOT_CHECK_PATH, resolveControlUiBootCheck } from "./control-ui-boot-check.js";
|
|
46
50
|
import { normalizePublicHost, resolveControlUiPublicHost } from "./control-ui-login.js";
|
|
@@ -100,12 +104,19 @@ function parseCookies(raw) {
|
|
|
100
104
|
}
|
|
101
105
|
return cookies;
|
|
102
106
|
}
|
|
103
|
-
function
|
|
107
|
+
function normalizeHostName(host) {
|
|
104
108
|
const raw = host.trim().toLowerCase();
|
|
105
|
-
|
|
109
|
+
return raw.startsWith("[") ? (() => {
|
|
106
110
|
const end = raw.indexOf("]");
|
|
107
111
|
return end > 0 ? raw.slice(1, end) : raw;
|
|
108
112
|
})() : raw.replace(/:\d+$/, "");
|
|
113
|
+
}
|
|
114
|
+
function isLiteralLoopbackHostName(host) {
|
|
115
|
+
const normalized = normalizeHostName(host);
|
|
116
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1";
|
|
117
|
+
}
|
|
118
|
+
function isLocalHostName(host) {
|
|
119
|
+
const normalized = normalizeHostName(host);
|
|
109
120
|
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized.endsWith(".local");
|
|
110
121
|
}
|
|
111
122
|
function isLoopbackBrowserOrigin(origin) {
|
|
@@ -114,7 +125,18 @@ function isLoopbackBrowserOrigin(origin) {
|
|
|
114
125
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
115
126
|
return false;
|
|
116
127
|
}
|
|
117
|
-
return
|
|
128
|
+
return isLiteralLoopbackHostName(parsed.host);
|
|
129
|
+
} catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function isSameBrowserOriginHost(origin, host) {
|
|
134
|
+
try {
|
|
135
|
+
const parsed = new URL(origin);
|
|
136
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return parsed.host.toLowerCase() === host.trim().toLowerCase();
|
|
118
140
|
} catch {
|
|
119
141
|
return false;
|
|
120
142
|
}
|
|
@@ -132,7 +154,7 @@ function applyLoopbackCorsIfAllowed(req, res, host) {
|
|
|
132
154
|
if (!origin) {
|
|
133
155
|
return false;
|
|
134
156
|
}
|
|
135
|
-
if (!isLocalHostName(host) || !isLoopbackBrowserOrigin(origin)) {
|
|
157
|
+
if (!isLocalHostName(host) || !isLoopbackBrowserOrigin(origin) && !isSameBrowserOriginHost(origin, host)) {
|
|
136
158
|
return false;
|
|
137
159
|
}
|
|
138
160
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
@@ -935,20 +957,20 @@ async function fetchSolanaLamportsViaRpc(params) {
|
|
|
935
957
|
if (!rpcUrl || !address) {
|
|
936
958
|
return null;
|
|
937
959
|
}
|
|
938
|
-
|
|
939
|
-
const timeout = setTimeout(() => controller.abort(), Math.max(250, params.timeoutMs));
|
|
960
|
+
let release;
|
|
940
961
|
try {
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
962
|
+
const guarded = await fetchPinnedSolanaRpcRead({
|
|
963
|
+
rpcUrl,
|
|
964
|
+
timeoutMs: params.timeoutMs,
|
|
944
965
|
body: JSON.stringify({
|
|
945
966
|
jsonrpc: "2.0",
|
|
946
967
|
id: "wallet-balance-fallback",
|
|
947
968
|
method: "getBalance",
|
|
948
969
|
params: [address]
|
|
949
|
-
})
|
|
950
|
-
signal: controller.signal
|
|
970
|
+
})
|
|
951
971
|
});
|
|
972
|
+
release = guarded.release;
|
|
973
|
+
const response = guarded.response;
|
|
952
974
|
if (!response.ok) {
|
|
953
975
|
recordWalletGatewayRpcMethod("direct.getBalance", "failure");
|
|
954
976
|
return null;
|
|
@@ -962,7 +984,7 @@ async function fetchSolanaLamportsViaRpc(params) {
|
|
|
962
984
|
recordWalletGatewayRpcMethod("direct.getBalance", "failure");
|
|
963
985
|
return null;
|
|
964
986
|
} finally {
|
|
965
|
-
|
|
987
|
+
await release?.();
|
|
966
988
|
}
|
|
967
989
|
}
|
|
968
990
|
function resolveWalletProbeTimeoutMs(env) {
|
|
@@ -1004,11 +1026,18 @@ function resolveMiningAgentWalletConflict(walletId) {
|
|
|
1004
1026
|
return null;
|
|
1005
1027
|
}
|
|
1006
1028
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
1007
|
-
if (activeMiningWalletId
|
|
1008
|
-
return
|
|
1029
|
+
if (activeMiningWalletId && activeMiningWalletId !== normalizedWalletId) {
|
|
1030
|
+
return `SAT Mining already uses ${activeMiningWalletId}. Archive that singleton wallet before attaching a replacement.`;
|
|
1009
1031
|
}
|
|
1010
1032
|
const registry = readWalletProviderRegistry(process.env);
|
|
1011
1033
|
const wallet = registry.wallets.find((entry) => entry.id === normalizedWalletId);
|
|
1034
|
+
const otherMiningWallet = registry.wallets.find((entry) => entry.id !== normalizedWalletId && resolveWalletUserRole(entry) === "mining");
|
|
1035
|
+
if (otherMiningWallet) {
|
|
1036
|
+
return `SAT Mining already has the singleton wallet ${otherMiningWallet.id}. Archive it before attaching a replacement.`;
|
|
1037
|
+
}
|
|
1038
|
+
if (!wallet) {
|
|
1039
|
+
return "SAT Mining requires an existing dedicated Mining wallet.";
|
|
1040
|
+
}
|
|
1012
1041
|
const purpose = resolveWalletUserRole(wallet);
|
|
1013
1042
|
if (normalizedWalletId === registry.defaultWalletId || purpose === "agent") {
|
|
1014
1043
|
return "SAT Mining must use a dedicated Mining wallet. Create a new Mining wallet instead of reusing an Agent wallet.";
|
|
@@ -1288,9 +1317,9 @@ async function checkSolanaAtaReadiness(address, env) {
|
|
|
1288
1317
|
}
|
|
1289
1318
|
try {
|
|
1290
1319
|
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
|
|
1320
|
+
const guarded = await fetchPinnedSolanaRpcRead({
|
|
1321
|
+
rpcUrl,
|
|
1322
|
+
timeoutMs: 1e4,
|
|
1294
1323
|
body: JSON.stringify({
|
|
1295
1324
|
jsonrpc: "2.0",
|
|
1296
1325
|
id: 1,
|
|
@@ -1302,15 +1331,19 @@ async function checkSolanaAtaReadiness(address, env) {
|
|
|
1302
1331
|
]
|
|
1303
1332
|
})
|
|
1304
1333
|
});
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1334
|
+
try {
|
|
1335
|
+
if (!guarded.response.ok) {
|
|
1336
|
+
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", "failure");
|
|
1337
|
+
return false;
|
|
1338
|
+
}
|
|
1339
|
+
const payload = await guarded.response.json();
|
|
1340
|
+
const accounts = payload?.result?.value;
|
|
1341
|
+
const ok = Array.isArray(accounts);
|
|
1342
|
+
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", ok ? "success" : "failure");
|
|
1343
|
+
return ok && accounts.length > 0;
|
|
1344
|
+
} finally {
|
|
1345
|
+
await guarded.release();
|
|
1308
1346
|
}
|
|
1309
|
-
const payload = await response.json();
|
|
1310
|
-
const accounts = payload?.result?.value;
|
|
1311
|
-
const ok = Array.isArray(accounts);
|
|
1312
|
-
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", ok ? "success" : "failure");
|
|
1313
|
-
return ok && accounts.length > 0;
|
|
1314
1347
|
} catch {
|
|
1315
1348
|
recordWalletGatewayRpcMethod("direct.getTokenAccountsByOwner", "failure");
|
|
1316
1349
|
return false;
|
|
@@ -3065,7 +3098,20 @@ function createGatewayHttpServer(opts) {
|
|
|
3065
3098
|
const directLocalRequest = !tailscaleProxyConfigured && isDirectLoopbackRequest(req, trustedProxies);
|
|
3066
3099
|
const ensureWalletApiAuthorized = async () => {
|
|
3067
3100
|
if (directLocalRequest) {
|
|
3068
|
-
|
|
3101
|
+
const requestOrigin = String(getHeader(req, "origin") ?? "").trim();
|
|
3102
|
+
if (!requestOrigin || isLoopbackBrowserOrigin(requestOrigin)) {
|
|
3103
|
+
return true;
|
|
3104
|
+
}
|
|
3105
|
+
if (!loopbackCorsApplied) {
|
|
3106
|
+
sendLoginResponse(403, {
|
|
3107
|
+
ok: false,
|
|
3108
|
+
error: {
|
|
3109
|
+
code: "forbidden_origin",
|
|
3110
|
+
message: "cross-origin browser requests are not allowed on the loopback wallet API"
|
|
3111
|
+
}
|
|
3112
|
+
});
|
|
3113
|
+
return false;
|
|
3114
|
+
}
|
|
3069
3115
|
}
|
|
3070
3116
|
let authorized = false;
|
|
3071
3117
|
const bearer = getBearerToken(req);
|
|
@@ -4476,24 +4522,24 @@ function createGatewayHttpServer(opts) {
|
|
|
4476
4522
|
const requestedWalletId = typeof payload.walletId === "string" ? payload.walletId.trim() : "";
|
|
4477
4523
|
const roleProvided = Object.prototype.hasOwnProperty.call(payload, "role");
|
|
4478
4524
|
const normalizedRole = roleProvided ? normalizeWalletUserRole(payload.role) : undefined;
|
|
4479
|
-
const requestedRole = normalizedRole === "agent" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4525
|
+
const requestedRole = normalizedRole === "agent" || normalizedRole === "mining" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4480
4526
|
if (roleProvided && !requestedRole) {
|
|
4481
4527
|
sendLoginResponse(400, {
|
|
4482
4528
|
ok: false,
|
|
4483
4529
|
error: {
|
|
4484
4530
|
code: "invalid_wallet_role",
|
|
4485
|
-
message: "role must be agent or vault"
|
|
4531
|
+
message: "role must be agent, mining, or vault"
|
|
4486
4532
|
}
|
|
4487
4533
|
});
|
|
4488
4534
|
return;
|
|
4489
4535
|
}
|
|
4490
4536
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
4491
|
-
if (requestedRole &&
|
|
4537
|
+
if (requestedRole === "mining" && activeMiningWalletId && requestedWalletId !== activeMiningWalletId) {
|
|
4492
4538
|
sendLoginResponse(409, {
|
|
4493
4539
|
ok: false,
|
|
4494
4540
|
error: {
|
|
4495
4541
|
code: "wallet_in_use",
|
|
4496
|
-
message:
|
|
4542
|
+
message: `Mining already uses the singleton wallet ${activeMiningWalletId}; use the reviewed Replace/Archive flow instead of creating a second Mining wallet`
|
|
4497
4543
|
}
|
|
4498
4544
|
});
|
|
4499
4545
|
return;
|
|
@@ -4581,6 +4627,16 @@ function createGatewayHttpServer(opts) {
|
|
|
4581
4627
|
});
|
|
4582
4628
|
return;
|
|
4583
4629
|
}
|
|
4630
|
+
if (!requestedRole) {
|
|
4631
|
+
sendLoginResponse(400, {
|
|
4632
|
+
ok: false,
|
|
4633
|
+
error: {
|
|
4634
|
+
code: "invalid_wallet_role",
|
|
4635
|
+
message: "choose agent, mining, or vault; the native signer never infers a role"
|
|
4636
|
+
}
|
|
4637
|
+
});
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4584
4640
|
const chain = inferLocalSignerCreateChain({
|
|
4585
4641
|
payloadChain: payload.chain,
|
|
4586
4642
|
walletId: requestedWalletId,
|
|
@@ -4597,18 +4653,26 @@ function createGatewayHttpServer(opts) {
|
|
|
4597
4653
|
});
|
|
4598
4654
|
return;
|
|
4599
4655
|
}
|
|
4656
|
+
const rpcUrl = typeof payload.rpcUrl === "string" ? payload.rpcUrl.trim() : "";
|
|
4657
|
+
if (!rpcUrl) {
|
|
4658
|
+
sendLoginResponse(400, {
|
|
4659
|
+
ok: false,
|
|
4660
|
+
error: {
|
|
4661
|
+
code: "invalid_request",
|
|
4662
|
+
message: "one primary Solana RPC URL is required for native signer wallet creation"
|
|
4663
|
+
}
|
|
4664
|
+
});
|
|
4665
|
+
return;
|
|
4666
|
+
}
|
|
4600
4667
|
try {
|
|
4601
|
-
const effectiveEnv = {
|
|
4602
|
-
...process.env,
|
|
4603
|
-
...cfg.env?.vars
|
|
4604
|
-
};
|
|
4605
4668
|
await walletSetupCommand(silentWalletSetupRuntime, {
|
|
4606
4669
|
mode: "local-signer-create",
|
|
4607
4670
|
chain,
|
|
4608
4671
|
walletId: requestedWalletId,
|
|
4609
4672
|
walletName,
|
|
4610
|
-
rpcUrl
|
|
4673
|
+
rpcUrl,
|
|
4611
4674
|
role: requestedRole,
|
|
4675
|
+
force: true,
|
|
4612
4676
|
nonInteractive: true,
|
|
4613
4677
|
noSignerHints: true,
|
|
4614
4678
|
noDoctor: true
|
|
@@ -4738,13 +4802,15 @@ function createGatewayHttpServer(opts) {
|
|
|
4738
4802
|
const name = typeof payload.name === "string" && payload.name.trim() ? payload.name.trim() : undefined;
|
|
4739
4803
|
const roleProvided = Object.prototype.hasOwnProperty.call(payload, "role");
|
|
4740
4804
|
const normalizedRole = roleProvided ? normalizeWalletUserRole(payload.role) : undefined;
|
|
4741
|
-
const requestedRole = normalizedRole === "agent" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4742
|
-
|
|
4805
|
+
const requestedRole = normalizedRole === "agent" || normalizedRole === "mining" || normalizedRole === "vault" ? normalizedRole : undefined;
|
|
4806
|
+
const rpcUrl = typeof payload.rpcUrl === "string" ? payload.rpcUrl.trim() : "";
|
|
4807
|
+
const rpcProvided = Object.prototype.hasOwnProperty.call(payload, "rpcUrl");
|
|
4808
|
+
if (!walletId || !name && !roleProvided && !rpcProvided) {
|
|
4743
4809
|
sendLoginResponse(400, {
|
|
4744
4810
|
ok: false,
|
|
4745
4811
|
error: {
|
|
4746
4812
|
code: "invalid_request",
|
|
4747
|
-
message: "walletId and
|
|
4813
|
+
message: "walletId and role or rpcUrl are required"
|
|
4748
4814
|
}
|
|
4749
4815
|
});
|
|
4750
4816
|
return;
|
|
@@ -4754,7 +4820,7 @@ function createGatewayHttpServer(opts) {
|
|
|
4754
4820
|
ok: false,
|
|
4755
4821
|
error: {
|
|
4756
4822
|
code: "invalid_wallet_role",
|
|
4757
|
-
message: "role must be agent or vault"
|
|
4823
|
+
message: "role must be agent, mining, or vault"
|
|
4758
4824
|
}
|
|
4759
4825
|
});
|
|
4760
4826
|
return;
|
|
@@ -4781,13 +4847,117 @@ function createGatewayHttpServer(opts) {
|
|
|
4781
4847
|
});
|
|
4782
4848
|
return;
|
|
4783
4849
|
}
|
|
4850
|
+
if (rpcProvided) {
|
|
4851
|
+
if (!rpcUrl) {
|
|
4852
|
+
sendLoginResponse(400, {
|
|
4853
|
+
ok: false,
|
|
4854
|
+
error: {
|
|
4855
|
+
code: "invalid_request",
|
|
4856
|
+
message: "rpcUrl must be a non-empty primary Solana RPC URL"
|
|
4857
|
+
}
|
|
4858
|
+
});
|
|
4859
|
+
return;
|
|
4860
|
+
}
|
|
4861
|
+
if (existing.providerId !== "local-socket-signer") {
|
|
4862
|
+
sendLoginResponse(409, {
|
|
4863
|
+
ok: false,
|
|
4864
|
+
error: {
|
|
4865
|
+
code: "invalid_provider",
|
|
4866
|
+
message: "primary RPC editing is available only for native signer wallets"
|
|
4867
|
+
}
|
|
4868
|
+
});
|
|
4869
|
+
return;
|
|
4870
|
+
}
|
|
4871
|
+
const cfg = loadConfig();
|
|
4872
|
+
if (!ensureWalletApprovalAuthorized({
|
|
4873
|
+
operation: "wallet.network",
|
|
4874
|
+
cfg
|
|
4875
|
+
})) {
|
|
4876
|
+
return;
|
|
4877
|
+
}
|
|
4878
|
+
try {
|
|
4879
|
+
const effectiveEnv = {
|
|
4880
|
+
...process.env,
|
|
4881
|
+
...cfg.env?.vars
|
|
4882
|
+
};
|
|
4883
|
+
const signerWalletId = resolveNativeSignerWalletId(existing);
|
|
4884
|
+
const network = await configureSignerOwnedWalletNetwork({
|
|
4885
|
+
walletId: signerWalletId,
|
|
4886
|
+
primaryRpcUrl: rpcUrl,
|
|
4887
|
+
env: effectiveEnv,
|
|
4888
|
+
socketPath: resolveLocalSignerSocketPath(effectiveEnv)
|
|
4889
|
+
});
|
|
4890
|
+
const suffix = normalizeWalletIdForEnvSuffix(walletId)?.toUpperCase();
|
|
4891
|
+
const rpcKey = suffix ? `FASED_WALLET_SOLANA_RPC_URL__${suffix}` : "FASED_WALLET_SOLANA_RPC_URL";
|
|
4892
|
+
const configUpdate = await updateWalletConfig({
|
|
4893
|
+
env: effectiveEnv,
|
|
4894
|
+
mutate: (next) => {
|
|
4895
|
+
next.env = {
|
|
4896
|
+
...next.env,
|
|
4897
|
+
vars: {
|
|
4898
|
+
...next.env?.vars,
|
|
4899
|
+
[rpcKey]: rpcUrl
|
|
4900
|
+
}
|
|
4901
|
+
};
|
|
4902
|
+
}
|
|
4903
|
+
});
|
|
4904
|
+
if (!configUpdate.ok) {
|
|
4905
|
+
throw new Error(`signer accepted network version ${network.version}, but app configuration persistence failed: ${configUpdate.message}`);
|
|
4906
|
+
}
|
|
4907
|
+
upsertNamedWallet({
|
|
4908
|
+
walletId: existing.id,
|
|
4909
|
+
name: existing.name,
|
|
4910
|
+
providerId: existing.providerId,
|
|
4911
|
+
addresses: existing.addresses,
|
|
4912
|
+
metadata: {
|
|
4913
|
+
...existing.metadata,
|
|
4914
|
+
networkHash: network.hash,
|
|
4915
|
+
networkVersion: network.version,
|
|
4916
|
+
networkReady: network.ready
|
|
4917
|
+
},
|
|
4918
|
+
env: process.env
|
|
4919
|
+
});
|
|
4920
|
+
appendWalletAuditEntry({
|
|
4921
|
+
action: "wallet_rpc_updated",
|
|
4922
|
+
actor: "control-ui",
|
|
4923
|
+
details: {
|
|
4924
|
+
walletId,
|
|
4925
|
+
networkVersion: network.version,
|
|
4926
|
+
networkReady: network.ready
|
|
4927
|
+
},
|
|
4928
|
+
env: process.env
|
|
4929
|
+
});
|
|
4930
|
+
} catch (err) {
|
|
4931
|
+
sendLoginResponse(502, {
|
|
4932
|
+
ok: false,
|
|
4933
|
+
error: {
|
|
4934
|
+
code: "wallet_rpc_update_failed",
|
|
4935
|
+
message: err instanceof Error ? err.message : String(err)
|
|
4936
|
+
}
|
|
4937
|
+
});
|
|
4938
|
+
return;
|
|
4939
|
+
}
|
|
4940
|
+
}
|
|
4784
4941
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
4785
|
-
if (requestedRole
|
|
4942
|
+
if (requestedRole === "mining") {
|
|
4943
|
+
const miningConflict = resolveMiningAgentWalletConflict(walletId);
|
|
4944
|
+
if (miningConflict) {
|
|
4945
|
+
sendLoginResponse(409, {
|
|
4946
|
+
ok: false,
|
|
4947
|
+
error: {
|
|
4948
|
+
code: "wallet_in_use",
|
|
4949
|
+
message: miningConflict
|
|
4950
|
+
}
|
|
4951
|
+
});
|
|
4952
|
+
return;
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
if (requestedRole && requestedRole !== "mining" && walletId === activeMiningWalletId) {
|
|
4786
4956
|
sendLoginResponse(409, {
|
|
4787
4957
|
ok: false,
|
|
4788
4958
|
error: {
|
|
4789
4959
|
code: "wallet_in_use",
|
|
4790
|
-
message: "walletId is the singleton SAT
|
|
4960
|
+
message: "walletId is the singleton SAT Mining wallet; use the guarded Archive/Replace flow before creating a wallet with a different role"
|
|
4791
4961
|
}
|
|
4792
4962
|
});
|
|
4793
4963
|
return;
|
|
@@ -4806,7 +4976,7 @@ function createGatewayHttpServer(opts) {
|
|
|
4806
4976
|
ok: false,
|
|
4807
4977
|
error: {
|
|
4808
4978
|
code: "signer_wallet_role_immutable",
|
|
4809
|
-
message: `The native signer owns this wallet as role=${signerPolicy.role}; the Gateway cannot change it to ${requestedRole}. ` + "Create a new signer-owned wallet with the required locked role
|
|
4979
|
+
message: `The native signer owns this wallet as role=${signerPolicy.role}; the Gateway cannot change it to ${requestedRole}. ` + "Create a new signer-owned wallet with the required locked role, then use the guarded Archive/Replace flow for the old wallet."
|
|
4810
4980
|
}
|
|
4811
4981
|
});
|
|
4812
4982
|
return;
|
|
@@ -4863,6 +5033,8 @@ function createGatewayHttpServer(opts) {
|
|
|
4863
5033
|
}
|
|
4864
5034
|
const payload = body.value ?? {};
|
|
4865
5035
|
const walletId = typeof payload.walletId === "string" ? payload.walletId.trim() : "";
|
|
5036
|
+
const archiveRequested = payload.archive === true;
|
|
5037
|
+
const archiveConfirmation = typeof payload.confirmWalletId === "string" ? payload.confirmWalletId.trim() : "";
|
|
4866
5038
|
if (!walletId) {
|
|
4867
5039
|
sendLoginResponse(400, {
|
|
4868
5040
|
ok: false,
|
|
@@ -4873,13 +5045,23 @@ function createGatewayHttpServer(opts) {
|
|
|
4873
5045
|
});
|
|
4874
5046
|
return;
|
|
4875
5047
|
}
|
|
5048
|
+
if (archiveRequested && archiveConfirmation !== walletId) {
|
|
5049
|
+
sendLoginResponse(400, {
|
|
5050
|
+
ok: false,
|
|
5051
|
+
error: {
|
|
5052
|
+
code: "archive_confirmation_required",
|
|
5053
|
+
message: "confirmWalletId must exactly match walletId"
|
|
5054
|
+
}
|
|
5055
|
+
});
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
4876
5058
|
const activeMiningWalletId = readSatMiningWalletIdFromConfig(loadConfig());
|
|
4877
|
-
if (activeMiningWalletId === walletId) {
|
|
5059
|
+
if (activeMiningWalletId === walletId && !archiveRequested) {
|
|
4878
5060
|
sendLoginResponse(409, {
|
|
4879
5061
|
ok: false,
|
|
4880
5062
|
error: {
|
|
4881
5063
|
code: "wallet_in_use",
|
|
4882
|
-
message: "walletId is the singleton SAT
|
|
5064
|
+
message: "walletId is the singleton SAT Mining wallet; request the guarded Archive flow instead of ordinary delete"
|
|
4883
5065
|
}
|
|
4884
5066
|
});
|
|
4885
5067
|
return;
|
|
@@ -4911,6 +5093,88 @@ function createGatewayHttpServer(opts) {
|
|
|
4911
5093
|
});
|
|
4912
5094
|
return;
|
|
4913
5095
|
}
|
|
5096
|
+
if (existing.providerId === "local-socket-signer" && archiveRequested) {
|
|
5097
|
+
const cfg = loadConfig();
|
|
5098
|
+
if (!ensureWalletApprovalAuthorized({
|
|
5099
|
+
operation: "wallet.archive",
|
|
5100
|
+
cfg
|
|
5101
|
+
})) {
|
|
5102
|
+
return;
|
|
5103
|
+
}
|
|
5104
|
+
let archivedPolicy;
|
|
5105
|
+
try {
|
|
5106
|
+
const effectiveEnv = {
|
|
5107
|
+
...process.env,
|
|
5108
|
+
...cfg.env?.vars
|
|
5109
|
+
};
|
|
5110
|
+
archivedPolicy = await lockSignerOwnedWalletForArchive({
|
|
5111
|
+
wallet: existing,
|
|
5112
|
+
socketPath: resolveLocalSignerSocketPath(effectiveEnv)
|
|
5113
|
+
});
|
|
5114
|
+
const federationWalletId = resolveFederationBondDefaultWalletId(cfg);
|
|
5115
|
+
const suffix = normalizeWalletIdForEnvSuffix(walletId)?.toUpperCase();
|
|
5116
|
+
const rpcKey = suffix ? `FASED_WALLET_SOLANA_RPC_URL__${suffix}` : "FASED_WALLET_SOLANA_RPC_URL";
|
|
5117
|
+
const updated = await updateWalletConfig({
|
|
5118
|
+
env: effectiveEnv,
|
|
5119
|
+
mutate: (next) => {
|
|
5120
|
+
if (next.env?.vars) {
|
|
5121
|
+
delete next.env.vars[rpcKey];
|
|
5122
|
+
}
|
|
5123
|
+
const currentEntry = next.plugins?.entries?.["sat-mining"];
|
|
5124
|
+
const currentSatConfig = currentEntry?.config && typeof currentEntry.config === "object" && !Array.isArray(currentEntry.config) ? { ...currentEntry.config } : {};
|
|
5125
|
+
if (currentSatConfig.walletId === walletId) {
|
|
5126
|
+
delete currentSatConfig.walletId;
|
|
5127
|
+
next.plugins = {
|
|
5128
|
+
...next.plugins,
|
|
5129
|
+
entries: {
|
|
5130
|
+
...next.plugins?.entries,
|
|
5131
|
+
"sat-mining": {
|
|
5132
|
+
enabled: true,
|
|
5133
|
+
...currentEntry,
|
|
5134
|
+
config: currentSatConfig
|
|
5135
|
+
}
|
|
5136
|
+
}
|
|
5137
|
+
};
|
|
5138
|
+
}
|
|
5139
|
+
if (federationWalletId === walletId) {
|
|
5140
|
+
applyFederationBondWalletConfig(next, null);
|
|
5141
|
+
}
|
|
5142
|
+
}
|
|
5143
|
+
});
|
|
5144
|
+
if (!updated.ok) {
|
|
5145
|
+
throw new Error(`signer locked the wallet, but attachment cleanup failed: ${updated.message}`);
|
|
5146
|
+
}
|
|
5147
|
+
} catch (err) {
|
|
5148
|
+
sendLoginResponse(502, {
|
|
5149
|
+
ok: false,
|
|
5150
|
+
error: {
|
|
5151
|
+
code: "wallet_archive_failed",
|
|
5152
|
+
message: err instanceof Error ? err.message : String(err)
|
|
5153
|
+
}
|
|
5154
|
+
});
|
|
5155
|
+
return;
|
|
5156
|
+
}
|
|
5157
|
+
const removed = deleteNamedWallet({
|
|
5158
|
+
walletId,
|
|
5159
|
+
env: process.env
|
|
5160
|
+
});
|
|
5161
|
+
appendWalletAuditEntry({
|
|
5162
|
+
action: "wallet_archived",
|
|
5163
|
+
actor: "control-ui",
|
|
5164
|
+
details: {
|
|
5165
|
+
walletId,
|
|
5166
|
+
signerWalletId: archivedPolicy.walletId,
|
|
5167
|
+
denyAllPolicyVersion: archivedPolicy.version
|
|
5168
|
+
},
|
|
5169
|
+
env: process.env
|
|
5170
|
+
});
|
|
5171
|
+
sendLoginResponse(200, {
|
|
5172
|
+
ok: true,
|
|
5173
|
+
removed: removed.removed,
|
|
5174
|
+
archived: true
|
|
5175
|
+
});
|
|
5176
|
+
return;
|
|
5177
|
+
}
|
|
4914
5178
|
if (existing.providerId === "local-socket-signer" || existing.providerId === "embedded-keystore" || existing.metadata?.selfHosted === true) {
|
|
4915
5179
|
sendLoginResponse(409, {
|
|
4916
5180
|
ok: false,
|
|
@@ -4943,6 +5207,44 @@ function createGatewayHttpServer(opts) {
|
|
|
4943
5207
|
});
|
|
4944
5208
|
return;
|
|
4945
5209
|
}
|
|
5210
|
+
if (requestPath === "/api/wallet/receive-qr") {
|
|
5211
|
+
if (!await ensureWalletApiAuthorized()) {
|
|
5212
|
+
return;
|
|
5213
|
+
}
|
|
5214
|
+
if (req.method !== "GET") {
|
|
5215
|
+
res.statusCode = 405;
|
|
5216
|
+
res.setHeader("Allow", "GET");
|
|
5217
|
+
sendLoginResponse(405, {
|
|
5218
|
+
ok: false,
|
|
5219
|
+
error: {
|
|
5220
|
+
code: "method_not_allowed",
|
|
5221
|
+
message: "method must be GET"
|
|
5222
|
+
}
|
|
5223
|
+
});
|
|
5224
|
+
return;
|
|
5225
|
+
}
|
|
5226
|
+
const walletId = parsedUrl.searchParams.get("walletId")?.trim() ?? "";
|
|
5227
|
+
const wallet = readWalletProviderRegistry(process.env).wallets.find((entry) => entry.id === walletId);
|
|
5228
|
+
const address = wallet?.addresses?.solana?.trim() ?? "";
|
|
5229
|
+
if (!walletId || !address || !isValidSolanaAddress(address)) {
|
|
5230
|
+
sendLoginResponse(404, {
|
|
5231
|
+
ok: false,
|
|
5232
|
+
error: {
|
|
5233
|
+
code: "wallet_address_not_found",
|
|
5234
|
+
message: "wallet address not found"
|
|
5235
|
+
}
|
|
5236
|
+
});
|
|
5237
|
+
return;
|
|
5238
|
+
}
|
|
5239
|
+
const png = Buffer.from(await renderQrPngBase64(`solana:${address}`), "base64");
|
|
5240
|
+
res.statusCode = 200;
|
|
5241
|
+
res.setHeader("Content-Type", "image/png");
|
|
5242
|
+
res.setHeader("Content-Length", String(png.byteLength));
|
|
5243
|
+
res.setHeader("Cache-Control", "private, no-store");
|
|
5244
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
5245
|
+
res.end(png);
|
|
5246
|
+
return;
|
|
5247
|
+
}
|
|
4946
5248
|
if (requestPath === "/api/wallet/assignments") {
|
|
4947
5249
|
if (!await ensureWalletApiAuthorized()) {
|
|
4948
5250
|
return;
|
|
@@ -4987,7 +5289,7 @@ function createGatewayHttpServer(opts) {
|
|
|
4987
5289
|
ok: false,
|
|
4988
5290
|
error: {
|
|
4989
5291
|
code: "wallet_in_use",
|
|
4990
|
-
message: "walletId is the singleton SAT
|
|
5292
|
+
message: "walletId is the singleton SAT Mining wallet; Archive/Replace Mining with an Agent wallet before making it the primary Agent wallet"
|
|
4991
5293
|
}
|
|
4992
5294
|
});
|
|
4993
5295
|
return;
|
|
@@ -7129,7 +7431,7 @@ function createGatewayHttpServer(opts) {
|
|
|
7129
7431
|
});
|
|
7130
7432
|
return;
|
|
7131
7433
|
}
|
|
7132
|
-
if (operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7434
|
+
if (operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.network" && operation !== "wallet.archive" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7133
7435
|
sendLoginResponse(400, {
|
|
7134
7436
|
ok: false,
|
|
7135
7437
|
error: {
|
|
@@ -7263,7 +7565,7 @@ function createGatewayHttpServer(opts) {
|
|
|
7263
7565
|
const payloadRaw = body.value ?? {};
|
|
7264
7566
|
const requestId = typeof payloadRaw.requestId === "string" ? payloadRaw.requestId.trim() || undefined : undefined;
|
|
7265
7567
|
const operation = typeof payloadRaw.operation === "string" ? payloadRaw.operation.trim() || undefined : undefined;
|
|
7266
|
-
if (operation && operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7568
|
+
if (operation && operation !== "wallet.approve" && operation !== "wallet.policy" && operation !== "wallet.settings" && operation !== "wallet.provider-credentials" && operation !== "wallet.network" && operation !== "wallet.archive" && operation !== "wallet.passkey-enroll" && operation !== "wallet.passkey-remove" && operation !== "wallet.reset" && operation !== "wallet.rotate" && operation !== "wallet.execution-mode" && operation !== "wallet.send" && operation !== "mining.capital" && operation !== "mining.policy") {
|
|
7267
7569
|
sendLoginResponse(400, {
|
|
7268
7570
|
ok: false,
|
|
7269
7571
|
error: {
|
|
@@ -45,6 +45,7 @@ function detectRuntime() {
|
|
|
45
45
|
version,
|
|
46
46
|
execPath: process.execPath ?? null,
|
|
47
47
|
pathEnv: process.env.PATH ?? "(not set)",
|
|
48
|
+
platform: process.platform,
|
|
48
49
|
sqliteAvailable: kind === "node" ? detectNodeSqliteSupport() : false
|
|
49
50
|
};
|
|
50
51
|
}
|
|
@@ -57,6 +58,10 @@ function detectNodeSqliteSupport() {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
function runtimeSatisfies(details) {
|
|
61
|
+
const platform = details.platform ?? process.platform;
|
|
62
|
+
if (platform === "win32") {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
60
65
|
const parsed = parseSemver(details.version);
|
|
61
66
|
if (details.kind === "node") {
|
|
62
67
|
return isAtLeast(parsed, MIN_NODE) && details.sqliteAvailable !== false;
|
|
@@ -70,6 +75,17 @@ function assertSupportedRuntime(runtime = defaultRuntime, details = detectRuntim
|
|
|
70
75
|
if (runtimeSatisfies(details)) {
|
|
71
76
|
return;
|
|
72
77
|
}
|
|
78
|
+
const platform = details.platform ?? process.platform;
|
|
79
|
+
if (platform === "win32") {
|
|
80
|
+
runtime.error([
|
|
81
|
+
"Native Windows is not a supported Fased runtime.",
|
|
82
|
+
"Install Ubuntu in WSL2, enable systemd, and run Fased inside the Ubuntu shell.",
|
|
83
|
+
"PowerShell is supported only for installing WSL2 or connecting to a remote Linux VPS.",
|
|
84
|
+
"Guide: https://docs.fased.ai/platforms/windows"
|
|
85
|
+
].join("\n"));
|
|
86
|
+
runtime.exit(1);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
73
89
|
const versionLabel = details.version ?? "unknown";
|
|
74
90
|
const runtimeLabel = details.kind === "unknown" ? "unknown runtime" : `${details.kind} ${versionLabel}`;
|
|
75
91
|
const execLabel = details.execPath ?? "unknown";
|