@stelis/say-ur-intent 0.0.0 → 0.0.2
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/README.md +4 -39
- package/dist/adapters/adapterLifecycleValidators.js +7 -0
- package/dist/adapters/adapterPromptSurfaces.js +71 -0
- package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +175 -0
- package/dist/adapters/deepbook/deepbookQuotePolicy.js +112 -0
- package/dist/adapters/deepbook/deepbookReviewEvidence.js +507 -0
- package/dist/adapters/deepbook/deepbookReviewLifecycle.js +85 -0
- package/dist/adapters/deepbook/deepbookSwapIntent.js +79 -0
- package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +269 -0
- package/dist/adapters/flowx/flowxSwapHumanReviewProducer.js +176 -0
- package/dist/adapters/flowx/flowxSwapIntent.js +79 -0
- package/dist/adapters/flowx/flowxSwapQuotePolicy.js +104 -0
- package/dist/adapters/flowx/flowxSwapReviewEvidence.js +468 -0
- package/dist/adapters/flowx/flowxSwapReviewLifecycle.js +85 -0
- package/dist/adapters/flowx/flowxSwapTransactionMaterialProducer.js +362 -0
- package/dist/adapters/intentPlanFactories.js +59 -0
- package/dist/adapters/reviewAdapters.js +81 -0
- package/dist/core/action/adapterLifecycleValidation.js +12 -0
- package/dist/core/action/forbiddenFields.js +43 -0
- package/dist/core/action/humanReadableReviewEvidence.js +203 -0
- package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
- package/dist/core/action/ptbVisualizationProducer.js +66 -0
- package/dist/core/action/reviewCheckResults.js +6 -0
- package/dist/core/action/reviewStateValidation.js +11 -0
- package/dist/core/action/reviewTimeSimulationEvidence.js +471 -0
- package/dist/core/action/schemas.js +529 -0
- package/dist/core/action/signableAdapterContract.js +993 -0
- package/dist/core/action/swapHumanReadableReviewProjection.js +124 -0
- package/dist/core/action/swapQuotePolicyEvidence.js +278 -0
- package/dist/core/action/transactionObjectOwnershipEvidence.js +247 -0
- package/dist/core/action/transactionObjectOwnershipProducer.js +329 -0
- package/dist/core/action/types.js +35 -0
- package/dist/core/action/walletReviewContractAssembler.js +282 -0
- package/dist/core/activity/activityStore.js +15 -0
- package/dist/core/activity/localDataService.js +258 -0
- package/dist/core/activity/localDataTypes.js +11 -0
- package/dist/core/activity/localDataValidation.js +396 -0
- package/dist/core/activity/schemaVersion.js +1 -0
- package/dist/core/activity/sqliteActivityStore.js +820 -0
- package/dist/core/activity/sqliteActivityStoreRows.js +430 -0
- package/dist/core/activity/sqliteActivityStoreSchema.js +258 -0
- package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
- package/dist/core/activity/suiFunctionTarget.js +43 -0
- package/dist/core/activity/transactionActivityAccountEffects.js +189 -0
- package/dist/core/activity/transactionActivityAnalysis.js +295 -0
- package/dist/core/activity/transactionActivityClassifier.js +306 -0
- package/dist/core/activity/transactionActivityDetails.js +229 -0
- package/dist/core/activity/transactionActivityProtocolRules.js +218 -0
- package/dist/core/activity/transactionActivityScanPolicy.js +170 -0
- package/dist/core/activity/transactionActivityService.js +379 -0
- package/dist/core/activity/transactionActivityTypes.js +18 -0
- package/dist/core/eventlog/sink.js +35 -0
- package/dist/core/evidence/settlementFamilies.js +87 -0
- package/dist/core/evidence/userAnswerUse.js +1 -0
- package/dist/core/numeric/rawU64.js +63 -0
- package/dist/core/preferences/preferencesStore.js +26 -0
- package/dist/core/preferences/sqlitePreferencesRepository.js +136 -0
- package/dist/core/proposal/externalProposalReview.js +347 -0
- package/dist/core/proposal/schemas.js +208 -0
- package/dist/core/proposal/types.js +35 -0
- package/dist/core/read/amounts.js +14 -0
- package/dist/core/read/coinMetadata.js +60 -0
- package/dist/core/read/deepbookRawQuoteClient.js +86 -0
- package/dist/core/read/deepbookReadHelpers.js +265 -0
- package/dist/core/read/deepbookRegistry.js +133 -0
- package/dist/core/read/flowxQuoteClient.js +117 -0
- package/dist/core/read/flowxReadHelpers.js +145 -0
- package/dist/core/read/flowxRegistry.js +174 -0
- package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
- package/dist/core/read/readResponseGuidance.js +451 -0
- package/dist/core/read/readService.js +1164 -0
- package/dist/core/read/readServiceTypes.js +59 -0
- package/dist/core/read/settlementParityFormatting.js +82 -0
- package/dist/core/read/walletReadHelpers.js +99 -0
- package/dist/core/review/reviewChecks.js +54 -0
- package/dist/core/review/reviewComputation.js +38 -0
- package/dist/core/review/reviewComputationResult.js +87 -0
- package/dist/core/session/localSession.js +31 -0
- package/dist/core/session/privateReviewArtifacts.js +73 -0
- package/dist/core/session/sessionErrors.js +9 -0
- package/dist/core/session/sessionStore.js +821 -0
- package/dist/core/session/settingsSession.js +1 -0
- package/dist/core/session/settingsSessions.js +43 -0
- package/dist/core/session/status.js +86 -0
- package/dist/core/session/transactionMaterialStore.js +205 -0
- package/dist/core/session/wait.js +102 -0
- package/dist/core/session/walletIdentity.js +103 -0
- package/dist/core/session/walletIdentitySessions.js +189 -0
- package/dist/core/suiAddress.js +18 -0
- package/dist/core/suiEndpoint.js +72 -0
- package/dist/mcp/activeAccountResponse.js +24 -0
- package/dist/mcp/prompts.js +146 -0
- package/dist/mcp/registerTool.js +19 -0
- package/dist/mcp/resources.js +72 -0
- package/dist/mcp/responseGuidance.js +381 -0
- package/dist/mcp/result.js +17 -0
- package/dist/mcp/schemas.js +8 -0
- package/dist/mcp/server.js +30 -0
- package/dist/mcp/serverInfo.js +123 -0
- package/dist/mcp/toolErrors.js +105 -0
- package/dist/mcp/toolNames.js +50 -0
- package/dist/mcp/tools/account/index.js +44 -0
- package/dist/mcp/tools/action/prepareSuiActionReview.js +120 -0
- package/dist/mcp/tools/read/commonSchemas.js +43 -0
- package/dist/mcp/tools/read/deepbookReadTools.js +453 -0
- package/dist/mcp/tools/read/flowxReadTools.js +135 -0
- package/dist/mcp/tools/read/index.js +16 -0
- package/dist/mcp/tools/read/readToolHelpers.js +68 -0
- package/dist/mcp/tools/read/reviewActivityTools.js +176 -0
- package/dist/mcp/tools/read/serverStatusTools.js +103 -0
- package/dist/mcp/tools/read/transactionActivityOutput.js +300 -0
- package/dist/mcp/tools/read/transactionActivityTools.js +544 -0
- package/dist/mcp/tools/read/walletReadTools.js +733 -0
- package/dist/mcp/tools/session/executionResultTools.js +92 -0
- package/dist/mcp/tools/session/index.js +8 -0
- package/dist/mcp/tools/session/shared.js +79 -0
- package/dist/mcp/tools/session/statusTools.js +134 -0
- package/dist/mcp/tools/session/walletIdentityTools.js +119 -0
- package/dist/mcp/tools/settings/index.js +64 -0
- package/dist/review-app/analysis.css +1 -0
- package/dist/review-app/analysis.js +1 -0
- package/dist/review-app/arc-BjIacwQm.js +1 -0
- package/dist/review-app/architecture-U656AL7Q-aSB9x1OK.js +1 -0
- package/dist/review-app/architectureDiagram-VXUJARFQ-C5W6re2I.js +36 -0
- package/dist/review-app/array-BmXUUrU6.js +1 -0
- package/dist/review-app/blockDiagram-VD42YOAC-20MLNcUm.js +122 -0
- package/dist/review-app/c4Diagram-YG6GDRKO-BZXRrcck.js +10 -0
- package/dist/review-app/channel-lk2p_CUu.js +1 -0
- package/dist/review-app/chunk-4BX2VUAB-BPITOdjX.js +1 -0
- package/dist/review-app/chunk-55IACEB6-Dz-pyw5k.js +1 -0
- package/dist/review-app/chunk-76Q3JFCE-cK_X1P_l.js +1 -0
- package/dist/review-app/chunk-ABZYJK2D-Dt4W53JI.js +81 -0
- package/dist/review-app/chunk-ATLVNIR6-fZHLXURb.js +1 -0
- package/dist/review-app/chunk-B4BG7PRW-BbgcjusC.js +165 -0
- package/dist/review-app/chunk-BJD4TVEz.js +1 -0
- package/dist/review-app/chunk-CVBHYZKI-CViawAKX.js +1 -0
- package/dist/review-app/chunk-DI55MBZ5-C5aoul-d.js +220 -0
- package/dist/review-app/chunk-FMBD7UC4-Chxmw62A.js +15 -0
- package/dist/review-app/chunk-FPAJGGOC-DDHjQ09H.js +80 -0
- package/dist/review-app/chunk-FWNWRKHM-CVVQUptk.js +1 -0
- package/dist/review-app/chunk-HN2XXSSU-yzNpjaSZ.js +1 -0
- package/dist/review-app/chunk-JA3XYJ7Z-C5ZJdU01.js +70 -0
- package/dist/review-app/chunk-JZLCHNYA-BBST4Cnk.js +54 -0
- package/dist/review-app/chunk-LBM3YZW2-CdwAPuHr.js +1 -0
- package/dist/review-app/chunk-LHMN2FUI-BtB5uDcp.js +1 -0
- package/dist/review-app/chunk-O7ZBX7Z2-pxdK4Sa3.js +1 -0
- package/dist/review-app/chunk-QN33PNHL-CbVv3uGK.js +1 -0
- package/dist/review-app/chunk-QXUST7PY-DKM2-t2c.js +7 -0
- package/dist/review-app/chunk-QZHKN3VN-C5ni2pN_.js +1 -0
- package/dist/review-app/chunk-S3R3BYOJ-BWvOhDs0.js +2 -0
- package/dist/review-app/chunk-S6J4BHB3-D9Fk0YeD.js +1 -0
- package/dist/review-app/chunk-T53DSG4Q-C1qEyzyV.js +1 -0
- package/dist/review-app/chunk-TZMSLE5B-B--7eU69.js +1 -0
- package/dist/review-app/classDiagram-2ON5EDUG-DlL1m2bp.js +1 -0
- package/dist/review-app/classDiagram-v2-WZHVMYZB-FXRskT1j.js +1 -0
- package/dist/review-app/clone-BZZb7gpZ.js +1 -0
- package/dist/review-app/cose-bilkent-S5V4N54A-CRIb8XEO.js +1 -0
- package/dist/review-app/cytoscape.esm-C7jYqDP5.js +321 -0
- package/dist/review-app/dagre-6UL2VRFP-FNCAXbdE.js +4 -0
- package/dist/review-app/dagre-Be46QtUd.js +1 -0
- package/dist/review-app/defaultLocale-BaWNtAUL.js +1 -0
- package/dist/review-app/diagram-PSM6KHXK-ylLWjiNM.js +24 -0
- package/dist/review-app/diagram-QEK2KX5R-BCDcESxs.js +43 -0
- package/dist/review-app/diagram-S2PKOQOG-Vdrc-vrO.js +24 -0
- package/dist/review-app/dist-WPc74x_f.js +1 -0
- package/dist/review-app/erDiagram-Q2GNP2WA-E5ZsUbDF.js +60 -0
- package/dist/review-app/flatten-DHf9IeNI.js +1 -0
- package/dist/review-app/flowDiagram-NV44I4VS-DBSQuj6x.js +162 -0
- package/dist/review-app/ganttDiagram-LVOFAZNH-CKUOsqwl.js +267 -0
- package/dist/review-app/gitGraph-F6HP7TQM-DsAD6qK1.js +1 -0
- package/dist/review-app/gitGraphDiagram-NY62KEGX-BCeIMWdl.js +65 -0
- package/dist/review-app/graphlib-CiX5CXxR.js +1 -0
- package/dist/review-app/http-DMvwuuFk.js +1 -0
- package/dist/review-app/identity-DY8PXc6t.js +1 -0
- package/dist/review-app/info-NVLQJR56-Dlx1nZic.js +1 -0
- package/dist/review-app/infoDiagram-F6ZHWCRC-CAuANIrz.js +2 -0
- package/dist/review-app/init-BvqephKz.js +1 -0
- package/dist/review-app/journeyDiagram-XKPGCS4Q-C-Z9phnx.js +139 -0
- package/dist/review-app/kanban-definition-3W4ZIXB7-DufgZABq.js +89 -0
- package/dist/review-app/katex-B-Z-NXXN.js +257 -0
- package/dist/review-app/line-DiIv3Jgw.js +1 -0
- package/dist/review-app/linear-Cv-UPvo1.js +1 -0
- package/dist/review-app/math-kmyYrkHL.js +1 -0
- package/dist/review-app/mermaid-parser.core-DkwUYTPl.js +4 -0
- package/dist/review-app/mindmap-definition-VGOIOE7T-TM_CqdmV.js +68 -0
- package/dist/review-app/ordinal-BliTlkoG.js +1 -0
- package/dist/review-app/packet-BFZMPI3H-DqbnU92v.js +1 -0
- package/dist/review-app/path-AEo9W6mQ.js +1 -0
- package/dist/review-app/pie-7BOR55EZ-LJzaLkgr.js +1 -0
- package/dist/review-app/pieDiagram-ADFJNKIX-BAs8OfRS.js +30 -0
- package/dist/review-app/quadrantDiagram-AYHSOK5B-CyUDZP5S.js +7 -0
- package/dist/review-app/radar-NHE76QYJ-DBpHc8_Y.js +1 -0
- package/dist/review-app/reduce-B-HuPpdd.js +1 -0
- package/dist/review-app/requirementDiagram-UZGBJVZJ-BEHix78P.js +64 -0
- package/dist/review-app/review.css +1 -0
- package/dist/review-app/review.js +43 -0
- package/dist/review-app/sankeyDiagram-TZEHDZUN-B2bKbmsm.js +10 -0
- package/dist/review-app/sequenceDiagram-WL72ISMW-DVLOORFJ.js +145 -0
- package/dist/review-app/settings.css +1 -0
- package/dist/review-app/settings.js +1 -0
- package/dist/review-app/src-Buml7cM5.js +1 -0
- package/dist/review-app/stateDiagram-FKZM4ZOC-sFGGp2kV.js +1 -0
- package/dist/review-app/stateDiagram-v2-4FDKWEC3-BHfCF4dX.js +1 -0
- package/dist/review-app/timeline-definition-IT6M3QCI-BESnBijC.js +61 -0
- package/dist/review-app/treemap-KMMF4GRG-wnVLBDeQ.js +1 -0
- package/dist/review-app/walletStatus-CcojOdGy.js +7 -0
- package/dist/review-app/xychartDiagram-PRI3JC2R-BGWVfCx4.js +7 -0
- package/dist/review-server/assets.js +48 -0
- package/dist/review-server/html.js +66 -0
- package/dist/review-server/http.js +47 -0
- package/dist/review-server/middleware/hostOrigin.js +48 -0
- package/dist/review-server/middleware/reviewToken.js +7 -0
- package/dist/review-server/reviewServerPolicy.js +10 -0
- package/dist/review-server/server.js +568 -0
- package/dist/review-server/settingsApi.js +182 -0
- package/dist/review-server/walletIdentityResponse.js +13 -0
- package/dist/runtime/config.js +103 -0
- package/dist/runtime/localSettingsService.js +198 -0
- package/dist/runtime/logger.js +50 -0
- package/dist/runtime/reviewServerAcquire.js +128 -0
- package/dist/runtime/smokeMainnetRead.js +529 -0
- package/dist/runtime/smokeMainnetReadAssertions.js +308 -0
- package/dist/runtime/start.js +295 -0
- package/dist/runtime/suiEndpoint.js +97 -0
- package/dist/runtime/suiTransactionGraphqlMapping.js +200 -0
- package/dist/runtime/suiTransactionGraphqlQueries.js +231 -0
- package/dist/runtime/suiTransactionGraphqlSource.js +148 -0
- package/docs/AGENT_BEHAVIOR.md +1 -1
- package/docs/AGENT_DEVELOPMENT_POLICY.md +20 -0
- package/docs/FRONTEND_POLICY.md +4 -3
- package/docs/MCP_SETUP.md +59 -7
- package/docs/MCP_TOOLS.md +1 -1
- package/docs/SDK_API.md +5 -1
- package/package.json +3 -2
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { FAILURE_REASONS } from "../core/action/types.js";
|
|
3
|
+
import { computeReviewStateWithPrivateArtifacts } from "../core/review/reviewComputation.js";
|
|
4
|
+
import { SessionStoreError } from "../core/session/sessionStore.js";
|
|
5
|
+
import { getExecutionPollingStatus } from "../core/session/status.js";
|
|
6
|
+
import { walletIdentityResultInputSchema, walletIdentityPollingHint } from "../core/session/walletIdentity.js";
|
|
7
|
+
import { parseSuiAddress } from "../core/suiAddress.js";
|
|
8
|
+
import { validateHostOrigin } from "./middleware/hostOrigin.js";
|
|
9
|
+
import { readReviewToken } from "./middleware/reviewToken.js";
|
|
10
|
+
import { defaultReviewAssetsDir, serveReviewAsset } from "./assets.js";
|
|
11
|
+
import { analysisHtml, reviewHtml, settingsHtml } from "./html.js";
|
|
12
|
+
import { HttpError, readJsonBody, sendHtml, sendJson } from "./http.js";
|
|
13
|
+
import { ALLOWED_HOSTNAMES, SUI_BROWSER_EXECUTION_ORIGIN } from "./reviewServerPolicy.js";
|
|
14
|
+
import { routeSettingsApi } from "./settingsApi.js";
|
|
15
|
+
import { walletIdentitySessionResponse } from "./walletIdentityResponse.js";
|
|
16
|
+
const REVIEW_WALLET_IDENTITY_STATUSES = new Set([
|
|
17
|
+
"awaiting_wallet",
|
|
18
|
+
"wallet_connected",
|
|
19
|
+
"ready_for_wallet_review",
|
|
20
|
+
"refresh_required",
|
|
21
|
+
"blocked"
|
|
22
|
+
]);
|
|
23
|
+
export function createReviewHttpServer(options) {
|
|
24
|
+
const server = createServer(async (request, response) => {
|
|
25
|
+
try {
|
|
26
|
+
await routeRequest(request, response, options);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error instanceof HttpError) {
|
|
30
|
+
sendJson(response, error.status, { error: error.code });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
options.logger.error("review server request failed", {
|
|
34
|
+
error: error instanceof Error ? error.message : String(error)
|
|
35
|
+
});
|
|
36
|
+
sendJson(response, 500, { error: "internal_error" });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
start(port) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
server.once("error", reject);
|
|
43
|
+
server.listen(port, options.host, () => {
|
|
44
|
+
const address = server.address();
|
|
45
|
+
resolve({
|
|
46
|
+
host: options.host,
|
|
47
|
+
port: address.port,
|
|
48
|
+
close: () => new Promise((closeResolve, closeReject) => {
|
|
49
|
+
server.close((error) => (error ? closeReject(error) : closeResolve()));
|
|
50
|
+
})
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function requireWalletIdentityToken(store, sessionId, request, response) {
|
|
58
|
+
const token = readReviewToken(request.headers);
|
|
59
|
+
if (!token || !(await store.validateWalletIdentityToken(sessionId, token))) {
|
|
60
|
+
sendJson(response, 401, { error: "invalid_wallet_token" });
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return token;
|
|
64
|
+
}
|
|
65
|
+
async function requireReviewSessionToken(store, sessionId, request, response) {
|
|
66
|
+
const token = readReviewToken(request.headers);
|
|
67
|
+
if (!token || !(await store.validateReviewToken(sessionId, token))) {
|
|
68
|
+
sendJson(response, 401, { error: "invalid_review_token" });
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return token;
|
|
72
|
+
}
|
|
73
|
+
async function routeRequest(request, response, options) {
|
|
74
|
+
// Structural guard: every request to this server passes the Host/Origin
|
|
75
|
+
// policy once, so a new route cannot accidentally skip it.
|
|
76
|
+
const hostOrigin = validateHostOrigin(request, { allowedHostnames: ALLOWED_HOSTNAMES });
|
|
77
|
+
if (!hostOrigin.ok) {
|
|
78
|
+
sendJson(response, hostOrigin.status, { error: hostOrigin.reason });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const url = new URL(request.url ?? "/", "http://localhost");
|
|
82
|
+
// Loopback identity probe used by a newer instance to confirm this port is
|
|
83
|
+
// held by our own review server before taking it over. It exposes only the
|
|
84
|
+
// service name, role, version, and pid — no addresses, tokens, or session
|
|
85
|
+
// data — and is reachable only on the loopback host this server binds.
|
|
86
|
+
if (request.method === "GET" && url.pathname === "/__identity") {
|
|
87
|
+
sendJson(response, 200, {
|
|
88
|
+
service: options.serverInfo?.name ?? "say-ur-intent",
|
|
89
|
+
role: "review-server",
|
|
90
|
+
version: options.serverInfo?.version,
|
|
91
|
+
pid: process.pid
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const reviewMatch = /^\/review\/([^/]+)$/.exec(url.pathname);
|
|
96
|
+
const apiReviewMatch = /^\/api\/review\/([^/]+)$/.exec(url.pathname);
|
|
97
|
+
const apiReviewWalletIdentityMatch = /^\/api\/review\/([^/]+)\/wallet-identity$/.exec(url.pathname);
|
|
98
|
+
const apiReviewOpenedMatch = /^\/api\/review\/([^/]+)\/opened$/.exec(url.pathname);
|
|
99
|
+
const apiReviewStateMatch = /^\/api\/review\/([^/]+)\/state$/.exec(url.pathname);
|
|
100
|
+
const apiReviewResultMatch = /^\/api\/review\/([^/]+)\/result$/.exec(url.pathname);
|
|
101
|
+
const apiResultMatch = /^\/api\/result\/([^/]+)$/.exec(url.pathname);
|
|
102
|
+
const walletMatch = /^\/analysis\/([^/]+)$/.exec(url.pathname);
|
|
103
|
+
const apiReviewHandoffMatch = /^\/api\/review\/([^/]+)\/handoff$/.exec(url.pathname);
|
|
104
|
+
const apiReviewHandoffCancelMatch = /^\/api\/review\/([^/]+)\/handoff\/cancel$/.exec(url.pathname);
|
|
105
|
+
const analysisAssetsMatch = /^\/api\/analysis\/([^/]+)\/assets$/.exec(url.pathname);
|
|
106
|
+
const analysisActivityMatch = /^\/api\/analysis\/([^/]+)\/review-activity$/.exec(url.pathname);
|
|
107
|
+
const apiWalletOpenedMatch = /^\/api\/wallet\/([^/]+)\/opened$/.exec(url.pathname);
|
|
108
|
+
const apiWalletConnectingMatch = /^\/api\/wallet\/([^/]+)\/connecting$/.exec(url.pathname);
|
|
109
|
+
const apiWalletResultMatch = /^\/api\/wallet\/([^/]+)\/result$/.exec(url.pathname);
|
|
110
|
+
const settingsMatch = /^\/settings\/([^/]+)$/.exec(url.pathname);
|
|
111
|
+
const apiSettingsMatch = /^\/api\/settings\/([^/]+)$/.exec(url.pathname);
|
|
112
|
+
const apiSettingsWalletIdentityMatch = /^\/api\/settings\/([^/]+)\/wallet-identity$/.exec(url.pathname);
|
|
113
|
+
const apiSettingsClearActiveAccountMatch = /^\/api\/settings\/([^/]+)\/clear-active-account$/.exec(url.pathname);
|
|
114
|
+
const apiSettingsSuiGrpcUrlMatch = /^\/api\/settings\/([^/]+)\/sui-grpc-url$/.exec(url.pathname);
|
|
115
|
+
const apiSettingsSuiGrpcUrlDefaultMatch = /^\/api\/settings\/([^/]+)\/sui-grpc-url\/restore-default$/.exec(url.pathname);
|
|
116
|
+
const apiSettingsSuiGraphqlUrlMatch = /^\/api\/settings\/([^/]+)\/sui-graphql-url$/.exec(url.pathname);
|
|
117
|
+
const apiSettingsSuiGraphqlUrlDefaultMatch = /^\/api\/settings\/([^/]+)\/sui-graphql-url\/restore-default$/.exec(url.pathname);
|
|
118
|
+
const apiSettingsLocalDataExportMatch = /^\/api\/settings\/([^/]+)\/local-data\/export$/.exec(url.pathname);
|
|
119
|
+
const apiSettingsLocalDataPreviewMatch = /^\/api\/settings\/([^/]+)\/local-data\/import\/preview$/.exec(url.pathname);
|
|
120
|
+
const apiSettingsLocalDataImportMatch = /^\/api\/settings\/([^/]+)\/local-data\/import$/.exec(url.pathname);
|
|
121
|
+
const apiSettingsLocalDataResetMatch = /^\/api\/settings\/([^/]+)\/local-data\/reset$/.exec(url.pathname);
|
|
122
|
+
const reviewAssetMatch = /^\/review-assets\/(.+)$/.exec(url.pathname);
|
|
123
|
+
if (request.method === "GET" && reviewMatch?.[1]) {
|
|
124
|
+
sendHtml(response, reviewHtml(reviewMatch[1]), {
|
|
125
|
+
"content-security-policy": [
|
|
126
|
+
"default-src 'none'",
|
|
127
|
+
"base-uri 'none'",
|
|
128
|
+
// 'self' for review-server APIs; the Sui fullnode origin for the
|
|
129
|
+
// browser-side signed-transaction submission (see reviewServerPolicy).
|
|
130
|
+
`connect-src 'self' ${SUI_BROWSER_EXECUTION_ORIGIN}`,
|
|
131
|
+
"script-src 'self'",
|
|
132
|
+
// Inline styles are allowed for mermaid's SVG styling; scripts stay 'self'-only.
|
|
133
|
+
"style-src 'self' 'unsafe-inline'",
|
|
134
|
+
"img-src 'self' data:",
|
|
135
|
+
"form-action 'none'"
|
|
136
|
+
].join("; ")
|
|
137
|
+
});
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (request.method === "GET" && walletMatch?.[1]) {
|
|
141
|
+
sendHtml(response, analysisHtml(walletMatch[1]), {
|
|
142
|
+
"content-security-policy": [
|
|
143
|
+
"default-src 'none'",
|
|
144
|
+
"base-uri 'none'",
|
|
145
|
+
// 'self' for review-server APIs; the Sui fullnode origin so the dapp-kit
|
|
146
|
+
// chain client can read mainnet state during wallet connect.
|
|
147
|
+
`connect-src 'self' ${SUI_BROWSER_EXECUTION_ORIGIN}`,
|
|
148
|
+
"script-src 'self'",
|
|
149
|
+
// Inline styles are allowed for mermaid's SVG styling; scripts stay 'self'-only.
|
|
150
|
+
"style-src 'self' 'unsafe-inline'",
|
|
151
|
+
"img-src 'self' data:",
|
|
152
|
+
"form-action 'none'"
|
|
153
|
+
].join("; ")
|
|
154
|
+
});
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (request.method === "POST" && apiReviewHandoffCancelMatch?.[1]) {
|
|
158
|
+
const sessionId = apiReviewHandoffCancelMatch[1];
|
|
159
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
160
|
+
if (!token) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
await options.store.cancelWalletHandoff(sessionId);
|
|
165
|
+
sendJson(response, 200, { cancelled: true });
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
if (error instanceof SessionStoreError) {
|
|
169
|
+
sendJson(response, statusForStoreError(error), { error: error.code });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (request.method === "POST" && apiReviewHandoffMatch?.[1]) {
|
|
177
|
+
const sessionId = apiReviewHandoffMatch[1];
|
|
178
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
179
|
+
if (!token) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const body = await readJsonBody(request);
|
|
183
|
+
const planId = typeof body.planId === "string" ? body.planId : "";
|
|
184
|
+
const account = typeof body.account === "string" ? body.account : "";
|
|
185
|
+
if (!planId || !account) {
|
|
186
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
const handoff = await options.store.prepareWalletHandoff(sessionId, planId, account);
|
|
191
|
+
sendJson(response, 200, handoff);
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (error instanceof SessionStoreError) {
|
|
195
|
+
sendJson(response, statusForStoreError(error), { error: error.code });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (request.method === "GET" && (analysisAssetsMatch?.[1] || analysisActivityMatch?.[1])) {
|
|
203
|
+
const sessionId = (analysisAssetsMatch?.[1] ?? analysisActivityMatch?.[1]);
|
|
204
|
+
const token = await requireWalletIdentityToken(options.store, sessionId, request, response);
|
|
205
|
+
if (!token) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const walletSession = await options.store.getWalletIdentitySession(sessionId);
|
|
209
|
+
const connectedAccount = walletSession && walletSession.status === "connected" ? walletSession.account : undefined;
|
|
210
|
+
const active = options.activityStore ? await options.activityStore.getActiveAccount() : undefined;
|
|
211
|
+
const account = connectedAccount ?? active?.address;
|
|
212
|
+
if (!account) {
|
|
213
|
+
sendJson(response, 409, { error: "no_active_account" });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (analysisAssetsMatch?.[1]) {
|
|
217
|
+
if (!options.readService) {
|
|
218
|
+
sendJson(response, 503, { error: "analysis_data_unavailable" });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
const summary = await options.readService.summarizeWalletAssets({ account });
|
|
223
|
+
sendJson(response, 200, summary);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
sendJson(response, 502, { error: "wallet_read_failed" });
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (!options.activityStore) {
|
|
231
|
+
sendJson(response, 503, { error: "analysis_data_unavailable" });
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
try {
|
|
235
|
+
const funnel = await options.activityStore.summarizeReviewFunnel({ account });
|
|
236
|
+
sendJson(response, 200, funnel);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
sendJson(response, 502, { error: "review_activity_read_failed" });
|
|
240
|
+
}
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (request.method === "GET" && settingsMatch?.[1]) {
|
|
244
|
+
if (url.searchParams.has("token")) {
|
|
245
|
+
sendJson(response, 400, { error: "token_query_not_supported" });
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
sendHtml(response, settingsHtml(settingsMatch[1]), {
|
|
249
|
+
"content-security-policy": [
|
|
250
|
+
"default-src 'none'",
|
|
251
|
+
"base-uri 'none'",
|
|
252
|
+
"connect-src 'self'",
|
|
253
|
+
"script-src 'self'",
|
|
254
|
+
// Inline styles are allowed for mermaid's SVG styling; scripts stay 'self'-only.
|
|
255
|
+
"style-src 'self' 'unsafe-inline'",
|
|
256
|
+
"img-src 'self' data:",
|
|
257
|
+
"form-action 'none'"
|
|
258
|
+
].join("; ")
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (request.method === "GET" && reviewAssetMatch?.[1]) {
|
|
263
|
+
await serveReviewAsset(response, options.reviewAssetsDir ?? defaultReviewAssetsDir(), reviewAssetMatch[1]);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (apiSettingsMatch?.[1] ||
|
|
267
|
+
apiSettingsWalletIdentityMatch?.[1] ||
|
|
268
|
+
apiSettingsClearActiveAccountMatch?.[1] ||
|
|
269
|
+
apiSettingsSuiGrpcUrlMatch?.[1] ||
|
|
270
|
+
apiSettingsSuiGrpcUrlDefaultMatch?.[1] ||
|
|
271
|
+
apiSettingsSuiGraphqlUrlMatch?.[1] ||
|
|
272
|
+
apiSettingsSuiGraphqlUrlDefaultMatch?.[1] ||
|
|
273
|
+
apiSettingsLocalDataExportMatch?.[1] ||
|
|
274
|
+
apiSettingsLocalDataPreviewMatch?.[1] ||
|
|
275
|
+
apiSettingsLocalDataImportMatch?.[1] ||
|
|
276
|
+
apiSettingsLocalDataResetMatch?.[1]) {
|
|
277
|
+
await routeSettingsApi(request, response, options, url, {
|
|
278
|
+
status: apiSettingsMatch?.[1],
|
|
279
|
+
walletIdentity: apiSettingsWalletIdentityMatch?.[1],
|
|
280
|
+
clearActiveAccount: apiSettingsClearActiveAccountMatch?.[1],
|
|
281
|
+
setSuiGrpcUrl: apiSettingsSuiGrpcUrlMatch?.[1],
|
|
282
|
+
restoreDefaultSuiGrpcUrl: apiSettingsSuiGrpcUrlDefaultMatch?.[1],
|
|
283
|
+
setSuiGraphqlUrl: apiSettingsSuiGraphqlUrlMatch?.[1],
|
|
284
|
+
restoreDefaultSuiGraphqlUrl: apiSettingsSuiGraphqlUrlDefaultMatch?.[1],
|
|
285
|
+
exportLocalData: apiSettingsLocalDataExportMatch?.[1],
|
|
286
|
+
previewImport: apiSettingsLocalDataPreviewMatch?.[1],
|
|
287
|
+
importLocalData: apiSettingsLocalDataImportMatch?.[1],
|
|
288
|
+
resetLocalData: apiSettingsLocalDataResetMatch?.[1]
|
|
289
|
+
});
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
if (request.method === "GET" && apiReviewMatch?.[1]) {
|
|
293
|
+
const sessionId = apiReviewMatch[1];
|
|
294
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
295
|
+
if (!token) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const session = await options.store.getReviewSession(sessionId);
|
|
299
|
+
if (!session) {
|
|
300
|
+
sendJson(response, 404, { error: "session_not_found" });
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
const activeAccount = options.activityStore ? await options.activityStore.getActiveAccount() : undefined;
|
|
304
|
+
sendJson(response, 200, {
|
|
305
|
+
reviewSessionId: session.id,
|
|
306
|
+
internalStatus: session.status,
|
|
307
|
+
pollingStatus: getExecutionPollingStatus(session),
|
|
308
|
+
lastActivityAt: session.lastActivityAt,
|
|
309
|
+
...(session.executionResult ? { executionResult: session.executionResult } : {}),
|
|
310
|
+
signingInProgress: session.pendingHandoffDigest !== undefined,
|
|
311
|
+
activeAccount: activeAccount
|
|
312
|
+
? {
|
|
313
|
+
account: activeAccount.address,
|
|
314
|
+
source: activeAccount.source,
|
|
315
|
+
setAt: activeAccount.setAt,
|
|
316
|
+
...(activeAccount.walletName ? { walletName: activeAccount.walletName } : {}),
|
|
317
|
+
...(activeAccount.walletId ? { walletId: activeAccount.walletId } : {})
|
|
318
|
+
}
|
|
319
|
+
: undefined,
|
|
320
|
+
reviewState: session.reviewState,
|
|
321
|
+
plans: session.plans
|
|
322
|
+
});
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (request.method === "POST" && apiReviewWalletIdentityMatch?.[1]) {
|
|
326
|
+
const sessionId = apiReviewWalletIdentityMatch[1];
|
|
327
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
328
|
+
if (!token) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
await readJsonBody(request);
|
|
332
|
+
const session = await options.store.getReviewSession(sessionId);
|
|
333
|
+
if (!session) {
|
|
334
|
+
sendJson(response, 404, { error: "session_not_found" });
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (session.status === "expired") {
|
|
338
|
+
sendJson(response, 410, { error: "session_expired" });
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (!REVIEW_WALLET_IDENTITY_STATUSES.has(session.status)) {
|
|
342
|
+
sendJson(response, 409, { error: "invalid_session_transition" });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const wallet = await options.store.createWalletIdentitySession();
|
|
346
|
+
sendJson(response, 200, walletIdentitySessionResponse(wallet, requestBaseUrl(request)));
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (request.method === "POST" &&
|
|
350
|
+
(apiWalletOpenedMatch?.[1] || apiWalletConnectingMatch?.[1] || apiWalletResultMatch?.[1])) {
|
|
351
|
+
const sessionId = apiWalletOpenedMatch?.[1] ?? apiWalletConnectingMatch?.[1] ?? apiWalletResultMatch?.[1];
|
|
352
|
+
if (!sessionId) {
|
|
353
|
+
throw new HttpError(404, "not_found");
|
|
354
|
+
}
|
|
355
|
+
const token = await requireWalletIdentityToken(options.store, sessionId, request, response);
|
|
356
|
+
if (!token) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
let session;
|
|
360
|
+
if (apiWalletOpenedMatch?.[1]) {
|
|
361
|
+
session = await mapStoreError(() => options.store.recordWalletIdentityOpened(sessionId));
|
|
362
|
+
}
|
|
363
|
+
else if (apiWalletConnectingMatch?.[1]) {
|
|
364
|
+
session = await mapStoreError(() => options.store.recordWalletIdentityConnecting(sessionId));
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
const body = await readJsonBody(request);
|
|
368
|
+
const parsed = walletIdentityResultInputSchema.safeParse(body);
|
|
369
|
+
if (!parsed.success) {
|
|
370
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
session = await mapStoreError(() => options.store.recordWalletIdentityResult(sessionId, parsed.data));
|
|
374
|
+
}
|
|
375
|
+
sendJson(response, 200, publicWalletIdentitySession(session));
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (request.method === "POST" && apiReviewOpenedMatch?.[1]) {
|
|
379
|
+
const sessionId = apiReviewOpenedMatch[1];
|
|
380
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
381
|
+
if (!token) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const session = await mapStoreError(() => options.store.recordReviewPageOpened(sessionId));
|
|
385
|
+
sendJson(response, 200, {
|
|
386
|
+
reviewSessionId: session.id,
|
|
387
|
+
internalStatus: session.status,
|
|
388
|
+
pollingStatus: getExecutionPollingStatus(session),
|
|
389
|
+
lastActivityAt: session.lastActivityAt
|
|
390
|
+
});
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (request.method === "POST" && apiReviewStateMatch?.[1]) {
|
|
394
|
+
const sessionId = apiReviewStateMatch[1];
|
|
395
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
396
|
+
if (!token) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const body = await readJsonBody(request);
|
|
400
|
+
const account = typeof body.account === "string" ? body.account : undefined;
|
|
401
|
+
const planId = typeof body.planId === "string" ? body.planId : undefined;
|
|
402
|
+
if (!account || !planId) {
|
|
403
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
const normalizedAccount = parseSuiAddress(account);
|
|
407
|
+
if (!normalizedAccount) {
|
|
408
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const session = await options.store.getReviewSession(sessionId);
|
|
412
|
+
if (!session) {
|
|
413
|
+
sendJson(response, 404, { error: "session_not_found" });
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const plan = session.plans.find((candidate) => candidate.id === planId);
|
|
417
|
+
if (!plan) {
|
|
418
|
+
sendJson(response, 400, { error: "plan_not_in_session" });
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
await mapStoreError(() => options.store.recordWalletConnected(sessionId, normalizedAccount));
|
|
422
|
+
const computed = await computeReviewStateWithPrivateArtifacts({
|
|
423
|
+
reviewSessionId: sessionId,
|
|
424
|
+
plan,
|
|
425
|
+
account: normalizedAccount
|
|
426
|
+
}, options.reviewComputationDeps);
|
|
427
|
+
const updatedSession = await mapStoreError(() => options.store.recordReviewStateWithArtifacts(sessionId, computed.state, computed.privateArtifacts));
|
|
428
|
+
sendJson(response, 200, { reviewState: updatedSession.reviewState });
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (request.method === "POST" && apiReviewResultMatch?.[1]) {
|
|
432
|
+
const sessionId = apiReviewResultMatch[1];
|
|
433
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
434
|
+
if (!token) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const body = await readJsonBody(request);
|
|
438
|
+
const planId = typeof body.planId === "string" ? body.planId : undefined;
|
|
439
|
+
const status = body.status === "signed_pending_result" ||
|
|
440
|
+
body.status === "success" ||
|
|
441
|
+
body.status === "failure"
|
|
442
|
+
? body.status
|
|
443
|
+
: undefined;
|
|
444
|
+
if (!planId || !status) {
|
|
445
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const failureReason = typeof body.failureReason === "string" ? body.failureReason : undefined;
|
|
449
|
+
const txDigest = typeof body.txDigest === "string" ? body.txDigest : undefined;
|
|
450
|
+
const resultBase = {
|
|
451
|
+
reviewSessionId: sessionId,
|
|
452
|
+
planId,
|
|
453
|
+
recordedAt: new Date().toISOString()
|
|
454
|
+
};
|
|
455
|
+
let result;
|
|
456
|
+
if (status === "failure") {
|
|
457
|
+
if (!isFailureReason(failureReason)) {
|
|
458
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
result = { ...resultBase, status, failureReason };
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
if (failureReason !== undefined) {
|
|
465
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (!txDigest) {
|
|
469
|
+
sendJson(response, 400, { error: "input_invalid" });
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
result = { ...resultBase, status, txDigest };
|
|
473
|
+
}
|
|
474
|
+
if (status === "failure" && txDigest) {
|
|
475
|
+
result.txDigest = txDigest;
|
|
476
|
+
}
|
|
477
|
+
const updatedSession = await mapStoreError(() => options.store.recordExecutionResult(sessionId, result));
|
|
478
|
+
sendJson(response, 200, { executionResult: updatedSession.executionResult });
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (request.method === "GET" && apiResultMatch?.[1]) {
|
|
482
|
+
const sessionId = apiResultMatch[1];
|
|
483
|
+
const token = await requireReviewSessionToken(options.store, sessionId, request, response);
|
|
484
|
+
if (!token) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const session = await options.store.getReviewSession(sessionId);
|
|
488
|
+
if (!session) {
|
|
489
|
+
sendJson(response, 404, { error: "session_not_found" });
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
sendJson(response, 200, {
|
|
493
|
+
reviewSessionId: session.id,
|
|
494
|
+
status: getExecutionPollingStatus(session),
|
|
495
|
+
lastActivityAt: session.lastActivityAt,
|
|
496
|
+
executionResult: session.executionResult
|
|
497
|
+
});
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
sendJson(response, 404, { error: "not_found" });
|
|
501
|
+
}
|
|
502
|
+
async function mapStoreError(operation) {
|
|
503
|
+
try {
|
|
504
|
+
return await operation();
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
if (error instanceof SessionStoreError) {
|
|
508
|
+
throw new HttpError(statusForStoreError(error), error.code);
|
|
509
|
+
}
|
|
510
|
+
throw error;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function statusForStoreError(error) {
|
|
514
|
+
switch (error.code) {
|
|
515
|
+
case "active_account_not_set":
|
|
516
|
+
return 409;
|
|
517
|
+
case "input_invalid":
|
|
518
|
+
return 400;
|
|
519
|
+
case "invalid_session_transition":
|
|
520
|
+
case "execution_result_finalized":
|
|
521
|
+
case "signed_pending_result_conflict":
|
|
522
|
+
return 409;
|
|
523
|
+
case "plan_not_in_session":
|
|
524
|
+
case "session_mismatch":
|
|
525
|
+
return 400;
|
|
526
|
+
case "handoff_unavailable":
|
|
527
|
+
case "handoff_commitment_mismatch":
|
|
528
|
+
return 409;
|
|
529
|
+
case "session_expired":
|
|
530
|
+
return 410;
|
|
531
|
+
case "session_not_found":
|
|
532
|
+
return 404;
|
|
533
|
+
default:
|
|
534
|
+
return assertNever(error.code);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function assertNever(value) {
|
|
538
|
+
throw new Error(`Unhandled store error code: ${String(value)}`);
|
|
539
|
+
}
|
|
540
|
+
function isFailureReason(value) {
|
|
541
|
+
return value !== undefined && FAILURE_REASONS.includes(value);
|
|
542
|
+
}
|
|
543
|
+
function requestBaseUrl(request) {
|
|
544
|
+
const host = request.headers.host;
|
|
545
|
+
if (!host) {
|
|
546
|
+
throw new HttpError(400, "host_required");
|
|
547
|
+
}
|
|
548
|
+
return `http://${host}`;
|
|
549
|
+
}
|
|
550
|
+
function publicWalletIdentitySession(session) {
|
|
551
|
+
return {
|
|
552
|
+
walletSessionId: session.id,
|
|
553
|
+
status: session.status,
|
|
554
|
+
account: session.status === "connected" ? session.account : undefined,
|
|
555
|
+
chain: session.status === "connected" ? session.chain : undefined,
|
|
556
|
+
walletName: session.status === "connected" || session.status === "rejected" || session.status === "failed"
|
|
557
|
+
? session.walletName
|
|
558
|
+
: undefined,
|
|
559
|
+
walletId: session.status === "connected" || session.status === "rejected" || session.status === "failed"
|
|
560
|
+
? session.walletId
|
|
561
|
+
: undefined,
|
|
562
|
+
failureReason: session.status === "rejected" || session.status === "failed" ? session.failureReason : undefined,
|
|
563
|
+
failureDetail: session.status === "rejected" || session.status === "failed" ? session.failureDetail : undefined,
|
|
564
|
+
expiresAt: session.expiresAt,
|
|
565
|
+
lastActivityAt: session.lastActivityAt,
|
|
566
|
+
pollingHint: walletIdentityPollingHint()
|
|
567
|
+
};
|
|
568
|
+
}
|