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

@xenition/sdk

v0.1.2

Published

Official Node.js SDK for Xenition — auth, data, storage, chatbot, payments, push, email, AI, and more. Works in Node 18+ and Cloudflare Workers (with nodejs_compat).

Readme

@xenition/sdk

Official Node.js SDK for Xenition. Gives apps created via xenition's seller dashboard an auth / query / storage / chatbot / payments / push / email / AI / search surface over HTTPS.

Install

# Development builds (hits api-dev.xenition.com)
npm install "github:xenition/node-sdk#develop"

# Production builds (hits api.xenition.com)
npm install "github:xenition/node-sdk"

npm publishing will follow in 1.0.0. For now, github: install is the only supported path — matches the xenition deploy pipeline's expectations.

Quick start

import { XenitionClient } from '@xenition/sdk';

const client = new XenitionClient(process.env.XENITION_API_KEY!);

// Sign up an end user
const { user, token } = await client.auth.register({
  email: '[email protected]',
  password: 'hunter2',
  name: 'Jane Doe',
});

// Sign in
const session = await client.auth.login({
  email: '[email protected]',
  password: 'hunter2',
});

// Fetch the current user (requires session token)
client.setHeader('Authorization', `Bearer ${session.token}`);
const me = await client.auth.me();

Content modules (v0)

The SDK ships a small module framework: content-domain features (CMS pages, forms, reviews) implemented client-side on top of the existing /app-platform/query and /app-platform/raw endpoints. Each module is just a migration set plus a typed client — no new server surface.

// service key (backend / deploy step) — runs the module's migrations
// through the ledger, idempotent, then unlocks the accessor:
await client.modules.enable('cms');

const about = await client.modules.cms.createPage({
  title: 'About Us',            // slug auto-generated: 'about-us'
  body_html: '<h1>Hi</h1>',
  published: true,
});
const page = await client.modules.cms.getPageBySlug('about-us');

// anon key (browser) — tables were migrated by the backend already;
// mark the module usable without running DDL:
client.modules.use('forms');
await client.modules.forms.submit('contact', {
  name: 'Ada',
  email: '[email protected]',     // validated against the stored field schema
});

Modules

| Module | Tables | Client surface | |-----------|---------------------------------------|----------------| | cms | cms__pages, cms__collections, cms__items | pages CRUD + getPageBySlug; ensureCollection/getCollection; items CRUD + listItems(collection, {published, orderBy}) + getItemBySlug. Slugs auto-kebab from titles, deduped -2, -3, … | | forms | forms__forms, forms__submissions | ensureForm(key, fields) (declarative field schema); submit(key, data) — validates required/type/email/maxLength/select client-side, works with the anon key (schema read + one insert); listSubmissions/setStatus are service-key back-office calls | | reviews | reviews__reviews | submit (rating rounded + clamped 1–5, always status pending); listApproved(target); aggregate(target){count, average} computed in the DB; moderate(id, status) service-key |

Conventions

  • Every module's tables are prefixed <module>__ — they live in your app's own database next to your tables; query them directly whenever the typed client is too narrow.

  • Schema is managed by client.migrations, a content-addressed migration ledger: apply([{id, sql}]) records each applied id with the sha-256 of its SQL in _sdk_migrations. Re-apply is a no-op; editing an applied migration's SQL throws (write a new migration instead — never silently re-run). Migrations use raw SQL, so they are service-key only. You can use the ledger for your own app tables too:

    await client.migrations.apply([
      { id: 'app/0001_create_widgets', sql: 'CREATE TABLE IF NOT EXISTS widgets (...)' },
    ]);
  • Custom modules: defineModule({name, migrations, factory}) gives your own domain the same shape (migrations + typed client over ctx.query/ctx.raw).

v0 scope — read this

Validation runs in the SDK, so it protects well-behaved apps from bad data — it does not protect the database from clients that bypass the SDK. Server-side hardening (per-table policies, module-aware endpoints) comes later per the platform master plan. For the same reason, money-path domains (cart, booking, payments) are deliberately NOT v0 client-side modules: they need server-side invariants (stock, double-booking, idempotent charging) that a client-side layer cannot honestly provide. They arrive as server-backed modules in a later phase.

Backend routers (@xenition/sdk/hono)

Prebuilt, mountable Hono routers that turn a generated app's backend into composition instead of hand-written code. They run inside the app's own Cloudflare Worker with the service key the deploy pipeline injects (XENITION_API_KEY + XENITION_API_URL), so the React/Expo frontend talks to its own backend and never holds a platform key — and since the platform bans anon-key writes, these routers are the sanctioned write path for forms and reviews.

import { Hono } from 'hono';
import { createXenitionApi } from '@xenition/sdk/hono';

const app = new Hono();
app.route('/api', createXenitionApi()); // /api/cms, /api/forms, /api/reviews
export default app;

Routes

| Method | Path | Behavior | |--------|------|----------| | GET | /cms/pages/:slug | Published page (404 for drafts/missing) | | GET | /cms/collections/:key/items | Items; ?published=1&orderBy=&direction=&limit=&offset= (published-only by default, published=all opts out) | | GET | /cms/collections/:key/items/:slug | Published item | | GET | /forms/:key | The form's field schema (for rendering) | | POST | /forms/:key/submissions | Body = the data object → SDK-validated insert; 201 {id} or 400 with the aggregated validation message | | GET | /reviews/:targetType/:targetId | {reviews, aggregate: {count, average}} (approved only) in one payload | | POST | /reviews/:targetType/:targetId | {authorName, rating, title?, body?}201 {id, status: 'pending'} (always lands pending) |

OptionscreateXenitionApi({ modules?, cors?, client?, rateLimit? }): modules picks which routers to mount (default all three; individual cmsRouter() / formsRouter() / reviewsRouter() are also exported for selective mounting), cors is true (permissive, default), an origin allowlist array, or false, client overrides the env-built XenitionClient, and rateLimit is submissions-per-minute-per-IP for the write routes (default 10, false disables — best-effort: the token bucket is per Workers isolate, so it dampens abuse rather than enforcing a hard quota).

One stable response shape. The two platform runtimes disagree on row casing (the gateway camelCases, the engine returns snake_case verbatim); every row leaving these routers is normalized to camelCase (body_htmlbodyHtml). jsonb payloads (data, seo, meta) keep their inner keys untouched — that casing is your app's contract.

Errors map to proper HTTP statuses (400 validation, 404 missing, 429 rate limited, 502/504 upstream) and never leak keys or upstream URLs. hono is an optional peer dependency — the SDK core never imports it, and the ./hono subpath is Worker/Node-only (excluded from the browser build). Routers only ever call modules.use() — never enable()/DDL at request time; migrations belong in the deploy step.

Status

Phase 1: client.auth.* (register, login, logout, me, OAuth, password reset, email verification, teams).

Phases 2–12 add client.query.*, client.storage.*, client.email.*, client.push.*, client.ai.*, client.chatbot.*, client.search.*, client.vector.*, client.payment.*, client.realtime.*, client.videoConferencing.*. See the xenition repo's APP-SDK-IMPLEMENTATION.md for the roadmap.

Development

Source of truth lives in the private repo xenition/node-sdk-private. The public xenition/node-sdk repo is synced by CI on every push to develop or main. The main sync runs scripts/patch-urls-for-public.sh to rewrite the base URL to api.xenition.com.

npm install
npm run build
npm test

License

MIT © Xenition