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

@opitacode/ocais

v3.0.1

Published

OCAIS — Opita Code AI Stream. Lightweight AI streaming SDK for AWS Lambda. Zero deps, TypeScript-first, provider-agnostic.

Readme

OCAIS — Opita Code AI Stream

Lightweight AI streaming SDK for AWS Lambda. Zero deps. TypeScript-first. Provider-agnostic.

License: MIT Node.js

Why OCAIS?

Other SDKs (Vercel AI SDK, LangChain) are designed for fullstack web frameworks. OCAIS is designed for a single use case: streaming AI in AWS Lambda with SSE.

| | Vercel AI SDK | OCAIS | |---|---|---| | Bundle | ~2.8 MB | ~15 KB | | Dependencies | 30+ transitive | 0 | | Target | Next.js, React | AWS Lambda | | Tool execution | Optional | First-class with execute | | Cancellation | AbortController | AbortSignal + timeoutMs | | Errors | Generic | Typed hierarchy |

Install

npm install @opitacode/ocais

Peer dependencies

Some optional features require installing peer-dependencies. None are required for the core streaming API.

| Feature | Package | Install | |---------|---------|---------| | generateObject() (structured output via Zod) | zod | Included as a direct dependency in 3.0.1+ | | signJWT() / verifyJWT() with algorithm: "EdDSA" | @noble/ed25519 | npm install @noble/ed25519 | | passwordHash() / passwordVerify() / needsRehash() | @node-rs/argon2 | npm install @node-rs/argon2 |

The provider modules (openai(), google()) and core streaming (streamText()) need only fetch, available in Node 20+. See docs/peer-deps.md for the full table.

Quick start

Streaming with DeepSeek

import { streamText, openai } from "@opitacode/ocais";

const stream = streamText({
  provider: openai({
    apiKey: process.env.DEEP_SEEK_KEY!,
    baseURL: "https://api.deepseek.com",
  }),
  model: "deepseek-chat",
  system: "You are a helpful assistant.",
  messages: [{ role: "user", content: "Hello" }],
});

for await (const chunk of stream) {
  if (chunk.type === "text") process.stdout.write(chunk.text);
}

Streaming with Google Gemini

import { streamText, google } from "@opitacode/ocais";

const stream = streamText({
  provider: google({ apiKey: process.env.API_GOOGLE_CLOUD! }),
  model: "gemini-2.5-flash",
  messages: [{ role: "user", content: "Hello" }],
});

In AWS Lambda (Function URL + SSE)

import { streamText, openai, createSSEWriter } from "@opitacode/ocais";

export const handler = awslambda.streamifyResponse(
  async (event, responseStream) => {
    const writer = createSSEWriter(responseStream);
    const body = JSON.parse(event.body || "{}");

    const stream = streamText({
      provider: openai({
        apiKey: process.env.DEEP_SEEK_KEY!,
        baseURL: "https://api.deepseek.com",
      }),
      model: "deepseek-chat",
      system: "Eres Aura, asistente de Vibe Studio.",
      messages: body.messages,
    });

    for await (const chunk of stream) {
      writer.write(chunk);
    }
    writer.done();
  },
);

Server-side tool execution (multi-step)

import { streamText, openai } from "@opitacode/ocais";

const stream = streamText({
  provider: openai({ apiKey, baseURL: "https://api.deepseek.com" }),
  model: "deepseek-chat",
  system: "You can check the weather and book flights.",
  messages: [{ role: "user", content: "Book me a flight to Bogotá" }],
  tools: {
    getWeather: {
      description: "Get weather for a city",
      parameters: {
        type: "object",
        properties: { city: { type: "string" } },
        required: ["city"],
      },
      execute: async ({ city }) => {
        return { temp: 22, condition: "sunny" };
      },
    },
    bookFlight: {
      description: "Book a flight",
      parameters: { type: "object", properties: { to: { type: "string" } } },
      execute: async ({ to }) => ({ confirmation: `Flight to ${to} booked` }),
    },
  },
  maxSteps: 5, // up to 5 LLM round-trips
});

for await (const chunk of stream) {
  if (chunk.type === "text") process.stdout.write(chunk.text);
  if (chunk.type === "tool-call") console.log("tool:", chunk.toolName, chunk.args);
  if (chunk.type === "tool-result") console.log("result:", chunk.result);
}

Structured output (Zod)

import { generateObject, google } from "@opitacode/ocais";
import { z } from "zod";

const { object } = await generateObject({
  provider: google({ apiKey }),
  model: "gemini-2.5-flash",
  schema: z.object({
    name: z.string(),
    age: z.number(),
  }),
  prompt: "Generate a fictional person",
});
// object: { name: string; age: number }

Cancellation

Use standard AbortSignal and/or timeoutMs. Both throw typed errors.

import { streamText, OCAISAbortError, OCAISTimeoutError } from "@opitacode/ocais";

// AbortSignal (e.g. from a request)
const controller = new AbortController();
req.on("close", () => controller.abort());

try {
  for await (const chunk of streamText({
    provider: openai({ apiKey }),
    model: "deepseek-chat",
    messages: [{ role: "user", content: "Long task" }],
    signal: controller.signal,
  })) {
    if (chunk.type === "text") process.stdout.write(chunk.text);
  }
} catch (err) {
  if (err instanceof OCAISAbortError) {
    // request was closed by client
  } else if (err instanceof OCAISTimeoutError) {
    // exceeded timeoutMs
    console.log(`Timed out after ${err.elapsedMs}ms (limit: ${err.timeoutMs}ms)`);
  } else {
    throw err;
  }
}

// Or just timeoutMs without an explicit AbortController
for await (const chunk of streamText({
  ...,
  timeoutMs: 5000, // throw OCAISTimeoutError if it takes >5s
})) { ... }

Observability

Pass lifecycle hooks to track requests without wrapping the stream:

for await (const chunk of streamText({
  provider: openai({ apiKey }),
  model: "deepseek-chat",
  messages: [{ role: "user", content: "Hi" }],
  onStart: (ctx) => {
    console.log(`[start] model=${ctx.model} tools=${ctx.toolNames?.join(",")}`);
  },
  onComplete: (ctx) => {
    console.log(
      `[complete] steps=${ctx.steps} duration=${ctx.durationMs}ms ` +
      `tokens=${ctx.usage?.totalTokens ?? "?"}`,
    );
  },
  onError: (ctx) => {
    console.error(`[error] step=${ctx.step}`, ctx.error);
  },
  onAbort: () => {
    console.warn("[abort]");
  },
})) {
  // consume
}

The lifecycle hooks (onStart, onComplete, onError, onAbort) above are the canonical observability API.

Error hierarchy

All OCAIS errors extend OCAISError for easy instanceof checks:

OCAISError (base)
├── OCAISAbortError        // user cancelled via AbortSignal
├── OCAISTimeoutError      // exceeded timeoutMs (has .timeoutMs, .elapsedMs)
├── OCAISParseError        // malformed JSON, SSE parse error (has .raw)
├── OCAISToolError         // tool execute() threw (has .toolName, .toolCallId)
└── OCAISProviderError     // provider returned non-2xx (has .provider, .status)

API Reference

streamText(options)

| Option | Type | Required | Default | Description | |---|---|---|---|---| | provider | Provider | ✅ | — | Provider instance (openai(), google()) | | model | string | ✅ | — | Model name (e.g. deepseek-chat, gemini-2.5-flash) | | messages | Message[] | ✅ | — | Conversation history | | system | string | — | — | System prompt | | tools | Record<string, ToolDefinition> | — | — | Tools available to the model | | temperature | number | — | — | Sampling temperature | | maxTokens | number | — | — | Max output tokens | | maxSteps | number | — | 5 | Max LLM round-trips (for tool execution) | | signal | AbortSignal | — | — | Cancel the operation | | timeoutMs | number | — | — | Throw after N milliseconds | | onStart | (ctx) => void | — | — | Called before the first request | | onComplete | (ctx) => void | — | — | Called after successful stream | | onError | (ctx) => void | — | — | Called on any error | | onAbort | () => void | — | — | Called when signal/timeout fires |

generateObject(options)

Same as streamText except:

  • prompt: string (replaces messages + system)
  • schema: ZodSchema (required) — validates the output

createSSEWriter(stream)

Helper for writing to AWS Lambda's responseStream in SSE format. See Lambda example.

Providers

| Provider | Constructor | Compatible APIs | |---|---|---| | OpenAI-compatible | openai({ apiKey, baseURL? }) | OpenAI, DeepSeek, OpenRouter, Groq, etc. | | Google Gemini | google({ apiKey }) | Gemini 1.5, 2.0, 2.5 |

Roadmap

  • [x] Streaming text (v1.0)
  • [x] Server-side tool execution with multi-step (v1.0)
  • [x] Structured output via Zod (v1.0)
  • [x] AbortSignal + timeout + typed errors (v2.0)
  • [x] Observability hooks (v2.0)
  • [ ] Anthropic Claude provider (v2.1)
  • [ ] streamObject — streaming structured output (v2.1)
  • [ ] Local Ollama provider (v2.1)
  • [ ] Event-based observability API (v2.1)
  • [ ] Pre-built cultural prompt helpers (v2.2)

Development

npm install
npm run typecheck   # tsc --noEmit
npm test            # node --test --experimental-strip-types tests/*.test.ts

License

MIT © Opita Code