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

@cueplusplus/id-admin

v0.3.1

Published

CUE++ ID — server-only admin SDK (service-role PostgREST + auth.admin + security-definer RPCs) for the admin console.

Readme

@cueplusplus/id-admin

Server-only admin SDK for CUE++ ID. It wraps a service-role Supabase client and exposes the five management surfaces the admin console needs — invites, users, OAuth clients, the audit log and webhooks — writing admin_audit_log rows for the mutations it performs directly and delegating the rest to security-definer RPCs.

The service-role key bypasses RLS. This package imports server-only, so a bundler will fail the build if it ever reaches a client component.

Install

pnpm add @cueplusplus/id-admin

Usage

import { createCueIdAdmin } from '@cueplusplus/id-admin'

const admin = createCueIdAdmin({
  url: process.env.SUPABASE_URL!,
  serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
})

// Invite-only signup: create returns the RAW token — build the accept link
// yourself; only its sha256 hash is stored.
const { data, error } = await admin.invites.create({ email: '[email protected]', role: 'member' })

// `data.token` is a BEARER CREDENTIAL: it creates an account at the chosen role.
// Hand it to the mailer, never to a log — a log line lands in aggregation.
// NOTE: `data` and `error` can BOTH be set. If the invite committed but its
// audit row did not, you still get the token (it exists nowhere else) plus the
// error to raise. Check `error`; do not infer failure from `data === null`.
if (data) {
  await mailer.sendInvite(data.id, `https://id.cueplusplus.com/accept?token=${data.token}`)
}
if (error) reportToOncall(error)

// `token` is a NON-ENUMERABLE ACCESSOR. `data.token` and `const { token } =
// data` work; every blanket serializer omits it — JSON.stringify, %j,
// console.log, console.log('%o', …), Object.keys/entries, spread,
// Object.assign, structuredClone — so `logger.error({ result })` cannot put a
// live bearer credential into log aggregation. (`%o` prints `[token]: [Getter]`:
// it reveals the property exists without invoking it.)
// The trade-off: `{ ...data }` does not copy it — read `data.token` directly.

await admin.users.setRole({ userId, role: 'admin', actorId })
await admin.users.revokeSessions({ userId })

// OAuth clients go through Supabase Auth's own admin API — `clientId` is the
// ONLY identifier (there is no separate row id), and `delete` is a soft delete.
const { data: client } = await admin.clients.create({
  name: 'Dashboard',
  redirectUris: ['https://dash.cueplusplus.com/auth/callback'],
  actorId,
})
// `client.clientSecret` is shown ONCE — Supabase keeps only its hash. Like the
// invite token it is a non-enumerable accessor: read it directly, never via a
// spread or a log line. Defaults to `token_endpoint_auth_method =
// client_secret_basic` (spec §7.3), which is @cueplusplus/id's default.

// A PKCE-only PUBLIC client (mobile, CLI, SPA): no secret is minted, and
// `clientSecret: null` is then the SUCCESSFUL outcome. There is no
// `client_type` to pass — the server infers it from the auth method.
await admin.clients.create({
  name: 'CUE++ CLI',
  redirectUris: ['http://127.0.0.1:7777/callback'],
  tokenEndpointAuthMethod: 'none',
  actorId,
})

await admin.clients.update({ clientId: client!.clientId, redirectUris: [...], actorId })

// The ONLY repair path for a leaked or lost secret — nothing can re-show the
// old one. DESTRUCTIVE: the previous secret stops working immediately, so every
// consumer holding it fails token exchange until it is updated.
const { data: rotated } = await admin.clients.regenerateSecret({ clientId: client!.clientId, actorId })
// rotated.clientSecret — again, once, and again a non-enumerable accessor.

await admin.clients.delete({ clientId: client!.clientId, actorId })
// A soft delete, and what that means for ACCESS is deliberate (issue #51):
// once a client is retired, `effective_access` stops resolving grants and
// client-group memberships that point at it, and its introspection credential
// stops verifying — so `/api/access/token` will not mint for it. Both are
// enforced in the derivation, not at this call, so they hold for clients
// deleted before that change and cannot be bypassed by a different code path.
// The rows themselves survive: the grant, the membership and the
// `access_api_clients` row are all still there for history.

// `list()` PAGES and says whether it reached the end. `rows` is a prefix when
// `complete` is false — GoTrue's list endpoint pages and auth-js's cursor
// cannot be trusted past page 9, so a caller must not render `rows` as
// "every client" without checking.
const { data: page } = await admin.clients.list()
page!.rows // ClientRow[]   page!.complete // boolean

// `audit.list()` is a SCRIPT helper, like `users.list()` — one page, newest
// first, `complete` false when the page filled, `nextBefore` to walk further.
// A console reads public.admin_audit_log directly; see the type docs for why.
const { data: page } = await admin.audit.list({ action: 'invite.create', limit: 50 })
const { rows, complete, nextBefore } = page ?? { rows: [], complete: false, nextBefore: null }

Webhooks

// Register an endpoint. The signing secret is returned ONCE and exists nowhere
// else afterwards — it lives in a table no role holds any privilege on, and
// Postgres (not this process) computes every HMAC. Rotation is the only repair.
const { data: hook } = await admin.webhooks.create({
  url: 'https://example.com/hooks/cue-id',
  eventNames: ['login', 'invite.accepted', 'invite.declined'],
  actorId,
})
hook!.signingSecret // read DIRECTLY — a non-enumerable accessor, like the invite token

// Every mutation writes its admin_audit_log row inside the SAME transaction as
// the mutation (the RPC does it), so unlike invites/clients there is no state
// where the change committed and the audit row did not.
await admin.webhooks.setEnabled({ id: hook!.id, enabled: false, reason: 'consumer migration', actorId })
await admin.webhooks.rotateSecret({ id: hook!.id, actorId }) // DESTRUCTIVE, no overlap window
await admin.webhooks.delete({ id: hook!.id, actorId })       // soft: history survives, the key does not

// The delivery log. `complete` is false when the page filled — never render
// `rows` as "everything", and never render a FAILED read as an empty log.
const { data: log, error } = await admin.webhooks.listDeliveries({ status: 'dead', limit: 50 })
if (error) throw error // `data: null` here means the read failed, not "nothing was sent"

await admin.webhooks.replayDelivery({ id: log!.rows[0]!.id, actorId })

Delivery is at-least-once. Consumers must de-duplicate on the Cue-Event-Id header (also id in the body), verify Cue-Signature in constant time, and reject a timestamp outside a few minutes. The full consumer contract is in docs/runbooks/webhooks.md.

dispatchWebhooks() is the delivery loop itself — claim, POST, settle — with newClient, fetchImpl and now injected so it can be driven in a test. It never sleeps on a consumer's Retry-After, never follows a redirect, bounds each attempt with an AbortController and bounds the whole invocation with a wall-clock budget.

users.list() is the same kind of script helper, and it takes no search parameter — GoTrue has no server-side user search, so any query here could only ever filter the page it happened to fetch. It was removed rather than documented, so the wrong answer is unreachable. Build a directory from public.profiles instead (exact count, server-side ilike, stable ordering).

Every call returns { data, error } — error is an AdminError ({ message, code?, status? }); nothing throws.

Timeouts

Every client carries a total request deadline shared by all of its calls — CUE_ID_ADMIN_TIMEOUT_MS, default 5000ms — and postgrest-js's 503 retry ladder is off. Both are deliberate: postgrest-js honours Retry-After with no upper bound, so a single 503 Retry-After: 120 would park each of three retries for two minutes, and a deadline cannot interrupt its backoff sleep. Values at or above the 7s retry ladder are refused.

License

MIT — see LICENSE.