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

@anchrd/gate-sdk

v0.13.0

Published

The typed client and CLI for **gate** — login and permissions as a finished product. The only package a customer edge installs.

Readme

@anchrd/gate-sdk

The typed client and CLI for gate — login and permissions as a finished product. The only package a customer edge installs.

  • authorize(bearer)can(interface, function) — one remote call per request, then local permission checks.
  • gate CLI — register your service and generate typed code.
  • Runtime-neutral — standard fetch only; runs in Cloudflare Workers, Node, Bun, and the browser.

Install

npm i @anchrd/gate-sdk

Quick start

1. Register your service (once, as an admin — the app key lives in GATE_ADMIN_KEY):

export GATE_URL=https://gate.your-customer.dev
export GATE_ADMIN_KEY=gate_ak_…            # admin application key (x-api-key)
gate register dashboard --fn read,export   # → service key is written to .env (GATE_KEY)

This creates a service named dashboard — the unit that owns exactly one key — together with its interface of the same name. Further interfaces use that same key and can be managed in the admin UI or declared by the service itself with gate.interfaces.set().

If .env already carries a GATE_KEY, gate register stops before talking to the gate. The key is handed out exactly once, so creating a second service here would leave one behind whose key nobody ever sees.

2. Generate types for your service:

gate init   # writes gate.gen.ts (deterministic, never edit by hand)

/schema is scoped to the service your key belongs to: gate.gen.ts contains exactly your own interfaces. Another service's handle is not in there — and therefore a compile error at your call site, not a rule that silently never matches.

3. Authorize in your edge (~5 lines):

import { createGateClient } from "@anchrd/gate-sdk";

const gate = createGateClient({
  url: process.env.GATE_URL!,
  serviceKey: process.env.GATE_KEY!,   // from the .env written by `gate register`
});

// per request:
const result = await gate.authorize(userBearer);
if (!result.ok) return new Response(null, { status: result.status }); // 401 / 403 / 5xx
if (!result.can("dashboard", "read")) return new Response(null, { status: 403 });
// … result.identity is the user (id, email)

Client

createGateClient({ url, serviceKey, fetch?, timeoutMs? }) returns a client. Service-key requests time out after 10 seconds by default; timeoutMs overrides that limit.

| | | |---|---| | authorize(bearer) | One call to /api/v1/authorization. The response is validated. An invalid or expired bearer is a structured result ({ ok: false, status, problem }), not an exception — the edge can tell 401 from 500. | | result.can(handle, fn) | Local, no further network call (rules[handle]?.includes(fn)). | | result.identity · result.rules | Who the user is · their flattened permission set. | | gate.interfaces.list() | List this service's own interfaces. | | gate.interfaces.set(handle, functions) | Idempotently create or replace one own interface. This never grants a user access. Gate's internal interfaces cannot be managed this way. | | gate.interfaces.remove(handle) | Remove one own interface and its grants. |

The gate.interfaces methods throw GateInterfaceError ({ status, problem }) on errors, including 401/403 responses and 502 when gate breaks the response contract. Unlike authorize, they do not return a structured failure result.

After gate init, can is typed: can("dashboard", "read") — an unknown interface or function is a compile error, with no string escape hatch.

fetch is injectable (mocking in tests means passing a fetch, not an HTTP framework). The service key never appears in logs, errors, or results.

CLI

| Command | | |---|---| | gate register <name> --fn a,b,c | Create a service plus its interface of the same name (admin). The service key is written to .env exactly once (GATE_KEY) — never to stdout. <name> is a lowercase slug (a-z, 0-9, -). | | gate init | Generate types from /api/v1/schema — the interfaces of your service (gate.gen.ts). | | gate build | Apply gate.json to the local admin UI and build it. Pure file work — no key, no network. |

Env, per command: register needs GATE_URL + GATE_ADMIN_KEY (app key); init needs GATE_URL + GATE_KEY (service key); build needs none — it never talks to a gate.

Rechte werden nicht mehr über die CLI gesetzt (der frühere gate grant entfiel mit dem Ausbau des grants-Slice, GATE-65/66) — sie gehören der Rolle und werden in der Admin-UI (Rollen-Matrix) geschaltet.

Branding the admin UI — gate.json

Put a gate.json next to your package.json. gate build reads it, writes two files into the local admin UI (@anchrd/gate-ui) and builds it; the output is the static asset directory your gate worker serves (see the api README).

{
  "ui": {
    "theme": "./branding/theme.css",
    "defaultLanguage": "en",
    "languages": { "de": "./i18n/de.json" }
  }
}

| Field | | |---|---| | ui.theme | A CSS file with your design tokens (:root { --primary: … }). It is imported after the UI's own stylesheet, so your tokens win — no component is touched. | | ui.languages | Language code → catalog file. Every listed file is checked against the UI's en.json (the key source). | | ui.defaultLanguage | Which of them is built in. Defaults to "en" — the UI's own catalog. |

Three things are deliberate:

  • Unknown fields are rejected, not ignored. A typo (langauges) aborts the build naming the field, instead of silently doing nothing.
  • An incomplete translation aborts the build, naming the file and the missing keys. There is no silent fallback — you would not see it until a user did, mid-screen, in the wrong language.
  • No gate.json is fine. gate build then builds the defaults (English, stock tokens) — the same output as before this feature existed.

Everything happens at build time. The running UI loads no config, picks no language and switches no theme: it finds exactly one stylesheet and exactly one catalog.

gate build works against the gate-ui already present locallynode_modules/@anchrd/gate-ui (install it: it ships as source precisely so that this build can apply your config), or packages/ui in this workspace. The output lands where it belongs to you:

| gate-ui found in | output | |---|---| | node_modules/@anchrd/gate-ui | .gate/ui in your project root — point assets.directory there | | packages/ui (this workspace) | packages/ui/dist, unchanged since GATE-45 |

⚠️ The installed case never builds into node_modules: the next npm ci would wipe the output while your wrangler.jsonc still pointed at it — a worker serving nothing, with nobody having touched a thing. The two mount points (src/theme/custom.css, src/i18n/custom.json) do live in node_modules, and may: gate build rewrites both every run.

The two-token rule

Never confuse them:

  • Service key (GATE_KEY, in the edge's .env) — only says "this code may talk to gate".
  • User bearer (per request from the client) — the only thing can() checks. Permissions always come from the resolved token, never from an argument.

Related