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

@lotagate/sdk

v0.1.7

Published

Type-safe JavaScript and TypeScript client for the LotaGate AI gateway.

Readme

@lotagate/sdk

Official JavaScript and TypeScript SDK for the LotaGate AI gateway.

The SDK provides one typed client for the capabilities exposed by LotaGate. It keeps provider routing, provider credentials, usage metering, billing and provider-specific URLs behind the gateway API.

Highlights

  • ESM-first JavaScript and TypeScript API.
  • Node.js 22 or newer.
  • Text generation, embeddings, image generation and image editing.
  • Speech synthesis, audio transcription and audio translation.
  • Video generation, operation polling and video download.
  • Google-native v1beta text, embedding, image, prediction and interactions APIs.
  • Function tools, tool choice, tool calls and tool results across supported gateway formats.
  • Model discovery and model details.
  • Typed gateway and SDK errors with request and correlation identifiers.
  • Streaming support for text generation, speech synthesis and audio transcription.
  • Multipart upload support for image and audio inputs.
  • Bounded response and stream buffers, request timeouts and cancellation.

Text resources expose provider-compatible content types instead of a single cross-provider multimodal abstraction. Anthropic native document blocks are available through client.messages; Responses requests continue to use the gateway's canonical input_file shape.

Table of contents

Requirements

  • Node.js 22+.
  • An environment with the standard Fetch API, FormData, Blob, streams, AbortController, TextEncoder and TextDecoder globals.
  • A LotaGate API key.

The package is ESM-only. Use import syntax and ensure your application is configured for ESM, for example with "type": "module" in package.json.

Installation

npm install @lotagate/sdk

For pnpm:

pnpm add @lotagate/sdk

For yarn:

yarn add @lotagate/sdk

Quick start

Store the API key in a server-side environment variable. Do not expose it in a browser bundle, client-side application code or source control.

import { LotaGate } from '@lotagate/sdk';

const client = new LotaGate({
  apiKey: process.env.LOTA_GATE_API_KEY!,
});

const response = await client.chat.completions.create({
  model: 'your-text-model',
  messages: [
    { role: 'user', content: 'Explain how an API gateway helps application teams.' },
  ],
});

console.log(response.choices[0]?.message.content);

The default production gateway is:

https://api.lotagate.com

Client configuration

import { LotaGate } from '@lotagate/sdk';

const client = new LotaGate({
  apiKey: process.env.LOTA_GATE_API_KEY!,
  baseURL: 'https://api.lotagate.com',
  timeoutMs: 60_000,
  defaultHeaders: {
    'x-application-name': 'my-service',
  },
});

| Option | Default | Purpose | | --- | --- | --- | | apiKey | Required | Bearer token sent to the gateway. | | baseURL | https://api.lotagate.com | Gateway base URL. | | timeoutMs | 60000 | Default request timeout. | | defaultHeaders | None | Headers added to every request. | | fetch | Runtime fetch | Optional fetch implementation for tests or custom runtimes. |

Each resource method also accepts request options:

const response = await client.models.list({
  timeoutMs: 10_000,
  signal: abortController.signal,
  headers: { 'x-request-purpose': 'model-selection' },
});

Only apiKey is required when creating the client. defaultHeaders is optional and is intended for application metadata, tracing or similar headers; the SDK always manages the Authorization header from apiKey.

Gateway payload limits

The SDK validates JSON and media file/aggregate payloads before sending them using the same limits as the public gateway contract. The server remains authoritative for the complete raw multipart envelope:

| Payload | Limit | | --- | ---: | | JSON request body on /v1 and /v1beta | 25 MB decimal | | Audio file for transcription or translation | 50 MB decimal | | Audio multipart request envelope | 70 MB decimal raw request body | | Image edit: each image | 47 MB decimal | | Image edit: mask | 4 MB decimal | | Image edit: total images and mask | 128 MB decimal | | Image edit: number of images | 16 | | Image-edit multipart request envelope | 150 MB decimal raw request body |

These limits are not configurable through the SDK. The server remains the authoritative validator, and provider-specific limits may be stricter after the gateway resolves a model.

The JSON limit is measured on the serialized UTF-8 request body, including the prompt, history, tool definitions/results, and inline Base64 media. Multipart file, aggregate-file, and raw-request limits are separate. Raw multipart envelope limits include boundaries and form metadata; provider limits may still be stricter after the gateway resolves a model.

The SDK also has fixed internal response and SSE safety guardrails to bound buffering and stream parsing. They are implementation details and are not exposed as client options.

API reference

The client exposes these resource groups:

client.chat.completions
client.messages
client.responses
client.embeddings
client.images.generations
client.images.edits
client.audio.speech
client.audio.transcriptions
client.audio.translations
client.video.generations
client.video.operations
client.google.models
client.google.interactions
client.google.operations
client.models

Text generation

Chat completions

const response = await client.chat.completions.create({
  model: 'your-text-model',
  messages: [
    { role: 'system', content: 'You are a concise technical assistant.' },
    { role: 'user', content: 'Summarize this incident report.' },
  ],
  temperature: 0.2,
  max_tokens: 500,
});

Method: client.chat.completions.create(request, options?)

The request requires model and messages. The supported common fields are temperature, top_p, max_tokens, max_completion_tokens, max_output_tokens, stop, stop_sequences, tools, tool_choice, toolChoice, toolConfig, reasoning_effort and stream.

Use reasoning_effort to control the model's reasoning effort for the request:

const response = await client.chat.completions.create({
  model: 'your-reasoning-model',
  messages: [{ role: 'user', content: 'Analyze this incident.' }],
  reasoning_effort: 'high',
});

Function tools

Tools use the gateway's normalized function-tool contract. Tool calls returned by the model are available on message.tool_calls and streaming deltas.

const response = await client.chat.completions.create({
  model: 'your-text-model',
  messages: [{ role: 'user', content: 'What is the weather in Hanoi?' }],
  tools: [{
    type: 'function',
    function: {
      name: 'get_weather',
      description: 'Get current weather for a city.',
      parameters: {
        type: 'object',
        properties: { city: { type: 'string' } },
        required: ['city'],
      },
    },
  }],
  tool_choice: 'auto',
});

const toolCall = response.choices[0]?.message.tool_calls?.[0];

To send the tool result back, append an assistant message with tool_calls, followed by a role: 'tool' message with the matching tool_call_id. The same ToolDefinition type accepts the OpenAI, Anthropic and Google tool declaration shapes supported by the gateway. The SDK validates and normalizes these forms through one shared utility before sending them to the normalized text resources and Google Interactions. Google-native generateContent keeps Google's native payload unchanged, so use its functionDeclarations shape there.

Messages

const response = await client.messages.create({
  model: 'your-text-model',
  system: 'You are a helpful assistant.',
  messages: [{ role: 'user', content: 'Write a short release note for this change.' }],
  temperature: 0.4,
});

Method: client.messages.create(request, options?)

The request requires model and messages. Use system for a system instruction. This resource follows the server's Anthropic-compatible message contract, including tool-use, tool-result and native document content blocks.

Anthropic documents are sent inline through content without the Files API:

const response = await client.messages.create({
  model: 'your-anthropic-model',
  messages: [{
    role: 'user',
    content: [
      {
        type: 'document',
        source: {
          type: 'text',
          media_type: 'text/plain',
          data: 'Hello from the attached document.',
        },
      },
      { type: 'text', text: 'Summarize the document.' },
    ],
  }],
});

The supported inline document sources are text, base64 and url. Use text/* media types with text; use application/pdf with PDF base64 or url sources. file_id and the Anthropic Files API are not part of this SDK contract.

Responses

const response = await client.responses.create({
  model: 'your-text-model',
  instructions: ['Answer in three bullet points.', { type: 'input_text', text: 'Use plain language.' }],
  input: [{ role: 'user', content: 'What are the main benefits of typed API clients?' }],
  tools: [{
    type: 'function',
    function: {
      name: 'get_weather',
      description: 'Get current weather for a city.',
      parameters: {
        type: 'object',
        properties: { city: { type: 'string' } },
        required: ['city'],
      },
      strict: true,
    },
  }],
  tool_choice: { type: 'function', name: 'get_weather' },
});

Method: client.responses.create(request, options?)

The request requires model and input. input can be a string or a message array. For tool-enabled turns it can also contain Responses function-call and function-call-output items, allowing a tool result to be sent back with its call_id. instructions can be a string or an array of strings/text items. Responses function tools accept the shared function definition shape and are normalized to the native flat payload (name, description, parameters, and optional strict). tool_choice can select a function with the native { type: 'function', name: '...' } form or the shared nested function form. Responses usage may expose input_tokens and output_tokens in addition to the common token fields.

Responses does not use Anthropic native document blocks. For file content in client.responses.create, use the canonical input_file content part with file_data or file_url and an optional filename.

Streaming text responses

Set stream: true to receive an async iterable. The SDK parses SSE events and handles chunk boundaries for you.

const stream = client.chat.completions.create({
  model: 'your-text-model',
  messages: [{ role: 'user', content: 'Explain rate limiting in one paragraph.' }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta.content ?? '');
}

The same streaming pattern is available for:

client.messages.create({
  model: 'your-text-model',
  messages: [{ role: 'user', content: 'Stream a message response.' }],
  stream: true,
});
client.responses.create({
  model: 'your-text-model',
  input: 'Stream a response.',
  stream: true,
});

Those resources return AsyncIterable<TextStreamEvent>.

Google-native v1beta

Use client.google when the application needs Google's native payload shape instead of the normalized /v1 gateway contract.

const model = await client.google.models.retrieve('your-text-model');

const response = await client.google.models.generateContent('your-text-model', {
  contents: [{
    role: 'user',
    parts: [{ text: 'Explain vector search in one paragraph.' }],
  }],
  generationConfig: {
    temperature: 0.2,
    maxOutputTokens: 300,
  },
});

Available model operations are:

  • client.google.models.retrieve(modelCode, options?)
  • client.google.models.generateContent(modelCode, request, options?)
  • client.google.models.streamGenerateContent(modelCode, request, options?)
  • client.google.models.embedContent(modelCode, request, options?)
  • client.google.models.generateImages(modelCode, request, options?)
  • client.google.models.predict(modelCode, request, options?)
  • client.google.models.predictLongRunning(modelCode, request, options?)

The prediction methods use the server's native instances and parameters fields. Long-running predictions return a Google operation:

const operation = await client.google.models.predictLongRunning('your-video-model', {
  instances: [{ prompt: 'A slow sunrise over a quiet coastal town.' }],
  parameters: { aspectRatio: '16:9' },
});

const status = await client.google.operations.retrieve(operation.name);
if (status.done) {
  const video = await client.google.operations.downloadVideo(operation.name);
}

Google Interactions are available through client.google.interactions.create:

const interaction = await client.google.interactions.create({
  model: 'your-text-model',
  input: 'What is the weather in Hanoi?',
  tools: [{
    type: 'function',
    name: 'get_weather',
    description: 'Get current weather for a city.',
    parameters: {
      type: 'object',
      properties: { city: { type: 'string' } },
      required: ['city'],
    },
  }],
  tool_choice: 'auto',
});

Set stream: true to receive an async iterable of native stream events. Use client.google.operations.downloadVideo(operationId) for completed video operations.

The existing client.video resource is the concise video-specific alias for the supported :generateVideos and operation video routes.

Embeddings

const response = await client.embeddings.create({
  model: 'your-embedding-model',
  input: [
    'First document to index.',
    'Second document to index.',
  ],
  encoding_format: 'float',
  dimensions: 1536,
});

const vectors = response.data.map((item) => item.embedding);

Method: client.embeddings.create(request, options?)

Required fields are model and input. input can be a string, string array, token array or token-array batch. Optional fields include encoding_format, dimensions and user.

Images

Image generation

const response = await client.images.generations.create({
  model: 'your-image-model',
  prompt: 'A clean editorial illustration of a secure API gateway.',
  n: 1,
  size: '1024x1024',
  quality: 'high',
  response_format: 'b64_json',
});

const image = response.data[0];

Method: client.images.generations.create(request, options?)

Required fields are model and prompt. Supported fields are n, size, quality, background, output_format, output_compression, moderation, user and response_format.

Image editing

Image edits use multipart form data. The image field accepts one file or an array of files. Upload values can be Blob, File, ArrayBuffer or Uint8Array.

import { readFile } from 'node:fs/promises';

const sourceImage = await readFile('./assets/source.png');
const mask = await readFile('./assets/mask.png');

const response = await client.images.edits.create({
  model: 'your-image-model',
  prompt: 'Replace the background with a soft blue gradient.',
  image: sourceImage,
  mask,
  filename: 'source.png',
  n: 1,
  size: '1024x1024',
  quality: 'high',
  background: 'transparent',
  output_format: 'png',
  output_compression: 80,
  moderation: 'low',
  user: 'internal-image-service',
  input_fidelity: 'high',
  response_format: 'b64_json',
});

Method: client.images.edits.create(request, options?)

Required fields are model, prompt and image. The optional fields are mask, filename, n, size, quality, background, output_format, output_compression, moderation, user, input_fidelity and response_format.

Audio

Speech synthesis

const audio = await client.audio.speech.create({
  model: 'your-speech-model',
  input: 'Your deployment completed successfully.',
  voice: 'default',
  instructions: 'Speak clearly and professionally.',
  response_format: 'mp3',
  speed: 1,
});

await import('node:fs/promises').then(({ writeFile }) =>
  writeFile('./output.mp3', new Uint8Array(audio.data)),
);

Method: client.audio.speech.create(request, options?)

The request requires model, input and voice. Optional fields are instructions, response_format, speed and stream_format. Without stream_format: 'sse', it returns an object containing audio data as an ArrayBuffer and response headers.

Streaming speech

Set stream_format: 'sse' to receive AsyncIterable<AudioSpeechStreamEvent>:

const events = client.audio.speech.create({
  model: 'your-speech-model',
  input: 'Stream this audio response.',
  voice: 'default',
  stream_format: 'sse',
});

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

The camelCase alias streamFormat: 'sse' is also accepted when that naming style is preferred.

Transcription

import { readFile } from 'node:fs/promises';

const transcript = await client.audio.transcriptions.create({
  model: 'your-transcription-model',
  file: await readFile('./assets/meeting.wav'),
  filename: 'meeting.wav',
  language: 'en',
  prompt: 'Use proper product names and punctuation.',
  response_format: 'verbose_json',
  temperature: 0.1,
  timestamp_granularities: ['segment'],
  include: ['logprobs'],
});

console.log(transcript.text);

Method: client.audio.transcriptions.create(request, options?)

Required fields are model and file. Supported optional fields are filename, language, prompt, response_format, temperature, timestamp_granularities, include and stream.

Streaming transcription

Set stream: true to receive AsyncIterable<AudioTranscriptionStreamEvent>:

const events = client.audio.transcriptions.create({
  model: 'your-transcription-model',
  file: await readFile('./assets/meeting.wav'),
  filename: 'meeting.wav',
  response_format: 'verbose_json',
  stream: true,
});

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

Translation

const translation = await client.audio.translations.create({
  model: 'your-translation-model',
  file: await readFile('./assets/meeting.wav'),
  filename: 'meeting.wav',
  prompt: 'Preserve technical terminology.',
  response_format: 'text',
  temperature: 0.2,
});

console.log(translation.text);

Method: client.audio.translations.create(request, options?).

Required fields are model and file. Supported optional fields are filename, prompt, response_format and temperature.

Video

Start a generation

Video generation returns an asynchronous operation. Keep the operation name and poll it until it is complete.

const operation = await client.video.generations.create({
  model: 'your-video-model',
  instances: [{ prompt: 'A slow aerial shot over a quiet coastal town at sunrise.' }],
  parameters: {
    aspectRatio: '16:9',
  },
});

console.log(operation.name);

Method: client.video.generations.create(request, options?).

The request requires model and instances. Each instance requires prompt. Provider-compatible values can be passed through parameters.

Retrieve operation status and download the video

const operationId = operation.name;

const status = await client.video.operations.retrieve(operationId);
if (status.done) {
  const video = await client.video.operations.download(operationId);
  await import('node:fs/promises').then(({ writeFile }) =>
    writeFile('./output.mp4', new Uint8Array(video.data)),
  );
}

Methods:

  • client.video.operations.retrieve(operationId, options?)
  • client.video.operations.download(operationId, options?)

The operation identifier must be a Google UUID v4. It may be supplied either as the UUID itself or as a gateway operation name such as operations/123e4567-e89b-42d3-a456-426614174000.

Models

const models = await client.models.list();
const model = await client.models.retrieve('your-text-model');

console.log(models.data);
console.log(model.id);

Methods:

  • client.models.list(options?)
  • client.models.retrieve(modelCode, options?)

Model codes are URL-encoded by the SDK. An empty model code is rejected before the request is sent.

Error handling

Gateway failures and SDK transport failures are represented by LotaGateError.

import { LotaGateError, SdkErrorCode } from '@lotagate/sdk';

try {
  await client.models.retrieve('your-model');
} catch (error: unknown) {
  if (error instanceof LotaGateError) {
    console.error({
      statusCode: error.statusCode,
      errorCode: error.errorCode,
      requestId: error.requestId,
      correlationId: error.correlationId,
      details: error.details,
    });

    if (error.errorCode === SdkErrorCode.RequestTimeout) {
      // Retry only when the operation is safe and the application policy allows it.
    }
  }
  throw error;
}

LotaGateError can expose:

  • statusCode: HTTP status, or 0 for a failure before an HTTP response.
  • errorCode: gateway error code or an SDK error code.
  • requestId: request identifier returned by the gateway.
  • correlationId: correlation identifier returned by the gateway.
  • details: structured gateway error details, when available.

SDK transport error codes are exported through SdkErrorCode:

| Code | Meaning | | --- | --- | | REQUEST_TIMEOUT | The request exceeded its timeout. | | REQUEST_ABORTED | The caller cancelled the request. | | NETWORK_ERROR | The request could not reach the gateway. | | REQUEST_SERIALIZATION_ERROR | The request body could not be serialized. | | REQUEST_VALIDATION_ERROR | The SDK rejected an invalid request before sending it. | | REQUEST_PAYLOAD_TOO_LARGE | A request exceeded a gateway payload limit. | | RESPONSE_BODY_READ_ERROR | The response body could not be read. | | RESPONSE_PARSE_ERROR | The response or stream event was malformed. | | RESPONSE_TOO_LARGE | A buffered response exceeded its limit. | | STREAM_EVENT_TOO_LARGE | An SSE line or event exceeded its limit. | | EMPTY_STREAM_RESPONSE | A stream response contained no usable events. |

Do not log API keys, uploaded file contents, prompts containing secrets or untrusted full response bodies. Use request and correlation IDs to investigate failures safely.

Cancellation and timeouts

Use an AbortController for caller-controlled cancellation:

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5_000);

try {
  await client.chat.completions.create(
    {
      model: 'your-text-model',
      messages: [{ role: 'user', content: 'Generate a short status update.' }],
    },
    { signal: controller.signal },
  );
} finally {
  clearTimeout(timeout);
}

Prefer the SDK timeoutMs option for a standard request deadline and AbortSignal when cancellation is tied to a request lifecycle or user action.

TypeScript and runtime notes

The SDK exports a curated set of request, response and stream contracts for typed wrappers and API integrations. Direct SDK calls do not require importing these types because TypeScript infers them from each client method.

Public type catalog

| Area | Public types | | --- | --- | | Client and errors | LotaGate, LotaGateCore, LotaGateClientOptions, RequestOptions, LotaGateErrorDetails, SdkErrorCodeValue | | Common responses | BinaryResponse, Usage | | Text generation | TextGenerationRequest, TextGenerationOptions, ReasoningEffort, TextMessage, TextMessageContent, TextContentPart, TextContentTextPart, TextImageContentPart, TextFileContentPart, AnthropicImageContentPart, AnthropicDocumentSource, AnthropicDocumentContentPart, AnthropicMessageContentPart, AnthropicMessageContent, MessageRequestMessage, AnthropicToolResultContentPart, AnthropicToolUseContentPart, GoogleFunctionCallContentPart, GoogleInlineDataContentPart, TextMessageDelta, TextRole, AssistantResponseMessage, AssistantTextMessage, UserTextMessage, ToolTextMessage, ToolDefinition, OpenAiFunctionTool, NamedToolDefinition, GoogleToolDefinition, GoogleInteractionToolDefinition, FunctionToolDefinition, GoogleFunctionDeclaration, JsonSchema, ToolChoice, ToolChoiceMode, ToolChoiceModeObject, NamedToolChoice, FunctionToolChoice, GoogleToolChoice, ToolCall, ChatCompletionRequest, ChatCompletionResponse, ChatCompletionChoice, ChatCompletionChunk, ChatCompletionChunkChoice, MessageRequest, MessageResponse, ResponseInput, ResponseInstruction, ResponseRequest, ResponseResponse, ResponseOutput, TextStreamEvent | | Embeddings | EmbeddingInput, EmbeddingRequest, EmbeddingResponse, EmbeddingItem | | Images | ImageGenerationRequest, ImageGenerationResponse, ImageResult, ImageEditRequest, ImageQuality, ImageBackground, ImageOutputFormat, ImageInputFidelity, UploadFile | | Audio | SpeechRequest, SpeechResponseFormat, SpeechStreamFormat, AudioSpeechStreamEvent, AudioTranscriptionRequest, AudioTranscriptionResponseFormat, AudioTranscriptionStreamEvent, AudioTranslationRequest, AudioTranslationResponseFormat, AudioTimestampGranularity, AudioTextResponse | | Video and Google | VideoGenerationRequest, VideoPromptInstance, VideoOperation, GoogleContent, GoogleContentPart, GoogleSystemInstruction, GoogleGenerationConfig, GoogleNativePayload, GoogleGenerateContentRequest, GoogleEmbedContentRequest, GooglePredictionRequest, GoogleInteractionInput, GoogleInteractionRequest, GoogleModel, GoogleOperation, GoogleStreamEvent | | Models | ModelListResponse, ModelSummary |

For example, a wrapper can reuse the public request and response contracts:

import { LotaGate } from '@lotagate/sdk';
import type {
  ChatCompletionRequest,
  ChatCompletionResponse,
} from '@lotagate/sdk';

export async function createChat(
  client: LotaGate,
  request: ChatCompletionRequest & { stream?: false },
): Promise<ChatCompletionResponse> {
  return client.chat.completions.create(request);
}

Low-level transport, multipart, validation, parser and internal base types are not part of the public package contract.

The SDK uses the standard Web platform interfaces for uploads and responses. For Node.js file uploads, Uint8Array values from node:fs/promises can be passed directly, as shown in the examples.

Package and licensing

  • Package: @lotagate/sdk
  • License: LotaGate Proprietary Software License v1.0 (see LICENSE.md)
  • Website: LotaGate
  • Support and bug reports: Contact LotaGate