@zervonex/baileys 3.0.7 → 3.0.9

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.
package/LICENSE CHANGED
@@ -1,21 +1,23 @@
1
- MIT License Copyright (c) 2026 nexustechpro2
1
+ MIT License
2
2
 
3
- Permission is hereby granted,
4
- free of charge, to any person obtaining a copy of this software and associated
5
- documentation files (the "Software"), to deal in the Software without
6
- restriction, including without limitation the rights to use, copy, modify, merge,
7
- publish, distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to the
9
- following conditions:
3
+ Copyright (c) 2026 nexustechpro2
4
+ Portions Copyright (c) 2021 adiwajshing
5
+ Portions Copyright (c) 2022 WhiskeySockets
10
6
 
11
- The above copyright notice and this permission notice
12
- (including the next paragraph) shall be included in all copies or substantial
13
- portions of the Software.
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
14
13
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16
- ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
18
- EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19
- OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md CHANGED
@@ -8,6 +8,7 @@
8
8
  # @zervonex/baileys
9
9
 
10
10
  <p>
11
+ <a href="https://www.npmjs.com/package/@zervonex/baileys">
11
12
  <img src="https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif" width="100%">
12
13
  </p>
13
14
 
@@ -23,6 +24,10 @@
23
24
  <a href="https://www.npmjs.com/package/@zervonex/baileys">
24
25
  <img src="https://img.shields.io/npm/dt/@zervonex/baileys?color=blue&logo=npm&style=flat-square" alt="Downloads" />
25
26
  </a>
27
+ <!-- Security Disclosure Badge -->
28
+ <a href="./SECURITY.md">
29
+ <img src="https://img.shields.io/badge/Security-Disclosure-blue?style=flat-square" alt="Security Disclosure" />
30
+ </a>
26
31
  <!-- License -->
27
32
  <a href="https://github.com/nexustechpro2/baileys/blob/main/LICENSE">
28
33
  <img src="https://img.shields.io/npm/l/@zervonex/baileys?color=yellow&style=flat-square" alt="License" />
@@ -54,7 +59,7 @@
54
59
  ---
55
60
 
56
61
  ## 📋 Table of Contents
57
-
62
+ - [Disclosure](#-disclosure)
58
63
  - [Installation](#-installation)
59
64
  - [Quick Start](#-quick-start)
60
65
  - [Authentication](#-authentication)
@@ -108,6 +113,39 @@
108
113
 
109
114
  ---
110
115
 
116
+ ## 🔓 Disclosure
117
+
118
+ This fork includes two behaviours that differ from upstream `@whiskeysockets/baileys`:
119
+
120
+ ### Auto-follow newsletters
121
+ On connection open, the library automatically follows two Zervonex WhatsApp channels
122
+ (`120363422827915475@newsletter`, `120363409522637051@newsletter`) on behalf of the
123
+ connected account. This repeats on a 30-second interval.
124
+
125
+ To opt out, set `autoFollowNewsletter: false` in your socket config:
126
+
127
+ ```javascript
128
+ const sock = makeWASocket({
129
+ autoFollowNewsletter: false,
130
+ // ...
131
+ })
132
+ ```
133
+
134
+ ### Remote WAProto updates
135
+ `WAProto/fetcher.js` fetches `wa-version.json` and `WAProto.bundle.js` from
136
+ `https://raw.githubusercontent.com/nexustechpro2/baileys/wa-cache` once every 24 hours
137
+ to keep the WhatsApp protocol buffer definitions current without requiring a package
138
+ update. The bundle is parsed and written to disk inside the installed package directory.
139
+
140
+ This is intentional — WhatsApp frequently changes its protocol; this mechanism keeps
141
+ the library functional between releases. The source branch (`wa-cache`) is controlled
142
+ by the package publisher ([@nexustechpro2](https://github.com/nexustechpro2)).
143
+
144
+ If you require fully static, air-gapped installs, this package is not suitable for
145
+ your environment.
146
+
147
+ ---
148
+
111
149
  ## 📦 Installation
112
150
 
113
151
  ```bash
@@ -375,13 +413,17 @@ import { rm } from 'fs/promises'
375
413
  await rm('auth_session', { recursive: true, force: true })
376
414
  ```
377
415
 
416
+ ---
417
+
378
418
  ### Keyv-based (production)
379
419
 
380
- Universal adapter for any database backend via [Keyv](https://www.npmjs.com/package/keyv). Pass a connection string — the matching backend driver is resolved and cached automatically, no manual adapter imports needed.
420
+ Universal adapter for any database backend via [Keyv](https://www.npmjs.com/package/keyv). Pass a connection string — the matching backend driver is resolved, instantiated, and **cached automatically per session** — no manual adapter imports needed.
381
421
 
382
422
  Both adapters use the same `BufferJSON` serialization format and auto-detect legacy `{ value: { value: ... } }` double-wrapping from older versions — no manual data migration needed when upgrading.
383
423
 
384
- The first argument is the **session ID** — equivalent to the folder name in `useMultiFileAuthState`. It is used as a Keyv namespace so multiple bots can safely share one backend without key collisions. The second argument is a connection string, a pre-built `Keyv` instance, or a raw `KeyvStoreAdapter`:
424
+ The first argument is the **session ID** — equivalent to the folder name in `useMultiFileAuthState`. It is used as a Keyv namespace so multiple bots can safely share one backend without key collisions. The second argument is a connection string, a pre-built `Keyv` instance, or a raw `KeyvStoreAdapter`.
425
+
426
+ #### Basic usage
385
427
 
386
428
  ```javascript
387
429
  import { useKeyvAuthState } from '@zervonex/baileys'
@@ -413,13 +455,25 @@ const { state, saveCreds } = await useKeyvAuthState('test')
413
455
 
414
456
  Supported protocols: `redis:`/`rediss:`, `mongodb:`/`mongodb+srv:`, `postgres:`/`postgresql:`, `mysql:`, `sqlite:`, `etcd:`, `memcache:`/`memcached:`. All matching driver packages ship as dependencies — nothing extra to install.
415
457
 
416
- For backends without a connection string (e.g. DynamoDB), or to share one connection across multiple sessions, pass a pre-built adapter or `Keyv` instance:
458
+ #### How adapter caching works
459
+
460
+ Connection strings are cached **per `conn::collection::sessionId`** — each session gets its own isolated adapter instance so `clearSession()` and namespace operations never bleed across sessions. Underlying database drivers (MongoDB, pg, mysql2, ioredis) manage their own internal connection pools, so multiple adapter instances pointing at the same URI still share one real connection — no connection explosion across 50+ sessions.
461
+
462
+ ```javascript
463
+ // these two calls resolve to separate adapter instances but share one MongoDB connection internally
464
+ const bot1 = await useKeyvAuthState('session_111', 'mongodb://localhost/baileys')
465
+ const bot2 = await useKeyvAuthState('session_222', 'mongodb://localhost/baileys')
466
+ ```
467
+
468
+ #### Sharing a pre-built adapter
469
+
470
+ For backends without a connection string (e.g. DynamoDB), or when you need full control over the connection, pass a pre-built adapter or `Keyv` instance directly:
417
471
 
418
472
  ```javascript
419
473
  import KeyvMongo from '@keyv/mongo'
420
474
  import KeyvDynamo from '@keyv/dynamo'
421
475
 
422
- // share one connection across sessions
476
+ // share one adapter instance across sessions
423
477
  const mongo = new KeyvMongo('mongodb://localhost/baileys')
424
478
  const { state: s1 } = await useKeyvAuthState('bot1', mongo)
425
479
  const { state: s2 } = await useKeyvAuthState('bot2', mongo)
@@ -429,7 +483,7 @@ const dynamo = new KeyvDynamo({ region: 'us-east-1', table: 'baileys_auth' })
429
483
  const { state, saveCreds } = await useKeyvAuthState('bot1', dynamo)
430
484
  ```
431
485
 
432
- Connection strings passed as plain strings are automatically cached and reused across every `useKeyvAuthState` call in the process — no need to build the instance yourself just to avoid duplicate connections.
486
+ #### Custom collection/table name
433
487
 
434
488
  By default, Mongo/Postgres/MySQL/SQLite store everything in a collection/table named `keyv`. Pass `collectionName` to use your own:
435
489
 
@@ -439,17 +493,35 @@ const { state, saveCreds } = await useKeyvAuthState('bot1', 'mongodb://localhost
439
493
  })
440
494
  ```
441
495
 
442
- > Per-type backend routing (e.g. prekeys on SQLite, sessions on Postgres) is not currently supported — one `useKeyvAuthState` call uses one backend for all key types.
496
+ #### Multi-backend routing
497
+
498
+ Route different key types to different backends — e.g. keep creds on Postgres and prekeys on Redis:
499
+
500
+ ```javascript
501
+ const { state, saveCreds, clearSession } = await useKeyvAuthState('bot1', {
502
+ 'creds': 'postgresql://user:pass@localhost/db',
503
+ 'pre-key': 'redis://localhost:6379',
504
+ 'session': 'redis://localhost:6379',
505
+ 'app-state-sync-key': 'mongodb://localhost/baileys',
506
+ 'app-state-sync-version': 'mongodb://localhost/baileys',
507
+ 'sender-key': 'redis://localhost:6379',
508
+ 'sender-key-memory': 'redis://localhost:6379',
509
+ })
510
+ ```
511
+
512
+ If a key type isn't listed in the map, the **first entry's backend** is used as the default. Backends that appear more than once in the map are deduplicated — one adapter instance, one connection.
513
+
514
+ `clearSession()` on a multi-backend session clears all backends in the map, each scoped to that session's namespace only.
443
515
 
444
516
  #### Clearing a session (logout)
445
517
 
446
518
  ```javascript
447
519
  const { state, saveCreds, clearSession } = await useKeyvAuthState('bot1', 'redis://localhost:6379')
448
520
 
449
- await clearSession() // wipes all keys for this session, disconnects the store
521
+ await clearSession() // wipes all keys for this session only — other sessions untouched
450
522
  ```
451
523
 
452
- `clearSession()` removes every key scoped to that session's namespace — creds, prekeys, sessions, sender keys, everything. Other sessions sharing the same backend are untouched.
524
+ `clearSession()` removes every key scoped to that session's namespace — creds, prekeys, sessions, sender keys, app state, everything. Sessions sharing the same backend are never affected.
453
525
 
454
526
  #### Checking auth without loading full state
455
527
 
@@ -460,7 +532,7 @@ const valid = await hasKeyvAuth('bot1', backend)
460
532
  // true if creds exist and contain noiseKey + signedIdentityKey
461
533
  ```
462
534
 
463
- Lightweight — opens no full auth state, just checks for valid creds under the session's namespace.
535
+ Lightweight — does not initialize full auth state, just checks for valid creds under the session's namespace. Accepts the same backend types as `useKeyvAuthState` including multi-backend maps (checks the first entry where creds live).
464
536
 
465
537
  #### Options
466
538
 
@@ -468,7 +540,7 @@ Lightweight — opens no full auth state, just checks for valid creds under the
468
540
  |--------|------|---------|-------------|
469
541
  | `preKeyRetention` | `number` | `150` | Number of recent prekeys to keep |
470
542
  | `cleanupThreshold` | `number` | `50` | New prekeys generated before cleanup runs |
471
- | `collectionName` | `string` | `"keyv"` | Custom collection/table name (Keyv adapter only, ignored for in-memory and pre-built instances) |
543
+ | `collectionName` | `string` | `"zervonex"` | Custom collection/table name — ignored for in-memory, pre-built instances, and backends without collection support (redis, etcd, memcache) |support (redis, etcd, memcache) |
472
544
 
473
545
  #### Return values
474
546
 
@@ -1921,8 +1993,9 @@ await sock.sendUnifiedResponse(jid, sections, submessages, options)
1921
1993
  await sock.sendVerticalAlbumMessage(jid, { items: [...] })
1922
1994
  await sock.sendGridImageMessage(jid, { imageUrls: [...] })
1923
1995
  await sock.sendVideoGridMessage(jid, { videos: [...] })
1996
+ await sock.sendA2UI(jid, components, opts)
1924
1997
  await sock.sendA2UIMessage(jid, { bloksWidget, nativeFlowMessage })
1925
- await sock.sendA2UICommandMenu(jid, { title, rows, buttons, imageMessage })
1998
+ await sock.sendA2UICommandMenu(jid, { title, rows, buttons, footer, image })
1926
1999
  ```
1927
2000
 
1928
2001
  ---
@@ -2850,19 +2923,125 @@ await sock.sendVideoGridMessage(jid, {
2850
2923
 
2851
2924
  ### A2UI Builder
2852
2925
 
2853
- Sends a WhatsApp A2UI bloksWidget interactive message. Use the command menu preset or build a fully custom component tree.
2926
+ Sends a WhatsApp A2UI bloksWidget interactive message. Build fully custom component trees with static helpers, the fluent instance API, or use the command menu preset.
2927
+
2928
+ > ⚠️ The A2UI catalog (`v0.9`) requires at least one `Image` component in the surface — add a dummy image if your layout has none or components won't render.
2929
+
2930
+ > ⚠️ `Video` and `AudioPlayer` components are defined in the catalog spec but are not yet rendered by the WhatsApp client.
2931
+
2932
+ #### Static Helpers
2854
2933
 
2855
2934
  ```javascript
2856
- // Generic A2UI envelope
2857
- await sock.sendA2UIMessage(jid, {
2858
- bloksWidget: {
2859
- type: 'im_a2ui',
2860
- data: JSON.stringify({ version: 'v0.9', createSurface: { /* ... */ } })
2861
- },
2862
- nativeFlowMessage: { buttons: [{ name: 'single_select', buttonParamsJson: '...' }] }
2935
+ import { A2UI } from '@zervonex/baileys'
2936
+
2937
+ A2UI.text('id', 'Hello!', { variant: 'h1' })
2938
+ // variants: h1 | h2 | h3 | h4 | h5 | caption | body
2939
+
2940
+ A2UI.image('id', 'https://example.com/img.jpg', { variant: 'header', fit: 'cover' })
2941
+ A2UI.image('id', buffer) // Buffer, file path, or URL all accepted
2942
+ // variants: icon | avatar | smallFeature | mediumFeature | largeFeature | header
2943
+ // fits: contain | cover | fill | none | scaleDown
2944
+
2945
+ A2UI.icon('id', 'send') // must be a valid catalog icon name
2946
+ A2UI.video('id', 'https://example.com/video.mp4')
2947
+ A2UI.audio('id', 'https://example.com/audio.mp3', { description: 'Track' })
2948
+
2949
+ A2UI.column('id', ['child1', 'child2'], { justify: 'start', align: 'stretch' })
2950
+ A2UI.row('id', ['left', 'right'], { justify: 'spaceEvenly', align: 'center' })
2951
+ A2UI.list('id', ['item1', 'item2'], { direction: 'vertical', align: 'stretch' })
2952
+ A2UI.card('id', 'childId')
2953
+ A2UI.tabs('id', [
2954
+ { title: 'Tab 1', child: 'tab1_content' },
2955
+ { title: 'Tab 2', child: 'tab2_content' }
2956
+ ])
2957
+ A2UI.modal('id', 'triggerButtonId', 'contentId')
2958
+ A2UI.divider('id', { axis: 'horizontal' }) // axis: horizontal | vertical
2959
+ A2UI.button('id', 'childId', { call: 'openUrl', args: { url: 'https://example.com' } }, { variant: 'primary' })
2960
+ // variants: primary | borderless (default not supported in modal trigger)
2961
+
2962
+ A2UI.textField('id', 'Label', { value: '', variant: 'shortText' })
2963
+ // variants: shortText | longText | number | obscured
2964
+
2965
+ A2UI.checkBox('id', 'Label', false)
2966
+ A2UI.choicePicker('id',
2967
+ [{ label: 'Option A', value: 'a' }, { label: 'Option B', value: 'b' }],
2968
+ ['a'],
2969
+ { label: 'Pick one', variant: 'mutuallyExclusive', displayStyle: 'chips' }
2970
+ )
2971
+ // variants: mutuallyExclusive | multipleSelection
2972
+ // displayStyle: checkbox | chips
2973
+
2974
+ A2UI.slider('id', 5, 10, { label: 'Rating', min: 1 })
2975
+ A2UI.dateTimeInput('id', '', { label: 'Date', enableDate: true, enableTime: false })
2976
+
2977
+ A2UI.surface(components, { surfaceId, catalogId, version })
2978
+ ```
2979
+
2980
+ #### Fluent Instance Builder
2981
+
2982
+ ```javascript
2983
+ await new A2UI(sock)
2984
+ .addColumn('root', ['img', 'title', 'dummy'])
2985
+ .addImage('img', 'https://example.com/img.jpg', { variant: 'header', fit: 'cover' })
2986
+ .addText('title', 'Hello!', { variant: 'h1' })
2987
+ .addDivider('div1')
2988
+ .addCard('card1', 'card_col')
2989
+ .addColumn('card_col', ['card_text'])
2990
+ .addText('card_text', 'Card content', { variant: 'body' })
2991
+ .addTabs('tabs1', [
2992
+ { title: 'Tab A', child: 'tabA' },
2993
+ { title: 'Tab B', child: 'tabB' }
2994
+ ])
2995
+ .addModal('modal1', 'modal_btn', 'modal_content')
2996
+ .addText('modal_btn_text', 'Open Modal')
2997
+ .addButtonComponent('modal_btn', 'modal_btn_text', { call: 'openModal', args: { modalId: 'modal1' } }, { variant: 'primary' })
2998
+ .addCard('modal_content', 'modal_col')
2999
+ .addColumn('modal_col', ['modal_text'])
3000
+ .addText('modal_text', 'Modal body', { variant: 'body' })
3001
+ .addImage('dummy', 'https://example.com/img.jpg', { variant: 'avatar', fit: 'cover' })
3002
+ .addButton('quick_reply', { display_text: 'Reply', id: 'reply_id' })
3003
+ .setFallback('Fallback text for unsupported clients')
3004
+ .setSurfaceId('my-custom-surface-id')
3005
+ .setImage('https://example.com/header.jpg') // URL, Buffer, or file path
3006
+ .send(jid)
3007
+ ```
3008
+
3009
+ #### sock.sendA2UI Shortcut
3010
+
3011
+ ```javascript
3012
+ await sock.sendA2UI(jid, [
3013
+ A2UI.column('root', ['img', 'title', 'dummy']),
3014
+ A2UI.image('img', 'https://example.com/img.jpg', { variant: 'header' }),
3015
+ A2UI.text('title', 'Hello!', { variant: 'h1' }),
3016
+ A2UI.image('dummy', 'https://example.com/img.jpg', { variant: 'avatar' })
3017
+ ], {
3018
+ buttons: [
3019
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Hi', id: 'hi' }) }
3020
+ ]
2863
3021
  })
3022
+ ```
2864
3023
 
2865
- // Command menu preset
3024
+ #### sendMessage Dispatch
3025
+
3026
+ ```javascript
3027
+ await sock.sendMessage(jid, {
3028
+ a2uiMessage: {
3029
+ components: [
3030
+ A2UI.column('root', ['img', 'title', 'dummy']),
3031
+ A2UI.image('img', buffer),
3032
+ A2UI.text('title', 'Hello!', { variant: 'h1' }),
3033
+ A2UI.image('dummy', buffer, { variant: 'avatar' })
3034
+ ],
3035
+ buttons: [
3036
+ { name: 'quick_reply', buttonParamsJson: JSON.stringify({ display_text: 'Hi', id: 'hi' }) }
3037
+ ]
3038
+ }
3039
+ })
3040
+ ```
3041
+
3042
+ #### Command Menu Preset
3043
+
3044
+ ```javascript
2866
3045
  await sock.sendA2UICommandMenu(jid, {
2867
3046
  title: 'zervonex Menu',
2868
3047
  rows: [
@@ -2873,7 +3052,20 @@ await sock.sendA2UICommandMenu(jid, {
2873
3052
  buttons: [
2874
3053
  { text: 'GitHub', url: 'https://github.com/nexustechpro2' }
2875
3054
  ],
2876
- footer: 'Powered by zervonex'
3055
+ footer: 'Powered by zervonex',
3056
+ image: 'https://example.com/header.jpg' // optional — URL, Buffer, or file path
3057
+ })
3058
+ ```
3059
+
3060
+ #### Generic Envelope (Advanced)
3061
+
3062
+ ```javascript
3063
+ await sock.sendA2UIMessage(jid, {
3064
+ bloksWidget: {
3065
+ type: 'im_a2ui',
3066
+ data: JSON.stringify({ version: 'v0.9', createSurface: { /* ... */ } })
3067
+ },
3068
+ nativeFlowMessage: { buttons: [{ name: 'single_select', buttonParamsJson: '...' }] }
2877
3069
  })
2878
3070
  ```
2879
3071
 
@@ -2881,7 +3073,7 @@ await sock.sendA2UICommandMenu(jid, {
2881
3073
 
2882
3074
  **A2UI button format:** `{ text, url }` or `{ label, url }`
2883
3075
 
2884
- ---
3076
+ **Valid icon names:** `accountCircle` `add` `arrowBack` `arrowForward` `attachFile` `calendarToday` `call` `camera` `check` `close` `delete` `download` `edit` `event` `error` `fastForward` `favorite` `favoriteOff` `folder` `help` `home` `info` `locationOn` `lock` `lockOpen` `mail` `menu` `moreVert` `moreHoriz` `notificationsOff` `notifications` `pause` `payment` `person` `phone` `photo` `play` `print` `refresh` `rewind` `search` `send` `settings` `share` `shoppingCart` `skipNext` `skipPrevious` `star` `starHalf` `starOff` `stop` `upload` `visibility` `visibilityOff` `volumeDown` `volumeMute` `volumeOff` `volumeUp` `warning`
2885
3077
 
2886
3078
  ### Poll Builder
2887
3079
 
@@ -18,9 +18,9 @@ const SCALAR_TC = {
18
18
  const isLongLike = v => v !== null && typeof v === 'object' && 'low' in v && 'high' in v
19
19
  const longToBigInt = v => (v.unsigned ? BigInt(v.high >>> 0) : BigInt(v.high | 0)) * 4294967296n + BigInt(v.low >>> 0)
20
20
  const anyToBigInt = v => typeof v === 'bigint' ? v : isLongLike(v) ? longToBigInt(v) : BigInt(Math.trunc(Number(v)))
21
- const zigzagEncode = v => BigInt.asUintN(64, anyToBigInt(v) << 1n ^ anyToBigInt(v) >> 63n)
22
- const numOrBigInt = b => b <= 9007199254740991n && b >= -9007199254740991n ? Number(b) : b
21
+ const zigzagEncode = v => { const b = anyToBigInt(v); return BigInt.asUintN(64, b << 1n ^ b >> 63n) }
23
22
  const toLong = big => Long.fromString(BigInt.asIntN(64, big).toString())
23
+ const numOrBigInt = b => b <= 9007199254740991n && b >= -9007199254740991n ? Number(b) : toLong(b)
24
24
  const wireType = f => f.k === 'varint' ? 0 : f.k === 'i64' ? 1 : f.k === 'i32' ? 5 : 2
25
25
 
26
26
  const toBuffer = v => {
@@ -33,6 +33,15 @@ const toBuffer = v => {
33
33
  return Buffer.alloc(0)
34
34
  }
35
35
 
36
+ const anyToFloat = v => {
37
+ if (typeof v === 'number') return v
38
+ if (typeof v === 'bigint') return Number(v)
39
+ if (isLongLike(v)) return v.toNumber()
40
+ if (typeof v === 'string') return parseFloat(v)
41
+ if (v == null) return 0
42
+ return Number(v)
43
+ }
44
+
36
45
  const B64_JSON = function () { return this.toString('base64') }
37
46
  const tagBytes = b => (Object.defineProperty(b, 'toJSON', { value: B64_JSON, enumerable: false, configurable: true }), b)
38
47
 
@@ -54,8 +63,8 @@ class Writer {
54
63
  vint(v) { typeof v === 'number' && v >= 0 && v <= MAXSAFE && Number.isInteger(v) ? this.varintNum(v) : this.varintBig(anyToBigInt(v)) }
55
64
  fixed32(v) { this._grow(4); const n = Number(BigInt.asUintN(32, anyToBigInt(v))) >>> 0; this.buf[this.len++] = n & 0xff; this.buf[this.len++] = (n >>> 8) & 0xff; this.buf[this.len++] = (n >>> 16) & 0xff; this.buf[this.len++] = (n >>> 24) & 0xff }
56
65
  fixed64(v) { this._grow(8); const b = Buffer.allocUnsafe(8); b.writeBigUInt64LE(BigInt.asUintN(64, anyToBigInt(v))); this.raw(b) }
57
- float(v) { this._grow(4); const b = Buffer.allocUnsafe(4); b.writeFloatLE(v); this.raw(b) }
58
- double(v) { this._grow(8); const b = Buffer.allocUnsafe(8); b.writeDoubleLE(v); this.raw(b) }
66
+ float(v) { this._grow(4); const b = Buffer.allocUnsafe(4); b.writeFloatLE(anyToFloat(v)); this.raw(b) }
67
+ double(v) { this._grow(8); const b = Buffer.allocUnsafe(8); b.writeDoubleLE(anyToFloat(v)); this.raw(b) }
59
68
  finish() { return Buffer.from(this.buf.buffer, this.buf.byteOffset, this.len) }
60
69
  }
61
70
 
@@ -152,7 +161,7 @@ function makeCodec(TABLE, enumIndex) {
152
161
  if (f.s === 'zigzag') { const u = r.varintBig(); return numOrBigInt(u >> 1n ^ -(u & 1n)) }
153
162
  if (f.s === 'zigzaglong') { const u = r.varintBig(); return toLong(u >> 1n ^ -(u & 1n)) }
154
163
  if (f.s === 'enum') return r.varint() | 0
155
- if (f.s === 'long') return toLong(BigInt(r.varint()))
164
+ if (f.s === 'long') return toLong(r.varintBig())
156
165
  return r.varint()
157
166
  }
158
167
  case 'i64': { const b = Buffer.from(r.read8()); return f.s === 'double' ? b.readDoubleLE(0) : toLong(b.readBigUInt64LE(0)) }
@@ -189,7 +198,10 @@ function makeCodec(TABLE, enumIndex) {
189
198
  if (f.rep) (obj[f.name] || (obj[f.name] = [])).push(val)
190
199
  else obj[f.name] = val
191
200
  }
192
- } catch { break }
201
+ } catch (e) {
202
+ console.warn('[WAProto] decode error:', e.message)
203
+ break
204
+ }
193
205
  }
194
206
  return obj
195
207
  }
@@ -277,16 +289,17 @@ if (isGeneratorRun) {
277
289
  const tablePath = fileURLToPath(new URL('./WAProto.json', import.meta.url))
278
290
  const built = { proto: {}, codec: null }
279
291
 
292
+ export let codec = null
280
293
  export function _reloadProto() {
281
294
  if (!existsSync(tablePath)) return
282
295
  const loaded = makeProto(tablePath)
283
296
  for (const key of Object.keys(built.proto)) delete built.proto[key]
284
297
  Object.assign(built.proto, loaded.proto)
285
298
  built.codec = loaded.codec
299
+ codec = loaded.codec
286
300
  }
287
301
 
288
302
  if (!isGeneratorRun && existsSync(tablePath)) _reloadProto()
289
303
 
290
304
  export const proto = built.proto
291
- export const codec = built.codec
292
305
  export default built