@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.
Files changed (234) hide show
  1. package/README.md +4 -39
  2. package/dist/adapters/adapterLifecycleValidators.js +7 -0
  3. package/dist/adapters/adapterPromptSurfaces.js +71 -0
  4. package/dist/adapters/deepbook/deepbookHumanReviewProducer.js +175 -0
  5. package/dist/adapters/deepbook/deepbookQuotePolicy.js +112 -0
  6. package/dist/adapters/deepbook/deepbookReviewEvidence.js +507 -0
  7. package/dist/adapters/deepbook/deepbookReviewLifecycle.js +85 -0
  8. package/dist/adapters/deepbook/deepbookSwapIntent.js +79 -0
  9. package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +269 -0
  10. package/dist/adapters/flowx/flowxSwapHumanReviewProducer.js +176 -0
  11. package/dist/adapters/flowx/flowxSwapIntent.js +79 -0
  12. package/dist/adapters/flowx/flowxSwapQuotePolicy.js +104 -0
  13. package/dist/adapters/flowx/flowxSwapReviewEvidence.js +468 -0
  14. package/dist/adapters/flowx/flowxSwapReviewLifecycle.js +85 -0
  15. package/dist/adapters/flowx/flowxSwapTransactionMaterialProducer.js +362 -0
  16. package/dist/adapters/intentPlanFactories.js +59 -0
  17. package/dist/adapters/reviewAdapters.js +81 -0
  18. package/dist/core/action/adapterLifecycleValidation.js +12 -0
  19. package/dist/core/action/forbiddenFields.js +43 -0
  20. package/dist/core/action/humanReadableReviewEvidence.js +203 -0
  21. package/dist/core/action/humanReadableReviewProjectionVerifier.js +29 -0
  22. package/dist/core/action/ptbVisualizationProducer.js +66 -0
  23. package/dist/core/action/reviewCheckResults.js +6 -0
  24. package/dist/core/action/reviewStateValidation.js +11 -0
  25. package/dist/core/action/reviewTimeSimulationEvidence.js +471 -0
  26. package/dist/core/action/schemas.js +529 -0
  27. package/dist/core/action/signableAdapterContract.js +993 -0
  28. package/dist/core/action/swapHumanReadableReviewProjection.js +124 -0
  29. package/dist/core/action/swapQuotePolicyEvidence.js +278 -0
  30. package/dist/core/action/transactionObjectOwnershipEvidence.js +247 -0
  31. package/dist/core/action/transactionObjectOwnershipProducer.js +329 -0
  32. package/dist/core/action/types.js +35 -0
  33. package/dist/core/action/walletReviewContractAssembler.js +282 -0
  34. package/dist/core/activity/activityStore.js +15 -0
  35. package/dist/core/activity/localDataService.js +258 -0
  36. package/dist/core/activity/localDataTypes.js +11 -0
  37. package/dist/core/activity/localDataValidation.js +396 -0
  38. package/dist/core/activity/schemaVersion.js +1 -0
  39. package/dist/core/activity/sqliteActivityStore.js +820 -0
  40. package/dist/core/activity/sqliteActivityStoreRows.js +430 -0
  41. package/dist/core/activity/sqliteActivityStoreSchema.js +258 -0
  42. package/dist/core/activity/sqliteActivityStoreTypes.js +5 -0
  43. package/dist/core/activity/suiFunctionTarget.js +43 -0
  44. package/dist/core/activity/transactionActivityAccountEffects.js +189 -0
  45. package/dist/core/activity/transactionActivityAnalysis.js +295 -0
  46. package/dist/core/activity/transactionActivityClassifier.js +306 -0
  47. package/dist/core/activity/transactionActivityDetails.js +229 -0
  48. package/dist/core/activity/transactionActivityProtocolRules.js +218 -0
  49. package/dist/core/activity/transactionActivityScanPolicy.js +170 -0
  50. package/dist/core/activity/transactionActivityService.js +379 -0
  51. package/dist/core/activity/transactionActivityTypes.js +18 -0
  52. package/dist/core/eventlog/sink.js +35 -0
  53. package/dist/core/evidence/settlementFamilies.js +87 -0
  54. package/dist/core/evidence/userAnswerUse.js +1 -0
  55. package/dist/core/numeric/rawU64.js +63 -0
  56. package/dist/core/preferences/preferencesStore.js +26 -0
  57. package/dist/core/preferences/sqlitePreferencesRepository.js +136 -0
  58. package/dist/core/proposal/externalProposalReview.js +347 -0
  59. package/dist/core/proposal/schemas.js +208 -0
  60. package/dist/core/proposal/types.js +35 -0
  61. package/dist/core/read/amounts.js +14 -0
  62. package/dist/core/read/coinMetadata.js +60 -0
  63. package/dist/core/read/deepbookRawQuoteClient.js +86 -0
  64. package/dist/core/read/deepbookReadHelpers.js +265 -0
  65. package/dist/core/read/deepbookRegistry.js +133 -0
  66. package/dist/core/read/flowxQuoteClient.js +117 -0
  67. package/dist/core/read/flowxReadHelpers.js +145 -0
  68. package/dist/core/read/flowxRegistry.js +174 -0
  69. package/dist/core/read/intentEvidenceResponseFormatting.js +228 -0
  70. package/dist/core/read/readResponseGuidance.js +451 -0
  71. package/dist/core/read/readService.js +1164 -0
  72. package/dist/core/read/readServiceTypes.js +59 -0
  73. package/dist/core/read/settlementParityFormatting.js +82 -0
  74. package/dist/core/read/walletReadHelpers.js +99 -0
  75. package/dist/core/review/reviewChecks.js +54 -0
  76. package/dist/core/review/reviewComputation.js +38 -0
  77. package/dist/core/review/reviewComputationResult.js +87 -0
  78. package/dist/core/session/localSession.js +31 -0
  79. package/dist/core/session/privateReviewArtifacts.js +73 -0
  80. package/dist/core/session/sessionErrors.js +9 -0
  81. package/dist/core/session/sessionStore.js +821 -0
  82. package/dist/core/session/settingsSession.js +1 -0
  83. package/dist/core/session/settingsSessions.js +43 -0
  84. package/dist/core/session/status.js +86 -0
  85. package/dist/core/session/transactionMaterialStore.js +205 -0
  86. package/dist/core/session/wait.js +102 -0
  87. package/dist/core/session/walletIdentity.js +103 -0
  88. package/dist/core/session/walletIdentitySessions.js +189 -0
  89. package/dist/core/suiAddress.js +18 -0
  90. package/dist/core/suiEndpoint.js +72 -0
  91. package/dist/mcp/activeAccountResponse.js +24 -0
  92. package/dist/mcp/prompts.js +146 -0
  93. package/dist/mcp/registerTool.js +19 -0
  94. package/dist/mcp/resources.js +72 -0
  95. package/dist/mcp/responseGuidance.js +381 -0
  96. package/dist/mcp/result.js +17 -0
  97. package/dist/mcp/schemas.js +8 -0
  98. package/dist/mcp/server.js +30 -0
  99. package/dist/mcp/serverInfo.js +123 -0
  100. package/dist/mcp/toolErrors.js +105 -0
  101. package/dist/mcp/toolNames.js +50 -0
  102. package/dist/mcp/tools/account/index.js +44 -0
  103. package/dist/mcp/tools/action/prepareSuiActionReview.js +120 -0
  104. package/dist/mcp/tools/read/commonSchemas.js +43 -0
  105. package/dist/mcp/tools/read/deepbookReadTools.js +453 -0
  106. package/dist/mcp/tools/read/flowxReadTools.js +135 -0
  107. package/dist/mcp/tools/read/index.js +16 -0
  108. package/dist/mcp/tools/read/readToolHelpers.js +68 -0
  109. package/dist/mcp/tools/read/reviewActivityTools.js +176 -0
  110. package/dist/mcp/tools/read/serverStatusTools.js +103 -0
  111. package/dist/mcp/tools/read/transactionActivityOutput.js +300 -0
  112. package/dist/mcp/tools/read/transactionActivityTools.js +544 -0
  113. package/dist/mcp/tools/read/walletReadTools.js +733 -0
  114. package/dist/mcp/tools/session/executionResultTools.js +92 -0
  115. package/dist/mcp/tools/session/index.js +8 -0
  116. package/dist/mcp/tools/session/shared.js +79 -0
  117. package/dist/mcp/tools/session/statusTools.js +134 -0
  118. package/dist/mcp/tools/session/walletIdentityTools.js +119 -0
  119. package/dist/mcp/tools/settings/index.js +64 -0
  120. package/dist/review-app/analysis.css +1 -0
  121. package/dist/review-app/analysis.js +1 -0
  122. package/dist/review-app/arc-BjIacwQm.js +1 -0
  123. package/dist/review-app/architecture-U656AL7Q-aSB9x1OK.js +1 -0
  124. package/dist/review-app/architectureDiagram-VXUJARFQ-C5W6re2I.js +36 -0
  125. package/dist/review-app/array-BmXUUrU6.js +1 -0
  126. package/dist/review-app/blockDiagram-VD42YOAC-20MLNcUm.js +122 -0
  127. package/dist/review-app/c4Diagram-YG6GDRKO-BZXRrcck.js +10 -0
  128. package/dist/review-app/channel-lk2p_CUu.js +1 -0
  129. package/dist/review-app/chunk-4BX2VUAB-BPITOdjX.js +1 -0
  130. package/dist/review-app/chunk-55IACEB6-Dz-pyw5k.js +1 -0
  131. package/dist/review-app/chunk-76Q3JFCE-cK_X1P_l.js +1 -0
  132. package/dist/review-app/chunk-ABZYJK2D-Dt4W53JI.js +81 -0
  133. package/dist/review-app/chunk-ATLVNIR6-fZHLXURb.js +1 -0
  134. package/dist/review-app/chunk-B4BG7PRW-BbgcjusC.js +165 -0
  135. package/dist/review-app/chunk-BJD4TVEz.js +1 -0
  136. package/dist/review-app/chunk-CVBHYZKI-CViawAKX.js +1 -0
  137. package/dist/review-app/chunk-DI55MBZ5-C5aoul-d.js +220 -0
  138. package/dist/review-app/chunk-FMBD7UC4-Chxmw62A.js +15 -0
  139. package/dist/review-app/chunk-FPAJGGOC-DDHjQ09H.js +80 -0
  140. package/dist/review-app/chunk-FWNWRKHM-CVVQUptk.js +1 -0
  141. package/dist/review-app/chunk-HN2XXSSU-yzNpjaSZ.js +1 -0
  142. package/dist/review-app/chunk-JA3XYJ7Z-C5ZJdU01.js +70 -0
  143. package/dist/review-app/chunk-JZLCHNYA-BBST4Cnk.js +54 -0
  144. package/dist/review-app/chunk-LBM3YZW2-CdwAPuHr.js +1 -0
  145. package/dist/review-app/chunk-LHMN2FUI-BtB5uDcp.js +1 -0
  146. package/dist/review-app/chunk-O7ZBX7Z2-pxdK4Sa3.js +1 -0
  147. package/dist/review-app/chunk-QN33PNHL-CbVv3uGK.js +1 -0
  148. package/dist/review-app/chunk-QXUST7PY-DKM2-t2c.js +7 -0
  149. package/dist/review-app/chunk-QZHKN3VN-C5ni2pN_.js +1 -0
  150. package/dist/review-app/chunk-S3R3BYOJ-BWvOhDs0.js +2 -0
  151. package/dist/review-app/chunk-S6J4BHB3-D9Fk0YeD.js +1 -0
  152. package/dist/review-app/chunk-T53DSG4Q-C1qEyzyV.js +1 -0
  153. package/dist/review-app/chunk-TZMSLE5B-B--7eU69.js +1 -0
  154. package/dist/review-app/classDiagram-2ON5EDUG-DlL1m2bp.js +1 -0
  155. package/dist/review-app/classDiagram-v2-WZHVMYZB-FXRskT1j.js +1 -0
  156. package/dist/review-app/clone-BZZb7gpZ.js +1 -0
  157. package/dist/review-app/cose-bilkent-S5V4N54A-CRIb8XEO.js +1 -0
  158. package/dist/review-app/cytoscape.esm-C7jYqDP5.js +321 -0
  159. package/dist/review-app/dagre-6UL2VRFP-FNCAXbdE.js +4 -0
  160. package/dist/review-app/dagre-Be46QtUd.js +1 -0
  161. package/dist/review-app/defaultLocale-BaWNtAUL.js +1 -0
  162. package/dist/review-app/diagram-PSM6KHXK-ylLWjiNM.js +24 -0
  163. package/dist/review-app/diagram-QEK2KX5R-BCDcESxs.js +43 -0
  164. package/dist/review-app/diagram-S2PKOQOG-Vdrc-vrO.js +24 -0
  165. package/dist/review-app/dist-WPc74x_f.js +1 -0
  166. package/dist/review-app/erDiagram-Q2GNP2WA-E5ZsUbDF.js +60 -0
  167. package/dist/review-app/flatten-DHf9IeNI.js +1 -0
  168. package/dist/review-app/flowDiagram-NV44I4VS-DBSQuj6x.js +162 -0
  169. package/dist/review-app/ganttDiagram-LVOFAZNH-CKUOsqwl.js +267 -0
  170. package/dist/review-app/gitGraph-F6HP7TQM-DsAD6qK1.js +1 -0
  171. package/dist/review-app/gitGraphDiagram-NY62KEGX-BCeIMWdl.js +65 -0
  172. package/dist/review-app/graphlib-CiX5CXxR.js +1 -0
  173. package/dist/review-app/http-DMvwuuFk.js +1 -0
  174. package/dist/review-app/identity-DY8PXc6t.js +1 -0
  175. package/dist/review-app/info-NVLQJR56-Dlx1nZic.js +1 -0
  176. package/dist/review-app/infoDiagram-F6ZHWCRC-CAuANIrz.js +2 -0
  177. package/dist/review-app/init-BvqephKz.js +1 -0
  178. package/dist/review-app/journeyDiagram-XKPGCS4Q-C-Z9phnx.js +139 -0
  179. package/dist/review-app/kanban-definition-3W4ZIXB7-DufgZABq.js +89 -0
  180. package/dist/review-app/katex-B-Z-NXXN.js +257 -0
  181. package/dist/review-app/line-DiIv3Jgw.js +1 -0
  182. package/dist/review-app/linear-Cv-UPvo1.js +1 -0
  183. package/dist/review-app/math-kmyYrkHL.js +1 -0
  184. package/dist/review-app/mermaid-parser.core-DkwUYTPl.js +4 -0
  185. package/dist/review-app/mindmap-definition-VGOIOE7T-TM_CqdmV.js +68 -0
  186. package/dist/review-app/ordinal-BliTlkoG.js +1 -0
  187. package/dist/review-app/packet-BFZMPI3H-DqbnU92v.js +1 -0
  188. package/dist/review-app/path-AEo9W6mQ.js +1 -0
  189. package/dist/review-app/pie-7BOR55EZ-LJzaLkgr.js +1 -0
  190. package/dist/review-app/pieDiagram-ADFJNKIX-BAs8OfRS.js +30 -0
  191. package/dist/review-app/quadrantDiagram-AYHSOK5B-CyUDZP5S.js +7 -0
  192. package/dist/review-app/radar-NHE76QYJ-DBpHc8_Y.js +1 -0
  193. package/dist/review-app/reduce-B-HuPpdd.js +1 -0
  194. package/dist/review-app/requirementDiagram-UZGBJVZJ-BEHix78P.js +64 -0
  195. package/dist/review-app/review.css +1 -0
  196. package/dist/review-app/review.js +43 -0
  197. package/dist/review-app/sankeyDiagram-TZEHDZUN-B2bKbmsm.js +10 -0
  198. package/dist/review-app/sequenceDiagram-WL72ISMW-DVLOORFJ.js +145 -0
  199. package/dist/review-app/settings.css +1 -0
  200. package/dist/review-app/settings.js +1 -0
  201. package/dist/review-app/src-Buml7cM5.js +1 -0
  202. package/dist/review-app/stateDiagram-FKZM4ZOC-sFGGp2kV.js +1 -0
  203. package/dist/review-app/stateDiagram-v2-4FDKWEC3-BHfCF4dX.js +1 -0
  204. package/dist/review-app/timeline-definition-IT6M3QCI-BESnBijC.js +61 -0
  205. package/dist/review-app/treemap-KMMF4GRG-wnVLBDeQ.js +1 -0
  206. package/dist/review-app/walletStatus-CcojOdGy.js +7 -0
  207. package/dist/review-app/xychartDiagram-PRI3JC2R-BGWVfCx4.js +7 -0
  208. package/dist/review-server/assets.js +48 -0
  209. package/dist/review-server/html.js +66 -0
  210. package/dist/review-server/http.js +47 -0
  211. package/dist/review-server/middleware/hostOrigin.js +48 -0
  212. package/dist/review-server/middleware/reviewToken.js +7 -0
  213. package/dist/review-server/reviewServerPolicy.js +10 -0
  214. package/dist/review-server/server.js +568 -0
  215. package/dist/review-server/settingsApi.js +182 -0
  216. package/dist/review-server/walletIdentityResponse.js +13 -0
  217. package/dist/runtime/config.js +103 -0
  218. package/dist/runtime/localSettingsService.js +198 -0
  219. package/dist/runtime/logger.js +50 -0
  220. package/dist/runtime/reviewServerAcquire.js +128 -0
  221. package/dist/runtime/smokeMainnetRead.js +529 -0
  222. package/dist/runtime/smokeMainnetReadAssertions.js +308 -0
  223. package/dist/runtime/start.js +295 -0
  224. package/dist/runtime/suiEndpoint.js +97 -0
  225. package/dist/runtime/suiTransactionGraphqlMapping.js +200 -0
  226. package/dist/runtime/suiTransactionGraphqlQueries.js +231 -0
  227. package/dist/runtime/suiTransactionGraphqlSource.js +148 -0
  228. package/docs/AGENT_BEHAVIOR.md +1 -1
  229. package/docs/AGENT_DEVELOPMENT_POLICY.md +20 -0
  230. package/docs/FRONTEND_POLICY.md +4 -3
  231. package/docs/MCP_SETUP.md +59 -7
  232. package/docs/MCP_TOOLS.md +1 -1
  233. package/docs/SDK_API.md +5 -1
  234. package/package.json +3 -2
@@ -0,0 +1,258 @@
1
+ import { SuiEndpointError, parseGraphqlUrl, parseGrpcUrl } from "../suiEndpoint.js";
2
+ import { LOCAL_DATA_EXPORT_FORMAT, LOCAL_DATA_NETWORK, LocalDataError } from "./localDataTypes.js";
3
+ import { activeAccountChange, countsForPayload, defaultsInjectedForImport, invalidBackup, maxNumber, parseLocalDataEnvelope, suiGraphqlUrlFromPayload, suiGrpcUrlFromPayload } from "./localDataValidation.js";
4
+ export * from "./localDataTypes.js";
5
+ export class SqliteLocalDataService {
6
+ db;
7
+ options;
8
+ validateAdapterLifecycle;
9
+ constructor(db, options, validateAdapterLifecycle) {
10
+ this.db = db;
11
+ this.options = options;
12
+ this.validateAdapterLifecycle = validateAdapterLifecycle;
13
+ }
14
+ async getDataCounts() {
15
+ return this.getDataCountsSync();
16
+ }
17
+ async exportLocalData(now = new Date()) {
18
+ return this.db.transaction(() => {
19
+ const envelope = {
20
+ format: LOCAL_DATA_EXPORT_FORMAT,
21
+ network: LOCAL_DATA_NETWORK,
22
+ exportedAt: now.toISOString(),
23
+ data: {
24
+ accounts: this.selectAll("accounts"),
25
+ activeAccountContext: this.selectAll("active_account_context"),
26
+ reviewSessions: this.selectAll("review_sessions"),
27
+ reviewStateSnapshots: this.selectAll("review_state_snapshots"),
28
+ reviewStatusTransitions: this.selectAll("review_status_transitions"),
29
+ reviewExecutions: this.selectAll("review_executions"),
30
+ externalActivityScans: this.selectAll("external_activity_scans"),
31
+ externalActivityTransactions: this.selectAll("external_activity_transactions"),
32
+ localSettings: this.selectAll("local_settings")
33
+ }
34
+ };
35
+ return parseLocalDataEnvelope(envelope, {
36
+ defaultSuiGraphqlUrl: this.options.suiGraphqlUrl,
37
+ validateAdapterLifecycle: this.validateAdapterLifecycle
38
+ });
39
+ })();
40
+ }
41
+ async previewImportLocalData(input) {
42
+ const defaultsInjected = defaultsInjectedForImport(input);
43
+ const envelope = parseLocalDataEnvelope(input, {
44
+ defaultSuiGraphqlUrl: this.options.suiGraphqlUrl,
45
+ validateAdapterLifecycle: this.validateAdapterLifecycle
46
+ });
47
+ return {
48
+ status: "valid",
49
+ format: envelope.format,
50
+ network: envelope.network,
51
+ exportedAt: envelope.exportedAt,
52
+ currentCounts: this.getDataCountsSync(),
53
+ incomingCounts: countsForPayload(envelope.data),
54
+ willReplace: true,
55
+ activeAccountChange: activeAccountChange(this.selectAll("accounts"), this.selectAll("active_account_context"), envelope.data.accounts, envelope.data.activeAccountContext),
56
+ restartRequiredAfterImport: true,
57
+ defaultsInjected
58
+ };
59
+ }
60
+ async importLocalDataReplace(input, _now = new Date()) {
61
+ const envelope = await this.parseAndVerifyImportEnvelope(input);
62
+ this.db.transaction(() => {
63
+ this.resetLocalDataTables();
64
+ this.insertAccounts(envelope.data.accounts);
65
+ this.insertActiveAccountContext(envelope.data.activeAccountContext);
66
+ this.insertReviewSessions(envelope.data.reviewSessions);
67
+ this.insertReviewStateSnapshots(envelope.data.reviewStateSnapshots);
68
+ this.insertReviewStatusTransitions(envelope.data.reviewStatusTransitions);
69
+ this.insertReviewExecutions(envelope.data.reviewExecutions);
70
+ this.insertExternalActivityScans(envelope.data.externalActivityScans);
71
+ this.insertExternalActivityTransactions(envelope.data.externalActivityTransactions);
72
+ this.insertLocalSettings(envelope.data.localSettings);
73
+ this.syncSqliteSequences(envelope.data);
74
+ })();
75
+ return {
76
+ status: "imported",
77
+ dataCounts: this.getDataCountsSync(),
78
+ sessionsInvalidated: true
79
+ };
80
+ }
81
+ async resetLocalData(now = new Date()) {
82
+ this.db.transaction(() => {
83
+ this.resetLocalDataTables();
84
+ this.insertDefaultSuiGrpcUrl(now);
85
+ })();
86
+ return {
87
+ status: "reset",
88
+ dataCounts: this.getDataCountsSync(),
89
+ sessionsInvalidated: true
90
+ };
91
+ }
92
+ resetLocalDataTables() {
93
+ for (const table of [
94
+ "external_activity_transactions",
95
+ "external_activity_scans",
96
+ "review_state_snapshots",
97
+ "review_status_transitions",
98
+ "review_executions",
99
+ "review_sessions",
100
+ "coin_metadata_cache",
101
+ "active_account_context",
102
+ "accounts",
103
+ "local_settings"
104
+ ]) {
105
+ this.db.prepare(`DELETE FROM ${table}`).run();
106
+ }
107
+ this.db.prepare("DELETE FROM sqlite_sequence WHERE name IN ('accounts', 'review_state_snapshots', 'review_status_transitions')").run();
108
+ }
109
+ insertDefaultSuiGrpcUrl(now) {
110
+ const statement = this.db.prepare(`INSERT INTO local_settings (key, value_json, updated_at)
111
+ VALUES (?, ?, ?)`);
112
+ statement.run("suiGrpcUrl", JSON.stringify(parseGrpcUrl(this.options.suiGrpcUrl)), now.toISOString());
113
+ statement.run("suiGraphqlUrl", JSON.stringify(parseGraphqlUrl(this.options.suiGraphqlUrl)), now.toISOString());
114
+ }
115
+ getDataCountsSync() {
116
+ return {
117
+ accounts: this.count("accounts"),
118
+ reviewSessions: this.count("review_sessions"),
119
+ reviewStateSnapshots: this.count("review_state_snapshots"),
120
+ reviewStatusTransitions: this.count("review_status_transitions"),
121
+ reviewExecutions: this.count("review_executions"),
122
+ externalActivityScans: this.count("external_activity_scans"),
123
+ externalActivityTransactions: this.count("external_activity_transactions"),
124
+ localSettings: this.count("local_settings")
125
+ };
126
+ }
127
+ count(table) {
128
+ return this.db.prepare(`SELECT COUNT(*) AS count FROM ${table}`).get().count;
129
+ }
130
+ selectAll(table) {
131
+ return this.db.prepare(`SELECT * FROM ${table} ORDER BY rowid ASC`).all();
132
+ }
133
+ insertAccounts(rows) {
134
+ const statement = this.db.prepare(`INSERT INTO accounts (id, sui_address, first_seen_at, last_used_at, first_source, last_source)
135
+ VALUES (?, ?, ?, ?, ?, ?)`);
136
+ for (const row of rows) {
137
+ statement.run(row.id, row.sui_address, row.first_seen_at, row.last_used_at, row.first_source, row.last_source);
138
+ }
139
+ }
140
+ insertActiveAccountContext(rows) {
141
+ const statement = this.db.prepare(`INSERT INTO active_account_context (id, account_id, source, set_at, wallet_name, wallet_id)
142
+ VALUES (?, ?, ?, ?, ?, ?)`);
143
+ for (const row of rows) {
144
+ statement.run(row.id, row.account_id, row.source, row.set_at, row.wallet_name ?? null, row.wallet_id ?? null);
145
+ }
146
+ }
147
+ insertReviewSessions(rows) {
148
+ const statement = this.db.prepare(`INSERT INTO review_sessions
149
+ (id, plan_id, action_kind, adapter_id, protocol, account_id, current_status, plan_json, intent_json, created_at, updated_at)
150
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
151
+ for (const row of rows) {
152
+ statement.run(row.id, row.plan_id, row.action_kind, row.adapter_id, row.protocol, row.account_id, row.current_status, row.plan_json, row.intent_json, row.created_at, row.updated_at);
153
+ }
154
+ }
155
+ insertReviewStateSnapshots(rows) {
156
+ const statement = this.db.prepare(`INSERT INTO review_state_snapshots
157
+ (id, review_session_id, plan_id, account_id, status, blocked_reason, refresh_reason, state_json, updated_at, recorded_at)
158
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
159
+ for (const row of rows) {
160
+ statement.run(row.id, row.review_session_id, row.plan_id, row.account_id, row.status, row.blocked_reason, row.refresh_reason, row.state_json, row.updated_at, row.recorded_at);
161
+ }
162
+ }
163
+ insertReviewStatusTransitions(rows) {
164
+ const statement = this.db.prepare(`INSERT INTO review_status_transitions
165
+ (id, review_session_id, event, from_status, to_status, account_id, reason, transitioned_at)
166
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
167
+ for (const row of rows) {
168
+ statement.run(row.id, row.review_session_id, row.event, row.from_status, row.to_status, row.account_id, row.reason, row.transitioned_at);
169
+ }
170
+ }
171
+ insertReviewExecutions(rows) {
172
+ const statement = this.db.prepare(`INSERT INTO review_executions
173
+ (review_session_id, plan_id, account_id, status, tx_digest, explorer_url, failure_reason, result_json, recorded_at, updated_at)
174
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
175
+ for (const row of rows) {
176
+ statement.run(row.review_session_id, row.plan_id, row.account_id, row.status, row.tx_digest, row.explorer_url, row.failure_reason, row.result_json, row.recorded_at, row.updated_at);
177
+ }
178
+ }
179
+ insertExternalActivityScans(rows) {
180
+ const statement = this.db.prepare(`INSERT INTO external_activity_scans
181
+ (scan_id, kind, account_id, relationship, input_digest, from_checkpoint, to_checkpoint,
182
+ from_timestamp, to_timestamp, limit_count, request_cursor, response_cursor, endpoint_host,
183
+ chain_identifier, fetched_at, stored_count, skipped_count, has_more, window_complete,
184
+ incomplete_reason)
185
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
186
+ for (const row of rows) {
187
+ statement.run(row.scan_id, row.kind, row.account_id, row.relationship, row.input_digest, row.from_checkpoint, row.to_checkpoint, row.from_timestamp, row.to_timestamp, row.limit_count, row.request_cursor, row.response_cursor, row.endpoint_host, row.chain_identifier, row.fetched_at, row.stored_count, row.skipped_count, row.has_more, row.window_complete, row.incomplete_reason);
188
+ }
189
+ }
190
+ insertExternalActivityTransactions(rows) {
191
+ const statement = this.db.prepare(`INSERT INTO external_activity_transactions
192
+ (account_id, digest, relationship, checkpoint, timestamp, status, known_sender_account_id,
193
+ first_scan_id, last_scan_id, first_fetched_at, last_fetched_at, detail_json)
194
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
195
+ for (const row of rows) {
196
+ statement.run(row.account_id, row.digest, row.relationship, row.checkpoint, row.timestamp, row.status, row.known_sender_account_id, row.first_scan_id, row.last_scan_id, row.first_fetched_at, row.last_fetched_at, row.detail_json);
197
+ }
198
+ }
199
+ insertLocalSettings(rows) {
200
+ const statement = this.db.prepare(`INSERT INTO local_settings (key, value_json, updated_at)
201
+ VALUES (?, ?, ?)`);
202
+ for (const row of rows) {
203
+ statement.run(row.key, row.value_json, row.updated_at);
204
+ }
205
+ }
206
+ syncSqliteSequences(data) {
207
+ const sequenceRows = [
208
+ ["accounts", maxNumber(data.accounts.map((row) => row.id))],
209
+ ["review_state_snapshots", maxNumber(data.reviewStateSnapshots.map((row) => row.id))],
210
+ ["review_status_transitions", maxNumber(data.reviewStatusTransitions.map((row) => row.id))]
211
+ ];
212
+ const update = this.db.prepare("UPDATE sqlite_sequence SET seq = ? WHERE name = ?");
213
+ const insert = this.db.prepare("INSERT INTO sqlite_sequence (name, seq) VALUES (?, ?)");
214
+ for (const [name, seq] of sequenceRows) {
215
+ if (seq > 0) {
216
+ const result = update.run(seq, name);
217
+ if (result.changes === 0) {
218
+ insert.run(name, seq);
219
+ }
220
+ }
221
+ }
222
+ }
223
+ async parseAndVerifyImportEnvelope(input) {
224
+ const envelope = parseLocalDataEnvelope(input, {
225
+ defaultSuiGraphqlUrl: this.options.suiGraphqlUrl,
226
+ validateAdapterLifecycle: this.validateAdapterLifecycle
227
+ });
228
+ await this.verifyImportedSuiGrpcUrl(suiGrpcUrlFromPayload(envelope.data));
229
+ await this.verifyImportedSuiGraphqlUrl(suiGraphqlUrlFromPayload(envelope.data));
230
+ return envelope;
231
+ }
232
+ async verifyImportedSuiGrpcUrl(url) {
233
+ try {
234
+ await this.options.verifySuiGrpcUrl(url);
235
+ }
236
+ catch (error) {
237
+ if (error instanceof SuiEndpointError) {
238
+ throw invalidBackup("invalid_sui_grpc_url_endpoint", { endpointReason: error.kind });
239
+ }
240
+ throw new LocalDataError("internal_error", "Could not verify imported Sui gRPC endpoint", {
241
+ message: "Could not verify imported Sui gRPC endpoint"
242
+ });
243
+ }
244
+ }
245
+ async verifyImportedSuiGraphqlUrl(url) {
246
+ try {
247
+ await this.options.verifySuiGraphqlUrl(url);
248
+ }
249
+ catch (error) {
250
+ if (error instanceof SuiEndpointError) {
251
+ throw invalidBackup("invalid_sui_graphql_url_endpoint", { endpointReason: error.kind });
252
+ }
253
+ throw new LocalDataError("internal_error", "Could not verify imported Sui GraphQL endpoint", {
254
+ message: "Could not verify imported Sui GraphQL endpoint"
255
+ });
256
+ }
257
+ }
258
+ }
@@ -0,0 +1,11 @@
1
+ export const LOCAL_DATA_EXPORT_FORMAT = "say-ur-intent.local-data";
2
+ export const LOCAL_DATA_NETWORK = "mainnet";
3
+ export class LocalDataError extends Error {
4
+ kind;
5
+ details;
6
+ constructor(kind, message, details = {}) {
7
+ super(message);
8
+ this.kind = kind;
9
+ this.details = details;
10
+ }
11
+ }
@@ -0,0 +1,396 @@
1
+ import { z } from "zod";
2
+ import { assertNoForbiddenMcpFields } from "../action/forbiddenFields.js";
3
+ import { parseLifecycleValidatedReviewState } from "../action/reviewStateValidation.js";
4
+ import { actionPlanSchema, executionResultSchema, internalSessionStatusSchema } from "../action/schemas.js";
5
+ import { parseSuiAddress } from "../suiAddress.js";
6
+ import { parseGraphqlUrl, parseGrpcUrl } from "../suiEndpoint.js";
7
+ import { EXTERNAL_ACTIVITY_TRANSACTION_DETAIL_JSON_MAX_BYTES, externalActivityTransactionDetailJsonByteLength, externalActivityTransactionDetailSchema, externalActivityTransactionDetailsReferenceOnlyAccount } from "./transactionActivityDetails.js";
8
+ import { LOCAL_DATA_EXPORT_FORMAT, LOCAL_DATA_NETWORK, LocalDataError } from "./localDataTypes.js";
9
+ const isoTimestamp = z.string().refine((value) => {
10
+ const parsed = new Date(value);
11
+ return !Number.isNaN(parsed.getTime()) && parsed.toISOString() === value;
12
+ }, "must be an ISO 8601 UTC timestamp");
13
+ const nullableString = z.string().nullable();
14
+ const accountRowSchema = z.object({
15
+ id: z.number().int().positive(),
16
+ sui_address: z.string().refine((value) => parseSuiAddress(value) === value, "must be a normalized Sui address"),
17
+ first_seen_at: isoTimestamp,
18
+ last_used_at: isoTimestamp,
19
+ first_source: z.enum(["wallet_identity", "review_execution"]),
20
+ last_source: z.enum(["wallet_identity", "review_execution"])
21
+ }).strict();
22
+ const activeAccountContextRowSchema = z.object({
23
+ id: z.literal(1),
24
+ account_id: z.number().int().positive().nullable(),
25
+ source: z.enum(["wallet_identity", "cleared"]),
26
+ set_at: isoTimestamp,
27
+ wallet_name: z.string().min(1).max(200).nullish(),
28
+ wallet_id: z.string().min(1).max(200).nullish()
29
+ }).strict();
30
+ const reviewSessionRowSchema = z.object({
31
+ id: z.string().min(1),
32
+ plan_id: z.string().min(1),
33
+ action_kind: z.string().min(1),
34
+ adapter_id: z.string().min(1),
35
+ protocol: z.string().min(1),
36
+ account_id: z.number().int().positive().nullable(),
37
+ current_status: internalSessionStatusSchema,
38
+ plan_json: z.string(),
39
+ intent_json: z.string().nullable(),
40
+ created_at: isoTimestamp,
41
+ updated_at: isoTimestamp
42
+ }).strict();
43
+ const reviewStateSnapshotRowSchema = z.object({
44
+ id: z.number().int().positive(),
45
+ review_session_id: z.string().min(1),
46
+ plan_id: z.string().min(1),
47
+ account_id: z.number().int().positive(),
48
+ status: z.enum(["ready_for_wallet_review", "refresh_required", "blocked"]),
49
+ blocked_reason: nullableString,
50
+ refresh_reason: nullableString,
51
+ state_json: z.string(),
52
+ updated_at: isoTimestamp,
53
+ recorded_at: isoTimestamp
54
+ }).strict();
55
+ const reviewStatusTransitionRowSchema = z.object({
56
+ id: z.number().int().positive(),
57
+ review_session_id: z.string().min(1),
58
+ event: z.enum(["created", "opened", "wallet_connected", "state_computed", "result_recorded", "expired"]),
59
+ from_status: internalSessionStatusSchema.nullable(),
60
+ to_status: internalSessionStatusSchema,
61
+ account_id: z.number().int().positive().nullable(),
62
+ reason: nullableString,
63
+ transitioned_at: isoTimestamp
64
+ }).strict();
65
+ const reviewExecutionRowSchema = z.object({
66
+ review_session_id: z.string().min(1),
67
+ plan_id: z.string().min(1),
68
+ account_id: z.number().int().positive(),
69
+ status: z.enum(["signed_pending_result", "success", "failure"]),
70
+ tx_digest: nullableString,
71
+ explorer_url: nullableString,
72
+ failure_reason: nullableString,
73
+ result_json: z.string(),
74
+ recorded_at: isoTimestamp,
75
+ updated_at: isoTimestamp
76
+ }).strict();
77
+ const externalActivityScanRowSchema = z.object({
78
+ scan_id: z.string().min(1),
79
+ kind: z.enum(["digest_lookup", "account_scan", "function_scan"]),
80
+ account_id: z.number().int().positive(),
81
+ relationship: z.enum(["affected", "sent"]),
82
+ input_digest: nullableString,
83
+ from_checkpoint: nullableString,
84
+ to_checkpoint: nullableString,
85
+ from_timestamp: isoTimestamp.nullable(),
86
+ to_timestamp: isoTimestamp.nullable(),
87
+ limit_count: z.number().int().min(1).max(100),
88
+ request_cursor: nullableString,
89
+ response_cursor: nullableString,
90
+ endpoint_host: z.string().min(1),
91
+ chain_identifier: z.string().min(1),
92
+ fetched_at: isoTimestamp,
93
+ stored_count: z.number().int().nonnegative(),
94
+ skipped_count: z.number().int().nonnegative(),
95
+ has_more: z.union([z.literal(0), z.literal(1)]),
96
+ window_complete: z.union([z.literal(0), z.literal(1)]).nullable(),
97
+ incomplete_reason: z.enum(["limit_reached", "ordering_unverified", "cursor_invalid", "provider_error"]).nullable()
98
+ }).strict();
99
+ const externalActivityTransactionRowSchema = z.object({
100
+ account_id: z.number().int().positive(),
101
+ digest: z.string().min(1),
102
+ relationship: z.enum(["affected", "sent"]),
103
+ checkpoint: nullableString,
104
+ timestamp: isoTimestamp.nullable(),
105
+ status: z.enum(["success", "failure", "unknown"]),
106
+ known_sender_account_id: z.number().int().positive().nullable(),
107
+ first_scan_id: z.string().min(1),
108
+ last_scan_id: z.string().min(1),
109
+ first_fetched_at: isoTimestamp,
110
+ last_fetched_at: isoTimestamp,
111
+ detail_json: z.string().nullable().default(null)
112
+ }).strict();
113
+ const localSettingRowSchema = z.object({
114
+ key: z.enum(["suiGrpcUrl", "suiGraphqlUrl"]),
115
+ value_json: z.string(),
116
+ updated_at: isoTimestamp
117
+ }).strict();
118
+ const payloadSchema = z.object({
119
+ accounts: z.array(accountRowSchema),
120
+ activeAccountContext: z.array(activeAccountContextRowSchema).max(1),
121
+ reviewSessions: z.array(reviewSessionRowSchema),
122
+ reviewStateSnapshots: z.array(reviewStateSnapshotRowSchema),
123
+ reviewStatusTransitions: z.array(reviewStatusTransitionRowSchema),
124
+ reviewExecutions: z.array(reviewExecutionRowSchema),
125
+ externalActivityScans: z.array(externalActivityScanRowSchema).default([]),
126
+ externalActivityTransactions: z.array(externalActivityTransactionRowSchema).default([]),
127
+ localSettings: z.array(localSettingRowSchema).min(1).max(2)
128
+ }).strict();
129
+ const envelopeSchema = z.object({
130
+ format: z.literal(LOCAL_DATA_EXPORT_FORMAT),
131
+ network: z.literal(LOCAL_DATA_NETWORK),
132
+ exportedAt: isoTimestamp,
133
+ data: payloadSchema
134
+ }).strict();
135
+ export function parseLocalDataEnvelope(input, options) {
136
+ const parsed = envelopeSchema.safeParse(input);
137
+ if (!parsed.success) {
138
+ throw new LocalDataError("input_invalid", "Invalid local data backup", {
139
+ reason: "invalid_backup_shape"
140
+ });
141
+ }
142
+ const normalized = withDefaultSuiGraphqlSetting(parsed.data, options.defaultSuiGraphqlUrl);
143
+ validatePayloadSemantics(normalized.data, options.validateAdapterLifecycle);
144
+ return normalized;
145
+ }
146
+ export function defaultsInjectedForImport(input) {
147
+ const parsed = envelopeSchema.safeParse(input);
148
+ if (!parsed.success) {
149
+ return [];
150
+ }
151
+ return parsed.data.data.localSettings.some((row) => row.key === "suiGraphqlUrl") ? [] : ["suiGraphqlUrl"];
152
+ }
153
+ function validatePayloadSemantics(data, validateAdapterLifecycle) {
154
+ ensureUnique(data.accounts.map((row) => row.id), "duplicate_account_id");
155
+ ensureUnique(data.accounts.map((row) => row.sui_address), "duplicate_account_address");
156
+ ensureUnique(data.reviewSessions.map((row) => row.id), "duplicate_review_session_id");
157
+ ensureUnique(data.reviewStateSnapshots.map((row) => row.id), "duplicate_review_state_snapshot_id");
158
+ ensureUnique(data.reviewStatusTransitions.map((row) => row.id), "duplicate_review_transition_id");
159
+ ensureUnique(data.reviewExecutions.map((row) => row.review_session_id), "duplicate_review_execution_id");
160
+ ensureUnique(data.externalActivityScans.map((row) => row.scan_id), "duplicate_external_activity_scan_id");
161
+ ensureUnique(data.externalActivityTransactions.map((row) => `${row.account_id}:${row.digest}:${row.relationship}`), "duplicate_external_activity_transaction");
162
+ ensureUnique(data.localSettings.map((row) => row.key), "duplicate_local_setting_key");
163
+ const accountIds = new Set(data.accounts.map((row) => row.id));
164
+ const accountAddressesById = new Map(data.accounts.map((row) => [row.id, row.sui_address]));
165
+ for (const row of data.activeAccountContext) {
166
+ if (row.source === "cleared" && row.account_id !== null) {
167
+ throw invalidBackup("invalid_active_account_context");
168
+ }
169
+ if (row.source === "wallet_identity" && (row.account_id === null || !accountIds.has(row.account_id))) {
170
+ throw invalidBackup("invalid_active_account_context");
171
+ }
172
+ }
173
+ for (const row of data.reviewSessions) {
174
+ validateJsonColumn(row.plan_json, "plan_json", actionPlanSchema);
175
+ validateOptionalJsonColumn(row.intent_json, "intent_json");
176
+ if (row.account_id !== null && !accountIds.has(row.account_id)) {
177
+ throw invalidBackup("invalid_review_session_account");
178
+ }
179
+ }
180
+ const reviewSessionIds = new Set(data.reviewSessions.map((row) => row.id));
181
+ for (const row of data.reviewStateSnapshots) {
182
+ if (!reviewSessionIds.has(row.review_session_id) || !accountIds.has(row.account_id)) {
183
+ throw invalidBackup("invalid_review_state_snapshot_reference");
184
+ }
185
+ if (row.status === "blocked" && (row.blocked_reason === null || row.refresh_reason !== null)) {
186
+ throw invalidBackup("invalid_review_state_snapshot_status");
187
+ }
188
+ if (row.status === "refresh_required" && (row.refresh_reason === null || row.blocked_reason !== null)) {
189
+ throw invalidBackup("invalid_review_state_snapshot_status");
190
+ }
191
+ if (row.status === "ready_for_wallet_review" && (row.blocked_reason !== null || row.refresh_reason !== null)) {
192
+ throw invalidBackup("invalid_review_state_snapshot_status");
193
+ }
194
+ validateReviewStateJsonColumn(row.state_json, "state_json", validateAdapterLifecycle);
195
+ }
196
+ for (const row of data.reviewStatusTransitions) {
197
+ if (!reviewSessionIds.has(row.review_session_id) || (row.account_id !== null && !accountIds.has(row.account_id))) {
198
+ throw invalidBackup("invalid_review_transition_reference");
199
+ }
200
+ }
201
+ for (const row of data.reviewExecutions) {
202
+ if (!reviewSessionIds.has(row.review_session_id) || !accountIds.has(row.account_id)) {
203
+ throw invalidBackup("invalid_review_execution_reference");
204
+ }
205
+ if (row.status === "failure" && row.failure_reason === null) {
206
+ throw invalidBackup("invalid_review_execution_status");
207
+ }
208
+ if (row.status !== "failure" && row.failure_reason !== null) {
209
+ throw invalidBackup("invalid_review_execution_status");
210
+ }
211
+ validateJsonColumn(row.result_json, "result_json", executionResultSchema);
212
+ }
213
+ const scanIds = new Set(data.externalActivityScans.map((row) => row.scan_id));
214
+ for (const row of data.externalActivityScans) {
215
+ if (!accountIds.has(row.account_id)) {
216
+ throw invalidBackup("invalid_external_activity_scan_account");
217
+ }
218
+ if (row.from_timestamp !== null && row.to_timestamp !== null && row.from_timestamp > row.to_timestamp) {
219
+ throw invalidBackup("invalid_external_activity_scan_window");
220
+ }
221
+ if (row.window_complete !== null && row.window_complete !== 0 && row.window_complete !== 1) {
222
+ throw invalidBackup("invalid_external_activity_scan_window_complete");
223
+ }
224
+ }
225
+ for (const row of data.externalActivityTransactions) {
226
+ if (!accountIds.has(row.account_id) || !scanIds.has(row.first_scan_id) || !scanIds.has(row.last_scan_id)) {
227
+ throw invalidBackup("invalid_external_activity_transaction_reference");
228
+ }
229
+ if (row.known_sender_account_id !== null && !accountIds.has(row.known_sender_account_id)) {
230
+ throw invalidBackup("invalid_external_activity_sender_reference");
231
+ }
232
+ if (row.detail_json !== null) {
233
+ if (externalActivityTransactionDetailJsonByteLength(row.detail_json) > EXTERNAL_ACTIVITY_TRANSACTION_DETAIL_JSON_MAX_BYTES) {
234
+ throw invalidBackup("external_activity_detail_too_large", {
235
+ maxBytes: EXTERNAL_ACTIVITY_TRANSACTION_DETAIL_JSON_MAX_BYTES
236
+ });
237
+ }
238
+ const detail = validateJsonColumn(row.detail_json, "external_activity_transactions.detail_json");
239
+ const parsedDetail = externalActivityTransactionDetailSchema.safeParse(detail);
240
+ if (!parsedDetail.success) {
241
+ throw invalidBackup("invalid_external_activity_detail_json");
242
+ }
243
+ const account = accountAddressesById.get(row.account_id);
244
+ if (account === undefined || !externalActivityTransactionDetailsReferenceOnlyAccount(parsedDetail.data, account)) {
245
+ throw invalidBackup("invalid_external_activity_detail_json");
246
+ }
247
+ }
248
+ }
249
+ const localSettingKeys = new Set(data.localSettings.map((row) => row.key));
250
+ if (!localSettingKeys.has("suiGrpcUrl")) {
251
+ throw invalidBackup("missing_sui_grpc_url");
252
+ }
253
+ for (const row of data.localSettings) {
254
+ const value = validateJsonColumn(row.value_json, "local_settings.value_json");
255
+ if (typeof value !== "string") {
256
+ throw invalidBackup(row.key === "suiGrpcUrl" ? "invalid_sui_grpc_url" : "invalid_sui_graphql_url");
257
+ }
258
+ try {
259
+ if (row.key === "suiGrpcUrl") {
260
+ parseGrpcUrl(value);
261
+ }
262
+ else {
263
+ parseGraphqlUrl(value);
264
+ }
265
+ }
266
+ catch {
267
+ throw invalidBackup(row.key === "suiGrpcUrl" ? "invalid_sui_grpc_url" : "invalid_sui_graphql_url");
268
+ }
269
+ }
270
+ }
271
+ function validateReviewStateJsonColumn(value, field, validateAdapterLifecycle) {
272
+ const parsed = validateJsonColumn(value, field);
273
+ try {
274
+ parseLifecycleValidatedReviewState(parsed, validateAdapterLifecycle);
275
+ }
276
+ catch {
277
+ throw invalidBackup("invalid_json_shape", { field });
278
+ }
279
+ }
280
+ function withDefaultSuiGraphqlSetting(envelope, defaultSuiGraphqlUrl) {
281
+ if (envelope.data.localSettings.some((row) => row.key === "suiGraphqlUrl")) {
282
+ return envelope;
283
+ }
284
+ return {
285
+ ...envelope,
286
+ data: {
287
+ ...envelope.data,
288
+ localSettings: [
289
+ ...envelope.data.localSettings,
290
+ {
291
+ key: "suiGraphqlUrl",
292
+ value_json: JSON.stringify(parseGraphqlUrl(defaultSuiGraphqlUrl)),
293
+ updated_at: envelope.exportedAt
294
+ }
295
+ ]
296
+ }
297
+ };
298
+ }
299
+ export function suiGrpcUrlFromPayload(data) {
300
+ const row = data.localSettings.find((setting) => setting.key === "suiGrpcUrl");
301
+ if (!row) {
302
+ throw invalidBackup("missing_sui_grpc_url");
303
+ }
304
+ const value = validateJsonColumn(row.value_json, "local_settings.value_json");
305
+ if (typeof value !== "string") {
306
+ throw invalidBackup("invalid_sui_grpc_url");
307
+ }
308
+ try {
309
+ return parseGrpcUrl(value);
310
+ }
311
+ catch {
312
+ throw invalidBackup("invalid_sui_grpc_url");
313
+ }
314
+ }
315
+ export function suiGraphqlUrlFromPayload(data) {
316
+ const row = data.localSettings.find((setting) => setting.key === "suiGraphqlUrl");
317
+ if (!row) {
318
+ throw invalidBackup("missing_sui_graphql_url");
319
+ }
320
+ const value = validateJsonColumn(row.value_json, "local_settings.value_json");
321
+ if (typeof value !== "string") {
322
+ throw invalidBackup("invalid_sui_graphql_url");
323
+ }
324
+ try {
325
+ return parseGraphqlUrl(value);
326
+ }
327
+ catch {
328
+ throw invalidBackup("invalid_sui_graphql_url");
329
+ }
330
+ }
331
+ function ensureUnique(values, reason) {
332
+ if (new Set(values).size !== values.length) {
333
+ throw invalidBackup(reason);
334
+ }
335
+ }
336
+ function validateJsonColumn(value, field, schema) {
337
+ let parsed;
338
+ try {
339
+ parsed = JSON.parse(value);
340
+ }
341
+ catch {
342
+ throw invalidBackup("malformed_json", { field });
343
+ }
344
+ try {
345
+ assertNoForbiddenMcpFields(parsed);
346
+ }
347
+ catch {
348
+ throw invalidBackup("forbidden_field", { field });
349
+ }
350
+ if (schema) {
351
+ const result = schema.safeParse(parsed);
352
+ if (!result.success) {
353
+ throw invalidBackup("invalid_json_shape", { field });
354
+ }
355
+ return result.data;
356
+ }
357
+ return parsed;
358
+ }
359
+ function validateOptionalJsonColumn(value, field) {
360
+ if (value !== null) {
361
+ validateJsonColumn(value, field);
362
+ }
363
+ }
364
+ export function invalidBackup(reason, details = {}) {
365
+ return new LocalDataError("input_invalid", "Invalid local data backup", { reason, ...details });
366
+ }
367
+ export function countsForPayload(data) {
368
+ return {
369
+ accounts: data.accounts.length,
370
+ reviewSessions: data.reviewSessions.length,
371
+ reviewStateSnapshots: data.reviewStateSnapshots.length,
372
+ reviewStatusTransitions: data.reviewStatusTransitions.length,
373
+ reviewExecutions: data.reviewExecutions.length,
374
+ externalActivityScans: data.externalActivityScans.length,
375
+ externalActivityTransactions: data.externalActivityTransactions.length,
376
+ localSettings: data.localSettings.length
377
+ };
378
+ }
379
+ export function activeAccountChange(currentAccounts, current, incomingAccounts, incoming) {
380
+ const currentAccount = activeAccountAddress(currentAccounts, current);
381
+ const incomingAccount = activeAccountAddress(incomingAccounts, incoming);
382
+ if (currentAccount === incomingAccount) {
383
+ return "unchanged";
384
+ }
385
+ return incomingAccount === null ? "cleared" : "set";
386
+ }
387
+ function activeAccountAddress(accounts, context) {
388
+ const accountId = context[0]?.account_id ?? null;
389
+ if (accountId === null) {
390
+ return null;
391
+ }
392
+ return accounts.find((account) => account.id === accountId)?.sui_address ?? null;
393
+ }
394
+ export function maxNumber(values) {
395
+ return values.reduce((max, value) => Math.max(max, value), 0);
396
+ }
@@ -0,0 +1 @@
1
+ export const DB_USER_VERSION = 5;