@rempays/shared-core 1.0.2-beta.11 → 1.0.2-beta.13
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.
|
@@ -46,12 +46,9 @@ export declare class ChatService {
|
|
|
46
46
|
listChatsByBusiness(businessId: string, status: string, params?: PaginationParams): Promise<PaginatedResult<Chat>>;
|
|
47
47
|
/**
|
|
48
48
|
* Lista todos los chats de un business (todos los status)
|
|
49
|
+
* Nota: Hace múltiples queries, una por cada status común
|
|
49
50
|
*/
|
|
50
51
|
listAllChatsByBusiness(businessId: string, params?: PaginationParams): Promise<PaginatedResult<Chat>>;
|
|
51
|
-
/**
|
|
52
|
-
* Incrementa el contador de mensajes no leídos
|
|
53
|
-
*/
|
|
54
|
-
incrementUnreadCount(chatId: string): Promise<void>;
|
|
55
52
|
/**
|
|
56
53
|
* Marca todos los mensajes como leídos
|
|
57
54
|
*/
|
|
@@ -242,48 +242,33 @@ class ChatService {
|
|
|
242
242
|
}
|
|
243
243
|
/**
|
|
244
244
|
* Lista todos los chats de un business (todos los status)
|
|
245
|
+
* Nota: Hace múltiples queries, una por cada status común
|
|
245
246
|
*/
|
|
246
247
|
async listAllChatsByBusiness(businessId, params = {}) {
|
|
247
|
-
const { limit = 20
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
248
|
+
const { limit = 20 } = params;
|
|
249
|
+
const statuses = ['active', 'closed', 'pending', 'archived'];
|
|
250
|
+
const allChats = [];
|
|
251
|
+
// Query para cada status
|
|
252
|
+
for (const status of statuses) {
|
|
253
|
+
const result = await this.listChatsByBusiness(businessId, status, {
|
|
254
|
+
limit: Math.ceil(limit / statuses.length),
|
|
255
|
+
});
|
|
256
|
+
allChats.push(...result.items);
|
|
257
|
+
// Si ya tenemos suficientes, parar
|
|
258
|
+
if (allChats.length >= limit) {
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Ordenar por lastMessageTimestamp descendente
|
|
263
|
+
allChats.sort((a, b) => b.lastMessageTimestamp - a.lastMessageTimestamp);
|
|
264
|
+
// Limitar resultados
|
|
265
|
+
const items = allChats.slice(0, limit);
|
|
264
266
|
return {
|
|
265
267
|
items,
|
|
266
|
-
lastEvaluatedKey:
|
|
267
|
-
hasMore:
|
|
268
|
+
lastEvaluatedKey: undefined,
|
|
269
|
+
hasMore: allChats.length > limit,
|
|
268
270
|
};
|
|
269
271
|
}
|
|
270
|
-
/**
|
|
271
|
-
* Incrementa el contador de mensajes no leídos
|
|
272
|
-
*/
|
|
273
|
-
async incrementUnreadCount(chatId) {
|
|
274
|
-
await this.client.send(new client_dynamodb_1.UpdateItemCommand({
|
|
275
|
-
TableName: this.tableName,
|
|
276
|
-
Key: (0, util_dynamodb_1.marshall)({
|
|
277
|
-
PK: `CHAT#${chatId}`,
|
|
278
|
-
SK: 'METADATA',
|
|
279
|
-
}),
|
|
280
|
-
UpdateExpression: 'SET unreadCount = if_not_exists(unreadCount, :zero) + :inc',
|
|
281
|
-
ExpressionAttributeValues: (0, util_dynamodb_1.marshall)({
|
|
282
|
-
':inc': 1,
|
|
283
|
-
':zero': 0,
|
|
284
|
-
}),
|
|
285
|
-
}));
|
|
286
|
-
}
|
|
287
272
|
/**
|
|
288
273
|
* Marca todos los mensajes como leídos
|
|
289
274
|
*/
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { SendTextParams, SendTemplateParams, SendInteractiveParams, SendInteractiveListParams, SendImageParams, SendDocumentParams, SendLocationParams, SetTypingParams, MarkAsReadParams } from
|
|
1
|
+
import type { SendTextParams, SendTemplateParams, SendInteractiveParams, SendInteractiveListParams, SendImageParams, SendDocumentParams, SendLocationParams, SetTypingParams, MarkAsReadParams, SendAudioParams, SendVideoParams, MediaInfoResponse, CreateTemplateParams } from "./types";
|
|
2
2
|
export declare class FacebookApi {
|
|
3
3
|
private static token;
|
|
4
4
|
private static phoneNumberId;
|
|
5
5
|
private static apiVersion;
|
|
6
|
+
constructor(token?: string, phoneNumberId?: string, apiVersion?: string);
|
|
6
7
|
private static init;
|
|
7
8
|
private static post;
|
|
8
9
|
static sendText(params: SendTextParams): Promise<any>;
|
|
@@ -11,7 +12,15 @@ export declare class FacebookApi {
|
|
|
11
12
|
static sendInteractiveList(params: SendInteractiveListParams): Promise<any>;
|
|
12
13
|
static sendImage(params: SendImageParams): Promise<any>;
|
|
13
14
|
static sendDocument(params: SendDocumentParams): Promise<any>;
|
|
15
|
+
static sendAudio(params: SendAudioParams): Promise<any>;
|
|
16
|
+
static sendVideo(params: SendVideoParams): Promise<any>;
|
|
14
17
|
static sendLocation(params: SendLocationParams): Promise<any>;
|
|
15
18
|
static setTyping(params: SetTypingParams): Promise<any>;
|
|
16
19
|
static markAsRead(params: MarkAsReadParams): Promise<any>;
|
|
20
|
+
static getMediaInfo(mediaId: string): Promise<MediaInfoResponse>;
|
|
21
|
+
static downloadMedia(mediaId: string): Promise<Buffer>;
|
|
22
|
+
static buildGoogleMapsUrl(latitude: number, longitude: number): string;
|
|
23
|
+
static listTemplates(wabaId: string): Promise<any>;
|
|
24
|
+
static createTemplate(params: CreateTemplateParams): Promise<any>;
|
|
25
|
+
static deleteTemplate(wabaId: string, name: string): Promise<any>;
|
|
17
26
|
}
|
|
@@ -3,12 +3,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FacebookApi = void 0;
|
|
4
4
|
const http_1 = require("./http");
|
|
5
5
|
class FacebookApi {
|
|
6
|
+
constructor(token, phoneNumberId, apiVersion) {
|
|
7
|
+
if (token)
|
|
8
|
+
FacebookApi.token = token;
|
|
9
|
+
if (phoneNumberId)
|
|
10
|
+
FacebookApi.phoneNumberId = phoneNumberId;
|
|
11
|
+
if (apiVersion)
|
|
12
|
+
FacebookApi.apiVersion = apiVersion;
|
|
13
|
+
}
|
|
6
14
|
static async init() {
|
|
7
15
|
if (this.token && this.phoneNumberId && this.apiVersion)
|
|
8
16
|
return;
|
|
9
|
-
this.token = process.env.FACEBOOK_API_TOKEN || null;
|
|
10
|
-
this.phoneNumberId =
|
|
11
|
-
|
|
17
|
+
this.token = this.token || process.env.FACEBOOK_API_TOKEN || null;
|
|
18
|
+
this.phoneNumberId =
|
|
19
|
+
this.phoneNumberId || process.env.FACEBOOK_PHONE_NUMBER_ID || null;
|
|
20
|
+
this.apiVersion =
|
|
21
|
+
this.apiVersion || process.env.FACEBOOK_API_VERSION || "v18.0";
|
|
12
22
|
if (!this.token || !this.phoneNumberId) {
|
|
13
23
|
throw new Error("Facebook API environment variables are not properly configured (FACEBOOK_API_TOKEN, FACEBOOK_PHONE_NUMBER_ID)");
|
|
14
24
|
}
|
|
@@ -37,16 +47,25 @@ class FacebookApi {
|
|
|
37
47
|
throw new Error(msg);
|
|
38
48
|
}
|
|
39
49
|
}
|
|
50
|
+
/*
|
|
51
|
+
TEXT
|
|
52
|
+
*/
|
|
40
53
|
static async sendText(params) {
|
|
41
54
|
const payload = {
|
|
42
55
|
messaging_product: "whatsapp",
|
|
43
56
|
recipient_type: "individual",
|
|
44
57
|
to: params.to,
|
|
45
58
|
type: "text",
|
|
46
|
-
text: {
|
|
59
|
+
text: {
|
|
60
|
+
body: params.body,
|
|
61
|
+
preview_url: params.previewUrl ?? true,
|
|
62
|
+
},
|
|
47
63
|
};
|
|
48
64
|
return await this.post("messages", payload);
|
|
49
65
|
}
|
|
66
|
+
/*
|
|
67
|
+
TEMPLATE
|
|
68
|
+
*/
|
|
50
69
|
static async sendTemplate(params) {
|
|
51
70
|
const payload = {
|
|
52
71
|
messaging_product: "whatsapp",
|
|
@@ -60,6 +79,9 @@ class FacebookApi {
|
|
|
60
79
|
};
|
|
61
80
|
return await this.post("messages", payload);
|
|
62
81
|
}
|
|
82
|
+
/*
|
|
83
|
+
BUTTONS
|
|
84
|
+
*/
|
|
63
85
|
static async sendInteractiveButtons(params) {
|
|
64
86
|
const payload = {
|
|
65
87
|
messaging_product: "whatsapp",
|
|
@@ -80,6 +102,9 @@ class FacebookApi {
|
|
|
80
102
|
};
|
|
81
103
|
return await this.post("messages", payload);
|
|
82
104
|
}
|
|
105
|
+
/*
|
|
106
|
+
LIST
|
|
107
|
+
*/
|
|
83
108
|
static async sendInteractiveList(params) {
|
|
84
109
|
const payload = {
|
|
85
110
|
messaging_product: "whatsapp",
|
|
@@ -109,6 +134,9 @@ class FacebookApi {
|
|
|
109
134
|
}
|
|
110
135
|
return await this.post("messages", payload);
|
|
111
136
|
}
|
|
137
|
+
/*
|
|
138
|
+
IMAGE
|
|
139
|
+
*/
|
|
112
140
|
static async sendImage(params) {
|
|
113
141
|
const payload = {
|
|
114
142
|
messaging_product: "whatsapp",
|
|
@@ -118,6 +146,9 @@ class FacebookApi {
|
|
|
118
146
|
};
|
|
119
147
|
return await this.post("messages", payload);
|
|
120
148
|
}
|
|
149
|
+
/*
|
|
150
|
+
DOCUMENT
|
|
151
|
+
*/
|
|
121
152
|
static async sendDocument(params) {
|
|
122
153
|
const payload = {
|
|
123
154
|
messaging_product: "whatsapp",
|
|
@@ -131,6 +162,38 @@ class FacebookApi {
|
|
|
131
162
|
};
|
|
132
163
|
return await this.post("messages", payload);
|
|
133
164
|
}
|
|
165
|
+
/*
|
|
166
|
+
AUDIO (NEW)
|
|
167
|
+
*/
|
|
168
|
+
static async sendAudio(params) {
|
|
169
|
+
const payload = {
|
|
170
|
+
messaging_product: "whatsapp",
|
|
171
|
+
to: params.to,
|
|
172
|
+
type: "audio",
|
|
173
|
+
audio: {
|
|
174
|
+
link: params.link,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
return await this.post("messages", payload);
|
|
178
|
+
}
|
|
179
|
+
/*
|
|
180
|
+
VIDEO (NEW)
|
|
181
|
+
*/
|
|
182
|
+
static async sendVideo(params) {
|
|
183
|
+
const payload = {
|
|
184
|
+
messaging_product: "whatsapp",
|
|
185
|
+
to: params.to,
|
|
186
|
+
type: "video",
|
|
187
|
+
video: {
|
|
188
|
+
link: params.link,
|
|
189
|
+
caption: params.caption,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
return await this.post("messages", payload);
|
|
193
|
+
}
|
|
194
|
+
/*
|
|
195
|
+
LOCATION
|
|
196
|
+
*/
|
|
134
197
|
static async sendLocation(params) {
|
|
135
198
|
const payload = {
|
|
136
199
|
messaging_product: "whatsapp",
|
|
@@ -145,6 +208,9 @@ class FacebookApi {
|
|
|
145
208
|
};
|
|
146
209
|
return await this.post("messages", payload);
|
|
147
210
|
}
|
|
211
|
+
/*
|
|
212
|
+
TYPING
|
|
213
|
+
*/
|
|
148
214
|
static async setTyping(params) {
|
|
149
215
|
const payload = {
|
|
150
216
|
messaging_product: "whatsapp",
|
|
@@ -154,6 +220,9 @@ class FacebookApi {
|
|
|
154
220
|
};
|
|
155
221
|
return await this.post("messages", payload);
|
|
156
222
|
}
|
|
223
|
+
/*
|
|
224
|
+
READ
|
|
225
|
+
*/
|
|
157
226
|
static async markAsRead(params) {
|
|
158
227
|
const payload = {
|
|
159
228
|
messaging_product: "whatsapp",
|
|
@@ -162,6 +231,68 @@ class FacebookApi {
|
|
|
162
231
|
};
|
|
163
232
|
return await this.post("messages", payload);
|
|
164
233
|
}
|
|
234
|
+
/*
|
|
235
|
+
MEDIA INFO (NEW)
|
|
236
|
+
*/
|
|
237
|
+
static async getMediaInfo(mediaId) {
|
|
238
|
+
await this.init();
|
|
239
|
+
const http = (0, http_1.getHttpClient)(this.token);
|
|
240
|
+
const url = `https://graph.facebook.com/${this.apiVersion}/${mediaId}`;
|
|
241
|
+
const { data } = await http.get(url);
|
|
242
|
+
return data;
|
|
243
|
+
}
|
|
244
|
+
/*
|
|
245
|
+
DOWNLOAD MEDIA (NEW)
|
|
246
|
+
*/
|
|
247
|
+
static async downloadMedia(mediaId) {
|
|
248
|
+
await this.init();
|
|
249
|
+
const media = await this.getMediaInfo(mediaId);
|
|
250
|
+
const http = (0, http_1.getHttpClient)(this.token);
|
|
251
|
+
const { data } = await http.get(media.url, {
|
|
252
|
+
responseType: "arraybuffer",
|
|
253
|
+
});
|
|
254
|
+
return data;
|
|
255
|
+
}
|
|
256
|
+
/*
|
|
257
|
+
GOOGLE MAP URL (NEW)
|
|
258
|
+
*/
|
|
259
|
+
static buildGoogleMapsUrl(latitude, longitude) {
|
|
260
|
+
return `https://www.google.com/maps?q=${latitude},${longitude}`;
|
|
261
|
+
}
|
|
262
|
+
static async listTemplates(wabaId) {
|
|
263
|
+
await this.init();
|
|
264
|
+
const http = (0, http_1.getHttpClient)(this.token);
|
|
265
|
+
const url = `https://graph.facebook.com/${this.apiVersion}/${wabaId}/message_templates`;
|
|
266
|
+
const { data } = await http.get(url);
|
|
267
|
+
return data;
|
|
268
|
+
}
|
|
269
|
+
static async createTemplate(params) {
|
|
270
|
+
await this.init();
|
|
271
|
+
const http = (0, http_1.getHttpClient)(this.token);
|
|
272
|
+
const url = `https://graph.facebook.com/${this.apiVersion}/${params.wabaId}/message_templates`;
|
|
273
|
+
const payload = {
|
|
274
|
+
name: params.name,
|
|
275
|
+
category: params.category,
|
|
276
|
+
language: params.language,
|
|
277
|
+
components: [
|
|
278
|
+
{
|
|
279
|
+
type: "BODY",
|
|
280
|
+
text: params.bodyText
|
|
281
|
+
}
|
|
282
|
+
]
|
|
283
|
+
};
|
|
284
|
+
const { data } = await http.post(url, payload);
|
|
285
|
+
return data;
|
|
286
|
+
}
|
|
287
|
+
static async deleteTemplate(wabaId, name) {
|
|
288
|
+
await this.init();
|
|
289
|
+
const http = (0, http_1.getHttpClient)(this.token);
|
|
290
|
+
const url = `https://graph.facebook.com/${this.apiVersion}/${wabaId}/message_templates`;
|
|
291
|
+
const { data } = await http.delete(url, {
|
|
292
|
+
params: { name }
|
|
293
|
+
});
|
|
294
|
+
return data;
|
|
295
|
+
}
|
|
165
296
|
}
|
|
166
297
|
exports.FacebookApi = FacebookApi;
|
|
167
298
|
FacebookApi.token = null;
|
|
@@ -7,7 +7,13 @@ export interface SendTemplateParams {
|
|
|
7
7
|
to: string;
|
|
8
8
|
name: string;
|
|
9
9
|
languageCode: string;
|
|
10
|
-
components?:
|
|
10
|
+
components?: Array<{
|
|
11
|
+
type: "header" | "body" | "button";
|
|
12
|
+
parameters?: Array<{
|
|
13
|
+
type: "text" | "image" | "document" | "video";
|
|
14
|
+
text?: string;
|
|
15
|
+
}>;
|
|
16
|
+
}>;
|
|
11
17
|
}
|
|
12
18
|
export interface SendInteractiveParams {
|
|
13
19
|
to: string;
|
|
@@ -107,3 +113,25 @@ export interface PhoneNumberInfo {
|
|
|
107
113
|
quality_rating?: string;
|
|
108
114
|
code_verification_status?: string;
|
|
109
115
|
}
|
|
116
|
+
export interface SendAudioParams {
|
|
117
|
+
to: string;
|
|
118
|
+
link: string;
|
|
119
|
+
}
|
|
120
|
+
export interface SendVideoParams {
|
|
121
|
+
to: string;
|
|
122
|
+
link: string;
|
|
123
|
+
caption?: string;
|
|
124
|
+
}
|
|
125
|
+
export interface MediaInfoResponse {
|
|
126
|
+
url: string;
|
|
127
|
+
mime_type: string;
|
|
128
|
+
sha256: string;
|
|
129
|
+
file_size: number;
|
|
130
|
+
}
|
|
131
|
+
export interface CreateTemplateParams {
|
|
132
|
+
wabaId: string;
|
|
133
|
+
name: string;
|
|
134
|
+
category: "MARKETING" | "UTILITY" | "AUTHENTICATION";
|
|
135
|
+
language: string;
|
|
136
|
+
bodyText: string;
|
|
137
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rempays/shared-core",
|
|
3
|
-
"version": "1.0.2-beta.
|
|
3
|
+
"version": "1.0.2-beta.13",
|
|
4
4
|
"description": "Core utilities layer for RemPays platform with AWS services integration (Cognito, S3, Secrets Manager, Textract, Facebook API, DynamoDB)",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"build": "tsc",
|
|
39
39
|
"build:watch": "tsc --watch",
|
|
40
40
|
"prepublishOnly": "npm run build",
|
|
41
|
-
"dev": "tsc --watch"
|
|
41
|
+
"dev": "tsc --watch",
|
|
42
|
+
"test:chat": "tsx examples/test-chat-service.ts"
|
|
42
43
|
},
|
|
43
44
|
"dependencies": {
|
|
44
45
|
"@aws-sdk/client-cognito-identity-provider": "^3.454.0",
|
|
@@ -50,6 +51,8 @@
|
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@types/node": "^20.11.0",
|
|
54
|
+
"dotenv": "^17.3.1",
|
|
55
|
+
"tsx": "^4.7.0",
|
|
53
56
|
"typescript": "^5.3.0"
|
|
54
57
|
},
|
|
55
58
|
"files": [
|