@wazzapi/wazzapi 0.2.0

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.cjs ADDED
@@ -0,0 +1,1550 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
24
+ EVENT_HEADER: () => EVENT_HEADER,
25
+ EVENT_ID_HEADER: () => EVENT_ID_HEADER,
26
+ SIGNATURE_HEADER: () => SIGNATURE_HEADER,
27
+ WazzapiAPIError: () => WazzapiAPIError,
28
+ WazzapiClient: () => WazzapiClient,
29
+ WazzapiError: () => WazzapiError,
30
+ WazzapiMediaError: () => WazzapiMediaError,
31
+ WazzapiWebhookError: () => WazzapiWebhookError,
32
+ WazzapiWebhookParseError: () => WazzapiWebhookParseError,
33
+ WazzapiWebhookVerificationError: () => WazzapiWebhookVerificationError,
34
+ WebhookHandler: () => WebhookHandler,
35
+ __version__: () => __version__,
36
+ _decryptWaMedia: () => _decryptWaMedia,
37
+ _decrypt_wa_media: () => _decrypt_wa_media,
38
+ _mediaInfoBytes: () => _mediaInfoBytes,
39
+ _media_info_bytes: () => _media_info_bytes,
40
+ downloadMedia: () => downloadMedia,
41
+ download_media: () => download_media,
42
+ generateWebhookSignature: () => generateWebhookSignature,
43
+ generate_webhook_signature: () => generate_webhook_signature,
44
+ models: () => models_exports,
45
+ parseAddToGroupResponse: () => parseAddToGroupResponse,
46
+ parseBuiltinVariableInfo: () => parseBuiltinVariableInfo,
47
+ parseBuiltinVariablesResponse: () => parseBuiltinVariablesResponse,
48
+ parseBulkDeleteResponse: () => parseBulkDeleteResponse,
49
+ parseCSVExportResponse: () => parseCSVExportResponse,
50
+ parseCSVImportResponse: () => parseCSVImportResponse,
51
+ parseCancelMessageResponse: () => parseCancelMessageResponse,
52
+ parseContactGroupItem: () => parseContactGroupItem,
53
+ parseContactGroupListResponse: () => parseContactGroupListResponse,
54
+ parseContactGroupMembersResponse: () => parseContactGroupMembersResponse,
55
+ parseContactItem: () => parseContactItem,
56
+ parseContactListResponse: () => parseContactListResponse,
57
+ parseContactResponse: () => parseContactResponse,
58
+ parseContactSyncHistoryItem: () => parseContactSyncHistoryItem,
59
+ parseContactSyncHistoryResponse: () => parseContactSyncHistoryResponse,
60
+ parseContactSyncResponse: () => parseContactSyncResponse,
61
+ parseContactSyncStatusResponse: () => parseContactSyncStatusResponse,
62
+ parseContactSyncStatusResponseList: () => parseContactSyncStatusResponseList,
63
+ parseCreateGroupResponseModel: () => parseCreateGroupResponseModel,
64
+ parseGroupDetailResponse: () => parseGroupDetailResponse,
65
+ parseGroupInviteInfoResponseModel: () => parseGroupInviteInfoResponseModel,
66
+ parseGroupInviteLinkResponseModel: () => parseGroupInviteLinkResponseModel,
67
+ parseGroupListItem: () => parseGroupListItem,
68
+ parseGroupListResponse: () => parseGroupListResponse,
69
+ parseGroupOperationResponseModel: () => parseGroupOperationResponseModel,
70
+ parseGroupParticipantItem: () => parseGroupParticipantItem,
71
+ parseGroupParticipantsResponse: () => parseGroupParticipantsResponse,
72
+ parseInteractiveButton: () => parseInteractiveButton,
73
+ parseInteractiveMessageResponse: () => parseInteractiveMessageResponse,
74
+ parseInteractiveRow: () => parseInteractiveRow,
75
+ parseInteractiveSection: () => parseInteractiveSection,
76
+ parseMediaDownloadResult: () => parseMediaDownloadResult,
77
+ parseMessageItem: () => parseMessageItem,
78
+ parseMessageListResponse: () => parseMessageListResponse,
79
+ parseMessageResponse: () => parseMessageResponse,
80
+ parseMessageStatsResponse: () => parseMessageStatsResponse,
81
+ parsePublicDeviceWebhook: () => parsePublicDeviceWebhook,
82
+ parsePublicMessageWebhook: () => parsePublicMessageWebhook,
83
+ parsePublicWebhookDeviceData: () => parsePublicWebhookDeviceData,
84
+ parsePublicWebhookMessageData: () => parsePublicWebhookMessageData,
85
+ parseRetryMessageResponse: () => parseRetryMessageResponse,
86
+ parseSendGroupResponse: () => parseSendGroupResponse,
87
+ parseSendMessageResponse: () => parseSendMessageResponse,
88
+ parseTemplateItem: () => parseTemplateItem,
89
+ parseTemplateListResponse: () => parseTemplateListResponse,
90
+ parseTemplatePreviewResponse: () => parseTemplatePreviewResponse,
91
+ parseTemplateResponse: () => parseTemplateResponse,
92
+ parseWebhook: () => parseWebhook,
93
+ parseWebhookPayload: () => parseWebhookPayload,
94
+ parse_webhook: () => parse_webhook,
95
+ verifyWebhookSignature: () => verifyWebhookSignature,
96
+ verify_webhook_signature: () => verify_webhook_signature
97
+ });
98
+ module.exports = __toCommonJS(index_exports);
99
+
100
+ // src/errors.ts
101
+ var WazzapiError = class extends Error {
102
+ constructor(message) {
103
+ super(message);
104
+ this.name = "WazzapiError";
105
+ Object.setPrototypeOf(this, new.target.prototype);
106
+ }
107
+ };
108
+ var WazzapiAPIError = class _WazzapiAPIError extends WazzapiError {
109
+ constructor(statusCode, message, options) {
110
+ super(`WazzAPI API error ${statusCode}: ${message}`);
111
+ this.name = "WazzapiAPIError";
112
+ this.statusCode = statusCode;
113
+ this.message = message;
114
+ this.details = options?.details;
115
+ this.responseText = options?.responseText;
116
+ }
117
+ static fromResponseParts(statusCode, reasonPhrase, responseText, payload) {
118
+ let details;
119
+ let message = reasonPhrase || "Request failed";
120
+ if (payload && typeof payload === "object" && !Array.isArray(payload)) {
121
+ const normalizedPayload = payload;
122
+ details = normalizedPayload.detail === void 0 ? payload : normalizedPayload.detail;
123
+ if (typeof details === "string") {
124
+ message = details;
125
+ } else if (Array.isArray(details) && details.length > 0) {
126
+ const firstItem = details[0];
127
+ if (firstItem && typeof firstItem === "object" && "msg" in firstItem && typeof firstItem.msg === "string") {
128
+ message = firstItem.msg;
129
+ } else {
130
+ message = formatErrorMessage(firstItem);
131
+ }
132
+ } else if (normalizedPayload.message !== void 0) {
133
+ message = formatErrorMessage(normalizedPayload.message);
134
+ }
135
+ } else if (payload !== void 0) {
136
+ details = payload;
137
+ message = formatErrorMessage(payload);
138
+ }
139
+ return new _WazzapiAPIError(statusCode, message, {
140
+ details,
141
+ responseText
142
+ });
143
+ }
144
+ };
145
+ function formatErrorMessage(value) {
146
+ if (typeof value === "string") {
147
+ return value;
148
+ }
149
+ if (value === void 0 || value === null) {
150
+ return "Request failed";
151
+ }
152
+ try {
153
+ const serialized = JSON.stringify(value);
154
+ return serialized ?? "Request failed";
155
+ } catch {
156
+ return "Request failed";
157
+ }
158
+ }
159
+ var WazzapiMediaError = class extends WazzapiError {
160
+ constructor(message) {
161
+ super(message);
162
+ this.name = "WazzapiMediaError";
163
+ }
164
+ };
165
+
166
+ // src/models/base.ts
167
+ function cloneObject(input) {
168
+ if (!input || typeof input !== "object") {
169
+ return {};
170
+ }
171
+ const output = {};
172
+ Object.entries(input).forEach(([key, value]) => {
173
+ output[key] = value;
174
+ });
175
+ return output;
176
+ }
177
+ function withDateFields(input, fields) {
178
+ const output = cloneObject(input);
179
+ const mutableOutput = output;
180
+ fields.forEach((field) => {
181
+ if (mutableOutput[field] !== void 0 && mutableOutput[field] !== null) {
182
+ mutableOutput[field] = new Date(
183
+ mutableOutput[field]
184
+ );
185
+ }
186
+ });
187
+ return output;
188
+ }
189
+ function mapArray(value, parser) {
190
+ if (!Array.isArray(value)) {
191
+ return [];
192
+ }
193
+ return value.map((item) => parser(item));
194
+ }
195
+ function serializeData(value) {
196
+ if (value === void 0 || value === null) {
197
+ return void 0;
198
+ }
199
+ if (value instanceof Date) {
200
+ return value.toISOString();
201
+ }
202
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
203
+ return value;
204
+ }
205
+ if (Array.isArray(value)) {
206
+ return value.map((item) => serializeData(item)).filter((item) => item !== void 0);
207
+ }
208
+ if (typeof value === "object") {
209
+ const output = {};
210
+ Object.entries(value).forEach(([key, rawValue]) => {
211
+ const serialized = serializeData(rawValue);
212
+ if (serialized !== void 0) {
213
+ output[key] = serialized;
214
+ }
215
+ });
216
+ return output;
217
+ }
218
+ return value;
219
+ }
220
+ function filterNone(data) {
221
+ if (!data) {
222
+ return void 0;
223
+ }
224
+ const output = {};
225
+ Object.entries(data).forEach(([key, value]) => {
226
+ if (value !== void 0 && value !== null) {
227
+ output[key] = value;
228
+ }
229
+ });
230
+ return output;
231
+ }
232
+
233
+ // src/resources/base.ts
234
+ var BaseResource = class {
235
+ constructor(client) {
236
+ this._client = client;
237
+ }
238
+ };
239
+
240
+ // src/models/index.ts
241
+ var models_exports = {};
242
+ __export(models_exports, {
243
+ parseAddToGroupResponse: () => parseAddToGroupResponse,
244
+ parseBuiltinVariableInfo: () => parseBuiltinVariableInfo,
245
+ parseBuiltinVariablesResponse: () => parseBuiltinVariablesResponse,
246
+ parseBulkDeleteResponse: () => parseBulkDeleteResponse,
247
+ parseCSVExportResponse: () => parseCSVExportResponse,
248
+ parseCSVImportResponse: () => parseCSVImportResponse,
249
+ parseCancelMessageResponse: () => parseCancelMessageResponse,
250
+ parseContactGroupItem: () => parseContactGroupItem,
251
+ parseContactGroupListResponse: () => parseContactGroupListResponse,
252
+ parseContactGroupMembersResponse: () => parseContactGroupMembersResponse,
253
+ parseContactItem: () => parseContactItem,
254
+ parseContactListResponse: () => parseContactListResponse,
255
+ parseContactResponse: () => parseContactResponse,
256
+ parseContactSyncHistoryItem: () => parseContactSyncHistoryItem,
257
+ parseContactSyncHistoryResponse: () => parseContactSyncHistoryResponse,
258
+ parseContactSyncResponse: () => parseContactSyncResponse,
259
+ parseContactSyncStatusResponse: () => parseContactSyncStatusResponse,
260
+ parseContactSyncStatusResponseList: () => parseContactSyncStatusResponseList,
261
+ parseCreateGroupResponseModel: () => parseCreateGroupResponseModel,
262
+ parseGroupDetailResponse: () => parseGroupDetailResponse,
263
+ parseGroupInviteInfoResponseModel: () => parseGroupInviteInfoResponseModel,
264
+ parseGroupInviteLinkResponseModel: () => parseGroupInviteLinkResponseModel,
265
+ parseGroupListItem: () => parseGroupListItem,
266
+ parseGroupListResponse: () => parseGroupListResponse,
267
+ parseGroupOperationResponseModel: () => parseGroupOperationResponseModel,
268
+ parseGroupParticipantItem: () => parseGroupParticipantItem,
269
+ parseGroupParticipantsResponse: () => parseGroupParticipantsResponse,
270
+ parseInteractiveButton: () => parseInteractiveButton,
271
+ parseInteractiveMessageResponse: () => parseInteractiveMessageResponse,
272
+ parseInteractiveRow: () => parseInteractiveRow,
273
+ parseInteractiveSection: () => parseInteractiveSection,
274
+ parseMediaDownloadResult: () => parseMediaDownloadResult,
275
+ parseMessageItem: () => parseMessageItem,
276
+ parseMessageListResponse: () => parseMessageListResponse,
277
+ parseMessageResponse: () => parseMessageResponse,
278
+ parseMessageStatsResponse: () => parseMessageStatsResponse,
279
+ parsePublicDeviceWebhook: () => parsePublicDeviceWebhook,
280
+ parsePublicMessageWebhook: () => parsePublicMessageWebhook,
281
+ parsePublicWebhookDeviceData: () => parsePublicWebhookDeviceData,
282
+ parsePublicWebhookMessageData: () => parsePublicWebhookMessageData,
283
+ parseRetryMessageResponse: () => parseRetryMessageResponse,
284
+ parseSendGroupResponse: () => parseSendGroupResponse,
285
+ parseSendMessageResponse: () => parseSendMessageResponse,
286
+ parseTemplateItem: () => parseTemplateItem,
287
+ parseTemplateListResponse: () => parseTemplateListResponse,
288
+ parseTemplatePreviewResponse: () => parseTemplatePreviewResponse,
289
+ parseTemplateResponse: () => parseTemplateResponse,
290
+ parseWebhookPayload: () => parseWebhookPayload
291
+ });
292
+
293
+ // src/models/contacts.ts
294
+ function parseAddToGroupResponse(input) {
295
+ return cloneObject(input);
296
+ }
297
+ function parseBulkDeleteResponse(input) {
298
+ return cloneObject(input);
299
+ }
300
+ function parseCSVExportResponse(input) {
301
+ return cloneObject(input);
302
+ }
303
+ function parseCSVImportResponse(input) {
304
+ const output = cloneObject(input);
305
+ if (!Array.isArray(output.errors)) {
306
+ output.errors = [];
307
+ }
308
+ return output;
309
+ }
310
+ function parseContactGroupItem(input) {
311
+ return withDateFields(input, ["created_at"]);
312
+ }
313
+ function parseContactGroupListResponse(input) {
314
+ const output = cloneObject(input);
315
+ const typedInput = typeof input === "object" && input ? input : void 0;
316
+ output.groups = mapArray(typedInput?.groups, parseContactGroupItem);
317
+ return output;
318
+ }
319
+ function parseContactItem(input) {
320
+ const output = withDateFields(input, [
321
+ "last_message_at",
322
+ "created_at"
323
+ ]);
324
+ if (!Array.isArray(output.tags)) {
325
+ output.tags = [];
326
+ }
327
+ return output;
328
+ }
329
+ function parseContactGroupMembersResponse(input) {
330
+ const output = cloneObject(input);
331
+ const typedInput = typeof input === "object" && input ? input : void 0;
332
+ output.group = parseContactGroupItem(typedInput?.group);
333
+ output.contacts = mapArray(typedInput?.contacts, parseContactItem);
334
+ return output;
335
+ }
336
+ function parseContactListResponse(input) {
337
+ const output = cloneObject(input);
338
+ const typedInput = typeof input === "object" && input ? input : void 0;
339
+ output.contacts = mapArray(typedInput?.contacts, parseContactItem);
340
+ return output;
341
+ }
342
+ function parseContactResponse(input) {
343
+ const output = withDateFields(input, [
344
+ "opted_out_at",
345
+ "last_message_at",
346
+ "created_at",
347
+ "updated_at"
348
+ ]);
349
+ if (!Array.isArray(output.tags)) {
350
+ output.tags = [];
351
+ }
352
+ return output;
353
+ }
354
+ function parseContactSyncHistoryItem(input) {
355
+ return withDateFields(input, [
356
+ "started_at",
357
+ "completed_at"
358
+ ]);
359
+ }
360
+ function parseContactSyncHistoryResponse(input) {
361
+ const output = cloneObject(input);
362
+ const typedInput = typeof input === "object" && input ? input : void 0;
363
+ output.history = mapArray(typedInput?.history, parseContactSyncHistoryItem);
364
+ return output;
365
+ }
366
+ function parseContactSyncResponse(input) {
367
+ return cloneObject(input);
368
+ }
369
+ function parseContactSyncStatusResponse(input) {
370
+ return withDateFields(input, ["last_sync_at"]);
371
+ }
372
+ function parseContactSyncStatusResponseList(input) {
373
+ return mapArray(input, parseContactSyncStatusResponse);
374
+ }
375
+
376
+ // src/models/groups.ts
377
+ function parseGroupListItem(input) {
378
+ const output = cloneObject(input);
379
+ output.participants_count ?? (output.participants_count = 0);
380
+ return output;
381
+ }
382
+ function parseGroupListResponse(input) {
383
+ const output = cloneObject(input);
384
+ output.groups = mapArray(
385
+ input?.groups,
386
+ parseGroupListItem
387
+ );
388
+ return output;
389
+ }
390
+ function parseGroupDetailResponse(input) {
391
+ const output = cloneObject(input);
392
+ output.participants_count ?? (output.participants_count = 0);
393
+ return output;
394
+ }
395
+ function parseGroupParticipantItem(input) {
396
+ const output = cloneObject(input);
397
+ output.is_admin ?? (output.is_admin = false);
398
+ output.is_super_admin ?? (output.is_super_admin = false);
399
+ return output;
400
+ }
401
+ function parseGroupParticipantsResponse(input) {
402
+ const output = cloneObject(input);
403
+ output.participants = mapArray(
404
+ input?.participants,
405
+ parseGroupParticipantItem
406
+ );
407
+ return output;
408
+ }
409
+ function parseGroupOperationResponseModel(input) {
410
+ return cloneObject(input);
411
+ }
412
+ function parseCreateGroupResponseModel(input) {
413
+ return cloneObject(input);
414
+ }
415
+ function parseSendGroupResponse(input) {
416
+ return cloneObject(input);
417
+ }
418
+ function parseGroupInviteLinkResponseModel(input) {
419
+ return cloneObject(input);
420
+ }
421
+ function parseGroupInviteInfoResponseModel(input) {
422
+ const output = cloneObject(input);
423
+ output.participants ?? (output.participants = 0);
424
+ return output;
425
+ }
426
+
427
+ // src/models/media.ts
428
+ function parseMediaDownloadResult(input) {
429
+ return cloneObject(input);
430
+ }
431
+
432
+ // src/models/messages.ts
433
+ function parseInteractiveButton(input) {
434
+ return cloneObject(input);
435
+ }
436
+ function parseCancelMessageResponse(input) {
437
+ return cloneObject(input);
438
+ }
439
+ function parseInteractiveMessageResponse(input) {
440
+ return cloneObject(input);
441
+ }
442
+ function parseInteractiveRow(input) {
443
+ return cloneObject(input);
444
+ }
445
+ function parseInteractiveSection(input) {
446
+ const output = cloneObject(input);
447
+ const typedInput = typeof input === "object" && input ? input : void 0;
448
+ output.rows = mapArray(typedInput?.rows, parseInteractiveRow);
449
+ return output;
450
+ }
451
+ function parseMessageItem(input) {
452
+ const output = withDateFields(input, [
453
+ "scheduled_for",
454
+ "created_at",
455
+ "sent_at",
456
+ "delivered_at",
457
+ "read_at"
458
+ ]);
459
+ output.message_type ?? (output.message_type = "text");
460
+ return output;
461
+ }
462
+ function parseMessageListResponse(input) {
463
+ const output = cloneObject(input);
464
+ const typedInput = typeof input === "object" && input ? input : void 0;
465
+ output.messages = mapArray(typedInput?.messages, parseMessageItem);
466
+ return output;
467
+ }
468
+ function parseMessageResponse(input) {
469
+ const output = withDateFields(input, [
470
+ "scheduled_for",
471
+ "queued_at",
472
+ "sent_at",
473
+ "delivered_at",
474
+ "read_at",
475
+ "failed_at",
476
+ "created_at",
477
+ "updated_at"
478
+ ]);
479
+ output.message_type ?? (output.message_type = "text");
480
+ return output;
481
+ }
482
+ function parseMessageStatsResponse(input) {
483
+ return cloneObject(input);
484
+ }
485
+ function parseRetryMessageResponse(input) {
486
+ return cloneObject(input);
487
+ }
488
+ function parseSendMessageResponse(input) {
489
+ return cloneObject(input);
490
+ }
491
+
492
+ // src/models/templates.ts
493
+ function parseBuiltinVariableInfo(input) {
494
+ return cloneObject(input);
495
+ }
496
+ function parseBuiltinVariablesResponse(input) {
497
+ const output = cloneObject(input);
498
+ const typedInput = typeof input === "object" && input ? input : void 0;
499
+ output.variables = mapArray(typedInput?.variables, parseBuiltinVariableInfo);
500
+ return output;
501
+ }
502
+ function parseTemplateItem(input) {
503
+ const output = withDateFields(input, [
504
+ "last_used_at",
505
+ "created_at"
506
+ ]);
507
+ if (!Array.isArray(output.variables)) {
508
+ output.variables = [];
509
+ }
510
+ if (!Array.isArray(output.builtin_variables)) {
511
+ output.builtin_variables = [];
512
+ }
513
+ if (!Array.isArray(output.custom_variables)) {
514
+ output.custom_variables = [];
515
+ }
516
+ return output;
517
+ }
518
+ function parseTemplateListResponse(input) {
519
+ const output = cloneObject(input);
520
+ const typedInput = typeof input === "object" && input ? input : void 0;
521
+ output.data = mapArray(typedInput?.data, parseTemplateItem);
522
+ return output;
523
+ }
524
+ function parseTemplatePreviewResponse(input) {
525
+ const output = cloneObject(input);
526
+ if (!Array.isArray(output.all_variables)) {
527
+ output.all_variables = [];
528
+ }
529
+ if (!Array.isArray(output.builtin_variables)) {
530
+ output.builtin_variables = [];
531
+ }
532
+ if (!Array.isArray(output.custom_variables)) {
533
+ output.custom_variables = [];
534
+ }
535
+ if (!Array.isArray(output.missing_variables)) {
536
+ output.missing_variables = [];
537
+ }
538
+ return output;
539
+ }
540
+ function parseTemplateResponse(input) {
541
+ const output = withDateFields(input, [
542
+ "last_used_at",
543
+ "created_at",
544
+ "updated_at"
545
+ ]);
546
+ if (!Array.isArray(output.variables)) {
547
+ output.variables = [];
548
+ }
549
+ if (!Array.isArray(output.builtin_variables)) {
550
+ output.builtin_variables = [];
551
+ }
552
+ if (!Array.isArray(output.custom_variables)) {
553
+ output.custom_variables = [];
554
+ }
555
+ return output;
556
+ }
557
+
558
+ // src/models/webhooks.ts
559
+ function parsePublicWebhookMessageData(input) {
560
+ return withDateFields(input, [
561
+ "sent_at",
562
+ "delivered_at",
563
+ "read_at",
564
+ "failed_at"
565
+ ]);
566
+ }
567
+ function parsePublicWebhookDeviceData(input) {
568
+ return withDateFields(input, [
569
+ "sent_at",
570
+ "delivered_at",
571
+ "read_at",
572
+ "failed_at"
573
+ ]);
574
+ }
575
+ function parsePublicMessageWebhook(input) {
576
+ const output = withDateFields(input, ["timestamp"]);
577
+ const typedInput = typeof input === "object" && input ? input : void 0;
578
+ output.data = parsePublicWebhookMessageData(typedInput?.data);
579
+ return output;
580
+ }
581
+ function parsePublicDeviceWebhook(input) {
582
+ const output = withDateFields(input, ["timestamp"]);
583
+ const typedInput = typeof input === "object" && input ? input : void 0;
584
+ output.data = parsePublicWebhookDeviceData(typedInput?.data);
585
+ return output;
586
+ }
587
+ function parseWebhookPayload(input) {
588
+ const output = cloneObject(input);
589
+ if (typeof output.event_type !== "string") {
590
+ const error = new TypeError("Webhook payload is missing event_type");
591
+ throw error;
592
+ }
593
+ if (output.event_type.startsWith("message.")) {
594
+ return parsePublicMessageWebhook(output);
595
+ }
596
+ if (output.event_type.startsWith("device.")) {
597
+ return parsePublicDeviceWebhook(output);
598
+ }
599
+ throw new TypeError(`Unsupported webhook event type: ${output.event_type}`);
600
+ }
601
+
602
+ // src/resources/contacts.ts
603
+ var ContactsResource = class extends BaseResource {
604
+ async list(options) {
605
+ return this._client._request("GET", "/api/v1/contacts", {
606
+ params: options,
607
+ responseParser: parseContactListResponse
608
+ });
609
+ }
610
+ async create(payload) {
611
+ return this._client._request("POST", "/api/v1/contacts", {
612
+ jsonBody: payload,
613
+ responseParser: parseContactResponse
614
+ });
615
+ }
616
+ async bulkDelete(payload) {
617
+ return this._client._request("POST", "/api/v1/contacts/bulk-delete", {
618
+ jsonBody: payload,
619
+ responseParser: parseBulkDeleteResponse
620
+ });
621
+ }
622
+ async bulk_delete(payload) {
623
+ return this.bulkDelete(payload);
624
+ }
625
+ async listGroups(options) {
626
+ return this._client._request("GET", "/api/v1/contacts/groups", {
627
+ params: options,
628
+ responseParser: parseContactGroupListResponse
629
+ });
630
+ }
631
+ async list_groups(options) {
632
+ return this.listGroups(options);
633
+ }
634
+ async createGroup(payload) {
635
+ return this._client._request("POST", "/api/v1/contacts/groups", {
636
+ jsonBody: payload,
637
+ responseParser: parseContactGroupItem
638
+ });
639
+ }
640
+ async create_group(payload) {
641
+ return this.createGroup(payload);
642
+ }
643
+ async getGroup(groupId, options) {
644
+ return this._client._request("GET", `/api/v1/contacts/groups/${groupId}`, {
645
+ params: options,
646
+ responseParser: parseContactGroupMembersResponse
647
+ });
648
+ }
649
+ async get_group(groupId, options) {
650
+ return this.getGroup(groupId, options);
651
+ }
652
+ async updateGroup(groupId, payload) {
653
+ return this._client._request(
654
+ "PATCH",
655
+ `/api/v1/contacts/groups/${groupId}`,
656
+ {
657
+ jsonBody: payload,
658
+ responseParser: parseContactGroupItem
659
+ }
660
+ );
661
+ }
662
+ async update_group(groupId, payload) {
663
+ return this.updateGroup(groupId, payload);
664
+ }
665
+ async deleteGroup(groupId) {
666
+ await this._client._request("DELETE", `/api/v1/contacts/groups/${groupId}`);
667
+ }
668
+ async delete_group(groupId) {
669
+ return this.deleteGroup(groupId);
670
+ }
671
+ async addToGroup(groupId, payload) {
672
+ return this._client._request(
673
+ "POST",
674
+ `/api/v1/contacts/groups/${groupId}/members`,
675
+ {
676
+ jsonBody: payload,
677
+ responseParser: parseAddToGroupResponse
678
+ }
679
+ );
680
+ }
681
+ async add_to_group(groupId, payload) {
682
+ return this.addToGroup(groupId, payload);
683
+ }
684
+ async removeFromGroup(groupId, payload) {
685
+ return this._client._request(
686
+ "DELETE",
687
+ `/api/v1/contacts/groups/${groupId}/members`,
688
+ {
689
+ jsonBody: payload,
690
+ responseParser: parseAddToGroupResponse
691
+ }
692
+ );
693
+ }
694
+ async remove_from_group(groupId, payload) {
695
+ return this.removeFromGroup(groupId, payload);
696
+ }
697
+ async importCsv(payload) {
698
+ return this._client._request("POST", "/api/v1/contacts/import/csv", {
699
+ jsonBody: payload,
700
+ responseParser: parseCSVImportResponse
701
+ });
702
+ }
703
+ async import_csv(payload) {
704
+ return this.importCsv(payload);
705
+ }
706
+ async exportCsv(options) {
707
+ return this._client._request("GET", "/api/v1/contacts/export/csv", {
708
+ params: options,
709
+ responseParser: parseCSVExportResponse
710
+ });
711
+ }
712
+ async export_csv(options) {
713
+ return this.exportCsv(options);
714
+ }
715
+ async sync(payload) {
716
+ return this._client._request("POST", "/api/v1/contacts/sync", {
717
+ jsonBody: payload,
718
+ responseParser: parseContactSyncResponse
719
+ });
720
+ }
721
+ async syncStatus() {
722
+ return this._client._request("GET", "/api/v1/contacts/sync/status", {
723
+ responseParser: parseContactSyncStatusResponseList
724
+ });
725
+ }
726
+ async sync_status() {
727
+ return this.syncStatus();
728
+ }
729
+ async syncHistory(options) {
730
+ return this._client._request("GET", "/api/v1/contacts/sync/history", {
731
+ params: options,
732
+ responseParser: parseContactSyncHistoryResponse
733
+ });
734
+ }
735
+ async sync_history(options) {
736
+ return this.syncHistory(options);
737
+ }
738
+ async importTemplate() {
739
+ return this._client._request(
740
+ "GET",
741
+ "/api/v1/contacts/import/template"
742
+ );
743
+ }
744
+ async import_template() {
745
+ return this.importTemplate();
746
+ }
747
+ async get(contactId) {
748
+ return this._client._request("GET", `/api/v1/contacts/${contactId}`, {
749
+ responseParser: parseContactResponse
750
+ });
751
+ }
752
+ async update(contactId, payload) {
753
+ return this._client._request("PATCH", `/api/v1/contacts/${contactId}`, {
754
+ jsonBody: payload,
755
+ responseParser: parseContactResponse
756
+ });
757
+ }
758
+ async delete(contactId) {
759
+ await this._client._request("DELETE", `/api/v1/contacts/${contactId}`);
760
+ }
761
+ };
762
+
763
+ // src/resources/groups.ts
764
+ var GroupsResource = class extends BaseResource {
765
+ async list(options) {
766
+ return this._client._request("GET", "/api/v1/groups", {
767
+ params: options,
768
+ responseParser: parseGroupListResponse
769
+ });
770
+ }
771
+ async get(groupJid, options) {
772
+ return this._client._request("GET", `/api/v1/groups/${groupJid}`, {
773
+ params: options,
774
+ responseParser: parseGroupDetailResponse
775
+ });
776
+ }
777
+ async getParticipants(groupJid, options) {
778
+ return this._client._request(
779
+ "GET",
780
+ `/api/v1/groups/${groupJid}/participants`,
781
+ {
782
+ params: options,
783
+ responseParser: parseGroupParticipantsResponse
784
+ }
785
+ );
786
+ }
787
+ async get_participants(groupJid, options) {
788
+ return this.getParticipants(groupJid, options);
789
+ }
790
+ async create(payload) {
791
+ return this._client._request("POST", "/api/v1/groups/create", {
792
+ jsonBody: payload,
793
+ responseParser: parseCreateGroupResponseModel
794
+ });
795
+ }
796
+ async sendText(payload) {
797
+ return this._client._request("POST", "/api/v1/groups/send", {
798
+ jsonBody: payload,
799
+ responseParser: parseSendGroupResponse
800
+ });
801
+ }
802
+ async send_text(payload) {
803
+ return this.sendText(payload);
804
+ }
805
+ async sendMedia(payload) {
806
+ return this._client._request("POST", "/api/v1/groups/send/media", {
807
+ jsonBody: payload,
808
+ responseParser: parseSendGroupResponse
809
+ });
810
+ }
811
+ async send_media(payload) {
812
+ return this.sendMedia(payload);
813
+ }
814
+ async updateParticipants(payload) {
815
+ return this._client._request("POST", "/api/v1/groups/participants", {
816
+ jsonBody: payload,
817
+ responseParser: parseGroupOperationResponseModel
818
+ });
819
+ }
820
+ async update_participants(payload) {
821
+ return this.updateParticipants(payload);
822
+ }
823
+ async addParticipant(groupJid, options) {
824
+ return this._client._request(
825
+ "POST",
826
+ `/api/v1/groups/${groupJid}/participants/add`,
827
+ {
828
+ params: options,
829
+ responseParser: parseGroupOperationResponseModel
830
+ }
831
+ );
832
+ }
833
+ async add_participant(groupJid, options) {
834
+ return this.addParticipant(groupJid, options);
835
+ }
836
+ async removeParticipant(groupJid, options) {
837
+ return this._client._request(
838
+ "POST",
839
+ `/api/v1/groups/${groupJid}/participants/remove`,
840
+ {
841
+ params: options,
842
+ responseParser: parseGroupOperationResponseModel
843
+ }
844
+ );
845
+ }
846
+ async remove_participant(groupJid, options) {
847
+ return this.removeParticipant(groupJid, options);
848
+ }
849
+ async getInviteLink(groupJid, options) {
850
+ return this._client._request(
851
+ "POST",
852
+ `/api/v1/groups/${groupJid}/invite-link`,
853
+ {
854
+ params: options,
855
+ responseParser: parseGroupInviteLinkResponseModel
856
+ }
857
+ );
858
+ }
859
+ async get_invite_link(groupJid, options) {
860
+ return this.getInviteLink(groupJid, options);
861
+ }
862
+ async getInviteInfo(payload) {
863
+ return this._client._request("POST", "/api/v1/groups/invite-info", {
864
+ jsonBody: payload,
865
+ responseParser: parseGroupInviteInfoResponseModel
866
+ });
867
+ }
868
+ async get_invite_info(payload) {
869
+ return this.getInviteInfo(payload);
870
+ }
871
+ async join(payload) {
872
+ return this._client._request("POST", "/api/v1/groups/join", {
873
+ jsonBody: payload,
874
+ responseParser: parseGroupOperationResponseModel
875
+ });
876
+ }
877
+ async leave(groupJid, options) {
878
+ return this._client._request("POST", `/api/v1/groups/${groupJid}/leave`, {
879
+ params: options,
880
+ responseParser: parseGroupOperationResponseModel
881
+ });
882
+ }
883
+ async setName(groupJid, payload) {
884
+ return this._client._request("POST", `/api/v1/groups/${groupJid}/name`, {
885
+ jsonBody: payload,
886
+ responseParser: parseGroupOperationResponseModel
887
+ });
888
+ }
889
+ async set_name(groupJid, payload) {
890
+ return this.setName(groupJid, payload);
891
+ }
892
+ async setTopic(groupJid, payload) {
893
+ return this._client._request("POST", `/api/v1/groups/${groupJid}/topic`, {
894
+ jsonBody: payload,
895
+ responseParser: parseGroupOperationResponseModel
896
+ });
897
+ }
898
+ async set_topic(groupJid, payload) {
899
+ return this.setTopic(groupJid, payload);
900
+ }
901
+ async setPhoto(groupJid, payload) {
902
+ return this._client._request("POST", `/api/v1/groups/${groupJid}/photo`, {
903
+ jsonBody: payload,
904
+ responseParser: parseGroupOperationResponseModel
905
+ });
906
+ }
907
+ async set_photo(groupJid, payload) {
908
+ return this.setPhoto(groupJid, payload);
909
+ }
910
+ async removePhoto(groupJid, options) {
911
+ return this._client._request("DELETE", `/api/v1/groups/${groupJid}/photo`, {
912
+ params: options,
913
+ responseParser: parseGroupOperationResponseModel
914
+ });
915
+ }
916
+ async remove_photo(groupJid, options) {
917
+ return this.removePhoto(groupJid, options);
918
+ }
919
+ async setAnnounce(groupJid, payload) {
920
+ return this._client._request(
921
+ "POST",
922
+ `/api/v1/groups/${groupJid}/announce`,
923
+ {
924
+ jsonBody: payload,
925
+ responseParser: parseGroupOperationResponseModel
926
+ }
927
+ );
928
+ }
929
+ async set_announce(groupJid, payload) {
930
+ return this.setAnnounce(groupJid, payload);
931
+ }
932
+ async setLocked(groupJid, payload) {
933
+ return this._client._request("POST", `/api/v1/groups/${groupJid}/locked`, {
934
+ jsonBody: payload,
935
+ responseParser: parseGroupOperationResponseModel
936
+ });
937
+ }
938
+ async set_locked(groupJid, payload) {
939
+ return this.setLocked(groupJid, payload);
940
+ }
941
+ async setEphemeral(groupJid, payload) {
942
+ return this._client._request(
943
+ "POST",
944
+ `/api/v1/groups/${groupJid}/ephemeral`,
945
+ {
946
+ jsonBody: payload,
947
+ responseParser: parseGroupOperationResponseModel
948
+ }
949
+ );
950
+ }
951
+ async set_ephemeral(groupJid, payload) {
952
+ return this.setEphemeral(groupJid, payload);
953
+ }
954
+ };
955
+
956
+ // src/resources/messages.ts
957
+ var MessagesResource = class extends BaseResource {
958
+ async lookup(whatsappMessageId) {
959
+ return this._client._request("GET", "/api/v1/messages/lookup", {
960
+ params: { whatsapp_message_id: whatsappMessageId },
961
+ responseParser: parseMessageResponse
962
+ });
963
+ }
964
+ async list(options) {
965
+ return this._client._request("GET", "/api/v1/messages", {
966
+ params: options,
967
+ responseParser: parseMessageListResponse
968
+ });
969
+ }
970
+ async get(messageId) {
971
+ return this._client._request("GET", `/api/v1/messages/${messageId}`, {
972
+ responseParser: parseMessageResponse
973
+ });
974
+ }
975
+ async stats() {
976
+ return this._client._request("GET", "/api/v1/messages/stats/summary", {
977
+ responseParser: parseMessageStatsResponse
978
+ });
979
+ }
980
+ async send(payload) {
981
+ return this._client._request("POST", "/api/v1/messages/send", {
982
+ jsonBody: payload,
983
+ responseParser: parseSendMessageResponse
984
+ });
985
+ }
986
+ async sendImage(payload) {
987
+ return this._client._request("POST", "/api/v1/messages/send/image", {
988
+ jsonBody: payload,
989
+ responseParser: parseSendMessageResponse
990
+ });
991
+ }
992
+ async send_image(payload) {
993
+ return this.sendImage(payload);
994
+ }
995
+ async sendVideo(payload) {
996
+ return this._client._request("POST", "/api/v1/messages/send/video", {
997
+ jsonBody: payload,
998
+ responseParser: parseSendMessageResponse
999
+ });
1000
+ }
1001
+ async send_video(payload) {
1002
+ return this.sendVideo(payload);
1003
+ }
1004
+ async sendVoice(payload) {
1005
+ return this._client._request("POST", "/api/v1/messages/send/voice", {
1006
+ jsonBody: payload,
1007
+ responseParser: parseSendMessageResponse
1008
+ });
1009
+ }
1010
+ async send_voice(payload) {
1011
+ return this.sendVoice(payload);
1012
+ }
1013
+ async sendDocument(payload) {
1014
+ return this._client._request("POST", "/api/v1/messages/send/document", {
1015
+ jsonBody: payload,
1016
+ responseParser: parseSendMessageResponse
1017
+ });
1018
+ }
1019
+ async send_document(payload) {
1020
+ return this.sendDocument(payload);
1021
+ }
1022
+ async sendLocation(payload) {
1023
+ return this._client._request("POST", "/api/v1/messages/send/location", {
1024
+ jsonBody: payload,
1025
+ responseParser: parseSendMessageResponse
1026
+ });
1027
+ }
1028
+ async send_location(payload) {
1029
+ return this.sendLocation(payload);
1030
+ }
1031
+ async sendContact(payload) {
1032
+ return this._client._request("POST", "/api/v1/messages/send/contact", {
1033
+ jsonBody: payload,
1034
+ responseParser: parseSendMessageResponse
1035
+ });
1036
+ }
1037
+ async send_contact(payload) {
1038
+ return this.sendContact(payload);
1039
+ }
1040
+ async retry(messageId) {
1041
+ return this._client._request(
1042
+ "POST",
1043
+ `/api/v1/messages/${messageId}/retry`,
1044
+ {
1045
+ responseParser: parseRetryMessageResponse
1046
+ }
1047
+ );
1048
+ }
1049
+ async cancel(messageId) {
1050
+ return this._client._request(
1051
+ "POST",
1052
+ `/api/v1/messages/${messageId}/cancel`,
1053
+ {
1054
+ responseParser: parseCancelMessageResponse
1055
+ }
1056
+ );
1057
+ }
1058
+ async sendButtons(payload) {
1059
+ return this._client._request(
1060
+ "POST",
1061
+ "/api/v1/messages/send/interactive/buttons",
1062
+ {
1063
+ jsonBody: payload,
1064
+ responseParser: parseInteractiveMessageResponse
1065
+ }
1066
+ );
1067
+ }
1068
+ async send_buttons(payload) {
1069
+ return this.sendButtons(payload);
1070
+ }
1071
+ async sendList(payload) {
1072
+ return this._client._request(
1073
+ "POST",
1074
+ "/api/v1/messages/send/interactive/list",
1075
+ {
1076
+ jsonBody: payload,
1077
+ responseParser: parseInteractiveMessageResponse
1078
+ }
1079
+ );
1080
+ }
1081
+ async send_list(payload) {
1082
+ return this.sendList(payload);
1083
+ }
1084
+ };
1085
+
1086
+ // src/resources/templates.ts
1087
+ var TemplatesResource = class extends BaseResource {
1088
+ async builtinVariables() {
1089
+ return this._client._request("GET", "/api/v1/templates/builtin-variables", {
1090
+ responseParser: parseBuiltinVariablesResponse
1091
+ });
1092
+ }
1093
+ async builtin_variables() {
1094
+ return this.builtinVariables();
1095
+ }
1096
+ async list(options) {
1097
+ return this._client._request("GET", "/api/v1/templates", {
1098
+ params: options,
1099
+ responseParser: parseTemplateListResponse
1100
+ });
1101
+ }
1102
+ async create(payload) {
1103
+ return this._client._request("POST", "/api/v1/templates", {
1104
+ jsonBody: payload,
1105
+ responseParser: parseTemplateResponse
1106
+ });
1107
+ }
1108
+ async get(templateId) {
1109
+ return this._client._request("GET", `/api/v1/templates/${templateId}`, {
1110
+ responseParser: parseTemplateResponse
1111
+ });
1112
+ }
1113
+ async update(templateId, payload) {
1114
+ return this._client._request("PATCH", `/api/v1/templates/${templateId}`, {
1115
+ jsonBody: payload,
1116
+ responseParser: parseTemplateResponse
1117
+ });
1118
+ }
1119
+ async delete(templateId) {
1120
+ await this._client._request("DELETE", `/api/v1/templates/${templateId}`);
1121
+ }
1122
+ async preview(payload) {
1123
+ return this._client._request("POST", "/api/v1/templates/preview", {
1124
+ jsonBody: payload,
1125
+ responseParser: parseTemplatePreviewResponse
1126
+ });
1127
+ }
1128
+ };
1129
+
1130
+ // src/client.ts
1131
+ var DEFAULT_BASE_URL = "https://api.wazzapi.com";
1132
+ function buildHeaders(apiKey, headers) {
1133
+ const merged = {
1134
+ Accept: "application/json",
1135
+ "Content-Type": "application/json"
1136
+ };
1137
+ if (headers) {
1138
+ Object.entries(headers).forEach(([key, value]) => {
1139
+ merged[key] = value;
1140
+ });
1141
+ }
1142
+ if (apiKey) {
1143
+ merged.Authorization = apiKey.toLowerCase().startsWith("bearer ") ? apiKey : `Bearer ${apiKey}`;
1144
+ }
1145
+ return merged;
1146
+ }
1147
+ function parseJson(text) {
1148
+ if (!text) {
1149
+ return void 0;
1150
+ }
1151
+ return JSON.parse(text);
1152
+ }
1153
+ function normalizeBaseUrl(baseUrl) {
1154
+ return baseUrl.replace(/\/+$/, "");
1155
+ }
1156
+ var WazzapiClient = class {
1157
+ constructor(options = {}) {
1158
+ const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
1159
+ const timeout = options.timeout ?? 3e4;
1160
+ const fetcher = options.fetch ?? fetch;
1161
+ this.http = {
1162
+ baseUrl: normalizeBaseUrl(baseUrl),
1163
+ headers: buildHeaders(options.apiKey, options.headers),
1164
+ timeout,
1165
+ fetch: fetcher
1166
+ };
1167
+ this.contacts = new ContactsResource(this);
1168
+ this.groups = new GroupsResource(this);
1169
+ this.messages = new MessagesResource(this);
1170
+ this.templates = new TemplatesResource(this);
1171
+ }
1172
+ get base_url() {
1173
+ return this.http.baseUrl;
1174
+ }
1175
+ async close() {
1176
+ return;
1177
+ }
1178
+ async _request(method, path, options = {}) {
1179
+ const url = new URL(path, `${this.http.baseUrl}/`);
1180
+ const params = filterNone(options.params);
1181
+ if (params) {
1182
+ Object.entries(params).forEach(([key, value]) => {
1183
+ url.searchParams.set(key, String(value));
1184
+ });
1185
+ }
1186
+ const body = options.jsonBody ? JSON.stringify(serializeData(options.jsonBody)) : void 0;
1187
+ const controller = new AbortController();
1188
+ const timeoutId = setTimeout(() => {
1189
+ controller.abort();
1190
+ }, this.http.timeout);
1191
+ try {
1192
+ const response = await this.http.fetch(url.toString(), {
1193
+ method,
1194
+ headers: this.http.headers,
1195
+ body,
1196
+ signal: controller.signal
1197
+ });
1198
+ const responseText = await response.text();
1199
+ const payload = responseText.length > 0 ? parseJson(responseText) : void 0;
1200
+ if (response.status >= 400) {
1201
+ throw WazzapiAPIError.fromResponseParts(
1202
+ response.status,
1203
+ response.statusText,
1204
+ responseText,
1205
+ payload
1206
+ );
1207
+ }
1208
+ if (response.status === 204 || responseText.length === 0) {
1209
+ return void 0;
1210
+ }
1211
+ if (options.responseParser) {
1212
+ return options.responseParser(payload);
1213
+ }
1214
+ return payload ?? responseText;
1215
+ } finally {
1216
+ clearTimeout(timeoutId);
1217
+ }
1218
+ }
1219
+ };
1220
+
1221
+ // src/media.ts
1222
+ var import_node_crypto = require("crypto");
1223
+ var WA_MEDIA_INFO = {
1224
+ image: Buffer.from("WhatsApp Image Keys", "utf8"),
1225
+ video: Buffer.from("WhatsApp Video Keys", "utf8"),
1226
+ audio: Buffer.from("WhatsApp Audio Keys", "utf8"),
1227
+ ptt: Buffer.from("WhatsApp Audio Keys", "utf8"),
1228
+ document: Buffer.from("WhatsApp Document Keys", "utf8"),
1229
+ sticker: Buffer.from("WhatsApp Image Keys", "utf8"),
1230
+ history: Buffer.from("WhatsApp History Keys", "utf8")
1231
+ };
1232
+ function _mediaInfoBytes(mimetype) {
1233
+ const mt = mimetype.toLowerCase();
1234
+ if (mt.startsWith("image/")) {
1235
+ return WA_MEDIA_INFO.image;
1236
+ }
1237
+ if (mt.startsWith("video/")) {
1238
+ return WA_MEDIA_INFO.video;
1239
+ }
1240
+ if (mt.startsWith("audio/")) {
1241
+ return WA_MEDIA_INFO.audio;
1242
+ }
1243
+ return WA_MEDIA_INFO.document;
1244
+ }
1245
+ function _decryptWaMedia(mediaKeyBase64, encryptedData, mimetype) {
1246
+ if (encryptedData.length < 10) {
1247
+ throw new WazzapiMediaError("Encrypted data too short");
1248
+ }
1249
+ let mediaKey;
1250
+ try {
1251
+ mediaKey = Buffer.from(mediaKeyBase64, "base64");
1252
+ } catch {
1253
+ throw new WazzapiMediaError("Invalid media_key base64");
1254
+ }
1255
+ if (mediaKey.length === 0) {
1256
+ throw new WazzapiMediaError("Invalid media_key base64");
1257
+ }
1258
+ const expanded = Buffer.from(
1259
+ (0, import_node_crypto.hkdfSync)(
1260
+ "sha256",
1261
+ mediaKey,
1262
+ Buffer.alloc(0),
1263
+ _mediaInfoBytes(mimetype),
1264
+ 112
1265
+ )
1266
+ );
1267
+ const iv = expanded.subarray(0, 16);
1268
+ const aesKey = expanded.subarray(16, 48);
1269
+ const macKey = expanded.subarray(48, 80);
1270
+ const ciphertext = encryptedData.subarray(0, -10);
1271
+ const mac = encryptedData.subarray(-10);
1272
+ const computedMac = (0, import_node_crypto.createHmac)("sha256", macKey).update(Buffer.concat([iv, ciphertext])).digest().subarray(0, 10);
1273
+ if (!computedMac.equals(mac)) {
1274
+ throw new WazzapiMediaError(
1275
+ "MAC verification failed \u2014 media may be corrupted or mediaKey is wrong"
1276
+ );
1277
+ }
1278
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-cbc", aesKey, iv);
1279
+ decipher.setAutoPadding(false);
1280
+ const paddedPlaintext = Buffer.concat([
1281
+ decipher.update(ciphertext),
1282
+ decipher.final()
1283
+ ]);
1284
+ if (paddedPlaintext.length === 0) {
1285
+ throw new WazzapiMediaError("Decrypted plaintext is empty");
1286
+ }
1287
+ const padLen = paddedPlaintext[paddedPlaintext.length - 1];
1288
+ if (padLen === 0 || padLen > 16 || padLen > paddedPlaintext.length) {
1289
+ throw new WazzapiMediaError("Invalid PKCS7 padding");
1290
+ }
1291
+ for (let i = paddedPlaintext.length - padLen; i < paddedPlaintext.length; i += 1) {
1292
+ if (paddedPlaintext[i] !== padLen) {
1293
+ throw new WazzapiMediaError("Invalid PKCS7 padding");
1294
+ }
1295
+ }
1296
+ return paddedPlaintext.subarray(0, paddedPlaintext.length - padLen);
1297
+ }
1298
+ async function downloadMedia(url, mediaKey, mimetype, options) {
1299
+ const fetcher = options?.fetch ?? fetch;
1300
+ let response;
1301
+ try {
1302
+ response = await fetcher(url);
1303
+ } catch (error) {
1304
+ throw new WazzapiMediaError(`CDN fetch error: ${String(error)}`);
1305
+ }
1306
+ if (!response.ok) {
1307
+ throw new WazzapiMediaError(`CDN fetch failed: ${response.status}`);
1308
+ }
1309
+ const encryptedData = Buffer.from(await response.arrayBuffer());
1310
+ if (options?.file_enc_sha256) {
1311
+ const expectedEncrypted = Buffer.from(options.file_enc_sha256, "base64");
1312
+ const actualEncrypted = (0, import_node_crypto.createHash)("sha256").update(encryptedData).digest();
1313
+ if (!actualEncrypted.equals(expectedEncrypted)) {
1314
+ throw new WazzapiMediaError(
1315
+ `file_enc_sha256 mismatch: CDN returned wrong data (got ${encryptedData.length} bytes)`
1316
+ );
1317
+ }
1318
+ }
1319
+ const plaintext = _decryptWaMedia(mediaKey, encryptedData, mimetype);
1320
+ if (options?.file_sha256) {
1321
+ const expectedPlain = Buffer.from(options.file_sha256, "base64");
1322
+ const actualPlain = (0, import_node_crypto.createHash)("sha256").update(plaintext).digest();
1323
+ if (!actualPlain.equals(expectedPlain)) {
1324
+ throw new WazzapiMediaError("file_sha256 mismatch after decryption");
1325
+ }
1326
+ }
1327
+ return {
1328
+ content: plaintext,
1329
+ mimetype,
1330
+ file_name: options?.file_name || "media",
1331
+ file_size: plaintext.length
1332
+ };
1333
+ }
1334
+ var download_media = downloadMedia;
1335
+ var _decrypt_wa_media = _decryptWaMedia;
1336
+ var _media_info_bytes = _mediaInfoBytes;
1337
+
1338
+ // src/webhooks.ts
1339
+ var import_node_crypto2 = require("crypto");
1340
+ var SIGNATURE_HEADER = "X-Wazzapi-Signature";
1341
+ var EVENT_HEADER = "X-Wazzapi-Event";
1342
+ var EVENT_ID_HEADER = "X-Wazzapi-Event-ID";
1343
+ var SIGNATURE_PREFIX = "sha256=";
1344
+ var WazzapiWebhookError = class extends Error {
1345
+ constructor(message) {
1346
+ super(message);
1347
+ this.name = "WazzapiWebhookError";
1348
+ Object.setPrototypeOf(this, new.target.prototype);
1349
+ }
1350
+ };
1351
+ var WazzapiWebhookVerificationError = class extends WazzapiWebhookError {
1352
+ constructor(message) {
1353
+ super(message);
1354
+ this.name = "WazzapiWebhookVerificationError";
1355
+ }
1356
+ };
1357
+ var WazzapiWebhookParseError = class extends WazzapiWebhookError {
1358
+ constructor(message) {
1359
+ super(message);
1360
+ this.name = "WazzapiWebhookParseError";
1361
+ }
1362
+ };
1363
+ function toBuffer(payload) {
1364
+ if (typeof payload === "string") {
1365
+ return Buffer.from(payload, "utf8");
1366
+ }
1367
+ return Buffer.from(payload);
1368
+ }
1369
+ function getHeader(headers, name) {
1370
+ const normalizedName = name.toLowerCase();
1371
+ if (typeof Headers !== "undefined" && headers instanceof Headers) {
1372
+ return headers.get(name) ?? void 0;
1373
+ }
1374
+ return Object.entries(headers).find(
1375
+ ([key]) => key.toLowerCase() === normalizedName
1376
+ )?.[1];
1377
+ }
1378
+ function generateWebhookSignature(payload, secret) {
1379
+ const digest = (0, import_node_crypto2.createHmac)("sha256", Buffer.from(secret, "utf8")).update(toBuffer(payload)).digest("hex");
1380
+ return `${SIGNATURE_PREFIX}${digest}`;
1381
+ }
1382
+ function verifyWebhookSignature(payload, signature, secret) {
1383
+ const normalizedSignature = signature.trim();
1384
+ const expected = Buffer.from(
1385
+ generateWebhookSignature(payload, secret),
1386
+ "utf8"
1387
+ );
1388
+ const actual = Buffer.from(normalizedSignature, "utf8");
1389
+ if (expected.length !== actual.length) {
1390
+ return false;
1391
+ }
1392
+ return (0, import_node_crypto2.timingSafeEqual)(expected, actual);
1393
+ }
1394
+ var WebhookHandler = class {
1395
+ constructor(secret) {
1396
+ this.secret = secret;
1397
+ }
1398
+ generateSignature(payload) {
1399
+ return generateWebhookSignature(payload, this.secret);
1400
+ }
1401
+ verifySignature(payload, signature) {
1402
+ return verifyWebhookSignature(payload, signature, this.secret);
1403
+ }
1404
+ verifyHeaders(payload, headers) {
1405
+ const signature = getHeader(headers, SIGNATURE_HEADER);
1406
+ if (!signature) {
1407
+ throw new WazzapiWebhookVerificationError(
1408
+ `Missing required webhook header: ${SIGNATURE_HEADER}`
1409
+ );
1410
+ }
1411
+ if (!this.verifySignature(payload, signature)) {
1412
+ throw new WazzapiWebhookVerificationError("Invalid webhook signature");
1413
+ }
1414
+ if (!getHeader(headers, EVENT_HEADER)) {
1415
+ throw new WazzapiWebhookVerificationError(
1416
+ `Missing required webhook header: ${EVENT_HEADER}`
1417
+ );
1418
+ }
1419
+ if (!getHeader(headers, EVENT_ID_HEADER)) {
1420
+ throw new WazzapiWebhookVerificationError(
1421
+ `Missing required webhook header: ${EVENT_ID_HEADER}`
1422
+ );
1423
+ }
1424
+ }
1425
+ parse(payload) {
1426
+ let rawPayload;
1427
+ try {
1428
+ rawPayload = JSON.parse(toBuffer(payload).toString("utf8"));
1429
+ } catch {
1430
+ throw new WazzapiWebhookParseError("Webhook payload is not valid JSON");
1431
+ }
1432
+ if (!rawPayload || typeof rawPayload !== "object" || Array.isArray(rawPayload)) {
1433
+ throw new WazzapiWebhookParseError(
1434
+ "Webhook payload must be a JSON object"
1435
+ );
1436
+ }
1437
+ const eventType = rawPayload.event_type;
1438
+ if (typeof eventType !== "string") {
1439
+ throw new WazzapiWebhookParseError(
1440
+ "Webhook payload is missing event_type"
1441
+ );
1442
+ }
1443
+ if (eventType.startsWith("message.")) {
1444
+ return parsePublicMessageWebhook(rawPayload);
1445
+ }
1446
+ if (eventType.startsWith("device.")) {
1447
+ return parsePublicDeviceWebhook(rawPayload);
1448
+ }
1449
+ throw new WazzapiWebhookParseError(
1450
+ `Unsupported webhook event type: ${eventType}`
1451
+ );
1452
+ }
1453
+ verifyAndParse(payload, headers) {
1454
+ this.verifyHeaders(payload, headers);
1455
+ const parsed = this.parse(payload);
1456
+ const headerEvent = getHeader(headers, EVENT_HEADER);
1457
+ if (headerEvent && headerEvent !== parsed.event_type) {
1458
+ throw new WazzapiWebhookVerificationError(
1459
+ "Webhook event header does not match payload event_type"
1460
+ );
1461
+ }
1462
+ return parsed;
1463
+ }
1464
+ };
1465
+ function parseWebhook(payload, headers, secret) {
1466
+ return new WebhookHandler(secret).verifyAndParse(payload, headers);
1467
+ }
1468
+ var generate_webhook_signature = generateWebhookSignature;
1469
+ var verify_webhook_signature = verifyWebhookSignature;
1470
+ var parse_webhook = parseWebhook;
1471
+
1472
+ // src/index.ts
1473
+ var __version__ = "0.2.0";
1474
+ // Annotate the CommonJS export names for ESM import in node:
1475
+ 0 && (module.exports = {
1476
+ DEFAULT_BASE_URL,
1477
+ EVENT_HEADER,
1478
+ EVENT_ID_HEADER,
1479
+ SIGNATURE_HEADER,
1480
+ WazzapiAPIError,
1481
+ WazzapiClient,
1482
+ WazzapiError,
1483
+ WazzapiMediaError,
1484
+ WazzapiWebhookError,
1485
+ WazzapiWebhookParseError,
1486
+ WazzapiWebhookVerificationError,
1487
+ WebhookHandler,
1488
+ __version__,
1489
+ _decryptWaMedia,
1490
+ _decrypt_wa_media,
1491
+ _mediaInfoBytes,
1492
+ _media_info_bytes,
1493
+ downloadMedia,
1494
+ download_media,
1495
+ generateWebhookSignature,
1496
+ generate_webhook_signature,
1497
+ models,
1498
+ parseAddToGroupResponse,
1499
+ parseBuiltinVariableInfo,
1500
+ parseBuiltinVariablesResponse,
1501
+ parseBulkDeleteResponse,
1502
+ parseCSVExportResponse,
1503
+ parseCSVImportResponse,
1504
+ parseCancelMessageResponse,
1505
+ parseContactGroupItem,
1506
+ parseContactGroupListResponse,
1507
+ parseContactGroupMembersResponse,
1508
+ parseContactItem,
1509
+ parseContactListResponse,
1510
+ parseContactResponse,
1511
+ parseContactSyncHistoryItem,
1512
+ parseContactSyncHistoryResponse,
1513
+ parseContactSyncResponse,
1514
+ parseContactSyncStatusResponse,
1515
+ parseContactSyncStatusResponseList,
1516
+ parseCreateGroupResponseModel,
1517
+ parseGroupDetailResponse,
1518
+ parseGroupInviteInfoResponseModel,
1519
+ parseGroupInviteLinkResponseModel,
1520
+ parseGroupListItem,
1521
+ parseGroupListResponse,
1522
+ parseGroupOperationResponseModel,
1523
+ parseGroupParticipantItem,
1524
+ parseGroupParticipantsResponse,
1525
+ parseInteractiveButton,
1526
+ parseInteractiveMessageResponse,
1527
+ parseInteractiveRow,
1528
+ parseInteractiveSection,
1529
+ parseMediaDownloadResult,
1530
+ parseMessageItem,
1531
+ parseMessageListResponse,
1532
+ parseMessageResponse,
1533
+ parseMessageStatsResponse,
1534
+ parsePublicDeviceWebhook,
1535
+ parsePublicMessageWebhook,
1536
+ parsePublicWebhookDeviceData,
1537
+ parsePublicWebhookMessageData,
1538
+ parseRetryMessageResponse,
1539
+ parseSendGroupResponse,
1540
+ parseSendMessageResponse,
1541
+ parseTemplateItem,
1542
+ parseTemplateListResponse,
1543
+ parseTemplatePreviewResponse,
1544
+ parseTemplateResponse,
1545
+ parseWebhook,
1546
+ parseWebhookPayload,
1547
+ parse_webhook,
1548
+ verifyWebhookSignature,
1549
+ verify_webhook_signature
1550
+ });