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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@theanomaly/nova-link-sdk

v0.2.72

Published

Authentication SDK for Nova Link

Readme

NovaLink SDK – System Overview

This repository packages the NovaLink authentication experience as both a reusable Web Component (Lit-based) and an ergonomic JavaScript SDK that can be consumed from ES modules, CommonJS, or as a global UMD script. It ships the widget UI, provider-specific auth flows, wallet integrations, and a thin API client so host applications can delegate login, profile access, and wallet insight to NovaLink’s backend.

Installation & Quick Start

  • Install the SDK: npm install @theanomaly/nova-link-sdk
  • Initialize once on the client:
    import NovaLink from '@theanomaly/nova-link-sdk';
    
    NovaLink.init({
      apiKey: 'your-api-key',
      telegramBotId: 'your-public-bot-id',          // optional, needed for TG Mini App
      enabledProviders: ['google','telegram','email','ethereum'], // defaults to all
      container: document.getElementById('modal-root'), // optional
    });
  • Interact with the modal via promises or callbacks:
    // Promise-based login
    NovaLink.loginAsync()
      .then(user => console.log('User logged in', user))
      .catch(error => console.error('Login failed', error.code, error.message));
    
    // Callback variant
    NovaLink.login((profile, error) => {
      if (error) return console.error('Login failed', error);
      console.log('Authenticated profile', profile);
    });
    
    const profile = await NovaLink.getCurrentUser(); // resolves null when logged out
    await NovaLink.logoutAsync();                    // clears token + widget state
    NovaLink.closeAuth();                            // manually hide modal if needed
  • The widget renders into document.body by default. Pass container to target another DOM node.

Packaging & Build

  • package.json (@theanomaly/nova-link-sdk) exposes dist/nova-link-sdk.{cjs|esm|umd}.js plus types/. Consumers can import NovaLink from '@theanomaly/nova-link-sdk' or drop the UMD bundle directly into a <script>.
  • rollup.config.js builds all formats with a single entry (src/index.js), injects the SDK version and critical env vars (BACKEND_BASE_URL, TELEGRAM_BOT_NAME, WALLET_CONNECT_ID) via @rollup/plugin-replace, and copies any static assets. npm run build/npm run dev are the main workflows.
  • dist/ holds the compiled bundles, while types/nova-link-sdk.d.ts surfaces TypeScript definitions for the SDK, widget, token manager, and API service.
  • Ops scripts: bumpAndPublish.ts bumps the patch version, runs the build, and npm publishes via Bun; demoBuild.sh copies the UMD build into a sibling example app; telegram-stats-immediate.js is an optional drop-in script that reports Telegram WebApp usage metrics straight to https://api.novalink.io/telegram/stat.

Repository Map

  • src/index.js – SDK façade (exposes the NovaLink singleton).
  • nova-link-widget.js – the LitElement Web Component implementing the modal UI and all runtime logic.
  • components/ – stateless view templates (initial-view, email-input-view, code-entry-view, profile-view, etc.), basic atoms (login-button, input-field, icons), and wallet-info-element which is a standalone Lit custom element.
  • auth/ – service layer: api-service.js, token-manager.js, and wallet-connector.js (WalletConnect/AppKit + Wagmi adapter).
  • utils/ – shared styles, helpers (validateEmail, formatTimeRemaining), and font loaders to inject the Sofia Pro family into Shadow DOM scopes.
  • examples/basic-usage.html – vanilla HTML playground showing init/login/logout flows, wallet info, and Telegram mini-app verification via the UMD build.
  • PAYMENT_SDK_DOCS.md – aspirational documentation for a payment confirmation API (NovaLink.confirmPayment), which is not implemented in the current codebase.

Using NovaLink with Next.js / SSR

  • Web Components require browser APIs, so defer SDK usage until after hydration.
  • Dynamic import inside useEffect:
    const [novaLink, setNovaLink] = useState(null);
    useEffect(() => {
      import('@theanomaly/nova-link-sdk').then(({ default: NovaLink }) => {
        NovaLink.init({ apiKey: 'your-api-key' });
        setNovaLink(NovaLink);
      });
    }, []);
  • Client-only wrapper via next/dynamic:
    const NovaLinkWrapper = dynamic(() => Promise.resolve(({ apiKey }) => {
      useEffect(() => {
        import('@theanomaly/nova-link-sdk').then(({ default: NovaLink }) =>
          NovaLink.init({ apiKey })
        );
      }, [apiKey]);
      return <button onClick={() => NovaLink.loginAsync()}>Login</button>;
    }), { ssr: false });
  • next/script + UMD bundle: include https://unpkg.com/@theanomaly/nova-link-sdk/dist/nova-link-sdk.umd.js with strategy="afterInteractive" and run window.NovaLink.init(...) inside onLoad.
  • Always guard with if (typeof window === 'undefined') before referencing NovaLink, and only call init once per page load.

SDK Entry Point (src/index.js)

  • Guards against SSR: immediately bails if window/document are undefined and logs a warning.
  • NovaLinkSDK stores init config (API key, Telegram bot details, enabled providers, DOM container) and ensures the nova-link-widget custom element is registered by importing ../nova-link-widget.js.
  • init(config) validates options, normalizes enabledProviders, resolves env-derived defaults for backend URLs/Telegram bot name, and either creates or updates the widget element (a fixed-position modal appended to config.container or document.body). Returns false on config errors so hosts can fail fast.
  • loginAsync()/login(callback) show the widget, track the pending promise/callback, and wait for auth-token-changed events emitted by the widget. closeAuth() hides the modal and cancels an in-flight login (rejecting the stored promise/callback with AUTHENTICATION_CANCELLED).
  • logoutAsync()/logout(callback) delegate to the widget’s logout(), then resolve immediately (the widget clears local storage and emits state change events).
  • getCurrentUser() lazily creates the widget if needed, asks it to refresh the profile (_refreshProfile), and resolves with the cached _userProfile.
  • verifyTGMiniAppUser(miniAppAuthToken) and showWalletInfo() are thin wrappers that ensure init has happened, then call the widget’s methods (which in turn hit the API and update the view).

Widget Architecture (nova-link-widget.js)

  • Built with Lit’s reactive system: static properties declares all reflected attributes (api-key, backend-base-url, telegram-bot-id, enabled-providers) plus internal state (_view, _isLoading, _authToken, _userProfile, OTP timers, provider toggles, etc.). willUpdate parses the JSON enabledProviders attribute into _enabledProvidersArray.
  • Lifecycle:
    • connectedCallback: registers a message listener for popup responses, wires window.onTelegramAuth, instantiates TokenManager/ApiService, checks for Telegram Mini App context via isTMA(), loads any stored token, and bootstraps WalletConnect (if WALLET_CONNECT_ID was injected).
    • disconnectedCallback: removes listeners, clears popups/timers, and unregisters Telegram handlers to avoid leaks.
  • Rendering: A switch(this._view) powers the modal. Views include initial, email_input, code_entry, success, error, profile, and wallet_info. Each view function receives handler callbacks and overlay elements for loading/popup states or wallet signing instructions.
  • Close semantics: the ContainerView component includes an × button that fires novalink-close-requested. The parent SDK listens for this event to hide/destroy the modal.
  • Events: every successful auth calls _dispatchAuthTokenEvent, which emits auth-token-changed (detail contains token + expiry). Host apps can listen for it directly if they embed <nova-link-widget> manually.
  • Mini App mode: isTMA() toggles auto-login; _handleTelegramMiniAppLogin() grabs retrieveRawInitData(), posts it to /api/v1/telegram-miniapp/verify, and ensures the spinner stays up at least 500 ms so Telegram users see progress.

Service Layer (auth/)

  • token-manager.js namespaces localStorage entries by API key, decodes JWT payloads to determine expiry, and exposes getTokenExpiration() for UI display. Stale/invalid entries get wiped automatically.
  • api-service.js wraps fetch calls to the NovaLink backend:
    • Profile: GET /api/v1/profile and GET /api/v1/profile/balances.
    • Google OAuth kickoff: GET /api/v1/auth/google/start.
    • Telegram WebApp flow: POST /api/v1/auth/telegram/{start|callback}.
    • Email OTP: POST /api/v1/auth/email/request-code & /verify-code.
    • Token exchange: POST /api/v1/auth/exchange-token.
    • Ethereum auth: GET /api/v1/auth/ethereum/nonce/:address and POST /api/v1/auth/ethereum/verify-signature.
    • Telegram Mini App verification endpoints.
  • wallet-connector.js integrates WalletConnect v2 via Reown AppKit + Wagmi. It sets up the modal, watches account changes, requests a signing payload (nonce/message) from the backend, signs with the connected wallet, and hands the response back to the widget via callbacks. Ethereum auth respects enabledProviders so the option disappears if the host disables ethereum.

UI Components & Styling

  • Presentational helpers live under components/. Notable pieces:
    • initial-view.js renders provider buttons (Google, Telegram, Email, Ethereum) via the shared LoginButton atom and inline SVG icons. When isMiniApp is true, it shows an auto-login message instead of buttons.
    • email-input-view.js and code-entry-view.js handle the OTP UX with the InputField Web Component, error display, resend controls, and countdown timers (formatTimeRemaining).
    • profile-view.js and wallet-info-element.js visualise profile metadata, linked auth providers, connected wallets, and live balances; addresses have copy buttons via the Clipboard API.
    • overlay-components.js describes three overlay layers (popup blockers, wallet signing spinner, and a placeholder for generic loading).
    • container-view.js standardises the modal chrome (blurred glass background, the NovaLink logo, and the close button) and emits the close event.
  • utils/styles.js supplies base CSS (fonts, button styles, error states) that each view inherits. utils/font-loader.js injects the Sofia Pro font stack into document.adoptedStyleSheets, with fallback variants in font-loader-link.js/font-loader-fallback.js.

Authentication & Wallet Flows

  • Existing sessions: _loadStoredToken() reads from TokenManager, refreshes the profile, optionally shows the profile view (if auto-show-profile is set) or auto-approves mini-app sessions.
  • Google: ApiService.startGoogleAuth() returns an authUrl. _openAuthPopup() opens a centered window and tracks it via _popupCheckInterval. The popup posts GOOGLE_AUTH_RESULT / GOOGLE_AUTH_ERROR via window.postMessage; _handleAuthMessage exchanges the received exchangeToken for a JWT through /auth/exchange-token, then funnels success into _processAuthResult.
  • Telegram Web: _handleTelegramLoginClick() hits /auth/telegram/start, the popup sends either a serialized tgAuthResult: string or a JSON event, and _handleTelegramAuth() relays it to /auth/telegram/callback.
  • Telegram Mini App: handled entirely client-side (no popups) using retrieveRawInitData() + /telegram-miniapp/verify. Hosts can also call NovaLink.verifyTGMiniAppUser(token) if they already obtained a short-lived token from the Mini App JS SDK.
  • Email OTP: _handleEmailSubmit() validates via validateEmail(), requests a code, starts both expiration (10 min) and resend (60 s) timers, and moves to code_entry. _handleCodeSubmit() verifies the 6-digit code, handles rate-limit errors, stores the token, and transitions to success.
  • Ethereum wallets: _handleEthWalletClick() invokes the WalletConnect modal (if a WALLET_CONNECT_ID was configured during the build). watchAccount() auto-triggers signing when the account connects; _handleWalletSigningStateChange() gives the UI a blocking overlay until the signature and verification succeed.
  • Wallet balances: showWalletInfo() requires an authenticated user, fetches /profile/balances, and passes the response to wallet-info-element, which supports copying addresses and showing per-chain token holdings.
  • Every success path shares _processAuthResult(provider, authToken, userId): store the token, emit auth-token-changed, refresh the profile, show a success message, clear timers/popup state, and auto-close after 1 s (the SDK’s loginAsync promise resolves with the refreshed profile).

Host Integration Details

  • NovaLink.init accepts { apiKey, telegramBotId, container, enabledProviders }. enabledProviders can be any subset of ['google','telegram','email','ethereum']; invalid entries are filtered out with a console warning. When omitted or empty, every provider is enabled.
  • The widget reflects the config through attributes (e.g., <nova-link-widget enabled-providers='["email"]'>) so you can embed the element manually if desired.
  • The modal is appended once and re-used; repeated loginAsync() calls simply fade it back in. transitionDuration (300 ms) gates the fade-out before display: none.
  • SSR/Next.js guidance is outlined above (“Using NovaLink with Next.js / SSR”). Web Components rely on browser APIs, so always gate SDK access behind client-only checks; attempting to import the SDK server-side will trip the guard at the top of src/index.js.
  • Events: besides auth-token-changed, the widget emits novalink-close-requested whenever the user hits the close button or when _handleCloseWidget() auto-fires after success. Host apps can listen for either to sync their own UI (and NovaLink.closeAuth() reuses _hideWidgetModal() to animate the fade-out).

Supporting Docs & Examples

  • examples/basic-usage.html demonstrates every public SDK method (init, login promise/callback, getCurrentUser, logout, showWalletInfo, verifyTGMiniAppUser) plus UI helpers to show the returned profile. It relies on the built UMD bundle living under dist/.
  • PAYMENT_SDK_DOCS.md outlines an upcoming payment confirmation surface. Treat it as a roadmap; there is no NovaLink.confirmPayment implementation yet, so referencing it will throw unless future code lands.
  • lit.md is a quick reference of Lit idioms (decorators, property declarations) for contributors touching the widget/components.

Extensibility & Gotchas

  • All network requests depend on the env-injected BACKEND_BASE_URL. When authoring new features, update .env, then rebuild so rollup-plugin-replace bakes the values into the bundle.
  • Fonts are loaded from https://assets.connectnova.link. If those assets are unreachable (e.g., CSP), switch to the loadSofiaProFontViaLink or fallback loader and ensure hosts allow the origin.
  • Popup blockers: _openAuthPopup throws if the window was blocked, and _handleAuthError routes users to an error view with a retry button. Host apps should surface the rejection from loginAsync() so users know to allow popups.
  • Token lifetime: TokenManager.storeToken naively decodes JWTs; if backend payloads change, update the decode logic to keep expiration accurate. Always clear localStorage if verification fails to avoid partial sessions.
  • Ensure WALLET_CONNECT_ID is set before enabling the Ethereum provider; otherwise _handleEthWalletClick pushes the UI into the error view with “Wallet connection not available.”
  • Because the SDK manipulates the DOM directly, only call NovaLink.init once per page load. Subsequent calls return early but will reconfigure enabledProviders/Telegram IDs on the existing widget instance.

With these pieces in mind, you can confidently navigate the codebase, extend authentication providers, tweak the UI, or integrate NovaLink into host applications regardless of framework. The SDK entry point coordinates lifecycle and host communication, the widget orchestrates UX and API calls, and the supporting modules (auth services, UI components, utilities, scripts) keep the system modular and easy to evolve.

Development

npm install                   # install dependencies
npm run build                 # rollup build (CJS/ESM/UMD)
npm run dev                   # rollup -w for iterative development
npx http-server . --port 8181 # serve repo root to test examples/basic-usage.html
  • Create a .env from .env.example so rollup can inline BACKEND_BASE_URL, TELEGRAM_BOT_NAME, and WALLET_CONNECT_ID.
  • Rebuild after changing env vars—they are baked in at compile time.
  • examples/basic-usage.html pulls from dist/, so rerun npm run build whenever source files change before refreshing the example.

License

MIT