webs-sdk
v0.18.35
Published
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.
Keywords
Readme
webs-sdk
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.
Versión actual: 0.18.9
Instalación
npm install webs-sdkUso básico
import WebsSDK from 'webs-sdk';
// Inicializar sesión
await WebsSDK.Session.init();
// Petición HTTP
const data = await WebsSDK.Networking.request('/api/endpoint', { param: 'value' });
// Almacenamiento local
WebsSDK.Storage.set('key', 'value');
const value = WebsSDK.Storage.get('key');Librerías disponibles
Networking
// Petición HTTP (inyecta sessionData automáticamente)
await WebsSDK.Networking.request(url, data);
// Eventos de tracking
await WebsSDK.Networking.sendEvent('action', 'button_click', { button_id: 'submit' });
// Suscripciones
await WebsSDK.Networking.createSubscription(subscriptionData);
const { success, subscription_active } = await WebsSDK.Networking.checkSubscription();Storage
WebsSDK.Storage.set('key', 'value');
const value = WebsSDK.Storage.get('key');
// Compresión de imágenes (0.8 ratio, 1024px max)
const compressed = await WebsSDK.Storage.compressImage(imageFile, 2); // 2MB max
// Creaciones (imágenes generadas por el usuario)
await WebsSDK.Storage.handleDownloadImageToCreations(base64, 'id', metadata);
const creations = await WebsSDK.Storage.getCreations();
await WebsSDK.Storage.deleteCreation('id');Session
await WebsSDK.Session.init();
const sessionData = WebsSDK.Session.getSessionData();
const userId = WebsSDK.Session.getUserID();
const lang = WebsSDK.Session.getDeviceLanguage();
const isSubscribed = WebsSDK.Session.getIsSubscribed();Utils
const id = WebsSDK.Utils.generateId();
const isValidEmail = WebsSDK.Utils.isValidEmail('[email protected]');
const isMobile = WebsSDK.Utils.isMobile();
const deviceInfo = WebsSDK.Utils.getDeviceInfo();
const truncated = WebsSDK.Utils.truncateText('Long text...', 10);MixPanel
await WebsSDK.MixPanel.initialize(token, false, false, false);
await WebsSDK.MixPanel.trackEvent('page_view', { page: 'home' });
await WebsSDK.MixPanel.identifyUser('user_123');
await WebsSDK.MixPanel.setUserProperties({ plan: 'premium' });AuthManager
// Login estándar
await WebsSDK.AuthManager.authUser({ login, password, website_id });
// Login sin password (MSISDN)
await WebsSDK.AuthManager.authOnlyUser({ login, website_id });
// Login con OTP
await WebsSDK.AuthManager.authOnlyUserOTP({ login, website_id, pincode });
// Registro
await WebsSDK.AuthManager.createUser({ login, password, website_id });
// Auto-login post-pago (usado en el proxy de next_template)
await WebsSDK.AuthManager.auto_login(cfg_sessionid, websiteData, requestUrl);
// Baja/cancelación
await WebsSDK.AuthManager.unsubscribeUser({ user_id, callback_url?, org? });
// Gestión de perfil
await WebsSDK.AuthManager.setUserMetadata(params);
await WebsSDK.AuthManager.uploadProfilePhoto(params); // JPG/PNG/WEBP, max 5MB
await WebsSDK.AuthManager.changePassword(params);Andromeda — Portales
// Metadata del portal (optimizado con cookie websiteDataFlag)
await WebsSDK.Andromeda.getWebsiteMetadatabyHostname('portal.com');
// Configuración del producto (langs, login_type, logo, favicon, theme)
await WebsSDK.Andromeda.getWebsiteConfig('portal-corp-web');ContentManager
// Contenido por preset
await WebsSDK.ContentManager.getContentByPreset('homepage', { lang: 'es' });
// Colección filtrada por tags
await WebsSDK.ContentManager.getCollection(['tag1', 'tag2'], 'es', false);User
await WebsSDK.User.checkSession(token); // Valida token (usado en middleware)
await WebsSDK.User.getUserData(user_id, website_id);
await WebsSDK.User.getCredits(user_id, website_id);CorporateAuthManager
// Server-side (middleware Next.js)
const result = await WebsSDK.CorporateAuthManager.validateCorporateAuthServerSide(request);
if (!result.authenticated) return result.redirectResponse;
// Client-side
await WebsSDK.CorporateAuthManager.checkCorporateLogin();
await WebsSDK.CorporateAuthManager.validateUser(autoRedirect?);
await WebsSDK.CorporateAuthManager.login(returnTo?);
await WebsSDK.CorporateAuthManager.logout(redirectTo?);
await WebsSDK.CorporateAuthManager.isAdmin(userData?);Legal
await WebsSDK.Legal.getLegalText('tos' | 'privacy' | 'faq', web_id, lang);Namespace pre — Pre-producción
// Lazy-loaded, apunta a bc1742-pre.gways.org
await WebsSDK.pre.AuthManager.authUser(params);
await WebsSDK.pre.Andromeda.getWebsiteMetadatabyHostname(hostname);Componentes React
CookieConsent — Banner GDPR
import { CookieConsent, getCookieConsentTexts } from 'webs-sdk';
import type { CookieConsentProps, CookieConsentTheme, CookieConsentPreferences } from 'webs-sdk';
<CookieConsent
locale="es" // en | es | fr | nl | ar | de | fi | ro | tr
privacyPolicyUrl="/privacy"
theme={{
backgroundColor: '#1a1a2e',
accentColor: '#6c63ff', // aplica a botón Accept, borde Reject, links y glow
acceptButtonBg: 'linear-gradient(90deg, #6c63ff, #a855f7)', // soporta gradients CSS
textColor: '#ffffff',
}}
onAccept={() => updateGAConsent('granted')}
onReject={() => updateGAConsent('denied')}
onSaveSettings={(prefs: CookieConsentPreferences) => handlePrefs(prefs)}
/>Storage:
- Cookie
cookieConsent:accepted | rejected | custom(1 año) localStorage.TRACKING_PERMISSION:granted | deniedlocalStorage.FUNCTIONAL_PERMISSION:granted | denied
Google Analytics — GA4
import { initGoogleAnalytics, updateGAConsent, trackGAEvent, trackGAPageView, isGALoaded } from 'webs-sdk';
// Registra el GA ID. Carga el script SOLO si hay consentimiento previo.
await initGoogleAnalytics('G-XXXXXXXXXX', { sendPageView: true, debug: false });
// Llamar tras decisión del usuario en CookieConsent
updateGAConsent('granted'); // carga GA si había pendingTrackingId
updateGAConsent('denied'); // GA nunca se carga
// Tracking
trackGAEvent('purchase', { value: 9.99, currency: 'EUR' });
trackGAPageView('/home', 'Inicio');
isGALoaded(); // booleanGDPR estricto: GA no usa Consent Mode v2. Si no hay consentimiento, el script
gtag.jsnunca se inyecta en el DOM.
CDN Proxy
import { handleCDNRequest } from 'webs-sdk';
import type { CDNOptions } from 'webs-sdk';
// Usar en un route handler de Next.js (compatible con Edge Runtime)
async function handleCDNRequest(
pathname: string, // '/cdn/apariencias/33702/image.png'
options?: {
cdnBaseUrl?: string; // Default: 'https://dy822md8ge77v.cloudfront.net'
cacheSeconds?: number; // Default: 300 (5 min)
}
): Promise<Response | null> // null si pathname no empieza por /cdn/Componentes "For You" — Creación de contenido AI
import {
AvatarAI, AvatarAIPage, AvatarAIForYouCard,
CreativeFaceSwap, CreativeFaceSwapPage, CreativeFaceSwapForYouCard,
MemeGenerator, MemeGeneratorPage, MemeGeneratorForYouCard,
WallpapersName, WallpapersNamePage, WallpapersNameForYouCard,
Wallpapers,
Ringtone,
} from 'webs-sdk';Todos aceptan websiteId?: string para tracking multi-portal.
ARFilters — Filtros AR con DeepAR
import { ARFilters, ARFiltersForYouCard } from 'webs-sdk';
import type { DeepARProps, DeepARFilter, DeepARTexts } from 'webs-sdk';
<ARFilters
licenseKey="deepar-license-key"
websiteId="portal-web-id"
apiBaseUrl="https://api.fluver-ai.com"
downloadProxyUrl="/cdn" // Proxy CORS para descarga de efectos
filterTag="ar-filters-tag" // Obtiene filtros del CMS por tag
// O bien: filters={[{ file: 'beauty', thumbUrl: '/thumb.jpg' }]}
locale="es"
texts={getARFiltersTexts('es')} // requerido
onPhotoTaken={(url) => share(url)}
onVideoRecorded={(url) => share(url)}
/>Soporta fullscreen en mobile (vendor-prefixed API para iOS Safari).
SpinningWheel — Ruleta
import { SpinningWheel, wheelThemes } from 'webs-sdk';
// Temas: vodacom | totalgym | womantoday | afristream | efc
<SpinningWheel
userId={userId}
websiteId={websiteId}
theme="vodacom"
onResult={(segment) => handleWin(segment)}
canSpin={true}
alreadySpunToday={false}
/>Quiz y Stickers
import { Quiz, Stickers } from 'webs-sdk';Esports — Noticias, Vídeos y Partidas en Directo
import { EsportsNews, EsportsVideos, EsportsLive } from 'webs-sdk';EsportsNews
<EsportsNews
config={{
key: 'api-key',
contents: [{ preset: 'esports_news', apiProviderId: 'id', category: [], tags: [], limit: 10 }]
}}
language="es"
onNewsClick={(item) => router.push(`/news/${item.id}`)}
theme={theme} // CSS classes para container, cards, badges, etc.
categoryStyles={{ gaming: { badge: 'bg-blue-500', badgeText: 'text-white' } }}
// Modo detalle (renderiza EsportsNewsDetail):
newsId="article-id"
newsData={item} // opcional si ya tienes los datos
onBack={() => router.back()}
/>EsportsVideos
<EsportsVideos
config={{ key: 'api-key', contents: [...] }}
language="es"
onVideoClick={(item) => openPlayer(item.video_url)}
theme={theme} // incluye clases para duration overlay
/>EsportsLive
<EsportsLive
language="es"
timezone="Europe/Madrid"
onLiveClick={(item) => openStream(item.streamUrl)}
onMatchClick={(match) => openMatchDetail(match)}
onGameClick={(gameId) => filterByGame(gameId)}
website_id="portal-web-id"
theme={theme}
// Modo detalle de partida:
matchId="serie-id"
matchData={calendarMatch}
onBack={() => setMatchId(null)}
/>Utilidades de validación de vídeo
import { validateVideoUrl, validateVideoBatch, clearValidationCache } from 'webs-sdk';
import { useValidateVideoOnMount, useLazyVideoValidation } from 'webs-sdk';
// Función pura (sin React)
const state = await validateVideoUrl('https://stream.example.com/live.m3u8');
// 'valid' | 'invalid' | 'unknown'
// Batch con concurrencia 3
const results = await validateVideoBatch([url1, url2, url3]);
// React: validar al montar (evita renderizar streams rotos)
const { isValid, isInvalid, isValidating } = useValidateVideoOnMount(videoUrl);
// React: validación manual
const { validate, isValid, isInvalid } = useLazyVideoValidation();
await validate(videoUrl);Soporta HLS, DASH, MP4. Cache en memoria con TTL de 5 minutos.
Estructura del proyecto
src/
├── config.ts # Configuración central (URLs, endpoints, constantes)
├── index.ts # Barrel export principal
├── libraries/
│ ├── networking.ts # HTTP + events
│ ├── auth.ts # Autenticación, login, baja
│ ├── session.ts # Sesiones y dispositivo
│ ├── storage.ts # LocalStorage + compresión de imágenes
│ ├── utils.ts # Utilidades generales
│ ├── andromeda.ts # Metadata y config de portales
│ ├── corp_auth.ts # Auth corporativa (JWT)
│ ├── user.ts # Datos de usuario
│ ├── mixpanel.ts # Analytics
│ ├── audio.ts # Text-to-speech
│ ├── calypso.ts # Event tracking interno
│ ├── legal.ts # Textos legales
│ ├── content.ts # Contenido dinámico + colecciones por tags
│ ├── cdn.ts # CDN Proxy (Edge Runtime compatible)
│ └── googleAnalytics.ts # GA4 con carga diferida por consentimiento
├── utils/
│ ├── videoValidation.ts # Validación de URLs de streaming
│ ├── useVideoValidation.ts # React hooks para validación
│ └── timeUtils.ts # getTimeAgo — tiempo relativo i18n
└── components/
├── AvatarAI.tsx
├── CreativeFaceSwap.tsx
├── Wallpapers.tsx
├── WallpapersName.tsx
├── Ringtone.tsx
├── MemeGenerator.tsx
├── Quiz.tsx
├── Stickers.tsx
├── VideoPlayer.tsx
├── ARFilters/
├── SpinningWheel/
├── CookieConsent/
└── esports/
├── news/
├── videos/
└── live/Desarrollo
npm install
npm run build # tsc → dist/
npm run build:watch # watch mode
npm run lintPublicación
# Incluir [ROAD-361723] en el commit para auto-publish en CI
git commit -m "feat: descripción [ROAD-361723]"
git pushTras publicar, actualizar en los portales:
npm install webs-sdk@<nueva-version>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:
const { nuevaFuncion } = require('./dist/index.js');
module.exports.nuevaFuncion = nuevaFuncion;