c2-desafiox 1.0.136 → 1.0.138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Schema, Types } from "mongoose";
|
|
2
|
+
import { IDefault } from "./IDefault";
|
|
3
|
+
export declare enum WhatsAppTemplateStatus {
|
|
4
|
+
APPROVED = "APPROVED",
|
|
5
|
+
PENDING = "PENDING",
|
|
6
|
+
REJECTED = "REJECTED",
|
|
7
|
+
PAUSED = "PAUSED",
|
|
8
|
+
DISABLED = "DISABLED",
|
|
9
|
+
IN_APPEAL = "IN_APPEAL",
|
|
10
|
+
DELETED = "DELETED"
|
|
11
|
+
}
|
|
12
|
+
export declare enum WhatsAppTemplateCategory {
|
|
13
|
+
MARKETING = "MARKETING",
|
|
14
|
+
UTILITY = "UTILITY",
|
|
15
|
+
AUTHENTICATION = "AUTHENTICATION"
|
|
16
|
+
}
|
|
17
|
+
export type WhatsAppTemplateComponentType = "HEADER" | "BODY" | "FOOTER" | "BUTTONS";
|
|
18
|
+
export type WhatsAppTemplateHeaderFormat = "TEXT" | "IMAGE" | "VIDEO" | "DOCUMENT" | "LOCATION";
|
|
19
|
+
export type WhatsAppTemplateVariableKind = "text" | "media";
|
|
20
|
+
export interface IWhatsAppTemplateButton {
|
|
21
|
+
type?: string;
|
|
22
|
+
text?: string;
|
|
23
|
+
url?: string;
|
|
24
|
+
phoneNumber?: string;
|
|
25
|
+
example?: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface IWhatsAppTemplateComponent {
|
|
28
|
+
type: string;
|
|
29
|
+
format?: string;
|
|
30
|
+
text?: string;
|
|
31
|
+
example?: unknown;
|
|
32
|
+
buttons?: IWhatsAppTemplateButton[];
|
|
33
|
+
}
|
|
34
|
+
export interface IWhatsAppTemplateVariable {
|
|
35
|
+
key: string;
|
|
36
|
+
component: string;
|
|
37
|
+
buttonIndex?: number;
|
|
38
|
+
index?: number;
|
|
39
|
+
name?: string;
|
|
40
|
+
label: string;
|
|
41
|
+
example?: string;
|
|
42
|
+
kind: WhatsAppTemplateVariableKind;
|
|
43
|
+
}
|
|
44
|
+
export interface IWhatsAppTemplate extends IDefault {
|
|
45
|
+
_id?: Types.ObjectId;
|
|
46
|
+
externalId?: string;
|
|
47
|
+
wabaId?: string;
|
|
48
|
+
name: string;
|
|
49
|
+
language: string;
|
|
50
|
+
status: string;
|
|
51
|
+
category?: string;
|
|
52
|
+
parameterFormat?: string;
|
|
53
|
+
qualityScore?: string;
|
|
54
|
+
rejectedReason?: string;
|
|
55
|
+
components: IWhatsAppTemplateComponent[];
|
|
56
|
+
variables: IWhatsAppTemplateVariable[];
|
|
57
|
+
lastSyncedAt?: Date;
|
|
58
|
+
}
|
|
59
|
+
export declare const WhatsAppTemplateSchema: Schema<IWhatsAppTemplate, import("mongoose").Model<IWhatsAppTemplate, any, any, any, import("mongoose").Document<unknown, any, IWhatsAppTemplate, any> & IWhatsAppTemplate & Required<{
|
|
60
|
+
_id: Types.ObjectId;
|
|
61
|
+
}> & {
|
|
62
|
+
__v: number;
|
|
63
|
+
}, any>, {}, {}, {}, {}, import("mongoose").DefaultSchemaOptions, IWhatsAppTemplate, import("mongoose").Document<unknown, {}, import("mongoose").FlatRecord<IWhatsAppTemplate>, {}> & import("mongoose").FlatRecord<IWhatsAppTemplate> & Required<{
|
|
64
|
+
_id: Types.ObjectId;
|
|
65
|
+
}> & {
|
|
66
|
+
__v: number;
|
|
67
|
+
}>;
|
|
68
|
+
export declare function extractPlaceholders(text?: string): string[];
|
|
69
|
+
export declare function extractWhatsAppTemplateVariables(components: IWhatsAppTemplateComponent[]): IWhatsAppTemplateVariable[];
|
|
70
|
+
export declare function applyWhatsAppTemplateValues(text: string | undefined, values: Record<string, string>, prefix: string): string;
|
|
71
|
+
export declare function renderWhatsAppTemplateContent(template: Pick<IWhatsAppTemplate, "components" | "name">, values?: Record<string, string>): string;
|
|
72
|
+
export declare function buildWhatsAppSendComponents(template: Pick<IWhatsAppTemplate, "components" | "parameterFormat">, values?: Record<string, string>): Record<string, unknown>[];
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WhatsAppTemplateSchema = exports.WhatsAppTemplateCategory = exports.WhatsAppTemplateStatus = void 0;
|
|
4
|
+
exports.extractPlaceholders = extractPlaceholders;
|
|
5
|
+
exports.extractWhatsAppTemplateVariables = extractWhatsAppTemplateVariables;
|
|
6
|
+
exports.applyWhatsAppTemplateValues = applyWhatsAppTemplateValues;
|
|
7
|
+
exports.renderWhatsAppTemplateContent = renderWhatsAppTemplateContent;
|
|
8
|
+
exports.buildWhatsAppSendComponents = buildWhatsAppSendComponents;
|
|
9
|
+
const mongoose_1 = require("mongoose");
|
|
10
|
+
var WhatsAppTemplateStatus;
|
|
11
|
+
(function (WhatsAppTemplateStatus) {
|
|
12
|
+
WhatsAppTemplateStatus["APPROVED"] = "APPROVED";
|
|
13
|
+
WhatsAppTemplateStatus["PENDING"] = "PENDING";
|
|
14
|
+
WhatsAppTemplateStatus["REJECTED"] = "REJECTED";
|
|
15
|
+
WhatsAppTemplateStatus["PAUSED"] = "PAUSED";
|
|
16
|
+
WhatsAppTemplateStatus["DISABLED"] = "DISABLED";
|
|
17
|
+
WhatsAppTemplateStatus["IN_APPEAL"] = "IN_APPEAL";
|
|
18
|
+
WhatsAppTemplateStatus["DELETED"] = "DELETED";
|
|
19
|
+
})(WhatsAppTemplateStatus || (exports.WhatsAppTemplateStatus = WhatsAppTemplateStatus = {}));
|
|
20
|
+
var WhatsAppTemplateCategory;
|
|
21
|
+
(function (WhatsAppTemplateCategory) {
|
|
22
|
+
WhatsAppTemplateCategory["MARKETING"] = "MARKETING";
|
|
23
|
+
WhatsAppTemplateCategory["UTILITY"] = "UTILITY";
|
|
24
|
+
WhatsAppTemplateCategory["AUTHENTICATION"] = "AUTHENTICATION";
|
|
25
|
+
})(WhatsAppTemplateCategory || (exports.WhatsAppTemplateCategory = WhatsAppTemplateCategory = {}));
|
|
26
|
+
const WhatsAppTemplateButtonSchema = new mongoose_1.Schema({
|
|
27
|
+
type: { type: String },
|
|
28
|
+
text: { type: String },
|
|
29
|
+
url: { type: String },
|
|
30
|
+
phoneNumber: { type: String },
|
|
31
|
+
example: [{ type: String }],
|
|
32
|
+
}, { _id: false });
|
|
33
|
+
const WhatsAppTemplateComponentSchema = new mongoose_1.Schema({
|
|
34
|
+
type: { type: String, required: true },
|
|
35
|
+
format: { type: String },
|
|
36
|
+
text: { type: String },
|
|
37
|
+
example: { type: mongoose_1.Schema.Types.Mixed },
|
|
38
|
+
buttons: [WhatsAppTemplateButtonSchema],
|
|
39
|
+
}, { _id: false });
|
|
40
|
+
const WhatsAppTemplateVariableSchema = new mongoose_1.Schema({
|
|
41
|
+
key: { type: String, required: true },
|
|
42
|
+
component: { type: String, required: true },
|
|
43
|
+
buttonIndex: { type: Number },
|
|
44
|
+
index: { type: Number },
|
|
45
|
+
name: { type: String },
|
|
46
|
+
label: { type: String, required: true },
|
|
47
|
+
example: { type: String },
|
|
48
|
+
kind: { type: String, enum: ["text", "media"], required: true, default: "text" },
|
|
49
|
+
}, { _id: false });
|
|
50
|
+
exports.WhatsAppTemplateSchema = new mongoose_1.Schema({
|
|
51
|
+
externalId: { type: String },
|
|
52
|
+
wabaId: { type: String },
|
|
53
|
+
name: { type: String, required: true },
|
|
54
|
+
language: { type: String, required: true },
|
|
55
|
+
status: { type: String, required: true },
|
|
56
|
+
category: { type: String },
|
|
57
|
+
parameterFormat: { type: String },
|
|
58
|
+
qualityScore: { type: String },
|
|
59
|
+
rejectedReason: { type: String },
|
|
60
|
+
components: { type: [WhatsAppTemplateComponentSchema], default: [] },
|
|
61
|
+
variables: { type: [WhatsAppTemplateVariableSchema], default: [] },
|
|
62
|
+
lastSyncedAt: { type: Date },
|
|
63
|
+
}, {
|
|
64
|
+
timestamps: { createdAt: "createdAtDateTime", updatedAt: "updatedAtDateTime" },
|
|
65
|
+
});
|
|
66
|
+
exports.WhatsAppTemplateSchema.index({ name: 1, language: 1 }, { unique: true });
|
|
67
|
+
exports.WhatsAppTemplateSchema.index({ status: 1, name: 1 });
|
|
68
|
+
exports.WhatsAppTemplateSchema.index({ externalId: 1 });
|
|
69
|
+
const PLACEHOLDER_RE = /\{\{\s*([a-zA-Z_][\w]*|\d+)\s*\}\}/g;
|
|
70
|
+
function asRecord(value) {
|
|
71
|
+
return value && typeof value === "object" ? value : {};
|
|
72
|
+
}
|
|
73
|
+
function firstExampleString(example, fallbackIndex = 0) {
|
|
74
|
+
const record = asRecord(example);
|
|
75
|
+
const headerText = record.header_text;
|
|
76
|
+
if (Array.isArray(headerText) && headerText[fallbackIndex] != null)
|
|
77
|
+
return String(headerText[fallbackIndex]);
|
|
78
|
+
const headerHandle = record.header_handle;
|
|
79
|
+
if (Array.isArray(headerHandle) && headerHandle[0] != null)
|
|
80
|
+
return String(headerHandle[0]);
|
|
81
|
+
const bodyText = record.body_text;
|
|
82
|
+
if (Array.isArray(bodyText) && Array.isArray(bodyText[0]) && bodyText[0][fallbackIndex] != null) {
|
|
83
|
+
return String(bodyText[0][fallbackIndex]);
|
|
84
|
+
}
|
|
85
|
+
const named = record.body_text_named_params;
|
|
86
|
+
if (Array.isArray(named) && named[fallbackIndex]) {
|
|
87
|
+
const row = asRecord(named[fallbackIndex]);
|
|
88
|
+
if (row.example != null)
|
|
89
|
+
return String(row.example);
|
|
90
|
+
}
|
|
91
|
+
const headerNamed = record.header_text_named_params;
|
|
92
|
+
if (Array.isArray(headerNamed) && headerNamed[fallbackIndex]) {
|
|
93
|
+
const row = asRecord(headerNamed[fallbackIndex]);
|
|
94
|
+
if (row.example != null)
|
|
95
|
+
return String(row.example);
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
function extractPlaceholders(text) {
|
|
100
|
+
if (!text)
|
|
101
|
+
return [];
|
|
102
|
+
const found = [];
|
|
103
|
+
const seen = new Set();
|
|
104
|
+
const re = new RegExp(PLACEHOLDER_RE.source, "g");
|
|
105
|
+
let match;
|
|
106
|
+
while ((match = re.exec(text))) {
|
|
107
|
+
const token = match[1];
|
|
108
|
+
if (seen.has(token))
|
|
109
|
+
continue;
|
|
110
|
+
seen.add(token);
|
|
111
|
+
found.push(token);
|
|
112
|
+
}
|
|
113
|
+
return found;
|
|
114
|
+
}
|
|
115
|
+
function placeholderLabel(component, token, kind) {
|
|
116
|
+
if (kind === "media") {
|
|
117
|
+
if (component === "HEADER")
|
|
118
|
+
return "Mídia do cabeçalho (URL)";
|
|
119
|
+
return `Mídia (${component})`;
|
|
120
|
+
}
|
|
121
|
+
const where = component === "HEADER" ? "cabeçalho" : component === "BODY" ? "corpo" : component === "BUTTON" ? "botão" : component.toLowerCase();
|
|
122
|
+
return isNaN(Number(token)) ? `${where}: {{${token}}}` : `${where} {{${token}}}`;
|
|
123
|
+
}
|
|
124
|
+
function extractWhatsAppTemplateVariables(components) {
|
|
125
|
+
const variables = [];
|
|
126
|
+
for (const component of components) {
|
|
127
|
+
const type = String(component.type || "").toUpperCase();
|
|
128
|
+
if (type === "HEADER") {
|
|
129
|
+
const format = String(component.format || "TEXT").toUpperCase();
|
|
130
|
+
if (format === "IMAGE" || format === "VIDEO" || format === "DOCUMENT") {
|
|
131
|
+
variables.push({
|
|
132
|
+
key: "header.media",
|
|
133
|
+
component: "HEADER",
|
|
134
|
+
label: placeholderLabel("HEADER", "media", "media"),
|
|
135
|
+
example: firstExampleString(component.example),
|
|
136
|
+
kind: "media",
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (type === "HEADER" || type === "BODY") {
|
|
141
|
+
const tokens = extractPlaceholders(component.text);
|
|
142
|
+
tokens.forEach((token, order) => {
|
|
143
|
+
const index = Number(token);
|
|
144
|
+
variables.push({
|
|
145
|
+
key: `${type.toLowerCase()}.${token}`,
|
|
146
|
+
component: type,
|
|
147
|
+
index: Number.isFinite(index) ? index : order + 1,
|
|
148
|
+
name: Number.isFinite(index) ? undefined : token,
|
|
149
|
+
label: placeholderLabel(type, token, "text"),
|
|
150
|
+
example: firstExampleString(component.example, Number.isFinite(index) ? index - 1 : order),
|
|
151
|
+
kind: "text",
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (type === "BUTTONS") {
|
|
156
|
+
(component.buttons || []).forEach((button, buttonIndex) => {
|
|
157
|
+
const tokens = extractPlaceholders(button.url);
|
|
158
|
+
tokens.forEach((token, order) => {
|
|
159
|
+
const index = Number(token);
|
|
160
|
+
variables.push({
|
|
161
|
+
key: `button.${buttonIndex}.${token}`,
|
|
162
|
+
component: "BUTTON",
|
|
163
|
+
buttonIndex,
|
|
164
|
+
index: Number.isFinite(index) ? index : order + 1,
|
|
165
|
+
name: Number.isFinite(index) ? undefined : token,
|
|
166
|
+
label: `botão ${button.text || buttonIndex + 1} {{${token}}}`,
|
|
167
|
+
example: button.example?.[order],
|
|
168
|
+
kind: "text",
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return variables;
|
|
175
|
+
}
|
|
176
|
+
function applyWhatsAppTemplateValues(text, values, prefix) {
|
|
177
|
+
if (!text)
|
|
178
|
+
return "";
|
|
179
|
+
return text.replace(PLACEHOLDER_RE, (_full, token) => {
|
|
180
|
+
const exact = values[`${prefix}.${token}`];
|
|
181
|
+
if (exact != null && exact !== "")
|
|
182
|
+
return exact;
|
|
183
|
+
const byToken = values[token];
|
|
184
|
+
if (byToken != null && byToken !== "")
|
|
185
|
+
return byToken;
|
|
186
|
+
return `{{${token}}}`;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function renderWhatsAppTemplateContent(template, values = {}) {
|
|
190
|
+
const parts = [];
|
|
191
|
+
for (const component of template.components || []) {
|
|
192
|
+
const type = String(component.type || "").toUpperCase();
|
|
193
|
+
if (type === "HEADER") {
|
|
194
|
+
const format = String(component.format || "TEXT").toUpperCase();
|
|
195
|
+
if (format === "TEXT") {
|
|
196
|
+
const text = applyWhatsAppTemplateValues(component.text, values, "header");
|
|
197
|
+
if (text)
|
|
198
|
+
parts.push(text);
|
|
199
|
+
}
|
|
200
|
+
else if (values["header.media"]) {
|
|
201
|
+
parts.push(values["header.media"]);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (type === "BODY") {
|
|
205
|
+
const text = applyWhatsAppTemplateValues(component.text, values, "body");
|
|
206
|
+
if (text)
|
|
207
|
+
parts.push(text);
|
|
208
|
+
}
|
|
209
|
+
if (type === "FOOTER" && component.text) {
|
|
210
|
+
parts.push(component.text);
|
|
211
|
+
}
|
|
212
|
+
if (type === "BUTTONS") {
|
|
213
|
+
for (const button of component.buttons || []) {
|
|
214
|
+
if (button.text)
|
|
215
|
+
parts.push(button.text);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return parts.join("\n\n").trim() || template.name;
|
|
220
|
+
}
|
|
221
|
+
function buildWhatsAppSendComponents(template, values = {}) {
|
|
222
|
+
const named = String(template.parameterFormat || "").toUpperCase() === "NAMED";
|
|
223
|
+
const payload = [];
|
|
224
|
+
for (const component of template.components || []) {
|
|
225
|
+
const type = String(component.type || "").toUpperCase();
|
|
226
|
+
if (type === "HEADER") {
|
|
227
|
+
const format = String(component.format || "TEXT").toUpperCase();
|
|
228
|
+
if (format === "IMAGE" || format === "VIDEO" || format === "DOCUMENT") {
|
|
229
|
+
const link = values["header.media"];
|
|
230
|
+
if (link) {
|
|
231
|
+
const mediaType = format.toLowerCase();
|
|
232
|
+
payload.push({
|
|
233
|
+
type: "header",
|
|
234
|
+
parameters: [{ type: mediaType, [mediaType]: { link } }],
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
const tokens = extractPlaceholders(component.text);
|
|
240
|
+
if (!tokens.length)
|
|
241
|
+
continue;
|
|
242
|
+
payload.push({
|
|
243
|
+
type: "header",
|
|
244
|
+
parameters: tokens.map((token) => parameterOf(token, values, "header", named)),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
if (type === "BODY") {
|
|
248
|
+
const tokens = extractPlaceholders(component.text);
|
|
249
|
+
if (!tokens.length)
|
|
250
|
+
continue;
|
|
251
|
+
payload.push({
|
|
252
|
+
type: "body",
|
|
253
|
+
parameters: tokens.map((token) => parameterOf(token, values, "body", named)),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (type === "BUTTONS") {
|
|
257
|
+
(component.buttons || []).forEach((button, buttonIndex) => {
|
|
258
|
+
const tokens = extractPlaceholders(button.url);
|
|
259
|
+
if (!tokens.length)
|
|
260
|
+
return;
|
|
261
|
+
payload.push({
|
|
262
|
+
type: "button",
|
|
263
|
+
sub_type: "url",
|
|
264
|
+
index: String(buttonIndex),
|
|
265
|
+
parameters: tokens.map((token) => ({
|
|
266
|
+
type: "text",
|
|
267
|
+
text: values[`button.${buttonIndex}.${token}`] || values[token] || "",
|
|
268
|
+
})),
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return payload;
|
|
274
|
+
}
|
|
275
|
+
function parameterOf(token, values, prefix, named) {
|
|
276
|
+
const text = values[`${prefix}.${token}`] || values[token] || "";
|
|
277
|
+
if (named && isNaN(Number(token))) {
|
|
278
|
+
return { type: "text", parameter_name: token, text };
|
|
279
|
+
}
|
|
280
|
+
return { type: "text", text };
|
|
281
|
+
}
|
package/dist/models/index.d.ts
CHANGED
package/dist/models/index.js
CHANGED
package/package.json
CHANGED