meta-cloud-api 1.1.7 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2640 +1,12 @@
1
- import { AudioMediaTypesEnum, BusinessVerticalEnum, ButtonPositionEnum, CategoryEnum, ComponentTypesEnum, ConversationTypesEnum, CurrencyCodesEnum, DataLocalizationRegionEnum, DocumentMediaTypesEnum, FlowActionEnum, FlowCategoryEnum, FlowStatusEnum, FlowTypeEnum, HttpMethodsEnum, ImageMediaTypesEnum, InteractiveTypesEnum, LanguagesEnum, MessageTypesEnum, ParametersTypesEnum, ReferralSourceTypesEnum, RequestCodeMethodsEnum, StatusEnum, StickerMediaTypesEnum, SubTypeEnum, SystemChangeTypesEnum, TemplateStatusEnum, VideoMediaTypesEnum, WabaAccountReviewStatus, WabaAccountStatus, WabaBusinessVerificationStatus, WabaConfigEnum, WabaHealthStatusCanSendMessage, WebhookTypesEnum, enums_exports } from "./types-Ov9U2ABw.js";
2
- import { Agent } from "https";
3
- import { readFileSync } from "fs";
4
- import { join } from "path";
5
- import * as crypto$1 from "crypto";
6
- import crypto from "crypto";
7
-
8
- //#region src/utils/logger.ts
9
- var Logger = class {
10
- name;
11
- debug;
12
- constructor(name, debug = false) {
13
- this.name = name;
14
- this.debug = debug;
15
- }
16
- log(...data) {
17
- if (this.debug) {
18
- let prefix = `[ ${Date.now()} ]`;
19
- if (this.name) {
20
- prefix += ` - ${this.name}`;
21
- }
22
- console.log.apply(console, [
23
- prefix,
24
- ": ",
25
- ...data
26
- ]);
27
- }
28
- }
29
- error(...data) {
30
- let prefix = `[ ${Date.now()} ] - ERROR`;
31
- if (this.name) {
32
- prefix += ` - ${this.name}`;
33
- }
34
- console.error.apply(console, [
35
- prefix,
36
- ": ",
37
- ...data
38
- ]);
39
- }
40
- warn(...data) {
41
- let prefix = `[ ${Date.now()} ] - WARN`;
42
- if (this.name) {
43
- prefix += ` - ${this.name}`;
44
- }
45
- console.warn.apply(console, [
46
- prefix,
47
- ": ",
48
- ...data
49
- ]);
50
- }
51
- info(...data) {
52
- let prefix = `[ ${Date.now()} ] - INFO`;
53
- if (this.name) {
54
- prefix += ` - ${this.name}`;
55
- }
56
- console.info.apply(console, [
57
- prefix,
58
- ": ",
59
- ...data
60
- ]);
61
- }
62
- };
63
-
64
- //#endregion
65
- //#region src/config/importConfig.ts
66
- const LIB_NAME$4 = "UTILS";
67
- const LOG_LOCAL$2 = false;
68
- const LOGGER$5 = new Logger(LIB_NAME$4, process.env.DEBUG === "true" || LOG_LOCAL$2);
69
- const DEFAULT_LISTENER_PORT = 3e3;
70
- const DEFAULT_MAX_RETRIES_AFTER_WAIT = 30;
71
- const DEFAULT_REQUEST_TIMEOUT = 2e4;
72
- const emptyConfigChecker = (config) => {
73
- if (!process.env[WabaConfigEnum.AccessToken] && !config?.accessToken) {
74
- LOGGER$5.log(`Environmental variable: CLOUD_API_ACCESS_TOKEN and/or access token argument is undefined.`);
75
- throw new Error("Missing WhatsApp access token.");
76
- }
77
- };
78
- const importConfig = (inputConfig) => {
79
- emptyConfigChecker(inputConfig);
80
- const wabaConfig = {
81
- [WabaConfigEnum.AppId]: inputConfig?.appId || process.env.M4D_APP_ID || "",
82
- [WabaConfigEnum.AppSecret]: inputConfig?.appSecret || process.env.M4D_APP_SECRET || "",
83
- [WabaConfigEnum.PhoneNumberId]: inputConfig?.phoneNumberId || Number(process.env.WA_PHONE_NUMBER_ID),
84
- [WabaConfigEnum.BusinessAcctId]: inputConfig?.businessAcctId || process.env.WA_BUSINESS_ACCOUNT_ID || "",
85
- [WabaConfigEnum.APIVersion]: inputConfig?.apiVersion || process.env.CLOUD_API_VERSION || "",
86
- [WabaConfigEnum.AccessToken]: inputConfig?.accessToken || process.env.CLOUD_API_ACCESS_TOKEN || "",
87
- [WabaConfigEnum.WebhookEndpoint]: inputConfig?.webhookEndpoint || process.env.WEBHOOK_ENDPOINT || "",
88
- [WabaConfigEnum.WebhookVerificationToken]: inputConfig?.webhookVerificationToken || process.env.WEBHOOK_VERIFICATION_TOKEN || "",
89
- [WabaConfigEnum.ListenerPort]: inputConfig?.listenerPort || parseInt(process.env.LISTENER_PORT || "") || DEFAULT_LISTENER_PORT,
90
- [WabaConfigEnum.MaxRetriesAfterWait]: inputConfig?.maxRetriesAfterWait || parseInt(process.env.MAX_RETRIES_AFTER_WAIT || "") || DEFAULT_MAX_RETRIES_AFTER_WAIT,
91
- [WabaConfigEnum.RequestTimeout]: inputConfig?.requestTimeout || parseInt(process.env.REQUEST_TIMEOUT || "") || DEFAULT_REQUEST_TIMEOUT,
92
- [WabaConfigEnum.Debug]: inputConfig?.debug || process.env.DEBUG === "true",
93
- [WabaConfigEnum.PrivatePem]: inputConfig?.privatePem || process.env.FLOW_API_PRIVATE_PEM || "",
94
- [WabaConfigEnum.Passphrase]: inputConfig?.passphrase || process.env.FLOW_API_PASSPHRASE || ""
95
- };
96
- return wabaConfig;
97
- };
98
-
99
- //#endregion
100
- //#region src/utils/configTable.ts
101
- /**
102
- * Formats configuration as a terminal table
103
- * @param config - The WABA configuration object
104
- * @param apiName - The name of the API being initialized
105
- * @returns Formatted table string
106
- */
107
- function formatConfigTable(config) {
108
- const configData = [
109
- ["App ID", config[WabaConfigEnum.AppId] || "Not Set"],
110
- ["Phone Number ID", config[WabaConfigEnum.PhoneNumberId]?.toString() || "Not Set"],
111
- ["Business Account ID", config[WabaConfigEnum.BusinessAcctId] || "Not Set"],
112
- ["API Version", config[WabaConfigEnum.APIVersion] || "Not Set"],
113
- ["Access Token", config[WabaConfigEnum.AccessToken] ? `${config[WabaConfigEnum.AccessToken].substring(0, 20)}...` : "Not Set"],
114
- ["Webhook Endpoint", config[WabaConfigEnum.WebhookEndpoint] || "Not Set"],
115
- ["Webhook Verification Token", config[WabaConfigEnum.WebhookVerificationToken] ? `${config[WabaConfigEnum.WebhookVerificationToken].substring(0, 10)}...` : "Not Set"],
116
- ["Listener Port", config[WabaConfigEnum.ListenerPort]?.toString() || "Not Set"],
117
- ["Debug Mode", config[WabaConfigEnum.Debug] ? "Enabled" : "Disabled"],
118
- ["Max Retries", config[WabaConfigEnum.MaxRetriesAfterWait]?.toString() || "Not Set"],
119
- ["Request Timeout", config[WabaConfigEnum.RequestTimeout] ? `${config[WabaConfigEnum.RequestTimeout]}ms` : "Not Set"],
120
- ["Private PEM", config[WabaConfigEnum.PrivatePem] ? "Configured" : "Not Set"],
121
- ["Passphrase", config[WabaConfigEnum.Passphrase] ? "Configured" : "Not Set"]
122
- ];
123
- const maxKeyLength = Math.max(...configData.map(([key]) => key?.length || 0));
124
- const maxValueLength = Math.max(...configData.map(([, value]) => value?.length || 0));
125
- const keyWidth = Math.max(maxKeyLength, 20);
126
- const valueWidth = Math.max(maxValueLength, 30);
127
- const horizontalLine = `┌${"─".repeat(keyWidth + 2)}┬${"─".repeat(valueWidth + 2)}┐`;
128
- const separator = `├${"─".repeat(keyWidth + 2)}┼${"─".repeat(valueWidth + 2)}┤`;
129
- const bottomLine = `└${"─".repeat(keyWidth + 2)}┴${"─".repeat(valueWidth + 2)}┘`;
130
- const header = `│ ${"Configuration".padEnd(keyWidth)} │ ${"Value".padEnd(valueWidth)} │`;
131
- const rows = configData.map(([key, value]) => `│ ${key?.padEnd(keyWidth)} │ ${value?.padEnd(valueWidth)} │`);
132
- return [
133
- horizontalLine,
134
- header,
135
- separator,
136
- ...rows,
137
- bottomLine
138
- ].join("\n");
139
- }
140
-
141
- //#endregion
142
- //#region src/utils/isMetaError.ts
143
- /**
144
- * Determines if the error is a Meta API error response
145
- * @param error Any error object to check
146
- * @returns Type guard indicating if error is a Meta API error
147
- */
148
- function isMetaError(error) {
149
- return error != null && typeof error === "object" && "error" in error && typeof error.error === "object" && error.error != null && "message" in error.error && typeof error.error.message === "string" && "type" in error.error && typeof error.error.type === "string" && "code" in error.error && typeof error.error.code === "number" && "fbtrace_id" in error.error && typeof error.error.fbtrace_id === "string" && (!("error_data" in error.error) || typeof error.error.error_data === "object" && error.error.error_data != null && "messaging_product" in error.error.error_data && error.error.error_data.messaging_product === "whatsapp" && "details" in error.error.error_data && typeof error.error.error_data.details === "string") && (!("error_subcode" in error.error) || typeof error.error.error_subcode === "number");
150
- }
151
-
152
- //#endregion
153
- //#region src/utils/http/httpsClient.ts
154
- const LIB_NAME$3 = "HttpsClient";
155
- const LOG_LOCAL$1 = false;
156
- const LOGGER$4 = new Logger(LIB_NAME$3, process.env.DEBUG === "true" || LOG_LOCAL$1);
157
- var HttpsClient = class {
158
- agent;
159
- constructor() {
160
- this.agent = new Agent({ keepAlive: true });
161
- }
162
- clearSockets() {
163
- this.agent.destroy();
164
- return true;
165
- }
166
- async sendRequest(hostname, path, method, headers, timeout, body) {
167
- const url = `https://${hostname}/${path}`;
168
- const controller = new AbortController();
169
- const timeoutId = setTimeout(() => controller.abort(), timeout);
170
- try {
171
- const response = await fetch(url, {
172
- method,
173
- headers,
174
- body,
175
- signal: controller.signal
176
- });
177
- LOGGER$4.log(`${method} : ${url} - ${JSON.stringify(response)}`);
178
- clearTimeout(timeoutId);
179
- return new HttpsClientResponse(response);
180
- } catch (error) {
181
- LOGGER$4.error(`${method} : ${url} - ${JSON.stringify(error)}`);
182
- throw error;
183
- }
184
- }
185
- };
186
- var HttpsClientResponse = class {
187
- res;
188
- respStatusCode;
189
- respHeaders;
190
- constructor(resp) {
191
- this.res = resp;
192
- this.respStatusCode = resp.status;
193
- this.respHeaders = Object.fromEntries(resp.headers.entries());
194
- }
195
- statusCode() {
196
- return this.respStatusCode;
197
- }
198
- headers() {
199
- return this.respHeaders;
200
- }
201
- rawResponse() {
202
- return this.res;
203
- }
204
- async json() {
205
- try {
206
- return await this.res.json();
207
- } catch (err) {
208
- throw new Error("Failed to parse response body to JSON: " + err.message);
209
- }
210
- }
211
- };
212
-
213
- //#endregion
214
- //#region src/utils/http/request.ts
215
- const LIB_NAME$2 = "REQUESTER";
216
- const LOG_LOCAL = false;
217
- const LOGGER$3 = new Logger(LIB_NAME$2, process.env.DEBUG === "true" || LOG_LOCAL);
218
- var Requester = class {
219
- client;
220
- accessToken;
221
- phoneNumberId;
222
- businessAcctId;
223
- apiVersion;
224
- userAgent;
225
- host;
226
- protocol = "https:";
227
- constructor(apiVersion, phoneNumberId, accessToken, businessAcctId, userAgent) {
228
- this.client = new HttpsClient();
229
- this.host = "graph.facebook.com";
230
- this.apiVersion = apiVersion || "22";
231
- this.phoneNumberId = phoneNumberId;
232
- this.accessToken = accessToken;
233
- this.businessAcctId = businessAcctId;
234
- this.userAgent = userAgent;
235
- }
236
- buildHeader(contentType, additionalHeaders) {
237
- const headers = {
238
- Authorization: `Bearer ${this.accessToken}`,
239
- "User-Agent": this.userAgent
240
- };
241
- if (contentType !== "multipart/form-data") {
242
- headers["Content-Type"] = contentType;
243
- }
244
- if (additionalHeaders) {
245
- Object.assign(headers, additionalHeaders);
246
- }
247
- return headers;
248
- }
249
- buildCAPIPath(endpoint) {
250
- return `v${this.apiVersion}.0/${endpoint}`;
251
- }
252
- async sendRequest(method, endpoint, timeout, body, contentType = "application/json", additionalHeaders) {
253
- let effectiveContentType = contentType;
254
- if (body instanceof FormData) {
255
- effectiveContentType = "multipart/form-data";
256
- } else if (typeof body === "string" && body.startsWith("<?xml")) {
257
- effectiveContentType = "application/xml";
258
- }
259
- const path = `${this.protocol.toLowerCase()}//${this.host}/${this.buildCAPIPath(endpoint)}`;
260
- LOGGER$3.log(`${method} : ${path} (${effectiveContentType})`);
261
- try {
262
- const response = await this.client.sendRequest(this.host, this.buildCAPIPath(endpoint), method, this.buildHeader(effectiveContentType, additionalHeaders), timeout, method === "POST" || method === "PUT" ? body : undefined);
263
- if (!response.rawResponse().ok) {
264
- const errorData = await response.json();
265
- if (isMetaError(errorData)) {
266
- throw errorData;
267
- }
268
- throw {
269
- name: "MetaError",
270
- message: "Unknown error occurred",
271
- error: {
272
- message: errorData.message || "Unknown error occurred",
273
- type: "UnknownError",
274
- code: response.statusCode(),
275
- fbtrace_id: ""
276
- }
277
- };
278
- }
279
- return response;
280
- } catch (error) {
281
- if (isMetaError(error)) {
282
- throw error;
283
- }
284
- throw {
285
- name: "MetaError",
286
- message: error instanceof Error ? error.message : "Network error occurred",
287
- error: {
288
- message: error instanceof Error ? error.message : "Network error occurred",
289
- type: "NetworkError",
290
- code: 500,
291
- fbtrace_id: ""
292
- }
293
- };
294
- }
295
- }
296
- async getJson(method, endpoint, timeout, body, additionalHeaders) {
297
- const res = await this.sendRequest(method, endpoint, timeout, body, "application/json", additionalHeaders);
298
- return await res.json();
299
- }
300
- async sendFormData(method, endpoint, timeout, formData, additionalHeaders) {
301
- const res = await this.sendRequest(method, endpoint, timeout, formData, "multipart/form-data", additionalHeaders);
302
- return await res.json();
303
- }
304
- async sendUrlEncodedForm(method, endpoint, timeout, formData, additionalHeaders) {
305
- const urlEncodedBody = new URLSearchParams(formData).toString();
306
- const res = await this.sendRequest(method, endpoint, timeout, urlEncodedBody, "application/x-www-form-urlencoded", additionalHeaders);
307
- return await res.json();
308
- }
309
- };
310
-
311
- //#endregion
312
- //#region src/utils/version.ts
313
- /**
314
- * Get SDK version from package.json
315
- */
316
- function getVersion() {
317
- try {
318
- const packagePath = join(__dirname, "../../package.json");
319
- const packageJson = JSON.parse(readFileSync(packagePath, "utf-8"));
320
- return packageJson.version;
321
- } catch (error) {
322
- return "unknown";
323
- }
324
- }
325
- /**
326
- * Generate User-Agent string following official SDK pattern
327
- */
328
- function getUserAgent() {
329
- const version = getVersion();
330
- const nodeVersion = process.version;
331
- return `WhatsApp-Nodejs-SDK/${version} (Node.js ${nodeVersion})`;
332
- }
333
-
334
- //#endregion
335
- //#region src/types/base.ts
336
- var BaseAPI = class {
337
- config;
338
- client;
339
- constructor(config, client) {
340
- this.config = config;
341
- this.client = client;
342
- }
343
- sendJson(method, endpoint, timeout, body) {
344
- return this.client.getJson(method, endpoint, timeout, body);
345
- }
346
- sendFormData(method, endpoint, timeout, body) {
347
- return this.client.sendFormData(method, endpoint, timeout, body);
348
- }
349
- sendUrlEncodedForm(method, endpoint, timeout, body) {
350
- return this.client.sendUrlEncodedForm(method, endpoint, timeout, body);
351
- }
352
- };
353
-
354
- //#endregion
355
- //#region src/api/encryption/EncryptionApi.ts
356
- var EncryptionApi = class extends BaseAPI {
357
- endpoint = "whatsapp_business_encryption";
358
- constructor(config, client) {
359
- super(config, client);
360
- }
361
- async getEncryptionPublicKey() {
362
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], null);
363
- }
364
- async setEncryptionPublicKey(businessPublicKey) {
365
- const formData = new FormData();
366
- formData.append("business_public_key", businessPublicKey);
367
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], formData);
368
- }
369
- };
370
-
371
- //#endregion
372
- //#region src/api/encryption/index.ts
373
- var encryption_default = EncryptionApi;
374
-
375
- //#endregion
376
- //#region src/api/flow/FlowApi.ts
377
- /**
378
- * API for managing WhatsApp Flows.
379
- *
380
- * This API allows you to:
381
- * - List flows
382
- * - Create flows
383
- * - Get flow details and previews
384
- * - Update flow metadata and JSON
385
- * - Delete flows
386
- * - Publish and deprecate flows
387
- * - Migrate flows between WABAs
388
- * - Validate flow JSON
389
- */
390
- var FlowApi = class extends BaseAPI {
391
- constructor(config, client) {
392
- super(config, client);
393
- }
394
- /**
395
- * List Flows
396
- *
397
- * @param wabaId - The WABA ID
398
- * @returns Promise with the list of flows
399
- */
400
- async listFlows(wabaId) {
401
- return this.sendJson(HttpMethodsEnum.Get, `/${wabaId}/flows`, this.config[WabaConfigEnum.RequestTimeout], null);
402
- }
403
- /**
404
- * Create Flow
405
- *
406
- * @param wabaId - The WABA ID
407
- * @param data - The flow data including name, categories, endpoint_uri, and optional clone_flow_id
408
- * @returns Promise with the created flow ID and validation errors if any
409
- */
410
- async createFlow(wabaId, data) {
411
- const payload = {
412
- name: data.name,
413
- categories: data.categories,
414
- ...data.endpoint_uri && { endpoint_uri: data.endpoint_uri },
415
- ...data.clone_flow_id && { clone_flow_id: data.clone_flow_id },
416
- ...data.flow_json && { flow_json: data.flow_json },
417
- ...data.publish !== undefined && { publish: data.publish }
418
- };
419
- return this.sendJson(HttpMethodsEnum.Post, `/${wabaId}/flows`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(payload));
420
- }
421
- /**
422
- * Get Flow details
423
- *
424
- * @param flowId - The flow ID
425
- * @param fields - Optional fields to return (e.g., 'name,status,preview.invalidate(false)')
426
- * @param dateFormat - Optional date format
427
- * @returns Promise with the flow details or preview response
428
- */
429
- async getFlow(flowId, fields, dateFormat) {
430
- const params = new URLSearchParams();
431
- if (fields) params.append("fields", fields);
432
- if (dateFormat) params.append("date_format", dateFormat);
433
- const queryString = params.toString() ? `?${params.toString()}` : "";
434
- return this.sendJson(HttpMethodsEnum.Get, `/${flowId}${queryString}`, this.config[WabaConfigEnum.RequestTimeout], null);
435
- }
436
- /**
437
- * Get Flow Preview URL
438
- *
439
- * @param flowId - The flow ID
440
- * @param invalidate - Optional. If true, invalidates existing preview and generates a new one. Defaults to false.
441
- * @returns Promise with the flow preview details
442
- */
443
- async getFlowPreview(flowId, invalidate = false) {
444
- const fields = `preview.invalidate(${invalidate})`;
445
- return this.getFlow(flowId, fields);
446
- }
447
- /**
448
- * Update Flow Metadata
449
- *
450
- * @param flowId - The flow ID
451
- * @param data - The flow metadata to update (name, categories, endpoint_uri, application_id)
452
- * @returns Promise with the success status
453
- */
454
- async updateFlowMetadata(flowId, data) {
455
- const payload = {
456
- ...data.name && { name: data.name },
457
- ...data.categories && { categories: data.categories },
458
- ...data.endpoint_uri && { endpoint_uri: data.endpoint_uri },
459
- ...data.application_id && { application_id: data.application_id }
460
- };
461
- return this.sendJson(HttpMethodsEnum.Post, `/${flowId}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(payload));
462
- }
463
- /**
464
- * Delete Flow (only works if the Flow is in DRAFT status)
465
- *
466
- * @param flowId - The flow ID
467
- * @returns Promise with the success status
468
- */
469
- async deleteFlow(flowId) {
470
- return this.sendJson(HttpMethodsEnum.Delete, `/${flowId}`, this.config[WabaConfigEnum.RequestTimeout], null);
471
- }
472
- /**
473
- * List Assets (e.g., get Flow JSON download URL)
474
- *
475
- * @param flowId - The flow ID
476
- * @returns Promise with the list of assets
477
- */
478
- async listAssets(flowId) {
479
- return this.sendJson(HttpMethodsEnum.Get, `/${flowId}/assets`, this.config[WabaConfigEnum.RequestTimeout], null);
480
- }
481
- /**
482
- * Update Flow JSON by uploading a file, buffer, JSON object, or Blob.
483
- *
484
- * @param flowId - The flow ID
485
- * @param data - Object containing the file data and optional name.
486
- * @param data.file - The Flow JSON content as a Buffer, JSON object, or Blob.
487
- * @param data.name - Optional name for the asset, defaults to 'flow.json'.
488
- * @returns Promise with the success status and validation errors, if any.
489
- */
490
- async updateFlowJson(flowId, data) {
491
- const formData = new FormData();
492
- let fileContent;
493
- if (data.file instanceof Buffer) {
494
- fileContent = new globalThis.Blob([data.file]);
495
- formData.append("file", fileContent);
496
- } else if (typeof data.file === "object" && !(data.file instanceof Blob)) {
497
- try {
498
- fileContent = new globalThis.Blob([JSON.stringify(data.file, null, 2)], { type: "application/json" });
499
- formData.append("file", fileContent);
500
- } catch (e) {
501
- throw new Error("Failed to stringify JSON object for Flow JSON update.");
502
- }
503
- } else if (data.file instanceof Blob) {
504
- fileContent = data.file;
505
- formData.append("file", fileContent);
506
- } else {
507
- throw new Error("Invalid file type provided for Flow JSON update. Must be a Buffer, JSON object, or Blob.");
508
- }
509
- formData.append("asset_type", "FLOW_JSON");
510
- formData.append("name", data.name || "flow.json");
511
- return this.sendFormData(HttpMethodsEnum.Post, `/${flowId}/assets`, this.config[WabaConfigEnum.RequestTimeout], formData);
512
- }
513
- /**
514
- * Validate Flow JSON by attempting an update without publishing.
515
- * This is a convenience method; the API doesn't have a dedicated validation endpoint.
516
- *
517
- * @param flowId - The ID of the Flow (must exist, can be in DRAFT status).
518
- * @param flowJsonData - The Flow JSON content as a file path (string), Buffer, JSON object, or Blob.
519
- * @returns Promise indicating if the JSON is valid and includes validation errors if any.
520
- */
521
- async validateFlowJson(flowId, flowJsonData) {
522
- try {
523
- const result = await this.updateFlowJson(flowId, { file: flowJsonData });
524
- const isValid = !result.validation_errors || result.validation_errors.length === 0;
525
- const enhancedResponse = {
526
- ...result,
527
- valid: isValid
528
- };
529
- return enhancedResponse;
530
- } catch (error) {
531
- throw error;
532
- }
533
- }
534
- /**
535
- * Publish Flow
536
- *
537
- * @param flowId - The flow ID
538
- * @returns Promise with the success status
539
- */
540
- async publishFlow(flowId) {
541
- return this.sendJson(HttpMethodsEnum.Post, `/${flowId}/publish`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify({}));
542
- }
543
- /**
544
- * Deprecate Flow
545
- *
546
- * @param flowId - The flow ID
547
- * @returns Promise with the success status
548
- */
549
- async deprecateFlow(flowId) {
550
- return this.sendJson(HttpMethodsEnum.Post, `/${flowId}/deprecate`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify({}));
551
- }
552
- /**
553
- * Migrate Flows between WABAs
554
- *
555
- * @param destinationWabaId - The destination WABA ID
556
- * @param data - The migration data including source_waba_id and optional source_flow_names
557
- * @returns Promise with migration results (successes and failures)
558
- */
559
- async migrateFlows(destinationWabaId, data) {
560
- const payload = {
561
- source_waba_id: data.source_waba_id,
562
- ...data.source_flow_names && { source_flow_names: data.source_flow_names }
563
- };
564
- return this.sendJson(HttpMethodsEnum.Post, `/${destinationWabaId}/migrate_flows`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(payload));
565
- }
566
- };
567
-
568
- //#endregion
569
- //#region src/api/flow/index.ts
570
- var flow_default = FlowApi;
571
-
572
- //#endregion
573
- //#region src/api/media/MediaApi.ts
574
- /**
575
- * API for managing WhatsApp Media.
576
- *
577
- * This API allows you to:
578
- * - Get media information by ID
579
- * - Upload media files
580
- * - Delete media files
581
- * - Download media files from URLs
582
- */
583
- var MediaApi = class extends BaseAPI {
584
- endpoint = "media";
585
- constructor(config, client) {
586
- super(config, client);
587
- }
588
- /**
589
- * Retrieve media information by media ID.
590
- *
591
- * @param mediaId The media ID to retrieve information for
592
- * @param phone_number_id Optional phone number ID (defaults to configured one)
593
- * @returns Media information including URL, mime type, file size, etc.
594
- *
595
- * @example
596
- * const mediaInfo = await whatsappClient.media.getMediaById('media_id_123');
597
- */
598
- async getMediaById(mediaId, phone_number_id) {
599
- return this.sendJson(HttpMethodsEnum.Get, `${mediaId}`, this.config[WabaConfigEnum.RequestTimeout], null);
600
- }
601
- /**
602
- * Upload a media file to WhatsApp.
603
- *
604
- * @param file The file to upload
605
- * @param messagingProduct The messaging product (default: 'whatsapp')
606
- * @returns Upload response containing the media ID
607
- *
608
- * @example
609
- * const file = new File([buffer], 'image.jpg', { type: 'image/jpeg' });
610
- * const result = await whatsappClient.media.uploadMedia(file);
611
- */
612
- async uploadMedia(file, messagingProduct = "whatsapp") {
613
- const formData = new FormData();
614
- formData.append("file", file);
615
- formData.append("messaging_product", messagingProduct);
616
- formData.append("type", file.type);
617
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], formData);
618
- }
619
- /**
620
- * Delete a media file.
621
- *
622
- * @param mediaId The media ID to delete
623
- * @param phone_number_id Optional phone number ID (defaults to configured one)
624
- * @returns Response indicating success or failure
625
- *
626
- * @example
627
- * await whatsappClient.media.deleteMedia('media_id_123');
628
- */
629
- async deleteMedia(mediaId, phone_number_id) {
630
- return this.sendJson(HttpMethodsEnum.Delete, `${mediaId}`, this.config[WabaConfigEnum.RequestTimeout], null);
631
- }
632
- /**
633
- * Download media from a URL.
634
- *
635
- * @param mediaUrl The URL to download media from
636
- * @returns Blob containing the media data
637
- *
638
- * @example
639
- * const blob = await whatsappClient.media.downloadMedia('https://...');
640
- */
641
- async downloadMedia(mediaUrl) {
642
- return this.sendJson(HttpMethodsEnum.Get, mediaUrl, this.config[WabaConfigEnum.RequestTimeout], null);
643
- }
644
- };
645
-
646
- //#endregion
647
- //#region src/api/media/index.ts
648
- var media_default = MediaApi;
649
-
650
- //#endregion
651
- //#region src/api/messages/MessageApi.ts
652
- var MessagesApi = class extends BaseAPI {
653
- commonMethod = HttpMethodsEnum.Post;
654
- commonEndpoint = "messages";
655
- constructor(config, client) {
656
- super(config, client);
657
- }
658
- /**
659
- * Builds the request body for WhatsApp API messages
660
- * @param type The type of message to send
661
- * @param payload The message payload object
662
- * @param to The recipient's phone number
663
- * @param replyMessageId Optional message ID to reply to
664
- * @returns The formatted request body
665
- */
666
- bodyBuilder(type, payload, to, replyMessageId) {
667
- const body = {
668
- messaging_product: "whatsapp",
669
- recipient_type: "individual",
670
- to,
671
- type,
672
- [type]: payload
673
- };
674
- if (replyMessageId) body["context"] = { message_id: replyMessageId };
675
- return body;
676
- }
677
- /**
678
- * Sends a request to the WhatsApp API
679
- * @param body The request body to send
680
- * @returns Promise with the API response
681
- */
682
- send(body) {
683
- return this.sendJson(this.commonMethod, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.commonEndpoint}`, this.config[WabaConfigEnum.RequestTimeout], body);
684
- }
685
- /**
686
- * Sends an audio message via WhatsApp
687
- * @param params The audio message parameter object
688
- * @returns Promise with the message response
689
- */
690
- async audio(params) {
691
- const { body, to, replyMessageId } = params;
692
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Audio, body, to, replyMessageId)));
693
- }
694
- /**
695
- * Sends a contact card via WhatsApp
696
- * @param params The contact message parameter object
697
- * @returns Promise with the message response
698
- */
699
- async contacts(params) {
700
- const { body, to, replyMessageId } = params;
701
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Contacts, body, to, replyMessageId)));
702
- }
703
- /**
704
- * Sends a document via WhatsApp
705
- * @param params The document message parameter object
706
- * @returns Promise with the message response
707
- */
708
- async document(params) {
709
- const { body, to, replyMessageId } = params;
710
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Document, body, to, replyMessageId)));
711
- }
712
- /**
713
- * Sends an image via WhatsApp
714
- * @param params The image message parameter object
715
- * @returns Promise with the message response
716
- */
717
- async image(params) {
718
- const { body, to, replyMessageId } = params;
719
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Image, body, to, replyMessageId)));
720
- }
721
- /**
722
- * Sends an interactive message via WhatsApp
723
- * @param params The interactive message parameter object
724
- * @returns Promise with the message response
725
- */
726
- async interactive(params) {
727
- const { body, to, replyMessageId } = params;
728
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Interactive, body, to, replyMessageId)));
729
- }
730
- /**
731
- * Sends a location via WhatsApp
732
- * @param params The location message parameter object
733
- * @returns Promise with the message response
734
- */
735
- async location(params) {
736
- const { body, to, replyMessageId } = params;
737
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Location, body, to, replyMessageId)));
738
- }
739
- /**
740
- * Sends a sticker via WhatsApp
741
- * @param params The sticker message parameter object
742
- * @returns Promise with the message response
743
- */
744
- async sticker(params) {
745
- const { body, to, replyMessageId } = params;
746
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Sticker, body, to, replyMessageId)));
747
- }
748
- /**
749
- * Sends a template message via WhatsApp
750
- * @param params The template message parameter object
751
- * @returns Promise with the message response
752
- */
753
- async template(params) {
754
- const { body, to, replyMessageId } = params;
755
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Template, body, to, replyMessageId)));
756
- }
757
- /**
758
- * Sends a text message via WhatsApp
759
- * @param params The text message parameter object
760
- * @returns Promise with the message response
761
- */
762
- async text(params) {
763
- const { body, to, replyMessageId, previewUrl } = params;
764
- const textPayload = typeof body === "string" ? {
765
- body,
766
- preview_url: previewUrl ?? true
767
- } : {
768
- ...body,
769
- preview_url: previewUrl ?? body.preview_url ?? true
770
- };
771
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Text, textPayload, to, replyMessageId)));
772
- }
773
- /**
774
- * Sends a video message via WhatsApp
775
- * @param params The video message parameter object
776
- * @returns Promise with the message response
777
- */
778
- async video(params) {
779
- const { body, to, replyMessageId } = params;
780
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Video, body, to, replyMessageId)));
781
- }
782
- /**
783
- * Updates message status (mark as read, etc.)
784
- * @param params The status update parameters
785
- * @returns Promise with the API response
786
- */
787
- async status(params) {
788
- const body = {
789
- messaging_product: "whatsapp",
790
- status: params.status,
791
- message_id: params.messageId,
792
- ...params.typingIndicator && { typing_indicator: params.typingIndicator }
793
- };
794
- return this.send(JSON.stringify(body));
795
- }
796
- /**
797
- * Marks a message as read
798
- * @param params Object containing messageId
799
- * @returns Promise with the API response
800
- */
801
- async markAsRead(params) {
802
- return this.status({
803
- status: "read",
804
- messageId: params.messageId
805
- });
806
- }
807
- /**
808
- * Shows typing indicator
809
- * @param params Object containing messageId
810
- * @returns Promise with the API response
811
- */
812
- async showTypingIndicator(params) {
813
- return this.status({
814
- status: "read",
815
- messageId: params.messageId,
816
- typingIndicator: { type: "text" }
817
- });
818
- }
819
- /**
820
- * Sends a list interactive message
821
- * @param params The list interactive message parameters
822
- * @returns Promise with the message response
823
- */
824
- async interactiveList(params) {
825
- return this.interactive(params);
826
- }
827
- /**
828
- * Sends a CTA URL interactive message
829
- * @param params The CTA URL interactive message parameters
830
- * @returns Promise with the message response
831
- */
832
- async interactiveCtaUrl(params) {
833
- return this.interactive(params);
834
- }
835
- /**
836
- * Sends a location request interactive message
837
- * @param params The location request interactive message parameters
838
- * @returns Promise with the message response
839
- */
840
- async interactiveLocationRequest(params) {
841
- return this.interactive(params);
842
- }
843
- /**
844
- * Sends an address message interactive message
845
- * @param params The address message interactive message parameters
846
- * @returns Promise with the message response
847
- */
848
- async interactiveAddressMessage(params) {
849
- return this.interactive(params);
850
- }
851
- /**
852
- * Sends a reply buttons interactive message
853
- * @param params The reply buttons interactive message parameters
854
- * @returns Promise with the message response
855
- */
856
- async interactiveReplyButtons(params) {
857
- return this.interactive(params);
858
- }
859
- /**
860
- * Sends a flow interactive message
861
- * @param params The flow interactive message parameters
862
- * @returns Promise with the message response
863
- */
864
- async interactiveFlow(params) {
865
- return this.interactive(params);
866
- }
867
- /**
868
- * Sends a reaction to a message
869
- * @param params The reaction parameters
870
- * @returns Promise with the message response
871
- */
872
- async reaction(params) {
873
- const reactionPayload = {
874
- message_id: params.messageId,
875
- emoji: params.emoji
876
- };
877
- return this.send(JSON.stringify(this.bodyBuilder(MessageTypesEnum.Reaction, reactionPayload, params.to)));
878
- }
879
- };
880
-
881
- //#endregion
882
- //#region src/api/messages/index.ts
883
- var messages_default = MessagesApi;
884
-
885
- //#endregion
886
- //#region src/utils/objectToQueryString.ts
887
- const objectToQueryString = (params) => {
888
- if (!params || Object.keys(params).length === 0) {
889
- return "";
890
- }
891
- const queryParts = [];
892
- for (const [key, value] of Object.entries(params)) {
893
- if (value !== undefined) {
894
- const encodedKey = encodeURIComponent(key);
895
- const encodedValue = encodeURIComponent(String(value));
896
- queryParts.push(`${encodedKey}=${encodedValue}`);
897
- }
898
- }
899
- return queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
900
- };
901
-
902
- //#endregion
903
- //#region src/api/phone/PhoneNumberApi.ts
904
- /**
905
- * API for managing WhatsApp Phone Numb ers.
906
- *
907
- * This API allows you to:
908
- * - Get phone number information by ID
909
- * - Get all phone numbers for a business account
910
- * - Request verification codes for phone numbers
911
- * - Verify phone numbers with codes
912
- */
913
- var PhoneNumberApi = class extends BaseAPI {
914
- endpoint = "phone_numbers";
915
- constructor(config, client) {
916
- super(config, client);
917
- }
918
- /**
919
- * Get phone number information by ID.
920
- *
921
- * @param fields Optional comma-separated list of fields to include in the response
922
- * @returns Phone number information including verification status, quality rating, etc.
923
- *
924
- * @example
925
- * const phoneNumber = await whatsappClient.phoneNumber.getPhoneNumberById();
926
- * const phoneNumberWithFields = await whatsappClient.phoneNumber.getPhoneNumberById('display_phone_number,verified_name');
927
- */
928
- async getPhoneNumberById(fields) {
929
- const queryParams = fields ? objectToQueryString({ fields }) : "";
930
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.PhoneNumberId]}${queryParams}`, this.config[WabaConfigEnum.RequestTimeout], null);
931
- }
932
- /**
933
- * Get all phone numbers for the business account.
934
- *
935
- * @returns List of phone numbers associated with the business account
936
- *
937
- * @example
938
- * const phoneNumbers = await whatsappClient.phoneNumber.getPhoneNumbers();
939
- */
940
- async getPhoneNumbers() {
941
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.BusinessAcctId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], null);
942
- }
943
- /**
944
- * Request a verification code for the phone number.
945
- *
946
- * @param request Verification code request containing method and language
947
- * @returns Response indicating success or failure
948
- *
949
- * @example
950
- * await whatsappClient.phoneNumber.requestVerificationCode({
951
- * code_method: 'SMS',
952
- * language: 'en_US'
953
- * });
954
- */
955
- async requestVerificationCode(request) {
956
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/request_code`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(request));
957
- }
958
- /**
959
- * Verify the phone number with the received code.
960
- *
961
- * @param request Verification request containing the code
962
- * @returns Response indicating success or failure
963
- *
964
- * @example
965
- * await whatsappClient.phoneNumber.verifyCode({
966
- * code: '123456'
967
- * });
968
- */
969
- async verifyCode(request) {
970
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/verify_code`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(request));
971
- }
972
- };
973
-
974
- //#endregion
975
- //#region src/api/phone/index.ts
976
- var phone_default = PhoneNumberApi;
977
-
978
- //#endregion
979
- //#region src/utils/buildFieldsQueryString.ts
980
- function buildFieldsQueryString(fields) {
981
- if (!fields) return "";
982
- let fieldParams = "";
983
- if (Array.isArray(fields)) {
984
- fieldParams = fields.join(",");
985
- } else if (typeof fields === "string") {
986
- fieldParams = fields;
987
- } else {
988
- fieldParams = Object.entries(fields).filter(([_, value]) => value).map(([key]) => key).join(",");
989
- }
990
- return fieldParams ? `?fields=${fieldParams}` : "";
991
- }
992
-
993
- //#endregion
994
- //#region src/api/profile/BusinessProfileApi.ts
995
- /**
996
- * API for managing WhatsApp Business Profiles and profile pictures.
997
- *
998
- * This API allows you to:
999
- * - Get business profile information
1000
- * - Update business profile details
1001
- * - Upload profile pictures using a three-step process:
1002
- * 1. Create an upload session
1003
- * 2. Upload the image binary data
1004
- * 3. Get the upload handle to use when updating the profile
1005
- */
1006
- var BusinessProfileApi = class extends BaseAPI {
1007
- endpoint = "whatsapp_business_profile";
1008
- constructor(config, client) {
1009
- super(config, client);
1010
- }
1011
- /**
1012
- * Get your business profile information.
1013
- *
1014
- * Use this method to retrieve details about your WhatsApp business profile, including
1015
- * about text, address, description, email, profile picture URL, websites, and vertical.
1016
- *
1017
- * @param fields Fields to be returned in the response. If not specified, all fields will be returned.
1018
- * Possible values: about, address, description, email, profile_picture_url, websites, vertical
1019
- * @returns The business profile information.
1020
- *
1021
- * @example
1022
- * // Get all business profile fields
1023
- * const profile = await whatsappClient.businessProfile.getBusinessProfile();
1024
- *
1025
- * // Get specific business profile fields
1026
- * const profile = await whatsappClient.businessProfile.getBusinessProfile('about,address,email');
1027
- *
1028
- * // Using the BusinessProfileFieldsParam type
1029
- * const profile = await whatsappClient.businessProfile.getBusinessProfile(['about', 'address', 'email']);
1030
- */
1031
- async getBusinessProfile(fields) {
1032
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}${buildFieldsQueryString(fields)}`, this.config[WabaConfigEnum.RequestTimeout], null);
1033
- }
1034
- /**
1035
- * Update your business profile.
1036
- *
1037
- * Use this method to update one or more fields of your WhatsApp business profile.
1038
- *
1039
- * @param updateRequest The request object containing the fields to update.
1040
- * - messaging_product: Required. Always set to "whatsapp".
1041
- * - about: Optional. Business's About text (1-139 characters).
1042
- * - address: Optional. Business address (max 256 characters).
1043
- * - description: Optional. Business description (max 512 characters).
1044
- * - vertical: Optional. Business category (use BusinessVerticalEnum for type safety).
1045
- * - email: Optional. Contact email (valid format, max 128 characters).
1046
- * - websites: Optional. Up to 2 URLs (max 256 characters each).
1047
- * - profile_picture_handle: Optional. Handle from upload process.
1048
- * @returns Response indicating success or failure.
1049
- *
1050
- * @example
1051
- * // Update business profile with multiple fields including vertical using enum
1052
- * await whatsappClient.businessProfile.updateBusinessProfile({
1053
- * messaging_product: 'whatsapp',
1054
- * about: 'We provide excellent service',
1055
- * email: 'contact@example.com',
1056
- * websites: ['https://example.com'],
1057
- * vertical: BusinessVerticalEnum.RETAIL
1058
- * });
1059
- */
1060
- async updateBusinessProfile(updateRequest) {
1061
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(updateRequest));
1062
- }
1063
- /**
1064
- * Create an upload session for a profile picture.
1065
- *
1066
- * This is the first step in the profile picture upload process.
1067
- *
1068
- * @param fileLength Length of the file to be uploaded in bytes.
1069
- * @param fileType MIME type of the file (e.g., 'image/jpeg').
1070
- * @param fileName Name of the file with extension.
1071
- * @returns Response containing the upload session ID needed for the next step.
1072
- *
1073
- * @example
1074
- * // Create upload session for profile picture
1075
- * const session = await whatsappClient.businessProfile.createUploadSession(
1076
- * fileBuffer.length,
1077
- * 'image/jpeg',
1078
- * 'profile.jpg'
1079
- * );
1080
- * const uploadSessionId = session.upload_session_id;
1081
- */
1082
- async createUploadSession(fileLength, fileType, fileName) {
1083
- const queryParams = objectToQueryString({
1084
- file_length: fileLength,
1085
- file_type: fileType,
1086
- file_name: fileName
1087
- });
1088
- return this.sendJson(HttpMethodsEnum.Post, `app/uploads/${queryParams}`, this.config[WabaConfigEnum.RequestTimeout], null);
1089
- }
1090
- /**
1091
- * Upload media file to the upload session.
1092
- *
1093
- * This is the second step in the profile picture upload process.
1094
- * Upload the binary content of the file to the previously created upload session.
1095
- *
1096
- * @param uploadId The upload session ID from createUploadSession response.
1097
- * @param file The binary data of the file (Buffer).
1098
- * @returns Response indicating success or failure.
1099
- *
1100
- * @example
1101
- * // Upload the actual file content
1102
- * await whatsappClient.businessProfile.uploadMedia(
1103
- * uploadSessionId,
1104
- * fileBuffer
1105
- * );
1106
- */
1107
- async uploadMedia(uploadId, file) {
1108
- return this.sendJson(HttpMethodsEnum.Post, `${uploadId}`, this.config[WabaConfigEnum.RequestTimeout], file);
1109
- }
1110
- /**
1111
- * Get the upload handle information.
1112
- *
1113
- * This is the third step in the profile picture upload process.
1114
- * After uploading the file, get the handle to use when updating the profile.
1115
- *
1116
- * @param uploadId The upload session ID from createUploadSession response.
1117
- * @returns Response containing the upload handle information.
1118
- *
1119
- * @example
1120
- * // Complete profile picture update process
1121
- * // 1. Create upload session
1122
- * const session = await whatsappClient.businessProfile.createUploadSession(
1123
- * fileBuffer.length, 'image/jpeg', 'profile.jpg'
1124
- * );
1125
- *
1126
- * // 2. Upload the image data
1127
- * await whatsappClient.businessProfile.uploadMedia(
1128
- * session.upload_session_id, fileBuffer
1129
- * );
1130
- *
1131
- * // 3. Get the handle for the uploaded file
1132
- * const handleInfo = await whatsappClient.businessProfile.getUploadHandle(
1133
- * session.upload_session_id
1134
- * );
1135
- *
1136
- * // 4. Update profile with new picture and business information
1137
- * await whatsappClient.businessProfile.updateBusinessProfile({
1138
- * messaging_product: 'whatsapp',
1139
- * profile_picture_handle: handleInfo.handle,
1140
- * vertical: BusinessVerticalEnum.RESTAURANT,
1141
- * about: 'Delicious food served daily'
1142
- * });
1143
- */
1144
- async getUploadHandle(uploadId) {
1145
- return this.sendJson(HttpMethodsEnum.Get, `${uploadId}`, this.config[WabaConfigEnum.RequestTimeout], null);
1146
- }
1147
- };
1148
-
1149
- //#endregion
1150
- //#region src/api/profile/index.ts
1151
- var profile_default = BusinessProfileApi;
1152
-
1153
- //#endregion
1154
- //#region src/api/qrCode/QrCodeApi.ts
1155
- /**
1156
- * API for managing WhatsApp QR Codes.
1157
- *
1158
- * This API allows you to:
1159
- * - Create QR codes with prefilled messages
1160
- * - Get all QR codes
1161
- * - Get specific QR code details
1162
- * - Update QR code messages
1163
- * - Delete QR codes
1164
- */
1165
- var QrCodeApi = class extends BaseAPI {
1166
- endpoint = "message_qrdls";
1167
- constructor(config, client) {
1168
- super(config, client);
1169
- }
1170
- /**
1171
- * Create a new QR code with a prefilled message.
1172
- *
1173
- * @param request The QR code creation request
1174
- * @returns QR code information including code, deep link URL, and optional image URL
1175
- *
1176
- * @example
1177
- * const qrCode = await whatsappClient.qrCode.createQrCode({
1178
- * prefilled_message: 'Hello from WhatsApp!',
1179
- * generate_qr_image: 'PNG'
1180
- * });
1181
- */
1182
- async createQrCode(request) {
1183
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(request));
1184
- }
1185
- /**
1186
- * Get all QR codes for the current phone number.
1187
- *
1188
- * @returns List of all QR codes
1189
- *
1190
- * @example
1191
- * const qrCodes = await whatsappClient.qrCode.getQrCodes();
1192
- */
1193
- async getQrCodes() {
1194
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], null);
1195
- }
1196
- /**
1197
- * Get a specific QR code by ID.
1198
- *
1199
- * @param qrCodeId The QR code ID to retrieve
1200
- * @returns QR code information
1201
- *
1202
- * @example
1203
- * const qrCode = await whatsappClient.qrCode.getQrCode('qr_code_123');
1204
- */
1205
- async getQrCode(qrCodeId) {
1206
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}/${qrCodeId}`, this.config[WabaConfigEnum.RequestTimeout], null);
1207
- }
1208
- /**
1209
- * Update an existing QR code's prefilled message.
1210
- *
1211
- * @param request The QR code update request containing code and new message
1212
- * @returns Updated QR code information
1213
- *
1214
- * @example
1215
- * const updatedQrCode = await whatsappClient.qrCode.updateQrCode({
1216
- * code: 'existing_qr_code',
1217
- * prefilled_message: 'Updated message!'
1218
- * });
1219
- */
1220
- async updateQrCode(request) {
1221
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(request));
1222
- }
1223
- /**
1224
- * Delete a QR code.
1225
- *
1226
- * @param qrCodeId The QR code ID to delete
1227
- * @returns Response indicating success or failure
1228
- *
1229
- * @example
1230
- * await whatsappClient.qrCode.deleteQrCode('qr_code_123');
1231
- */
1232
- async deleteQrCode(qrCodeId) {
1233
- return this.sendJson(HttpMethodsEnum.Delete, `${this.config[WabaConfigEnum.PhoneNumberId]}/${this.endpoint}/${qrCodeId}`, this.config[WabaConfigEnum.RequestTimeout], null);
1234
- }
1235
- };
1236
-
1237
- //#endregion
1238
- //#region src/api/qrCode/index.ts
1239
- var qrCode_default = QrCodeApi;
1240
-
1241
- //#endregion
1242
- //#region src/api/registration/RegistrationApi.ts
1243
- /**
1244
- * API for managing WhatsApp Business Account registration.
1245
- *
1246
- * This API allows you to:
1247
- * - Register a WhatsApp Business Account with a PIN
1248
- * - Deregister a WhatsApp Business Account
1249
- */
1250
- var RegistrationApi = class extends BaseAPI {
1251
- constructor(config, client) {
1252
- super(config, client);
1253
- }
1254
- /**
1255
- * Register a WhatsApp Business Account using a PIN.
1256
- *
1257
- * @param pin The registration PIN received via SMS or voice call
1258
- * @param dataLocalizationRegion Optional data localization region
1259
- * @returns Response indicating success or failure
1260
- *
1261
- * @example
1262
- * await whatsappClient.registration.register('123456', DataLocalizationRegionEnum.Asia);
1263
- */
1264
- async register(pin, dataLocalizationRegion) {
1265
- const body = {
1266
- messaging_product: "whatsapp",
1267
- pin,
1268
- ...dataLocalizationRegion && { data_localization_region: dataLocalizationRegion }
1269
- };
1270
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/register`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(body));
1271
- }
1272
- /**
1273
- * Deregister a WhatsApp Business Account.
1274
- *
1275
- * @returns Response indicating success or failure
1276
- *
1277
- * @example
1278
- * await whatsappClient.registration.deregister();
1279
- */
1280
- async deregister() {
1281
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}/deregister`, this.config[WabaConfigEnum.RequestTimeout], null);
1282
- }
1283
- };
1284
-
1285
- //#endregion
1286
- //#region src/api/registration/index.ts
1287
- var registration_default = RegistrationApi;
1288
-
1289
- //#endregion
1290
- //#region src/api/template/TemplateApi.ts
1291
- var TemplateApi = class extends BaseAPI {
1292
- endpoint = "message_templates";
1293
- constructor(config, client) {
1294
- super(config, client);
1295
- }
1296
- async getTemplate(templateId) {
1297
- return this.sendJson(HttpMethodsEnum.Get, `${templateId}`, this.config[WabaConfigEnum.RequestTimeout], null);
1298
- }
1299
- async updateTemplate(templateId, template) {
1300
- return this.sendJson(HttpMethodsEnum.Post, `${templateId}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(template));
1301
- }
1302
- async getTemplates(params) {
1303
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.BusinessAcctId]}/${this.endpoint}${objectToQueryString(params ?? {})}`, this.config[WabaConfigEnum.RequestTimeout], null);
1304
- }
1305
- async createTemplate(template) {
1306
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.BusinessAcctId]}/${this.endpoint}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(template));
1307
- }
1308
- async deleteTemplate(params) {
1309
- return this.sendJson(HttpMethodsEnum.Delete, `${this.config[WabaConfigEnum.BusinessAcctId]}/${this.endpoint}${objectToQueryString(params)}`, this.config[WabaConfigEnum.RequestTimeout], null);
1310
- }
1311
- };
1312
-
1313
- //#endregion
1314
- //#region src/api/template/factories/index.ts
1315
- function createHeader(options) {
1316
- const header = {
1317
- type: "HEADER",
1318
- format: options.format
1319
- };
1320
- if (options.text) {
1321
- header.text = options.text;
1322
- }
1323
- if (options.example) {
1324
- header.example = options.example;
1325
- }
1326
- return header;
1327
- }
1328
- function createBody(options) {
1329
- const body = {
1330
- type: "BODY",
1331
- text: options.text
1332
- };
1333
- if (options.example) {
1334
- body.example = options.example;
1335
- }
1336
- return body;
1337
- }
1338
- function createFooter(options) {
1339
- return {
1340
- type: "FOOTER",
1341
- text: options.text
1342
- };
1343
- }
1344
- function createButtons(options) {
1345
- const buttons = [];
1346
- if (options.phone_number) {
1347
- buttons.push({
1348
- type: "PHONE_NUMBER",
1349
- text: options.phone_number.text,
1350
- phone_number: options.phone_number.phone_number
1351
- });
1352
- }
1353
- if (options.url) {
1354
- const urlButton = {
1355
- type: "URL",
1356
- text: options.url.text,
1357
- url: options.url.url
1358
- };
1359
- if (options.url.example) {
1360
- urlButton.example = [options.url.example];
1361
- }
1362
- buttons.push(urlButton);
1363
- }
1364
- if (options.quick_reply) {
1365
- options.quick_reply.forEach((qr) => {
1366
- buttons.push({
1367
- type: "QUICK_REPLY",
1368
- text: qr.text
1369
- });
1370
- });
1371
- }
1372
- if (options.copy_code) {
1373
- buttons.push({
1374
- type: "COPY_CODE",
1375
- example: options.copy_code.example
1376
- });
1377
- }
1378
- if (options.flow) {
1379
- const flowButton = {
1380
- type: "FLOW",
1381
- text: options.flow.text
1382
- };
1383
- if (options.flow.flow_id) flowButton.flow_id = options.flow.flow_id;
1384
- if (options.flow.flow_name) flowButton.flow_name = options.flow.flow_name;
1385
- if (options.flow.flow_json) flowButton.flow_json = options.flow.flow_json;
1386
- if (options.flow.flow_action) flowButton.flow_action = options.flow.flow_action;
1387
- if (options.flow.navigate_screen) flowButton.navigate_screen = options.flow.navigate_screen;
1388
- buttons.push(flowButton);
1389
- }
1390
- if (options.mpm) {
1391
- buttons.push({ type: "MPM" });
1392
- }
1393
- if (options.otp) {
1394
- buttons.push({ type: "OTP" });
1395
- }
1396
- if (options.spm) {
1397
- buttons.push({ type: "SPM" });
1398
- }
1399
- return buttons.length > 0 ? [{
1400
- type: "BUTTONS",
1401
- buttons
1402
- }] : [];
1403
- }
1404
- function formatParameterExamples(parameters) {
1405
- return parameters.map((param) => {
1406
- switch (param.type) {
1407
- case "text": return param.value;
1408
- case "currency": return param.fallback_value;
1409
- case "date_time": return param.fallback_value;
1410
- case "image":
1411
- case "video":
1412
- case "document": return param.handle || param.link || "";
1413
- case "location": return param.name || "";
1414
- case "product": return param.product_retailer_id;
1415
- default: return "";
1416
- }
1417
- });
1418
- }
1419
- function createTemplate(options) {
1420
- const components = [];
1421
- if (options.header) {
1422
- components.push(createHeader(options.header));
1423
- }
1424
- if (options.body) {
1425
- components.push(createBody(options.body));
1426
- }
1427
- if (options.footer) {
1428
- components.push(createFooter(options.footer));
1429
- }
1430
- if (options.buttons) {
1431
- components.push(...createButtons(options.buttons));
1432
- }
1433
- if (options.carousel) {
1434
- const carouselComponents = [];
1435
- options.carousel.cards.forEach((card, index) => {
1436
- if (card.image || card.video || card.product) {
1437
- const format = card.image ? "IMAGE" : card.video ? "VIDEO" : "DOCUMENT";
1438
- const handle = card.image || card.video || card.product || "";
1439
- carouselComponents.push({
1440
- type: "HEADER",
1441
- format,
1442
- example: { header_handle: [handle] }
1443
- });
1444
- }
1445
- if (card.body) {
1446
- carouselComponents.push({
1447
- type: "BODY",
1448
- text: card.body,
1449
- example: card.bodyParameters ? { body_text: [formatParameterExamples(card.bodyParameters)] } : undefined
1450
- });
1451
- }
1452
- if (card.buttons) {
1453
- carouselComponents.push(...createButtons(card.buttons));
1454
- }
1455
- });
1456
- components.push(...carouselComponents);
1457
- }
1458
- if (options.limitedTimeOffer) {
1459
- components.push({
1460
- type: "LIMITED_TIME_OFFER",
1461
- limited_time_offer: { expiration_time_ms: options.limitedTimeOffer.expiration_time_ms }
1462
- });
1463
- }
1464
- return {
1465
- name: options.name,
1466
- language: options.language,
1467
- category: options.category,
1468
- components: components.length > 0 ? components : undefined
1469
- };
1470
- }
1471
- function createOTPTemplate(options) {
1472
- const components = [];
1473
- let bodyText = "*{{1}}* is your verification code.";
1474
- if (options.add_security_recommendation) {
1475
- bodyText += " For your security, do not share this code.";
1476
- }
1477
- if (options.code_expiration_minutes) {
1478
- bodyText += ` This code expires in ${options.code_expiration_minutes} minutes.`;
1479
- }
1480
- components.push({
1481
- type: "BODY",
1482
- text: bodyText,
1483
- example: { body_text: [["123456"]] }
1484
- });
1485
- components.push({
1486
- type: "BUTTONS",
1487
- buttons: [{ type: "OTP" }]
1488
- });
1489
- return {
1490
- name: options.name,
1491
- language: options.language,
1492
- category: CategoryEnum.Authentication,
1493
- components
1494
- };
1495
- }
1496
- function createAuthenticationTemplate(options) {
1497
- const components = [];
1498
- let bodyText = "Your security code is *{{1}}*.";
1499
- if (options.add_security_recommendation) {
1500
- bodyText += " Do not share this code with anyone.";
1501
- }
1502
- if (options.code_expiration_minutes) {
1503
- bodyText += ` This code expires in ${options.code_expiration_minutes} minutes.`;
1504
- }
1505
- components.push({
1506
- type: "BODY",
1507
- text: bodyText,
1508
- example: { body_text: [["ABCD1234"]] }
1509
- });
1510
- if (options.copy_code_button) {
1511
- components.push({
1512
- type: "BUTTONS",
1513
- buttons: [{
1514
- type: "COPY_CODE",
1515
- example: "ABCD1234"
1516
- }]
1517
- });
1518
- }
1519
- return {
1520
- name: options.name,
1521
- language: options.language,
1522
- category: CategoryEnum.Authentication,
1523
- components
1524
- };
1525
- }
1526
- function createCatalogTemplate(options) {
1527
- const components = [];
1528
- if (options.header) {
1529
- components.push(createHeader({
1530
- ...options.header,
1531
- format: "TEXT"
1532
- }));
1533
- }
1534
- components.push(createBody(options.body));
1535
- if (options.footer) {
1536
- components.push(createFooter(options.footer));
1537
- }
1538
- components.push({
1539
- type: "BUTTONS",
1540
- buttons: [{
1541
- type: "CATALOG",
1542
- action: { thumbnail_product_retailer_id: options.thumbnail_product_retailer_id }
1543
- }]
1544
- });
1545
- return {
1546
- name: options.name,
1547
- language: options.language,
1548
- category: CategoryEnum.Marketing,
1549
- components
1550
- };
1551
- }
1552
- function createCouponTemplate(options) {
1553
- const components = [];
1554
- if (options.header) {
1555
- components.push(createHeader({
1556
- ...options.header,
1557
- format: "TEXT"
1558
- }));
1559
- }
1560
- components.push(createBody(options.body));
1561
- if (options.footer) {
1562
- components.push(createFooter(options.footer));
1563
- }
1564
- components.push({
1565
- type: "BUTTONS",
1566
- buttons: [{
1567
- type: "COPY_CODE",
1568
- example: options.coupon_code
1569
- }]
1570
- });
1571
- return {
1572
- name: options.name,
1573
- language: options.language,
1574
- category: CategoryEnum.Marketing,
1575
- components
1576
- };
1577
- }
1578
- function createLimitedTimeOfferTemplate(options) {
1579
- const components = [];
1580
- components.push({
1581
- type: "LIMITED_TIME_OFFER",
1582
- limited_time_offer: { expiration_time_ms: options.expiration_time_ms }
1583
- });
1584
- if (options.header) {
1585
- components.push(createHeader({
1586
- ...options.header,
1587
- format: "TEXT"
1588
- }));
1589
- }
1590
- components.push(createBody(options.body));
1591
- if (options.footer) {
1592
- components.push(createFooter(options.footer));
1593
- }
1594
- return {
1595
- name: options.name,
1596
- language: options.language,
1597
- category: CategoryEnum.Marketing,
1598
- components
1599
- };
1600
- }
1601
- function createMediaCardCarouselTemplate(options) {
1602
- const components = [];
1603
- const carouselCards = [];
1604
- options.cards.forEach((card, index) => {
1605
- const cardComponents = [];
1606
- cardComponents.push({
1607
- type: "HEADER",
1608
- format: card.header.format,
1609
- example: card.header.example
1610
- });
1611
- cardComponents.push(createBody(card.body));
1612
- if (card.buttons) {
1613
- cardComponents.push(...createButtons(card.buttons));
1614
- }
1615
- carouselCards.push({
1616
- card_index: index,
1617
- components: cardComponents
1618
- });
1619
- });
1620
- components.push({
1621
- type: "CAROUSEL",
1622
- cards: carouselCards
1623
- });
1624
- return {
1625
- name: options.name,
1626
- language: options.language,
1627
- category: CategoryEnum.Marketing,
1628
- components
1629
- };
1630
- }
1631
- function createMPMTemplate(options) {
1632
- const components = [];
1633
- if (options.header) {
1634
- components.push(createHeader({
1635
- ...options.header,
1636
- format: "TEXT"
1637
- }));
1638
- }
1639
- components.push(createBody(options.body));
1640
- if (options.footer) {
1641
- components.push(createFooter(options.footer));
1642
- }
1643
- components.push({
1644
- type: "BUTTONS",
1645
- buttons: [{
1646
- type: "MPM",
1647
- action: {
1648
- thumbnail_product_retailer_id: options.thumbnail_product_retailer_id,
1649
- sections: options.sections
1650
- }
1651
- }]
1652
- });
1653
- return {
1654
- name: options.name,
1655
- language: options.language,
1656
- category: CategoryEnum.Marketing,
1657
- components
1658
- };
1659
- }
1660
- function createProductCardCarouselTemplate(options) {
1661
- const components = [];
1662
- if (options.header) {
1663
- components.push(createHeader({
1664
- ...options.header,
1665
- format: "TEXT"
1666
- }));
1667
- }
1668
- components.push(createBody(options.body));
1669
- if (options.footer) {
1670
- components.push(createFooter(options.footer));
1671
- }
1672
- const carouselCards = options.cards.map((card, index) => ({
1673
- card_index: index,
1674
- components: [{
1675
- type: "HEADER",
1676
- format: "PRODUCT",
1677
- example: { header_handle: [card.product_retailer_id] }
1678
- }]
1679
- }));
1680
- components.push({
1681
- type: "CAROUSEL",
1682
- cards: carouselCards
1683
- });
1684
- return {
1685
- name: options.name,
1686
- language: options.language,
1687
- category: CategoryEnum.Marketing,
1688
- components
1689
- };
1690
- }
1691
- function createSPMTemplate(options) {
1692
- const components = [];
1693
- if (options.header) {
1694
- components.push(createHeader({
1695
- ...options.header,
1696
- format: "TEXT"
1697
- }));
1698
- }
1699
- components.push(createBody(options.body));
1700
- if (options.footer) {
1701
- components.push(createFooter(options.footer));
1702
- }
1703
- components.push({
1704
- type: "BUTTONS",
1705
- buttons: [{
1706
- type: "SPM",
1707
- action: { product_retailer_id: options.product_retailer_id }
1708
- }]
1709
- });
1710
- return {
1711
- name: options.name,
1712
- language: options.language,
1713
- category: CategoryEnum.Marketing,
1714
- components
1715
- };
1716
- }
1717
-
1718
- //#endregion
1719
- //#region src/api/twoStepVerification/TwoStepVerificationApi.ts
1720
- /**
1721
- * API for managing WhatsApp Two-Step Verification.
1722
- *
1723
- * This API allows you to:
1724
- * - Set a two-step verification PIN code
1725
- * - Manage two-step verification settings
1726
- */
1727
- var TwoStepVerificationApi = class extends BaseAPI {
1728
- constructor(config, client) {
1729
- super(config, client);
1730
- }
1731
- /**
1732
- * Set a two-step verification PIN code.
1733
- *
1734
- * @param pin The PIN code to set for two-step verification (6-digit numeric string)
1735
- * @returns Response indicating success or failure
1736
- *
1737
- * @example
1738
- * await whatsappClient.twoStepVerification.setTwoStepVerificationCode('123456');
1739
- */
1740
- async setTwoStepVerificationCode(pin) {
1741
- const body = { pin };
1742
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.PhoneNumberId]}`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(body));
1743
- }
1744
- };
1745
-
1746
- //#endregion
1747
- //#region src/api/twoStepVerification/index.ts
1748
- var twoStepVerification_default = TwoStepVerificationApi;
1749
-
1750
- //#endregion
1751
- //#region src/api/waba/WabaApi.ts
1752
- /**
1753
- * API for managing WhatsApp Business Account (WABA).
1754
- *
1755
- * This API allows you to:
1756
- * - Get WABA account information
1757
- * - Manage WABA subscriptions
1758
- * - Subscribe/unsubscribe from WABA webhooks
1759
- * - Update subscription settings
1760
- */
1761
- var WabaApi = class extends BaseAPI {
1762
- constructor(config, client) {
1763
- super(config, client);
1764
- }
1765
- /**
1766
- * Retrieve WhatsApp Business Account information.
1767
- *
1768
- * @param fields Optional array of specific fields to retrieve
1769
- * @returns WABA account information including status, health, verification status, etc.
1770
- *
1771
- * @example
1772
- * const account = await whatsappClient.waba.getWabaAccount(['id', 'name', 'status']);
1773
- */
1774
- async getWabaAccount(fields) {
1775
- const queryString = buildFieldsQueryString(fields)?.replace(/,/g, "%2C");
1776
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.BusinessAcctId]}${queryString}`, this.config[WabaConfigEnum.RequestTimeout], null);
1777
- }
1778
- /**
1779
- * Get all WABA subscriptions for the business account.
1780
- *
1781
- * @returns List of all subscribed apps and their configurations
1782
- *
1783
- * @example
1784
- * const subscriptions = await whatsappClient.waba.getAllWabaSubscriptions();
1785
- */
1786
- async getAllWabaSubscriptions() {
1787
- return this.sendJson(HttpMethodsEnum.Get, `${this.config[WabaConfigEnum.BusinessAcctId]}/subscribed_apps`, this.config[WabaConfigEnum.RequestTimeout], null);
1788
- }
1789
- /**
1790
- * Update WABA subscription configuration.
1791
- *
1792
- * @param params Configuration parameters including callback URI and verify token
1793
- * @returns Response indicating success or failure
1794
- *
1795
- * @example
1796
- * await whatsappClient.waba.updateWabaSubscription({
1797
- * override_callback_uri: 'https://example.com/webhook',
1798
- * verify_token: 'your_verify_token'
1799
- * });
1800
- */
1801
- async updateWabaSubscription({ override_callback_uri, verify_token }) {
1802
- const body = {
1803
- override_callback_uri,
1804
- verify_token
1805
- };
1806
- return this.sendJson(HttpMethodsEnum.Post, `${this.config[WabaConfigEnum.BusinessAcctId]}/subscribed_apps`, this.config[WabaConfigEnum.RequestTimeout], JSON.stringify(body));
1807
- }
1808
- /**
1809
- * Unsubscribe from WABA webhooks.
1810
- *
1811
- * @returns Response indicating success or failure
1812
- *
1813
- * @example
1814
- * await whatsappClient.waba.unsubscribeFromWaba();
1815
- */
1816
- async unsubscribeFromWaba() {
1817
- return this.sendJson(HttpMethodsEnum.Delete, `${this.config[WabaConfigEnum.BusinessAcctId]}/subscribed_apps`, this.config[WabaConfigEnum.RequestTimeout], null);
1818
- }
1819
- };
1820
-
1821
- //#endregion
1822
- //#region src/api/waba/index.ts
1823
- var waba_default = WabaApi;
1824
-
1825
- //#endregion
1826
- //#region src/utils/logoConsole.ts
1827
- function printLogo() {
1828
- if (process.env.NODE_ENV === "test" || process.env.VITEST === "true" || typeof global !== "undefined" && global.__VITEST__) {
1829
- return;
1830
- }
1831
- console.log("\x1B[36m%s\x1B[0m", `
1
+ import{__export as e}from"./chunk-CTAAG5j7.js";import{Agent as t}from"https";import{readFileSync as n}from"fs";import{join as r}from"path";import*as i from"crypto";import a from"crypto";var o=e({AudioMediaTypesEnum:()=>oe,BusinessVerticalEnum:()=>pe,ButtonPositionEnum:()=>p,CategoryEnum:()=>s,ComponentTypesEnum:()=>h,ConversationTypesEnum:()=>ee,CurrencyCodesEnum:()=>de,DataLocalizationRegionEnum:()=>fe,DocumentMediaTypesEnum:()=>ae,HttpMethodsEnum:()=>l,ImageMediaTypesEnum:()=>ie,InteractiveTypesEnum:()=>f,LanguagesEnum:()=>_,MessageTypesEnum:()=>u,ParametersTypesEnum:()=>d,ReferralSourceTypesEnum:()=>le,RequestCodeMethodsEnum:()=>ue,StatusEnum:()=>te,StickerMediaTypesEnum:()=>re,SubTypeEnum:()=>m,SystemChangeTypesEnum:()=>ce,TemplateStatusEnum:()=>c,VideoMediaTypesEnum:()=>ne,WabaConfigEnum:()=>g,WebhookTypesEnum:()=>se});let s=function(e){return e.Authentication=`AUTHENTICATION`,e.Marketing=`MARKETING`,e.Utility=`UTILITY`,e}({}),c=function(e){return e.Approved=`APPROVED`,e.Pending=`PENDING`,e.Rejected=`REJECTED`,e}({}),l=function(e){return e.Get=`GET`,e.Post=`POST`,e.Put=`PUT`,e.Delete=`DELETE`,e}({}),u=function(e){return e.Audio=`audio`,e.Contacts=`contacts`,e.Document=`document`,e.Image=`image`,e.Interactive=`interactive`,e.Location=`location`,e.Reaction=`reaction`,e.Sticker=`sticker`,e.Template=`template`,e.Text=`text`,e.Video=`video`,e.Button=`button`,e.Order=`order`,e.System=`system`,e.Unknown=`unknown`,e.Statuses=`statuses`,e[`*`]=`*`,e}({}),d=function(e){return e.Action=`ACTION`,e.CouponCode=`COUPON_CODE`,e.Currency=`CURRENCY`,e.DateTime=`DATE_TIME`,e.Document=`DOCUMENT`,e.ExpirationTimeMs=`EXPIRATION_TIME_MS`,e.Image=`IMAGE`,e.LimitedTimeOffer=`LIMITED_TIME_OFFER`,e.Location=`LOCATION`,e.OrderStatus=`ORDER_STATUS`,e.Payload=`PAYLOAD`,e.Product=`PRODUCT`,e.Text=`TEXT`,e.TtlMinutes=`TTL_MINUTES`,e.Video=`VIDEO`,e.WebviewInteraction=`WEBVIEW_INTERACTION`,e.WebviewPresentation=`WEBVIEW_PRESENTATION`,e}({}),f=function(e){return e.Button=`button`,e.List=`list`,e.Product=`product`,e.ProductList=`product_list`,e.CtaUrl=`cta_url`,e.LocationRequest=`location_request_message`,e.AddressMessage=`address_message`,e.Flow=`flow`,e}({}),p=function(e){return e[e.First=1]=`First`,e[e.Second=2]=`Second`,e[e.Third=3]=`Third`,e[e.Fourth=4]=`Fourth`,e[e.Fifth=5]=`Fifth`,e}({}),m=function(e){return e.Catalog=`CATALOG`,e.CopyCode=`COPY_CODE`,e.Flow=`FLOW`,e.Mpm=`MPM`,e.OrderDetails=`ORDER_DETAILS`,e.QuickReply=`QUICK_REPLY`,e.Reminder=`REMINDER`,e.Url=`URL`,e.VoiceCall=`VOICE_CALL`,e}({}),h=function(e){return e.Header=`HEADER`,e.Body=`BODY`,e.Button=`BUTTON`,e.Footer=`FOOTER`,e}({}),g=function(e){return e.AppId=`M4D_APP_ID`,e.Port=`WA_PORT`,e.AppSecret=`M4D_APP_SECRET`,e.PhoneNumberId=`WA_PHONE_NUMBER_ID`,e.BusinessAcctId=`WA_BUSINESS_ACCOUNT_ID`,e.APIVersion=`CLOUD_API_VERSION`,e.AccessToken=`CLOUD_API_ACCESS_TOKEN`,e.WebhookEndpoint=`WEBHOOK_ENDPOINT`,e.WebhookVerificationToken=`WEBHOOK_VERIFICATION_TOKEN`,e.ListenerPort=`LISTENER_PORT`,e.MaxRetriesAfterWait=`MAX_RETRIES_AFTER_WAIT`,e.RequestTimeout=`REQUEST_TIMEOUT`,e.Debug=`DEBUG`,e.PrivatePem=`FLOW_API_PRIVATE_PEM`,e.Passphrase=`FLOW_API_PASSPHRASE`,e}({}),ee=function(e){return e.BusinessInitiated=`business_initiated`,e.CustomerInitiated=`customer_initiated`,e.ReferralConversion=`referral_conversion`,e}({}),te=function(e){return e.Delivered=`delivered`,e.Read=`read`,e.Sent=`sent`,e}({}),ne=function(e){return e.Mp4=`video/mp4`,e.Threegp=`video/3gp`,e}({}),re=function(e){return e.Webp=`image/webp`,e}({}),ie=function(e){return e.Jpeg=`image/jpeg`,e.Png=`image/png`,e}({}),ae=function(e){return e.Text=`text/plain`,e.Pdf=`application/pdf`,e.Ppt=`application/vnd.ms-powerpoint`,e.Word=`application/msword`,e.Excel=`application/vnd.ms-excel`,e.OpenDoc=`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,e.OpenPres=`application/vnd.openxmlformats-officedocument.presentationml.presentation`,e.OpenSheet=`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`,e}({}),oe=function(e){return e.Aac=`audio/aac`,e.Mp4=`audio/mp4`,e.Mpeg=`audio/mpeg`,e.Amr=`audio/amr`,e.Ogg=`audio/ogg`,e}({}),se=function(e){return e.Audio=`audio`,e.Button=`button`,e.Document=`document`,e.Text=`text`,e.Image=`image`,e.Interactive=`interactive`,e.Order=`order`,e.Sticker=`sticker`,e.System=`system`,e.Unknown=`unknown`,e.Video=`video`,e}({}),ce=function(e){return e.CustomerChangedNumber=`customer_changed_number`,e.CustomerIdentityChanged=`customer_identity_changed`,e}({}),le=function(e){return e.Ad=`ad`,e.Post=`post`,e}({}),ue=function(e){return e.Sms=`SMS`,e.Voice=`VOICE`,e}({}),_=function(e){return e.Afrikaans=`af`,e.Albanian=`sq`,e.Arabic=`ar`,e.Azerbaijani=`az`,e.Bengali=`bn`,e.Bulgarian=`bg`,e.Catalan=`ca`,e.Chinese_CHN=`zh_CN`,e.Chinese_HKG=`zh_HK`,e.Chinese_TAI=`zh_TW`,e.Croatian=`hr`,e.Czech=`cs`,e.Danish=`da`,e.Dutch=`nl`,e.English=`en`,e.English_UK=`en_GB`,e.English_US=`en_US`,e.Estonian=`et`,e.Filipino=`fil`,e.Finnish=`fi`,e.French=`fr`,e.Georgian=`ka`,e.German=`de`,e.Greek=`el`,e.Gujarati=`gu`,e.Hausa=`ha`,e.Hebrew=`he`,e.Hindi=`hi`,e.Hungarian=`hu`,e.Indonesian=`id`,e.Irish=`ga`,e.Italian=`it`,e.Japanese=`ja`,e.Kannada=`kn`,e.Kazakh=`kk`,e.Kinyarwanda=`rw_RW`,e.Korean=`ko`,e.Kyrgyz_Kyrgyzstan=`ky_KG`,e.Lao=`lo`,e.Latvian=`lv`,e.Lithuanian=`lt`,e.Macedonian=`mk`,e.Malay=`ms`,e.Malayalam=`ml`,e.Marathi=`mr`,e.Norwegian=`nb`,e.Persian=`fa`,e.Polish=`pl`,e.Portuguese_BR=`pt_BR`,e.Portuguese_POR=`pt_PT`,e.Punjabi=`pa`,e.Romanian=`ro`,e.Russian=`ru`,e.Serbian=`sr`,e.Slovak=`sk`,e.Slovenian=`sl`,e.Spanish=`es`,e.Spanish_ARG=`es_AR`,e.Spanish_SPA=`es_ES`,e.Spanish_MEX=`es_MX`,e.Swahili=`sw`,e.Swedish=`sv`,e.Tamil=`ta`,e.Telugu=`te`,e.Thai=`th`,e.Turkish=`tr`,e.Ukrainian=`uk`,e.Urdu=`ur`,e.Uzbek=`uz`,e.Vietnamese=`vi`,e.Zulu=`zu`,e}({}),de=function(e){return e.AFN=`AFN`,e.EUR=`EUR`,e.ALL=`ALL`,e.DZD=`DZD`,e.USD=`USD`,e.AOA=`AOA`,e.XCD=`XCD`,e.ARS=`ARS`,e.AMD=`AMD`,e.AWG=`AWG`,e.AUD=`AUD`,e.AZN=`AZN`,e.BSD=`BSD`,e.BHD=`BHD`,e.BDT=`BDT`,e.BBD=`BBD`,e.BYN=`BYN`,e.BZD=`BZD`,e.XOF=`XOF`,e.BMD=`BMD`,e.INR=`INR`,e.BTN=`BTN`,e.BOB=`BOB`,e.BOV=`BOV`,e.BAM=`BAM`,e.BWP=`BWP`,e.NOK=`NOK`,e.BRL=`BRL`,e.BND=`BND`,e.BGN=`BGN`,e.BIF=`BIF`,e.CVE=`CVE`,e.KHR=`KHR`,e.XAF=`XAF`,e.CAD=`CAD`,e.KYD=`KYD`,e.CLP=`CLP`,e.CLF=`CLF`,e.CNY=`CNY`,e.COP=`COP`,e.COU=`COU`,e.KMF=`KMF`,e.CDF=`CDF`,e.NZD=`NZD`,e.CRC=`CRC`,e.HRK=`HRK`,e.CUP=`CUP`,e.CUC=`CUC`,e.ANG=`ANG`,e.CZK=`CZK`,e.DKK=`DKK`,e.DJF=`DJF`,e.DOP=`DOP`,e.EGP=`EGP`,e.SVC=`SVC`,e.ERN=`ERN`,e.SZL=`SZL`,e.ETB=`ETB`,e.FKP=`FKP`,e.FJD=`FJD`,e.XPF=`XPF`,e.GMD=`GMD`,e.GEL=`GEL`,e.GHS=`GHS`,e.GIP=`GIP`,e.GTQ=`GTQ`,e.GBP=`GBP`,e.GNF=`GNF`,e.GYD=`GYD`,e.HTG=`HTG`,e.HNL=`HNL`,e.HKD=`HKD`,e.HUF=`HUF`,e.ISK=`ISK`,e.IDR=`IDR`,e.XDR=`XDR`,e.IRR=`IRR`,e.IQD=`IQD`,e.ILS=`ILS`,e.JMD=`JMD`,e.JPY=`JPY`,e.JOD=`JOD`,e.KZT=`KZT`,e.KES=`KES`,e.KPW=`KPW`,e.KRW=`KRW`,e.KWD=`KWD`,e.KGS=`KGS`,e.LAK=`LAK`,e.LBP=`LBP`,e.LSL=`LSL`,e.ZAR=`ZAR`,e.LRD=`LRD`,e.LYD=`LYD`,e.CHF=`CHF`,e.MOP=`MOP`,e.MKD=`MKD`,e.MGA=`MGA`,e.MWK=`MWK`,e.MYR=`MYR`,e.MVR=`MVR`,e.MRU=`MRU`,e.MUR=`MUR`,e.XUA=`XUA`,e.MXN=`MXN`,e.MXV=`MXV`,e.MDL=`MDL`,e.MNT=`MNT`,e.MAD=`MAD`,e.MZN=`MZN`,e.MMK=`MMK`,e.NAD=`NAD`,e.NPR=`NPR`,e.NIO=`NIO`,e.NGN=`NGN`,e.OMR=`OMR`,e.PKR=`PKR`,e.PAB=`PAB`,e.PGK=`PGK`,e.PYG=`PYG`,e.PEN=`PEN`,e.PHP=`PHP`,e.PLN=`PLN`,e.QAR=`QAR`,e.RON=`RON`,e.RUB=`RUB`,e.RWF=`RWF`,e.SHP=`SHP`,e.WST=`WST`,e.STN=`STN`,e.SAR=`SAR`,e.RSD=`RSD`,e.SCR=`SCR`,e.SLL=`SLL`,e.SGD=`SGD`,e.XSU=`XSU`,e.SBD=`SBD`,e.SOS=`SOS`,e.SSP=`SSP`,e.LKR=`LKR`,e.SDG=`SDG`,e.SRD=`SRD`,e.SEK=`SEK`,e.CHE=`CHE`,e.CHW=`CHW`,e.SYP=`SYP`,e.TWD=`TWD`,e.TJS=`TJS`,e.TZS=`TZS`,e.THB=`THB`,e.TOP=`TOP`,e.TTD=`TTD`,e.TND=`TND`,e.TRY=`TRY`,e.TMT=`TMT`,e.UGX=`UGX`,e.UAH=`UAH`,e.AED=`AED`,e.USN=`USN`,e.UYU=`UYU`,e.UYI=`UYI`,e.UYW=`UYW`,e.UZS=`UZS`,e.VUV=`VUV`,e.VES=`VES`,e.VND=`VND`,e.YER=`YER`,e.ZMW=`ZMW`,e.ZWL=`ZWL`,e.XBA=`XBA`,e.XBB=`XBB`,e.XBC=`XBC`,e.XBD=`XBD`,e.XTS=`XTS`,e.XXX=`XXX`,e.XAU=`XAU`,e.XPD=`XPD`,e.XPT=`XPT`,e.XAG=`XAG`,e.AFA=`AFA`,e.FIM=`FIM`,e.ALK=`ALK`,e.ADP=`ADP`,e.ESP=`ESP`,e.FRF=`FRF`,e.AOK=`AOK`,e.AON=`AON`,e.AOR=`AOR`,e.ARA=`ARA`,e.ARP=`ARP`,e.ARY=`ARY`,e.RUR=`RUR`,e.ATS=`ATS`,e.AYM=`AYM`,e.AZM=`AZM`,e.BYB=`BYB`,e.BYR=`BYR`,e.BEC=`BEC`,e.BEF=`BEF`,e.BEL=`BEL`,e.BOP=`BOP`,e.BAD=`BAD`,e.BRB=`BRB`,e.BRC=`BRC`,e.BRE=`BRE`,e.BRN=`BRN`,e.BRR=`BRR`,e.BGJ=`BGJ`,e.BGK=`BGK`,e.BGL=`BGL`,e.BUK=`BUK`,e.HRD=`HRD`,e.CYP=`CYP`,e.CSJ=`CSJ`,e.CSK=`CSK`,e.ECS=`ECS`,e.ECV=`ECV`,e.GQE=`GQE`,e.EEK=`EEK`,e.XEU=`XEU`,e.GEK=`GEK`,e.DDM=`DDM`,e.DEM=`DEM`,e.GHC=`GHC`,e.GHP=`GHP`,e.GRD=`GRD`,e.GNE=`GNE`,e.GNS=`GNS`,e.GWE=`GWE`,e.GWP=`GWP`,e.ITL=`ITL`,e.ISJ=`ISJ`,e.IEP=`IEP`,e.ILP=`ILP`,e.ILR=`ILR`,e.LAJ=`LAJ`,e.LVL=`LVL`,e.LVR=`LVR`,e.LSM=`LSM`,e.ZAL=`ZAL`,e.LTL=`LTL`,e.LTT=`LTT`,e.LUC=`LUC`,e.LUF=`LUF`,e.LUL=`LUL`,e.MGF=`MGF`,e.MVQ=`MVQ`,e.MLF=`MLF`,e.MTL=`MTL`,e.MTP=`MTP`,e.MRO=`MRO`,e.MXP=`MXP`,e.MZE=`MZE`,e.MZM=`MZM`,e.NLG=`NLG`,e.NIC=`NIC`,e.PEH=`PEH`,e.PEI=`PEI`,e.PES=`PES`,e.PLZ=`PLZ`,e.PTE=`PTE`,e.ROK=`ROK`,e.ROL=`ROL`,e.STD=`STD`,e.CSD=`CSD`,e.SKK=`SKK`,e.SIT=`SIT`,e.RHD=`RHD`,e.ESA=`ESA`,e.ESB=`ESB`,e.SDD=`SDD`,e.SDP=`SDP`,e.SRG=`SRG`,e.CHC=`CHC`,e.TJR=`TJR`,e.TPE=`TPE`,e.TRL=`TRL`,e.TMM=`TMM`,e.UGS=`UGS`,e.UGW=`UGW`,e.UAK=`UAK`,e.SUR=`SUR`,e.USS=`USS`,e.UYN=`UYN`,e.UYP=`UYP`,e.VEB=`VEB`,e.VEF=`VEF`,e.VNC=`VNC`,e.YDD=`YDD`,e.YUD=`YUD`,e.YUM=`YUM`,e.YUN=`YUN`,e.ZRN=`ZRN`,e.ZRZ=`ZRZ`,e.ZMK=`ZMK`,e.ZWC=`ZWC`,e.ZWD=`ZWD`,e.ZWN=`ZWN`,e.ZWR=`ZWR`,e.XFO=`XFO`,e.XRE=`XRE`,e.XFU=`XFU`,e}({}),fe=function(e){return e.AU=`AU`,e.ID=`ID`,e.IN=`IN`,e.JP=`JP`,e.SG=`SG`,e.KR=`KR`,e.DE=`DE`,e.CH=`CH`,e.GB=`GB`,e.BR=`BR`,e.BH=`BH`,e.ZA=`ZA`,e.AE=`AE`,e.CA=`CA`,e}({}),pe=function(e){return e.ALCOHOL=`ALCOHOL`,e.APPAREL=`APPAREL`,e.AUTO=`AUTO`,e.BEAUTY=`BEAUTY`,e.EDU=`EDU`,e.ENTERTAIN=`ENTERTAIN`,e.EVENT_PLAN=`EVENT_PLAN`,e.FINANCE=`FINANCE`,e.GOVT=`GOVT`,e.GROCERY=`GROCERY`,e.HEALTH=`HEALTH`,e.HOTEL=`HOTEL`,e.NONPROFIT=`NONPROFIT`,e.ONLINE_GAMBLING=`ONLINE_GAMBLING`,e.OTC_DRUGS=`OTC_DRUGS`,e.OTHER=`OTHER`,e.PHYSICAL_GAMBLING=`PHYSICAL_GAMBLING`,e.PROF_SERVICES=`PROF_SERVICES`,e.RESTAURANT=`RESTAURANT`,e.RETAIL=`RETAIL`,e.TRAVEL=`TRAVEL`,e}({});var v=class{name;debug;constructor(e,t=!1){this.name=e,this.debug=t}log(...e){if(this.debug){let t=`[ ${Date.now()} ]`;this.name&&(t+=` - ${this.name}`),console.log.apply(console,[t,`: `,...e])}}error(...e){let t=`[ ${Date.now()} ] - ERROR`;this.name&&(t+=` - ${this.name}`),console.error.apply(console,[t,`: `,...e])}warn(...e){let t=`[ ${Date.now()} ] - WARN`;this.name&&(t+=` - ${this.name}`),console.warn.apply(console,[t,`: `,...e])}info(...e){let t=`[ ${Date.now()} ] - INFO`;this.name&&(t+=` - ${this.name}`),console.info.apply(console,[t,`: `,...e])}};const me=new v(`UTILS`,process.env.DEBUG===`true`||!1),he=e=>{if(!process.env[g.AccessToken]&&!e?.accessToken)throw me.log(`Environmental variable: CLOUD_API_ACCESS_TOKEN and/or access token argument is undefined.`),Error(`Missing WhatsApp access token.`)},ge=e=>(he(e),{[g.AppId]:e?.appId||process.env.M4D_APP_ID||``,[g.AppSecret]:e?.appSecret||process.env.M4D_APP_SECRET||``,[g.PhoneNumberId]:e?.phoneNumberId||Number(process.env.WA_PHONE_NUMBER_ID),[g.BusinessAcctId]:e?.businessAcctId||process.env.WA_BUSINESS_ACCOUNT_ID||``,[g.APIVersion]:e?.apiVersion||process.env.CLOUD_API_VERSION||``,[g.AccessToken]:e?.accessToken||process.env.CLOUD_API_ACCESS_TOKEN||``,[g.WebhookEndpoint]:e?.webhookEndpoint||process.env.WEBHOOK_ENDPOINT||``,[g.WebhookVerificationToken]:e?.webhookVerificationToken||process.env.WEBHOOK_VERIFICATION_TOKEN||``,[g.ListenerPort]:e?.listenerPort||parseInt(process.env.LISTENER_PORT||``)||3e3,[g.MaxRetriesAfterWait]:e?.maxRetriesAfterWait||parseInt(process.env.MAX_RETRIES_AFTER_WAIT||``)||30,[g.RequestTimeout]:e?.requestTimeout||parseInt(process.env.REQUEST_TIMEOUT||``)||2e4,[g.Debug]:e?.debug||process.env.DEBUG===`true`,[g.PrivatePem]:e?.privatePem||process.env.FLOW_API_PRIVATE_PEM||``,[g.Passphrase]:e?.passphrase||process.env.FLOW_API_PASSPHRASE||``});function _e(e){let t=[[`App ID`,e[g.AppId]||`Not Set`],[`Phone Number ID`,e[g.PhoneNumberId]?.toString()||`Not Set`],[`Business Account ID`,e[g.BusinessAcctId]||`Not Set`],[`API Version`,e[g.APIVersion]||`Not Set`],[`Access Token`,e[g.AccessToken]?`${e[g.AccessToken].substring(0,20)}...`:`Not Set`],[`Webhook Endpoint`,e[g.WebhookEndpoint]||`Not Set`],[`Webhook Verification Token`,e[g.WebhookVerificationToken]?`${e[g.WebhookVerificationToken].substring(0,10)}...`:`Not Set`],[`Listener Port`,e[g.ListenerPort]?.toString()||`Not Set`],[`Debug Mode`,e[g.Debug]?`Enabled`:`Disabled`],[`Max Retries`,e[g.MaxRetriesAfterWait]?.toString()||`Not Set`],[`Request Timeout`,e[g.RequestTimeout]?`${e[g.RequestTimeout]}ms`:`Not Set`],[`Private PEM`,e[g.PrivatePem]?`Configured`:`Not Set`],[`Passphrase`,e[g.Passphrase]?`Configured`:`Not Set`]],n=Math.max(...t.map(([e])=>e?.length||0)),r=Math.max(...t.map(([,e])=>e?.length||0)),i=Math.max(n,20),a=Math.max(r,30),o=`┌${`─`.repeat(i+2)}┬${`─`.repeat(a+2)}┐`,s=`├${`─`.repeat(i+2)}┼${`─`.repeat(a+2)}┤`,c=`└${`─`.repeat(i+2)}┴${`─`.repeat(a+2)}┘`,l=`│ ${`Configuration`.padEnd(i)} │ ${`Value`.padEnd(a)} │`,u=t.map(([e,t])=>`│ ${e?.padEnd(i)} │ ${t?.padEnd(a)} │`);return[o,l,s,...u,c].join(`
2
+ `)}function ve(e){return typeof e==`object`&&!!e&&`error`in e&&typeof e.error==`object`&&e.error!=null&&`message`in e.error&&typeof e.error.message==`string`&&`type`in e.error&&typeof e.error.type==`string`&&`code`in e.error&&typeof e.error.code==`number`&&`fbtrace_id`in e.error&&typeof e.error.fbtrace_id==`string`&&(!(`error_data`in e.error)||typeof e.error.error_data==`object`&&e.error.error_data!=null&&`messaging_product`in e.error.error_data&&e.error.error_data.messaging_product===`whatsapp`&&`details`in e.error.error_data&&typeof e.error.error_data.details==`string`)&&(!(`error_subcode`in e.error)||typeof e.error.error_subcode==`number`)}const ye=new v(`HttpsClient`,process.env.DEBUG===`true`||!1);var be=class{agent;constructor(){this.agent=new t({keepAlive:!0})}clearSockets(){return this.agent.destroy(),!0}async sendRequest(e,t,n,r,i,a){let o=`https://${e}/${t}`,s=new AbortController,c=setTimeout(()=>s.abort(),i);try{let e=await fetch(o,{method:n,headers:r,body:a,signal:s.signal});return ye.log(`${n} : ${o} - ${JSON.stringify(e)}`),clearTimeout(c),new xe(e)}catch(e){throw ye.error(`${n} : ${o} - ${JSON.stringify(e)}`),e}}},xe=class{res;respStatusCode;respHeaders;constructor(e){this.res=e,this.respStatusCode=e.status,this.respHeaders=Object.fromEntries(e.headers.entries())}statusCode(){return this.respStatusCode}headers(){return this.respHeaders}rawResponse(){return this.res}async json(){try{return await this.res.json()}catch(e){throw Error(`Failed to parse response body to JSON: `+e.message)}}};const Se=new v(`REQUESTER`,process.env.DEBUG===`true`||!1);var Ce=class{client;accessToken;phoneNumberId;businessAcctId;apiVersion;userAgent;host;protocol=`https:`;constructor(e,t,n,r,i){this.client=new be,this.host=`graph.facebook.com`,this.apiVersion=e||`22`,this.phoneNumberId=t,this.accessToken=n,this.businessAcctId=r,this.userAgent=i}buildHeader(e,t){let n={Authorization:`Bearer ${this.accessToken}`,"User-Agent":this.userAgent};return e!==`multipart/form-data`&&(n[`Content-Type`]=e),t&&Object.assign(n,t),n}buildCAPIPath(e){return`v${this.apiVersion}.0/${e}`}async sendRequest(e,t,n,r,i=`application/json`,a){let o=i;r instanceof FormData?o=`multipart/form-data`:typeof r==`string`&&r.startsWith(`<?xml`)&&(o=`application/xml`);let s=`${this.protocol.toLowerCase()}//${this.host}/${this.buildCAPIPath(t)}`;Se.log(`${e} : ${s} (${o})`);try{let i=await this.client.sendRequest(this.host,this.buildCAPIPath(t),e,this.buildHeader(o,a),n,e===`POST`||e===`PUT`?r:void 0);if(!i.rawResponse().ok){let e=await i.json();throw ve(e)?e:{name:`MetaError`,message:`Unknown error occurred`,error:{message:e.message||`Unknown error occurred`,type:`UnknownError`,code:i.statusCode(),fbtrace_id:``}}}return i}catch(e){throw ve(e)?e:{name:`MetaError`,message:e instanceof Error?e.message:`Network error occurred`,error:{message:e instanceof Error?e.message:`Network error occurred`,type:`NetworkError`,code:500,fbtrace_id:``}}}}async getJson(e,t,n,r,i){return await(await this.sendRequest(e,t,n,r,`application/json`,i)).json()}async sendFormData(e,t,n,r,i){return await(await this.sendRequest(e,t,n,r,`multipart/form-data`,i)).json()}async sendUrlEncodedForm(e,t,n,r,i){let a=new URLSearchParams(r).toString();return await(await this.sendRequest(e,t,n,a,`application/x-www-form-urlencoded`,i)).json()}};function y(){try{let e=r(__dirname,`../../package.json`);return JSON.parse(n(e,`utf-8`)).version}catch{return`unknown`}}function we(){let e=y(),t=process.version;return`WhatsApp-Nodejs-SDK/${e} (Node.js ${t})`}var b=class{config;client;constructor(e,t){this.config=e,this.client=t}sendJson(e,t,n,r){return this.client.getJson(e,t,n,r)}sendFormData(e,t,n,r){return this.client.sendFormData(e,t,n,r)}sendUrlEncodedForm(e,t,n,r){return this.client.sendUrlEncodedForm(e,t,n,r)}},x=class extends b{endpoint=`whatsapp_business_encryption`;constructor(e,t){super(e,t)}async getEncryptionPublicKey(){return this.sendJson(l.Get,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],null)}async setEncryptionPublicKey(e){let t=new FormData;return t.append(`business_public_key`,e),this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],t)}},S=class extends b{constructor(e,t){super(e,t)}async listFlows(e){return this.sendJson(l.Get,`/${e}/flows`,this.config[g.RequestTimeout],null)}async createFlow(e,t){let n={name:t.name,categories:t.categories,...t.endpoint_uri&&{endpoint_uri:t.endpoint_uri},...t.clone_flow_id&&{clone_flow_id:t.clone_flow_id},...t.flow_json&&{flow_json:t.flow_json},...t.publish!==void 0&&{publish:t.publish}};return this.sendJson(l.Post,`/${e}/flows`,this.config[g.RequestTimeout],JSON.stringify(n))}async getFlow(e,t,n){let r=new URLSearchParams;t&&r.append(`fields`,t),n&&r.append(`date_format`,n);let i=r.toString()?`?${r.toString()}`:``;return this.sendJson(l.Get,`/${e}${i}`,this.config[g.RequestTimeout],null)}async getFlowPreview(e,t=!1){let n=`preview.invalidate(${t})`;return this.getFlow(e,n)}async updateFlowMetadata(e,t){let n={...t.name&&{name:t.name},...t.categories&&{categories:t.categories},...t.endpoint_uri&&{endpoint_uri:t.endpoint_uri},...t.application_id&&{application_id:t.application_id}};return this.sendJson(l.Post,`/${e}`,this.config[g.RequestTimeout],JSON.stringify(n))}async deleteFlow(e){return this.sendJson(l.Delete,`/${e}`,this.config[g.RequestTimeout],null)}async listAssets(e){return this.sendJson(l.Get,`/${e}/assets`,this.config[g.RequestTimeout],null)}async updateFlowJson(e,t){let n=new FormData,r;if(t.file instanceof Buffer)r=new globalThis.Blob([t.file]),n.append(`file`,r);else if(typeof t.file==`object`&&!(t.file instanceof Blob))try{r=new globalThis.Blob([JSON.stringify(t.file,null,2)],{type:`application/json`}),n.append(`file`,r)}catch{throw Error(`Failed to stringify JSON object for Flow JSON update.`)}else if(t.file instanceof Blob)r=t.file,n.append(`file`,r);else throw Error(`Invalid file type provided for Flow JSON update. Must be a Buffer, JSON object, or Blob.`);return n.append(`asset_type`,`FLOW_JSON`),n.append(`name`,t.name||`flow.json`),this.sendFormData(l.Post,`/${e}/assets`,this.config[g.RequestTimeout],n)}async validateFlowJson(e,t){try{let n=await this.updateFlowJson(e,{file:t}),r=!n.validation_errors||n.validation_errors.length===0;return{...n,valid:r}}catch(e){throw e}}async publishFlow(e){return this.sendJson(l.Post,`/${e}/publish`,this.config[g.RequestTimeout],JSON.stringify({}))}async deprecateFlow(e){return this.sendJson(l.Post,`/${e}/deprecate`,this.config[g.RequestTimeout],JSON.stringify({}))}async migrateFlows(e,t){let n={source_waba_id:t.source_waba_id,...t.source_flow_names&&{source_flow_names:t.source_flow_names}};return this.sendJson(l.Post,`/${e}/migrate_flows`,this.config[g.RequestTimeout],JSON.stringify(n))}};let C=function(e){return e.INIT=`INIT`,e.BACK=`BACK`,e.DATA_EXCHANGE=`data_exchange`,e}({}),w=function(e){return e.Ping=`ping`,e.Change=`data_exchange`,e.Error=`error`,e.All=`*`,e}({});var T=class extends b{endpoint=`media`;constructor(e,t){super(e,t)}async getMediaById(e,t){return this.sendJson(l.Get,`${e}`,this.config[g.RequestTimeout],null)}async uploadMedia(e,t=`whatsapp`){let n=new FormData;return n.append(`file`,e),n.append(`messaging_product`,t),n.append(`type`,e.type),this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],n)}async deleteMedia(e,t){return this.sendJson(l.Delete,`${e}`,this.config[g.RequestTimeout],null)}async downloadMedia(e){return this.sendJson(l.Get,e,this.config[g.RequestTimeout],null)}},E=class extends b{commonMethod=l.Post;commonEndpoint=`messages`;constructor(e,t){super(e,t)}bodyBuilder(e,t,n,r){let i={messaging_product:`whatsapp`,recipient_type:`individual`,to:n,type:e,[e]:t};return r&&(i.context={message_id:r}),i}send(e){return this.sendJson(this.commonMethod,`${this.config[g.PhoneNumberId]}/${this.commonEndpoint}`,this.config[g.RequestTimeout],e)}async audio(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Audio,t,n,r)))}async contacts(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Contacts,t,n,r)))}async document(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Document,t,n,r)))}async image(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Image,t,n,r)))}async interactive(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Interactive,t,n,r)))}async location(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Location,t,n,r)))}async sticker(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Sticker,t,n,r)))}async template(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Template,t,n,r)))}async text(e){let{body:t,to:n,replyMessageId:r,previewUrl:i}=e,a=typeof t==`string`?{body:t,preview_url:i??!0}:{...t,preview_url:i??t.preview_url??!0};return this.send(JSON.stringify(this.bodyBuilder(u.Text,a,n,r)))}async video(e){let{body:t,to:n,replyMessageId:r}=e;return this.send(JSON.stringify(this.bodyBuilder(u.Video,t,n,r)))}async status(e){let t={messaging_product:`whatsapp`,status:e.status,message_id:e.messageId,...e.typingIndicator&&{typing_indicator:e.typingIndicator}};return this.send(JSON.stringify(t))}async markAsRead(e){return this.status({status:`read`,messageId:e.messageId})}async showTypingIndicator(e){return this.status({status:`read`,messageId:e.messageId,typingIndicator:{type:`text`}})}async interactiveList(e){return this.interactive(e)}async interactiveCtaUrl(e){return this.interactive(e)}async interactiveLocationRequest(e){return this.interactive(e)}async interactiveAddressMessage(e){return this.interactive(e)}async interactiveReplyButtons(e){return this.interactive(e)}async interactiveFlow(e){return this.interactive(e)}async reaction(e){let t={message_id:e.messageId,emoji:e.emoji};return this.send(JSON.stringify(this.bodyBuilder(u.Reaction,t,e.to)))}},D=class{contact={};setName(e){if(!e||typeof e!=`object`)throw Error(`Name must be an object`);return this.contact.name=e,this}setSimpleName(e,t){if(!e||typeof e!=`string`)throw Error(`First name must be a non-empty string`);let n={formatted_name:t?`${e} ${t}`:e,first_name:e};return t&&(n.last_name=t),this.setName(n)}setFullName(e,t,n,r,i){if(!e||typeof e!=`string`)throw Error(`First name must be a non-empty string`);let a={formatted_name:[i,e,n,t,r].filter(Boolean).join(` `),first_name:e};return t&&(a.last_name=t),n&&(a.middle_name=n),r&&(a.suffix=r),i&&(a.prefix=i),this.setName(a)}addPhone(e,t,n){if(!e||typeof e!=`string`)throw Error(`Phone number must be a non-empty string`);let r={phone:`PHONE_NUMBER`};return t&&(r.type=t),n&&(r.wa_id=n),this.contact.phones||(this.contact.phones=[]),this.contact.phones.push(r),this}addEmail(e,t){if(!e||typeof e!=`string`)throw Error(`Email must be a non-empty string`);if(!e.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/))throw Error(`Invalid email format`);let n={email:e};return t&&(n.type=t),this.contact.emails||(this.contact.emails=[]),this.contact.emails.push(n),this}addAddress(e){if(!e||typeof e!=`object`)throw Error(`Address must be an object`);return this.contact.addresses||(this.contact.addresses=[]),this.contact.addresses.push(e),this}addSimpleAddress(e,t,n,r){let i={street:e,city:t,country:n};return r&&(i.type=r),this.addAddress(i)}setOrganization(e,t,n){let r={};return e&&(r.company=e),t&&(r.department=t),n&&(r.title=n),this.contact.org=r,this}addUrl(e,t){if(!e||typeof e!=`string`)throw Error(`URL must be a non-empty string`);let n={url:e};return t&&(n.type=t),this.contact.urls||(this.contact.urls=[]),this.contact.urls.push(n),this}setBirthday(e,t,n){let r=t.toString().padStart(2,`0`),i=n.toString().padStart(2,`0`);return this.contact.birthday=`${e}-${r}-${i}`,this}build(){if(!this.contact.name)throw Error(`Contact name is required`);return this.contact}reset(){return this.contact={},this}},Te=class{static createSimpleContact(e,t){return new D().setSimpleName(e).addPhone(t).build()}static createBusinessContact(e,t,n,r,i,a){return new D().setSimpleName(e,t).setOrganization(n,void 0,r).addPhone(i,`WORK`).addEmail(a,`WORK`).build()}static createPersonalContact(e,t,n,r,i){let a=new D().setSimpleName(e,t).addPhone(n,`MOBILE`);return r&&a.addEmail(r,`HOME`),i&&a.setBirthday(i.year,i.month,i.day),a.build()}};function O(e){return!(`name`in e)}var k=class{message={};setType(e){return this.message.type=e,this}setBody(e){return this.message.body={text:e},this}setFooter(e){return this.message.footer={text:e},this}setTextHeader(e){return this.message.header={type:`text`,text:e},this}setImageHeader(e){return this.message.header={type:`image`,image:{link:e}},this}addReplyButtons(e){this.message.action||(this.message.action={});let t=this.message.action;return O(t)&&(t.buttons=e.map(e=>({type:`reply`,reply:{id:e.id,title:e.title}}))),this}addListSections(e){this.message.action||(this.message.action={});let t=this.message.action;return O(t)&&(t.sections=e.map(e=>({title:e.title,rows:e.rows}))),this}setListButtonText(e){this.message.action||(this.message.action={});let t=this.message.action;return O(t)&&(t.button=e),this}setCTAUrl(e,t){return this.message.action={name:`cta_url`,parameters:{display_text:e,url:t}},this}build(){if(!this.message.type)throw Error(`Interactive message type is required`);if(!this.message.body)throw Error(`Interactive message body is required`);if(!this.message.action)throw Error(`Interactive message action is required`);return this.message}reset(){return this.message={},this}},Ee=class{static createButtonMessage(e,t,n){let r=new k().setType(f.Button).setBody(e).addReplyButtons(t);return n?.headerText&&r.setTextHeader(n.headerText),n?.footerText&&r.setFooter(n.footerText),r.build()}static createListMessage(e,t,n,r){let i=new k().setType(f.List).setBody(e).addListSections(n);r?.headerText&&i.setTextHeader(r.headerText),r?.footerText&&i.setFooter(r.footerText);let a=i.build(),o=a.action;return O(o)&&(o.button=t),a}static createCTAUrlMessage(e,t,n,r){let i=new k().setType(f.CtaUrl).setBody(e).setCTAUrl(t,n);return r?.headerText&&i.setTextHeader(r.headerText),r?.footerText&&i.setFooter(r.footerText),i.build()}},A=class{location={};setLatitude(e){if(typeof e!=`number`||e<-90||e>90)throw Error(`Latitude must be a number between -90 and 90`);return this.location.latitude=e,this}setLongitude(e){if(typeof e!=`number`||e<-180||e>180)throw Error(`Longitude must be a number between -180 and 180`);return this.location.longitude=e,this}setCoordinates(e,t){return this.setLatitude(e).setLongitude(t)}setName(e){if(e&&typeof e!=`string`)throw Error(`Location name must be a string`);return this.location.name=e,this}setAddress(e){if(e&&typeof e!=`string`)throw Error(`Location address must be a string`);return this.location.address=e,this}build(){if(this.location.latitude===void 0)throw Error(`Latitude is required`);if(this.location.longitude===void 0)throw Error(`Longitude is required`);return this.location}reset(){return this.location={},this}},De=class{static createSimpleLocation(e,t){return new A().setCoordinates(e,t).build()}static createNamedLocation(e,t,n,r){return new A().setCoordinates(e,t).setName(n).setAddress(r).build()}static createBusinessLocation(e,t,n,r){return new A().setCoordinates(e,t).setName(n).setAddress(r).build()}},j=class{media={};setId(e){if(!e||typeof e!=`string`)throw Error(`Media ID must be a non-empty string`);return this.media.id=e,this}setLink(e){if(!e||typeof e!=`string`)throw Error(`Media URL must be a non-empty string`);if(!e.match(/^https?:\/\//))throw Error(`Media URL must be a valid HTTP/HTTPS URL`);return this.media.link=e,this}setCaption(e){if(e&&typeof e!=`string`)throw Error(`Caption must be a string`);return this.media.caption=e,this}build(){if(!this.media.id&&!this.media.link)throw Error(`Either media ID or link is required`);return this.media}reset(){return this.media={},this}},M=class extends j{},N=class extends j{},P=class extends j{setCaption(e){throw Error(`Audio messages do not support captions`)}},F=class extends j{setFilename(e){if(!e||typeof e!=`string`)throw Error(`Filename must be a non-empty string`);return this.media.filename=e,this}},I=class extends j{setCaption(e){throw Error(`Sticker messages do not support captions`)}},Oe=class{static createImageWithCaption(e,t,n=!1){let r=new M;return n?r.setId(e):r.setLink(e),r.setCaption(t).build()}static createVideoWithCaption(e,t,n=!1){let r=new N;return n?r.setId(e):r.setLink(e),r.setCaption(t).build()}static createDocument(e,t,n,r=!1){let i=new F;return r?i.setId(e):i.setLink(e),i.setFilename(t),n&&i.setCaption(n),i.build()}static createAudio(e,t=!1){let n=new P;return t?n.setId(e):n.setLink(e),n.build()}static createSticker(e,t=!1){let n=new I;return t?n.setId(e):n.setLink(e),n.build()}},L=class{reaction={};setMessageId(e){if(!e||typeof e!=`string`)throw Error(`Message ID must be a non-empty string`);return this.reaction.message_id=e,this}setEmoji(e){if(!e||typeof e!=`string`)throw Error(`Emoji must be a non-empty string`);if(e.length>4)throw Error(`Please provide a single emoji character`);return this.reaction.emoji=e,this}removeReaction(){return this.reaction.emoji=``,this}build(){if(!this.reaction.message_id)throw Error(`Message ID is required`);if(this.reaction.emoji===void 0)throw Error(`Emoji is required (use empty string to remove reaction)`);return this.reaction}reset(){return this.reaction={},this}},ke=class{static createLike(e){return new L().setMessageId(e).setEmoji(`👍`).build()}static createHeart(e){return new L().setMessageId(e).setEmoji(`❤️`).build()}static createLaugh(e){return new L().setMessageId(e).setEmoji(`😂`).build()}static createWow(e){return new L().setMessageId(e).setEmoji(`😮`).build()}static createSad(e){return new L().setMessageId(e).setEmoji(`😢`).build()}static createAngry(e){return new L().setMessageId(e).setEmoji(`😠`).build()}static removeReaction(e){return new L().setMessageId(e).removeReaction().build()}};function Ae(e){return Object.values(_).includes(e)}function je(e){return Object.values(p).includes(e)}var R=class{template={components:[]};setName(e){if(!e||e.trim().length===0)throw Error(`Template name cannot be empty`);return this.template.name=e,this}setLanguage(e){if(!Ae(e))throw Error(`Invalid language code: ${e}. Must be a valid LanguagesEnum value.`);return this.template.language={policy:`deterministic`,code:e},this}addTextHeader(e){if(!Array.isArray(e))throw Error(`Parameters must be an array`);let t={type:h.Header,parameters:e.map(e=>{if(typeof e!=`string`)throw Error(`All parameters must be strings`);return{type:d.Text,text:e}})};return this.template.components||(this.template.components=[]),this.template.components.push(t),this}addImageHeader(e){if(!e||typeof e!=`string`)throw Error(`Image URL must be a non-empty string`);let t={type:h.Header,parameters:[{type:d.Image,image:{link:e}}]};return this.template.components||(this.template.components=[]),this.template.components.push(t),this}addBody(e){if(!Array.isArray(e))throw Error(`Parameters must be an array`);let t={type:h.Body,parameters:e.map(e=>{if(typeof e!=`string`)throw Error(`All parameters must be strings`);return{type:d.Text,text:e}})};return this.template.components||(this.template.components=[]),this.template.components.push(t),this}addFooter(){let e={type:h.Footer};return this.template.components||(this.template.components=[]),this.template.components.push(e),this}addButtons(e){if(!Array.isArray(e))throw Error(`Buttons must be an array`);return e.forEach(e=>{if(typeof e.index!=`number`||!je(e.index))throw Error(`Button index must be a valid ButtonPositionEnum value: ${e.index}`);let t=e.type===`quick_reply`?m.QuickReply:m.Url,n={type:h.Button,sub_type:t,index:e.index};if(e.parameters&&e.parameters.length>0){if(!Array.isArray(e.parameters))throw Error(`Button parameters must be an array`);e.type===`quick_reply`?n.parameters=e.parameters.map(e=>{if(typeof e!=`string`)throw Error(`All button parameters must be strings`);return{type:d.Payload,payload:e}}):e.type===`url`&&(n.parameters=e.parameters.map(e=>{if(typeof e!=`string`)throw Error(`All button parameters must be strings`);return{type:d.Text,text:e}}))}this.template.components||(this.template.components=[]),this.template.components.push(n)}),this}addCurrencyParameter(e,t,n){if(!e||typeof e!=`string`)throw Error(`Fallback value must be a non-empty string`);if(!t||typeof t!=`string`)throw Error(`Currency code must be a non-empty string`);if(typeof n!=`number`||n<0)throw Error(`Amount must be a non-negative number`);return{type:d.Currency,currency:{fallback_value:e,code:t,amount_1000:n*1e3}}}addDateTimeParameter(e,t){if(!e||typeof e!=`string`)throw Error(`Fallback value must be a non-empty string`);if(typeof t!=`number`||t<=0)throw Error(`Timestamp must be a positive number`);return{type:d.DateTime,date_time:{fallback_value:e,timestamp:t}}}build(){if(!this.template.name)throw Error(`Template name is required`);if(!this.template.language)throw Error(`Template language is required`);return this.template}reset(){return this.template={components:[]},this}},Me=class{static createSimpleTextTemplate(e,t,n){if(!e||!t||!Array.isArray(n))throw Error(`Invalid parameters for simple text template`);return new R().setName(e).setLanguage(t).addBody(n).build()}static createCompleteTemplate(e,t,n){if(!e||!t||!n.bodyParameters)throw Error(`Invalid parameters for complete template`);let r=new R().setName(e).setLanguage(t).addBody(n.bodyParameters);return n.headerParameters?r.addTextHeader(n.headerParameters):n.headerImage&&r.addImageHeader(n.headerImage),n.buttons&&r.addButtons(n.buttons),r.build()}static createOrderConfirmationTemplate(e,t,n,r,i){if(!e||!t||!n||typeof r!=`number`||!i)throw Error(`Invalid parameters for order confirmation template`);return new R().setName(`order_confirmation`).setLanguage(e).addBody([t,n,r.toString(),i]).addButtons([{index:0,type:`quick_reply`},{index:1,type:`url`,parameters:[n]}]).build()}},z=class{textMessage={};setBody(e){if(!e||typeof e!=`string`)throw Error(`Message body must be a non-empty string`);return this.textMessage.body=e,this}setPreviewUrl(e=!0){return this.textMessage.preview_url=e,this}build(){if(!this.textMessage.body)throw Error(`Message body is required`);return this.textMessage}reset(){return this.textMessage={},this}},Ne=class{static createSimpleText(e){return new z().setBody(e).build()}static createTextWithPreview(e){return new z().setBody(e).setPreviewUrl(!0).build()}static createNotification(e,t){return new z().setBody(`*${e}*\n\n${t}`).build()}};const B=e=>{if(!e||Object.keys(e).length===0)return``;let t=[];for(let[n,r]of Object.entries(e))if(r!==void 0){let e=encodeURIComponent(n),i=encodeURIComponent(String(r));t.push(`${e}=${i}`)}return t.length>0?`?${t.join(`&`)}`:``};var V=class extends b{endpoint=`phone_numbers`;constructor(e,t){super(e,t)}async getPhoneNumberById(e){let t=e?B({fields:e}):``;return this.sendJson(l.Get,`${this.config[g.PhoneNumberId]}${t}`,this.config[g.RequestTimeout],null)}async getPhoneNumbers(){return this.sendJson(l.Get,`${this.config[g.BusinessAcctId]}/${this.endpoint}`,this.config[g.RequestTimeout],null)}async requestVerificationCode(e){return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/request_code`,this.config[g.RequestTimeout],JSON.stringify(e))}async verifyCode(e){return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/verify_code`,this.config[g.RequestTimeout],JSON.stringify(e))}};function Pe(e){if(!e)return``;let t=``;return t=Array.isArray(e)?e.join(`,`):typeof e==`string`?e:Object.entries(e).filter(([e,t])=>t).map(([e])=>e).join(`,`),t?`?fields=${t}`:``}var Fe=class extends b{endpoint=`whatsapp_business_profile`;constructor(e,t){super(e,t)}async getBusinessProfile(e){return this.sendJson(l.Get,`${this.config[g.PhoneNumberId]}/${this.endpoint}${Pe(e)}`,this.config[g.RequestTimeout],null)}async updateBusinessProfile(e){return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],JSON.stringify(e))}async createUploadSession(e,t,n){let r=B({file_length:e,file_type:t,file_name:n});return this.sendJson(l.Post,`app/uploads/${r}`,this.config[g.RequestTimeout],null)}async uploadMedia(e,t){return this.sendJson(l.Post,`${e}`,this.config[g.RequestTimeout],t)}async getUploadHandle(e){return this.sendJson(l.Get,`${e}`,this.config[g.RequestTimeout],null)}},Ie=class extends b{endpoint=`message_qrdls`;constructor(e,t){super(e,t)}async createQrCode(e){return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],JSON.stringify(e))}async getQrCodes(){return this.sendJson(l.Get,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],null)}async getQrCode(e){return this.sendJson(l.Get,`${this.config[g.PhoneNumberId]}/${this.endpoint}/${e}`,this.config[g.RequestTimeout],null)}async updateQrCode(e){return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/${this.endpoint}`,this.config[g.RequestTimeout],JSON.stringify(e))}async deleteQrCode(e){return this.sendJson(l.Delete,`${this.config[g.PhoneNumberId]}/${this.endpoint}/${e}`,this.config[g.RequestTimeout],null)}},Le=class extends b{constructor(e,t){super(e,t)}async register(e,t){let n={messaging_product:`whatsapp`,pin:e,...t&&{data_localization_region:t}};return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/register`,this.config[g.RequestTimeout],JSON.stringify(n))}async deregister(){return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}/deregister`,this.config[g.RequestTimeout],null)}},Re=class extends b{endpoint=`message_templates`;constructor(e,t){super(e,t)}async getTemplate(e){return this.sendJson(l.Get,`${e}`,this.config[g.RequestTimeout],null)}async updateTemplate(e,t){return this.sendJson(l.Post,`${e}`,this.config[g.RequestTimeout],JSON.stringify(t))}async getTemplates(e){return this.sendJson(l.Get,`${this.config[g.BusinessAcctId]}/${this.endpoint}${B(e??{})}`,this.config[g.RequestTimeout],null)}async createTemplate(e){return this.sendJson(l.Post,`${this.config[g.BusinessAcctId]}/${this.endpoint}`,this.config[g.RequestTimeout],JSON.stringify(e))}async deleteTemplate(e){return this.sendJson(l.Delete,`${this.config[g.BusinessAcctId]}/${this.endpoint}${B(e)}`,this.config[g.RequestTimeout],null)}};function H(e){let t={type:`HEADER`,format:e.format};return e.text&&(t.text=e.text),e.example&&(t.example=e.example),t}function U(e){let t={type:`BODY`,text:e.text};return e.example&&(t.example=e.example),t}function W(e){return{type:`FOOTER`,text:e.text}}function G(e){let t=[];if(e.phone_number&&t.push({type:`PHONE_NUMBER`,text:e.phone_number.text,phone_number:e.phone_number.phone_number}),e.url){let n={type:`URL`,text:e.url.text,url:e.url.url};e.url.example&&(n.example=[e.url.example]),t.push(n)}if(e.quick_reply&&e.quick_reply.forEach(e=>{t.push({type:`QUICK_REPLY`,text:e.text})}),e.copy_code&&t.push({type:`COPY_CODE`,example:e.copy_code.example}),e.flow){let n={type:`FLOW`,text:e.flow.text};e.flow.flow_id&&(n.flow_id=e.flow.flow_id),e.flow.flow_name&&(n.flow_name=e.flow.flow_name),e.flow.flow_json&&(n.flow_json=e.flow.flow_json),e.flow.flow_action&&(n.flow_action=e.flow.flow_action),e.flow.navigate_screen&&(n.navigate_screen=e.flow.navigate_screen),t.push(n)}return e.mpm&&t.push({type:`MPM`}),e.otp&&t.push({type:`OTP`}),e.spm&&t.push({type:`SPM`}),t.length>0?[{type:`BUTTONS`,buttons:t}]:[]}function ze(e){return e.map(e=>{switch(e.type){case`text`:return e.value;case`currency`:return e.fallback_value;case`date_time`:return e.fallback_value;case`image`:case`video`:case`document`:return e.handle||e.link||``;case`location`:return e.name||``;case`product`:return e.product_retailer_id;default:return``}})}function Be(e){let t=[];if(e.header&&t.push(H(e.header)),e.body&&t.push(U(e.body)),e.footer&&t.push(W(e.footer)),e.buttons&&t.push(...G(e.buttons)),e.carousel){let n=[];e.carousel.cards.forEach((e,t)=>{if(e.image||e.video||e.product){let t=e.image?`IMAGE`:e.video?`VIDEO`:`DOCUMENT`,r=e.image||e.video||e.product||``;n.push({type:`HEADER`,format:t,example:{header_handle:[r]}})}e.body&&n.push({type:`BODY`,text:e.body,example:e.bodyParameters?{body_text:[ze(e.bodyParameters)]}:void 0}),e.buttons&&n.push(...G(e.buttons))}),t.push(...n)}return e.limitedTimeOffer&&t.push({type:`LIMITED_TIME_OFFER`,limited_time_offer:{expiration_time_ms:e.limitedTimeOffer.expiration_time_ms}}),{name:e.name,language:e.language,category:e.category,components:t.length>0?t:void 0}}function Ve(e){let t=[],n=`*{{1}}* is your verification code.`;return e.add_security_recommendation&&(n+=` For your security, do not share this code.`),e.code_expiration_minutes&&(n+=` This code expires in ${e.code_expiration_minutes} minutes.`),t.push({type:`BODY`,text:n,example:{body_text:[[`123456`]]}}),t.push({type:`BUTTONS`,buttons:[{type:`OTP`}]}),{name:e.name,language:e.language,category:s.Authentication,components:t}}function He(e){let t=[],n=`Your security code is *{{1}}*.`;return e.add_security_recommendation&&(n+=` Do not share this code with anyone.`),e.code_expiration_minutes&&(n+=` This code expires in ${e.code_expiration_minutes} minutes.`),t.push({type:`BODY`,text:n,example:{body_text:[[`ABCD1234`]]}}),e.copy_code_button&&t.push({type:`BUTTONS`,buttons:[{type:`COPY_CODE`,example:`ABCD1234`}]}),{name:e.name,language:e.language,category:s.Authentication,components:t}}function Ue(e){let t=[];return e.header&&t.push(H({...e.header,format:`TEXT`})),t.push(U(e.body)),e.footer&&t.push(W(e.footer)),t.push({type:`BUTTONS`,buttons:[{type:`CATALOG`,action:{thumbnail_product_retailer_id:e.thumbnail_product_retailer_id}}]}),{name:e.name,language:e.language,category:s.Marketing,components:t}}function We(e){let t=[];return e.header&&t.push(H({...e.header,format:`TEXT`})),t.push(U(e.body)),e.footer&&t.push(W(e.footer)),t.push({type:`BUTTONS`,buttons:[{type:`COPY_CODE`,example:e.coupon_code}]}),{name:e.name,language:e.language,category:s.Marketing,components:t}}function Ge(e){let t=[];return t.push({type:`LIMITED_TIME_OFFER`,limited_time_offer:{expiration_time_ms:e.expiration_time_ms}}),e.header&&t.push(H({...e.header,format:`TEXT`})),t.push(U(e.body)),e.footer&&t.push(W(e.footer)),{name:e.name,language:e.language,category:s.Marketing,components:t}}function Ke(e){let t=[],n=[];return e.cards.forEach((e,t)=>{let r=[];r.push({type:`HEADER`,format:e.header.format,example:e.header.example}),r.push(U(e.body)),e.buttons&&r.push(...G(e.buttons)),n.push({card_index:t,components:r})}),t.push({type:`CAROUSEL`,cards:n}),{name:e.name,language:e.language,category:s.Marketing,components:t}}function qe(e){let t=[];return e.header&&t.push(H({...e.header,format:`TEXT`})),t.push(U(e.body)),e.footer&&t.push(W(e.footer)),t.push({type:`BUTTONS`,buttons:[{type:`MPM`,action:{thumbnail_product_retailer_id:e.thumbnail_product_retailer_id,sections:e.sections}}]}),{name:e.name,language:e.language,category:s.Marketing,components:t}}function Je(e){let t=[];e.header&&t.push(H({...e.header,format:`TEXT`})),t.push(U(e.body)),e.footer&&t.push(W(e.footer));let n=e.cards.map((e,t)=>({card_index:t,components:[{type:`HEADER`,format:`PRODUCT`,example:{header_handle:[e.product_retailer_id]}}]}));return t.push({type:`CAROUSEL`,cards:n}),{name:e.name,language:e.language,category:s.Marketing,components:t}}function Ye(e){let t=[];return e.header&&t.push(H({...e.header,format:`TEXT`})),t.push(U(e.body)),e.footer&&t.push(W(e.footer)),t.push({type:`BUTTONS`,buttons:[{type:`SPM`,action:{product_retailer_id:e.product_retailer_id}}]}),{name:e.name,language:e.language,category:s.Marketing,components:t}}var Xe=class extends b{constructor(e,t){super(e,t)}async setTwoStepVerificationCode(e){let t={pin:e};return this.sendJson(l.Post,`${this.config[g.PhoneNumberId]}`,this.config[g.RequestTimeout],JSON.stringify(t))}},Ze=class extends b{constructor(e,t){super(e,t)}async getWabaAccount(e){let t=Pe(e)?.replace(/,/g,`%2C`);return this.sendJson(l.Get,`${this.config[g.BusinessAcctId]}${t}`,this.config[g.RequestTimeout],null)}async getAllWabaSubscriptions(){return this.sendJson(l.Get,`${this.config[g.BusinessAcctId]}/subscribed_apps`,this.config[g.RequestTimeout],null)}async updateWabaSubscription({override_callback_uri:e,verify_token:t}){let n={override_callback_uri:e,verify_token:t};return this.sendJson(l.Post,`${this.config[g.BusinessAcctId]}/subscribed_apps`,this.config[g.RequestTimeout],JSON.stringify(n))}async unsubscribeFromWaba(){return this.sendJson(l.Delete,`${this.config[g.BusinessAcctId]}/subscribed_apps`,this.config[g.RequestTimeout],null)}};function Qe(){process.env.NODE_ENV===`test`||process.env.VITEST===`true`||typeof global<`u`&&global.__VITEST__||console.log(`\x1B[36m%s\x1B[0m`,`
1832
3
  ██████╗ ██╗ ██████╗ ██╗ ██╗ ██████╗ █████╗ ██████╗ ██╗
1833
4
  ██╔════╝ ██║ ██╔═══██╗ ██║ ██║ ██╔══██╗ ██╔══██╗ ██╔══██╗ ██║
1834
5
  ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║ ███████║ ██████╔╝ ██║
1835
6
  ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██║ ██╔══██║ ██╔═══╝ ██║
1836
7
  ╚██████╗ ███████╗ ╚██████╔╝ ╚██████╔╝ ██████╔╝ ██║ ██║ ██║ ██║
1837
8
  ╚═════╝ ╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
1838
- `);
1839
- }
1840
-
1841
- //#endregion
1842
- //#region src/core/whatsapp/WhatsApp.ts
1843
- const LIB_NAME$1 = "WHATSAPP";
1844
- const LOGGER$2 = new Logger(LIB_NAME$1, process.env.DEBUG === "true");
1845
- /**
1846
- * WhatsApp SDK Main Class following official patterns
1847
- * Provides unified access to WhatsApp Cloud API and Flows API
1848
- */
1849
- var WhatsApp = class {
1850
- config;
1851
- requester;
1852
- messages;
1853
- media;
1854
- phoneNumbers;
1855
- twoStepVerification;
1856
- flows;
1857
- businessProfile;
1858
- templates;
1859
- encryption;
1860
- qrCode;
1861
- registration;
1862
- waba;
1863
- constructor(config) {
1864
- printLogo();
1865
- this.config = importConfig(config);
1866
- this.requester = new Requester(this.config[WabaConfigEnum.APIVersion], this.config[WabaConfigEnum.PhoneNumberId], this.config[WabaConfigEnum.AccessToken], this.config[WabaConfigEnum.BusinessAcctId], this.getUserAgent());
1867
- this.messages = new messages_default(this.config, this.requester);
1868
- this.media = new media_default(this.config, this.requester);
1869
- this.phoneNumbers = new phone_default(this.config, this.requester);
1870
- this.twoStepVerification = new twoStepVerification_default(this.config, this.requester);
1871
- this.flows = new flow_default(this.config, this.requester);
1872
- this.businessProfile = new profile_default(this.config, this.requester);
1873
- this.templates = new TemplateApi(this.config, this.requester);
1874
- this.encryption = new encryption_default(this.config, this.requester);
1875
- this.qrCode = new qrCode_default(this.config, this.requester);
1876
- this.registration = new registration_default(this.config, this.requester);
1877
- this.waba = new waba_default(this.config, this.requester);
1878
- LOGGER$2.log("\n" + formatConfigTable(this.config));
1879
- }
1880
- /**
1881
- * Runtime configuration updates following official patterns
1882
- */
1883
- updateTimeout(timeout) {
1884
- this.config[WabaConfigEnum.RequestTimeout] = timeout;
1885
- if ("updateTimeout" in this.requester) {
1886
- this.requester.updateTimeout(timeout);
1887
- }
1888
- LOGGER$2.log(`Timeout updated to ${timeout}ms`);
1889
- }
1890
- updateSenderNumberId(phoneNumberId) {
1891
- this.config[WabaConfigEnum.PhoneNumberId] = phoneNumberId;
1892
- LOGGER$2.log(`Sender number ID updated to ${phoneNumberId}`);
1893
- }
1894
- updateAccessToken(accessToken) {
1895
- this.config[WabaConfigEnum.AccessToken] = accessToken;
1896
- if ("updateAccessToken" in this.requester) {
1897
- this.requester.updateAccessToken(accessToken);
1898
- }
1899
- LOGGER$2.log("Access token updated");
1900
- }
1901
- /**
1902
- * Get SDK version
1903
- */
1904
- version() {
1905
- return getVersion();
1906
- }
1907
- /**
1908
- * Static enums access
1909
- */
1910
- static get Enums() {
1911
- return enums_exports;
1912
- }
1913
- /**
1914
- * Get User-Agent string
1915
- */
1916
- getUserAgent() {
1917
- return getUserAgent();
1918
- }
1919
- };
1920
-
1921
- //#endregion
1922
- //#region src/utils/flowTypeGuards.ts
1923
- /**
1924
- * Helper function to check if a value is an object
1925
- * @param value The value to check
1926
- * @returns True if the value is a non-null object
1927
- */
1928
- function isObject(value) {
1929
- return typeof value === "object" && value !== null;
1930
- }
1931
- /**
1932
- * Helper function to check if a value is a string
1933
- * @param value The value to check
1934
- * @returns True if the value is a string
1935
- */
1936
- function isString(value) {
1937
- return typeof value === "string";
1938
- }
1939
- const DATA_EXCHANGE_ACTIONS = [
1940
- FlowActionEnum.DATA_EXCHANGE,
1941
- FlowActionEnum.INIT,
1942
- FlowActionEnum.BACK
1943
- ];
1944
- const ERROR_ACTIONS = [FlowActionEnum.DATA_EXCHANGE, FlowActionEnum.INIT];
1945
- /**
1946
- * Type guard to check if a request is a Data Exchange request
1947
- * Validates the request structure according to the Flow API specifications
1948
- *
1949
- * @param request The Flow endpoint request to check
1950
- * @returns True if the request is a valid Data Exchange request, false otherwise
1951
- */
1952
- function isFlowDataExchangeRequest(request) {
1953
- if (!("flow_token" in request && isString(request.flow_token) && "action" in request)) {
1954
- return false;
1955
- }
1956
- const { action, version, screen, data } = request;
1957
- const hasValidVersion = version === "3.0";
1958
- const hasValidAction = DATA_EXCHANGE_ACTIONS.includes(action);
1959
- const hasValidScreen = typeof screen === "undefined" || isString(screen) && screen !== "SUCCESS";
1960
- const hasValidData = action === FlowActionEnum.DATA_EXCHANGE || isObject(data);
1961
- return hasValidVersion && hasValidAction && hasValidScreen && hasValidData;
1962
- }
1963
- /**
1964
- * Type guard to check if a request is an Error Notification request
1965
- * Validates the request structure according to the Flow API error specifications
1966
- *
1967
- * @param request The Flow endpoint request to check
1968
- * @returns True if the request is a valid Error Notification request, false otherwise
1969
- */
1970
- function isFlowErrorRequest(request) {
1971
- if (!("flow_token" in request && isString(request.flow_token) && "action" in request)) {
1972
- return false;
1973
- }
1974
- const { action, screen, data } = request;
1975
- const hasValidAction = ERROR_ACTIONS.includes(action);
1976
- const hasValidScreen = isString(screen);
1977
- const hasValidData = isObject(data) && "error_key" in data && isString(data.error) && "error_message" in data && isString(data.error_message);
1978
- return hasValidAction && hasValidScreen && hasValidData;
1979
- }
1980
- /**
1981
- * Type guard to check if a request is a Ping (health check) request
1982
- * Simple validation for health check endpoints in the Flow API
1983
- *
1984
- * @param request The Flow endpoint request to check
1985
- * @returns True if the request is a Ping request, false otherwise
1986
- */
1987
- function isFlowPingRequest(request) {
1988
- return "action" in request && request.action === "ping";
1989
- }
1990
-
1991
- //#endregion
1992
- //#region src/core/webhook/utils/webhookUtils.ts
1993
- const LIB_NAME = "WEBHOOK_UTILS";
1994
- const LOGGER$1 = new Logger(LIB_NAME, process.env.DEBUG === "true");
1995
- /**
1996
- * Process webhook messages
1997
- */
1998
- async function processWebhookMessages(request, whatsapp, handlers) {
1999
- try {
2000
- LOGGER$1.info("Processing webhook messages request");
2001
- const body = await request.json();
2002
- LOGGER$1.info("Webhook request body:", body);
2003
- if (body.object !== "whatsapp_business_account") {
2004
- const errorMsg = "Received webhook for non-WhatsApp event";
2005
- LOGGER$1.warn(errorMsg, { body });
2006
- return new Response(JSON.stringify({ error: errorMsg }), { status: 404 });
2007
- }
2008
- const errors = [];
2009
- for (const entry of body.entry) {
2010
- try {
2011
- LOGGER$1.info("Processing webhook entry:", { entryId: entry.id });
2012
- const changes = entry.changes;
2013
- for (const change of changes) {
2014
- if (change.field === "messages") {
2015
- LOGGER$1.info("Processing messages change:", { change });
2016
- await processMessages(entry.id, change.value, whatsapp, handlers);
2017
- }
2018
- }
2019
- } catch (error) {
2020
- const errorMsg = `Error processing webhook: ${error}`;
2021
- LOGGER$1.error(errorMsg, {
2022
- entry,
2023
- error
2024
- });
2025
- errors.push(errorMsg);
2026
- }
2027
- }
2028
- LOGGER$1.info("Webhook processing complete", { errorCount: errors.length });
2029
- return new Response(errors.length > 0 ? JSON.stringify({ errors }) : null, { status: 200 });
2030
- } catch (error) {
2031
- LOGGER$1.error("Error processing webhook:", error);
2032
- return new Response(JSON.stringify({ error: "Internal Server Error" }), { status: 500 });
2033
- }
2034
- }
2035
- /**
2036
- * Handle flow requests
2037
- */
2038
- async function processFlowRequest(request, config, whatsapp, flowHandlers) {
2039
- try {
2040
- LOGGER$1.info("Processing flow request");
2041
- const body = await request.text();
2042
- const signature = request.headers.get("x-hub-signature-256");
2043
- LOGGER$1.info("Flow request signature:", { signature });
2044
- if (!verifySignature(body, signature, config.WEBHOOK_VERIFICATION_TOKEN || "")) {
2045
- LOGGER$1.warn("Invalid request signature", { signature });
2046
- return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401 });
2047
- }
2048
- const data = JSON.parse(body);
2049
- LOGGER$1.info("Flow request data:", data);
2050
- const { decryptedBody } = decryptFlowRequest(data, config);
2051
- LOGGER$1.info("Decrypted flow request:", decryptedBody);
2052
- const handler = flowHandlers.get(FlowTypeEnum.All);
2053
- if (!handler) {
2054
- LOGGER$1.warn("No handler registered for flow action:", { action: decryptedBody.action });
2055
- return new Response(JSON.stringify({ error: "Handler not found" }), { status: 404 });
2056
- }
2057
- if (isFlowPingRequest(decryptedBody)) {
2058
- LOGGER$1.info("Handling flow ping request");
2059
- return new Response(JSON.stringify({
2060
- version: "3.0",
2061
- data: { status: "active" }
2062
- }), { status: 200 });
2063
- }
2064
- if (isFlowErrorRequest(decryptedBody)) {
2065
- LOGGER$1.warn("Flow error request received:", decryptedBody);
2066
- return new Response(null, { status: 200 });
2067
- }
2068
- if (isFlowDataExchangeRequest(decryptedBody)) {
2069
- LOGGER$1.info("Processing flow data exchange request");
2070
- const result = await handler(whatsapp, decryptedBody);
2071
- LOGGER$1.info("Flow handler result:", result);
2072
- const encryptedResponse = encryptFlowResponse(result, Buffer.from(data.aes_key, "base64"), Buffer.from(data.initial_vector, "base64"));
2073
- LOGGER$1.info("Encrypted flow response generated");
2074
- return new Response(JSON.stringify(encryptedResponse), { status: 200 });
2075
- }
2076
- LOGGER$1.warn("Unknown flow request type:", decryptedBody);
2077
- return new Response(JSON.stringify({ error: "Unknown request type" }), { status: 400 });
2078
- } catch (error) {
2079
- LOGGER$1.error("Error handling flow request:", error);
2080
- return new Response(JSON.stringify({ error: "Internal server error" }), { status: 500 });
2081
- }
2082
- }
2083
- /**
2084
- * Verify webhook signature
2085
- */
2086
- function verifySignature(body, signature, verificationToken) {
2087
- if (!signature) {
2088
- LOGGER$1.warn("Missing signature in request");
2089
- return false;
2090
- }
2091
- LOGGER$1.info("Signature verification details:", {
2092
- bodyLength: body.length,
2093
- verificationTokenLength: verificationToken.length,
2094
- rawSignature: signature,
2095
- cleanedSignature: signature.replace("sha256=", "")
2096
- });
2097
- const expectedSignature = crypto.createHmac("sha256", verificationToken).update(body).digest("hex");
2098
- LOGGER$1.info("Signature verification:", {
2099
- received: signature.replace("sha256=", ""),
2100
- expected: expectedSignature
2101
- });
2102
- return crypto.timingSafeEqual(Buffer.from(signature.replace("sha256=", "")), Buffer.from(expectedSignature));
2103
- }
2104
- /**
2105
- * Constructs a full URL from framework-specific request headers and URL
2106
- * @param headers - Request headers containing host and protocol information
2107
- * @param url - Relative URL path
2108
- * @returns Full URL string
2109
- */
2110
- function constructFullUrl(headers, url) {
2111
- const protocol = headers["x-forwarded-proto"] || "http";
2112
- const host = headers.host || "localhost";
2113
- const path = url || "/";
2114
- return `${protocol}://${host}${path}`;
2115
- }
2116
- /**
2117
- * Private helper functions
2118
- */
2119
- async function processMessages(waba_id, value, whatsapp, handlers) {
2120
- LOGGER$1.info("Processing messages:", {
2121
- waba_id,
2122
- value
2123
- });
2124
- const metadata = value.metadata;
2125
- const contacts = value.contacts;
2126
- const wabaId = waba_id;
2127
- const displayPhoneNumber = metadata?.display_phone_number || "";
2128
- const phoneNumberId = metadata?.phone_number_id || "";
2129
- const profileName = contacts?.[0]?.profile?.name || "";
2130
- if (value.statuses && value.statuses.length > 0) {
2131
- LOGGER$1.info("Processing statuses:", { statusCount: value.statuses.length });
2132
- const statuses = value.statuses;
2133
- for (const status of statuses) {
2134
- const processedStatus = {
2135
- wabaId,
2136
- id: status.id,
2137
- from: status.recipient_id,
2138
- timestamp: status.timestamp,
2139
- type: MessageTypesEnum.Statuses,
2140
- phoneNumberId,
2141
- displayPhoneNumber,
2142
- profileName,
2143
- statuses: value.statuses[0],
2144
- originalData: status
2145
- };
2146
- LOGGER$1.info("Processing status:", processedStatus);
2147
- await executeHandler(handlers.messageHandlers.get(MessageTypesEnum.Statuses), whatsapp, processedStatus, MessageTypesEnum.Statuses);
2148
- }
2149
- return;
2150
- }
2151
- if (value.messages && value.messages.length > 0) {
2152
- LOGGER$1.info("Processing messages:", { messageCount: value.messages.length });
2153
- const messages = value.messages;
2154
- for (const message of messages) {
2155
- const messageType = message.type;
2156
- LOGGER$1.info("Processing message:", {
2157
- messageType,
2158
- messageId: message.id
2159
- });
2160
- const processedMessage = {
2161
- wabaId,
2162
- id: message.id,
2163
- from: message.from,
2164
- timestamp: message.timestamp,
2165
- type: message.type,
2166
- phoneNumberId,
2167
- displayPhoneNumber,
2168
- profileName,
2169
- originalData: message
2170
- };
2171
- switch (messageType) {
2172
- case MessageTypesEnum.Text:
2173
- processedMessage.text = message.text;
2174
- break;
2175
- case MessageTypesEnum.Image:
2176
- processedMessage.image = message.image;
2177
- break;
2178
- case MessageTypesEnum.Video:
2179
- processedMessage.video = message.video;
2180
- break;
2181
- case MessageTypesEnum.Audio:
2182
- processedMessage.audio = message.audio;
2183
- break;
2184
- case MessageTypesEnum.Document:
2185
- processedMessage.document = message.document;
2186
- break;
2187
- case MessageTypesEnum.Sticker:
2188
- processedMessage.sticker = message.sticker;
2189
- break;
2190
- case MessageTypesEnum.Location:
2191
- processedMessage.location = message.location;
2192
- break;
2193
- case MessageTypesEnum.Contacts:
2194
- processedMessage.contacts = message.contacts;
2195
- break;
2196
- case MessageTypesEnum.Interactive:
2197
- processedMessage.interactive = message.interactive;
2198
- break;
2199
- case MessageTypesEnum.Button:
2200
- processedMessage.button = message.button;
2201
- break;
2202
- case MessageTypesEnum.Order:
2203
- processedMessage.order = message.order;
2204
- break;
2205
- case MessageTypesEnum.System:
2206
- processedMessage.system = message.system;
2207
- break;
2208
- case MessageTypesEnum.Reaction:
2209
- processedMessage.reaction = message.reaction;
2210
- break;
2211
- default:
2212
- LOGGER$1.warn("Unknown message type:", { messageType });
2213
- break;
2214
- }
2215
- LOGGER$1.info("Executing message handlers");
2216
- await executeHandler(handlers.preProcessHandler, whatsapp, processedMessage, "pre-process");
2217
- await executeHandler(handlers.messageHandlers.get(messageType), whatsapp, processedMessage, messageType);
2218
- await executeHandler(handlers.postProcessHandler, whatsapp, processedMessage, "post-process");
2219
- }
2220
- }
2221
- }
2222
- async function executeHandler(handler, whatsapp, message, handlerType) {
2223
- if (handler) {
2224
- try {
2225
- LOGGER$1.info("Executing handler:", {
2226
- handlerType,
2227
- messageId: message.id
2228
- });
2229
- await handler(whatsapp, message);
2230
- LOGGER$1.info("Handler execution complete:", {
2231
- handlerType,
2232
- messageId: message.id
2233
- });
2234
- } catch (error) {
2235
- LOGGER$1.error(`Error in ${handlerType} handler:`, {
2236
- error,
2237
- messageId: message.id
2238
- });
2239
- }
2240
- } else {
2241
- LOGGER$1.info("No handler registered:", { handlerType });
2242
- }
2243
- }
2244
- function decryptFlowRequest(body, config) {
2245
- LOGGER$1.info("Decrypting flow request");
2246
- const { encrypted_aes_key, encrypted_flow_data, initial_vector } = body;
2247
- if (!encrypted_aes_key || !encrypted_flow_data || !initial_vector) {
2248
- LOGGER$1.error("Missing required encryption properties");
2249
- throw new Error("Missing required encryption properties");
2250
- }
2251
- const privatePem = config.FLOW_API_PRIVATE_PEM.replace(/\\n/g, "\n");
2252
- const passphrase = config.FLOW_API_PASSPHRASE;
2253
- const privateKey = crypto.createPrivateKey({
2254
- key: privatePem,
2255
- passphrase
2256
- });
2257
- let decryptedAesKey;
2258
- try {
2259
- LOGGER$1.info("Decrypting AES key");
2260
- decryptedAesKey = crypto.privateDecrypt({
2261
- key: privateKey,
2262
- padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
2263
- oaepHash: "sha256"
2264
- }, Buffer.from(encrypted_aes_key, "base64"));
2265
- } catch (error) {
2266
- LOGGER$1.error("Failed to decrypt AES key:", error);
2267
- throw new Error("Failed to decrypt the request. Please verify your private key.");
2268
- }
2269
- const flowDataBuffer = Buffer.from(encrypted_flow_data, "base64");
2270
- const initialVectorBuffer = Buffer.from(initial_vector, "base64");
2271
- const TAG_LENGTH = 16;
2272
- const encrypted_flow_data_body = flowDataBuffer.subarray(0, -TAG_LENGTH);
2273
- const encrypted_flow_data_tag = flowDataBuffer.subarray(-TAG_LENGTH);
2274
- LOGGER$1.info("Decrypting flow data");
2275
- const decipher = crypto.createDecipheriv("aes-128-gcm", decryptedAesKey, initialVectorBuffer);
2276
- decipher.setAuthTag(encrypted_flow_data_tag);
2277
- const decryptedJSONString = Buffer.concat([decipher.update(encrypted_flow_data_body), decipher.final()]).toString("utf-8");
2278
- LOGGER$1.info("Flow request decryption complete");
2279
- return {
2280
- decryptedBody: JSON.parse(decryptedJSONString),
2281
- aesKeyBuffer: decryptedAesKey,
2282
- initialVectorBuffer
2283
- };
2284
- }
2285
- function encryptFlowResponse(response, aesKeyBuffer, initialVectorBuffer) {
2286
- LOGGER$1.info("Encrypting flow response");
2287
- const flipped_iv = [];
2288
- for (const pair of Array.from(initialVectorBuffer.entries())) {
2289
- flipped_iv.push(~pair[1]);
2290
- }
2291
- try {
2292
- const cipher = crypto.createCipheriv("aes-128-gcm", aesKeyBuffer, Buffer.from(flipped_iv));
2293
- const encryptedResponse = Buffer.concat([
2294
- cipher.update(JSON.stringify(response || {}), "utf-8"),
2295
- cipher.final(),
2296
- cipher.getAuthTag()
2297
- ]).toString("base64");
2298
- LOGGER$1.info("Flow response encryption complete");
2299
- return encryptedResponse;
2300
- } catch (error) {
2301
- LOGGER$1.error("Response encryption error:", error);
2302
- throw new Error("Failed to encrypt response. Internal server error.");
2303
- }
2304
- }
2305
-
2306
- //#endregion
2307
- //#region src/core/webhook/WebhookProcessor.ts
2308
- const LOGGER = new Logger("WEBHOOK_PROCESSOR", process.env.DEBUG === "true");
2309
- var WebhookProcessor = class {
2310
- config;
2311
- client;
2312
- messageHandlers = new Map();
2313
- preProcessHandler = undefined;
2314
- postProcessHandler = undefined;
2315
- flowHandlers = new Map();
2316
- constructor(config) {
2317
- this.config = importConfig(config);
2318
- this.client = new WhatsApp(config);
2319
- LOGGER.log("WebhookProcessor instantiated");
2320
- }
2321
- async processVerification(mode, token, challenge) {
2322
- if (mode === "subscribe" && token === this.config.WEBHOOK_VERIFICATION_TOKEN) {
2323
- return {
2324
- status: 200,
2325
- body: challenge || "",
2326
- headers: { "Content-Type": "text/plain" }
2327
- };
2328
- }
2329
- return {
2330
- status: 403,
2331
- body: JSON.stringify({ error: "Forbidden" }),
2332
- headers: { "Content-Type": "application/json" }
2333
- };
2334
- }
2335
- async processWebhook(request) {
2336
- try {
2337
- const webResponse = await processWebhookMessages(request, this.client, {
2338
- messageHandlers: this.messageHandlers,
2339
- preProcessHandler: this.preProcessHandler,
2340
- postProcessHandler: this.postProcessHandler
2341
- });
2342
- const body = await webResponse.text();
2343
- const contentType = webResponse.headers.get("content-type") || "application/json";
2344
- return {
2345
- status: webResponse.status,
2346
- body,
2347
- headers: { "Content-Type": contentType }
2348
- };
2349
- } catch (error) {
2350
- LOGGER.log(`Error processing webhook: ${error}`);
2351
- return {
2352
- status: 500,
2353
- body: JSON.stringify({ error: "Internal Server Error" }),
2354
- headers: { "Content-Type": "application/json" }
2355
- };
2356
- }
2357
- }
2358
- async processFlow(request) {
2359
- try {
2360
- const webResponse = await processFlowRequest(request, this.config, this.client, this.flowHandlers);
2361
- const body = await webResponse.text();
2362
- const contentType = webResponse.headers.get("content-type") || "application/json";
2363
- return {
2364
- status: webResponse.status,
2365
- body,
2366
- headers: { "Content-Type": contentType }
2367
- };
2368
- } catch (error) {
2369
- LOGGER.log(`Error processing flow: ${error}`);
2370
- return {
2371
- status: 500,
2372
- body: JSON.stringify({ error: "Internal Server Error" }),
2373
- headers: { "Content-Type": "application/json" }
2374
- };
2375
- }
2376
- }
2377
- onMessage(type, handler) {
2378
- this.messageHandlers.set(type, handler);
2379
- LOGGER.log(`Registered message handler for ${type}`);
2380
- }
2381
- onMessagePreProcess(handler) {
2382
- this.preProcessHandler = handler;
2383
- LOGGER.log("Registered pre-process handler");
2384
- }
2385
- onMessagePostProcess(handler) {
2386
- this.postProcessHandler = handler;
2387
- LOGGER.log("Registered post-process handler");
2388
- }
2389
- onFlow(type, handler) {
2390
- this.flowHandlers.set(type, handler);
2391
- LOGGER.log(`Registered flow handler for ${type}`);
2392
- }
2393
- getClient() {
2394
- return this.client;
2395
- }
2396
- getConfig() {
2397
- return this.config;
2398
- }
2399
- };
2400
-
2401
- //#endregion
2402
- //#region src/core/webhook/frameworks/handler.ts
2403
- /**
2404
- * Abstract base class for framework-agnostic webhook handlers
2405
- * Provides common architecture and functionality across all frameworks
2406
- */
2407
- var BaseWebhookHandler = class {
2408
- processor;
2409
- constructor(config) {
2410
- this.processor = new WebhookProcessor(config);
2411
- }
2412
- /**
2413
- * Common webhook verification logic
2414
- */
2415
- async processVerification(mode, token, challenge) {
2416
- return await this.processor.processVerification(mode, token, challenge);
2417
- }
2418
- /**
2419
- * Common webhook processing logic
2420
- */
2421
- async processWebhook(request) {
2422
- return await this.processor.processWebhook(request);
2423
- }
2424
- /**
2425
- * Common flow processing logic
2426
- */
2427
- async processFlow(request) {
2428
- return await this.processor.processFlow(request);
2429
- }
2430
- /**
2431
- * Helper to construct full URL from headers and path
2432
- */
2433
- constructFullUrl(headers, url = "") {
2434
- return constructFullUrl(headers, url);
2435
- }
2436
- /**
2437
- * Helper to apply result headers to response
2438
- */
2439
- applyHeaders(result, res) {
2440
- if (res.setHeader) {
2441
- Object.entries(result.headers).forEach(([key, value]) => {
2442
- res.setHeader(key, value);
2443
- });
2444
- }
2445
- }
2446
- /**
2447
- * Auto-routing method handler that dispatches based on request method
2448
- */
2449
- async autoRoute(req, res, ...args) {
2450
- const method = req.method?.toUpperCase();
2451
- switch (method) {
2452
- case "GET": return await this.handleGet(req, res, ...args);
2453
- case "POST": return await this.handlePost(req, res, ...args);
2454
- default:
2455
- if (res.status && res.json) {
2456
- return res.status(405).json({ error: "Method Not Allowed" });
2457
- }
2458
- throw new Error("Method Not Allowed");
2459
- }
2460
- }
2461
- /**
2462
- * Get the processor instance for handler registration
2463
- */
2464
- get webhookProcessor() {
2465
- return this.processor;
2466
- }
2467
- };
2468
-
2469
- //#endregion
2470
- //#region src/core/webhook/frameworks/express.ts
2471
- /**
2472
- * Express-specific webhook handler extending the base handler
2473
- */
2474
- var ExpressWebhookHandler = class extends BaseWebhookHandler {
2475
- constructor(config) {
2476
- super(config);
2477
- }
2478
- async handleGet(req, res, next) {
2479
- try {
2480
- const { "hub.mode": mode, "hub.verify_token": token, "hub.challenge": challenge } = req.query;
2481
- const result = await this.processVerification(mode || null, token || null, challenge || null);
2482
- this.applyHeaders(result, res);
2483
- return res.status(result.status).send(result.body);
2484
- } catch (error) {
2485
- next(error);
2486
- return res;
2487
- }
2488
- }
2489
- async handlePost(req, res, next) {
2490
- try {
2491
- const fullUrl = this.constructFullUrl(req.headers, req.url);
2492
- const webRequest = new globalThis.Request(fullUrl, {
2493
- method: req.method,
2494
- headers: req.headers,
2495
- body: JSON.stringify(req.body)
2496
- });
2497
- const result = await this.processWebhook(webRequest);
2498
- this.applyHeaders(result, res);
2499
- return res.status(result.status).send(result.body);
2500
- } catch (error) {
2501
- next(error);
2502
- return res;
2503
- }
2504
- }
2505
- async handleFlow(req, res, next) {
2506
- try {
2507
- const fullUrl = this.constructFullUrl(req.headers, req.url);
2508
- const webRequest = new globalThis.Request(fullUrl, {
2509
- method: req.method,
2510
- headers: req.headers,
2511
- body: req.method === "POST" ? JSON.stringify(req.body) : undefined
2512
- });
2513
- const result = await this.processFlow(webRequest);
2514
- this.applyHeaders(result, res);
2515
- return res.status(result.status).send(result.body);
2516
- } catch (error) {
2517
- next(error);
2518
- return res;
2519
- }
2520
- }
2521
- getHandlers() {
2522
- return {
2523
- GET: (req, res, next) => this.handleGet(req, res, next),
2524
- POST: (req, res, next) => this.handlePost(req, res, next),
2525
- webhook: (req, res, next) => this.autoRoute(req, res, next),
2526
- flow: (req, res, next) => this.handleFlow(req, res, next),
2527
- processor: this.webhookProcessor
2528
- };
2529
- }
2530
- };
2531
- function webhookHandler(config) {
2532
- const handler = new ExpressWebhookHandler(config);
2533
- return handler.getHandlers();
2534
- }
2535
-
2536
- //#endregion
2537
- //#region src/core/webhook/frameworks/nextjs.ts
2538
- /**
2539
- * Next.js Page Router webhook handler extending the base handler
2540
- */
2541
- var NextJsWebhookHandler = class extends BaseWebhookHandler {
2542
- constructor(config) {
2543
- super(config);
2544
- }
2545
- async parseRequestBody(req) {
2546
- if (req.method === "POST" && !req.body) {
2547
- const chunks = [];
2548
- if (typeof req[Symbol.asyncIterator] === "function") {
2549
- for await (const chunk of req) {
2550
- chunks.push(chunk);
2551
- }
2552
- const body = Buffer.concat(chunks).toString();
2553
- if (body.trim()) {
2554
- try {
2555
- req.body = JSON.parse(body);
2556
- } catch (error) {
2557
- throw new Error("Invalid JSON in request body");
2558
- }
2559
- } else {
2560
- req.body = {};
2561
- }
2562
- }
2563
- }
2564
- }
2565
- async handleGet(req, res) {
2566
- try {
2567
- const { "hub.mode": mode, "hub.verify_token": token, "hub.challenge": challenge } = req.query;
2568
- const result = await this.processVerification(mode || null, token || null, challenge || null);
2569
- this.applyHeaders(result, res);
2570
- return res.status(result.status).send(result.body);
2571
- } catch (error) {
2572
- console.error("Webhook verification error:", error);
2573
- return res.status(500).json({ error: "Internal Server Error" });
2574
- }
2575
- }
2576
- async handlePost(req, res) {
2577
- try {
2578
- await this.parseRequestBody(req);
2579
- } catch (error) {
2580
- console.error("Webhook processing error:", error);
2581
- if (error instanceof Error && error.message === "Invalid JSON in request body") {
2582
- return res.status(400).json({ error: "Invalid JSON" });
2583
- }
2584
- return res.status(500).json({ error: "Internal Server Error" });
2585
- }
2586
- try {
2587
- const fullUrl = this.constructFullUrl(req.headers, req.url);
2588
- const webRequest = new Request(fullUrl, {
2589
- method: "POST",
2590
- headers: req.headers,
2591
- body: JSON.stringify(req.body)
2592
- });
2593
- const result = await this.processWebhook(webRequest);
2594
- this.applyHeaders(result, res);
2595
- return res.status(result.status).send(result.body);
2596
- } catch (error) {
2597
- console.error("Webhook processing error:", error);
2598
- return res.status(500).json({ error: "Internal Server Error" });
2599
- }
2600
- }
2601
- async handleFlow(req, res) {
2602
- try {
2603
- const fullUrl = this.constructFullUrl(req.headers, req.url);
2604
- const webRequest = new Request(fullUrl, {
2605
- method: req.method,
2606
- headers: req.headers,
2607
- body: req.method === "POST" ? JSON.stringify(req.body) : undefined
2608
- });
2609
- const result = await this.processFlow(webRequest);
2610
- this.applyHeaders(result, res);
2611
- return res.status(result.status).send(result.body);
2612
- } catch (error) {
2613
- console.error("Flow error:", error);
2614
- return res.status(500).json({ error: "Internal Server Error" });
2615
- }
2616
- }
2617
- getHandlers() {
2618
- return {
2619
- GET: (req, res) => this.handleGet(req, res),
2620
- POST: (req, res) => this.handlePost(req, res),
2621
- webhook: (req, res) => this.autoRoute(req, res),
2622
- flow: (req, res) => this.handleFlow(req, res),
2623
- processor: this.webhookProcessor
2624
- };
2625
- }
2626
- };
2627
- function webhookHandler$1(config) {
2628
- const handler = new NextJsWebhookHandler(config);
2629
- return handler.getHandlers();
2630
- }
2631
-
2632
- //#endregion
2633
- //#region src/core/webhook/utils/generateXHub256Sig.ts
2634
- const generateXHub256Sig = (body, appSecret) => {
2635
- return crypto$1.createHmac("sha256", appSecret).update(body, "utf-8").digest("hex");
2636
- };
2637
-
2638
- //#endregion
2639
- export { AudioMediaTypesEnum, profile_default as BusinessProfileApi, BusinessVerticalEnum, ButtonPositionEnum, CategoryEnum, ComponentTypesEnum, ConversationTypesEnum, CurrencyCodesEnum, DataLocalizationRegionEnum, DocumentMediaTypesEnum, encryption_default as EncryptionApi, webhookHandler as ExpressWebhook, FlowActionEnum, flow_default as FlowApi, FlowCategoryEnum, FlowStatusEnum, FlowTypeEnum, HttpMethodsEnum, ImageMediaTypesEnum, InteractiveTypesEnum, LanguagesEnum, media_default as MediaApi, MessageTypesEnum, messages_default as MessagesApi, webhookHandler$1 as NextJsWebhook, ParametersTypesEnum, phone_default as PhoneNumberApi, qrCode_default as QrCodeApi, ReferralSourceTypesEnum, registration_default as RegistrationApi, RequestCodeMethodsEnum, StatusEnum, StickerMediaTypesEnum, SubTypeEnum, SystemChangeTypesEnum, TemplateApi, TemplateStatusEnum, twoStepVerification_default as TwoStepVerificationApi, VideoMediaTypesEnum, WabaAccountReviewStatus, WabaAccountStatus, waba_default as WabaApi, WabaBusinessVerificationStatus, WabaConfigEnum, WabaHealthStatusCanSendMessage, WebhookTypesEnum, WhatsApp, WhatsApp as WhatsAppLegacy, isFlowDataExchangeRequest, isFlowErrorRequest, isFlowPingRequest, isMetaError };
9
+ `)}const K=new v(`WHATSAPP`,process.env.DEBUG===`true`);var $e=class{config;requester;messages;media;phoneNumbers;twoStepVerification;flows;businessProfile;templates;encryption;qrCode;registration;waba;constructor(e){Qe(),this.config=ge(e),this.requester=new Ce(this.config[g.APIVersion],this.config[g.PhoneNumberId],this.config[g.AccessToken],this.config[g.BusinessAcctId],this.getUserAgent()),this.messages=new E(this.config,this.requester),this.media=new T(this.config,this.requester),this.phoneNumbers=new V(this.config,this.requester),this.twoStepVerification=new Xe(this.config,this.requester),this.flows=new S(this.config,this.requester),this.businessProfile=new Fe(this.config,this.requester),this.templates=new Re(this.config,this.requester),this.encryption=new x(this.config,this.requester),this.qrCode=new Ie(this.config,this.requester),this.registration=new Le(this.config,this.requester),this.waba=new Ze(this.config,this.requester),K.log(`
10
+ `+_e(this.config))}updateTimeout(e){this.config[g.RequestTimeout]=e,`updateTimeout`in this.requester&&this.requester.updateTimeout(e),K.log(`Timeout updated to ${e}ms`)}updateSenderNumberId(e){this.config[g.PhoneNumberId]=e,K.log(`Sender number ID updated to ${e}`)}updateAccessToken(e){this.config[g.AccessToken]=e,`updateAccessToken`in this.requester&&this.requester.updateAccessToken(e),K.log(`Access token updated`)}version(){return y()}static get Enums(){return o}getUserAgent(){return we()}};function et(e){return typeof e==`object`&&!!e}function q(e){return typeof e==`string`}const tt=[C.DATA_EXCHANGE,C.INIT,C.BACK],nt=[C.DATA_EXCHANGE,C.INIT];function rt(e){if(!(`flow_token`in e&&q(e.flow_token)&&`action`in e))return!1;let{action:t,version:n,screen:r,data:i}=e,a=n===`3.0`,o=tt.includes(t),s=r===void 0||q(r)&&r!==`SUCCESS`,c=t===C.DATA_EXCHANGE||et(i);return a&&o&&s&&c}function it(e){if(!(`flow_token`in e&&q(e.flow_token)&&`action`in e))return!1;let{action:t,screen:n,data:r}=e,i=nt.includes(t),a=q(n),o=et(r)&&`error_key`in r&&q(r.error)&&`error_message`in r&&q(r.error_message);return i&&a&&o}function at(e){return`action`in e&&e.action===`ping`}const J=new v(`WEBHOOK_UTILS`,process.env.DEBUG===`true`);async function Y(e,t,n){try{J.info(`Processing webhook messages request`);let r=await e.json();if(J.info(`Webhook request body:`,r),r.object!==`whatsapp_business_account`){let e=`Received webhook for non-WhatsApp event`;return J.warn(e,{body:r}),new Response(JSON.stringify({error:e}),{status:404})}let i=[];for(let e of r.entry)try{J.info(`Processing webhook entry:`,{entryId:e.id});let r=e.changes;for(let i of r)i.field===`messages`&&(J.info(`Processing messages change:`,{change:i}),await lt(e.id,i.value,t,n))}catch(t){let n=`Error processing webhook: ${t}`;J.error(n,{entry:e,error:t}),i.push(n)}return J.info(`Webhook processing complete`,{errorCount:i.length}),new Response(i.length>0?JSON.stringify({errors:i}):null,{status:200})}catch(e){return J.error(`Error processing webhook:`,e),new Response(JSON.stringify({error:`Internal Server Error`}),{status:500})}}async function ot(e,t,n,r){try{J.info(`Processing flow request`);let i=await e.text(),a=e.headers.get(`x-hub-signature-256`);if(J.info(`Flow request signature:`,{signature:a}),!st(i,a,t.WEBHOOK_VERIFICATION_TOKEN||``))return J.warn(`Invalid request signature`,{signature:a}),new Response(JSON.stringify({error:`Unauthorized`}),{status:401});let o=JSON.parse(i);J.info(`Flow request data:`,o);let{decryptedBody:s}=ut(o,t);J.info(`Decrypted flow request:`,s);let c=r.get(w.All);if(!c)return J.warn(`No handler registered for flow action:`,{action:s.action}),new Response(JSON.stringify({error:`Handler not found`}),{status:404});if(at(s))return J.info(`Handling flow ping request`),new Response(JSON.stringify({version:`3.0`,data:{status:`active`}}),{status:200});if(it(s))return J.warn(`Flow error request received:`,s),new Response(null,{status:200});if(rt(s)){J.info(`Processing flow data exchange request`);let e=await c(n,s);J.info(`Flow handler result:`,e);let t=dt(e,Buffer.from(o.aes_key,`base64`),Buffer.from(o.initial_vector,`base64`));return J.info(`Encrypted flow response generated`),new Response(JSON.stringify(t),{status:200})}return J.warn(`Unknown flow request type:`,s),new Response(JSON.stringify({error:`Unknown request type`}),{status:400})}catch(e){return J.error(`Error handling flow request:`,e),new Response(JSON.stringify({error:`Internal server error`}),{status:500})}}function st(e,t,n){if(!t)return J.warn(`Missing signature in request`),!1;J.info(`Signature verification details:`,{bodyLength:e.length,verificationTokenLength:n.length,rawSignature:t,cleanedSignature:t.replace(`sha256=`,``)});let r=a.createHmac(`sha256`,n).update(e).digest(`hex`);return J.info(`Signature verification:`,{received:t.replace(`sha256=`,``),expected:r}),a.timingSafeEqual(Buffer.from(t.replace(`sha256=`,``)),Buffer.from(r))}function ct(e,t){let n=e[`x-forwarded-proto`]||`http`,r=e.host||`localhost`;return`${n}://${r}${t||`/`}`}async function lt(e,t,n,r){J.info(`Processing messages:`,{waba_id:e,value:t});let i=t.metadata,a=t.contacts,o=e,s=i?.display_phone_number||``,c=i?.phone_number_id||``,l=a?.[0]?.profile?.name||``;if(t.statuses&&t.statuses.length>0){J.info(`Processing statuses:`,{statusCount:t.statuses.length});let e=t.statuses;for(let i of e){let e={wabaId:o,id:i.id,from:i.recipient_id,timestamp:i.timestamp,type:u.Statuses,phoneNumberId:c,displayPhoneNumber:s,profileName:l,statuses:t.statuses[0],originalData:i};J.info(`Processing status:`,e),await X(r.messageHandlers.get(u.Statuses),n,e,u.Statuses)}return}if(t.messages&&t.messages.length>0){J.info(`Processing messages:`,{messageCount:t.messages.length});let e=t.messages;for(let t of e){let e=t.type;J.info(`Processing message:`,{messageType:e,messageId:t.id});let i={wabaId:o,id:t.id,from:t.from,timestamp:t.timestamp,type:t.type,phoneNumberId:c,displayPhoneNumber:s,profileName:l,originalData:t};switch(e){case u.Text:i.text=t.text;break;case u.Image:i.image=t.image;break;case u.Video:i.video=t.video;break;case u.Audio:i.audio=t.audio;break;case u.Document:i.document=t.document;break;case u.Sticker:i.sticker=t.sticker;break;case u.Location:i.location=t.location;break;case u.Contacts:i.contacts=t.contacts;break;case u.Interactive:i.interactive=t.interactive;break;case u.Button:i.button=t.button;break;case u.Order:i.order=t.order;break;case u.System:i.system=t.system;break;case u.Reaction:i.reaction=t.reaction;break;default:J.warn(`Unknown message type:`,{messageType:e});break}J.info(`Executing message handlers`),await X(r.preProcessHandler,n,i,`pre-process`),await X(r.messageHandlers.get(e),n,i,e),await X(r.postProcessHandler,n,i,`post-process`)}}}async function X(e,t,n,r){if(e)try{J.info(`Executing handler:`,{handlerType:r,messageId:n.id}),await e(t,n),J.info(`Handler execution complete:`,{handlerType:r,messageId:n.id})}catch(e){J.error(`Error in ${r} handler:`,{error:e,messageId:n.id})}else J.info(`No handler registered:`,{handlerType:r})}function ut(e,t){J.info(`Decrypting flow request`);let{encrypted_aes_key:n,encrypted_flow_data:r,initial_vector:i}=e;if(!n||!r||!i)throw J.error(`Missing required encryption properties`),Error(`Missing required encryption properties`);let o=t.FLOW_API_PRIVATE_PEM.replace(/\\n/g,`
11
+ `),s=t.FLOW_API_PASSPHRASE,c=a.createPrivateKey({key:o,passphrase:s}),l;try{J.info(`Decrypting AES key`),l=a.privateDecrypt({key:c,padding:a.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:`sha256`},Buffer.from(n,`base64`))}catch(e){throw J.error(`Failed to decrypt AES key:`,e),Error(`Failed to decrypt the request. Please verify your private key.`)}let u=Buffer.from(r,`base64`),d=Buffer.from(i,`base64`),f=u.subarray(0,-16),p=u.subarray(-16);J.info(`Decrypting flow data`);let m=a.createDecipheriv(`aes-128-gcm`,l,d);m.setAuthTag(p);let h=Buffer.concat([m.update(f),m.final()]).toString(`utf-8`);return J.info(`Flow request decryption complete`),{decryptedBody:JSON.parse(h),aesKeyBuffer:l,initialVectorBuffer:d}}function dt(e,t,n){J.info(`Encrypting flow response`);let r=[];for(let e of Array.from(n.entries()))r.push(~e[1]);try{let n=a.createCipheriv(`aes-128-gcm`,t,Buffer.from(r)),i=Buffer.concat([n.update(JSON.stringify(e||{}),`utf-8`),n.final(),n.getAuthTag()]).toString(`base64`);return J.info(`Flow response encryption complete`),i}catch(e){throw J.error(`Response encryption error:`,e),Error(`Failed to encrypt response. Internal server error.`)}}const Z=new v(`WEBHOOK_PROCESSOR`,process.env.DEBUG===`true`);var Q=class{config;client;messageHandlers=new Map;preProcessHandler=void 0;postProcessHandler=void 0;flowHandlers=new Map;constructor(e){this.config=ge(e),this.client=new $e(e),Z.log(`WebhookProcessor instantiated`)}async processVerification(e,t,n){return e===`subscribe`&&t===this.config.WEBHOOK_VERIFICATION_TOKEN?{status:200,body:n||``,headers:{"Content-Type":`text/plain`}}:{status:403,body:JSON.stringify({error:`Forbidden`}),headers:{"Content-Type":`application/json`}}}async processWebhook(e){try{let t=await Y(e,this.client,{messageHandlers:this.messageHandlers,preProcessHandler:this.preProcessHandler,postProcessHandler:this.postProcessHandler}),n=await t.text(),r=t.headers.get(`content-type`)||`application/json`;return{status:t.status,body:n,headers:{"Content-Type":r}}}catch(e){return Z.log(`Error processing webhook: ${e}`),{status:500,body:JSON.stringify({error:`Internal Server Error`}),headers:{"Content-Type":`application/json`}}}}async processFlow(e){try{let t=await ot(e,this.config,this.client,this.flowHandlers),n=await t.text(),r=t.headers.get(`content-type`)||`application/json`;return{status:t.status,body:n,headers:{"Content-Type":r}}}catch(e){return Z.log(`Error processing flow: ${e}`),{status:500,body:JSON.stringify({error:`Internal Server Error`}),headers:{"Content-Type":`application/json`}}}}onMessage(e,t){this.messageHandlers.set(e,t),Z.log(`Registered message handler for ${e}`)}onMessagePreProcess(e){this.preProcessHandler=e,Z.log(`Registered pre-process handler`)}onMessagePostProcess(e){this.postProcessHandler=e,Z.log(`Registered post-process handler`)}onFlow(e,t){this.flowHandlers.set(e,t),Z.log(`Registered flow handler for ${e}`)}getClient(){return this.client}getConfig(){return this.config}},$=class{processor;constructor(e){this.processor=new Q(e)}async processVerification(e,t,n){return await this.processor.processVerification(e,t,n)}async processWebhook(e){return await this.processor.processWebhook(e)}async processFlow(e){return await this.processor.processFlow(e)}constructFullUrl(e,t=``){return ct(e,t)}applyHeaders(e,t){t.setHeader&&Object.entries(e.headers).forEach(([e,n])=>{t.setHeader(e,n)})}async autoRoute(e,t,...n){switch(e.method?.toUpperCase()){case`GET`:return await this.handleGet(e,t,...n);case`POST`:return await this.handlePost(e,t,...n);default:if(t.status&&t.json)return t.status(405).json({error:`Method Not Allowed`});throw Error(`Method Not Allowed`)}}get webhookProcessor(){return this.processor}},ft=class extends ${constructor(e){super(e)}async handleGet(e,t,n){try{let{"hub.mode":n,"hub.verify_token":r,"hub.challenge":i}=e.query,a=await this.processVerification(n||null,r||null,i||null);return this.applyHeaders(a,t),t.status(a.status).send(a.body)}catch(e){return n(e),t}}async handlePost(e,t,n){try{let n=this.constructFullUrl(e.headers,e.url),r=new globalThis.Request(n,{method:e.method,headers:e.headers,body:JSON.stringify(e.body)}),i=await this.processWebhook(r);return this.applyHeaders(i,t),t.status(i.status).send(i.body)}catch(e){return n(e),t}}async handleFlow(e,t,n){try{let n=this.constructFullUrl(e.headers,e.url),r=new globalThis.Request(n,{method:e.method,headers:e.headers,body:e.method===`POST`?JSON.stringify(e.body):void 0}),i=await this.processFlow(r);return this.applyHeaders(i,t),t.status(i.status).send(i.body)}catch(e){return n(e),t}}getHandlers(){return{GET:(e,t,n)=>this.handleGet(e,t,n),POST:(e,t,n)=>this.handlePost(e,t,n),webhook:(e,t,n)=>this.autoRoute(e,t,n),flow:(e,t,n)=>this.handleFlow(e,t,n),processor:this.webhookProcessor}}};function pt(e){return new ft(e).getHandlers()}var mt=class extends ${constructor(e){super(e)}async parseRequestBody(e){if(e.method===`POST`&&!e.body){let t=[];if(typeof e[Symbol.asyncIterator]==`function`){for await(let n of e)t.push(n);let n=Buffer.concat(t).toString();if(n.trim())try{e.body=JSON.parse(n)}catch{throw Error(`Invalid JSON in request body`)}else e.body={}}}}async handleGet(e,t){try{let{"hub.mode":n,"hub.verify_token":r,"hub.challenge":i}=e.query,a=await this.processVerification(n||null,r||null,i||null);return this.applyHeaders(a,t),t.status(a.status).send(a.body)}catch(e){return console.error(`Webhook verification error:`,e),t.status(500).json({error:`Internal Server Error`})}}async handlePost(e,t){try{await this.parseRequestBody(e)}catch(e){return console.error(`Webhook processing error:`,e),e instanceof Error&&e.message===`Invalid JSON in request body`?t.status(400).json({error:`Invalid JSON`}):t.status(500).json({error:`Internal Server Error`})}try{let n=this.constructFullUrl(e.headers,e.url),r=new Request(n,{method:`POST`,headers:e.headers,body:JSON.stringify(e.body)}),i=await this.processWebhook(r);return this.applyHeaders(i,t),t.status(i.status).send(i.body)}catch(e){return console.error(`Webhook processing error:`,e),t.status(500).json({error:`Internal Server Error`})}}async handleFlow(e,t){try{let n=this.constructFullUrl(e.headers,e.url),r=new Request(n,{method:e.method,headers:e.headers,body:e.method===`POST`?JSON.stringify(e.body):void 0}),i=await this.processFlow(r);return this.applyHeaders(i,t),t.status(i.status).send(i.body)}catch(e){return console.error(`Flow error:`,e),t.status(500).json({error:`Internal Server Error`})}}getHandlers(){return{GET:(e,t)=>this.handleGet(e,t),POST:(e,t)=>this.handlePost(e,t),webhook:(e,t)=>this.autoRoute(e,t),flow:(e,t)=>this.handleFlow(e,t),processor:this.webhookProcessor}}};function ht(e){return new mt(e).getHandlers()}function gt(e){let t=new Q(e);return{GET:async e=>{try{let{searchParams:n}=new URL(e.url),r=n.get(`hub.mode`),i=n.get(`hub.verify_token`),a=n.get(`hub.challenge`),o=await t.processVerification(r,i,a);return new Response(o.body,{status:o.status,headers:o.headers})}catch(e){return console.error(`Webhook verification error:`,e),new Response(`Internal Server Error`,{status:500})}},POST:async e=>{try{let n=await t.processWebhook(e);return new Response(n.body,{status:n.status,headers:n.headers})}catch(e){return console.error(`Webhook processing error:`,e),new Response(`Internal Server Error`,{status:500})}},webhook:{GET:async e=>{try{let{searchParams:n}=new URL(e.url),r=n.get(`hub.mode`),i=n.get(`hub.verify_token`),a=n.get(`hub.challenge`),o=await t.processVerification(r,i,a);return new Response(o.body,{status:o.status,headers:o.headers})}catch(e){return console.error(`Webhook verification error:`,e),new Response(`Internal Server Error`,{status:500})}},POST:async e=>{try{let n=await t.processWebhook(e);return new Response(n.body,{status:n.status,headers:n.headers})}catch(e){return console.error(`Webhook processing error:`,e),new Response(`Internal Server Error`,{status:500})}}},flow:{GET:async e=>{try{let n=await t.processFlow(e);return Response.json(n.body,{status:n.status,headers:n.headers})}catch(e){return console.error(`Flow GET error:`,e),new Response(`Internal Server Error`,{status:500})}},POST:async e=>{try{let n=await t.processFlow(e);return Response.json(n.body,{status:n.status,headers:n.headers})}catch(e){return console.error(`Flow POST error:`,e),new Response(`Internal Server Error`,{status:500})}}},processor:t}}const _t=(e,t)=>i.createHmac(`sha256`,t).update(e,`utf-8`).digest(`hex`);export{P as AudioMessageBuilder,Fe as BusinessProfileApi,D as ContactMessageBuilder,Te as ContactMessageFactory,F as DocumentMessageBuilder,x as EncryptionApi,S as FlowApi,w as FlowTypeEnum,M as ImageMessageBuilder,k as InteractiveMessageBuilder,Ee as InteractiveMessageFactory,A as LocationMessageBuilder,De as LocationMessageFactory,T as MediaApi,Oe as MediaMessageFactory,E as MessageApi,E as MessagesApi,V as PhoneNumberApi,Ie as QrCodeApi,L as ReactionMessageBuilder,ke as ReactionMessageFactory,Le as RegistrationApi,I as StickerMessageBuilder,Re as TemplateApi,R as TemplateMessageBuilder,Me as TemplateMessageFactory,z as TextMessageBuilder,Ne as TextMessageFactory,Xe as TwoStepVerificationApi,N as VideoMessageBuilder,Ze as WabaApi,Q as WebhookProcessor,$e as WhatsApp,ct as constructFullUrl,He as createAuthenticationTemplate,Ue as createCatalogTemplate,We as createCouponTemplate,Ge as createLimitedTimeOfferTemplate,qe as createMPMTemplate,Ke as createMediaCardCarouselTemplate,Ve as createOTPTemplate,Je as createProductCardCarouselTemplate,Ye as createSPMTemplate,Be as createTemplate,pt as expressWebhookHandler,_t as generateXHub256Sig,gt as nextjsAppWebhookHandler,ht as nextjsWebhookHandler,ot as processFlowRequest,Y as processWebhookMessages};
2640
12
  //# sourceMappingURL=index.js.map