md-face-engine 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/client-BGSZMMvf.js +620 -0
- package/dist/client-BGSZMMvf.js.map +1 -0
- package/dist/client-DimGdJ4Y.cjs +619 -0
- package/dist/client-DimGdJ4Y.cjs.map +1 -0
- package/dist/client.cjs +5 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.js +5 -0
- package/dist/client.js.map +1 -0
- package/dist/index.cjs +8661 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +8643 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# md-face-engine
|
|
2
|
+
|
|
3
|
+
Motor reusable para detección facial y aplicación de filtros.
|
|
4
|
+
|
|
5
|
+
## Instalación
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install md-face-engine
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Uso en frontend
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { createMdFaceEngineClient } from 'md-face-engine/client';
|
|
15
|
+
|
|
16
|
+
const client = createMdFaceEngineClient({
|
|
17
|
+
token: import.meta.env.VITE_MD_FACE_ENGINE_TOKEN,
|
|
18
|
+
products: []
|
|
19
|
+
});
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
El frontend solo necesita un valor:
|
|
23
|
+
|
|
24
|
+
- `VITE_MD_FACE_ENGINE_TOKEN`
|
|
25
|
+
|
|
26
|
+
## Build del paquete
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm run build
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Publicar en npm
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm login
|
|
36
|
+
npm publish --access public
|
|
37
|
+
```
|
|
@@ -0,0 +1,620 @@
|
|
|
1
|
+
const wrinkles = {
|
|
2
|
+
key: "wrinkles",
|
|
3
|
+
label: "Arrugas",
|
|
4
|
+
defaults: { intensity: 0.5, sigma: 4, brightness: 0 },
|
|
5
|
+
deep: {
|
|
6
|
+
smooth: { enabled: true, radius: 8, passes: 4, opacity: 0.7 },
|
|
7
|
+
brightness: { enabled: true, value: 10 },
|
|
8
|
+
contrast: { enabled: true, value: 1.03 },
|
|
9
|
+
warmth: { enabled: true, rPlus: 8, bMinus: 5, alpha: 0.3 },
|
|
10
|
+
toneUnify: { enabled: true, threshold: 12, mix: 0.4 },
|
|
11
|
+
blemish: { enabled: true, microBlur: 3, alpha: 0.4 },
|
|
12
|
+
contourLift: { enabled: true, lift: 0.06, shade: 0.04, feather: 20 }
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const brightness = {
|
|
16
|
+
key: "brightness",
|
|
17
|
+
label: "Luminosidad",
|
|
18
|
+
defaults: { intensity: 0, sigma: 0, brightness: 0.07 },
|
|
19
|
+
deep: {
|
|
20
|
+
smooth: { enabled: true, radius: 5, passes: 3, opacity: 0.5 },
|
|
21
|
+
brightness: { enabled: true, value: 18 },
|
|
22
|
+
contrast: { enabled: true, value: 1.15 },
|
|
23
|
+
warmth: { enabled: true, rPlus: 12, bMinus: 8, alpha: 0.45 },
|
|
24
|
+
toneUnify: { enabled: true, threshold: 10, mix: 0.3 },
|
|
25
|
+
blemish: { enabled: true, microBlur: 2, alpha: 0.3 },
|
|
26
|
+
contourLift: { enabled: true, lift: 0.12, shade: 0.08, feather: 18 }
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
const spots = {
|
|
30
|
+
key: "spots",
|
|
31
|
+
label: "Manchas/Tono",
|
|
32
|
+
defaults: { intensity: 0.65, sigma: 5, brightness: 0.05 },
|
|
33
|
+
deep: {
|
|
34
|
+
smooth: { enabled: true, radius: 6, passes: 3, opacity: 0.6 },
|
|
35
|
+
brightness: { enabled: true, value: 12 },
|
|
36
|
+
contrast: { enabled: true, value: 1.08 },
|
|
37
|
+
warmth: { enabled: true, rPlus: 7, bMinus: 4, alpha: 0.3 },
|
|
38
|
+
toneUnify: { enabled: true, threshold: 8, mix: 0.6 },
|
|
39
|
+
blemish: { enabled: true, microBlur: 4, alpha: 0.5 },
|
|
40
|
+
contourLift: { enabled: true, lift: 0.08, shade: 0.06, feather: 16 }
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const acne = {
|
|
44
|
+
key: "acne",
|
|
45
|
+
label: "Acné",
|
|
46
|
+
defaults: { intensity: 0.55, sigma: 3.4, brightness: 0.1 },
|
|
47
|
+
deep: {
|
|
48
|
+
smooth: { enabled: true, radius: 7, passes: 4, opacity: 0.65 },
|
|
49
|
+
brightness: { enabled: true, value: 8 },
|
|
50
|
+
contrast: { enabled: true, value: 1.02 },
|
|
51
|
+
warmth: { enabled: true, rPlus: 6, bMinus: 3, alpha: 0.25 },
|
|
52
|
+
toneUnify: { enabled: true, threshold: 10, mix: 0.5 },
|
|
53
|
+
blemish: { enabled: true, microBlur: 5, alpha: 0.7 },
|
|
54
|
+
contourLift: { enabled: true, lift: 0.06, shade: 0.04, feather: 20 }
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const firmness = {
|
|
58
|
+
key: "firmness",
|
|
59
|
+
label: "Firmeza",
|
|
60
|
+
defaults: { intensity: 0.7, sigma: 2, brightness: 0 },
|
|
61
|
+
deep: {
|
|
62
|
+
smooth: { enabled: true, radius: 3, passes: 2, opacity: 0.3 },
|
|
63
|
+
brightness: { enabled: true, value: 6 },
|
|
64
|
+
contrast: { enabled: true, value: 1.12 },
|
|
65
|
+
warmth: { enabled: true, rPlus: 5, bMinus: 3, alpha: 0.2 },
|
|
66
|
+
toneUnify: { enabled: true, threshold: 18, mix: 0.2 },
|
|
67
|
+
blemish: { enabled: false, microBlur: 1, alpha: 0.1 },
|
|
68
|
+
contourLift: { enabled: true, lift: 0.15, shade: 0.12, feather: 12 }
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
const FILTERS = {
|
|
72
|
+
wrinkles,
|
|
73
|
+
brightness,
|
|
74
|
+
spots,
|
|
75
|
+
acne,
|
|
76
|
+
firmness
|
|
77
|
+
};
|
|
78
|
+
function getFilter(key) {
|
|
79
|
+
return FILTERS[key] || null;
|
|
80
|
+
}
|
|
81
|
+
const FILTER_ORDER = ["wrinkles", "brightness", "spots", "acne", "firmness"];
|
|
82
|
+
const DEFAULT_FILTER_CONFIG = {
|
|
83
|
+
// 1) Arrugas → Suavizado de piel
|
|
84
|
+
smooth: {
|
|
85
|
+
enabled: true,
|
|
86
|
+
intensity: 36,
|
|
87
|
+
// referencia visual
|
|
88
|
+
radius: 4,
|
|
89
|
+
passes: 2,
|
|
90
|
+
opacity: 0.4
|
|
91
|
+
},
|
|
92
|
+
// 2) Piel apagada → Brillo
|
|
93
|
+
brightness: {
|
|
94
|
+
enabled: true,
|
|
95
|
+
intensity: 91,
|
|
96
|
+
// referencia visual
|
|
97
|
+
value: 8
|
|
98
|
+
},
|
|
99
|
+
// Ajuste de contraste general
|
|
100
|
+
contrast: {
|
|
101
|
+
enabled: true,
|
|
102
|
+
intensity: 10,
|
|
103
|
+
value: 1.05
|
|
104
|
+
},
|
|
105
|
+
// Tono cálido / glow
|
|
106
|
+
warmth: {
|
|
107
|
+
enabled: true,
|
|
108
|
+
intensity: 20,
|
|
109
|
+
rPlus: 6,
|
|
110
|
+
bMinus: 4,
|
|
111
|
+
alpha: 0.25
|
|
112
|
+
},
|
|
113
|
+
// 2) Manchas → Unificar tono
|
|
114
|
+
toneUnify: {
|
|
115
|
+
enabled: true,
|
|
116
|
+
intensity: 65,
|
|
117
|
+
// referencia visual
|
|
118
|
+
threshold: 15,
|
|
119
|
+
mix: 0.25
|
|
120
|
+
},
|
|
121
|
+
// 5) Acné → Reducir imperfecciones
|
|
122
|
+
blemish: {
|
|
123
|
+
enabled: true,
|
|
124
|
+
intensity: 35,
|
|
125
|
+
// referencia visual
|
|
126
|
+
microBlur: 2,
|
|
127
|
+
alpha: 0.25
|
|
128
|
+
},
|
|
129
|
+
// 3) Firmeza → Lifting y contouring
|
|
130
|
+
contourLift: {
|
|
131
|
+
enabled: true,
|
|
132
|
+
intensity: 24,
|
|
133
|
+
// referencia visual
|
|
134
|
+
lift: 0.08,
|
|
135
|
+
shade: 0.06,
|
|
136
|
+
feather: 15
|
|
137
|
+
},
|
|
138
|
+
// Extras
|
|
139
|
+
highlights: {
|
|
140
|
+
enabled: false,
|
|
141
|
+
intensity: 10
|
|
142
|
+
},
|
|
143
|
+
shadows: {
|
|
144
|
+
enabled: false,
|
|
145
|
+
intensity: 5
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const CONCERN_PRESETS = {
|
|
149
|
+
arrugas: {
|
|
150
|
+
smooth: { enabled: true, intensity: 36, radius: 6, passes: 3, opacity: 0.6 },
|
|
151
|
+
contourLift: { enabled: true, intensity: 20, lift: 0.06, shade: 0.05, feather: 18 }
|
|
152
|
+
},
|
|
153
|
+
manchas: {
|
|
154
|
+
toneUnify: { enabled: true, intensity: 65, threshold: 14, mix: 0.35 },
|
|
155
|
+
brightness: { enabled: true, intensity: 20, value: 10 }
|
|
156
|
+
},
|
|
157
|
+
firmeza: {
|
|
158
|
+
contourLift: { enabled: true, intensity: 24, lift: 0.08, shade: 0.06, feather: 20 },
|
|
159
|
+
contrast: { enabled: true, intensity: 12, value: 1.07 }
|
|
160
|
+
},
|
|
161
|
+
luminosidad: {
|
|
162
|
+
brightness: { enabled: true, intensity: 91, value: 12 },
|
|
163
|
+
warmth: { enabled: true, intensity: 25, rPlus: 8, bMinus: 5, alpha: 0.3 }
|
|
164
|
+
},
|
|
165
|
+
acne: {
|
|
166
|
+
blemish: { enabled: true, intensity: 35, microBlur: 3, alpha: 0.35 },
|
|
167
|
+
toneUnify: { enabled: true, intensity: 40, threshold: 16, mix: 0.3 }
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const CATEGORY_PRESETS = {
|
|
171
|
+
// Antiaging: foco en arrugas y firmeza
|
|
172
|
+
antiaging: {
|
|
173
|
+
smooth: { enabled: true, intensity: 36, radius: 6, passes: 3, opacity: 0.6 },
|
|
174
|
+
contourLift: { enabled: true, intensity: 24, lift: 0.07, shade: 0.05, feather: 18 },
|
|
175
|
+
brightness: { enabled: true, intensity: 20, value: 10 },
|
|
176
|
+
warmth: { enabled: true, intensity: 22, rPlus: 7, bMinus: 5, alpha: 0.28 }
|
|
177
|
+
},
|
|
178
|
+
// Manchas / pigmentación: foco en unificar tono y luminosidad
|
|
179
|
+
manchas: {
|
|
180
|
+
toneUnify: { enabled: true, intensity: 65, threshold: 14, mix: 0.35 },
|
|
181
|
+
brightness: { enabled: true, intensity: 25, value: 10 },
|
|
182
|
+
warmth: { enabled: false }
|
|
183
|
+
},
|
|
184
|
+
// Hidratación: suavizado ligero y glow moderado
|
|
185
|
+
hidratacion: {
|
|
186
|
+
smooth: { enabled: true, intensity: 25, radius: 3, passes: 2, opacity: 0.35 },
|
|
187
|
+
brightness: { enabled: true, intensity: 18, value: 8 },
|
|
188
|
+
warmth: { enabled: true, intensity: 15, rPlus: 5, bMinus: 3, alpha: 0.2 }
|
|
189
|
+
},
|
|
190
|
+
// Acné: foco en reducción de imperfecciones y tono uniforme
|
|
191
|
+
acne: {
|
|
192
|
+
blemish: { enabled: true, intensity: 35, microBlur: 3, alpha: 0.35 },
|
|
193
|
+
toneUnify: { enabled: true, intensity: 40, threshold: 16, mix: 0.3 },
|
|
194
|
+
brightness: { enabled: false }
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
class FilterConfigManager {
|
|
198
|
+
constructor(options = {}) {
|
|
199
|
+
this.storageKey = "martiderm_filter_configs";
|
|
200
|
+
this.authKey = "martiderm_admin_auth";
|
|
201
|
+
this.backupKey = "martiderm_config_backup";
|
|
202
|
+
this.products = Array.isArray(options.products) ? options.products : [];
|
|
203
|
+
this.init();
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Inicializa el gestor de configuraciones
|
|
207
|
+
*/
|
|
208
|
+
init() {
|
|
209
|
+
const savedConfigs = this.loadConfigurations();
|
|
210
|
+
if ((!savedConfigs || Object.keys(savedConfigs).length === 0) && this.products.length > 0) {
|
|
211
|
+
this.initializeDefaultConfigurations();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
setProducts(products = []) {
|
|
215
|
+
this.products = Array.isArray(products) ? products : [];
|
|
216
|
+
const savedConfigs = this.loadConfigurations();
|
|
217
|
+
if ((!savedConfigs || Object.keys(savedConfigs).length === 0) && this.products.length > 0) {
|
|
218
|
+
this.initializeDefaultConfigurations();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Inicializa configuraciones predeterminadas para todos los productos
|
|
223
|
+
*/
|
|
224
|
+
initializeDefaultConfigurations() {
|
|
225
|
+
try {
|
|
226
|
+
const configs = {};
|
|
227
|
+
this.products.forEach((product) => {
|
|
228
|
+
configs[product.id] = this.generateProductConfig(product);
|
|
229
|
+
});
|
|
230
|
+
this.saveConfigurations(configs);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
console.error("Error inicializando configuraciones:", error);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Genera configuración específica para un producto
|
|
237
|
+
*/
|
|
238
|
+
generateProductConfig(product) {
|
|
239
|
+
const baseConfig = { ...DEFAULT_FILTER_CONFIG };
|
|
240
|
+
const categoryPreset = CATEGORY_PRESETS[product.category];
|
|
241
|
+
if (categoryPreset) {
|
|
242
|
+
Object.keys(categoryPreset).forEach((filterType) => {
|
|
243
|
+
if (baseConfig[filterType]) {
|
|
244
|
+
baseConfig[filterType] = {
|
|
245
|
+
...baseConfig[filterType],
|
|
246
|
+
...categoryPreset[filterType]
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (product.targetConcerns && Array.isArray(product.targetConcerns)) {
|
|
252
|
+
product.targetConcerns.forEach((concern) => {
|
|
253
|
+
const preset = CONCERN_PRESETS[concern];
|
|
254
|
+
if (preset) {
|
|
255
|
+
Object.keys(preset).forEach((filterType) => {
|
|
256
|
+
if (baseConfig[filterType]) {
|
|
257
|
+
baseConfig[filterType] = {
|
|
258
|
+
...baseConfig[filterType],
|
|
259
|
+
...preset[filterType]
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
productId: product.id,
|
|
268
|
+
productName: product.name,
|
|
269
|
+
category: product.category,
|
|
270
|
+
filters: baseConfig,
|
|
271
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString(),
|
|
272
|
+
version: "1.0"
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Obtiene la configuración de filtros para un producto específico
|
|
277
|
+
*/
|
|
278
|
+
getProductConfig(productId) {
|
|
279
|
+
const configs = this.loadConfigurations();
|
|
280
|
+
return configs[productId] || null;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Guarda la configuración de filtros para un producto
|
|
284
|
+
*/
|
|
285
|
+
saveProductConfig(productId, config) {
|
|
286
|
+
const configs = this.loadConfigurations();
|
|
287
|
+
configs[productId] = {
|
|
288
|
+
...config,
|
|
289
|
+
lastModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
290
|
+
};
|
|
291
|
+
this.saveConfigurations(configs);
|
|
292
|
+
return true;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Obtiene todas las configuraciones
|
|
296
|
+
*/
|
|
297
|
+
getAllConfigurations() {
|
|
298
|
+
return this.loadConfigurations();
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Carga configuraciones desde localStorage
|
|
302
|
+
*/
|
|
303
|
+
loadConfigurations() {
|
|
304
|
+
try {
|
|
305
|
+
const saved = localStorage.getItem(this.storageKey);
|
|
306
|
+
return saved ? JSON.parse(saved) : {};
|
|
307
|
+
} catch (error) {
|
|
308
|
+
console.error("Error cargando configuraciones:", error);
|
|
309
|
+
return {};
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Guarda configuraciones en localStorage
|
|
314
|
+
*/
|
|
315
|
+
saveConfigurations(configs) {
|
|
316
|
+
try {
|
|
317
|
+
localStorage.setItem(this.storageKey, JSON.stringify(configs));
|
|
318
|
+
this.createBackup(configs);
|
|
319
|
+
return true;
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error("Error guardando configuraciones:", error);
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Crea un backup de las configuraciones
|
|
327
|
+
*/
|
|
328
|
+
createBackup(configs = null) {
|
|
329
|
+
try {
|
|
330
|
+
const configsToBackup = configs || this.loadConfigurations();
|
|
331
|
+
const backup = {
|
|
332
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
333
|
+
configurations: configsToBackup,
|
|
334
|
+
version: "1.0"
|
|
335
|
+
};
|
|
336
|
+
localStorage.setItem(this.backupKey, JSON.stringify(backup));
|
|
337
|
+
return true;
|
|
338
|
+
} catch (error) {
|
|
339
|
+
console.error("Error creando backup:", error);
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Restaura configuraciones desde backup
|
|
345
|
+
*/
|
|
346
|
+
restoreFromBackup() {
|
|
347
|
+
try {
|
|
348
|
+
const backup = localStorage.getItem(this.backupKey);
|
|
349
|
+
if (backup) {
|
|
350
|
+
const backupData = JSON.parse(backup);
|
|
351
|
+
this.saveConfigurations(backupData.configurations);
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
return false;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error("Error restaurando backup:", error);
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Exporta configuraciones para descarga
|
|
362
|
+
*/
|
|
363
|
+
exportConfigurations() {
|
|
364
|
+
const configs = this.loadConfigurations();
|
|
365
|
+
const exportData = {
|
|
366
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
367
|
+
configurations: configs,
|
|
368
|
+
version: "1.0"
|
|
369
|
+
};
|
|
370
|
+
return JSON.stringify(exportData, null, 2);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Importa configuraciones desde archivo
|
|
374
|
+
*/
|
|
375
|
+
importConfigurations(jsonData) {
|
|
376
|
+
try {
|
|
377
|
+
const importData = JSON.parse(jsonData);
|
|
378
|
+
if (importData.configurations) {
|
|
379
|
+
this.saveConfigurations(importData.configurations);
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
return false;
|
|
383
|
+
} catch (error) {
|
|
384
|
+
console.error("Error importando configuraciones:", error);
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Resetea configuraciones a valores predeterminados
|
|
390
|
+
*/
|
|
391
|
+
resetToDefaults() {
|
|
392
|
+
try {
|
|
393
|
+
localStorage.removeItem(this.storageKey);
|
|
394
|
+
this.initializeDefaultConfigurations();
|
|
395
|
+
return true;
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.error("Error reseteando configuraciones:", error);
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Estado de autenticación del administrador
|
|
403
|
+
*/
|
|
404
|
+
isAuthenticated() {
|
|
405
|
+
try {
|
|
406
|
+
const raw = localStorage.getItem(this.authKey);
|
|
407
|
+
if (!raw) return false;
|
|
408
|
+
const data = JSON.parse(raw);
|
|
409
|
+
return !!(data == null ? void 0 : data.authenticated);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Autentica al administrador con credenciales simples de demo
|
|
416
|
+
*/
|
|
417
|
+
authenticateAdmin(username, password) {
|
|
418
|
+
const validUser = username === "admin";
|
|
419
|
+
const validPass = password === "martiderm2024";
|
|
420
|
+
if (validUser && validPass) {
|
|
421
|
+
const session = {
|
|
422
|
+
authenticated: true,
|
|
423
|
+
username,
|
|
424
|
+
token: `adm-${Date.now()}`,
|
|
425
|
+
lastLogin: (/* @__PURE__ */ new Date()).toISOString()
|
|
426
|
+
};
|
|
427
|
+
localStorage.setItem(this.authKey, JSON.stringify(session));
|
|
428
|
+
return { success: true, username };
|
|
429
|
+
}
|
|
430
|
+
return { success: false, error: "Credenciales inválidas" };
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Obtiene información del usuario autenticado
|
|
434
|
+
*/
|
|
435
|
+
getAuthenticatedUser() {
|
|
436
|
+
try {
|
|
437
|
+
const raw = localStorage.getItem(this.authKey);
|
|
438
|
+
if (!raw) return null;
|
|
439
|
+
const data = JSON.parse(raw);
|
|
440
|
+
if (data == null ? void 0 : data.authenticated) {
|
|
441
|
+
return { username: data.username };
|
|
442
|
+
}
|
|
443
|
+
return null;
|
|
444
|
+
} catch (e) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Cierra sesión del administrador
|
|
450
|
+
*/
|
|
451
|
+
logout() {
|
|
452
|
+
try {
|
|
453
|
+
localStorage.removeItem(this.authKey);
|
|
454
|
+
return true;
|
|
455
|
+
} catch (e) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Compatibilidad: método singular usado por AdminPanel
|
|
461
|
+
*/
|
|
462
|
+
exportConfiguration() {
|
|
463
|
+
return this.exportConfigurations();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
const filterConfigManager = new FilterConfigManager();
|
|
467
|
+
function buildWebglConfigForProduct(product) {
|
|
468
|
+
var _a, _b, _c, _d;
|
|
469
|
+
const pc = filterConfigManager.getProductConfig(product.id) || {};
|
|
470
|
+
const lockedType = product.filterType || pc.webglConfig && pc.webglConfig.filterType || "wrinkles";
|
|
471
|
+
const defaults = FILTERS[lockedType] && FILTERS[lockedType].defaults || { intensity: 0.5, sigma: 4, brightness: 0 };
|
|
472
|
+
const deep = FILTERS[lockedType] && FILTERS[lockedType].deep || {};
|
|
473
|
+
const base = {
|
|
474
|
+
filterType: lockedType,
|
|
475
|
+
intensity: product.defaultIntensity !== void 0 ? product.defaultIntensity : defaults.intensity,
|
|
476
|
+
sigma: product.defaultSigma !== void 0 ? product.defaultSigma : defaults.sigma,
|
|
477
|
+
brightness: product.defaultBrightness !== void 0 ? product.defaultBrightness : defaults.brightness,
|
|
478
|
+
contrast: typeof ((_a = deep.contrast) == null ? void 0 : _a.value) === "number" ? deep.contrast.value : 1,
|
|
479
|
+
warmthR: typeof ((_b = deep.warmth) == null ? void 0 : _b.rPlus) === "number" ? deep.warmth.rPlus : 0,
|
|
480
|
+
warmthB: typeof ((_c = deep.warmth) == null ? void 0 : _c.bMinus) === "number" ? deep.warmth.bMinus : 0,
|
|
481
|
+
warmthA: typeof ((_d = deep.warmth) == null ? void 0 : _d.alpha) === "number" ? deep.warmth.alpha : 0
|
|
482
|
+
};
|
|
483
|
+
const adminCfg = pc.webglConfig || {};
|
|
484
|
+
return { ...base, ...adminCfg, filterType: lockedType };
|
|
485
|
+
}
|
|
486
|
+
const TOKEN_PREFIX = "mdfe_";
|
|
487
|
+
const PRODUCT_CODE = "md-face-engine";
|
|
488
|
+
const LICENSE_SECRET = "md-face-engine-license-v1";
|
|
489
|
+
function hashToken(value) {
|
|
490
|
+
let hash = 5381;
|
|
491
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
492
|
+
hash = (hash << 5) + hash + value.charCodeAt(i);
|
|
493
|
+
hash &= 4294967295;
|
|
494
|
+
}
|
|
495
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
496
|
+
}
|
|
497
|
+
function decodeBase64Url(value) {
|
|
498
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
499
|
+
const padding = normalized.length % 4;
|
|
500
|
+
const padded = padding ? normalized + "=".repeat(4 - padding) : normalized;
|
|
501
|
+
return atob(padded);
|
|
502
|
+
}
|
|
503
|
+
function validateLicenseToken(token, options = {}) {
|
|
504
|
+
const { now = Date.now() } = options;
|
|
505
|
+
if (!token || typeof token !== "string") {
|
|
506
|
+
return { valid: false, reason: "Token vacío o inválido" };
|
|
507
|
+
}
|
|
508
|
+
if (!token.startsWith(TOKEN_PREFIX)) {
|
|
509
|
+
return { valid: false, reason: "Prefijo de token inválido" };
|
|
510
|
+
}
|
|
511
|
+
const raw = token.slice(TOKEN_PREFIX.length);
|
|
512
|
+
const parts = raw.split(".");
|
|
513
|
+
if (parts.length !== 2) {
|
|
514
|
+
return { valid: false, reason: "Formato de token inválido" };
|
|
515
|
+
}
|
|
516
|
+
const [payloadPart, signature] = parts;
|
|
517
|
+
const expected = hashToken(`${payloadPart}.${LICENSE_SECRET}`);
|
|
518
|
+
if (signature !== expected) {
|
|
519
|
+
return { valid: false, reason: "Firma de licencia inválida" };
|
|
520
|
+
}
|
|
521
|
+
let payload;
|
|
522
|
+
try {
|
|
523
|
+
payload = JSON.parse(decodeBase64Url(payloadPart));
|
|
524
|
+
} catch (_err) {
|
|
525
|
+
return { valid: false, reason: "Payload de licencia inválido" };
|
|
526
|
+
}
|
|
527
|
+
if (payload.productCode !== PRODUCT_CODE) {
|
|
528
|
+
return { valid: false, reason: "Licencia de otro producto" };
|
|
529
|
+
}
|
|
530
|
+
if (typeof payload.exp !== "number" || payload.exp < now) {
|
|
531
|
+
return { valid: false, reason: "Licencia vencida" };
|
|
532
|
+
}
|
|
533
|
+
return { valid: true, reason: null, payload };
|
|
534
|
+
}
|
|
535
|
+
class MdFaceEngine {
|
|
536
|
+
constructor() {
|
|
537
|
+
this.license = null;
|
|
538
|
+
this.activated = false;
|
|
539
|
+
}
|
|
540
|
+
activate(token) {
|
|
541
|
+
const result = validateLicenseToken(token);
|
|
542
|
+
if (!result.valid) {
|
|
543
|
+
this.license = null;
|
|
544
|
+
this.activated = false;
|
|
545
|
+
throw new Error(`Licencia inválida: ${result.reason}`);
|
|
546
|
+
}
|
|
547
|
+
this.license = result.payload;
|
|
548
|
+
this.activated = true;
|
|
549
|
+
return result.payload;
|
|
550
|
+
}
|
|
551
|
+
isActivated() {
|
|
552
|
+
return this.activated;
|
|
553
|
+
}
|
|
554
|
+
assertActivated() {
|
|
555
|
+
if (!this.activated) {
|
|
556
|
+
throw new Error("md-face-engine no está activado. Configura VITE_MD_FACE_ENGINE_TOKEN.");
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
getLicense() {
|
|
560
|
+
this.assertActivated();
|
|
561
|
+
return this.license;
|
|
562
|
+
}
|
|
563
|
+
getProductCode() {
|
|
564
|
+
return PRODUCT_CODE;
|
|
565
|
+
}
|
|
566
|
+
getFilterRegistry() {
|
|
567
|
+
this.assertActivated();
|
|
568
|
+
return FILTERS;
|
|
569
|
+
}
|
|
570
|
+
getFilterOrder() {
|
|
571
|
+
this.assertActivated();
|
|
572
|
+
return FILTER_ORDER;
|
|
573
|
+
}
|
|
574
|
+
getFilter(key) {
|
|
575
|
+
this.assertActivated();
|
|
576
|
+
return getFilter(key);
|
|
577
|
+
}
|
|
578
|
+
getFilterConfigManager() {
|
|
579
|
+
this.assertActivated();
|
|
580
|
+
return filterConfigManager;
|
|
581
|
+
}
|
|
582
|
+
buildWebglConfigForProduct(product) {
|
|
583
|
+
this.assertActivated();
|
|
584
|
+
return buildWebglConfigForProduct(product);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
function createMdFaceEngineClient({ token, products = [] } = {}) {
|
|
588
|
+
if (!token) {
|
|
589
|
+
throw new Error("Falta token de licencia para activar md-face-engine.");
|
|
590
|
+
}
|
|
591
|
+
const engine = new MdFaceEngine();
|
|
592
|
+
engine.activate(token);
|
|
593
|
+
engine.assertActivated();
|
|
594
|
+
const filterConfigManager2 = engine.getFilterConfigManager();
|
|
595
|
+
if (Array.isArray(products)) {
|
|
596
|
+
filterConfigManager2.setProducts(products);
|
|
597
|
+
}
|
|
598
|
+
return {
|
|
599
|
+
engine,
|
|
600
|
+
FILTERS: engine.getFilterRegistry(),
|
|
601
|
+
FILTER_ORDER: engine.getFilterOrder(),
|
|
602
|
+
getFilter: (key) => engine.getFilter(key),
|
|
603
|
+
filterConfigManager: filterConfigManager2,
|
|
604
|
+
buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
export {
|
|
608
|
+
CATEGORY_PRESETS as C,
|
|
609
|
+
DEFAULT_FILTER_CONFIG as D,
|
|
610
|
+
FILTERS as F,
|
|
611
|
+
MdFaceEngine as M,
|
|
612
|
+
FILTER_ORDER as a,
|
|
613
|
+
FilterConfigManager as b,
|
|
614
|
+
createMdFaceEngineClient as c,
|
|
615
|
+
buildWebglConfigForProduct as d,
|
|
616
|
+
filterConfigManager as f,
|
|
617
|
+
getFilter as g,
|
|
618
|
+
validateLicenseToken as v
|
|
619
|
+
};
|
|
620
|
+
//# sourceMappingURL=client-BGSZMMvf.js.map
|