@jackiemacklein/nettz-utils
Version:
Serviços de imagem, e-mail, códigos de barras, utilitários numéricos e componentes React para apps Node.js com TypeScript
358 lines (357 loc) • 13.6 kB
JavaScript
;
/**
* @author Jackiê Macklein
* @company Onside tecnologia/Nettz
* @copyright Todos direitos reservados.
* @description Cliente HTTP para WhatsApp Cloud API (envio de mensagens via Graph API).
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWhatsAppCloudClient = createWhatsAppCloudClient;
const errors_1 = require("./errors");
const types_1 = require("./types");
async function readResponseBody(res) {
try {
return await res.text();
}
catch {
return "";
}
}
function applyReplyContext(payload, replyToMessageId) {
if (replyToMessageId) {
payload.context = { message_id: replyToMessageId };
}
}
function createWhatsAppCloudClient(config) {
var _a, _b, _c, _d;
const graphBaseUrl = ((_a = config.graphBaseUrl) !== null && _a !== void 0 ? _a : types_1.WHATSAPP_GRAPH_DEFAULT_BASE_URL).replace(/\/$/, "");
const graphApiVersion = (_b = config.graphApiVersion) !== null && _b !== void 0 ? _b : types_1.WHATSAPP_GRAPH_DEFAULT_VERSION;
const phoneNumberId = config.phoneNumberId;
const accessToken = config.accessToken;
const timeoutMs = (_c = config.timeoutMs) !== null && _c !== void 0 ? _c : 30000;
const fetchFn = (_d = config.fetchImpl) !== null && _d !== void 0 ? _d : fetch;
if (!accessToken || !phoneNumberId) {
throw new errors_1.WhatsAppCloudApiError("WhatsApp Cloud: accessToken e phoneNumberId são obrigatórios", 400, "");
}
function versionedPath(suffix) {
const s = suffix.startsWith("/") ? suffix : `/${suffix}`;
return `/${graphApiVersion}/${phoneNumberId}${s}`;
}
async function graphRequest(path, init) {
var _a, _b;
const url = `${graphBaseUrl}${path.startsWith("/") ? path : `/${path}`}`;
const controller = new AbortController();
const t = setTimeout(() => controller.abort(), (_a = init === null || init === void 0 ? void 0 : init.timeoutMs) !== null && _a !== void 0 ? _a : timeoutMs);
try {
const res = await fetchFn(url, {
...init,
signal: (_b = init === null || init === void 0 ? void 0 : init.signal) !== null && _b !== void 0 ? _b : controller.signal,
headers: {
Accept: "application/json",
...((init === null || init === void 0 ? void 0 : init.body) ? { "Content-Type": "application/json" } : {}),
Authorization: `Bearer ${accessToken}`,
...init === null || init === void 0 ? void 0 : init.headers,
},
});
const text = await readResponseBody(res);
if (!res.ok) {
throw new errors_1.WhatsAppCloudApiError(`WhatsApp Cloud HTTP ${res.status} ${res.statusText}`, res.status, text);
}
if (!text || text.trim() === "") {
return undefined;
}
try {
return JSON.parse(text);
}
catch {
throw new errors_1.WhatsAppCloudApiError("WhatsApp Cloud resposta não é JSON válido", res.status, text);
}
}
finally {
clearTimeout(t);
}
}
async function postMessages(body) {
return graphRequest(versionedPath("/messages"), {
method: "POST",
body: JSON.stringify(body),
});
}
const api = {
graphBaseUrl,
graphApiVersion,
phoneNumberId,
async sendMessage(body) {
return postMessages(body);
},
async sendTextMessage(options) {
var _a;
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "text",
text: {
preview_url: (_a = options.previewUrl) !== null && _a !== void 0 ? _a : false,
body: options.body,
},
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendTemplateMessage(options) {
var _a;
const payload = {
messaging_product: "whatsapp",
to: options.to,
type: "template",
template: {
name: options.templateName,
language: { code: options.languageCode },
...(((_a = options.components) === null || _a === void 0 ? void 0 : _a.length)
? { components: options.components }
: {}),
},
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendAddressMessage(options) {
var _a;
const parameters = {
country: options.country,
...((_a = options.actionParameters) !== null && _a !== void 0 ? _a : {}),
};
const interactive = {
type: "address_message",
body: { text: options.bodyText },
action: {
name: "address_message",
parameters,
},
};
if (options.headerText) {
interactive.header = { type: "text", text: options.headerText };
}
if (options.footerText) {
interactive.footer = { text: options.footerText };
}
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "interactive",
interactive,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendAudioMessage(options) {
const audio = {};
if (options.id)
audio.id = options.id;
if (options.link)
audio.link = options.link;
if (options.voice === true)
audio.voice = true;
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "audio",
audio,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendContactsMessage(options) {
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "contacts",
contacts: options.contacts,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendDocumentMessage(options) {
const document = {};
if (options.id)
document.id = options.id;
if (options.link)
document.link = options.link;
if (options.caption)
document.caption = options.caption;
if (options.filename)
document.filename = options.filename;
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "document",
document,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendImageMessage(options) {
const image = {};
if (options.id)
image.id = options.id;
if (options.link)
image.link = options.link;
if (options.caption)
image.caption = options.caption;
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "image",
image,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendVideoMessage(options) {
const video = {};
if (options.id)
video.id = options.id;
if (options.link)
video.link = options.link;
if (options.caption)
video.caption = options.caption;
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "video",
video,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendLocationMessage(options) {
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "location",
location: {
latitude: String(options.latitude),
longitude: String(options.longitude),
...(options.name ? { name: options.name } : {}),
...(options.address ? { address: options.address } : {}),
},
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendInteractiveCtaUrlMessage(options) {
const interactive = {
type: "cta_url",
body: { text: options.bodyText },
action: {
name: "cta_url",
parameters: {
display_text: options.buttonDisplayText,
url: options.buttonUrl,
},
},
};
if (options.header) {
interactive.header = options.header;
}
if (options.footerText) {
interactive.footer = { text: options.footerText };
}
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "interactive",
interactive,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendInteractiveListMessage(options) {
const interactive = {
type: "list",
body: { text: options.bodyText },
action: {
button: options.actionButtonText,
sections: options.sections,
},
};
if (options.headerText) {
interactive.header = { type: "text", text: options.headerText };
}
if (options.footerText) {
interactive.footer = { text: options.footerText };
}
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "interactive",
interactive,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendInteractiveMediaCarouselMessage(options) {
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "interactive",
interactive: {
type: "carousel",
body: { text: options.mainBodyText },
action: { cards: options.cards },
},
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async sendInteractiveReplyButtonsMessage(options) {
const interactive = {
type: "button",
body: { text: options.bodyText },
action: {
buttons: options.buttons.map((b) => ({
type: "reply",
reply: { id: b.id, title: b.title },
})),
},
};
if (options.header) {
interactive.header = options.header;
}
if (options.footerText) {
interactive.footer = { text: options.footerText };
}
const payload = {
messaging_product: "whatsapp",
recipient_type: "individual",
to: options.to,
type: "interactive",
interactive,
};
applyReplyContext(payload, options.replyToMessageId);
return postMessages(payload);
},
async getPhoneNumber(fields) {
const q = fields
? `?${new URLSearchParams({ fields }).toString()}`
: "";
return graphRequest(`/${graphApiVersion}/${encodeURIComponent(phoneNumberId)}${q}`);
},
};
return {
...api,
sendText: api.sendTextMessage,
sendTemplate: api.sendTemplateMessage,
};
}