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

@airstore/sdk

v0.1.8

Published

Official TypeScript SDK for the Airstore API

Readme

@airstore/sdk

Official TypeScript SDK for the Airstore API. Create workspaces, connect data sources, run agents, and observe everything — all from your backend.

Installation

npm install @airstore/sdk

Quick Start

import Airstore from '@airstore/sdk';

const airstore = new Airstore({ apiKey: process.env.AIRSTORE_API_KEY });

// Create a workspace
const ws = await airstore.workspaces.create({ name: 'user-123' });

// Create an agent
const agent = await airstore.agents.create(ws.external_id, {
  agentKey: 'support-agent',
  name: 'Support Agent',
  runner: 'claude_code',
  config: { model: 'claude-sonnet-4-6' },
});

// Submit a task
const { task, run_id } = await airstore.tasks.create(ws.external_id, {
  message: 'Summarize recent support tickets',
  agentId: agent.id,
});

// Poll for logs and events
const batch = await airstore.tasks.streamEvents(ws.external_id, task.id);
console.log(batch.logs);

Configuration

const airstore = new Airstore({
  apiKey: 'org_...',                // or set AIRSTORE_API_KEY env var
  baseURL: 'https://api.airstore.ai/api/v1', // or AIRSTORE_BASE_URL
  timeout: 30_000,                  // request timeout in ms (default: 60000)
  maxRetries: 3,                    // retries for 429/5xx (default: 2)
});

API Reference

Agents

// Create
const agent = await airstore.agents.create(wsId, {
  agentKey: 'my-agent',
  name: 'My Agent',
  runner: 'claude_code',
  config: { model: 'claude-sonnet-4-6', system_prompt: 'You are helpful.' },
});

// List
const agents = await airstore.agents.list(wsId);

// Retrieve
const a = await airstore.agents.retrieve(wsId, agentId);

// Update
await airstore.agents.update(wsId, agentId, { name: 'Renamed Agent' });

// Delete (also removes bound hooks)
await airstore.agents.delete(wsId, agentId);

Tasks

// Create a task (returns accepted response with task + run_id)
const { task, run_id } = await airstore.tasks.create(wsId, {
  message: 'Do something',
  agentId: agent.id,
  idempotencyKey: 'unique-key',     // optional, server generates if omitted
  sessionId: 'session-abc',         // optional, groups related tasks
  timeoutMs: 120_000,               // optional
  policy: {                         // optional execution policy
    host: 'sandbox',
    security: 'allowlist',
    runtimeType: 'gvisor',
    workspaceAccess: 'rw',
  },
});

// List with filters
const page = await airstore.tasks.list(wsId, {
  state: ['running', 'idle'],
  agentId: agent.id,
  limit: 20,
});

// Retrieve
const t = await airstore.tasks.retrieve(wsId, taskId);

// Cancel a running task
await airstore.tasks.cancel(wsId, taskId);

// Archive a completed/idle task
await airstore.tasks.archive(wsId, taskId);

Log Streaming & Events

// Fetch logs for a task (cursor-based for incremental reads)
const logs = await airstore.tasks.listLogs(wsId, taskId);

// Composite event stream: task/run state + logs + run events in one call
let logCursor = 0;
let eventCursor = 0;

const batch = await airstore.tasks.streamEvents(wsId, taskId, {
  logCursor,
  runEventCursor: eventCursor,
});

// Use next cursors for subsequent polls
logCursor = batch.next_log_cursor;
eventCursor = batch.next_run_event_cursor;

Runs

// List runs
const runs = await airstore.runs.list(wsId, { status: 'running' });

// Retrieve a run
const run = await airstore.runs.retrieve(wsId, runId);

// List snapshots (intermediate state)
const snapshots = await airstore.runs.listSnapshots(wsId, runId);

// List execution events
const events = await airstore.runs.listEvents(wsId, runId);

// Cancel
await airstore.runs.cancel(wsId, runId);

Channels (Follow-Up Messages)

// Send a new task to an agent via direct channel
await airstore.channels.sendDirectAgentMessage(wsId, agentId, {
  message: 'What about the billing tickets?',
});

// Send follow-up input to an active run
await airstore.channels.sendDirectRunMessage(wsId, runId, {
  message: 'Focus on the last 24 hours',
  taskId: task.id,
  queueMode: 'steer', // 'queue' | 'followup' | 'steer' | 'interrupt'
});

Scheduled Tasks (Cron)

// Create a schedule
const schedule = await airstore.tasks.createSchedule(wsId, {
  agentId: agent.id,
  cronExpr: '0 9 * * 1-5',    // every weekday at 9am
  timezone: 'America/New_York',
  prompt: 'Summarize overnight support tickets',
});

// List schedules
const schedules = await airstore.tasks.listSchedules(wsId);

// Update (pause, change cron, etc.)
await airstore.tasks.updateSchedule(wsId, schedule.external_id, {
  active: false,
});

// Delete
await airstore.tasks.deleteSchedule(wsId, schedule.external_id);

Hooks (File-System Triggers)

// Create a hook on a source view folder
const hook = await airstore.hooks.create(wsId, {
  path: '/sources/gmail/Recent Emails',
  prompt: 'Triage this email and draft a reply',
  eventTypes: ['create'],
  agentName: 'Email Triager',
});

// List / Retrieve / Update / Delete
const hooks = await airstore.hooks.list(wsId);
await airstore.hooks.update(wsId, hookId, { active: false });
await airstore.hooks.delete(wsId, hookId);

Workspaces

const ws = await airstore.workspaces.create({ name: 'my-workspace' });
const workspaces = await airstore.workspaces.list();
const ws2 = await airstore.workspaces.retrieve(wsId);
await airstore.workspaces.del(wsId);

Connections

// OAuth tokens
await airstore.connections.create(wsId, {
  integrationType: 'gmail',
  accessToken: '...',
  refreshToken: '...',
});

// API key
await airstore.connections.create(wsId, {
  integrationType: 'github',
  apiKey: 'ghp_...',
});

const connections = await airstore.connections.list(wsId);
await airstore.connections.del(wsId, connectionId);

Source Views

// Smart mode (LLM-inferred)
const view = await airstore.views.create(wsId, {
  integration: 'gmail',
  name: 'Important Emails',
  guidance: 'Emails marked as important from the last month',
});

// Query mode (structured filter)
const view2 = await airstore.views.create(wsId, {
  integration: 'github',
  name: 'Open PRs',
  filter: { repo: 'acme/api', type: 'prs', state: 'open' },
});

// Sync, update, delete
await airstore.views.sync(wsId, viewId);
await airstore.views.update(wsId, viewId, { guidance: 'Updated' });
await airstore.views.del(wsId, viewId);

Tokens, Members, OAuth

// Tokens (for CLI mounting)
const token = await airstore.tokens.create(wsId, {
  email: 'agent@internal', name: 'vm-mount',
});

// Members
const member = await airstore.members.create(wsId, {
  email: '[email protected]', name: 'Jane', role: 'member',
});

// Interactive OAuth
const session = await airstore.oauth.createSession({
  integrationType: 'gmail',
  returnTo: 'https://myapp.com/callback',
});
const completed = await airstore.oauth.poll(session.session_id);

Filesystem

const entries = await airstore.fs.list(wsId, { path: '/' });
const content = await airstore.fs.read(wsId, { path: '/sources/gmail/email.txt' });
const tree = await airstore.fs.tree(wsId, { path: '/', maxKeys: 100 });
const meta = await airstore.fs.stat(wsId, '/sources/gmail/email.txt');

Error Handling

import { NotFoundError, RateLimitError, AuthenticationError } from '@airstore/sdk';

try {
  await airstore.workspaces.retrieve('ws_nonexistent');
} catch (err) {
  if (err instanceof NotFoundError) console.log('Not found');
  if (err instanceof RateLimitError) console.log('Rate limited');
  if (err instanceof AuthenticationError) console.log('Bad API key');
}

| Class | Status | Description | |---|---|---| | AirstoreError | — | Base error for all SDK errors | | APIError | varies | Base for HTTP errors | | AuthenticationError | 401 | Invalid or missing API key | | PermissionDeniedError | 403 | Token lacks permission | | NotFoundError | 404 | Resource not found | | ConflictError | 409 | Conflicting operation | | UnprocessableEntityError | 422 | Validation failed | | RateLimitError | 429 | Rate limit exceeded | | InternalServerError | 5xx | Server error (retried automatically) | | APIConnectionError | — | Network failure | | APIConnectionTimeoutError | — | Request timed out |

Per-Request Options

Every method accepts an optional last argument for per-request overrides:

await airstore.workspaces.list({
  timeout: 10_000,
  maxRetries: 5,
  signal: controller.signal,
  headers: { 'X-Trace-Id': 'abc' },
});

Response Metadata

Every response includes a non-enumerable lastResponse property:

const ws = await airstore.workspaces.create({ name: 'test' });
ws.lastResponse.statusCode;  // 200
ws.lastResponse.requestId;   // 'req_abc123'

Raw Requests

For endpoints not yet covered by the SDK:

const response = await airstore.rawRequest('POST', '/some/new/endpoint', {
  body: { key: 'value' },
});

Requirements

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

License

Apache-2.0