@vanzxy/baileys 1.4.1 → 1.4.2
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.
Potentially problematic release.
This version of @vanzxy/baileys might be problematic. Click here for more details.
- package/cjs/WAProto/index.js +106053 -0
- package/cjs/lib/Defaults/index.js +168 -0
- package/cjs/lib/Signal/Group/ciphertext-message.js +16 -0
- package/cjs/lib/Signal/Group/group-session-builder.js +67 -0
- package/cjs/lib/Signal/Group/group_cipher.js +86 -0
- package/cjs/lib/Signal/Group/index.js +58 -0
- package/cjs/lib/Signal/Group/keyhelper.js +56 -0
- package/cjs/lib/Signal/Group/sender-chain-key.js +30 -0
- package/cjs/lib/Signal/Group/sender-key-distribution-message.js +67 -0
- package/cjs/lib/Signal/Group/sender-key-message.js +70 -0
- package/cjs/lib/Signal/Group/sender-key-name.js +52 -0
- package/cjs/lib/Signal/Group/sender-key-record.js +45 -0
- package/cjs/lib/Signal/Group/sender-key-state.js +88 -0
- package/cjs/lib/Signal/Group/sender-message-key.js +30 -0
- package/cjs/lib/Signal/libsignal.js +467 -0
- package/cjs/lib/Signal/lid-mapping.js +281 -0
- package/cjs/lib/Socket/Client/index.js +19 -0
- package/cjs/lib/Socket/Client/types.js +15 -0
- package/cjs/lib/Socket/Client/websocket.js +61 -0
- package/cjs/lib/Socket/business.js +384 -0
- package/cjs/lib/Socket/chats.js +1257 -0
- package/cjs/lib/Socket/communities.js +442 -0
- package/cjs/lib/Socket/dugong.js +753 -0
- package/cjs/lib/Socket/groups.js +360 -0
- package/cjs/lib/Socket/index.js +19 -0
- package/cjs/lib/Socket/messages-recv.js +1790 -0
- package/cjs/lib/Socket/messages-send.js +1390 -0
- package/cjs/lib/Socket/mex.js +46 -0
- package/cjs/lib/Socket/newsletter.js +340 -0
- package/cjs/lib/Socket/socket.js +1007 -0
- package/cjs/lib/Store/index.js +20 -0
- package/cjs/lib/Store/make-in-memory-store.js +438 -0
- package/cjs/lib/Store/make-ordered-dictionary.js +82 -0
- package/cjs/lib/Store/object-repository.js +28 -0
- package/cjs/lib/Types/Auth.js +3 -0
- package/cjs/lib/Types/Bussines.js +3 -0
- package/cjs/lib/Types/Call.js +3 -0
- package/cjs/lib/Types/Chat.js +11 -0
- package/cjs/lib/Types/Contact.js +3 -0
- package/cjs/lib/Types/Events.js +4 -0
- package/cjs/lib/Types/GroupMetadata.js +3 -0
- package/cjs/lib/Types/Label.js +26 -0
- package/cjs/lib/Types/LabelAssociation.js +8 -0
- package/cjs/lib/Types/Message.js +19 -0
- package/cjs/lib/Types/Mex.js +40 -0
- package/cjs/lib/Types/Product.js +3 -0
- package/cjs/lib/Types/RichType.js +24 -0
- package/cjs/lib/Types/Signal.js +4 -0
- package/cjs/lib/Types/Socket.js +4 -0
- package/cjs/lib/Types/State.js +54 -0
- package/cjs/lib/Types/USync.js +4 -0
- package/cjs/lib/Types/index.js +42 -0
- package/cjs/lib/Utils/MessageBuilder.js +2164 -0
- package/cjs/lib/Utils/auth-utils.js +312 -0
- package/cjs/lib/Utils/browser-utils.js +32 -0
- package/cjs/lib/Utils/business.js +245 -0
- package/cjs/lib/Utils/chat-utils.js +937 -0
- package/cjs/lib/Utils/companion-reg-client-utils.js +45 -0
- package/cjs/lib/Utils/crypto.js +196 -0
- package/cjs/lib/Utils/decode-wa-message.js +324 -0
- package/cjs/lib/Utils/event-buffer.js +643 -0
- package/cjs/lib/Utils/generics.js +429 -0
- package/cjs/lib/Utils/history.js +151 -0
- package/cjs/lib/Utils/identity-change-handler.js +56 -0
- package/cjs/lib/Utils/index.js +42 -0
- package/cjs/lib/Utils/link-preview.js +122 -0
- package/cjs/lib/Utils/logger.js +8 -0
- package/cjs/lib/Utils/lt-hash.js +62 -0
- package/cjs/lib/Utils/make-mutex.js +38 -0
- package/cjs/lib/Utils/message-retry-manager.js +267 -0
- package/cjs/lib/Utils/messages-media.js +933 -0
- package/cjs/lib/Utils/messages.js +2175 -0
- package/cjs/lib/Utils/noise-handler.js +205 -0
- package/cjs/lib/Utils/offline-node-processor.js +43 -0
- package/cjs/lib/Utils/pre-key-manager.js +113 -0
- package/cjs/lib/Utils/process-message.js +772 -0
- package/cjs/lib/Utils/reporting-utils.js +263 -0
- package/cjs/lib/Utils/rich-message-utils.js +439 -0
- package/cjs/lib/Utils/signal.js +214 -0
- package/cjs/lib/Utils/stanza-ack.js +41 -0
- package/cjs/lib/Utils/sync-action-utils.js +54 -0
- package/cjs/lib/Utils/tc-token-utils.js +174 -0
- package/cjs/lib/Utils/use-multi-file-auth-state.js +125 -0
- package/cjs/lib/Utils/use-single-file-auth-state.js +121 -0
- package/cjs/lib/Utils/use-sqlite-auth-state.js +182 -0
- package/cjs/lib/Utils/validate-connection.js +210 -0
- package/cjs/lib/WABinary/constants.js +1470 -0
- package/cjs/lib/WABinary/decode.js +301 -0
- package/cjs/lib/WABinary/encode.js +257 -0
- package/cjs/lib/WABinary/generic-utils.js +274 -0
- package/cjs/lib/WABinary/index.js +22 -0
- package/cjs/lib/WABinary/jid-utils.js +114 -0
- package/cjs/lib/WABinary/types.js +37 -0
- package/cjs/lib/WAM/BinaryInfo.js +14 -0
- package/cjs/lib/WAM/constants.js +22856 -0
- package/cjs/lib/WAM/encode.js +154 -0
- package/cjs/lib/WAM/index.js +20 -0
- package/cjs/lib/WAUSync/Protocols/USyncContactProtocol.js +56 -0
- package/cjs/lib/WAUSync/Protocols/USyncDeviceProtocol.js +67 -0
- package/cjs/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +31 -0
- package/cjs/lib/WAUSync/Protocols/USyncStatusProtocol.js +42 -0
- package/cjs/lib/WAUSync/Protocols/USyncUsernameProtocol.js +29 -0
- package/cjs/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +55 -0
- package/cjs/lib/WAUSync/Protocols/UsyncLIDProtocol.js +33 -0
- package/cjs/lib/WAUSync/Protocols/index.js +24 -0
- package/cjs/lib/WAUSync/USyncQuery.js +126 -0
- package/cjs/lib/WAUSync/USyncUser.js +35 -0
- package/cjs/lib/WAUSync/index.js +20 -0
- package/cjs/lib/index.js +34 -0
- package/cjs/package.json +1 -0
- package/package.json +16 -5
|
@@ -0,0 +1,2164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/Utils/MessageBuilder.js — AIRich / Button / ButtonV2 / Carousel / Toolkit
|
|
3
|
+
*
|
|
4
|
+
* Part of @vanzxy/baileys 1.3.9. Third-party attribution for the base
|
|
5
|
+
* implementation this file was adapted from is kept in /NOTICE.md
|
|
6
|
+
* (not inline here) per the original author's license terms.
|
|
7
|
+
*
|
|
8
|
+
* Vanz@Merge 15-08-26 --- Ported into @vanzxy/baileys 1.3.9 from the
|
|
9
|
+
* @blurose/baileys 1.1.13 fork (base, feature-complete) with perf defaults
|
|
10
|
+
* and message-authenticity fields backported from arslan-baileys 1.1.0 and
|
|
11
|
+
* this project's own rich-message-utils.js. See changes tagged "Vanz@" below.
|
|
12
|
+
*/
|
|
13
|
+
'use strict';
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
48
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
49
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
50
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
51
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
52
|
+
};
|
|
53
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
54
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
55
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
56
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
57
|
+
};
|
|
58
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
59
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
60
|
+
};
|
|
61
|
+
var _a, _Button_client, _Button_validateAgainstSchema, _ButtonV2_client, _Carousel_client, _AIRich_client;
|
|
62
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
63
|
+
exports.Toolkit = exports.AIRich = exports.Carousel = exports.ButtonV2 = exports.Button = exports.MESSAGE_BUILDER_VERSION = void 0;
|
|
64
|
+
const MESSAGE_BUILDER_VERSION = '4.6';
|
|
65
|
+
exports.MESSAGE_BUILDER_VERSION = MESSAGE_BUILDER_VERSION;
|
|
66
|
+
const messages_js_1 = require("./messages.js");
|
|
67
|
+
const rich_message_utils_js_1 = require("./rich-message-utils.js");
|
|
68
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
69
|
+
const stream_1 = require("stream");
|
|
70
|
+
// Vanz@Fix 15-08-26 --- sharp/fluent-ffmpeg were statically imported in the blurose source.
|
|
71
|
+
// Both are optional peer deps here (see package.json peerDependenciesMeta); a static import
|
|
72
|
+
// throws at module-load time when they're not installed, which would crash the entire
|
|
73
|
+
// lib/Utils barrel export (and therefore bot startup) even for users who never call
|
|
74
|
+
// AIRich.addImage()/addVideo()/Toolkit.*. Lazy-load them instead, matching the pattern
|
|
75
|
+
// already used in messages-media.js's getImageProcessingLibrary().
|
|
76
|
+
let _sharp;
|
|
77
|
+
const getSharp = async () => {
|
|
78
|
+
if (_sharp === undefined) {
|
|
79
|
+
_sharp = await Promise.resolve().then(() => __importStar(require('sharp'))).then((m) => m.default ?? m).catch(() => null);
|
|
80
|
+
}
|
|
81
|
+
if (!_sharp)
|
|
82
|
+
throw new Error('sharp is required for this operation. Install it with: npm i sharp');
|
|
83
|
+
return _sharp;
|
|
84
|
+
};
|
|
85
|
+
let _ffmpeg;
|
|
86
|
+
const getFfmpeg = async () => {
|
|
87
|
+
if (_ffmpeg === undefined) {
|
|
88
|
+
_ffmpeg = await Promise.resolve().then(() => __importStar(require('fluent-ffmpeg'))).then((m) => m.default ?? m).catch(() => null);
|
|
89
|
+
}
|
|
90
|
+
if (!_ffmpeg)
|
|
91
|
+
throw new Error('fluent-ffmpeg is required for this operation. Install it with: npm i fluent-ffmpeg');
|
|
92
|
+
return _ffmpeg;
|
|
93
|
+
};
|
|
94
|
+
function extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
|
|
95
|
+
if (!extract) {
|
|
96
|
+
return {
|
|
97
|
+
text,
|
|
98
|
+
ie: [],
|
|
99
|
+
inline_entities: [],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const createIE = (type, ie) => {
|
|
103
|
+
if (type == 'hyperlink') {
|
|
104
|
+
return {
|
|
105
|
+
key: ie.key,
|
|
106
|
+
metadata: {
|
|
107
|
+
display_name: ie.text,
|
|
108
|
+
is_trusted: ie.is_trusted,
|
|
109
|
+
url: ie.url,
|
|
110
|
+
__typename: 'GenAIInlineLinkItem',
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (type == 'citation') {
|
|
115
|
+
return {
|
|
116
|
+
key: ie.key,
|
|
117
|
+
metadata: {
|
|
118
|
+
reference_id: ie.reference_id,
|
|
119
|
+
reference_url: ie.url,
|
|
120
|
+
reference_title: ie.url,
|
|
121
|
+
reference_display_name: ie.url,
|
|
122
|
+
sources: [],
|
|
123
|
+
__typename: 'GenAISearchCitationItem',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (type == 'latex') {
|
|
128
|
+
return {
|
|
129
|
+
key: ie.key,
|
|
130
|
+
metadata: {
|
|
131
|
+
latex_expression: ie.text,
|
|
132
|
+
latex_image: {
|
|
133
|
+
url: ie.url,
|
|
134
|
+
width: Number(ie.width) || 100,
|
|
135
|
+
height: Number(ie.height) || 100,
|
|
136
|
+
},
|
|
137
|
+
font_height: Number(ie.font_height) || 83.333333333333,
|
|
138
|
+
padding: Number(ie.padding) || 15,
|
|
139
|
+
__typename: 'GenAILatexItem',
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
let ie = [];
|
|
145
|
+
let inline_entities = [];
|
|
146
|
+
let result = '';
|
|
147
|
+
let last = 0;
|
|
148
|
+
let citation_index = 1;
|
|
149
|
+
let hyperlink_index = 0;
|
|
150
|
+
let latex_index = 0;
|
|
151
|
+
let stack = [];
|
|
152
|
+
for (let i = 0; i < text.length; i++) {
|
|
153
|
+
if (text[i] == '[' && text[i - 1] != '\\') {
|
|
154
|
+
stack.push(i);
|
|
155
|
+
}
|
|
156
|
+
else if (text[i] == ']' && (text[i + 1] == '(' || text[i + 1] == '<')) {
|
|
157
|
+
let start = stack.pop();
|
|
158
|
+
if (start == null)
|
|
159
|
+
continue;
|
|
160
|
+
let open = text[i + 1];
|
|
161
|
+
let close = open == '(' ? ')' : '>';
|
|
162
|
+
let type = open == '(' ? 'link' : 'latex';
|
|
163
|
+
let end = i + 2;
|
|
164
|
+
let depth = 1;
|
|
165
|
+
while (end < text.length && depth) {
|
|
166
|
+
if (text[end] == open && text[end - 1] != '\\')
|
|
167
|
+
depth++;
|
|
168
|
+
else if (text[end] == close && text[end - 1] != '\\')
|
|
169
|
+
depth--;
|
|
170
|
+
end++;
|
|
171
|
+
}
|
|
172
|
+
if (depth)
|
|
173
|
+
continue;
|
|
174
|
+
let raw = text.slice(start + 1, i).trim();
|
|
175
|
+
let url = text.slice(i + 2, end - 1).trim();
|
|
176
|
+
let key;
|
|
177
|
+
let tag;
|
|
178
|
+
let data;
|
|
179
|
+
if (type == 'latex') {
|
|
180
|
+
if (!latex)
|
|
181
|
+
continue;
|
|
182
|
+
let [txt = '', width = null, height = null, font_height = null, padding = null] = raw.split('|');
|
|
183
|
+
key = `\u004E\u0049\u0058\u0045\u004C_LATEX_${latex_index++}`;
|
|
184
|
+
tag = `{{${key}}}${txt || 'image'}{{/${key}}}`;
|
|
185
|
+
data = {
|
|
186
|
+
type: 'latex',
|
|
187
|
+
ie: {
|
|
188
|
+
key,
|
|
189
|
+
text: txt,
|
|
190
|
+
url,
|
|
191
|
+
width,
|
|
192
|
+
height,
|
|
193
|
+
font_height,
|
|
194
|
+
padding,
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
else if (raw) {
|
|
199
|
+
if (!hyperlink)
|
|
200
|
+
continue;
|
|
201
|
+
const trusted = !url.startsWith('!');
|
|
202
|
+
if (!trusted) {
|
|
203
|
+
url = url.slice(1);
|
|
204
|
+
}
|
|
205
|
+
key = `\u004E\u0049\u0058\u0045\u004C_HYPERLINK_${hyperlink_index++}`;
|
|
206
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
207
|
+
data = {
|
|
208
|
+
type: 'hyperlink',
|
|
209
|
+
ie: {
|
|
210
|
+
key,
|
|
211
|
+
text: raw,
|
|
212
|
+
url,
|
|
213
|
+
is_trusted: trusted,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
if (!citation)
|
|
219
|
+
continue;
|
|
220
|
+
key = `\u004E\u0049\u0058\u0045\u004C_CITATION_${citation_index - 1}`;
|
|
221
|
+
tag = `{{${key}}}${url}{{/${key}}}`;
|
|
222
|
+
data = {
|
|
223
|
+
type: 'citation',
|
|
224
|
+
ie: {
|
|
225
|
+
reference_id: citation_index++,
|
|
226
|
+
key,
|
|
227
|
+
text: '',
|
|
228
|
+
url,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
result += text.slice(last, start) + tag;
|
|
233
|
+
last = end;
|
|
234
|
+
ie.push(data);
|
|
235
|
+
const entity = createIE(data.type, data.ie);
|
|
236
|
+
if (entity) {
|
|
237
|
+
inline_entities.push(entity);
|
|
238
|
+
}
|
|
239
|
+
i = end - 1;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
result += text.slice(last);
|
|
243
|
+
return {
|
|
244
|
+
text: result,
|
|
245
|
+
ie,
|
|
246
|
+
inline_entities,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async function waitAllPromises(input) {
|
|
250
|
+
const isPromise = (v) => v && typeof v.then === 'function';
|
|
251
|
+
const isObject = (v) => v && typeof v === 'object';
|
|
252
|
+
const deep = async (v) => {
|
|
253
|
+
if (isPromise(v))
|
|
254
|
+
return deep(await v);
|
|
255
|
+
if (Array.isArray(v))
|
|
256
|
+
return Promise.all(v.map(deep));
|
|
257
|
+
if (isObject(v)) {
|
|
258
|
+
const entries = await Promise.all(Object.entries(v).map(async ([k, val]) => [k, await deep(val)]));
|
|
259
|
+
return Object.fromEntries(entries);
|
|
260
|
+
}
|
|
261
|
+
return v;
|
|
262
|
+
};
|
|
263
|
+
return deep(await input);
|
|
264
|
+
}
|
|
265
|
+
class Toolkit {
|
|
266
|
+
constructor() { }
|
|
267
|
+
static extractIE(text, { extract = true, hyperlink = true, citation = true, latex = true } = {}) {
|
|
268
|
+
return extractIE(text, { extract, hyperlink, citation, latex });
|
|
269
|
+
}
|
|
270
|
+
static async resize(buffer, x, y, fit = 'cover') {
|
|
271
|
+
const sharp = await getSharp();
|
|
272
|
+
return await sharp(buffer)
|
|
273
|
+
.resize(x, y, {
|
|
274
|
+
fit,
|
|
275
|
+
position: 'center',
|
|
276
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
277
|
+
})
|
|
278
|
+
.png()
|
|
279
|
+
.toBuffer();
|
|
280
|
+
}
|
|
281
|
+
static async waitAllPromises(input) {
|
|
282
|
+
return await waitAllPromises(input);
|
|
283
|
+
}
|
|
284
|
+
static async fetchBuffer(url, options = {}, { silent = true } = {}) {
|
|
285
|
+
try {
|
|
286
|
+
let response = await fetch(url, options);
|
|
287
|
+
if (!response.ok)
|
|
288
|
+
throw Error(`HTTP ${response.status}`);
|
|
289
|
+
return Buffer.from(await response.arrayBuffer());
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
if (silent)
|
|
293
|
+
return Buffer.alloc(0);
|
|
294
|
+
throw error;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
static async toUrl(_client, path, mediaType = 'document') {
|
|
298
|
+
if (!path)
|
|
299
|
+
throw new Error('Url or buffer needed');
|
|
300
|
+
const media = await (0, messages_js_1.prepareWAMessageMedia)({
|
|
301
|
+
[mediaType]: Buffer.isBuffer(path) ? path : { url: path },
|
|
302
|
+
}, {
|
|
303
|
+
upload: _client.waUploadToServer,
|
|
304
|
+
jid: '\u0040\u006e\u0065\u0077\u0073\u006c\u0065\u0074\u0074\u0065\u0072',
|
|
305
|
+
});
|
|
306
|
+
return Object.values(media)[0]?.url;
|
|
307
|
+
}
|
|
308
|
+
static async resolveMedia(_client, media, mediaType = 'image', { resolveUrl = false, resolveWAUrl = false, result = 'url', resize = false, width = 300, height = 300 } = {}) {
|
|
309
|
+
const isUrl = (str) => /^https?:\/\/.+/i.test(str);
|
|
310
|
+
const isWAUrl = (str) => /^https?:\/\/[^/]*\.whatsapp\.net\//i.test(str);
|
|
311
|
+
if (Array.isArray(media)) {
|
|
312
|
+
return Promise.all(media.map((item) => Toolkit.resolveMedia(_client, item, mediaType, {
|
|
313
|
+
resolveUrl,
|
|
314
|
+
resolveWAUrl,
|
|
315
|
+
result,
|
|
316
|
+
resize,
|
|
317
|
+
width,
|
|
318
|
+
height,
|
|
319
|
+
})));
|
|
320
|
+
}
|
|
321
|
+
const originalIsBuffer = Buffer.isBuffer(media);
|
|
322
|
+
if (typeof media === 'string' && isUrl(media)) {
|
|
323
|
+
if (isWAUrl(media)) {
|
|
324
|
+
if (resolveWAUrl) {
|
|
325
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
326
|
+
}
|
|
327
|
+
else if (!resolveUrl) {
|
|
328
|
+
if (result === 'url')
|
|
329
|
+
return media;
|
|
330
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
if (!resolveUrl) {
|
|
335
|
+
if (result === 'url')
|
|
336
|
+
return media;
|
|
337
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
media = await Toolkit.fetchBuffer(media, {}, { silent: true });
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (typeof media === 'string' && !isUrl(media)) {
|
|
345
|
+
media = Buffer.from(media, 'base64');
|
|
346
|
+
}
|
|
347
|
+
if (!Buffer.isBuffer(media) || !media.length) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (resize && Buffer.isBuffer(media)) {
|
|
351
|
+
media = await Toolkit.resize(media, width, height);
|
|
352
|
+
}
|
|
353
|
+
if (result === 'buffer') {
|
|
354
|
+
return media;
|
|
355
|
+
}
|
|
356
|
+
if (result === 'base64') {
|
|
357
|
+
return media.toString('base64');
|
|
358
|
+
}
|
|
359
|
+
if (originalIsBuffer) {
|
|
360
|
+
return Toolkit.toUrl(_client, media, mediaType);
|
|
361
|
+
}
|
|
362
|
+
return Toolkit.toUrl(_client, media, mediaType);
|
|
363
|
+
}
|
|
364
|
+
static getMp4Duration(buffer, { silent = true } = {}) {
|
|
365
|
+
try {
|
|
366
|
+
if (!Buffer.isBuffer(buffer) || buffer.length < 8) {
|
|
367
|
+
if (silent)
|
|
368
|
+
return 0;
|
|
369
|
+
throw new Error('Invalid buffer');
|
|
370
|
+
}
|
|
371
|
+
let offset = 0;
|
|
372
|
+
while (offset < buffer.length - 8) {
|
|
373
|
+
const size = buffer.readUInt32BE(offset);
|
|
374
|
+
if (size < 8 || offset + size > buffer.length) {
|
|
375
|
+
if (silent)
|
|
376
|
+
return 0;
|
|
377
|
+
throw new Error('Invalid atom size');
|
|
378
|
+
}
|
|
379
|
+
const type = buffer.toString('ascii', offset + 4, offset + 8);
|
|
380
|
+
if (type === 'moov') {
|
|
381
|
+
let moovOffset = offset + 8;
|
|
382
|
+
const moovEnd = offset + size;
|
|
383
|
+
while (moovOffset < moovEnd - 8) {
|
|
384
|
+
const childSize = buffer.readUInt32BE(moovOffset);
|
|
385
|
+
if (childSize < 8 || moovOffset + childSize > moovEnd) {
|
|
386
|
+
if (silent)
|
|
387
|
+
return 0;
|
|
388
|
+
throw new Error('Invalid child atom size');
|
|
389
|
+
}
|
|
390
|
+
const childType = buffer.toString('ascii', moovOffset + 4, moovOffset + 8);
|
|
391
|
+
if (childType === 'mvhd') {
|
|
392
|
+
const version = buffer.readUInt8(moovOffset + 8);
|
|
393
|
+
if (version === 0) {
|
|
394
|
+
const timescale = buffer.readUInt32BE(moovOffset + 20);
|
|
395
|
+
const duration = buffer.readUInt32BE(moovOffset + 24);
|
|
396
|
+
if (!timescale) {
|
|
397
|
+
if (silent)
|
|
398
|
+
return 0;
|
|
399
|
+
throw new Error('Invalid timescale');
|
|
400
|
+
}
|
|
401
|
+
return duration / timescale;
|
|
402
|
+
}
|
|
403
|
+
if (version === 1) {
|
|
404
|
+
const timescale = buffer.readUInt32BE(moovOffset + 32);
|
|
405
|
+
const duration = Number(buffer.readBigUInt64BE(moovOffset + 36));
|
|
406
|
+
if (!timescale) {
|
|
407
|
+
if (silent)
|
|
408
|
+
return 0;
|
|
409
|
+
throw new Error('Invalid timescale');
|
|
410
|
+
}
|
|
411
|
+
return duration / timescale;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
moovOffset += childSize;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
offset += size;
|
|
418
|
+
}
|
|
419
|
+
if (silent)
|
|
420
|
+
return 0;
|
|
421
|
+
throw new Error('No mvhd found!');
|
|
422
|
+
}
|
|
423
|
+
catch (err) {
|
|
424
|
+
if (silent)
|
|
425
|
+
return 0;
|
|
426
|
+
throw err;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
static getMp4Preview(videoBuffer, { time, result = 'buffer', resize = true, width = 300, height = 300, silent = true } = {}) {
|
|
430
|
+
return new Promise((resolve, reject) => {
|
|
431
|
+
const fail = (err) => {
|
|
432
|
+
if (silent) {
|
|
433
|
+
return resolve(result === 'base64' ? '' : Buffer.alloc(0));
|
|
434
|
+
}
|
|
435
|
+
return reject(err);
|
|
436
|
+
};
|
|
437
|
+
try {
|
|
438
|
+
if (!Buffer.isBuffer(videoBuffer) || !videoBuffer.length) {
|
|
439
|
+
return fail(new Error('videoBuffer tidak valid atau kosong'));
|
|
440
|
+
}
|
|
441
|
+
const inputStream = new stream_1.Readable({ read() { } });
|
|
442
|
+
inputStream.push(videoBuffer);
|
|
443
|
+
inputStream.push(null);
|
|
444
|
+
const outputStream = new stream_1.PassThrough();
|
|
445
|
+
const chunks = [];
|
|
446
|
+
outputStream.on('data', (chunk) => chunks.push(chunk));
|
|
447
|
+
outputStream.on('end', async () => {
|
|
448
|
+
try {
|
|
449
|
+
let output = Buffer.concat(chunks);
|
|
450
|
+
if (!output.length) {
|
|
451
|
+
return fail(new Error('Output kosong — cek format atau timestamp video'));
|
|
452
|
+
}
|
|
453
|
+
if (resize) {
|
|
454
|
+
output = await Toolkit.resize(output, width, height);
|
|
455
|
+
}
|
|
456
|
+
return resolve(result === 'base64' ? output.toString('base64') : output);
|
|
457
|
+
}
|
|
458
|
+
catch (err) {
|
|
459
|
+
return fail(err);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
outputStream.on('error', fail);
|
|
463
|
+
time ??= Math.min(Toolkit.getMp4Duration(videoBuffer) * 0.2, 10);
|
|
464
|
+
getFfmpeg()
|
|
465
|
+
.then((ffmpeg) => {
|
|
466
|
+
ffmpeg(inputStream)
|
|
467
|
+
.outputOptions([`-ss ${time}`, '-vframes 1', '-vcodec png', '-f image2pipe'])
|
|
468
|
+
.on('error', (err) => fail(new Error(`ffmpeg error: ${err.message}`)))
|
|
469
|
+
.pipe(outputStream, { end: true });
|
|
470
|
+
})
|
|
471
|
+
.catch(fail);
|
|
472
|
+
}
|
|
473
|
+
catch (err) {
|
|
474
|
+
return fail(err);
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
exports.Toolkit = Toolkit;
|
|
480
|
+
class BaseBuilder {
|
|
481
|
+
constructor() {
|
|
482
|
+
this._title = '';
|
|
483
|
+
this._subtitle = '';
|
|
484
|
+
this._body = '';
|
|
485
|
+
this._footer = '';
|
|
486
|
+
this._contextInfo = {};
|
|
487
|
+
this._extraPayload = {};
|
|
488
|
+
}
|
|
489
|
+
setTitle(title) {
|
|
490
|
+
if (typeof title !== 'string') {
|
|
491
|
+
throw new TypeError('Title must be a string');
|
|
492
|
+
}
|
|
493
|
+
this._title = title;
|
|
494
|
+
return this;
|
|
495
|
+
}
|
|
496
|
+
setSubtitle(subtitle) {
|
|
497
|
+
if (typeof subtitle !== 'string') {
|
|
498
|
+
throw new TypeError('Subtitle must be a string');
|
|
499
|
+
}
|
|
500
|
+
this._subtitle = subtitle;
|
|
501
|
+
return this;
|
|
502
|
+
}
|
|
503
|
+
setBody(body) {
|
|
504
|
+
if (typeof body !== 'string') {
|
|
505
|
+
throw new TypeError('Body must be a string');
|
|
506
|
+
}
|
|
507
|
+
this._body = body;
|
|
508
|
+
return this;
|
|
509
|
+
}
|
|
510
|
+
setFooter(footer) {
|
|
511
|
+
if (typeof footer !== 'string') {
|
|
512
|
+
throw new TypeError('Footer must be a string');
|
|
513
|
+
}
|
|
514
|
+
this._footer = footer;
|
|
515
|
+
return this;
|
|
516
|
+
}
|
|
517
|
+
setContextInfo(obj) {
|
|
518
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
519
|
+
throw new TypeError('ContextInfo must be a plain object');
|
|
520
|
+
}
|
|
521
|
+
this._contextInfo = obj;
|
|
522
|
+
return this;
|
|
523
|
+
}
|
|
524
|
+
addPayload(obj) {
|
|
525
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
526
|
+
throw new TypeError('Payload must be a plain object');
|
|
527
|
+
}
|
|
528
|
+
Object.assign(this._extraPayload, obj);
|
|
529
|
+
return this;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
class Button extends BaseBuilder {
|
|
533
|
+
constructor(client) {
|
|
534
|
+
super();
|
|
535
|
+
_Button_client.set(this, void 0);
|
|
536
|
+
if (!client) {
|
|
537
|
+
throw new Error('Socket is required');
|
|
538
|
+
}
|
|
539
|
+
__classPrivateFieldSet(this, _Button_client, client, "f");
|
|
540
|
+
this._buttons = [];
|
|
541
|
+
this._data;
|
|
542
|
+
this._currentSelectionIndex = -1;
|
|
543
|
+
this._currentSectionIndex = -1;
|
|
544
|
+
this._params = {};
|
|
545
|
+
}
|
|
546
|
+
setVideo(path, options = {}) {
|
|
547
|
+
if (!path)
|
|
548
|
+
throw new Error('Url or buffer needed');
|
|
549
|
+
Buffer.isBuffer(path) ? (this._data = { video: path, ...options }) : (this._data = { video: { url: path }, ...options });
|
|
550
|
+
return this;
|
|
551
|
+
}
|
|
552
|
+
setImage(path, options = {}) {
|
|
553
|
+
if (!path)
|
|
554
|
+
throw new Error('Url or buffer needed');
|
|
555
|
+
Buffer.isBuffer(path) ? (this._data = { image: path, ...options }) : (this._data = { image: { url: path }, ...options });
|
|
556
|
+
return this;
|
|
557
|
+
}
|
|
558
|
+
setDocument(path, options = {}) {
|
|
559
|
+
if (!path)
|
|
560
|
+
throw new Error('Url or buffer needed');
|
|
561
|
+
Buffer.isBuffer(path) ? (this._data = { document: path, ...options }) : (this._data = { document: { url: path }, ...options });
|
|
562
|
+
return this;
|
|
563
|
+
}
|
|
564
|
+
setMedia(obj) {
|
|
565
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
566
|
+
throw new TypeError('Media must be a plain object');
|
|
567
|
+
}
|
|
568
|
+
this._data = obj;
|
|
569
|
+
return this;
|
|
570
|
+
}
|
|
571
|
+
clearButtons() {
|
|
572
|
+
this._buttons = [];
|
|
573
|
+
return this;
|
|
574
|
+
}
|
|
575
|
+
setParams(obj) {
|
|
576
|
+
this._params = obj;
|
|
577
|
+
return this;
|
|
578
|
+
}
|
|
579
|
+
addButton(name, params) {
|
|
580
|
+
this._buttons.push({
|
|
581
|
+
name,
|
|
582
|
+
buttonParamsJson: typeof params === 'string' ? params : JSON.stringify(params),
|
|
583
|
+
});
|
|
584
|
+
return this;
|
|
585
|
+
}
|
|
586
|
+
makeRow(header = '', title = '', description = '', id = '') {
|
|
587
|
+
if (this._currentSelectionIndex === -1 || this._currentSectionIndex === -1) {
|
|
588
|
+
throw new Error('You need to create a selection and a section first');
|
|
589
|
+
}
|
|
590
|
+
const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
|
|
591
|
+
buttonParams.sections[this._currentSectionIndex].rows.push({ header, title, description, id });
|
|
592
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
|
|
593
|
+
return this;
|
|
594
|
+
}
|
|
595
|
+
makeSection(title = '', highlight_label = '') {
|
|
596
|
+
if (this._currentSelectionIndex === -1) {
|
|
597
|
+
throw new Error('You need to create a selection first');
|
|
598
|
+
}
|
|
599
|
+
const buttonParams = JSON.parse(this._buttons[this._currentSelectionIndex].buttonParamsJson);
|
|
600
|
+
buttonParams.sections.push({ title, highlight_label, rows: [] });
|
|
601
|
+
this._currentSectionIndex = buttonParams.sections.length - 1;
|
|
602
|
+
this._buttons[this._currentSelectionIndex].buttonParamsJson = JSON.stringify(buttonParams);
|
|
603
|
+
return this;
|
|
604
|
+
}
|
|
605
|
+
addSelection(title, options = {}) {
|
|
606
|
+
this._buttons.push({ ...options, name: 'single_select', buttonParamsJson: JSON.stringify({ title, sections: [] }) });
|
|
607
|
+
this._currentSelectionIndex = this._buttons.length - 1;
|
|
608
|
+
this._currentSectionIndex = -1;
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
addReply(display_text = '', id = '', options = {}) {
|
|
612
|
+
this._buttons.push({
|
|
613
|
+
name: 'quick_reply',
|
|
614
|
+
buttonParamsJson: JSON.stringify({
|
|
615
|
+
display_text,
|
|
616
|
+
id,
|
|
617
|
+
...options,
|
|
618
|
+
}),
|
|
619
|
+
});
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
addCall(display_text = '', id = '', options = {}) {
|
|
623
|
+
this._buttons.push({
|
|
624
|
+
name: 'cta_call',
|
|
625
|
+
buttonParamsJson: JSON.stringify({
|
|
626
|
+
display_text,
|
|
627
|
+
id,
|
|
628
|
+
...options,
|
|
629
|
+
}),
|
|
630
|
+
});
|
|
631
|
+
return this;
|
|
632
|
+
}
|
|
633
|
+
addReminder(display_text = '', id = '', options = {}) {
|
|
634
|
+
this._buttons.push({
|
|
635
|
+
name: 'cta_reminder',
|
|
636
|
+
buttonParamsJson: JSON.stringify({
|
|
637
|
+
display_text,
|
|
638
|
+
id,
|
|
639
|
+
...options,
|
|
640
|
+
}),
|
|
641
|
+
});
|
|
642
|
+
return this;
|
|
643
|
+
}
|
|
644
|
+
addCancelReminder(display_text = '', id = '', options = {}) {
|
|
645
|
+
this._buttons.push({
|
|
646
|
+
name: 'cta_cancel_reminder',
|
|
647
|
+
buttonParamsJson: JSON.stringify({
|
|
648
|
+
display_text,
|
|
649
|
+
id,
|
|
650
|
+
...options,
|
|
651
|
+
}),
|
|
652
|
+
});
|
|
653
|
+
return this;
|
|
654
|
+
}
|
|
655
|
+
addAddress(display_text = '', id = '', options = {}) {
|
|
656
|
+
this._buttons.push({
|
|
657
|
+
name: 'address_message',
|
|
658
|
+
buttonParamsJson: JSON.stringify({
|
|
659
|
+
display_text,
|
|
660
|
+
id,
|
|
661
|
+
...options,
|
|
662
|
+
}),
|
|
663
|
+
});
|
|
664
|
+
return this;
|
|
665
|
+
}
|
|
666
|
+
addLocation(options = {}) {
|
|
667
|
+
this._buttons.push({
|
|
668
|
+
name: 'send_location',
|
|
669
|
+
buttonParamsJson: JSON.stringify(options),
|
|
670
|
+
});
|
|
671
|
+
return this;
|
|
672
|
+
}
|
|
673
|
+
addUrl(display_text = '', url = '', webview_interaction = false, options = {}) {
|
|
674
|
+
this._buttons.push({
|
|
675
|
+
...options,
|
|
676
|
+
name: 'cta_url',
|
|
677
|
+
buttonParamsJson: JSON.stringify({
|
|
678
|
+
display_text,
|
|
679
|
+
url,
|
|
680
|
+
webview_interaction,
|
|
681
|
+
...options,
|
|
682
|
+
}),
|
|
683
|
+
});
|
|
684
|
+
return this;
|
|
685
|
+
}
|
|
686
|
+
addCopy(display_text = '', copy_code = '', options = {}) {
|
|
687
|
+
this._buttons.push({
|
|
688
|
+
name: 'cta_copy',
|
|
689
|
+
buttonParamsJson: JSON.stringify({
|
|
690
|
+
display_text,
|
|
691
|
+
copy_code,
|
|
692
|
+
...options,
|
|
693
|
+
}),
|
|
694
|
+
});
|
|
695
|
+
return this;
|
|
696
|
+
}
|
|
697
|
+
setLimitedTimeOffer({ text = '', url = '', copy_code = '', expiration_time } = {}) {
|
|
698
|
+
const data = { text, url, copy_code, expiration_time };
|
|
699
|
+
__classPrivateFieldGet(_a, _a, "m", _Button_validateAgainstSchema).call(_a, _a.paramsList.limited_time_offer, data, 'limited_time_offer');
|
|
700
|
+
this._params = { ...this._params, limited_time_offer: data };
|
|
701
|
+
return this;
|
|
702
|
+
}
|
|
703
|
+
setBottomSheet({ in_thread_buttons_limit, divider_indices = [], list_title = '', button_title = '' } = {}) {
|
|
704
|
+
const data = { in_thread_buttons_limit, divider_indices, list_title, button_title };
|
|
705
|
+
__classPrivateFieldGet(_a, _a, "m", _Button_validateAgainstSchema).call(_a, _a.paramsList.bottom_sheet, data, 'bottom_sheet');
|
|
706
|
+
this._params = { ...this._params, bottom_sheet: data };
|
|
707
|
+
return this;
|
|
708
|
+
}
|
|
709
|
+
setTapTargetConfiguration({ title = '', description = '', canonical_url = '', domain = '', buttonIndex = 0 } = {}) {
|
|
710
|
+
const data = { title, description, canonical_url, domain, buttonIndex };
|
|
711
|
+
__classPrivateFieldGet(_a, _a, "m", _Button_validateAgainstSchema).call(_a, _a.paramsList.tap_target_configuration, data, 'tap_target_configuration');
|
|
712
|
+
this._params = { ...this._params, tap_target_configuration: data };
|
|
713
|
+
return this;
|
|
714
|
+
}
|
|
715
|
+
async toCard() {
|
|
716
|
+
return {
|
|
717
|
+
body: {
|
|
718
|
+
text: this._body,
|
|
719
|
+
},
|
|
720
|
+
footer: {
|
|
721
|
+
text: this._footer,
|
|
722
|
+
},
|
|
723
|
+
header: {
|
|
724
|
+
title: this._title,
|
|
725
|
+
subtitle: this._subtitle,
|
|
726
|
+
hasMediaAttachment: !!this._data,
|
|
727
|
+
...(this._data
|
|
728
|
+
? await (0, messages_js_1.prepareWAMessageMedia)(this._data, { upload: __classPrivateFieldGet(this, _Button_client, "f").waUploadToServer }).catch((e) => {
|
|
729
|
+
if (String(e).includes('Invalid media type'))
|
|
730
|
+
return this._data;
|
|
731
|
+
throw e;
|
|
732
|
+
})
|
|
733
|
+
: {}),
|
|
734
|
+
},
|
|
735
|
+
nativeFlowMessage: {
|
|
736
|
+
messageParamsJson: JSON.stringify(this._params),
|
|
737
|
+
buttons: this._buttons,
|
|
738
|
+
},
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
async build(jid, { ...options } = {}) {
|
|
742
|
+
const message = await this.toCard();
|
|
743
|
+
return (0, messages_js_1.generateWAMessageFromContent)(jid, {
|
|
744
|
+
...this._extraPayload,
|
|
745
|
+
interactiveMessage: {
|
|
746
|
+
...message,
|
|
747
|
+
contextInfo: this._contextInfo,
|
|
748
|
+
},
|
|
749
|
+
}, { ...options });
|
|
750
|
+
}
|
|
751
|
+
async send(jid, { ...options } = {}) {
|
|
752
|
+
const msg = await this.build(jid, options);
|
|
753
|
+
await __classPrivateFieldGet(this, _Button_client, "f").relayMessage(msg.key.remoteJid, msg.message, {
|
|
754
|
+
messageId: msg.key.id,
|
|
755
|
+
additionalNodes: [
|
|
756
|
+
{
|
|
757
|
+
tag: 'biz',
|
|
758
|
+
attrs: {},
|
|
759
|
+
content: [
|
|
760
|
+
{
|
|
761
|
+
tag: 'interactive',
|
|
762
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
763
|
+
content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
|
|
764
|
+
},
|
|
765
|
+
],
|
|
766
|
+
},
|
|
767
|
+
],
|
|
768
|
+
...options,
|
|
769
|
+
});
|
|
770
|
+
return msg;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
exports.Button = Button;
|
|
774
|
+
_a = Button, _Button_client = new WeakMap(), _Button_validateAgainstSchema = function _Button_validateAgainstSchema(schema, data, label) {
|
|
775
|
+
for (const [key, type] of Object.entries(schema)) {
|
|
776
|
+
if (data[key] === undefined)
|
|
777
|
+
continue;
|
|
778
|
+
const expectsArray = Array.isArray(type);
|
|
779
|
+
if (expectsArray) {
|
|
780
|
+
if (!Array.isArray(data[key]) || !data[key].every((v) => typeof v === type[0])) {
|
|
781
|
+
throw new TypeError(`${label}.${key} must be an array of ${type[0]}`);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
else if (typeof data[key] !== type) {
|
|
785
|
+
throw new TypeError(`${label}.${key} must be a ${type}`);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
Button.paramsList = {
|
|
790
|
+
limited_time_offer: {
|
|
791
|
+
text: 'string',
|
|
792
|
+
url: 'string',
|
|
793
|
+
copy_code: 'string',
|
|
794
|
+
expiration_time: 'number',
|
|
795
|
+
},
|
|
796
|
+
bottom_sheet: {
|
|
797
|
+
in_thread_buttons_limit: 'number',
|
|
798
|
+
divider_indices: ['number'],
|
|
799
|
+
list_title: 'string',
|
|
800
|
+
button_title: 'string',
|
|
801
|
+
},
|
|
802
|
+
tap_target_configuration: {
|
|
803
|
+
title: 'string',
|
|
804
|
+
description: 'string',
|
|
805
|
+
canonical_url: 'string',
|
|
806
|
+
domain: 'string',
|
|
807
|
+
buttonIndex: 'number',
|
|
808
|
+
},
|
|
809
|
+
};
|
|
810
|
+
class ButtonV2 extends BaseBuilder {
|
|
811
|
+
constructor(client) {
|
|
812
|
+
super();
|
|
813
|
+
_ButtonV2_client.set(this, void 0);
|
|
814
|
+
if (!client) {
|
|
815
|
+
throw new Error('Socket is required');
|
|
816
|
+
}
|
|
817
|
+
__classPrivateFieldSet(this, _ButtonV2_client, client, "f");
|
|
818
|
+
this._image;
|
|
819
|
+
this._data;
|
|
820
|
+
this._buttons = [];
|
|
821
|
+
}
|
|
822
|
+
addButton(displayText = '', buttonId = crypto_1.default.randomUUID()) {
|
|
823
|
+
this._buttons.push({
|
|
824
|
+
buttonId,
|
|
825
|
+
buttonText: { displayText },
|
|
826
|
+
type: 1,
|
|
827
|
+
});
|
|
828
|
+
return this;
|
|
829
|
+
}
|
|
830
|
+
addRawButton(obj) {
|
|
831
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
832
|
+
throw new TypeError('Buttons must be a plain object');
|
|
833
|
+
}
|
|
834
|
+
this._buttons.push(obj);
|
|
835
|
+
return this;
|
|
836
|
+
}
|
|
837
|
+
setThumbnail(path) {
|
|
838
|
+
if (!path)
|
|
839
|
+
throw new Error('Url or buffer needed');
|
|
840
|
+
this._image = path;
|
|
841
|
+
return this;
|
|
842
|
+
}
|
|
843
|
+
setMedia(obj) {
|
|
844
|
+
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
|
|
845
|
+
throw new TypeError('Media must be a plain object');
|
|
846
|
+
}
|
|
847
|
+
this._data = obj;
|
|
848
|
+
return this;
|
|
849
|
+
}
|
|
850
|
+
async build(jid, { ...options } = {}) {
|
|
851
|
+
let _thumbnail = this._image ? await Toolkit.resize(Buffer.isBuffer(this._image) ? this._image : await Toolkit.fetchBuffer(this._image, {}, { silent: true }), 300, 300) : null;
|
|
852
|
+
const msg = (0, messages_js_1.generateWAMessageFromContent)(jid, {
|
|
853
|
+
...this._extraPayload,
|
|
854
|
+
buttonsMessage: {
|
|
855
|
+
contentText: this._body,
|
|
856
|
+
footerText: this._footer,
|
|
857
|
+
...(this._data
|
|
858
|
+
? this._data
|
|
859
|
+
: {
|
|
860
|
+
headerType: 6,
|
|
861
|
+
locationMessage: {
|
|
862
|
+
degreesLatitude: 0,
|
|
863
|
+
degreesLongitude: 0,
|
|
864
|
+
name: this._title,
|
|
865
|
+
address: this._subtitle,
|
|
866
|
+
jpegThumbnail: _thumbnail,
|
|
867
|
+
},
|
|
868
|
+
}),
|
|
869
|
+
viewOnce: true,
|
|
870
|
+
contextInfo: this._contextInfo,
|
|
871
|
+
buttons: [...this._buttons],
|
|
872
|
+
},
|
|
873
|
+
}, { ...options });
|
|
874
|
+
return msg;
|
|
875
|
+
}
|
|
876
|
+
async send(jid, { ...options } = {}) {
|
|
877
|
+
if (this._buttons.length < 1)
|
|
878
|
+
throw new Error('ButtonV2 requires at least one button');
|
|
879
|
+
const msg = await this.build(jid, options);
|
|
880
|
+
await __classPrivateFieldGet(this, _ButtonV2_client, "f").relayMessage(msg.key.remoteJid, msg.message, {
|
|
881
|
+
messageId: msg.key.id,
|
|
882
|
+
additionalNodes: [
|
|
883
|
+
{
|
|
884
|
+
tag: 'biz',
|
|
885
|
+
attrs: {},
|
|
886
|
+
content: [
|
|
887
|
+
{
|
|
888
|
+
tag: 'interactive',
|
|
889
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
890
|
+
content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
|
|
891
|
+
},
|
|
892
|
+
],
|
|
893
|
+
},
|
|
894
|
+
],
|
|
895
|
+
...options,
|
|
896
|
+
});
|
|
897
|
+
return msg;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
exports.ButtonV2 = ButtonV2;
|
|
901
|
+
_ButtonV2_client = new WeakMap();
|
|
902
|
+
class Carousel extends BaseBuilder {
|
|
903
|
+
constructor(client) {
|
|
904
|
+
super();
|
|
905
|
+
_Carousel_client.set(this, void 0);
|
|
906
|
+
if (!client) {
|
|
907
|
+
throw new Error('Socket is required');
|
|
908
|
+
}
|
|
909
|
+
__classPrivateFieldSet(this, _Carousel_client, client, "f");
|
|
910
|
+
this._cards = [];
|
|
911
|
+
}
|
|
912
|
+
addCard(card) {
|
|
913
|
+
const cards = Array.isArray(card) ? card : [card];
|
|
914
|
+
const baseIndex = this._cards.length;
|
|
915
|
+
for (const [index, c] of cards.entries()) {
|
|
916
|
+
if (!c?.header?.hasMediaAttachment) {
|
|
917
|
+
throw new Error(`Card [${baseIndex + index}] must include an image or video in header`);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
this._cards.push(...cards);
|
|
921
|
+
return this;
|
|
922
|
+
}
|
|
923
|
+
build(jid, { ...options } = {}) {
|
|
924
|
+
return (0, messages_js_1.generateWAMessageFromContent)(jid, {
|
|
925
|
+
...this._extraPayload,
|
|
926
|
+
interactiveMessage: {
|
|
927
|
+
header: {
|
|
928
|
+
hasMediaAttachment: false,
|
|
929
|
+
},
|
|
930
|
+
body: { text: this._body },
|
|
931
|
+
footer: { text: this._footer },
|
|
932
|
+
contextInfo: this._contextInfo,
|
|
933
|
+
carouselMessage: {
|
|
934
|
+
cards: this._cards,
|
|
935
|
+
},
|
|
936
|
+
},
|
|
937
|
+
}, { ...options });
|
|
938
|
+
}
|
|
939
|
+
async send(jid, { ...options } = {}) {
|
|
940
|
+
const msg = this.build(jid, options);
|
|
941
|
+
await __classPrivateFieldGet(this, _Carousel_client, "f").relayMessage(msg.key.remoteJid, msg.message, {
|
|
942
|
+
messageId: msg.key.id,
|
|
943
|
+
additionalNodes: [
|
|
944
|
+
{
|
|
945
|
+
tag: 'biz',
|
|
946
|
+
attrs: {},
|
|
947
|
+
content: [
|
|
948
|
+
{
|
|
949
|
+
tag: 'interactive',
|
|
950
|
+
attrs: { type: 'native_flow', v: '1' },
|
|
951
|
+
content: [{ tag: 'native_flow', attrs: { v: '9', name: 'mixed' } }],
|
|
952
|
+
},
|
|
953
|
+
],
|
|
954
|
+
},
|
|
955
|
+
],
|
|
956
|
+
...options,
|
|
957
|
+
});
|
|
958
|
+
return msg;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
exports.Carousel = Carousel;
|
|
962
|
+
_Carousel_client = new WeakMap();
|
|
963
|
+
class AIRich extends BaseBuilder {
|
|
964
|
+
constructor(client) {
|
|
965
|
+
if (!client) {
|
|
966
|
+
throw new Error('Socket is required');
|
|
967
|
+
}
|
|
968
|
+
super();
|
|
969
|
+
_AIRich_client.set(this, void 0);
|
|
970
|
+
__classPrivateFieldSet(this, _AIRich_client, client, "f");
|
|
971
|
+
this._contextInfo = {};
|
|
972
|
+
this._submessages = [];
|
|
973
|
+
this._sections = [];
|
|
974
|
+
this._richResponseSources = [];
|
|
975
|
+
// Vanz@Fix (bug 42 / inline image fallback): WA rejects rendering AIRichResponseInlineImageMetadata
|
|
976
|
+
// for third-party bots regardless of URL (confirmed empirically — Meta/WA CDN url with valid
|
|
977
|
+
// mediaKey still doesn't render, so it's a trust-chain gate, not a domain/encoding issue).
|
|
978
|
+
// Track every addInlineImage() call here so send() can fall back to a normal imageMessage.
|
|
979
|
+
this._inlineImages = [];
|
|
980
|
+
}
|
|
981
|
+
addSubmessage(submessage) {
|
|
982
|
+
const items = Array.isArray(submessage) ? submessage : [submessage];
|
|
983
|
+
for (const item of items) {
|
|
984
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item)) {
|
|
985
|
+
throw new TypeError('Submessage must be a plain object or array of plain objects');
|
|
986
|
+
}
|
|
987
|
+
this._submessages.push(item);
|
|
988
|
+
}
|
|
989
|
+
return this;
|
|
990
|
+
}
|
|
991
|
+
addSection(section) {
|
|
992
|
+
const items = Array.isArray(section) ? section : [section];
|
|
993
|
+
for (const item of items) {
|
|
994
|
+
if (typeof item !== 'object' || item === null || Array.isArray(item)) {
|
|
995
|
+
throw new TypeError('Section must be a plain object or array of plain objects');
|
|
996
|
+
}
|
|
997
|
+
this._sections.push(item);
|
|
998
|
+
}
|
|
999
|
+
return this;
|
|
1000
|
+
}
|
|
1001
|
+
addText(text, { hyperlink = true, citation = true, latex = true } = {}) {
|
|
1002
|
+
if (typeof text != 'string') {
|
|
1003
|
+
throw new TypeError('Text must be a string');
|
|
1004
|
+
}
|
|
1005
|
+
const { text: extractedText, inline_entities } = extractIE(text, {
|
|
1006
|
+
hyperlink,
|
|
1007
|
+
citation,
|
|
1008
|
+
latex,
|
|
1009
|
+
});
|
|
1010
|
+
this._submessages.push({
|
|
1011
|
+
messageType: 2,
|
|
1012
|
+
messageText: extractedText,
|
|
1013
|
+
});
|
|
1014
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1015
|
+
text: extractedText,
|
|
1016
|
+
...(inline_entities.length && {
|
|
1017
|
+
inline_entities,
|
|
1018
|
+
}),
|
|
1019
|
+
__typename: 'GenAIMarkdownTextUXPrimitive',
|
|
1020
|
+
}));
|
|
1021
|
+
return this;
|
|
1022
|
+
}
|
|
1023
|
+
addCode(language, code) {
|
|
1024
|
+
if (typeof language !== 'string' || typeof code !== 'string') {
|
|
1025
|
+
throw new TypeError('Language and code must be a string');
|
|
1026
|
+
}
|
|
1027
|
+
const meta = AIRich.tokenizer(code, language);
|
|
1028
|
+
this._submessages.push({
|
|
1029
|
+
messageType: 5,
|
|
1030
|
+
codeMetadata: {
|
|
1031
|
+
codeLanguage: language,
|
|
1032
|
+
codeBlocks: meta.codeBlock,
|
|
1033
|
+
},
|
|
1034
|
+
});
|
|
1035
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1036
|
+
language,
|
|
1037
|
+
code_blocks: meta.unified_codeBlock,
|
|
1038
|
+
__typename: 'GenAICodeUXPrimitive',
|
|
1039
|
+
}));
|
|
1040
|
+
return this;
|
|
1041
|
+
}
|
|
1042
|
+
addTable(table, { hyperlink = true, citation = true, latex = true } = {}) {
|
|
1043
|
+
if (!Array.isArray(table)) {
|
|
1044
|
+
throw new TypeError('Table must be an array');
|
|
1045
|
+
}
|
|
1046
|
+
const meta = AIRich.toTableMetadata(table, { hyperlink, citation, latex });
|
|
1047
|
+
this._submessages.push({
|
|
1048
|
+
messageType: 4,
|
|
1049
|
+
tableMetadata: {
|
|
1050
|
+
title: meta.title,
|
|
1051
|
+
rows: meta.rows,
|
|
1052
|
+
},
|
|
1053
|
+
});
|
|
1054
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1055
|
+
rows: meta.unified_rows,
|
|
1056
|
+
__typename: 'GenATableUXPrimitive',
|
|
1057
|
+
}));
|
|
1058
|
+
return this;
|
|
1059
|
+
}
|
|
1060
|
+
addSource(sources = []) {
|
|
1061
|
+
if (!(Array.isArray(sources) && (sources.every((item) => typeof item === 'string') || sources.every((item) => Array.isArray(item) && item.every((v) => typeof v === 'string'))))) {
|
|
1062
|
+
throw new TypeError('Sources must be a string array or an array of string arrays');
|
|
1063
|
+
}
|
|
1064
|
+
if (sources.every((item) => typeof item === 'string')) {
|
|
1065
|
+
sources = [sources];
|
|
1066
|
+
}
|
|
1067
|
+
const source = sources.map(([icon, url, text]) => ({
|
|
1068
|
+
source_type: 'THIRD_PARTY',
|
|
1069
|
+
source_display_name: text ?? '',
|
|
1070
|
+
source_subtitle: 'AI',
|
|
1071
|
+
source_url: url ?? '',
|
|
1072
|
+
favicon: {
|
|
1073
|
+
url: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), icon ?? '', 'image'),
|
|
1074
|
+
mime_type: 'image/jpeg',
|
|
1075
|
+
width: 16,
|
|
1076
|
+
height: 16,
|
|
1077
|
+
},
|
|
1078
|
+
}));
|
|
1079
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1080
|
+
sources: source,
|
|
1081
|
+
__typename: 'GenAISearchResultPrimitive',
|
|
1082
|
+
}));
|
|
1083
|
+
return this;
|
|
1084
|
+
}
|
|
1085
|
+
addReels(reelsItems = []) {
|
|
1086
|
+
if (!((reelsItems && typeof reelsItems === 'object' && !Array.isArray(reelsItems)) ||
|
|
1087
|
+
(Array.isArray(reelsItems) && reelsItems.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
|
|
1088
|
+
throw new TypeError('Reels items must be an object or an array of objects');
|
|
1089
|
+
}
|
|
1090
|
+
if (!Array.isArray(reelsItems)) {
|
|
1091
|
+
reelsItems = [reelsItems];
|
|
1092
|
+
}
|
|
1093
|
+
const reels = reelsItems.map((item) => ({
|
|
1094
|
+
...item,
|
|
1095
|
+
_avatar: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item.profileIconUrl ?? item.profile_url ?? item.profile ?? '', 'image'),
|
|
1096
|
+
_thumbnail: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item.thumbnailUrl ?? item.thumbnail ?? '', 'image'),
|
|
1097
|
+
}));
|
|
1098
|
+
this._submessages.push({
|
|
1099
|
+
messageType: 9,
|
|
1100
|
+
contentItemsMetadata: {
|
|
1101
|
+
contentType: 1,
|
|
1102
|
+
itemsMetadata: reels.map((item) => ({
|
|
1103
|
+
reelItem: {
|
|
1104
|
+
title: item.username ?? '',
|
|
1105
|
+
profileIconUrl: item._avatar,
|
|
1106
|
+
thumbnailUrl: item._thumbnail,
|
|
1107
|
+
videoUrl: item.videoUrl ?? item.url ?? '',
|
|
1108
|
+
},
|
|
1109
|
+
})),
|
|
1110
|
+
},
|
|
1111
|
+
});
|
|
1112
|
+
reels.forEach((item, idx) => {
|
|
1113
|
+
this._richResponseSources.push({
|
|
1114
|
+
provider: 'Evernight AI',
|
|
1115
|
+
thumbnailCDNURL: item._thumbnail,
|
|
1116
|
+
sourceProviderURL: item.videoUrl ?? item.url ?? '',
|
|
1117
|
+
sourceQuery: '',
|
|
1118
|
+
faviconCDNURL: item._avatar,
|
|
1119
|
+
citationNumber: idx + 1,
|
|
1120
|
+
sourceTitle: item.username ?? '',
|
|
1121
|
+
});
|
|
1122
|
+
});
|
|
1123
|
+
this._sections.push(AIRich.newLayout('HScroll', reels.map((item) => ({
|
|
1124
|
+
reels_url: item.videoUrl ?? item.url ?? '',
|
|
1125
|
+
thumbnail_url: item._thumbnail,
|
|
1126
|
+
creator: item.username ?? item.title ?? '',
|
|
1127
|
+
avatar_url: item._avatar,
|
|
1128
|
+
reels_title: item.reels_title ?? item.title ?? '',
|
|
1129
|
+
likes_count: item.likes_count ?? item.like ?? 0,
|
|
1130
|
+
shares_count: item.shares_count ?? item.share ?? 0,
|
|
1131
|
+
view_count: item.view_count ?? item.view ?? 0,
|
|
1132
|
+
reel_source: item.reel_source ?? item.source ?? 'IG',
|
|
1133
|
+
is_verified: !!(item.is_verified || item.verified),
|
|
1134
|
+
__typename: 'GenAIReelPrimitive',
|
|
1135
|
+
}))));
|
|
1136
|
+
return this;
|
|
1137
|
+
}
|
|
1138
|
+
addImage(imageUrl, { resolveUrl = false } = {}) {
|
|
1139
|
+
if (!(typeof imageUrl === 'string' || Buffer.isBuffer(imageUrl) || (Array.isArray(imageUrl) && imageUrl.every((v) => typeof v === 'string' || Buffer.isBuffer(v))))) {
|
|
1140
|
+
throw new TypeError('imageUrl must be string | buffer | array of string/buffer');
|
|
1141
|
+
}
|
|
1142
|
+
const list = Array.isArray(imageUrl)
|
|
1143
|
+
? imageUrl.map((v) => {
|
|
1144
|
+
const url = Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), v, 'image', { resolveUrl });
|
|
1145
|
+
return {
|
|
1146
|
+
imagePreviewUrl: url,
|
|
1147
|
+
imageHighResUrl: url,
|
|
1148
|
+
sourceUrl: url,
|
|
1149
|
+
};
|
|
1150
|
+
})
|
|
1151
|
+
: (() => {
|
|
1152
|
+
const url = Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), imageUrl, 'image', { resolveUrl });
|
|
1153
|
+
return [
|
|
1154
|
+
{
|
|
1155
|
+
imagePreviewUrl: url,
|
|
1156
|
+
imageHighResUrl: url,
|
|
1157
|
+
sourceUrl: url,
|
|
1158
|
+
},
|
|
1159
|
+
];
|
|
1160
|
+
})();
|
|
1161
|
+
this._submessages.push({
|
|
1162
|
+
messageType: 1,
|
|
1163
|
+
gridImageMetadata: {
|
|
1164
|
+
gridImageUrl: {
|
|
1165
|
+
imagePreviewUrl: list[0]?.imagePreviewUrl,
|
|
1166
|
+
},
|
|
1167
|
+
imageUrls: list,
|
|
1168
|
+
},
|
|
1169
|
+
});
|
|
1170
|
+
list.forEach(({ imagePreviewUrl }) => {
|
|
1171
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1172
|
+
media: {
|
|
1173
|
+
url: imagePreviewUrl,
|
|
1174
|
+
mime_type: 'image/png',
|
|
1175
|
+
},
|
|
1176
|
+
imagine_type: 'IMAGE',
|
|
1177
|
+
status: { status: 'READY' },
|
|
1178
|
+
__typename: 'GenAIImaginePrimitive',
|
|
1179
|
+
}));
|
|
1180
|
+
});
|
|
1181
|
+
return this;
|
|
1182
|
+
}
|
|
1183
|
+
// Vanz@Fix 15-08-26 (bug 41) --- addImage() only builds GRID_IMAGE (messageType 1).
|
|
1184
|
+
// There was no helper for standalone INLINE_IMAGE (messageType 3): callers were manually
|
|
1185
|
+
// pushing addSubmessage() (correct proto shape) + addSection() (WRONG shape — reused the
|
|
1186
|
+
// GRID_IMAGE/GenAIImaginePrimitive section schema instead of GenAIInlineImageUXPrimitive),
|
|
1187
|
+
// which broke client-side unifiedResponse rendering even though the submessage itself was fine.
|
|
1188
|
+
// Mirrors RichSubMessageType.INLINE_IMAGE handling in rich-message-utils.js's toUnified().
|
|
1189
|
+
addInlineImage(imageUrl, { text = '', alignment = 'center', tapLinkUrl = '', resolveUrl = false } = {}) {
|
|
1190
|
+
if (!(typeof imageUrl === 'string' || Buffer.isBuffer(imageUrl) || (imageUrl && typeof imageUrl === 'object'))) {
|
|
1191
|
+
throw new TypeError('imageUrl must be string | buffer | { imagePreviewUrl, imageHighResUrl, sourceUrl }');
|
|
1192
|
+
}
|
|
1193
|
+
const ALIGNMENT_ENUM = { leading: 0, trailing: 1, center: 2 };
|
|
1194
|
+
const ALIGNMENT_NAME = ['AI_RICH_RESPONSE_IMAGE_LAYOUT_LEADING_ALIGNED', 'AI_RICH_RESPONSE_IMAGE_LAYOUT_TRAILING_ALIGNED', 'AI_RICH_RESPONSE_IMAGE_LAYOUT_CENTER_ALIGNED'];
|
|
1195
|
+
const alignmentNum = typeof alignment === 'number' ? alignment : (ALIGNMENT_ENUM[String(alignment).toLowerCase()] ?? ALIGNMENT_ENUM.center);
|
|
1196
|
+
const url = imageUrl && typeof imageUrl === 'object'
|
|
1197
|
+
? {
|
|
1198
|
+
imagePreviewUrl: imageUrl.imagePreviewUrl || imageUrl.url,
|
|
1199
|
+
imageHighResUrl: imageUrl.imageHighResUrl || imageUrl.url,
|
|
1200
|
+
sourceUrl: imageUrl.sourceUrl || imageUrl.url,
|
|
1201
|
+
}
|
|
1202
|
+
: (() => {
|
|
1203
|
+
const resolved = Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), imageUrl, 'image', { resolveUrl });
|
|
1204
|
+
return { imagePreviewUrl: resolved, imageHighResUrl: resolved, sourceUrl: resolved };
|
|
1205
|
+
})();
|
|
1206
|
+
this._submessages.push({
|
|
1207
|
+
messageType: 3,
|
|
1208
|
+
imageMetadata: {
|
|
1209
|
+
imageUrl: url,
|
|
1210
|
+
imageText: text,
|
|
1211
|
+
alignment: alignmentNum,
|
|
1212
|
+
tapLinkUrl,
|
|
1213
|
+
},
|
|
1214
|
+
});
|
|
1215
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1216
|
+
image_url: {
|
|
1217
|
+
image_preview_url: url.imagePreviewUrl || '',
|
|
1218
|
+
image_high_res_url: url.imageHighResUrl || '',
|
|
1219
|
+
source_url: url.sourceUrl || '',
|
|
1220
|
+
},
|
|
1221
|
+
image_text: text,
|
|
1222
|
+
alignment: ALIGNMENT_NAME[alignmentNum],
|
|
1223
|
+
tap_link_url: tapLinkUrl,
|
|
1224
|
+
__typename: 'GenAIInlineImageUXPrimitive',
|
|
1225
|
+
}));
|
|
1226
|
+
// Vanz@Fix (bug 42): stash for the imageMessage fallback in send()
|
|
1227
|
+
this._inlineImages.push({
|
|
1228
|
+
url: url.sourceUrl || url.imageHighResUrl || url.imagePreviewUrl,
|
|
1229
|
+
caption: text || undefined,
|
|
1230
|
+
});
|
|
1231
|
+
return this;
|
|
1232
|
+
}
|
|
1233
|
+
// Vanz@Perf 15-08-26 --- autoFill defaults to false (arslan-baileys behavior): skips the
|
|
1234
|
+
// fetch-full-video + ffmpeg-frame-extraction + duration-parse round trip per video, which
|
|
1235
|
+
// was the main source of blurose's slower response time. Pass { autoFill: true } to opt
|
|
1236
|
+
// back into the complete/slow path (real thumbnail + duration + file_length).
|
|
1237
|
+
addVideo(videoUrl, { autoFill = false } = {}) {
|
|
1238
|
+
const isObjectVideo = (v) => v && typeof v === 'object' && v.url;
|
|
1239
|
+
const isValidPrimitive = typeof videoUrl === 'string' ||
|
|
1240
|
+
Buffer.isBuffer(videoUrl) ||
|
|
1241
|
+
isObjectVideo(videoUrl) ||
|
|
1242
|
+
(Array.isArray(videoUrl) && videoUrl.every((v) => typeof v === 'string' || Buffer.isBuffer(v) || isObjectVideo(v)));
|
|
1243
|
+
if (!isValidPrimitive) {
|
|
1244
|
+
throw new TypeError('videoUrl must be string | buffer | object | array');
|
|
1245
|
+
}
|
|
1246
|
+
const items = Array.isArray(videoUrl) ? videoUrl : [videoUrl];
|
|
1247
|
+
this._submessages.push({
|
|
1248
|
+
messageType: 2,
|
|
1249
|
+
messageText: '[ Video tidak dapat dimuat ]',
|
|
1250
|
+
});
|
|
1251
|
+
items.forEach((item) => {
|
|
1252
|
+
const isObject = isObjectVideo(item);
|
|
1253
|
+
const url = isObject ? Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item.url ?? '', 'video') : Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item, 'video');
|
|
1254
|
+
const bufferPromise = autoFill ? Promise.resolve(url).then((u) => Toolkit.fetchBuffer(u)) : null;
|
|
1255
|
+
const file_length = isObject && item.file_length != null ? item.file_length : autoFill ? bufferPromise.then((b) => b?.length ?? 0) : 0;
|
|
1256
|
+
const duration = isObject && item.duration != null
|
|
1257
|
+
? item.duration
|
|
1258
|
+
: autoFill
|
|
1259
|
+
? bufferPromise.then((b) => Toolkit.getMp4Duration(b, {
|
|
1260
|
+
silent: true,
|
|
1261
|
+
}))
|
|
1262
|
+
: 0;
|
|
1263
|
+
const thumbnail = isObject && item.thumbnail
|
|
1264
|
+
? Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item.thumbnail, 'image', {
|
|
1265
|
+
result: 'base64',
|
|
1266
|
+
resize: true,
|
|
1267
|
+
width: 300,
|
|
1268
|
+
height: 300,
|
|
1269
|
+
})
|
|
1270
|
+
: autoFill
|
|
1271
|
+
? bufferPromise
|
|
1272
|
+
? bufferPromise.then((b) => Toolkit.getMp4Preview(b, {
|
|
1273
|
+
time: 0,
|
|
1274
|
+
result: 'base64',
|
|
1275
|
+
}))
|
|
1276
|
+
: null
|
|
1277
|
+
: null;
|
|
1278
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1279
|
+
media: {
|
|
1280
|
+
url,
|
|
1281
|
+
mime_type: isObject ? (item.mime_type ?? 'video/mp4') : 'video/mp4',
|
|
1282
|
+
file_length,
|
|
1283
|
+
duration,
|
|
1284
|
+
},
|
|
1285
|
+
imagine_type: 'ANIMATE',
|
|
1286
|
+
status: { status: 'READY' },
|
|
1287
|
+
thumbnail: {
|
|
1288
|
+
raw_media: thumbnail,
|
|
1289
|
+
},
|
|
1290
|
+
__typename: 'GenAIImaginePrimitive',
|
|
1291
|
+
}));
|
|
1292
|
+
});
|
|
1293
|
+
return this;
|
|
1294
|
+
}
|
|
1295
|
+
addProduct(data = {}) {
|
|
1296
|
+
if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
|
|
1297
|
+
throw new TypeError('Product items must be an object or an array of objects');
|
|
1298
|
+
}
|
|
1299
|
+
this._submessages.push({
|
|
1300
|
+
messageType: 2,
|
|
1301
|
+
messageText: '[ Produk tidak dapat dimuat ]',
|
|
1302
|
+
});
|
|
1303
|
+
const items = Array.isArray(data) ? data : [data];
|
|
1304
|
+
const product = items.map((item) => ({
|
|
1305
|
+
title: item.title,
|
|
1306
|
+
brand: item.brand,
|
|
1307
|
+
price: item.price,
|
|
1308
|
+
sale_price: item.sale_price,
|
|
1309
|
+
product_url: item.product_url ?? item.url,
|
|
1310
|
+
image: {
|
|
1311
|
+
url: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item.image_url ?? item.image, 'image'),
|
|
1312
|
+
},
|
|
1313
|
+
additional_images: [
|
|
1314
|
+
{
|
|
1315
|
+
url: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), item.icon_url ?? item.icon, 'image'),
|
|
1316
|
+
},
|
|
1317
|
+
],
|
|
1318
|
+
__typename: 'GenAIProductItemCardPrimitive',
|
|
1319
|
+
}));
|
|
1320
|
+
this._sections.push(AIRich.newLayout(Array.isArray(data) ? 'HScroll' : 'Single', Array.isArray(data) ? product : product[0]));
|
|
1321
|
+
return this;
|
|
1322
|
+
}
|
|
1323
|
+
addPost(data = {}) {
|
|
1324
|
+
if (!((data && typeof data === 'object' && !Array.isArray(data)) || (Array.isArray(data) && data.every((item) => item && typeof item === 'object' && !Array.isArray(item))))) {
|
|
1325
|
+
throw new TypeError('Post items must be an object or an array of objects');
|
|
1326
|
+
}
|
|
1327
|
+
const posts = Array.isArray(data) ? data : [data];
|
|
1328
|
+
this._submessages.push({
|
|
1329
|
+
messageType: 2,
|
|
1330
|
+
messageText: '[ Postingan tidak dapat dimuat ]',
|
|
1331
|
+
});
|
|
1332
|
+
const primitives = posts.map((p) => ({
|
|
1333
|
+
title: p.title ?? '',
|
|
1334
|
+
subtitle: p.subtitle ?? '',
|
|
1335
|
+
username: p.username ?? '',
|
|
1336
|
+
profile_picture_url: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), p.profile_picture_url ?? p.profile_url ?? p.profile ?? '', 'image'),
|
|
1337
|
+
is_verified: !!(p.is_verified || p.verified),
|
|
1338
|
+
thumbnail_url: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), p.thumbnail_url ?? p.thumbnail ?? '', 'image'),
|
|
1339
|
+
post_caption: p.post_caption ?? p.caption ?? '',
|
|
1340
|
+
likes_count: p.likes_count ?? p.like ?? 0,
|
|
1341
|
+
comments_count: p.comments_count ?? p.comment ?? 0,
|
|
1342
|
+
shares_count: p.shares_count ?? p.share ?? 0,
|
|
1343
|
+
post_url: p.post_url ?? p.url ?? '',
|
|
1344
|
+
post_deeplink: p.post_deeplink ?? p.deeplink ?? '',
|
|
1345
|
+
source_app: p.source_app || p.source || 'INSTAGRAM',
|
|
1346
|
+
footer_label: p.footer_label ?? p.footer ?? '',
|
|
1347
|
+
footer_icon: Toolkit.resolveMedia(__classPrivateFieldGet(this, _AIRich_client, "f"), p.footer_icon ?? p.icon ?? '', 'image'),
|
|
1348
|
+
is_carousel: posts.length > 1,
|
|
1349
|
+
orientation: p.orientation ?? 'LANDSCAPE',
|
|
1350
|
+
post_type: p.post_type ?? 'VIDEO',
|
|
1351
|
+
__typename: 'GenAIPostPrimitive',
|
|
1352
|
+
}));
|
|
1353
|
+
this._sections.push(AIRich.newLayout('HScroll', primitives));
|
|
1354
|
+
return this;
|
|
1355
|
+
}
|
|
1356
|
+
addTip(text) {
|
|
1357
|
+
this._submessages.push({
|
|
1358
|
+
messageType: 2,
|
|
1359
|
+
messageText: text,
|
|
1360
|
+
});
|
|
1361
|
+
this._sections.push(AIRich.newLayout('Single', {
|
|
1362
|
+
text,
|
|
1363
|
+
__typename: 'GenAIMetadataTextPrimitive',
|
|
1364
|
+
}));
|
|
1365
|
+
return this;
|
|
1366
|
+
}
|
|
1367
|
+
addSuggest(suggestion, { scroll = true, layout } = {}) {
|
|
1368
|
+
if (!(typeof suggestion === 'string' || (Array.isArray(suggestion) && suggestion.every((v) => typeof v === 'string')))) {
|
|
1369
|
+
throw new TypeError('Suggestion must be a string or array of strings');
|
|
1370
|
+
}
|
|
1371
|
+
const suggest = Array.isArray(suggestion)
|
|
1372
|
+
? suggestion.map((text) => ({
|
|
1373
|
+
prompt_text: text,
|
|
1374
|
+
prompt_type: 'SUGGESTED_PROMPT',
|
|
1375
|
+
__typename: 'GenAIFollowUpSuggestionPillPrimitive',
|
|
1376
|
+
}))
|
|
1377
|
+
: [
|
|
1378
|
+
{
|
|
1379
|
+
prompt_text: suggestion,
|
|
1380
|
+
prompt_type: 'SUGGESTED_PROMPT',
|
|
1381
|
+
__typename: 'GenAIFollowUpSuggestionPillPrimitive',
|
|
1382
|
+
},
|
|
1383
|
+
];
|
|
1384
|
+
const type = layout ?? (suggest.length === 1 ? 'Single' : scroll ? 'HScroll' : 'ActionRow');
|
|
1385
|
+
this._sections.push(AIRich.newLayout(type, type === 'Single' ? suggest[0] : suggest, { __typename: 'GenAIUnifiedResponseSection' }));
|
|
1386
|
+
return this;
|
|
1387
|
+
}
|
|
1388
|
+
async build({ forwarded = true, notification = false, includesUnifiedResponse = true, includesSubmessages = true, quoted, quotedParticipant, ...options } = {}) {
|
|
1389
|
+
const forward = forwarded
|
|
1390
|
+
? {
|
|
1391
|
+
forwardingScore: 1,
|
|
1392
|
+
isForwarded: true,
|
|
1393
|
+
forwardedAiBotMessageInfo: { botJid: '0@bot' },
|
|
1394
|
+
forwardOrigin: 4,
|
|
1395
|
+
}
|
|
1396
|
+
: {};
|
|
1397
|
+
const notif = notification
|
|
1398
|
+
? {
|
|
1399
|
+
sessionTransparencyMetadata: {
|
|
1400
|
+
disclaimerText: '~ Ahmad tumbuh kembang',
|
|
1401
|
+
hcaId: `hca_${Date.now()}`,
|
|
1402
|
+
sessionTransparencyType: 1,
|
|
1403
|
+
},
|
|
1404
|
+
}
|
|
1405
|
+
: {};
|
|
1406
|
+
const qObj = quoted
|
|
1407
|
+
? {
|
|
1408
|
+
stanzaId: quoted?.key?.id || quoted?.id,
|
|
1409
|
+
participant: quotedParticipant || quoted?.key?.participant || quoted?.key?.remoteJid,
|
|
1410
|
+
quotedType: 0,
|
|
1411
|
+
quotedMessage: typeof quoted === 'object' && quoted !== null ? (quoted.message ?? quoted) : undefined,
|
|
1412
|
+
}
|
|
1413
|
+
: {};
|
|
1414
|
+
const sections = this._footer
|
|
1415
|
+
? [
|
|
1416
|
+
...(await waitAllPromises(this._sections)),
|
|
1417
|
+
AIRich.newLayout('Single', {
|
|
1418
|
+
text: this._footer,
|
|
1419
|
+
__typename: 'GenAIMetadataTextPrimitive',
|
|
1420
|
+
}),
|
|
1421
|
+
]
|
|
1422
|
+
: [...(await waitAllPromises(this._sections))];
|
|
1423
|
+
// Vanz@Merge 15-08-26 --- Neither blurose nor arslan sign the bot metadata with
|
|
1424
|
+
// verificationMetadata (proofs/certificateChain). Backported from this project's own
|
|
1425
|
+
// rich-message-utils.js botMetadataSignature/botMetadataCertificate helpers, plus a
|
|
1426
|
+
// botResponseId tying the signed metadata to unifiedResponse.response_id.
|
|
1427
|
+
const responseId = crypto_1.default.randomUUID();
|
|
1428
|
+
return {
|
|
1429
|
+
messageContextInfo: {
|
|
1430
|
+
deviceListMetadata: {},
|
|
1431
|
+
deviceListMetadataVersion: 2,
|
|
1432
|
+
botMetadata: {
|
|
1433
|
+
messageDisclaimerText: this._title,
|
|
1434
|
+
richResponseSourcesMetadata: { sources: this._richResponseSources },
|
|
1435
|
+
botResponseId: responseId,
|
|
1436
|
+
verificationMetadata: {
|
|
1437
|
+
proofs: [
|
|
1438
|
+
{
|
|
1439
|
+
certificateChain: [(0, rich_message_utils_js_1.botMetadataCertificate)(), (0, rich_message_utils_js_1.botMetadataCertificate)(892)],
|
|
1440
|
+
version: 1,
|
|
1441
|
+
useCase: 1,
|
|
1442
|
+
signature: (0, rich_message_utils_js_1.botMetadataSignature)(),
|
|
1443
|
+
},
|
|
1444
|
+
],
|
|
1445
|
+
},
|
|
1446
|
+
...notif,
|
|
1447
|
+
},
|
|
1448
|
+
},
|
|
1449
|
+
...this._extraPayload,
|
|
1450
|
+
botForwardedMessage: {
|
|
1451
|
+
message: {
|
|
1452
|
+
richResponseMessage: {
|
|
1453
|
+
messageType: 1,
|
|
1454
|
+
submessages: includesSubmessages ? await waitAllPromises(this._submessages) : [],
|
|
1455
|
+
unifiedResponse: {
|
|
1456
|
+
data: includesUnifiedResponse ? Buffer.from(JSON.stringify({ response_id: responseId, sections })).toString('base64') : '',
|
|
1457
|
+
},
|
|
1458
|
+
contextInfo: {
|
|
1459
|
+
...forward,
|
|
1460
|
+
...qObj,
|
|
1461
|
+
...this._contextInfo,
|
|
1462
|
+
},
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
},
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
// Vanz@Fix (bug 42 / inline image fallback) --- WA won't render AIRichResponseInlineImageMetadata
|
|
1469
|
+
// for bot-sent messages (confirmed: even a valid WA-CDN url with mediaKey stays blank), so any
|
|
1470
|
+
// image added via addInlineImage() is sent here as a normal imageMessage instead. Pass
|
|
1471
|
+
// { skipImageFallback: true } to opt out and send only the (image-less-looking) rich card.
|
|
1472
|
+
// Vanz@Fix (bug 42 / inline image fallback) --- WA won't render AIRichResponseInlineImageMetadata
|
|
1473
|
+
// for bot-sent messages (confirmed: even a valid WA-CDN url with mediaKey stays blank), so any
|
|
1474
|
+
// image added via addInlineImage() is sent here as a normal imageMessage instead. Pass
|
|
1475
|
+
// { skipImageFallback: true } to opt out and send only the (image-less-looking) rich card.
|
|
1476
|
+
// Vanz@Fix: don't spread relayMessage-shaped `options` into sendMessage()'s options param —
|
|
1477
|
+
// the two calls expect different option shapes, so the fallback now only forwards `quoted`
|
|
1478
|
+
// (the one option that clearly applies to both) instead of blindly spreading everything.
|
|
1479
|
+
async send(jid, { forwarded, notification, includesUnifiedResponse, includesSubmessages, skipImageFallback = false, quoted, ...options } = {}) {
|
|
1480
|
+
const msg = await this.build({ forwarded, notification, includesUnifiedResponse, includesSubmessages, quoted, ...options });
|
|
1481
|
+
if (!skipImageFallback && this._inlineImages.length) {
|
|
1482
|
+
for (const { url, caption } of this._inlineImages) {
|
|
1483
|
+
try {
|
|
1484
|
+
await __classPrivateFieldGet(this, _AIRich_client, "f").sendMessage(jid, { image: { url }, caption }, quoted ? { quoted } : {});
|
|
1485
|
+
}
|
|
1486
|
+
catch (err) {
|
|
1487
|
+
// Vanz@Fix: don't let a fallback image failure block the actual rich card from sending
|
|
1488
|
+
__classPrivateFieldGet(this, _AIRich_client, "f").logger?.warn?.({ err, url }, 'inline image fallback failed, continuing with rich card');
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return await __classPrivateFieldGet(this, _AIRich_client, "f").relayMessage(jid, msg, { ...options });
|
|
1493
|
+
}
|
|
1494
|
+
static tokenizer(code, lang = 'javascript') {
|
|
1495
|
+
const keywordsMap = {
|
|
1496
|
+
javascript: new Set([
|
|
1497
|
+
'break',
|
|
1498
|
+
'case',
|
|
1499
|
+
'catch',
|
|
1500
|
+
'continue',
|
|
1501
|
+
'debugger',
|
|
1502
|
+
'delete',
|
|
1503
|
+
'do',
|
|
1504
|
+
'else',
|
|
1505
|
+
'finally',
|
|
1506
|
+
'for',
|
|
1507
|
+
'function',
|
|
1508
|
+
'if',
|
|
1509
|
+
'in',
|
|
1510
|
+
'instanceof',
|
|
1511
|
+
'new',
|
|
1512
|
+
'return',
|
|
1513
|
+
'switch',
|
|
1514
|
+
'this',
|
|
1515
|
+
'throw',
|
|
1516
|
+
'try',
|
|
1517
|
+
'typeof',
|
|
1518
|
+
'var',
|
|
1519
|
+
'void',
|
|
1520
|
+
'while',
|
|
1521
|
+
'with',
|
|
1522
|
+
'true',
|
|
1523
|
+
'false',
|
|
1524
|
+
'null',
|
|
1525
|
+
'undefined',
|
|
1526
|
+
'class',
|
|
1527
|
+
'const',
|
|
1528
|
+
'let',
|
|
1529
|
+
'super',
|
|
1530
|
+
'extends',
|
|
1531
|
+
'export',
|
|
1532
|
+
'import',
|
|
1533
|
+
'yield',
|
|
1534
|
+
'static',
|
|
1535
|
+
'constructor',
|
|
1536
|
+
'async',
|
|
1537
|
+
'await',
|
|
1538
|
+
'get',
|
|
1539
|
+
'set',
|
|
1540
|
+
]),
|
|
1541
|
+
typescript: new Set([
|
|
1542
|
+
'abstract',
|
|
1543
|
+
'any',
|
|
1544
|
+
'as',
|
|
1545
|
+
'asserts',
|
|
1546
|
+
'bigint',
|
|
1547
|
+
'boolean',
|
|
1548
|
+
'declare',
|
|
1549
|
+
'enum',
|
|
1550
|
+
'implements',
|
|
1551
|
+
'infer',
|
|
1552
|
+
'interface',
|
|
1553
|
+
'is',
|
|
1554
|
+
'keyof',
|
|
1555
|
+
'module',
|
|
1556
|
+
'namespace',
|
|
1557
|
+
'never',
|
|
1558
|
+
'readonly',
|
|
1559
|
+
'require',
|
|
1560
|
+
'number',
|
|
1561
|
+
'object',
|
|
1562
|
+
'override',
|
|
1563
|
+
'private',
|
|
1564
|
+
'protected',
|
|
1565
|
+
'public',
|
|
1566
|
+
'satisfies',
|
|
1567
|
+
'string',
|
|
1568
|
+
'symbol',
|
|
1569
|
+
'type',
|
|
1570
|
+
'unknown',
|
|
1571
|
+
'using',
|
|
1572
|
+
'from',
|
|
1573
|
+
'break',
|
|
1574
|
+
'case',
|
|
1575
|
+
'catch',
|
|
1576
|
+
'continue',
|
|
1577
|
+
'do',
|
|
1578
|
+
'else',
|
|
1579
|
+
'finally',
|
|
1580
|
+
'for',
|
|
1581
|
+
'function',
|
|
1582
|
+
'if',
|
|
1583
|
+
'new',
|
|
1584
|
+
'return',
|
|
1585
|
+
'switch',
|
|
1586
|
+
'this',
|
|
1587
|
+
'throw',
|
|
1588
|
+
'try',
|
|
1589
|
+
'var',
|
|
1590
|
+
'void',
|
|
1591
|
+
'while',
|
|
1592
|
+
'class',
|
|
1593
|
+
'const',
|
|
1594
|
+
'let',
|
|
1595
|
+
'extends',
|
|
1596
|
+
'import',
|
|
1597
|
+
'export',
|
|
1598
|
+
'async',
|
|
1599
|
+
'await',
|
|
1600
|
+
]),
|
|
1601
|
+
python: new Set([
|
|
1602
|
+
'False',
|
|
1603
|
+
'None',
|
|
1604
|
+
'True',
|
|
1605
|
+
'and',
|
|
1606
|
+
'as',
|
|
1607
|
+
'assert',
|
|
1608
|
+
'async',
|
|
1609
|
+
'await',
|
|
1610
|
+
'break',
|
|
1611
|
+
'class',
|
|
1612
|
+
'continue',
|
|
1613
|
+
'def',
|
|
1614
|
+
'del',
|
|
1615
|
+
'elif',
|
|
1616
|
+
'else',
|
|
1617
|
+
'except',
|
|
1618
|
+
'finally',
|
|
1619
|
+
'for',
|
|
1620
|
+
'from',
|
|
1621
|
+
'global',
|
|
1622
|
+
'if',
|
|
1623
|
+
'import',
|
|
1624
|
+
'in',
|
|
1625
|
+
'is',
|
|
1626
|
+
'lambda',
|
|
1627
|
+
'nonlocal',
|
|
1628
|
+
'not',
|
|
1629
|
+
'or',
|
|
1630
|
+
'pass',
|
|
1631
|
+
'raise',
|
|
1632
|
+
'return',
|
|
1633
|
+
'try',
|
|
1634
|
+
'while',
|
|
1635
|
+
'with',
|
|
1636
|
+
'yield',
|
|
1637
|
+
]),
|
|
1638
|
+
java: new Set([
|
|
1639
|
+
'abstract',
|
|
1640
|
+
'assert',
|
|
1641
|
+
'boolean',
|
|
1642
|
+
'break',
|
|
1643
|
+
'byte',
|
|
1644
|
+
'case',
|
|
1645
|
+
'catch',
|
|
1646
|
+
'char',
|
|
1647
|
+
'class',
|
|
1648
|
+
'const',
|
|
1649
|
+
'continue',
|
|
1650
|
+
'default',
|
|
1651
|
+
'do',
|
|
1652
|
+
'double',
|
|
1653
|
+
'else',
|
|
1654
|
+
'enum',
|
|
1655
|
+
'extends',
|
|
1656
|
+
'final',
|
|
1657
|
+
'finally',
|
|
1658
|
+
'float',
|
|
1659
|
+
'for',
|
|
1660
|
+
'goto',
|
|
1661
|
+
'if',
|
|
1662
|
+
'implements',
|
|
1663
|
+
'import',
|
|
1664
|
+
'instanceof',
|
|
1665
|
+
'int',
|
|
1666
|
+
'interface',
|
|
1667
|
+
'long',
|
|
1668
|
+
'native',
|
|
1669
|
+
'new',
|
|
1670
|
+
'package',
|
|
1671
|
+
'private',
|
|
1672
|
+
'protected',
|
|
1673
|
+
'public',
|
|
1674
|
+
'return',
|
|
1675
|
+
'short',
|
|
1676
|
+
'static',
|
|
1677
|
+
'strictfp',
|
|
1678
|
+
'super',
|
|
1679
|
+
'switch',
|
|
1680
|
+
'synchronized',
|
|
1681
|
+
'this',
|
|
1682
|
+
'throw',
|
|
1683
|
+
'throws',
|
|
1684
|
+
'transient',
|
|
1685
|
+
'try',
|
|
1686
|
+
'void',
|
|
1687
|
+
'volatile',
|
|
1688
|
+
'while',
|
|
1689
|
+
]),
|
|
1690
|
+
golang: new Set([
|
|
1691
|
+
'break',
|
|
1692
|
+
'case',
|
|
1693
|
+
'chan',
|
|
1694
|
+
'const',
|
|
1695
|
+
'continue',
|
|
1696
|
+
'default',
|
|
1697
|
+
'defer',
|
|
1698
|
+
'else',
|
|
1699
|
+
'fallthrough',
|
|
1700
|
+
'for',
|
|
1701
|
+
'func',
|
|
1702
|
+
'go',
|
|
1703
|
+
'goto',
|
|
1704
|
+
'if',
|
|
1705
|
+
'import',
|
|
1706
|
+
'interface',
|
|
1707
|
+
'map',
|
|
1708
|
+
'package',
|
|
1709
|
+
'range',
|
|
1710
|
+
'return',
|
|
1711
|
+
'select',
|
|
1712
|
+
'struct',
|
|
1713
|
+
'switch',
|
|
1714
|
+
'type',
|
|
1715
|
+
'var',
|
|
1716
|
+
]),
|
|
1717
|
+
c: new Set([
|
|
1718
|
+
'auto',
|
|
1719
|
+
'break',
|
|
1720
|
+
'case',
|
|
1721
|
+
'char',
|
|
1722
|
+
'const',
|
|
1723
|
+
'continue',
|
|
1724
|
+
'default',
|
|
1725
|
+
'do',
|
|
1726
|
+
'double',
|
|
1727
|
+
'else',
|
|
1728
|
+
'enum',
|
|
1729
|
+
'extern',
|
|
1730
|
+
'float',
|
|
1731
|
+
'for',
|
|
1732
|
+
'goto',
|
|
1733
|
+
'if',
|
|
1734
|
+
'int',
|
|
1735
|
+
'long',
|
|
1736
|
+
'register',
|
|
1737
|
+
'return',
|
|
1738
|
+
'short',
|
|
1739
|
+
'signed',
|
|
1740
|
+
'sizeof',
|
|
1741
|
+
'static',
|
|
1742
|
+
'struct',
|
|
1743
|
+
'switch',
|
|
1744
|
+
'typedef',
|
|
1745
|
+
'union',
|
|
1746
|
+
'unsigned',
|
|
1747
|
+
'void',
|
|
1748
|
+
'volatile',
|
|
1749
|
+
'while',
|
|
1750
|
+
]),
|
|
1751
|
+
cpp: new Set([
|
|
1752
|
+
'alignas',
|
|
1753
|
+
'alignof',
|
|
1754
|
+
'and',
|
|
1755
|
+
'auto',
|
|
1756
|
+
'bool',
|
|
1757
|
+
'break',
|
|
1758
|
+
'case',
|
|
1759
|
+
'catch',
|
|
1760
|
+
'class',
|
|
1761
|
+
'const',
|
|
1762
|
+
'constexpr',
|
|
1763
|
+
'continue',
|
|
1764
|
+
'delete',
|
|
1765
|
+
'do',
|
|
1766
|
+
'double',
|
|
1767
|
+
'else',
|
|
1768
|
+
'enum',
|
|
1769
|
+
'explicit',
|
|
1770
|
+
'export',
|
|
1771
|
+
'extern',
|
|
1772
|
+
'false',
|
|
1773
|
+
'float',
|
|
1774
|
+
'for',
|
|
1775
|
+
'friend',
|
|
1776
|
+
'if',
|
|
1777
|
+
'inline',
|
|
1778
|
+
'int',
|
|
1779
|
+
'long',
|
|
1780
|
+
'mutable',
|
|
1781
|
+
'namespace',
|
|
1782
|
+
'new',
|
|
1783
|
+
'noexcept',
|
|
1784
|
+
'nullptr',
|
|
1785
|
+
'operator',
|
|
1786
|
+
'private',
|
|
1787
|
+
'protected',
|
|
1788
|
+
'public',
|
|
1789
|
+
'return',
|
|
1790
|
+
'short',
|
|
1791
|
+
'signed',
|
|
1792
|
+
'sizeof',
|
|
1793
|
+
'static',
|
|
1794
|
+
'struct',
|
|
1795
|
+
'switch',
|
|
1796
|
+
'template',
|
|
1797
|
+
'this',
|
|
1798
|
+
'throw',
|
|
1799
|
+
'true',
|
|
1800
|
+
'try',
|
|
1801
|
+
'typedef',
|
|
1802
|
+
'typename',
|
|
1803
|
+
'union',
|
|
1804
|
+
'unsigned',
|
|
1805
|
+
'using',
|
|
1806
|
+
'virtual',
|
|
1807
|
+
'void',
|
|
1808
|
+
'while',
|
|
1809
|
+
]),
|
|
1810
|
+
php: new Set([
|
|
1811
|
+
'abstract',
|
|
1812
|
+
'and',
|
|
1813
|
+
'array',
|
|
1814
|
+
'as',
|
|
1815
|
+
'break',
|
|
1816
|
+
'callable',
|
|
1817
|
+
'case',
|
|
1818
|
+
'catch',
|
|
1819
|
+
'class',
|
|
1820
|
+
'clone',
|
|
1821
|
+
'const',
|
|
1822
|
+
'continue',
|
|
1823
|
+
'declare',
|
|
1824
|
+
'default',
|
|
1825
|
+
'do',
|
|
1826
|
+
'echo',
|
|
1827
|
+
'else',
|
|
1828
|
+
'elseif',
|
|
1829
|
+
'empty',
|
|
1830
|
+
'enddeclare',
|
|
1831
|
+
'endfor',
|
|
1832
|
+
'endforeach',
|
|
1833
|
+
'endif',
|
|
1834
|
+
'endswitch',
|
|
1835
|
+
'endwhile',
|
|
1836
|
+
'extends',
|
|
1837
|
+
'final',
|
|
1838
|
+
'finally',
|
|
1839
|
+
'fn',
|
|
1840
|
+
'for',
|
|
1841
|
+
'foreach',
|
|
1842
|
+
'function',
|
|
1843
|
+
'global',
|
|
1844
|
+
'goto',
|
|
1845
|
+
'if',
|
|
1846
|
+
'implements',
|
|
1847
|
+
'include',
|
|
1848
|
+
'include_once',
|
|
1849
|
+
'instanceof',
|
|
1850
|
+
'interface',
|
|
1851
|
+
'match',
|
|
1852
|
+
'namespace',
|
|
1853
|
+
'new',
|
|
1854
|
+
'null',
|
|
1855
|
+
'or',
|
|
1856
|
+
'private',
|
|
1857
|
+
'protected',
|
|
1858
|
+
'public',
|
|
1859
|
+
'require',
|
|
1860
|
+
'require_once',
|
|
1861
|
+
'return',
|
|
1862
|
+
'static',
|
|
1863
|
+
'switch',
|
|
1864
|
+
'throw',
|
|
1865
|
+
'trait',
|
|
1866
|
+
'try',
|
|
1867
|
+
'use',
|
|
1868
|
+
'var',
|
|
1869
|
+
'while',
|
|
1870
|
+
'yield',
|
|
1871
|
+
]),
|
|
1872
|
+
rust: new Set([
|
|
1873
|
+
'as',
|
|
1874
|
+
'break',
|
|
1875
|
+
'const',
|
|
1876
|
+
'continue',
|
|
1877
|
+
'crate',
|
|
1878
|
+
'else',
|
|
1879
|
+
'enum',
|
|
1880
|
+
'extern',
|
|
1881
|
+
'false',
|
|
1882
|
+
'fn',
|
|
1883
|
+
'for',
|
|
1884
|
+
'if',
|
|
1885
|
+
'impl',
|
|
1886
|
+
'in',
|
|
1887
|
+
'let',
|
|
1888
|
+
'loop',
|
|
1889
|
+
'match',
|
|
1890
|
+
'mod',
|
|
1891
|
+
'move',
|
|
1892
|
+
'mut',
|
|
1893
|
+
'pub',
|
|
1894
|
+
'ref',
|
|
1895
|
+
'return',
|
|
1896
|
+
'self',
|
|
1897
|
+
'Self',
|
|
1898
|
+
'static',
|
|
1899
|
+
'struct',
|
|
1900
|
+
'super',
|
|
1901
|
+
'trait',
|
|
1902
|
+
'true',
|
|
1903
|
+
'type',
|
|
1904
|
+
'unsafe',
|
|
1905
|
+
'use',
|
|
1906
|
+
'where',
|
|
1907
|
+
'while',
|
|
1908
|
+
]),
|
|
1909
|
+
html: new Set([
|
|
1910
|
+
'html',
|
|
1911
|
+
'head',
|
|
1912
|
+
'body',
|
|
1913
|
+
'div',
|
|
1914
|
+
'span',
|
|
1915
|
+
'p',
|
|
1916
|
+
'a',
|
|
1917
|
+
'img',
|
|
1918
|
+
'video',
|
|
1919
|
+
'audio',
|
|
1920
|
+
'script',
|
|
1921
|
+
'style',
|
|
1922
|
+
'link',
|
|
1923
|
+
'meta',
|
|
1924
|
+
'form',
|
|
1925
|
+
'input',
|
|
1926
|
+
'button',
|
|
1927
|
+
'table',
|
|
1928
|
+
'tr',
|
|
1929
|
+
'td',
|
|
1930
|
+
'th',
|
|
1931
|
+
'ul',
|
|
1932
|
+
'ol',
|
|
1933
|
+
'li',
|
|
1934
|
+
'section',
|
|
1935
|
+
'article',
|
|
1936
|
+
'header',
|
|
1937
|
+
'footer',
|
|
1938
|
+
'nav',
|
|
1939
|
+
'main',
|
|
1940
|
+
]),
|
|
1941
|
+
bash: new Set([
|
|
1942
|
+
'if',
|
|
1943
|
+
'then',
|
|
1944
|
+
'else',
|
|
1945
|
+
'elif',
|
|
1946
|
+
'fi',
|
|
1947
|
+
'for',
|
|
1948
|
+
'while',
|
|
1949
|
+
'do',
|
|
1950
|
+
'done',
|
|
1951
|
+
'case',
|
|
1952
|
+
'esac',
|
|
1953
|
+
'function',
|
|
1954
|
+
'in',
|
|
1955
|
+
'select',
|
|
1956
|
+
'until',
|
|
1957
|
+
'break',
|
|
1958
|
+
'continue',
|
|
1959
|
+
'return',
|
|
1960
|
+
'export',
|
|
1961
|
+
'readonly',
|
|
1962
|
+
'local',
|
|
1963
|
+
'declare',
|
|
1964
|
+
]),
|
|
1965
|
+
markdown: new Set(['#', '##', '###', '####', '#####', '######']),
|
|
1966
|
+
};
|
|
1967
|
+
if (!lang || lang === 'txt' || lang === 'text' || lang === 'plaintext') {
|
|
1968
|
+
return {
|
|
1969
|
+
codeBlock: [
|
|
1970
|
+
{
|
|
1971
|
+
codeContent: code,
|
|
1972
|
+
highlightType: 0,
|
|
1973
|
+
},
|
|
1974
|
+
],
|
|
1975
|
+
unified_codeBlock: [
|
|
1976
|
+
{
|
|
1977
|
+
content: code,
|
|
1978
|
+
type: 'DEFAULT',
|
|
1979
|
+
},
|
|
1980
|
+
],
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
const TYPE_MAP = {
|
|
1984
|
+
0: 'DEFAULT',
|
|
1985
|
+
1: 'KEYWORD',
|
|
1986
|
+
2: 'METHOD',
|
|
1987
|
+
3: 'STR',
|
|
1988
|
+
4: 'NUMBER',
|
|
1989
|
+
5: 'COMMENT',
|
|
1990
|
+
};
|
|
1991
|
+
const keywords = keywordsMap[lang.toLowerCase()] || new Set();
|
|
1992
|
+
const tokens = [];
|
|
1993
|
+
let i = 0;
|
|
1994
|
+
const push = (content, type) => {
|
|
1995
|
+
if (!content)
|
|
1996
|
+
return;
|
|
1997
|
+
const last = tokens[tokens.length - 1];
|
|
1998
|
+
if (last && last.highlightType === type) {
|
|
1999
|
+
last.codeContent += content;
|
|
2000
|
+
}
|
|
2001
|
+
else {
|
|
2002
|
+
tokens.push({
|
|
2003
|
+
codeContent: content,
|
|
2004
|
+
highlightType: type,
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
const isIdentifier = (char) => {
|
|
2009
|
+
switch (lang.toLowerCase()) {
|
|
2010
|
+
case 'css':
|
|
2011
|
+
return /[a-zA-Z0-9_$-]/.test(char);
|
|
2012
|
+
case 'html':
|
|
2013
|
+
return /[a-zA-Z0-9_$:-]/.test(char);
|
|
2014
|
+
default:
|
|
2015
|
+
return /[a-zA-Z0-9_$]/.test(char);
|
|
2016
|
+
}
|
|
2017
|
+
};
|
|
2018
|
+
while (i < code.length) {
|
|
2019
|
+
const c = code[i];
|
|
2020
|
+
if (/\s/.test(c)) {
|
|
2021
|
+
let s = i;
|
|
2022
|
+
while (i < code.length && /\s/.test(code[i])) {
|
|
2023
|
+
i++;
|
|
2024
|
+
}
|
|
2025
|
+
push(code.slice(s, i), 0);
|
|
2026
|
+
continue;
|
|
2027
|
+
}
|
|
2028
|
+
if ((c === '/' && code[i + 1] === '/') || (c === '#' && ['python', 'bash'].includes(lang))) {
|
|
2029
|
+
let s = i;
|
|
2030
|
+
while (i < code.length && code[i] !== '\n') {
|
|
2031
|
+
i++;
|
|
2032
|
+
}
|
|
2033
|
+
push(code.slice(s, i), 5);
|
|
2034
|
+
continue;
|
|
2035
|
+
}
|
|
2036
|
+
if (c === '"' || c === "'" || c === '`') {
|
|
2037
|
+
let s = i;
|
|
2038
|
+
const q = c;
|
|
2039
|
+
i++;
|
|
2040
|
+
while (i < code.length) {
|
|
2041
|
+
if (code[i] === '\\' && i + 1 < code.length) {
|
|
2042
|
+
i += 2;
|
|
2043
|
+
}
|
|
2044
|
+
else if (code[i] === q) {
|
|
2045
|
+
i++;
|
|
2046
|
+
break;
|
|
2047
|
+
}
|
|
2048
|
+
else {
|
|
2049
|
+
i++;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
push(code.slice(s, i), 3);
|
|
2053
|
+
continue;
|
|
2054
|
+
}
|
|
2055
|
+
if (/[0-9]/.test(c)) {
|
|
2056
|
+
let s = i;
|
|
2057
|
+
while (i < code.length && /[0-9._]/.test(code[i])) {
|
|
2058
|
+
i++;
|
|
2059
|
+
}
|
|
2060
|
+
push(code.slice(s, i), 4);
|
|
2061
|
+
continue;
|
|
2062
|
+
}
|
|
2063
|
+
if (/[a-zA-Z_$]/.test(c)) {
|
|
2064
|
+
let s = i;
|
|
2065
|
+
while (i < code.length && isIdentifier(code[i])) {
|
|
2066
|
+
i++;
|
|
2067
|
+
}
|
|
2068
|
+
const word = code.slice(s, i);
|
|
2069
|
+
let type = 0;
|
|
2070
|
+
if (keywords.has(word)) {
|
|
2071
|
+
type = 1;
|
|
2072
|
+
}
|
|
2073
|
+
else if (lang === 'css') {
|
|
2074
|
+
let j = i;
|
|
2075
|
+
while (j < code.length && /\s/.test(code[j])) {
|
|
2076
|
+
j++;
|
|
2077
|
+
}
|
|
2078
|
+
if (code[j] === ':') {
|
|
2079
|
+
type = 1;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
else if (lang === 'html') {
|
|
2083
|
+
let p = s - 1;
|
|
2084
|
+
while (p >= 0 && /\s/.test(code[p])) {
|
|
2085
|
+
p--;
|
|
2086
|
+
}
|
|
2087
|
+
if (code[p] === '<' || (code[p] === '/' && code[p - 1] === '<')) {
|
|
2088
|
+
type = 1;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
if (type === 0) {
|
|
2092
|
+
let j = i;
|
|
2093
|
+
while (j < code.length && /\s/.test(code[j])) {
|
|
2094
|
+
j++;
|
|
2095
|
+
}
|
|
2096
|
+
if (code[j] === '(') {
|
|
2097
|
+
type = 2;
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
push(word, type);
|
|
2101
|
+
continue;
|
|
2102
|
+
}
|
|
2103
|
+
push(c, 0);
|
|
2104
|
+
i++;
|
|
2105
|
+
}
|
|
2106
|
+
return {
|
|
2107
|
+
codeBlock: tokens,
|
|
2108
|
+
unified_codeBlock: tokens.map((t) => ({
|
|
2109
|
+
content: t.codeContent,
|
|
2110
|
+
type: TYPE_MAP[t.highlightType],
|
|
2111
|
+
})),
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
static toTableMetadata(arr, { hyperlink = true, citation = true, latex = true } = {}) {
|
|
2115
|
+
if (!Array.isArray(arr) || !arr.every((row) => Array.isArray(row) && row.every((cell) => typeof cell === 'string'))) {
|
|
2116
|
+
throw new TypeError('Table must be a nested array of strings');
|
|
2117
|
+
}
|
|
2118
|
+
const [header, ...rows] = arr;
|
|
2119
|
+
const maxLen = Math.max(header.length, ...rows.map((r) => r.length));
|
|
2120
|
+
const normalize = (r) => [...r, ...Array(maxLen - r.length).fill('')];
|
|
2121
|
+
const unified_rows = [
|
|
2122
|
+
{
|
|
2123
|
+
is_header: true,
|
|
2124
|
+
cells: normalize(header),
|
|
2125
|
+
},
|
|
2126
|
+
...rows.map((r) => ({
|
|
2127
|
+
is_header: false,
|
|
2128
|
+
cells: normalize(r),
|
|
2129
|
+
})),
|
|
2130
|
+
].map((row) => {
|
|
2131
|
+
const markdown_cells = row.cells.map((cell) => {
|
|
2132
|
+
const extracted = extractIE(cell, { hyperlink, citation, latex });
|
|
2133
|
+
return {
|
|
2134
|
+
text: extracted.text,
|
|
2135
|
+
...(extracted.inline_entities.length ? { inline_entities: extracted.inline_entities } : {}),
|
|
2136
|
+
};
|
|
2137
|
+
});
|
|
2138
|
+
return {
|
|
2139
|
+
...row,
|
|
2140
|
+
...(markdown_cells.some((c) => c.inline_entities?.length) ? { markdown_cells } : {}),
|
|
2141
|
+
};
|
|
2142
|
+
});
|
|
2143
|
+
const rowsMeta = unified_rows.map((r) => ({
|
|
2144
|
+
items: r.cells,
|
|
2145
|
+
...(r.is_header ? { isHeading: true } : {}),
|
|
2146
|
+
}));
|
|
2147
|
+
return {
|
|
2148
|
+
title: '',
|
|
2149
|
+
rows: rowsMeta,
|
|
2150
|
+
unified_rows,
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
static newLayout(name, data, extra = {}) {
|
|
2154
|
+
return {
|
|
2155
|
+
...extra,
|
|
2156
|
+
view_model: {
|
|
2157
|
+
[Array.isArray(data) ? 'primitives' : 'primitive']: data,
|
|
2158
|
+
__typename: `GenAI${name}LayoutViewModel`,
|
|
2159
|
+
},
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
exports.AIRich = AIRich;
|
|
2164
|
+
_AIRich_client = new WeakMap();
|