@archipelagolab/lobi 1.0.0

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 (315) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/ENDOFFILE +0 -0
  3. package/EOF +0 -0
  4. package/LICENSE +21 -0
  5. package/SPEC-SUPPORT.md +116 -0
  6. package/YAMLEND +0 -0
  7. package/api.ts +18 -0
  8. package/archipelagolab-lobi-1.0.0.tgz +0 -0
  9. package/auth-presence.ts +56 -0
  10. package/channel-plugin-api.ts +3 -0
  11. package/cli-metadata.ts +11 -0
  12. package/contract-api.ts +17 -0
  13. package/docs/CHECKLIST.md +83 -0
  14. package/docs/FORK_SDK_GUIDE.md +279 -0
  15. package/helper-api.ts +3 -0
  16. package/index.test.ts +61 -0
  17. package/index.ts +65 -0
  18. package/openclaw.plugin.json +23 -0
  19. package/package.json +52 -0
  20. package/plugin-entry.handlers.runtime.ts +1 -0
  21. package/runtime-api.ts +54 -0
  22. package/runtime-heavy-api.ts +1 -0
  23. package/scripts/migrate-to-lobi.sh +72 -0
  24. package/secret-contract-api.ts +5 -0
  25. package/setup-entry.ts +13 -0
  26. package/src/account-selection.test.ts +124 -0
  27. package/src/account-selection.ts +226 -0
  28. package/src/actions.account-propagation.test.ts +251 -0
  29. package/src/actions.test.ts +251 -0
  30. package/src/actions.ts +336 -0
  31. package/src/approval-auth.test.ts +23 -0
  32. package/src/approval-auth.ts +25 -0
  33. package/src/approval-handler.runtime.test.ts +46 -0
  34. package/src/approval-handler.runtime.ts +400 -0
  35. package/src/approval-ids.ts +6 -0
  36. package/src/approval-native.test.ts +329 -0
  37. package/src/approval-native.ts +336 -0
  38. package/src/approval-reactions.test.ts +107 -0
  39. package/src/approval-reactions.ts +158 -0
  40. package/src/auth-precedence.ts +61 -0
  41. package/src/channel-account-paths.ts +92 -0
  42. package/src/channel.account-paths.test.ts +102 -0
  43. package/src/channel.directory.test.ts +601 -0
  44. package/src/channel.resolve.test.ts +38 -0
  45. package/src/channel.runtime.ts +16 -0
  46. package/src/channel.setup.test.ts +269 -0
  47. package/src/channel.ts +570 -0
  48. package/src/cli-metadata.ts +19 -0
  49. package/src/cli.test.ts +1015 -0
  50. package/src/cli.ts +1198 -0
  51. package/src/config-adapter.ts +41 -0
  52. package/src/config-schema.test.ts +90 -0
  53. package/src/config-schema.ts +114 -0
  54. package/src/directory-live.test.ts +200 -0
  55. package/src/directory-live.ts +238 -0
  56. package/src/doctor-contract.ts +287 -0
  57. package/src/doctor.test.ts +440 -0
  58. package/src/doctor.ts +262 -0
  59. package/src/env-vars.ts +92 -0
  60. package/src/exec-approval-resolver.test.ts +68 -0
  61. package/src/exec-approval-resolver.ts +23 -0
  62. package/src/exec-approvals.test.ts +483 -0
  63. package/src/exec-approvals.ts +290 -0
  64. package/src/group-mentions.ts +41 -0
  65. package/src/legacy-crypto-inspector-availability.test.ts +81 -0
  66. package/src/legacy-crypto-inspector-availability.ts +60 -0
  67. package/src/legacy-crypto.test.ts +234 -0
  68. package/src/legacy-crypto.ts +549 -0
  69. package/src/legacy-state.test.ts +86 -0
  70. package/src/legacy-state.ts +156 -0
  71. package/src/matrix/account-config.ts +150 -0
  72. package/src/matrix/accounts.readiness.test.ts +27 -0
  73. package/src/matrix/accounts.test.ts +757 -0
  74. package/src/matrix/accounts.ts +194 -0
  75. package/src/matrix/actions/client.test.ts +215 -0
  76. package/src/matrix/actions/client.ts +31 -0
  77. package/src/matrix/actions/devices.test.ts +114 -0
  78. package/src/matrix/actions/devices.ts +34 -0
  79. package/src/matrix/actions/limits.test.ts +15 -0
  80. package/src/matrix/actions/limits.ts +6 -0
  81. package/src/matrix/actions/messages.test.ts +289 -0
  82. package/src/matrix/actions/messages.ts +123 -0
  83. package/src/matrix/actions/pins.test.ts +74 -0
  84. package/src/matrix/actions/pins.ts +64 -0
  85. package/src/matrix/actions/polls.test.ts +71 -0
  86. package/src/matrix/actions/polls.ts +109 -0
  87. package/src/matrix/actions/profile.test.ts +109 -0
  88. package/src/matrix/actions/profile.ts +37 -0
  89. package/src/matrix/actions/reactions.test.ts +135 -0
  90. package/src/matrix/actions/reactions.ts +59 -0
  91. package/src/matrix/actions/room.test.ts +79 -0
  92. package/src/matrix/actions/room.ts +71 -0
  93. package/src/matrix/actions/summary.test.ts +87 -0
  94. package/src/matrix/actions/summary.ts +88 -0
  95. package/src/matrix/actions/types.ts +82 -0
  96. package/src/matrix/actions/verification.test.ts +105 -0
  97. package/src/matrix/actions/verification.ts +237 -0
  98. package/src/matrix/actions.ts +37 -0
  99. package/src/matrix/active-client.ts +26 -0
  100. package/src/matrix/async-lock.ts +18 -0
  101. package/src/matrix/backup-health.ts +115 -0
  102. package/src/matrix/client/config-runtime-api.ts +14 -0
  103. package/src/matrix/client/config-secret-input.runtime.ts +1 -0
  104. package/src/matrix/client/config.ts +982 -0
  105. package/src/matrix/client/create-client.test.ts +115 -0
  106. package/src/matrix/client/create-client.ts +101 -0
  107. package/src/matrix/client/env-auth.ts +6 -0
  108. package/src/matrix/client/file-sync-store.test.ts +265 -0
  109. package/src/matrix/client/file-sync-store.ts +289 -0
  110. package/src/matrix/client/logging.ts +123 -0
  111. package/src/matrix/client/migration-snapshot.runtime.ts +1 -0
  112. package/src/matrix/client/private-network-host.ts +56 -0
  113. package/src/matrix/client/runtime.ts +4 -0
  114. package/src/matrix/client/shared.test.ts +344 -0
  115. package/src/matrix/client/shared.ts +306 -0
  116. package/src/matrix/client/storage.test.ts +634 -0
  117. package/src/matrix/client/storage.ts +544 -0
  118. package/src/matrix/client/types.ts +50 -0
  119. package/src/matrix/client-bootstrap.test.ts +84 -0
  120. package/src/matrix/client-bootstrap.ts +164 -0
  121. package/src/matrix/client-resolver.test-helpers.ts +147 -0
  122. package/src/matrix/client.test.ts +1521 -0
  123. package/src/matrix/client.ts +23 -0
  124. package/src/matrix/config-paths.ts +31 -0
  125. package/src/matrix/config-update.test.ts +237 -0
  126. package/src/matrix/config-update.ts +291 -0
  127. package/src/matrix/credentials-read.ts +206 -0
  128. package/src/matrix/credentials-write.runtime.ts +26 -0
  129. package/src/matrix/credentials.test.ts +501 -0
  130. package/src/matrix/credentials.ts +95 -0
  131. package/src/matrix/deps.test.ts +74 -0
  132. package/src/matrix/deps.ts +225 -0
  133. package/src/matrix/device-health.test.ts +45 -0
  134. package/src/matrix/device-health.ts +31 -0
  135. package/src/matrix/direct-management.test.ts +350 -0
  136. package/src/matrix/direct-management.ts +347 -0
  137. package/src/matrix/direct-room.test.ts +61 -0
  138. package/src/matrix/direct-room.ts +128 -0
  139. package/src/matrix/draft-stream.test.ts +406 -0
  140. package/src/matrix/draft-stream.ts +216 -0
  141. package/src/matrix/encryption-guidance.ts +27 -0
  142. package/src/matrix/errors.ts +21 -0
  143. package/src/matrix/format.test.ts +340 -0
  144. package/src/matrix/format.ts +428 -0
  145. package/src/matrix/legacy-crypto-inspector.ts +95 -0
  146. package/src/matrix/media-errors.ts +20 -0
  147. package/src/matrix/media-text.ts +169 -0
  148. package/src/matrix/monitor/access-state.test.ts +45 -0
  149. package/src/matrix/monitor/access-state.ts +77 -0
  150. package/src/matrix/monitor/ack-config.test.ts +57 -0
  151. package/src/matrix/monitor/ack-config.ts +26 -0
  152. package/src/matrix/monitor/allowlist.test.ts +45 -0
  153. package/src/matrix/monitor/allowlist.ts +94 -0
  154. package/src/matrix/monitor/auto-join.test.ts +203 -0
  155. package/src/matrix/monitor/auto-join.ts +86 -0
  156. package/src/matrix/monitor/config.test.ts +197 -0
  157. package/src/matrix/monitor/config.ts +303 -0
  158. package/src/matrix/monitor/context-summary.ts +43 -0
  159. package/src/matrix/monitor/direct.test.ts +529 -0
  160. package/src/matrix/monitor/direct.ts +270 -0
  161. package/src/matrix/monitor/events.test.ts +1524 -0
  162. package/src/matrix/monitor/events.ts +213 -0
  163. package/src/matrix/monitor/handler.body-for-agent.test.ts +396 -0
  164. package/src/matrix/monitor/handler.group-history.test.ts +648 -0
  165. package/src/matrix/monitor/handler.media-failure.test.ts +267 -0
  166. package/src/matrix/monitor/handler.test-helpers.ts +308 -0
  167. package/src/matrix/monitor/handler.test.ts +2952 -0
  168. package/src/matrix/monitor/handler.thread-root-media.test.ts +82 -0
  169. package/src/matrix/monitor/handler.ts +1679 -0
  170. package/src/matrix/monitor/inbound-dedupe.test.ts +146 -0
  171. package/src/matrix/monitor/inbound-dedupe.ts +267 -0
  172. package/src/matrix/monitor/index.test.ts +920 -0
  173. package/src/matrix/monitor/index.ts +434 -0
  174. package/src/matrix/monitor/legacy-crypto-restore.test.ts +206 -0
  175. package/src/matrix/monitor/legacy-crypto-restore.ts +139 -0
  176. package/src/matrix/monitor/location.ts +100 -0
  177. package/src/matrix/monitor/media.test.ts +159 -0
  178. package/src/matrix/monitor/media.ts +119 -0
  179. package/src/matrix/monitor/mentions.test.ts +289 -0
  180. package/src/matrix/monitor/mentions.ts +177 -0
  181. package/src/matrix/monitor/reaction-events.test.ts +326 -0
  182. package/src/matrix/monitor/reaction-events.ts +187 -0
  183. package/src/matrix/monitor/recent-invite.test.ts +92 -0
  184. package/src/matrix/monitor/recent-invite.ts +30 -0
  185. package/src/matrix/monitor/replies.test.ts +265 -0
  186. package/src/matrix/monitor/replies.ts +136 -0
  187. package/src/matrix/monitor/reply-context.test.ts +276 -0
  188. package/src/matrix/monitor/reply-context.ts +92 -0
  189. package/src/matrix/monitor/room-history.test.ts +258 -0
  190. package/src/matrix/monitor/room-history.ts +301 -0
  191. package/src/matrix/monitor/room-info.test.ts +201 -0
  192. package/src/matrix/monitor/room-info.ts +126 -0
  193. package/src/matrix/monitor/rooms.test.ts +121 -0
  194. package/src/matrix/monitor/rooms.ts +52 -0
  195. package/src/matrix/monitor/route.test.ts +255 -0
  196. package/src/matrix/monitor/route.ts +178 -0
  197. package/src/matrix/monitor/runtime-api.ts +31 -0
  198. package/src/matrix/monitor/startup-verification.test.ts +294 -0
  199. package/src/matrix/monitor/startup-verification.ts +237 -0
  200. package/src/matrix/monitor/startup.test.ts +257 -0
  201. package/src/matrix/monitor/startup.ts +218 -0
  202. package/src/matrix/monitor/status.ts +111 -0
  203. package/src/matrix/monitor/sync-lifecycle.test.ts +224 -0
  204. package/src/matrix/monitor/sync-lifecycle.ts +91 -0
  205. package/src/matrix/monitor/task-runner.ts +38 -0
  206. package/src/matrix/monitor/thread-context.test.ts +149 -0
  207. package/src/matrix/monitor/thread-context.ts +108 -0
  208. package/src/matrix/monitor/threads.test.ts +68 -0
  209. package/src/matrix/monitor/threads.ts +85 -0
  210. package/src/matrix/monitor/types.ts +30 -0
  211. package/src/matrix/monitor/verification-events.ts +627 -0
  212. package/src/matrix/monitor/verification-utils.test.ts +47 -0
  213. package/src/matrix/monitor/verification-utils.ts +46 -0
  214. package/src/matrix/outbound-media-runtime.ts +1 -0
  215. package/src/matrix/poll-summary.ts +110 -0
  216. package/src/matrix/poll-types.test.ts +205 -0
  217. package/src/matrix/poll-types.ts +433 -0
  218. package/src/matrix/probe.runtime.ts +4 -0
  219. package/src/matrix/probe.test.ts +154 -0
  220. package/src/matrix/probe.ts +96 -0
  221. package/src/matrix/profile.test.ts +154 -0
  222. package/src/matrix/profile.ts +184 -0
  223. package/src/matrix/reaction-common.test.ts +96 -0
  224. package/src/matrix/reaction-common.ts +147 -0
  225. package/src/matrix/sdk/crypto-bootstrap.test.ts +505 -0
  226. package/src/matrix/sdk/crypto-bootstrap.ts +341 -0
  227. package/src/matrix/sdk/crypto-facade.test.ts +197 -0
  228. package/src/matrix/sdk/crypto-facade.ts +207 -0
  229. package/src/matrix/sdk/crypto-node.runtime.test.ts +27 -0
  230. package/src/matrix/sdk/crypto-node.runtime.ts +9 -0
  231. package/src/matrix/sdk/crypto-runtime.ts +11 -0
  232. package/src/matrix/sdk/decrypt-bridge.ts +356 -0
  233. package/src/matrix/sdk/event-helpers.test.ts +60 -0
  234. package/src/matrix/sdk/event-helpers.ts +71 -0
  235. package/src/matrix/sdk/http-client.test.ts +134 -0
  236. package/src/matrix/sdk/http-client.ts +87 -0
  237. package/src/matrix/sdk/idb-persistence-lock.ts +51 -0
  238. package/src/matrix/sdk/idb-persistence.lock-order.test.ts +108 -0
  239. package/src/matrix/sdk/idb-persistence.test-helpers.ts +88 -0
  240. package/src/matrix/sdk/idb-persistence.test.ts +149 -0
  241. package/src/matrix/sdk/idb-persistence.ts +283 -0
  242. package/src/matrix/sdk/logger.test.ts +25 -0
  243. package/src/matrix/sdk/logger.ts +108 -0
  244. package/src/matrix/sdk/read-response-with-limit.ts +19 -0
  245. package/src/matrix/sdk/recovery-key-store.test.ts +385 -0
  246. package/src/matrix/sdk/recovery-key-store.ts +430 -0
  247. package/src/matrix/sdk/transport.test.ts +161 -0
  248. package/src/matrix/sdk/transport.ts +344 -0
  249. package/src/matrix/sdk/types.ts +236 -0
  250. package/src/matrix/sdk/verification-manager.test.ts +509 -0
  251. package/src/matrix/sdk/verification-manager.ts +694 -0
  252. package/src/matrix/sdk/verification-status.ts +23 -0
  253. package/src/matrix/sdk.test.ts +2568 -0
  254. package/src/matrix/sdk.ts +1789 -0
  255. package/src/matrix/send/client.test.ts +174 -0
  256. package/src/matrix/send/client.ts +90 -0
  257. package/src/matrix/send/formatting.ts +189 -0
  258. package/src/matrix/send/media.ts +244 -0
  259. package/src/matrix/send/targets.test.ts +254 -0
  260. package/src/matrix/send/targets.ts +104 -0
  261. package/src/matrix/send/types.ts +134 -0
  262. package/src/matrix/send.test.ts +958 -0
  263. package/src/matrix/send.ts +609 -0
  264. package/src/matrix/session-store-metadata.ts +108 -0
  265. package/src/matrix/startup-abort.ts +44 -0
  266. package/src/matrix/sync-state.ts +27 -0
  267. package/src/matrix/target-ids.ts +102 -0
  268. package/src/matrix/thread-bindings-shared.ts +201 -0
  269. package/src/matrix/thread-bindings.test.ts +673 -0
  270. package/src/matrix/thread-bindings.ts +577 -0
  271. package/src/matrix-migration.runtime.ts +9 -0
  272. package/src/migration-config.test.ts +228 -0
  273. package/src/migration-config.ts +243 -0
  274. package/src/migration-snapshot-backup.ts +117 -0
  275. package/src/migration-snapshot.test.ts +184 -0
  276. package/src/migration-snapshot.ts +55 -0
  277. package/src/onboarding.resolve.test.ts +55 -0
  278. package/src/onboarding.test-harness.ts +158 -0
  279. package/src/onboarding.test.ts +665 -0
  280. package/src/onboarding.ts +773 -0
  281. package/src/outbound.test.ts +173 -0
  282. package/src/outbound.ts +78 -0
  283. package/src/plugin-entry.runtime.js +159 -0
  284. package/src/plugin-entry.runtime.test.ts +108 -0
  285. package/src/plugin-entry.runtime.ts +68 -0
  286. package/src/profile-update.ts +68 -0
  287. package/src/record-shared.ts +3 -0
  288. package/src/resolve-targets.test.ts +178 -0
  289. package/src/resolve-targets.ts +175 -0
  290. package/src/resolver.ts +21 -0
  291. package/src/runtime-api.ts +144 -0
  292. package/src/runtime.ts +7 -0
  293. package/src/secret-contract.ts +174 -0
  294. package/src/session-route.test.ts +315 -0
  295. package/src/session-route.ts +113 -0
  296. package/src/setup-bootstrap.ts +94 -0
  297. package/src/setup-config.ts +222 -0
  298. package/src/setup-contract.ts +89 -0
  299. package/src/setup-core.test.ts +326 -0
  300. package/src/setup-core.ts +50 -0
  301. package/src/setup-surface.ts +4 -0
  302. package/src/startup-maintenance.test.ts +227 -0
  303. package/src/startup-maintenance.ts +114 -0
  304. package/src/storage-paths.ts +92 -0
  305. package/src/test-helpers.ts +42 -0
  306. package/src/test-mocks.ts +55 -0
  307. package/src/test-runtime.ts +72 -0
  308. package/src/test-support/monitor-route-test-support.ts +8 -0
  309. package/src/tool-actions.runtime.ts +1 -0
  310. package/src/tool-actions.test.ts +422 -0
  311. package/src/tool-actions.ts +498 -0
  312. package/src/types.ts +230 -0
  313. package/test-api.ts +2 -0
  314. package/thread-bindings-runtime.ts +4 -0
  315. package/tsconfig.json +16 -0
@@ -0,0 +1,509 @@
1
+ import { EventEmitter } from "node:events";
2
+ import {
3
+ VerificationPhase,
4
+ VerificationRequestEvent,
5
+ } from "@archipelagolab/lobi-js-sdk/lib/crypto-api/verification.js";
6
+ import { describe, expect, it, vi } from "vitest";
7
+ import {
8
+ MatrixVerificationManager,
9
+ type MatrixShowQrCodeCallbacks,
10
+ type MatrixShowSasCallbacks,
11
+ type MatrixVerificationRequestLike,
12
+ type MatrixVerifierLike,
13
+ } from "./verification-manager.js";
14
+
15
+ class MockVerifier extends EventEmitter implements MatrixVerifierLike {
16
+ constructor(
17
+ private readonly sasCallbacks: MatrixShowSasCallbacks | null,
18
+ private readonly qrCallbacks: MatrixShowQrCodeCallbacks | null,
19
+ private readonly verifyImpl: () => Promise<void> = async () => {},
20
+ ) {
21
+ super();
22
+ }
23
+
24
+ verify(): Promise<void> {
25
+ return this.verifyImpl();
26
+ }
27
+
28
+ cancel(_e: Error): void {
29
+ void _e;
30
+ }
31
+
32
+ getShowSasCallbacks(): MatrixShowSasCallbacks | null {
33
+ return this.sasCallbacks;
34
+ }
35
+
36
+ getReciprocateQrCodeCallbacks(): MatrixShowQrCodeCallbacks | null {
37
+ return this.qrCallbacks;
38
+ }
39
+ }
40
+
41
+ class MockVerificationRequest extends EventEmitter implements MatrixVerificationRequestLike {
42
+ transactionId?: string;
43
+ roomId?: string;
44
+ initiatedByMe = false;
45
+ otherUserId = "@alice:example.org";
46
+ otherDeviceId?: string;
47
+ isSelfVerification = false;
48
+ phase = VerificationPhase.Requested;
49
+ pending = true;
50
+ accepting = false;
51
+ declining = false;
52
+ methods: string[] = ["m.sas.v1"];
53
+ chosenMethod?: string | null;
54
+ cancellationCode?: string | null;
55
+ verifier?: MatrixVerifierLike;
56
+
57
+ constructor(init?: Partial<MockVerificationRequest>) {
58
+ super();
59
+ Object.assign(this, init);
60
+ }
61
+
62
+ accept = vi.fn(async () => {
63
+ this.phase = VerificationPhase.Ready;
64
+ });
65
+
66
+ cancel = vi.fn(async () => {
67
+ this.phase = VerificationPhase.Cancelled;
68
+ });
69
+
70
+ startVerification = vi.fn(async (_method: string) => {
71
+ if (!this.verifier) {
72
+ throw new Error("verifier not configured");
73
+ }
74
+ this.phase = VerificationPhase.Started;
75
+ return this.verifier;
76
+ });
77
+
78
+ scanQRCode = vi.fn(async (_qrCodeData: Uint8ClampedArray) => {
79
+ if (!this.verifier) {
80
+ throw new Error("verifier not configured");
81
+ }
82
+ this.phase = VerificationPhase.Started;
83
+ return this.verifier;
84
+ });
85
+
86
+ generateQRCode = vi.fn(async () => new Uint8ClampedArray([1, 2, 3]));
87
+ }
88
+
89
+ function createSasVerifierFixture(params: {
90
+ decimal: [number, number, number];
91
+ emoji: [string, string][];
92
+ verifyImpl?: () => Promise<void>;
93
+ }) {
94
+ const confirm = vi.fn(async () => {});
95
+ const mismatch = vi.fn();
96
+ const cancel = vi.fn();
97
+ const verify = vi.fn(params.verifyImpl ?? (async () => {}));
98
+ return {
99
+ confirm,
100
+ mismatch,
101
+ verify,
102
+ verifier: new MockVerifier(
103
+ {
104
+ sas: {
105
+ decimal: params.decimal,
106
+ emoji: params.emoji,
107
+ },
108
+ confirm,
109
+ mismatch,
110
+ cancel,
111
+ },
112
+ null,
113
+ verify,
114
+ ),
115
+ };
116
+ }
117
+
118
+ function createReadyRequestWithoutVerifier(params: {
119
+ transactionId: string;
120
+ isSelfVerification: boolean;
121
+ verifier: MatrixVerifierLike;
122
+ }) {
123
+ const request = new MockVerificationRequest({
124
+ transactionId: params.transactionId,
125
+ initiatedByMe: false,
126
+ isSelfVerification: params.isSelfVerification,
127
+ verifier: undefined,
128
+ });
129
+ request.startVerification = vi.fn(async (_method: string) => {
130
+ request.phase = VerificationPhase.Started;
131
+ request.verifier = params.verifier;
132
+ return params.verifier;
133
+ });
134
+ return request;
135
+ }
136
+
137
+ function expectTrackedSas(
138
+ manager: MatrixVerificationManager,
139
+ trackedId: string,
140
+ decimal: [number, number, number],
141
+ ) {
142
+ const summary = manager.listVerifications().find((item) => item.id === trackedId);
143
+ expect(summary?.hasSas).toBe(true);
144
+ expect(summary?.sas?.decimal).toEqual(decimal);
145
+ expect(manager.getVerificationSas(trackedId).decimal).toEqual(decimal);
146
+ }
147
+
148
+ describe("MatrixVerificationManager", () => {
149
+ it("handles rust verification requests whose methods getter throws", () => {
150
+ const manager = new MatrixVerificationManager();
151
+ const request = new MockVerificationRequest({
152
+ transactionId: "txn-rust-methods",
153
+ phase: VerificationPhase.Requested,
154
+ initiatedByMe: true,
155
+ });
156
+ Object.defineProperty(request, "methods", {
157
+ get() {
158
+ throw new Error("not implemented");
159
+ },
160
+ });
161
+
162
+ const summary = manager.trackVerificationRequest(request);
163
+
164
+ expect(summary.id).toBeTruthy();
165
+ expect(summary.methods).toEqual([]);
166
+ expect(summary.phaseName).toBe("requested");
167
+ });
168
+
169
+ it("reuses the same tracked id for repeated transaction IDs", () => {
170
+ const manager = new MatrixVerificationManager();
171
+ const first = new MockVerificationRequest({
172
+ transactionId: "txn-1",
173
+ phase: VerificationPhase.Requested,
174
+ });
175
+ const second = new MockVerificationRequest({
176
+ transactionId: "txn-1",
177
+ phase: VerificationPhase.Ready,
178
+ pending: false,
179
+ chosenMethod: "m.sas.v1",
180
+ });
181
+
182
+ const firstSummary = manager.trackVerificationRequest(first);
183
+ const secondSummary = manager.trackVerificationRequest(second);
184
+
185
+ expect(secondSummary.id).toBe(firstSummary.id);
186
+ expect(secondSummary.phase).toBe(VerificationPhase.Ready);
187
+ expect(secondSummary.pending).toBe(false);
188
+ expect(secondSummary.chosenMethod).toBe("m.sas.v1");
189
+ });
190
+
191
+ it("starts SAS verification and exposes SAS payload/callback flow", async () => {
192
+ const confirm = vi.fn(async () => {});
193
+ const mismatch = vi.fn();
194
+ const verifier = new MockVerifier(
195
+ {
196
+ sas: {
197
+ decimal: [111, 222, 333],
198
+ emoji: [
199
+ ["cat", "cat"],
200
+ ["dog", "dog"],
201
+ ["fox", "fox"],
202
+ ],
203
+ },
204
+ confirm,
205
+ mismatch,
206
+ cancel: vi.fn(),
207
+ },
208
+ null,
209
+ async () => {},
210
+ );
211
+ const request = new MockVerificationRequest({
212
+ transactionId: "txn-2",
213
+ verifier,
214
+ });
215
+ const manager = new MatrixVerificationManager();
216
+ const tracked = manager.trackVerificationRequest(request);
217
+
218
+ const started = await manager.startVerification(tracked.id, "sas");
219
+ expect(started.hasSas).toBe(true);
220
+ expect(started.sas?.decimal).toEqual([111, 222, 333]);
221
+ expect(started.sas?.emoji?.length).toBe(3);
222
+
223
+ const sas = manager.getVerificationSas(tracked.id);
224
+ expect(sas.decimal).toEqual([111, 222, 333]);
225
+ expect(sas.emoji?.length).toBe(3);
226
+
227
+ await manager.confirmVerificationSas(tracked.id);
228
+ expect(confirm).toHaveBeenCalledTimes(1);
229
+
230
+ manager.mismatchVerificationSas(tracked.id);
231
+ expect(mismatch).toHaveBeenCalledTimes(1);
232
+ });
233
+
234
+ it("auto-starts an incoming verifier exposed via request change events", async () => {
235
+ const { verifier, verify } = createSasVerifierFixture({
236
+ decimal: [6158, 1986, 3513],
237
+ emoji: [
238
+ ["gift", "Gift"],
239
+ ["globe", "Globe"],
240
+ ["horse", "Horse"],
241
+ ],
242
+ });
243
+ const request = new MockVerificationRequest({
244
+ transactionId: "txn-incoming-change",
245
+ verifier: undefined,
246
+ });
247
+ const manager = new MatrixVerificationManager();
248
+ const tracked = manager.trackVerificationRequest(request);
249
+
250
+ request.verifier = verifier;
251
+ request.emit(VerificationRequestEvent.Change);
252
+
253
+ await vi.waitFor(() => {
254
+ expect(verify).toHaveBeenCalledTimes(1);
255
+ });
256
+ expectTrackedSas(manager, tracked.id, [6158, 1986, 3513]);
257
+ });
258
+
259
+ it("emits summary updates when SAS becomes available", async () => {
260
+ const { verifier } = createSasVerifierFixture({
261
+ decimal: [6158, 1986, 3513],
262
+ emoji: [
263
+ ["gift", "Gift"],
264
+ ["globe", "Globe"],
265
+ ["horse", "Horse"],
266
+ ],
267
+ });
268
+ const request = new MockVerificationRequest({
269
+ transactionId: "txn-summary-listener",
270
+ roomId: "!dm:example.org",
271
+ verifier: undefined,
272
+ });
273
+ const manager = new MatrixVerificationManager();
274
+ const summaries: ReturnType<typeof manager.listVerifications> = [];
275
+ manager.onSummaryChanged((summary) => {
276
+ summaries.push(summary);
277
+ });
278
+
279
+ manager.trackVerificationRequest(request);
280
+ request.verifier = verifier;
281
+ request.emit(VerificationRequestEvent.Change);
282
+
283
+ await vi.waitFor(() => {
284
+ expect(
285
+ summaries.some(
286
+ (summary) =>
287
+ summary.transactionId === "txn-summary-listener" &&
288
+ summary.roomId === "!dm:example.org" &&
289
+ summary.hasSas,
290
+ ),
291
+ ).toBe(true);
292
+ });
293
+ });
294
+
295
+ it("does not auto-start non-self inbound SAS when request becomes ready without a verifier", async () => {
296
+ const { verifier, verify } = createSasVerifierFixture({
297
+ decimal: [1234, 5678, 9012],
298
+ emoji: [
299
+ ["gift", "Gift"],
300
+ ["rocket", "Rocket"],
301
+ ["butterfly", "Butterfly"],
302
+ ],
303
+ });
304
+ const request = createReadyRequestWithoutVerifier({
305
+ transactionId: "txn-no-auto-start-dm-sas",
306
+ isSelfVerification: false,
307
+ verifier,
308
+ });
309
+ const manager = new MatrixVerificationManager();
310
+ const tracked = manager.trackVerificationRequest(request);
311
+
312
+ request.phase = VerificationPhase.Ready;
313
+ request.emit(VerificationRequestEvent.Change);
314
+
315
+ await vi.waitFor(() => {
316
+ expect(manager.listVerifications().find((item) => item.id === tracked.id)?.phase).toBe(
317
+ VerificationPhase.Ready,
318
+ );
319
+ });
320
+ expect(request.startVerification).not.toHaveBeenCalled();
321
+ expect(verify).not.toHaveBeenCalled();
322
+ expect(manager.listVerifications().find((item) => item.id === tracked.id)?.hasSas).toBe(false);
323
+ });
324
+
325
+ it("auto-starts self verification SAS when request becomes ready without a verifier", async () => {
326
+ const { verifier, verify } = createSasVerifierFixture({
327
+ decimal: [1234, 5678, 9012],
328
+ emoji: [
329
+ ["gift", "Gift"],
330
+ ["rocket", "Rocket"],
331
+ ["butterfly", "Butterfly"],
332
+ ],
333
+ });
334
+ const request = createReadyRequestWithoutVerifier({
335
+ transactionId: "txn-auto-start-self-sas",
336
+ isSelfVerification: true,
337
+ verifier,
338
+ });
339
+ const manager = new MatrixVerificationManager();
340
+ const tracked = manager.trackVerificationRequest(request);
341
+
342
+ request.phase = VerificationPhase.Ready;
343
+ request.emit(VerificationRequestEvent.Change);
344
+
345
+ await vi.waitFor(() => {
346
+ expect(request.startVerification).toHaveBeenCalledWith("m.sas.v1");
347
+ });
348
+ await vi.waitFor(() => {
349
+ expect(verify).toHaveBeenCalledTimes(1);
350
+ });
351
+ expectTrackedSas(manager, tracked.id, [1234, 5678, 9012]);
352
+ });
353
+
354
+ it("auto-accepts incoming verification requests only once per transaction", async () => {
355
+ const request = new MockVerificationRequest({
356
+ transactionId: "txn-auto-accept-once",
357
+ initiatedByMe: false,
358
+ isSelfVerification: false,
359
+ phase: VerificationPhase.Requested,
360
+ accepting: false,
361
+ declining: false,
362
+ });
363
+ const manager = new MatrixVerificationManager();
364
+
365
+ manager.trackVerificationRequest(request);
366
+ request.emit(VerificationRequestEvent.Change);
367
+ manager.trackVerificationRequest(request);
368
+
369
+ await vi.waitFor(() => {
370
+ expect(request.accept).toHaveBeenCalledTimes(1);
371
+ });
372
+ });
373
+
374
+ it("auto-confirms inbound SAS after a human-safe delay", async () => {
375
+ vi.useFakeTimers();
376
+ const confirm = vi.fn(async () => {});
377
+ const verifier = new MockVerifier(
378
+ {
379
+ sas: {
380
+ decimal: [6158, 1986, 3513],
381
+ emoji: [
382
+ ["gift", "Gift"],
383
+ ["globe", "Globe"],
384
+ ["horse", "Horse"],
385
+ ],
386
+ },
387
+ confirm,
388
+ mismatch: vi.fn(),
389
+ cancel: vi.fn(),
390
+ },
391
+ null,
392
+ async () => {},
393
+ );
394
+ const request = new MockVerificationRequest({
395
+ transactionId: "txn-auto-confirm",
396
+ initiatedByMe: false,
397
+ verifier,
398
+ });
399
+ try {
400
+ const manager = new MatrixVerificationManager();
401
+ manager.trackVerificationRequest(request);
402
+
403
+ await vi.advanceTimersByTimeAsync(29_000);
404
+ expect(confirm).not.toHaveBeenCalled();
405
+
406
+ await vi.advanceTimersByTimeAsync(1_100);
407
+ expect(confirm).toHaveBeenCalledTimes(1);
408
+ } finally {
409
+ vi.useRealTimers();
410
+ }
411
+ });
412
+
413
+ it("does not auto-confirm SAS for verifications initiated by this device", async () => {
414
+ vi.useFakeTimers();
415
+ const confirm = vi.fn(async () => {});
416
+ const verifier = new MockVerifier(
417
+ {
418
+ sas: {
419
+ decimal: [111, 222, 333],
420
+ emoji: [
421
+ ["cat", "Cat"],
422
+ ["dog", "Dog"],
423
+ ["fox", "Fox"],
424
+ ],
425
+ },
426
+ confirm,
427
+ mismatch: vi.fn(),
428
+ cancel: vi.fn(),
429
+ },
430
+ null,
431
+ async () => {},
432
+ );
433
+ const request = new MockVerificationRequest({
434
+ transactionId: "txn-no-auto-confirm",
435
+ initiatedByMe: true,
436
+ verifier,
437
+ });
438
+ try {
439
+ const manager = new MatrixVerificationManager();
440
+ manager.trackVerificationRequest(request);
441
+
442
+ await vi.advanceTimersByTimeAsync(20);
443
+ expect(confirm).not.toHaveBeenCalled();
444
+ } finally {
445
+ vi.useRealTimers();
446
+ }
447
+ });
448
+
449
+ it("cancels a pending auto-confirm when SAS is explicitly mismatched", async () => {
450
+ vi.useFakeTimers();
451
+ const confirm = vi.fn(async () => {});
452
+ const mismatch = vi.fn();
453
+ const verifier = new MockVerifier(
454
+ {
455
+ sas: {
456
+ decimal: [444, 555, 666],
457
+ emoji: [
458
+ ["panda", "Panda"],
459
+ ["rocket", "Rocket"],
460
+ ["crown", "Crown"],
461
+ ],
462
+ },
463
+ confirm,
464
+ mismatch,
465
+ cancel: vi.fn(),
466
+ },
467
+ null,
468
+ async () => {},
469
+ );
470
+ const request = new MockVerificationRequest({
471
+ transactionId: "txn-mismatch-cancels-auto-confirm",
472
+ initiatedByMe: false,
473
+ verifier,
474
+ });
475
+ try {
476
+ const manager = new MatrixVerificationManager();
477
+ const tracked = manager.trackVerificationRequest(request);
478
+
479
+ manager.mismatchVerificationSas(tracked.id);
480
+ await vi.advanceTimersByTimeAsync(2000);
481
+
482
+ expect(mismatch).toHaveBeenCalledTimes(1);
483
+ expect(confirm).not.toHaveBeenCalled();
484
+ } finally {
485
+ vi.useRealTimers();
486
+ }
487
+ });
488
+
489
+ it("prunes stale terminal sessions during list operations", () => {
490
+ const now = new Date("2026-02-08T15:00:00.000Z").getTime();
491
+ const nowSpy = vi.spyOn(Date, "now");
492
+ nowSpy.mockReturnValue(now);
493
+
494
+ const manager = new MatrixVerificationManager();
495
+ manager.trackVerificationRequest(
496
+ new MockVerificationRequest({
497
+ transactionId: "txn-old-done",
498
+ phase: VerificationPhase.Done,
499
+ pending: false,
500
+ }),
501
+ );
502
+
503
+ nowSpy.mockReturnValue(now + 24 * 60 * 60 * 1000 + 1);
504
+ const summaries = manager.listVerifications();
505
+
506
+ expect(summaries).toHaveLength(0);
507
+ nowSpy.mockRestore();
508
+ });
509
+ });