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

@spryui/sdk

v0.1.3

Published

Display and manage SpryUI banners in browser and server-rendered applications

Readme

@spryui/sdk

Publish and deliver SpryUI banners with a browser SDK or server-rendered initial HTML. No runtime dependencies; includes TypeScript declarations. Requires an existing SpryUI project public key and approved site domain. Loopback hosts are supported for development.

Install

npm install @spryui/[email protected]

Nuxt 4: server-rendered banners

See the live Nuxt SSR demo and compare it with the HTML demo.

Install the adapter and SDK:

npm install @spryui/nuxt @spryui/sdk

Register the module in nuxt.config.ts:

export default defineNuxtConfig({
  modules: ["@spryui/nuxt"],
  spryui: {
    publicKey: "{YOUR_PROJECT_PUBLIC_KEY}",
  },
});

Place the components in app/app.vue:

<template>
  <SpryUiBanners position="top" />
  <NuxtPage />
  <SpryUiBanners position="bottom" />
</template>

Use each position once. The module owns the endpoint, host detection, server fetch, targeting context, visitor cookies, route changes, and browser handoff. Approve your deployed domain on the matching SpryUI project. Defaults are PRODUCTION and a 1,500 ms fetch timeout. No manual host configuration is needed.

The module sets private/no-store responses and rejects shared route caching and prerendering. Keep these pages out of CDN page caches. Include its first-party cookies in your consent policy where needed. Device-restricted banners may wait for browser evaluation.

Advanced SDK-only Nuxt recipe

For apps that need to own the integration, a lower-level recipe ships in dist/nuxt/. It handles the same server fetch and browser handoff explicitly. Supply NUXT_SPRYUI_PUBLIC_KEY; NUXT_SPRYUI_ENV is optional and defaults to PRODUCTION. The endpoint derives the host from the incoming request.

Server API

import { fetchSpryUiConfig } from '@spryui/sdk/server'

const config = await fetchSpryUiConfig({
  publicKey: 'your_project_public_key',
  host: 'https://your-site.example',
  env: 'PRODUCTION',
  timeoutMs: 1500,
})

host is required on the server and must match the project's approved domain, including a non-default port. The helper uses the existing signed token and config APIs. It returns config only; the temporary server token is not included. It uses Web APIs, with no Node runtime dependency, and works in Nitro/Cloudflare. Optional signal and standard-fetch fetcher support cancellation and testing. Errors reject; the Nuxt recipe catches them and renders the host page without banners.

HTML and browser handoff

import { createSpryUiDeliveryState, renderSpryUiHtml } from '@spryui/sdk/server'

const state = createSpryUiDeliveryState(visitorKey, sessionKey, savedHistory)
const context = { path: '/pricing' }
const html = renderSpryUiHtml(config, { state, context })
// Return html, config, context and state through Nuxt's payload, not hand-built scripts.

In the browser, after mounting the container containing that HTML:

import { initSpryUi } from '@spryui/sdk'

const sdk = initSpryUi({
  publicKey: 'your_project_public_key',
  mountId: 'your-banner-slot',
  initialConfig: config,
  deliveryState: state,
  targetingContext: context,
  onDeliveryStateChange: persistHistory,
  defer: false,
})
// Call sdk.destroy() when the component unmounts.

Use the included two-slot component to position relative banners around the page. Optional positions on both rendering and initialization restricts each slot to top or bottom positions. renderSpryUiHtml returns slot contents, not a document or script. Insert it through v-html; Vue owns the slot element and SpryUI owns its contents after mounting.

State, targeting, and caching

  • Keep delivery state per visitor/request. Never store it in a process-global variable or shared cache. The server renderer does not mutate it.
  • The recipe uses first-party visitor, session, and display-history cookies. Apply your own consent policy before persisting them; use an application session store for larger histories. Cookie storage is size-limited, so do not use a single growing cookie as an unlimited history store.
  • Visitor IDs control deterministic variants. Use the same state on server and client. Cookies are not authorization or entitlement evidence.
  • The recipe starts fresh state when migrating from the hosted browser SDK; it does not import existing localStorage dismissals. If preserving those is required, migrate that browser state before enabling SSR for returning visitors.
  • Config and personalized HTML must use private/no-store caching. Do not prerender or share-cache the cookie-based recipe. No server config cache is introduced; a paused banner disappears on the next successful fetch/navigation.
  • Pass known referrer, UTM, country and visitor status through context. Unknown targeting values suppress restricted banners during SSR. Device-specific banners wait for browser viewport evaluation unless you supply a device value. Local-hour/day schedules without an explicit timezone also wait for the browser.
  • SSR removes the client fetch waterfall for eligible banners, not network latency itself. The server waits up to the configured timeout. Browser-only rules can still render after hydration.
  • Existing scoped CSS is retained. This is not Shadow DOM isolation. Match your site's CSP to the SDK's inline styles.

Browser-only use

import { initSpryUi } from '@spryui/sdk'
const sdk = initSpryUi({ publicKey: 'your_project_public_key' })

refresh() fetches current config; destroy() removes the instance's rendered messages and timers. setConsent() and setOptOut() control event collection. Browser-only initialization still defaults to waiting for window load; use defer: false when the host is ready. Importing the package on the server is safe, but browser initialization there is a no-op.

Repository validation

Delivery diagnostics

Set debug: true to see delivery status, readable exclusion reasons, the resolved environment and whether configuration came from the network or initialConfig. Server configuration can include an optional delivery status and reason code. The overlay distinguishes exhausted allowance, blocked delivery, no active banners, and client filtering. Older responses remain supported without guessing why they are empty. Token, config and rendering errors identify the stage that failed.

Debug mode warns once per server pause/block reason per SDK instance in the console; normal mode stays silent. No tokens, account details or usage totals are added to these diagnostics. Mounted carousel slides count as rendered even while hidden. Analytics acceptance is separate from rendering and is not established by this count.

npm run pack:sdk
node --test scripts/test-sdk-ssr.mjs

Publishing is separate from building. Publication without provenance is owner-approved; see the repository's SDK publishing and security policy.