@zapo-js/fake-server 0.3.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 (238) hide show
  1. package/README.md +176 -0
  2. package/dist/api/AppStateSyncManager.d.ts +27 -0
  3. package/dist/api/AppStateSyncManager.d.ts.map +1 -0
  4. package/dist/api/AppStateSyncManager.js +151 -0
  5. package/dist/api/AppStateSyncManager.js.map +1 -0
  6. package/dist/api/FakePairingDriver.d.ts +27 -0
  7. package/dist/api/FakePairingDriver.d.ts.map +1 -0
  8. package/dist/api/FakePairingDriver.js +36 -0
  9. package/dist/api/FakePairingDriver.js.map +1 -0
  10. package/dist/api/FakePeer.d.ts +143 -0
  11. package/dist/api/FakePeer.d.ts.map +1 -0
  12. package/dist/api/FakePeer.js +408 -0
  13. package/dist/api/FakePeer.js.map +1 -0
  14. package/dist/api/FakeWaServer.d.ts +167 -0
  15. package/dist/api/FakeWaServer.d.ts.map +1 -0
  16. package/dist/api/FakeWaServer.js +652 -0
  17. package/dist/api/FakeWaServer.js.map +1 -0
  18. package/dist/api/PreKeyDispenser.d.ts +23 -0
  19. package/dist/api/PreKeyDispenser.d.ts.map +1 -0
  20. package/dist/api/PreKeyDispenser.js +98 -0
  21. package/dist/api/PreKeyDispenser.js.map +1 -0
  22. package/dist/api/Scenario.d.ts +24 -0
  23. package/dist/api/Scenario.d.ts.map +1 -0
  24. package/dist/api/Scenario.js +38 -0
  25. package/dist/api/Scenario.js.map +1 -0
  26. package/dist/api/ServerRegistries.d.ts +110 -0
  27. package/dist/api/ServerRegistries.d.ts.map +1 -0
  28. package/dist/api/ServerRegistries.js +268 -0
  29. package/dist/api/ServerRegistries.js.map +1 -0
  30. package/dist/api/iq-handlers.d.ts +47 -0
  31. package/dist/api/iq-handlers.d.ts.map +1 -0
  32. package/dist/api/iq-handlers.js +498 -0
  33. package/dist/api/iq-handlers.js.map +1 -0
  34. package/dist/cli.d.ts +4 -0
  35. package/dist/cli.d.ts.map +1 -0
  36. package/dist/cli.js +249 -0
  37. package/dist/cli.js.map +1 -0
  38. package/dist/index.d.ts +51 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +74 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/infra/WaFakeConnection.d.ts +23 -0
  43. package/dist/infra/WaFakeConnection.d.ts.map +1 -0
  44. package/dist/infra/WaFakeConnection.js +54 -0
  45. package/dist/infra/WaFakeConnection.js.map +1 -0
  46. package/dist/infra/WaFakeConnectionPipeline.d.ts +51 -0
  47. package/dist/infra/WaFakeConnectionPipeline.d.ts.map +1 -0
  48. package/dist/infra/WaFakeConnectionPipeline.js +224 -0
  49. package/dist/infra/WaFakeConnectionPipeline.js.map +1 -0
  50. package/dist/infra/WaFakeFrameSocket.d.ts +29 -0
  51. package/dist/infra/WaFakeFrameSocket.d.ts.map +1 -0
  52. package/dist/infra/WaFakeFrameSocket.js +122 -0
  53. package/dist/infra/WaFakeFrameSocket.js.map +1 -0
  54. package/dist/infra/WaFakeMediaHttpsServer.d.ts +16 -0
  55. package/dist/infra/WaFakeMediaHttpsServer.d.ts.map +1 -0
  56. package/dist/infra/WaFakeMediaHttpsServer.js +131 -0
  57. package/dist/infra/WaFakeMediaHttpsServer.js.map +1 -0
  58. package/dist/infra/WaFakeNoiseHandshake.d.ts +23 -0
  59. package/dist/infra/WaFakeNoiseHandshake.d.ts.map +1 -0
  60. package/dist/infra/WaFakeNoiseHandshake.js +76 -0
  61. package/dist/infra/WaFakeNoiseHandshake.js.map +1 -0
  62. package/dist/infra/WaFakeTransport.d.ts +15 -0
  63. package/dist/infra/WaFakeTransport.d.ts.map +1 -0
  64. package/dist/infra/WaFakeTransport.js +34 -0
  65. package/dist/infra/WaFakeTransport.js.map +1 -0
  66. package/dist/infra/WaFakeWsServer.d.ts +29 -0
  67. package/dist/infra/WaFakeWsServer.d.ts.map +1 -0
  68. package/dist/infra/WaFakeWsServer.js +101 -0
  69. package/dist/infra/WaFakeWsServer.js.map +1 -0
  70. package/dist/protocol/auth/cert-chain.d.ts +18 -0
  71. package/dist/protocol/auth/cert-chain.d.ts.map +1 -0
  72. package/dist/protocol/auth/cert-chain.js +44 -0
  73. package/dist/protocol/auth/cert-chain.js.map +1 -0
  74. package/dist/protocol/auth/client-payload-validate.d.ts +21 -0
  75. package/dist/protocol/auth/client-payload-validate.d.ts.map +1 -0
  76. package/dist/protocol/auth/client-payload-validate.js +61 -0
  77. package/dist/protocol/auth/client-payload-validate.js.map +1 -0
  78. package/dist/protocol/auth/fake-primary-device.d.ts +19 -0
  79. package/dist/protocol/auth/fake-primary-device.d.ts.map +1 -0
  80. package/dist/protocol/auth/fake-primary-device.js +53 -0
  81. package/dist/protocol/auth/fake-primary-device.js.map +1 -0
  82. package/dist/protocol/auth/pair-device.d.ts +26 -0
  83. package/dist/protocol/auth/pair-device.d.ts.map +1 -0
  84. package/dist/protocol/auth/pair-device.js +104 -0
  85. package/dist/protocol/auth/pair-device.js.map +1 -0
  86. package/dist/protocol/auth/success-node.d.ts +15 -0
  87. package/dist/protocol/auth/success-node.d.ts.map +1 -0
  88. package/dist/protocol/auth/success-node.js +30 -0
  89. package/dist/protocol/auth/success-node.js.map +1 -0
  90. package/dist/protocol/iq/abprops.d.ts +14 -0
  91. package/dist/protocol/iq/abprops.d.ts.map +1 -0
  92. package/dist/protocol/iq/abprops.js +34 -0
  93. package/dist/protocol/iq/abprops.js.map +1 -0
  94. package/dist/protocol/iq/appstate-sync.d.ts +38 -0
  95. package/dist/protocol/iq/appstate-sync.d.ts.map +1 -0
  96. package/dist/protocol/iq/appstate-sync.js +154 -0
  97. package/dist/protocol/iq/appstate-sync.js.map +1 -0
  98. package/dist/protocol/iq/business.d.ts +13 -0
  99. package/dist/protocol/iq/business.d.ts.map +1 -0
  100. package/dist/protocol/iq/business.js +64 -0
  101. package/dist/protocol/iq/business.js.map +1 -0
  102. package/dist/protocol/iq/dirty-bits.d.ts +8 -0
  103. package/dist/protocol/iq/dirty-bits.d.ts.map +1 -0
  104. package/dist/protocol/iq/dirty-bits.js +23 -0
  105. package/dist/protocol/iq/dirty-bits.js.map +1 -0
  106. package/dist/protocol/iq/group-ops.d.ts +34 -0
  107. package/dist/protocol/iq/group-ops.d.ts.map +1 -0
  108. package/dist/protocol/iq/group-ops.js +164 -0
  109. package/dist/protocol/iq/group-ops.js.map +1 -0
  110. package/dist/protocol/iq/newsletter.d.ts +4 -0
  111. package/dist/protocol/iq/newsletter.d.ts.map +1 -0
  112. package/dist/protocol/iq/newsletter.js +18 -0
  113. package/dist/protocol/iq/newsletter.js.map +1 -0
  114. package/dist/protocol/iq/prekey-fetch.d.ts +18 -0
  115. package/dist/protocol/iq/prekey-fetch.d.ts.map +1 -0
  116. package/dist/protocol/iq/prekey-fetch.js +92 -0
  117. package/dist/protocol/iq/prekey-fetch.js.map +1 -0
  118. package/dist/protocol/iq/privacy-token.d.ts +9 -0
  119. package/dist/protocol/iq/privacy-token.d.ts.map +1 -0
  120. package/dist/protocol/iq/privacy-token.js +30 -0
  121. package/dist/protocol/iq/privacy-token.js.map +1 -0
  122. package/dist/protocol/iq/privacy.d.ts +22 -0
  123. package/dist/protocol/iq/privacy.d.ts.map +1 -0
  124. package/dist/protocol/iq/privacy.js +133 -0
  125. package/dist/protocol/iq/privacy.js.map +1 -0
  126. package/dist/protocol/iq/profile.d.ts +22 -0
  127. package/dist/protocol/iq/profile.d.ts.map +1 -0
  128. package/dist/protocol/iq/profile.js +80 -0
  129. package/dist/protocol/iq/profile.js.map +1 -0
  130. package/dist/protocol/iq/router.d.ts +39 -0
  131. package/dist/protocol/iq/router.d.ts.map +1 -0
  132. package/dist/protocol/iq/router.js +118 -0
  133. package/dist/protocol/iq/router.js.map +1 -0
  134. package/dist/protocol/iq/usync.d.ts +8 -0
  135. package/dist/protocol/iq/usync.d.ts.map +1 -0
  136. package/dist/protocol/iq/usync.js +68 -0
  137. package/dist/protocol/iq/usync.js.map +1 -0
  138. package/dist/protocol/push/app-state-key-share.d.ts +17 -0
  139. package/dist/protocol/push/app-state-key-share.d.ts.map +1 -0
  140. package/dist/protocol/push/app-state-key-share.js +30 -0
  141. package/dist/protocol/push/app-state-key-share.js.map +1 -0
  142. package/dist/protocol/push/call-failure.d.ts +16 -0
  143. package/dist/protocol/push/call-failure.d.ts.map +1 -0
  144. package/dist/protocol/push/call-failure.js +32 -0
  145. package/dist/protocol/push/call-failure.js.map +1 -0
  146. package/dist/protocol/push/chatstate.d.ts +15 -0
  147. package/dist/protocol/push/chatstate.d.ts.map +1 -0
  148. package/dist/protocol/push/chatstate.js +27 -0
  149. package/dist/protocol/push/chatstate.js.map +1 -0
  150. package/dist/protocol/push/error-stanza.d.ts +8 -0
  151. package/dist/protocol/push/error-stanza.d.ts.map +1 -0
  152. package/dist/protocol/push/error-stanza.js +17 -0
  153. package/dist/protocol/push/error-stanza.js.map +1 -0
  154. package/dist/protocol/push/history-sync.d.ts +46 -0
  155. package/dist/protocol/push/history-sync.d.ts.map +1 -0
  156. package/dist/protocol/push/history-sync.js +117 -0
  157. package/dist/protocol/push/history-sync.js.map +1 -0
  158. package/dist/protocol/push/message.d.ts +21 -0
  159. package/dist/protocol/push/message.d.ts.map +1 -0
  160. package/dist/protocol/push/message.js +42 -0
  161. package/dist/protocol/push/message.js.map +1 -0
  162. package/dist/protocol/push/notification.d.ts +21 -0
  163. package/dist/protocol/push/notification.d.ts.map +1 -0
  164. package/dist/protocol/push/notification.js +34 -0
  165. package/dist/protocol/push/notification.js.map +1 -0
  166. package/dist/protocol/push/presence.d.ts +11 -0
  167. package/dist/protocol/push/presence.d.ts.map +1 -0
  168. package/dist/protocol/push/presence.js +18 -0
  169. package/dist/protocol/push/presence.js.map +1 -0
  170. package/dist/protocol/push/receipt.d.ts +14 -0
  171. package/dist/protocol/push/receipt.d.ts.map +1 -0
  172. package/dist/protocol/push/receipt.js +25 -0
  173. package/dist/protocol/push/receipt.js.map +1 -0
  174. package/dist/protocol/signal/fake-app-state-crypto.d.ts +49 -0
  175. package/dist/protocol/signal/fake-app-state-crypto.d.ts.map +1 -0
  176. package/dist/protocol/signal/fake-app-state-crypto.js +202 -0
  177. package/dist/protocol/signal/fake-app-state-crypto.js.map +1 -0
  178. package/dist/protocol/signal/fake-peer-double-ratchet.d.ts +38 -0
  179. package/dist/protocol/signal/fake-peer-double-ratchet.d.ts.map +1 -0
  180. package/dist/protocol/signal/fake-peer-double-ratchet.js +408 -0
  181. package/dist/protocol/signal/fake-peer-double-ratchet.js.map +1 -0
  182. package/dist/protocol/signal/fake-peer-group-recv-session.d.ts +10 -0
  183. package/dist/protocol/signal/fake-peer-group-recv-session.d.ts.map +1 -0
  184. package/dist/protocol/signal/fake-peer-group-recv-session.js +129 -0
  185. package/dist/protocol/signal/fake-peer-group-recv-session.js.map +1 -0
  186. package/dist/protocol/signal/fake-peer-identity.d.ts +7 -0
  187. package/dist/protocol/signal/fake-peer-identity.d.ts.map +1 -0
  188. package/dist/protocol/signal/fake-peer-identity.js +12 -0
  189. package/dist/protocol/signal/fake-peer-identity.js.map +1 -0
  190. package/dist/protocol/signal/fake-peer-key-bundle.d.ts +24 -0
  191. package/dist/protocol/signal/fake-peer-key-bundle.d.ts.map +1 -0
  192. package/dist/protocol/signal/fake-peer-key-bundle.js +29 -0
  193. package/dist/protocol/signal/fake-peer-key-bundle.js.map +1 -0
  194. package/dist/protocol/signal/fake-peer-recv-session.d.ts +60 -0
  195. package/dist/protocol/signal/fake-peer-recv-session.d.ts.map +1 -0
  196. package/dist/protocol/signal/fake-peer-recv-session.js +284 -0
  197. package/dist/protocol/signal/fake-peer-recv-session.js.map +1 -0
  198. package/dist/protocol/signal/fake-peer-session.d.ts +87 -0
  199. package/dist/protocol/signal/fake-peer-session.d.ts.map +1 -0
  200. package/dist/protocol/signal/fake-peer-session.js +207 -0
  201. package/dist/protocol/signal/fake-peer-session.js.map +1 -0
  202. package/dist/protocol/signal/fake-sender-key.d.ts +15 -0
  203. package/dist/protocol/signal/fake-sender-key.d.ts.map +1 -0
  204. package/dist/protocol/signal/fake-sender-key.js +91 -0
  205. package/dist/protocol/signal/fake-sender-key.js.map +1 -0
  206. package/dist/protocol/signal/prekey-upload.d.ts +22 -0
  207. package/dist/protocol/signal/prekey-upload.d.ts.map +1 -0
  208. package/dist/protocol/signal/prekey-upload.js +113 -0
  209. package/dist/protocol/signal/prekey-upload.js.map +1 -0
  210. package/dist/protocol/stream/stream-error.d.ts +8 -0
  211. package/dist/protocol/stream/stream-error.d.ts.map +1 -0
  212. package/dist/protocol/stream/stream-error.js +64 -0
  213. package/dist/protocol/stream/stream-error.js.map +1 -0
  214. package/dist/state/fake-app-state-collection.d.ts +35 -0
  215. package/dist/state/fake-app-state-collection.d.ts.map +1 -0
  216. package/dist/state/fake-app-state-collection.js +139 -0
  217. package/dist/state/fake-app-state-collection.js.map +1 -0
  218. package/dist/state/fake-media-store.d.ts +35 -0
  219. package/dist/state/fake-media-store.d.ts.map +1 -0
  220. package/dist/state/fake-media-store.js +57 -0
  221. package/dist/state/fake-media-store.js.map +1 -0
  222. package/dist/transport/codec.d.ts +10 -0
  223. package/dist/transport/codec.d.ts.map +1 -0
  224. package/dist/transport/codec.js +17 -0
  225. package/dist/transport/codec.js.map +1 -0
  226. package/dist/transport/crypto.d.ts +11 -0
  227. package/dist/transport/crypto.d.ts.map +1 -0
  228. package/dist/transport/crypto.js +36 -0
  229. package/dist/transport/crypto.js.map +1 -0
  230. package/dist/transport/index.d.ts +4 -0
  231. package/dist/transport/index.d.ts.map +1 -0
  232. package/dist/transport/index.js +20 -0
  233. package/dist/transport/index.js.map +1 -0
  234. package/dist/transport/protos.d.ts +10 -0
  235. package/dist/transport/protos.d.ts.map +1 -0
  236. package/dist/transport/protos.js +13 -0
  237. package/dist/transport/protos.js.map +1 -0
  238. package/package.json +43 -0
@@ -0,0 +1,652 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FakeWaServer = void 0;
4
+ const node_https_1 = require("node:https");
5
+ const WaFakeConnectionPipeline_1 = require("../infra/WaFakeConnectionPipeline");
6
+ const WaFakeMediaHttpsServer_1 = require("../infra/WaFakeMediaHttpsServer");
7
+ const WaFakeWsServer_1 = require("../infra/WaFakeWsServer");
8
+ const cert_chain_1 = require("../protocol/auth/cert-chain");
9
+ const router_1 = require("../protocol/iq/router");
10
+ const fake_media_store_1 = require("../state/fake-media-store");
11
+ const crypto_1 = require("../transport/crypto");
12
+ const AppStateSyncManager_1 = require("./AppStateSyncManager");
13
+ const FakePairingDriver_1 = require("./FakePairingDriver");
14
+ const FakePeer_1 = require("./FakePeer");
15
+ const iq_handlers_1 = require("./iq-handlers");
16
+ const PreKeyDispenser_1 = require("./PreKeyDispenser");
17
+ const Scenario_1 = require("./Scenario");
18
+ const ServerRegistries_1 = require("./ServerRegistries");
19
+ class FakeWaServer {
20
+ constructor(options = {}) {
21
+ this.registries = new ServerRegistries_1.ServerRegistries();
22
+ this.preKeyDispenser = new PreKeyDispenser_1.PreKeyDispenser();
23
+ this.appStateSync = new AppStateSyncManager_1.AppStateSyncManager();
24
+ this.pipelines = new Set();
25
+ this.iqRouter = new router_1.WaFakeIqRouter();
26
+ this.capturedStanzas = [];
27
+ this.pendingIqExpectations = new Set();
28
+ this.pendingStanzaExpectations = new Set();
29
+ this.authenticatedListeners = new Set();
30
+ this.inboundStanzaListeners = new Set();
31
+ this.rootCa = null;
32
+ this.serverStaticKeyPair = null;
33
+ this.listenInfo = null;
34
+ this.pipelineListener = null;
35
+ this.rejectMode = null;
36
+ this.mediaStore = new fake_media_store_1.FakeMediaStore();
37
+ this.mediaHttpsServer = new WaFakeMediaHttpsServer_1.WaFakeMediaHttpsServer();
38
+ this.capturedMediaUploads = [];
39
+ this.nextUploadCounter = 0;
40
+ this.cachedMediaProxyAgent = null;
41
+ this.wsServer = new WaFakeWsServer_1.WaFakeWsServer(options);
42
+ this.wsServer.onConnection((connection) => this.handleConnection(connection));
43
+ (0, iq_handlers_1.registerDefaultIqHandlers)(this.iqRouter, this.buildIqHandlerDeps());
44
+ }
45
+ buildIqHandlerDeps() {
46
+ const reg = this.registries;
47
+ const preKey = this.preKeyDispenser;
48
+ const appState = this.appStateSync;
49
+ return {
50
+ get peerRegistry() {
51
+ return reg.peerRegistry;
52
+ },
53
+ get groupRegistry() {
54
+ return reg.groupRegistry;
55
+ },
56
+ get privacySettings() {
57
+ return reg.privacySettings;
58
+ },
59
+ get blocklistJids() {
60
+ return reg.blocklistJids;
61
+ },
62
+ get profilePicturesByJid() {
63
+ return reg.profilePicturesByJid;
64
+ },
65
+ get businessProfilesByJid() {
66
+ return reg.businessProfilesByJid;
67
+ },
68
+ get abPropsInput() {
69
+ return reg.abPropsInput;
70
+ },
71
+ get issuedPrivacyTokens() {
72
+ return reg.issuedPrivacyTokens;
73
+ },
74
+ get latestStatusText() {
75
+ return reg.latestStatusText;
76
+ },
77
+ setLatestStatusText: (text) => {
78
+ reg.latestStatusText = text;
79
+ },
80
+ lookupDeviceIdsForUser: (userJid) => reg.lookupDeviceIdsForUser(userJid),
81
+ notifyGroupOp: (op) => reg.notifyGroupOp(op),
82
+ mutatePrivacySettings: (category, value) => reg.mutatePrivacySettings(category, value),
83
+ mutateBlocklist: (action, jid) => reg.mutateBlocklist(action, jid),
84
+ notifyProfilePictureSet: (op) => reg.notifyProfilePictureSet(op),
85
+ handleProfilePictureSet: (targetJid, newId) => reg.handleProfilePictureSet(targetJid, newId),
86
+ notifyStatusSet: (text) => reg.notifyStatusSet(text),
87
+ notifyLogout: () => reg.notifyLogout(),
88
+ notifyPrivacyTokenIssue: (token) => reg.notifyPrivacyTokenIssue(token),
89
+ notifyDirtyBitsClear: (op) => reg.notifyDirtyBitsClear(op),
90
+ notifyPrivacySet: (change) => {
91
+ for (const listener of reg.privacySetListeners) {
92
+ try {
93
+ listener(change);
94
+ }
95
+ catch (error) {
96
+ void error;
97
+ }
98
+ }
99
+ },
100
+ notifyBlocklistChange: (change) => {
101
+ for (const listener of reg.blocklistChangeListeners) {
102
+ try {
103
+ listener(change);
104
+ }
105
+ catch (error) {
106
+ void error;
107
+ }
108
+ }
109
+ },
110
+ capturePreKeyBundle: (bundle) => preKey.captureBundle(bundle),
111
+ consumeOutboundAppStatePatches: (iq) => appState.consumeOutboundAppStatePatches(iq),
112
+ get appStateCollectionProviders() {
113
+ return appState.appStateCollectionProviders;
114
+ },
115
+ requireMediaHttpsInfo: () => this.requireMediaHttpsInfo()
116
+ };
117
+ }
118
+ registerIqHandler(matcher, respond, label) {
119
+ const handler = { matcher, respond, label };
120
+ return this.iqRouter.register(handler, { priority: 'high' });
121
+ }
122
+ async routeIqForTest(iq) {
123
+ return this.iqRouter.route(iq);
124
+ }
125
+ onOutboundGroupOp(listener) {
126
+ return this.registries.onOutboundGroupOp(listener);
127
+ }
128
+ onOutboundPrivacySet(listener) {
129
+ return this.registries.onOutboundPrivacySet(listener);
130
+ }
131
+ onOutboundBlocklistChange(listener) {
132
+ return this.registries.onOutboundBlocklistChange(listener);
133
+ }
134
+ onOutboundProfilePictureSet(listener) {
135
+ return this.registries.onOutboundProfilePictureSet(listener);
136
+ }
137
+ onOutboundStatusSet(listener) {
138
+ return this.registries.onOutboundStatusSet(listener);
139
+ }
140
+ onLogout(listener) {
141
+ return this.registries.onLogout(listener);
142
+ }
143
+ onOutboundPrivacyTokenIssue(listener) {
144
+ return this.registries.onOutboundPrivacyTokenIssue(listener);
145
+ }
146
+ onOutboundDirtyBitsClear(listener) {
147
+ return this.registries.onOutboundDirtyBitsClear(listener);
148
+ }
149
+ privacyTokensIssuedSnapshot() {
150
+ return this.registries.privacyTokensIssuedSnapshot();
151
+ }
152
+ privacySettingsSnapshot() {
153
+ return this.registries.privacySettingsSnapshot();
154
+ }
155
+ blocklistSnapshot() {
156
+ return this.registries.blocklistSnapshot();
157
+ }
158
+ latestStatusSnapshot() {
159
+ return this.registries.latestStatusSnapshot();
160
+ }
161
+ groupRegistrySnapshot() {
162
+ return this.registries.groupRegistrySnapshot();
163
+ }
164
+ setAbProps(input) {
165
+ this.registries.setAbProps(input);
166
+ }
167
+ setPrivacyDisallowedList(category, jids) {
168
+ this.registries.setPrivacyDisallowedList(category, jids);
169
+ }
170
+ setProfilePictureRecord(jid, picture) {
171
+ this.registries.setProfilePictureRecord(jid, picture);
172
+ }
173
+ setBusinessProfileRecord(jid, profile) {
174
+ this.registries.setBusinessProfileRecord(jid, profile);
175
+ }
176
+ createFakeGroup(input) {
177
+ return this.registries.createFakeGroup(input);
178
+ }
179
+ async triggerPreKeyUpload(pipeline, options = {}) {
180
+ return this.preKeyDispenser.triggerPreKeyUpload(pipeline, options);
181
+ }
182
+ awaitPreKeyBundle(timeoutMs = 15000) {
183
+ return this.preKeyDispenser.awaitPreKeyBundle(timeoutMs);
184
+ }
185
+ capturedPreKeyBundleSnapshot() {
186
+ return this.preKeyDispenser.capturedPreKeyBundleSnapshot();
187
+ }
188
+ dispenseOneTimePreKey() {
189
+ return this.preKeyDispenser.dispenseOneTimePreKey();
190
+ }
191
+ preKeyDispenserMissesSnapshot() {
192
+ return this.preKeyDispenser.preKeyDispenserMissesSnapshot();
193
+ }
194
+ preKeysAvailable() {
195
+ return this.preKeyDispenser.preKeysAvailable();
196
+ }
197
+ registerAppStateSyncKey(keyId, keyData) {
198
+ this.appStateSync.registerAppStateSyncKey(keyId, keyData);
199
+ }
200
+ onOutboundAppStateMutation(listener) {
201
+ return this.appStateSync.onOutboundAppStateMutation(listener);
202
+ }
203
+ expectAppStateMutation(predicate, timeoutMs = 15000) {
204
+ return this.appStateSync.expectAppStateMutation(predicate, timeoutMs);
205
+ }
206
+ provideAppStateCollection(name, provider) {
207
+ return this.appStateSync.provideAppStateCollection(name, provider);
208
+ }
209
+ async pushServerSyncNotification(pipeline, input) {
210
+ return this.appStateSync.pushServerSyncNotification(pipeline, input);
211
+ }
212
+ onAuthenticatedPipeline(listener) {
213
+ this.authenticatedListeners.add(listener);
214
+ return () => this.authenticatedListeners.delete(listener);
215
+ }
216
+ scenario(configure) {
217
+ configure(new Scenario_1.Scenario(this));
218
+ }
219
+ expectIq(matcher, options = {}) {
220
+ const timeoutMs = options.timeoutMs ?? 2000;
221
+ for (const captured of this.capturedStanzas) {
222
+ if (matchesIq(captured, matcher)) {
223
+ return Promise.resolve(captured);
224
+ }
225
+ }
226
+ return new Promise((resolve, reject) => {
227
+ const expectation = {
228
+ matcher,
229
+ resolve: (iq) => {
230
+ this.pendingIqExpectations.delete(expectation);
231
+ clearTimeout(expectation.timer);
232
+ resolve(iq);
233
+ },
234
+ reject: (error) => {
235
+ this.pendingIqExpectations.delete(expectation);
236
+ clearTimeout(expectation.timer);
237
+ reject(error);
238
+ },
239
+ timer: setTimeout(() => {
240
+ this.pendingIqExpectations.delete(expectation);
241
+ reject(new Error(`expectIq timed out after ${timeoutMs}ms (${describeMatcher(matcher)})`));
242
+ }, timeoutMs)
243
+ };
244
+ this.pendingIqExpectations.add(expectation);
245
+ });
246
+ }
247
+ capturedStanzaSnapshot() {
248
+ return this.capturedStanzas.slice();
249
+ }
250
+ expectStanza(matcher, options = {}) {
251
+ const timeoutMs = options.timeoutMs ?? 2000;
252
+ for (const captured of this.capturedStanzas) {
253
+ if (matchesStanza(captured, matcher)) {
254
+ return Promise.resolve(captured);
255
+ }
256
+ }
257
+ return new Promise((resolve, reject) => {
258
+ const expectation = {
259
+ matcher,
260
+ resolve: (node) => {
261
+ this.pendingStanzaExpectations.delete(expectation);
262
+ clearTimeout(expectation.timer);
263
+ resolve(node);
264
+ },
265
+ reject: (error) => {
266
+ this.pendingStanzaExpectations.delete(expectation);
267
+ clearTimeout(expectation.timer);
268
+ reject(error);
269
+ },
270
+ timer: setTimeout(() => {
271
+ this.pendingStanzaExpectations.delete(expectation);
272
+ reject(new Error(`expectStanza timed out after ${timeoutMs}ms (${describeStanzaMatcher(matcher)})`));
273
+ }, timeoutMs)
274
+ };
275
+ this.pendingStanzaExpectations.add(expectation);
276
+ });
277
+ }
278
+ async broadcastStanza(node) {
279
+ const tasks = [];
280
+ for (const pipeline of this.pipelines) {
281
+ tasks.push(pipeline.sendStanza(node).catch(() => undefined));
282
+ }
283
+ await Promise.all(tasks);
284
+ return tasks.length;
285
+ }
286
+ waitForAuthenticatedPipeline(timeoutMs = 60000) {
287
+ for (const pipeline of this.pipelines) {
288
+ if (pipeline.isAuthenticated()) {
289
+ return Promise.resolve(pipeline);
290
+ }
291
+ }
292
+ return this.waitForNextAuthenticatedPipeline(timeoutMs);
293
+ }
294
+ waitForNextAuthenticatedPipeline(timeoutMs = 60000) {
295
+ return new Promise((resolve, reject) => {
296
+ const timer = setTimeout(() => reject(new Error(`waitForNextAuthenticatedPipeline timed out after ${timeoutMs}ms`)), timeoutMs);
297
+ const unregister = this.onAuthenticatedPipeline((pipeline) => {
298
+ clearTimeout(timer);
299
+ unregister();
300
+ resolve(pipeline);
301
+ });
302
+ });
303
+ }
304
+ async publishMediaBlob(input) {
305
+ return this.mediaStore.publish(input);
306
+ }
307
+ mediaUrl(path) {
308
+ const info = this.requireMediaHttpsInfo();
309
+ const normalized = path.startsWith('/') ? path : `/${path}`;
310
+ return `https://${info.host}:${info.port}${normalized}`;
311
+ }
312
+ requireMediaHttpsInfo() {
313
+ const info = this.mediaHttpsServer.info;
314
+ if (!info) {
315
+ throw new Error('fake media https server is not listening');
316
+ }
317
+ return info;
318
+ }
319
+ get mediaProxyAgent() {
320
+ if (!this.cachedMediaProxyAgent) {
321
+ this.cachedMediaProxyAgent = new node_https_1.Agent({ rejectUnauthorized: false });
322
+ }
323
+ return this.cachedMediaProxyAgent;
324
+ }
325
+ capturedMediaUploadSnapshot() {
326
+ return this.capturedMediaUploads.slice();
327
+ }
328
+ async createFakePeer(options, pipeline) {
329
+ const peer = await FakePeer_1.FakePeer.create(options, this.buildFakePeerDeps(pipeline));
330
+ this.registries.registerPeer(peer);
331
+ return peer;
332
+ }
333
+ async createFakePeerWithDevices(input, pipeline) {
334
+ if (input.deviceIds.length === 0) {
335
+ throw new Error('createFakePeerWithDevices requires at least one deviceId');
336
+ }
337
+ const atIdx = input.userJid.indexOf('@');
338
+ if (atIdx < 0) {
339
+ throw new Error(`invalid userJid ${input.userJid}`);
340
+ }
341
+ const userPart = input.userJid.slice(0, atIdx);
342
+ const server = input.userJid.slice(atIdx + 1);
343
+ const peers = [];
344
+ for (const deviceId of input.deviceIds) {
345
+ const deviceJid = deviceId === 0 ? input.userJid : `${userPart}:${deviceId}@${server}`;
346
+ const peer = await FakePeer_1.FakePeer.create({
347
+ jid: deviceJid,
348
+ displayName: input.displayName,
349
+ skipOneTimePreKey: input.skipOneTimePreKey
350
+ }, this.buildFakePeerDeps(pipeline));
351
+ this.registries.registerPeer(peer);
352
+ peers.push(peer);
353
+ }
354
+ return peers;
355
+ }
356
+ buildFakePeerDeps(pipeline) {
357
+ return {
358
+ bundleResolver: () => this.preKeyDispenser.awaitPreKeyBundle(),
359
+ reserveOneTimePreKey: () => this.preKeyDispenser.dispenseOneTimePreKey(),
360
+ pushStanza: (stanza) => pipeline.sendStanza(stanza),
361
+ subscribeInboundMessages: (listener) => {
362
+ const wrapped = (node) => {
363
+ if (node.tag !== 'message')
364
+ return;
365
+ listener(node);
366
+ };
367
+ this.inboundStanzaListeners.add(wrapped);
368
+ return () => {
369
+ this.inboundStanzaListeners.delete(wrapped);
370
+ };
371
+ }
372
+ };
373
+ }
374
+ async runPairing(pipeline, options, companionMaterialResolver) {
375
+ const driver = new FakePairingDriver_1.FakePairingDriver(options, {
376
+ pipeline,
377
+ companionMaterialResolver,
378
+ waitForPairDeviceAck: async (pairDeviceIqId) => {
379
+ await this.expectIq({
380
+ id: pairDeviceIqId
381
+ }, {
382
+ timeoutMs: 15000
383
+ });
384
+ }
385
+ });
386
+ await driver.run();
387
+ }
388
+ setRejectMode(info) {
389
+ if (info === null) {
390
+ this.rejectMode = null;
391
+ return;
392
+ }
393
+ this.rejectMode = {
394
+ code: info.code ?? 1011,
395
+ reason: info.reason ?? 'fake-server reject mode'
396
+ };
397
+ }
398
+ static async start(options = {}) {
399
+ const server = new FakeWaServer(options);
400
+ await server.listen();
401
+ return server;
402
+ }
403
+ get url() {
404
+ return this.requireListening().url;
405
+ }
406
+ get host() {
407
+ return this.requireListening().host;
408
+ }
409
+ get port() {
410
+ return this.requireListening().port;
411
+ }
412
+ get noiseRootCa() {
413
+ const root = this.requireRootCa();
414
+ return { publicKey: root.publicKey, serial: root.serial };
415
+ }
416
+ onPipeline(listener) {
417
+ this.pipelineListener = listener;
418
+ }
419
+ async listen() {
420
+ if (this.listenInfo) {
421
+ return;
422
+ }
423
+ ;
424
+ [this.rootCa, this.serverStaticKeyPair] = await Promise.all([
425
+ (0, cert_chain_1.generateFakeNoiseRootCa)(),
426
+ crypto_1.X25519.generateKeyPair()
427
+ ]);
428
+ const mediaHandler = this.buildMediaRequestHandler();
429
+ this.wsServer.setHttpRequestHandler(mediaHandler);
430
+ this.mediaHttpsServer.setRequestHandler(mediaHandler);
431
+ this.listenInfo = await this.wsServer.listen();
432
+ await this.mediaHttpsServer.listen('127.0.0.1');
433
+ }
434
+ async stop() {
435
+ this.pipelines.clear();
436
+ await this.wsServer.close();
437
+ await this.mediaHttpsServer.close();
438
+ if (this.cachedMediaProxyAgent) {
439
+ this.cachedMediaProxyAgent.destroy();
440
+ this.cachedMediaProxyAgent = null;
441
+ }
442
+ this.listenInfo = null;
443
+ this.rootCa = null;
444
+ this.serverStaticKeyPair = null;
445
+ }
446
+ handleConnection(connection) {
447
+ if (this.rejectMode) {
448
+ connection.close(this.rejectMode.code, this.rejectMode.reason);
449
+ return;
450
+ }
451
+ if (!this.rootCa || !this.serverStaticKeyPair) {
452
+ connection.close(1011, 'fake server not initialized');
453
+ return;
454
+ }
455
+ const pipeline = new WaFakeConnectionPipeline_1.WaFakeConnectionPipeline({
456
+ connection,
457
+ rootCa: this.rootCa,
458
+ serverStaticKeyPair: this.serverStaticKeyPair,
459
+ iqRouter: this.iqRouter
460
+ });
461
+ this.pipelines.add(pipeline);
462
+ pipeline.setEvents({
463
+ onAuthenticated: () => {
464
+ for (const listener of this.authenticatedListeners) {
465
+ void listener(pipeline);
466
+ }
467
+ },
468
+ onStanza: (node) => this.handleCapturedStanza(node),
469
+ onClose: () => this.pipelines.delete(pipeline)
470
+ });
471
+ this.pipelineListener?.(pipeline);
472
+ }
473
+ handleCapturedStanza(node) {
474
+ this.capturedStanzas.push(node);
475
+ for (const listener of this.inboundStanzaListeners) {
476
+ try {
477
+ listener(node);
478
+ }
479
+ catch (error) {
480
+ void error;
481
+ }
482
+ }
483
+ for (const expectation of this.pendingStanzaExpectations) {
484
+ if (matchesStanza(node, expectation.matcher)) {
485
+ expectation.resolve(node);
486
+ break;
487
+ }
488
+ }
489
+ if (node.tag !== 'iq') {
490
+ return;
491
+ }
492
+ for (const expectation of this.pendingIqExpectations) {
493
+ if (matchesIq(node, expectation.matcher)) {
494
+ expectation.resolve(node);
495
+ return;
496
+ }
497
+ }
498
+ }
499
+ buildMediaRequestHandler() {
500
+ return (req, res) => {
501
+ const rawUrl = req.url ?? '';
502
+ const [path, query] = rawUrl.split('?');
503
+ const method = (req.method ?? 'GET').toUpperCase();
504
+ if (method === 'POST') {
505
+ this.handleMediaUpload(req, res, path, query);
506
+ return;
507
+ }
508
+ const blob = this.mediaStore.get(path);
509
+ if (!blob) {
510
+ res.statusCode = 404;
511
+ res.end();
512
+ return;
513
+ }
514
+ res.statusCode = 200;
515
+ res.setHeader('content-type', 'application/octet-stream');
516
+ res.setHeader('content-length', String(blob.encryptedBytes.byteLength));
517
+ res.end(Buffer.from(blob.encryptedBytes));
518
+ };
519
+ }
520
+ handleMediaUpload(req, res, path, query) {
521
+ const chunks = [];
522
+ req.on('data', (chunk) => {
523
+ chunks.push(chunk);
524
+ });
525
+ req.on('end', () => {
526
+ const encryptedBytes = new Uint8Array(Buffer.concat(chunks));
527
+ const segments = path.split('/').filter(Boolean);
528
+ const mediaType = segments[1] ?? 'unknown';
529
+ const auth = parseQueryParam(query, 'auth');
530
+ const upload = {
531
+ path,
532
+ mediaType,
533
+ encryptedBytes,
534
+ contentType: req.headers['content-type'],
535
+ auth,
536
+ receivedAtMs: Date.now()
537
+ };
538
+ this.capturedMediaUploads.push(upload);
539
+ this.mediaStore.setRaw(path, encryptedBytes, mediaType);
540
+ this.nextUploadCounter += 1;
541
+ const downloadUrl = this.mediaUrl(path);
542
+ const responseBody = JSON.stringify({
543
+ url: downloadUrl,
544
+ direct_path: path
545
+ });
546
+ res.statusCode = 200;
547
+ res.setHeader('content-type', 'application/json');
548
+ res.setHeader('content-length', String(Buffer.byteLength(responseBody)));
549
+ res.end(responseBody);
550
+ });
551
+ req.on('error', (error) => {
552
+ if (!res.headersSent) {
553
+ res.statusCode = 500;
554
+ }
555
+ res.end(error.message);
556
+ });
557
+ }
558
+ requireListening() {
559
+ if (!this.listenInfo) {
560
+ throw new Error('fake server is not listening');
561
+ }
562
+ return this.listenInfo;
563
+ }
564
+ requireRootCa() {
565
+ if (!this.rootCa) {
566
+ throw new Error('fake server is not listening');
567
+ }
568
+ return this.rootCa;
569
+ }
570
+ }
571
+ exports.FakeWaServer = FakeWaServer;
572
+ function parseQueryParam(query, name) {
573
+ if (!query)
574
+ return undefined;
575
+ for (const pair of query.split('&')) {
576
+ const eq = pair.indexOf('=');
577
+ if (eq < 0)
578
+ continue;
579
+ const key = decodeURIComponent(pair.slice(0, eq));
580
+ if (key !== name)
581
+ continue;
582
+ return decodeURIComponent(pair.slice(eq + 1));
583
+ }
584
+ return undefined;
585
+ }
586
+ function matchesIq(iq, matcher) {
587
+ if (iq.tag !== 'iq')
588
+ return false;
589
+ if (matcher.id !== undefined && iq.attrs.id !== matcher.id)
590
+ return false;
591
+ if (matcher.type !== undefined && iq.attrs.type !== matcher.type)
592
+ return false;
593
+ if (matcher.xmlns !== undefined && iq.attrs.xmlns !== matcher.xmlns)
594
+ return false;
595
+ if (matcher.childTag !== undefined) {
596
+ const children = Array.isArray(iq.content) ? iq.content : null;
597
+ if (!children || children.length === 0)
598
+ return false;
599
+ if (children[0].tag !== matcher.childTag)
600
+ return false;
601
+ }
602
+ return true;
603
+ }
604
+ function describeMatcher(matcher) {
605
+ const parts = [];
606
+ if (matcher.id !== undefined)
607
+ parts.push(`id=${matcher.id}`);
608
+ if (matcher.type !== undefined)
609
+ parts.push(`type=${matcher.type}`);
610
+ if (matcher.xmlns !== undefined)
611
+ parts.push(`xmlns=${matcher.xmlns}`);
612
+ if (matcher.childTag !== undefined)
613
+ parts.push(`childTag=${matcher.childTag}`);
614
+ return parts.length > 0 ? parts.join(', ') : 'any iq';
615
+ }
616
+ function matchesStanza(node, matcher) {
617
+ if (matcher.tag !== undefined && node.tag !== matcher.tag)
618
+ return false;
619
+ if (matcher.type !== undefined && node.attrs.type !== matcher.type)
620
+ return false;
621
+ if (matcher.xmlns !== undefined && node.attrs.xmlns !== matcher.xmlns)
622
+ return false;
623
+ if (matcher.from !== undefined && node.attrs.from !== matcher.from)
624
+ return false;
625
+ if (matcher.to !== undefined && node.attrs.to !== matcher.to)
626
+ return false;
627
+ if (matcher.childTag !== undefined) {
628
+ const children = Array.isArray(node.content) ? node.content : null;
629
+ if (!children || children.length === 0)
630
+ return false;
631
+ if (children[0].tag !== matcher.childTag)
632
+ return false;
633
+ }
634
+ return true;
635
+ }
636
+ function describeStanzaMatcher(matcher) {
637
+ const parts = [];
638
+ if (matcher.tag !== undefined)
639
+ parts.push(`tag=${matcher.tag}`);
640
+ if (matcher.type !== undefined)
641
+ parts.push(`type=${matcher.type}`);
642
+ if (matcher.xmlns !== undefined)
643
+ parts.push(`xmlns=${matcher.xmlns}`);
644
+ if (matcher.from !== undefined)
645
+ parts.push(`from=${matcher.from}`);
646
+ if (matcher.to !== undefined)
647
+ parts.push(`to=${matcher.to}`);
648
+ if (matcher.childTag !== undefined)
649
+ parts.push(`childTag=${matcher.childTag}`);
650
+ return parts.length > 0 ? parts.join(', ') : 'any stanza';
651
+ }
652
+ //# sourceMappingURL=FakeWaServer.js.map