@runnerpro/backend 1.17.6 → 1.17.7
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/README.md +82 -82
- package/lib/cjs/chat/api/conversation.js +4 -4
- package/lib/cjs/chat/api/listConversations.js +12 -12
- package/lib/cjs/chat/saveResponseTime.js +5 -5
- package/lib/cjs/chat/utils/getCountNotificaciones.js +12 -12
- package/lib/cjs/mediaProcessing/index.js +11 -16
- package/lib/cjs/prompt/index.js +1 -1
- package/lib/cjs/sendMail/index.js +65 -65
- package/lib/cjs/types/mediaProcessing/index.d.ts.map +1 -1
- package/package.json +81 -81
package/README.md
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
# modern-npm-package
|
|
2
|
-
|
|
3
|
-
An npm packages for common backend logic between client and dashboard app.
|
|
4
|
-
|
|
5
|
-
## Get Started
|
|
6
|
-
|
|
7
|
-
1. Run `npm install @runnerpro/backend`
|
|
8
|
-
|
|
9
|
-
## Functions
|
|
10
|
-
|
|
11
|
-
### query
|
|
12
|
-
|
|
13
|
-
Connection with the PostgresSQL database
|
|
14
|
-
|
|
15
|
-
- <b>Param</b>: string with PostgreSQL query
|
|
16
|
-
- <b>Param</b>: array of values
|
|
17
|
-
- <b>Return</b>: promise of array of values (each item is a row of the table)
|
|
18
|
-
|
|
19
|
-
### batchQuery
|
|
20
|
-
|
|
21
|
-
Connection with PostgreSQL database in batches. Use for faster query execution when we need to execute many queries.
|
|
22
|
-
|
|
23
|
-
- <b>Param</b>: Array of queries
|
|
24
|
-
- query: string with PostgreSQL query
|
|
25
|
-
- values: array of values
|
|
26
|
-
- <b>Param?</b>: length of promises wait together. Default 5
|
|
27
|
-
- <b>Return</b>: promise (without values)
|
|
28
|
-
|
|
29
|
-
### sendMail
|
|
30
|
-
|
|
31
|
-
Send mail with company logo and template
|
|
32
|
-
|
|
33
|
-
- <b>Param</b>: { subject, title, body, to, link?, attachments?, bcc? }
|
|
34
|
-
|
|
35
|
-
- subject: title of the mail
|
|
36
|
-
- body: text inside card
|
|
37
|
-
- to: array of mails. In DEV and SBX the value is taken from .env GMAIL_EMAIL_USER
|
|
38
|
-
- link: button to redirect to the app. { text: text inside button, url: path (after runnerpro.com) }
|
|
39
|
-
- attachments: array of files to attach. { filename: name and extension of file, path: path of file, cid?: identifier to insert inside the body (`<img src="cid:__cid__" />`) }
|
|
40
|
-
- bcc: array of mails to send via bcc
|
|
41
|
-
|
|
42
|
-
- <b>Return</b>: promise (without values)
|
|
43
|
-
|
|
44
|
-
### sendNotification
|
|
45
|
-
|
|
46
|
-
Send web or native notification to client: TODO
|
|
47
|
-
|
|
48
|
-
- <b>Param</b>: Array of queries { query: string with PostgreSQL query, values: array of values }
|
|
49
|
-
- <b>Param?</b>: length of promises wait together. Default 5
|
|
50
|
-
- <b>Return</b>: promise (without values)
|
|
51
|
-
|
|
52
|
-
### sleep
|
|
53
|
-
|
|
54
|
-
Wait X miliseconds to execute next line
|
|
55
|
-
|
|
56
|
-
- <b>Param</b>: number of miliseconds of the promise
|
|
57
|
-
- <b>Return</b>: promise (without values)
|
|
58
|
-
|
|
59
|
-
## Deploy new version
|
|
60
|
-
|
|
61
|
-
1. Create a folder with the name of functionality and index.ts inside. Write the function and export it.
|
|
62
|
-
2. In main index.ts (the one inside src), import and export it
|
|
63
|
-
3. Change the version number of the package ([using this convenction](https://docs.npmjs.com/about-semantic-versioning))
|
|
64
|
-
4. Run `npm login`
|
|
65
|
-
5. Run `npm run publish`
|
|
66
|
-
|
|
67
|
-
### Testing
|
|
68
|
-
|
|
69
|
-
1. Install developer dependencies using the following command in your terminal `npm i -D mocha @types/mocha chai @types/chai ts-node`
|
|
70
|
-
1. Create a new file `.mocharc.json` in the root directory with the following contents:
|
|
71
|
-
```json
|
|
72
|
-
{
|
|
73
|
-
"extension": ["ts"],
|
|
74
|
-
"spec": "./**/*.spec.ts",
|
|
75
|
-
"require": "ts-node/register"
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
1. Create a `tests` folder
|
|
79
|
-
1. Create an `index.spec.ts` file in the `tests` folder
|
|
80
|
-
1. Write unit tests in the `index.spec.ts` file to test the code in `index.ts`
|
|
81
|
-
1. Add a `"test"` property in the `package.json` file and give it a value of `"mocha"`
|
|
82
|
-
1. Run `npm test` in your terminal from the root folder of the project
|
|
1
|
+
# modern-npm-package
|
|
2
|
+
|
|
3
|
+
An npm packages for common backend logic between client and dashboard app.
|
|
4
|
+
|
|
5
|
+
## Get Started
|
|
6
|
+
|
|
7
|
+
1. Run `npm install @runnerpro/backend`
|
|
8
|
+
|
|
9
|
+
## Functions
|
|
10
|
+
|
|
11
|
+
### query
|
|
12
|
+
|
|
13
|
+
Connection with the PostgresSQL database
|
|
14
|
+
|
|
15
|
+
- <b>Param</b>: string with PostgreSQL query
|
|
16
|
+
- <b>Param</b>: array of values
|
|
17
|
+
- <b>Return</b>: promise of array of values (each item is a row of the table)
|
|
18
|
+
|
|
19
|
+
### batchQuery
|
|
20
|
+
|
|
21
|
+
Connection with PostgreSQL database in batches. Use for faster query execution when we need to execute many queries.
|
|
22
|
+
|
|
23
|
+
- <b>Param</b>: Array of queries
|
|
24
|
+
- query: string with PostgreSQL query
|
|
25
|
+
- values: array of values
|
|
26
|
+
- <b>Param?</b>: length of promises wait together. Default 5
|
|
27
|
+
- <b>Return</b>: promise (without values)
|
|
28
|
+
|
|
29
|
+
### sendMail
|
|
30
|
+
|
|
31
|
+
Send mail with company logo and template
|
|
32
|
+
|
|
33
|
+
- <b>Param</b>: { subject, title, body, to, link?, attachments?, bcc? }
|
|
34
|
+
|
|
35
|
+
- subject: title of the mail
|
|
36
|
+
- body: text inside card
|
|
37
|
+
- to: array of mails. In DEV and SBX the value is taken from .env GMAIL_EMAIL_USER
|
|
38
|
+
- link: button to redirect to the app. { text: text inside button, url: path (after runnerpro.com) }
|
|
39
|
+
- attachments: array of files to attach. { filename: name and extension of file, path: path of file, cid?: identifier to insert inside the body (`<img src="cid:__cid__" />`) }
|
|
40
|
+
- bcc: array of mails to send via bcc
|
|
41
|
+
|
|
42
|
+
- <b>Return</b>: promise (without values)
|
|
43
|
+
|
|
44
|
+
### sendNotification
|
|
45
|
+
|
|
46
|
+
Send web or native notification to client: TODO
|
|
47
|
+
|
|
48
|
+
- <b>Param</b>: Array of queries { query: string with PostgreSQL query, values: array of values }
|
|
49
|
+
- <b>Param?</b>: length of promises wait together. Default 5
|
|
50
|
+
- <b>Return</b>: promise (without values)
|
|
51
|
+
|
|
52
|
+
### sleep
|
|
53
|
+
|
|
54
|
+
Wait X miliseconds to execute next line
|
|
55
|
+
|
|
56
|
+
- <b>Param</b>: number of miliseconds of the promise
|
|
57
|
+
- <b>Return</b>: promise (without values)
|
|
58
|
+
|
|
59
|
+
## Deploy new version
|
|
60
|
+
|
|
61
|
+
1. Create a folder with the name of functionality and index.ts inside. Write the function and export it.
|
|
62
|
+
2. In main index.ts (the one inside src), import and export it
|
|
63
|
+
3. Change the version number of the package ([using this convenction](https://docs.npmjs.com/about-semantic-versioning))
|
|
64
|
+
4. Run `npm login`
|
|
65
|
+
5. Run `npm run publish`
|
|
66
|
+
|
|
67
|
+
### Testing
|
|
68
|
+
|
|
69
|
+
1. Install developer dependencies using the following command in your terminal `npm i -D mocha @types/mocha chai @types/chai ts-node`
|
|
70
|
+
1. Create a new file `.mocharc.json` in the root directory with the following contents:
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"extension": ["ts"],
|
|
74
|
+
"spec": "./**/*.spec.ts",
|
|
75
|
+
"require": "ts-node/register"
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
1. Create a `tests` folder
|
|
79
|
+
1. Create an `index.spec.ts` file in the `tests` folder
|
|
80
|
+
1. Write unit tests in the `index.spec.ts` file to test the code in `index.ts`
|
|
81
|
+
1. Add a `"test"` property in the `package.json` file and give it a value of `"mocha"`
|
|
82
|
+
1. Run `npm test` in your terminal from the root folder of the project
|
|
@@ -472,10 +472,6 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, isClient, buc
|
|
|
472
472
|
yield bucket.file(`Chat/${file.id}`).save(file.data);
|
|
473
473
|
}
|
|
474
474
|
fs_1.default.unlinkSync(filePath);
|
|
475
|
-
// ✅ Procesar archivo multimedia en background (transcripción de audio / descripción de imagen)
|
|
476
|
-
if (req.file.mimetype.startsWith('audio/') || req.file.mimetype.startsWith('image/')) {
|
|
477
|
-
(0, mediaProcessing_1.processMediaFile)(idFile, fileData, req.file.mimetype);
|
|
478
|
-
}
|
|
479
475
|
if (!isClient) {
|
|
480
476
|
let textFile = 'Archivo adjunto';
|
|
481
477
|
if (Number(type) === 4)
|
|
@@ -494,6 +490,10 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, isClient, buc
|
|
|
494
490
|
});
|
|
495
491
|
yield updateSenderView({ userid, idCliente, idMessage: idFile });
|
|
496
492
|
}
|
|
493
|
+
// ✅ Procesar archivo multimedia en background (transcripción de audio / descripción de imagen)
|
|
494
|
+
if (req.file.mimetype.startsWith('audio/') || req.file.mimetype.startsWith('image/')) {
|
|
495
|
+
(0, mediaProcessing_1.processMediaFile)(idFile, fileData, req.file.mimetype);
|
|
496
|
+
}
|
|
497
497
|
});
|
|
498
498
|
const getThumbnailFromVideo = (videoPath, duration) => __awaiter(void 0, void 0, void 0, function* () {
|
|
499
499
|
const targetWidth = 500;
|
|
@@ -32,18 +32,18 @@ const getList = (req, res, { query, isClient }) => __awaiter(void 0, void 0, voi
|
|
|
32
32
|
else {
|
|
33
33
|
const { page } = req.query;
|
|
34
34
|
const limit = 20;
|
|
35
|
-
const list = yield query(`
|
|
36
|
-
SELECT [C].[ID], [C].[NAME],
|
|
37
|
-
[CM].[DATE], [CM].[TEXT],
|
|
38
|
-
CASE WHEN [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE] THEN 0
|
|
39
|
-
ELSE 1 END AS [READ]
|
|
40
|
-
FROM [CLIENTE] AS [C]
|
|
41
|
-
LEFT JOIN (
|
|
42
|
-
SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
|
|
43
|
-
FROM [CHAT MESSAGE]
|
|
44
|
-
) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
|
|
45
|
-
ORDER BY CASE WHEN [CM].[DATE] IS NULL THEN 1 ELSE 0 END, [CM].[DATE] DESC
|
|
46
|
-
LIMIT ? OFFSET ?
|
|
35
|
+
const list = yield query(`
|
|
36
|
+
SELECT [C].[ID], [C].[NAME],
|
|
37
|
+
[CM].[DATE], [CM].[TEXT],
|
|
38
|
+
CASE WHEN [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE] THEN 0
|
|
39
|
+
ELSE 1 END AS [READ]
|
|
40
|
+
FROM [CLIENTE] AS [C]
|
|
41
|
+
LEFT JOIN (
|
|
42
|
+
SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
|
|
43
|
+
FROM [CHAT MESSAGE]
|
|
44
|
+
) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
|
|
45
|
+
ORDER BY CASE WHEN [CM].[DATE] IS NULL THEN 1 ELSE 0 END, [CM].[DATE] DESC
|
|
46
|
+
LIMIT ? OFFSET ?
|
|
47
47
|
`, [limit, limit * page]);
|
|
48
48
|
res.send(list);
|
|
49
49
|
}
|
|
@@ -16,11 +16,11 @@ const saveResponseTime = (idCliente) => __awaiter(void 0, void 0, void 0, functi
|
|
|
16
16
|
let firstNotReadMessage;
|
|
17
17
|
// eslint-disable-next-line no-constant-condition
|
|
18
18
|
while (true) {
|
|
19
|
-
const [lastMessage] = yield (0, index_1.query)(`
|
|
20
|
-
SELECT * FROM [CHAT MESSAGE]
|
|
21
|
-
WHERE [ID CLIENTE] = ? AND [ID] < ?
|
|
22
|
-
ORDER BY [DATE] DESC
|
|
23
|
-
LIMIT 1
|
|
19
|
+
const [lastMessage] = yield (0, index_1.query)(`
|
|
20
|
+
SELECT * FROM [CHAT MESSAGE]
|
|
21
|
+
WHERE [ID CLIENTE] = ? AND [ID] < ?
|
|
22
|
+
ORDER BY [DATE] DESC
|
|
23
|
+
LIMIT 1
|
|
24
24
|
`, [idCliente, (lastNotReadMessage === null || lastNotReadMessage === void 0 ? void 0 : lastNotReadMessage.id) || 2147483646]);
|
|
25
25
|
// Si no hay más mensajes || el mensaje no es del cliente || ya tiene tiempo de respuesta => salimos del bucle
|
|
26
26
|
if (!lastMessage || (lastMessage.idSender && lastMessage.idCliente !== lastMessage.idSender) || lastMessage.tiempoRespuesta)
|
|
@@ -12,22 +12,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.getCountNotificaciones = void 0;
|
|
13
13
|
const getCountNotificaciones = ({ query, isClient, idClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
14
14
|
if (isClient) {
|
|
15
|
-
const [{ chat }] = yield query(`
|
|
16
|
-
SELECT COUNT([ID]) AS [CHAT]
|
|
17
|
-
FROM [CHAT MESSAGE]
|
|
18
|
-
WHERE [ID CLIENTE] = ? AND [READ] = FALSE AND [ID SENDER] != [ID CLIENTE]
|
|
15
|
+
const [{ chat }] = yield query(`
|
|
16
|
+
SELECT COUNT([ID]) AS [CHAT]
|
|
17
|
+
FROM [CHAT MESSAGE]
|
|
18
|
+
WHERE [ID CLIENTE] = ? AND [READ] = FALSE AND [ID SENDER] != [ID CLIENTE]
|
|
19
19
|
`, [idClient]);
|
|
20
20
|
return chat;
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
|
-
const [{ chat }] = yield query(`
|
|
24
|
-
SELECT COUNT([C].[ID]) AS [CHAT]
|
|
25
|
-
FROM [CLIENTE] AS [C]
|
|
26
|
-
LEFT JOIN (
|
|
27
|
-
SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
|
|
28
|
-
FROM [CHAT MESSAGE]
|
|
29
|
-
) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
|
|
30
|
-
WHERE [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE]
|
|
23
|
+
const [{ chat }] = yield query(`
|
|
24
|
+
SELECT COUNT([C].[ID]) AS [CHAT]
|
|
25
|
+
FROM [CLIENTE] AS [C]
|
|
26
|
+
LEFT JOIN (
|
|
27
|
+
SELECT *, ROW_NUMBER() OVER (PARTITION BY [ID CLIENTE] ORDER BY [DATE] DESC) AS [ROW]
|
|
28
|
+
FROM [CHAT MESSAGE]
|
|
29
|
+
) AS [CM] ON [CM].[ID CLIENTE] = [C].[ID] AND [CM].[ROW] = 1
|
|
30
|
+
WHERE [CM].[READ] = FALSE AND [CM].[ID SENDER] = [CM].[ID CLIENTE]
|
|
31
31
|
`);
|
|
32
32
|
return chat;
|
|
33
33
|
}
|
|
@@ -14,19 +14,14 @@ const index_1 = require("../prompt/index");
|
|
|
14
14
|
const index_2 = require("../db/index");
|
|
15
15
|
const index_3 = require("../err/index");
|
|
16
16
|
// ✅ PROMPTS PARA PROCESAMIENTO DE ARCHIVOS MULTIMEDIA
|
|
17
|
-
const AUDIO_TRANSCRIPTION_PROMPT = `Transcribe el audio de forma literal y completa en español.
|
|
18
|
-
Si el audio está en otro idioma, tradúcelo al español.
|
|
19
|
-
Devuelve ÚNICAMENTE la transcripción, sin comentarios adicionales.
|
|
17
|
+
const AUDIO_TRANSCRIPTION_PROMPT = `Transcribe el audio de forma literal y completa en español.
|
|
18
|
+
Si el audio está en otro idioma, tradúcelo al español.
|
|
19
|
+
Devuelve ÚNICAMENTE la transcripción, sin comentarios adicionales.
|
|
20
20
|
Si no puedes entender el audio o está vacío, responde: "[Audio no reconocible]"`;
|
|
21
|
-
const IMAGE_DESCRIPTION_PROMPT = `
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
2. **Información relevante**: si es una captura de datos, extrae los valores importantes (ritmo, distancia, frecuencia cardíaca, zonas, etc.)
|
|
26
|
-
3. **Contexto útil para el entrenador**: cualquier información que ayude a entender el estado del atleta o su entrenamiento.
|
|
27
|
-
|
|
28
|
-
Devuelve una descripción concisa y útil en español (máximo 300 palabras).
|
|
29
|
-
Si la imagen no está relacionada con deporte/fitness, descríbela brevemente.`;
|
|
21
|
+
const IMAGE_DESCRIPTION_PROMPT = `Describe esta imagen de forma directa y completa en un solo párrafo continuo, sin introducciones ni listas.
|
|
22
|
+
Si la imagen es de contenido deportivo (captura de Garmin/Strava/reloj deportivo, foto de lesión/dolor, gráfica de entrenamiento, selfie deportivo, foto de equipamiento, datos de entrenamiento, etc.), incluye el tipo de imagen, los datos relevantes si es una captura (ritmo, distancia, frecuencia cardíaca, zonas, etc.), y cualquier contexto útil para entender el estado del atleta o su entrenamiento.
|
|
23
|
+
Si la imagen NO es deportiva, describe su contenido de forma general pero útil para entender el contexto de la conversación.
|
|
24
|
+
Devuelve ÚNICAMENTE la descripción en español, sin comentarios adicionales ni formato de lista. Máximo 300 palabras.`;
|
|
30
25
|
/**
|
|
31
26
|
* Transcribe un archivo de audio usando Gemini (Vertex AI)
|
|
32
27
|
*
|
|
@@ -140,10 +135,10 @@ const reprocessRecentMedia = (bucket) => __awaiter(void 0, void 0, void 0, funct
|
|
|
140
135
|
let errors = 0;
|
|
141
136
|
try {
|
|
142
137
|
// ✅ Buscar mensajes de los últimos 2 días con MIMETYPE de audio/imagen y sin FILE TEXT
|
|
143
|
-
const messages = yield (0, index_2.query)(`SELECT "ID", "MIMETYPE" FROM "CHAT MESSAGE"
|
|
144
|
-
WHERE "DATE" >= NOW() - INTERVAL '2 days'
|
|
145
|
-
AND "FILE TEXT" IS NULL
|
|
146
|
-
AND ("MIMETYPE" LIKE 'audio/%' OR "MIMETYPE" LIKE 'image/%')
|
|
138
|
+
const messages = yield (0, index_2.query)(`SELECT "ID", "MIMETYPE" FROM "CHAT MESSAGE"
|
|
139
|
+
WHERE "DATE" >= NOW() - INTERVAL '2 days'
|
|
140
|
+
AND "FILE TEXT" IS NULL
|
|
141
|
+
AND ("MIMETYPE" LIKE 'audio/%' OR "MIMETYPE" LIKE 'image/%')
|
|
147
142
|
ORDER BY "DATE" DESC`, []);
|
|
148
143
|
// eslint-disable-next-line no-console
|
|
149
144
|
console.log(`[reprocessRecentMedia] Encontrados ${messages.length} mensajes para procesar`);
|
package/lib/cjs/prompt/index.js
CHANGED
|
@@ -56,7 +56,7 @@ function sendPrompt(prompt, model = 'FLASH', systemPrompt = undefined, media = u
|
|
|
56
56
|
if (model === 'LITE')
|
|
57
57
|
modelGemini = 'gemini-2.5-flash-lite';
|
|
58
58
|
else if (model === 'PRO')
|
|
59
|
-
modelGemini = 'gemini-
|
|
59
|
+
modelGemini = 'gemini-3-pro-preview'; // Modelo más potente y estable
|
|
60
60
|
else
|
|
61
61
|
modelGemini = 'gemini-2.5-flash';
|
|
62
62
|
// Configura el modelo generativo
|
|
@@ -45,72 +45,72 @@ const sendMail = ({ subject, title, body, to, link, attachments, bcc }) => __awa
|
|
|
45
45
|
});
|
|
46
46
|
exports.sendMail = sendMail;
|
|
47
47
|
function getBodyHTML(title, body, link) {
|
|
48
|
-
return `
|
|
49
|
-
<html lang="es">
|
|
50
|
-
<head>
|
|
51
|
-
<meta charset="UTF-8">
|
|
52
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
53
|
-
<title>Correo con estilo</title>
|
|
54
|
-
<style>
|
|
55
|
-
/* Estilos generales */
|
|
56
|
-
body {
|
|
57
|
-
margin: 0;
|
|
58
|
-
padding: 0;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/* Estilos específicos del botón */
|
|
62
|
-
.button {
|
|
63
|
-
display: inline-block;
|
|
64
|
-
padding: 12px 26px;
|
|
65
|
-
font-size: 17px;
|
|
66
|
-
text-align: center;
|
|
67
|
-
text-decoration: none;
|
|
68
|
-
background-color: #ea5b1b;
|
|
69
|
-
color: #ffffff !important;
|
|
70
|
-
margin: 40px 0 20px 0;
|
|
71
|
-
font-family: 'Sofia Sans', 'Roboto', sans-serif;
|
|
72
|
-
font-weight: bold;
|
|
73
|
-
border-radius: 4px;
|
|
74
|
-
border: 2px solid #ea5b1b;
|
|
75
|
-
}
|
|
76
|
-
</style>
|
|
77
|
-
</head>
|
|
78
|
-
<body style="background: #f0f0f0; padding: 0 0 40px 0">
|
|
79
|
-
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0">
|
|
80
|
-
<tr>
|
|
81
|
-
<td align="center" style="padding:0;">
|
|
82
|
-
<table role="presentation" style="width:100%;border-collapse:collapse;border-spacing:0;text-align:left;">
|
|
83
|
-
<tr>
|
|
84
|
-
<td align="center" style="padding:5px 0 0 0;background:#ea5b1b;">
|
|
85
|
-
<img src="cid:logo" alt="" width="220" style="height:auto;display:block;">
|
|
86
|
-
</td>
|
|
87
|
-
</tr>
|
|
88
|
-
<tr>
|
|
89
|
-
<td style="padding:20px 24px 0px 24px; max-width: 600px" align="center">
|
|
90
|
-
<h1 style="font-size:22px;text-align:center;margin:16px 0 6px 0;font-family:'Sofia Sans', 'Roboto', sans-serif;font-style: italic">
|
|
91
|
-
${title || ''}
|
|
92
|
-
</h1>
|
|
93
|
-
<p style="text-align:left;margin:0 0 12px 0;font-size:15px;line-height:24px;font-family:'Sofia Sans', 'Roboto', sans-serif;">
|
|
94
|
-
${body.split('\n').join('<br>')}
|
|
95
|
-
</p>
|
|
48
|
+
return `
|
|
49
|
+
<html lang="es">
|
|
50
|
+
<head>
|
|
51
|
+
<meta charset="UTF-8">
|
|
52
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
53
|
+
<title>Correo con estilo</title>
|
|
54
|
+
<style>
|
|
55
|
+
/* Estilos generales */
|
|
56
|
+
body {
|
|
57
|
+
margin: 0;
|
|
58
|
+
padding: 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Estilos específicos del botón */
|
|
62
|
+
.button {
|
|
63
|
+
display: inline-block;
|
|
64
|
+
padding: 12px 26px;
|
|
65
|
+
font-size: 17px;
|
|
66
|
+
text-align: center;
|
|
67
|
+
text-decoration: none;
|
|
68
|
+
background-color: #ea5b1b;
|
|
69
|
+
color: #ffffff !important;
|
|
70
|
+
margin: 40px 0 20px 0;
|
|
71
|
+
font-family: 'Sofia Sans', 'Roboto', sans-serif;
|
|
72
|
+
font-weight: bold;
|
|
73
|
+
border-radius: 4px;
|
|
74
|
+
border: 2px solid #ea5b1b;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
77
|
+
</head>
|
|
78
|
+
<body style="background: #f0f0f0; padding: 0 0 40px 0">
|
|
79
|
+
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0">
|
|
80
|
+
<tr>
|
|
81
|
+
<td align="center" style="padding:0;">
|
|
82
|
+
<table role="presentation" style="width:100%;border-collapse:collapse;border-spacing:0;text-align:left;">
|
|
83
|
+
<tr>
|
|
84
|
+
<td align="center" style="padding:5px 0 0 0;background:#ea5b1b;">
|
|
85
|
+
<img src="cid:logo" alt="" width="220" style="height:auto;display:block;">
|
|
86
|
+
</td>
|
|
87
|
+
</tr>
|
|
88
|
+
<tr>
|
|
89
|
+
<td style="padding:20px 24px 0px 24px; max-width: 600px" align="center">
|
|
90
|
+
<h1 style="font-size:22px;text-align:center;margin:16px 0 6px 0;font-family:'Sofia Sans', 'Roboto', sans-serif;font-style: italic">
|
|
91
|
+
${title || ''}
|
|
92
|
+
</h1>
|
|
93
|
+
<p style="text-align:left;margin:0 0 12px 0;font-size:15px;line-height:24px;font-family:'Sofia Sans', 'Roboto', sans-serif;">
|
|
94
|
+
${body.split('\n').join('<br>')}
|
|
95
|
+
</p>
|
|
96
96
|
${link
|
|
97
|
-
? `
|
|
98
|
-
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0;">
|
|
99
|
-
<tr>
|
|
100
|
-
<td align="center" style="padding:0;">
|
|
101
|
-
<a href="${link.external ? '' : process.env.FRONTEND_URL}${link.url}" class="button" style="color:white">${link.text}</a>
|
|
102
|
-
</td>
|
|
103
|
-
</tr>
|
|
104
|
-
</table>
|
|
97
|
+
? `
|
|
98
|
+
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#f0f0f0;">
|
|
99
|
+
<tr>
|
|
100
|
+
<td align="center" style="padding:0;">
|
|
101
|
+
<a href="${link.external ? '' : process.env.FRONTEND_URL}${link.url}" class="button" style="color:white">${link.text}</a>
|
|
102
|
+
</td>
|
|
103
|
+
</tr>
|
|
104
|
+
</table>
|
|
105
105
|
`
|
|
106
|
-
: ''}
|
|
107
|
-
</td>
|
|
108
|
-
</tr>
|
|
109
|
-
</table>
|
|
110
|
-
</td>
|
|
111
|
-
</tr>
|
|
112
|
-
</table>
|
|
113
|
-
</body>
|
|
114
|
-
</html>
|
|
106
|
+
: ''}
|
|
107
|
+
</td>
|
|
108
|
+
</tr>
|
|
109
|
+
</table>
|
|
110
|
+
</td>
|
|
111
|
+
</tr>
|
|
112
|
+
</table>
|
|
113
|
+
</body>
|
|
114
|
+
</html>
|
|
115
115
|
`;
|
|
116
116
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mediaProcessing/index.ts"],"names":[],"mappings":";AAgBA;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,eAAe,eAAsB,MAAM,YAAY,MAAM,KAAG,QAAQ,MAAM,CAanF,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,QAAA,MAAM,aAAa,eAAsB,MAAM,YAAY,MAAM,KAAG,QAAQ,MAAM,CAajF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,gBAAgB,cAAqB,MAAM,cAAc,MAAM,YAAY,MAAM,KAAG,QAAQ,IAAI,CAkBrG,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,oBAAoB,WAAkB,GAAG;eAAwB,MAAM;YAAU,MAAM;EAwD5F,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@runnerpro/backend",
|
|
3
|
-
"version": "1.17.
|
|
4
|
-
"description": "A collection of common backend functions",
|
|
5
|
-
"exports": {
|
|
6
|
-
".": "./lib/cjs/index.js"
|
|
7
|
-
},
|
|
8
|
-
"types": "./lib/cjs/types/index.d.ts",
|
|
9
|
-
"main": "./lib/cjs/index.js",
|
|
10
|
-
"files": [
|
|
11
|
-
"lib/**/*"
|
|
12
|
-
],
|
|
13
|
-
"scripts": {
|
|
14
|
-
"clean": "del-cli ./lib",
|
|
15
|
-
"build": "npm run clean && tsc -p ./configs/tsconfig.cjs.json",
|
|
16
|
-
"deploy": "npm run build && npm publish",
|
|
17
|
-
"semantic-release": "semantic-release",
|
|
18
|
-
"lint": "eslint --ext .ts --ignore-path .gitignore .",
|
|
19
|
-
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
20
|
-
"prepare": "husky",
|
|
21
|
-
"test": "jest"
|
|
22
|
-
},
|
|
23
|
-
"release": {
|
|
24
|
-
"branches": [
|
|
25
|
-
"main"
|
|
26
|
-
]
|
|
27
|
-
},
|
|
28
|
-
"publishConfig": {
|
|
29
|
-
"access": "public"
|
|
30
|
-
},
|
|
31
|
-
"repository": {
|
|
32
|
-
"type": "git",
|
|
33
|
-
"url": "https://gitlab.com/runner-pro/runnerpro-backend.git"
|
|
34
|
-
},
|
|
35
|
-
"author": "Runner Pro",
|
|
36
|
-
"license": "MIT",
|
|
37
|
-
"devDependencies": {
|
|
38
|
-
"@eslint/js": "^9.6.0",
|
|
39
|
-
"@types/eslint__js": "^8.42.3",
|
|
40
|
-
"@types/jest": "^30.0.0",
|
|
41
|
-
"@types/nodemailer": "^6.4.15",
|
|
42
|
-
"@types/pg": "^8.11.3",
|
|
43
|
-
"del-cli": "5.1.0",
|
|
44
|
-
"eslint": "^8.57.0",
|
|
45
|
-
"eslint-config-prettier": "^9.1.0",
|
|
46
|
-
"eslint-plugin-exception-handling": "^1.0.2",
|
|
47
|
-
"eslint-plugin-sonarjs": "^1.0.3",
|
|
48
|
-
"husky": "^9.0.11",
|
|
49
|
-
"jest": "^29.7.0",
|
|
50
|
-
"semantic-release": "23.0.2",
|
|
51
|
-
"ts-jest": "^29.4.6",
|
|
52
|
-
"ts-node": "10.9.2",
|
|
53
|
-
"typescript": "5.3.3",
|
|
54
|
-
"typescript-eslint": "^7.15.0"
|
|
55
|
-
},
|
|
56
|
-
"peerDependencies": {
|
|
57
|
-
"@napi-rs/canvas": "^0.1.53",
|
|
58
|
-
"@runnerpro/common": "^1.5.10",
|
|
59
|
-
"axios": "^1.6.7",
|
|
60
|
-
"image-size": "^1.0.2",
|
|
61
|
-
"jimp": "^0.22.10",
|
|
62
|
-
"nodemailer": "6.9.9",
|
|
63
|
-
"pg": "8.11.3",
|
|
64
|
-
"uuidv4": "^6.2.13"
|
|
65
|
-
},
|
|
66
|
-
"dependencies": {
|
|
67
|
-
"@google-cloud/storage": "^7.11.3",
|
|
68
|
-
"@google-cloud/translate": "^8.3.0",
|
|
69
|
-
"@google-cloud/vertexai": "^1.4.0",
|
|
70
|
-
"@notionhq/client": "^2.2.15",
|
|
71
|
-
"exifr": "^7.1.3",
|
|
72
|
-
"ffmpeg-static": "^5.2.0",
|
|
73
|
-
"ffprobe-static": "^3.1.0",
|
|
74
|
-
"firebase-admin": "^11.10.1",
|
|
75
|
-
"fluent-ffmpeg": "^2.1.3",
|
|
76
|
-
"googleapis": "^144.0.0",
|
|
77
|
-
"multer": "^1.4.5-lts.1",
|
|
78
|
-
"oauth-signature": "1.5.0",
|
|
79
|
-
"socket.io": "^4.7.2"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@runnerpro/backend",
|
|
3
|
+
"version": "1.17.7",
|
|
4
|
+
"description": "A collection of common backend functions",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./lib/cjs/index.js"
|
|
7
|
+
},
|
|
8
|
+
"types": "./lib/cjs/types/index.d.ts",
|
|
9
|
+
"main": "./lib/cjs/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"lib/**/*"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"clean": "del-cli ./lib",
|
|
15
|
+
"build": "npm run clean && tsc -p ./configs/tsconfig.cjs.json",
|
|
16
|
+
"deploy": "npm run build && npm publish",
|
|
17
|
+
"semantic-release": "semantic-release",
|
|
18
|
+
"lint": "eslint --ext .ts --ignore-path .gitignore .",
|
|
19
|
+
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
20
|
+
"prepare": "husky",
|
|
21
|
+
"test": "jest"
|
|
22
|
+
},
|
|
23
|
+
"release": {
|
|
24
|
+
"branches": [
|
|
25
|
+
"main"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://gitlab.com/runner-pro/runnerpro-backend.git"
|
|
34
|
+
},
|
|
35
|
+
"author": "Runner Pro",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@eslint/js": "^9.6.0",
|
|
39
|
+
"@types/eslint__js": "^8.42.3",
|
|
40
|
+
"@types/jest": "^30.0.0",
|
|
41
|
+
"@types/nodemailer": "^6.4.15",
|
|
42
|
+
"@types/pg": "^8.11.3",
|
|
43
|
+
"del-cli": "5.1.0",
|
|
44
|
+
"eslint": "^8.57.0",
|
|
45
|
+
"eslint-config-prettier": "^9.1.0",
|
|
46
|
+
"eslint-plugin-exception-handling": "^1.0.2",
|
|
47
|
+
"eslint-plugin-sonarjs": "^1.0.3",
|
|
48
|
+
"husky": "^9.0.11",
|
|
49
|
+
"jest": "^29.7.0",
|
|
50
|
+
"semantic-release": "23.0.2",
|
|
51
|
+
"ts-jest": "^29.4.6",
|
|
52
|
+
"ts-node": "10.9.2",
|
|
53
|
+
"typescript": "5.3.3",
|
|
54
|
+
"typescript-eslint": "^7.15.0"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@napi-rs/canvas": "^0.1.53",
|
|
58
|
+
"@runnerpro/common": "^1.5.10",
|
|
59
|
+
"axios": "^1.6.7",
|
|
60
|
+
"image-size": "^1.0.2",
|
|
61
|
+
"jimp": "^0.22.10",
|
|
62
|
+
"nodemailer": "6.9.9",
|
|
63
|
+
"pg": "8.11.3",
|
|
64
|
+
"uuidv4": "^6.2.13"
|
|
65
|
+
},
|
|
66
|
+
"dependencies": {
|
|
67
|
+
"@google-cloud/storage": "^7.11.3",
|
|
68
|
+
"@google-cloud/translate": "^8.3.0",
|
|
69
|
+
"@google-cloud/vertexai": "^1.4.0",
|
|
70
|
+
"@notionhq/client": "^2.2.15",
|
|
71
|
+
"exifr": "^7.1.3",
|
|
72
|
+
"ffmpeg-static": "^5.2.0",
|
|
73
|
+
"ffprobe-static": "^3.1.0",
|
|
74
|
+
"firebase-admin": "^11.10.1",
|
|
75
|
+
"fluent-ffmpeg": "^2.1.3",
|
|
76
|
+
"googleapis": "^144.0.0",
|
|
77
|
+
"multer": "^1.4.5-lts.1",
|
|
78
|
+
"oauth-signature": "1.5.0",
|
|
79
|
+
"socket.io": "^4.7.2"
|
|
80
|
+
}
|
|
81
|
+
}
|