@oxidezap/baileyrs 0.0.7 → 0.0.8

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 (159) hide show
  1. package/README.md +119 -5
  2. package/lib/Bridge/__tests__/adapt.test.d.ts +2 -0
  3. package/lib/Bridge/__tests__/adapt.test.d.ts.map +1 -0
  4. package/lib/Bridge/__tests__/adapt.test.js +355 -0
  5. package/lib/Bridge/__tests__/adapt.test.js.map +1 -0
  6. package/lib/Bridge/__tests__/dts-drift.test.d.ts +13 -0
  7. package/lib/Bridge/__tests__/dts-drift.test.d.ts.map +1 -0
  8. package/lib/Bridge/__tests__/dts-drift.test.js +92 -0
  9. package/lib/Bridge/__tests__/dts-drift.test.js.map +1 -0
  10. package/lib/Bridge/__tests__/fixtures.d.ts +192 -0
  11. package/lib/Bridge/__tests__/fixtures.d.ts.map +1 -0
  12. package/lib/Bridge/__tests__/fixtures.js +99 -0
  13. package/lib/Bridge/__tests__/fixtures.js.map +1 -0
  14. package/lib/Bridge/adapt.d.ts +28 -0
  15. package/lib/Bridge/adapt.d.ts.map +1 -0
  16. package/lib/Bridge/adapt.js +504 -0
  17. package/lib/Bridge/adapt.js.map +1 -0
  18. package/lib/Bridge/index.d.ts +12 -0
  19. package/lib/Bridge/index.d.ts.map +1 -0
  20. package/lib/Bridge/index.js +12 -0
  21. package/lib/Bridge/index.js.map +1 -0
  22. package/lib/Bridge/primitives.d.ts +56 -0
  23. package/lib/Bridge/primitives.d.ts.map +1 -0
  24. package/lib/Bridge/primitives.js +58 -0
  25. package/lib/Bridge/primitives.js.map +1 -0
  26. package/lib/Bridge/types.d.ts +273 -0
  27. package/lib/Bridge/types.d.ts.map +1 -0
  28. package/lib/Bridge/types.js +17 -0
  29. package/lib/Bridge/types.js.map +1 -0
  30. package/lib/Defaults/index.d.ts.map +1 -1
  31. package/lib/Defaults/index.js +2 -2
  32. package/lib/Defaults/index.js.map +1 -1
  33. package/lib/Socket/blocking.d.ts.map +1 -1
  34. package/lib/Socket/chat-actions.d.ts.map +1 -1
  35. package/lib/Socket/contacts.d.ts +9 -4
  36. package/lib/Socket/contacts.d.ts.map +1 -1
  37. package/lib/Socket/contacts.js +11 -8
  38. package/lib/Socket/contacts.js.map +1 -1
  39. package/lib/Socket/events.d.ts +7 -1
  40. package/lib/Socket/events.d.ts.map +1 -1
  41. package/lib/Socket/events.js +212 -243
  42. package/lib/Socket/events.js.map +1 -1
  43. package/lib/Socket/group-notifications.d.ts +25 -0
  44. package/lib/Socket/group-notifications.d.ts.map +1 -0
  45. package/lib/Socket/group-notifications.js +162 -0
  46. package/lib/Socket/group-notifications.js.map +1 -0
  47. package/lib/Socket/groups.d.ts +12 -1
  48. package/lib/Socket/groups.d.ts.map +1 -1
  49. package/lib/Socket/groups.js +44 -1
  50. package/lib/Socket/groups.js.map +1 -1
  51. package/lib/Socket/index.d.ts +47 -13
  52. package/lib/Socket/index.d.ts.map +1 -1
  53. package/lib/Socket/index.js +158 -24
  54. package/lib/Socket/index.js.map +1 -1
  55. package/lib/Socket/messages.d.ts +5 -2
  56. package/lib/Socket/messages.d.ts.map +1 -1
  57. package/lib/Socket/messages.js +42 -21
  58. package/lib/Socket/messages.js.map +1 -1
  59. package/lib/Socket/newsletter.d.ts.map +1 -1
  60. package/lib/Socket/presence.d.ts.map +1 -1
  61. package/lib/Socket/profile.d.ts +7 -1
  62. package/lib/Socket/profile.d.ts.map +1 -1
  63. package/lib/Socket/profile.js +20 -5
  64. package/lib/Socket/profile.js.map +1 -1
  65. package/lib/Socket/transport.d.ts.map +1 -1
  66. package/lib/Socket/transport.js +14 -13
  67. package/lib/Socket/transport.js.map +1 -1
  68. package/lib/Socket/types.d.ts.map +1 -1
  69. package/lib/Types/Auth.d.ts +1 -1
  70. package/lib/Types/Auth.d.ts.map +1 -1
  71. package/lib/Types/Bussines.d.ts +1 -1
  72. package/lib/Types/Bussines.d.ts.map +1 -1
  73. package/lib/Types/Chat.d.ts +1 -1
  74. package/lib/Types/Chat.d.ts.map +1 -1
  75. package/lib/Types/Events.d.ts +12 -3
  76. package/lib/Types/Events.d.ts.map +1 -1
  77. package/lib/Types/Events.js +1 -1
  78. package/lib/Types/Events.js.map +1 -1
  79. package/lib/Types/GroupMetadata.d.ts.map +1 -1
  80. package/lib/Types/Message.d.ts +16 -1
  81. package/lib/Types/Message.d.ts.map +1 -1
  82. package/lib/Types/Message.js +1 -1
  83. package/lib/Types/Message.js.map +1 -1
  84. package/lib/Types/Socket.d.ts +42 -1
  85. package/lib/Types/Socket.d.ts.map +1 -1
  86. package/lib/Types/State.d.ts +1 -1
  87. package/lib/Types/State.d.ts.map +1 -1
  88. package/lib/Types/index.d.ts +1 -1
  89. package/lib/Types/index.d.ts.map +1 -1
  90. package/lib/Types/index.js +17 -12
  91. package/lib/Types/index.js.map +1 -1
  92. package/lib/Utils/__tests__/wrap-legacy-store-lid-mapping.test.d.ts +23 -0
  93. package/lib/Utils/__tests__/wrap-legacy-store-lid-mapping.test.d.ts.map +1 -0
  94. package/lib/Utils/__tests__/wrap-legacy-store-lid-mapping.test.js +157 -0
  95. package/lib/Utils/__tests__/wrap-legacy-store-lid-mapping.test.js.map +1 -0
  96. package/lib/Utils/__tests__/wrap-legacy-store-sender-key.test.d.ts +31 -0
  97. package/lib/Utils/__tests__/wrap-legacy-store-sender-key.test.d.ts.map +1 -0
  98. package/lib/Utils/__tests__/wrap-legacy-store-sender-key.test.js +253 -0
  99. package/lib/Utils/__tests__/wrap-legacy-store-sender-key.test.js.map +1 -0
  100. package/lib/Utils/__tests__/wrap-legacy-store-session.test.d.ts +32 -0
  101. package/lib/Utils/__tests__/wrap-legacy-store-session.test.d.ts.map +1 -0
  102. package/lib/Utils/__tests__/wrap-legacy-store-session.test.js +488 -0
  103. package/lib/Utils/__tests__/wrap-legacy-store-session.test.js.map +1 -0
  104. package/lib/Utils/boom.d.ts +33 -0
  105. package/lib/Utils/boom.d.ts.map +1 -0
  106. package/lib/Utils/boom.js +63 -0
  107. package/lib/Utils/boom.js.map +1 -0
  108. package/lib/Utils/browser-utils.d.ts.map +1 -1
  109. package/lib/Utils/event-buffer.d.ts.map +1 -1
  110. package/lib/Utils/generics.d.ts +37 -1
  111. package/lib/Utils/generics.d.ts.map +1 -1
  112. package/lib/Utils/generics.js +60 -2
  113. package/lib/Utils/generics.js.map +1 -1
  114. package/lib/Utils/index.d.ts +1 -0
  115. package/lib/Utils/index.d.ts.map +1 -1
  116. package/lib/Utils/index.js +10 -9
  117. package/lib/Utils/index.js.map +1 -1
  118. package/lib/Utils/lid-mapping-store.d.ts +81 -0
  119. package/lib/Utils/lid-mapping-store.d.ts.map +1 -0
  120. package/lib/Utils/lid-mapping-store.js +126 -0
  121. package/lib/Utils/lid-mapping-store.js.map +1 -0
  122. package/lib/Utils/logger.d.ts.map +1 -1
  123. package/lib/Utils/logger.js +25 -1
  124. package/lib/Utils/logger.js.map +1 -1
  125. package/lib/Utils/messages-media.d.ts.map +1 -1
  126. package/lib/Utils/messages-media.js +1 -1
  127. package/lib/Utils/messages-media.js.map +1 -1
  128. package/lib/Utils/messages.d.ts +30 -1
  129. package/lib/Utils/messages.d.ts.map +1 -1
  130. package/lib/Utils/messages.js +115 -41
  131. package/lib/Utils/messages.js.map +1 -1
  132. package/lib/Utils/native-crypto-provider.d.ts +18 -0
  133. package/lib/Utils/native-crypto-provider.d.ts.map +1 -0
  134. package/lib/Utils/native-crypto-provider.js +67 -0
  135. package/lib/Utils/native-crypto-provider.js.map +1 -0
  136. package/lib/Utils/use-bridge-store.d.ts.map +1 -1
  137. package/lib/Utils/use-memory-store.d.ts.map +1 -1
  138. package/lib/Utils/use-memory-store.js +1 -1
  139. package/lib/Utils/use-memory-store.js.map +1 -1
  140. package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -1
  141. package/lib/Utils/use-multi-file-auth-state.js +1 -1
  142. package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
  143. package/lib/Utils/wrap-legacy-store.d.ts.map +1 -1
  144. package/lib/Utils/wrap-legacy-store.js +621 -13
  145. package/lib/Utils/wrap-legacy-store.js.map +1 -1
  146. package/lib/WABinary/index.d.ts.map +1 -1
  147. package/lib/WABinary/index.js +1 -1
  148. package/lib/WABinary/index.js.map +1 -1
  149. package/lib/__tests__/expect.d.ts +30 -0
  150. package/lib/__tests__/expect.d.ts.map +1 -0
  151. package/lib/__tests__/expect.js +60 -0
  152. package/lib/__tests__/expect.js.map +1 -0
  153. package/lib/index.d.ts +1 -1
  154. package/lib/index.d.ts.map +1 -1
  155. package/lib/index.js +9 -6
  156. package/lib/index.js.map +1 -1
  157. package/package.json +30 -25
  158. package/WAProto/index.d.ts +0 -13875
  159. package/WAProto/index.js +0 -175
package/README.md CHANGED
@@ -25,20 +25,45 @@ so existing integrations can migrate with minimal changes. See
25
25
 
26
26
  ## Installation
27
27
 
28
+ ### New project
29
+
28
30
  ```sh
29
31
  npm install @oxidezap/baileyrs
30
32
  ```
31
33
 
32
- Then import:
33
34
  ```ts
34
35
  import makeWASocket from '@oxidezap/baileyrs'
35
36
  ```
36
37
 
38
+ ### Drop-in replacement for upstream Baileys
39
+
40
+ baileyrs is API-compatible with [@whiskeysockets/baileys](https://github.com/WhiskeySockets/Baileys).
41
+ Existing projects switch over by aliasing the package — **no source changes needed**:
42
+
43
+ ```sh
44
+ npm install @whiskeysockets/baileys@npm:@oxidezap/baileyrs
45
+ ```
46
+
47
+ That writes the alias to your `package.json`:
48
+
49
+ ```jsonc
50
+ {
51
+ "dependencies": {
52
+ "@whiskeysockets/baileys": "npm:@oxidezap/baileyrs@^0.0.8"
53
+ }
54
+ }
55
+ ```
56
+
57
+ Every `import { makeWASocket } from '@whiskeysockets/baileys'` in your codebase
58
+ now resolves to baileyrs. Auth state, event listeners, and message APIs work
59
+ unchanged — see [Migrating from Upstream Baileys](#migrating-from-upstream-baileys)
60
+ for what happens behind the scenes and the (very small) surface where behavior
61
+ differs.
62
+
37
63
  ## Quick Start
38
64
 
39
65
  ```ts
40
- import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@oxidezap/baileyrs'
41
- import { Boom } from '@hapi/boom'
66
+ import makeWASocket, { Boom, DisconnectReason, useMultiFileAuthState } from '@oxidezap/baileyrs'
42
67
 
43
68
  const { state } = await useMultiFileAuthState('auth_info')
44
69
  const sock = makeWASocket({ auth: state })
@@ -63,6 +88,31 @@ sock.ev.on('messages.upsert', ({ messages }) => {
63
88
  })
64
89
  ```
65
90
 
91
+ ## Error Handling
92
+
93
+ baileyrs ships its own `Boom` error class, API-compatible with
94
+ [`@hapi/boom`](https://github.com/hapijs/boom) — no extra dependency needed.
95
+ Methods that fail (including `sendMessage`, media uploads, and connection errors)
96
+ throw a `Boom` with a `statusCode` aligned to WhatsApp disconnect reasons.
97
+
98
+ ```ts
99
+ import { Boom } from '@oxidezap/baileyrs'
100
+
101
+ try {
102
+ await sock.sendMessage(jid, { text: 'hi' })
103
+ } catch (err) {
104
+ if (Boom.isBoom(err)) {
105
+ console.log(err.statusCode) // fast path
106
+ console.log(err.output.statusCode) // @hapi/boom-compatible
107
+ console.log(err.data) // optional user payload
108
+ }
109
+ }
110
+ ```
111
+
112
+ If you have existing code importing `Boom` from `@hapi/boom`, the
113
+ `(err as Boom)?.output?.statusCode` pattern continues to work via structural
114
+ typing — only the underlying dependency changed.
115
+
66
116
  ## Connecting
67
117
 
68
118
  ### QR Code
@@ -132,12 +182,76 @@ No creds management, no type routing — just `(store, key) → bytes`. Works wi
132
182
 
133
183
  ### Migrating from Upstream Baileys
134
184
 
135
- `wrapLegacyStore` imports an existing session from [@whiskeysockets/baileys](https://github.com/WhiskeySockets/Baileys) (or any custom store built on it, like [mysql-baileys](https://github.com/bobslavtriev/mysql-baileys)) without requiring a new QR scan.
185
+ baileyrs accepts the upstream `auth: { creds, keys }` shape directly the
186
+ internal `wrapLegacyStore` adapter runs automatically when it sees that
187
+ shape, so the **`makeWASocket(...)` call site needs zero changes**:
188
+
189
+ ```ts
190
+ // makeWASocket() works as-is once the npm alias is in place.
191
+ // Auto-wrap kicks in when it sees {creds, keys}.
192
+ const sock = makeWASocket({ auth: state })
193
+
194
+ sock.ev.on('creds.update', saveCreds) // still fires — adapter re-emits
195
+ ```
196
+
197
+ The one switch you do make is **how you load `state`**. baileyrs's
198
+ `useMultiFileAuthState` is a *new-state-only* helper: it provisions a
199
+ binary `.bin` store for the Rust engine and ignores any pre-existing
200
+ upstream JSON. To carry an existing pairing across the migration, swap
201
+ the import to `useLegacyMultiFileAuthState` (one line):
202
+
203
+ ```diff
204
+ - import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
205
+ + import makeWASocket, { useLegacyMultiFileAuthState as useMultiFileAuthState } from '@whiskeysockets/baileys'
206
+
207
+ const { state, saveCreds } = await useMultiFileAuthState('auth_info')
208
+ const sock = makeWASocket({ auth: state })
209
+ sock.ev.on('creds.update', saveCreds)
210
+ ```
211
+
212
+ Same approach works for any custom upstream auth (`useMySQLAuthState`,
213
+ `useRedisAuthState`, mysql-baileys, etc.) — your loader keeps returning
214
+ `{creds, keys, saveCreds}`, baileyrs auto-wraps it on the way in.
215
+
216
+ #### Existing sessions migrate without re-pairing
217
+
218
+ `useLegacyMultiFileAuthState` reads the existing `creds.json` +
219
+ `pre-key-*.json` / `session-*.json` files from the same folder upstream
220
+ Baileys was using and hands them to the Rust engine. Pair-ID, identity,
221
+ signed pre-keys, and Signal sessions are all preserved. No QR re-scan,
222
+ no logged-out events.
223
+
224
+ > **Where the new state goes**: baileyrs continues to write the legacy
225
+ > JSON files (via `saveCreds`) so the folder stays compatible with both
226
+ > sides during a rollback window. The Rust engine treats the JSON as the
227
+ > source of truth as long as you keep using `useLegacyMultiFileAuthState`.
228
+ > If you later want to drop the JSON layer, switch to
229
+ > `useMultiFileAuthState` — but that path requires a fresh QR.
230
+
231
+ #### Gotchas
232
+
233
+ A few behaviors that differ from upstream — almost always to your advantage:
234
+
235
+ - **Auto-reconnect is built in.** Don't call `makeWASocket()` again from
236
+ `connection.update`'s `'close'` branch. The Rust engine retries with
237
+ fibonacci backoff; opening a second socket leaks the first one.
238
+ - **No `getMessage` / `cachedGroupMetadata` polyfill required.** The Rust
239
+ side caches group metadata and message keys natively. You can still pass
240
+ them — they're respected as overrides — but they're optional.
241
+ - **`Boom` ships in the box.** baileyrs exports its own
242
+ `@hapi/boom`-compatible `Boom` (see [Error Handling](#error-handling))
243
+ so the existing `(err as Boom).output.statusCode` pattern works
244
+ unchanged. If your `package.json` was pulling `@hapi/boom` only for
245
+ baileys, you can drop the dependency.
246
+
247
+ #### Manual `wrapLegacyStore` (advanced)
248
+
249
+ If you want explicit control over when the adapter runs (testing, custom
250
+ shapes, mixed storage), call it yourself:
136
251
 
137
252
  ```ts
138
253
  import makeWASocket, { useLegacyMultiFileAuthState, wrapLegacyStore } from '@oxidezap/baileyrs'
139
254
 
140
- // Works with any upstream auth state: useMultiFileAuthState, useMySQLAuthState, etc.
141
255
  const { state, saveCreds } = await useLegacyMultiFileAuthState('/path/to/baileys_auth_info')
142
256
  const store = await wrapLegacyStore(state, saveCreds)
143
257
  const sock = makeWASocket({ auth: { store } })
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adapt.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapt.test.d.ts","sourceRoot":"","sources":["../../../src/Bridge/__tests__/adapt.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,355 @@
1
+ import { describe, it } from 'node:test';
2
+ import { adaptBridgeEvent } from "../adapt.js";
3
+ import { expect } from "../../__tests__/expect.js";
4
+ import { groupAnnouncementWireFixture, groupDemotePascalFixture, groupDemoteWireFixture, groupNotAnnouncementWireFixture, groupPromotePascalFixture, groupRevokeWireFixture } from "./fixtures.js";
5
+ describe('adaptBridgeEvent — anti-corruption layer', () => {
6
+ describe('connection lifecycle', () => {
7
+ it('connected → canonical "connected"', () => {
8
+ expect(adaptBridgeEvent({ type: 'connected' })).toEqual({ type: 'connected' });
9
+ });
10
+ it('disconnected → canonical "disconnected"', () => {
11
+ expect(adaptBridgeEvent({ type: 'disconnected' })).toEqual({ type: 'disconnected' });
12
+ });
13
+ it('qr → canonical "qr" with code', () => {
14
+ expect(adaptBridgeEvent({ type: 'qr', data: { code: 'ABC', timeout: 60 } })).toEqual({
15
+ type: 'qr',
16
+ code: 'ABC'
17
+ });
18
+ });
19
+ it('pairing_code collapses to canonical "qr"', () => {
20
+ expect(adaptBridgeEvent({ type: 'pairing_code', data: { code: 'XYZ', timeout: 60 } })).toEqual({
21
+ type: 'qr',
22
+ code: 'XYZ'
23
+ });
24
+ });
25
+ it('pair_success normalizes snake_case to camelCase fields', () => {
26
+ const result = adaptBridgeEvent({
27
+ type: 'pair_success',
28
+ data: { id: '5511999990000@s.whatsapp.net', lid: '100@lid', business_name: 'Acme', platform: 'android' }
29
+ });
30
+ expect(result).toEqual({
31
+ type: 'pairSuccess',
32
+ id: '5511999990000@s.whatsapp.net',
33
+ lid: '100@lid',
34
+ businessName: 'Acme',
35
+ platform: 'android'
36
+ });
37
+ });
38
+ });
39
+ describe('group_update — the PascalCase regression', () => {
40
+ it('captured Demote payload normalizes to canonical "demote"', () => {
41
+ const result = adaptBridgeEvent(groupDemotePascalFixture);
42
+ expect(result?.type).toBe('groupUpdate');
43
+ if (result?.type !== 'groupUpdate')
44
+ throw new Error('narrowing');
45
+ expect(result.action.type).toBe('demote');
46
+ expect(result.groupJid).toBe('120363040237990503@g.us');
47
+ expect(result.author).toBe('236395184570386@lid');
48
+ expect(result.authorPn).toBe('559984726662@s.whatsapp.net');
49
+ expect(result.isLidAddressingMode).toBe(true);
50
+ // ISO timestamp coerced to unix seconds
51
+ expect(result.timestamp).toBe(Math.floor(Date.parse('2026-04-18T05:45:46Z') / 1000));
52
+ if (result.action.type !== 'demote')
53
+ throw new Error('narrowing');
54
+ expect(result.action.participants).toEqual([
55
+ { jid: '65546133500078@lid', phoneNumber: '559984246891@s.whatsapp.net' }
56
+ ]);
57
+ });
58
+ it('captured Promote payload normalizes to canonical "promote"', () => {
59
+ const result = adaptBridgeEvent(groupPromotePascalFixture);
60
+ if (result?.type !== 'groupUpdate' || result.action.type !== 'promote') {
61
+ throw new Error('expected canonical promote');
62
+ }
63
+ expect(result.action.participants[0].jid).toBe('65546133500078@lid');
64
+ });
65
+ it('snake_case action.type also passes through (forward-compat with rust fix)', () => {
66
+ const fixture = {
67
+ ...groupDemotePascalFixture,
68
+ data: {
69
+ ...groupDemotePascalFixture.data,
70
+ action: { ...groupDemotePascalFixture.data.action, type: 'demote' }
71
+ }
72
+ };
73
+ const result = adaptBridgeEvent(fixture);
74
+ expect(result?.type === 'groupUpdate' && result.action.type).toBe('demote');
75
+ });
76
+ it('unknown action.type falls back to {type: "unknown", rawType}', () => {
77
+ const fixture = {
78
+ ...groupDemotePascalFixture,
79
+ data: { ...groupDemotePascalFixture.data, action: { type: 'BrandNewAction', participants: [] } }
80
+ };
81
+ const result = adaptBridgeEvent(fixture);
82
+ if (result?.type !== 'groupUpdate' || result.action.type !== 'unknown')
83
+ throw new Error('narrowing');
84
+ expect(result.action.rawType).toBe('BrandNewAction');
85
+ });
86
+ it('subject action carries through with new subject', () => {
87
+ const fixture = {
88
+ type: 'group_update',
89
+ data: {
90
+ group_jid: { user: '123', server: 'g.us' },
91
+ participant: { user: '999', server: 'lid' },
92
+ timestamp: 1734000000,
93
+ is_lid_addressing_mode: false,
94
+ action: {
95
+ type: 'Subject',
96
+ subject: 'New name',
97
+ subject_owner: { user: '999', server: 'lid' },
98
+ subject_time: 1734000000
99
+ }
100
+ }
101
+ };
102
+ const result = adaptBridgeEvent(fixture);
103
+ if (result?.type !== 'groupUpdate' || result.action.type !== 'subject')
104
+ throw new Error('narrowing');
105
+ expect(result.action.subject).toBe('New name');
106
+ expect(result.action.subjectOwner).toBe('999@lid');
107
+ expect(result.action.subjectTime).toBe(1734000000);
108
+ });
109
+ it('Locked / Unlocked / Announce / NotAnnounce normalize to camelCase', () => {
110
+ const cases = [
111
+ ['Locked', 'locked'],
112
+ ['Unlocked', 'unlocked'],
113
+ ['Announce', 'announce'],
114
+ ['NotAnnounce', 'notAnnounce']
115
+ ];
116
+ for (const [raw, canonical] of cases) {
117
+ const fixture = {
118
+ type: 'group_update',
119
+ data: {
120
+ group_jid: { user: '123', server: 'g.us' },
121
+ timestamp: 0,
122
+ is_lid_addressing_mode: false,
123
+ action: { type: raw }
124
+ }
125
+ };
126
+ const result = adaptBridgeEvent(fixture);
127
+ if (result?.type !== 'groupUpdate')
128
+ throw new Error(`expected groupUpdate, got ${result?.type}`);
129
+ expect(result.action.type).toBe(canonical);
130
+ }
131
+ });
132
+ it('MembershipApprovalMode preserves enabled flag', () => {
133
+ const fixture = {
134
+ type: 'group_update',
135
+ data: {
136
+ group_jid: { user: '123', server: 'g.us' },
137
+ timestamp: 0,
138
+ is_lid_addressing_mode: false,
139
+ action: { type: 'MembershipApprovalMode', enabled: true }
140
+ }
141
+ };
142
+ const result = adaptBridgeEvent(fixture);
143
+ if (result?.type !== 'groupUpdate' || result.action.type !== 'membershipApprovalMode')
144
+ throw new Error('narrowing');
145
+ expect(result.action.enabled).toBe(true);
146
+ });
147
+ it('rejects malformed payloads (missing group_jid)', () => {
148
+ expect(adaptBridgeEvent({ type: 'group_update', data: { action: { type: 'demote' } } })).toBe(null);
149
+ });
150
+ });
151
+ // Wire-tag fixtures — what the bridge emits today (post whatsapp-rust PR
152
+ // #567). These are the canonical reality the adapter must agree with.
153
+ describe('group_update — wire-tag canonical (post-WireEnum)', () => {
154
+ it('lowercase "demote" payload normalizes to canonical "demote"', () => {
155
+ const result = adaptBridgeEvent(groupDemoteWireFixture);
156
+ if (result?.type !== 'groupUpdate' || result.action.type !== 'demote')
157
+ throw new Error('narrowing');
158
+ expect(result.action.participants[0].jid).toBe('65546133500078@lid');
159
+ expect(result.timestamp).toBe(1776490677);
160
+ });
161
+ it('XML wire tag "announcement" maps to canonical "announce"', () => {
162
+ const result = adaptBridgeEvent(groupAnnouncementWireFixture);
163
+ if (result?.type !== 'groupUpdate')
164
+ throw new Error('narrowing');
165
+ expect(result.action.type).toBe('announce');
166
+ });
167
+ it('XML wire tag "not_announcement" maps to canonical "notAnnounce"', () => {
168
+ const result = adaptBridgeEvent(groupNotAnnouncementWireFixture);
169
+ if (result?.type !== 'groupUpdate')
170
+ throw new Error('narrowing');
171
+ expect(result.action.type).toBe('notAnnounce');
172
+ });
173
+ it('XML wire tag "revoke" (was "revoke_invite" pre-#567) maps to canonical "revokeInvite"', () => {
174
+ const result = adaptBridgeEvent(groupRevokeWireFixture);
175
+ if (result?.type !== 'groupUpdate')
176
+ throw new Error('narrowing');
177
+ expect(result.action.type).toBe('revokeInvite');
178
+ });
179
+ it('new variants from PR #567 surface as `unknown` with the wire-tag preserved', () => {
180
+ for (const tag of ['membership_approval_request', 'created_membership_requests', 'revoked_membership_requests']) {
181
+ const result = adaptBridgeEvent({
182
+ type: 'group_update',
183
+ data: {
184
+ group_jid: { user: '120', server: 'g.us' },
185
+ timestamp: 0,
186
+ is_lid_addressing_mode: false,
187
+ action: { type: tag }
188
+ }
189
+ });
190
+ if (result?.type !== 'groupUpdate' || result.action.type !== 'unknown')
191
+ throw new Error('narrowing');
192
+ expect(result.action.rawType).toBe(tag);
193
+ }
194
+ });
195
+ });
196
+ describe('messages & receipts', () => {
197
+ it('coerces ISO MessageInfo.timestamp to unix seconds', () => {
198
+ const result = adaptBridgeEvent({
199
+ type: 'message',
200
+ data: {
201
+ message: { conversation: 'hi' },
202
+ info: {
203
+ id: 'MSG1',
204
+ timestamp: '2026-04-18T05:00:00Z',
205
+ push_name: 'alice',
206
+ source: {
207
+ chat: { user: '5511', server: 's.whatsapp.net' },
208
+ sender: { user: '5511', server: 's.whatsapp.net' },
209
+ is_from_me: false,
210
+ is_group: false
211
+ }
212
+ }
213
+ }
214
+ });
215
+ if (result?.type !== 'message')
216
+ throw new Error('narrowing');
217
+ expect(result.timestamp).toBe(Math.floor(Date.parse('2026-04-18T05:00:00Z') / 1000));
218
+ expect(result.id).toBe('MSG1');
219
+ expect(result.chatJid).toBe('5511@s.whatsapp.net');
220
+ expect(result.isGroup).toBe(false);
221
+ });
222
+ it('group message extracts senderJid + participantAlt', () => {
223
+ const result = adaptBridgeEvent({
224
+ type: 'message',
225
+ data: {
226
+ message: { conversation: 'hi' },
227
+ info: {
228
+ id: 'MSG2',
229
+ timestamp: 1734000000,
230
+ source: {
231
+ chat: { user: '120', server: 'g.us' },
232
+ sender: { user: '5511', server: 's.whatsapp.net' },
233
+ sender_alt: { user: '999', server: 'lid' },
234
+ is_from_me: false,
235
+ is_group: true
236
+ }
237
+ }
238
+ }
239
+ });
240
+ if (result?.type !== 'message')
241
+ throw new Error('narrowing');
242
+ expect(result.senderJid).toBe('5511@s.whatsapp.net');
243
+ expect(result.participantAlt).toBe('999@lid');
244
+ });
245
+ it('receipt collects message_ids and timestamp', () => {
246
+ const result = adaptBridgeEvent({
247
+ type: 'receipt',
248
+ data: {
249
+ message_ids: ['M1', 'M2'],
250
+ timestamp: '2026-04-18T05:00:00Z',
251
+ source: {
252
+ chat: { user: '120', server: 'g.us' },
253
+ sender: { user: '5511', server: 's.whatsapp.net' },
254
+ is_from_me: false,
255
+ is_group: true
256
+ }
257
+ }
258
+ });
259
+ if (result?.type !== 'receipt')
260
+ throw new Error('narrowing');
261
+ expect(result.messageIds).toEqual(['M1', 'M2']);
262
+ expect(result.chatJid).toBe('120@g.us');
263
+ expect(result.senderJid).toBe('5511@s.whatsapp.net');
264
+ expect(result.isGroup).toBe(true);
265
+ expect(result.timestamp).toBe(Math.floor(Date.parse('2026-04-18T05:00:00Z') / 1000));
266
+ });
267
+ });
268
+ describe('chat state', () => {
269
+ it('archive_update maps to canonical archiveUpdate', () => {
270
+ const result = adaptBridgeEvent({
271
+ type: 'archive_update',
272
+ data: { jid: { user: '5511', server: 's.whatsapp.net' } }
273
+ });
274
+ expect(result).toEqual({ type: 'archiveUpdate', jid: '5511@s.whatsapp.net' });
275
+ });
276
+ it('star_update reads action.starred even when wrapped', () => {
277
+ const result = adaptBridgeEvent({
278
+ type: 'star_update',
279
+ data: {
280
+ chat_jid: { user: '5511', server: 's.whatsapp.net' },
281
+ message_id: 'MID1',
282
+ from_me: true,
283
+ action: { starred: true }
284
+ }
285
+ });
286
+ expect(result).toEqual({
287
+ type: 'starUpdate',
288
+ chatJid: '5511@s.whatsapp.net',
289
+ messageId: 'MID1',
290
+ fromMe: true,
291
+ participantJid: undefined,
292
+ starred: true
293
+ });
294
+ });
295
+ });
296
+ describe('calls', () => {
297
+ it('pre_accept normalizes to camelCase preAccept', () => {
298
+ const result = adaptBridgeEvent({
299
+ type: 'incoming_call',
300
+ data: {
301
+ from: { user: '5511', server: 's.whatsapp.net' },
302
+ stanza_id: 'STZ',
303
+ timestamp: 1734000000,
304
+ offline: false,
305
+ action: { type: 'pre_accept', call_id: 'CID', call_creator: { user: '5511', server: 's.whatsapp.net' } }
306
+ }
307
+ });
308
+ if (result?.type !== 'incomingCall')
309
+ throw new Error('narrowing');
310
+ expect(result.action.type).toBe('preAccept');
311
+ expect(result.action.callId).toBe('CID');
312
+ });
313
+ it('offer carries callerPn + isVideo', () => {
314
+ const result = adaptBridgeEvent({
315
+ type: 'incoming_call',
316
+ data: {
317
+ from: { user: '5511', server: 's.whatsapp.net' },
318
+ stanza_id: 'STZ',
319
+ timestamp: 1734000000,
320
+ offline: false,
321
+ action: {
322
+ type: 'offer',
323
+ call_id: 'CID2',
324
+ call_creator: { user: '5511', server: 's.whatsapp.net' },
325
+ caller_pn: { user: '5522', server: 's.whatsapp.net' },
326
+ is_video: true,
327
+ joinable: true,
328
+ audio: []
329
+ }
330
+ }
331
+ });
332
+ if (result?.type !== 'incomingCall' || result.action.type !== 'offer')
333
+ throw new Error('narrowing');
334
+ expect(result.action.callerPn).toBe('5522@s.whatsapp.net');
335
+ expect(result.action.isVideo).toBe(true);
336
+ });
337
+ });
338
+ describe('noop / passthrough', () => {
339
+ it('history_sync collapses to noop', () => {
340
+ expect(adaptBridgeEvent({ type: 'history_sync', data: {} })).toEqual({
341
+ type: 'noop',
342
+ bridgeType: 'history_sync'
343
+ });
344
+ });
345
+ it('raw_node passes through with tag/attrs', () => {
346
+ const node = { tag: 'iq', attrs: { id: 'abc' }, content: undefined };
347
+ const result = adaptBridgeEvent({ type: 'raw_node', data: node });
348
+ expect(result?.type).toBe('rawNode');
349
+ });
350
+ it('truly unknown event types return null (caller drops)', () => {
351
+ expect(adaptBridgeEvent({ type: 'invented_2099', data: {} })).toBe(null);
352
+ });
353
+ });
354
+ });
355
+ //# sourceMappingURL=adapt.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapt.test.js","sourceRoot":"","sources":["../../../src/Bridge/__tests__/adapt.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Drift detection between the bridge's `WhatsAppEvent` union (the runtime
3
+ * contract) and our adapter's `KNOWN_BRIDGE_EVENT_TYPES` (the set of types
4
+ * we explicitly handle).
5
+ *
6
+ * When the bridge ships a new event variant or removes an existing one, this
7
+ * test fails with a precise diff — long before the missing handler shows up
8
+ * as a silently-dropped event in production. Pair with
9
+ * `bun run revalidate` so any bridge bump that changes the event surface is
10
+ * caught before merge.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=dts-drift.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dts-drift.test.d.ts","sourceRoot":"","sources":["../../../src/Bridge/__tests__/dts-drift.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Drift detection between the bridge's `WhatsAppEvent` union (the runtime
3
+ * contract) and our adapter's `KNOWN_BRIDGE_EVENT_TYPES` (the set of types
4
+ * we explicitly handle).
5
+ *
6
+ * When the bridge ships a new event variant or removes an existing one, this
7
+ * test fails with a precise diff — long before the missing handler shows up
8
+ * as a silently-dropped event in production. Pair with
9
+ * `bun run revalidate` so any bridge bump that changes the event surface is
10
+ * caught before merge.
11
+ */
12
+ import { readFileSync } from 'node:fs';
13
+ import path from 'node:path';
14
+ import { fileURLToPath } from 'node:url';
15
+ import { describe, it } from 'node:test';
16
+ import { KNOWN_BRIDGE_EVENT_TYPES } from "../adapt.js";
17
+ import { expect } from "../../__tests__/expect.js";
18
+ const `${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}` = path.dirname(fileURLToPath(import.meta.url));
19
+ /** Resolve `whatsapp_rust_bridge.d.ts` from the installed package. */
20
+ function loadBridgeDts() {
21
+ const candidates = [
22
+ path.resolve(`${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}`, '../../../node_modules/whatsapp-rust-bridge/pkg/whatsapp_rust_bridge.d.ts'),
23
+ path.resolve(`${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}`, '../../../../whatsapp-rust-bridge/pkg/whatsapp_rust_bridge.d.ts')
24
+ ];
25
+ for (const candidate of candidates) {
26
+ try {
27
+ return readFileSync(candidate, 'utf8');
28
+ }
29
+ catch {
30
+ /* try next */
31
+ }
32
+ }
33
+ throw new Error(`Could not find whatsapp_rust_bridge.d.ts. Tried:\n ${candidates.join('\n ')}`);
34
+ }
35
+ /**
36
+ * Extract every discriminator string from the `WhatsAppEvent` union. The
37
+ * bridge declares it as:
38
+ *
39
+ * export type WhatsAppEvent =
40
+ * | { type: 'connected'; data: ... }
41
+ * | { type: 'disconnected'; data: ... }
42
+ * ...
43
+ * ;
44
+ *
45
+ * We slice from the `export type WhatsAppEvent =` line down to the
46
+ * terminating `;` and pull out every quoted `type:` literal.
47
+ */
48
+ function extractWhatsAppEventTypes(dts) {
49
+ const start = dts.indexOf('export type WhatsAppEvent =');
50
+ if (start < 0)
51
+ throw new Error('WhatsAppEvent union not found in .d.ts');
52
+ const after = dts.slice(start);
53
+ const end = after.indexOf(';\n');
54
+ if (end < 0)
55
+ throw new Error('WhatsAppEvent union has no terminator in .d.ts');
56
+ const block = after.slice(0, end);
57
+ // Match `type: 'foo'` or `type: "foo"` (the bridge currently uses single quotes
58
+ // but stay forgiving).
59
+ const re = /type:\s*['"]([a-z_]+)['"]/g;
60
+ const seen = new Set();
61
+ for (const m of block.matchAll(re)) {
62
+ seen.add(m[1]);
63
+ }
64
+ if (seen.size === 0)
65
+ throw new Error('Failed to parse any variant from WhatsAppEvent union');
66
+ // `[...seen]` is already a fresh copy — sorting it in place is safe.
67
+ // eslint-disable-next-line unicorn/no-array-sort
68
+ return [...seen].sort();
69
+ }
70
+ describe('Bridge .d.ts ↔ adapter drift', () => {
71
+ const bridgeTypes = extractWhatsAppEventTypes(loadBridgeDts());
72
+ it('every bridge event type from .d.ts is handled by the adapter', () => {
73
+ const missing = bridgeTypes.filter(t => !KNOWN_BRIDGE_EVENT_TYPES.has(t));
74
+ // If this fails, the bridge added a new variant we don't handle yet.
75
+ // Add a `case` in `adaptBridgeEvent` and the matching string in
76
+ // `KNOWN_BRIDGE_EVENT_TYPES`.
77
+ expect(missing).toEqual([]);
78
+ });
79
+ it('KNOWN_BRIDGE_EVENT_TYPES has no entries the bridge no longer ships', () => {
80
+ const stale = [...KNOWN_BRIDGE_EVENT_TYPES].filter(t => !bridgeTypes.includes(t));
81
+ // If this fails, the bridge removed a variant we still claim to handle.
82
+ // Remove the corresponding `case` from `adaptBridgeEvent` and the entry
83
+ // from `KNOWN_BRIDGE_EVENT_TYPES`.
84
+ expect(stale).toEqual([]);
85
+ });
86
+ it('parser found a non-trivial number of variants (sanity check)', () => {
87
+ // If this drops to 0/few, the regex broke against a `.d.ts` reformat
88
+ // and the two assertions above would silently pass.
89
+ expect(bridgeTypes.length).toBeGreaterThanOrEqual(20);
90
+ });
91
+ });
92
+ //# sourceMappingURL=dts-drift.test.js.map