@runnerpro/backend 1.21.0 → 1.21.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"estructuraWorkout.d.ts","sourceRoot":"","sources":["../../../../src/workout/estructuraWorkout.ts"],"names":[],"mappings":"AAuCA,QAAA,MAAM,mBAAmB,YAAa,GAAG,cAAc,GAAG,QAiCzD,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,wBAAwB,cAAqB,GAAG,kBAkBrD,CAAC;AAuOF,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"estructuraWorkout.d.ts","sourceRoot":"","sources":["../../../../src/workout/estructuraWorkout.ts"],"names":[],"mappings":"AAuCA,QAAA,MAAM,mBAAmB,YAAa,GAAG,cAAc,GAAG,QAiCzD,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,wBAAwB,cAAqB,GAAG,kBAkBrD,CAAC;AAuPF,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"saveWorkoutAplication.d.ts","sourceRoot":"","sources":["../../../../src/workout/saveWorkoutAplication.ts"],"names":[],"mappings":"AAsPA;;;;;;;;;GASG;AACH,QAAA,MAAM,qBAAqB,SACnB,GAAG,UAED,GAAG,KACV,QAAQ,MAAM,GAAG,IAAI,CAmDvB,CAAC;AA+DF,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"saveWorkoutAplication.d.ts","sourceRoot":"","sources":["../../../../src/workout/saveWorkoutAplication.ts"],"names":[],"mappings":"AAwPA;;;;;;;;;GASG;AACH,QAAA,MAAM,qBAAqB,SACnB,GAAG,UAED,GAAG,KACV,QAAQ,MAAM,GAAG,IAAI,CA0DvB,CAAC;AA+DF,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"saveWorkoutLaps.d.ts","sourceRoot":"","sources":["../../../../src/workout/saveWorkoutLaps.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,QAAA,MAAM,eAAe,cAAqB,GAAG,QAAQ,GAAG,EAAE,mBAAmB,GAAG,KAAG,QAAQ,IAAI,CAuB9F,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"saveWorkoutLaps.d.ts","sourceRoot":"","sources":["../../../../src/workout/saveWorkoutLaps.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,QAAA,MAAM,eAAe,cAAqB,GAAG,QAAQ,GAAG,EAAE,mBAAmB,GAAG,KAAG,QAAQ,IAAI,CAuB9F,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -116,7 +116,17 @@ const saveDoneStructuraWorkoutWatch = (idWorkout, streamData, laps, workout, est
116
116
  });
117
117
  const numPasos = estructura.length;
118
118
  const numLaps = laps.length;
119
- if (numPasos !== numLaps && numPasos !== numLaps + 1) {
119
+ // Casos aceptados:
120
+ // - numLaps === numPasos: cada paso tiene su lap (1:1).
121
+ // - numLaps === numPasos - 1: el cooldown no se marcó como lap aparte
122
+ // (típico cuando el plan acaba en el último intervalo de trabajo y el
123
+ // runner enfría sin pulsar lap).
124
+ // - numLaps === numPasos + 1: el runner siguió moviéndose tras la vuelta
125
+ // a la calma planeada antes de parar el reloj → el lap "extra" final
126
+ // se absorbe en el último paso del plan (ver bucle abajo).
127
+ // Cualquier otra desviación es anómala (faltan laps en medio, doble extra,
128
+ // etc.) y se reporta para auditoría manual.
129
+ if (numPasos !== numLaps && numPasos !== numLaps + 1 && numLaps !== numPasos + 1) {
120
130
  return (0, sendMail_1.sendMail)({
121
131
  title: 'Estructura workout: laps no coinciden con pasos',
122
132
  subject: 'Dedup cross-proveedor - Error saving steps structure workout',
@@ -155,7 +165,13 @@ const saveDoneStructuraWorkoutWatch = (idWorkout, streamData, laps, workout, est
155
165
  }
156
166
  if (lapIndex !== null && lapIndex >= 0 && lapIndex < laps.length) {
157
167
  const currentLap = laps[lapIndex];
158
- const nextLap = laps[lapIndex + 1];
168
+ // Si hay un lap más que pasos y estamos en el último paso (cooldown),
169
+ // absorbemos el lap extra (post-cooldown): ignoramos laps[lapIndex+1]
170
+ // como límite y consideramos toda la actividad hasta workout.duration
171
+ // como parte de este paso. La duración resultante = cooldown planeado
172
+ // + lo que el runner siguió moviéndose después.
173
+ const isLastStepAbsorbingExtraLap = numLaps === numPasos + 1 && i === numPasos - 1;
174
+ const nextLap = isLastStepAbsorbingExtraLap ? null : laps[lapIndex + 1];
159
175
  if (nextLap) {
160
176
  duration = nextLap.durationStartLap - currentLap.durationStartLap;
161
177
  }
@@ -95,6 +95,7 @@ function camelizeRow(row) {
95
95
  });
96
96
  return aux;
97
97
  }
98
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
98
99
  const withTx = (fn) => __awaiter(void 0, void 0, void 0, function* () {
99
100
  const client = yield db_1.pool.connect();
100
101
  try {
@@ -252,9 +253,16 @@ _data) => __awaiter(void 0, void 0, void 0, function* () {
252
253
  // (Strava-webhook y Garmin-push pueden entrar casi a la vez).
253
254
  yield q('SELECT pg_advisory_xact_lock(?)', [hashInt(`${opts.idCliente}|${dateStr}|${bucketTipo(opts.type)}`)]);
254
255
  // 1) dedup intra-proveedor / completar planificado (comportamiento actual común).
256
+ // Ambas ramas filtran por "ID CLIENTE": el activityId de un proveedor es
257
+ // global pero pertenece a un único usuario en su plataforma; si por
258
+ // cualquier motivo (test, re-conexión OAuth con cuenta distinta, fallo
259
+ // de resolución upstream) llegara con un idCliente distinto al que ya
260
+ // tenía esa fila, NO debemos hacer merge cross-cliente.
255
261
  const [exist] = yield q(`SELECT "ID", "TYPE" FROM "WORKOUT"
256
- WHERE ("ID CLIENTE" = ? AND "DATE" = ? AND ${pt.sql} AND "DONE" = FALSE AND "SHOW CLIENT" = TRUE)
257
- OR ("ID APLICATION" = ? AND "TIPO APLICATION" = ?)
262
+ WHERE "ID CLIENTE" = ? AND (
263
+ ("DATE" = ? AND ${pt.sql} AND "DONE" = FALSE AND "SHOW CLIENT" = TRUE)
264
+ OR ("ID APLICATION" = ? AND "TIPO APLICATION" = ?)
265
+ )
258
266
  LIMIT 1`, [opts.idCliente, dateStr, ...pt.params, opts.aplicationId, opts.aplicationType]);
259
267
  if (exist) {
260
268
  yield aplicarMerge(q, exist.id, opts, false);
@@ -37,6 +37,7 @@ const estructuraWorkout_1 = require("./estructuraWorkout");
37
37
  * @param {{index:number,durationStartLap:number}[]} laps
38
38
  * @param {number} aplicationType TIPO_APLICACION.* (reservado para trazabilidad)
39
39
  */
40
+ // eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
40
41
  const saveWorkoutLaps = (idWorkout, laps, aplicationType) => __awaiter(void 0, void 0, void 0, function* () {
41
42
  if (!idWorkout)
42
43
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runnerpro/backend",
3
- "version": "1.21.0",
3
+ "version": "1.21.2",
4
4
  "description": "A collection of common backend functions",
5
5
  "exports": {
6
6
  ".": "./lib/cjs/index.js"