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

pocoaiwebsdk

v1.1.0

Published

PocoAI Gift Card SDK for the web — embed a gift card rewards store on your website with an iframe wrapper

Readme

pocoaiwebsdk

PocoAI Gift Card SDK for the web. Embed the rewards store on your website in a few lines.

Install

npm install pocoaiwebsdk

Quick start

<div id="rewards-store" style="width: 100%; height: 720px"></div>

<script type="module">
  import { SubspaceSDK } from 'pocoaiwebsdk';

  SubspaceSDK.init({
    container: '#rewards-store',
    auth: 'YOUR_AUTH_TOKEN',
    clientId: 'YOUR_CLIENT_ID',
    onReady: () => console.log('ready'),
    onPurchase: (d) => console.log('purchase', d),
    onClose: () => console.log('close'),
    onError: (e) => console.warn('error', e),
  });
</script>

Call SubspaceSDK.destroy() to tear down the iframe and listeners.

Config

| Field | Type | Required | Description | |---|---|---|---| | container | string \| HTMLElement | yes | CSS selector or element to mount the iframe into | | auth | string \| null | no | Partner-issued JWT. Omit (or pass null/undefined/"") for guest mode — see below | | clientId | string | yes | Partner-issued client id | | initialRoute | SDKSection | no | Pin the SDK to a single section — see below | | productId | string | no | Deep-link to a specific item within the focused section. With initialRoute: 'giftcards' → opens /product/<id>; with initialRoute: 'subscriptions' → opens /subscriptions/<id>. Ignored otherwise. | | theme | SDKTheme | no | Runtime theme override (merged on top of the per-client config). See Theme override. | | onReady | () => void | no | Fires when the SDK is ready to receive postMessages | | onPurchase | ({ orderId, amount, brand }) => void | no | Fires when a gift card purchase completes | | onSubscriptionJoined | ({ room_id, service_name?, plan_name? }) => void | no | Fires when the user joins a shared-subscription room | | onClose | () => void | no | Fires when the user requests to close | | onError | ({ code, message }) => void | no | Fires on SDK errors — see Error codes |

Guest mode

auth is optional. Omit it, or pass null / undefined / "", to open the SDK without a signed-in user. Guests can browse gift cards and brands, but authenticated-only sections (orders, chats, quick-payments) render an "Authentication required" screen.

// Authenticated
SubspaceSDK.init({
  container: '#rewards-store',
  auth: 'YOUR_AUTH_TOKEN',
  clientId: 'YOUR_CLIENT_ID',
});

// Guest
SubspaceSDK.init({
  container: '#rewards-store',
  clientId: 'YOUR_CLIENT_ID',
});

The string literals "null" and "undefined" are also treated as guest, so auth: String(maybeToken) is safe even when maybeToken is null or undefined.

initialRoute — pin the SDK to one section

Omit initialRoute for the full rewards store (default). Set it to bind a button on your site to a single section — the user lands there with a trimmed header and stays within that section.

| Value | Opens | |---|---| | 'transactions' | Order history | | 'chats' | Chat inbox | | 'subscriptions' | Shared subscriptions | | 'quick-payments' | Bill payments (BBPS) | | 'giftcards' | Gift-card store (BBPS + subscription tiles auto-hidden) |

SubspaceSDK.init({
  container: '#my-transactions',
  auth: TOKEN,
  clientId: CID,
  initialRoute: 'transactions',
});

productId — deep-link to a specific item

Pair initialRoute with productId to open the SDK directly on a specific gift-card brand or subscription plan, skipping the section's hub list:

// Open straight on the Amazon gift-card page
SubspaceSDK.init({
  container: '#rewards-store',
  auth: TOKEN,
  clientId: CID,
  initialRoute: 'giftcards',
  productId: 'c098ee4a-b886-47c5-8b6f-093f30211163',  // brand UUID
});

// Open straight on the Netflix Premium subscription plan
SubspaceSDK.init({
  container: '#subs-button',
  auth: TOKEN,
  clientId: CID,
  initialRoute: 'subscriptions',
  productId: 'b2e557ab-4154-4f5a-8a95-018c92a0d779',  // plan UUID
});

To find the right productId: open the SDK in a browser, navigate to the brand or plan, and copy the UUID from the URL (https://sdk.pocoai.store/product/<id> for gift cards, /subscriptions/<id> for plans).

productId is ignored for transactions, chats, and quick-payments.

Browser permissions

The SDK's delivery-address picker uses navigator.geolocation. The iframe is created with allow="clipboard-write; geolocation" automatically — no partner code change needed in the common case.

If your site sets a strict Permissions-Policy header, you must relax the geolocation directive so the SDK's origin is allowed. Example:

Permissions-Policy: geolocation=(self "https://sdk.pocoai.store")

Partners who omit that header entirely are unaffected. Users can always type or search for an address manually if they deny the browser prompt — "Detect my location" is the only feature that needs the permission.

Framework integration

init() touches document and window, so call it after your component mounts (not at module top-level). Importing the package is SSR-safe — only init() is browser-only.

React / Next.js

In Next.js App Router, the file must be a client component ('use client').

'use client';

import { useEffect, useRef } from 'react';
import { SubspaceSDK } from 'pocoaiwebsdk';

export function RewardsStore() {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!ref.current) return;
    SubspaceSDK.init({
      container: ref.current,
      auth: process.env.NEXT_PUBLIC_AUTH_TOKEN,
      clientId: process.env.NEXT_PUBLIC_CLIENT_ID!,
      onPurchase: (p) => console.log('purchase', p),
    });
    return () => SubspaceSDK.destroy();
  }, []);

  return <div ref={ref} style={{ width: '100%', height: 720 }} />;
}

The same pattern works in Vite/CRA React — drop the 'use client' directive.

Vue (Nuxt 3)

<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue';
import { SubspaceSDK } from 'pocoaiwebsdk';

const container = ref<HTMLElement | null>(null);

onMounted(() => {
  if (!container.value) return;
  SubspaceSDK.init({
    container: container.value,
    auth: AUTH_TOKEN,
    clientId: CLIENT_ID,
  });
});

onBeforeUnmount(() => SubspaceSDK.destroy());
</script>

<template>
  <div ref="container" style="width: 100%; height: 720px" />
</template>

In Nuxt with SSR enabled, wrap the component in <ClientOnly> at the call site.

SvelteKit

<script lang="ts">
  import { onMount } from 'svelte';
  import { SubspaceSDK } from 'pocoaiwebsdk';

  let container: HTMLDivElement;

  onMount(() => {
    SubspaceSDK.init({ container, auth: AUTH, clientId: CID });
    return () => SubspaceSDK.destroy();
  });
</script>

<div bind:this={container} style="width: 100%; height: 720px"></div>

Theme override

Theme is normally configured per client at provisioning time, so most embeds work without passing theme at all. Pass it only when you need to override the per-client defaults at runtime (dark-mode toggles, multi-tenant white-labelling, etc.). Whatever you pass is merged on top of the per-client config, so you only need to specify the keys you want to change.

| Key | Type | Notes | |---|---|---| | primaryColor | string | Buttons, active states | | accentColor | string | Discounts, savings highlights | | backgroundColor | string | Page background | | surfaceColor | string | Card backgrounds | | textColor | string | Primary text | | textSecondaryColor | string | Secondary text | | fontFamily | string | CSS font-family value | | borderRadius | 'sharp' \| 'rounded' \| 'pill' | Corner radius scale | | mode | 'light' \| 'dark' | Color mode | | logoUrl | string | Header logo image URL | | storeTitle | string | Header title text | | ctaText | string | Primary CTA copy | | hideSections | string[] | Hide header surfaces — e.g. ['chat', 'orders', 'location'] |

SubspaceSDK.init({
  container: '#rewards-store',
  auth: TOKEN,
  clientId: CID,
  theme: { mode: 'dark', primaryColor: '#FF6B00' },
});

Error codes

onError payload codes emitted by this wrapper or by the SDK:

| Code | Cause | |---|---| | INVALID_CLIENT_ID | clientId was empty or missing on init(). | | AUTH_REQUIRED | The provided JWT expired or was revoked mid-session. Re-issue a fresh token and call init() again. |

TypeScript

Exported types: SubspaceSDKConfig, SDKSection, SDKTheme, PurchasePayload, SubscriptionJoinedPayload, ErrorPayload. Import from pocoaiwebsdk directly.

API

  • SubspaceSDK.init(config) — mount the iframe.
  • SubspaceSDK.destroy() — remove the iframe and clean up listeners.
  • SubspaceSDK.navigate(page) — advanced runtime navigation. Most partners use initialRoute instead and never call this.

Troubleshooting

| Symptom | Diagnosis | |---|---| | Build fails with document is not defined (Next.js / Nuxt / SvelteKit) | init() was called at module top-level. Move it inside useEffect / onMounted / onMount — see Framework integration. | | [SubspaceSDK] Container not found in console | The CSS selector resolves to nothing at the time init() runs. Pass an HTMLElement (via ref) instead of a selector — guarantees the element exists. | | Iframe is blank / shows a loading spinner forever | Most often an expired or malformed JWT. Decode it at jwt.io and check exp. Also confirm clientId matches a real partner row. | | "Detect my location" silently fails on a strict site | The site has a Permissions-Policy header that blocks geolocation. Relax it — see Browser permissions. | | UPI button does nothing on desktop | Expected. UPI is mobile-only; desktop browsers won't resolve upi:// schemes. The flow works on mobile devices with a UPI app installed. | | Theme override not applying after init() | The wrapper applies theme once, on SUBSPACE_READY. To change theme after that, call destroy() then init() again with the new theme. | | AUTH_REQUIRED fires partway through a session | The JWT expired or was revoked. Re-issue a fresh token and call init() again with the new value (init auto-destroys the previous instance). |