@runnerpro/backend 1.21.12 → 1.21.15

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 (51) hide show
  1. package/lib/cjs/achievements/catalog.js +204 -0
  2. package/lib/cjs/achievements/index.js +805 -0
  3. package/lib/cjs/achievements/streak.js +126 -0
  4. package/lib/cjs/chat/api/conversation.js +21 -29
  5. package/lib/cjs/chat/exposed/conversation.js +0 -7
  6. package/lib/cjs/chat/index.js +0 -7
  7. package/lib/cjs/index.js +34 -5
  8. package/lib/cjs/locale/en.js +0 -4
  9. package/lib/cjs/locale/es.js +0 -4
  10. package/lib/cjs/locale/fr.js +0 -4
  11. package/lib/cjs/locale/it.js +0 -4
  12. package/lib/cjs/prompt/azureModel.js +7 -35
  13. package/lib/cjs/prompt/constants.js +12 -67
  14. package/lib/cjs/prompt/googleModel.js +6 -11
  15. package/lib/cjs/prompt/index.js +1 -4
  16. package/lib/cjs/prompt/modelPricing.js +1 -22
  17. package/lib/cjs/sendMail/index.js +1 -1
  18. package/lib/cjs/sendNotification/index.js +4 -88
  19. package/lib/cjs/types/achievements/catalog.d.ts +104 -0
  20. package/lib/cjs/types/achievements/catalog.d.ts.map +1 -0
  21. package/lib/cjs/types/achievements/index.d.ts +41 -0
  22. package/lib/cjs/types/achievements/index.d.ts.map +1 -0
  23. package/lib/cjs/types/achievements/streak.d.ts +20 -0
  24. package/lib/cjs/types/achievements/streak.d.ts.map +1 -0
  25. package/lib/cjs/types/chat/api/conversation.d.ts.map +1 -1
  26. package/lib/cjs/types/chat/exposed/conversation.d.ts.map +1 -1
  27. package/lib/cjs/types/chat/index.d.ts.map +1 -1
  28. package/lib/cjs/types/index.d.ts +4 -2
  29. package/lib/cjs/types/index.d.ts.map +1 -1
  30. package/lib/cjs/types/locale/en.d.ts +0 -4
  31. package/lib/cjs/types/locale/en.d.ts.map +1 -1
  32. package/lib/cjs/types/locale/es.d.ts +0 -4
  33. package/lib/cjs/types/locale/es.d.ts.map +1 -1
  34. package/lib/cjs/types/locale/fr.d.ts +0 -4
  35. package/lib/cjs/types/locale/fr.d.ts.map +1 -1
  36. package/lib/cjs/types/locale/it.d.ts +0 -4
  37. package/lib/cjs/types/locale/it.d.ts.map +1 -1
  38. package/lib/cjs/types/prompt/azureModel.d.ts.map +1 -1
  39. package/lib/cjs/types/prompt/constants.d.ts +7 -28
  40. package/lib/cjs/types/prompt/constants.d.ts.map +1 -1
  41. package/lib/cjs/types/prompt/googleModel.d.ts.map +1 -1
  42. package/lib/cjs/types/prompt/index.d.ts +2 -2
  43. package/lib/cjs/types/prompt/index.d.ts.map +1 -1
  44. package/lib/cjs/types/prompt/modelPricing.d.ts.map +1 -1
  45. package/lib/cjs/types/sendNotification/index.d.ts +1 -20
  46. package/lib/cjs/types/sendNotification/index.d.ts.map +1 -1
  47. package/lib/cjs/types/workout/planificacionPrueba7dias/index.d.ts.map +1 -1
  48. package/lib/cjs/types/workout/saveWorkoutAplication.d.ts.map +1 -1
  49. package/lib/cjs/workout/planificacionPrueba7dias/index.js +7 -3
  50. package/lib/cjs/workout/saveWorkoutAplication.js +10 -0
  51. package/package.json +2 -2
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ /**
3
+ * Catálogo de REGLAS de logros (umbrales). Vive en el paquete compartido para
4
+ * que lo usen tanto los hooks de evento (saveWorkoutAplication.postHooks y los
5
+ * eventos de Cliente-backend) como el backfill.
6
+ *
7
+ * Los `id` deben coincidir EXACTAMENTE con el catálogo de PRESENTACIÓN del
8
+ * frontend (Cliente-app/src/screens/PlanMap/utils/achievementCatalog.js).
9
+ * Frontend = labels/iconos/colores; aquí = umbrales/reglas.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BRICK_TYPES = exports.RECOVERY_RUN_ZONE = exports.RECOVERY_RUN_DAYS = exports.STRENGTH_HABIT_WEEKS = exports.STRENGTH_WINDOWS = exports.PLAN_RACE_PACE_MIN_DISTANCE = exports.PLAN_RACE_PACE_TOLERANCE = exports.PLAN_LONG_RUN_MIN_DURATION = exports.PLAN_LONG_RUN_MIN_DISTANCE = exports.PLAN_RUN_TYPES = exports.PLAN_RACE_WEEK_DAYS = exports.PLAN_COMPLETE_ADHERENCE = exports.PLAN_BLOCK_ADHERENCE = exports.PLAN_ADHERENCE_82 = exports.PLAN_SESSION_TYPES = exports.WEARABLE_APPS = exports.NUTRITION_DAYS_THRESHOLD = exports.NUTRITION_MEALS = exports.CHAT_MSG = exports.TRI_SWIM_DISTANCE = exports.TRAIL_ELEVATION = exports.TRAIL_DISTANCE = exports.SWIM_DISTANCE = exports.CYCLING_VOLUME = exports.CYCLING_DISTANCE = exports.RACE_COUNT = exports.STRENGTH_COUNT = exports.PR_DISTANCE_BADGE = exports.PR_MANUAL_FLOOR = exports.PR_NO_STREAM_MARGIN = exports.TIME_PR = exports.PACE = exports.PR_DISTANCES = exports.RUNNING_TYPES = exports.VOLUME = exports.DISTANCE = exports.CONSISTENCY = void 0;
13
+ // ── Consistencia (racha por semanas, contra `longest`) ──────────────────────
14
+ exports.CONSISTENCY = [
15
+ { id: 'consistency_1w', weeks: 1 },
16
+ { id: 'consistency_2w', weeks: 2 },
17
+ { id: 'consistency_4w', weeks: 4 },
18
+ { id: 'consistency_8w', weeks: 8 },
19
+ { id: 'consistency_12w', weeks: 12 },
20
+ { id: 'consistency_26w', weeks: 26 },
21
+ { id: 'consistency_52w', weeks: 52 },
22
+ { id: 'consistency_104w', weeks: 104 },
23
+ { id: 'consistency_156w', weeks: 156 },
24
+ ];
25
+ // ── Distancia (máx distancia de un entreno de carrera, metros; cascada) ─────
26
+ exports.DISTANCE = [
27
+ { id: 'dist_1k', meters: 1000 },
28
+ { id: 'dist_2k', meters: 2000 },
29
+ { id: 'dist_3k', meters: 3000 },
30
+ { id: 'dist_5k', meters: 5000 },
31
+ { id: 'dist_7k', meters: 7000 },
32
+ { id: 'dist_10k', meters: 10000 },
33
+ { id: 'dist_15k', meters: 15000 },
34
+ { id: 'dist_21k', meters: 21000 },
35
+ { id: 'dist_25k', meters: 25000 },
36
+ { id: 'dist_30k', meters: 30000 },
37
+ { id: 'dist_35k', meters: 35000 },
38
+ { id: 'dist_42k', meters: 42000 },
39
+ { id: 'dist_50k', meters: 50000 },
40
+ { id: 'dist_100k', meters: 100000 },
41
+ ];
42
+ // ── Volumen acumulado (suma km corridos desde el ancla) ─────────────────────
43
+ exports.VOLUME = [
44
+ { id: 'vol_50', km: 50 },
45
+ { id: 'vol_100', km: 100 },
46
+ { id: 'vol_250', km: 250 },
47
+ { id: 'vol_500', km: 500 },
48
+ { id: 'vol_1000', km: 1000 },
49
+ { id: 'vol_2500', km: 2500 },
50
+ { id: 'vol_5000', km: 5000 },
51
+ { id: 'vol_10000', km: 10000 },
52
+ { id: 'vol_25000', km: 25000 },
53
+ ];
54
+ // Tipos que cuentan como "carrera a pie" (mismos equivalentes que saveWorkoutAplication).
55
+ exports.RUNNING_TYPES = ['CORRER', 'TRAIL', 'COMPETICION'];
56
+ // ── Ritmo / PRs ─────────────────────────────────────────────────────────────
57
+ exports.PR_DISTANCES = [1000, 5000, 10000, 21097, 42195];
58
+ exports.PACE = [
59
+ { id: 'pace_sub8', maxSecPerKm: 8 * 60 },
60
+ { id: 'pace_sub7', maxSecPerKm: 7 * 60 },
61
+ { id: 'pace_sub630', maxSecPerKm: 6 * 60 + 30 },
62
+ { id: 'pace_sub6', maxSecPerKm: 6 * 60 },
63
+ { id: 'pace_sub530', maxSecPerKm: 5 * 60 + 30 },
64
+ { id: 'pace_sub5', maxSecPerKm: 5 * 60 },
65
+ ];
66
+ exports.TIME_PR = [
67
+ { id: 'pr_5k_sub30', distance: 5000, maxSeconds: 30 * 60 },
68
+ { id: 'pr_5k_sub25', distance: 5000, maxSeconds: 25 * 60 },
69
+ { id: 'pr_5k_sub20', distance: 5000, maxSeconds: 20 * 60 },
70
+ { id: 'pr_10k_sub60', distance: 10000, maxSeconds: 60 * 60 },
71
+ { id: 'pr_10k_sub50', distance: 10000, maxSeconds: 50 * 60 },
72
+ { id: 'pr_10k_sub45', distance: 10000, maxSeconds: 45 * 60 },
73
+ { id: 'pr_21k_sub2h', distance: 21097, maxSeconds: 120 * 60 },
74
+ { id: 'pr_21k_sub145', distance: 21097, maxSeconds: 105 * 60 },
75
+ { id: 'pr_21k_sub130', distance: 21097, maxSeconds: 90 * 60 },
76
+ { id: 'pr_42k_sub4h', distance: 42195, maxSeconds: 240 * 60 },
77
+ { id: 'pr_42k_sub330', distance: 42195, maxSeconds: 210 * 60 },
78
+ { id: 'pr_42k_sub3h', distance: 42195, maxSeconds: 180 * 60 },
79
+ ];
80
+ // Sin stream: cuenta como esfuerzo de X solo si distancia total ∈ [X, X*margen].
81
+ exports.PR_NO_STREAM_MARGIN = 1.05;
82
+ // Entrada MANUAL (sin stream): la app guarda la media/maratón redondeadas
83
+ // (21000/42000), no la distancia oficial (21097/42195). Sin esto, una media
84
+ // manual quedaría justo por debajo del oficial y NO contaría como PR. Este mapa
85
+ // "oficial → suelo manual aceptado" hace que se dé por hecho que 21000 = media y
86
+ // 42000 = maratón. NO afecta al camino con stream (Strava/Garmin), que sigue
87
+ // usando la distancia oficial con ventana deslizante. Solo aplica sin stream.
88
+ exports.PR_MANUAL_FLOOR = {
89
+ 21097: 21000,
90
+ 42195: 42000,
91
+ };
92
+ // Dónde se guarda el PR de cada distancia: en los PARAMS del logro de distancia
93
+ // correspondiente (modelo de tabla única). metros → LOGRO ID.
94
+ exports.PR_DISTANCE_BADGE = {
95
+ 1000: 'dist_1k',
96
+ 5000: 'dist_5k',
97
+ 10000: 'dist_10k',
98
+ 21097: 'dist_21k',
99
+ 42195: 'dist_42k',
100
+ };
101
+ // ── Fuerza (conteo de sesiones FUERZA) ──────────────────────────────────────
102
+ exports.STRENGTH_COUNT = [
103
+ { id: 'str_first', count: 1 },
104
+ { id: 'str_10', count: 10 },
105
+ { id: 'str_25', count: 25 },
106
+ { id: 'str_50', count: 50 },
107
+ { id: 'str_100', count: 100 },
108
+ { id: 'str_250', count: 250 },
109
+ { id: 'str_500', count: 500 },
110
+ ];
111
+ // ── Post-carrera (COMPETICION completadas) ──────────────────────────────────
112
+ exports.RACE_COUNT = [
113
+ { id: 'pc_finisher', count: 1 },
114
+ { id: 'pc_10_medallero', count: 10 },
115
+ ];
116
+ // ── Ciclismo (BIKE) ─────────────────────────────────────────────────────────
117
+ exports.CYCLING_DISTANCE = [
118
+ { id: 'bike_20k', meters: 20000 },
119
+ { id: 'bike_50k', meters: 50000 },
120
+ { id: 'bike_100k', meters: 100000 },
121
+ { id: 'bike_200k', meters: 200000 },
122
+ ];
123
+ exports.CYCLING_VOLUME = [
124
+ { id: 'bike_500', km: 500 },
125
+ { id: 'bike_1000', km: 1000 },
126
+ { id: 'bike_2500', km: 2500 },
127
+ ];
128
+ // ── Natación (SWIM) ─────────────────────────────────────────────────────────
129
+ exports.SWIM_DISTANCE = [
130
+ { id: 'swim_500m', meters: 500 },
131
+ { id: 'swim_1k', meters: 1000 },
132
+ { id: 'swim_2k', meters: 2000 },
133
+ { id: 'swim_5k', meters: 5000 },
134
+ ];
135
+ // ── Trail (TRAIL) ───────────────────────────────────────────────────────────
136
+ exports.TRAIL_DISTANCE = [
137
+ { id: 'trail_10k', meters: 10000 },
138
+ { id: 'trail_21k', meters: 21000 },
139
+ { id: 'trail_30k', meters: 30000 },
140
+ { id: 'trail_42k', meters: 42000 },
141
+ ];
142
+ // Desnivel ACUMULADO (suma de DESNIVEL en metros) de los entrenos de trail.
143
+ exports.TRAIL_ELEVATION = [
144
+ { id: 'trail_desnivel_1k', meters: 1000 },
145
+ { id: 'trail_desnivel_5k', meters: 5000 },
146
+ { id: 'trail_desnivel_10k', meters: 10000 },
147
+ ];
148
+ // ── Triatlón (nado: mismos datos SWIM que Natación) ─────────────────────────
149
+ exports.TRI_SWIM_DISTANCE = [
150
+ { id: 'tri_500m', meters: 500 },
151
+ { id: 'tri_1k', meters: 1000 },
152
+ { id: 'tri_2k', meters: 2000 },
153
+ ];
154
+ // ── Coach & Chat (mensajes enviados por el usuario) ─────────────────────────
155
+ exports.CHAT_MSG = [
156
+ { id: 'coach_1er_msg', count: 1 },
157
+ { id: 'coach_10_msg', count: 10 },
158
+ ];
159
+ // ── Nutrición (comidas registradas) ─────────────────────────────────────────
160
+ exports.NUTRITION_MEALS = [
161
+ { id: 'nut_1a_receta', count: 1 },
162
+ { id: 'nut_50_comidas', count: 50 },
163
+ ];
164
+ exports.NUTRITION_DAYS_THRESHOLD = 7; // nut_7d_plan
165
+ // ── Wearables (conexiones; TIPO APLICATION numérico) ────────────────────────
166
+ exports.WEARABLE_APPS = [
167
+ { id: 'wear_garmin', tipo: 2 },
168
+ { id: 'wear_strava', tipo: 1 },
169
+ { id: 'wear_apple', tipo: 5 },
170
+ ];
171
+ // ── Plan + Hitos del Plan (TIER 1) ───────────────────────────────────────────
172
+ // Adherencia al plan = sesiones planificadas (WORKOUT "SHOW CLIENT"=true de un
173
+ // tipo entrenable) completadas / debidas (DATE <= hoy; no penaliza las futuras).
174
+ // Los bloques base/desarrollo/pico/taper salen de CLIENTE."ALGORITMO BLOQUE N
175
+ // INICIO/FIN". La semana de carrera, de la competición alrededor de "GOAL DATE".
176
+ exports.PLAN_SESSION_TYPES = ['CORRER', 'FUERZA', 'SPORT', 'BIKE', 'SWIM', 'TRAIL', 'WALK'];
177
+ exports.PLAN_ADHERENCE_82 = 0.82; // plan_82
178
+ exports.PLAN_BLOCK_ADHERENCE = 0.8; // hito_base/desarrollo/pico/taper (≥80% del bloque)
179
+ exports.PLAN_COMPLETE_ADHERENCE = 0.8; // plan_completado (al alcanzar GOAL DATE)
180
+ exports.PLAN_RACE_WEEK_DAYS = 6; // días antes de GOAL DATE que cuentan como semana de carrera
181
+ // Tipos que cuentan como carrera a pie para tirada larga / ritmo carrera.
182
+ exports.PLAN_RUN_TYPES = ['CORRER', 'TRAIL'];
183
+ // plan_tirada_larga: la tirada larga del plan (la carrera prevista más larga de
184
+ // su semana) completada, si supera un mínimo de volumen.
185
+ exports.PLAN_LONG_RUN_MIN_DISTANCE = 14000; // metros
186
+ exports.PLAN_LONG_RUN_MIN_DURATION = 75 * 60; // segundos
187
+ // plan_ritmo_carrera: carrera planificada hecha cuyo ritmo medio (DURATION/
188
+ // DISTANCE) ≈ ritmo objetivo (GOAL DURATION/GOAL DISTANCE). Solo si hay objetivo.
189
+ exports.PLAN_RACE_PACE_TOLERANCE = 0.04; // ±4%
190
+ exports.PLAN_RACE_PACE_MIN_DISTANCE = 5000; // metros (esfuerzo significativo)
191
+ // ── Fuerza: frecuencia / hábito ──────────────────────────────────────────────
192
+ // Sobre las fechas de las sesiones de FUERZA completadas (desde el ancla).
193
+ exports.STRENGTH_WINDOWS = [
194
+ { id: 'str_racha7d', sessions: 3, days: 7 }, // ≥3 sesiones en 7 días
195
+ { id: 'str_racha30d', sessions: 10, days: 30 }, // ≥10 sesiones en 30 días
196
+ ];
197
+ exports.STRENGTH_HABIT_WEEKS = 4; // str_habito: 4 semanas ISO consecutivas con ≥1 sesión
198
+ // ── Post-carrera: recovery run ────────────────────────────────────────────────
199
+ // pc_recovery: rodaje suave (zona) en los N días siguientes a una COMPETICION hecha.
200
+ exports.RECOVERY_RUN_DAYS = 3;
201
+ exports.RECOVERY_RUN_ZONE = 2;
202
+ // ── Triatlón: brick ───────────────────────────────────────────────────────────
203
+ // tri_brick: una BIKE y una CORRER completadas el mismo día.
204
+ exports.BRICK_TYPES = ['BIKE', 'CORRER'];