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

@safercity/sdk-core

v0.4.0

Published

Core utilities for SaferCity SDK - fetch abstraction, streaming, and authentication

Readme

@safercity/sdk-core

Core utilities for SaferCity SDK including fetch abstraction, streaming support, and authentication helpers.

Note: Most users should use @safercity/sdk instead. This package contains low-level utilities used internally.

What's New in v0.4.0

  • No breaking changes - Internal package only. Bumped for consistency with SDK v0.4.0.

What's New in v0.3.2

  • ProxyModeConfig Enhanced - Added tenantId, userId, and headers support to ProxyModeConfig for white-label apps using proxy mode.

What's New in v0.3.1

  • No breaking changes - Internal package only. Bumped for consistency with SDK client v0.3.1.

What's New in v0.3.0

  • Foundation for Typed SDK - Core types and utilities updated to support the auto-generated OpenAPI SDK.

Installation

npm install @safercity/sdk-core

What's New in v0.2.0

  • User Scoping - Added userId to DirectModeConfig and CookieModeConfig for automatic request scoping

What's New in v0.1.3

  • OAuth endpoint path fix - Token and refresh endpoints now correctly use /v1/oauth/* prefix

What's New in v0.1.0

  • Auth Mode Types - Three authentication modes: proxy, direct, and cookie
  • Token Manager - Server-side OAuth token management with automatic refresh and request deduplication
  • Token Storage - Pluggable token storage interface with in-memory default

Features

  • Type definitions - Common types for API requests/responses and auth mode configuration
  • Authentication utilities - Token management, JWT parsing, OAuth token lifecycle
  • Streaming/SSE support - Cross-platform Server-Sent Events
  • Base HTTP client - Fetch wrapper with timeout and error handling

Usage

Auth Mode Types

The SDK supports three authentication modes for different deployment scenarios:

import type {
  AuthMode,
  ProxyModeConfig,
  DirectModeConfig,
  CookieModeConfig,
  ClientModeConfig,
} from '@safercity/sdk-core';

| Mode | Flow | Best For | |------|------|----------| | "proxy" | Client -> Your Backend -> SaferCity API | Production web apps (most secure) | | "direct" | Client -> SaferCity API with external token | White-label apps with external auth (Clerk, Auth0, better-auth) | | "cookie" | Browser with credentials: include | First-party web apps using session cookies |

// Proxy mode (default) - backend adds tenant credentials
const proxyConfig: ProxyModeConfig = {
  mode: 'proxy',
  proxyBaseUrl: '/api/safercity', // defaults to "/api/safercity"
};

// Direct mode - external auth provider supplies the token
const directConfig: DirectModeConfig = {
  mode: 'direct',
  baseUrl: 'https://api.safercity.com',
  tenantId: 'tenant-123',
  userId: 'user-123', // optional, for user-scoped operations
  getAccessToken: () => session?.accessToken,
};

// Cookie mode - session cookies sent automatically
const cookieConfig: CookieModeConfig = {
  mode: 'cookie',
  baseUrl: 'https://api.safercity.com',
  tenantId: 'tenant-123', // optional, can come from cookie
  userId: 'user-123', // optional, for user-scoped operations
};

Token Manager

Server-side OAuth token management with automatic refresh and concurrent request deduplication:

import { TokenManager, MemoryTokenStorage } from '@safercity/sdk-core';

const tokenManager = new TokenManager({
  credentials: {
    clientId: process.env.SAFERCITY_CLIENT_ID!,
    clientSecret: process.env.SAFERCITY_CLIENT_SECRET!,
    tenantId: 'tenant-123', // optional
  },
  baseUrl: 'https://api.safercity.com',
  refreshBuffer: 60000, // refresh 1 minute before expiry (default)
  storage: new MemoryTokenStorage(), // default, or provide custom
});

// Get token (auto-refreshes if expired, dedupes concurrent calls)
const token = await tokenManager.getToken();

// Force refresh (useful for error recovery)
const freshToken = await tokenManager.forceRefresh();

// Check state
tokenManager.hasToken(); // boolean
tokenManager.clear();    // remove stored tokens

Token Storage

Implement the TokenStorage interface for custom persistence:

import type { TokenStorage, AuthTokens } from '@safercity/sdk-core';

// Built-in: MemoryTokenStorage (default, no persistence)
import { MemoryTokenStorage } from '@safercity/sdk-core';

// Custom implementation
class MyTokenStorage implements TokenStorage {
  get(): AuthTokens | null { /* ... */ }
  set(tokens: AuthTokens): void { /* ... */ }
  clear(): void { /* ... */ }
}

Stream Adapters

import { 
  WebStreamAdapter, 
  FetchStreamAdapter, 
  createStreamAdapter 
} from '@safercity/sdk-core';

// Auto-detect best adapter for environment
const adapter = createStreamAdapter();

// Or use specific adapter
const webAdapter = new WebStreamAdapter(); // Browser with EventSource
const fetchAdapter = new FetchStreamAdapter(fetch); // Node.js / React Native

// Stream events
const stream = adapter.createEventSource('https://api.example.com/stream', {
  headers: { Authorization: 'Bearer token' },
});

for await (const event of stream) {
  console.log(event.data);
}

Authentication Helpers

import {
  createAuthHeader,
  parseJwtPayload,
  getJwtExpiration,
  isTokenExpired,
} from '@safercity/sdk-core';

// Create auth header
const header = createAuthHeader('my-token'); // "Bearer my-token"

// Parse JWT (without verification)
const payload = parseJwtPayload(token);
console.log(payload?.sub); // User ID

// Check expiration
const expiresAt = getJwtExpiration(token);
if (isTokenExpired(expiresAt)) {
  // Token expired, refresh it
}

Base Client

import { BaseClient } from '@safercity/sdk-core';

const client = new BaseClient({
  baseUrl: 'https://api.example.com',
  token: 'my-token',
  timeout: 30000,
});

// Make requests
const response = await client.get('/users');
const created = await client.post('/users', { name: 'John' });

Error Handling

import { SaferCityApiError } from '@safercity/sdk-core';

try {
  await client.get('/not-found');
} catch (error) {
  if (error instanceof SaferCityApiError) {
    console.log(error.error);   // "not_found"
    console.log(error.message); // "Resource not found"
    console.log(error.status);  // 404
  }
}

Types

SaferCityConfig

interface SaferCityConfig {
  baseUrl: string;
  token?: string;
  tenantId?: string;
  fetch?: typeof fetch;
  timeout?: number;
  headers?: Record<string, string>;
}

AuthTokens

interface AuthTokens {
  accessToken: string;
  refreshToken?: string;
  expiresAt?: number;
  tokenType: string;
}

OAuthCredentials

interface OAuthCredentials {
  clientId: string;
  clientSecret: string;
  tenantId?: string;
}

ServerSentEvent

interface ServerSentEvent {
  id?: string;
  event?: string;
  data: string;
  retry?: number;
}

License

MIT