@runnerpro/backend 1.33.1 → 1.34.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.
- package/lib/cjs/almacenamiento/index.js +153 -0
- package/lib/cjs/index.js +9 -2
- package/lib/cjs/types/almacenamiento/index.d.ts +65 -0
- package/lib/cjs/types/almacenamiento/index.d.ts.map +1 -0
- package/lib/cjs/types/index.d.ts +1 -0
- package/lib/cjs/types/index.d.ts.map +1 -1
- package/lib/cjs/types/workout/saveWorkoutAplication.d.ts +22 -1
- package/lib/cjs/types/workout/saveWorkoutAplication.d.ts.map +1 -1
- package/lib/cjs/workout/saveWorkoutAplication.js +99 -11
- package/package.json +4 -2
|
@@ -0,0 +1,153 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.urlPublica = exports.Storage = exports.Contenedor = exports.Archivo = exports.TIPO_POR_DEFECTO = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* Almacenamiento de archivos en Azure Blob Storage.
|
|
15
|
+
*
|
|
16
|
+
* Expone la MISMA forma que el cliente de `@google-cloud/storage` que había antes
|
|
17
|
+
* (`storage.bucket(nombre).file(ruta).save()/download()/exists()/delete()`), para que los
|
|
18
|
+
* puntos de llamada no cambien más allá del import. Se migró el 19-ago-2026: los servicios
|
|
19
|
+
* ya corrían en Azure pero seguían escribiendo en los cubos de Google, así que cada archivo
|
|
20
|
+
* nuevo nacía en la nube que estábamos apagando.
|
|
21
|
+
*
|
|
22
|
+
* El "nombre de cubo" es ahora `cuenta/contenedor` (p.ej. `rppublicprod/public`), que es lo
|
|
23
|
+
* que llevan las variables CLOUD_STORAGE_BUCKET y CLOUD_STORAGE_BUCKET_PUBLIC. La clave de
|
|
24
|
+
* cada cuenta se lee de `AZURE_STORAGE_KEY_<CUENTA EN MAYÚSCULAS>`.
|
|
25
|
+
*
|
|
26
|
+
* Gemelo de `Cliente-backend/src/utils/almacenamiento.js`: si cambias uno, cambia el otro.
|
|
27
|
+
*/
|
|
28
|
+
const storage_blob_1 = require("@azure/storage-blob");
|
|
29
|
+
/**
|
|
30
|
+
* Tipo por defecto cuando quien sube no dice cuál es. Es exactamente lo que ponía Google en
|
|
31
|
+
* los archivos sin extensión (los mapas de entreno no la tienen), así que respetarlo evita
|
|
32
|
+
* que un archivo servido cambie de tipo al migrar.
|
|
33
|
+
*/
|
|
34
|
+
exports.TIPO_POR_DEFECTO = 'application/octet-stream';
|
|
35
|
+
/** Reintentos por defecto del SDK de Azure si nadie pide otra cosa. Son los suyos. */
|
|
36
|
+
const REINTENTOS_POR_DEFECTO = 4;
|
|
37
|
+
/** Clientes ya construidos, por cuenta+presupuesto. Uno por petición sería tirar conexiones. */
|
|
38
|
+
const clientesPorCuenta = new Map();
|
|
39
|
+
/**
|
|
40
|
+
* Nombres de los cubos viejos de Google y dónde viven ahora en Azure.
|
|
41
|
+
*
|
|
42
|
+
* Está aquí para que el despliegue no tenga que ser coordinado: los consumidores piden el
|
|
43
|
+
* paquete con `^1.31`, así que cualquier servicio que se redespliegue por un motivo ajeno se
|
|
44
|
+
* trae esta versión. Si además hubiera que haber cambiado sus variables a mano y en el mismo
|
|
45
|
+
* momento, ese servicio subiría a ninguna parte hasta que alguien se diera cuenta. Con la
|
|
46
|
+
* traducción aquí, la configuración vieja sigue funcionando y cambiar las variables pasa a ser
|
|
47
|
+
* limpieza, no un requisito.
|
|
48
|
+
*/
|
|
49
|
+
const CUBOS_ANTIGUOS = {
|
|
50
|
+
web_runnerpro: 'rpwebprod/web',
|
|
51
|
+
runnerpro_public_prod: 'rppublicprod/public',
|
|
52
|
+
assets_runnerpro: 'rppublicprod/assets',
|
|
53
|
+
};
|
|
54
|
+
const partirNombre = (nombre) => {
|
|
55
|
+
if (!nombre) {
|
|
56
|
+
throw new Error('almacenamiento: falta el nombre del contenedor (cuenta/contenedor)');
|
|
57
|
+
}
|
|
58
|
+
const [cuenta, contenedor] = (CUBOS_ANTIGUOS[nombre] || nombre).split('/');
|
|
59
|
+
if (!cuenta || !contenedor) {
|
|
60
|
+
throw new Error(`almacenamiento: "${nombre}" no tiene la forma cuenta/contenedor (p.ej. rppublicprod/public)`);
|
|
61
|
+
}
|
|
62
|
+
return { cuenta, contenedor };
|
|
63
|
+
};
|
|
64
|
+
const clienteDeCuenta = (cuenta, presupuestoS) => {
|
|
65
|
+
const llave = `${cuenta}|${presupuestoS || 0}`;
|
|
66
|
+
const yaEsta = clientesPorCuenta.get(llave);
|
|
67
|
+
if (yaEsta)
|
|
68
|
+
return yaEsta;
|
|
69
|
+
const clave = process.env[`AZURE_STORAGE_KEY_${cuenta.toUpperCase()}`];
|
|
70
|
+
if (!clave) {
|
|
71
|
+
throw new Error(`almacenamiento: falta la variable AZURE_STORAGE_KEY_${cuenta.toUpperCase()}`);
|
|
72
|
+
}
|
|
73
|
+
const opciones = presupuestoS
|
|
74
|
+
? {
|
|
75
|
+
retryOptions: {
|
|
76
|
+
maxTries: REINTENTOS_POR_DEFECTO,
|
|
77
|
+
tryTimeoutInMs: Math.floor((presupuestoS * 1000) / REINTENTOS_POR_DEFECTO),
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: undefined;
|
|
81
|
+
const cliente = new storage_blob_1.BlobServiceClient(`https://${cuenta}.blob.core.windows.net`, new storage_blob_1.StorageSharedKeyCredential(cuenta, clave), opciones);
|
|
82
|
+
clientesPorCuenta.set(llave, cliente);
|
|
83
|
+
return cliente;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Un archivo dentro de un contenedor. `download()` y `exists()` devuelven ARRAY porque así
|
|
87
|
+
* lo desestructura el código que ya existe (`const [data] = await ....download()`).
|
|
88
|
+
*/
|
|
89
|
+
class Archivo {
|
|
90
|
+
constructor(contenedor, ruta) {
|
|
91
|
+
this.ruta = ruta;
|
|
92
|
+
this.blob = contenedor.getBlockBlobClient(ruta);
|
|
93
|
+
}
|
|
94
|
+
save(datos, opciones = {}) {
|
|
95
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
96
|
+
const buffer = Buffer.isBuffer(datos) ? datos : Buffer.from(datos);
|
|
97
|
+
yield this.blob.uploadData(buffer, {
|
|
98
|
+
blobHTTPHeaders: { blobContentType: opciones.contentType || exports.TIPO_POR_DEFECTO },
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
download() {
|
|
103
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
return [yield this.blob.downloadToBuffer()];
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
exists() {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
return [yield this.blob.exists()];
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
delete() {
|
|
113
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
114
|
+
yield this.blob.deleteIfExists();
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.Archivo = Archivo;
|
|
119
|
+
/** Un contenedor. Equivale al `Bucket` de Google. */
|
|
120
|
+
class Contenedor {
|
|
121
|
+
constructor(nombre, presupuestoS) {
|
|
122
|
+
const { cuenta, contenedor } = partirNombre(nombre);
|
|
123
|
+
this.contenedor = clienteDeCuenta(cuenta, presupuestoS).getContainerClient(contenedor);
|
|
124
|
+
}
|
|
125
|
+
file(ruta) {
|
|
126
|
+
return new Archivo(this.contenedor, ruta);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.Contenedor = Contenedor;
|
|
130
|
+
/** Equivale al `Storage` de Google: `new Storage().bucket(nombre)`. */
|
|
131
|
+
class Storage {
|
|
132
|
+
/**
|
|
133
|
+
* Acepta el mismo objeto de opciones que el cliente de Google. `keyFilename` se ignora (la
|
|
134
|
+
* credencial de Azure va por variable de entorno); `retryOptions.totalTimeout` sí se respeta.
|
|
135
|
+
*/
|
|
136
|
+
constructor(opciones = {}) {
|
|
137
|
+
var _a;
|
|
138
|
+
this.presupuestoS = (_a = opciones === null || opciones === void 0 ? void 0 : opciones.retryOptions) === null || _a === void 0 ? void 0 : _a.totalTimeout;
|
|
139
|
+
}
|
|
140
|
+
bucket(nombre) {
|
|
141
|
+
return new Contenedor(nombre, this.presupuestoS);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.Storage = Storage;
|
|
145
|
+
/**
|
|
146
|
+
* Dirección pública de un archivo. Sustituye a los
|
|
147
|
+
* `https://storage.googleapis.com/${bucket}/${ruta}` que se construían a mano.
|
|
148
|
+
*/
|
|
149
|
+
const urlPublica = (nombre, ruta) => {
|
|
150
|
+
const { cuenta, contenedor } = partirNombre(nombre);
|
|
151
|
+
return `https://${cuenta}.blob.core.windows.net/${contenedor}/${ruta}`;
|
|
152
|
+
};
|
|
153
|
+
exports.urlPublica = urlPublica;
|
package/lib/cjs/index.js
CHANGED
|
@@ -23,8 +23,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
27
|
-
exports.
|
|
26
|
+
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.TIPO_POR_DEFECTO = exports.urlPublica = exports.Archivo = exports.Contenedor = exports.StorageAzure = exports.achievementsCatalog = void 0;
|
|
27
|
+
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_FALLBACK_MODELS = exports.AZURE_PRIMARY_MODELS = exports.AZURE_DEEPSEEK_V4_FLASH = exports.AZURE_DEEPSEEK_V4_PRO = exports.AZURE_GPT_5_4_NANO = exports.AZURE_GPT_5_4_MINI = exports.AZURE_GPT_5_6_LUNA = exports.AZURE_GPT_5_6_TERRA = exports.AZURE_GPT_5_6_SOL = exports.AZURE_GPT_5_5 = exports.AZURE_DEEPSEEK_V4_FLASH_DEPLOYMENT = exports.AZURE_DEEPSEEK_V4_PRO_DEPLOYMENT = exports.AZURE_GPT_5_4_NANO_DEPLOYMENT = exports.AZURE_GPT_5_4_MINI_DEPLOYMENT = exports.AZURE_GPT_5_6_LUNA_DEPLOYMENT = exports.AZURE_GPT_5_6_TERRA_DEPLOYMENT = exports.AZURE_GPT_5_6_SOL_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 = exports.analyzeFile = exports.describeTextFile = exports.describePdf = exports.describeVideo = exports.describeImage = exports.transcribeAudio = exports.updateSenderView = exports.saveResponseTime = exports.getZone = void 0;
|
|
28
|
+
exports.calculateCost = exports.MODEL_PRICING = exports.AISTUDIO_PREFIX = exports.BEDROCK_CLAUDE_HAIKU = void 0;
|
|
28
29
|
const sendNotification_1 = require("./sendNotification");
|
|
29
30
|
Object.defineProperty(exports, "sendNotification", { enumerable: true, get: function () { return sendNotification_1.sendNotification; } });
|
|
30
31
|
const sleep_1 = require("./sleep");
|
|
@@ -152,3 +153,9 @@ Object.defineProperty(exports, "BEDROCK_CLAUDE_HAIKU", { enumerable: true, get:
|
|
|
152
153
|
Object.defineProperty(exports, "AISTUDIO_PREFIX", { enumerable: true, get: function () { return prompt_1.AISTUDIO_PREFIX; } });
|
|
153
154
|
Object.defineProperty(exports, "MODEL_PRICING", { enumerable: true, get: function () { return prompt_1.MODEL_PRICING; } });
|
|
154
155
|
Object.defineProperty(exports, "calculateCost", { enumerable: true, get: function () { return prompt_1.calculateCost; } });
|
|
156
|
+
var almacenamiento_1 = require("./almacenamiento");
|
|
157
|
+
Object.defineProperty(exports, "StorageAzure", { enumerable: true, get: function () { return almacenamiento_1.Storage; } });
|
|
158
|
+
Object.defineProperty(exports, "Contenedor", { enumerable: true, get: function () { return almacenamiento_1.Contenedor; } });
|
|
159
|
+
Object.defineProperty(exports, "Archivo", { enumerable: true, get: function () { return almacenamiento_1.Archivo; } });
|
|
160
|
+
Object.defineProperty(exports, "urlPublica", { enumerable: true, get: function () { return almacenamiento_1.urlPublica; } });
|
|
161
|
+
Object.defineProperty(exports, "TIPO_POR_DEFECTO", { enumerable: true, get: function () { return almacenamiento_1.TIPO_POR_DEFECTO; } });
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* Almacenamiento de archivos en Azure Blob Storage.
|
|
4
|
+
*
|
|
5
|
+
* Expone la MISMA forma que el cliente de `@google-cloud/storage` que había antes
|
|
6
|
+
* (`storage.bucket(nombre).file(ruta).save()/download()/exists()/delete()`), para que los
|
|
7
|
+
* puntos de llamada no cambien más allá del import. Se migró el 19-ago-2026: los servicios
|
|
8
|
+
* ya corrían en Azure pero seguían escribiendo en los cubos de Google, así que cada archivo
|
|
9
|
+
* nuevo nacía en la nube que estábamos apagando.
|
|
10
|
+
*
|
|
11
|
+
* El "nombre de cubo" es ahora `cuenta/contenedor` (p.ej. `rppublicprod/public`), que es lo
|
|
12
|
+
* que llevan las variables CLOUD_STORAGE_BUCKET y CLOUD_STORAGE_BUCKET_PUBLIC. La clave de
|
|
13
|
+
* cada cuenta se lee de `AZURE_STORAGE_KEY_<CUENTA EN MAYÚSCULAS>`.
|
|
14
|
+
*
|
|
15
|
+
* Gemelo de `Cliente-backend/src/utils/almacenamiento.js`: si cambias uno, cambia el otro.
|
|
16
|
+
*/
|
|
17
|
+
import { ContainerClient } from '@azure/storage-blob';
|
|
18
|
+
/**
|
|
19
|
+
* Tipo por defecto cuando quien sube no dice cuál es. Es exactamente lo que ponía Google en
|
|
20
|
+
* los archivos sin extensión (los mapas de entreno no la tienen), así que respetarlo evita
|
|
21
|
+
* que un archivo servido cambie de tipo al migrar.
|
|
22
|
+
*/
|
|
23
|
+
export declare const TIPO_POR_DEFECTO = "application/octet-stream";
|
|
24
|
+
/**
|
|
25
|
+
* Un archivo dentro de un contenedor. `download()` y `exists()` devuelven ARRAY porque así
|
|
26
|
+
* lo desestructura el código que ya existe (`const [data] = await ....download()`).
|
|
27
|
+
*/
|
|
28
|
+
export declare class Archivo {
|
|
29
|
+
ruta: string;
|
|
30
|
+
private blob;
|
|
31
|
+
constructor(contenedor: ContainerClient, ruta: string);
|
|
32
|
+
save(datos: Buffer | string, opciones?: {
|
|
33
|
+
contentType?: string;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
download(): Promise<[Buffer]>;
|
|
36
|
+
exists(): Promise<[boolean]>;
|
|
37
|
+
delete(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/** Un contenedor. Equivale al `Bucket` de Google. */
|
|
40
|
+
export declare class Contenedor {
|
|
41
|
+
private contenedor;
|
|
42
|
+
constructor(nombre?: string, presupuestoS?: number);
|
|
43
|
+
file(ruta: string): Archivo;
|
|
44
|
+
}
|
|
45
|
+
/** Equivale al `Storage` de Google: `new Storage().bucket(nombre)`. */
|
|
46
|
+
export declare class Storage {
|
|
47
|
+
private presupuestoS?;
|
|
48
|
+
/**
|
|
49
|
+
* Acepta el mismo objeto de opciones que el cliente de Google. `keyFilename` se ignora (la
|
|
50
|
+
* credencial de Azure va por variable de entorno); `retryOptions.totalTimeout` sí se respeta.
|
|
51
|
+
*/
|
|
52
|
+
constructor(opciones?: {
|
|
53
|
+
keyFilename?: string;
|
|
54
|
+
retryOptions?: {
|
|
55
|
+
totalTimeout?: number;
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
bucket(nombre?: string): Contenedor;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Dirección pública de un archivo. Sustituye a los
|
|
62
|
+
* `https://storage.googleapis.com/${bucket}/${ruta}` que se construían a mano.
|
|
63
|
+
*/
|
|
64
|
+
export declare const urlPublica: (nombre: string | undefined, ruta: string) => string;
|
|
65
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/almacenamiento/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAiD,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAErG;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAiE3D;;;GAGG;AACH,qBAAa,OAAO;IAG8B,IAAI,EAAE,MAAM;IAF5D,OAAO,CAAC,IAAI,CAAC;gBAED,UAAU,EAAE,eAAe,EAAS,IAAI,EAAE,MAAM;IAItD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpF,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;IAI7B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC;IAI5B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAG9B;AAED,qDAAqD;AACrD,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAkB;gBAExB,MAAM,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;IAKlD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAG5B;AAED,uEAAuE;AACvE,qBAAa,OAAO;IAClB,OAAO,CAAC,YAAY,CAAC,CAAS;IAE9B;;;OAGG;gBACS,QAAQ,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE;YAAE,YAAY,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAO;IAI7F,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU;CAGpC;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,WAAY,MAAM,GAAG,SAAS,QAAQ,MAAM,KAAG,MAGrE,CAAC"}
|
package/lib/cjs/types/index.d.ts
CHANGED
|
@@ -24,5 +24,6 @@ import { saveResponseTime } from './chat/saveResponseTime';
|
|
|
24
24
|
import { updateSenderView } from './chat/api/conversation';
|
|
25
25
|
import { transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, analyzeFile, processMediaFile, reprocessRecentMedia } from './mediaProcessing';
|
|
26
26
|
import { generateObject, generateText, createGoogleModel, createGoogleModelFromString, createBedrockModelFromString, createAzureModelFromString, createModelFromString, runWithCostTracking, runWithModels, MODEL_TIER, AI_MODELS, GOOGLE_MODELS, AZURE_PREFIX, AZURE_GPT_5_5_DEPLOYMENT, AZURE_GPT_5_6_SOL_DEPLOYMENT, AZURE_GPT_5_6_TERRA_DEPLOYMENT, AZURE_GPT_5_6_LUNA_DEPLOYMENT, AZURE_GPT_5_4_MINI_DEPLOYMENT, AZURE_GPT_5_4_NANO_DEPLOYMENT, AZURE_DEEPSEEK_V4_PRO_DEPLOYMENT, AZURE_DEEPSEEK_V4_FLASH_DEPLOYMENT, AZURE_GPT_5_5, AZURE_GPT_5_6_SOL, AZURE_GPT_5_6_TERRA, AZURE_GPT_5_6_LUNA, AZURE_GPT_5_4_MINI, AZURE_GPT_5_4_NANO, AZURE_DEEPSEEK_V4_PRO, AZURE_DEEPSEEK_V4_FLASH, AZURE_PRIMARY_MODELS, AZURE_FALLBACK_MODELS, PRODUCTION_MODELS, FALLBACK_MODELS, BEDROCK_CLAUDE_OPUS, BEDROCK_CLAUDE_SONNET, BEDROCK_CLAUDE_OPUS_4_5, BEDROCK_CLAUDE_OPUS_4_1, BEDROCK_CLAUDE_SONNET_4_5, BEDROCK_CLAUDE_SONNET_4, BEDROCK_CLAUDE_HAIKU, AISTUDIO_PREFIX, MODEL_PRICING, calculateCost } from './prompt';
|
|
27
|
+
export { Storage as StorageAzure, Contenedor, Archivo, urlPublica, TIPO_POR_DEFECTO, } from './almacenamiento';
|
|
27
28
|
export { sendNotification, sleep, query, queryWithClient, longRunningQuery, batchQuery, toPgArray, pool, sendMail, err, fetchIA, notifySlack, CHANNEL_SLACK, translate, LANGUAGES, useTranslation, getExerciseTranslatedDescription, chat, chatApi, chatExposed, getCountNotificaciones, notionGetUsers, notionGetDatabase, notionAddPage, notionEditPage, NOTION_DATABASES_ID, readSheet, findCellByValue, writeSheet, appendSheet, getNumberByLetter, getLetter, reduceSizeImage, generateShareMap, getDefaultWorkoutImage, sendWorkoutToWatch, getPlanificacionPrueba7dias, saveWorkoutAplication, saveWorkoutLaps, evaluateAchievements, evaluateAchievementsBounded, getUnlockedAchievements, computeStreakStats, saveDoneStructuraWorkout, getZone, saveResponseTime, updateSenderView, transcribeAudio, describeImage, describeVideo, describePdf, describeTextFile, analyzeFile, processMediaFile, reprocessRecentMedia, generateObject, generateText, createGoogleModel, createGoogleModelFromString, createBedrockModelFromString, createAzureModelFromString, createModelFromString, runWithCostTracking, runWithModels, MODEL_TIER, AI_MODELS, GOOGLE_MODELS, AZURE_PREFIX, AZURE_GPT_5_5_DEPLOYMENT, AZURE_GPT_5_6_SOL_DEPLOYMENT, AZURE_GPT_5_6_TERRA_DEPLOYMENT, AZURE_GPT_5_6_LUNA_DEPLOYMENT, AZURE_GPT_5_4_MINI_DEPLOYMENT, AZURE_GPT_5_4_NANO_DEPLOYMENT, AZURE_DEEPSEEK_V4_PRO_DEPLOYMENT, AZURE_DEEPSEEK_V4_FLASH_DEPLOYMENT, AZURE_GPT_5_5, AZURE_GPT_5_6_SOL, AZURE_GPT_5_6_TERRA, AZURE_GPT_5_6_LUNA, AZURE_GPT_5_4_MINI, AZURE_GPT_5_4_NANO, AZURE_DEEPSEEK_V4_PRO, AZURE_DEEPSEEK_V4_FLASH, AZURE_PRIMARY_MODELS, AZURE_FALLBACK_MODELS, PRODUCTION_MODELS, FALLBACK_MODELS, BEDROCK_CLAUDE_OPUS, BEDROCK_CLAUDE_SONNET, BEDROCK_CLAUDE_OPUS_4_5, BEDROCK_CLAUDE_OPUS_4_1, BEDROCK_CLAUDE_SONNET_4_5, BEDROCK_CLAUDE_SONNET_4, BEDROCK_CLAUDE_HAIKU, AISTUDIO_PREFIX, MODEL_PRICING, calculateCost, };
|
|
28
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC7F,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACjH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAClH,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAIhI,OAAO,KAAK,mBAAmB,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,2BAA2B,EAC3B,4BAA4B,EAC5B,0BAA0B,EAC1B,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,SAAS,EACT,aAAa,EACb,YAAY,EACZ,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,EAC9B,6BAA6B,EAC7B,6BAA6B,EAC7B,6BAA6B,EAC7B,gCAAgC,EAChC,kCAAkC,EAClC,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,aAAa,EACd,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,OAAO,IAAI,YAAY,EACvB,UAAU,EACV,OAAO,EACP,UAAU,EACV,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,gBAAgB,EAChB,KAAK,EACL,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,SAAS,EACT,IAAI,EACJ,QAAQ,EACR,GAAG,EACH,OAAO,EACP,WAAW,EACX,aAAa,EACb,SAAS,EACT,SAAS,EACT,cAAc,EACd,gCAAgC,EAChC,IAAI,EACJ,OAAO,EACP,WAAW,EACX,sBAAsB,EACtB,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,SAAS,EACT,eAAe,EACf,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,EAC3B,qBAAqB,EACrB,eAAe,EACf,oBAAoB,EACpB,2BAA2B,EAC3B,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,EACxB,OAAO,EACP,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,2BAA2B,EAC3B,4BAA4B,EAC5B,0BAA0B,EAC1B,qBAAqB,EACrB,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,SAAS,EACT,aAAa,EACb,YAAY,EACZ,wBAAwB,EACxB,4BAA4B,EAC5B,8BAA8B,EAC9B,6BAA6B,EAC7B,6BAA6B,EAC7B,6BAA6B,EAC7B,gCAAgC,EAChC,kCAAkC,EAClC,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,aAAa,GACd,CAAC"}
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Algunas ingestas entregan la distancia del RESUMEN en millas pero rotulada en metros
|
|
3
|
+
* (9.051 m reales -> se guarda 5.600, que son 5,6 millas x 1000). El gráfico y los
|
|
4
|
+
* parciales salen bien porque se calculan del stream, pero la distancia total y el ritmo
|
|
5
|
+
* medio quedan ~1,61x peores, y `getZone` clasifica mal porque sale de duración/distancia.
|
|
6
|
+
*
|
|
7
|
+
* El stream SÍ viene en metros, así que hace de árbitro: se corrige sólo si reconstruir
|
|
8
|
+
* "millas x 1000" desde el stream reproduce la distancia candidata con menos de un 1% de
|
|
9
|
+
* desvío.
|
|
10
|
+
*
|
|
11
|
+
* OJO con leer el filtro de ratio de más abajo como un segundo criterio independiente:
|
|
12
|
+
* NO lo es, es la misma cuenta despejada. Sirve para descartar barato el 99,99% de las
|
|
13
|
+
* ingestas sin dividir. El rango que decide de verdad es ratio ∈ [1,5932 – 1,6254].
|
|
14
|
+
*
|
|
15
|
+
* Ese pasillo es estrecho a propósito, y por eso la corrección deja traza: en producción
|
|
16
|
+
* hay entrenos SANOS pegados a los dos bordes —w699672 a ratio 1,5784 y w694890 a 1,6301,
|
|
17
|
+
* con el stream más largo que el resumen por pausas o deriva de GPS—, y entre 1,40 y 1,80
|
|
18
|
+
* hay una nube continua de entrenos legítimos. Si alguno acaba cayendo dentro, el rastro
|
|
19
|
+
* es lo único que permitirá distinguirlo de un fallo de la fuente.
|
|
20
|
+
*/
|
|
21
|
+
declare const corregirDistanciaEnMillas: (distance: any, streamFinal: number | null) => any;
|
|
1
22
|
/**
|
|
2
23
|
* @param opts {{
|
|
3
24
|
* date, type, title, description, distance, duration, power, desnivel, polyline,
|
|
@@ -10,5 +31,5 @@
|
|
|
10
31
|
* @returns {Promise<number|null>} idWorkout (o null si no se pudo crear) — firma intacta
|
|
11
32
|
*/
|
|
12
33
|
declare const saveWorkoutAplication: (opts: any, _data?: any) => Promise<number | null>;
|
|
13
|
-
export { saveWorkoutAplication };
|
|
34
|
+
export { saveWorkoutAplication, corregirDistanciaEnMillas };
|
|
14
35
|
//# sourceMappingURL=saveWorkoutAplication.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"saveWorkoutAplication.d.ts","sourceRoot":"","sources":["../../../../src/workout/saveWorkoutAplication.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"saveWorkoutAplication.d.ts","sourceRoot":"","sources":["../../../../src/workout/saveWorkoutAplication.ts"],"names":[],"mappings":"AA2RA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,QAAA,MAAM,yBAAyB,aAAc,GAAG,eAAe,MAAM,GAAG,IAAI,KAAG,GAe9E,CAAC;AA8FF;;;;;;;;;;GAUG;AACH,QAAA,MAAM,qBAAqB,SACnB,GAAG,UAED,GAAG,KACV,QAAQ,MAAM,GAAG,IAAI,CAqFvB,CAAC;AAuGF,OAAO,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,CAAC"}
|
|
@@ -12,10 +12,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.saveWorkoutAplication = void 0;
|
|
15
|
+
exports.corregirDistanciaEnMillas = exports.saveWorkoutAplication = void 0;
|
|
16
16
|
const db_1 = require("../db");
|
|
17
|
-
const
|
|
18
|
-
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const almacenamiento_1 = require("../almacenamiento");
|
|
19
18
|
const axios_1 = __importDefault(require("axios"));
|
|
20
19
|
const generateShareMap_1 = require("../image/generateShareMap");
|
|
21
20
|
const getDefaultWorkoutImage_1 = require("../image/getDefaultWorkoutImage");
|
|
@@ -244,6 +243,95 @@ const registrarFuente = (q, idWorkout, tipo, idApp) => __awaiter(void 0, void 0,
|
|
|
244
243
|
ON CONFLICT ("ID WORKOUT", "TIPO APLICATION")
|
|
245
244
|
DO UPDATE SET "ID APLICATION" = EXCLUDED."ID APLICATION", "INGESTED AT" = NOW()`, [idWorkout, String(tipo), idApp !== null && idApp !== undefined ? String(idApp) : null]);
|
|
246
245
|
});
|
|
246
|
+
// =============================================================================
|
|
247
|
+
// Guardarraíl de unidad: distancia en MILLAS rotulada como metros
|
|
248
|
+
// =============================================================================
|
|
249
|
+
const METROS_POR_MILLA = 1609.344;
|
|
250
|
+
// Desvío máximo admitido al reconstruir la candidata desde el stream. NO se puede
|
|
251
|
+
// apretar: Strava redondea la distancia del resumen a una décima de milla, y en un
|
|
252
|
+
// entreno corto ese redondeo ya vale casi un 1% (0,05 mi sobre 3,9 mi = 1,3%).
|
|
253
|
+
const TOLERANCIA_RECONSTRUCCION = 0.01;
|
|
254
|
+
/**
|
|
255
|
+
* Último valor útil del stream de distancia, en metros. Mira primero el stream que
|
|
256
|
+
* entra con esta ingesta y, si no viene, el que ya esté guardado para el workout
|
|
257
|
+
* (p.ej. lo dejó otra fuente). Devuelve null si no hay ninguno: sin árbitro no se
|
|
258
|
+
* toca la distancia.
|
|
259
|
+
*
|
|
260
|
+
* La consulta pide SÓLO el último punto (`-> -1`) y no el array entero: un stream de
|
|
261
|
+
* distancia son miles de puntos en un campo TOAST, y esto corre dentro de la tx que
|
|
262
|
+
* sostiene el advisory lock de la ingesta. Traerlo completo para leer un número sería
|
|
263
|
+
* alargar el lock que ya es el punto donde más se cae el pool.
|
|
264
|
+
*/
|
|
265
|
+
const distanciaFinalDelStream = (q, idWorkout, streams) => __awaiter(void 0, void 0, void 0, function* () {
|
|
266
|
+
const valido = (v) => {
|
|
267
|
+
const n = Number(v);
|
|
268
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
269
|
+
};
|
|
270
|
+
const entrantes = streams === null || streams === void 0 ? void 0 : streams.distance;
|
|
271
|
+
if (Array.isArray(entrantes) && entrantes.length > 0) {
|
|
272
|
+
const ultimo = valido(entrantes[entrantes.length - 1]);
|
|
273
|
+
if (ultimo !== null)
|
|
274
|
+
return ultimo;
|
|
275
|
+
}
|
|
276
|
+
const [row] = yield q(`SELECT CASE WHEN jsonb_typeof("DATA"::jsonb) = 'array' AND jsonb_array_length("DATA"::jsonb) > 0
|
|
277
|
+
THEN "DATA"::jsonb -> -1 ELSE NULL END AS ultimo
|
|
278
|
+
FROM "WORKOUT STREAM" WHERE "ID WORKOUT" = ? AND "METRIC TYPE" = ?`, [idWorkout, 'distance']);
|
|
279
|
+
return row ? valido(row.ultimo) : null;
|
|
280
|
+
});
|
|
281
|
+
/**
|
|
282
|
+
* Algunas ingestas entregan la distancia del RESUMEN en millas pero rotulada en metros
|
|
283
|
+
* (9.051 m reales -> se guarda 5.600, que son 5,6 millas x 1000). El gráfico y los
|
|
284
|
+
* parciales salen bien porque se calculan del stream, pero la distancia total y el ritmo
|
|
285
|
+
* medio quedan ~1,61x peores, y `getZone` clasifica mal porque sale de duración/distancia.
|
|
286
|
+
*
|
|
287
|
+
* El stream SÍ viene en metros, así que hace de árbitro: se corrige sólo si reconstruir
|
|
288
|
+
* "millas x 1000" desde el stream reproduce la distancia candidata con menos de un 1% de
|
|
289
|
+
* desvío.
|
|
290
|
+
*
|
|
291
|
+
* OJO con leer el filtro de ratio de más abajo como un segundo criterio independiente:
|
|
292
|
+
* NO lo es, es la misma cuenta despejada. Sirve para descartar barato el 99,99% de las
|
|
293
|
+
* ingestas sin dividir. El rango que decide de verdad es ratio ∈ [1,5932 – 1,6254].
|
|
294
|
+
*
|
|
295
|
+
* Ese pasillo es estrecho a propósito, y por eso la corrección deja traza: en producción
|
|
296
|
+
* hay entrenos SANOS pegados a los dos bordes —w699672 a ratio 1,5784 y w694890 a 1,6301,
|
|
297
|
+
* con el stream más largo que el resumen por pausas o deriva de GPS—, y entre 1,40 y 1,80
|
|
298
|
+
* hay una nube continua de entrenos legítimos. Si alguno acaba cayendo dentro, el rastro
|
|
299
|
+
* es lo único que permitirá distinguirlo de un fallo de la fuente.
|
|
300
|
+
*/
|
|
301
|
+
const corregirDistanciaEnMillas = (distance, streamFinal) => {
|
|
302
|
+
const d = Number(distance);
|
|
303
|
+
if (!Number.isFinite(d) || d <= 0 || streamFinal === null || !(streamFinal > 0))
|
|
304
|
+
return distance;
|
|
305
|
+
// Filtro barato: fuera de la horquilla de la milla no hay nada que mirar.
|
|
306
|
+
const ratio = streamFinal / d;
|
|
307
|
+
if (ratio < 1.58 || ratio > 1.64)
|
|
308
|
+
return distance;
|
|
309
|
+
// La fuente trató las MILLAS como si fueran kilómetros: el valor que nos llega es
|
|
310
|
+
// "millas x 1000" (5,6 mi -> 5600). Reconstruimos ese número desde el stream y exigimos
|
|
311
|
+
// que reproduzca la candidata; si no, el desajuste tiene otra causa y no se toca.
|
|
312
|
+
const millasEscaladas = (streamFinal / METROS_POR_MILLA) * 1000;
|
|
313
|
+
if (Math.abs(millasEscaladas - d) / d > TOLERANCIA_RECONSTRUCCION)
|
|
314
|
+
return distance;
|
|
315
|
+
return Math.round(streamFinal / 10) * 10;
|
|
316
|
+
};
|
|
317
|
+
exports.corregirDistanciaEnMillas = corregirDistanciaEnMillas;
|
|
318
|
+
const resolverDistanciaConStream = (q, idWorkout, distance, streams) => __awaiter(void 0, void 0, void 0, function* () {
|
|
319
|
+
const d = Number(distance);
|
|
320
|
+
if (!Number.isFinite(d) || d <= 0)
|
|
321
|
+
return distance;
|
|
322
|
+
const streamFinal = yield distanciaFinalDelStream(q, idWorkout, streams);
|
|
323
|
+
const corregida = corregirDistanciaEnMillas(distance, streamFinal);
|
|
324
|
+
// Traza obligatoria: esto pisa un dato del cliente por heurística y en un margen fino.
|
|
325
|
+
// Sin rastro, un "mi entreno marca de más" no se podría distinguir de un fallo de la
|
|
326
|
+
// fuente, ni se sabría cuántas veces ha actuado el guardarraíl.
|
|
327
|
+
if (Number(corregida) !== d) {
|
|
328
|
+
// eslint-disable-next-line no-console
|
|
329
|
+
console.warn(`corregirDistanciaEnMillas: idWorkout=${idWorkout} DISTANCE ${d} -> ${corregida} ` +
|
|
330
|
+
`(stream=${streamFinal}, ratio=${(Number(streamFinal) / d).toFixed(4)}). ` +
|
|
331
|
+
'La fuente entregó la distancia del resumen en millas.');
|
|
332
|
+
}
|
|
333
|
+
return corregida;
|
|
334
|
+
});
|
|
247
335
|
const aplicarMerge = (q, idWorkout, opts, esFilaNueva) => __awaiter(void 0, void 0, void 0, function* () {
|
|
248
336
|
var _a, _b, _c, _d;
|
|
249
337
|
const [row] = yield q(`SELECT "DISTANCE", "DURATION", "POTENCIA", "DESNIVEL", "CALORIES", "FC MEDIA",
|
|
@@ -251,7 +339,10 @@ const aplicarMerge = (q, idWorkout, opts, esFilaNueva) => __awaiter(void 0, void
|
|
|
251
339
|
FROM "WORKOUT" WHERE "ID" = ? FOR UPDATE`, [idWorkout]);
|
|
252
340
|
const prioNueva = prioridadFuente(opts.aplicationType);
|
|
253
341
|
const prioActual = esFilaNueva ? -1 : prioridadFuente(row === null || row === void 0 ? void 0 : row.tipoAplication);
|
|
254
|
-
const
|
|
342
|
+
const distanceMerge = resolverEscalar(row === null || row === void 0 ? void 0 : row.distance, opts.distance, prioActual, prioNueva);
|
|
343
|
+
// El stream (metros) arbitra sobre la distancia del resumen: corrige el caso en que la
|
|
344
|
+
// fuente la entrega en millas. Va ANTES de getZone, que se calcula con esta distancia.
|
|
345
|
+
const distance = yield resolverDistanciaConStream(q, idWorkout, distanceMerge, opts.streams);
|
|
255
346
|
const duration = resolverEscalar(row === null || row === void 0 ? void 0 : row.duration, opts.duration, prioActual, prioNueva);
|
|
256
347
|
const potencia = resolverEscalar(row === null || row === void 0 ? void 0 : row.potencia, opts.power, prioActual, prioNueva);
|
|
257
348
|
const desnivel = resolverEscalar(row === null || row === void 0 ? void 0 : row.desnivel, opts.desnivel, prioActual, prioNueva);
|
|
@@ -440,8 +531,7 @@ const saveMap = (idWorkout, polyline) => __awaiter(void 0, void 0, void 0, funct
|
|
|
440
531
|
if (!polyline)
|
|
441
532
|
return;
|
|
442
533
|
// @ts-ignore
|
|
443
|
-
const
|
|
444
|
-
const storage = new storage_1.Storage({ keyFilename: serviceKey });
|
|
534
|
+
const storage = new almacenamiento_1.Storage();
|
|
445
535
|
const encodedPolyline = encodeURIComponent(typeof polyline === 'string' ? polyline : getPolyline(polyline) || '');
|
|
446
536
|
if (!encodedPolyline)
|
|
447
537
|
return;
|
|
@@ -449,7 +539,7 @@ const saveMap = (idWorkout, polyline) => __awaiter(void 0, void 0, void 0, funct
|
|
|
449
539
|
const imageBuffer = Buffer.from(result.data, 'binary');
|
|
450
540
|
// @ts-ignore
|
|
451
541
|
yield storage.bucket(process.env.CLOUD_STORAGE_BUCKET_PUBLIC).file(`Workout/${idWorkout}`).save(imageBuffer);
|
|
452
|
-
const urlMap =
|
|
542
|
+
const urlMap = (0, almacenamiento_1.urlPublica)(process.env.CLOUD_STORAGE_BUCKET_PUBLIC, `Workout/${idWorkout}`);
|
|
453
543
|
try {
|
|
454
544
|
yield (0, db_1.query)('UPDATE "WORKOUT" SET "HAVE MAP IMAGE" = TRUE, "PHOTO URL" = ? WHERE "ID" = ?', [urlMap, idWorkout]);
|
|
455
545
|
}
|
|
@@ -461,9 +551,7 @@ const saveMap = (idWorkout, polyline) => __awaiter(void 0, void 0, void 0, funct
|
|
|
461
551
|
}
|
|
462
552
|
});
|
|
463
553
|
const saveShareWorkoutImage = (id, type) => __awaiter(void 0, void 0, void 0, function* () {
|
|
464
|
-
|
|
465
|
-
const serviceKey = path_1.default.join(process.cwd(), process.env.FIREBASE_STORAGE_CREDENTIALS);
|
|
466
|
-
const storage = new storage_1.Storage({ keyFilename: serviceKey });
|
|
554
|
+
const storage = new almacenamiento_1.Storage();
|
|
467
555
|
// @ts-ignore
|
|
468
556
|
const [exists] = yield storage.bucket(process.env.CLOUD_STORAGE_BUCKET_PUBLIC).file(`Workout/${id}`).exists();
|
|
469
557
|
let image;
|
|
@@ -479,7 +567,7 @@ const saveShareWorkoutImage = (id, type) => __awaiter(void 0, void 0, void 0, fu
|
|
|
479
567
|
return;
|
|
480
568
|
// @ts-ignore
|
|
481
569
|
yield storage.bucket(process.env.CLOUD_STORAGE_BUCKET_PUBLIC).file(`Workout/${id}-share`).save(shareMap);
|
|
482
|
-
const urlShare =
|
|
570
|
+
const urlShare = (0, almacenamiento_1.urlPublica)(process.env.CLOUD_STORAGE_BUCKET_PUBLIC, `Workout/${id}-share`);
|
|
483
571
|
try {
|
|
484
572
|
yield (0, db_1.query)('UPDATE "WORKOUT" SET "PHOTO URL SHARE" = ? WHERE "ID" = ?', [urlShare, id]);
|
|
485
573
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runnerpro/backend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.1",
|
|
4
4
|
"description": "A collection of common backend functions",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./lib/cjs/index.js"
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"test:generate-share-map-guard": "ts-node --transpile-only -P configs/tsconfig.cjs.json scripts/testGenerateShareMapGuard.ts",
|
|
21
21
|
"test:pg-query-conexion": "ts-node --transpile-only -P configs/tsconfig.cjs.json scripts/testPgQueryConexion.ts",
|
|
22
22
|
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
|
|
23
|
-
"prepare": "husky"
|
|
23
|
+
"prepare": "husky",
|
|
24
|
+
"test:distancia-millas": "ts-node --transpile-only -P configs/tsconfig.cjs.json scripts/testDistanciaMillas.ts"
|
|
24
25
|
},
|
|
25
26
|
"release": {
|
|
26
27
|
"branches": [
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
"@ai-sdk/azure": "^3.0.74",
|
|
69
70
|
"@ai-sdk/google": "^3.0.43",
|
|
70
71
|
"@ai-sdk/google-vertex": "^4.0.102",
|
|
72
|
+
"@azure/storage-blob": "^12.32.0",
|
|
71
73
|
"@google-cloud/speech": "^7.2.1",
|
|
72
74
|
"@google-cloud/storage": "^7.11.3",
|
|
73
75
|
"@google-cloud/translate": "^8.3.0",
|