md-face-engine 1.0.0 → 1.1.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 +14 -5
- package/dist/{client-BGSZMMvf.js → client-B8NLJ0b1.js} +110 -36
- package/dist/client-B8NLJ0b1.js.map +1 -0
- package/dist/{client-DimGdJ4Y.cjs → client-Com8umy4.cjs} +107 -33
- package/dist/client-Com8umy4.cjs.map +1 -0
- package/dist/client.cjs +2 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +3 -2
- package/dist/index.cjs +3 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/client-BGSZMMvf.js.map +0 -1
- package/dist/client-DimGdJ4Y.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -8,20 +8,29 @@ Motor reusable para detección facial y aplicación de filtros.
|
|
|
8
8
|
npm install md-face-engine
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## API rápida
|
|
12
|
+
|
|
13
|
+
- `createMdFaceEngineClient({ token, products })`: exige licencia válida.
|
|
14
|
+
- `createMdFaceEngineRuntime({ token, products })`: funciona con o sin licencia (útil para modo demo/watermark).
|
|
15
|
+
|
|
16
|
+
Ambas APIs son `async`.
|
|
17
|
+
|
|
18
|
+
## Uso recomendado (runtime)
|
|
12
19
|
|
|
13
20
|
```js
|
|
14
|
-
import {
|
|
21
|
+
import { createMdFaceEngineRuntime } from 'md-face-engine/client';
|
|
15
22
|
|
|
16
|
-
const
|
|
23
|
+
const runtime = await createMdFaceEngineRuntime({
|
|
17
24
|
token: import.meta.env.VITE_MD_FACE_ENGINE_TOKEN,
|
|
18
25
|
products: []
|
|
19
26
|
});
|
|
27
|
+
|
|
28
|
+
console.log(runtime.license.active); // true/false
|
|
20
29
|
```
|
|
21
30
|
|
|
22
|
-
|
|
31
|
+
## Tokens
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
Formato esperado: `mdfe2_...` con firma asimétrica ECDSA.
|
|
25
34
|
|
|
26
35
|
## Build del paquete
|
|
27
36
|
|
|
@@ -463,10 +463,10 @@ class FilterConfigManager {
|
|
|
463
463
|
return this.exportConfigurations();
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
|
-
const
|
|
466
|
+
const coreFilterConfigManager = new FilterConfigManager();
|
|
467
467
|
function buildWebglConfigForProduct(product) {
|
|
468
468
|
var _a, _b, _c, _d;
|
|
469
|
-
const pc =
|
|
469
|
+
const pc = coreFilterConfigManager.getProductConfig(product.id) || {};
|
|
470
470
|
const lockedType = product.filterType || pc.webglConfig && pc.webglConfig.filterType || "wrinkles";
|
|
471
471
|
const defaults = FILTERS[lockedType] && FILTERS[lockedType].defaults || { intensity: 0.5, sigma: 4, brightness: 0 };
|
|
472
472
|
const deep = FILTERS[lockedType] && FILTERS[lockedType].deep || {};
|
|
@@ -483,25 +483,58 @@ function buildWebglConfigForProduct(product) {
|
|
|
483
483
|
const adminCfg = pc.webglConfig || {};
|
|
484
484
|
return { ...base, ...adminCfg, filterType: lockedType };
|
|
485
485
|
}
|
|
486
|
-
const TOKEN_PREFIX = "
|
|
486
|
+
const TOKEN_PREFIX = "mdfe2_";
|
|
487
487
|
const PRODUCT_CODE = "md-face-engine";
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
hash &= 4294967295;
|
|
494
|
-
}
|
|
495
|
-
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
496
|
-
}
|
|
488
|
+
const LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
489
|
+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW9CHbTVvVXcm09wZIj6GKGaq8ae1
|
|
490
|
+
XGQAum9LBLgoT3+4q3xPc7W9KSw1z4xgfOByTi8OzdjbjEaF3VrHjzl05w==
|
|
491
|
+
-----END PUBLIC KEY-----`;
|
|
492
|
+
let publicKeyCache = null;
|
|
497
493
|
function decodeBase64Url(value) {
|
|
498
494
|
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
499
|
-
const
|
|
500
|
-
const padded = padding ? normalized + "=".repeat(4 - padding) : normalized;
|
|
495
|
+
const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
|
|
501
496
|
return atob(padded);
|
|
502
497
|
}
|
|
503
|
-
function
|
|
504
|
-
const
|
|
498
|
+
function decodeBase64UrlToBytes(value) {
|
|
499
|
+
const bin = decodeBase64Url(value);
|
|
500
|
+
const bytes = new Uint8Array(bin.length);
|
|
501
|
+
for (let i = 0; i < bin.length; i += 1) {
|
|
502
|
+
bytes[i] = bin.charCodeAt(i);
|
|
503
|
+
}
|
|
504
|
+
return bytes;
|
|
505
|
+
}
|
|
506
|
+
function pemToArrayBuffer(pem) {
|
|
507
|
+
const b64 = pem.replace(/-----BEGIN PUBLIC KEY-----/g, "").replace(/-----END PUBLIC KEY-----/g, "").replace(/\s+/g, "");
|
|
508
|
+
const raw = atob(b64);
|
|
509
|
+
const bytes = new Uint8Array(raw.length);
|
|
510
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
511
|
+
bytes[i] = raw.charCodeAt(i);
|
|
512
|
+
}
|
|
513
|
+
return bytes.buffer;
|
|
514
|
+
}
|
|
515
|
+
async function importPublicKey(publicKeyPem = LICENSE_PUBLIC_KEY_PEM) {
|
|
516
|
+
if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM && publicKeyCache) {
|
|
517
|
+
return publicKeyCache;
|
|
518
|
+
}
|
|
519
|
+
const keyData = pemToArrayBuffer(publicKeyPem);
|
|
520
|
+
const key = await crypto.subtle.importKey(
|
|
521
|
+
"spki",
|
|
522
|
+
keyData,
|
|
523
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
524
|
+
false,
|
|
525
|
+
["verify"]
|
|
526
|
+
);
|
|
527
|
+
if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM) {
|
|
528
|
+
publicKeyCache = key;
|
|
529
|
+
}
|
|
530
|
+
return key;
|
|
531
|
+
}
|
|
532
|
+
async function validateLicenseToken(token, options = {}) {
|
|
533
|
+
const {
|
|
534
|
+
now = Date.now(),
|
|
535
|
+
publicKeyPem = LICENSE_PUBLIC_KEY_PEM,
|
|
536
|
+
allowExpired = false
|
|
537
|
+
} = options;
|
|
505
538
|
if (!token || typeof token !== "string") {
|
|
506
539
|
return { valid: false, reason: "Token vacío o inválido" };
|
|
507
540
|
}
|
|
@@ -513,22 +546,32 @@ function validateLicenseToken(token, options = {}) {
|
|
|
513
546
|
if (parts.length !== 2) {
|
|
514
547
|
return { valid: false, reason: "Formato de token inválido" };
|
|
515
548
|
}
|
|
516
|
-
const [payloadPart,
|
|
517
|
-
const expected = hashToken(`${payloadPart}.${LICENSE_SECRET}`);
|
|
518
|
-
if (signature !== expected) {
|
|
519
|
-
return { valid: false, reason: "Firma de licencia inválida" };
|
|
520
|
-
}
|
|
549
|
+
const [payloadPart, signaturePart] = parts;
|
|
521
550
|
let payload;
|
|
522
551
|
try {
|
|
523
552
|
payload = JSON.parse(decodeBase64Url(payloadPart));
|
|
524
553
|
} catch (_err) {
|
|
525
554
|
return { valid: false, reason: "Payload de licencia inválido" };
|
|
526
555
|
}
|
|
556
|
+
try {
|
|
557
|
+
const key = await importPublicKey(publicKeyPem);
|
|
558
|
+
const isValid = await crypto.subtle.verify(
|
|
559
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
560
|
+
key,
|
|
561
|
+
decodeBase64UrlToBytes(signaturePart),
|
|
562
|
+
new TextEncoder().encode(payloadPart)
|
|
563
|
+
);
|
|
564
|
+
if (!isValid) {
|
|
565
|
+
return { valid: false, reason: "Firma de licencia inválida" };
|
|
566
|
+
}
|
|
567
|
+
} catch (_err) {
|
|
568
|
+
return { valid: false, reason: "Error verificando firma de licencia" };
|
|
569
|
+
}
|
|
527
570
|
if (payload.productCode !== PRODUCT_CODE) {
|
|
528
571
|
return { valid: false, reason: "Licencia de otro producto" };
|
|
529
572
|
}
|
|
530
|
-
if (typeof payload.exp !== "number" || payload.exp < now) {
|
|
531
|
-
return { valid: false, reason: "Licencia vencida" };
|
|
573
|
+
if (!allowExpired && (typeof payload.exp !== "number" || payload.exp < now)) {
|
|
574
|
+
return { valid: false, reason: "Licencia vencida", payload };
|
|
532
575
|
}
|
|
533
576
|
return { valid: true, reason: null, payload };
|
|
534
577
|
}
|
|
@@ -537,8 +580,8 @@ class MdFaceEngine {
|
|
|
537
580
|
this.license = null;
|
|
538
581
|
this.activated = false;
|
|
539
582
|
}
|
|
540
|
-
activate(token) {
|
|
541
|
-
const result = validateLicenseToken(token);
|
|
583
|
+
async activate(token) {
|
|
584
|
+
const result = await validateLicenseToken(token);
|
|
542
585
|
if (!result.valid) {
|
|
543
586
|
this.license = null;
|
|
544
587
|
this.activated = false;
|
|
@@ -577,44 +620,75 @@ class MdFaceEngine {
|
|
|
577
620
|
}
|
|
578
621
|
getFilterConfigManager() {
|
|
579
622
|
this.assertActivated();
|
|
580
|
-
return
|
|
623
|
+
return coreFilterConfigManager;
|
|
581
624
|
}
|
|
582
625
|
buildWebglConfigForProduct(product) {
|
|
583
626
|
this.assertActivated();
|
|
584
627
|
return buildWebglConfigForProduct(product);
|
|
585
628
|
}
|
|
586
629
|
}
|
|
587
|
-
function createMdFaceEngineClient({ token, products = [] } = {}) {
|
|
630
|
+
async function createMdFaceEngineClient({ token, products = [] } = {}) {
|
|
588
631
|
if (!token) {
|
|
589
632
|
throw new Error("Falta token de licencia para activar md-face-engine.");
|
|
590
633
|
}
|
|
591
634
|
const engine = new MdFaceEngine();
|
|
592
|
-
engine.activate(token);
|
|
635
|
+
await engine.activate(token);
|
|
593
636
|
engine.assertActivated();
|
|
594
|
-
const
|
|
637
|
+
const filterConfigManager = engine.getFilterConfigManager();
|
|
595
638
|
if (Array.isArray(products)) {
|
|
596
|
-
|
|
639
|
+
filterConfigManager.setProducts(products);
|
|
597
640
|
}
|
|
598
641
|
return {
|
|
599
642
|
engine,
|
|
600
643
|
FILTERS: engine.getFilterRegistry(),
|
|
601
644
|
FILTER_ORDER: engine.getFilterOrder(),
|
|
602
645
|
getFilter: (key) => engine.getFilter(key),
|
|
603
|
-
filterConfigManager
|
|
646
|
+
filterConfigManager,
|
|
604
647
|
buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)
|
|
605
648
|
};
|
|
606
649
|
}
|
|
650
|
+
async function createMdFaceEngineRuntime({ token, products = [] } = {}) {
|
|
651
|
+
let client = null;
|
|
652
|
+
let licenseError = null;
|
|
653
|
+
let isLicenseActive = false;
|
|
654
|
+
if (token) {
|
|
655
|
+
try {
|
|
656
|
+
client = await createMdFaceEngineClient({ token, products });
|
|
657
|
+
isLicenseActive = true;
|
|
658
|
+
} catch (error) {
|
|
659
|
+
licenseError = error;
|
|
660
|
+
isLicenseActive = false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
if (!client && Array.isArray(products) && typeof (coreFilterConfigManager == null ? void 0 : coreFilterConfigManager.setProducts) === "function") {
|
|
664
|
+
coreFilterConfigManager.setProducts(products);
|
|
665
|
+
}
|
|
666
|
+
return {
|
|
667
|
+
engine: (client == null ? void 0 : client.engine) || null,
|
|
668
|
+
FILTERS: (client == null ? void 0 : client.FILTERS) || FILTERS,
|
|
669
|
+
FILTER_ORDER: (client == null ? void 0 : client.FILTER_ORDER) || FILTER_ORDER,
|
|
670
|
+
getFilter: (client == null ? void 0 : client.getFilter) || getFilter,
|
|
671
|
+
filterConfigManager: (client == null ? void 0 : client.filterConfigManager) || coreFilterConfigManager,
|
|
672
|
+
buildWebglConfigForProduct: (client == null ? void 0 : client.buildWebglConfigForProduct) || buildWebglConfigForProduct,
|
|
673
|
+
license: {
|
|
674
|
+
active: isLicenseActive,
|
|
675
|
+
error: licenseError,
|
|
676
|
+
mode: isLicenseActive ? "licensed" : "unlicensed"
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
}
|
|
607
680
|
export {
|
|
608
681
|
CATEGORY_PRESETS as C,
|
|
609
682
|
DEFAULT_FILTER_CONFIG as D,
|
|
610
683
|
FILTERS as F,
|
|
611
684
|
MdFaceEngine as M,
|
|
612
|
-
|
|
613
|
-
|
|
685
|
+
createMdFaceEngineRuntime as a,
|
|
686
|
+
FILTER_ORDER as b,
|
|
614
687
|
createMdFaceEngineClient as c,
|
|
615
|
-
|
|
616
|
-
|
|
688
|
+
coreFilterConfigManager as d,
|
|
689
|
+
FilterConfigManager as e,
|
|
690
|
+
buildWebglConfigForProduct as f,
|
|
617
691
|
getFilter as g,
|
|
618
692
|
validateLicenseToken as v
|
|
619
693
|
};
|
|
620
|
-
//# sourceMappingURL=client-
|
|
694
|
+
//# sourceMappingURL=client-B8NLJ0b1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-B8NLJ0b1.js","sources":["../src/core/filters/wrinkles.js","../src/core/filters/brightness.js","../src/core/filters/spots.js","../src/core/filters/acne.js","../src/core/filters/firmness.js","../src/core/filters/index.js","../src/core/config/FilterConfigManager.js","../src/core/webgl/buildWebglConfigForProduct.js","../src/license/token.js","../src/MartidermEngine.js","../src/client.js"],"sourcesContent":["export default {\n key: 'wrinkles',\n label: 'Arrugas',\n defaults: { intensity: 0.5, sigma: 4, brightness: 0 },\n deep: {\n smooth: { enabled: true, radius: 8, passes: 4, opacity: 0.7 },\n brightness: { enabled: true, value: 10 },\n contrast: { enabled: true, value: 1.03 },\n warmth: { enabled: true, rPlus: 8, bMinus: 5, alpha: 0.3 },\n toneUnify: { enabled: true, threshold: 12, mix: 0.4 },\n blemish: { enabled: true, microBlur: 3, alpha: 0.4 },\n contourLift: { enabled: true, lift: 0.06, shade: 0.04, feather: 20 }\n }\n}\n","export default {\n key: 'brightness',\n label: 'Luminosidad',\n defaults: { intensity: 0, sigma: 0, brightness: 0.07 },\n deep: {\n smooth: { enabled: true, radius: 5, passes: 3, opacity: 0.5 },\n brightness: { enabled: true, value: 18 },\n contrast: { enabled: true, value: 1.15 },\n warmth: { enabled: true, rPlus: 12, bMinus: 8, alpha: 0.45 },\n toneUnify: { enabled: true, threshold: 10, mix: 0.3 },\n blemish: { enabled: true, microBlur: 2, alpha: 0.3 },\n contourLift: { enabled: true, lift: 0.12, shade: 0.08, feather: 18 }\n }\n}\n","export default {\n key: 'spots',\n label: 'Manchas/Tono',\n defaults: { intensity: 0.65, sigma: 5, brightness: 0.05 },\n deep: {\n smooth: { enabled: true, radius: 6, passes: 3, opacity: 0.6 },\n brightness: { enabled: true, value: 12 },\n contrast: { enabled: true, value: 1.08 },\n warmth: { enabled: true, rPlus: 7, bMinus: 4, alpha: 0.3 },\n toneUnify: { enabled: true, threshold: 8, mix: 0.6 },\n blemish: { enabled: true, microBlur: 4, alpha: 0.5 },\n contourLift: { enabled: true, lift: 0.08, shade: 0.06, feather: 16 }\n }\n}\n","export default {\n key: 'acne',\n label: 'Acné',\n defaults: { intensity: 0.55, sigma: 3.4, brightness: 0.1 },\n deep: {\n smooth: { enabled: true, radius: 7, passes: 4, opacity: 0.65 },\n brightness: { enabled: true, value: 8 },\n contrast: { enabled: true, value: 1.02 },\n warmth: { enabled: true, rPlus: 6, bMinus: 3, alpha: 0.25 },\n toneUnify: { enabled: true, threshold: 10, mix: 0.5 },\n blemish: { enabled: true, microBlur: 5, alpha: 0.7 },\n contourLift: { enabled: true, lift: 0.06, shade: 0.04, feather: 20 }\n }\n}\n","export default {\n key: 'firmness',\n label: 'Firmeza',\n defaults: { intensity: 0.7, sigma: 2, brightness: 0 },\n deep: {\n smooth: { enabled: true, radius: 3, passes: 2, opacity: 0.3 },\n brightness: { enabled: true, value: 6 },\n contrast: { enabled: true, value: 1.12 },\n warmth: { enabled: true, rPlus: 5, bMinus: 3, alpha: 0.2 },\n toneUnify: { enabled: true, threshold: 18, mix: 0.2 },\n blemish: { enabled: false, microBlur: 1, alpha: 0.1 },\n contourLift: { enabled: true, lift: 0.15, shade: 0.12, feather: 12 }\n }\n}\n","import wrinkles from './wrinkles'\nimport brightness from './brightness'\nimport spots from './spots'\nimport acne from './acne'\nimport firmness from './firmness'\n\nexport const FILTERS = {\n wrinkles,\n brightness,\n spots,\n acne,\n firmness,\n}\n\nexport function getFilter(key) {\n return FILTERS[key] || null\n}\n\nexport const FILTER_ORDER = ['wrinkles','brightness','spots','acne','firmness']\n","/**\n * FilterConfigManager - Servicio para gestionar configuraciones de filtros por producto\n * \n * Funcionalidades:\n * - Almacenamiento persistente de configuraciones de filtros\n * - Gestión de configuraciones por producto\n * - Sistema de autenticación para administradores\n * - Backup y restauración de configuraciones\n * - Valores predeterminados para filtros\n */\n\n// Configuraciones predeterminadas para cada tipo de filtro (alineadas con beautyFilters)\nconst DEFAULT_FILTER_CONFIG = {\n // 1) Arrugas → Suavizado de piel\n smooth: {\n enabled: true,\n intensity: 36, // referencia visual\n radius: 4,\n passes: 2,\n opacity: 0.4\n },\n // 2) Piel apagada → Brillo\n brightness: {\n enabled: true,\n intensity: 91, // referencia visual\n value: 8\n },\n // Ajuste de contraste general\n contrast: {\n enabled: true,\n intensity: 10,\n value: 1.05\n },\n // Tono cálido / glow\n warmth: {\n enabled: true,\n intensity: 20,\n rPlus: 6,\n bMinus: 4,\n alpha: 0.25\n },\n // 2) Manchas → Unificar tono\n toneUnify: {\n enabled: true,\n intensity: 65, // referencia visual\n threshold: 15,\n mix: 0.25\n },\n // 5) Acné → Reducir imperfecciones\n blemish: {\n enabled: true,\n intensity: 35, // referencia visual\n microBlur: 2,\n alpha: 0.25\n },\n // 3) Firmeza → Lifting y contouring\n contourLift: {\n enabled: true,\n intensity: 24, // referencia visual\n lift: 0.08,\n shade: 0.06,\n feather: 15\n },\n // Extras\n highlights: {\n enabled: false,\n intensity: 10\n },\n shadows: {\n enabled: false,\n intensity: 5\n }\n};\n\n// Presets por preocupación de piel\nconst CONCERN_PRESETS = {\n arrugas: {\n smooth: { enabled: true, intensity: 36, radius: 6, passes: 3, opacity: 0.6 },\n contourLift: { enabled: true, intensity: 20, lift: 0.06, shade: 0.05, feather: 18 }\n },\n manchas: {\n toneUnify: { enabled: true, intensity: 65, threshold: 14, mix: 0.35 },\n brightness: { enabled: true, intensity: 20, value: 10 }\n },\n firmeza: {\n contourLift: { enabled: true, intensity: 24, lift: 0.08, shade: 0.06, feather: 20 },\n contrast: { enabled: true, intensity: 12, value: 1.07 }\n },\n luminosidad: {\n brightness: { enabled: true, intensity: 91, value: 12 },\n warmth: { enabled: true, intensity: 25, rPlus: 8, bMinus: 5, alpha: 0.3 }\n },\n acne: {\n blemish: { enabled: true, intensity: 35, microBlur: 3, alpha: 0.35 },\n toneUnify: { enabled: true, intensity: 40, threshold: 16, mix: 0.3 }\n }\n};\n\n// Configuraciones específicas por categoría de producto (usando categorías reales)\nconst CATEGORY_PRESETS = {\n // Antiaging: foco en arrugas y firmeza\n antiaging: {\n smooth: { enabled: true, intensity: 36, radius: 6, passes: 3, opacity: 0.6 },\n contourLift: { enabled: true, intensity: 24, lift: 0.07, shade: 0.05, feather: 18 },\n brightness: { enabled: true, intensity: 20, value: 10 },\n warmth: { enabled: true, intensity: 22, rPlus: 7, bMinus: 5, alpha: 0.28 }\n },\n // Manchas / pigmentación: foco en unificar tono y luminosidad\n manchas: {\n toneUnify: { enabled: true, intensity: 65, threshold: 14, mix: 0.35 },\n brightness: { enabled: true, intensity: 25, value: 10 },\n warmth: { enabled: false }\n },\n // Hidratación: suavizado ligero y glow moderado\n hidratacion: {\n smooth: { enabled: true, intensity: 25, radius: 3, passes: 2, opacity: 0.35 },\n brightness: { enabled: true, intensity: 18, value: 8 },\n warmth: { enabled: true, intensity: 15, rPlus: 5, bMinus: 3, alpha: 0.2 }\n },\n // Acné: foco en reducción de imperfecciones y tono uniforme\n acne: {\n blemish: { enabled: true, intensity: 35, microBlur: 3, alpha: 0.35 },\n toneUnify: { enabled: true, intensity: 40, threshold: 16, mix: 0.3 },\n brightness: { enabled: false }\n }\n};\n\nclass FilterConfigManager {\n constructor(options = {}) {\n this.storageKey = 'martiderm_filter_configs';\n this.authKey = 'martiderm_admin_auth';\n this.backupKey = 'martiderm_config_backup';\n this.products = Array.isArray(options.products) ? options.products : [];\n this.init();\n }\n\n /**\n * Inicializa el gestor de configuraciones\n */\n init() {\n // Verificar si existen configuraciones guardadas\n const savedConfigs = this.loadConfigurations();\n if ((!savedConfigs || Object.keys(savedConfigs).length === 0) && this.products.length > 0) {\n this.initializeDefaultConfigurations();\n }\n }\n\n setProducts(products = []) {\n this.products = Array.isArray(products) ? products : [];\n const savedConfigs = this.loadConfigurations();\n if ((!savedConfigs || Object.keys(savedConfigs).length === 0) && this.products.length > 0) {\n this.initializeDefaultConfigurations();\n }\n }\n\n /**\n * Inicializa configuraciones predeterminadas para todos los productos\n */\n initializeDefaultConfigurations() {\n try {\n const configs = {};\n this.products.forEach(product => {\n configs[product.id] = this.generateProductConfig(product);\n });\n this.saveConfigurations(configs);\n } catch (error) {\n console.error('Error inicializando configuraciones:', error);\n }\n }\n\n /**\n * Genera configuración específica para un producto\n */\n generateProductConfig(product) {\n const baseConfig = { ...DEFAULT_FILTER_CONFIG };\n const categoryPreset = CATEGORY_PRESETS[product.category];\n \n if (categoryPreset) {\n // Aplicar presets específicos de la categoría\n Object.keys(categoryPreset).forEach(filterType => {\n if (baseConfig[filterType]) {\n baseConfig[filterType] = {\n ...baseConfig[filterType],\n ...categoryPreset[filterType]\n };\n }\n });\n }\n\n // Aplicar presets por preocupaciones del producto (si existen)\n if (product.targetConcerns && Array.isArray(product.targetConcerns)) {\n product.targetConcerns.forEach(concern => {\n const preset = CONCERN_PRESETS[concern];\n if (preset) {\n Object.keys(preset).forEach(filterType => {\n if (baseConfig[filterType]) {\n baseConfig[filterType] = {\n ...baseConfig[filterType],\n ...preset[filterType]\n };\n }\n });\n }\n });\n }\n \n return {\n productId: product.id,\n productName: product.name,\n category: product.category,\n filters: baseConfig,\n lastModified: new Date().toISOString(),\n version: '1.0'\n };\n }\n\n /**\n * Obtiene la configuración de filtros para un producto específico\n */\n getProductConfig(productId) {\n const configs = this.loadConfigurations();\n return configs[productId] || null;\n }\n\n /**\n * Guarda la configuración de filtros para un producto\n */\n saveProductConfig(productId, config) {\n const configs = this.loadConfigurations();\n configs[productId] = {\n ...config,\n lastModified: new Date().toISOString()\n };\n this.saveConfigurations(configs);\n return true;\n }\n\n /**\n * Obtiene todas las configuraciones\n */\n getAllConfigurations() {\n return this.loadConfigurations();\n }\n\n /**\n * Carga configuraciones desde localStorage\n */\n loadConfigurations() {\n try {\n const saved = localStorage.getItem(this.storageKey);\n return saved ? JSON.parse(saved) : {};\n } catch (error) {\n console.error('Error cargando configuraciones:', error);\n return {};\n }\n }\n\n /**\n * Guarda configuraciones en localStorage\n */\n saveConfigurations(configs) {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(configs));\n // Crear backup automático\n this.createBackup(configs);\n return true;\n } catch (error) {\n console.error('Error guardando configuraciones:', error);\n return false;\n }\n }\n\n /**\n * Crea un backup de las configuraciones\n */\n createBackup(configs = null) {\n try {\n const configsToBackup = configs || this.loadConfigurations();\n const backup = {\n timestamp: new Date().toISOString(),\n configurations: configsToBackup,\n version: '1.0'\n };\n localStorage.setItem(this.backupKey, JSON.stringify(backup));\n return true;\n } catch (error) {\n console.error('Error creando backup:', error);\n return false;\n }\n }\n\n /**\n * Restaura configuraciones desde backup\n */\n restoreFromBackup() {\n try {\n const backup = localStorage.getItem(this.backupKey);\n if (backup) {\n const backupData = JSON.parse(backup);\n this.saveConfigurations(backupData.configurations);\n return true;\n }\n return false;\n } catch (error) {\n console.error('Error restaurando backup:', error);\n return false;\n }\n }\n\n /**\n * Exporta configuraciones para descarga\n */\n exportConfigurations() {\n const configs = this.loadConfigurations();\n const exportData = {\n timestamp: new Date().toISOString(),\n configurations: configs,\n version: '1.0'\n };\n return JSON.stringify(exportData, null, 2);\n }\n\n /**\n * Importa configuraciones desde archivo\n */\n importConfigurations(jsonData) {\n try {\n const importData = JSON.parse(jsonData);\n if (importData.configurations) {\n this.saveConfigurations(importData.configurations);\n return true;\n }\n return false;\n } catch (error) {\n console.error('Error importando configuraciones:', error);\n return false;\n }\n }\n\n /**\n * Resetea configuraciones a valores predeterminados\n */\n resetToDefaults() {\n try {\n localStorage.removeItem(this.storageKey);\n this.initializeDefaultConfigurations();\n return true;\n } catch (error) {\n console.error('Error reseteando configuraciones:', error);\n return false;\n }\n }\n\n /**\n * Estado de autenticación del administrador\n */\n isAuthenticated() {\n try {\n const raw = localStorage.getItem(this.authKey);\n if (!raw) return false;\n const data = JSON.parse(raw);\n return !!data?.authenticated;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Autentica al administrador con credenciales simples de demo\n */\n authenticateAdmin(username, password) {\n // Credenciales de prueba visibles en AdminAuth\n const validUser = username === 'admin';\n const validPass = password === 'martiderm2024';\n if (validUser && validPass) {\n const session = {\n authenticated: true,\n username,\n token: `adm-${Date.now()}`,\n lastLogin: new Date().toISOString()\n };\n localStorage.setItem(this.authKey, JSON.stringify(session));\n return { success: true, username };\n }\n return { success: false, error: 'Credenciales inválidas' };\n }\n\n /**\n * Obtiene información del usuario autenticado\n */\n getAuthenticatedUser() {\n try {\n const raw = localStorage.getItem(this.authKey);\n if (!raw) return null;\n const data = JSON.parse(raw);\n if (data?.authenticated) {\n return { username: data.username };\n }\n return null;\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Cierra sesión del administrador\n */\n logout() {\n try {\n localStorage.removeItem(this.authKey);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Compatibilidad: método singular usado por AdminPanel\n */\n exportConfiguration() {\n return this.exportConfigurations();\n }\n}\n\nexport default new FilterConfigManager();\n\n// Exportar también la clase para testing\nexport { FilterConfigManager, DEFAULT_FILTER_CONFIG, CATEGORY_PRESETS };\n","import { FILTERS } from '../filters/index.js';\nimport filterConfigManager from '../config/FilterConfigManager.js';\n\nexport function buildWebglConfigForProduct(product) {\n const pc = filterConfigManager.getProductConfig(product.id) || {};\n const lockedType = product.filterType || (pc.webglConfig && pc.webglConfig.filterType) || 'wrinkles';\n const defaults = (FILTERS[lockedType] && FILTERS[lockedType].defaults) || { intensity: 0.5, sigma: 4, brightness: 0 };\n const deep = (FILTERS[lockedType] && FILTERS[lockedType].deep) || {};\n const base = {\n filterType: lockedType,\n intensity: (product.defaultIntensity !== undefined) ? product.defaultIntensity : defaults.intensity,\n sigma: (product.defaultSigma !== undefined) ? product.defaultSigma : defaults.sigma,\n brightness: (product.defaultBrightness !== undefined) ? product.defaultBrightness : defaults.brightness,\n contrast: typeof deep.contrast?.value === 'number' ? deep.contrast.value : 1.0,\n warmthR: typeof deep.warmth?.rPlus === 'number' ? deep.warmth.rPlus : 0,\n warmthB: typeof deep.warmth?.bMinus === 'number' ? deep.warmth.bMinus : 0,\n warmthA: typeof deep.warmth?.alpha === 'number' ? deep.warmth.alpha : 0,\n };\n const adminCfg = pc.webglConfig || {};\n return { ...base, ...adminCfg, filterType: lockedType };\n}\n\nexport default buildWebglConfigForProduct;\n","const TOKEN_PREFIX = 'mdfe2_';\nconst PRODUCT_CODE = 'md-face-engine';\nconst LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW9CHbTVvVXcm09wZIj6GKGaq8ae1\nXGQAum9LBLgoT3+4q3xPc7W9KSw1z4xgfOByTi8OzdjbjEaF3VrHjzl05w==\n-----END PUBLIC KEY-----`;\n\nlet publicKeyCache = null;\n\nfunction decodeBase64Url(value) {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);\n return atob(padded);\n}\n\nfunction decodeBase64UrlToBytes(value) {\n const bin = decodeBase64Url(value);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i += 1) {\n bytes[i] = bin.charCodeAt(i);\n }\n return bytes;\n}\n\nfunction pemToArrayBuffer(pem) {\n const b64 = pem\n .replace(/-----BEGIN PUBLIC KEY-----/g, '')\n .replace(/-----END PUBLIC KEY-----/g, '')\n .replace(/\\s+/g, '');\n const raw = atob(b64);\n const bytes = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i += 1) {\n bytes[i] = raw.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nasync function importPublicKey(publicKeyPem = LICENSE_PUBLIC_KEY_PEM) {\n if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM && publicKeyCache) {\n return publicKeyCache;\n }\n\n const keyData = pemToArrayBuffer(publicKeyPem);\n const key = await crypto.subtle.importKey(\n 'spki',\n keyData,\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['verify']\n );\n\n if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM) {\n publicKeyCache = key;\n }\n\n return key;\n}\n\nexport async function validateLicenseToken(token, options = {}) {\n const {\n now = Date.now(),\n publicKeyPem = LICENSE_PUBLIC_KEY_PEM,\n allowExpired = false\n } = options;\n\n if (!token || typeof token !== 'string') {\n return { valid: false, reason: 'Token vacío o inválido' };\n }\n\n if (!token.startsWith(TOKEN_PREFIX)) {\n return { valid: false, reason: 'Prefijo de token inválido' };\n }\n\n const raw = token.slice(TOKEN_PREFIX.length);\n const parts = raw.split('.');\n if (parts.length !== 2) {\n return { valid: false, reason: 'Formato de token inválido' };\n }\n\n const [payloadPart, signaturePart] = parts;\n\n let payload;\n try {\n payload = JSON.parse(decodeBase64Url(payloadPart));\n } catch (_err) {\n return { valid: false, reason: 'Payload de licencia inválido' };\n }\n\n try {\n const key = await importPublicKey(publicKeyPem);\n const isValid = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n key,\n decodeBase64UrlToBytes(signaturePart),\n new TextEncoder().encode(payloadPart)\n );\n\n if (!isValid) {\n return { valid: false, reason: 'Firma de licencia inválida' };\n }\n } catch (_err) {\n return { valid: false, reason: 'Error verificando firma de licencia' };\n }\n\n if (payload.productCode !== PRODUCT_CODE) {\n return { valid: false, reason: 'Licencia de otro producto' };\n }\n\n if (!allowExpired && (typeof payload.exp !== 'number' || payload.exp < now)) {\n return { valid: false, reason: 'Licencia vencida', payload };\n }\n\n return { valid: true, reason: null, payload };\n}\n\nexport { TOKEN_PREFIX, PRODUCT_CODE, LICENSE_PUBLIC_KEY_PEM };\n","import { FILTERS, FILTER_ORDER, getFilter, filterConfigManager, buildWebglConfigForProduct } from './core/index.js';\nimport { validateLicenseToken, PRODUCT_CODE } from './license/token.js';\n\nexport class MdFaceEngine {\n constructor() {\n this.license = null;\n this.activated = false;\n }\n\n async activate(token) {\n const result = await validateLicenseToken(token);\n\n if (!result.valid) {\n this.license = null;\n this.activated = false;\n throw new Error(`Licencia inválida: ${result.reason}`);\n }\n\n this.license = result.payload;\n this.activated = true;\n return result.payload;\n }\n\n isActivated() {\n return this.activated;\n }\n\n assertActivated() {\n if (!this.activated) {\n throw new Error('md-face-engine no está activado. Configura VITE_MD_FACE_ENGINE_TOKEN.');\n }\n }\n\n getLicense() {\n this.assertActivated();\n return this.license;\n }\n\n getProductCode() {\n return PRODUCT_CODE;\n }\n\n getFilterRegistry() {\n this.assertActivated();\n return FILTERS;\n }\n\n getFilterOrder() {\n this.assertActivated();\n return FILTER_ORDER;\n }\n\n getFilter(key) {\n this.assertActivated();\n return getFilter(key);\n }\n\n getFilterConfigManager() {\n this.assertActivated();\n return filterConfigManager;\n }\n\n buildWebglConfigForProduct(product) {\n this.assertActivated();\n return buildWebglConfigForProduct(product);\n }\n}\n\nexport { MdFaceEngine as MartidermEngine };\nexport default MdFaceEngine;\n","import MdFaceEngine from './MartidermEngine.js';\nimport {\n FILTERS as CORE_FILTERS,\n FILTER_ORDER as CORE_FILTER_ORDER,\n getFilter as coreGetFilter,\n filterConfigManager as coreFilterConfigManager,\n buildWebglConfigForProduct as coreBuildWebglConfigForProduct\n} from './core/index.js';\n\nexport async function createMdFaceEngineClient({ token, products = [] } = {}) {\n if (!token) {\n throw new Error('Falta token de licencia para activar md-face-engine.');\n }\n\n const engine = new MdFaceEngine();\n await engine.activate(token);\n engine.assertActivated();\n\n const filterConfigManager = engine.getFilterConfigManager();\n if (Array.isArray(products)) {\n filterConfigManager.setProducts(products);\n }\n\n return {\n engine,\n FILTERS: engine.getFilterRegistry(),\n FILTER_ORDER: engine.getFilterOrder(),\n getFilter: (key) => engine.getFilter(key),\n filterConfigManager,\n buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)\n };\n}\n\nexport async function createMdFaceEngineRuntime({ token, products = [] } = {}) {\n let client = null;\n let licenseError = null;\n let isLicenseActive = false;\n\n if (token) {\n try {\n client = await createMdFaceEngineClient({ token, products });\n isLicenseActive = true;\n } catch (error) {\n licenseError = error;\n isLicenseActive = false;\n }\n }\n\n if (!client && Array.isArray(products) && typeof coreFilterConfigManager?.setProducts === 'function') {\n coreFilterConfigManager.setProducts(products);\n }\n\n return {\n engine: client?.engine || null,\n FILTERS: client?.FILTERS || CORE_FILTERS,\n FILTER_ORDER: client?.FILTER_ORDER || CORE_FILTER_ORDER,\n getFilter: client?.getFilter || coreGetFilter,\n filterConfigManager: client?.filterConfigManager || coreFilterConfigManager,\n buildWebglConfigForProduct: client?.buildWebglConfigForProduct || coreBuildWebglConfigForProduct,\n license: {\n active: isLicenseActive,\n error: licenseError,\n mode: isLicenseActive ? 'licensed' : 'unlicensed'\n }\n };\n}\n"],"names":["filterConfigManager","CORE_FILTERS","CORE_FILTER_ORDER","coreGetFilter","coreBuildWebglConfigForProduct"],"mappings":"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"}
|
|
@@ -464,10 +464,10 @@ class FilterConfigManager {
|
|
|
464
464
|
return this.exportConfigurations();
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
|
-
const
|
|
467
|
+
const coreFilterConfigManager = new FilterConfigManager();
|
|
468
468
|
function buildWebglConfigForProduct(product) {
|
|
469
469
|
var _a, _b, _c, _d;
|
|
470
|
-
const pc =
|
|
470
|
+
const pc = coreFilterConfigManager.getProductConfig(product.id) || {};
|
|
471
471
|
const lockedType = product.filterType || pc.webglConfig && pc.webglConfig.filterType || "wrinkles";
|
|
472
472
|
const defaults = FILTERS[lockedType] && FILTERS[lockedType].defaults || { intensity: 0.5, sigma: 4, brightness: 0 };
|
|
473
473
|
const deep = FILTERS[lockedType] && FILTERS[lockedType].deep || {};
|
|
@@ -484,25 +484,58 @@ function buildWebglConfigForProduct(product) {
|
|
|
484
484
|
const adminCfg = pc.webglConfig || {};
|
|
485
485
|
return { ...base, ...adminCfg, filterType: lockedType };
|
|
486
486
|
}
|
|
487
|
-
const TOKEN_PREFIX = "
|
|
487
|
+
const TOKEN_PREFIX = "mdfe2_";
|
|
488
488
|
const PRODUCT_CODE = "md-face-engine";
|
|
489
|
-
const
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
hash &= 4294967295;
|
|
495
|
-
}
|
|
496
|
-
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
497
|
-
}
|
|
489
|
+
const LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
490
|
+
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW9CHbTVvVXcm09wZIj6GKGaq8ae1
|
|
491
|
+
XGQAum9LBLgoT3+4q3xPc7W9KSw1z4xgfOByTi8OzdjbjEaF3VrHjzl05w==
|
|
492
|
+
-----END PUBLIC KEY-----`;
|
|
493
|
+
let publicKeyCache = null;
|
|
498
494
|
function decodeBase64Url(value) {
|
|
499
495
|
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
500
|
-
const
|
|
501
|
-
const padded = padding ? normalized + "=".repeat(4 - padding) : normalized;
|
|
496
|
+
const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
|
|
502
497
|
return atob(padded);
|
|
503
498
|
}
|
|
504
|
-
function
|
|
505
|
-
const
|
|
499
|
+
function decodeBase64UrlToBytes(value) {
|
|
500
|
+
const bin = decodeBase64Url(value);
|
|
501
|
+
const bytes = new Uint8Array(bin.length);
|
|
502
|
+
for (let i = 0; i < bin.length; i += 1) {
|
|
503
|
+
bytes[i] = bin.charCodeAt(i);
|
|
504
|
+
}
|
|
505
|
+
return bytes;
|
|
506
|
+
}
|
|
507
|
+
function pemToArrayBuffer(pem) {
|
|
508
|
+
const b64 = pem.replace(/-----BEGIN PUBLIC KEY-----/g, "").replace(/-----END PUBLIC KEY-----/g, "").replace(/\s+/g, "");
|
|
509
|
+
const raw = atob(b64);
|
|
510
|
+
const bytes = new Uint8Array(raw.length);
|
|
511
|
+
for (let i = 0; i < raw.length; i += 1) {
|
|
512
|
+
bytes[i] = raw.charCodeAt(i);
|
|
513
|
+
}
|
|
514
|
+
return bytes.buffer;
|
|
515
|
+
}
|
|
516
|
+
async function importPublicKey(publicKeyPem = LICENSE_PUBLIC_KEY_PEM) {
|
|
517
|
+
if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM && publicKeyCache) {
|
|
518
|
+
return publicKeyCache;
|
|
519
|
+
}
|
|
520
|
+
const keyData = pemToArrayBuffer(publicKeyPem);
|
|
521
|
+
const key = await crypto.subtle.importKey(
|
|
522
|
+
"spki",
|
|
523
|
+
keyData,
|
|
524
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
525
|
+
false,
|
|
526
|
+
["verify"]
|
|
527
|
+
);
|
|
528
|
+
if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM) {
|
|
529
|
+
publicKeyCache = key;
|
|
530
|
+
}
|
|
531
|
+
return key;
|
|
532
|
+
}
|
|
533
|
+
async function validateLicenseToken(token, options = {}) {
|
|
534
|
+
const {
|
|
535
|
+
now = Date.now(),
|
|
536
|
+
publicKeyPem = LICENSE_PUBLIC_KEY_PEM,
|
|
537
|
+
allowExpired = false
|
|
538
|
+
} = options;
|
|
506
539
|
if (!token || typeof token !== "string") {
|
|
507
540
|
return { valid: false, reason: "Token vacío o inválido" };
|
|
508
541
|
}
|
|
@@ -514,22 +547,32 @@ function validateLicenseToken(token, options = {}) {
|
|
|
514
547
|
if (parts.length !== 2) {
|
|
515
548
|
return { valid: false, reason: "Formato de token inválido" };
|
|
516
549
|
}
|
|
517
|
-
const [payloadPart,
|
|
518
|
-
const expected = hashToken(`${payloadPart}.${LICENSE_SECRET}`);
|
|
519
|
-
if (signature !== expected) {
|
|
520
|
-
return { valid: false, reason: "Firma de licencia inválida" };
|
|
521
|
-
}
|
|
550
|
+
const [payloadPart, signaturePart] = parts;
|
|
522
551
|
let payload;
|
|
523
552
|
try {
|
|
524
553
|
payload = JSON.parse(decodeBase64Url(payloadPart));
|
|
525
554
|
} catch (_err) {
|
|
526
555
|
return { valid: false, reason: "Payload de licencia inválido" };
|
|
527
556
|
}
|
|
557
|
+
try {
|
|
558
|
+
const key = await importPublicKey(publicKeyPem);
|
|
559
|
+
const isValid = await crypto.subtle.verify(
|
|
560
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
561
|
+
key,
|
|
562
|
+
decodeBase64UrlToBytes(signaturePart),
|
|
563
|
+
new TextEncoder().encode(payloadPart)
|
|
564
|
+
);
|
|
565
|
+
if (!isValid) {
|
|
566
|
+
return { valid: false, reason: "Firma de licencia inválida" };
|
|
567
|
+
}
|
|
568
|
+
} catch (_err) {
|
|
569
|
+
return { valid: false, reason: "Error verificando firma de licencia" };
|
|
570
|
+
}
|
|
528
571
|
if (payload.productCode !== PRODUCT_CODE) {
|
|
529
572
|
return { valid: false, reason: "Licencia de otro producto" };
|
|
530
573
|
}
|
|
531
|
-
if (typeof payload.exp !== "number" || payload.exp < now) {
|
|
532
|
-
return { valid: false, reason: "Licencia vencida" };
|
|
574
|
+
if (!allowExpired && (typeof payload.exp !== "number" || payload.exp < now)) {
|
|
575
|
+
return { valid: false, reason: "Licencia vencida", payload };
|
|
533
576
|
}
|
|
534
577
|
return { valid: true, reason: null, payload };
|
|
535
578
|
}
|
|
@@ -538,8 +581,8 @@ class MdFaceEngine {
|
|
|
538
581
|
this.license = null;
|
|
539
582
|
this.activated = false;
|
|
540
583
|
}
|
|
541
|
-
activate(token) {
|
|
542
|
-
const result = validateLicenseToken(token);
|
|
584
|
+
async activate(token) {
|
|
585
|
+
const result = await validateLicenseToken(token);
|
|
543
586
|
if (!result.valid) {
|
|
544
587
|
this.license = null;
|
|
545
588
|
this.activated = false;
|
|
@@ -578,33 +621,63 @@ class MdFaceEngine {
|
|
|
578
621
|
}
|
|
579
622
|
getFilterConfigManager() {
|
|
580
623
|
this.assertActivated();
|
|
581
|
-
return
|
|
624
|
+
return coreFilterConfigManager;
|
|
582
625
|
}
|
|
583
626
|
buildWebglConfigForProduct(product) {
|
|
584
627
|
this.assertActivated();
|
|
585
628
|
return buildWebglConfigForProduct(product);
|
|
586
629
|
}
|
|
587
630
|
}
|
|
588
|
-
function createMdFaceEngineClient({ token, products = [] } = {}) {
|
|
631
|
+
async function createMdFaceEngineClient({ token, products = [] } = {}) {
|
|
589
632
|
if (!token) {
|
|
590
633
|
throw new Error("Falta token de licencia para activar md-face-engine.");
|
|
591
634
|
}
|
|
592
635
|
const engine = new MdFaceEngine();
|
|
593
|
-
engine.activate(token);
|
|
636
|
+
await engine.activate(token);
|
|
594
637
|
engine.assertActivated();
|
|
595
|
-
const
|
|
638
|
+
const filterConfigManager = engine.getFilterConfigManager();
|
|
596
639
|
if (Array.isArray(products)) {
|
|
597
|
-
|
|
640
|
+
filterConfigManager.setProducts(products);
|
|
598
641
|
}
|
|
599
642
|
return {
|
|
600
643
|
engine,
|
|
601
644
|
FILTERS: engine.getFilterRegistry(),
|
|
602
645
|
FILTER_ORDER: engine.getFilterOrder(),
|
|
603
646
|
getFilter: (key) => engine.getFilter(key),
|
|
604
|
-
filterConfigManager
|
|
647
|
+
filterConfigManager,
|
|
605
648
|
buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)
|
|
606
649
|
};
|
|
607
650
|
}
|
|
651
|
+
async function createMdFaceEngineRuntime({ token, products = [] } = {}) {
|
|
652
|
+
let client = null;
|
|
653
|
+
let licenseError = null;
|
|
654
|
+
let isLicenseActive = false;
|
|
655
|
+
if (token) {
|
|
656
|
+
try {
|
|
657
|
+
client = await createMdFaceEngineClient({ token, products });
|
|
658
|
+
isLicenseActive = true;
|
|
659
|
+
} catch (error) {
|
|
660
|
+
licenseError = error;
|
|
661
|
+
isLicenseActive = false;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (!client && Array.isArray(products) && typeof (coreFilterConfigManager == null ? void 0 : coreFilterConfigManager.setProducts) === "function") {
|
|
665
|
+
coreFilterConfigManager.setProducts(products);
|
|
666
|
+
}
|
|
667
|
+
return {
|
|
668
|
+
engine: (client == null ? void 0 : client.engine) || null,
|
|
669
|
+
FILTERS: (client == null ? void 0 : client.FILTERS) || FILTERS,
|
|
670
|
+
FILTER_ORDER: (client == null ? void 0 : client.FILTER_ORDER) || FILTER_ORDER,
|
|
671
|
+
getFilter: (client == null ? void 0 : client.getFilter) || getFilter,
|
|
672
|
+
filterConfigManager: (client == null ? void 0 : client.filterConfigManager) || coreFilterConfigManager,
|
|
673
|
+
buildWebglConfigForProduct: (client == null ? void 0 : client.buildWebglConfigForProduct) || buildWebglConfigForProduct,
|
|
674
|
+
license: {
|
|
675
|
+
active: isLicenseActive,
|
|
676
|
+
error: licenseError,
|
|
677
|
+
mode: isLicenseActive ? "licensed" : "unlicensed"
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
}
|
|
608
681
|
exports.CATEGORY_PRESETS = CATEGORY_PRESETS;
|
|
609
682
|
exports.DEFAULT_FILTER_CONFIG = DEFAULT_FILTER_CONFIG;
|
|
610
683
|
exports.FILTERS = FILTERS;
|
|
@@ -612,8 +685,9 @@ exports.FILTER_ORDER = FILTER_ORDER;
|
|
|
612
685
|
exports.FilterConfigManager = FilterConfigManager;
|
|
613
686
|
exports.MdFaceEngine = MdFaceEngine;
|
|
614
687
|
exports.buildWebglConfigForProduct = buildWebglConfigForProduct;
|
|
688
|
+
exports.coreFilterConfigManager = coreFilterConfigManager;
|
|
615
689
|
exports.createMdFaceEngineClient = createMdFaceEngineClient;
|
|
616
|
-
exports.
|
|
690
|
+
exports.createMdFaceEngineRuntime = createMdFaceEngineRuntime;
|
|
617
691
|
exports.getFilter = getFilter;
|
|
618
692
|
exports.validateLicenseToken = validateLicenseToken;
|
|
619
|
-
//# sourceMappingURL=client-
|
|
693
|
+
//# sourceMappingURL=client-Com8umy4.cjs.map
|