@oxidezap/baileyrs 0.0.18 → 0.0.21

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 (84) hide show
  1. package/lib/Bridge/__tests__/adapt.test.js +41 -9
  2. package/lib/Bridge/__tests__/adapt.test.js.map +1 -1
  3. package/lib/Bridge/adapt.d.ts +10 -16
  4. package/lib/Bridge/adapt.d.ts.map +1 -1
  5. package/lib/Bridge/adapt.js +12 -515
  6. package/lib/Bridge/adapt.js.map +1 -1
  7. package/lib/Bridge/schema.d.ts +36 -0
  8. package/lib/Bridge/schema.d.ts.map +1 -0
  9. package/lib/Bridge/schema.js +773 -0
  10. package/lib/Bridge/schema.js.map +1 -0
  11. package/lib/Bridge/types.d.ts +257 -3
  12. package/lib/Bridge/types.d.ts.map +1 -1
  13. package/lib/Socket/events.d.ts +18 -9
  14. package/lib/Socket/events.d.ts.map +1 -1
  15. package/lib/Socket/events.js +520 -204
  16. package/lib/Socket/events.js.map +1 -1
  17. package/lib/Socket/group-notifications.d.ts +6 -0
  18. package/lib/Socket/group-notifications.d.ts.map +1 -1
  19. package/lib/Socket/group-notifications.js +123 -16
  20. package/lib/Socket/group-notifications.js.map +1 -1
  21. package/lib/Socket/groups.d.ts +10 -2
  22. package/lib/Socket/groups.d.ts.map +1 -1
  23. package/lib/Socket/groups.js +24 -30
  24. package/lib/Socket/groups.js.map +1 -1
  25. package/lib/Socket/index.d.ts +31 -8
  26. package/lib/Socket/index.d.ts.map +1 -1
  27. package/lib/Socket/index.js +178 -13
  28. package/lib/Socket/index.js.map +1 -1
  29. package/lib/Socket/messages.d.ts +13 -2
  30. package/lib/Socket/messages.d.ts.map +1 -1
  31. package/lib/Socket/messages.js +27 -6
  32. package/lib/Socket/messages.js.map +1 -1
  33. package/lib/Types/Call.d.ts +20 -0
  34. package/lib/Types/Call.d.ts.map +1 -1
  35. package/lib/Types/Contact.d.ts +3 -1
  36. package/lib/Types/Contact.d.ts.map +1 -1
  37. package/lib/Types/Events.d.ts +2 -0
  38. package/lib/Types/Events.d.ts.map +1 -1
  39. package/lib/Utils/generics.d.ts +17 -0
  40. package/lib/Utils/generics.d.ts.map +1 -1
  41. package/lib/Utils/generics.js +31 -0
  42. package/lib/Utils/generics.js.map +1 -1
  43. package/lib/Utils/group-stub-params.d.ts +29 -0
  44. package/lib/Utils/group-stub-params.d.ts.map +1 -0
  45. package/lib/Utils/group-stub-params.js +45 -0
  46. package/lib/Utils/group-stub-params.js.map +1 -0
  47. package/lib/Utils/messages-media.d.ts +1 -1
  48. package/lib/Utils/messages-media.d.ts.map +1 -1
  49. package/lib/Utils/messages-media.js +1 -1
  50. package/lib/Utils/messages-media.js.map +1 -1
  51. package/lib/Utils/messages.d.ts.map +1 -1
  52. package/lib/Utils/messages.js +4 -6
  53. package/lib/Utils/messages.js.map +1 -1
  54. package/lib/Utils/process-history-message.d.ts +30 -0
  55. package/lib/Utils/process-history-message.d.ts.map +1 -0
  56. package/lib/Utils/process-history-message.js +148 -0
  57. package/lib/Utils/process-history-message.js.map +1 -0
  58. package/lib/Utils/use-bridge-store.d.ts.map +1 -1
  59. package/lib/Utils/use-bridge-store.js +50 -6
  60. package/lib/Utils/use-bridge-store.js.map +1 -1
  61. package/lib/Utils/use-multi-file-auth-state.d.ts +7 -0
  62. package/lib/Utils/use-multi-file-auth-state.d.ts.map +1 -1
  63. package/lib/Utils/use-multi-file-auth-state.js +11 -1
  64. package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
  65. package/lib/Utils/wrap-legacy-store.d.ts.map +1 -1
  66. package/lib/Utils/wrap-legacy-store.js +110 -90
  67. package/lib/Utils/wrap-legacy-store.js.map +1 -1
  68. package/lib/WABinary/generic-utils.d.ts +17 -0
  69. package/lib/WABinary/generic-utils.d.ts.map +1 -0
  70. package/lib/WABinary/generic-utils.js +44 -0
  71. package/lib/WABinary/generic-utils.js.map +1 -0
  72. package/lib/WABinary/index.d.ts +1 -0
  73. package/lib/WABinary/index.d.ts.map +1 -1
  74. package/lib/WABinary/index.js +1 -0
  75. package/lib/WABinary/index.js.map +1 -1
  76. package/lib/WABinary/jid-utils.d.ts +4 -0
  77. package/lib/WABinary/jid-utils.d.ts.map +1 -1
  78. package/lib/WABinary/jid-utils.js +4 -0
  79. package/lib/WABinary/jid-utils.js.map +1 -1
  80. package/lib/__tests__/expect.d.ts +14 -0
  81. package/lib/__tests__/expect.d.ts.map +1 -1
  82. package/lib/__tests__/expect.js +42 -2
  83. package/lib/__tests__/expect.js.map +1 -1
  84. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"use-bridge-store.d.ts","sourceRoot":"","sources":["../../src/Utils/use-bridge-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAE5D;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,CA2HvG"}
1
+ {"version":3,"file":"use-bridge-store.d.ts","sourceRoot":"","sources":["../../src/Utils/use-bridge-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAsC5D;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,CAsIvG"}
@@ -1,6 +1,41 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
  import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
+ /**
5
+ * Stores whose loss on SIGKILL produces undecryptable messages or
6
+ * permanent app-state divergence. Each entry below carries a reason —
7
+ * promoting a store to "critical" doubles disk I/O, so don't add
8
+ * anything here that can be re-derived from the network.
9
+ *
10
+ * `session` / `identity` — Signal session ratchet steps. Lose
11
+ * one step → next inbound message from peer undecryptable.
12
+ * `device` — own device record (noiseKey, signedIdentityKey,
13
+ * adv_secret_key). Loss = forced re-pair.
14
+ * `prekey` — consumed prekey must be durably consumed; reuse
15
+ * on a different peer makes the server reject the bundle.
16
+ * `sync_key` — app-state HMAC key. Loss → permanent gap in
17
+ * app-state mutations until full re-sync.
18
+ * `sender_key` — group-message ratchet (same model as `session`,
19
+ * but per group). Lose a step → next inbound message from the
20
+ * same group undecryptable.
21
+ * `sync_version` — LTHash state per app-state collection
22
+ * (regular_high / regular_low / critical_block / etc.). Gates
23
+ * every mutation MAC verification — lose it and every
24
+ * subsequent app-state action throws "hash mismatch" until
25
+ * full re-sync.
26
+ * `mutation_mac` — replay-protection cache for app-state
27
+ * mutations. Loss can let a replayed mutation re-apply.
28
+ */
29
+ const CRITICAL_STORES = new Set([
30
+ 'session',
31
+ 'identity',
32
+ 'device',
33
+ 'prekey',
34
+ 'sync_key',
35
+ 'sender_key',
36
+ 'sync_version',
37
+ 'mutation_mac'
38
+ ]);
4
39
  /**
5
40
  * Creates a file-based store for the WASM bridge.
6
41
  *
@@ -43,9 +78,21 @@ export async function useBridgeStore(folder) {
43
78
  // Ignore — folder may have been deleted during cleanup
44
79
  }
45
80
  };
81
+ const FLUSH_MAX_PASSES = 32;
46
82
  const flushAll = async () => {
47
- const keys = [...pendingWrites.keys()];
48
- await Promise.all(keys.map(flushWrite));
83
+ // Drain in a loop because new sets can land while we're awaiting the
84
+ // previous batch's writeFile. Bounded so a caller emitting writes in
85
+ // a tight loop can't lock us forever — `Socket/index.ts.end()` waits
86
+ // on this and must always return. If the cap is hit with writes
87
+ // still pending, surface that to the caller — silently dropping
88
+ // them would lose Signal session steps and corrupt next decrypt.
89
+ for (let i = 0; i < FLUSH_MAX_PASSES && pendingWrites.size > 0; i++) {
90
+ const keys = [...pendingWrites.keys()];
91
+ await Promise.all(keys.map(flushWrite));
92
+ }
93
+ if (pendingWrites.size > 0) {
94
+ throw new Error(`use-bridge-store flushAll did not quiesce after ${FLUSH_MAX_PASSES} passes (${pendingWrites.size} pending writes remain)`);
95
+ }
49
96
  };
50
97
  return {
51
98
  async get(store, key) {
@@ -75,10 +122,7 @@ export async function useBridgeStore(folder) {
75
122
  return;
76
123
  }
77
124
  touchCache(cacheKey, value);
78
- // Signal sessions and identity keys must be flushed immediately —
79
- // losing a ratchet step on crash causes undecryptable messages.
80
- const critical = store === 'session' || store === 'identity' || store === 'device';
81
- if (critical) {
125
+ if (CRITICAL_STORES.has(store)) {
82
126
  const existing = pendingWrites.get(cacheKey);
83
127
  if (existing) {
84
128
  clearTimeout(existing.timer);
@@ -1 +1 @@
1
- {"version":3,"file":"use-bridge-store.js","sourceRoot":"","sources":["../../src/Utils/use-bridge-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-bridge-store.js","sourceRoot":"","sources":["../../src/Utils/use-bridge-store.ts"],"names":[],"mappings":"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"}
@@ -5,9 +5,16 @@ import type { AuthenticationState } from '../Types/index.js';
5
5
  * All crypto keys, sessions, and identity are managed by the Rust engine
6
6
  * and persisted as `.bin` files via the bridge store. No `creds.json` needed.
7
7
  *
8
+ * Returns a `saveCreds` no-op for upstream-Baileys API parity. Upstream
9
+ * bots wire `ev.on('creds.update', saveCreds)` as the persistence hook;
10
+ * in baileyrs the bridge auto-persists everything through the store, so
11
+ * the function is a stable shim that lets the same call sites keep
12
+ * working without changes.
13
+ *
8
14
  * @param folder Directory to store bridge state files
9
15
  */
10
16
  export declare const useMultiFileAuthState: (folder: string) => Promise<{
11
17
  state: AuthenticationState;
18
+ saveCreds: () => Promise<void>;
12
19
  }>;
13
20
  //# sourceMappingURL=use-multi-file-auth-state.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-multi-file-auth-state.d.ts","sourceRoot":"","sources":["../../src/Utils/use-multi-file-auth-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAG5D;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAAU,QAAQ,MAAM,KAAG,OAAO,CAAC;IAAE,KAAK,EAAE,mBAAmB,CAAA;CAAE,CAiBlG,CAAA"}
1
+ {"version":3,"file":"use-multi-file-auth-state.d.ts","sourceRoot":"","sources":["../../src/Utils/use-multi-file-auth-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAG5D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,qBAAqB,GACjC,QAAQ,MAAM,KACZ,OAAO,CAAC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAqBxE,CAAA"}
@@ -6,6 +6,12 @@ import { useBridgeStore } from "./use-bridge-store.js";
6
6
  * All crypto keys, sessions, and identity are managed by the Rust engine
7
7
  * and persisted as `.bin` files via the bridge store. No `creds.json` needed.
8
8
  *
9
+ * Returns a `saveCreds` no-op for upstream-Baileys API parity. Upstream
10
+ * bots wire `ev.on('creds.update', saveCreds)` as the persistence hook;
11
+ * in baileyrs the bridge auto-persists everything through the store, so
12
+ * the function is a stable shim that lets the same call sites keep
13
+ * working without changes.
14
+ *
9
15
  * @param folder Directory to store bridge state files
10
16
  */
11
17
  export const useMultiFileAuthState = async (folder) => {
@@ -20,7 +26,11 @@ export const useMultiFileAuthState = async (folder) => {
20
26
  }
21
27
  const store = await useBridgeStore(folder);
22
28
  return {
23
- state: { store }
29
+ state: { store },
30
+ saveCreds: async () => {
31
+ // no-op: bridge owns creds and writes them through `store.set('device', …)`.
32
+ // Kept on the surface so upstream-Baileys code paths keep type-checking.
33
+ }
24
34
  };
25
35
  };
26
36
  //# sourceMappingURL=use-multi-file-auth-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-multi-file-auth-state.js","sourceRoot":"","sources":["../../src/Utils/use-multi-file-auth-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAE,MAAc,EAA2C,EAAE;IACtG,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACrD,IAAI,UAAU,EAAE,CAAC;QAChB,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACd,8CAA8C,MAAM,oDAAoD,CACxG,CAAA;QACF,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;IAE1C,OAAO;QACN,KAAK,EAAE,EAAE,KAAK,EAAE;KAChB,CAAA;AACF,CAAC,CAAA"}
1
+ {"version":3,"file":"use-multi-file-auth-state.js","sourceRoot":"","sources":["../../src/Utils/use-multi-file-auth-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAEtD;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EACzC,MAAc,EAC4D,EAAE;IAC5E,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACrD,IAAI,UAAU,EAAE,CAAC;QAChB,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACd,8CAA8C,MAAM,oDAAoD,CACxG,CAAA;QACF,CAAC;IACF,CAAC;SAAM,CAAC;QACP,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACzC,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAA;IAE1C,OAAO;QACN,KAAK,EAAE,EAAE,KAAK,EAAE;QAChB,SAAS,EAAE,KAAK,IAAI,EAAE;YACrB,6EAA6E;YAC7E,yEAAyE;QAC1E,CAAC;KACD,CAAA;AACF,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-legacy-store.d.ts","sourceRoot":"","sources":["../../src/Utils/wrap-legacy-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE5D,OAAO,KAAK,EAAuB,mBAAmB,EAAkC,MAAM,mBAAmB,CAAA;AAqBjH,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,OAAO,IAAI,IAAI,CAAA;CACf;AAk+BD,wBAAsB,eAAe,CACpC,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC9B,MAAM,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACrD,OAAO,CAAC,kBAAkB,CAAC,CA4O7B;AAqCD;;;;;;;;;GASG;AACH,wBAAsB,2BAA2B,CAChD,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAoEzE"}
1
+ {"version":3,"file":"wrap-legacy-store.d.ts","sourceRoot":"","sources":["../../src/Utils/wrap-legacy-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAE5D,OAAO,KAAK,EAAuB,mBAAmB,EAAkC,MAAM,mBAAmB,CAAA;AAuBjH,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACtB,OAAO,IAAI,IAAI,CAAA;CACf;AAu+BD,wBAAsB,eAAe,CACpC,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC9B,MAAM,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACrD,OAAO,CAAC,kBAAkB,CAAC,CA+P7B;AASD;;;;;;;;;GASG;AACH,wBAAsB,2BAA2B,CAChD,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAoEzE"}
@@ -15,6 +15,8 @@ import { createHmac } from 'node:crypto';
15
15
  import { mkdir, readFile, stat, unlink, writeFile } from 'node:fs/promises';
16
16
  import { join } from 'node:path';
17
17
  import { proto } from 'whatsapp-rust-bridge/proto-types';
18
+ import { jidDecode } from "../WABinary/jid-utils.js";
19
+ import { BufferJSON } from "./generics.js";
18
20
  const protoLookup = proto;
19
21
  const ADVSignedDeviceIdentity = protoLookup.ADVSignedDeviceIdentity ?? protoLookup.AdvSignedDeviceIdentity;
20
22
  function warn(msg, err) {
@@ -47,36 +49,32 @@ const STORE_MAP = {
47
49
  mutation_mac: 'bridge-mutation-mac',
48
50
  meta: 'bridge-meta'
49
51
  };
50
- // Stores where bridge data is passthrough binary (no conversion).
51
- // All Signal-protocol records (`identity`, `session`, `sender_key`) now
52
- // route through converters because every one of them either:
53
- // has a different key shape between bridge and upstream, OR
54
- // • has a different value-byte encoding (proto / JSON / 32-vs-33-byte
55
- // prefix), OR
56
- // • both.
57
- // Keeping the empty set as an extension point — future bridge stores that
58
- // are byte-compatible with upstream can land here without a converter.
52
+ // Stores that are byte-compatible between bridge and upstream and so can
53
+ // be persisted unchanged. Currently empty every Signal record needs
54
+ // either a key rewrite or a value-byte conversion, both handled by
55
+ // `converters` below.
59
56
  const BINARY_STORES = new Set();
60
- // Bridge-only stores — raw binary persisted through keys interface.
61
- // `lid_mapping` is intentionally excluded it has a converter so the
62
- // `pn:`/`lid:` prefixed bridge keys translate to upstream's bare-userpart
63
- // `{pnUser}` + `{lidUser}_reverse` shape, letting both libraries share
64
- // the same on-disk LID↔PN mapping table.
65
- const BRIDGE_ONLY_STORES = new Set([
66
- 'signed_prekey',
67
- 'sender_key_devices',
68
- 'base_key',
69
- 'sent_message',
70
- 'mutation_mac',
71
- 'meta'
72
- ]);
57
+ // Bridge-only stores — raw binary persisted through the keys interface.
58
+ // Derived from STORE_MAP: anything mapped to a `bridge-*` upstream type
59
+ // has no peer in upstream Baileys' SignalDataTypeMap and must round-trip
60
+ // as raw bytes. `lid_mapping` is mapped to upstream's `lid-mapping` type
61
+ // instead (its converter rewrites the key prefixes), so it's not
62
+ // bridge-only and is naturally excluded by the prefix filter.
63
+ const BRIDGE_ONLY_STORES = new Set(Object.entries(STORE_MAP)
64
+ .filter(([, upstreamType]) => upstreamType.startsWith('bridge-'))
65
+ .map(([bridgeName]) => bridgeName));
73
66
  /** Reconstruct a JID string from the bridge's serialized Jid object.
74
- * Format: "user:device@server" (device omitted when 0). */
67
+ * Format: `user[_<agent>][:<device>]@<server>`. The agent suffix is
68
+ * required to round-trip hosted Business accounts (`5511_2@hosted`) —
69
+ * `credsToDeviceJson` stores it, so the load path must also emit it.
70
+ * Without this, `creds.me.id` would lose the `_<agent>` half on every
71
+ * reload and the next `credsToDeviceJson` save would zero `agent`. */
75
72
  function bridgeJidToString(j) {
76
73
  if (!j?.user || !j?.server)
77
74
  return null;
75
+ const agent = j.agent ?? 0;
78
76
  const device = j.device ?? 0;
79
- return `${j.user}${device > 0 ? ':' + device : ''}@${j.server}`;
77
+ return `${j.user}${agent > 0 ? '_' + agent : ''}${device > 0 ? ':' + device : ''}@${j.server}`;
80
78
  }
81
79
  // ---- Helpers ----
82
80
  const toJson = (v) => new TextEncoder().encode(JSON.stringify(v));
@@ -85,6 +83,24 @@ const toBuf = (v) => v instanceof Uint8Array ? v : Buffer.isBuffer(v) ? new Uint
85
83
  /** Convert Buffer/Uint8Array to a plain number[] for JSON serialization.
86
84
  * Matches Rust's serde_json Vec<u8> format: [byte, byte, ...] */
87
85
  const bufToNumArray = (v) => Array.from(Buffer.from(v));
86
+ /**
87
+ * `true` when the key bytes are absent or all zeros. Used at the device-read
88
+ * boundary to detect a partially-hydrated creds object (e.g. migration
89
+ * remnants where only `me.id` survived) and tell the bridge to bootstrap
90
+ * fresh material instead of blowing up the noise handshake with `precondition-required`.
91
+ */
92
+ const isZeroKey = (b) => {
93
+ if (!b)
94
+ return true;
95
+ // Buffer is a Uint8Array subclass at runtime, so this view is always safe.
96
+ const view = b;
97
+ if (view.length === 0)
98
+ return true;
99
+ for (let i = 0; i < view.length; i++)
100
+ if (view[i] !== 0)
101
+ return false;
102
+ return true;
103
+ };
88
104
  /** Bridge uses hex-encoded key IDs for sync_key; upstream uses base64. Convert hex→base64. */
89
105
  const hexToBase64 = (hex) => Buffer.from(hex, 'hex').toString('base64');
90
106
  const converters = {
@@ -336,21 +352,6 @@ const converters = {
336
352
  }
337
353
  }
338
354
  };
339
- // BufferJSON-compatible replacer/reviver matching upstream `Utils/generics`.
340
- const bufferJsonReplacer = (_k, v) => {
341
- if (Buffer.isBuffer(v) || v instanceof Uint8Array || v?.type === 'Buffer') {
342
- const data = v?.data ?? v;
343
- return { type: 'Buffer', data: Buffer.from(data).toString('base64') };
344
- }
345
- return v;
346
- };
347
- const bufferJsonReviver = (_k, v) => {
348
- const obj = v;
349
- if (obj && typeof obj === 'object' && obj.type === 'Buffer' && typeof obj.data === 'string') {
350
- return Buffer.from(obj.data, 'base64');
351
- }
352
- return v;
353
- };
354
355
  const sk_toBytes = (v) => v ? new Uint8Array(Buffer.from(v)) : new Uint8Array();
355
356
  const sk_toBuffer = (v) => Buffer.from(v ?? new Uint8Array());
356
357
  function bridgeSenderKeyProtoToJson(protoBytes) {
@@ -367,10 +368,10 @@ function bridgeSenderKeyProtoToJson(protoBytes) {
367
368
  seed: sk_toBuffer(mk.seed)
368
369
  }))
369
370
  }));
370
- return Buffer.from(JSON.stringify(states, bufferJsonReplacer), 'utf-8');
371
+ return Buffer.from(JSON.stringify(states, BufferJSON.replacer), 'utf-8');
371
372
  }
372
373
  function upstreamSenderKeyJsonToProto(jsonBuf) {
373
- const states = JSON.parse(Buffer.from(jsonBuf).toString('utf-8'), bufferJsonReviver);
374
+ const states = JSON.parse(Buffer.from(jsonBuf).toString('utf-8'), BufferJSON.reviver);
374
375
  const senderKeyStates = states.map(s => ({
375
376
  senderKeyId: s.senderKeyId ?? 0,
376
377
  senderChainKey: { iteration: s.senderChainKey?.iteration ?? 0, seed: sk_toBytes(s.senderChainKey?.seed) },
@@ -607,20 +608,27 @@ function upstreamSessionRecordToProto(record) {
607
608
  // session/identity key translation: bridge `{user}[:dev]@{server}.{sig}`
608
609
  // → upstream `{signalUser}.{deviceId}` via `bridgeAddrToBaileysAddr`.
609
610
  // ---- Device/Creds ----
610
- /** Parse a JID string into { user, device, server } */
611
- function parseJid(jid) {
612
- if (!jid)
613
- return null;
614
- const atIdx = jid.indexOf('@');
611
+ /**
612
+ * Extract the literal `_<n>` agent suffix from a raw JID. `jidDecode`
613
+ * folds it into `domainType` only for plain `s.whatsapp.net`; for special
614
+ * servers (`hosted`, `hosted.lid`) it is parsed-then-discarded because
615
+ * `domainType` is taken from the server. The bridge's `Jid.agent`
616
+ * field needs the literal number, so recover it here.
617
+ */
618
+ function jidAgent(rawJid) {
619
+ if (!rawJid)
620
+ return 0;
621
+ const atIdx = rawJid.indexOf('@');
615
622
  if (atIdx < 0)
616
- return null;
617
- const server = jid.slice(atIdx + 1);
618
- const userPart = jid.slice(0, atIdx);
619
- const colonIdx = userPart.indexOf(':');
620
- if (colonIdx >= 0) {
621
- return { user: userPart.slice(0, colonIdx), device: parseInt(userPart.slice(colonIdx + 1)) || 0, server };
622
- }
623
- return { user: userPart, device: 0, server };
623
+ return 0;
624
+ const userPart = rawJid.slice(0, atIdx).split(':', 1)[0];
625
+ if (!userPart)
626
+ return 0;
627
+ const sepIdx = userPart.indexOf('_');
628
+ if (sepIdx < 0)
629
+ return 0;
630
+ const n = parseInt(userPart.slice(sepIdx + 1), 10);
631
+ return Number.isFinite(n) ? n : 0;
624
632
  }
625
633
  function credsToDeviceJson(creds) {
626
634
  /** Serialize a key pair as [private(32) + public(32)] matching Rust key_pair_serde */
@@ -629,15 +637,19 @@ function credsToDeviceJson(creds) {
629
637
  return Array(64).fill(0);
630
638
  return bufToNumArray(Buffer.from(pair.private)).concat(bufToNumArray(Buffer.from(pair.public)));
631
639
  };
632
- // Extract device number from me.id (e.g. "559984726662:7@s.whatsapp.net")
633
- // or fall back to me.lid (e.g. "236395184570386:10@lid") for the device index
634
- const pnJid = parseJid(creds.me?.id);
635
- const lidJid = parseJid(creds.me?.lid);
636
- // If me.id has no device suffix, use the LID's device number
637
- const deviceNum = pnJid && pnJid.device > 0 ? pnJid.device : (lidJid?.device ?? 0);
640
+ const pnJid = jidDecode(creds.me?.id);
641
+ const lidJid = jidDecode(creds.me?.lid);
642
+ const deviceNum = pnJid?.device ?? lidJid?.device ?? 0;
643
+ const pnAgent = jidAgent(creds.me?.id);
644
+ const lidAgent = jidAgent(creds.me?.lid);
645
+ // Preserve `server` and recover the literal `_<n>` agent suffix so
646
+ // hosted / hosted.lid accounts (e.g. `5511_2@hosted`) survive a
647
+ // drop-in migration from upstream Baileys.
638
648
  return toJson({
639
- pn: pnJid ? { user: pnJid.user, server: 's.whatsapp.net', device: deviceNum, agent: 0, integrator: 0 } : null,
640
- lid: lidJid ? { user: lidJid.user, server: 'lid', device: lidJid.device, agent: 0, integrator: 0 } : null,
649
+ pn: pnJid ? { user: pnJid.user, server: pnJid.server, device: deviceNum, agent: pnAgent, integrator: 0 } : null,
650
+ lid: lidJid
651
+ ? { user: lidJid.user, server: lidJid.server, device: lidJid.device ?? 0, agent: lidAgent, integrator: 0 }
652
+ : null,
641
653
  registration_id: creds.registrationId ?? 0,
642
654
  noise_key: kp(creds.noiseKey),
643
655
  identity_key: kp(creds.signedIdentityKey),
@@ -879,7 +891,7 @@ export async function wrapLegacyStore(state, saveCreds, logger) {
879
891
  clearTimeout(credsTimer);
880
892
  credsTimer = setTimeout(() => {
881
893
  credsTimer = null;
882
- saveCreds().catch(() => { });
894
+ saveCreds().catch(err => warn('saveCreds failed', err));
883
895
  }, 100);
884
896
  };
885
897
  /** Route a store to its handler */
@@ -980,6 +992,16 @@ export async function wrapLegacyStore(state, saveCreds, logger) {
980
992
  // through `set('device', 'device', …)` on pair-success.
981
993
  if (!creds.noiseKey && !creds.me?.id)
982
994
  return null;
995
+ // Even when `noiseKey` is present as an object, the bytes
996
+ // can still be all-zero — happens after a partial migration
997
+ // from a legacy creds.json that only persisted `me.id`.
998
+ // `credsToDeviceJson` would happily emit zero-filled key
999
+ // slots, which the server rejects with the same 428. Treat
1000
+ // any zero-byte critical key as a bootstrap signal.
1001
+ if (isZeroKey(creds.noiseKey?.private) || isZeroKey(creds.signedIdentityKey?.private)) {
1002
+ warn('device read: noiseKey/signedIdentityKey is zero-valued; signaling bootstrap to bridge');
1003
+ return null;
1004
+ }
983
1005
  return credsToDeviceJson(creds);
984
1006
  }
985
1007
  if (key === 'account') {
@@ -989,14 +1011,10 @@ export async function wrapLegacyStore(state, saveCreds, logger) {
989
1011
  }
990
1012
  return readBinary(type, key);
991
1013
  }
992
- if (route === 'signal') {
993
- // `BINARY_STORES` is empty as of the move-to-converter
994
- // migration keeping the branch for future passthrough
995
- // stores. No identity fallback needed: identity now goes
996
- // through the converter, which handles both the address
997
- // rewrite and the 32↔33-byte prefix.
1014
+ // `signal` route is currently unreachable (BINARY_STORES is empty);
1015
+ // kept for future byte-compatible stores.
1016
+ if (route === 'signal')
998
1017
  return readBinary(type, key);
999
- }
1000
1018
  if (route === 'bridge-only')
1001
1019
  return readBinary(type, key);
1002
1020
  if (route === 'converter') {
@@ -1064,36 +1082,38 @@ export async function wrapLegacyStore(state, saveCreds, logger) {
1064
1082
  }
1065
1083
  },
1066
1084
  async flush() {
1067
- if (credsTimer) {
1085
+ // Drain in a loop because `set('device', ...)` calls landing
1086
+ // during `await saveCreds()` queue a fresh `credsTimer`. A
1087
+ // single-pass flush would leave the latest creds on the timer
1088
+ // — `dispose()` then fires saveCreds() but the orchestrator
1089
+ // has already moved on (`free()`), so the write is racing
1090
+ // against process exit. Looping until the timer is null after
1091
+ // a save closes the window deterministically. Bounded by a
1092
+ // small max-iterations guard so a saveCreds() that re-emits
1093
+ // credentials in a tight loop can't lock us forever.
1094
+ for (let i = 0; i < 32 && credsTimer; i++) {
1068
1095
  clearTimeout(credsTimer);
1069
1096
  credsTimer = null;
1070
1097
  await saveCreds();
1071
1098
  }
1099
+ if (credsTimer) {
1100
+ warn('flush hit max-iterations cap; pending credsTimer dropped — saveCreds may be re-emitting in a loop');
1101
+ clearTimeout(credsTimer);
1102
+ credsTimer = null;
1103
+ }
1072
1104
  },
1073
1105
  dispose() {
1074
1106
  if (credsTimer) {
1075
1107
  clearTimeout(credsTimer);
1076
- saveCreds().catch(() => { });
1108
+ saveCreds().catch(err => warn('saveCreds failed during dispose', err));
1077
1109
  }
1078
1110
  }
1079
1111
  };
1080
1112
  }
1081
- const bufferReviver = (_, value) => {
1082
- if (value !== null &&
1083
- value !== undefined &&
1084
- typeof value === 'object' &&
1085
- (value.type === 'Buffer' || value.buffer === true)) {
1086
- const data = value.data ?? value.value;
1087
- return typeof data === 'string'
1088
- ? Buffer.from(data, 'base64')
1089
- : Buffer.from((Array.isArray(data) ? data : []));
1090
- }
1091
- return value;
1092
- };
1093
- /** JSON replacer that serializes Buffer/Uint8Array → `{ type: "Buffer", data: "base64" }` */
1094
- const bufferReplacer = (_, value) => value instanceof Uint8Array || Buffer.isBuffer(value)
1095
- ? { type: 'Buffer', data: Buffer.from(value).toString('base64') }
1096
- : value;
1113
+ // ---- Legacy multi-file auth state loader ----
1114
+ // Reads upstream Baileys' creds.json + per-key .json files via the
1115
+ // shared `BufferJSON` codec (same as @whiskeysockets/baileys
1116
+ // useMultiFileAuthState).
1097
1117
  const fixFileName = (file) => file?.replace(/\//g, '__')?.replace(/:/g, '-');
1098
1118
  /**
1099
1119
  * Loads an upstream Baileys session (creds.json + key .json files) and returns
@@ -1116,14 +1136,14 @@ export async function useLegacyMultiFileAuthState(folder) {
1116
1136
  const readData = async (file) => {
1117
1137
  try {
1118
1138
  const data = await readFile(join(folder, fixFileName(file)), 'utf-8');
1119
- return JSON.parse(data, bufferReviver);
1139
+ return JSON.parse(data, BufferJSON.reviver);
1120
1140
  }
1121
1141
  catch {
1122
1142
  return null;
1123
1143
  }
1124
1144
  };
1125
1145
  const writeData = async (data, file) => {
1126
- await writeFile(join(folder, fixFileName(file)), JSON.stringify(data, bufferReplacer));
1146
+ await writeFile(join(folder, fixFileName(file)), JSON.stringify(data, BufferJSON.replacer));
1127
1147
  };
1128
1148
  const removeData = async (file) => {
1129
1149
  try {