SDKsTypeScript

TypeScript SDK

The official Orsa TypeScript SDK for Node.js and edge runtimes.

Installation

npm install @orsa.dev/sdk
# or
bun add @orsa.dev/sdk
# or
pnpm add @orsa.dev/sdk
# or
yarn add @orsa.dev/sdk

Requirements: Node.js 18+ or any runtime with native fetch. Ships ESM + CJS + TypeScript types.

Playground

The repo ships a local Next.js sandbox at apps/sdk-playground that exercises every SDK method against a running API — useful both as a working reference and a place to feel out the developer experience. From the monorepo root:

cp apps/sdk-playground/.env.example apps/sdk-playground/.env.local
# add ORSA_API_KEY=or_live_…
bun --filter='@orsa/sdk-playground' run dev
# → http://localhost:3300

The /brand, /web, and /ai pages give you a form-driven UI for each method; /errors demonstrates the four Orsa*Error classes live; /dx-notes is a copy-paste-ready DX checklist.

Quick Start

import Orsa from '@orsa.dev/sdk';
 
const client = new Orsa({ apiKey: process.env.ORSA_API_KEY! });
 
const brand = await client.brand.retrieve({ domain: 'stripe.com' });
console.log(brand.title);              // "Stripe"
console.log(brand.colors[0]);          // { hex: "#635BFF", name: "Iris" }

Every method returns the unwrapped response payload — the { data, _meta } envelope is unpacked for you.

Configuration

const client = new Orsa({
  apiKey: 'or_live_...',           // Required
  baseUrl: 'https://api.orsa.dev', // Optional (default)
  timeout: 30_000,                  // Per-request timeout in ms
  maxRetries: 3,                    // Retry on 429/5xx and connection errors
  userAgent: 'my-app/1.0',          // Appended after the SDK identifier
});
OptionTypeDefaultDescription
apiKeystringYour Orsa API key (required)
baseUrlstringhttps://api.orsa.devAPI base URL
timeoutnumber30_000Request timeout in ms
maxRetriesnumber3Max retries on 429/5xx + connection errors
userAgentstringOptional suffix appended to the SDK User-Agent

Per-call overrides via RequestOptions:

const ac = new AbortController();
await client.brand.retrieve(
  { domain: 'stripe.com' },
  { signal: ac.signal, timeout: 5_000, headers: { 'x-correlation-id': 'abc' } },
);

Namespaces

client.brand — Brand Intelligence

// Full brand record (Context.dev-shaped: array colors/logos/socials + *_legacy mirrors)
const brand = await client.brand.retrieve({ domain: 'stripe.com' });
 
// Aliases — legacy dict-shaped Brand
const byDomain = await client.brand.retrieveByDomain({ domain: 'stripe.com' });
const byEmail  = await client.brand.retrieveByEmail({ email: 'support@stripe.com' });
const byTicker = await client.brand.retrieveByTicker({ ticker: 'AAPL' });
const byISIN   = await client.brand.retrieveByISIN({ isin: 'US0378331005' });
 
// Fuzzy name match — returns { brand, matches: [{ id, domain, title, similarity }] }
const byName = await client.brand.retrieveByName({ name: 'Stripe' });
 
// Lightweight profile — just domain/title/logo/primaryColor/industries
const simple = await client.brand.retrieveSimplified({ domain: 'linear.app' });
 
// Inline base64 PNG screenshot
const shot = await client.brand.screenshot({ domain: 'stripe.com' });
 
// Design system: W3C-DTCG tokens + components + paste-ready DESIGN.md
const guide = await client.brand.styleguide({ domain: 'stripe.com' });
 
// Fonts only — same browser pool, half the cost
const fonts = await client.brand.fonts({ domain: 'stripe.com' });
 
// Industry classification (industries array, primary_industry)
const naics = await client.brand.naics({ domain: 'stripe.com' });
 
// Identify the merchant behind a bank transaction descriptor
const txn = await client.brand.transactionIdentifier({
  transactionInfo: 'SQ *VERCEL INC 555-1234 CA',
});

client.web — Web Scraping

// Single-page scrape. mode defaults to 'markdown' — pass 'html' or 'text' for those.
const page = await client.web.scrape({ url: 'https://stripe.com/docs' });
console.log(page.markdown);
 
const raw  = await client.web.scrape({ url: 'https://stripe.com', mode: 'html' });
const text = await client.web.scrape({ url: 'https://stripe.com', mode: 'text' });
 
// Image extraction with role classification (logo / hero / product / icon / decorative)
const images = await client.web.scrapeImages({ url: 'https://stripe.com' });
const logos  = images.images.filter((i) => i.role === 'logo');
 
// Sitemap discovery — reads robots.txt, walks sitemap-index files,
// returns up to 1,000 URLs plus path-grouped buckets
const sitemap = await client.web.scrapeSitemap({ domain: 'stripe.com' });
console.log(sitemap.groups.docs?.count);

client.ai — AI Extraction

// Natural-language prompt against a domain. `result` is a string; ask for
// JSON explicitly if you want structured output.
const ans = await client.ai.query({
  domain: 'stripe.com',
  dataToExtract: 'Return the pricing plans as a JSON array.',
});
console.log(ans.result);
console.log(ans.usage.input_tokens);
 
// Tool-use-enforced product extraction from the homepage
const products = await client.ai.products({ domain: 'linear.app' });
for (const p of products.products) {
  console.log(p.name, p.pricing?.amount);
}

Error Handling

All errors extend OrsaError:

import {
  OrsaError,           // base class
  OrsaAPIError,        // 4xx/5xx response — has .status, .errorCode, .requestId
  OrsaTimeoutError,    // request exceeded the timeout / was aborted
  OrsaConnectionError, // network failure after retries
} from '@orsa.dev/sdk';
 
try {
  await client.brand.retrieve({ domain: 'stripe.com' });
} catch (err) {
  if (err instanceof OrsaAPIError && err.status === 404) {
    console.log('No brand cached yet — request /retrieve first.');
  } else if (err instanceof OrsaTimeoutError) {
    console.log('Took too long.');
  } else if (err instanceof OrsaConnectionError) {
    console.log('Network failure.');
  } else {
    throw err;
  }
}

Retries are automatic for 429, 500, 502, 503 and connection errors (exponential backoff, honors Retry-After). 4xx errors throw immediately.

TypeScript Types

All response and parameter types are exported:

import type {
  // Config
  OrsaConfig,
  RequestOptions,
  ResponseMeta,
 
  // Brand
  Brand,
  BrandContextDev,
  SimplifiedBrand,
  BrandSearchResult,
 
  // Visual
  Styleguide,
  FontsResult,
  Screenshot,
 
  // Classification
  NaicsResult,
  TransactionIdentifierResult,
 
  // Scraping
  ScrapeResult,
  ScrapeMode,
  ScrapeImagesResult,
  ScrapeSitemapResult,
  ScrapedImage,
  ImageRole,
 
  // AI
  AIQueryResult,
  AIProductsResult,
  ExtractedProduct,
} from '@orsa.dev/sdk';

Framework Examples

Next.js Server Component

import Orsa from '@orsa.dev/sdk';
 
const client = new Orsa({ apiKey: process.env.ORSA_API_KEY! });
 
export default async function BrandPage({ params }: { params: { domain: string } }) {
  const brand = await client.brand.retrieve({ domain: params.domain });
 
  return (
    <div>
      <h1>{brand.title}</h1>
      <p>{brand.description}</p>
      <div style={{ background: brand.colors[0]?.hex }} />
    </div>
  );
}

Hono / Express

import Orsa from '@orsa.dev/sdk';
import { Hono } from 'hono';
 
const app = new Hono();
const orsa = new Orsa({ apiKey: process.env.ORSA_API_KEY! });
 
app.get('/brand/:domain', async (c) => {
  const brand = await orsa.brand.retrieve({ domain: c.req.param('domain') });
  return c.json(brand);
});