@zapo-js/fake-server 0.3.0 → 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 (298) hide show
  1. package/README.md +3 -3
  2. package/dist/api/AppStateSyncManager.d.ts +0 -1
  3. package/dist/api/AppStateSyncManager.js +0 -1
  4. package/dist/api/FakePairingDriver.d.ts +0 -1
  5. package/dist/api/FakePairingDriver.js +0 -1
  6. package/dist/api/FakePeer.d.ts +77 -4
  7. package/dist/api/FakePeer.js +201 -1
  8. package/dist/api/FakeWaServer.d.ts +11 -1
  9. package/dist/api/FakeWaServer.js +34 -2
  10. package/dist/api/PreKeyDispenser.d.ts +0 -1
  11. package/dist/api/PreKeyDispenser.js +0 -1
  12. package/dist/api/Scenario.d.ts +0 -1
  13. package/dist/api/Scenario.js +0 -1
  14. package/dist/api/ServerRegistries.d.ts +0 -1
  15. package/dist/api/ServerRegistries.js +0 -1
  16. package/dist/api/iq-handlers.d.ts +0 -1
  17. package/dist/api/iq-handlers.js +0 -1
  18. package/dist/{cli.d.ts → bin.d.ts} +0 -1
  19. package/dist/{cli.js → bin.js} +1 -2
  20. package/dist/esm/api/AppStateSyncManager.js +146 -0
  21. package/dist/esm/api/FakePairingDriver.js +31 -0
  22. package/dist/esm/api/FakePeer.js +604 -0
  23. package/dist/esm/api/FakeWaServer.js +680 -0
  24. package/dist/esm/api/PreKeyDispenser.js +93 -0
  25. package/dist/esm/api/Scenario.js +32 -0
  26. package/dist/esm/api/ServerRegistries.js +261 -0
  27. package/dist/esm/api/iq-handlers.js +492 -0
  28. package/dist/esm/bin.js +246 -0
  29. package/dist/esm/index.js +26 -0
  30. package/dist/esm/infra/WaFakeConnection.js +49 -0
  31. package/dist/esm/infra/WaFakeConnectionPipeline.js +223 -0
  32. package/dist/esm/infra/WaFakeFrameSocket.js +117 -0
  33. package/dist/esm/infra/WaFakeMediaHttpsServer.js +126 -0
  34. package/dist/esm/infra/WaFakeNoiseHandshake.js +67 -0
  35. package/dist/esm/infra/WaFakeTransport.js +31 -0
  36. package/dist/esm/infra/WaFakeWsServer.js +96 -0
  37. package/dist/esm/package.json +3 -0
  38. package/dist/esm/protocol/auth/cert-chain.js +39 -0
  39. package/dist/esm/protocol/auth/client-payload-validate.js +55 -0
  40. package/dist/esm/protocol/auth/fake-primary-device.js +47 -0
  41. package/dist/esm/protocol/auth/pair-device.js +87 -0
  42. package/dist/esm/protocol/auth/success-node.js +26 -0
  43. package/dist/esm/protocol/iq/abprops.js +30 -0
  44. package/dist/esm/protocol/iq/appstate-sync.js +146 -0
  45. package/dist/esm/protocol/iq/business.js +59 -0
  46. package/dist/esm/protocol/iq/dirty-bits.js +19 -0
  47. package/dist/esm/protocol/iq/group-ops.js +154 -0
  48. package/dist/esm/protocol/iq/newsletter.js +14 -0
  49. package/dist/esm/protocol/iq/prekey-fetch.js +88 -0
  50. package/dist/esm/protocol/iq/privacy-token.js +26 -0
  51. package/dist/esm/protocol/iq/privacy.js +123 -0
  52. package/dist/esm/protocol/iq/profile.js +72 -0
  53. package/dist/esm/protocol/iq/router.js +111 -0
  54. package/dist/esm/protocol/iq/usync.js +64 -0
  55. package/dist/esm/protocol/push/app-state-key-share.js +26 -0
  56. package/dist/esm/protocol/push/call-failure.js +27 -0
  57. package/dist/esm/protocol/push/chatstate.js +23 -0
  58. package/dist/esm/protocol/push/error-stanza.js +13 -0
  59. package/dist/esm/protocol/push/history-sync.js +111 -0
  60. package/dist/esm/protocol/push/message.js +38 -0
  61. package/dist/esm/protocol/push/notification.js +29 -0
  62. package/dist/esm/protocol/push/presence.js +14 -0
  63. package/dist/esm/protocol/push/receipt.js +21 -0
  64. package/dist/esm/protocol/signal/fake-app-state-crypto.js +196 -0
  65. package/dist/esm/protocol/signal/fake-peer-double-ratchet.js +398 -0
  66. package/dist/esm/protocol/signal/fake-peer-group-recv-session.js +120 -0
  67. package/dist/esm/protocol/signal/fake-peer-identity.js +8 -0
  68. package/dist/esm/protocol/signal/fake-peer-key-bundle.js +25 -0
  69. package/dist/esm/protocol/signal/fake-sender-key.js +83 -0
  70. package/dist/esm/protocol/signal/prekey-upload.js +107 -0
  71. package/dist/esm/protocol/stream/stream-error.js +56 -0
  72. package/dist/esm/state/fake-app-state-collection.js +134 -0
  73. package/dist/esm/state/fake-media-store.js +53 -0
  74. package/dist/esm/transport/codec.js +8 -0
  75. package/dist/esm/transport/crypto.js +8 -0
  76. package/dist/esm/transport/protos.js +7 -0
  77. package/dist/esm/transport/util.js +8 -0
  78. package/dist/index.d.ts +0 -1
  79. package/dist/index.js +0 -1
  80. package/dist/infra/WaFakeConnection.d.ts +0 -1
  81. package/dist/infra/WaFakeConnection.js +0 -1
  82. package/dist/infra/WaFakeConnectionPipeline.d.ts +0 -1
  83. package/dist/infra/WaFakeConnectionPipeline.js +27 -24
  84. package/dist/infra/WaFakeFrameSocket.d.ts +0 -1
  85. package/dist/infra/WaFakeFrameSocket.js +0 -1
  86. package/dist/infra/WaFakeMediaHttpsServer.d.ts +0 -1
  87. package/dist/infra/WaFakeMediaHttpsServer.js +0 -1
  88. package/dist/infra/WaFakeNoiseHandshake.d.ts +8 -10
  89. package/dist/infra/WaFakeNoiseHandshake.js +19 -24
  90. package/dist/infra/WaFakeTransport.d.ts +2 -4
  91. package/dist/infra/WaFakeTransport.js +2 -1
  92. package/dist/infra/WaFakeWsServer.d.ts +0 -1
  93. package/dist/infra/WaFakeWsServer.js +0 -1
  94. package/dist/protocol/auth/cert-chain.d.ts +0 -1
  95. package/dist/protocol/auth/cert-chain.js +0 -1
  96. package/dist/protocol/auth/client-payload-validate.d.ts +0 -1
  97. package/dist/protocol/auth/client-payload-validate.js +0 -1
  98. package/dist/protocol/auth/fake-primary-device.d.ts +0 -1
  99. package/dist/protocol/auth/fake-primary-device.js +1 -3
  100. package/dist/protocol/auth/pair-device.d.ts +0 -1
  101. package/dist/protocol/auth/pair-device.js +4 -16
  102. package/dist/protocol/auth/success-node.d.ts +0 -1
  103. package/dist/protocol/auth/success-node.js +0 -1
  104. package/dist/protocol/iq/abprops.d.ts +0 -1
  105. package/dist/protocol/iq/abprops.js +0 -1
  106. package/dist/protocol/iq/appstate-sync.d.ts +0 -1
  107. package/dist/protocol/iq/appstate-sync.js +0 -1
  108. package/dist/protocol/iq/business.d.ts +0 -1
  109. package/dist/protocol/iq/business.js +0 -1
  110. package/dist/protocol/iq/dirty-bits.d.ts +0 -1
  111. package/dist/protocol/iq/dirty-bits.js +0 -1
  112. package/dist/protocol/iq/group-ops.d.ts +0 -1
  113. package/dist/protocol/iq/group-ops.js +0 -1
  114. package/dist/protocol/iq/newsletter.d.ts +0 -1
  115. package/dist/protocol/iq/newsletter.js +0 -1
  116. package/dist/protocol/iq/prekey-fetch.d.ts +0 -1
  117. package/dist/protocol/iq/prekey-fetch.js +0 -1
  118. package/dist/protocol/iq/privacy-token.d.ts +0 -1
  119. package/dist/protocol/iq/privacy-token.js +0 -1
  120. package/dist/protocol/iq/privacy.d.ts +0 -1
  121. package/dist/protocol/iq/privacy.js +15 -16
  122. package/dist/protocol/iq/profile.d.ts +0 -1
  123. package/dist/protocol/iq/profile.js +0 -1
  124. package/dist/protocol/iq/router.d.ts +0 -1
  125. package/dist/protocol/iq/router.js +0 -1
  126. package/dist/protocol/iq/usync.d.ts +0 -1
  127. package/dist/protocol/iq/usync.js +0 -1
  128. package/dist/protocol/push/app-state-key-share.d.ts +0 -1
  129. package/dist/protocol/push/app-state-key-share.js +0 -1
  130. package/dist/protocol/push/call-failure.d.ts +0 -1
  131. package/dist/protocol/push/call-failure.js +0 -1
  132. package/dist/protocol/push/chatstate.d.ts +0 -1
  133. package/dist/protocol/push/chatstate.js +0 -1
  134. package/dist/protocol/push/error-stanza.d.ts +0 -1
  135. package/dist/protocol/push/error-stanza.js +0 -1
  136. package/dist/protocol/push/history-sync.d.ts +0 -1
  137. package/dist/protocol/push/history-sync.js +0 -1
  138. package/dist/protocol/push/message.d.ts +0 -1
  139. package/dist/protocol/push/message.js +0 -1
  140. package/dist/protocol/push/notification.d.ts +0 -1
  141. package/dist/protocol/push/notification.js +0 -1
  142. package/dist/protocol/push/presence.d.ts +0 -1
  143. package/dist/protocol/push/presence.js +0 -1
  144. package/dist/protocol/push/receipt.d.ts +0 -1
  145. package/dist/protocol/push/receipt.js +0 -1
  146. package/dist/protocol/signal/fake-app-state-crypto.d.ts +7 -9
  147. package/dist/protocol/signal/fake-app-state-crypto.js +31 -33
  148. package/dist/protocol/signal/fake-peer-double-ratchet.d.ts +0 -1
  149. package/dist/protocol/signal/fake-peer-double-ratchet.js +23 -28
  150. package/dist/protocol/signal/fake-peer-group-recv-session.d.ts +0 -1
  151. package/dist/protocol/signal/fake-peer-group-recv-session.js +6 -10
  152. package/dist/protocol/signal/fake-peer-identity.d.ts +0 -1
  153. package/dist/protocol/signal/fake-peer-identity.js +0 -1
  154. package/dist/protocol/signal/fake-peer-key-bundle.d.ts +0 -1
  155. package/dist/protocol/signal/fake-peer-key-bundle.js +0 -1
  156. package/dist/protocol/signal/fake-sender-key.d.ts +0 -1
  157. package/dist/protocol/signal/fake-sender-key.js +5 -9
  158. package/dist/protocol/signal/prekey-upload.d.ts +0 -1
  159. package/dist/protocol/signal/prekey-upload.js +0 -1
  160. package/dist/protocol/stream/stream-error.d.ts +0 -1
  161. package/dist/protocol/stream/stream-error.js +0 -1
  162. package/dist/state/fake-app-state-collection.d.ts +0 -1
  163. package/dist/state/fake-app-state-collection.js +0 -1
  164. package/dist/state/fake-media-store.d.ts +0 -1
  165. package/dist/state/fake-media-store.js +2 -2
  166. package/dist/transport/codec.d.ts +2 -3
  167. package/dist/transport/codec.js +2 -3
  168. package/dist/transport/crypto.d.ts +5 -7
  169. package/dist/transport/crypto.js +6 -11
  170. package/dist/transport/protos.d.ts +2 -4
  171. package/dist/transport/protos.js +2 -4
  172. package/dist/transport/util.d.ts +8 -0
  173. package/dist/transport/util.js +15 -0
  174. package/package.json +21 -6
  175. package/dist/api/AppStateSyncManager.d.ts.map +0 -1
  176. package/dist/api/AppStateSyncManager.js.map +0 -1
  177. package/dist/api/FakePairingDriver.d.ts.map +0 -1
  178. package/dist/api/FakePairingDriver.js.map +0 -1
  179. package/dist/api/FakePeer.d.ts.map +0 -1
  180. package/dist/api/FakePeer.js.map +0 -1
  181. package/dist/api/FakeWaServer.d.ts.map +0 -1
  182. package/dist/api/FakeWaServer.js.map +0 -1
  183. package/dist/api/PreKeyDispenser.d.ts.map +0 -1
  184. package/dist/api/PreKeyDispenser.js.map +0 -1
  185. package/dist/api/Scenario.d.ts.map +0 -1
  186. package/dist/api/Scenario.js.map +0 -1
  187. package/dist/api/ServerRegistries.d.ts.map +0 -1
  188. package/dist/api/ServerRegistries.js.map +0 -1
  189. package/dist/api/iq-handlers.d.ts.map +0 -1
  190. package/dist/api/iq-handlers.js.map +0 -1
  191. package/dist/cli.d.ts.map +0 -1
  192. package/dist/cli.js.map +0 -1
  193. package/dist/index.d.ts.map +0 -1
  194. package/dist/index.js.map +0 -1
  195. package/dist/infra/WaFakeConnection.d.ts.map +0 -1
  196. package/dist/infra/WaFakeConnection.js.map +0 -1
  197. package/dist/infra/WaFakeConnectionPipeline.d.ts.map +0 -1
  198. package/dist/infra/WaFakeConnectionPipeline.js.map +0 -1
  199. package/dist/infra/WaFakeFrameSocket.d.ts.map +0 -1
  200. package/dist/infra/WaFakeFrameSocket.js.map +0 -1
  201. package/dist/infra/WaFakeMediaHttpsServer.d.ts.map +0 -1
  202. package/dist/infra/WaFakeMediaHttpsServer.js.map +0 -1
  203. package/dist/infra/WaFakeNoiseHandshake.d.ts.map +0 -1
  204. package/dist/infra/WaFakeNoiseHandshake.js.map +0 -1
  205. package/dist/infra/WaFakeTransport.d.ts.map +0 -1
  206. package/dist/infra/WaFakeTransport.js.map +0 -1
  207. package/dist/infra/WaFakeWsServer.d.ts.map +0 -1
  208. package/dist/infra/WaFakeWsServer.js.map +0 -1
  209. package/dist/protocol/auth/cert-chain.d.ts.map +0 -1
  210. package/dist/protocol/auth/cert-chain.js.map +0 -1
  211. package/dist/protocol/auth/client-payload-validate.d.ts.map +0 -1
  212. package/dist/protocol/auth/client-payload-validate.js.map +0 -1
  213. package/dist/protocol/auth/fake-primary-device.d.ts.map +0 -1
  214. package/dist/protocol/auth/fake-primary-device.js.map +0 -1
  215. package/dist/protocol/auth/pair-device.d.ts.map +0 -1
  216. package/dist/protocol/auth/pair-device.js.map +0 -1
  217. package/dist/protocol/auth/success-node.d.ts.map +0 -1
  218. package/dist/protocol/auth/success-node.js.map +0 -1
  219. package/dist/protocol/iq/abprops.d.ts.map +0 -1
  220. package/dist/protocol/iq/abprops.js.map +0 -1
  221. package/dist/protocol/iq/appstate-sync.d.ts.map +0 -1
  222. package/dist/protocol/iq/appstate-sync.js.map +0 -1
  223. package/dist/protocol/iq/business.d.ts.map +0 -1
  224. package/dist/protocol/iq/business.js.map +0 -1
  225. package/dist/protocol/iq/dirty-bits.d.ts.map +0 -1
  226. package/dist/protocol/iq/dirty-bits.js.map +0 -1
  227. package/dist/protocol/iq/group-ops.d.ts.map +0 -1
  228. package/dist/protocol/iq/group-ops.js.map +0 -1
  229. package/dist/protocol/iq/newsletter.d.ts.map +0 -1
  230. package/dist/protocol/iq/newsletter.js.map +0 -1
  231. package/dist/protocol/iq/prekey-fetch.d.ts.map +0 -1
  232. package/dist/protocol/iq/prekey-fetch.js.map +0 -1
  233. package/dist/protocol/iq/privacy-token.d.ts.map +0 -1
  234. package/dist/protocol/iq/privacy-token.js.map +0 -1
  235. package/dist/protocol/iq/privacy.d.ts.map +0 -1
  236. package/dist/protocol/iq/privacy.js.map +0 -1
  237. package/dist/protocol/iq/profile.d.ts.map +0 -1
  238. package/dist/protocol/iq/profile.js.map +0 -1
  239. package/dist/protocol/iq/router.d.ts.map +0 -1
  240. package/dist/protocol/iq/router.js.map +0 -1
  241. package/dist/protocol/iq/usync.d.ts.map +0 -1
  242. package/dist/protocol/iq/usync.js.map +0 -1
  243. package/dist/protocol/push/app-state-key-share.d.ts.map +0 -1
  244. package/dist/protocol/push/app-state-key-share.js.map +0 -1
  245. package/dist/protocol/push/call-failure.d.ts.map +0 -1
  246. package/dist/protocol/push/call-failure.js.map +0 -1
  247. package/dist/protocol/push/chatstate.d.ts.map +0 -1
  248. package/dist/protocol/push/chatstate.js.map +0 -1
  249. package/dist/protocol/push/error-stanza.d.ts.map +0 -1
  250. package/dist/protocol/push/error-stanza.js.map +0 -1
  251. package/dist/protocol/push/history-sync.d.ts.map +0 -1
  252. package/dist/protocol/push/history-sync.js.map +0 -1
  253. package/dist/protocol/push/message.d.ts.map +0 -1
  254. package/dist/protocol/push/message.js.map +0 -1
  255. package/dist/protocol/push/notification.d.ts.map +0 -1
  256. package/dist/protocol/push/notification.js.map +0 -1
  257. package/dist/protocol/push/presence.d.ts.map +0 -1
  258. package/dist/protocol/push/presence.js.map +0 -1
  259. package/dist/protocol/push/receipt.d.ts.map +0 -1
  260. package/dist/protocol/push/receipt.js.map +0 -1
  261. package/dist/protocol/signal/fake-app-state-crypto.d.ts.map +0 -1
  262. package/dist/protocol/signal/fake-app-state-crypto.js.map +0 -1
  263. package/dist/protocol/signal/fake-peer-double-ratchet.d.ts.map +0 -1
  264. package/dist/protocol/signal/fake-peer-double-ratchet.js.map +0 -1
  265. package/dist/protocol/signal/fake-peer-group-recv-session.d.ts.map +0 -1
  266. package/dist/protocol/signal/fake-peer-group-recv-session.js.map +0 -1
  267. package/dist/protocol/signal/fake-peer-identity.d.ts.map +0 -1
  268. package/dist/protocol/signal/fake-peer-identity.js.map +0 -1
  269. package/dist/protocol/signal/fake-peer-key-bundle.d.ts.map +0 -1
  270. package/dist/protocol/signal/fake-peer-key-bundle.js.map +0 -1
  271. package/dist/protocol/signal/fake-peer-recv-session.d.ts +0 -60
  272. package/dist/protocol/signal/fake-peer-recv-session.d.ts.map +0 -1
  273. package/dist/protocol/signal/fake-peer-recv-session.js +0 -284
  274. package/dist/protocol/signal/fake-peer-recv-session.js.map +0 -1
  275. package/dist/protocol/signal/fake-peer-session.d.ts +0 -87
  276. package/dist/protocol/signal/fake-peer-session.d.ts.map +0 -1
  277. package/dist/protocol/signal/fake-peer-session.js +0 -207
  278. package/dist/protocol/signal/fake-peer-session.js.map +0 -1
  279. package/dist/protocol/signal/fake-sender-key.d.ts.map +0 -1
  280. package/dist/protocol/signal/fake-sender-key.js.map +0 -1
  281. package/dist/protocol/signal/prekey-upload.d.ts.map +0 -1
  282. package/dist/protocol/signal/prekey-upload.js.map +0 -1
  283. package/dist/protocol/stream/stream-error.d.ts.map +0 -1
  284. package/dist/protocol/stream/stream-error.js.map +0 -1
  285. package/dist/state/fake-app-state-collection.d.ts.map +0 -1
  286. package/dist/state/fake-app-state-collection.js.map +0 -1
  287. package/dist/state/fake-media-store.d.ts.map +0 -1
  288. package/dist/state/fake-media-store.js.map +0 -1
  289. package/dist/transport/codec.d.ts.map +0 -1
  290. package/dist/transport/codec.js.map +0 -1
  291. package/dist/transport/crypto.d.ts.map +0 -1
  292. package/dist/transport/crypto.js.map +0 -1
  293. package/dist/transport/index.d.ts +0 -4
  294. package/dist/transport/index.d.ts.map +0 -1
  295. package/dist/transport/index.js +0 -20
  296. package/dist/transport/index.js.map +0 -1
  297. package/dist/transport/protos.d.ts.map +0 -1
  298. package/dist/transport/protos.js.map +0 -1
@@ -0,0 +1,93 @@
1
+ import { buildNotification } from '../protocol/push/notification.js';
2
+ export class PreKeyDispenser {
3
+ constructor() {
4
+ this.capturedPreKeyBundle = null;
5
+ this.preKeyDispenserCursor = 0;
6
+ this.preKeyDispenserMisses = 0;
7
+ this.nextPreKeyNotificationId = 1;
8
+ this.preKeyBundleWaiters = new Set();
9
+ }
10
+ captureBundle(bundle) {
11
+ this.capturedPreKeyBundle = bundle;
12
+ this.preKeyDispenserCursor = 0;
13
+ this.preKeyDispenserMisses = 0;
14
+ for (const waiter of this.preKeyBundleWaiters) {
15
+ waiter.resolve(bundle);
16
+ }
17
+ this.preKeyBundleWaiters.clear();
18
+ }
19
+ awaitPreKeyBundle(timeoutMs = 15000) {
20
+ if (this.capturedPreKeyBundle) {
21
+ return Promise.resolve(this.capturedPreKeyBundle);
22
+ }
23
+ return new Promise((resolve, reject) => {
24
+ const waiter = {
25
+ resolve: (bundle) => {
26
+ clearTimeout(waiter.timer);
27
+ this.preKeyBundleWaiters.delete(waiter);
28
+ resolve(bundle);
29
+ },
30
+ reject: (error) => {
31
+ clearTimeout(waiter.timer);
32
+ this.preKeyBundleWaiters.delete(waiter);
33
+ reject(error);
34
+ },
35
+ timer: setTimeout(() => {
36
+ this.preKeyBundleWaiters.delete(waiter);
37
+ reject(new Error(`awaitPreKeyBundle timed out after ${timeoutMs}ms`));
38
+ }, timeoutMs)
39
+ };
40
+ this.preKeyBundleWaiters.add(waiter);
41
+ });
42
+ }
43
+ capturedPreKeyBundleSnapshot() {
44
+ return this.capturedPreKeyBundle;
45
+ }
46
+ dispenseOneTimePreKey() {
47
+ const bundle = this.capturedPreKeyBundle;
48
+ if (!bundle) {
49
+ this.preKeyDispenserMisses += 1;
50
+ return null;
51
+ }
52
+ if (this.preKeyDispenserCursor >= bundle.preKeys.length) {
53
+ this.preKeyDispenserMisses += 1;
54
+ return null;
55
+ }
56
+ const entry = bundle.preKeys[this.preKeyDispenserCursor];
57
+ this.preKeyDispenserCursor += 1;
58
+ return { keyId: entry.keyId, publicKey: entry.publicKey };
59
+ }
60
+ preKeysAvailable() {
61
+ const bundle = this.capturedPreKeyBundle;
62
+ if (!bundle)
63
+ return 0;
64
+ return Math.max(0, bundle.preKeys.length - this.preKeyDispenserCursor);
65
+ }
66
+ preKeyDispenserMissesSnapshot() {
67
+ return this.preKeyDispenserMisses;
68
+ }
69
+ async triggerPreKeyUpload(pipeline, options = {}) {
70
+ const opts = typeof options === 'number' ? { timeoutMs: options } : options;
71
+ const timeoutMs = opts.timeoutMs ?? 15000;
72
+ if (!opts.force && this.capturedPreKeyBundle) {
73
+ return this.capturedPreKeyBundle;
74
+ }
75
+ if (opts.force) {
76
+ this.capturedPreKeyBundle = null;
77
+ this.preKeyDispenserCursor = 0;
78
+ }
79
+ const bundlePromise = this.awaitPreKeyBundle(timeoutMs);
80
+ const id = `prekey-low-${this.nextPreKeyNotificationId++}`;
81
+ await pipeline.sendStanza(buildNotification({
82
+ id,
83
+ type: 'encrypt',
84
+ content: [
85
+ {
86
+ tag: 'count',
87
+ attrs: { value: '0' }
88
+ }
89
+ ]
90
+ }));
91
+ return bundlePromise;
92
+ }
93
+ }
@@ -0,0 +1,32 @@
1
+ export class Scenario {
2
+ constructor(server) {
3
+ this.server = server;
4
+ }
5
+ onIq(matcher) {
6
+ return new IqExpectation(this.server, matcher);
7
+ }
8
+ afterAuth(listener) {
9
+ this.server.onAuthenticatedPipeline(listener);
10
+ }
11
+ }
12
+ export class IqExpectation {
13
+ constructor(server, matcher) {
14
+ this.server = server;
15
+ this.matcher = matcher;
16
+ }
17
+ respondWith(response) {
18
+ this.server.registerIqHandler(this.matcher, () => response);
19
+ return this;
20
+ }
21
+ respond(responder) {
22
+ this.server.registerIqHandler(this.matcher, responder);
23
+ return this;
24
+ }
25
+ respondOnce(response) {
26
+ const unregister = this.server.registerIqHandler(this.matcher, async (iq) => {
27
+ unregister();
28
+ return typeof response === 'function' ? response(iq) : response;
29
+ });
30
+ return this;
31
+ }
32
+ }
@@ -0,0 +1,261 @@
1
+ import { FAKE_DEFAULT_PRIVACY_SETTINGS } from '../protocol/iq/privacy.js';
2
+ export function toUserJidPart(deviceJid) {
3
+ const atIdx = deviceJid.indexOf('@');
4
+ if (atIdx < 0)
5
+ return deviceJid;
6
+ const userPart = deviceJid.slice(0, atIdx);
7
+ const server = deviceJid.slice(atIdx + 1);
8
+ const colonIdx = userPart.indexOf(':');
9
+ const baseUser = colonIdx < 0 ? userPart : userPart.slice(0, colonIdx);
10
+ return `${baseUser}@${server}`;
11
+ }
12
+ export function toDeviceIdPart(deviceJid) {
13
+ const atIdx = deviceJid.indexOf('@');
14
+ if (atIdx < 0)
15
+ return 0;
16
+ const userPart = deviceJid.slice(0, atIdx);
17
+ const colonIdx = userPart.indexOf(':');
18
+ if (colonIdx < 0)
19
+ return 0;
20
+ const parsed = Number.parseInt(userPart.slice(colonIdx + 1), 10);
21
+ return Number.isFinite(parsed) ? parsed : 0;
22
+ }
23
+ export class ServerRegistries {
24
+ constructor() {
25
+ this.peerRegistry = new Map();
26
+ this.deviceIdsByUser = new Map();
27
+ this.groupRegistry = new Map();
28
+ this.privacySettings = FAKE_DEFAULT_PRIVACY_SETTINGS;
29
+ this.blocklistJids = new Set();
30
+ this.profilePicturesByJid = new Map();
31
+ this.businessProfilesByJid = new Map();
32
+ this.latestStatusText = null;
33
+ this.issuedPrivacyTokens = new Map();
34
+ this.abPropsInput = {};
35
+ this.groupOpListeners = new Set();
36
+ this.privacySetListeners = new Set();
37
+ this.blocklistChangeListeners = new Set();
38
+ this.profilePictureSetListeners = new Set();
39
+ this.statusSetListeners = new Set();
40
+ this.logoutListeners = new Set();
41
+ this.privacyTokenIssueListeners = new Set();
42
+ this.dirtyBitsClearListeners = new Set();
43
+ }
44
+ onOutboundGroupOp(listener) {
45
+ this.groupOpListeners.add(listener);
46
+ return () => {
47
+ this.groupOpListeners.delete(listener);
48
+ };
49
+ }
50
+ onOutboundPrivacySet(listener) {
51
+ this.privacySetListeners.add(listener);
52
+ return () => {
53
+ this.privacySetListeners.delete(listener);
54
+ };
55
+ }
56
+ onOutboundBlocklistChange(listener) {
57
+ this.blocklistChangeListeners.add(listener);
58
+ return () => {
59
+ this.blocklistChangeListeners.delete(listener);
60
+ };
61
+ }
62
+ onOutboundProfilePictureSet(listener) {
63
+ this.profilePictureSetListeners.add(listener);
64
+ return () => {
65
+ this.profilePictureSetListeners.delete(listener);
66
+ };
67
+ }
68
+ onOutboundStatusSet(listener) {
69
+ this.statusSetListeners.add(listener);
70
+ return () => {
71
+ this.statusSetListeners.delete(listener);
72
+ };
73
+ }
74
+ onLogout(listener) {
75
+ this.logoutListeners.add(listener);
76
+ return () => {
77
+ this.logoutListeners.delete(listener);
78
+ };
79
+ }
80
+ onOutboundPrivacyTokenIssue(listener) {
81
+ this.privacyTokenIssueListeners.add(listener);
82
+ return () => {
83
+ this.privacyTokenIssueListeners.delete(listener);
84
+ };
85
+ }
86
+ onOutboundDirtyBitsClear(listener) {
87
+ this.dirtyBitsClearListeners.add(listener);
88
+ return () => {
89
+ this.dirtyBitsClearListeners.delete(listener);
90
+ };
91
+ }
92
+ privacyTokensIssuedSnapshot() {
93
+ return new Map(this.issuedPrivacyTokens);
94
+ }
95
+ privacySettingsSnapshot() {
96
+ return this.privacySettings;
97
+ }
98
+ blocklistSnapshot() {
99
+ return [...this.blocklistJids].sort();
100
+ }
101
+ latestStatusSnapshot() {
102
+ return this.latestStatusText;
103
+ }
104
+ groupRegistrySnapshot() {
105
+ const out = new Map();
106
+ for (const [groupJid, metadata] of this.groupRegistry) {
107
+ out.set(groupJid, {
108
+ groupJid: metadata.groupJid,
109
+ subject: metadata.subject,
110
+ description: metadata.description,
111
+ creator: metadata.creator,
112
+ creationSeconds: metadata.creationSeconds,
113
+ participants: metadata.participants
114
+ });
115
+ }
116
+ return out;
117
+ }
118
+ setProfilePictureRecord(jid, picture) {
119
+ this.profilePicturesByJid.set(jid, picture);
120
+ }
121
+ setBusinessProfileRecord(jid, profile) {
122
+ this.businessProfilesByJid.set(jid, profile);
123
+ }
124
+ setAbProps(input) {
125
+ this.abPropsInput = input;
126
+ }
127
+ setPrivacyDisallowedList(category, jids) {
128
+ this.privacySettings = {
129
+ ...this.privacySettings,
130
+ disallowed: {
131
+ ...this.privacySettings.disallowed,
132
+ [category]: [...jids]
133
+ }
134
+ };
135
+ }
136
+ createFakeGroup(input) {
137
+ if (input.participants.length === 0) {
138
+ throw new Error('createFakeGroup requires at least one participant');
139
+ }
140
+ const creator = input.creator ?? toUserJidPart(input.participants[0].jid);
141
+ const mutable = {
142
+ groupJid: input.groupJid,
143
+ subject: input.subject ?? 'Fake Group',
144
+ description: input.description,
145
+ creator,
146
+ creationSeconds: input.creationSeconds ?? Math.floor(Date.now() / 1000),
147
+ participants: [...input.participants]
148
+ };
149
+ this.groupRegistry.set(input.groupJid, mutable);
150
+ return {
151
+ groupJid: mutable.groupJid,
152
+ subject: mutable.subject,
153
+ description: mutable.description,
154
+ creator: mutable.creator,
155
+ creationSeconds: mutable.creationSeconds,
156
+ participants: mutable.participants
157
+ };
158
+ }
159
+ mutatePrivacySettings(category, value) {
160
+ const next = {
161
+ ...this.privacySettings,
162
+ settings: {
163
+ ...this.privacySettings.settings,
164
+ [category]: value
165
+ }
166
+ };
167
+ this.privacySettings = next;
168
+ }
169
+ mutateBlocklist(action, jid) {
170
+ if (action === 'block') {
171
+ this.blocklistJids.add(jid);
172
+ }
173
+ else {
174
+ this.blocklistJids.delete(jid);
175
+ }
176
+ }
177
+ notifyGroupOp(op) {
178
+ for (const listener of this.groupOpListeners) {
179
+ try {
180
+ listener(op);
181
+ }
182
+ catch (error) {
183
+ void error;
184
+ }
185
+ }
186
+ }
187
+ registerPeer(peer) {
188
+ this.peerRegistry.set(peer.jid, peer);
189
+ const userJid = toUserJidPart(peer.jid);
190
+ const deviceId = toDeviceIdPart(peer.jid);
191
+ const ids = this.deviceIdsByUser.get(userJid);
192
+ if (ids) {
193
+ ids.push(deviceId);
194
+ ids.sort((a, b) => a - b);
195
+ }
196
+ else {
197
+ this.deviceIdsByUser.set(userJid, [deviceId]);
198
+ }
199
+ }
200
+ lookupDeviceIdsForUser(userJid) {
201
+ return this.deviceIdsByUser.get(userJid) ?? [];
202
+ }
203
+ notifyProfilePictureSet(op) {
204
+ for (const listener of this.profilePictureSetListeners) {
205
+ try {
206
+ listener(op);
207
+ }
208
+ catch (error) {
209
+ void error;
210
+ }
211
+ }
212
+ }
213
+ notifyStatusSet(text) {
214
+ for (const listener of this.statusSetListeners) {
215
+ try {
216
+ listener({ text });
217
+ }
218
+ catch (error) {
219
+ void error;
220
+ }
221
+ }
222
+ }
223
+ notifyLogout() {
224
+ for (const listener of this.logoutListeners) {
225
+ try {
226
+ listener();
227
+ }
228
+ catch (error) {
229
+ void error;
230
+ }
231
+ }
232
+ }
233
+ notifyPrivacyTokenIssue(token) {
234
+ for (const listener of this.privacyTokenIssueListeners) {
235
+ try {
236
+ listener(token);
237
+ }
238
+ catch (error) {
239
+ void error;
240
+ }
241
+ }
242
+ }
243
+ notifyDirtyBitsClear(op) {
244
+ for (const listener of this.dirtyBitsClearListeners) {
245
+ try {
246
+ listener(op);
247
+ }
248
+ catch (error) {
249
+ void error;
250
+ }
251
+ }
252
+ }
253
+ handleProfilePictureSet(targetJid, newId) {
254
+ this.profilePicturesByJid.set(targetJid, {
255
+ id: newId,
256
+ url: `https://fake-media.local/profile/${targetJid}/${newId}.jpg`,
257
+ directPath: `/profile/${targetJid}/${newId}.jpg`,
258
+ type: 'image'
259
+ });
260
+ }
261
+ }