npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

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-sdk

Uso 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 | denied
  • localStorage.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(); // boolean

GDPR estricto: GA no usa Consent Mode v2. Si no hay consentimiento, el script gtag.js nunca 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 lint

Publicación

# Incluir [ROAD-361723] en el commit para auto-publish en CI
git commit -m "feat: descripción [ROAD-361723]"
git push

Tras 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;