@geekapps/post-fastify 0.1.13 → 0.1.15
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.d.ts +192 -1
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +3 -0
- package/src/index.ts +16 -0
- package/src/resources/whatsapp-messages.ts +83 -0
- package/src/types.ts +122 -0
package/dist/index.d.ts
CHANGED
|
@@ -212,6 +212,15 @@ interface TemplateVariables {
|
|
|
212
212
|
footer?: TemplateVariable[];
|
|
213
213
|
buttons?: TemplateVariable[];
|
|
214
214
|
}
|
|
215
|
+
interface EmailAttachment {
|
|
216
|
+
filename: string;
|
|
217
|
+
/** Conteúdo do arquivo em base64. Informe `content` ou `url`. */
|
|
218
|
+
content?: string;
|
|
219
|
+
/** URL pública (http/https) do arquivo. Informe `content` ou `url`. */
|
|
220
|
+
url?: string;
|
|
221
|
+
/** Ex.: "application/pdf". Se omitido, é inferido pelo nome do arquivo. */
|
|
222
|
+
contentType?: string;
|
|
223
|
+
}
|
|
215
224
|
interface SendMessageInput {
|
|
216
225
|
type: MessageType;
|
|
217
226
|
to: string;
|
|
@@ -222,6 +231,8 @@ interface SendMessageInput {
|
|
|
222
231
|
subject?: string;
|
|
223
232
|
body?: string;
|
|
224
233
|
variables?: TemplateVariable[] | TemplateVariables;
|
|
234
|
+
/** Apenas para `type: "email"`. Máx. 10 arquivos / 25MB no total. */
|
|
235
|
+
attachments?: EmailAttachment[];
|
|
225
236
|
}
|
|
226
237
|
interface CreateTemplateInput {
|
|
227
238
|
name: string;
|
|
@@ -489,6 +500,147 @@ interface MessagePresenceResult {
|
|
|
489
500
|
success: boolean;
|
|
490
501
|
phoneNumberId: string;
|
|
491
502
|
}
|
|
503
|
+
/** Mídia já enviada (`id`) ou URL pública (`link`). */
|
|
504
|
+
interface WhatsappMediaRef {
|
|
505
|
+
id?: string;
|
|
506
|
+
link?: string;
|
|
507
|
+
}
|
|
508
|
+
interface WhatsappContactCard {
|
|
509
|
+
name: {
|
|
510
|
+
formattedName: string;
|
|
511
|
+
firstName?: string;
|
|
512
|
+
lastName?: string;
|
|
513
|
+
};
|
|
514
|
+
phones?: {
|
|
515
|
+
phone: string;
|
|
516
|
+
type?: string;
|
|
517
|
+
waId?: string;
|
|
518
|
+
}[];
|
|
519
|
+
emails?: {
|
|
520
|
+
email: string;
|
|
521
|
+
type?: string;
|
|
522
|
+
}[];
|
|
523
|
+
org?: {
|
|
524
|
+
company?: string;
|
|
525
|
+
title?: string;
|
|
526
|
+
};
|
|
527
|
+
urls?: {
|
|
528
|
+
url: string;
|
|
529
|
+
type?: string;
|
|
530
|
+
}[];
|
|
531
|
+
/** YYYY-MM-DD */
|
|
532
|
+
birthday?: string;
|
|
533
|
+
}
|
|
534
|
+
interface WhatsappInteractiveButtons {
|
|
535
|
+
kind: "buttons";
|
|
536
|
+
body: string;
|
|
537
|
+
header?: string;
|
|
538
|
+
footer?: string;
|
|
539
|
+
/** Até 3 botões. `id` volta em `message_received` quando o usuário clica. */
|
|
540
|
+
buttons: {
|
|
541
|
+
id: string;
|
|
542
|
+
title: string;
|
|
543
|
+
}[];
|
|
544
|
+
}
|
|
545
|
+
interface WhatsappInteractiveList {
|
|
546
|
+
kind: "list";
|
|
547
|
+
body: string;
|
|
548
|
+
header?: string;
|
|
549
|
+
footer?: string;
|
|
550
|
+
buttonText: string;
|
|
551
|
+
sections: {
|
|
552
|
+
title?: string;
|
|
553
|
+
rows: {
|
|
554
|
+
id: string;
|
|
555
|
+
title: string;
|
|
556
|
+
description?: string;
|
|
557
|
+
}[];
|
|
558
|
+
}[];
|
|
559
|
+
}
|
|
560
|
+
interface WhatsappInteractiveCtaUrl {
|
|
561
|
+
kind: "cta_url";
|
|
562
|
+
body: string;
|
|
563
|
+
header?: string;
|
|
564
|
+
footer?: string;
|
|
565
|
+
buttonText: string;
|
|
566
|
+
url: string;
|
|
567
|
+
}
|
|
568
|
+
interface WhatsappInteractiveLocationRequest {
|
|
569
|
+
kind: "location_request";
|
|
570
|
+
body: string;
|
|
571
|
+
}
|
|
572
|
+
type WhatsappInteractive = WhatsappInteractiveButtons | WhatsappInteractiveList | WhatsappInteractiveCtaUrl | WhatsappInteractiveLocationRequest;
|
|
573
|
+
type WhatsappMessage = {
|
|
574
|
+
type: "text";
|
|
575
|
+
body: string;
|
|
576
|
+
previewUrl?: boolean;
|
|
577
|
+
} | ({
|
|
578
|
+
type: "image";
|
|
579
|
+
caption?: string;
|
|
580
|
+
} & WhatsappMediaRef) | ({
|
|
581
|
+
type: "video";
|
|
582
|
+
caption?: string;
|
|
583
|
+
} & WhatsappMediaRef) | ({
|
|
584
|
+
type: "audio";
|
|
585
|
+
} & WhatsappMediaRef) | ({
|
|
586
|
+
type: "document";
|
|
587
|
+
caption?: string;
|
|
588
|
+
filename?: string;
|
|
589
|
+
} & WhatsappMediaRef) | ({
|
|
590
|
+
type: "sticker";
|
|
591
|
+
} & WhatsappMediaRef) | {
|
|
592
|
+
type: "location";
|
|
593
|
+
latitude: number;
|
|
594
|
+
longitude: number;
|
|
595
|
+
name?: string;
|
|
596
|
+
address?: string;
|
|
597
|
+
} | {
|
|
598
|
+
type: "contacts";
|
|
599
|
+
contacts: WhatsappContactCard[];
|
|
600
|
+
} | {
|
|
601
|
+
type: "reaction";
|
|
602
|
+
messageId: string;
|
|
603
|
+
emoji: string;
|
|
604
|
+
} | {
|
|
605
|
+
type: "interactive";
|
|
606
|
+
interactive: WhatsappInteractive;
|
|
607
|
+
};
|
|
608
|
+
interface SendWhatsappMessageInput {
|
|
609
|
+
to: string;
|
|
610
|
+
message: WhatsappMessage;
|
|
611
|
+
/** Meta phone_number_id. Padrão: primeiro número ativo da org. */
|
|
612
|
+
phoneNumberId?: string;
|
|
613
|
+
/** `messageId` de uma mensagem para responder citando. */
|
|
614
|
+
replyTo?: string;
|
|
615
|
+
}
|
|
616
|
+
interface SendWhatsappMessageResult {
|
|
617
|
+
messageId: string;
|
|
618
|
+
phoneNumberId: string;
|
|
619
|
+
}
|
|
620
|
+
interface UploadWhatsappMediaInput {
|
|
621
|
+
/** Conteúdo do arquivo em base64. */
|
|
622
|
+
data: string;
|
|
623
|
+
mimeType: string;
|
|
624
|
+
filename?: string;
|
|
625
|
+
phoneNumberId?: string;
|
|
626
|
+
}
|
|
627
|
+
interface UploadWhatsappMediaResult {
|
|
628
|
+
id: string;
|
|
629
|
+
phoneNumberId: string;
|
|
630
|
+
}
|
|
631
|
+
interface WhatsappMediaInfo {
|
|
632
|
+
id: string;
|
|
633
|
+
mimeType: string;
|
|
634
|
+
fileSize: number | null;
|
|
635
|
+
sha256: string | null;
|
|
636
|
+
}
|
|
637
|
+
interface WhatsappMediaDownload {
|
|
638
|
+
id: string;
|
|
639
|
+
mimeType: string;
|
|
640
|
+
fileSize: number;
|
|
641
|
+
/** Conteúdo em base64. */
|
|
642
|
+
data: string;
|
|
643
|
+
}
|
|
492
644
|
|
|
493
645
|
declare class DomainsResource {
|
|
494
646
|
private readonly http;
|
|
@@ -620,6 +772,44 @@ declare class WhatsappCallsResource {
|
|
|
620
772
|
getPermission(to: string, phoneNumberId?: string): Promise<CallPermissionStatus>;
|
|
621
773
|
}
|
|
622
774
|
|
|
775
|
+
type Target = {
|
|
776
|
+
to: string;
|
|
777
|
+
phoneNumberId?: string;
|
|
778
|
+
replyTo?: string;
|
|
779
|
+
};
|
|
780
|
+
declare class WhatsappMessagesResource {
|
|
781
|
+
private readonly http;
|
|
782
|
+
constructor(http: HttpClient);
|
|
783
|
+
/** Envio genérico de qualquer tipo de mensagem. */
|
|
784
|
+
send(input: SendWhatsappMessageInput): Promise<SendWhatsappMessageResult>;
|
|
785
|
+
sendText(target: Target, body: string, previewUrl?: boolean): Promise<SendWhatsappMessageResult>;
|
|
786
|
+
sendImage(target: Target, media: WhatsappMediaRef, caption?: string): Promise<SendWhatsappMessageResult>;
|
|
787
|
+
sendVideo(target: Target, media: WhatsappMediaRef, caption?: string): Promise<SendWhatsappMessageResult>;
|
|
788
|
+
sendAudio(target: Target, media: WhatsappMediaRef): Promise<SendWhatsappMessageResult>;
|
|
789
|
+
sendDocument(target: Target, media: WhatsappMediaRef, extra?: {
|
|
790
|
+
caption?: string;
|
|
791
|
+
filename?: string;
|
|
792
|
+
}): Promise<SendWhatsappMessageResult>;
|
|
793
|
+
sendSticker(target: Target, media: WhatsappMediaRef): Promise<SendWhatsappMessageResult>;
|
|
794
|
+
sendLocation(target: Target, location: {
|
|
795
|
+
latitude: number;
|
|
796
|
+
longitude: number;
|
|
797
|
+
name?: string;
|
|
798
|
+
address?: string;
|
|
799
|
+
}): Promise<SendWhatsappMessageResult>;
|
|
800
|
+
sendContacts(target: Target, contacts: WhatsappContactCard[]): Promise<SendWhatsappMessageResult>;
|
|
801
|
+
/** Reage a uma mensagem. Emoji vazio remove a reação. */
|
|
802
|
+
sendReaction(target: Target, messageId: string, emoji: string): Promise<SendWhatsappMessageResult>;
|
|
803
|
+
/** Botões de resposta rápida, lista, botão com link ou pedido de localização. */
|
|
804
|
+
sendInteractive(target: Target, interactive: WhatsappInteractive): Promise<SendWhatsappMessageResult>;
|
|
805
|
+
/** Sobe um arquivo (base64) e devolve o `id` para usar em `sendImage`, `sendVideo` etc. */
|
|
806
|
+
uploadMedia(input: UploadWhatsappMediaInput): Promise<UploadWhatsappMediaResult>;
|
|
807
|
+
/** Metadados de uma mídia (id recebido em `message_received`). */
|
|
808
|
+
getMedia(mediaId: string, phoneNumberId?: string): Promise<WhatsappMediaInfo>;
|
|
809
|
+
/** Baixa uma mídia recebida (conteúdo em base64). */
|
|
810
|
+
downloadMedia(mediaId: string, phoneNumberId?: string): Promise<WhatsappMediaDownload>;
|
|
811
|
+
}
|
|
812
|
+
|
|
623
813
|
declare class WhatsappNumbersResource {
|
|
624
814
|
private readonly http;
|
|
625
815
|
constructor(http: HttpClient);
|
|
@@ -658,6 +848,7 @@ declare class PostClient {
|
|
|
658
848
|
readonly whatsappTemplates: WhatsappTemplatesResource;
|
|
659
849
|
readonly whatsappNumbers: WhatsappNumbersResource;
|
|
660
850
|
readonly calls: WhatsappCallsResource;
|
|
851
|
+
readonly whatsappMessages: WhatsappMessagesResource;
|
|
661
852
|
readonly domains: DomainsResource;
|
|
662
853
|
readonly webhooks: WebhooksResource;
|
|
663
854
|
readonly smtp: SmtpResource;
|
|
@@ -707,4 +898,4 @@ declare function verifyWebhookSignature(rawBody: string, signatureHeader: string
|
|
|
707
898
|
/** Verifies the signature and parses the payload; throws if invalid. */
|
|
708
899
|
declare function constructWebhookEvent(rawBody: string, signatureHeader: string | null | undefined, secret: string): PostWebhookPayload;
|
|
709
900
|
|
|
710
|
-
export { type AreaCode, type AvailablePlan, type CallActionResult, type CallAnswerInput, type CallConnectWebhookData, type CallPermissionStatus, type CallStatusWebhookData, type CallTargetInput, type CallTerminateWebhookData, type CallingSettings, type CallingStatus, type ConnectCallInput, type ConnectCallResult, type ConnectWabaInput, type ConnectWhatsappNumberInput, type CreateDomainInput, type CreateDomainResult, type CreateTemplateInput, type CreateWebhookInput, type CreateWhatsappTemplateInput, type DnsRecord, type DomainStatus, type DomainType, DomainsResource, HistoryResource, type ListHistoryParams, type ManagedNumber, type ManagedNumberStatus, ManagedNumbersResource, type MessageLog, type MessageLogDetail, type MessagePresenceInput, type MessagePresenceResult, type MessageReceivedWebhookData, type MessageStatus, type MessageTemplate, type MessageType, MessagesResource, type OrgDomain, type OrgPlan, type OrgUsage, type OrgWaba, type OrgWebhook, type OrgWebhookWithSecret, type PaginatedResult, type PhoneNumberStatusResult, type PlanTier, PlansResource, type PlansResult, PostApiError, PostClient, type PostPluginOptions, type PostWebhookPayload, type RegisterWhatsappNumberInput, type RequestCallPermissionInput, type RequestCallPermissionResult, type RotateSecretResult, type SaveDraftInput, type SendMessageInput, type SendMessageResult, type SmtpConfig, SmtpResource, type StatisticsParams, StatisticsResource, type StatisticsResult, type SyncWhatsappTemplatesResult, type TemplateVariable, type TemplateVariables, TemplatesResource, type UpdateCallingSettingsInput, type UpdatePlanInput, type UpdateTemplateInput, type UpdateWebhookInput, type UpdateWhatsappProfileInput, type UpdateWhatsappTemplateInput, type UpsertSmtpConfigInput, type WabaStatus, type WebhookDelivery, type WebhookEvent, type WebhookSdpSession, WebhooksResource, WhatsappCallsResource, type WhatsappNumber, type WhatsappNumberProfile, type WhatsappNumberStatus, WhatsappNumbersResource, type WhatsappTemplate, type WhatsappTemplateCategory, type WhatsappTemplateStatus, WhatsappTemplatesResource, constructWebhookEvent, _default as postPlugin, verifyWebhookSignature };
|
|
901
|
+
export { type AreaCode, type AvailablePlan, type CallActionResult, type CallAnswerInput, type CallConnectWebhookData, type CallPermissionStatus, type CallStatusWebhookData, type CallTargetInput, type CallTerminateWebhookData, type CallingSettings, type CallingStatus, type ConnectCallInput, type ConnectCallResult, type ConnectWabaInput, type ConnectWhatsappNumberInput, type CreateDomainInput, type CreateDomainResult, type CreateTemplateInput, type CreateWebhookInput, type CreateWhatsappTemplateInput, type DnsRecord, type DomainStatus, type DomainType, DomainsResource, type EmailAttachment, HistoryResource, type ListHistoryParams, type ManagedNumber, type ManagedNumberStatus, ManagedNumbersResource, type MessageLog, type MessageLogDetail, type MessagePresenceInput, type MessagePresenceResult, type MessageReceivedWebhookData, type MessageStatus, type MessageTemplate, type MessageType, MessagesResource, type OrgDomain, type OrgPlan, type OrgUsage, type OrgWaba, type OrgWebhook, type OrgWebhookWithSecret, type PaginatedResult, type PhoneNumberStatusResult, type PlanTier, PlansResource, type PlansResult, PostApiError, PostClient, type PostPluginOptions, type PostWebhookPayload, type RegisterWhatsappNumberInput, type RequestCallPermissionInput, type RequestCallPermissionResult, type RotateSecretResult, type SaveDraftInput, type SendMessageInput, type SendMessageResult, type SendWhatsappMessageInput, type SendWhatsappMessageResult, type SmtpConfig, SmtpResource, type StatisticsParams, StatisticsResource, type StatisticsResult, type SyncWhatsappTemplatesResult, type TemplateVariable, type TemplateVariables, TemplatesResource, type UpdateCallingSettingsInput, type UpdatePlanInput, type UpdateTemplateInput, type UpdateWebhookInput, type UpdateWhatsappProfileInput, type UpdateWhatsappTemplateInput, type UploadWhatsappMediaInput, type UploadWhatsappMediaResult, type UpsertSmtpConfigInput, type WabaStatus, type WebhookDelivery, type WebhookEvent, type WebhookSdpSession, WebhooksResource, WhatsappCallsResource, type WhatsappContactCard, type WhatsappInteractive, type WhatsappInteractiveButtons, type WhatsappInteractiveCtaUrl, type WhatsappInteractiveList, type WhatsappInteractiveLocationRequest, type WhatsappMediaDownload, type WhatsappMediaInfo, type WhatsappMediaRef, type WhatsappMessage, WhatsappMessagesResource, type WhatsappNumber, type WhatsappNumberProfile, type WhatsappNumberStatus, WhatsappNumbersResource, type WhatsappTemplate, type WhatsappTemplateCategory, type WhatsappTemplateStatus, WhatsappTemplatesResource, constructWebhookEvent, _default as postPlugin, verifyWebhookSignature };
|
package/dist/index.js
CHANGED
|
@@ -315,6 +315,61 @@ var WhatsappCallsResource = class {
|
|
|
315
315
|
}
|
|
316
316
|
};
|
|
317
317
|
|
|
318
|
+
// src/resources/whatsapp-messages.ts
|
|
319
|
+
var WhatsappMessagesResource = class {
|
|
320
|
+
constructor(http) {
|
|
321
|
+
this.http = http;
|
|
322
|
+
}
|
|
323
|
+
/** Envio genérico de qualquer tipo de mensagem. */
|
|
324
|
+
send(input) {
|
|
325
|
+
return this.http.post("/whatsapp/messages/send", input);
|
|
326
|
+
}
|
|
327
|
+
sendText(target, body, previewUrl) {
|
|
328
|
+
return this.send({ ...target, message: { type: "text", body, previewUrl } });
|
|
329
|
+
}
|
|
330
|
+
sendImage(target, media, caption) {
|
|
331
|
+
return this.send({ ...target, message: { type: "image", ...media, caption } });
|
|
332
|
+
}
|
|
333
|
+
sendVideo(target, media, caption) {
|
|
334
|
+
return this.send({ ...target, message: { type: "video", ...media, caption } });
|
|
335
|
+
}
|
|
336
|
+
sendAudio(target, media) {
|
|
337
|
+
return this.send({ ...target, message: { type: "audio", ...media } });
|
|
338
|
+
}
|
|
339
|
+
sendDocument(target, media, extra) {
|
|
340
|
+
return this.send({ ...target, message: { type: "document", ...media, ...extra } });
|
|
341
|
+
}
|
|
342
|
+
sendSticker(target, media) {
|
|
343
|
+
return this.send({ ...target, message: { type: "sticker", ...media } });
|
|
344
|
+
}
|
|
345
|
+
sendLocation(target, location) {
|
|
346
|
+
return this.send({ ...target, message: { type: "location", ...location } });
|
|
347
|
+
}
|
|
348
|
+
sendContacts(target, contacts) {
|
|
349
|
+
return this.send({ ...target, message: { type: "contacts", contacts } });
|
|
350
|
+
}
|
|
351
|
+
/** Reage a uma mensagem. Emoji vazio remove a reação. */
|
|
352
|
+
sendReaction(target, messageId, emoji) {
|
|
353
|
+
return this.send({ ...target, message: { type: "reaction", messageId, emoji } });
|
|
354
|
+
}
|
|
355
|
+
/** Botões de resposta rápida, lista, botão com link ou pedido de localização. */
|
|
356
|
+
sendInteractive(target, interactive) {
|
|
357
|
+
return this.send({ ...target, message: { type: "interactive", interactive } });
|
|
358
|
+
}
|
|
359
|
+
/** Sobe um arquivo (base64) e devolve o `id` para usar em `sendImage`, `sendVideo` etc. */
|
|
360
|
+
uploadMedia(input) {
|
|
361
|
+
return this.http.post("/whatsapp/media", input);
|
|
362
|
+
}
|
|
363
|
+
/** Metadados de uma mídia (id recebido em `message_received`). */
|
|
364
|
+
getMedia(mediaId, phoneNumberId) {
|
|
365
|
+
return this.http.get(`/whatsapp/media/${mediaId}${phoneNumberId ? `?phoneNumberId=${encodeURIComponent(phoneNumberId)}` : ""}`);
|
|
366
|
+
}
|
|
367
|
+
/** Baixa uma mídia recebida (conteúdo em base64). */
|
|
368
|
+
downloadMedia(mediaId, phoneNumberId) {
|
|
369
|
+
return this.http.get(`/whatsapp/media/${mediaId}/download${phoneNumberId ? `?phoneNumberId=${encodeURIComponent(phoneNumberId)}` : ""}`);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
|
|
318
373
|
// src/resources/whatsapp-numbers.ts
|
|
319
374
|
var WhatsappNumbersResource = class {
|
|
320
375
|
constructor(http) {
|
|
@@ -403,6 +458,7 @@ var PostClient = class {
|
|
|
403
458
|
this.whatsappTemplates = new WhatsappTemplatesResource(this.http);
|
|
404
459
|
this.whatsappNumbers = new WhatsappNumbersResource(this.http);
|
|
405
460
|
this.calls = new WhatsappCallsResource(this.http);
|
|
461
|
+
this.whatsappMessages = new WhatsappMessagesResource(this.http);
|
|
406
462
|
this.domains = new DomainsResource(this.http);
|
|
407
463
|
this.webhooks = new WebhooksResource(this.http);
|
|
408
464
|
this.smtp = new SmtpResource(this.http);
|
|
@@ -577,6 +633,7 @@ export {
|
|
|
577
633
|
TemplatesResource,
|
|
578
634
|
WebhooksResource,
|
|
579
635
|
WhatsappCallsResource,
|
|
636
|
+
WhatsappMessagesResource,
|
|
580
637
|
WhatsappNumbersResource,
|
|
581
638
|
WhatsappTemplatesResource,
|
|
582
639
|
constructWebhookEvent,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/domains.ts","../src/resources/history.ts","../src/resources/managed-numbers.ts","../src/resources/messages.ts","../src/resources/plans.ts","../src/resources/smtp.ts","../src/resources/statistics.ts","../src/resources/templates.ts","../src/resources/webhooks.ts","../src/resources/whatsapp-calls.ts","../src/resources/whatsapp-numbers.ts","../src/resources/whatsapp-templates.ts","../src/client.ts","../src/plugin.ts","../src/webhook.ts"],"sourcesContent":["export class PostApiError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly detail?: string,\n ) {\n super(detail ? `${message}: ${detail}` : message);\n this.name = \"PostApiError\";\n }\n\n get isNotFound() {\n return this.status === 404;\n }\n\n get isUnauthorized() {\n return this.status === 401;\n }\n\n get isForbidden() {\n return this.status === 403;\n }\n\n get isRateLimited() {\n return this.status === 429;\n }\n\n get isValidationError() {\n return this.status === 400;\n }\n}\n","import { PostApiError } from \"./errors.js\";\n\nexport type TokenResolver = string | (() => string | Promise<string>);\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token: TokenResolver;\n organizationId?: string | (() => string | Promise<string>);\n}\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly token: TokenResolver;\n private readonly organizationId?: string | (() => string | Promise<string>);\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token;\n this.organizationId = options.organizationId;\n }\n\n private async resolveToken(): Promise<string> {\n return typeof this.token === \"function\" ? await this.token() : this.token;\n }\n\n private async resolveOrgId(): Promise<string | undefined> {\n if (!this.organizationId) return undefined;\n return typeof this.organizationId === \"function\"\n ? await this.organizationId()\n : this.organizationId;\n }\n\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const token = await this.resolveToken();\n const orgId = await this.resolveOrgId();\n\n const res = await fetch(`${this.baseUrl}/v1${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n ...(body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n ...(orgId ? { \"X-Organization-Id\": orgId } : {}),\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cache: \"no-store\" as any,\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as {\n error?: string;\n detail?: string;\n };\n throw new PostApiError(\n res.status,\n err.error ?? `HTTP ${res.status}`,\n err.detail,\n );\n }\n\n if (res.status === 204) return undefined as T;\n return res.json() as Promise<T>;\n }\n\n get<T>(path: string) {\n return this.request<T>(\"GET\", path);\n }\n\n post<T>(path: string, body?: unknown) {\n return this.request<T>(\"POST\", path, body);\n }\n\n put<T>(path: string, body?: unknown) {\n return this.request<T>(\"PUT\", path, body);\n }\n\n patch<T>(path: string, body?: unknown) {\n return this.request<T>(\"PATCH\", path, body);\n }\n\n delete<T = void>(path: string) {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CreateDomainInput, CreateDomainResult, OrgDomain } from \"../types.js\";\n\nexport class DomainsResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<OrgDomain[]> {\n return this.http.get<OrgDomain[]>(\"/domains\");\n }\n\n get(id: string): Promise<OrgDomain> {\n return this.http.get<OrgDomain>(`/domains/${id}`);\n }\n\n create(input: CreateDomainInput): Promise<CreateDomainResult> {\n return this.http.post<CreateDomainResult>(\"/domains\", input);\n }\n\n verify(id: string): Promise<{ status: \"verified\" | \"failed\" }> {\n return this.http.post<{ status: \"verified\" | \"failed\" }>(`/domains/${id}/verify`);\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/domains/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { ListHistoryParams, MessageLog, MessageLogDetail, PaginatedResult } from \"../types.js\";\n\nexport class HistoryResource {\n constructor(private readonly http: HttpClient) {}\n\n list(params?: ListHistoryParams): Promise<PaginatedResult<MessageLog>> {\n const qs = new URLSearchParams();\n if (params?.type) qs.set(\"type\", params.type);\n if (params?.status) qs.set(\"status\", params.status);\n if (params?.from) qs.set(\"from\", params.from);\n if (params?.to) qs.set(\"to\", params.to);\n if (params?.page !== undefined) qs.set(\"page\", String(params.page));\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n const query = qs.toString();\n return this.http.get<PaginatedResult<MessageLog>>(`/history${query ? `?${query}` : \"\"}`);\n }\n\n get(id: string): Promise<MessageLogDetail> {\n return this.http.get<MessageLogDetail>(`/history/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { AreaCode, ManagedNumber } from \"../types.js\";\n\nexport interface ProvisionManagedNumberInput {\n areaCode: number;\n name?: string;\n displayName: string;\n otpMethod?: \"SMS\" | \"VOICE\";\n otpLanguage?: string;\n pin?: string;\n orgWabaId?: string;\n wabaId?: string;\n accessToken?: string;\n}\n\nexport interface RetryVerificationInput {\n otpMethod?: \"SMS\" | \"VOICE\";\n otpLanguage?: string;\n}\n\nexport class ManagedNumbersResource {\n constructor(private readonly http: HttpClient) {}\n\n listAreaCodes(): Promise<AreaCode[]> {\n return this.http.get<AreaCode[]>(\"/managed-numbers/area-codes\");\n }\n\n list(): Promise<ManagedNumber[]> {\n return this.http.get<ManagedNumber[]>(\"/managed-numbers\");\n }\n\n get(id: string): Promise<ManagedNumber> {\n return this.http.get<ManagedNumber>(`/managed-numbers/${id}`);\n }\n\n provision(input: ProvisionManagedNumberInput): Promise<ManagedNumber> {\n return this.http.post<ManagedNumber>(\"/managed-numbers\", input);\n }\n\n retryVerification(id: string, input?: RetryVerificationInput): Promise<ManagedNumber> {\n return this.http.post<ManagedNumber>(`/managed-numbers/${id}/retry-verification`, input);\n }\n\n cancel(id: string): Promise<ManagedNumber> {\n return this.http.post<ManagedNumber>(`/managed-numbers/${id}/cancel`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { MessagePresenceInput, MessagePresenceResult, SendMessageInput, SendMessageResult } from \"../types.js\";\n\nexport class MessagesResource {\n constructor(private readonly http: HttpClient) {}\n\n send(input: SendMessageInput): Promise<SendMessageResult> {\n return this.http.post<SendMessageResult>(\"/messages\", input);\n }\n\n /** Marca uma mensagem recebida como lida (tique azul). */\n markAsRead(input: MessagePresenceInput): Promise<MessagePresenceResult> {\n return this.http.post<MessagePresenceResult>(\"/whatsapp/messages/read\", input);\n }\n\n /** Marca como lida e mostra \"digitando…\" até a resposta ser enviada (máx. ~25s). */\n sendTyping(input: MessagePresenceInput): Promise<MessagePresenceResult> {\n return this.http.post<MessagePresenceResult>(\"/whatsapp/messages/typing\", input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { AvailablePlan, OrgPlan, PlansResult, UpdatePlanInput } from \"../types.js\";\n\nexport class PlansResource {\n constructor(private readonly http: HttpClient) {}\n\n get(): Promise<PlansResult> {\n return this.http.get<PlansResult>(\"/plans\");\n }\n\n update(input: UpdatePlanInput): Promise<OrgPlan> {\n return this.http.put<OrgPlan>(\"/plans\", input);\n }\n\n listAvailable(): Promise<AvailablePlan[]> {\n return this.http.get<AvailablePlan[]>(\"/plans/available\");\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { SmtpConfig, UpsertSmtpConfigInput } from \"../types.js\";\n\nexport class SmtpResource {\n constructor(private readonly http: HttpClient) {}\n\n get(): Promise<SmtpConfig> {\n return this.http.get<SmtpConfig>(\"/smtp-config\");\n }\n\n upsert(input: UpsertSmtpConfigInput): Promise<SmtpConfig> {\n return this.http.put<SmtpConfig>(\"/smtp-config\", input);\n }\n\n delete(): Promise<void> {\n return this.http.delete(\"/smtp-config\");\n }\n\n test(to: string): Promise<{ success: boolean; error?: string }> {\n return this.http.post<{ success: boolean; error?: string }>(\"/smtp-config/test\", { to });\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { StatisticsParams, StatisticsResult } from \"../types.js\";\n\nexport class StatisticsResource {\n constructor(private readonly http: HttpClient) {}\n\n get(params?: StatisticsParams): Promise<StatisticsResult> {\n const qs = new URLSearchParams();\n if (params?.from) qs.set(\"from\", params.from);\n if (params?.to) qs.set(\"to\", params.to);\n if (params?.groupBy) qs.set(\"groupBy\", params.groupBy);\n const query = qs.toString();\n return this.http.get<StatisticsResult>(`/statistics${query ? `?${query}` : \"\"}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CreateTemplateInput,\n MessageTemplate,\n MessageType,\n SaveDraftInput,\n UpdateTemplateInput,\n} from \"../types.js\";\n\nexport class TemplatesResource {\n constructor(private readonly http: HttpClient) {}\n\n list(params?: { type?: MessageType; isActive?: boolean }): Promise<MessageTemplate[]> {\n const qs = new URLSearchParams();\n if (params?.type) qs.set(\"type\", params.type);\n if (params?.isActive !== undefined) qs.set(\"isActive\", String(params.isActive));\n const query = qs.toString();\n return this.http.get<MessageTemplate[]>(`/templates${query ? `?${query}` : \"\"}`);\n }\n\n get(id: string): Promise<MessageTemplate> {\n return this.http.get<MessageTemplate>(`/templates/${id}`);\n }\n\n create(input: CreateTemplateInput): Promise<MessageTemplate> {\n return this.http.post<MessageTemplate>(\"/templates\", input);\n }\n\n update(id: string, input: UpdateTemplateInput): Promise<MessageTemplate> {\n return this.http.put<MessageTemplate>(`/templates/${id}`, input);\n }\n\n saveDraft(id: string, input: SaveDraftInput): Promise<MessageTemplate> {\n return this.http.patch<MessageTemplate>(`/templates/${id}/draft`, input);\n }\n\n publish(id: string): Promise<MessageTemplate> {\n return this.http.post<MessageTemplate>(`/templates/${id}/publish`);\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/templates/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CreateWebhookInput,\n OrgWebhook,\n OrgWebhookWithSecret,\n RotateSecretResult,\n UpdateWebhookInput,\n WebhookDelivery,\n} from \"../types.js\";\n\nexport class WebhooksResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<OrgWebhook[]> {\n return this.http.get<OrgWebhook[]>(\"/webhooks\");\n }\n\n create(input: CreateWebhookInput): Promise<OrgWebhookWithSecret> {\n return this.http.post<OrgWebhookWithSecret>(\"/webhooks\", input);\n }\n\n update(id: string, input: UpdateWebhookInput): Promise<OrgWebhook> {\n return this.http.put<OrgWebhook>(`/webhooks/${id}`, input);\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/webhooks/${id}`);\n }\n\n listDeliveries(id: string): Promise<WebhookDelivery[]> {\n return this.http.get<WebhookDelivery[]>(`/webhooks/${id}/deliveries`);\n }\n\n rotateSecret(id: string): Promise<RotateSecretResult> {\n return this.http.post<RotateSecretResult>(`/webhooks/${id}/rotate-secret`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CallActionResult,\n CallAnswerInput,\n CallPermissionStatus,\n CallTargetInput,\n CallingSettings,\n ConnectCallInput,\n ConnectCallResult,\n RequestCallPermissionInput,\n RequestCallPermissionResult,\n UpdateCallingSettingsInput,\n} from \"../types.js\";\n\n// WhatsApp Cloud API Calling. Signaling only: media flows over WebRTC between\n// Meta and your server. Incoming calls arrive via the `call_connect` webhook.\nexport class WhatsappCallsResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Lê a configuração de chamadas de um número (id do WhatsappNumber no Post). */\n getSettings(numberId: string): Promise<CallingSettings> {\n return this.http.get<CallingSettings>(`/whatsapp/numbers/${numberId}/calling`);\n }\n\n /** Ativa/desativa chamadas no número. */\n updateSettings(numberId: string, input: UpdateCallingSettingsInput): Promise<CallingSettings> {\n return this.http.put<CallingSettings>(`/whatsapp/numbers/${numberId}/calling`, input);\n }\n\n /** Pré-aceita uma chamada recebida (opcional, acelera a conexão de mídia). */\n preAccept(callId: string, input: CallAnswerInput): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/pre-accept`, input);\n }\n\n /** Aceita uma chamada recebida enviando o SDP de resposta. */\n accept(callId: string, input: CallAnswerInput): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/accept`, input);\n }\n\n /** Rejeita uma chamada recebida. */\n reject(callId: string, input: CallTargetInput = {}): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/reject`, input);\n }\n\n /** Encerra uma chamada em andamento. */\n terminate(callId: string, input: CallTargetInput = {}): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/terminate`, input);\n }\n\n /** Inicia uma chamada (business-initiated). Exige permissão prévia do usuário. */\n connect(input: ConnectCallInput): Promise<ConnectCallResult> {\n return this.http.post<ConnectCallResult>(\"/whatsapp/calls\", input);\n }\n\n /** Envia ao usuário o pedido de permissão para receber chamadas. */\n requestPermission(input: RequestCallPermissionInput): Promise<RequestCallPermissionResult> {\n return this.http.post<RequestCallPermissionResult>(\"/whatsapp/calls/permissions\", input);\n }\n\n /** Consulta o status de permissão de chamada de um usuário. */\n getPermission(to: string, phoneNumberId?: string): Promise<CallPermissionStatus> {\n return this.http.get<CallPermissionStatus>(`/whatsapp/calls/permissions?${new URLSearchParams({ to, ...(phoneNumberId ? { phoneNumberId } : {}) })}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n ConnectWabaInput,\n ConnectWhatsappNumberInput,\n OrgWaba,\n PhoneNumberStatusResult,\n RegisterWhatsappNumberInput,\n UpdateWhatsappProfileInput,\n WabaHealthResult,\n WhatsappNumber,\n WhatsappNumberProfile,\n} from \"../types.js\";\n\nexport class WhatsappNumbersResource {\n constructor(private readonly http: HttpClient) {}\n\n // ── WABAs ────────────────────────────────────────────────────────────────\n\n listWabas(): Promise<OrgWaba[]> {\n return this.http.get<OrgWaba[]>(\"/whatsapp/wabas\");\n }\n\n connectWaba(input: ConnectWabaInput): Promise<OrgWaba> {\n return this.http.post<OrgWaba>(\"/whatsapp/wabas/connect\", input);\n }\n\n reconnectWaba(id: string): Promise<OrgWaba> {\n return this.http.post<OrgWaba>(`/whatsapp/wabas/${id}/reconnect`);\n }\n\n disconnectWaba(id: string): Promise<void> {\n return this.http.delete(`/whatsapp/wabas/${id}`);\n }\n\n getWabaHealth(id: string): Promise<WabaHealthResult> {\n return this.http.get<WabaHealthResult>(`/whatsapp/wabas/${id}/health`);\n }\n\n // ── Numbers ──────────────────────────────────────────────────────────────\n\n listNumbers(): Promise<WhatsappNumber[]> {\n return this.http.get<WhatsappNumber[]>(\"/whatsapp/numbers\");\n }\n\n connectNumber(input: ConnectWhatsappNumberInput): Promise<WhatsappNumber> {\n return this.http.post<WhatsappNumber>(\"/whatsapp/numbers/connect\", input);\n }\n\n registerNumber(input: RegisterWhatsappNumberInput): Promise<WhatsappNumber> {\n return this.http.post<WhatsappNumber>(\"/whatsapp/numbers\", input);\n }\n\n verifyCode(id: string, code: string): Promise<WhatsappNumber> {\n return this.http.post<WhatsappNumber>(`/whatsapp/numbers/${id}/verify-code`, { code });\n }\n\n resendCode(id: string): Promise<void> {\n return this.http.post(`/whatsapp/numbers/${id}/resend-code`);\n }\n\n getProfile(id: string): Promise<WhatsappNumberProfile> {\n return this.http.get<WhatsappNumberProfile>(`/whatsapp/numbers/${id}/profile`);\n }\n\n updateProfile(id: string, input: UpdateWhatsappProfileInput): Promise<WhatsappNumberProfile> {\n return this.http.patch<WhatsappNumberProfile>(`/whatsapp/numbers/${id}/profile`, input);\n }\n\n updateDisplayName(id: string, displayName: string): Promise<WhatsappNumber> {\n return this.http.patch<WhatsappNumber>(`/whatsapp/numbers/${id}`, { displayName });\n }\n\n getStatus(id: string): Promise<PhoneNumberStatusResult> {\n return this.http.get<PhoneNumberStatusResult>(`/whatsapp/numbers/${id}/status`);\n }\n\n refreshNumbers(): Promise<WhatsappNumber[]> {\n return this.http.post<WhatsappNumber[]>(\"/whatsapp/numbers/refresh\");\n }\n\n deleteNumber(id: string): Promise<void> {\n return this.http.delete(`/whatsapp/numbers/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CreateWhatsappTemplateInput,\n SyncWhatsappTemplatesResult,\n UpdateWhatsappTemplateInput,\n WhatsappTemplate,\n} from \"../types.js\";\n\nexport class WhatsappTemplatesResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<WhatsappTemplate[]> {\n return this.http.get<WhatsappTemplate[]>(\"/whatsapp/templates\");\n }\n\n create(input: CreateWhatsappTemplateInput): Promise<WhatsappTemplate> {\n return this.http.post<WhatsappTemplate>(\"/whatsapp/templates\", input);\n }\n\n update(id: string, input: UpdateWhatsappTemplateInput): Promise<WhatsappTemplate> {\n return this.http.put<WhatsappTemplate>(`/whatsapp/templates/${id}`, input);\n }\n\n sync(): Promise<SyncWhatsappTemplatesResult> {\n return this.http.post<SyncWhatsappTemplatesResult>(\"/whatsapp/templates/sync\");\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/whatsapp/templates/${id}`);\n }\n}\n","import { HttpClient, type HttpClientOptions } from \"./http.js\";\nimport { DomainsResource } from \"./resources/domains.js\";\nimport { HistoryResource } from \"./resources/history.js\";\nimport { ManagedNumbersResource } from \"./resources/managed-numbers.js\";\nimport { MessagesResource } from \"./resources/messages.js\";\nimport { PlansResource } from \"./resources/plans.js\";\nimport { SmtpResource } from \"./resources/smtp.js\";\nimport { StatisticsResource } from \"./resources/statistics.js\";\nimport { TemplatesResource } from \"./resources/templates.js\";\nimport { WebhooksResource } from \"./resources/webhooks.js\";\nimport { WhatsappCallsResource } from \"./resources/whatsapp-calls.js\";\nimport { WhatsappNumbersResource } from \"./resources/whatsapp-numbers.js\";\nimport { WhatsappTemplatesResource } from \"./resources/whatsapp-templates.js\";\n\nexport interface PostClientOptions\n extends Omit<HttpClientOptions, \"baseUrl\"> {\n baseUrl?: string;\n}\n\nexport class PostClient {\n private readonly http: HttpClient;\n\n readonly messages: MessagesResource;\n readonly templates: TemplatesResource;\n readonly whatsappTemplates: WhatsappTemplatesResource;\n readonly whatsappNumbers: WhatsappNumbersResource;\n readonly calls: WhatsappCallsResource;\n readonly domains: DomainsResource;\n readonly webhooks: WebhooksResource;\n readonly smtp: SmtpResource;\n readonly plans: PlansResource;\n readonly history: HistoryResource;\n readonly statistics: StatisticsResource;\n readonly managedNumbers: ManagedNumbersResource;\n\n constructor(optionsOrHttp: HttpClientOptions | HttpClient) {\n this.http = optionsOrHttp instanceof HttpClient ? optionsOrHttp : new HttpClient(optionsOrHttp);\n\n this.messages = new MessagesResource(this.http);\n this.templates = new TemplatesResource(this.http);\n this.whatsappTemplates = new WhatsappTemplatesResource(this.http);\n this.whatsappNumbers = new WhatsappNumbersResource(this.http);\n this.calls = new WhatsappCallsResource(this.http);\n this.domains = new DomainsResource(this.http);\n this.webhooks = new WebhooksResource(this.http);\n this.smtp = new SmtpResource(this.http);\n this.plans = new PlansResource(this.http);\n this.history = new HistoryResource(this.http);\n this.statistics = new StatisticsResource(this.http);\n this.managedNumbers = new ManagedNumbersResource(this.http);\n }\n}\n","import type { FastifyBaseLogger, FastifyInstance, FastifyPluginAsync, FastifyRequest } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { PostClient } from \"./client.js\";\nimport { HttpClient } from \"./http.js\";\n\nexport interface ServiceAccountOptions {\n issuerUrl: string;\n clientId: string;\n clientSecret: string;\n}\n\nexport interface PostPluginOptions {\n serviceAccount: ServiceAccountOptions;\n baseUrl?: string;\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n}\n\ninterface CachedToken {\n value: string;\n expiresAt: number;\n organizationId: string | undefined;\n}\n\ntype Logger = Pick<FastifyBaseLogger, \"debug\" | \"info\" | \"warn\" | \"error\">;\n\nfunction log(logger: Logger, msg: string, data?: Record<string, unknown>) {\n if (data) {\n process.stdout.write(`[geekapps-post] ${msg} ${JSON.stringify(data, null, 2)}\\n`);\n } else {\n process.stdout.write(`[geekapps-post] ${msg}\\n`);\n }\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> {\n try {\n const [, payload] = token.split(\".\");\n if (!payload) return {};\n const json = Buffer.from(payload, \"base64url\").toString(\"utf-8\");\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nclass TokenProvider {\n private readonly issuerUrl: string;\n private readonly clientId: string;\n private readonly clientSecret: string;\n private readonly logger: Logger;\n private cached: CachedToken | null = null;\n private inflight: Promise<CachedToken> | null = null;\n\n constructor(options: PostPluginOptions, logger: Logger) {\n this.issuerUrl = options.serviceAccount.issuerUrl.replace(/\\/$/, \"\");\n this.clientId = options.serviceAccount.clientId;\n this.clientSecret = options.serviceAccount.clientSecret;\n this.logger = logger;\n }\n\n private async ensureFresh(): Promise<CachedToken> {\n const now = Date.now();\n if (this.cached && this.cached.expiresAt - now > 30_000) {\n log(this.logger, \"service account token cache hit\", {\n expiresAt: new Date(this.cached.expiresAt).toISOString(),\n });\n return this.cached;\n }\n log(this.logger, \"service account token cache miss — fetching new token\");\n if (this.inflight) return this.inflight;\n this.inflight = this.fetchToken().finally(() => { this.inflight = null; });\n return this.inflight;\n }\n\n getToken(): Promise<string> {\n return this.ensureFresh().then((c) => c.value);\n }\n\n getOrganizationId(): Promise<string | undefined> {\n return this.ensureFresh().then((c) => c.organizationId);\n }\n\n private async fetchToken(): Promise<CachedToken> {\n log(this.logger, \"fetching service account token\", {\n url: `${this.issuerUrl}/auth/token`,\n clientId: this.clientId,\n });\n\n const credentials = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString(\"base64\");\n const res = await fetch(`${this.issuerUrl}/auth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${credentials}`,\n },\n body: JSON.stringify({ grant_type: \"service_account\" }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string };\n const msg = `auth failed (${res.status}): ${err.error ?? \"unknown error\"}`;\n log(this.logger, msg);\n throw new Error(`[geekapps-post] ${msg}`);\n }\n\n const data = await res.json() as { access_token: string; expires_in?: number };\n const claims = decodeJwtPayload(data.access_token);\n const organizationId =\n typeof claims.organizationId === \"string\" ? claims.organizationId :\n typeof claims.organization_id === \"string\" ? claims.organization_id :\n undefined;\n\n this.cached = {\n value: data.access_token,\n expiresAt: Date.now() + (data.expires_in ?? 420) * 1000,\n organizationId,\n };\n\n log(this.logger, \"service account token acquired\", {\n claims: { organizationId },\n expiresIn: `${data.expires_in ?? 420}s`,\n });\n\n return this.cached;\n }\n}\n\nexport class LoggingHttpClient extends HttpClient {\n private readonly logger: Logger;\n private readonly baseUrlLog: string;\n\n constructor(options: ConstructorParameters<typeof HttpClient>[0], logger: Logger) {\n super(options);\n this.logger = logger;\n this.baseUrlLog = options.baseUrl.replace(/\\/$/, \"\");\n }\n\n override async request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrlLog}/v1${path}`;\n log(this.logger, \"api request\", { method, url });\n if (body !== undefined) {\n log(this.logger, \"api request body\", { body });\n }\n try {\n const result = await super.request<T>(method, path, body);\n log(this.logger, \"api response\", { method, url, status: 200 });\n return result;\n } catch (err) {\n const status = (err as { status?: number }).status;\n log(this.logger, \"api response error\", { method, url, status });\n throw err;\n }\n }\n}\n\ndeclare module \"fastify\" {\n interface FastifyInstance {\n postClient: PostClient;\n }\n interface FastifyRequest {\n postClient: PostClient;\n }\n}\n\nconst postPlugin: FastifyPluginAsync<PostPluginOptions> = async (\n fastify: FastifyInstance,\n options: PostPluginOptions,\n) => {\n const logger = options.logLevel\n ? fastify.log.child({ level: options.logLevel })\n : fastify.log;\n\n const baseUrl = options.baseUrl ?? \"https://post-api.geekapps.com.br\";\n const provider = new TokenProvider(options, logger);\n\n log(logger, \"geekapps post initialized\", {\n issuerUrl: options.serviceAccount.issuerUrl,\n baseUrl,\n serviceAccount: true,\n });\n\n const http = new LoggingHttpClient(\n {\n baseUrl,\n token: () => provider.getToken(),\n organizationId: () => provider.getOrganizationId() as Promise<string>,\n },\n logger,\n );\n\n const client = new PostClient(http);\n\n fastify.decorate(\"postClient\", client);\n\n fastify.addHook(\"onRequest\", async (request: FastifyRequest) => {\n request.postClient = client;\n });\n};\n\nexport default fp(postPlugin, {\n fastify: \">=4.0.0\",\n name: \"@geekapps/post-fastify\",\n});\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { PostWebhookPayload } from \"./types.js\";\n\n/**\n * Verifies the `X-Post-Signature` header (`sha256=<hex>`) of a Post webhook.\n * `rawBody` must be the exact request body string, before JSON parsing.\n */\nexport function verifyWebhookSignature(\n rawBody: string,\n signatureHeader: string | null | undefined,\n secret: string,\n): boolean {\n if (!signatureHeader?.startsWith(\"sha256=\")) return false;\n const expected = Buffer.from(createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\"));\n const received = Buffer.from(signatureHeader.slice(\"sha256=\".length));\n return expected.length === received.length && timingSafeEqual(expected, received);\n}\n\n/** Verifies the signature and parses the payload; throws if invalid. */\nexport function constructWebhookEvent(\n rawBody: string,\n signatureHeader: string | null | undefined,\n secret: string,\n): PostWebhookPayload {\n if (!verifyWebhookSignature(rawBody, signatureHeader, secret)) {\n throw new Error(\"Invalid Post webhook signature\");\n }\n return JSON.parse(rawBody) as PostWebhookPayload;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/resources/domains.ts","../src/resources/history.ts","../src/resources/managed-numbers.ts","../src/resources/messages.ts","../src/resources/plans.ts","../src/resources/smtp.ts","../src/resources/statistics.ts","../src/resources/templates.ts","../src/resources/webhooks.ts","../src/resources/whatsapp-calls.ts","../src/resources/whatsapp-messages.ts","../src/resources/whatsapp-numbers.ts","../src/resources/whatsapp-templates.ts","../src/client.ts","../src/plugin.ts","../src/webhook.ts"],"sourcesContent":["export class PostApiError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly detail?: string,\n ) {\n super(detail ? `${message}: ${detail}` : message);\n this.name = \"PostApiError\";\n }\n\n get isNotFound() {\n return this.status === 404;\n }\n\n get isUnauthorized() {\n return this.status === 401;\n }\n\n get isForbidden() {\n return this.status === 403;\n }\n\n get isRateLimited() {\n return this.status === 429;\n }\n\n get isValidationError() {\n return this.status === 400;\n }\n}\n","import { PostApiError } from \"./errors.js\";\n\nexport type TokenResolver = string | (() => string | Promise<string>);\n\nexport interface HttpClientOptions {\n baseUrl: string;\n token: TokenResolver;\n organizationId?: string | (() => string | Promise<string>);\n}\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly token: TokenResolver;\n private readonly organizationId?: string | (() => string | Promise<string>);\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n this.token = options.token;\n this.organizationId = options.organizationId;\n }\n\n private async resolveToken(): Promise<string> {\n return typeof this.token === \"function\" ? await this.token() : this.token;\n }\n\n private async resolveOrgId(): Promise<string | undefined> {\n if (!this.organizationId) return undefined;\n return typeof this.organizationId === \"function\"\n ? await this.organizationId()\n : this.organizationId;\n }\n\n async request<T = unknown>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const token = await this.resolveToken();\n const orgId = await this.resolveOrgId();\n\n const res = await fetch(`${this.baseUrl}/v1${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n ...(body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n ...(orgId ? { \"X-Organization-Id\": orgId } : {}),\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cache: \"no-store\" as any,\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as {\n error?: string;\n detail?: string;\n };\n throw new PostApiError(\n res.status,\n err.error ?? `HTTP ${res.status}`,\n err.detail,\n );\n }\n\n if (res.status === 204) return undefined as T;\n return res.json() as Promise<T>;\n }\n\n get<T>(path: string) {\n return this.request<T>(\"GET\", path);\n }\n\n post<T>(path: string, body?: unknown) {\n return this.request<T>(\"POST\", path, body);\n }\n\n put<T>(path: string, body?: unknown) {\n return this.request<T>(\"PUT\", path, body);\n }\n\n patch<T>(path: string, body?: unknown) {\n return this.request<T>(\"PATCH\", path, body);\n }\n\n delete<T = void>(path: string) {\n return this.request<T>(\"DELETE\", path);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { CreateDomainInput, CreateDomainResult, OrgDomain } from \"../types.js\";\n\nexport class DomainsResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<OrgDomain[]> {\n return this.http.get<OrgDomain[]>(\"/domains\");\n }\n\n get(id: string): Promise<OrgDomain> {\n return this.http.get<OrgDomain>(`/domains/${id}`);\n }\n\n create(input: CreateDomainInput): Promise<CreateDomainResult> {\n return this.http.post<CreateDomainResult>(\"/domains\", input);\n }\n\n verify(id: string): Promise<{ status: \"verified\" | \"failed\" }> {\n return this.http.post<{ status: \"verified\" | \"failed\" }>(`/domains/${id}/verify`);\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/domains/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { ListHistoryParams, MessageLog, MessageLogDetail, PaginatedResult } from \"../types.js\";\n\nexport class HistoryResource {\n constructor(private readonly http: HttpClient) {}\n\n list(params?: ListHistoryParams): Promise<PaginatedResult<MessageLog>> {\n const qs = new URLSearchParams();\n if (params?.type) qs.set(\"type\", params.type);\n if (params?.status) qs.set(\"status\", params.status);\n if (params?.from) qs.set(\"from\", params.from);\n if (params?.to) qs.set(\"to\", params.to);\n if (params?.page !== undefined) qs.set(\"page\", String(params.page));\n if (params?.limit !== undefined) qs.set(\"limit\", String(params.limit));\n const query = qs.toString();\n return this.http.get<PaginatedResult<MessageLog>>(`/history${query ? `?${query}` : \"\"}`);\n }\n\n get(id: string): Promise<MessageLogDetail> {\n return this.http.get<MessageLogDetail>(`/history/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { AreaCode, ManagedNumber } from \"../types.js\";\n\nexport interface ProvisionManagedNumberInput {\n areaCode: number;\n name?: string;\n displayName: string;\n otpMethod?: \"SMS\" | \"VOICE\";\n otpLanguage?: string;\n pin?: string;\n orgWabaId?: string;\n wabaId?: string;\n accessToken?: string;\n}\n\nexport interface RetryVerificationInput {\n otpMethod?: \"SMS\" | \"VOICE\";\n otpLanguage?: string;\n}\n\nexport class ManagedNumbersResource {\n constructor(private readonly http: HttpClient) {}\n\n listAreaCodes(): Promise<AreaCode[]> {\n return this.http.get<AreaCode[]>(\"/managed-numbers/area-codes\");\n }\n\n list(): Promise<ManagedNumber[]> {\n return this.http.get<ManagedNumber[]>(\"/managed-numbers\");\n }\n\n get(id: string): Promise<ManagedNumber> {\n return this.http.get<ManagedNumber>(`/managed-numbers/${id}`);\n }\n\n provision(input: ProvisionManagedNumberInput): Promise<ManagedNumber> {\n return this.http.post<ManagedNumber>(\"/managed-numbers\", input);\n }\n\n retryVerification(id: string, input?: RetryVerificationInput): Promise<ManagedNumber> {\n return this.http.post<ManagedNumber>(`/managed-numbers/${id}/retry-verification`, input);\n }\n\n cancel(id: string): Promise<ManagedNumber> {\n return this.http.post<ManagedNumber>(`/managed-numbers/${id}/cancel`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { MessagePresenceInput, MessagePresenceResult, SendMessageInput, SendMessageResult } from \"../types.js\";\n\nexport class MessagesResource {\n constructor(private readonly http: HttpClient) {}\n\n send(input: SendMessageInput): Promise<SendMessageResult> {\n return this.http.post<SendMessageResult>(\"/messages\", input);\n }\n\n /** Marca uma mensagem recebida como lida (tique azul). */\n markAsRead(input: MessagePresenceInput): Promise<MessagePresenceResult> {\n return this.http.post<MessagePresenceResult>(\"/whatsapp/messages/read\", input);\n }\n\n /** Marca como lida e mostra \"digitando…\" até a resposta ser enviada (máx. ~25s). */\n sendTyping(input: MessagePresenceInput): Promise<MessagePresenceResult> {\n return this.http.post<MessagePresenceResult>(\"/whatsapp/messages/typing\", input);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { AvailablePlan, OrgPlan, PlansResult, UpdatePlanInput } from \"../types.js\";\n\nexport class PlansResource {\n constructor(private readonly http: HttpClient) {}\n\n get(): Promise<PlansResult> {\n return this.http.get<PlansResult>(\"/plans\");\n }\n\n update(input: UpdatePlanInput): Promise<OrgPlan> {\n return this.http.put<OrgPlan>(\"/plans\", input);\n }\n\n listAvailable(): Promise<AvailablePlan[]> {\n return this.http.get<AvailablePlan[]>(\"/plans/available\");\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { SmtpConfig, UpsertSmtpConfigInput } from \"../types.js\";\n\nexport class SmtpResource {\n constructor(private readonly http: HttpClient) {}\n\n get(): Promise<SmtpConfig> {\n return this.http.get<SmtpConfig>(\"/smtp-config\");\n }\n\n upsert(input: UpsertSmtpConfigInput): Promise<SmtpConfig> {\n return this.http.put<SmtpConfig>(\"/smtp-config\", input);\n }\n\n delete(): Promise<void> {\n return this.http.delete(\"/smtp-config\");\n }\n\n test(to: string): Promise<{ success: boolean; error?: string }> {\n return this.http.post<{ success: boolean; error?: string }>(\"/smtp-config/test\", { to });\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type { StatisticsParams, StatisticsResult } from \"../types.js\";\n\nexport class StatisticsResource {\n constructor(private readonly http: HttpClient) {}\n\n get(params?: StatisticsParams): Promise<StatisticsResult> {\n const qs = new URLSearchParams();\n if (params?.from) qs.set(\"from\", params.from);\n if (params?.to) qs.set(\"to\", params.to);\n if (params?.groupBy) qs.set(\"groupBy\", params.groupBy);\n const query = qs.toString();\n return this.http.get<StatisticsResult>(`/statistics${query ? `?${query}` : \"\"}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CreateTemplateInput,\n MessageTemplate,\n MessageType,\n SaveDraftInput,\n UpdateTemplateInput,\n} from \"../types.js\";\n\nexport class TemplatesResource {\n constructor(private readonly http: HttpClient) {}\n\n list(params?: { type?: MessageType; isActive?: boolean }): Promise<MessageTemplate[]> {\n const qs = new URLSearchParams();\n if (params?.type) qs.set(\"type\", params.type);\n if (params?.isActive !== undefined) qs.set(\"isActive\", String(params.isActive));\n const query = qs.toString();\n return this.http.get<MessageTemplate[]>(`/templates${query ? `?${query}` : \"\"}`);\n }\n\n get(id: string): Promise<MessageTemplate> {\n return this.http.get<MessageTemplate>(`/templates/${id}`);\n }\n\n create(input: CreateTemplateInput): Promise<MessageTemplate> {\n return this.http.post<MessageTemplate>(\"/templates\", input);\n }\n\n update(id: string, input: UpdateTemplateInput): Promise<MessageTemplate> {\n return this.http.put<MessageTemplate>(`/templates/${id}`, input);\n }\n\n saveDraft(id: string, input: SaveDraftInput): Promise<MessageTemplate> {\n return this.http.patch<MessageTemplate>(`/templates/${id}/draft`, input);\n }\n\n publish(id: string): Promise<MessageTemplate> {\n return this.http.post<MessageTemplate>(`/templates/${id}/publish`);\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/templates/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CreateWebhookInput,\n OrgWebhook,\n OrgWebhookWithSecret,\n RotateSecretResult,\n UpdateWebhookInput,\n WebhookDelivery,\n} from \"../types.js\";\n\nexport class WebhooksResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<OrgWebhook[]> {\n return this.http.get<OrgWebhook[]>(\"/webhooks\");\n }\n\n create(input: CreateWebhookInput): Promise<OrgWebhookWithSecret> {\n return this.http.post<OrgWebhookWithSecret>(\"/webhooks\", input);\n }\n\n update(id: string, input: UpdateWebhookInput): Promise<OrgWebhook> {\n return this.http.put<OrgWebhook>(`/webhooks/${id}`, input);\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/webhooks/${id}`);\n }\n\n listDeliveries(id: string): Promise<WebhookDelivery[]> {\n return this.http.get<WebhookDelivery[]>(`/webhooks/${id}/deliveries`);\n }\n\n rotateSecret(id: string): Promise<RotateSecretResult> {\n return this.http.post<RotateSecretResult>(`/webhooks/${id}/rotate-secret`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CallActionResult,\n CallAnswerInput,\n CallPermissionStatus,\n CallTargetInput,\n CallingSettings,\n ConnectCallInput,\n ConnectCallResult,\n RequestCallPermissionInput,\n RequestCallPermissionResult,\n UpdateCallingSettingsInput,\n} from \"../types.js\";\n\n// WhatsApp Cloud API Calling. Signaling only: media flows over WebRTC between\n// Meta and your server. Incoming calls arrive via the `call_connect` webhook.\nexport class WhatsappCallsResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Lê a configuração de chamadas de um número (id do WhatsappNumber no Post). */\n getSettings(numberId: string): Promise<CallingSettings> {\n return this.http.get<CallingSettings>(`/whatsapp/numbers/${numberId}/calling`);\n }\n\n /** Ativa/desativa chamadas no número. */\n updateSettings(numberId: string, input: UpdateCallingSettingsInput): Promise<CallingSettings> {\n return this.http.put<CallingSettings>(`/whatsapp/numbers/${numberId}/calling`, input);\n }\n\n /** Pré-aceita uma chamada recebida (opcional, acelera a conexão de mídia). */\n preAccept(callId: string, input: CallAnswerInput): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/pre-accept`, input);\n }\n\n /** Aceita uma chamada recebida enviando o SDP de resposta. */\n accept(callId: string, input: CallAnswerInput): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/accept`, input);\n }\n\n /** Rejeita uma chamada recebida. */\n reject(callId: string, input: CallTargetInput = {}): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/reject`, input);\n }\n\n /** Encerra uma chamada em andamento. */\n terminate(callId: string, input: CallTargetInput = {}): Promise<CallActionResult> {\n return this.http.post<CallActionResult>(`/whatsapp/calls/${callId}/terminate`, input);\n }\n\n /** Inicia uma chamada (business-initiated). Exige permissão prévia do usuário. */\n connect(input: ConnectCallInput): Promise<ConnectCallResult> {\n return this.http.post<ConnectCallResult>(\"/whatsapp/calls\", input);\n }\n\n /** Envia ao usuário o pedido de permissão para receber chamadas. */\n requestPermission(input: RequestCallPermissionInput): Promise<RequestCallPermissionResult> {\n return this.http.post<RequestCallPermissionResult>(\"/whatsapp/calls/permissions\", input);\n }\n\n /** Consulta o status de permissão de chamada de um usuário. */\n getPermission(to: string, phoneNumberId?: string): Promise<CallPermissionStatus> {\n return this.http.get<CallPermissionStatus>(`/whatsapp/calls/permissions?${new URLSearchParams({ to, ...(phoneNumberId ? { phoneNumberId } : {}) })}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n SendWhatsappMessageInput,\n SendWhatsappMessageResult,\n UploadWhatsappMediaInput,\n UploadWhatsappMediaResult,\n WhatsappContactCard,\n WhatsappInteractive,\n WhatsappMediaDownload,\n WhatsappMediaInfo,\n WhatsappMediaRef,\n WhatsappMessage,\n} from \"../types.js\";\n\ntype Target = { to: string; phoneNumberId?: string; replyTo?: string };\n\n// Mensagens livres: só dentro da janela de 24h aberta por uma mensagem recebida.\n// Fora dela, envie um template por `messages.send`.\nexport class WhatsappMessagesResource {\n constructor(private readonly http: HttpClient) {}\n\n /** Envio genérico de qualquer tipo de mensagem. */\n send(input: SendWhatsappMessageInput): Promise<SendWhatsappMessageResult> {\n return this.http.post<SendWhatsappMessageResult>(\"/whatsapp/messages/send\", input);\n }\n\n sendText(target: Target, body: string, previewUrl?: boolean) {\n return this.send({ ...target, message: { type: \"text\", body, previewUrl } });\n }\n\n sendImage(target: Target, media: WhatsappMediaRef, caption?: string) {\n return this.send({ ...target, message: { type: \"image\", ...media, caption } });\n }\n\n sendVideo(target: Target, media: WhatsappMediaRef, caption?: string) {\n return this.send({ ...target, message: { type: \"video\", ...media, caption } });\n }\n\n sendAudio(target: Target, media: WhatsappMediaRef) {\n return this.send({ ...target, message: { type: \"audio\", ...media } });\n }\n\n sendDocument(target: Target, media: WhatsappMediaRef, extra?: { caption?: string; filename?: string }) {\n return this.send({ ...target, message: { type: \"document\", ...media, ...extra } });\n }\n\n sendSticker(target: Target, media: WhatsappMediaRef) {\n return this.send({ ...target, message: { type: \"sticker\", ...media } });\n }\n\n sendLocation(target: Target, location: { latitude: number; longitude: number; name?: string; address?: string }) {\n return this.send({ ...target, message: { type: \"location\", ...location } });\n }\n\n sendContacts(target: Target, contacts: WhatsappContactCard[]) {\n return this.send({ ...target, message: { type: \"contacts\", contacts } });\n }\n\n /** Reage a uma mensagem. Emoji vazio remove a reação. */\n sendReaction(target: Target, messageId: string, emoji: string) {\n return this.send({ ...target, message: { type: \"reaction\", messageId, emoji } });\n }\n\n /** Botões de resposta rápida, lista, botão com link ou pedido de localização. */\n sendInteractive(target: Target, interactive: WhatsappInteractive) {\n return this.send({ ...target, message: { type: \"interactive\", interactive } });\n }\n\n /** Sobe um arquivo (base64) e devolve o `id` para usar em `sendImage`, `sendVideo` etc. */\n uploadMedia(input: UploadWhatsappMediaInput): Promise<UploadWhatsappMediaResult> {\n return this.http.post<UploadWhatsappMediaResult>(\"/whatsapp/media\", input);\n }\n\n /** Metadados de uma mídia (id recebido em `message_received`). */\n getMedia(mediaId: string, phoneNumberId?: string): Promise<WhatsappMediaInfo> {\n return this.http.get<WhatsappMediaInfo>(`/whatsapp/media/${mediaId}${phoneNumberId ? `?phoneNumberId=${encodeURIComponent(phoneNumberId)}` : \"\"}`);\n }\n\n /** Baixa uma mídia recebida (conteúdo em base64). */\n downloadMedia(mediaId: string, phoneNumberId?: string): Promise<WhatsappMediaDownload> {\n return this.http.get<WhatsappMediaDownload>(`/whatsapp/media/${mediaId}/download${phoneNumberId ? `?phoneNumberId=${encodeURIComponent(phoneNumberId)}` : \"\"}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n ConnectWabaInput,\n ConnectWhatsappNumberInput,\n OrgWaba,\n PhoneNumberStatusResult,\n RegisterWhatsappNumberInput,\n UpdateWhatsappProfileInput,\n WabaHealthResult,\n WhatsappNumber,\n WhatsappNumberProfile,\n} from \"../types.js\";\n\nexport class WhatsappNumbersResource {\n constructor(private readonly http: HttpClient) {}\n\n // ── WABAs ────────────────────────────────────────────────────────────────\n\n listWabas(): Promise<OrgWaba[]> {\n return this.http.get<OrgWaba[]>(\"/whatsapp/wabas\");\n }\n\n connectWaba(input: ConnectWabaInput): Promise<OrgWaba> {\n return this.http.post<OrgWaba>(\"/whatsapp/wabas/connect\", input);\n }\n\n reconnectWaba(id: string): Promise<OrgWaba> {\n return this.http.post<OrgWaba>(`/whatsapp/wabas/${id}/reconnect`);\n }\n\n disconnectWaba(id: string): Promise<void> {\n return this.http.delete(`/whatsapp/wabas/${id}`);\n }\n\n getWabaHealth(id: string): Promise<WabaHealthResult> {\n return this.http.get<WabaHealthResult>(`/whatsapp/wabas/${id}/health`);\n }\n\n // ── Numbers ──────────────────────────────────────────────────────────────\n\n listNumbers(): Promise<WhatsappNumber[]> {\n return this.http.get<WhatsappNumber[]>(\"/whatsapp/numbers\");\n }\n\n connectNumber(input: ConnectWhatsappNumberInput): Promise<WhatsappNumber> {\n return this.http.post<WhatsappNumber>(\"/whatsapp/numbers/connect\", input);\n }\n\n registerNumber(input: RegisterWhatsappNumberInput): Promise<WhatsappNumber> {\n return this.http.post<WhatsappNumber>(\"/whatsapp/numbers\", input);\n }\n\n verifyCode(id: string, code: string): Promise<WhatsappNumber> {\n return this.http.post<WhatsappNumber>(`/whatsapp/numbers/${id}/verify-code`, { code });\n }\n\n resendCode(id: string): Promise<void> {\n return this.http.post(`/whatsapp/numbers/${id}/resend-code`);\n }\n\n getProfile(id: string): Promise<WhatsappNumberProfile> {\n return this.http.get<WhatsappNumberProfile>(`/whatsapp/numbers/${id}/profile`);\n }\n\n updateProfile(id: string, input: UpdateWhatsappProfileInput): Promise<WhatsappNumberProfile> {\n return this.http.patch<WhatsappNumberProfile>(`/whatsapp/numbers/${id}/profile`, input);\n }\n\n updateDisplayName(id: string, displayName: string): Promise<WhatsappNumber> {\n return this.http.patch<WhatsappNumber>(`/whatsapp/numbers/${id}`, { displayName });\n }\n\n getStatus(id: string): Promise<PhoneNumberStatusResult> {\n return this.http.get<PhoneNumberStatusResult>(`/whatsapp/numbers/${id}/status`);\n }\n\n refreshNumbers(): Promise<WhatsappNumber[]> {\n return this.http.post<WhatsappNumber[]>(\"/whatsapp/numbers/refresh\");\n }\n\n deleteNumber(id: string): Promise<void> {\n return this.http.delete(`/whatsapp/numbers/${id}`);\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n CreateWhatsappTemplateInput,\n SyncWhatsappTemplatesResult,\n UpdateWhatsappTemplateInput,\n WhatsappTemplate,\n} from \"../types.js\";\n\nexport class WhatsappTemplatesResource {\n constructor(private readonly http: HttpClient) {}\n\n list(): Promise<WhatsappTemplate[]> {\n return this.http.get<WhatsappTemplate[]>(\"/whatsapp/templates\");\n }\n\n create(input: CreateWhatsappTemplateInput): Promise<WhatsappTemplate> {\n return this.http.post<WhatsappTemplate>(\"/whatsapp/templates\", input);\n }\n\n update(id: string, input: UpdateWhatsappTemplateInput): Promise<WhatsappTemplate> {\n return this.http.put<WhatsappTemplate>(`/whatsapp/templates/${id}`, input);\n }\n\n sync(): Promise<SyncWhatsappTemplatesResult> {\n return this.http.post<SyncWhatsappTemplatesResult>(\"/whatsapp/templates/sync\");\n }\n\n delete(id: string): Promise<void> {\n return this.http.delete(`/whatsapp/templates/${id}`);\n }\n}\n","import { HttpClient, type HttpClientOptions } from \"./http.js\";\nimport { DomainsResource } from \"./resources/domains.js\";\nimport { HistoryResource } from \"./resources/history.js\";\nimport { ManagedNumbersResource } from \"./resources/managed-numbers.js\";\nimport { MessagesResource } from \"./resources/messages.js\";\nimport { PlansResource } from \"./resources/plans.js\";\nimport { SmtpResource } from \"./resources/smtp.js\";\nimport { StatisticsResource } from \"./resources/statistics.js\";\nimport { TemplatesResource } from \"./resources/templates.js\";\nimport { WebhooksResource } from \"./resources/webhooks.js\";\nimport { WhatsappCallsResource } from \"./resources/whatsapp-calls.js\";\nimport { WhatsappMessagesResource } from \"./resources/whatsapp-messages.js\";\nimport { WhatsappNumbersResource } from \"./resources/whatsapp-numbers.js\";\nimport { WhatsappTemplatesResource } from \"./resources/whatsapp-templates.js\";\n\nexport interface PostClientOptions\n extends Omit<HttpClientOptions, \"baseUrl\"> {\n baseUrl?: string;\n}\n\nexport class PostClient {\n private readonly http: HttpClient;\n\n readonly messages: MessagesResource;\n readonly templates: TemplatesResource;\n readonly whatsappTemplates: WhatsappTemplatesResource;\n readonly whatsappNumbers: WhatsappNumbersResource;\n readonly calls: WhatsappCallsResource;\n readonly whatsappMessages: WhatsappMessagesResource;\n readonly domains: DomainsResource;\n readonly webhooks: WebhooksResource;\n readonly smtp: SmtpResource;\n readonly plans: PlansResource;\n readonly history: HistoryResource;\n readonly statistics: StatisticsResource;\n readonly managedNumbers: ManagedNumbersResource;\n\n constructor(optionsOrHttp: HttpClientOptions | HttpClient) {\n this.http = optionsOrHttp instanceof HttpClient ? optionsOrHttp : new HttpClient(optionsOrHttp);\n\n this.messages = new MessagesResource(this.http);\n this.templates = new TemplatesResource(this.http);\n this.whatsappTemplates = new WhatsappTemplatesResource(this.http);\n this.whatsappNumbers = new WhatsappNumbersResource(this.http);\n this.calls = new WhatsappCallsResource(this.http);\n this.whatsappMessages = new WhatsappMessagesResource(this.http);\n this.domains = new DomainsResource(this.http);\n this.webhooks = new WebhooksResource(this.http);\n this.smtp = new SmtpResource(this.http);\n this.plans = new PlansResource(this.http);\n this.history = new HistoryResource(this.http);\n this.statistics = new StatisticsResource(this.http);\n this.managedNumbers = new ManagedNumbersResource(this.http);\n }\n}\n","import type { FastifyBaseLogger, FastifyInstance, FastifyPluginAsync, FastifyRequest } from \"fastify\";\nimport fp from \"fastify-plugin\";\nimport { PostClient } from \"./client.js\";\nimport { HttpClient } from \"./http.js\";\n\nexport interface ServiceAccountOptions {\n issuerUrl: string;\n clientId: string;\n clientSecret: string;\n}\n\nexport interface PostPluginOptions {\n serviceAccount: ServiceAccountOptions;\n baseUrl?: string;\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n}\n\ninterface CachedToken {\n value: string;\n expiresAt: number;\n organizationId: string | undefined;\n}\n\ntype Logger = Pick<FastifyBaseLogger, \"debug\" | \"info\" | \"warn\" | \"error\">;\n\nfunction log(logger: Logger, msg: string, data?: Record<string, unknown>) {\n if (data) {\n process.stdout.write(`[geekapps-post] ${msg} ${JSON.stringify(data, null, 2)}\\n`);\n } else {\n process.stdout.write(`[geekapps-post] ${msg}\\n`);\n }\n}\n\nfunction decodeJwtPayload(token: string): Record<string, unknown> {\n try {\n const [, payload] = token.split(\".\");\n if (!payload) return {};\n const json = Buffer.from(payload, \"base64url\").toString(\"utf-8\");\n return JSON.parse(json) as Record<string, unknown>;\n } catch {\n return {};\n }\n}\n\nclass TokenProvider {\n private readonly issuerUrl: string;\n private readonly clientId: string;\n private readonly clientSecret: string;\n private readonly logger: Logger;\n private cached: CachedToken | null = null;\n private inflight: Promise<CachedToken> | null = null;\n\n constructor(options: PostPluginOptions, logger: Logger) {\n this.issuerUrl = options.serviceAccount.issuerUrl.replace(/\\/$/, \"\");\n this.clientId = options.serviceAccount.clientId;\n this.clientSecret = options.serviceAccount.clientSecret;\n this.logger = logger;\n }\n\n private async ensureFresh(): Promise<CachedToken> {\n const now = Date.now();\n if (this.cached && this.cached.expiresAt - now > 30_000) {\n log(this.logger, \"service account token cache hit\", {\n expiresAt: new Date(this.cached.expiresAt).toISOString(),\n });\n return this.cached;\n }\n log(this.logger, \"service account token cache miss — fetching new token\");\n if (this.inflight) return this.inflight;\n this.inflight = this.fetchToken().finally(() => { this.inflight = null; });\n return this.inflight;\n }\n\n getToken(): Promise<string> {\n return this.ensureFresh().then((c) => c.value);\n }\n\n getOrganizationId(): Promise<string | undefined> {\n return this.ensureFresh().then((c) => c.organizationId);\n }\n\n private async fetchToken(): Promise<CachedToken> {\n log(this.logger, \"fetching service account token\", {\n url: `${this.issuerUrl}/auth/token`,\n clientId: this.clientId,\n });\n\n const credentials = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString(\"base64\");\n const res = await fetch(`${this.issuerUrl}/auth/token`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Basic ${credentials}`,\n },\n body: JSON.stringify({ grant_type: \"service_account\" }),\n });\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({})) as { error?: string };\n const msg = `auth failed (${res.status}): ${err.error ?? \"unknown error\"}`;\n log(this.logger, msg);\n throw new Error(`[geekapps-post] ${msg}`);\n }\n\n const data = await res.json() as { access_token: string; expires_in?: number };\n const claims = decodeJwtPayload(data.access_token);\n const organizationId =\n typeof claims.organizationId === \"string\" ? claims.organizationId :\n typeof claims.organization_id === \"string\" ? claims.organization_id :\n undefined;\n\n this.cached = {\n value: data.access_token,\n expiresAt: Date.now() + (data.expires_in ?? 420) * 1000,\n organizationId,\n };\n\n log(this.logger, \"service account token acquired\", {\n claims: { organizationId },\n expiresIn: `${data.expires_in ?? 420}s`,\n });\n\n return this.cached;\n }\n}\n\nexport class LoggingHttpClient extends HttpClient {\n private readonly logger: Logger;\n private readonly baseUrlLog: string;\n\n constructor(options: ConstructorParameters<typeof HttpClient>[0], logger: Logger) {\n super(options);\n this.logger = logger;\n this.baseUrlLog = options.baseUrl.replace(/\\/$/, \"\");\n }\n\n override async request<T = unknown>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrlLog}/v1${path}`;\n log(this.logger, \"api request\", { method, url });\n if (body !== undefined) {\n log(this.logger, \"api request body\", { body });\n }\n try {\n const result = await super.request<T>(method, path, body);\n log(this.logger, \"api response\", { method, url, status: 200 });\n return result;\n } catch (err) {\n const status = (err as { status?: number }).status;\n log(this.logger, \"api response error\", { method, url, status });\n throw err;\n }\n }\n}\n\ndeclare module \"fastify\" {\n interface FastifyInstance {\n postClient: PostClient;\n }\n interface FastifyRequest {\n postClient: PostClient;\n }\n}\n\nconst postPlugin: FastifyPluginAsync<PostPluginOptions> = async (\n fastify: FastifyInstance,\n options: PostPluginOptions,\n) => {\n const logger = options.logLevel\n ? fastify.log.child({ level: options.logLevel })\n : fastify.log;\n\n const baseUrl = options.baseUrl ?? \"https://post-api.geekapps.com.br\";\n const provider = new TokenProvider(options, logger);\n\n log(logger, \"geekapps post initialized\", {\n issuerUrl: options.serviceAccount.issuerUrl,\n baseUrl,\n serviceAccount: true,\n });\n\n const http = new LoggingHttpClient(\n {\n baseUrl,\n token: () => provider.getToken(),\n organizationId: () => provider.getOrganizationId() as Promise<string>,\n },\n logger,\n );\n\n const client = new PostClient(http);\n\n fastify.decorate(\"postClient\", client);\n\n fastify.addHook(\"onRequest\", async (request: FastifyRequest) => {\n request.postClient = client;\n });\n};\n\nexport default fp(postPlugin, {\n fastify: \">=4.0.0\",\n name: \"@geekapps/post-fastify\",\n});\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport type { PostWebhookPayload } from \"./types.js\";\n\n/**\n * Verifies the `X-Post-Signature` header (`sha256=<hex>`) of a Post webhook.\n * `rawBody` must be the exact request body string, before JSON parsing.\n */\nexport function verifyWebhookSignature(\n rawBody: string,\n signatureHeader: string | null | undefined,\n secret: string,\n): boolean {\n if (!signatureHeader?.startsWith(\"sha256=\")) return false;\n const expected = Buffer.from(createHmac(\"sha256\", secret).update(rawBody).digest(\"hex\"));\n const received = Buffer.from(signatureHeader.slice(\"sha256=\".length));\n return expected.length === received.length && timingSafeEqual(expected, received);\n}\n\n/** Verifies the signature and parses the payload; throws if invalid. */\nexport function constructWebhookEvent(\n rawBody: string,\n signatureHeader: string | null | undefined,\n secret: string,\n): PostWebhookPayload {\n if (!verifyWebhookSignature(rawBody, signatureHeader, secret)) {\n throw new Error(\"Invalid Post webhook signature\");\n }\n return JSON.parse(rawBody) as PostWebhookPayload;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { StatisticsResource } from "./resources/statistics.js";
|
|
|
9
9
|
import { TemplatesResource } from "./resources/templates.js";
|
|
10
10
|
import { WebhooksResource } from "./resources/webhooks.js";
|
|
11
11
|
import { WhatsappCallsResource } from "./resources/whatsapp-calls.js";
|
|
12
|
+
import { WhatsappMessagesResource } from "./resources/whatsapp-messages.js";
|
|
12
13
|
import { WhatsappNumbersResource } from "./resources/whatsapp-numbers.js";
|
|
13
14
|
import { WhatsappTemplatesResource } from "./resources/whatsapp-templates.js";
|
|
14
15
|
|
|
@@ -25,6 +26,7 @@ export class PostClient {
|
|
|
25
26
|
readonly whatsappTemplates: WhatsappTemplatesResource;
|
|
26
27
|
readonly whatsappNumbers: WhatsappNumbersResource;
|
|
27
28
|
readonly calls: WhatsappCallsResource;
|
|
29
|
+
readonly whatsappMessages: WhatsappMessagesResource;
|
|
28
30
|
readonly domains: DomainsResource;
|
|
29
31
|
readonly webhooks: WebhooksResource;
|
|
30
32
|
readonly smtp: SmtpResource;
|
|
@@ -41,6 +43,7 @@ export class PostClient {
|
|
|
41
43
|
this.whatsappTemplates = new WhatsappTemplatesResource(this.http);
|
|
42
44
|
this.whatsappNumbers = new WhatsappNumbersResource(this.http);
|
|
43
45
|
this.calls = new WhatsappCallsResource(this.http);
|
|
46
|
+
this.whatsappMessages = new WhatsappMessagesResource(this.http);
|
|
44
47
|
this.domains = new DomainsResource(this.http);
|
|
45
48
|
this.webhooks = new WebhooksResource(this.http);
|
|
46
49
|
this.smtp = new SmtpResource(this.http);
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export { StatisticsResource } from "./resources/statistics.js";
|
|
|
13
13
|
export { TemplatesResource } from "./resources/templates.js";
|
|
14
14
|
export { WebhooksResource } from "./resources/webhooks.js";
|
|
15
15
|
export { WhatsappCallsResource } from "./resources/whatsapp-calls.js";
|
|
16
|
+
export { WhatsappMessagesResource } from "./resources/whatsapp-messages.js";
|
|
16
17
|
export { WhatsappNumbersResource } from "./resources/whatsapp-numbers.js";
|
|
17
18
|
export { constructWebhookEvent, verifyWebhookSignature } from "./webhook.js";
|
|
18
19
|
export { WhatsappTemplatesResource } from "./resources/whatsapp-templates.js";
|
|
@@ -70,7 +71,22 @@ export type {
|
|
|
70
71
|
RotateSecretResult,
|
|
71
72
|
SaveDraftInput,
|
|
72
73
|
SendMessageInput,
|
|
74
|
+
EmailAttachment,
|
|
73
75
|
MessagePresenceInput,
|
|
76
|
+
WhatsappMediaRef,
|
|
77
|
+
WhatsappContactCard,
|
|
78
|
+
WhatsappInteractive,
|
|
79
|
+
WhatsappInteractiveButtons,
|
|
80
|
+
WhatsappInteractiveList,
|
|
81
|
+
WhatsappInteractiveCtaUrl,
|
|
82
|
+
WhatsappInteractiveLocationRequest,
|
|
83
|
+
WhatsappMessage,
|
|
84
|
+
SendWhatsappMessageInput,
|
|
85
|
+
SendWhatsappMessageResult,
|
|
86
|
+
UploadWhatsappMediaInput,
|
|
87
|
+
UploadWhatsappMediaResult,
|
|
88
|
+
WhatsappMediaInfo,
|
|
89
|
+
WhatsappMediaDownload,
|
|
74
90
|
MessagePresenceResult,
|
|
75
91
|
SendMessageResult,
|
|
76
92
|
TemplateVariable,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { HttpClient } from "../http.js";
|
|
2
|
+
import type {
|
|
3
|
+
SendWhatsappMessageInput,
|
|
4
|
+
SendWhatsappMessageResult,
|
|
5
|
+
UploadWhatsappMediaInput,
|
|
6
|
+
UploadWhatsappMediaResult,
|
|
7
|
+
WhatsappContactCard,
|
|
8
|
+
WhatsappInteractive,
|
|
9
|
+
WhatsappMediaDownload,
|
|
10
|
+
WhatsappMediaInfo,
|
|
11
|
+
WhatsappMediaRef,
|
|
12
|
+
WhatsappMessage,
|
|
13
|
+
} from "../types.js";
|
|
14
|
+
|
|
15
|
+
type Target = { to: string; phoneNumberId?: string; replyTo?: string };
|
|
16
|
+
|
|
17
|
+
// Mensagens livres: só dentro da janela de 24h aberta por uma mensagem recebida.
|
|
18
|
+
// Fora dela, envie um template por `messages.send`.
|
|
19
|
+
export class WhatsappMessagesResource {
|
|
20
|
+
constructor(private readonly http: HttpClient) {}
|
|
21
|
+
|
|
22
|
+
/** Envio genérico de qualquer tipo de mensagem. */
|
|
23
|
+
send(input: SendWhatsappMessageInput): Promise<SendWhatsappMessageResult> {
|
|
24
|
+
return this.http.post<SendWhatsappMessageResult>("/whatsapp/messages/send", input);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
sendText(target: Target, body: string, previewUrl?: boolean) {
|
|
28
|
+
return this.send({ ...target, message: { type: "text", body, previewUrl } });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
sendImage(target: Target, media: WhatsappMediaRef, caption?: string) {
|
|
32
|
+
return this.send({ ...target, message: { type: "image", ...media, caption } });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
sendVideo(target: Target, media: WhatsappMediaRef, caption?: string) {
|
|
36
|
+
return this.send({ ...target, message: { type: "video", ...media, caption } });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
sendAudio(target: Target, media: WhatsappMediaRef) {
|
|
40
|
+
return this.send({ ...target, message: { type: "audio", ...media } });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
sendDocument(target: Target, media: WhatsappMediaRef, extra?: { caption?: string; filename?: string }) {
|
|
44
|
+
return this.send({ ...target, message: { type: "document", ...media, ...extra } });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
sendSticker(target: Target, media: WhatsappMediaRef) {
|
|
48
|
+
return this.send({ ...target, message: { type: "sticker", ...media } });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
sendLocation(target: Target, location: { latitude: number; longitude: number; name?: string; address?: string }) {
|
|
52
|
+
return this.send({ ...target, message: { type: "location", ...location } });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
sendContacts(target: Target, contacts: WhatsappContactCard[]) {
|
|
56
|
+
return this.send({ ...target, message: { type: "contacts", contacts } });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Reage a uma mensagem. Emoji vazio remove a reação. */
|
|
60
|
+
sendReaction(target: Target, messageId: string, emoji: string) {
|
|
61
|
+
return this.send({ ...target, message: { type: "reaction", messageId, emoji } });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Botões de resposta rápida, lista, botão com link ou pedido de localização. */
|
|
65
|
+
sendInteractive(target: Target, interactive: WhatsappInteractive) {
|
|
66
|
+
return this.send({ ...target, message: { type: "interactive", interactive } });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Sobe um arquivo (base64) e devolve o `id` para usar em `sendImage`, `sendVideo` etc. */
|
|
70
|
+
uploadMedia(input: UploadWhatsappMediaInput): Promise<UploadWhatsappMediaResult> {
|
|
71
|
+
return this.http.post<UploadWhatsappMediaResult>("/whatsapp/media", input);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Metadados de uma mídia (id recebido em `message_received`). */
|
|
75
|
+
getMedia(mediaId: string, phoneNumberId?: string): Promise<WhatsappMediaInfo> {
|
|
76
|
+
return this.http.get<WhatsappMediaInfo>(`/whatsapp/media/${mediaId}${phoneNumberId ? `?phoneNumberId=${encodeURIComponent(phoneNumberId)}` : ""}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Baixa uma mídia recebida (conteúdo em base64). */
|
|
80
|
+
downloadMedia(mediaId: string, phoneNumberId?: string): Promise<WhatsappMediaDownload> {
|
|
81
|
+
return this.http.get<WhatsappMediaDownload>(`/whatsapp/media/${mediaId}/download${phoneNumberId ? `?phoneNumberId=${encodeURIComponent(phoneNumberId)}` : ""}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -256,6 +256,16 @@ export interface TemplateVariables {
|
|
|
256
256
|
buttons?: TemplateVariable[];
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
+
export interface EmailAttachment {
|
|
260
|
+
filename: string;
|
|
261
|
+
/** Conteúdo do arquivo em base64. Informe `content` ou `url`. */
|
|
262
|
+
content?: string;
|
|
263
|
+
/** URL pública (http/https) do arquivo. Informe `content` ou `url`. */
|
|
264
|
+
url?: string;
|
|
265
|
+
/** Ex.: "application/pdf". Se omitido, é inferido pelo nome do arquivo. */
|
|
266
|
+
contentType?: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
259
269
|
export interface SendMessageInput {
|
|
260
270
|
type: MessageType;
|
|
261
271
|
to: string;
|
|
@@ -266,6 +276,8 @@ export interface SendMessageInput {
|
|
|
266
276
|
subject?: string;
|
|
267
277
|
body?: string;
|
|
268
278
|
variables?: TemplateVariable[] | TemplateVariables;
|
|
279
|
+
/** Apenas para `type: "email"`. Máx. 10 arquivos / 25MB no total. */
|
|
280
|
+
attachments?: EmailAttachment[];
|
|
269
281
|
}
|
|
270
282
|
|
|
271
283
|
export interface CreateTemplateInput {
|
|
@@ -559,3 +571,113 @@ export interface MessagePresenceResult {
|
|
|
559
571
|
success: boolean;
|
|
560
572
|
phoneNumberId: string;
|
|
561
573
|
}
|
|
574
|
+
|
|
575
|
+
// ─── WhatsApp: mensagens livres (janela de 24h) ──────────────────────────────
|
|
576
|
+
|
|
577
|
+
/** Mídia já enviada (`id`) ou URL pública (`link`). */
|
|
578
|
+
export interface WhatsappMediaRef {
|
|
579
|
+
id?: string;
|
|
580
|
+
link?: string;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
export interface WhatsappContactCard {
|
|
584
|
+
name: { formattedName: string; firstName?: string; lastName?: string };
|
|
585
|
+
phones?: { phone: string; type?: string; waId?: string }[];
|
|
586
|
+
emails?: { email: string; type?: string }[];
|
|
587
|
+
org?: { company?: string; title?: string };
|
|
588
|
+
urls?: { url: string; type?: string }[];
|
|
589
|
+
/** YYYY-MM-DD */
|
|
590
|
+
birthday?: string;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
export interface WhatsappInteractiveButtons {
|
|
594
|
+
kind: "buttons";
|
|
595
|
+
body: string;
|
|
596
|
+
header?: string;
|
|
597
|
+
footer?: string;
|
|
598
|
+
/** Até 3 botões. `id` volta em `message_received` quando o usuário clica. */
|
|
599
|
+
buttons: { id: string; title: string }[];
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export interface WhatsappInteractiveList {
|
|
603
|
+
kind: "list";
|
|
604
|
+
body: string;
|
|
605
|
+
header?: string;
|
|
606
|
+
footer?: string;
|
|
607
|
+
buttonText: string;
|
|
608
|
+
sections: { title?: string; rows: { id: string; title: string; description?: string }[] }[];
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export interface WhatsappInteractiveCtaUrl {
|
|
612
|
+
kind: "cta_url";
|
|
613
|
+
body: string;
|
|
614
|
+
header?: string;
|
|
615
|
+
footer?: string;
|
|
616
|
+
buttonText: string;
|
|
617
|
+
url: string;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export interface WhatsappInteractiveLocationRequest {
|
|
621
|
+
kind: "location_request";
|
|
622
|
+
body: string;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export type WhatsappInteractive =
|
|
626
|
+
| WhatsappInteractiveButtons
|
|
627
|
+
| WhatsappInteractiveList
|
|
628
|
+
| WhatsappInteractiveCtaUrl
|
|
629
|
+
| WhatsappInteractiveLocationRequest;
|
|
630
|
+
|
|
631
|
+
export type WhatsappMessage =
|
|
632
|
+
| { type: "text"; body: string; previewUrl?: boolean }
|
|
633
|
+
| ({ type: "image"; caption?: string } & WhatsappMediaRef)
|
|
634
|
+
| ({ type: "video"; caption?: string } & WhatsappMediaRef)
|
|
635
|
+
| ({ type: "audio" } & WhatsappMediaRef)
|
|
636
|
+
| ({ type: "document"; caption?: string; filename?: string } & WhatsappMediaRef)
|
|
637
|
+
| ({ type: "sticker" } & WhatsappMediaRef)
|
|
638
|
+
| { type: "location"; latitude: number; longitude: number; name?: string; address?: string }
|
|
639
|
+
| { type: "contacts"; contacts: WhatsappContactCard[] }
|
|
640
|
+
| { type: "reaction"; messageId: string; emoji: string }
|
|
641
|
+
| { type: "interactive"; interactive: WhatsappInteractive };
|
|
642
|
+
|
|
643
|
+
export interface SendWhatsappMessageInput {
|
|
644
|
+
to: string;
|
|
645
|
+
message: WhatsappMessage;
|
|
646
|
+
/** Meta phone_number_id. Padrão: primeiro número ativo da org. */
|
|
647
|
+
phoneNumberId?: string;
|
|
648
|
+
/** `messageId` de uma mensagem para responder citando. */
|
|
649
|
+
replyTo?: string;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
export interface SendWhatsappMessageResult {
|
|
653
|
+
messageId: string;
|
|
654
|
+
phoneNumberId: string;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
export interface UploadWhatsappMediaInput {
|
|
658
|
+
/** Conteúdo do arquivo em base64. */
|
|
659
|
+
data: string;
|
|
660
|
+
mimeType: string;
|
|
661
|
+
filename?: string;
|
|
662
|
+
phoneNumberId?: string;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
export interface UploadWhatsappMediaResult {
|
|
666
|
+
id: string;
|
|
667
|
+
phoneNumberId: string;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
export interface WhatsappMediaInfo {
|
|
671
|
+
id: string;
|
|
672
|
+
mimeType: string;
|
|
673
|
+
fileSize: number | null;
|
|
674
|
+
sha256: string | null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
export interface WhatsappMediaDownload {
|
|
678
|
+
id: string;
|
|
679
|
+
mimeType: string;
|
|
680
|
+
fileSize: number;
|
|
681
|
+
/** Conteúdo em base64. */
|
|
682
|
+
data: string;
|
|
683
|
+
}
|