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

@arsite/sdk

v0.2.1

Published

Build applications for ArSite — an intelligence layer for Canada, built in Canada

Readme

@arsite/sdk

TypeScript SDK to build applications for ArSite — an intelligence layer for Canada, built in Canada.

Your app hosts its own backend + UI. ArSite renders the UI in a sandboxed iframe inside its platform shell and proxies every API call through its gateway — auth, entitlement, per-cycle metering, and HMAC signing all happen on the platform side. Your job is to render React in the iframe and to verify HMAC-signed requests on your backend.

Install

npm install @arsite/sdk

react is an optional peer dependency — only required if you use @arsite/sdk/iframe/react.

Quick start with the scaffolder

npx create-arsite-app \
  --id=my-app --name="My App" \
  --framework=next-iframe --dir=./my-app
cd my-app
npm install
npm run dev

Then in a separate terminal:

npx @arsite/cli dev      # local gateway proxy on :7400 with fake auth + HMAC
npx @arsite/cli validate # schema + frame ping + healthcheck ping

API surface

@arsite/sdk/types — manifest

import { defineHostedApp } from '@arsite/sdk/types';

export default defineHostedApp({
  id: 'my-module',
  name: 'My Module',
  version: '0.1.0',
  description: '...',
  icon: 'database',
  category: 'intelligence',
  permissions: ['my-module:read', 'my-module:api'],
  routes: [{ path: '/', label: 'Home', icon: 'home' }],
  dependencies: [],
  integration: 'hosted',
  hosted: {
    frame: { url: 'https://my-module.example.com/embed' },
    upstream: { baseUrl: 'https://my-module-api.example.com', auth: { type: 'none' } },
    signing: { secretRef: 'my-module.signing_secret' },
    healthcheck: { path: '/health' },
    routes: [
      { method: 'GET', pattern: '/v1/search', billingUnits: 1 },
      { method: 'GET', pattern: '/v1/items/:id', billingUnits: 0.5 },
    ],
  },
});

@arsite/sdk/iframe — iframe runtime

import { createArsiteClient } from '@arsite/sdk/iframe';

const arsite = await createArsiteClient();

arsite.user; // { id, email, name, role, locale }
arsite.tenant; // { id, slug, name, planTier }
arsite.app; // { id, version, subscriptionTier, quotaRemaining }
arsite.theme; // design-token map injected by parent

const res = await arsite.api('/v1/search?q=foo');
// → GET https://arsite.ca/api/apps/my-module/v1/search?q=foo
//   with short-lived Bearer JWT; ArSite signs the upstream call with HMAC,
//   meters the route's billingUnits, writes a usage_event row.

arsite.resize.auto(); // auto-resize iframe based on body height
arsite.toast.success('Saved'); // surface a toast in the parent ArSite shell
arsite.events.on('tenantChange', () => location.reload());

@arsite/sdk/iframe/react — React adapters

import { ArsiteProvider, useArsiteUser, useArsiteApi } from '@arsite/sdk/iframe/react';

export function App() {
  return (
    <ArsiteProvider>
      <Greeting />
    </ArsiteProvider>
  );
}

function Greeting() {
  const user = useArsiteUser();
  return <p>Hi {user?.name}</p>;
}

Other hooks: useArsite(), useArsiteTenant(), useArsiteApp(), useArsiteTheme(), useArsiteApi().

@arsite/sdk/server — verify gateway-signed requests on your backend

import { verifyArsiteRequest } from '@arsite/sdk/server';

export async function GET(req: Request): Promise<Response> {
  const body = await req.text();
  const url = new URL(req.url);
  const verified = await verifyArsiteRequest(
    {
      method: 'GET',
      path: url.pathname + url.search,
      body,
      headers: Object.fromEntries(req.headers),
    },
    { signingSecret: process.env.ARSITE_SIGNING_SECRET! },
  );
  // verified.user.id, verified.tenant.id, verified.appId are now trustworthy
  return Response.json({ greeting: `hello ${verified.user.id}` });
}

Reference impl for non-TypeScript backends

The canonical-string format is small and language-agnostic. See DataFun's service/datafun_api/arsite_auth.py (Python + FastAPI, ~50 lines) as the reference implementation.

Manifest variants

The manifest is a discriminated union on integration. Pick the variant that matches how your app surfaces in ArSite:

| Variant | Helper | UI | When | | --------------------- | ------------------ | ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | hosted (frame) | defineHostedApp | iframed UI (hosted.ui: 'frame', frame URL required) | You host a backend + a UI you want embedded in ArSite. | | hosted (api-only) | defineApiOnlyApp | none (hosted.ui: 'api-only', no frame) | You only expose a metered REST API. Declare at least one non-frame tab (docs/api/usage). Reached via the gateway and GET/POST /api/v1/apps/{id}/{path}. | | listed | defineListedApp | external link | Your product lives on your own site. Optional billing.mode: 'rest-proxy' still meters an API through ArSite. |

defineHostedApp stays backward compatible — hosted.ui defaults to 'frame', route kind defaults to 'frame', and the composition fields default off. Use appManifestSchema to parse a manifest whose variant you do not know ahead of time.

Multi-tab apps

routes[].kind ('frame' | 'docs' | 'api' | 'usage', default 'frame') selects what the shell renders for each tab. docs/api/usage are platform-rendered and available to every variant, so API-only and listed apps still present docs and usage.

Cross-app composition

Declare a dependency on another published app's composable routes:

exposesPublicApi: true,                                    // expose your own routes
appDependencies: [                                         // depend on another app
  { appId: 'other-app', routes: ['/v1/data'], reason: 'fetch base data' },
],
hosted: {
  routes: [{ method: 'GET', pattern: '/v1/report', billingUnits: 1, composable: true }],
}

With the user's consent, your backend mints a delegated token at POST /api/apps/{yourApp}/delegate/{upstreamApp}/token, then calls /api/apps/{upstreamApp}/{path} with it. Usage is billed to the user's subscription to the upstream app.

@arsite/sdk/theme — native look

Match the ArSite shell without reverse-engineering the design tokens:

// tailwind.config.ts
import { arsiteTailwindPreset } from '@arsite/sdk/theme/tailwind';
export default { presets: [arsiteTailwindPreset], content: ['./src/**/*.{ts,tsx}'] };
import { createArsiteClient } from '@arsite/sdk/iframe';
const client = await createArsiteClient();
client.applyTheme(); // writes the host theme to :root as --arsite-* CSS vars
client.events.on('themeChange', () => client.applyTheme()); // track live theme

Also exported: arsiteTokens (the palette/scale constants), applyTheme, and tokenized React primitives (Button, Card, Input, Callout, Badge, Table) at @arsite/sdk/theme/react.

Examples

Runnable manifests for every variant live in examples/: hosted-frame-next, api-only-express, listed-rest-proxy, composed-app, native-themed.

License

MIT