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

refyne-sdk

v0.1.13

Published

Official TypeScript SDK for the Refyne API - LLM-powered web extraction

Readme

Refyne SDK for TypeScript

Official TypeScript SDK for the Refyne API - LLM-powered web extraction that transforms unstructured websites into clean, typed JSON data.

API Endpoint: https://api.refyne.uk | Documentation: refyne.uk/docs

npm version CI

Features

  • Type-Safe: Full TypeScript support with generated types from OpenAPI
  • Zero Dependencies: Uses native fetch - works in Node.js 18+, Bun, and Deno
  • Smart Caching: Respects Cache-Control headers automatically
  • Auto-Retry: Handles rate limits and transient errors with exponential backoff
  • Streaming: Real-time job progress via Server-Sent Events
  • SOLID Design: Dependency injection for loggers, HTTP clients, and caches
  • API Version Compatibility: Warns about breaking changes

Installation

# npm
npm install refyne-sdk

# pnpm
pnpm add refyne-sdk

# bun
bun add refyne-sdk

Quick Start

import { Refyne } from 'refyne-sdk';

// Create client using builder pattern
const refyne = new Refyne.Builder()
  .apiKey(process.env.REFYNE_API_KEY!)
  .build();

// Extract structured data from a web page
const result = await refyne.extract({
  url: 'https://example.com/product/123',
  schema: {
    name: { type: 'string', description: 'Product name' },
    price: { type: 'number', description: 'Price in USD' },
    inStock: { type: 'boolean' },
  },
});

console.log(result.data);
// { name: "Example Product", price: 29.99, inStock: true }

Type-Safe Extraction

Define your expected data shape with TypeScript:

interface ProductData {
  name: string;
  price: number;
  description: string;
  inStock: boolean;
}

const result = await refyne.extract<ProductData>({
  url: 'https://example.com/product',
  schema: {
    name: 'string',
    price: 'number',
    description: 'string',
    inStock: 'boolean',
  },
});

// result.data is typed as ProductData
console.log(result.data.name);

Crawl Jobs

Extract data from multiple pages:

// Start a crawl job
const job = await refyne.crawl({
  url: 'https://example.com/products',
  schema: {
    name: 'string',
    price: 'number',
  },
  options: {
    followSelector: 'a.product-link',
    maxPages: 20,
    delay: '1s',
  },
});

console.log(`Job started: ${job.jobId}`);

// Poll for completion
let status = await refyne.jobs.get(job.jobId);
while (status.status === 'running') {
  await new Promise(r => setTimeout(r, 2000));
  status = await refyne.jobs.get(job.jobId);
  console.log(`Progress: ${status.pageCount} pages`);
}

// Get results
const results = await refyne.jobs.getResults(job.jobId);
console.log(`Extracted ${results.pageCount} pages`);

Configuration

The SDK uses a builder pattern for flexible configuration:

const refyne = new Refyne.Builder()
  .apiKey(process.env.REFYNE_API_KEY!)   // Required
  .baseUrl('https://api.refyne.uk')       // Override API URL
  .timeout(60000)                          // Request timeout (ms)
  .maxRetries(3)                           // Retry attempts
  .userAgentSuffix('MyApp/1.0')           // Custom User-Agent
  .logger(customLogger)                    // Custom logger
  .httpClient(customHttpClient)           // Custom HTTP client
  .cache(customCache)                      // Custom cache
  .cacheEnabled(true)                      // Enable/disable caching
  .build();

Custom Logger

Inject your own logger for debugging:

import { Logger } from 'refyne-sdk';

const myLogger: Logger = {
  debug: (msg, meta) => console.debug(`[DEBUG] ${msg}`, meta),
  info: (msg, meta) => console.info(`[INFO] ${msg}`, meta),
  warn: (msg, meta) => console.warn(`[WARN] ${msg}`, meta),
  error: (msg, meta) => console.error(`[ERROR] ${msg}`, meta),
};

const refyne = new Refyne.Builder()
  .apiKey(process.env.REFYNE_API_KEY!)
  .logger(myLogger)
  .build();

Custom Cache

The SDK respects Cache-Control headers. Provide a custom cache implementation:

import { Cache, CacheEntry } from 'refyne-sdk';

class RedisCache implements Cache {
  async get(key: string): Promise<CacheEntry | undefined> {
    // Fetch from Redis
  }

  async set(key: string, entry: CacheEntry): Promise<void> {
    // Store in Redis with TTL from entry.expiresAt
  }

  async delete(key: string): Promise<void> {
    // Delete from Redis
  }
}

const refyne = new Refyne.Builder()
  .apiKey(process.env.REFYNE_API_KEY!)
  .cache(new RedisCache())
  .build();

BYOK (Bring Your Own Key)

Use your own LLM provider API keys:

// Configure your OpenAI key
await refyne.llm.upsertKey({
  provider: 'openai',
  apiKey: process.env.OPENAI_API_KEY!,
  defaultModel: 'gpt-4o',
});

// Set fallback chain
await refyne.llm.setChain({
  chain: [
    { provider: 'openai', model: 'gpt-4o' },
    { provider: 'anthropic', model: 'claude-3-5-sonnet-20241022' },
    { provider: 'credits', model: 'default' },
  ],
});

// Extract using your keys
const result = await refyne.extract({
  url: 'https://example.com/product',
  schema: { title: 'string' },
  // Or override per-request:
  llmConfig: {
    provider: 'openai',
    model: 'gpt-4o-mini',
  },
});

console.log(`Used BYOK: ${result.usage?.isByok}`);

Error Handling

The SDK provides typed errors for different scenarios:

import {
  RefyneError,
  RateLimitError,
  ValidationError,
  AuthenticationError,
  UnsupportedAPIVersionError,
} from 'refyne-sdk';

try {
  await refyne.extract({ url, schema });
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter}s`);
  } else if (error instanceof ValidationError) {
    console.log('Validation errors:', error.errors);
  } else if (error instanceof AuthenticationError) {
    console.log('Invalid API key');
  } else if (error instanceof UnsupportedAPIVersionError) {
    console.log(`API version ${error.apiVersion} not supported`);
  } else if (error instanceof RefyneError) {
    console.log(`API error: ${error.message} (${error.status})`);
  }
}

API Reference

Main Client

| Method | Description | |--------|-------------| | refyne.extract(request) | Extract data from a single page | | refyne.crawl(request) | Start an async crawl job | | refyne.analyze(request) | Analyze a site and suggest schema | | refyne.getUsage() | Get usage statistics |

Sub-Clients

| Client | Methods | |--------|---------| | refyne.jobs | list(), get(id), getResults(id), stream(id) | | refyne.schemas | list(), get(id), create(), update(), delete() | | refyne.sites | list(), get(id), create(), update(), delete() | | refyne.keys | list(), create(), revoke(id) | | refyne.llm | listProviders(), listKeys(), upsertKey(), getChain(), setChain() |

Documentation

Development

# Install dependencies
npm install

# Run tests
npm test

# Build
npm run build

# Generate types from OpenAPI
npm run generate

# Generate API docs
npm run docs

Testing with Demo Site

A demo site is available at demo.refyne.uk for testing SDK functionality. The site contains realistic data across multiple content types:

| Endpoint | Content Type | Example Use Case | |----------|--------------|------------------| | https://demo.refyne.uk/products | Product catalog | Extract prices, descriptions, ratings | | https://demo.refyne.uk/jobs | Job listings | Extract salaries, requirements, companies | | https://demo.refyne.uk/blog | Blog posts | Extract articles, authors, tags | | https://demo.refyne.uk/news | News articles | Extract headlines, sources, timestamps |

Example:

const result = await refyne.extract({
  url: 'https://demo.refyne.uk/products/1',
  schema: {
    name: 'string',
    price: 'number',
    description: 'string',
    brand: 'string',
    rating: 'number',
  },
});

License

MIT License - see LICENSE for details.