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

@switchy-ai/sdk

v0.4.0

Published

Official TypeScript/JavaScript SDK for Switchy: the v1 memory API and the MCP server, authenticated with an org API key.

Readme

@switchy-ai/sdk

Official TypeScript / JavaScript SDK for Switchy. Switchy is a client for the Switchy v1 API, which gives you team memory over HTTP and authenticates with an org API key (sk_live_…). McpClient is a client for Switchy's MCP server and authenticates with an MCP key.

Upgrading from 0.3.x? 0.3.x called Switchy's session-only web-app API, so with an API key every resource call returned 401. 0.4.0 targets the v1 API. See Migrating from 0.3.

Install

npm install @switchy-ai/sdk

Node 18+ or any runtime with a global fetch.

Get an API key

An owner or admin of your org mints an sk_live_… key in Settings → API keys. The key is shown once. It is scoped to that org and acts as the user who minted it. (McpClient uses a different key; see MCP client.)

Hello world

import { Switchy } from '@switchy-ai/sdk';

const client = new Switchy({ apiKey: process.env.SWITCHY_API_KEY! });

const memory = await client.memory.create({
  content: 'Deploys go out on Thursdays.',
  type: 'FACT',
  visibility: 'ORG',
});

const hits = await client.memory.search({ query: 'deploys' });
console.log(hits[0].content, hits[0].relevance);

const { memories, total } = await client.memory.list({ limit: 20 });

await client.memory.delete(memory.id);

What you can do

client.memory.list({ page, limit, type, minImportance })          // GET    /memory        → MemoryPage
client.memory.create({ content, type, visibility, projectId, tags }) // POST /memory        → CreatedMemory
client.memory.search({ query, type, limit, minImportance })       // POST   /memory/search → MemorySearchHit[]
client.memory.delete(id)                                          // DELETE /memory?id=    → { deleted: true, id }
  • Visibility: PRIVATE (only you, and the default), PROJECT (members of one Project, which needs projectId), or ORG (everyone in the org). Reads only return what the key's user is allowed to see.
  • type is required on create: FACT, CONTEXT, INSTRUCTION, PREFERENCE, CONVERSATION, SUMMARY or INSIGHT.
  • search returns memories whose content contains query, case-insensitively, best match first. It is a text match, not a semantic search.
  • list is ordered by importance, then newest first. The server ranks at most 100 visible memories, so total, stats and paging stop there.
  • Duplicates: writing content that already exists in the org throws ConflictError with code: 'DUPLICATE_CONTENT', and details.id holds the existing memory's id.

Every response type is exported: Memory, MemoryPage, MemoryStats, CreatedMemory, MemorySearchHit, DeletedMemory, Visibility, MemoryType.

For other v1 endpoints (spec at /api/v1/openapi.json), use the underlying HTTP client. It handles the auth header, the envelope and errors:

const data = await client.http.request<{ namespaces: unknown[] }>('GET', '/namespaces');

MCP client

Switchy is also an MCP server. You can call its tools over JSON-RPC from your own code:

import { McpClient } from '@switchy-ai/sdk'; // or '@switchy-ai/sdk/mcp'

const mcp = new McpClient({ apiKey: process.env.SWITCHY_API_KEY! });

const tools = await mcp.tools();
const { memories } = await mcp.searchMemory({ query: 'launch readiness' });

McpClient takes the site origin as baseUrl (default https://switchy.build) and posts to {baseUrl}/mcp/rpc. Do not pass it the REST base URL (…/api/v1).

Tool calls need a key with the matching mcp:* scopes. Click Mint MCP key in Settings → API keys to get one. An sk_live_ org key can initialize() and list tools, but it has no mcp:* scopes, so tool calls throw McpAuthError (403, SCOPE_MISSING). See /docs/mcp for the tool list and scopes.

Errors

Every method returns the unwrapped data on success. On failure it throws a typed error, chosen by HTTP status. The server's own code is on err.code:

| Class | HTTP | Typical code | |-------|------|----------------| | ValidationError | 400 | VALIDATION_ERROR, plus issues | | AuthError | 401 | AUTH_ERROR | | ForbiddenError | 403 | AUTHORIZATION_ERROR, INSUFFICIENT_SCOPE, NOT_ORG_MEMBER, NOT_PROJECT_MEMBER | | NotFoundError | 404 | NOT_FOUND | | ConflictError | 409 | DUPLICATE_CONTENT | | RateLimitError | 429 | RATE_LIMIT_EXCEEDED, plus retryAfter in seconds | | ServerError | 5xx | INTERNAL_ERROR |

An AuthError message tells you what to check: whether the key was revoked, whether it is an sk_live_ org key, and whether baseUrl points at the v1 API. It also names the base URL the client used.

import { AuthError, ConflictError, RateLimitError } from '@switchy-ai/sdk';

try {
  await client.memory.create({ content, type: 'FACT' });
} catch (err) {
  if (err instanceof ConflictError) console.log('already stored as', (err.details as { id: string }).id);
  else if (err instanceof RateLimitError) console.log(`retry in ${err.retryAfter}s`);
  else if (err instanceof AuthError) console.error(err.message);
  else throw err;
}

Rate limits and retries

v1 requests are rate limited per plan, per minute and per day. The SDK retries a 429 up to maxRetries times (default 2), but only when Retry-After is 60 seconds or less. A longer wait, such as a daily cap, throws RateLimitError right away so your process doesn't sleep for hours.

Migrating from 0.3

0.3.x called https://switchy.build/api, the API behind the Switchy web app. It authenticates with a browser session, not an API key, so every 0.3.x resource call returned 401. 0.4.0 calls the v1 API instead.

| 0.3.x | 0.4.0 | |-------|-------| | client.memory.create({ content, visibility: 'SPACE', spaceId }) | client.memory.create({ content, type: 'FACT', visibility: 'PROJECT', projectId }) | | client.memory.search({ query, spaceId }) → { memory, score }[] | client.memory.search({ query }) → { ...memory, relevance }[] | | client.memory.list({ visibility, spaceId, limit }) → Memory[] | client.memory.list({ page, limit, type, minImportance }) → MemoryPage | | client.memory.delete(id) → void | client.memory.delete(id) → { deleted: true, id } | | client.spaces, sessions, messages, members, invitations | Removed. Use the web app, or McpClient (listSpaces, listSessions, getSessionTranscript, postMessage) | | client.billing, client.mcp, client.keys | Removed. Manage billing, MCP servers and keys in the web app | | client.realtime(...) and the ably peer dependency | Removed | | { idempotencyKey } | Removed. No route implemented it. Duplicate memories are rejected by content |

The full list is in CHANGELOG.md.

Configuration reference

new Switchy({
  apiKey: 'sk_live_...',                    // required
  baseUrl: 'https://switchy.build/api/v1',  // default
  timeout: 60_000,                          // ms, default 60s
  maxRetries: 2,                            // 429 retries (Retry-After ≤ 60s)
  fetch,                                    // custom fetch (tests / non-Node)
  userAgent: 'my-app/1.0',                  // optional
});

License

MIT