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

@rexium-ai/app-sdk

v0.2.2

Published

Rexium App SDK — the escape hatch for genuinely-custom app UI. A typed client over OAuth 2.1 + PKCE → the Rexium MCP surface, with action methods GENERATED from the Spine ontology (writer=reader). Build any frontend, deploy it to {app}.rexium.app via the

Readme

@rexium-ai/app-sdk

The escape hatch for genuinely-custom app UI. When the declarative app runtime (config-driven dashboards/tools) isn't enough and you want to build any frontend, this SDK gives you a typed client over Rexium's OAuth 2.1 + PKCE → MCP surface. Build with React/Vue/Svelte/anything, then deploy the static bundle to {app}.rexium.app via the existing pipeline.

The action methods are generated from the Spine ontology — the SDK's typed surface is the ontology, kept in sync by codegen. (This is an ontology client, not a Palantir OSDK — it's our own thing.)

Install

npm i @rexium-ai/app-sdk

Register a PUBLIC (PKCE) OAuth app at build.rexium.ai/apps to get a clientId, with redirect https://{your-slug}.rexium.app/ (or your dev URL).

Use

import { createClient } from "@rexium-ai/app-sdk";

const rx = createClient({
  clientId: "rxa_…",
  // scopes default to the full surface; narrow to least privilege:
  scopes: ["commerce:read-orders", "commerce:write-products"],
  orgId: "my-org-id",
});

// On app load: resumes a session, finishes the PKCE redirect, or starts one.
const session = await rx.connect();
if (!session) {
  // We navigated to the consent screen; this page will reload with ?code=.
} else {
  // Typed reads + writes over the ontology:
  const stats = await rx.actions.getOrderStats({ days: 14 });
  await rx.actions.adjustPrice({ productId: "p_123", newPrice: 1990 });

  // Raw MCP escape hatch for anything not in the typed surface:
  const data = await rx.call("GetStudioAppData", { appId: "a_1" });

  // Inspect what your token can actually do:
  console.log(await rx.listTools());
}

rx.catalog lists every public action with its vertical / readonly flag / required scopes — handy for building scope pickers or debugging grants.

Deploy to {app}.rexium.app

The SDK is just the client — hosting reuses the existing build pipeline:

npm run build           # your app → dist/
# deploy dist/ via deployBuildApp (build.rexium.ai/apps "Deploy")

No build worker of ours runs your code; we serve your prebuilt static bundle from R2, exactly like the reference Surfaces.

Regenerating the typed surface

src/generated.ts is produced from the live ActionDefinition catalog (the agentInvokable subset). Re-run when actions change:

npm run build                                  # at the repo root (builds deps)
node packages/app-sdk/scripts/codegen.mjs

Server integrations (v0.2)

The browser client keeps a token in sessionStorage — fine for a dashboard, useless for a backend that must keep sending for months. For that, use the server profile: confidential client, refresh with rotation, single-flight locking, and the error handling you would otherwise discover in production.

import { createServerClient, buildIdempotencyKey } from "@rexium-ai/app-sdk";

const rexium = createServerClient({
  clientId: process.env.REXIUM_CLIENT_ID!,
  clientSecret: process.env.REXIUM_CLIENT_SECRET!,
  orgId: "your-org",
  redirectUri: "https://your.app/auth/rexium/callback/",
  store,            // 3 methods — see below
});

// 1. connect (admin clicks a button, once)
const url = await rexium.authorizeUrl(["comms:send-whatsapp"]);
// …redirect the admin there; on the callback:
await rexium.exchangeCode(code, state);

// 2. use it forever
await rexium.call("SendWhatsApp", {
  templateKey: "job-assigned",
  kind: "transactional",
  recipientPhone: "351912345678",
  mode: "template",
  templateName: "not_install",
  languageCode: "pt_PT",
  bodyVariables: JSON.stringify(["Ana", "12/03"]),
}, { idempotencyKey: buildIdempotencyKey("job", jobId, installerId) });

The store (the only thing you write)

const store: AsyncTokenStore = {
  load:  async () => (await db.doc("system/rexium").get()).data() ?? null,
  save:  async (c) => { await db.doc("system/rexium").set(c, { merge: true }); },
  clear: async () => { await db.doc("system/rexium").delete(); },
  // Optional but STRONGLY recommended with more than one instance: refresh
  // tokens rotate, so two concurrent refreshes invalidate each other.
  withLock: async (fn) => db.runTransaction(async () => fn()),
};

Three things that bite everyone (handled for you)

  1. Credentials go in the request BODY. Rexium's token endpoint ignores Authorization: Basic, even though discovery advertises it.
  2. Handler errors arrive as HTTP 200 with result.isError and the message in content[0].text. Checking only res.ok/body.error records every rejected call as a success.
  3. Refresh tokens rotate. Persist the new one or the connection dies — and never let two instances refresh at once.