@runnerpro/backend 1.21.11 → 1.21.14
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/lib/cjs/achievements/catalog.js +204 -0
- package/lib/cjs/achievements/index.js +805 -0
- package/lib/cjs/achievements/streak.js +126 -0
- package/lib/cjs/chat/api/conversation.js +21 -29
- package/lib/cjs/chat/exposed/conversation.js +0 -7
- package/lib/cjs/chat/index.js +0 -7
- package/lib/cjs/index.js +34 -2
- package/lib/cjs/locale/en.js +0 -4
- package/lib/cjs/locale/es.js +0 -4
- package/lib/cjs/locale/fr.js +0 -4
- package/lib/cjs/locale/it.js +0 -4
- package/lib/cjs/sendNotification/index.js +4 -70
- package/lib/cjs/types/achievements/catalog.d.ts +104 -0
- package/lib/cjs/types/achievements/catalog.d.ts.map +1 -0
- package/lib/cjs/types/achievements/index.d.ts +41 -0
- package/lib/cjs/types/achievements/index.d.ts.map +1 -0
- package/lib/cjs/types/achievements/streak.d.ts +20 -0
- package/lib/cjs/types/achievements/streak.d.ts.map +1 -0
- package/lib/cjs/types/chat/api/conversation.d.ts.map +1 -1
- package/lib/cjs/types/chat/exposed/conversation.d.ts.map +1 -1
- package/lib/cjs/types/chat/index.d.ts.map +1 -1
- package/lib/cjs/types/index.d.ts +3 -1
- package/lib/cjs/types/index.d.ts.map +1 -1
- package/lib/cjs/types/locale/en.d.ts +0 -4
- package/lib/cjs/types/locale/en.d.ts.map +1 -1
- package/lib/cjs/types/locale/es.d.ts +0 -4
- package/lib/cjs/types/locale/es.d.ts.map +1 -1
- package/lib/cjs/types/locale/fr.d.ts +0 -4
- package/lib/cjs/types/locale/fr.d.ts.map +1 -1
- package/lib/cjs/types/locale/it.d.ts +0 -4
- package/lib/cjs/types/locale/it.d.ts.map +1 -1
- package/lib/cjs/types/sendNotification/index.d.ts +1 -20
- package/lib/cjs/types/sendNotification/index.d.ts.map +1 -1
- package/lib/cjs/types/workout/planificacionPrueba7dias/index.d.ts.map +1 -1
- package/lib/cjs/types/workout/saveWorkoutAplication.d.ts.map +1 -1
- package/lib/cjs/workout/planificacionPrueba7dias/index.js +7 -3
- package/lib/cjs/workout/saveWorkoutAplication.js +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.computeStreakStats = exports.requiredFromPlanned = exports.STREAK_COMPLETION_THRESHOLD = void 0;
|
|
16
|
+
const db_1 = require("../db");
|
|
17
|
+
const moment_1 = __importDefault(require("moment"));
|
|
18
|
+
/**
|
|
19
|
+
* Regla de racha: una semana cuenta como completada si el usuario hace al menos
|
|
20
|
+
* el 80% de los entrenamientos planificados de esa semana (regla 80%). Tipos
|
|
21
|
+
* entrenables, semanas ISO. La semana actual incompleta no rompe la racha.
|
|
22
|
+
*/
|
|
23
|
+
exports.STREAK_COMPLETION_THRESHOLD = 0.8;
|
|
24
|
+
const requiredFromPlanned = (plannedWorkouts) => {
|
|
25
|
+
const planned = Number(plannedWorkouts) || 0;
|
|
26
|
+
if (planned <= 0)
|
|
27
|
+
return 0;
|
|
28
|
+
return Math.max(1, Math.ceil(planned * exports.STREAK_COMPLETION_THRESHOLD));
|
|
29
|
+
};
|
|
30
|
+
exports.requiredFromPlanned = requiredFromPlanned;
|
|
31
|
+
/**
|
|
32
|
+
* Racha actual (current) y récord histórico (longest), en semanas.
|
|
33
|
+
*
|
|
34
|
+
* @param userId ID del cliente.
|
|
35
|
+
* @param sinceDate Si se pasa, solo cuentan workouts con "DATE" >= sinceDate
|
|
36
|
+
* (ancla "empezar de cero" para logros). Sin él, comportamiento sobre todo el
|
|
37
|
+
* historial.
|
|
38
|
+
*/
|
|
39
|
+
const computeStreakStats = (userId, sinceDate = null) => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
|
+
const params = [userId];
|
|
41
|
+
let sinceFilter = '';
|
|
42
|
+
if (sinceDate) {
|
|
43
|
+
sinceFilter = ' AND "DATE"::date >= ?::date';
|
|
44
|
+
params.push(sinceDate);
|
|
45
|
+
}
|
|
46
|
+
const rows = yield (0, db_1.query)(`SELECT date_trunc('week', "DATE"::date) AS "WEEK START",
|
|
47
|
+
COUNT(*) FILTER (WHERE "DONE" = true) AS completed,
|
|
48
|
+
COUNT(*) AS planned
|
|
49
|
+
FROM "WORKOUT"
|
|
50
|
+
WHERE "ID CLIENTE" = ?
|
|
51
|
+
AND "TYPE" IN ('CORRER','FUERZA','SPORT','BIKE','SWIM','TRAIL','WALK')
|
|
52
|
+
AND "SHOW CLIENT" IS TRUE${sinceFilter}
|
|
53
|
+
GROUP BY 1
|
|
54
|
+
ORDER BY 1 ASC`, params);
|
|
55
|
+
if (rows.length === 0)
|
|
56
|
+
return { current: 0, longest: 0 };
|
|
57
|
+
const byWeek = new Map();
|
|
58
|
+
for (const row of rows) {
|
|
59
|
+
const weekKey = (0, moment_1.default)(row.weekStart).startOf('isoWeek').format('YYYY-MM-DD');
|
|
60
|
+
byWeek.set(weekKey, {
|
|
61
|
+
completed: Number(row.completed) || 0,
|
|
62
|
+
planned: Number(row.planned) || 0,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const now = (0, moment_1.default)();
|
|
66
|
+
const currentWeek = now.clone().startOf('isoWeek');
|
|
67
|
+
// ── Récord histórico ───────────────────────────────────────────────
|
|
68
|
+
const firstWeek = (0, moment_1.default)(rows[0].weekStart).startOf('isoWeek');
|
|
69
|
+
const lastWeek = currentWeek.clone();
|
|
70
|
+
let longest = 0;
|
|
71
|
+
let segment = 0;
|
|
72
|
+
const fwd = firstWeek.clone();
|
|
73
|
+
const MAX_WEEKS_FORWARD = 520;
|
|
74
|
+
for (let i = 0; i < MAX_WEEKS_FORWARD && fwd.isSameOrBefore(lastWeek, 'day'); i++) {
|
|
75
|
+
const k = fwd.format('YYYY-MM-DD');
|
|
76
|
+
const data = byWeek.get(k);
|
|
77
|
+
const required = data ? (0, exports.requiredFromPlanned)(data.planned) : 0;
|
|
78
|
+
const isCurrent = fwd.isSame(currentWeek, 'day');
|
|
79
|
+
const cumple = !!data && required > 0 && data.completed >= required;
|
|
80
|
+
if (cumple) {
|
|
81
|
+
segment++;
|
|
82
|
+
if (segment > longest)
|
|
83
|
+
longest = segment;
|
|
84
|
+
}
|
|
85
|
+
else if (!isCurrent) {
|
|
86
|
+
segment = 0;
|
|
87
|
+
}
|
|
88
|
+
fwd.add(1, 'week');
|
|
89
|
+
}
|
|
90
|
+
// ── Racha actual ───────────────────────────────────────────────────
|
|
91
|
+
const cursor = currentWeek.clone();
|
|
92
|
+
const currentData = byWeek.get(cursor.format('YYYY-MM-DD'));
|
|
93
|
+
let current = 0;
|
|
94
|
+
if (currentData) {
|
|
95
|
+
const required = (0, exports.requiredFromPlanned)(currentData.planned);
|
|
96
|
+
if (required > 0 && currentData.completed >= required) {
|
|
97
|
+
current++;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
cursor.subtract(1, 'week');
|
|
101
|
+
const MAX_LOOKBACK_WEEKS = 520;
|
|
102
|
+
let broken = false;
|
|
103
|
+
for (let i = 0; i < MAX_LOOKBACK_WEEKS && !broken; i++) {
|
|
104
|
+
const data = byWeek.get(cursor.format('YYYY-MM-DD'));
|
|
105
|
+
if (!data) {
|
|
106
|
+
broken = true;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
const required = (0, exports.requiredFromPlanned)(data.planned);
|
|
110
|
+
if (required === 0) {
|
|
111
|
+
cursor.subtract(1, 'week');
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (data.completed >= required) {
|
|
115
|
+
current++;
|
|
116
|
+
cursor.subtract(1, 'week');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
broken = true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (current > longest)
|
|
123
|
+
longest = current;
|
|
124
|
+
return { current, longest };
|
|
125
|
+
});
|
|
126
|
+
exports.computeStreakStats = computeStreakStats;
|
|
@@ -368,18 +368,22 @@ const sendMessage = (req, res, { sendNotification, firebaseMessaging, isClient }
|
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
370
|
const [message] = yield (0, index_1.query)('INSERT INTO [CHAT MESSAGE] ([ID CLIENTE], [ID SENDER], [TEXT], [TEXT PREFERRED LANGUAGE], [PREFERRED LANGUAGE], [REPLY MESSAGE ID], [ID WORKOUT], [TYPE]) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING [ID]', [isClient ? userid : idCliente, userid, textSpanish, textPreferredLanguage, preferredLanguage, replyMessageId, idWorkout, type]);
|
|
371
|
-
|
|
371
|
+
// Logros: mensaje enviado por el cliente → coach_1er_msg/coach_10_msg. Await
|
|
372
|
+
// acotado (1500 ms) para devolver los recién desbloqueados al FE (push). El
|
|
373
|
+
// bounded aísla fallo/lentitud: si vence, persiste en background y el FE lo
|
|
374
|
+
// recupera en el siguiente refetch.
|
|
375
|
+
let logrosDesbloqueados = [];
|
|
376
|
+
if (isClient) {
|
|
377
|
+
logrosDesbloqueados = yield (0, index_1.evaluateAchievementsBounded)(userid, 'chat', {}, 1500);
|
|
378
|
+
}
|
|
379
|
+
res.send({ idMessage: message.id, text: textSpanish, logrosDesbloqueados });
|
|
372
380
|
if (!isClient) {
|
|
373
|
-
// Recuperamos el nombre del entrenador para firmar el push con su nombre real (no genérico).
|
|
374
|
-
const [entrenadorRow] = yield (0, index_1.query)('SELECT [NAME] FROM [ENTRENADOR] WHERE [ID] = ?', [userid]);
|
|
375
|
-
const entrenador = ((entrenadorRow === null || entrenadorRow === void 0 ? void 0 : entrenadorRow.name) || 'Tu entrenador').split(' ')[0];
|
|
376
381
|
sendNotification({
|
|
377
382
|
firebaseMessaging,
|
|
378
383
|
idCliente,
|
|
379
|
-
title:
|
|
384
|
+
title: '💬 Nuevo mensaje de tu entrenador',
|
|
380
385
|
body: textPreferredLanguage || textSpanish,
|
|
381
386
|
screen: common_1.NOTIFICATION_SCREEN_TYPES.CHAT,
|
|
382
|
-
channelId: common_1.NOTIFICATION_CHANNELS.COACH,
|
|
383
387
|
});
|
|
384
388
|
// Enviar a N8N lo que ha escrito el entrenador
|
|
385
389
|
// const [lastSuggestionMsg] = await query(
|
|
@@ -431,20 +435,11 @@ const sendEmoji = (req, res, { sendNotification, firebaseMessaging, isClient })
|
|
|
431
435
|
]);
|
|
432
436
|
res.send({ idReaction: reaction.id });
|
|
433
437
|
if (!isClient) {
|
|
434
|
-
const [[entrenadorRow], [clienteRow]] = yield Promise.all([
|
|
435
|
-
(0, index_1.query)('SELECT [NAME] FROM [ENTRENADOR] WHERE [ID] = ?', [userid]),
|
|
436
|
-
(0, index_1.query)('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]),
|
|
437
|
-
]);
|
|
438
|
-
const entrenador = ((entrenadorRow === null || entrenadorRow === void 0 ? void 0 : entrenadorRow.name) || 'Tu entrenador').split(' ')[0];
|
|
439
|
-
const lang = (clienteRow === null || clienteRow === void 0 ? void 0 : clienteRow.preferredLanguage) || common_1.LANGUAGES.ES;
|
|
440
438
|
sendNotification({
|
|
441
439
|
firebaseMessaging,
|
|
442
440
|
idCliente,
|
|
443
|
-
body:
|
|
444
|
-
.replace('{{ entrenador }}', entrenador)
|
|
445
|
-
.replace('{{ emoji }}', emoji),
|
|
441
|
+
body: `El entrenador ha reaccionado a un mensaje '${emoji}'`,
|
|
446
442
|
screen: common_1.NOTIFICATION_SCREEN_TYPES.CHAT,
|
|
447
|
-
channelId: common_1.NOTIFICATION_CHANNELS.COACH,
|
|
448
443
|
});
|
|
449
444
|
}
|
|
450
445
|
});
|
|
@@ -486,6 +481,12 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, isClient, buc
|
|
|
486
481
|
thumbnail = yield getThumbnailFromVideo(filePath, duration);
|
|
487
482
|
}
|
|
488
483
|
const [{ id: idFile }] = yield (0, index_1.query)('INSERT INTO [CHAT MESSAGE] ([ID CLIENTE], [ID SENDER], [TEXT], [MIMETYPE], [DURATION], [TYPE]) VALUES (?, ?, ?, ?, ?, ?) RETURNING [ID]', [isClient ? userid : idCliente, userid, req.file.originalname, req.file.mimetype, duration || null, type || 2]);
|
|
484
|
+
// Logros: adjunto enviado por el cliente también cuenta como mensaje. Await
|
|
485
|
+
// acotado para devolver los recién desbloqueados al FE en la respuesta (push).
|
|
486
|
+
let logrosDesbloqueados = [];
|
|
487
|
+
if (isClient) {
|
|
488
|
+
logrosDesbloqueados = yield (0, index_1.evaluateAchievementsBounded)(userid, 'chat', {}, 1500);
|
|
489
|
+
}
|
|
489
490
|
const fileData = fs_1.default.readFileSync(filePath);
|
|
490
491
|
const files = [];
|
|
491
492
|
if (req.file.mimetype.includes('image')) {
|
|
@@ -506,7 +507,7 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, isClient, buc
|
|
|
506
507
|
else {
|
|
507
508
|
files.push({ data: fileData, id: idFile });
|
|
508
509
|
}
|
|
509
|
-
res.send({ idFile });
|
|
510
|
+
res.send({ idFile, logrosDesbloqueados });
|
|
510
511
|
for (const file of files) {
|
|
511
512
|
yield bucket.file(`Chat/${file.id}`).save(file.data);
|
|
512
513
|
}
|
|
@@ -519,22 +520,13 @@ const sendFile = (req, res, { sendNotification, firebaseMessaging, isClient, buc
|
|
|
519
520
|
textFile = 'Vídeo';
|
|
520
521
|
if (req.file.mimetype.includes('image'))
|
|
521
522
|
textFile = 'Imagen';
|
|
522
|
-
const [
|
|
523
|
-
(0, index_1.query)('SELECT [NAME] FROM [ENTRENADOR] WHERE [ID] = ?', [userid]),
|
|
524
|
-
(0, index_1.query)('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]),
|
|
525
|
-
]);
|
|
526
|
-
const entrenador = ((entrenadorRow === null || entrenadorRow === void 0 ? void 0 : entrenadorRow.name) || 'Tu entrenador').split(' ')[0];
|
|
527
|
-
const lang = (clienteRow === null || clienteRow === void 0 ? void 0 : clienteRow.preferredLanguage) || common_1.LANGUAGES.ES;
|
|
528
|
-
const tipoArchivo = (0, index_2.t)(textFile, lang);
|
|
523
|
+
const [cliente] = yield (0, index_1.query)('SELECT [PREFERRED LANGUAGE] FROM [CLIENTE] WHERE [ID] = ?', [idCliente]);
|
|
529
524
|
sendNotification({
|
|
530
525
|
firebaseMessaging,
|
|
531
526
|
idCliente,
|
|
532
|
-
title: (0, index_2.t)('
|
|
533
|
-
|
|
534
|
-
.replace('{{ tipoArchivo }}', tipoArchivo),
|
|
535
|
-
body: (0, index_2.t)('Ábrelo en el chat.', lang),
|
|
527
|
+
title: (0, index_2.t)('💬 Nuevo mensaje de tu entrenador', cliente.preferredLanguage),
|
|
528
|
+
body: (0, index_2.t)(textFile, cliente.preferredLanguage),
|
|
536
529
|
screen: common_1.NOTIFICATION_SCREEN_TYPES.CHAT,
|
|
537
|
-
channelId: common_1.NOTIFICATION_CHANNELS.COACH,
|
|
538
530
|
});
|
|
539
531
|
yield updateSenderView({ userid, idCliente, idMessage: idFile });
|
|
540
532
|
}
|
|
@@ -30,13 +30,6 @@ exports.conversationRoute = conversationRoute;
|
|
|
30
30
|
const socketConversation = (req, res, { isClient }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
31
31
|
const { idCliente } = req.body;
|
|
32
32
|
const ioEmitter = req.app.get('socketIo');
|
|
33
|
-
// El backend de la app ya no monta socket.io (la app recibe por push + recarga HTTP, no por
|
|
34
|
-
// websocket). Sin emisor no hay a quién emitir: respondemos ok y salimos. Antes esto caía al
|
|
35
|
-
// vacío igualmente porque la app no escuchaba el socket; ahora evitamos el 500 por undefined.
|
|
36
|
-
if (!ioEmitter) {
|
|
37
|
-
res.send({ status: 'ok' });
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
33
|
const room = (0, getRoom_1.getRoom)(isClient, idCliente);
|
|
41
34
|
ioEmitter.sockets.in(room).emit('message', req.body);
|
|
42
35
|
res.send({ status: 'ok' });
|
package/lib/cjs/chat/index.js
CHANGED
|
@@ -15,13 +15,6 @@ Object.defineProperty(exports, "chatExposed", { enumerable: true, get: function
|
|
|
15
15
|
const getCountNotificaciones_1 = require("./utils/getCountNotificaciones");
|
|
16
16
|
Object.defineProperty(exports, "getCountNotificaciones", { enumerable: true, get: function () { return getCountNotificaciones_1.getCountNotificaciones; } });
|
|
17
17
|
const chat = ({ server, app, verify_access_token, tokenExposed, backendExtremeUrl, frontendUrl, isClient }) => {
|
|
18
|
-
// El backend de la APP (isClient) NO usa websockets: la app recibe los mensajes por avisos
|
|
19
|
-
// push (FCM) + recarga HTTP de la conversación, nunca por socket.io (no tiene cliente de
|
|
20
|
-
// websocket). Montarlo aquí era código muerto — el emit caía al vacío — y además inflaba la
|
|
21
|
-
// latencia p95 del servicio con conexiones de larga duración. El dashboard de coaches
|
|
22
|
-
// (isClient=false) sí consume el socket, así que ahí se mantiene intacto.
|
|
23
|
-
if (isClient)
|
|
24
|
-
return;
|
|
25
18
|
// @ts-ignore
|
|
26
19
|
const io = (0, socket_io_1.default)(server, {
|
|
27
20
|
cors: {
|
package/lib/cjs/index.js
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.calculateCost = exports.MODEL_PRICING = exports.AISTUDIO_PREFIX = exports.BEDROCK_CLAUDE_HAIKU = exports.BEDROCK_CLAUDE_SONNET_4 = exports.BEDROCK_CLAUDE_SONNET_4_5 = exports.BEDROCK_CLAUDE_OPUS_4_1 = exports.BEDROCK_CLAUDE_OPUS_4_5 = exports.BEDROCK_CLAUDE_SONNET = exports.BEDROCK_CLAUDE_OPUS = exports.FALLBACK_MODELS = exports.PRODUCTION_MODELS = exports.AZURE_PRIMARY_MODELS = exports.AZURE_GPT_5_4_NANO = exports.AZURE_GPT_5_4_MINI = exports.AZURE_GPT_5_5 = exports.AZURE_GPT_5_4_NANO_DEPLOYMENT = exports.AZURE_GPT_5_4_MINI_DEPLOYMENT = exports.AZURE_GPT_5_5_DEPLOYMENT = exports.AZURE_PREFIX = exports.GOOGLE_MODELS = exports.AI_MODELS = exports.MODEL_TIER = exports.runWithModels = exports.runWithCostTracking = exports.createModelFromString = exports.createAzureModelFromString = exports.createBedrockModelFromString = exports.createGoogleModelFromString = void 0;
|
|
26
|
+
exports.describeImage = exports.transcribeAudio = exports.updateSenderView = exports.saveResponseTime = exports.getZone = exports.saveDoneStructuraWorkout = exports.computeStreakStats = exports.getUnlockedAchievements = exports.evaluateAchievementsBounded = exports.evaluateAchievements = exports.saveWorkoutLaps = exports.saveWorkoutAplication = exports.getPlanificacionPrueba7dias = exports.sendWorkoutToWatch = exports.getDefaultWorkoutImage = exports.generateShareMap = exports.reduceSizeImage = exports.getLetter = exports.getNumberByLetter = exports.appendSheet = exports.writeSheet = exports.findCellByValue = exports.readSheet = exports.NOTION_DATABASES_ID = exports.notionEditPage = exports.notionAddPage = exports.notionGetDatabase = exports.notionGetUsers = exports.getCountNotificaciones = exports.chatExposed = exports.chatApi = exports.chat = exports.getExerciseTranslatedDescription = exports.useTranslation = exports.LANGUAGES = exports.translate = exports.CHANNEL_SLACK = exports.notifySlack = exports.fetchIA = exports.err = exports.sendMail = exports.pool = exports.toPgArray = exports.batchQuery = exports.longRunningQuery = exports.queryWithClient = exports.query = exports.sleep = exports.sendNotification = exports.achievementsCatalog = void 0;
|
|
27
|
+
exports.calculateCost = exports.MODEL_PRICING = exports.AISTUDIO_PREFIX = exports.BEDROCK_CLAUDE_HAIKU = exports.BEDROCK_CLAUDE_SONNET_4 = exports.BEDROCK_CLAUDE_SONNET_4_5 = exports.BEDROCK_CLAUDE_OPUS_4_1 = exports.BEDROCK_CLAUDE_OPUS_4_5 = exports.BEDROCK_CLAUDE_SONNET = exports.BEDROCK_CLAUDE_OPUS = exports.FALLBACK_MODELS = exports.PRODUCTION_MODELS = exports.AZURE_PRIMARY_MODELS = exports.AZURE_GPT_5_4_NANO = exports.AZURE_GPT_5_4_MINI = exports.AZURE_GPT_5_5 = exports.AZURE_GPT_5_4_NANO_DEPLOYMENT = exports.AZURE_GPT_5_4_MINI_DEPLOYMENT = exports.AZURE_GPT_5_5_DEPLOYMENT = exports.AZURE_PREFIX = exports.GOOGLE_MODELS = exports.AI_MODELS = exports.MODEL_TIER = exports.runWithModels = exports.runWithCostTracking = exports.createModelFromString = exports.createAzureModelFromString = exports.createBedrockModelFromString = exports.createGoogleModelFromString = exports.createGoogleModel = exports.generateText = exports.generateObject = exports.reprocessRecentMedia = exports.processMediaFile = void 0;
|
|
5
28
|
const sendNotification_1 = require("./sendNotification");
|
|
6
29
|
Object.defineProperty(exports, "sendNotification", { enumerable: true, get: function () { return sendNotification_1.sendNotification; } });
|
|
7
30
|
const sleep_1 = require("./sleep");
|
|
@@ -59,6 +82,15 @@ const saveWorkoutAplication_1 = require("./workout/saveWorkoutAplication");
|
|
|
59
82
|
Object.defineProperty(exports, "saveWorkoutAplication", { enumerable: true, get: function () { return saveWorkoutAplication_1.saveWorkoutAplication; } });
|
|
60
83
|
const saveWorkoutLaps_1 = require("./workout/saveWorkoutLaps");
|
|
61
84
|
Object.defineProperty(exports, "saveWorkoutLaps", { enumerable: true, get: function () { return saveWorkoutLaps_1.saveWorkoutLaps; } });
|
|
85
|
+
const achievements_1 = require("./achievements");
|
|
86
|
+
Object.defineProperty(exports, "evaluateAchievements", { enumerable: true, get: function () { return achievements_1.evaluateAchievements; } });
|
|
87
|
+
Object.defineProperty(exports, "evaluateAchievementsBounded", { enumerable: true, get: function () { return achievements_1.evaluateAchievementsBounded; } });
|
|
88
|
+
Object.defineProperty(exports, "getUnlockedAchievements", { enumerable: true, get: function () { return achievements_1.getUnlockedAchievements; } });
|
|
89
|
+
Object.defineProperty(exports, "computeStreakStats", { enumerable: true, get: function () { return achievements_1.computeStreakStats; } });
|
|
90
|
+
// Catálogo de REGLAS de logros (umbrales + IDs). Fuente única de verdad para
|
|
91
|
+
// los consumidores del paquete (backfill, herramientas, tests). El catálogo de
|
|
92
|
+
// PRESENTACIÓN (labels/iconos) vive en el frontend.
|
|
93
|
+
exports.achievementsCatalog = __importStar(require("./achievements/catalog"));
|
|
62
94
|
const estructuraWorkout_1 = require("./workout/estructuraWorkout");
|
|
63
95
|
Object.defineProperty(exports, "saveDoneStructuraWorkout", { enumerable: true, get: function () { return estructuraWorkout_1.saveDoneStructuraWorkout; } });
|
|
64
96
|
const paceZone_1 = require("./workout/paceZone");
|
package/lib/cjs/locale/en.js
CHANGED
|
@@ -7,9 +7,5 @@ const en = {
|
|
|
7
7
|
Vídeo: 'Video',
|
|
8
8
|
Imagen: 'Image',
|
|
9
9
|
'💬 Nuevo mensaje de tu entrenador': '💬 New message from your trainer',
|
|
10
|
-
'{{ entrenador }} 💬': '{{ entrenador }} 💬',
|
|
11
|
-
'{{ entrenador }} te ha enviado {{ tipoArchivo }} 📎': '{{ entrenador }} sent you {{ tipoArchivo }} 📎',
|
|
12
|
-
'Ábrelo en el chat.': 'Open it in the chat.',
|
|
13
|
-
'{{ entrenador }} reaccionó {{ emoji }} a tu mensaje': '{{ entrenador }} reacted {{ emoji }} to your message',
|
|
14
10
|
};
|
|
15
11
|
exports.en = en;
|
package/lib/cjs/locale/es.js
CHANGED
|
@@ -7,9 +7,5 @@ const es = {
|
|
|
7
7
|
Vídeo: 'Vídeo',
|
|
8
8
|
Imagen: 'Imagen',
|
|
9
9
|
'💬 Nuevo mensaje de tu entrenador': '💬 Nuevo mensaje de tu entrenador',
|
|
10
|
-
'{{ entrenador }} 💬': '{{ entrenador }} 💬',
|
|
11
|
-
'{{ entrenador }} te ha enviado {{ tipoArchivo }} 📎': '{{ entrenador }} te ha enviado {{ tipoArchivo }} 📎',
|
|
12
|
-
'Ábrelo en el chat.': 'Ábrelo en el chat.',
|
|
13
|
-
'{{ entrenador }} reaccionó {{ emoji }} a tu mensaje': '{{ entrenador }} reaccionó {{ emoji }} a tu mensaje',
|
|
14
10
|
};
|
|
15
11
|
exports.es = es;
|
package/lib/cjs/locale/fr.js
CHANGED
|
@@ -7,9 +7,5 @@ const fr = {
|
|
|
7
7
|
Vídeo: 'Vidéo',
|
|
8
8
|
Imagen: 'Image',
|
|
9
9
|
'💬 Nuevo mensaje de tu entrenador': '💬 Nouveau message de votre entraîneur',
|
|
10
|
-
'{{ entrenador }} 💬': '{{ entrenador }} 💬',
|
|
11
|
-
'{{ entrenador }} te ha enviado {{ tipoArchivo }} 📎': '{{ entrenador }} t’a envoyé {{ tipoArchivo }} 📎',
|
|
12
|
-
'Ábrelo en el chat.': 'Ouvre-le dans le chat.',
|
|
13
|
-
'{{ entrenador }} reaccionó {{ emoji }} a tu mensaje': '{{ entrenador }} a réagi {{ emoji }} à ton message',
|
|
14
10
|
};
|
|
15
11
|
exports.fr = fr;
|
package/lib/cjs/locale/it.js
CHANGED
|
@@ -7,9 +7,5 @@ const it = {
|
|
|
7
7
|
Vídeo: 'Video',
|
|
8
8
|
Imagen: 'Immagine',
|
|
9
9
|
'💬 Nuevo mensaje de tu entrenador': '💬 Nuovo messaggio da tuo allenatore',
|
|
10
|
-
'{{ entrenador }} 💬': '{{ entrenador }} 💬',
|
|
11
|
-
'{{ entrenador }} te ha enviado {{ tipoArchivo }} 📎': '{{ entrenador }} ti ha inviato {{ tipoArchivo }} 📎',
|
|
12
|
-
'Ábrelo en el chat.': 'Aprilo nella chat.',
|
|
13
|
-
'{{ entrenador }} reaccionó {{ emoji }} a tu mensaje': '{{ entrenador }} ha reagito {{ emoji }} al tuo messaggio',
|
|
14
10
|
};
|
|
15
11
|
exports.it = it;
|
|
@@ -12,7 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.sendNotification = void 0;
|
|
13
13
|
const index_1 = require("../db/index");
|
|
14
14
|
const common_1 = require("@runnerpro/common");
|
|
15
|
-
const sendNotification = ({ firebaseMessaging, idCliente, title, body, screen = common_1.NOTIFICATION_SCREEN_TYPES.HOME, screenParams = {},
|
|
15
|
+
const sendNotification = ({ firebaseMessaging, idCliente, title, body, screen = common_1.NOTIFICATION_SCREEN_TYPES.HOME, screenParams = {}, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
16
|
const devices = yield (0, index_1.query)('SELECT [SUBSCRIPTION], [TYPE] FROM [PUSH MANAGER] WHERE [ID CLIENTE] = ?', [idCliente]);
|
|
17
17
|
const [{ id: idNotification }] = yield (0, index_1.query)('INSERT INTO "CLIENTE NOTIFICACION" ("ID CLIENTE", "TIMESTAMP", "TITLE", "BODY", "PARAMS") VALUES (?, NOW(), ?, ?, ?) RETURNING "ID"', [
|
|
18
18
|
idCliente,
|
|
@@ -31,89 +31,23 @@ const sendNotification = ({ firebaseMessaging, idCliente, title, body, screen =
|
|
|
31
31
|
idNotification: (idNotification || '0').toString(),
|
|
32
32
|
screen,
|
|
33
33
|
screenParams: screenParamsString,
|
|
34
|
-
imageUrl,
|
|
35
|
-
channelId,
|
|
36
|
-
largeIcon,
|
|
37
|
-
bigText,
|
|
38
|
-
actions,
|
|
39
|
-
progress,
|
|
40
|
-
sound,
|
|
41
|
-
coachNombre,
|
|
42
|
-
category,
|
|
43
34
|
}, device.subscription);
|
|
44
35
|
}
|
|
45
36
|
});
|
|
46
37
|
exports.sendNotification = sendNotification;
|
|
47
38
|
function notificationWEB(firebaseMessaging, msg, token) {
|
|
48
|
-
var _a, _b;
|
|
49
39
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
40
|
if (!msg.title)
|
|
51
41
|
msg.title = '';
|
|
52
42
|
try {
|
|
53
|
-
|
|
54
|
-
// app los reconstruya con Notifee al recibir el push.
|
|
55
|
-
const data = {
|
|
56
|
-
title: msg.title,
|
|
57
|
-
body: msg.body,
|
|
58
|
-
screen: msg.screen,
|
|
59
|
-
screenParams: msg.screenParams,
|
|
60
|
-
idNotification: String((_a = msg.idNotification) !== null && _a !== void 0 ? _a : ''),
|
|
61
|
-
};
|
|
62
|
-
if (msg.imageUrl)
|
|
63
|
-
data.imageUrl = msg.imageUrl;
|
|
64
|
-
if (msg.channelId)
|
|
65
|
-
data.channelId = msg.channelId;
|
|
66
|
-
if (msg.largeIcon)
|
|
67
|
-
data.largeIcon = msg.largeIcon;
|
|
68
|
-
if (msg.bigText)
|
|
69
|
-
data.bigText = msg.bigText;
|
|
70
|
-
if (msg.actions && msg.actions.length > 0)
|
|
71
|
-
data.actions = JSON.stringify(msg.actions);
|
|
72
|
-
if (msg.progress)
|
|
73
|
-
data.progress = JSON.stringify(msg.progress);
|
|
74
|
-
if (msg.sound)
|
|
75
|
-
data.sound = msg.sound;
|
|
76
|
-
if (msg.coachNombre)
|
|
77
|
-
data.coachNombre = msg.coachNombre;
|
|
78
|
-
const message = {
|
|
43
|
+
yield firebaseMessaging.send({
|
|
79
44
|
token,
|
|
80
45
|
notification: {
|
|
81
46
|
title: msg.title,
|
|
82
47
|
body: msg.body,
|
|
83
48
|
},
|
|
84
|
-
data,
|
|
85
|
-
};
|
|
86
|
-
// Bloques nativos solo cuando aportan, para no inflar el payload ni romper
|
|
87
|
-
// pushes existentes que no usan estos campos.
|
|
88
|
-
const channelIdResolved = (_b = msg.channelId) !== null && _b !== void 0 ? _b : common_1.NOTIFICATION_CHANNELS.DEFAULT;
|
|
89
|
-
const androidNotification = {
|
|
90
|
-
channelId: channelIdResolved,
|
|
91
|
-
};
|
|
92
|
-
if (msg.imageUrl)
|
|
93
|
-
androidNotification.imageUrl = msg.imageUrl;
|
|
94
|
-
if (msg.sound)
|
|
95
|
-
androidNotification.sound = msg.sound;
|
|
96
|
-
message.android = {
|
|
97
|
-
priority: 'high',
|
|
98
|
-
notification: androidNotification,
|
|
99
|
-
};
|
|
100
|
-
// iOS (APNs). mutable-content activa el Notification Service Extension, que
|
|
101
|
-
// necesitamos cuando hay imagen rica O avatar del coach (para pintarlo como
|
|
102
|
-
// communication notification con la cara del entrenador). category habilita
|
|
103
|
-
// los botones de acción (UNNotificationCategory registrada en la app).
|
|
104
|
-
const aps = {};
|
|
105
|
-
if (msg.imageUrl || msg.largeIcon)
|
|
106
|
-
aps['mutable-content'] = 1;
|
|
107
|
-
if (msg.sound)
|
|
108
|
-
aps.sound = msg.sound;
|
|
109
|
-
if (msg.category)
|
|
110
|
-
aps.category = msg.category;
|
|
111
|
-
if (Object.keys(aps).length > 0) {
|
|
112
|
-
message.apns = { payload: { aps } };
|
|
113
|
-
if (msg.imageUrl)
|
|
114
|
-
message.apns.fcm_options = { image: msg.imageUrl };
|
|
115
|
-
}
|
|
116
|
-
yield firebaseMessaging.send(message);
|
|
49
|
+
data: msg,
|
|
50
|
+
});
|
|
117
51
|
}
|
|
118
52
|
catch (error) {
|
|
119
53
|
return error;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catálogo de REGLAS de logros (umbrales). Vive en el paquete compartido para
|
|
3
|
+
* que lo usen tanto los hooks de evento (saveWorkoutAplication.postHooks y los
|
|
4
|
+
* eventos de Cliente-backend) como el backfill.
|
|
5
|
+
*
|
|
6
|
+
* Los `id` deben coincidir EXACTAMENTE con el catálogo de PRESENTACIÓN del
|
|
7
|
+
* frontend (Cliente-app/src/screens/PlanMap/utils/achievementCatalog.js).
|
|
8
|
+
* Frontend = labels/iconos/colores; aquí = umbrales/reglas.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CONSISTENCY: {
|
|
11
|
+
id: string;
|
|
12
|
+
weeks: number;
|
|
13
|
+
}[];
|
|
14
|
+
export declare const DISTANCE: {
|
|
15
|
+
id: string;
|
|
16
|
+
meters: number;
|
|
17
|
+
}[];
|
|
18
|
+
export declare const VOLUME: {
|
|
19
|
+
id: string;
|
|
20
|
+
km: number;
|
|
21
|
+
}[];
|
|
22
|
+
export declare const RUNNING_TYPES: string[];
|
|
23
|
+
export declare const PR_DISTANCES: number[];
|
|
24
|
+
export declare const PACE: {
|
|
25
|
+
id: string;
|
|
26
|
+
maxSecPerKm: number;
|
|
27
|
+
}[];
|
|
28
|
+
export declare const TIME_PR: {
|
|
29
|
+
id: string;
|
|
30
|
+
distance: number;
|
|
31
|
+
maxSeconds: number;
|
|
32
|
+
}[];
|
|
33
|
+
export declare const PR_NO_STREAM_MARGIN = 1.05;
|
|
34
|
+
export declare const PR_MANUAL_FLOOR: {
|
|
35
|
+
[official: number]: number;
|
|
36
|
+
};
|
|
37
|
+
export declare const PR_DISTANCE_BADGE: {
|
|
38
|
+
[meters: number]: string;
|
|
39
|
+
};
|
|
40
|
+
export declare const STRENGTH_COUNT: {
|
|
41
|
+
id: string;
|
|
42
|
+
count: number;
|
|
43
|
+
}[];
|
|
44
|
+
export declare const RACE_COUNT: {
|
|
45
|
+
id: string;
|
|
46
|
+
count: number;
|
|
47
|
+
}[];
|
|
48
|
+
export declare const CYCLING_DISTANCE: {
|
|
49
|
+
id: string;
|
|
50
|
+
meters: number;
|
|
51
|
+
}[];
|
|
52
|
+
export declare const CYCLING_VOLUME: {
|
|
53
|
+
id: string;
|
|
54
|
+
km: number;
|
|
55
|
+
}[];
|
|
56
|
+
export declare const SWIM_DISTANCE: {
|
|
57
|
+
id: string;
|
|
58
|
+
meters: number;
|
|
59
|
+
}[];
|
|
60
|
+
export declare const TRAIL_DISTANCE: {
|
|
61
|
+
id: string;
|
|
62
|
+
meters: number;
|
|
63
|
+
}[];
|
|
64
|
+
export declare const TRAIL_ELEVATION: {
|
|
65
|
+
id: string;
|
|
66
|
+
meters: number;
|
|
67
|
+
}[];
|
|
68
|
+
export declare const TRI_SWIM_DISTANCE: {
|
|
69
|
+
id: string;
|
|
70
|
+
meters: number;
|
|
71
|
+
}[];
|
|
72
|
+
export declare const CHAT_MSG: {
|
|
73
|
+
id: string;
|
|
74
|
+
count: number;
|
|
75
|
+
}[];
|
|
76
|
+
export declare const NUTRITION_MEALS: {
|
|
77
|
+
id: string;
|
|
78
|
+
count: number;
|
|
79
|
+
}[];
|
|
80
|
+
export declare const NUTRITION_DAYS_THRESHOLD = 7;
|
|
81
|
+
export declare const WEARABLE_APPS: {
|
|
82
|
+
id: string;
|
|
83
|
+
tipo: number;
|
|
84
|
+
}[];
|
|
85
|
+
export declare const PLAN_SESSION_TYPES: string[];
|
|
86
|
+
export declare const PLAN_ADHERENCE_82 = 0.82;
|
|
87
|
+
export declare const PLAN_BLOCK_ADHERENCE = 0.8;
|
|
88
|
+
export declare const PLAN_COMPLETE_ADHERENCE = 0.8;
|
|
89
|
+
export declare const PLAN_RACE_WEEK_DAYS = 6;
|
|
90
|
+
export declare const PLAN_RUN_TYPES: string[];
|
|
91
|
+
export declare const PLAN_LONG_RUN_MIN_DISTANCE = 14000;
|
|
92
|
+
export declare const PLAN_LONG_RUN_MIN_DURATION: number;
|
|
93
|
+
export declare const PLAN_RACE_PACE_TOLERANCE = 0.04;
|
|
94
|
+
export declare const PLAN_RACE_PACE_MIN_DISTANCE = 5000;
|
|
95
|
+
export declare const STRENGTH_WINDOWS: {
|
|
96
|
+
id: string;
|
|
97
|
+
sessions: number;
|
|
98
|
+
days: number;
|
|
99
|
+
}[];
|
|
100
|
+
export declare const STRENGTH_HABIT_WEEKS = 4;
|
|
101
|
+
export declare const RECOVERY_RUN_DAYS = 3;
|
|
102
|
+
export declare const RECOVERY_RUN_ZONE = 2;
|
|
103
|
+
export declare const BRICK_TYPES: string[];
|
|
104
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../../src/achievements/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export { computeStreakStats } from './streak';
|
|
2
|
+
/** Tiempos candidatos por distancia para un entreno (stream → best-effort; sin stream → híbrido). */
|
|
3
|
+
export declare const computeWorkoutEfforts: (workout: any, series: any) => any;
|
|
4
|
+
/**
|
|
5
|
+
* Evalúa los logros del usuario PARA UN EVENTO y persiste los desbloqueados
|
|
6
|
+
* (idempotente, no revoca). Se llama justo donde ocurre la condición:
|
|
7
|
+
* - 'workout' → al completar un entreno. opts.workoutId procesa SOLO ese
|
|
8
|
+
* entreno para los PRs (incremental); sin él, recalcula todos.
|
|
9
|
+
* - 'chat' | 'survey' | 'availability' | 'nutrition' | 'food_photo' | 'wearable'.
|
|
10
|
+
* - 'goal' → al añadir un objetivo (re-evalúa Plan, incl. pc_nuevo_capitulo).
|
|
11
|
+
* - 'all' → todo (backfill; recalcula los PRs desde cero).
|
|
12
|
+
* Nunca lanza por categorías aisladas (no debe romper el flujo que la invoca).
|
|
13
|
+
*
|
|
14
|
+
* Devuelve los logros RECIÉN desbloqueados en esta llamada: [{id, fechaDesbloqueo,
|
|
15
|
+
* params?}] (params solo en los dist_* con PR). Sirve para que el FE parchee su caché
|
|
16
|
+
* y suba el chip sin refetch. RETRO-COMPATIBLE: los callers que ignoran el retorno
|
|
17
|
+
* (backfill, postHooks de saveWorkoutAplication) siguen funcionando igual.
|
|
18
|
+
*/
|
|
19
|
+
export declare const evaluateAchievements: (userId: any, event?: string, opts?: any) => Promise<Array<{
|
|
20
|
+
id: string;
|
|
21
|
+
fechaDesbloqueo: any;
|
|
22
|
+
params?: any;
|
|
23
|
+
}>>;
|
|
24
|
+
/**
|
|
25
|
+
* Variante acotada con timeout para el CAMINO CALIENTE (hooks de evento que
|
|
26
|
+
* responden HTTP). Devuelve los recién desbloqueados si el motor termina dentro
|
|
27
|
+
* de `timeoutMs`; si vence (o falla), devuelve [] sin romper el flujo que la invoca.
|
|
28
|
+
*
|
|
29
|
+
* La promesa del motor lleva su propio `.catch` ANTES del race, así que si vence el
|
|
30
|
+
* timeout sigue corriendo en background SIN unhandled rejection y persiste igual
|
|
31
|
+
* (el INSERT ocurre dentro de evaluateAchievements) → el FE lo recupera en el
|
|
32
|
+
* siguiente refetch. Nunca lanza.
|
|
33
|
+
*/
|
|
34
|
+
export declare const evaluateAchievementsBounded: (userId: any, event?: string, opts?: any, timeoutMs?: number) => Promise<Array<{
|
|
35
|
+
id: string;
|
|
36
|
+
fechaDesbloqueo: any;
|
|
37
|
+
params?: any;
|
|
38
|
+
}>>;
|
|
39
|
+
/** Set completo de logros desbloqueados del usuario (para lecturas / verificación). */
|
|
40
|
+
export declare const getUnlockedAchievements: (userId: any) => Promise<string[]>;
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/achievements/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAiK9C,qGAAqG;AAErG,eAAO,MAAM,qBAAqB,YAAa,GAAG,UAAU,GAAG,KAAG,GAuBjE,CAAC;AAkjBF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,WACvB,GAAG,UACJ,MAAM,SACP,GAAG,KACR,QAAQ,MAAM;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CAyGnE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,WAC9B,GAAG,UACJ,MAAM,SACP,GAAG,yBAER,QAAQ,MAAM;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,GAAG,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAE,CAAC,CAWnE,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,uBAAuB,WAAkB,GAAG,KAAG,QAAQ,MAAM,EAAE,CAO3E,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regla de racha: una semana cuenta como completada si el usuario hace al menos
|
|
3
|
+
* el 80% de los entrenamientos planificados de esa semana (regla 80%). Tipos
|
|
4
|
+
* entrenables, semanas ISO. La semana actual incompleta no rompe la racha.
|
|
5
|
+
*/
|
|
6
|
+
export declare const STREAK_COMPLETION_THRESHOLD = 0.8;
|
|
7
|
+
export declare const requiredFromPlanned: (plannedWorkouts: any) => number;
|
|
8
|
+
/**
|
|
9
|
+
* Racha actual (current) y récord histórico (longest), en semanas.
|
|
10
|
+
*
|
|
11
|
+
* @param userId ID del cliente.
|
|
12
|
+
* @param sinceDate Si se pasa, solo cuentan workouts con "DATE" >= sinceDate
|
|
13
|
+
* (ancla "empezar de cero" para logros). Sin él, comportamiento sobre todo el
|
|
14
|
+
* historial.
|
|
15
|
+
*/
|
|
16
|
+
export declare const computeStreakStats: (userId: any, sinceDate?: any) => Promise<{
|
|
17
|
+
current: number;
|
|
18
|
+
longest: number;
|
|
19
|
+
}>;
|
|
20
|
+
//# sourceMappingURL=streak.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streak.d.ts","sourceRoot":"","sources":["../../../../src/achievements/streak.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C,eAAO,MAAM,mBAAmB,oBAAqB,GAAG,KAAG,MAI1D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,WACrB,GAAG,cACA,GAAG;aACM,MAAM;aAAW,MAAM;EA4F5C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../../../src/chat/api/conversation.ts"],"names":[],"mappings":"AAmBA,QAAA,MAAM,iBAAiB,0BAA2B,GAAG,SA0BpD,CAAC;AAoGF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,uBAAuB,qCAAkC,GAAG,iBAwCjE,CAAC;AAmGF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,WAAW,0EAAuE,GAAG,
|
|
1
|
+
{"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../../../src/chat/api/conversation.ts"],"names":[],"mappings":"AAmBA,QAAA,MAAM,iBAAiB,0BAA2B,GAAG,SA0BpD,CAAC;AAoGF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,uBAAuB,qCAAkC,GAAG,iBAwCjE,CAAC;AAmGF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,QAAA,MAAM,WAAW,0EAAuE,GAAG,kBA0E1F,CAAC;AAEF,QAAA,MAAM,gBAAgB;;;;mBAqBrB,CAAC;AAyTF,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC"}
|