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

@katla.app/sdk

v0.4.3

Published

TypeScript SDK for building custom cookie consent flows with Katla.

Downloads

723

Readme

@katla.app/sdk

TypeScript SDK for building custom cookie consent flows with Katla.

Get started:

Install

npm install @katla.app/sdk

Requirements:

  • Node.js 24+
  • React 18+ or 19+ (only for React/Next integrations)

Basic usage

import { createKatlaClient } from '@katla.app/sdk';

const client = createKatlaClient({
  siteId: 'your-site-id',
  // baseUrl: 'https://dist.katla.app', // optional override
});

const cookies = await client.getCookies();
const manifest = await client.getManifest();

const unsubscribe = client.onConsentChange((consent) => {
  console.log('Updated consent:', consent);
});

await client.injectGuard();

unsubscribe();

React usage

import {
  KatlaProvider,
  useKatlaCookies,
} from '@katla.app/sdk/react';

function CookieList() {
  const { cookies, loading, error } = useKatlaCookies();

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Failed: {error.message}</p>;
  if (!cookies) return null;

  return <pre>{JSON.stringify(cookies.cookies, null, 2)}</pre>;
}

export function App() {
  return (
    <KatlaProvider siteId="your-site-id">
      <CookieList />
    </KatlaProvider>
  );
}

KatlaProvider includes KatlaGuard and ConsentBridge automatically. Individual components are still exported for advanced use cases where you need full control.

Consent UI components

The SDK ships ready-to-use <CookieBanner> and <CookieCatalog> components plus a useConsentManager hook. All components are unstyled — they render semantic HTML with stable katla-* class names so you can apply your own CSS.

Quick start

Drop in a banner and catalog with zero configuration:

import {
  KatlaProvider,
  CookieBanner,
  CookieCatalog,
  useKatlaCookies,
} from '@katla.app/sdk/react';

function CookiePage() {
  const { cookies, loading, error } = useKatlaCookies();

  return (
    <>
      <CookieCatalog data={cookies} loading={loading} error={error} />
      <CookieBanner />
    </>
  );
}

export function App() {
  return (
    <KatlaProvider siteId="your-site-id">
      <CookiePage />
    </KatlaProvider>
  );
}

CookieBanner

Renders a consent banner with accept/reject/customize controls.

<CookieBanner
  title="We use cookies"
  description="Choose which categories you'd like to allow."
  labels={{
    acceptAll: 'Accept all',
    rejectAll: 'Reject non-essential',
    saveSelection: 'Save selection',
    functionalBadge: 'Functional always on',
    privacyTrigger: 'Privacy preferences',
  }}
  className="my-banner"
/>

Props:

| Prop | Type | Default | |------|------|---------| | title | string | "Cookie preferences" | | description | ReactNode | Brief consent copy | | labels | object | See above defaults | | className | string | — | | children | (state: ConsentManagerState) => ReactNode | — |

When children is provided as a render prop, the default UI is replaced entirely and you receive the full ConsentManagerState:

<CookieBanner>
  {({ acceptAll, rejectAll, open, setOpen, selected, toggleCategory, saveSelection }) => (
    <div className="my-custom-banner">
      <button onClick={acceptAll}>OK</button>
      <button onClick={rejectAll}>No thanks</button>
      <button onClick={() => setOpen(!open)}>Customize</button>
      {/* ... */}
    </div>
  )}
</CookieBanner>

CSS class names (for styling the default UI):

  • katla-banner — root <aside>
  • katla-banner-copy — title + description wrapper
  • katla-banner-controls — button area in preferences panel
  • katla-toggle-grid — category toggle container
  • katla-toggle-card — individual category toggle
  • katla-pill — "always on" badge
  • katla-button-row — row of action buttons
  • katla-button-accept, katla-button-reject, katla-button-save, katla-button-customize — individual buttons
  • katla-privacy-trigger — re-open button shown after consent

CookieCatalog

Displays cookies grouped by category.

import { useKatlaCookies, CookieCatalog } from '@katla.app/sdk/react';

function CookieList() {
  const { cookies, loading, error } = useKatlaCookies();
  return <CookieCatalog data={cookies} loading={loading} error={error} />;
}

Props:

| Prop | Type | Default | |------|------|---------| | data | CookieData \| null | — | | loading | boolean | false | | error | Error \| string \| null | — | | maxPerCategory | number | 5 | | className | string | — | | emptyMessage | string | "No cookies found." | | renderCategory | (category, cookies) => ReactNode | — | | renderCookie | (cookie, category) => ReactNode | — |

Customize per-cookie rendering while keeping the grid layout:

<CookieCatalog
  data={cookies}
  loading={loading}
  error={error}
  maxPerCategory={10}
  renderCookie={(cookie) => (
    <div>
      <code>{cookie.name}</code> — {cookie.domain}
    </div>
  )}
/>

CSS class names:

  • katla-catalog-grid — root grid container
  • katla-catalog-card — category card
  • katla-catalog-card-header — card header with category name + count
  • katla-empty-card — shown when no cookies exist

useConsentManager

Headless hook for building fully custom consent UIs. Both CookieBanner and CookieCatalog are built on top of this.

import { useConsentManager } from '@katla.app/sdk/react';

function MyConsentUI() {
  const {
    ready,            // true once window.KatlaConsent is available
    hasDecision,      // true after user has accepted/rejected
    open,             // preferences panel visibility
    setOpen,
    selected,         // currently toggled-on categories
    availableCategories, // categories with cookies (excludes functional/unknown)
    toggleCategory,
    acceptAll,        // calls KatlaConsent.acceptAll() + closes panel
    rejectAll,        // calls KatlaConsent.rejectAll() + closes panel
    saveSelection,    // calls KatlaConsent.acceptCategories() + closes panel
    cookies,          // { data, loading, error }
  } = useConsentManager();

  if (!ready) return null;

  return (
    <div>
      {!hasDecision && (
        <div>
          <p>We use cookies.</p>
          <button onClick={acceptAll}>Accept all</button>
          <button onClick={rejectAll}>Reject all</button>
        </div>
      )}

      {open && (
        <div>
          {availableCategories.map((cat) => (
            <label key={cat}>
              <input
                type="checkbox"
                checked={selected.includes(cat)}
                onChange={() => toggleCategory(cat)}
              />
              {cat}
            </label>
          ))}
          <button onClick={saveSelection}>Save</button>
        </div>
      )}
    </div>
  );
}

The ManageableCategory type ('personalization' | 'analytics' | 'marketing' | 'security') is also exported for type-safe category handling.

Next.js usage

Client provider:

import { KatlaNextProvider } from '@katla.app/sdk/next';

export default function Providers({ children }: { children: React.ReactNode }) {
  return <KatlaNextProvider siteId="your-site-id">{children}</KatlaNextProvider>;
}

Server-side cached fetch:

import { getCachedCookies } from '@katla.app/sdk/next/server';

export default async function Page() {
  const data = await getCachedCookies({ siteId: 'your-site-id' });
  return <pre>{JSON.stringify(data.cookies, null, 2)}</pre>;
}

All consent UI components (CookieBanner, CookieCatalog, useConsentManager) are available from @katla.app/sdk/next and work identically to the React versions:

"use client";

import {
  CookieBanner,
  CookieCatalog,
  useKatlaCookies,
} from '@katla.app/sdk/next';

export default function ConsentPage() {
  const { cookies, loading, error } = useKatlaCookies();

  return (
    <>
      <h1>Cookie information</h1>
      <CookieCatalog data={cookies} loading={loading} error={error} />
      <CookieBanner />
    </>
  );
}

Configuration file

Create a katla.config.mjs (ESM) or katla.config.js (CJS) in your project root to set defaults for katla pull:

// katla.config.mjs
export default {
  siteId: 'your-site-id',
  dir: '.katla',
  // locale: 'en-GB',
  // format: 'full',
};
// katla.config.js (CommonJS)
module.exports = {
  siteId: 'your-site-id',
};

| Option | Type | Default | Description | |--------|------|---------|-------------| | siteId | string | — | Your site's UUID | | dir | string | '.katla' | Output directory for pulled files | | baseUrl | string | 'https://dist.katla.app' | Override the CDN base URL | | locale | string | — | Pull a single locale only (e.g., 'en-GB'). Omit to pull all. | | format | string | 'full' | Policy format: 'full', 'cookie', or 'table' |

CLI flags always override config file values. With a config file, katla pull works without arguments.

Static cookie data (build-time)

CLI:

katla pull [site-id]
# Outputs: .katla/cookies.json, .katla/cookies.*.json, .katla/policy.*.json, .katla/guard.js, .katla/manifest.json

The site-id argument is optional when a config file is present.

Programmatic:

import { fetchStaticAll } from '@katla.app/sdk/static';

const { cookies, policies, guard, manifest } = await fetchStaticAll({
  siteId: 'your-site-id',
});

Use the generated cookies.json as initialCookies and guard.js as guardScript in KatlaProvider/KatlaNextProvider:

// Vite (raw import)
import cookies from './.katla/cookies.json';
import guardScript from './.katla/guard.js?raw';

<KatlaProvider siteId="your-site-id" initialCookies={cookies} guardScript={guardScript}>
// Next.js (server helper)
import { getStaticGuardScript } from '@katla.app/sdk/next/server';

const guardScript = await getStaticGuardScript();

<KatlaNextProvider siteId="your-site-id" initialCookies={cookies} guardScript={guardScript}>

Policies

Fetch auto-generated policy documents in any supported locale:

const client = createKatlaClient({ siteId: 'your-site-id' });

// Fetch combined cookie + privacy policy
const policy = await client.getPolicy({ locale: 'de-DE', format: 'full' });
console.log(policy.policy.markdown);

// Fetch cookie policy only
const cookiePolicy = await client.getPolicy({ format: 'cookie' });

// Fetch cookie tables only
const tables = await client.getPolicy({ format: 'table' });

Formats: full (combined cookie + privacy policy), cookie (cookie policy only), table (cookie tables only).

Supported locales: en-GB, en-US, de-DE, fr-FR, es-ES, it-IT, nl-NL, pt-PT, sv-SE, nb-NO, da-DK, pl-PL, fi-FI.

Build-time fetch (all locales):

import { fetchStaticAll } from '@katla.app/sdk/static';

const { cookies, policies, manifest } = await fetchStaticAll({
  siteId: 'your-site-id',
  // locale: 'de-DE',  // optional, omit to pull all locales
  // format: 'full',   // optional, default
});

CLI (katla pull fetches cookies + policies for all locales by default):

katla pull [site-id]
# Outputs: .katla/cookies.json, .katla/cookies.*.json, .katla/policy.*.json, .katla/guard.js, .katla/manifest.json

katla pull [site-id] --locale de-DE --format full
# Outputs: .katla/cookies.json, .katla/cookies.de-de.json, .katla/policy.de-de.json, .katla/guard.js, .katla/manifest.json

CCPA / GPC support

Check if the visitor's browser has Global Privacy Control enabled and handle CCPA opt-outs:

import { isGPCEnabled } from '@katla.app/sdk';

if (isGPCEnabled()) {
  // Browser has GPC enabled — honor opt-out
  window.KatlaConsent?.optOutOfSale();
}

// Check active regulation
window.KatlaConsent?.getRegulation(); // 'gdpr' or 'ccpa'

Documentation