@rempays/shared-core 1.0.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +346 -0
  2. package/dist/auth/authorizer-example.d.ts +24 -0
  3. package/dist/auth/authorizer-example.js +51 -0
  4. package/dist/auth/index.d.ts +2 -0
  5. package/dist/auth/index.js +1 -0
  6. package/dist/auth/jwt-validator.d.ts +37 -0
  7. package/dist/auth/jwt-validator.js +101 -0
  8. package/dist/auth/types.d.ts +28 -0
  9. package/dist/auth/types.js +1 -0
  10. package/dist/cognito/cognito.service.d.ts +45 -0
  11. package/dist/cognito/cognito.service.js +180 -0
  12. package/dist/cognito/index.d.ts +2 -0
  13. package/dist/cognito/index.js +2 -0
  14. package/dist/cognito/types.d.ts +38 -0
  15. package/dist/cognito/types.js +1 -0
  16. package/dist/dynamodb/dynamodb.client.d.ts +67 -0
  17. package/dist/dynamodb/dynamodb.client.js +166 -0
  18. package/dist/dynamodb/index.d.ts +1 -0
  19. package/dist/dynamodb/index.js +1 -0
  20. package/dist/facebook-api/facebook.d.ts +83 -0
  21. package/dist/facebook-api/facebook.js +165 -0
  22. package/dist/facebook-api/http.d.ts +2 -0
  23. package/dist/facebook-api/http.js +14 -0
  24. package/dist/facebook-api/index.d.ts +2 -0
  25. package/dist/facebook-api/index.js +1 -0
  26. package/dist/http/client.d.ts +17 -0
  27. package/dist/http/client.js +46 -0
  28. package/dist/http/index.d.ts +2 -0
  29. package/dist/http/index.js +1 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.js +8 -0
  32. package/dist/s3/index.d.ts +1 -0
  33. package/dist/s3/index.js +1 -0
  34. package/dist/s3/s3.service.d.ts +29 -0
  35. package/dist/s3/s3.service.js +60 -0
  36. package/dist/textract/index.d.ts +1 -0
  37. package/dist/textract/index.js +1 -0
  38. package/dist/textract/textract.service.d.ts +14 -0
  39. package/dist/textract/textract.service.js +63 -0
  40. package/package.json +103 -0
@@ -0,0 +1,165 @@
1
+ import { getHttpClient } from "./http";
2
+ export class FacebookApi {
3
+ static async init() {
4
+ if (this.token && this.phoneNumberId && this.apiVersion)
5
+ return;
6
+ this.token = process.env.FACEBOOK_API_TOKEN || null;
7
+ this.phoneNumberId = process.env.FACEBOOK_PHONE_NUMBER_ID || null;
8
+ this.apiVersion = process.env.FACEBOOK_API_VERSION || 'v18.0';
9
+ if (!this.token || !this.phoneNumberId) {
10
+ throw new Error("Facebook API environment variables are not properly configured (FACEBOOK_API_TOKEN, FACEBOOK_PHONE_NUMBER_ID)");
11
+ }
12
+ try {
13
+ const mask = (v) => v?.length > 6 ? `${v.slice(0, 3)}***${v.slice(-3)}` : "***";
14
+ console.log("[layer-core/facebook-api] Config loaded", {
15
+ phoneNumberId: this.phoneNumberId,
16
+ apiVersion: this.apiVersion,
17
+ tokenPreview: mask(this.token),
18
+ });
19
+ }
20
+ catch { }
21
+ }
22
+ static async post(path, payload) {
23
+ await this.init();
24
+ const url = `https://graph.facebook.com/${this.apiVersion}/${this.phoneNumberId}/${path}`;
25
+ try {
26
+ const http = getHttpClient(this.token);
27
+ const { data } = await http.post(url, payload);
28
+ return data;
29
+ }
30
+ catch (err) {
31
+ const status = err?.response?.status;
32
+ const data = err?.response?.data;
33
+ const msg = `Facebook API error${status ? " " + status : ""}: ${typeof data === "string" ? data : JSON.stringify(data)}`;
34
+ throw new Error(msg);
35
+ }
36
+ }
37
+ static async sendText(params) {
38
+ const payload = {
39
+ messaging_product: "whatsapp",
40
+ recipient_type: "individual",
41
+ to: params.to,
42
+ type: "text",
43
+ text: { body: params.body, preview_url: params.previewUrl ?? true },
44
+ };
45
+ return await this.post("messages", payload);
46
+ }
47
+ static async sendTemplate(params) {
48
+ const payload = {
49
+ messaging_product: "whatsapp",
50
+ to: params.to,
51
+ type: "template",
52
+ template: {
53
+ name: params.name,
54
+ language: { code: params.languageCode },
55
+ components: params.components,
56
+ },
57
+ };
58
+ return await this.post("messages", payload);
59
+ }
60
+ static async sendInteractiveButtons(params) {
61
+ const payload = {
62
+ messaging_product: "whatsapp",
63
+ to: params.to,
64
+ type: "interactive",
65
+ interactive: {
66
+ type: "button",
67
+ header: params.header,
68
+ body: { text: params.body },
69
+ footer: params.footer ? { text: params.footer } : undefined,
70
+ action: {
71
+ buttons: params.buttons.map((b) => ({
72
+ type: "reply",
73
+ reply: { id: b.id, title: b.title },
74
+ })),
75
+ },
76
+ },
77
+ };
78
+ return await this.post("messages", payload);
79
+ }
80
+ static async sendInteractiveList(params) {
81
+ const payload = {
82
+ messaging_product: "whatsapp",
83
+ to: params.to,
84
+ type: "interactive",
85
+ interactive: {
86
+ type: "list",
87
+ body: { text: params.body },
88
+ action: {
89
+ button: params.buttonText,
90
+ sections: params.sections.map((section) => ({
91
+ title: section.title,
92
+ rows: section.rows.map((row) => ({
93
+ id: row.id,
94
+ title: row.title,
95
+ description: row.description,
96
+ })),
97
+ })),
98
+ },
99
+ },
100
+ };
101
+ if (params.header) {
102
+ payload.interactive.header = params.header;
103
+ }
104
+ if (params.footer) {
105
+ payload.interactive.footer = { text: params.footer };
106
+ }
107
+ return await this.post("messages", payload);
108
+ }
109
+ static async sendImage(params) {
110
+ const payload = {
111
+ messaging_product: "whatsapp",
112
+ to: params.to,
113
+ type: "image",
114
+ image: { link: params.link, caption: params.caption },
115
+ };
116
+ return await this.post("messages", payload);
117
+ }
118
+ static async sendDocument(params) {
119
+ const payload = {
120
+ messaging_product: "whatsapp",
121
+ to: params.to,
122
+ type: "document",
123
+ document: {
124
+ link: params.link,
125
+ caption: params.caption,
126
+ filename: params.filename,
127
+ },
128
+ };
129
+ return await this.post("messages", payload);
130
+ }
131
+ static async sendLocation(params) {
132
+ const payload = {
133
+ messaging_product: "whatsapp",
134
+ to: params.to,
135
+ type: "location",
136
+ location: {
137
+ latitude: params.latitude,
138
+ longitude: params.longitude,
139
+ name: params.name,
140
+ address: params.address,
141
+ },
142
+ };
143
+ return await this.post("messages", payload);
144
+ }
145
+ static async setTyping(params) {
146
+ const payload = {
147
+ messaging_product: "whatsapp",
148
+ status: "read",
149
+ message_id: params.messageId,
150
+ typing_indicator: { type: "text" },
151
+ };
152
+ return await this.post("messages", payload);
153
+ }
154
+ static async markAsRead(params) {
155
+ const payload = {
156
+ messaging_product: "whatsapp",
157
+ status: "read",
158
+ message_id: params.messageId,
159
+ };
160
+ return await this.post("messages", payload);
161
+ }
162
+ }
163
+ FacebookApi.token = null;
164
+ FacebookApi.phoneNumberId = null;
165
+ FacebookApi.apiVersion = null;
@@ -0,0 +1,2 @@
1
+ import { AxiosInstance } from 'axios';
2
+ export declare function getHttpClient(token: string): AxiosInstance;
@@ -0,0 +1,14 @@
1
+ import axios from 'axios';
2
+ let client = null;
3
+ export function getHttpClient(token) {
4
+ if (client)
5
+ return client;
6
+ client = axios.create({
7
+ timeout: 10000,
8
+ headers: {
9
+ 'Authorization': `Bearer ${token}`,
10
+ 'Content-Type': 'application/json',
11
+ },
12
+ });
13
+ return client;
14
+ }
@@ -0,0 +1,2 @@
1
+ export { FacebookApi } from './facebook';
2
+ export type { SendTextParams, SendTemplateParams, SendInteractiveParams, SendInteractiveListParams, SendImageParams, SendDocumentParams, SendLocationParams, SetTypingParams, MarkAsReadParams, } from './facebook';
@@ -0,0 +1 @@
1
+ export { FacebookApi } from './facebook';
@@ -0,0 +1,17 @@
1
+ import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from 'axios';
2
+ export interface HttpClientConfig extends CreateAxiosDefaults {
3
+ token?: string;
4
+ }
5
+ export declare class HttpClient {
6
+ private client;
7
+ constructor(config?: HttpClientConfig);
8
+ getInstance(): AxiosInstance;
9
+ setAuthToken(token: string): void;
10
+ removeAuthToken(): void;
11
+ get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
12
+ post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
13
+ put<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
14
+ patch<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
15
+ delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T>;
16
+ }
17
+ export declare function createHttpClient(config?: HttpClientConfig): HttpClient;
@@ -0,0 +1,46 @@
1
+ import axios from 'axios';
2
+ export class HttpClient {
3
+ constructor(config = {}) {
4
+ const { token, ...axiosConfig } = config;
5
+ this.client = axios.create({
6
+ timeout: 10000,
7
+ headers: {
8
+ ...(token && { 'Authorization': `Bearer ${token}` }),
9
+ 'Content-Type': 'application/json',
10
+ },
11
+ ...axiosConfig,
12
+ });
13
+ }
14
+ getInstance() {
15
+ return this.client;
16
+ }
17
+ setAuthToken(token) {
18
+ this.client.defaults.headers.common['Authorization'] = `Bearer ${token}`;
19
+ }
20
+ removeAuthToken() {
21
+ delete this.client.defaults.headers.common['Authorization'];
22
+ }
23
+ async get(url, config) {
24
+ const response = await this.client.get(url, config);
25
+ return response.data;
26
+ }
27
+ async post(url, data, config) {
28
+ const response = await this.client.post(url, data, config);
29
+ return response.data;
30
+ }
31
+ async put(url, data, config) {
32
+ const response = await this.client.put(url, data, config);
33
+ return response.data;
34
+ }
35
+ async patch(url, data, config) {
36
+ const response = await this.client.patch(url, data, config);
37
+ return response.data;
38
+ }
39
+ async delete(url, config) {
40
+ const response = await this.client.delete(url, config);
41
+ return response.data;
42
+ }
43
+ }
44
+ export function createHttpClient(config) {
45
+ return new HttpClient(config);
46
+ }
@@ -0,0 +1,2 @@
1
+ export { HttpClient, createHttpClient } from './client';
2
+ export type { HttpClientConfig } from './client';
@@ -0,0 +1 @@
1
+ export { HttpClient, createHttpClient } from './client';
@@ -0,0 +1,7 @@
1
+ export * from './cognito/index';
2
+ export * from './auth/index';
3
+ export * from './s3/index';
4
+ export * from './textract/index';
5
+ export * from './facebook-api/index';
6
+ export * from './dynamodb/index';
7
+ export * from './http/index';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // Export all modules
2
+ export * from './cognito/index';
3
+ export * from './auth/index';
4
+ export * from './s3/index';
5
+ export * from './textract/index';
6
+ export * from './facebook-api/index';
7
+ export * from './dynamodb/index';
8
+ export * from './http/index';
@@ -0,0 +1 @@
1
+ export * from './s3.service';
@@ -0,0 +1 @@
1
+ export * from './s3.service';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Servicio para manejar archivos en S3
3
+ * Usado para almacenar documentos antes de procesarlos con Textract
4
+ */
5
+ export declare class S3Service {
6
+ private static readonly client;
7
+ private static readonly BUCKET_NAME;
8
+ /**
9
+ * Sube un archivo a S3 desde un buffer o URL
10
+ */
11
+ static uploadFile(params: {
12
+ key: string;
13
+ body: Buffer | Uint8Array | string;
14
+ contentType?: string;
15
+ metadata?: Record<string, string>;
16
+ }): Promise<string>;
17
+ /**
18
+ * Descarga un archivo de S3
19
+ */
20
+ static downloadFile(key: string): Promise<Buffer>;
21
+ /**
22
+ * Genera una key única para un documento
23
+ */
24
+ static generateDocumentKey(params: {
25
+ chatId: string;
26
+ messageId: string;
27
+ extension?: string;
28
+ }): string;
29
+ }
@@ -0,0 +1,60 @@
1
+ import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
2
+ /**
3
+ * Servicio para manejar archivos en S3
4
+ * Usado para almacenar documentos antes de procesarlos con Textract
5
+ */
6
+ export class S3Service {
7
+ /**
8
+ * Sube un archivo a S3 desde un buffer o URL
9
+ */
10
+ static async uploadFile(params) {
11
+ try {
12
+ const command = new PutObjectCommand({
13
+ Bucket: this.BUCKET_NAME,
14
+ Key: params.key,
15
+ Body: params.body,
16
+ ContentType: params.contentType || 'application/octet-stream',
17
+ Metadata: params.metadata || {},
18
+ });
19
+ await this.client.send(command);
20
+ return `s3://${this.BUCKET_NAME}/${params.key}`;
21
+ }
22
+ catch (error) {
23
+ throw new Error(`Failed to upload file to S3: ${error instanceof Error ? error.message : 'Unknown error'}`);
24
+ }
25
+ }
26
+ /**
27
+ * Descarga un archivo de S3
28
+ */
29
+ static async downloadFile(key) {
30
+ try {
31
+ const command = new GetObjectCommand({
32
+ Bucket: this.BUCKET_NAME,
33
+ Key: key,
34
+ });
35
+ const response = await this.client.send(command);
36
+ const chunks = [];
37
+ if (response.Body) {
38
+ for await (const chunk of response.Body) {
39
+ chunks.push(chunk);
40
+ }
41
+ }
42
+ return Buffer.concat(chunks);
43
+ }
44
+ catch (error) {
45
+ throw new Error(`Failed to download file from S3: ${error instanceof Error ? error.message : 'Unknown error'}`);
46
+ }
47
+ }
48
+ /**
49
+ * Genera una key única para un documento
50
+ */
51
+ static generateDocumentKey(params) {
52
+ const timestamp = Date.now();
53
+ const extension = params.extension ? `.${params.extension}` : '';
54
+ return `chats/${params.chatId}/messages/${params.messageId}-${timestamp}${extension}`;
55
+ }
56
+ }
57
+ S3Service.client = new S3Client({
58
+ region: process.env['AWS_REGION'] || 'us-east-1',
59
+ });
60
+ S3Service.BUCKET_NAME = process.env['S3_DOCUMENTS_BUCKET'] || 'rempays-documents';
@@ -0,0 +1 @@
1
+ export * from './textract.service';
@@ -0,0 +1 @@
1
+ export * from './textract.service';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Servicio para extraer texto de documentos usando AWS Textract
3
+ */
4
+ export declare class TextractService {
5
+ private static readonly client;
6
+ /**
7
+ * Analiza un documento desde S3 y extrae el texto
8
+ */
9
+ static analyzeDocumentFromS3(s3Bucket: string, s3Key: string): Promise<string>;
10
+ /**
11
+ * Analiza un documento desde bytes (para imágenes/documentos directos)
12
+ */
13
+ static analyzeDocumentFromBytes(bytes: Uint8Array): Promise<string>;
14
+ }
@@ -0,0 +1,63 @@
1
+ import { TextractClient, AnalyzeDocumentCommand } from '@aws-sdk/client-textract';
2
+ /**
3
+ * Servicio para extraer texto de documentos usando AWS Textract
4
+ */
5
+ export class TextractService {
6
+ /**
7
+ * Analiza un documento desde S3 y extrae el texto
8
+ */
9
+ static async analyzeDocumentFromS3(s3Bucket, s3Key) {
10
+ try {
11
+ const command = new AnalyzeDocumentCommand({
12
+ Document: {
13
+ S3Object: {
14
+ Bucket: s3Bucket,
15
+ Name: s3Key,
16
+ },
17
+ },
18
+ FeatureTypes: ['FORMS', 'TABLES'],
19
+ });
20
+ const response = await this.client.send(command);
21
+ // Extraer texto de los bloques
22
+ if (!response.Blocks) {
23
+ return '';
24
+ }
25
+ const textBlocks = response.Blocks
26
+ .filter(block => block.BlockType === 'LINE' && block.Text)
27
+ .map(block => block.Text || '')
28
+ .join('\n');
29
+ return textBlocks;
30
+ }
31
+ catch (error) {
32
+ throw new Error(`Failed to analyze document with Textract: ${error instanceof Error ? error.message : 'Unknown error'}`);
33
+ }
34
+ }
35
+ /**
36
+ * Analiza un documento desde bytes (para imágenes/documentos directos)
37
+ */
38
+ static async analyzeDocumentFromBytes(bytes) {
39
+ try {
40
+ const command = new AnalyzeDocumentCommand({
41
+ Document: {
42
+ Bytes: bytes,
43
+ },
44
+ FeatureTypes: ['FORMS', 'TABLES'],
45
+ });
46
+ const response = await this.client.send(command);
47
+ if (!response.Blocks) {
48
+ return '';
49
+ }
50
+ const textBlocks = response.Blocks
51
+ .filter(block => block.BlockType === 'LINE' && block.Text)
52
+ .map(block => block.Text || '')
53
+ .join('\n');
54
+ return textBlocks;
55
+ }
56
+ catch (error) {
57
+ throw new Error(`Failed to analyze document with Textract: ${error instanceof Error ? error.message : 'Unknown error'}`);
58
+ }
59
+ }
60
+ }
61
+ TextractService.client = new TextractClient({
62
+ region: process.env['AWS_REGION'] || 'us-east-1',
63
+ });
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@rempays/shared-core",
3
+ "version": "1.0.2-beta.1",
4
+ "description": "Core utilities layer for RemPays platform with AWS services integration (Cognito, S3, Secrets Manager, Textract, Facebook API, DynamoDB)",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "type": "module",
8
+ "private": false,
9
+ "author": "RemPays Team",
10
+ "license": "UNLICENSED",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/REMpays/shared-core.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/REMpays/shared-core/issues"
17
+ },
18
+ "homepage": "https://github.com/REMpays/shared-core#readme",
19
+ "keywords": [
20
+ "aws",
21
+ "cognito",
22
+ "auth",
23
+ "jwt",
24
+ "s3",
25
+ "textract",
26
+ "dynamodb",
27
+ "facebook-api",
28
+ "whatsapp",
29
+ "lambda",
30
+ "serverless",
31
+ "rempays"
32
+ ],
33
+ "engines": {
34
+ "node": ">=18.0.0",
35
+ "npm": ">=9.0.0"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc",
39
+ "build:watch": "tsc --watch",
40
+ "prepublishOnly": "npm run build",
41
+ "dev": "tsc --watch"
42
+ },
43
+ "dependencies": {
44
+ "@aws-sdk/client-cognito-identity-provider": "^3.454.0",
45
+ "@aws-sdk/client-dynamodb": "^3.454.0",
46
+ "@aws-sdk/client-s3": "^3.454.0",
47
+ "@aws-sdk/client-textract": "^3.454.0",
48
+ "@aws-sdk/util-dynamodb": "^3.454.0",
49
+ "axios": "^1.7.7"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^20.11.0",
53
+ "typescript": "^5.3.0"
54
+ },
55
+ "files": [
56
+ "dist/**/*",
57
+ "README.md",
58
+ "LICENSE"
59
+ ],
60
+ "exports": {
61
+ ".": {
62
+ "import": "./dist/index.js",
63
+ "types": "./dist/index.d.ts"
64
+ },
65
+ "./cognito": {
66
+ "import": "./dist/cognito/index.js",
67
+ "types": "./dist/cognito/index.d.ts"
68
+ },
69
+ "./auth": {
70
+ "import": "./dist/auth/index.js",
71
+ "types": "./dist/auth/index.d.ts"
72
+ },
73
+ "./s3": {
74
+ "import": "./dist/s3/index.js",
75
+ "types": "./dist/s3/index.d.ts"
76
+ },
77
+ "./secrets": {
78
+ "import": "./dist/secrets/index.js",
79
+ "types": "./dist/secrets/index.d.ts"
80
+ },
81
+ "./textract": {
82
+ "import": "./dist/textract/index.js",
83
+ "types": "./dist/textract/index.d.ts"
84
+ },
85
+ "./facebook-api": {
86
+ "import": "./dist/facebook-api/index.js",
87
+ "types": "./dist/facebook-api/index.d.ts"
88
+ },
89
+ "./dynamodb": {
90
+ "import": "./dist/dynamodb/index.js",
91
+ "types": "./dist/dynamodb/index.d.ts"
92
+ },
93
+ "./http": {
94
+ "import": "./dist/http/index.js",
95
+ "types": "./dist/http/index.d.ts"
96
+ },
97
+ "./package.json": "./package.json"
98
+ },
99
+ "publishConfig": {
100
+ "access": "public",
101
+ "registry": "https://registry.npmjs.org/"
102
+ }
103
+ }