@opendata.best/sdk
v0.1.0
Published
Official TypeScript/JavaScript SDK for the opendata.best API
Maintainers
Readme
@opendata/sdk
Official TypeScript/JavaScript SDK for the opendata.best API.
Features
- ✅ Full TypeScript support with strict types
- ✅ Zero runtime dependencies (native
fetch, Node 18+) - ✅ Auto-pagination via async iterators
- ✅ Automatic retry with exponential backoff
- ✅ Quota tracking from response headers
- ✅ Typed error hierarchy
Installation
npm install @opendata/sdkQuick Start
import { OpenData } from '@opendata/sdk';
const client = new OpenData({ apiKey: 'pk_live_xxx' });
// List products
const products = await client.products.list();
// Search records
const page = await client.products.search('us_sec', { q: 'Tesla', limit: 50 });
console.log(page.data); // Record<string, unknown>[]
console.log(page.meta.cursor); // string | null
// Auto-paginate
for await (const record of client.products.searchAll('us_sec', { q: 'Tesla' })) {
console.log(record);
}
// Export
const data = await client.products.export('us_sec', { format: 'json', limit: 5000 });
// Groups
const groups = await client.groups.list();
const results = await client.groups.search('us_compliance', { q: 'bank' });
// Quota info (updated after every request)
console.log(client.quota);Configuration
const client = new OpenData({
apiKey: 'pk_live_xxx', // Required
baseUrl: 'https://...', // Optional, default: https://opendata.best/api/v1/data
timeout: 30000, // ms, default: 30000
maxRetries: 3, // default: 3
});Error Handling
import {
OpenDataError,
AuthenticationError,
NotFoundError,
RateLimitError,
UpstreamError,
APIError,
} from '@opendata/sdk';
try {
await client.products.get('unknown');
} catch (err) {
if (err instanceof NotFoundError) {
console.log('Product not found');
} else if (err instanceof RateLimitError) {
console.log(`Quota exceeded (${err.quotaType}), retry after ${err.retryAfter}s`);
} else if (err instanceof AuthenticationError) {
console.log('Invalid API key');
}
}Error classes
| Class | Codes |
|-------|-------|
| AuthenticationError | AUTH_REQUIRED, AUTH_INVALID |
| PermissionError | PRODUCT_ACCESS_DENIED, EXPORT_NOT_ENABLED |
| NotFoundError | PRODUCT_NOT_FOUND |
| RateLimitError | QUOTA_EXCEEDED_DAILY, QUOTA_EXCEEDED_MONTHLY |
| UpstreamError | UPSTREAM_ERROR, UPSTREAM_TIMEOUT, UPSTREAM_RATE_LIMITED, UPSTREAM_UNAVAILABLE |
| APIError | INTERNAL_ERROR, unexpected |
| TimeoutError | Request timeout |
API Reference
client.products
| Method | Returns |
|--------|---------|
| list() | Promise<Product[]> |
| get(productId) | Promise<Product> |
| schema(productId) | Promise<ProductSchema> |
| search(productId, options?) | Promise<SearchResult> |
| searchAll(productId, options?) | AsyncGenerator<Record<string, unknown>> |
| export(productId, options?) | Promise<Record<string, unknown>[]> |
client.groups
| Method | Returns |
|--------|---------|
| list() | Promise<ProductGroup[]> |
| get(groupId) | Promise<ProductGroup> |
| search(groupId, options?) | Promise<SearchResult> |
| searchAll(groupId, options?) | AsyncGenerator<Record<string, unknown>> |
client.health()
No auth required. Returns server health status.
client.stats()
Returns usage stats scoped to your API key.
client.quota
Returns QuotaInfo extracted from the last response headers:
{
dailyLimit?: number;
dailyRemaining?: number;
monthlyLimit?: number;
monthlyRemaining?: number;
plan?: string;
}License
MIT
