kage-baileys 3.0.6 → 3.2.4

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 (217) hide show
  1. package/Example/connection.cjs +4 -0
  2. package/README.MD +4726 -48
  3. package/README.md +5941 -0
  4. package/WAProto/WAProto.proto +3395 -415
  5. package/WAProto/compat.cjs +12 -0
  6. package/WAProto/index.d.ts +47104 -19888
  7. package/WAProto/index.js +131979 -57361
  8. package/lib/Addon/http-error.js +43 -0
  9. package/lib/Addon/index.js +32 -0
  10. package/lib/Addon/keyed-db.js +250 -0
  11. package/lib/Addon/link-preview.js +82 -0
  12. package/lib/Defaults/baileys-version.json +3 -0
  13. package/lib/Defaults/connection.js +110 -0
  14. package/lib/Defaults/constants.js +156 -0
  15. package/lib/Defaults/history.js +46 -0
  16. package/lib/Defaults/index.js +230 -0
  17. package/lib/Defaults/media.js +104 -0
  18. package/lib/Defaults/phonenumber-mcc.json +223 -0
  19. package/lib/Defaults/prefix.js +44 -0
  20. package/lib/Extensions/business-advanced.js +382 -0
  21. package/lib/Extensions/business.js +159 -0
  22. package/lib/Extensions/chats-advanced.js +1106 -0
  23. package/lib/Extensions/chats.js +349 -0
  24. package/lib/Extensions/communities-advanced.js +430 -0
  25. package/lib/Extensions/community.js +94 -0
  26. package/lib/Extensions/groups-advanced.js +343 -0
  27. package/lib/Extensions/index.js +30 -0
  28. package/lib/Extensions/messages-recv-advanced.js +1690 -0
  29. package/lib/Extensions/messages-send-advanced.js +622 -0
  30. package/lib/Extensions/messages-send.js +1380 -0
  31. package/lib/Extensions/newsletter-advanced.js +228 -0
  32. package/lib/Extensions/newsletter.js +72 -0
  33. package/lib/Extensions/socket.js +389 -0
  34. package/lib/Modded/message_builder.js +2084 -4
  35. package/lib/Signal/Group/ciphertext-message.js +54 -0
  36. package/lib/Signal/Group/group-session-builder.js +124 -0
  37. package/lib/Signal/Group/group_cipher.js +216 -0
  38. package/lib/Signal/Group/index.js +124 -0
  39. package/lib/Signal/Group/keyhelper.js +108 -0
  40. package/lib/Signal/Group/sender-chain-key.js +83 -0
  41. package/lib/Signal/Group/sender-key-distribution-message.js +157 -0
  42. package/lib/Signal/Group/sender-key-message.js +166 -0
  43. package/lib/Signal/Group/sender-key-name.js +130 -0
  44. package/lib/Signal/Group/sender-key-record.js +113 -0
  45. package/lib/Signal/Group/sender-key-state.js +208 -0
  46. package/lib/Signal/Group/sender-message-key.js +82 -0
  47. package/lib/Signal/libsignal.js +935 -0
  48. package/lib/Signal/lid-mapping.js +545 -1
  49. package/lib/Socket/Client/index.js +60 -0
  50. package/lib/Socket/Client/types.js +51 -0
  51. package/lib/Socket/Client/websocket.js +152 -0
  52. package/lib/Socket/business.js +831 -0
  53. package/lib/Socket/chats.js +2535 -49
  54. package/lib/Socket/communities.js +450 -1
  55. package/lib/Socket/community.js +1022 -0
  56. package/lib/Socket/dugong.js +1 -1
  57. package/lib/Socket/groups.js +747 -0
  58. package/lib/Socket/index.js +60 -2
  59. package/lib/Socket/messages-recv.js +3450 -5
  60. package/lib/Socket/messages-send.js +3123 -0
  61. package/lib/Socket/mex.js +126 -1
  62. package/lib/Socket/newsletter.js +465 -0
  63. package/lib/Socket/socket.js +2217 -1
  64. package/lib/Store/index.js +79 -0
  65. package/lib/Store/make-cache-manager-store.js +186 -0
  66. package/lib/Store/make-in-memory-store.js +878 -0
  67. package/lib/Store/make-ordered-dictionary.js +187 -0
  68. package/lib/Store/object-repository.js +78 -0
  69. package/lib/Types/Auth.js +25 -0
  70. package/lib/Types/Bussines.js +25 -1
  71. package/lib/Types/Call.js +25 -0
  72. package/lib/Types/Chat.js +39 -0
  73. package/lib/Types/Contact.js +25 -0
  74. package/lib/Types/Events.js +25 -0
  75. package/lib/Types/GroupMetadata.js +25 -0
  76. package/lib/Types/Label.js +76 -0
  77. package/lib/Types/LabelAssociation.js +40 -0
  78. package/lib/Types/Message.js +57 -0
  79. package/lib/Types/Mex.js +56 -1
  80. package/lib/Types/MexUpdates.js +46 -0
  81. package/lib/Types/Newsletter.js +56 -0
  82. package/lib/Types/Product.js +25 -0
  83. package/lib/Types/RichType.js +23 -0
  84. package/lib/Types/Signal.js +25 -0
  85. package/lib/Types/Socket.js +25 -0
  86. package/lib/Types/State.js +92 -0
  87. package/lib/Types/USync.js +25 -0
  88. package/lib/Types/index.js +133 -0
  89. package/lib/Utils/auth-utils.js +703 -0
  90. package/lib/Utils/automation-tools.js +51 -16
  91. package/lib/Utils/baileys-event-stream.js +146 -0
  92. package/lib/Utils/browser-utils.js +95 -0
  93. package/lib/Utils/business.js +525 -0
  94. package/lib/Utils/chat-utils.js +1861 -0
  95. package/lib/Utils/companion-reg-client-utils.js +55 -1
  96. package/lib/Utils/crypto.js +355 -0
  97. package/lib/Utils/decode-wa-message.js +709 -0
  98. package/lib/Utils/event-buffer.js +1323 -8
  99. package/lib/Utils/generics.js +945 -1
  100. package/lib/Utils/history.js +266 -0
  101. package/lib/Utils/identity-change-handler.js +62 -1
  102. package/lib/Utils/index.js +114 -0
  103. package/lib/Utils/link-preview.js +179 -0
  104. package/lib/Utils/logger.js +42 -0
  105. package/lib/Utils/lt-hash.js +73 -0
  106. package/lib/Utils/make-mutex.js +104 -0
  107. package/lib/Utils/message-inspector.js +110 -0
  108. package/lib/Utils/message-retry-manager.js +507 -2
  109. package/lib/Utils/messages-media.js +1931 -1
  110. package/lib/Utils/messages.js +3748 -0
  111. package/lib/Utils/noise-handler.js +423 -0
  112. package/lib/Utils/offline-node-processor.js +53 -1
  113. package/lib/Utils/pre-key-manager.js +255 -1
  114. package/lib/Utils/process-message.js +1592 -0
  115. package/lib/Utils/reporting-utils.js +272 -1
  116. package/lib/Utils/rich-message-utils.js +377 -0
  117. package/lib/Utils/rich-messages.js +1 -1
  118. package/lib/Utils/signal.js +437 -0
  119. package/lib/Utils/stanza-ack.js +51 -1
  120. package/lib/Utils/status-refresh.js +37 -0
  121. package/lib/Utils/status-tools.js +4 -2
  122. package/lib/Utils/sync-action-utils.js +63 -1
  123. package/lib/Utils/tc-token-utils.js +185 -1
  124. package/lib/Utils/terminal-banner.js +31 -0
  125. package/lib/Utils/use-multi-file-auth-state.js +271 -0
  126. package/lib/Utils/use-single-file-auth-state.js +108 -0
  127. package/lib/Utils/use-sqlite-auth-state.js +142 -0
  128. package/lib/Utils/validate-connection.js +497 -1
  129. package/lib/Utils/view-once-compat.js +13 -5
  130. package/lib/VoIP/audio-feeder.js +150 -0
  131. package/lib/VoIP/index.js +289 -0
  132. package/lib/VoIP/relay-transport.js +608 -0
  133. package/lib/VoIP/signaling.js +583 -0
  134. package/lib/VoIP/types.js +30 -0
  135. package/lib/VoIP/wasm-engine.js +1261 -2
  136. package/lib/VoIP/worker-bootstrap.js +1090 -2
  137. package/lib/WABinary/constants.js +2805 -0
  138. package/lib/WABinary/decode.js +649 -2
  139. package/lib/WABinary/encode.js +564 -2
  140. package/lib/WABinary/generic-utils.js +401 -0
  141. package/lib/WABinary/index.js +82 -0
  142. package/lib/WABinary/jid-utils.js +290 -0
  143. package/lib/WABinary/types.js +25 -0
  144. package/lib/WAM/BinaryInfo.js +50 -0
  145. package/lib/WAM/constants.js +45747 -0
  146. package/lib/WAM/encode.js +393 -0
  147. package/lib/WAM/index.js +78 -0
  148. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +135 -0
  149. package/lib/WAUSync/Protocols/USyncContactProtocol.js +110 -0
  150. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +142 -0
  151. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +85 -0
  152. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +69 -0
  153. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +107 -0
  154. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +38 -1
  155. package/lib/WAUSync/Protocols/index.js +83 -0
  156. package/lib/WAUSync/USyncQuery.js +241 -2
  157. package/lib/WAUSync/USyncUser.js +86 -0
  158. package/lib/WAUSync/index.js +78 -0
  159. package/lib/assets/wasm/loader.js +1875 -1
  160. package/lib/assets/wasm/worker-modules.js +11047 -1
  161. package/lib/index.d.ts +126 -0
  162. package/lib/index.js +53 -21
  163. package/lib/index.mjs +437 -0
  164. package/licenses/upstream-MIT.txt +22 -0
  165. package/maintenance/api-coverage.json +1642 -0
  166. package/maintenance/archivos-sha256.json +207 -0
  167. package/maintenance/consumer-validation.log +3 -0
  168. package/maintenance/dependency-audit.json +4 -4
  169. package/maintenance/extension-inventory.json +57 -0
  170. package/maintenance/protocol-update.json +1101 -0
  171. package/maintenance/protocol-wire-audit.json +4 -0
  172. package/maintenance/reference-socket-surface.json +209 -0
  173. package/maintenance/resumen-validacion.json +50 -0
  174. package/maintenance/validation.log +2725 -0
  175. package/maintenance/verification.json +566 -0
  176. package/package.json +107 -9
  177. package/scripts/check-imports.cjs +10 -0
  178. package/scripts/check-package.cjs +40 -0
  179. package/scripts/check-syntax.cjs +1 -1
  180. package/scripts/generate-protobuf.cjs +6 -1
  181. package/scripts/generate-public-types.cjs +9 -0
  182. package/scripts/kage-base64-fix.cjs +45 -0
  183. package/scripts/maintenance.cjs +10 -0
  184. package/test/advanced.test.cjs +24 -0
  185. package/test/base64-fix.test.cjs +49 -0
  186. package/test/maintenance.test.cjs +1 -1
  187. package/test/npm-publication.test.cjs +141 -0
  188. package/test/recepcion-reparada.test.cjs +98 -0
  189. package/test/resilience-binary.test.cjs +69 -0
  190. package/test/resilience-transport.test.cjs +34 -0
  191. package/test/types.test.ts +5 -0
  192. package/test/upgrade.test.cjs +104 -0
  193. package/tsconfig.json +20 -0
  194. package/WAProto/p.html +0 -1
  195. package/lib/KageExtra/Modded/message_builder.js +0 -2330
  196. package/lib/KageExtra/VoIP/audio-feeder.js +0 -136
  197. package/lib/KageExtra/VoIP/index.js +0 -282
  198. package/lib/KageExtra/VoIP/relay-transport.js +0 -559
  199. package/lib/KageExtra/VoIP/signaling.js +0 -603
  200. package/lib/KageExtra/VoIP/types.js +0 -17
  201. package/lib/KageExtra/VoIP/wasm-engine.js +0 -1214
  202. package/lib/KageExtra/VoIP/worker-bootstrap.js +0 -1042
  203. package/lib/KageExtra/assets/wasm/loader.js +0 -5
  204. package/lib/KageExtra/assets/wasm/whatsapp.wasm +0 -0
  205. package/lib/KageExtra/assets/wasm/worker-modules.js +0 -273
  206. package/lib/KageExtra/index.js +0 -3
  207. package/lib/KageExtra/package.json +0 -1
  208. package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +0 -53
  209. package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +0 -24
  210. package/maintenance/revision-full-check.txt +0 -1097
  211. package/maintenance/revision-library-tests.tap +0 -1088
  212. package/maintenance/revision-protobuf.txt +0 -5
  213. package/maintenance/revision-syntax.txt +0 -5
  214. package/maintenance/schema-coverage.json +0 -23
  215. package/maintenance/schema-merge.json +0 -30
  216. package/maintenance/validation-node20.txt +0 -191
  217. package/maintenance/validation-node22.txt +0 -237
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kage-baileys",
3
- "version": "3.0.6",
4
- "description": "Kage Baileys una libreria de WhatsApp.",
3
+ "version": "3.2.4",
4
+ "description": "Kage Baileys: API de WhatsApp con comunidades, canales, medios y herramientas de diagnóstico.",
5
5
  "keywords": [
6
6
  "kage-baileys",
7
7
  "baileys",
@@ -17,7 +17,8 @@
17
17
  ],
18
18
  "homepage": "https://github.com/xrljosedv/kage-baileys",
19
19
  "repository": {
20
- "url": "git+https://github.com/xrljosedv/kage-baileys.git"
20
+ "url": "git+https://github.com/xrljosedv/kage-baileys.git",
21
+ "type": "git"
21
22
  },
22
23
  "license": "MIT",
23
24
  "author": "xrljosedv",
@@ -25,30 +26,42 @@
25
26
  "types": "lib/index.d.ts",
26
27
  "files": [
27
28
  "lib/**/*",
28
- "WAProto/*",
29
+ "WAProto/**/*",
29
30
  "engine-requirements.js",
30
31
  "scripts/**/*",
31
32
  "Example/**/*",
32
33
  "maintenance/**/*",
33
- "test/**/*"
34
+ "test/**/*",
35
+ "licenses/**/*",
36
+ "README.MD",
37
+ "LICENSE",
38
+ "tsconfig.json"
34
39
  ],
35
40
  "scripts": {
36
41
  "gen:protobuf": "node scripts/generate-protobuf.cjs",
37
- "lint": "node scripts/check-syntax.cjs",
42
+ "lint": "node scripts/check-syntax.cjs && node scripts/check-imports.cjs",
38
43
  "test": "node --test test/*.test.cjs",
39
- "check": "npm run lint && npm test",
44
+ "check": "npm run lint && npm run check:types && npm test && npm run check:package",
40
45
  "example": "node Example/connection.cjs",
41
46
  "gen:types": "node scripts/generate-public-types.cjs",
42
47
  "check:engine": "node engine-requirements.js",
43
- "prepublishOnly": "npm run gen:protobuf && npm run gen:types && npm run check"
48
+ "prepublishOnly": "npm run build && npm run check",
49
+ "maintenance": "node scripts/maintenance.cjs",
50
+ "check:imports": "node scripts/check-imports.cjs",
51
+ "check:types": "tsc -p tsconfig.json",
52
+ "build": "npm run check:engine && npm run gen:protobuf && npm run gen:types",
53
+ "check:package": "node scripts/check-package.cjs",
54
+ "prepack": "npm run check:package"
44
55
  },
45
56
  "dependencies": {
46
57
  "@adiwajshing/keyed-db": "^0.2.4",
47
58
  "@cacheable/node-cache": "^1.4.0",
48
59
  "@hapi/boom": "^9.1.3",
60
+ "@itsukichan/libsignal-node": "^1.0.1",
49
61
  "async-mutex": "^0.5.0",
50
62
  "axios": "^1.6.0",
51
63
  "cache-manager": "^5.7.6",
64
+ "cfonts": "^3.3.1",
52
65
  "chalk": "^4.1.2",
53
66
  "cheerio": "1.0.0",
54
67
  "fflate": "^0.8.0",
@@ -57,7 +70,6 @@
57
70
  "form-data": "^4.0.0",
58
71
  "gradient-string": "^2.0.2",
59
72
  "jimp": "1.6.1",
60
- "kage-baileys": "^3.0.2",
61
73
  "libphonenumber-js": "^1.10.20",
62
74
  "libsignal": "^6.0.0",
63
75
  "link-preview-js": "4.0.4",
@@ -67,7 +79,9 @@
67
79
  "p-queue": "6.6.2",
68
80
  "pino": "^9.6",
69
81
  "protobufjs": "8.8.1",
82
+ "qrcode": "^1.5.4",
70
83
  "qrcode-terminal": "^0.12.0",
84
+ "unfurl.js": "^6.4.0",
71
85
  "uuid": "11.1.1",
72
86
  "ws": "^8.13.0"
73
87
  },
@@ -77,7 +91,9 @@
77
91
  "typescript": "^5.8.2"
78
92
  },
79
93
  "peerDependencies": {
94
+ "@napi-rs/image": "^1.12.0",
80
95
  "audio-decode": "^2.1.3",
96
+ "better-sqlite3": ">=11",
81
97
  "sharp": "^0.34.1"
82
98
  },
83
99
  "peerDependenciesMeta": {
@@ -86,6 +102,12 @@
86
102
  },
87
103
  "sharp": {
88
104
  "optional": true
105
+ },
106
+ "better-sqlite3": {
107
+ "optional": true
108
+ },
109
+ "@napi-rs/image": {
110
+ "optional": true
89
111
  }
90
112
  },
91
113
  "engines": {
@@ -94,5 +116,81 @@
94
116
  "optionalDependencies": {
95
117
  "@roamhq/wrtc": "*",
96
118
  "whatsapp-rust-bridge": "0.5.2"
119
+ },
120
+ "contributors": [
121
+ "David Zuniga"
122
+ ],
123
+ "exports": {
124
+ ".": {
125
+ "types": "./lib/index.d.ts",
126
+ "import": "./lib/index.mjs",
127
+ "require": "./lib/index.js"
128
+ },
129
+ "./*": "./*"
130
+ },
131
+ "overrides": {
132
+ "@itsukichan/libsignal-node": {
133
+ "protobufjs": "^7.6.6"
134
+ },
135
+ "ajv@^6.12.4": "^6.14.0",
136
+ "basic-ftp": "^5.2.4",
137
+ "brace-expansion@^1.1.7": "^1.1.13",
138
+ "brace-expansion@^2.0.1": "^2.0.3",
139
+ "flatted": "^3.4.2",
140
+ "glob@^10.2.2": "^10.5.0",
141
+ "glob@^10.3.10": "^10.5.0",
142
+ "glob@^10.5.0": "^10.5.0",
143
+ "handlebars": "^4.7.9",
144
+ "ip-address": "^10.1.1",
145
+ "js-yaml@^3.13.1": "^3.14.2",
146
+ "js-yaml@^4.1.0": "^4.1.1",
147
+ "markdown-it": "^14.1.1",
148
+ "minimatch@^3.0.4": "^3.1.5",
149
+ "minimatch@^3.1.2": "^3.1.5",
150
+ "minimatch@^5.0.1": "^5.1.8",
151
+ "minimatch@^9.0.4": "^9.0.9",
152
+ "minimatch@^9.0.5": "^9.0.9",
153
+ "picomatch@^2.0.4": "^2.3.2",
154
+ "picomatch@^2.3.1": "^2.3.2",
155
+ "picomatch@^4.0.0": "^4.0.4",
156
+ "picomatch@^4.0.2": "^4.0.4",
157
+ "socks": "^2.8.8",
158
+ "tar": "^7.5.11",
159
+ "tmp": "^0.2.5",
160
+ "underscore": "^1.13.8",
161
+ "yaml@^2.6.1": "^2.8.4",
162
+ "zod@^3.23.8": "^4.6.7"
163
+ },
164
+ "publishConfig": {
165
+ "access": "public"
166
+ },
167
+ "resolutions": {
168
+ "ajv@npm:^6.12.4": "^6.14.0",
169
+ "basic-ftp": "^5.2.4",
170
+ "brace-expansion@npm:^1.1.7": "^1.1.13",
171
+ "brace-expansion@npm:^2.0.1": "^2.0.3",
172
+ "flatted": "^3.4.2",
173
+ "glob@npm:^10.2.2": "^10.5.0",
174
+ "glob@npm:^10.3.10": "^10.5.0",
175
+ "glob@npm:^10.5.0": "^10.5.0",
176
+ "handlebars": "^4.7.9",
177
+ "ip-address": "^10.1.1",
178
+ "js-yaml@npm:^3.13.1": "^3.14.2",
179
+ "js-yaml@npm:^4.1.0": "^4.1.1",
180
+ "markdown-it": "^14.1.1",
181
+ "minimatch@npm:^3.0.4": "^3.1.5",
182
+ "minimatch@npm:^3.1.2": "^3.1.5",
183
+ "minimatch@npm:^5.0.1": "^5.1.8",
184
+ "minimatch@npm:^9.0.4": "^9.0.9",
185
+ "minimatch@npm:^9.0.5": "^9.0.9",
186
+ "picomatch@npm:^2.0.4": "^2.3.2",
187
+ "picomatch@npm:^2.3.1": "^2.3.2",
188
+ "picomatch@npm:^4.0.0": "^4.0.4",
189
+ "picomatch@npm:^4.0.2": "^4.0.4",
190
+ "socks": "^2.8.8",
191
+ "tar": "^7.5.11",
192
+ "tmp": "^0.2.5",
193
+ "underscore": "^1.13.8",
194
+ "yaml@npm:^2.6.1": "^2.8.4"
97
195
  }
98
196
  }
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+ const fs=require('node:fs'),path=require('node:path'),{createRequire}=require('node:module');
3
+ const ts=require('typescript');const root=path.resolve(__dirname,'..');let checked=0;const failures=[];
4
+ function scan(dir){for(const e of fs.readdirSync(dir,{withFileTypes:true})){const f=path.join(dir,e.name);if(e.isDirectory())scan(f);else if(/\.(?:c?js|mjs)$/.test(f)){
5
+ const tree=ts.createSourceFile(f,fs.readFileSync(f,'utf8'),ts.ScriptTarget.Latest,true);const req=createRequire(f);
6
+ function walk(n){let value;if(ts.isCallExpression(n)&&n.expression.getText(tree)==='require'&&n.arguments.length===1&&ts.isStringLiteral(n.arguments[0]))value=n.arguments[0].text;else if((ts.isImportDeclaration(n)||ts.isExportDeclaration(n))&&n.moduleSpecifier&&ts.isStringLiteral(n.moduleSpecifier))value=n.moduleSpecifier.text;
7
+ if(value?.startsWith('.')){checked++;try{req.resolve(value)}catch(err){failures.push({archivo:path.relative(root,f),ruta:value,error:err.code})}}ts.forEachChild(n,walk)}walk(tree);
8
+ }}}
9
+ for(const dir of ['lib','WAProto','scripts','test','Example'])scan(path.join(root,dir));
10
+ console.log(JSON.stringify({importacionesLocales:checked,errores:failures},null,2));if(failures.length)process.exitCode=1;
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+ const { createRequire } = require('node:module');
5
+ const root = path.resolve(__dirname, '..');
6
+ const pkg = require('../package.json');
7
+ const failures = [];
8
+ const entries = new Map();
9
+ function scan(dir) {
10
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
11
+ if (entry.name === 'node_modules' || entry.name === '.git') continue;
12
+ const file = path.join(dir, entry.name);
13
+ const relative = path.relative(root, file).replaceAll(path.sep, '/');
14
+ const key = relative.toLowerCase();
15
+ if (entries.has(key)) failures.push('Colisión de mayúsculas: ' + entries.get(key) + ' / ' + relative);
16
+ entries.set(key, relative);
17
+ if (entry.isDirectory()) scan(file);
18
+ }
19
+ }
20
+ scan(root);
21
+ for (const entry of [pkg.main, pkg.types, pkg.exports['.'].import, 'WAProto/index.js', 'WAProto/index.d.ts', 'WAProto/WAProto.proto', 'licenses/upstream-MIT.txt', 'tsconfig.json']) {
22
+ if (!entry || !fs.existsSync(path.resolve(root, entry))) failures.push('Falta un archivo distribuido: ' + entry);
23
+ }
24
+ for (const item of require('../maintenance/api-coverage.json')) {
25
+ try {
26
+ const mod = require(path.join(root, item.archivo));
27
+ for (const name of item.exportaciones) if (!(name in mod)) failures.push('Exportación ausente: ' + item.archivo + ':' + name);
28
+ } catch (error) { failures.push(item.archivo + ': ' + error.message); }
29
+ }
30
+ const protocols = path.join(root, 'lib/WAUSync/Protocols');
31
+ for (const name of ['USyncLIDProtocol', 'USyncBotProfileProtocol']) {
32
+ try { createRequire(path.join(root, pkg.main)).resolve(path.join(protocols, name)); }
33
+ catch (error) { failures.push(name + ': ' + error.message); }
34
+ }
35
+ if (failures.length) {
36
+ console.error(failures.join('\n'));
37
+ process.exitCode = 1;
38
+ } else {
39
+ console.log('PACKAGE_OK: ' + pkg.name + '@' + pkg.version + '; sin colisiones; entradas CJS/ESM/tipos/protocolo presentes; API verificada.');
40
+ }
@@ -8,7 +8,7 @@ function scan(dir) {
8
8
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
9
9
  const file = path.join(dir, entry.name);
10
10
  if (entry.isDirectory()) scan(file);
11
- else if (/\.(?:js|cjs)$/.test(file)) {
11
+ else if (/\.(?:js|cjs|mjs)$/.test(file)) {
12
12
  const result = spawnSync(process.execPath, ['--check', file], { encoding: 'utf8' });
13
13
  if (result.status !== 0) { console.error(result.stderr); process.exit(1); }
14
14
  checked++;
@@ -11,10 +11,15 @@ pbjs.main(['-t', 'static-module', '-w', 'commonjs', '--keep-case', '-o', js, pat
11
11
  if (error) throw error;
12
12
  // Accept plain JSON int64 strings as well as Long instances in toObject.
13
13
  let source = fs.readFileSync(js, 'utf8');
14
+ // kage fix: inyecta decodificador base64 tolerante (evita "Error: invalid encoding"
15
+ // con base64 URL-safe, saltos de linea, padding roto o un caracter colgante residual
16
+ // en firmas/certificados de botMetadata.verificationMetadata.proofs).
17
+ const kageBase64Fix = fs.readFileSync(path.join(__dirname, 'kage-base64-fix.cjs'), 'utf8');
18
+ source = source.replace('var $protobuf = require("protobufjs/minimal");', 'var $protobuf = require("protobufjs/minimal");\n\n' + kageBase64Fix.trim());
14
19
  source = source.replace(/\$util\.Long\.prototype\.toString\.call\((message\.[\w]+)\)/g, 'kageLongString($1)');
15
20
  source = source.replace(/new \$util\.LongBits\((message\.[\w]+)\.low >>> 0, \1\.high >>> 0\)\.toNumber\((true)?\)/g, (_, value, unsigned) => `kageLongNumber(${value}, ${!!unsigned})`);
16
21
  source = source.replace(/\$util\.Long\.fromBits\((message\.[\w]+)\.low >>> 0, \1\.high >>> 0, (true|false)\)\.toBigInt\(\)/g, (_, value, unsigned) => `BigInt(kageLongString(${value}, ${unsigned}))`);
17
- source += `\nfunction kageLongString(value, unsigned) {\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') return String(value);\n const long = $util.Long.fromValue(value);\n return (unsigned === true ? long.toUnsigned() : long).toString();\n}\nfunction kageLongNumber(value, unsigned) {\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') return Number(value);\n const long = $util.Long.fromValue(value);\n return (unsigned ? long.toUnsigned() : long.toSigned()).toNumber();\n}\nrequire('./compat.cjs')(module.exports.proto);\n`;
22
+ source += `\nfunction kageLongString(value, unsigned) {\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') return String(value);\n const long = $util.Long.fromValue(value);\n return (unsigned === true ? long.toUnsigned() : long).toString();\n}\nfunction kageLongNumber(value, unsigned) {\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'bigint') return Number(value);\n const long = $util.Long.fromValue(value);\n return (unsigned ? long.toUnsigned() : long.toSigned()).toNumber();\n}\nrequire('./compat.cjs')(module.exports.proto);\n`; // kage-base64-fix.cjs es leído e inyectado arriba
18
23
  fs.writeFileSync(js, source);
19
24
  pbts.main(['-o', dts, js], error => {
20
25
  if (error) throw error;
@@ -29,6 +29,11 @@ export interface WASocket {
29
29
  relayMessage(jid: string, message: WAMessageContent, options?: Record<string, any>): Promise<string>;
30
30
  sendMessage(jid: string, content: Record<string, any>, options?: Record<string, any>): Promise<WAMessage | undefined>;
31
31
  end(error?: Error): void;
32
+ registerSocketEndHandler(handler: () => void | Promise<void>): () => void;
33
+ updateServerTimeOffset(node: { attrs?: { t?: string | number } }): void;
34
+ sendUnifiedSession(): Promise<void>;
35
+ fetchAccountReachoutTimelock(): Promise<{ isActive: boolean; timeEnforcementEnds?: Date; enforcementType: string }>;
36
+ fetchNewChatMessageCap(): Promise<any>;
32
37
  [method: string]: any;
33
38
  }
34
39
  export declare function makeWASocket(config: SocketConfig): WASocket;
@@ -50,3 +55,7 @@ for (const name of Object.keys(api).sort()) {
50
55
  }
51
56
  fs.writeFileSync(path.resolve(__dirname, '../lib/index.d.ts'), declaration);
52
57
  console.log('Public core types and JavaScript-extra declarations generated.');
58
+
59
+ const names = Object.keys(api).filter(name => name !== 'default' && name !== '__esModule' && /^[A-Za-z_$][\w$]*$/.test(name));
60
+ const esm = "import api from './index.js';\nexport default api.default;\n" + names.map(name => `export const ${name} = api.${name};`).join('\n') + '\n';
61
+ fs.writeFileSync(path.resolve(__dirname, '../lib/index.mjs'), esm);
@@ -0,0 +1,45 @@
1
+ 'use strict';
2
+ // ============================================================================
3
+ // kage fix: decodificador base64 tolerante.
4
+ // Evita "Error: invalid encoding" cuando WhatsApp/devlogs entregan firmas,
5
+ // certificados o hashes con base64 URL-safe, saltos de linea, padding roto
6
+ // o un caracter suelto residual (longitud % 4 === 1). En ese ultimo caso se
7
+ // descarta unicamente el caracter colgante y el resto se decodifica intacto.
8
+ // Este archivo es inyectado automaticamente por scripts/generate-protobuf.cjs
9
+ // al final de WAProto/index.js tras cada regeneracion.
10
+ // ============================================================================
11
+ (function () {
12
+ var b64 = $protobuf.util.base64;
13
+ if (b64.__kageTolerant)
14
+ return;
15
+ var nativeDecode = b64.decode;
16
+ var nativeLength = b64.length;
17
+ var clean = function (string) {
18
+ var s = $String(string).replace(/[\r\n\t\s]/g, "").replace(/-/g, "+").replace(/_/g, "/");
19
+ var rem = s.length % 4;
20
+ if (rem === 2)
21
+ s += "==";
22
+ else if (rem === 3)
23
+ s += "=";
24
+ else if (rem === 1)
25
+ s = s.slice(0, -1); // caracter colgante: 6 bits sin datos, no aporta bytes
26
+ return s;
27
+ };
28
+ b64.length = function (string) {
29
+ if (typeof string !== "string")
30
+ return nativeLength(string);
31
+ return nativeLength(clean(string));
32
+ };
33
+ b64.decode = function (string, buffer, start) {
34
+ if (typeof string !== "string")
35
+ return nativeDecode(string, buffer, start);
36
+ var s = clean(string);
37
+ try {
38
+ return nativeDecode(s, buffer, start);
39
+ } catch (e) {
40
+ // ultimo recurso: elimina cualquier caracter residual no-base64
41
+ return nativeDecode(s.replace(/[^A-Za-z0-9+/=]/g, ""), buffer, start);
42
+ }
43
+ };
44
+ b64.__kageTolerant = true;
45
+ })();
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+ const fs=require('node:fs'),path=require('node:path'),{spawnSync}=require('node:child_process');
3
+ const root=path.resolve(__dirname,'..');const api=require('../lib');const pb=require('protobufjs');const schema=pb.loadSync(path.join(root,'WAProto/WAProto.proto')).resolveAll();let types=0,fields=0;
4
+ function walk(n){if(n.fieldsArray){types++;fields+=n.fieldsArray.length;if(Object.keys(n.fieldsById).length!==n.fieldsArray.length)throw new Error('Identificadores duplicados en '+n.fullName)}for(const c of n.nestedArray||[])walk(c)}walk(schema);
5
+ const coverage=require('../maintenance/api-coverage.json').map(item=>{const mod=require(path.join(root,item.archivo));return {archivo:item.archivo,exportaciones:item.exportaciones.length,faltantes:item.exportaciones.filter(k=>!(k in mod))}});
6
+ const imports=spawnSync(process.execPath,[path.join(__dirname,'check-imports.cjs')],{encoding:'utf8'});
7
+ const report={paquete:require('../package.json').name,version:require('../package.json').version,node:process.version,estructuraUnica:!fs.existsSync(path.join(root,'vendor')),exportacionesPublicas:Object.keys(api).length,tiposProtocolo:types,camposProtocolo:fields,cobertura:coverage,importaciones:JSON.parse(imports.stdout),alcance:'Validación local. Los recorridos reales de WhatsApp necesitan una sesión y servicios compatibles.'};
8
+ fs.writeFileSync(path.join(root,'maintenance/verification.json'),JSON.stringify(report,null,2)+'\n');
9
+ console.log(JSON.stringify({paquete:report.paquete,version:report.version,estructuraUnica:report.estructuraUnica,exportaciones:report.exportacionesPublicas,tipos:types,campos:fields,modulosVerificados:coverage.length,errores:coverage.filter(x=>x.faltantes.length).length+report.importaciones.errores.length},null,2));
10
+ if(!report.estructuraUnica||imports.status||coverage.some(x=>x.faltantes.length))process.exitCode=1;
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+ const test=require('node:test'),assert=require('node:assert/strict'),fs=require('node:fs'),path=require('node:path');const api=require('../lib');const logger=require('pino')({level:'silent'});
3
+ const cases=[
4
+ ['bloque de código',{code:'console.log(1)',language:'javascript'},'botForwardedMessage'],
5
+ ['tabla',{table:[['Título'],['Valor']]},'botForwardedMessage'],
6
+ ['enlaces',{links:[{text:'Ejemplo',title:'Ejemplo',url:'https://example.com'}]},'botForwardedMessage'],
7
+ ['respuesta enriquecida',{richResponse:[{text:'Hola'}]},'botForwardedMessage'],
8
+ ['flujo nativo',{text:'Opciones',nativeFlow:[{text:'Sí',id:'si'}]},'interactiveMessage'],
9
+ ['pago',{paymentInviteServiceType:3},'paymentInviteMessage'],
10
+ ['contenido oculto',{text:'Hola',spoiler:true},'spoilerMessage'],
11
+ ['visualización única V2',{text:'Hola',viewOnceV2:true},'viewOnceMessageV2'],
12
+ ['visualización única extendida',{text:'Hola',viewOnceV2Extension:true},'viewOnceMessageV2Extension'],
13
+ ['estado de grupo',{text:'Hola',groupStatus:true},'groupStatusMessageV2'],
14
+ ['contenido directo',{raw:true,conversation:'Hola'},'conversation']
15
+ ];
16
+ for(const[name,content,key]of cases)test('formato avanzado: '+name,async()=>{
17
+ const m=await api.generateWAMessageContent(content,{logger,userJid:'123@s.whatsapp.net'});const decoded=api.proto.Message.decode(api.proto.Message.encode(api.proto.Message.fromObject(m)).finish());assert.ok(decoded[key],key);
18
+ });
19
+ test('el contenido raw no modifica el objeto del consumidor',async()=>{const m={raw:true,conversation:'Prueba'};await api.generateWAMessageContent(m,{logger});assert.equal(m.raw,true)});
20
+ test('citas de canal conservan el contenido y el identificador',async()=>{const m=await api.generateWAMessage('123@newsletter',{text:'Respuesta'},{logger,userJid:'123@s.whatsapp.net',quoted:{key:{id:'ABC',remoteJid:'123@newsletter',fromMe:false},message:{conversation:'Original'}}});assert.equal(m.message.extendedTextMessage.contextInfo.stanzaId,'ABC')});
21
+ test('nombres alternativos del esquema conservan el mismo campo al codificar',()=>{const T=api.proto.Message.ExtendedTextMessage;const m=T.fromObject({faviconMmsMetadata:{thumbnailWidth:32}});const r=T.decode(T.encode(m).finish());assert.equal(r.faviconMmsMetadata.thumbnailWidth,32)});
22
+ test('todos los módulos declarados conservan sus exportaciones',()=>{for(const item of require('../maintenance/api-coverage.json')){const mod=require('../'+item.archivo);for(const k of item.exportaciones)assert.ok(k in mod,item.archivo+': '+k)}});
23
+ test('una sola raíz de paquete, sin módulos duplicados en carpetas privadas',()=>{assert.equal(fs.existsSync(path.join(__dirname,'../vendor')),false);assert.equal(fs.existsSync(path.join(__dirname,'../lib/KageExtra')),false)});
24
+ test('banner solicitado y colores en terminales compatibles',()=>{const output=[];api.say('kage baileys',{font:'simple',align:'center',gradient:['red','magenta'],stream:{columns:40,isTTY:false,write:x=>output.push(x)}});api.say('Creado por xrljosedv',{font:'console',align:'center',colors:['cyan','magenta','yellow'],stream:{columns:40,isTTY:false,write:x=>output.push(x)}});assert.match(output.join(''),/KAGE BAILEYS/);assert.match(output.join(''),/Creado por xrljosedv/);assert.ok(!output.join('').includes('\x1b['))});
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+ // Test del fix base64 tolerante: evita "Error: invalid encoding" en
3
+ // BotSignatureVerificationUseCaseProof (signature / certificateChain).
4
+ const { test } = require('node:test');
5
+ const assert = require('node:assert');
6
+ const path = require('path');
7
+ const WAProto = require(path.join(__dirname, '..', 'WAProto', 'index.js'));
8
+
9
+ const makeProof = (signature, certificateChain) => ({
10
+ messageContextInfo: {
11
+ botMetadata: {
12
+ verificationMetadata: {
13
+ proofs: [{ version: 1, useCase: 'WA_BOT_MSG', signature, certificateChain }]
14
+ }
15
+ }
16
+ }
17
+ });
18
+
19
+ test('base64 estandar con padding correcto se decodifica igual que siempre', () => {
20
+ const msg = WAProto.proto.Message.fromObject(makeProof('AAAA', ['QQ==']));
21
+ assert.strictEqual(Buffer.from(msg.messageContextInfo.botMetadata.verificationMetadata.proofs[0].certificateChain[0]).toString(), 'A');
22
+ });
23
+
24
+ test('base64 URL-safe (- y _) se acepta sin error', () => {
25
+ // 'a-b_' es URL-safe; en base64 estricto lanzaria invalid encoding por los caracteres
26
+ const msg = WAProto.proto.Message.fromObject(makeProof('AAAA', ['_-__']));
27
+ assert.ok(msg.messageContextInfo.botMetadata.verificationMetadata.proofs[0].certificateChain[0].length >= 0);
28
+ });
29
+
30
+ test('base64 sin padding se completa automaticamente', () => {
31
+ // 'QQ' (2 chars) sin '==' debe decodificar a 'A'
32
+ const msg = WAProto.proto.Message.fromObject(makeProof('AAAA', ['QQ']));
33
+ assert.strictEqual(Buffer.from(msg.messageContextInfo.botMetadata.verificationMetadata.proofs[0].certificateChain[0]).toString(), 'A');
34
+ });
35
+
36
+ test('base64 con saltos de linea no lanza invalid encoding', () => {
37
+ const msg = WAProto.proto.Message.fromObject(makeProof('AAAA', ['QQ==\n']));
38
+ assert.strictEqual(Buffer.from(msg.messageContextInfo.botMetadata.verificationMetadata.proofs[0].certificateChain[0]).toString(), 'A');
39
+ });
40
+
41
+ test('certificado con caracter colgante (len % 4 === 1) no lanza invalid encoding', () => {
42
+ // Reproduce el caso real de WhatsApp: cadena de 1169 chars (resto 1).
43
+ // El caracter colgante se descarta (6 bits sin datos) y el resto se decodifica.
44
+ const broken = 'TklYRUwuTWVzc2FnZUJ1aWxkZXJWNC43LVZlcmlmaWNhdGlvblNpZ25hdHVyZS5NZXRhZGF0YQ' + 'A';
45
+ const msg = WAProto.proto.Message.fromObject(makeProof('AAAA', [broken]));
46
+ const bytes = msg.messageContextInfo.botMetadata.verificationMetadata.proofs[0].certificateChain[0];
47
+ assert.ok(bytes.length > 0);
48
+ assert.strictEqual(Buffer.from(bytes).toString('utf8', 0, 8), 'NIXEL.Me');
49
+ });
@@ -31,7 +31,7 @@ test('single canonical proto resolves every message, enum and wire identifier',
31
31
  for (const child of node.nestedArray || []) walk(child);
32
32
  }
33
33
  walk(root);
34
- assert.equal(fields, 2705); assert.equal(types, 539);
34
+ assert.ok(fields >= 2705); assert.ok(types >= 539);
35
35
  assert.equal(fs.existsSync(path.join(__dirname, '../WAProto/WAProto.kage-original.proto')), false);
36
36
  });
37
37
  test('restored media, bot and sync fields survive serialization', () => {
@@ -0,0 +1,141 @@
1
+ 'use strict';
2
+ const test = require('node:test');
3
+ const assert = require('node:assert/strict');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const api = require('../lib');
7
+ const logger = require('pino')({ level: 'silent' });
8
+ const tick = () => new Promise(resolve => setImmediate(resolve));
9
+ function makeSocket() {
10
+ return api.makeWASocket({
11
+ auth: { creds: api.initAuthCreds(), keys: { get: async () => ({}), set: async () => {} } },
12
+ logger, waWebSocketUrl: 'wss://127.0.0.1:1', connectTimeoutMs: 1000,
13
+ fireInitQueries: false, kageTools: { banner: false }
14
+ });
15
+ }
16
+ test('Android archive has no filenames differing only in case', () => {
17
+ const seen = new Map();
18
+ function scan(dir) {
19
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
20
+ if (e.name === 'node_modules' || e.name === '.git') continue;
21
+ const f = path.join(dir, e.name), key = f.toLowerCase();
22
+ assert.ok(!seen.has(key), (seen.get(key) || '') + ' / ' + f);
23
+ seen.set(key, f);
24
+ if (e.isDirectory()) scan(f);
25
+ }
26
+ }
27
+ scan(path.join(__dirname, '..'));
28
+ });
29
+ test('canonical LID protocol retains query, parser and per-user LID', () => {
30
+ const { USyncLIDProtocol } = require('../lib/WAUSync/Protocols/USyncLIDProtocol');
31
+ const p = new USyncLIDProtocol();
32
+ assert.deepEqual(p.getQueryElement(), { tag: 'lid', attrs: {} });
33
+ assert.equal(p.getUserElement(), null);
34
+ assert.deepEqual(p.getUserElement({ lid: '123@lid' }), { tag: 'lid', attrs: { jid: '123@lid' } });
35
+ assert.equal(p.parser({ tag: 'lid', attrs: { val: '123@lid' } }), '123@lid');
36
+ const query = new api.USyncQuery().withLIDProtocol();
37
+ assert.equal(query.protocols.find(p => p.name === 'lid').getUserElement({ lid: '123@lid' }).attrs.jid, '123@lid');
38
+ });
39
+ test('complete socket exposes every method in the supplemental surface', async () => {
40
+ const socket = makeSocket();
41
+ try {
42
+ for (const layer of require('../maintenance/reference-socket-surface.json')) {
43
+ for (const name of layer.methods) assert.ok(name in socket, layer.layer + ':' + name);
44
+ }
45
+ } finally { socket.end(); await tick(); }
46
+ });
47
+ test('socket end hooks run once, can be removed, and isolate rejected hooks', async () => {
48
+ const socket = makeSocket(); let calls = 0;
49
+ socket.registerSocketEndHandler(() => { calls++; });
50
+ socket.registerSocketEndHandler(async () => { calls++; throw new Error('expected cleanup error'); });
51
+ const remove = socket.registerSocketEndHandler(() => { calls += 100; });
52
+ remove(); socket.end(); socket.end(); await tick();
53
+ assert.equal(calls, 2);
54
+ socket.registerSocketEndHandler(() => { calls++; });
55
+ assert.equal(calls, 3);
56
+ });
57
+ test('account restriction and chat cap use existing WMex transport with correct paths', async () => {
58
+ const mex = require('../lib/Socket/mex'); const old = mex.executeWMexQuery;
59
+ const calls = [], events = []; const socket = makeSocket();
60
+ socket.ev.on('connection.update', e => { if (e.reachoutTimeLock) events.push(e.reachoutTimeLock); });
61
+ mex.executeWMexQuery = async (...args) => {
62
+ calls.push(args);
63
+ if (args[2] === api.XWAPaths.xwa2_fetch_account_reachout_timelock) {
64
+ return { is_active: true, time_enforcement_ends: '1800000000', enforcement_type: 'test' };
65
+ }
66
+ return { quota: 10, usage: 2 };
67
+ };
68
+ try {
69
+ const state = await socket.fetchAccountReachoutTimelock();
70
+ assert.equal(state.isActive, true);
71
+ assert.equal(state.timeEnforcementEnds.getTime(), 1800000000000);
72
+ assert.equal(state.enforcementType, 'test'); assert.equal(events.length, 1);
73
+ assert.deepEqual(await socket.fetchNewChatMessageCap(), { quota: 10, usage: 2 });
74
+ assert.deepEqual(calls[1][0], { input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } });
75
+ assert.equal(calls[0][1], api.QueryIds.REACHOUT_TIMELOCK);
76
+ assert.equal(calls[1][1], api.QueryIds.MESSAGE_CAPPING_INFO);
77
+ assert.equal(calls[0][3], socket.query);
78
+ assert.equal(calls[1][3], socket.query);
79
+ } finally { mex.executeWMexQuery = old; socket.end(); await tick(); }
80
+ });
81
+ test('closed socket ignores session telemetry and invalid server timestamps', async () => {
82
+ const socket = makeSocket();
83
+ socket.updateServerTimeOffset({ attrs: { t: 'Infinity' } });
84
+ socket.updateServerTimeOffset({ attrs: { t: 'invalid' } });
85
+ socket.updateServerTimeOffset({ attrs: { t: '0' } });
86
+ socket.updateServerTimeOffset({ attrs: { t: String(Math.floor(Date.now() / 1000)) } });
87
+ await socket.sendUnifiedSession(); socket.end(); await socket.sendUnifiedSession(); await tick();
88
+ });
89
+ test('Jimp resizing, cropping, effects and Kage thumbnails work with patched Zod', async () => {
90
+ const { Jimp } = require('jimp');
91
+ const image = new Jimp({ width: 32, height: 24, color: 0xff0000ff });
92
+ image.resize({ w: 64 }).crop({ x: 1, y: 1, w: 40, h: 20 }).flip({ horizontal: true });
93
+ image.contain({ w: 48, h: 48 }).cover({ w: 32, h: 32 }).rotate(90).circle();
94
+ image.color([{ apply: 'red', params: [10] }]);
95
+ const png = await image.getBuffer('image/png');
96
+ const thumbnail = await api.extractImageThumb(png, 16);
97
+ assert.equal(thumbnail.original.width, 32);
98
+ const thumbImage = await Jimp.read(thumbnail.buffer);
99
+ assert.equal(thumbImage.bitmap.width, 16);
100
+ const profile = await api.generateProfilePicture(png);
101
+ assert.ok(Buffer.isBuffer(profile.img));
102
+ });
103
+ test('npm overrides include each requested resolution and preserve major selection', () => {
104
+ const p = require('../package.json');
105
+ for (const [selector, range] of Object.entries(p.resolutions)) assert.equal(p.overrides[selector.replace('@npm:', '@')], range);
106
+ assert.equal(p.overrides['@itsukichan/libsignal-node'].protobufjs, '^7.6.6');
107
+ assert.equal(p.overrides['zod@^3.23.8'], '^4.6.7');
108
+ assert.equal(p.publishConfig.access, 'public');
109
+ assert.equal(api.KAGE_BUILD.version, p.version);
110
+ });
111
+ test('username builders and multimedia/account constants are exposed on active API', () => {
112
+ const user = new api.USyncUser().withUsername('example').withUsernameKey('key');
113
+ assert.equal(user.username, 'example'); assert.equal(user.usernameKey, 'key');
114
+ const query = new api.USyncQuery().withUsernameProtocol().withUser(user);
115
+ assert.equal(query.protocols[0].name, 'username');
116
+ assert.equal(api.QueryIds.REACHOUT_TIMELOCK, '23983697327930364');
117
+ assert.equal(api.QueryIds.MESSAGE_CAPPING_INFO, '24503548349331633');
118
+ assert.equal(api.QueryIds.SUBSCRIBED, '6388546374527196');
119
+ assert.equal(api.XWAPaths.xwa2_newsletter_subscribed, 'xwa2_newsletter_subscribed');
120
+ assert.equal(api.XWAPaths.xwa2_message_capping_info, 'xwa2_message_capping_info');
121
+ assert.equal(api.MEDIA_HKDF_KEY_MAPPING['sticker-pack'], 'Sticker Pack');
122
+ assert.equal(api.MEDIA_HKDF_KEY_MAPPING['product-catalog-image'], 'Product Catalog Image');
123
+ assert.ok(api.MEDIA_KEYS.includes('sticker-pack'));
124
+ });
125
+ test('retry manager accepts legacy and supplemental signatures and clears timers/caches', () => {
126
+ const manager = new api.MessageRetryManager(logger, 3);
127
+ const one = { conversation: 'one' }, two = { conversation: 'two' };
128
+ manager.addRecentMessage({ to: '1@s.whatsapp.net', id: 'a' }, one);
129
+ manager.addRecentMessage('2@s.whatsapp.net', 'b', two);
130
+ assert.equal(manager.getRecentMessage('1@s.whatsapp.net', 'a').message, one);
131
+ assert.equal(manager.getRecentMessage({ to: '2@s.whatsapp.net', id: 'b' }).message, two);
132
+ const key = Buffer.from([1, 2]); manager.saveBaseKey('address', 'b', key); key[0] = 9;
133
+ assert.equal(manager.hasSameBaseKey('address', 'b', Buffer.from([1, 2])), true);
134
+ manager.deleteBaseKey('address', 'b');
135
+ assert.equal(manager.hasSameBaseKey('address', 'b', Buffer.from([1, 2])), false);
136
+ manager.schedulePhoneRequest('a', () => assert.fail('cancelled timer fired'), 60000);
137
+ manager.clear();
138
+ assert.equal(manager.getRecentMessage('1@s.whatsapp.net', 'a'), undefined);
139
+ assert.deepEqual(Object.keys(manager.pendingPhoneRequests), []);
140
+ assert.equal(manager.statistics.totalRetries, 0);
141
+ });