webs-sdk 0.17.4 → 0.17.6
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 +347 -294
- package/dist/client.d.ts +2 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +7 -0
- package/dist/client.js.map +1 -0
- package/dist/context/TranslationContext.d.ts +12 -0
- package/dist/context/TranslationContext.d.ts.map +1 -0
- package/dist/context/TranslationContext.js +60 -0
- package/dist/context/TranslationContext.js.map +1 -0
- package/dist/libraries/auth.d.ts.map +1 -1
- package/dist/libraries/auth.js +19 -6
- package/dist/libraries/auth.js.map +1 -1
- package/dist/libraries/networking.d.ts.map +1 -1
- package/dist/libraries/networking.js +12 -1
- package/dist/libraries/networking.js.map +1 -1
- package/dist/libraries/session.d.ts +12 -1
- package/dist/libraries/session.d.ts.map +1 -1
- package/dist/libraries/session.js +64 -1
- package/dist/libraries/session.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# webs-sdk
|
|
2
2
|
|
|
3
|
-
SDK
|
|
3
|
+
SDK interno npm para portales Nexum. Encapsula toda la lógica común: autenticación, sesiones, comunicación con la API, tracking, internacionalización y componentes React reutilizables.
|
|
4
|
+
|
|
5
|
+
**Versión actual:** 0.17.4
|
|
4
6
|
|
|
5
7
|
## Instalación
|
|
6
8
|
|
|
@@ -8,391 +10,442 @@ SDK completo para aplicaciones web que proporciona funcionalidades esenciales pa
|
|
|
8
10
|
npm install webs-sdk
|
|
9
11
|
```
|
|
10
12
|
|
|
11
|
-
## Uso
|
|
13
|
+
## Uso básico
|
|
12
14
|
|
|
13
|
-
```
|
|
15
|
+
```typescript
|
|
14
16
|
import WebsSDK from 'webs-sdk';
|
|
15
17
|
|
|
16
|
-
// Inicializar
|
|
18
|
+
// Inicializar sesión
|
|
17
19
|
await WebsSDK.Session.init();
|
|
18
20
|
|
|
19
|
-
//
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
// Almacenar datos
|
|
23
|
-
await WebsSDK.Storage.storeData('user_preferences', { theme: 'dark' });
|
|
21
|
+
// Petición HTTP
|
|
22
|
+
const data = await WebsSDK.Networking.request('/api/endpoint', { param: 'value' });
|
|
24
23
|
|
|
25
|
-
//
|
|
26
|
-
|
|
24
|
+
// Almacenamiento local
|
|
25
|
+
WebsSDK.Storage.set('key', 'value');
|
|
26
|
+
const value = WebsSDK.Storage.get('key');
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
## Librerías
|
|
30
|
-
|
|
31
|
-
### 🌐 Networking
|
|
32
|
-
Manejo avanzado de peticiones HTTP y comunicación con APIs.
|
|
29
|
+
## Librerías disponibles
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
// Petición básica
|
|
36
|
-
const data = await WebsSDK.Networking.request('/api/endpoint', { param: 'value' });
|
|
31
|
+
### Networking
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
```typescript
|
|
34
|
+
// Petición HTTP (inyecta sessionData automáticamente)
|
|
35
|
+
await WebsSDK.Networking.request(url, data);
|
|
40
36
|
|
|
41
|
-
//
|
|
37
|
+
// Eventos de tracking
|
|
42
38
|
await WebsSDK.Networking.sendEvent('action', 'button_click', { button_id: 'submit' });
|
|
43
39
|
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// Gestión de suscripciones
|
|
48
|
-
const subscription = await WebsSDK.Networking.createSubscription(subscriptionData);
|
|
49
|
-
const isActive = await WebsSDK.Networking.checkSubscription();
|
|
40
|
+
// Suscripciones
|
|
41
|
+
await WebsSDK.Networking.createSubscription(subscriptionData);
|
|
42
|
+
const { success, subscription_active } = await WebsSDK.Networking.checkSubscription();
|
|
50
43
|
```
|
|
51
44
|
|
|
52
|
-
###
|
|
53
|
-
Almacenamiento local avanzado con soporte para datos complejos.
|
|
45
|
+
### Storage
|
|
54
46
|
|
|
55
|
-
```
|
|
56
|
-
// Métodos básicos
|
|
47
|
+
```typescript
|
|
57
48
|
WebsSDK.Storage.set('key', 'value');
|
|
58
49
|
const value = WebsSDK.Storage.get('key');
|
|
59
50
|
|
|
60
|
-
//
|
|
61
|
-
await WebsSDK.Storage.
|
|
62
|
-
const data = await WebsSDK.Storage.getData('complex_data');
|
|
51
|
+
// Compresión de imágenes (0.8 ratio, 1024px max)
|
|
52
|
+
const compressed = await WebsSDK.Storage.compressImage(imageFile, 2); // 2MB max
|
|
63
53
|
|
|
64
|
-
//
|
|
65
|
-
await WebsSDK.Storage.handleDownloadImageToCreations(
|
|
54
|
+
// Creaciones (imágenes generadas por el usuario)
|
|
55
|
+
await WebsSDK.Storage.handleDownloadImageToCreations(base64, 'id', metadata);
|
|
66
56
|
const creations = await WebsSDK.Storage.getCreations();
|
|
67
|
-
|
|
68
|
-
// Compresión de imágenes
|
|
69
|
-
const compressedImage = await WebsSDK.Storage.compressImage(imageUri, 2); // 2MB max
|
|
70
|
-
|
|
71
|
-
// Descarga de archivos
|
|
72
|
-
await WebsSDK.Storage.handleDownloadImage(base64, 'imagen');
|
|
73
|
-
|
|
74
|
-
// Compartir archivos
|
|
75
|
-
await WebsSDK.Storage.handleShareFile(fileUrl);
|
|
57
|
+
await WebsSDK.Storage.deleteCreation('id');
|
|
76
58
|
```
|
|
77
59
|
|
|
78
|
-
###
|
|
79
|
-
Gestión completa de sesiones de usuario y datos del dispositivo.
|
|
60
|
+
### Session
|
|
80
61
|
|
|
81
|
-
```
|
|
82
|
-
// Inicializar sesión
|
|
62
|
+
```typescript
|
|
83
63
|
await WebsSDK.Session.init();
|
|
84
64
|
|
|
85
|
-
// Obtener datos de sesión
|
|
86
65
|
const sessionData = WebsSDK.Session.getSessionData();
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
// Gestión de suscripciones
|
|
91
|
-
await WebsSDK.Session.setIsSubscribed(true);
|
|
66
|
+
const userId = WebsSDK.Session.getUserID();
|
|
67
|
+
const lang = WebsSDK.Session.getDeviceLanguage();
|
|
92
68
|
const isSubscribed = WebsSDK.Session.getIsSubscribed();
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Utils
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const id = WebsSDK.Utils.generateId();
|
|
75
|
+
const isValidEmail = WebsSDK.Utils.isValidEmail('user@example.com');
|
|
76
|
+
const isMobile = WebsSDK.Utils.isMobile();
|
|
77
|
+
const deviceInfo = WebsSDK.Utils.getDeviceInfo();
|
|
78
|
+
const truncated = WebsSDK.Utils.truncateText('Long text...', 10);
|
|
79
|
+
```
|
|
93
80
|
|
|
94
|
-
|
|
95
|
-
const language = WebsSDK.Session.getDeviceLanguage();
|
|
96
|
-
const languageRegion = WebsSDK.Session.getDeviceLanguageAndRegion();
|
|
97
|
-
const isFirstOpen = WebsSDK.Session.getIsFirstOpen();
|
|
81
|
+
### MixPanel
|
|
98
82
|
|
|
99
|
-
|
|
100
|
-
WebsSDK.
|
|
101
|
-
await WebsSDK.
|
|
83
|
+
```typescript
|
|
84
|
+
await WebsSDK.MixPanel.initialize(token, false, false, false);
|
|
85
|
+
await WebsSDK.MixPanel.trackEvent('page_view', { page: 'home' });
|
|
86
|
+
await WebsSDK.MixPanel.identifyUser('user_123');
|
|
87
|
+
await WebsSDK.MixPanel.setUserProperties({ plan: 'premium' });
|
|
102
88
|
```
|
|
103
89
|
|
|
104
|
-
###
|
|
105
|
-
Amplia colección de utilidades para desarrollo web.
|
|
90
|
+
### AuthManager
|
|
106
91
|
|
|
107
|
-
```
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
const formattedDate = WebsSDK.Utils.formatDate(new Date(), 'DD/MM/YYYY');
|
|
92
|
+
```typescript
|
|
93
|
+
// Login estándar
|
|
94
|
+
await WebsSDK.AuthManager.authUser({ login, password, website_id });
|
|
111
95
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
const isValidUrl = WebsSDK.Utils.isValidUrl('https://example.com');
|
|
96
|
+
// Login sin password (MSISDN)
|
|
97
|
+
await WebsSDK.AuthManager.authOnlyUser({ login, website_id });
|
|
115
98
|
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
const capitalized = WebsSDK.Utils.capitalizeFirst('hello world');
|
|
99
|
+
// Login con OTP
|
|
100
|
+
await WebsSDK.AuthManager.authOnlyUserOTP({ login, website_id, pincode });
|
|
119
101
|
|
|
120
|
-
//
|
|
121
|
-
await WebsSDK.
|
|
122
|
-
const randomNum = WebsSDK.Utils.getRandomInt(1, 100);
|
|
102
|
+
// Registro
|
|
103
|
+
await WebsSDK.AuthManager.createUser({ login, password, website_id });
|
|
123
104
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
const unique = WebsSDK.Utils.arrayUnique([1,1,2,3,3]);
|
|
127
|
-
const picked = WebsSDK.Utils.objectPick(obj, ['key1', 'key2']);
|
|
105
|
+
// Auto-login post-pago (usado en el proxy de next_template)
|
|
106
|
+
await WebsSDK.AuthManager.auto_login(cfg_sessionid, websiteData, requestUrl);
|
|
128
107
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
108
|
+
// Baja/cancelación
|
|
109
|
+
await WebsSDK.AuthManager.unsubscribeUser({ user_id, callback_url?, org? });
|
|
110
|
+
|
|
111
|
+
// Gestión de perfil
|
|
112
|
+
await WebsSDK.AuthManager.setUserMetadata(params);
|
|
113
|
+
await WebsSDK.AuthManager.uploadProfilePhoto(params); // JPG/PNG/WEBP, max 5MB
|
|
114
|
+
await WebsSDK.AuthManager.changePassword(params);
|
|
115
|
+
```
|
|
135
116
|
|
|
136
|
-
|
|
137
|
-
const isBase64 = WebsSDK.Utils.isBase64(string);
|
|
138
|
-
const isBase64Image = WebsSDK.Utils.isBase64Image(dataUri);
|
|
139
|
-
WebsSDK.Utils.downloadFile(data, 'filename.txt', 'text/plain');
|
|
140
|
-
await WebsSDK.Utils.copyToClipboard('texto a copiar');
|
|
117
|
+
### Andromeda — Portales
|
|
141
118
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
119
|
+
```typescript
|
|
120
|
+
// Metadata del portal (optimizado con cookie websiteDataFlag)
|
|
121
|
+
await WebsSDK.Andromeda.getWebsiteMetadatabyHostname('portal.com');
|
|
122
|
+
|
|
123
|
+
// Configuración del producto (langs, login_type, logo, favicon, theme)
|
|
124
|
+
await WebsSDK.Andromeda.getWebsiteConfig('portal-corp-web');
|
|
146
125
|
```
|
|
147
126
|
|
|
148
|
-
###
|
|
149
|
-
Sistema completo de análisis y tracking de eventos.
|
|
127
|
+
### ContentManager
|
|
150
128
|
|
|
151
|
-
```
|
|
152
|
-
//
|
|
153
|
-
await WebsSDK.
|
|
129
|
+
```typescript
|
|
130
|
+
// Contenido por preset
|
|
131
|
+
await WebsSDK.ContentManager.getContentByPreset('homepage', { lang: 'es' });
|
|
154
132
|
|
|
155
|
-
//
|
|
156
|
-
await WebsSDK.
|
|
157
|
-
|
|
133
|
+
// Colección filtrada por tags
|
|
134
|
+
await WebsSDK.ContentManager.getCollection(['tag1', 'tag2'], 'es', false);
|
|
135
|
+
```
|
|
158
136
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
await WebsSDK.
|
|
137
|
+
### User
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
await WebsSDK.User.checkSession(token); // Valida token (usado en middleware)
|
|
141
|
+
await WebsSDK.User.getUserData(user_id, website_id);
|
|
142
|
+
await WebsSDK.User.getCredits(user_id, website_id);
|
|
143
|
+
```
|
|
163
144
|
|
|
164
|
-
|
|
165
|
-
await WebsSDK.MixPanel.superProperties({ app_version: '1.0.0' });
|
|
166
|
-
await WebsSDK.MixPanel.superPropertiesAppend({ session_id: 'abc123' });
|
|
145
|
+
### CorporateAuthManager
|
|
167
146
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
WebsSDK.
|
|
171
|
-
|
|
147
|
+
```typescript
|
|
148
|
+
// Server-side (middleware Next.js)
|
|
149
|
+
const result = await WebsSDK.CorporateAuthManager.validateCorporateAuthServerSide(request);
|
|
150
|
+
if (!result.authenticated) return result.redirectResponse;
|
|
151
|
+
|
|
152
|
+
// Client-side
|
|
153
|
+
await WebsSDK.CorporateAuthManager.checkCorporateLogin();
|
|
154
|
+
await WebsSDK.CorporateAuthManager.validateUser(autoRedirect?);
|
|
155
|
+
await WebsSDK.CorporateAuthManager.login(returnTo?);
|
|
156
|
+
await WebsSDK.CorporateAuthManager.logout(redirectTo?);
|
|
157
|
+
await WebsSDK.CorporateAuthManager.isAdmin(userData?);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Legal
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
await WebsSDK.Legal.getLegalText('tos' | 'privacy' | 'faq', web_id, lang);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Namespace `pre` — Pre-producción
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// Lazy-loaded, apunta a bc1742-pre.gways.org
|
|
170
|
+
await WebsSDK.pre.AuthManager.authUser(params);
|
|
171
|
+
await WebsSDK.pre.Andromeda.getWebsiteMetadatabyHostname(hostname);
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Componentes React
|
|
177
|
+
|
|
178
|
+
### CookieConsent — Banner GDPR
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { CookieConsent, getCookieConsentTexts } from 'webs-sdk';
|
|
182
|
+
import type { CookieConsentProps, CookieConsentTheme, CookieConsentPreferences } from 'webs-sdk';
|
|
183
|
+
|
|
184
|
+
<CookieConsent
|
|
185
|
+
locale="es" // en | es | fr | nl | ar | de | fi | ro | tr
|
|
186
|
+
privacyPolicyUrl="/privacy"
|
|
187
|
+
theme={{
|
|
188
|
+
backgroundColor: '#1a1a2e',
|
|
189
|
+
accentColor: '#6c63ff', // aplica a botón Accept, borde Reject, links y glow
|
|
190
|
+
acceptButtonBg: 'linear-gradient(90deg, #6c63ff, #a855f7)', // soporta gradients CSS
|
|
191
|
+
textColor: '#ffffff',
|
|
192
|
+
}}
|
|
193
|
+
onAccept={() => updateGAConsent('granted')}
|
|
194
|
+
onReject={() => updateGAConsent('denied')}
|
|
195
|
+
onSaveSettings={(prefs: CookieConsentPreferences) => handlePrefs(prefs)}
|
|
196
|
+
/>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Storage:**
|
|
200
|
+
- Cookie `cookieConsent`: `accepted | rejected | custom` (1 año)
|
|
201
|
+
- `localStorage.TRACKING_PERMISSION`: `granted | denied`
|
|
202
|
+
- `localStorage.FUNCTIONAL_PERMISSION`: `granted | denied`
|
|
203
|
+
|
|
204
|
+
### Google Analytics — GA4
|
|
176
205
|
|
|
177
|
-
|
|
178
|
-
|
|
206
|
+
```typescript
|
|
207
|
+
import { initGoogleAnalytics, updateGAConsent, trackGAEvent, trackGAPageView, isGALoaded } from 'webs-sdk';
|
|
179
208
|
|
|
180
|
-
|
|
181
|
-
|
|
209
|
+
// Registra el GA ID. Carga el script SOLO si hay consentimiento previo.
|
|
210
|
+
await initGoogleAnalytics('G-XXXXXXXXXX', { sendPageView: true, debug: false });
|
|
182
211
|
|
|
183
|
-
|
|
184
|
-
|
|
212
|
+
// Llamar tras decisión del usuario en CookieConsent
|
|
213
|
+
updateGAConsent('granted'); // carga GA si había pendingTrackingId
|
|
214
|
+
updateGAConsent('denied'); // GA nunca se carga
|
|
185
215
|
|
|
186
|
-
|
|
187
|
-
|
|
216
|
+
// Tracking
|
|
217
|
+
trackGAEvent('purchase', { value: 9.99, currency: 'EUR' });
|
|
218
|
+
trackGAPageView('/home', 'Inicio');
|
|
219
|
+
isGALoaded(); // boolean
|
|
188
220
|
```
|
|
189
221
|
|
|
190
|
-
|
|
222
|
+
> **GDPR estricto:** GA no usa Consent Mode v2. Si no hay consentimiento, el script `gtag.js` nunca se inyecta en el DOM.
|
|
191
223
|
|
|
192
|
-
|
|
224
|
+
### CDN Proxy
|
|
193
225
|
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
|
|
226
|
+
```typescript
|
|
227
|
+
import { handleCDNRequest } from 'webs-sdk';
|
|
228
|
+
import type { CDNOptions } from 'webs-sdk';
|
|
197
229
|
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
|
|
230
|
+
// Usar en un route handler de Next.js (compatible con Edge Runtime)
|
|
231
|
+
async function handleCDNRequest(
|
|
232
|
+
pathname: string, // '/cdn/apariencias/33702/image.png'
|
|
233
|
+
options?: {
|
|
234
|
+
cdnBaseUrl?: string; // Default: 'https://dy822md8ge77v.cloudfront.net'
|
|
235
|
+
cacheSeconds?: number; // Default: 300 (5 min)
|
|
236
|
+
}
|
|
237
|
+
): Promise<Response | null> // null si pathname no empieza por /cdn/
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Componentes "For You" — Creación de contenido AI
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
import {
|
|
244
|
+
AvatarAI, AvatarAIPage, AvatarAIForYouCard,
|
|
245
|
+
CreativeFaceSwap, CreativeFaceSwapPage, CreativeFaceSwapForYouCard,
|
|
246
|
+
MemeGenerator, MemeGeneratorPage, MemeGeneratorForYouCard,
|
|
247
|
+
WallpapersName, WallpapersNamePage, WallpapersNameForYouCard,
|
|
248
|
+
Wallpapers,
|
|
249
|
+
Ringtone,
|
|
250
|
+
} from 'webs-sdk';
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Todos aceptan `websiteId?: string` para tracking multi-portal.
|
|
254
|
+
|
|
255
|
+
### ARFilters — Filtros AR con DeepAR
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { ARFilters, ARFiltersForYouCard } from 'webs-sdk';
|
|
259
|
+
import type { DeepARProps, DeepARFilter, DeepARTexts } from 'webs-sdk';
|
|
260
|
+
|
|
261
|
+
<ARFilters
|
|
262
|
+
licenseKey="deepar-license-key"
|
|
263
|
+
websiteId="portal-web-id"
|
|
264
|
+
apiBaseUrl="https://api.fluver-ai.com"
|
|
265
|
+
downloadProxyUrl="/cdn" // Proxy CORS para descarga de efectos
|
|
266
|
+
filterTag="ar-filters-tag" // Obtiene filtros del CMS por tag
|
|
267
|
+
// O bien: filters={[{ file: 'beauty', thumbUrl: '/thumb.jpg' }]}
|
|
268
|
+
locale="es"
|
|
269
|
+
texts={getARFiltersTexts('es')} // requerido
|
|
270
|
+
onPhotoTaken={(url) => share(url)}
|
|
271
|
+
onVideoRecorded={(url) => share(url)}
|
|
272
|
+
/>
|
|
273
|
+
```
|
|
201
274
|
|
|
202
|
-
|
|
203
|
-
config.MIXPANEL.TOKEN = 'tu_token_mixpanel';
|
|
275
|
+
Soporta fullscreen en mobile (vendor-prefixed API para iOS Safari).
|
|
204
276
|
|
|
205
|
-
|
|
206
|
-
config.DEBUG_MODE = true;
|
|
277
|
+
### SpinningWheel — Ruleta
|
|
207
278
|
|
|
208
|
-
|
|
209
|
-
|
|
279
|
+
```typescript
|
|
280
|
+
import { SpinningWheel, wheelThemes } from 'webs-sdk';
|
|
210
281
|
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
282
|
+
// Temas: vodacom | totalgym | womantoday | afristream | efc
|
|
283
|
+
<SpinningWheel
|
|
284
|
+
userId={userId}
|
|
285
|
+
websiteId={websiteId}
|
|
286
|
+
theme="vodacom"
|
|
287
|
+
onResult={(segment) => handleWin(segment)}
|
|
288
|
+
canSpin={true}
|
|
289
|
+
alreadySpunToday={false}
|
|
290
|
+
/>
|
|
215
291
|
```
|
|
216
292
|
|
|
217
|
-
|
|
293
|
+
### Quiz y Stickers
|
|
218
294
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
await WebsSDK.Networking.sendEvent('user_action', 'button_click', {
|
|
223
|
-
button_id: 'cta_primary',
|
|
224
|
-
page: 'landing',
|
|
225
|
-
timestamp: Date.now()
|
|
226
|
-
});
|
|
295
|
+
```typescript
|
|
296
|
+
import { Quiz, Stickers } from 'webs-sdk';
|
|
297
|
+
```
|
|
227
298
|
|
|
228
|
-
|
|
229
|
-
WebsSDK.Networking.addPendingEvent({
|
|
230
|
-
eventType: 'action',
|
|
231
|
-
eventKeyword: 'offline_action',
|
|
232
|
-
eventData: { action: 'save_draft' }
|
|
233
|
-
});
|
|
299
|
+
### Esports — Noticias, Vídeos y Partidas en Directo
|
|
234
300
|
|
|
235
|
-
|
|
236
|
-
|
|
301
|
+
```typescript
|
|
302
|
+
import { EsportsNews, EsportsVideos, EsportsLive } from 'webs-sdk';
|
|
237
303
|
```
|
|
238
304
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
305
|
+
#### EsportsNews
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
<EsportsNews
|
|
309
|
+
config={{
|
|
310
|
+
key: 'api-key',
|
|
311
|
+
contents: [{ preset: 'esports_news', apiProviderId: 'id', category: [], tags: [], limit: 10 }]
|
|
312
|
+
}}
|
|
313
|
+
language="es"
|
|
314
|
+
onNewsClick={(item) => router.push(`/news/${item.id}`)}
|
|
315
|
+
theme={theme} // CSS classes para container, cards, badges, etc.
|
|
316
|
+
categoryStyles={{ gaming: { badge: 'bg-blue-500', badgeText: 'text-white' } }}
|
|
317
|
+
// Modo detalle (renderiza EsportsNewsDetail):
|
|
318
|
+
newsId="article-id"
|
|
319
|
+
newsData={item} // opcional si ya tienes los datos
|
|
320
|
+
onBack={() => router.back()}
|
|
321
|
+
/>
|
|
322
|
+
```
|
|
247
323
|
|
|
248
|
-
|
|
249
|
-
const allCreations = await WebsSDK.Storage.getCreations();
|
|
324
|
+
#### EsportsVideos
|
|
250
325
|
|
|
251
|
-
|
|
252
|
-
|
|
326
|
+
```typescript
|
|
327
|
+
<EsportsVideos
|
|
328
|
+
config={{ key: 'api-key', contents: [...] }}
|
|
329
|
+
language="es"
|
|
330
|
+
onVideoClick={(item) => openPlayer(item.video_url)}
|
|
331
|
+
theme={theme} // incluye clases para duration overlay
|
|
332
|
+
/>
|
|
253
333
|
```
|
|
254
334
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
//
|
|
267
|
-
|
|
335
|
+
#### EsportsLive
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
<EsportsLive
|
|
339
|
+
language="es"
|
|
340
|
+
timezone="Europe/Madrid"
|
|
341
|
+
onLiveClick={(item) => openStream(item.streamUrl)}
|
|
342
|
+
onMatchClick={(match) => openMatchDetail(match)}
|
|
343
|
+
onGameClick={(gameId) => filterByGame(gameId)}
|
|
344
|
+
website_id="portal-web-id"
|
|
345
|
+
theme={theme}
|
|
346
|
+
// Modo detalle de partida:
|
|
347
|
+
matchId="serie-id"
|
|
348
|
+
matchData={calendarMatch}
|
|
349
|
+
onBack={() => setMatchId(null)}
|
|
350
|
+
/>
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
268
354
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
355
|
+
## Utilidades de validación de vídeo
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
import { validateVideoUrl, validateVideoBatch, clearValidationCache } from 'webs-sdk';
|
|
359
|
+
import { useValidateVideoOnMount, useLazyVideoValidation } from 'webs-sdk';
|
|
360
|
+
|
|
361
|
+
// Función pura (sin React)
|
|
362
|
+
const state = await validateVideoUrl('https://stream.example.com/live.m3u8');
|
|
363
|
+
// 'valid' | 'invalid' | 'unknown'
|
|
364
|
+
|
|
365
|
+
// Batch con concurrencia 3
|
|
366
|
+
const results = await validateVideoBatch([url1, url2, url3]);
|
|
367
|
+
|
|
368
|
+
// React: validar al montar (evita renderizar streams rotos)
|
|
369
|
+
const { isValid, isInvalid, isValidating } = useValidateVideoOnMount(videoUrl);
|
|
370
|
+
|
|
371
|
+
// React: validación manual
|
|
372
|
+
const { validate, isValid, isInvalid } = useLazyVideoValidation();
|
|
373
|
+
await validate(videoUrl);
|
|
277
374
|
```
|
|
278
375
|
|
|
279
|
-
|
|
376
|
+
Soporta HLS, DASH, MP4. Cache en memoria con TTL de 5 minutos.
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Estructura del proyecto
|
|
280
381
|
|
|
281
382
|
```
|
|
282
383
|
src/
|
|
283
|
-
├── config.ts # Configuración central
|
|
284
|
-
├── index.ts #
|
|
384
|
+
├── config.ts # Configuración central (URLs, endpoints, constantes)
|
|
385
|
+
├── index.ts # Barrel export principal
|
|
285
386
|
├── libraries/
|
|
286
|
-
│ ├── networking.ts #
|
|
287
|
-
│ ├──
|
|
288
|
-
│ ├── session.ts #
|
|
387
|
+
│ ├── networking.ts # HTTP + events
|
|
388
|
+
│ ├── auth.ts # Autenticación, login, baja
|
|
389
|
+
│ ├── session.ts # Sesiones y dispositivo
|
|
390
|
+
│ ├── storage.ts # LocalStorage + compresión de imágenes
|
|
289
391
|
│ ├── utils.ts # Utilidades generales
|
|
290
|
-
│ ├──
|
|
291
|
-
│ ├──
|
|
292
|
-
│ ├──
|
|
293
|
-
│ ├──
|
|
294
|
-
│ ├──
|
|
295
|
-
│
|
|
296
|
-
|
|
297
|
-
|
|
392
|
+
│ ├── andromeda.ts # Metadata y config de portales
|
|
393
|
+
│ ├── corp_auth.ts # Auth corporativa (JWT)
|
|
394
|
+
│ ├── user.ts # Datos de usuario
|
|
395
|
+
│ ├── mixpanel.ts # Analytics
|
|
396
|
+
│ ├── audio.ts # Text-to-speech
|
|
397
|
+
│ ├── calypso.ts # Event tracking interno
|
|
398
|
+
│ ├── legal.ts # Textos legales
|
|
399
|
+
│ ├── content.ts # Contenido dinámico + colecciones por tags
|
|
400
|
+
│ ├── cdn.ts # CDN Proxy (Edge Runtime compatible)
|
|
401
|
+
│ └── googleAnalytics.ts # GA4 con carga diferida por consentimiento
|
|
402
|
+
├── utils/
|
|
403
|
+
│ ├── videoValidation.ts # Validación de URLs de streaming
|
|
404
|
+
│ ├── useVideoValidation.ts # React hooks para validación
|
|
405
|
+
│ └── timeUtils.ts # getTimeAgo — tiempo relativo i18n
|
|
406
|
+
└── components/
|
|
407
|
+
├── AvatarAI.tsx
|
|
408
|
+
├── CreativeFaceSwap.tsx
|
|
409
|
+
├── Wallpapers.tsx
|
|
410
|
+
├── WallpapersName.tsx
|
|
411
|
+
├── Ringtone.tsx
|
|
412
|
+
├── MemeGenerator.tsx
|
|
413
|
+
├── Quiz.tsx
|
|
414
|
+
├── Stickers.tsx
|
|
415
|
+
├── VideoPlayer.tsx
|
|
416
|
+
├── ARFilters/
|
|
417
|
+
├── SpinningWheel/
|
|
418
|
+
├── CookieConsent/
|
|
419
|
+
└── esports/
|
|
420
|
+
├── news/
|
|
421
|
+
├── videos/
|
|
422
|
+
└── live/
|
|
298
423
|
```
|
|
299
424
|
|
|
300
425
|
## Desarrollo
|
|
301
426
|
|
|
302
427
|
```bash
|
|
303
|
-
# Instalar dependencias
|
|
304
428
|
npm install
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
npm run build:watch
|
|
308
|
-
|
|
309
|
-
# Compilar para producción
|
|
310
|
-
npm run build
|
|
311
|
-
|
|
312
|
-
# Ejecutar linting
|
|
429
|
+
npm run build # tsc → dist/
|
|
430
|
+
npm run build:watch # watch mode
|
|
313
431
|
npm run lint
|
|
314
|
-
|
|
315
|
-
# Ejecutar servidor de desarrollo
|
|
316
|
-
npm run dev
|
|
317
432
|
```
|
|
318
433
|
|
|
319
434
|
## Publicación
|
|
320
435
|
|
|
321
|
-
El proyecto está configurado para ser publicado como módulo npm:
|
|
322
|
-
|
|
323
436
|
```bash
|
|
324
|
-
#
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
# Publicar en npm
|
|
328
|
-
npm publish
|
|
437
|
+
# Incluir [ROAD-361723] en el commit para auto-publish en CI
|
|
438
|
+
git commit -m "feat: descripción [ROAD-361723]"
|
|
439
|
+
git push
|
|
329
440
|
```
|
|
330
441
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
- **TypeScript**: 5+
|
|
336
|
-
- **Frameworks**: Compatible con React, Vue, Angular, Vanilla JS
|
|
337
|
-
|
|
338
|
-
## Ejemplos de Uso
|
|
339
|
-
|
|
340
|
-
### Aplicación Básica
|
|
341
|
-
```javascript
|
|
342
|
-
import WebsSDK from 'webs-sdk';
|
|
442
|
+
Tras publicar, actualizar en los portales:
|
|
443
|
+
```bash
|
|
444
|
+
npm install webs-sdk@<nueva-version>
|
|
445
|
+
```
|
|
343
446
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
await WebsSDK.MixPanel.initialize(process.env.MIXPANEL_TOKEN);
|
|
350
|
-
|
|
351
|
-
// Obtener configuración del servidor
|
|
352
|
-
const config = await WebsSDK.Networking.request('/api/config');
|
|
353
|
-
|
|
354
|
-
// Guardar preferencias del usuario
|
|
355
|
-
await WebsSDK.Storage.storeData('app_config', config);
|
|
356
|
-
|
|
357
|
-
console.log('App inicializada correctamente');
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
initApp();
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### E-commerce
|
|
364
|
-
```javascript
|
|
365
|
-
// Tracking de eventos de e-commerce
|
|
366
|
-
await WebsSDK.MixPanel.trackEvent('product_viewed', {
|
|
367
|
-
product_id: 'ABC123',
|
|
368
|
-
category: 'electronics',
|
|
369
|
-
price: 299.99
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// Gestión de carrito
|
|
373
|
-
await WebsSDK.Storage.storeData('cart_items', cartItems);
|
|
374
|
-
const savedCart = await WebsSDK.Storage.getData('cart_items');
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Aplicación con Suscripciones
|
|
378
|
-
```javascript
|
|
379
|
-
// Verificar estado de suscripción
|
|
380
|
-
const isSubscribed = await WebsSDK.Session.getIsSubscribed();
|
|
381
|
-
|
|
382
|
-
if (!isSubscribed) {
|
|
383
|
-
// Mostrar paywall
|
|
384
|
-
await WebsSDK.MixPanel.trackEvent('paywall_shown', {
|
|
385
|
-
source: 'premium_feature'
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Crear nueva suscripción
|
|
390
|
-
const subscription = await WebsSDK.Networking.createSubscription({
|
|
391
|
-
plan: 'premium_monthly',
|
|
392
|
-
user_id: WebsSDK.Session.getUserID()
|
|
393
|
-
});
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## Licencia
|
|
397
|
-
|
|
398
|
-
MIT License
|
|
447
|
+
**Nota importante — `index.js` raíz:** es el barrel CommonJS mantenido manualmente. Cada export nuevo en `src/index.ts` debe añadirse también en `index.js`:
|
|
448
|
+
```js
|
|
449
|
+
const { nuevaFuncion } = require('./dist/index.js');
|
|
450
|
+
module.exports.nuevaFuncion = nuevaFuncion;
|
|
451
|
+
```
|