libreria-astro-lefebvre 0.0.58 → 0.0.59

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libreria-astro-lefebvre",
3
- "version": "0.0.58",
3
+ "version": "0.0.59",
4
4
  "description": "Librería de componentes Astro, React y Vue para Lefebvre",
5
5
  "author": "Equipo web desarrollo Lefebvre",
6
6
  "type": "module",
@@ -1,87 +0,0 @@
1
- ---
2
- /**
3
- * LimboProvider.astro
4
- *
5
- * Componente Astro que provee la integración con Limbo.
6
- * Incluye los assets necesarios (CSS/JS) y la inicialización automática.
7
- *
8
- * Uso:
9
- * ```astro
10
- * ---
11
- * import LimboProvider from 'libreria-astro-lefebvre/limbo/LimboProvider.astro';
12
- * ---
13
- * <LimboProvider
14
- * publicKey="pk_xxx"
15
- * apiKey="sk_xxx"
16
- * prod={false}
17
- * sizeModal="fullscreen"
18
- * />
19
- * ```
20
- */
21
-
22
- import { generateLimboInitScript, getLimboAssetUrls } from './init';
23
-
24
- interface Props {
25
- /** Public Key del portal de Limbo */
26
- publicKey: string;
27
- /** Usar API de producción */
28
- prod?: boolean;
29
- /** Selector CSS para detectar inputs (default: '.js-limbo') */
30
- selector?: string;
31
- /** Tipo de retorno por defecto */
32
- defaultReturnType?: 'url' | 'assetId' | 'object' | 'json' | 'base64';
33
- /** Modo UI por defecto */
34
- defaultModeUI?: 'full' | 'gallery-only' | 'upload-only' | 'crop-only';
35
- /** Tamaño del modal (default: 'xlarge') */
36
- sizeModal?: 'small' | 'medium' | 'large' | 'xlarge' | 'fullscreen';
37
- /** Texto del botón por defecto */
38
- defaultButtonText?: string;
39
- /** Permitir crops adicionales además de los obligatorios */
40
- allowAdditionalCrops?: boolean;
41
- /** Máximo número de crops permitidos */
42
- maxCrops?: number;
43
- /** Versión de limbo-component a usar (default: 'latest') */
44
- version?: string;
45
- /** Usar assets locales en vez de CDN (para desarrollo con npm link) */
46
- useLocalAssets?: boolean;
47
- }
48
-
49
- const {
50
- publicKey,
51
- prod = false,
52
- selector = '.js-limbo',
53
- defaultReturnType = 'json',
54
- defaultModeUI = 'full',
55
- sizeModal = 'xlarge',
56
- defaultButtonText = 'Seleccionar imagen',
57
- allowAdditionalCrops = true,
58
- maxCrops = 10,
59
- version = 'latest',
60
- useLocalAssets = !prod
61
- } = Astro.props;
62
-
63
- // Obtener URLs de assets
64
- const assets = getLimboAssetUrls({ prod: !useLocalAssets, version });
65
-
66
- // Generar script de inicialización
67
- const initScript = generateLimboInitScript({
68
- publicKey,
69
- prod,
70
- selector,
71
- defaultReturnType,
72
- defaultModeUI,
73
- sizeModal,
74
- defaultButtonText,
75
- allowAdditionalCrops,
76
- maxCrops
77
- });
78
- ---
79
-
80
- <!-- Limbo CSS -->
81
- <link rel="stylesheet" href={assets.css} />
82
-
83
- <!-- Limbo JS -->
84
- <script is:inline src={assets.js}></script>
85
-
86
- <!-- Limbo Initialization -->
87
- <script is:inline set:html={initScript}></script>
@@ -1,24 +0,0 @@
1
- /**
2
- * Limbo Integration Module
3
- *
4
- * Exportaciones para integrar limbo-component con la librería de page-builder.
5
- */
6
-
7
- // Exportar funciones de inicialización
8
- export {
9
- generateLimboInitScript,
10
- getLimboAssetUrls,
11
- type LimboConfig,
12
- type LimboInitOptions
13
- } from './init';
14
-
15
- // Exportar handler para API endpoint de token
16
- export {
17
- createLimboTokenHandler,
18
- type LimboTokenConfig,
19
- type LimboTokenResponse,
20
- LIMBO_ENV_VARS
21
- } from './tokenHandler';
22
-
23
- // El componente Astro se importa directamente:
24
- // import LimboProvider from 'libreria-astro-lefebvre/limbo/LimboProvider.astro';
package/src/limbo/init.ts DELETED
@@ -1,288 +0,0 @@
1
- /**
2
- * Limbo Integration Module for libreria-astro-lefebvre
3
- *
4
- * v2.0 - Actualizado para limbo-component v2.0
5
- *
6
- * Este módulo gestiona la inicialización y configuración de limbo-component
7
- * para ser usado en cualquier portal que consuma esta librería.
8
- *
9
- * Soporta configuración via data attributes en inputs HTML:
10
- * - data-mandatorycrops: JSON array de crops obligatorios
11
- * - data-modeui: full | gallery-only | upload-only | crop-only
12
- * - data-returntype: url | assetId | object | json | base64
13
- * - data-allowadditionalcrops: true | false
14
- * - data-maxcrops: number
15
- * - data-buttontext: texto personalizado del botón
16
- */
17
-
18
- export interface MandatoryCrop {
19
- label: string;
20
- width?: number;
21
- height?: number;
22
- required?: boolean;
23
- preset_aspect?: string;
24
- }
25
-
26
- export interface LimboConfig {
27
- publicKey: string;
28
- prod?: boolean;
29
- selector?: string;
30
- defaultReturnType?: "url" | "assetId" | "object" | "json" | "base64";
31
- defaultModeUI?: "full" | "gallery-only" | "upload-only" | "crop-only";
32
- sizeModal?: "small" | "medium" | "large" | "xlarge" | "fullscreen";
33
- defaultButtonText?: string;
34
- allowAdditionalCrops?: boolean;
35
- maxCrops?: number;
36
- onSelect?: (data: any) => void;
37
- onError?: (error: Error) => void;
38
- }
39
-
40
- export interface LimboInitOptions extends LimboConfig {
41
- autoInit?: boolean;
42
- }
43
-
44
- /**
45
- * Genera el script de inicialización de Limbo como string
46
- * para ser inyectado en el HTML
47
- */
48
- export function generateLimboInitScript(config: LimboConfig): string {
49
- const {
50
- publicKey,
51
- prod = false,
52
- selector = ".js-limbo",
53
- defaultReturnType = "json",
54
- defaultModeUI = "full",
55
- sizeModal = "xlarge",
56
- defaultButtonText = "Seleccionar imagen",
57
- allowAdditionalCrops = true,
58
- maxCrops = 10,
59
- } = config;
60
-
61
- // URL del proxy para evitar CORS (usa endpoint local del portal)
62
- // El proxy está en /api/limbo-token del portal que consume la librería
63
- const tokenProxyUrl = "/api/limbo-token";
64
-
65
- return `
66
- (function() {
67
- // Estado del token
68
- var cachedToken = null;
69
- var tokenExpiry = null;
70
-
71
- // Función para obtener token JWT (usa proxy local para evitar CORS)
72
- async function getToken() {
73
- // Si tenemos un token válido en caché, usarlo
74
- if (cachedToken && tokenExpiry && Date.now() < tokenExpiry) {
75
- return cachedToken;
76
- }
77
-
78
- try {
79
- // Usamos el proxy local para evitar problemas de CORS
80
- // Solo enviamos public_key - NO se requiere api_key
81
- var response = await fetch('${tokenProxyUrl}', {
82
- method: 'POST',
83
- headers: {
84
- 'Content-Type': 'application/json',
85
- },
86
- body: JSON.stringify({
87
- public_key: '${publicKey}'
88
- })
89
- });
90
-
91
- if (!response.ok) {
92
- var errorData = await response.json().catch(function() { return {}; });
93
- throw new Error('Error obteniendo token: ' + response.status + ' - ' + (errorData.error || ''));
94
- }
95
-
96
- var data = await response.json();
97
- cachedToken = data.token;
98
- // Guardar expiración con 30 segundos de margen
99
- tokenExpiry = Date.now() + ((data.expires_in || 3600) * 1000) - 30000;
100
- console.log('[Limbo] Token JWT obtenido correctamente');
101
- return cachedToken;
102
- } catch (error) {
103
- console.error('[Limbo] Error en tokenProvider:', error);
104
- throw error;
105
- }
106
- }
107
-
108
- // Estado de inicialización
109
- var initRetrys = 0;
110
- var maxRetrys = 20;
111
-
112
- // Función global para re-escanear inputs (útil después de hydration de Vue/React)
113
- window.LimboRescan = function(selector) {
114
- var targetSelector = selector || '${selector}';
115
- var inputs = document.querySelectorAll(targetSelector);
116
- var processed = 0;
117
- inputs.forEach(function(input) {
118
- if (input.tagName === 'INPUT' && !input.dataset.limboProcessed) {
119
- try {
120
- Limbo.autoInputs._processInput(input);
121
- input.dataset.limboProcessed = 'true';
122
- processed++;
123
- } catch (e) {
124
- console.error('[Limbo] Error procesando input:', e);
125
- }
126
- }
127
- });
128
- return processed;
129
- };
130
-
131
- // Esperamos a que Limbo esté disponible
132
- function initLimbo() {
133
- if (typeof Limbo === 'undefined') {
134
- initRetrys++;
135
- if (initRetrys <= maxRetrys) {
136
- console.warn('[Limbo] Limbo no está cargado. Reintentando... (' + initRetrys + '/' + maxRetrys + ')');
137
- setTimeout(initLimbo, 100);
138
- } else {
139
- console.error('[Limbo] No se pudo cargar Limbo después de ' + maxRetrys + ' intentos.');
140
- }
141
- return;
142
- }
143
-
144
- console.log('[Limbo] Inicializando integración con Page Builder...');
145
-
146
- // Configurar Limbo globalmente con tokenProvider como función
147
- // IMPORTANTE: tokenProvider va en el nivel superior, no dentro de auth
148
- Limbo.configure({
149
- prod: ${prod},
150
- publicKey: '${publicKey}',
151
- authMode: 'jwt',
152
- tokenProvider: getToken,
153
- modal: {
154
- size: '${sizeModal}'
155
- }
156
- });
157
-
158
- // Configurar auto-inputs para detectar elementos con el selector
159
- Limbo.configureAutoInputs({
160
- selector: '${selector}',
161
- buttonText: '${defaultButtonText}',
162
- returnType: '${defaultReturnType}',
163
- modeUI: '${defaultModeUI}',
164
- allowAdditionalCrops: ${allowAdditionalCrops},
165
- maxCrops: ${maxCrops},
166
- // 🔧 Los recortes se guardan en Limbo para garantizar persistencia
167
- // Los recortes del page-builder se pueden identificar por su nombre (contienen dimensiones)
168
- localCropsOnly: false,
169
-
170
- // Parsear configuración del input desde datasets
171
- // Los valores del dataset tienen prioridad sobre los defaults
172
- parseInputConfig: function(input) {
173
- var config = {};
174
-
175
- // Parsear mandatoryCrops si existe
176
- if (input.dataset.mandatorycrops) {
177
- try {
178
- config.mandatoryCrops = JSON.parse(input.dataset.mandatorycrops);
179
- } catch (e) {
180
- console.warn('[Limbo] Error parseando mandatoryCrops:', e);
181
- }
182
- }
183
-
184
- // Parsear returnType específico del input
185
- if (input.dataset.returntype) {
186
- config.returnType = input.dataset.returntype;
187
- }
188
-
189
- // Parsear modo UI
190
- if (input.dataset.modeui) {
191
- config.modeUI = input.dataset.modeui;
192
- }
193
-
194
- // Parsear allowAdditionalCrops
195
- if (input.dataset.allowadditionalcrops !== undefined) {
196
- config.allowAdditionalCrops = input.dataset.allowadditionalcrops === 'true';
197
- }
198
-
199
- // Parsear maxCrops
200
- if (input.dataset.maxcrops) {
201
- config.maxCrops = parseInt(input.dataset.maxcrops, 10);
202
- }
203
-
204
- // Parsear buttonText personalizado
205
- if (input.dataset.buttontext) {
206
- config.buttonText = input.dataset.buttontext;
207
- }
208
-
209
- return config;
210
- }
211
- });
212
-
213
- console.log('[Limbo] Integración configurada. Buscando inputs con selector: ${selector}');
214
-
215
- // Debug: Verificar que el observer esté activo
216
- console.log('[Limbo] AutoInputs stats:', Limbo.autoInputs?.getStats?.() || 'N/A');
217
-
218
- // Debug: Escanear manualmente después de un delay para Vue/React hydration
219
- setTimeout(function() {
220
- var inputs = document.querySelectorAll('${selector}');
221
- inputs.forEach(function(input, idx) {
222
- // Forzar procesamiento si es un input válido
223
- if (input.tagName === 'INPUT' && !input.dataset.limboProcessed) {
224
- try {
225
- Limbo.autoInputs._processInput(input);
226
- input.dataset.limboProcessed = 'true';
227
- } catch (e) {
228
- console.error('[Limbo] Error procesando input:', e);
229
- }
230
- }
231
- });
232
- }, 1000); // Esperar 1 segundo para Vue hydration
233
-
234
- // Segunda pasada después de 2.5 segundos para componentes Vue más lentos
235
- setTimeout(function() {
236
- var inputs = document.querySelectorAll('${selector}');
237
- var pendingInputs = Array.from(inputs).filter(function(input) {
238
- return input.tagName === 'INPUT' && !input.dataset.limboProcessed;
239
- });
240
- if (pendingInputs.length > 0) {
241
- pendingInputs.forEach(function(input) {
242
- try {
243
- Limbo.autoInputs._processInput(input);
244
- input.dataset.limboProcessed = 'true';
245
- } catch (e) {
246
- console.error('[Limbo] Error procesando input:', e);
247
- }
248
- });
249
- }
250
- }, 2500);
251
- }
252
-
253
- // Iniciar cuando el DOM esté listo
254
- if (document.readyState === 'loading') {
255
- document.addEventListener('DOMContentLoaded', initLimbo);
256
- } else {
257
- initLimbo();
258
- }
259
- })();
260
- `;
261
- }
262
-
263
- /**
264
- * Genera las URLs de los assets de Limbo (CSS y JS)
265
- */
266
- export function getLimboAssetUrls(
267
- options: { prod?: boolean; version?: string } = {}
268
- ) {
269
- const { prod = false, version = "latest" } = options;
270
- // En producción, usar CDN de npm o URL de producción
271
- if (prod) {
272
- return {
273
- css: `https://unpkg.com/limbo-component@${version}/dist/limbo.css`,
274
- js: `https://unpkg.com/limbo-component@${version}/dist/limbo.min.js`,
275
- };
276
- }
277
-
278
- // En desarrollo, usar el build local desde public/limbo
279
- return {
280
- css: "/limbo/limbo.css",
281
- js: "/limbo/limbo.min.js",
282
- };
283
- }
284
-
285
- export default {
286
- generateLimboInitScript,
287
- getLimboAssetUrls,
288
- };
@@ -1,207 +0,0 @@
1
- /**
2
- * Limbo Token Handler
3
- *
4
- * Handler genérico para obtener tokens JWT de Limbo.
5
- * Framework-agnostic: funciona en Astro, Next.js, Express, etc.
6
- *
7
- * La URL de la API de Limbo se determina automáticamente según `isProduction`:
8
- * - Producción: https://limbo.lefebvre.es
9
- * - Desarrollo: https://led-dev-limbo-dev.eu.els.local
10
- * - Local: http://localhost:8000
11
- *
12
- * @example Astro
13
- * ```ts
14
- * // src/pages/api/limbo-token.ts
15
- * import { createLimboTokenHandler } from 'libreria-astro-lefebvre/limbo';
16
- *
17
- * export const POST = createLimboTokenHandler({
18
- * publicKey: import.meta.env.PUBLIC_LIMBO_PUBLIC_KEY,
19
- * isProduction: import.meta.env.IS_PROD === 'TRUE'
20
- * });
21
- * ```
22
- *
23
- * @example Next.js App Router
24
- * ```ts
25
- * // app/api/limbo-token/route.ts
26
- * import { createLimboTokenHandler } from 'libreria-astro-lefebvre/limbo';
27
- *
28
- * export const POST = createLimboTokenHandler({
29
- * publicKey: process.env.PUBLIC_LIMBO_PUBLIC_KEY!,
30
- * isProduction: process.env.NODE_ENV === 'production'
31
- * });
32
- * ```
33
- */
34
-
35
- /** URLs por defecto de la API de Limbo */
36
- const LIMBO_API_URLS = {
37
- production: 'https://limbo.lefebvre.es',
38
- development: 'https://led-dev-limbo-dev.eu.els.local',
39
- } as const;
40
-
41
- export interface LimboTokenConfig {
42
- /** Public Key del portal de Limbo (pk_xxx) */
43
- publicKey: string;
44
- /** ¿Usar API de producción? (default: false = desarrollo) */
45
- isProduction?: boolean;
46
- /** URL base de la API de Limbo (opcional, se determina por isProduction si no se especifica) */
47
- limboApiUrl?: string;
48
- /** Permitir override de publicKey desde el body de la request (default: true) */
49
- allowPublicKeyOverride?: boolean;
50
- }
51
-
52
- export interface LimboTokenResponse {
53
- success: boolean;
54
- token?: string;
55
- expires_in?: number;
56
- error?: string;
57
- details?: string;
58
- hint?: string;
59
- }
60
-
61
- /**
62
- * Crea un handler para obtener tokens JWT de Limbo.
63
- *
64
- * Este handler actúa como proxy para evitar problemas de CORS,
65
- * haciendo la petición a Limbo desde el servidor.
66
- *
67
- * @param config - Configuración con publicKey e isProduction
68
- * @returns Handler compatible con Astro, Next.js, y otros frameworks
69
- */
70
- export function createLimboTokenHandler(config: LimboTokenConfig) {
71
- const {
72
- publicKey: defaultPublicKey,
73
- isProduction = false,
74
- limboApiUrl: customApiUrl,
75
- allowPublicKeyOverride = true,
76
- } = config;
77
-
78
- // Determinar URL de la API (custom > isProduction > desarrollo)
79
- const limboApiUrl = customApiUrl || (isProduction ? LIMBO_API_URLS.production : LIMBO_API_URLS.development);
80
-
81
- // Validar configuración al crear el handler
82
- if (!defaultPublicKey) {
83
- console.error('[Limbo Token Handler] PUBLIC_LIMBO_PUBLIC_KEY no está configurada');
84
- }
85
-
86
- console.log(`[Limbo Token Handler] Configurado para ${isProduction ? 'PRODUCCIÓN' : 'DESARROLLO'}: ${limboApiUrl}`);
87
-
88
- /**
89
- * Handler que procesa la petición de token
90
- */
91
- return async function handler({ request }: { request: Request }): Promise<Response> {
92
- try {
93
- // Determinar qué publicKey usar
94
- let publicKey = defaultPublicKey;
95
-
96
- // Permitir override desde el body si está habilitado
97
- if (allowPublicKeyOverride) {
98
- try {
99
- const body = await request.json();
100
- if (body.public_key) {
101
- publicKey = body.public_key;
102
- }
103
- } catch {
104
- // Si no hay body válido, usar la del entorno
105
- }
106
- }
107
-
108
- // Validar que tenemos publicKey
109
- if (!publicKey) {
110
- return new Response(
111
- JSON.stringify({
112
- success: false,
113
- error: 'PUBLIC_LIMBO_PUBLIC_KEY no configurada',
114
- } satisfies LimboTokenResponse),
115
- {
116
- status: 400,
117
- headers: { 'Content-Type': 'application/json' },
118
- }
119
- );
120
- }
121
-
122
- // Construir URL del endpoint de token
123
- const tokenUrl = `${limboApiUrl}/auth/token`;
124
- console.log('[Limbo Proxy] Requesting token from:', tokenUrl);
125
- console.log('[Limbo Proxy] Using public_key:', publicKey.substring(0, 10) + '...');
126
-
127
- // Hacer petición a Limbo
128
- const response = await fetch(tokenUrl, {
129
- method: 'POST',
130
- headers: {
131
- 'Content-Type': 'application/json',
132
- },
133
- body: JSON.stringify({
134
- public_key: publicKey,
135
- }),
136
- });
137
-
138
- // Manejar errores de la API
139
- if (!response.ok) {
140
- const errorText = await response.text();
141
- console.error('[Limbo Proxy] Error response:', response.status, errorText);
142
-
143
- return new Response(
144
- JSON.stringify({
145
- success: false,
146
- error: `API error: ${response.status}`,
147
- details: errorText,
148
- } satisfies LimboTokenResponse),
149
- {
150
- status: response.status,
151
- headers: { 'Content-Type': 'application/json' },
152
- }
153
- );
154
- }
155
-
156
- // Respuesta exitosa
157
- const data = await response.json();
158
- console.log('[Limbo Proxy] Token obtained successfully');
159
-
160
- return new Response(JSON.stringify(data), {
161
- status: 200,
162
- headers: { 'Content-Type': 'application/json' },
163
- });
164
- } catch (error) {
165
- console.error('[Limbo Proxy] Error completo:', error);
166
-
167
- // Mensaje descriptivo para debug
168
- let errorMsg = 'Unknown error';
169
- if (error instanceof Error) {
170
- errorMsg = error.message;
171
- if (error.cause) {
172
- errorMsg += ` (cause: ${JSON.stringify(error.cause)})`;
173
- }
174
- }
175
-
176
- return new Response(
177
- JSON.stringify({
178
- success: false,
179
- error: errorMsg,
180
- hint: 'Verifica que la API de Limbo sea accesible desde el servidor',
181
- } satisfies LimboTokenResponse),
182
- {
183
- status: 500,
184
- headers: { 'Content-Type': 'application/json' },
185
- }
186
- );
187
- }
188
- };
189
- }
190
-
191
- /**
192
- * URLs por defecto de la API de Limbo (exportadas para referencia).
193
- */
194
- export { LIMBO_API_URLS };
195
-
196
- /**
197
- * Helper para crear configuración desde variables de entorno comunes.
198
- * Útil para documentación y ejemplos.
199
- */
200
- export const LIMBO_ENV_VARS = {
201
- /** Variable de entorno para la Public Key (con prefijo PUBLIC_ para cliente) */
202
- PUBLIC_KEY: 'PUBLIC_LIMBO_PUBLIC_KEY',
203
- /** Variable de entorno para indicar si es producción */
204
- IS_PROD: 'IS_PROD',
205
- } as const;
206
-
207
- export default createLimboTokenHandler;