better-zap 0.0.1

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.
@@ -0,0 +1,51 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/client.ts
3
+ function createZapClient(options) {
4
+ const baseURL = options?.baseURL ?? (typeof window !== "undefined" ? window.location.origin : "");
5
+ const basePath = options?.basePath ?? "/api/whatsapp";
6
+ const fetchFn = options?.fetch ?? fetch;
7
+ async function request(path, init) {
8
+ const response = await fetchFn(`${baseURL}${basePath}${path}`, init);
9
+ if (!response.ok) {
10
+ const error = await response.json().catch(() => ({}));
11
+ throw new Error(error.error || `Request failed: ${response.status}`);
12
+ }
13
+ return response.json();
14
+ }
15
+ function post(path, body) {
16
+ return request(path, {
17
+ method: "POST",
18
+ headers: { "Content-Type": "application/json" },
19
+ body: JSON.stringify(body)
20
+ });
21
+ }
22
+ /** Strip non-digits to get the canonical 13-digit phone for URL paths. */
23
+ function normalizePhone(phone) {
24
+ return phone.replace(/\D/g, "");
25
+ }
26
+ return {
27
+ send: {
28
+ text: (params) => post("/send/text", params),
29
+ template: ((params) => post("/send/template", params)),
30
+ templateRaw: (params) => post("/send/template", params),
31
+ interactive: (params) => post("/send/interactive", params),
32
+ location: (params) => post("/send/location", params)
33
+ },
34
+ conversations: {
35
+ list: () => request("/conversations"),
36
+ get: (phone) => request(`/conversations/${normalizePhone(phone)}`).catch((err) => {
37
+ if (err.message?.includes("Conversation not found")) return null;
38
+ throw err;
39
+ }),
40
+ messages: (phone, opts) => {
41
+ const params = new URLSearchParams();
42
+ if (opts?.cursor) params.set("cursor", opts.cursor);
43
+ if (opts?.limit) params.set("limit", String(opts.limit));
44
+ const qs = params.toString();
45
+ return request(`/conversations/${normalizePhone(phone)}/messages${qs ? `?${qs}` : ""}`);
46
+ }
47
+ }
48
+ };
49
+ }
50
+ //#endregion
51
+ exports.createZapClient = createZapClient;
@@ -0,0 +1,2 @@
1
+ import { n as createZapClient, t as ZapClient } from "./client-D5Lgtacj.cjs";
2
+ export { ZapClient, createZapClient };
@@ -0,0 +1,2 @@
1
+ import { n as createZapClient, t as ZapClient } from "./client-ColqW3Zc.mjs";
2
+ export { ZapClient, createZapClient };
@@ -0,0 +1,50 @@
1
+ //#region src/client.ts
2
+ function createZapClient(options) {
3
+ const baseURL = options?.baseURL ?? (typeof window !== "undefined" ? window.location.origin : "");
4
+ const basePath = options?.basePath ?? "/api/whatsapp";
5
+ const fetchFn = options?.fetch ?? fetch;
6
+ async function request(path, init) {
7
+ const response = await fetchFn(`${baseURL}${basePath}${path}`, init);
8
+ if (!response.ok) {
9
+ const error = await response.json().catch(() => ({}));
10
+ throw new Error(error.error || `Request failed: ${response.status}`);
11
+ }
12
+ return response.json();
13
+ }
14
+ function post(path, body) {
15
+ return request(path, {
16
+ method: "POST",
17
+ headers: { "Content-Type": "application/json" },
18
+ body: JSON.stringify(body)
19
+ });
20
+ }
21
+ /** Strip non-digits to get the canonical 13-digit phone for URL paths. */
22
+ function normalizePhone(phone) {
23
+ return phone.replace(/\D/g, "");
24
+ }
25
+ return {
26
+ send: {
27
+ text: (params) => post("/send/text", params),
28
+ template: ((params) => post("/send/template", params)),
29
+ templateRaw: (params) => post("/send/template", params),
30
+ interactive: (params) => post("/send/interactive", params),
31
+ location: (params) => post("/send/location", params)
32
+ },
33
+ conversations: {
34
+ list: () => request("/conversations"),
35
+ get: (phone) => request(`/conversations/${normalizePhone(phone)}`).catch((err) => {
36
+ if (err.message?.includes("Conversation not found")) return null;
37
+ throw err;
38
+ }),
39
+ messages: (phone, opts) => {
40
+ const params = new URLSearchParams();
41
+ if (opts?.cursor) params.set("cursor", opts.cursor);
42
+ if (opts?.limit) params.set("limit", String(opts.limit));
43
+ const qs = params.toString();
44
+ return request(`/conversations/${normalizePhone(phone)}/messages${qs ? `?${qs}` : ""}`);
45
+ }
46
+ }
47
+ };
48
+ }
49
+ //#endregion
50
+ export { createZapClient };
package/dist/index.cjs ADDED
@@ -0,0 +1,580 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_client = require("./client.cjs");
3
+ //#region src/logger.ts
4
+ const LOG_LEVEL_ORDER = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3
9
+ };
10
+ const CONSOLE_METHODS = {
11
+ debug: "debug",
12
+ info: "info",
13
+ warn: "warn",
14
+ error: "error"
15
+ };
16
+ function defaultLog(level, message, context) {
17
+ const entry = {
18
+ level,
19
+ message,
20
+ context,
21
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
22
+ };
23
+ console[CONSOLE_METHODS[level]](JSON.stringify(entry));
24
+ }
25
+ function createLogger(config) {
26
+ if (config?.disabled) return noopLogger;
27
+ const minLevel = LOG_LEVEL_ORDER[config?.level ?? "info"];
28
+ const logFn = config?.log ?? defaultLog;
29
+ function emit(level, message, context) {
30
+ if (LOG_LEVEL_ORDER[level] >= minLevel) logFn(level, message, context ?? {});
31
+ }
32
+ return {
33
+ debug: (msg, ctx) => emit("debug", msg, ctx),
34
+ info: (msg, ctx) => emit("info", msg, ctx),
35
+ warn: (msg, ctx) => emit("warn", msg, ctx),
36
+ error: (msg, ctx) => emit("error", msg, ctx)
37
+ };
38
+ }
39
+ const noopLogger = {
40
+ debug() {},
41
+ info() {},
42
+ warn() {},
43
+ error() {}
44
+ };
45
+ function serializeError(err) {
46
+ if (err instanceof Error) return {
47
+ message: err.message,
48
+ name: err.name,
49
+ stack: err.stack
50
+ };
51
+ return { message: String(err) };
52
+ }
53
+ //#endregion
54
+ //#region src/utils/phone.ts
55
+ /**
56
+ * Formats a phone number to the international format required by Meta Cloud API.
57
+ * Currently defaults to Brazilian country code (55) if not provided.
58
+ * Normalizes Brazilian numbers to always include the 9th digit.
59
+ */
60
+ function formatPhone(phone) {
61
+ const digits = phone.replace(/\D/g, "");
62
+ if (digits.startsWith("55") && digits.length === 13) return digits;
63
+ if (digits.startsWith("55") && digits.length === 12) return `55${digits.slice(2, 4)}9${digits.slice(4)}`;
64
+ if (digits.length === 11) return `55${digits}`;
65
+ if (digits.length === 10) return `55${digits.slice(0, 2)}9${digits.slice(2)}`;
66
+ throw new Error(`[formatPhone] Cannot normalize phone: "${phone}" (${digits.length} digits). Expected 10–13 digit Brazilian number.`);
67
+ }
68
+ //#endregion
69
+ //#region src/utils/delay.ts
70
+ /**
71
+ * Utility function to pause execution for a given number of milliseconds.
72
+ * Useful for exponential backoff or rate limiting.
73
+ */
74
+ function delay(ms) {
75
+ return new Promise((resolve) => setTimeout(resolve, ms));
76
+ }
77
+ //#endregion
78
+ //#region src/services/whatsapp.service.ts
79
+ const META_API_VERSION = "v25.0";
80
+ const META_BASE_URL = "https://graph.facebook.com";
81
+ var WhatsAppService = class {
82
+ baseUrl;
83
+ token;
84
+ isDev;
85
+ logger;
86
+ log;
87
+ constructor(config, logger, log) {
88
+ this.baseUrl = `${META_BASE_URL}/${META_API_VERSION}/${config.phoneId}/messages`;
89
+ this.token = config.token;
90
+ this.isDev = config.environment === "development";
91
+ this.logger = logger;
92
+ this.log = log;
93
+ }
94
+ /** Send a text message (within 24h service window only). */
95
+ async sendText(to, body, logging) {
96
+ const hasUrl = /https?:\/\/\S+/i.test(body);
97
+ const payload = {
98
+ messaging_product: "whatsapp",
99
+ recipient_type: "individual",
100
+ to: formatPhone(to),
101
+ type: "text",
102
+ text: hasUrl ? {
103
+ body,
104
+ preview_url: true
105
+ } : { body }
106
+ };
107
+ return this.send(payload, {
108
+ ...logging,
109
+ messageType: logging?.messageType || "bot_reply",
110
+ content: body
111
+ });
112
+ }
113
+ /** Send a template message (works outside service window). */
114
+ async sendTemplate(to, templateName, languageCode = "pt_BR", components, logging) {
115
+ const payload = {
116
+ messaging_product: "whatsapp",
117
+ to: formatPhone(to),
118
+ type: "template",
119
+ template: {
120
+ name: templateName,
121
+ language: { code: languageCode },
122
+ ...components && { components }
123
+ }
124
+ };
125
+ return this.send(payload, logging);
126
+ }
127
+ /** Send an interactive message with reply buttons (up to 3). */
128
+ async sendInteractiveButtons(to, bodyText, buttons, logging) {
129
+ const payload = {
130
+ messaging_product: "whatsapp",
131
+ recipient_type: "individual",
132
+ to: formatPhone(to),
133
+ type: "interactive",
134
+ interactive: {
135
+ type: "button",
136
+ body: { text: bodyText },
137
+ action: { buttons: buttons.map((b) => ({
138
+ type: "reply",
139
+ reply: {
140
+ id: b.id,
141
+ title: b.title
142
+ }
143
+ })) }
144
+ }
145
+ };
146
+ return this.send(payload, {
147
+ ...logging,
148
+ messageType: logging?.messageType || "bot_reply",
149
+ content: bodyText
150
+ });
151
+ }
152
+ /** Send an interactive list message with sections and rows. */
153
+ async sendInteractiveList(to, bodyText, buttonLabel, sections, logging) {
154
+ const payload = {
155
+ messaging_product: "whatsapp",
156
+ recipient_type: "individual",
157
+ to: formatPhone(to),
158
+ type: "interactive",
159
+ interactive: {
160
+ type: "list",
161
+ body: { text: bodyText },
162
+ action: {
163
+ button: buttonLabel,
164
+ sections
165
+ }
166
+ }
167
+ };
168
+ return this.send(payload, {
169
+ ...logging,
170
+ messageType: logging?.messageType || "bot_reply",
171
+ content: bodyText
172
+ });
173
+ }
174
+ /** Send an interactive media carousel message (2-10 cards). */
175
+ async sendInteractiveMediaCarousel(data, logging) {
176
+ const { to, body, cards } = data;
177
+ if (cards.length < 2 || cards.length > 10) return {
178
+ success: false,
179
+ error: "[sendInteractiveMediaCarousel] cards must contain between 2 and 10 items"
180
+ };
181
+ const mappedCards = cards.map((card, index) => ({
182
+ card_index: index,
183
+ type: "cta_url",
184
+ header: {
185
+ type: card.header.type,
186
+ ...card.header.type === "image" ? { image: { link: card.header.link } } : { video: { link: card.header.link } }
187
+ },
188
+ ...card.bodyText ? { body: { text: card.bodyText } } : {},
189
+ action: {
190
+ name: "cta_url",
191
+ parameters: {
192
+ display_text: card.button.displayText,
193
+ url: card.button.url
194
+ }
195
+ }
196
+ }));
197
+ const payload = {
198
+ messaging_product: "whatsapp",
199
+ recipient_type: "individual",
200
+ to: formatPhone(to),
201
+ type: "interactive",
202
+ interactive: {
203
+ type: "carousel",
204
+ body: { text: body },
205
+ action: { cards: mappedCards }
206
+ }
207
+ };
208
+ return this.send(payload, {
209
+ ...logging,
210
+ messageType: logging?.messageType || "bot_reply",
211
+ content: body
212
+ });
213
+ }
214
+ /** Send a location pin message. */
215
+ async sendLocation(to, latitude, longitude, name, address, logging) {
216
+ const payload = {
217
+ messaging_product: "whatsapp",
218
+ recipient_type: "individual",
219
+ to: formatPhone(to),
220
+ type: "location",
221
+ location: {
222
+ latitude,
223
+ longitude,
224
+ name,
225
+ address
226
+ }
227
+ };
228
+ return this.send(payload, {
229
+ ...logging,
230
+ messageType: logging?.messageType || "bot_reply",
231
+ content: `[Localização: ${name} - ${address}]`
232
+ });
233
+ }
234
+ /**
235
+ * Mark an inbound message as read.
236
+ *
237
+ * @see https://developers.facebook.com/docs/whatsapp/cloud-api/messages/mark-messages-as-read
238
+ */
239
+ async markAsRead(messageId) {
240
+ const payload = {
241
+ messaging_product: "whatsapp",
242
+ status: "read",
243
+ message_id: messageId
244
+ };
245
+ if (this.isDev) {
246
+ this.log.debug("whatsapp.dev_send", {
247
+ action: "mark_as_read",
248
+ payload
249
+ });
250
+ return {
251
+ success: true,
252
+ messageId: `dev-${Date.now()}`
253
+ };
254
+ }
255
+ return this.performRequest(payload, 0);
256
+ }
257
+ /**
258
+ * Show or hide a typing indicator in the chat.
259
+ * When starting, the indicator auto-dismisses after 25 seconds or when a message is sent.
260
+ *
261
+ * @see https://developers.facebook.com/docs/whatsapp/cloud-api/typing-indicators/
262
+ */
263
+ async typingIndicator(messageId, action = "typing_on") {
264
+ const payload = {
265
+ messaging_product: "whatsapp",
266
+ status: "read",
267
+ message_id: messageId,
268
+ typing_indicator: { type: action === "typing_on" ? "text" : void 0 }
269
+ };
270
+ if (this.isDev) {
271
+ this.log.debug("whatsapp.dev_send", {
272
+ action: "typing_indicator",
273
+ typingAction: action,
274
+ payload
275
+ });
276
+ return {
277
+ success: true,
278
+ messageId: `dev-${Date.now()}`
279
+ };
280
+ }
281
+ return this.performRequest(payload, 0);
282
+ }
283
+ /**
284
+ * Add a reaction to a message.
285
+ *
286
+ * @see https://developers.facebook.com/docs/whatsapp/cloud-api/messages/reaction-messages
287
+ */
288
+ async sendReaction(to, messageId, emoji) {
289
+ const payload = {
290
+ messaging_product: "whatsapp",
291
+ recipient_type: "individual",
292
+ to: formatPhone(to),
293
+ type: "reaction",
294
+ reaction: {
295
+ message_id: messageId,
296
+ emoji
297
+ }
298
+ };
299
+ return this.send(payload);
300
+ }
301
+ /** Core send method with retry logic (2 retries, exponential backoff). */
302
+ async send(payload, logging, retries = 2) {
303
+ if (this.isDev) {
304
+ this.log.debug("whatsapp.dev_send", {
305
+ action: "send",
306
+ payload
307
+ });
308
+ return {
309
+ success: true,
310
+ messageId: `dev-${Date.now()}`
311
+ };
312
+ }
313
+ const result = await this.performRequest(payload, retries);
314
+ if (logging) try {
315
+ await this.logger.logOutgoing({
316
+ phone: payload.to,
317
+ userId: logging.userId,
318
+ messageType: logging.messageType,
319
+ content: logging.content,
320
+ templateName: payload.type === "template" ? payload.template.name : void 0,
321
+ result,
322
+ metadata: logging.metadata
323
+ });
324
+ } catch (logError) {
325
+ this.log.error("whatsapp.log_failed", serializeError(logError));
326
+ }
327
+ return result;
328
+ }
329
+ /** Actually performs the network request with retries. */
330
+ async performRequest(payload, retries) {
331
+ for (let attempt = 0; attempt <= retries; attempt++) try {
332
+ const response = await fetch(this.baseUrl, {
333
+ method: "POST",
334
+ headers: {
335
+ Authorization: `Bearer ${this.token}`,
336
+ "Content-Type": "application/json"
337
+ },
338
+ body: JSON.stringify(payload)
339
+ });
340
+ if (!response.ok) {
341
+ let errorData = null;
342
+ try {
343
+ errorData = await response.json();
344
+ } catch {
345
+ errorData = null;
346
+ }
347
+ if (response.status === 429 && attempt < retries) {
348
+ await delay(1e3 * (attempt + 1));
349
+ continue;
350
+ }
351
+ if (response.status >= 500 && attempt < retries) {
352
+ await delay(500 * (attempt + 1));
353
+ continue;
354
+ }
355
+ return {
356
+ success: false,
357
+ error: errorData?.error?.message || `HTTP ${response.status}`,
358
+ errorCode: errorData?.error?.code,
359
+ httpStatus: response.status
360
+ };
361
+ }
362
+ return {
363
+ success: true,
364
+ messageId: (await response.json()).messages[0]?.id
365
+ };
366
+ } catch (error) {
367
+ if (attempt < retries) {
368
+ await delay(500 * (attempt + 1));
369
+ continue;
370
+ }
371
+ return {
372
+ success: false,
373
+ error: error instanceof Error ? error.message : "Network error"
374
+ };
375
+ }
376
+ return {
377
+ success: false,
378
+ error: "Max retries exceeded"
379
+ };
380
+ }
381
+ };
382
+ //#endregion
383
+ //#region src/services/message-logger.service.ts
384
+ const WHATSAPP_MESSAGE_TYPES = [
385
+ "queue_position",
386
+ "next_in_line",
387
+ "queue_optin",
388
+ "marketing",
389
+ "bot_reply",
390
+ "reminder",
391
+ "satisfaction",
392
+ "incoming"
393
+ ];
394
+ var MessageLoggerService = class {
395
+ log;
396
+ constructor(store, log, notifier) {
397
+ this.store = store;
398
+ this.notifier = notifier;
399
+ this.log = log;
400
+ }
401
+ async notify(event) {
402
+ if (!this.notifier) return;
403
+ try {
404
+ await this.notifier.notify(event);
405
+ } catch (err) {
406
+ this.log.error("message_logger.sync_notify_failed", serializeError(err));
407
+ }
408
+ }
409
+ /**
410
+ * Check if a message with this waMessageId was already processed.
411
+ */
412
+ async isDuplicate(waMessageId) {
413
+ return !!await this.store.getMessageByWaId(waMessageId);
414
+ }
415
+ /**
416
+ * Log outgoing message for LGPD compliance
417
+ */
418
+ async logOutgoing(params) {
419
+ const inserted = await this.store.createWhatsAppLog({
420
+ phone: params.phone,
421
+ userId: params.userId,
422
+ direction: "outgoing",
423
+ messageType: params.messageType,
424
+ content: params.content,
425
+ templateName: params.templateName,
426
+ waMessageId: params.result.messageId,
427
+ status: params.result.success ? "sent" : "failed",
428
+ errorMessage: params.result.error,
429
+ sentAt: (/* @__PURE__ */ new Date()).toISOString(),
430
+ metadata: params.metadata
431
+ });
432
+ const conversation = await this.store.getConversationById(inserted.conversationId);
433
+ if (conversation) await this.notify({
434
+ type: "NEW_MESSAGE",
435
+ message: inserted,
436
+ conversation
437
+ });
438
+ return inserted.id;
439
+ }
440
+ /**
441
+ * Update message status from webhook callback.
442
+ * Only applies if the new status advances the lifecycle (atomic, no race conditions).
443
+ * Returns true if the update was applied, false if skipped.
444
+ */
445
+ async updateStatus(waMessageId, status, timestamp, errorMessage) {
446
+ const updates = { status };
447
+ if (status === "sent") updates.sentAt = timestamp;
448
+ else if (status === "delivered") updates.deliveredAt = timestamp;
449
+ else if (status === "read") updates.readAt = timestamp;
450
+ else if (status === "failed") updates.errorMessage = errorMessage;
451
+ const updated = await this.store.updateStatusIfProgressed(waMessageId, status, updates);
452
+ if (updated) await this.notify({
453
+ type: "STATUS_UPDATE",
454
+ waMessageId,
455
+ status,
456
+ timestamp,
457
+ deliveredAt: updates.deliveredAt,
458
+ readAt: updates.readAt
459
+ });
460
+ return updated;
461
+ }
462
+ /**
463
+ * Check if there's a recent outgoing message to this phone within N hours.
464
+ *
465
+ * @param {string} phone : The phone number to check (in E.164 format)
466
+ * @param {number} [withinHours=24] : Time in hours to look for incoming messages
467
+ */
468
+ async hasRecentOutgoingMessage(phone, withinHours = 24) {
469
+ return this.store.hasRecentOutgoingMessage(phone, withinHours);
470
+ }
471
+ /**
472
+ * Log incoming message (for audit trail)
473
+ */
474
+ async logIncoming(params) {
475
+ const inserted = await this.store.createWhatsAppLog({
476
+ phone: params.phone,
477
+ contactName: params.senderName,
478
+ waMessageId: params.waMessageId,
479
+ direction: "incoming",
480
+ messageType: "incoming",
481
+ content: params.content,
482
+ status: "delivered",
483
+ metadata: params.metadata,
484
+ sentAt: (/* @__PURE__ */ new Date()).toISOString()
485
+ });
486
+ const conversation = await this.store.getConversationById(inserted.conversationId);
487
+ if (conversation) await this.notify({
488
+ type: "NEW_MESSAGE",
489
+ message: inserted,
490
+ conversation
491
+ });
492
+ }
493
+ };
494
+ //#endregion
495
+ //#region src/template-registry.ts
496
+ const EMPTY_TEMPLATE_REGISTRY = defineTemplates({});
497
+ function defineTemplates(templates) {
498
+ return templates;
499
+ }
500
+ function hasConfiguredTemplates(templates) {
501
+ return Object.keys(templates).length > 0;
502
+ }
503
+ function getTemplateNames(templates) {
504
+ return Object.keys(templates);
505
+ }
506
+ function serializeTemplateFromRegistry(templates, templateName, options) {
507
+ const templateDefinition = templates[templateName];
508
+ if (!templateDefinition) throw new Error(`[betterZap] Template "${String(templateName)}" is not configured.`);
509
+ const params = options.params ?? {};
510
+ const components = templateDefinition.components ?? [];
511
+ const expectedParameterNames = components.flatMap((component) => component.parameters.map((parameter) => parameter.name));
512
+ const unexpectedParameterNames = Object.keys(params).filter((parameterName) => !expectedParameterNames.includes(parameterName));
513
+ if (unexpectedParameterNames.length > 0) throw new Error(`[betterZap] Unexpected template params for "${String(templateName)}": ${unexpectedParameterNames.join(", ")}`);
514
+ const serializedComponents = components.filter((component) => component.parameters.length > 0).map((component) => ({
515
+ type: component.type,
516
+ ...component.type === "button" ? {
517
+ sub_type: component.subType,
518
+ index: component.index
519
+ } : {},
520
+ parameters: component.parameters.map((parameter) => {
521
+ if (!(parameter.name in params)) throw new Error(`[betterZap] Missing template param "${parameter.name}" for "${String(templateName)}".`);
522
+ return serializeTemplateParameter(parameter, params[parameter.name]);
523
+ })
524
+ }));
525
+ return {
526
+ language: options.language ?? templateDefinition.language,
527
+ components: serializedComponents.length > 0 ? serializedComponents : void 0
528
+ };
529
+ }
530
+ function serializeTemplateParameter(parameter, value) {
531
+ switch (parameter.type) {
532
+ case "text": return {
533
+ type: "text",
534
+ text: value
535
+ };
536
+ case "payload": return {
537
+ type: "payload",
538
+ payload: value
539
+ };
540
+ case "location": return {
541
+ type: "location",
542
+ location: value
543
+ };
544
+ case "image": return {
545
+ type: "image",
546
+ image: value
547
+ };
548
+ case "video": return {
549
+ type: "video",
550
+ video: value
551
+ };
552
+ case "document": return {
553
+ type: "document",
554
+ document: value
555
+ };
556
+ case "currency": return {
557
+ type: "currency",
558
+ currency: value
559
+ };
560
+ case "date_time": return {
561
+ type: "date_time",
562
+ date_time: value
563
+ };
564
+ }
565
+ }
566
+ //#endregion
567
+ exports.EMPTY_TEMPLATE_REGISTRY = EMPTY_TEMPLATE_REGISTRY;
568
+ exports.MessageLoggerService = MessageLoggerService;
569
+ exports.WHATSAPP_MESSAGE_TYPES = WHATSAPP_MESSAGE_TYPES;
570
+ exports.WhatsAppService = WhatsAppService;
571
+ exports.createLogger = createLogger;
572
+ exports.createZapClient = require_client.createZapClient;
573
+ exports.defineTemplates = defineTemplates;
574
+ exports.delay = delay;
575
+ exports.formatPhone = formatPhone;
576
+ exports.getTemplateNames = getTemplateNames;
577
+ exports.hasConfiguredTemplates = hasConfiguredTemplates;
578
+ exports.noopLogger = noopLogger;
579
+ exports.serializeError = serializeError;
580
+ exports.serializeTemplateFromRegistry = serializeTemplateFromRegistry;