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

@alter-ai/alter-sdk

v0.4.0

Published

Official TypeScript SDK for Alter Vault — OAuth token management with policy enforcement

Readme

Alter SDK for TypeScript / Node.js

Official TypeScript SDK for Alter Vault — Credential management for agents with policy enforcement.

Features

  • Zero Token Exposure: Tokens are never exposed to developers — injected automatically
  • Single Entry Point: One method (vault.request()) for all provider APIs
  • Type-Safe Enums: HttpMethod enums with autocomplete
  • URL Templating: Path parameter substitution with automatic URL encoding
  • Automatic Audit Logging: All API calls logged with request metadata (HTTP method and URL) for full audit trail
  • Real-time Policy Enforcement: Every token request checked against current policies
  • Automatic Token Refresh: Tokens refreshed transparently by the backend
  • API Key and Custom Credential Support: Handles OAuth tokens, API keys, and custom credential formats automatically
  • AWS SigV4 Support: Automatic AWS Signature Version 4 signing for S3, Bedrock, DynamoDB, and other AWS services (no AWS SDK required)
  • Actor Tracking: First-class support for AI agent and MCP server observability
  • HMAC Request Signing: All SDK-to-backend requests are signed with a derived HMAC-SHA256 key for integrity, authenticity, and replay protection
  • Native Promises: Built on native fetch — no heavy dependencies

Installation

npm install @alter-ai/alter-sdk

Quick Start

import { AlterVault, ActorType, Provider, HttpMethod } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: "alter_key_...",
  actorType: ActorType.AI_AGENT,
  actorIdentifier: "my-agent",
});

// Make API request — token injected automatically, never exposed
const response = await vault.request(
  "CONNECTION_ID",  // from Alter Connect (see below)
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
  {
    queryParams: { maxResults: "10" },
  },
);

const events = await response.json();
console.log(events);

await vault.close();

Where does connectionId come from?

OAuth connections:

  1. User completes OAuth via Alter Connect (frontend widget)
  2. The onSuccess callback returns a connectionId (UUID)
  3. You save it in your database, mapped to your user
  4. You pass it to vault.request() when making API calls

Managed secrets (API keys, service tokens):

  1. Store credentials in the Developer Portal under Managed Secrets
  2. Copy the connectionId returned
  3. Use the same vault.request() — credentials are injected automatically
// You can also discover connectionIds programmatically:
const result = await vault.listConnections({ providerId: "google" });
for (const conn of result.connections) {
  console.log(`${conn.id}: ${conn.accountDisplayName}`);
}

Usage

The request() method returns the raw Response object. The token is injected automatically and never exposed. The backend token response includes connectionId and providerId for audit correlation.

Simple GET Request

const response = await vault.request(
  connectionId,
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
);

POST with JSON Body

const response = await vault.request(
  connectionId,
  HttpMethod.POST,
  "https://api.example.com/v1/items",
  {
    json: { name: "New Item", price: 99.99 },
    reason: "Creating new item",
  },
);

URL Path Templating

const response = await vault.request(
  connectionId,
  HttpMethod.PUT,
  "https://api.example.com/v1/items/{item_id}",
  {
    pathParams: { item_id: "123" },
    json: { price: 89.99 },
  },
);

Query Parameters and Extra Headers

const response = await vault.request(
  connectionId,
  HttpMethod.POST,
  "https://api.notion.com/v1/databases/{db_id}/query",
  {
    pathParams: { db_id: "abc123" },
    extraHeaders: { "Notion-Version": "2022-06-28" },
    json: { page_size: 10 },
  },
);

Using Managed Secrets

For your own APIs with API keys or service tokens (no OAuth flow needed):

const vault = new AlterVault({
  apiKey: "alter_key_...",
  actorType: ActorType.BACKEND_SERVICE,
  actorIdentifier: "my-service",
});

const response = await vault.request(
  "MANAGED_SECRET_CONNECTION_ID",  // from Developer Portal
  HttpMethod.GET,
  "https://api.internal.com/v1/data",
);

await vault.close();

The credential is injected automatically as the configured header type (Bearer, API Key, Basic Auth).

Connection Management

List Connections

Retrieve OAuth connections for your app, optionally filtered by provider:

const result = await vault.listConnections();
for (const conn of result.connections) {
  console.log(`${conn.providerId}: ${conn.accountDisplayName} (${conn.status})`);
}

// Filter by provider with pagination
const googleConns = await vault.listConnections({
  providerId: "google",
  limit: 10,
  offset: 0,
});
console.log(`Total: ${googleConns.total}, Has more: ${googleConns.hasMore}`);

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | providerId | string | - | Filter by provider (e.g., "google") | | limit | number | 100 | Max connections to return | | offset | number | 0 | Pagination offset |

Returns ConnectionListResult with: connections (ConnectionInfo[]), total, limit, offset, hasMore.

Create Connect Session

Generate a session URL for end-users to authenticate with OAuth providers:

const session = await vault.createConnectSession({
  endUser: { id: "alice" },
  allowedProviders: ["google", "github"],
  returnUrl: "https://myapp.com/callback",
});
console.log(`Connect URL: ${session.connectUrl}`);
console.log(`Expires in: ${session.expiresIn}s`);

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | endUser | { id: string } | required | End user identity | | allowedProviders | string[] | - | Restrict to specific providers | | returnUrl | string | - | Redirect URL after OAuth flow |

Returns ConnectSession with: sessionToken, connectUrl, expiresIn, expiresAt.

Headless Connect (from code)

For CLI tools, scripts, and server-side applications -- opens the browser, waits for the user to complete OAuth, and returns the result:

const results = await vault.connect({
  endUser: { id: "alice" },
  providers: ["google"],
  timeout: 300,        // max wait in seconds (default: 5 min)
  openBrowser: true,   // set false to print URL instead
});
for (const result of results) {
  console.log(`Connected: ${result.connectionId} (${result.providerId})`);
  console.log(`Account: ${result.accountIdentifier}`);
}

// Now use the connectionId with vault.request()
const response = await vault.request(
  results[0].connectionId,
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
);

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | endUser | { id: string } | required | End user identity | | providers | string[] | - | Restrict to specific providers | | timeout | number | 300 | Max seconds to wait for completion | | pollInterval | number | 2 | Seconds between status checks | | openBrowser | boolean | true | Open browser automatically |

Returns ConnectResult[] — one per connected provider. Each has: connectionId, providerId, accountIdentifier, scopes.

Throws ConnectTimeoutError if the user doesn't complete in time, ConnectFlowError if denied.

AI Agent Actor Tracking

import { AlterVault, ActorType, Provider, HttpMethod } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: "alter_key_...",
  actorType: ActorType.AI_AGENT,
  actorIdentifier: "email-assistant-v2",
  actorName: "Email Assistant",
  actorVersion: "2.0.0",
  framework: "langgraph",
});

const response = await vault.request(
  connectionId,
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
  {
    runId: "550e8400-e29b-41d4-a716-446655440000",  // auto-generated UUID if omitted
    threadId: "thread-xyz",
    toolCallId: "call_abc_123",
  },
);

Note: runId is auto-generated as a UUID v4 if not provided. All sub-actions within a single request() call share the same runId for audit log grouping.

Multi-Agent Deployments

Each agent must create its own AlterVault instance with a unique actor identity. Do not share a single instance across agents.

// Each agent gets its own vault instance
const emailAgent = new AlterVault({
  apiKey: "alter_key_...",
  actorType: ActorType.AI_AGENT,
  actorIdentifier: "email-assistant-v2",
  actorName: "Email Assistant",
});

const calendarAgent = new AlterVault({
  apiKey: "alter_key_...",
  actorType: ActorType.AI_AGENT,
  actorIdentifier: "calendar-agent-v1",
  actorName: "Calendar Agent",
});

// Audit logs and policies are tracked per agent
await emailAgent.request(
  gmailConnectionId,  // from Alter Connect
  HttpMethod.GET,
  "https://gmail.googleapis.com/gmail/v1/users/me/messages",
);
await calendarAgent.request(
  calendarConnectionId,  // from Alter Connect
  HttpMethod.GET,
  "https://www.googleapis.com/calendar/v3/calendars/primary/events",
);

// Clean up each instance
await emailAgent.close();
await calendarAgent.close();

Configuration

import { AlterVault, ActorType } from "@alter-ai/alter-sdk";

const vault = new AlterVault({
  apiKey: "alter_key_...",              // Required: Alter Vault API key
  actorType: ActorType.AI_AGENT,        // Required: ActorType enum
  actorIdentifier: "my-agent",          // Required: Unique identifier
  timeout: 30000,                       // Optional: HTTP timeout in ms (default: 30000)
  actorName: "My Agent",                // Optional: Human-readable name
  actorVersion: "1.0.0",               // Optional: Version string
  framework: "langgraph",              // Optional: AI framework
  clientType: "cursor",                 // Optional: MCP client type
});

Error Handling

Note: Input validation errors (invalid apiKey, invalid/missing actorType, missing actorIdentifier, invalid URL scheme, missing pathParams) throw AlterSDKError.

import {
  AlterVault,
  HttpMethod,
  AlterSDKError,              // Base error (including validation: apiKey, actorType, actorIdentifier, URL scheme, pathParams)
  PolicyViolationError,
  ConnectionNotFoundError,
  TokenExpiredError,
  TokenRetrievalError,
  ConnectFlowError,           // Headless connect() failed (denied, provider error)
  ConnectTimeoutError,        // Headless connect() timed out
  NetworkError,
  TimeoutError,
  ProviderAPIError,
} from "@alter-ai/alter-sdk";

try {
  const response = await vault.request(
    connectionId,
    HttpMethod.GET,
    "https://www.googleapis.com/calendar/v3/calendars/primary/events",
  );
} catch (error) {
  if (error instanceof PolicyViolationError) {
    console.error(`Policy denied: ${error.message}`);
  } else if (error instanceof ConnectionNotFoundError) {
    console.error("No OAuth connection — user needs to authenticate");
  } else if (error instanceof TokenExpiredError) {
    console.error(`Token expired for connection: ${error.connectionId}`);
  } else if (error instanceof TimeoutError) {
    console.error(`Request timed out — safe to retry: ${error.message}`);
  } else if (error instanceof NetworkError) {
    console.error(`Network issue: ${error.message}`);
  } else if (error instanceof ProviderAPIError) {
    console.error(`Provider error ${error.statusCode}: ${error.responseBody}`);
  }
}

Resource Management

// Manual cleanup (recommended)
const vault = new AlterVault({
  apiKey: "alter_key_...",
  actorType: ActorType.BACKEND_SERVICE,
  actorIdentifier: "my-service",
});
try {
  const response = await vault.request(...);
} finally {
  await vault.close(); // Waits for pending audit logs, cleans up timers
}

// close() is idempotent — safe to call multiple times
// Calling request() after close() throws AlterSDKError

Supported Providers

The SDK works with any OAuth provider configured in your Alter Vault dashboard. The first parameter to vault.request() is the connection_id (UUID) returned when a user connects via Alter Connect.

// Use the connection_id from Alter Connect
await vault.request("550e8400-e29b-41d4-a716-446655440000", HttpMethod.GET, url);

Requirements

  • Node.js 18+ (uses native fetch)
  • TypeScript 5.0+

License

MIT License