jagproject 26.2.15 → 26.3.12

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.
@@ -9,7 +9,7 @@ const libsignal_1 = require("../Signal/libsignal");
9
9
  const browser_utils_1 = require("../Utils/browser-utils");
10
10
  const logger_1 = __importDefault(require("../Utils/logger"));
11
11
  const waVer = require("./wileys-version.json");
12
- exports.version = waVer?.version || [2, 3000, 1033271296];
12
+ exports.version = waVer?.version || [2, 3000, 1035023383];
13
13
  exports.UNAUTHORIZED_CODES = [401, 403, 419];
14
14
  exports.DEFAULT_ORIGIN = 'https://web.whatsapp.com';
15
15
  exports.CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
@@ -59,6 +59,8 @@ exports.DEFAULT_CONNECTION_CONFIG = {
59
59
  shouldSyncHistoryMessage: () => true,
60
60
  shouldIgnoreJid: () => false,
61
61
  linkPreviewImageThumbnailWidth: 192,
62
+ // no forced delay between album items by default, to avoid slow perceived delivery
63
+ albumMessageItemDelayMs: 0,
62
64
  transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 },
63
65
  generateHighQualityLinkPreview: false,
64
66
  enableAutoSessionRecreation: true,
@@ -116,4 +118,4 @@ exports.DEFAULT_CACHE_TTLS = {
116
118
  MSG_RETRY: 60 * 60,
117
119
  CALL_OFFER: 5 * 60,
118
120
  USER_DEVICES: 5 * 60
119
- };
121
+ };
@@ -1 +1,3 @@
1
- { "version": [2, 3000, 1033271296] }
1
+ {
2
+ "version": [2, 3000, 1035023383]
3
+ }
@@ -11,11 +11,6 @@ class WebSocketClient extends types_1.AbstractSocketClient {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.socket = null;
14
- // queue & dispatch variables for throttling outgoing messages to avoid rate limits
15
- this._queue = [];
16
- this._isDispatching = false;
17
- this._lastDispatch = 0;
18
- this._minSendIntervalMs = (Defaults_1.DEFAULT_CONNECTION_CONFIG && Defaults_1.DEFAULT_CONNECTION_CONFIG.minSendIntervalMs) || 50;
19
14
  }
20
15
  get isOpen() {
21
16
  var _a;
@@ -69,43 +64,9 @@ class WebSocketClient extends types_1.AbstractSocketClient {
69
64
  await this.connect();
70
65
  }
71
66
  send(str, cb) {
72
- // throttle sends to reduce rate-limit likelihood
73
- const doSend = () => {
74
- var _a;
75
- (_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(str, cb);
76
- return Boolean(this.socket);
77
- };
78
- this._queue.push(doSend);
79
- this._dispatch();
67
+ var _a;
68
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.send(str, cb);
80
69
  return true;
81
70
  }
82
-
83
- _dispatch() {
84
- if (this._isDispatching) {
85
- return;
86
- }
87
- this._isDispatching = true;
88
- const tick = () => {
89
- const now = Date.now();
90
- if (this._queue.length === 0) {
91
- this._isDispatching = false;
92
- return;
93
- }
94
- const delta = now - this._lastDispatch;
95
- const wait = Math.max(0, this._minSendIntervalMs - delta);
96
- setTimeout(() => {
97
- const fn = this._queue.shift();
98
- this._lastDispatch = Date.now();
99
- try {
100
- fn && fn();
101
- }
102
- catch (_err) {
103
- // ignore send errors here; they'll surface elsewhere
104
- }
105
- tick();
106
- }, wait);
107
- };
108
- tick();
109
- }
110
71
  }
111
72
  exports.WebSocketClient = WebSocketClient;
@@ -37,6 +37,10 @@ const makeChatsSocket = (config) => {
37
37
  stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY,
38
38
  useClones: false
39
39
  });
40
+ const receivedMessageDedupCache = new node_cache_1.default({
41
+ stdTTL: 3 * 60,
42
+ useClones: false
43
+ });
40
44
  if (!config.placeholderResendCache) {
41
45
  config.placeholderResendCache = placeholderResendCache;
42
46
  }
@@ -728,8 +732,58 @@ const makeChatsSocket = (config) => {
728
732
  fetchPrivacySettings(),
729
733
  ]);
730
734
  };
735
+ const canonicalizeUserJid = (jid) => {
736
+ if (!jid) {
737
+ return jid;
738
+ }
739
+ if ((0, WABinary_1.isLidUser)(jid)) {
740
+ return (0, WABinary_1.lidToJid)(jid);
741
+ }
742
+ return jid;
743
+ };
744
+ const extractStanzaId = (msg) => {
745
+ var _a, _b;
746
+ const topLevelStanzaId = (_a = msg.messageContextInfo) === null || _a === void 0 ? void 0 : _a.stanzaId;
747
+ if (topLevelStanzaId) {
748
+ return topLevelStanzaId;
749
+ }
750
+ const messageContextStanzaId = (_b = msg.message) === null || _b === void 0 ? void 0 : _b.messageContextInfo;
751
+ if (messageContextStanzaId === null || messageContextStanzaId === void 0 ? void 0 : messageContextStanzaId.stanzaId) {
752
+ return messageContextStanzaId.stanzaId;
753
+ }
754
+ const normalizedContent = (0, Utils_1.normalizeMessageContent)(msg.message);
755
+ const contentType = normalizedContent ? (0, Utils_1.getContentType)(normalizedContent) : undefined;
756
+ const contentContextStanzaId = contentType
757
+ ? normalizedContent[contentType].contextInfo && normalizedContent[contentType].contextInfo.stanzaId
758
+ : undefined;
759
+ return contentContextStanzaId;
760
+ };
761
+ const buildMessageDedupKeys = (msg) => {
762
+ const remoteJid = canonicalizeUserJid(msg.key.remoteJid);
763
+ const participant = canonicalizeUserJid(msg.key.participant);
764
+ const stanzaId = extractStanzaId(msg);
765
+ const primaryKey = [remoteJid, participant, msg.key.id, msg.key.fromMe ? '1' : '0', stanzaId || ''].join('|');
766
+ const keys = [primaryKey];
767
+ // fallback alias key to collapse LID->PN duplicate deliveries for the same incoming user message ID
768
+ if (!msg.key.fromMe && ((0, WABinary_1.isJidUser)(msg.key.remoteJid) || (0, WABinary_1.isLidUser)(msg.key.remoteJid))) {
769
+ keys.push(`incoming-user-id|${msg.key.id}|${stanzaId || ''}`);
770
+ }
771
+ return keys;
772
+ };
773
+ const getDedupState = (msg) => msg.messageStubType === WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
774
+ ? 'ciphertext'
775
+ : 'final';
731
776
  const upsertMessage = ev.createBufferedFunction(async (msg, type) => {
732
777
  var _a, _b, _c;
778
+ const dedupKeys = buildMessageDedupKeys(msg);
779
+ const dedupState = getDedupState(msg);
780
+ const previousDedupState = dedupKeys
781
+ .map(key => receivedMessageDedupCache.get(key))
782
+ .find(state => !!state);
783
+ if (previousDedupState === 'final' || (previousDedupState === 'ciphertext' && dedupState === 'ciphertext')) {
784
+ logger.debug({ dedupKeys, messageId: msg.key.id, type, dedupState, previousDedupState }, 'skipping duplicate messages.upsert');
785
+ return;
786
+ }
733
787
  ev.emit('messages.upsert', { messages: [msg], type });
734
788
  if (!!msg.pushName) {
735
789
  let jid = msg.key.fromMe ? authState.creds.me.id : (msg.key.participant || msg.key.remoteJid);
@@ -800,6 +854,9 @@ const makeChatsSocket = (config) => {
800
854
  await doAppStateSync();
801
855
  pendingAppStateSync = false;
802
856
  }
857
+ for (const key of dedupKeys) {
858
+ receivedMessageDedupCache.set(key, dedupState);
859
+ }
803
860
  });
804
861
  ws.on('CB:presence', handlePresenceUpdate);
805
862
  ws.on('CB:chatstate', handlePresenceUpdate);
@@ -912,4 +969,4 @@ const makeChatsSocket = (config) => {
912
969
  star
913
970
  };
914
971
  };
915
- exports.makeChatsSocket = makeChatsSocket;
972
+ exports.makeChatsSocket = makeChatsSocket;
@@ -33,7 +33,55 @@ const makeMessagesRecvSocket = (config) => {
33
33
  stdTTL: Defaults_1.DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
34
34
  useClones: false
35
35
  });
36
+ const groupParticipantJidCache = new node_cache_1.default({
37
+ stdTTL: 10 * 60, // 10 mins
38
+ useClones: false
39
+ });
40
+ const groupMetadataWarmupCache = new node_cache_1.default({
41
+ stdTTL: 60, // avoid repeated warmup calls per group
42
+ useClones: false
43
+ });
36
44
  let sendActiveReceipts = false;
45
+ const cacheGroupParticipants = (metadata) => {
46
+ for (const participant of metadata.participants || []) {
47
+ if (!participant.id || !participant.jid) {
48
+ continue;
49
+ }
50
+ groupParticipantJidCache.set(`${metadata.id}:${participant.id}`, participant.jid);
51
+ if (participant.lid) {
52
+ groupParticipantJidCache.set(`${metadata.id}:${participant.lid}`, participant.jid);
53
+ }
54
+ }
55
+ };
56
+ const warmupGroupParticipants = async (groupJid) => {
57
+ if (groupMetadataWarmupCache.get(groupJid)) {
58
+ return;
59
+ }
60
+ groupMetadataWarmupCache.set(groupJid, true);
61
+ try {
62
+ const metadata = await groupMetadata(groupJid);
63
+ cacheGroupParticipants(metadata);
64
+ }
65
+ catch (error) {
66
+ logger.debug({ error, groupJid }, 'failed to warm up group participant cache');
67
+ }
68
+ };
69
+ const resolveGroupParticipantJid = async (groupJid, participantLid) => {
70
+ const cacheKey = `${groupJid}:${participantLid}`;
71
+ const cachedParticipant = groupParticipantJidCache.get(cacheKey);
72
+ if (cachedParticipant) {
73
+ return cachedParticipant;
74
+ }
75
+ try {
76
+ const metadata = await groupMetadata(groupJid);
77
+ cacheGroupParticipants(metadata);
78
+ return groupParticipantJidCache.get(cacheKey);
79
+ }
80
+ catch (error) {
81
+ logger.debug({ error, groupJid, participantLid }, 'failed to resolve group participant jid');
82
+ return undefined;
83
+ }
84
+ };
37
85
  const sendMessageAck = async ({ tag, attrs, content }, errorCode) => {
38
86
  const stanza = {
39
87
  tag: 'ack',
@@ -778,12 +826,14 @@ const makeMessagesRecvSocket = (config) => {
778
826
  }
779
827
  if ((0, WABinary_1.isJidGroup)(msg.key.remoteJid) && ((_f = (_e = (_d = (_c = msg.message) === null || _c === void 0 ? void 0 : _c.extendedTextMessage) === null || _d === void 0 ? void 0 : _d.contextInfo) === null || _e === void 0 ? void 0 : _e.participant) === null || _f === void 0 ? void 0 : _f.endsWith('@lid'))) {
780
828
  if (msg.message.extendedTextMessage.contextInfo) {
781
- const metadata = await groupMetadata(msg.key.remoteJid);
782
829
  const sender = msg.message.extendedTextMessage.contextInfo.participant;
783
- const found = metadata.participants.find(p => p.id === sender);
784
- msg.message.extendedTextMessage.contextInfo.participant = (found === null || found === void 0 ? void 0 : found.jid) || sender;
830
+ const resolvedSender = await resolveGroupParticipantJid(msg.key.remoteJid, sender);
831
+ msg.message.extendedTextMessage.contextInfo.participant = resolvedSender || sender;
785
832
  }
786
833
  }
834
+ else if ((0, WABinary_1.isJidGroup)(msg.key.remoteJid)) {
835
+ void warmupGroupParticipants(msg.key.remoteJid);
836
+ }
787
837
  if (!(0, WABinary_1.isJidGroup)(msg.key.remoteJid) && (0, WABinary_1.isLidUser)(msg.key.remoteJid)) {
788
838
  msg.key.remoteJid = node.attrs.sender_pn || node.attrs.peer_recipient_pn;
789
839
  }
@@ -89,14 +89,6 @@ const makeSocket = (config) => {
89
89
  // ignore
90
90
  }
91
91
  }
92
- // gently back off when encountering rate limits (429)
93
- if (message.includes('429') || message.includes('rate limit')) {
94
- const wait = Math.min(30000, (config.backoffDelayMs || 5000));
95
- logger.info({ wait }, 'backing off due to rate limit');
96
- setTimeout(() => {
97
- // intentionally empty; wait to delay further sends
98
- }, wait);
99
- }
100
92
  };
101
93
  /** await the next incoming message */
102
94
  const awaitNextMessage = async (sendMsg) => {
package/lib/index.js CHANGED
@@ -67,7 +67,7 @@ console.log(chalk.redBright.bold(title));
67
67
  padLine(`${chalk.magentaBright("Youtube")} : ${chalk.whiteBright(YOUTUBE)}`),
68
68
  padLine(`${chalk.blueBright("Kontak")} : ${chalk.whiteBright(CONTACT)}`),
69
69
  padLine(""),
70
- padLine(chalk.gray("Tip: di bailyes ini disarankan pakai Node >= 20.")),
70
+ padLine(chalk.gray("Tip: saran pakai Node >= 20.")),
71
71
  ];
72
72
 
73
73
  box(infoLines, (s) => chalk.white(s));
@@ -80,6 +80,7 @@ printBanner();
80
80
  PEMBATAS
81
81
  */
82
82
 
83
+
83
84
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
84
85
  if (k2 === undefined) k2 = k;
85
86
  var desc = Object.getOwnPropertyDescriptor(m, k);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jagproject",
3
- "version": "26.02.15",
4
- "update": "15 Februari 2026",
3
+ "version": "26.03.12",
4
+ "update": "12 Maret 2026",
5
5
  "description": "WhatsApp Web API Library",
6
6
  "keywords": [
7
7
  "jagoan",
@@ -12,11 +12,15 @@
12
12
  "automation",
13
13
  "multi-device"
14
14
  ],
15
- "homepage": "https://www.npmjs.com/package/jagoanproject",
15
+ "homepage": "https://whatsapp.com/channel/0029VanhMDo42DcjiRGJOc2m",
16
16
  "repository": {
17
17
  "type": "git",
18
18
  "url": "git+https://github.com/ChandraGO/jagoans.git"
19
19
  },
20
+ "funding": {
21
+ "type": "youtube",
22
+ "url": "https://youtube.com/@jagoanproject"
23
+ },
20
24
  "license": "MIT",
21
25
  "author": "jagoan",
22
26
  "main": "lib/index.js",
@@ -27,7 +31,7 @@
27
31
  "engine-requirements.js"
28
32
  ],
29
33
  "scripts": {
30
- "build:all": "tsc && typedoc",
34
+ "build:all": "tsc && typedoc",
31
35
  "build:docs": "typedoc",
32
36
  "build:tsc": "tsc",
33
37
  "changelog:last": "conventional-changelog -p angular -r 2",
@@ -37,10 +41,9 @@
37
41
  "gen:protobuf": "sh WAProto/GenerateStatics.sh",
38
42
  "lint": "eslint src --ext .js,.ts,.jsx,.tsx",
39
43
  "lint:fix": "eslint src --fix --ext .js,.ts,.jsx,.tsx",
40
- "prepack": "node -e \"const fs=require('fs');const pkg=JSON.parse(fs.readFileSync('package.json','utf8'));const t=pkg.update;if(!t)process.exit(1);const f=fs.existsSync('README.MD')?'README.MD':'README.md';let r=fs.readFileSync(f,'utf8');r=r.replace(/<sub>\\s*Last update:\\s*<strong>[\\s\\S]*?<\\/strong>\\s*<\\/sub>/i,`<sub>Last update: <strong>${t}</strong></sub>`);fs.writeFileSync(f,r);console.log('prepack synced README:',t);\"",
41
- "prepare": "echo 'jagoan WhatsApp Library'",
44
+ "prepack": "echo 'Wileys WhatsApp Library'",
45
+ "prepare": "echo 'Wileys WhatsApp Library'",
42
46
  "preinstall": "node ./engine-requirements.js",
43
- "postinstall": "node ./lib/Defaults/update-wa-version.js",
44
47
  "release": "release-it",
45
48
  "test": "jest"
46
49
  },
@@ -51,13 +54,11 @@
51
54
  "async-mutex": "^0.5.0",
52
55
  "axios": "^1.6.0",
53
56
  "chalk": "^4.1.2",
54
- "fluent-ffmpeg": "^2.1.2",
55
- "ffmpeg-static": "^5.2.0",
56
57
  "gradient-string": "^2.0.2",
57
58
  "cache-manager": "^5.7.6",
58
59
  "cheerio": "^1.0.0-rc.10",
59
60
  "libphonenumber-js": "^1.10.20",
60
- "libsignal": "github:ChandraGO/libsignal-node",
61
+ "libsignal": "github:NaufalYupra/libsignal-node",
61
62
  "lodash": "^4.17.21",
62
63
  "music-metadata": "^7.12.3",
63
64
  "pino": "^9.6",