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

@archie/node-sdk

v0.1.1

Published

Archie BAAS - Node.js server SDK with admin auth, JWT verification & middleware

Downloads

251

Readme

@archie/node-sdk

Node.js server SDK for the Archie BAAS platform. JWT verification, admin user management, service-role GraphQL & REST, and framework middleware for Express, Fastify, and Lambda.

Install

# npm
npm install @archie/js-sdk @archie/node-sdk

# pnpm
pnpm add @archie/js-sdk @archie/node-sdk

@archie/js-sdk is a required peer dependency. Framework integrations (express, fastify) are optional — install only what you use.

Requirements: Node.js >= 18.0.0


Quick Start

import { createAdminClient } from '@archie/node-sdk';

const archie = createAdminClient({
  projectId: 'your-project-uuid',
  apiKey: 'your-service-role-api-key',
  apiUrl: 'https://your-project.archiecore.com',
  environment: 'master',
  retries: 3,
  timeout: 15_000,
});

// Health check
const healthy = await archie.ping();

// Verify a JWT
const { user, error } = await archie.auth.verifyToken(token);

// List users
const { data, error: listErr } = await archie.auth.listUsers({ page: 1, limit: 20 });

// Service-role GraphQL
const { data: roles } = await archie.graphql.query('{ roles { items { id name } } }');

API Reference

createAdminClient(options)

Creates an admin client for server-side operations using a service-role API key.

const archie = createAdminClient({
  projectId: 'uuid',
  apiKey: 'service-role-api-key',
  environment: 'master',
  timeout: 15_000,
  retries: 3,
});

| Option | Type | Default | Description | | ------------- | -------------- | -------------------------- | ---------------------------------------------------------------- | | projectId | string | — | Required. Project UUID. | | apiKey | string | — | Required. Service-role API key. | | environment | string | 'master' | Environment name. | | apiUrl | string | 'https://api.archie.dev' | Base URL for the API. | | authUrl | string | same as apiUrl | Base URL for the Auth service. | | timeout | number | 30000 | Request timeout in milliseconds. Set 0 to disable. | | retries | number | 0 | Max retry attempts for transient errors (429, 500–504, network). | | retryDelay | number | 200 | Initial delay in ms for exponential backoff with jitter. | | fetch | typeof fetch | globalThis.fetch | Custom fetch implementation for testing or proxies. | | logger | ArchieLogger | {} | Logger for request lifecycle events. |

Returns an ArchieAdminClient with three modules:

  • archie.auth — JWT verification & admin user operations
  • archie.graphql — Service-role GraphQL queries & mutations
  • archie.rest — Service-role REST requests

JWT Verification

Verify JWTs issued by Archie using JWKS (JSON Web Key Set). Keys are cached for 5 minutes with automatic deduplication of concurrent fetches.

archie.auth.verifyToken(token, options?)

const { user, error } = await archie.auth.verifyToken('Bearer eyJhbG...');

Parameters:

| Parameter | Type | Description | | ------------------------------ | ---------- | ------------------------------------------------------------ | | token | string | JWT string. Bearer prefix is stripped automatically. | | options.requiredRoles | string[] | Require at least one of these roles. Returns 403 if missing. | | options.requireEmailVerified | boolean | Require emailVerified: true. Returns 403 if false. | | options.clockTolerance | number | Clock tolerance in seconds. Default: 30. |

Returns: Promise<VerifyTokenResult>

interface VerifyTokenResult {
  user: TokenUser | null;
  error: ArchieError | null;
}

interface TokenUser {
  id: string;
  email: string;
  firstName?: string;
  lastName?: string;
  roles: string[];
  exp: number;
  iat: number;
  emailVerified: boolean;
}

Examples:

// Basic verification
const { user, error } = await archie.auth.verifyToken(jwt);
if (error) {
  console.error(error.code); // AUTH_TOKEN_INVALID, AUTH_TOKEN_EXPIRED, etc.
}

// Require admin role
const { user, error } = await archie.auth.verifyToken(jwt, {
  requiredRoles: ['admin'],
});

// Require verified email
const { user, error } = await archie.auth.verifyToken(jwt, {
  requireEmailVerified: true,
});

JWKS Caching: The SDK automatically fetches and caches JWKS keys for 5 minutes. Concurrent verifyToken calls share a single JWKS fetch, preventing thundering-herd issues.


Admin User Operations

All admin operations use service-role authentication and return { data, error }.

archie.auth.createUser(params)

const { data, error } = await archie.auth.createUser({
  email: '[email protected]',
  password: 'SecurePass123!',
  firstName: 'John', // optional
  lastName: 'Doe', // optional
  roleId: 'role-uuid', // optional
  emailVerified: true, // optional
});

archie.auth.listUsers(params?)

const { data, error } = await archie.auth.listUsers({
  page: 1, // optional
  limit: 20, // optional
  search: 'john', // optional, searches email/name
  status: 'active', // optional: 'active' | 'locked' | 'unverified'
  orderBy: 'createdAt', // optional
});
// data: { users: User[], total: number, page: number, limit: number }

archie.auth.getUser(userId)

const { data, error } = await archie.auth.getUser('user-uuid');
// data: User { id, email, firstName, lastName, roles }

archie.auth.updateUser(userId, updates)

Accepts Partial<User> — any combination of firstName, lastName, email, roles, etc.:

const { data, error } = await archie.auth.updateUser('user-uuid', {
  firstName: 'Jane',
  lastName: 'Smith',
});

archie.auth.blockUser(userId)

const { data, error } = await archie.auth.blockUser('user-uuid');
// data: boolean

archie.auth.unblockUser(userId)

const { data, error } = await archie.auth.unblockUser('user-uuid');
// data: boolean

archie.auth.deleteUser(userId)

const { data, error } = await archie.auth.deleteUser('user-uuid');
// data: boolean

archie.auth.resendVerification(userId)

const { data, error } = await archie.auth.resendVerification('user-uuid');
// data: boolean

archie.auth.resetUserPassword(userId, newPassword)

const { data, error } = await archie.auth.resetUserPassword('user-uuid', 'NewPass123!');
// data: boolean

Service-Role GraphQL

Execute GraphQL operations with admin-level permissions.

archie.graphql.query<T>(gql, variables?, options?)

const { data, error } = await archie.graphql.query<{ users: User[] }>(
  '{ users { id email roles } }',
);

archie.graphql.mutate<T>(gql, variables?, options?)

const { data, error } = await archie.graphql.mutate(
  `mutation UpdateRole($userId: ID!, $roleId: ID!) {
    assignRole(userId: $userId, roleId: $roleId) { id roles }
  }`,
  { userId: 'user-uuid', roleId: 'admin-role' },
);

User Impersonation

Execute queries as a specific user while retaining service-role access:

const { data } = await archie.graphql.query(
  '{ myOrders { id total } }',
  {},
  { impersonateUserId: 'user-uuid' },
);

This adds the x-impersonate-user header to the request.


Service-Role REST

Direct REST API access with admin credentials.

const items = await archie.rest.get<Item[]>('/api/v1/items');
const created = await archie.rest.post<Item>('/api/v1/items', { name: 'New' });
const updated = await archie.rest.put<Item>('/api/v1/items/1', { name: 'Updated' });
const patched = await archie.rest.patch<Item>('/api/v1/items/1', { status: 'active' });
await archie.rest.delete('/api/v1/items/1');

All methods throw ArchieError on non-2xx responses with the HTTP status code embedded:

try {
  await archie.rest.get('/api/v1/missing');
} catch (err) {
  // err.code === 'HTTP_404'
  // err.status === 404
}

Note: Endpoints returning 204 No Content or Content-Length: 0 resolve with null data instead of attempting to parse an empty body.


Express Middleware

npm install express

createArchieMiddleware(client, options?)

Verifies JWT from the Authorization header and populates req.archieUser.

import express from 'express';
import { createAdminClient } from '@archie/node-sdk';
import { createArchieMiddleware, requireRole } from '@archie/node-sdk/express';

const archie = createAdminClient({ projectId: '...', apiKey: '...' });
const app = express();

// Optional auth — req.archieUser may be undefined
app.use(createArchieMiddleware(archie, { required: false }));

app.get('/api/profile', (req, res) => {
  if (!req.archieUser) return res.status(401).json({ error: 'Unauthorized' });
  res.json({ user: req.archieUser });
});

// Required auth — returns 401 automatically
app.use('/api/admin', createArchieMiddleware(archie, { required: true }));

app.get('/api/admin/dashboard', requireRole('admin'), (req, res) => {
  res.json({ admin: true, user: req.archieUser });
});

| Option | Type | Default | Description | | ---------- | ---------- | ------- | ------------------------------------------------------ | | required | boolean | false | Return 401 for unauthenticated requests. | | onError | function | — | Custom error handler: (err, req, res, next) => void. |

requireRole(...roles)

Express middleware that checks if req.archieUser has at least one of the specified roles. Returns 403 if not. Must be used after createArchieMiddleware.

app.get('/admin', requireRole('admin'), handler);
app.get('/editor', requireRole('admin', 'editor'), handler);

TypeScript

The middleware augments Express types — req.archieUser is typed as TokenUser | undefined:

app.get('/api/me', (req, res) => {
  const user = req.archieUser; // TokenUser | undefined
  res.json({ user });
});

Fastify Plugin

npm install fastify

archiePlugin

Fastify plugin that verifies JWT and decorates request.archieUser.

import Fastify from 'fastify';
import { createAdminClient } from '@archie/node-sdk';
import { archiePlugin } from '@archie/node-sdk/fastify';

const archie = createAdminClient({ projectId: '...', apiKey: '...' });
const fastify = Fastify();

fastify.register(archiePlugin, {
  client: archie,
  required: false, // set true to enforce auth on all routes
});

fastify.get('/api/profile', async (request) => {
  return { user: request.archieUser };
});

Lambda / Serverless

withArchieAuth(client, handler)

Wraps a Lambda handler to verify JWT and inject user into context.

import { createAdminClient } from '@archie/node-sdk';
import { withArchieAuth } from '@archie/node-sdk/lambda';

const archie = createAdminClient({ projectId: '...', apiKey: '...' });

export const handler = withArchieAuth(archie, async (event, context) => {
  const { user, client } = context.archie;

  // Access the verified user
  console.log('User:', user.id, user.email);

  // Use admin operations
  const { data } = await client.auth.listUsers();

  return {
    statusCode: 200,
    body: JSON.stringify({ userId: user.id, totalUsers: data?.total }),
  };
});

Returns 401 if no Authorization header is present or if the token is invalid.


Error Handling

All operations follow consistent error patterns:

  • Auth operations return { data, error } where error is ArchieError | null
  • Verify operations return { user, error } where error is AuthError | null
  • REST operations throw ArchieError on non-2xx responses
  • GraphQL operations return { data, error } with structured GraphQL errors

Error Codes

| Code | Status | Description | | ------------------------- | ------ | ------------------------------------------------------ | | AUTH_TOKEN_INVALID | 401 | Token is missing, malformed, or has invalid signature. | | AUTH_TOKEN_EXPIRED | 401 | Token has expired. | | AUTH_INSUFFICIENT_ROLE | 403 | User lacks a required role. | | AUTH_EMAIL_NOT_VERIFIED | 403 | Email is not verified but was required. | | AUTH_JWKS_FETCH_FAILED | varies | Failed to fetch JWKS keys. | | ADMIN_ERROR | varies | Admin operation returned an error. | | HTTP_<status> | varies | REST request failed with given HTTP status. | | TIMEOUT | 408 | Request timed out. | | NETWORK_ERROR | 0 | Network-level failure. |


Retry & Timeout

All HTTP requests go through a centralized engine with configurable retry and timeout.

Retry

Enable automatic retries for transient failures:

const archie = createAdminClient({
  projectId: '...',
  apiKey: '...',
  retries: 3, // retry up to 3 times
  retryDelay: 200, // start with 200ms delay
});

Retryable conditions:

  • HTTP status codes: 429, 500, 502, 503, 504
  • Network errors (DNS failures, connection refused, etc.)
  • Timeout errors

Backoff strategy: Exponential with jitter — delay × 2^attempt + random jitter, capped at 30 seconds. When a 429 response includes a Retry-After header, the SDK respects it.

Timeout

All requests have a 30-second timeout by default:

const archie = createAdminClient({
  projectId: '...',
  apiKey: '...',
  timeout: 10_000, // 10s timeout
});

Set timeout: 0 to disable timeouts entirely. When a request times out, an ArchieError is thrown with code: 'TIMEOUT' and status: 408.


Custom Fetch

Inject a custom fetch implementation for testing, proxies, or request interceptors:

import { createAdminClient } from '@archie/node-sdk';

const archie = createAdminClient({
  projectId: '...',
  apiKey: '...',
  fetch: myCustomFetch,
});

Use cases:

  • Unit testing with mocked fetch
  • HTTP proxy / agent injection (e.g., undici with proxy)
  • Request/response logging at the transport level

Logger

Plug in any logger (pino, winston, console, custom) to observe request lifecycle events:

import pino from 'pino';
import { createAdminClient } from '@archie/node-sdk';

const logger = pino({ level: 'debug' });

const archie = createAdminClient({
  projectId: '...',
  apiKey: '...',
  logger: {
    debug: (msg, meta) => logger.debug(meta, msg),
    warn: (msg, meta) => logger.warn(meta, msg),
  },
});

ArchieLogger interface

interface ArchieLogger {
  debug?: (message: string, meta?: Record<string, unknown>) => void;
  info?: (message: string, meta?: Record<string, unknown>) => void;
  warn?: (message: string, meta?: Record<string, unknown>) => void;
  error?: (message: string, meta?: Record<string, unknown>) => void;
}

Events logged: | Level | Event | Meta | |-------|-------|------| | debug | Request | { method, url } | | debug | Response | { url, status } | | warn | Retrying request | { url, attempt, delay } | | warn | Rate limited, waiting Retry-After | { url, retryAfter } | | warn | Network error, will retry | { url, attempt, error } |

All logger methods are optional — use only the levels you need.


Health Check

Verify API connectivity:

const healthy = await archie.ping();
if (!healthy) {
  console.error('Archie API is unreachable');
}

ping() sends a GET /health request and returns true if the server responds with 2xx within the configured timeout. Returns false on any error.


TypeScript

Exported Types

import type {
  AdminClientOptions,
  ArchieLogger,
  VerifyTokenOptions,
  VerifyTokenResult,
  TokenUser,
  CreateUserParams,
  ListUsersParams,
  ListUsersResult,
  MiddlewareOptions,
} from '@archie/node-sdk';

import type {
  IAdminAuthModule,
  IAdminGraphQLModule,
  IAdminRestModule,
  AdminResult,
} from '@archie/node-sdk';

Classes

The ArchieAdminClient class and concrete module classes are exported for instanceof checks, advanced typing, or mocking:

import {
  ArchieAdminClient,
  AdminAuthModule,
  AdminGraphQLModule,
  AdminRestModule,
} from '@archie/node-sdk';

// Direct instantiation (equivalent to createAdminClient)
const archie = new ArchieAdminClient({ projectId: '...', apiKey: '...' });

Re-exported from @archie/js-sdk

import type {
  User,
  Session,
  GraphQLResponse,
  ArchieError,
  AuthError,
  GraphQLError,
  NetworkError,
} from '@archie/node-sdk';

Playground

An interactive playground is available in examples/playground-node/:

cd examples/playground-node
cp .env.example .env
# Edit .env with your project credentials
pnpm install
pnpm dev
# Open http://localhost:3456

The playground provides a web dashboard to test all node-sdk features: JWT verification, admin user operations, service-role GraphQL, REST, and Express middleware.


License

MIT