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

@gatekpr/gatekeeper

v0.1.1

Published

Solana-native API gateway backend with a public Devnet CLI client

Readme

Gatekeeper

Gatekeeper is a Solana-native backend runtime that splits durable control-plane state from real-time execution state.

This refactor keeps the original backend story intact:

  • organizations
  • roles
  • API keys
  • policy enforcement
  • quota admission
  • audit visibility

But it now does so across two execution layers:

  • Base Solana for durable control-plane state
  • MagicBlock Ephemeral Rollups for delegated real-time runtime state

Project Overview

Gatekeeper models a familiar Web2 API gateway backend in Solana terms:

  • Organization is the tenant record
  • Role is the RBAC policy object
  • ApiKey is the credential record
  • QuotaPolicy is the durable rate-limit policy
  • QuotaRuntime is the fast mutable execution state
  • AuditCheckpoint is the durable settled summary

The result is a two-layer design:

  • base layer stores the canonical configuration and checkpointed runtime state
  • delegated runtime handles low-latency request admission and rolling audit history

Architecture Explanation

How this works in Web2

Gatekeeper follows the same split a normal API platform would use in a Web2 stack:

  • a database stores tenants, roles, API keys, and quota rules
  • a fast mutable store like Redis tracks rolling usage and recent request outcomes
  • request middleware checks authorization and quota on the hot path
  • a background process compacts recent runtime activity into durable audit state

In Web2 terms, Organization, Role, ApiKey, and QuotaPolicy are control-plane records, while QuotaRuntime behaves like the fast execution-state cache and AuditCheckpoint behaves like the durable settlement record.

How this works on Solana

On Solana, the same backend split is expressed with two execution layers:

  • Base Solana stores the durable PDAs: Gateway, Organization, Role, ApiKey, QuotaPolicy, and AuditCheckpoint
  • MagicBlock ER handles the high-frequency mutable account: QuotaRuntime
  • consume_request is the shared admission path, so the request logic stays the same whether runtime writes happen on base or through delegated execution
  • commit_quota_runtime, commit_and_undelegate_quota_runtime, and settle_runtime_checkpoint move fast-path state back into durable base-layer state

This keeps configuration and audit truth on base while moving the hottest mutable path to delegated runtime execution.

Tradeoffs & constraints

  • Only QuotaRuntime is delegated; this keeps the design legible, but it means settlement is an explicit operator step rather than an invisible background guarantee
  • Durable audit is checkpointed instead of writing one base account per request; this reduces hot-path cost, but long-term per-request history needs off-chain indexing if full retention is required
  • The plain base-RPC path still works without MagicBlock infrastructure; that improves portability, but it does not deliver the same latency profile as delegated execution
  • Full ER behavior depends on router-aware transport and compatible infrastructure; local tests focus on the base-compatible path, while ER validation is done with dedicated diagnostics and smoke flows

Devnet Transaction Links

Why This Matters

A normal Web2 gateway typically splits responsibilities anyway:

  • durable config in a database
  • hot counters in Redis or memory
  • request middleware at the edge
  • periodic background compaction or log shipping

Gatekeeper maps that directly onto Solana:

  • PDAs on base for durable control-plane truth
  • delegated writable runtime accounts for fast admission
  • periodic commit and settlement for durability

That makes the architecture readable to backend judges without pretending that every state mutation belongs on the slowest possible path.

Architecture

Base Solana: durable control plane

These accounts remain canonical on base:

  • Gateway
  • Organization
  • Role
  • ApiKey
  • QuotaPolicy
  • AuditCheckpoint

Base instructions are used for:

  • setup
  • admin mutations
  • durable policy changes
  • session finalization
  • settled checkpoint updates

MagicBlock ER: execution plane

Fast-path request admission runs against delegated runtime state:

  • QuotaRuntime

QuotaRuntime contains:

  • live window usage
  • total allowed/rejected counters
  • rolling request sequence
  • rolling in-memory-style audit buffer
  • delegation metadata

The same consume_request instruction works in both modes:

  • plain Solana mode: mutate QuotaRuntime directly on base
  • ER mode: mutate delegated QuotaRuntime through Magic Router

Durable vs Runtime State

Durable base state

Organization

Seed:

  • ["organization", gateway, name]

Fields:

  • authority
  • role_count
  • api_key_count
  • settlement_count

Role

Seed:

  • ["role", organization, role_name]

Fields:

  • policy_mask
  • created_at

ApiKey

Seed:

  • ["api_key", organization, key_id]

Fields:

  • role
  • label
  • active
  • created_by
  • created_at
  • revoked_at

QuotaPolicy

Seed:

  • ["quota_policy", api_key]

Fields:

  • max_requests
  • window_seconds

This is the durable contract for request admission. It does not store mutable usage.

AuditCheckpoint

Seed:

  • ["audit_checkpoint", api_key]

Fields:

  • last settled sequence
  • settled allowed/rejected totals
  • settled window state
  • last settled reason/action
  • last settlement timestamp

This is the durable base-layer summary of what the runtime has processed.

Runtime ER state

QuotaRuntime

Seed:

  • ["quota_runtime", api_key]

Fields:

  • current_window_used
  • current_window_started_at
  • total_allowed
  • total_rejected
  • rolling_sequence
  • rolling_audit
  • is_delegated
  • delegated_validator
  • commit_frequency_ms
  • last_settled_sequence
  • last_settled_at

This is the hot mutable account intended for delegation to MagicBlock.

Request Flow

Plain Solana compatibility path

  1. Create QuotaPolicy
  2. Initialize QuotaRuntime
  3. Call consume_request on base
  4. Periodically call settle_runtime_checkpoint

This keeps the project usable without MagicBlock infrastructure.

ER fast path

  1. Create QuotaPolicy on base
  2. Initialize QuotaRuntime on base
  3. Delegate QuotaRuntime with delegate_quota_runtime
  4. Route consume_request through Magic Router
  5. Periodically commit_quota_runtime
  6. When closing the delegated session, call commit_and_undelegate_quota_runtime
  7. Finalize durable summary with settle_runtime_checkpoint on base

Instruction Set

Base-layer control plane

  • initialize_gateway
  • create_organization
  • create_role
  • attach_policy_to_role
  • create_api_key
  • create_quota_policy
  • initialize_quota_runtime
  • revoke_api_key
  • settle_runtime_checkpoint

ER integration hooks

  • delegate_quota_runtime
  • commit_quota_runtime
  • commit_and_undelegate_quota_runtime

Shared request path

  • consume_request

The request instruction only mutates runtime state. That is the key design change that makes it safe for delegated execution.

Permission Model

Roles use a simple u64 bitmask:

  • bit 0: metrics:read
  • bit 1: metrics:write
  • bit 2: users:read
  • bit 3: users:write
  • bit 4: admin

admin is treated as an override bit.

Quota Model

The quota model is intentionally split:

  • QuotaPolicy says what the rules are
  • QuotaRuntime says what has happened recently

Admission logic:

  1. reject if the key is revoked
  2. reject if the action is invalid
  3. reject if the role bitmask does not allow the action
  4. if the current window expired, reset runtime window usage
  5. reject if current_window_used >= max_requests
  6. otherwise increment current_window_used
  7. append a rolling runtime audit record

Audit Model

This refactor no longer writes a new base PDA per request on the hot path.

Instead it uses two audit layers:

Runtime rolling audit

Stored inside QuotaRuntime as a capped rolling buffer.

Each entry records:

  • sequence
  • action
  • allowed/rejected
  • reason
  • timestamp
  • quota usage after the decision

Base settled checkpoint

Stored in AuditCheckpoint.

This is updated by settle_runtime_checkpoint after committed runtime state is safely back on base and no longer delegated.

MagicBlock Integration

Delegation hooks

The program now uses the official MagicBlock Rust SDK:

  • #[ephemeral] on the program
  • #[delegate] on the runtime delegation accounts
  • #[commit] on commit instructions

This keeps the ER-specific logic isolated to the runtime lifecycle instead of bleeding into the entire control plane.

Why only runtime is delegated

Only QuotaRuntime is on the high-frequency mutable path.

That makes it the right account to delegate. The rest of the model should remain simple base-layer state:

  • orgs
  • roles
  • keys
  • durable quota policy
  • settled checkpoints

This is the highest-signal architecture for judges because it matches the real separation between config and execution.

Magic Router Client Flow

The CLI now supports two transport modes:

Base RPC

Use normal RPC for:

  • setup
  • admin
  • policy changes
  • key management
  • runtime initialization
  • checkpoint settlement

Magic Router

Use Magic Router for transactions that touch delegated writable accounts:

  • consume_request
  • commit_quota_runtime
  • commit_and_undelegate_quota_runtime

The CLI supports:

  • --magic-router <url>
  • or MAGIC_ROUTER_URL

Under the hood it uses magic-router-sdk and its account-aware blockhash flow.

Blockhash / routing note

This matters:

  • delegated writable transactions must not assume a normal base-layer blockhash is sufficient
  • Magic Router derives a blockhash from the writable account set
  • the CLI uses sendMagicTransaction(...) for routed runtime writes

In other words: normal .rpc() is fine for base control-plane instructions, but delegated runtime writes should go through Router-aware transaction sending.

Repository Layout

programs/gatekeeper/    Anchor program with ER hooks
client/gatekeeper.ts    Shared TS PDA + router helpers
cli/gatekeeper.ts       Base + Magic Router CLI
tests/gatekeeper.ts     Plain-Solana runtime compatibility tests
scripts/*.ts            Ops + diagnostics for local/devnet runtime flows

Local Development

Prerequisites

  • Rust + Cargo
  • Solana CLI
  • AVM / Anchor 0.32.1
  • Node.js 24+

Setup

avm use 0.32.1
npm install
anchor build

Test Instructions

Rust check

cargo check -p gatekeeper

TypeScript check

node_modules/.bin/tsc.cmd --noEmit

Web2 demo test

This scenario-driven test is designed for demos. It walks through:

  • tenant onboarding
  • RBAC
  • API key issuance
  • quota enforcement
  • audit settlement
  • credential revocation
  • tenant isolation
npm run test:demo

Full local validator flow

avm use 0.32.1
anchor test --skip-build

The current automated suite validates the plain-Solana compatibility path:

  1. gateway initialization
  2. organization creation
  3. role creation
  4. API key creation
  5. quota policy creation
  6. runtime + checkpoint initialization
  7. authorized request admission
  8. unauthorized rejection
  9. quota exceeded rejection
  10. window expiry reset
  11. checkpoint settlement
  12. invalid-action rejection without quota consumption
  13. rolling runtime audit cap at eight entries
  14. revoked-key rejection after settlement

What is not locally automated

Full ER delegation and Router execution require MagicBlock infrastructure. This repo wires the hooks and client flow, but the local automated tests stay focused on the base-compatible path.

Local ER Diagnostics

The repo now includes focused diagnostics for local MagicBlock bring-up.

Router capability probe

This checks whether the endpoint you plan to use for delegated writes actually supports the router-only methods the CLI depends on:

npm run diag:router -- --magic-router http://127.0.0.1:7799
npm run diag:router -- --magic-router http://127.0.0.1:7799 --strict true

The strict form fails unless the endpoint supports:

  • getIdentity
  • getBlockhashForAccounts
  • getDelegationStatus

Local transport doctor

This verifies:

  • base RPC health
  • base blockhash fetch
  • router capability when --magic-router is provided
  • a plain JavaScript system transfer on base RPC
npm run diag:transport -- --cluster http://127.0.0.1:8899 --wallet wallets/localnet-authority.json
npm run diag:transport -- --cluster http://127.0.0.1:8899 --magic-router http://127.0.0.1:7799 --wallet wallets/localnet-authority.json

This is the fastest way to distinguish:

  • broken base validator setup
  • missing router capabilities
  • JavaScript client transport issues

Local runbook

For the full recommended local validation order, see docs/LOCAL_ER_RUNBOOK.md.

Public Devnet Client

The public shared client for this submission is the CLI in this repo. It is designed to work against the deployed Devnet program without requiring a local program build.

Quickstart

Use a funded Devnet wallet JSON file and point the client at Devnet explicitly:

npm install
npm exec --yes --package=@gatekpr/gatekeeper gatekpr help
node ./bin/gatekeeper.mjs help
node ./bin/gatekeeper.mjs init-gateway --cluster https://api.devnet.solana.com --wallet /path/to/devnet-wallet.json

Self-contained Devnet demo

This is the fastest public test path for reviewers because it provisions fresh tenant state under their own wallet and prints a JSON report:

npm install
npx tsx scripts/devnet-web2-demo.ts --cluster https://api.devnet.solana.com --wallet /path/to/devnet-wallet.json --run-id reviewer01

Public CLI examples

Once a reviewer has created their own org, role, key, and runtime state on Devnet, the shared client can be exercised directly:

node ./bin/gatekeeper.mjs create-org --cluster https://api.devnet.solana.com --wallet /path/to/devnet-wallet.json --name reviewer-acme
node ./bin/gatekeeper.mjs create-role --cluster https://api.devnet.solana.com --wallet /path/to/devnet-wallet.json --org-name reviewer-acme --role-name metrics-reader
node ./bin/gatekeeper.mjs attach-policy --cluster https://api.devnet.solana.com --wallet /path/to/devnet-wallet.json --org-name reviewer-acme --role-name metrics-reader --policy metrics:read

CLI Usage

Show help:

node ./bin/gatekeeper.mjs help
npx tsx cli/gatekeeper.ts help

Base setup flow

npx tsx cli/gatekeeper.ts init-gateway
npx tsx cli/gatekeeper.ts create-org --name acme
npx tsx cli/gatekeeper.ts create-role --org-name acme --role-name metrics-reader
npx tsx cli/gatekeeper.ts attach-policy --org-name acme --role-name metrics-reader --policy metrics:read
npx tsx cli/gatekeeper.ts create-key --org-name acme --role-name metrics-reader --label primary --key-material acme-key-1
npx tsx cli/gatekeeper.ts create-quota-policy --org-name acme --key-material acme-key-1 --max-requests 5 --window-seconds 60
npx tsx cli/gatekeeper.ts init-runtime --org-name acme --key-material acme-key-1

ER runtime flow

npx tsx cli/gatekeeper.ts delegate-runtime --org-name acme --key-material acme-key-1 --commit-frequency-ms 500 --magic-router https://your-magic-router
npx tsx cli/gatekeeper.ts call-endpoint --org-name acme --key-material acme-key-1 --action metrics:read --magic-router https://your-magic-router
npx tsx cli/gatekeeper.ts commit-runtime --org-name acme --key-material acme-key-1 --magic-router https://your-magic-router
npx tsx cli/gatekeeper.ts undelegate-runtime --org-name acme --key-material acme-key-1 --magic-router https://your-magic-router
npx tsx cli/gatekeeper.ts settle-checkpoint --org-name acme --key-material acme-key-1
npx tsx cli/gatekeeper.ts runtime-status --org-name acme --key-material acme-key-1
npx tsx cli/gatekeeper.ts view-audit --org-name acme --key-material acme-key-1

Ops Tooling

The repo now includes production-oriented operator tooling beyond the CLI:

Runtime health snapshot

Returns JSON with:

  • delegation state
  • rolling vs settled sequence drift
  • allowed/rejected totals
  • rolling audit entries
  • recommended next action
npm run ops:runtime-health -- --org-name acme --key-material acme-key-1

Runtime reconciliation

Supports safe operator workflows:

  • status
  • commit-only
  • settle-if-safe
  • undelegate-and-settle
npm run ops:reconcile -- --org-name acme --key-material acme-key-1 --mode status
npm run ops:reconcile -- --org-name acme --key-material acme-key-1 --mode settle-if-safe
npm run ops:reconcile -- --org-name acme --key-material acme-key-1 --mode undelegate-and-settle --magic-router https://your-magic-router

Devnet ER smoke flow

This script performs an idempotent control-plane setup and then runs:

  • delegate
  • routed request admission
  • commit
  • commit + undelegate
  • checkpoint settlement
npm run smoke:devnet:er -- --cluster https://api.devnet.solana.com --magic-router https://your-magic-router --org-name acme --role-name metrics-reader --key-material acme-key-1

Failure Recovery Runbook

Case: runtime is delegated and traffic has accumulated

Expected operator path:

  1. runtime-status
  2. commit-runtime if you want to keep the session open
  3. undelegate-runtime when closing the delegated window
  4. settle-checkpoint on base

Case: runtime is not delegated but drift is non-zero

That means runtime state has advanced beyond the durable checkpoint.

Use:

npm run ops:reconcile -- --org-name acme --key-material acme-key-1 --mode settle-if-safe

Case: runtime status is unclear

Use:

npm run ops:runtime-health -- --org-name acme --key-material acme-key-1

The script prints a recommended action based on:

  • delegated vs undelegated state
  • rolling sequence drift
  • rolling audit occupancy

Production Hardening Gaps

This repo is stronger operationally now, but it is still not production-ready.

Remaining gaps:

  • live MagicBlock ER integration testing on persistent infrastructure
  • security review / formal audit
  • alerting and dashboards around missed commits or checkpoint lag
  • multi-operator auth and key management policies
  • archival/indexing for long-term audit retention
  • throughput and cost benchmarking under real traffic
  • incident playbooks for router outages and validator-specific failures

Design Tradeoffs

  • Only the hot runtime account is delegated.
  • consume_request mutates runtime only.
  • Durable audit is checkpointed, not expanded into one base PDA per request.
  • Full local ER execution is not mocked in tests.
  • The checkpoint finalization step is intentionally explicit so the architecture stays inspectable.

Why This Is A Better Judge Story

This version tells a clearer Solana-native backend story than a single-layer contract:

  • base Solana is the durable control plane
  • MagicBlock ER is the execution plane
  • Router-aware clients send delegated writes correctly
  • settlement is explicit
  • the plain-Solana path still works without ER

That is a stronger backend-system translation than pretending every request mutation belongs in the same durability tier.