@stagewise/api-client
v4.0.0
Published
Type-safe API client for the Stagewise platform, powered by Eden Treaty
Readme
@stagewise/api-client
A type-safe Node.js / browser client for the Stagewise API, powered by Eden Treaty and ElysiaJS.
Every route, parameter, header, and response body is fully typed — you get autocomplete and compile-time safety with zero code generation.
Installation
npm install @stagewise/api-client
# or
pnpm add @stagewise/api-client
# or
yarn add @stagewise/api-clientQuick Start
import { createApiClient } from '@stagewise/api-client';
const api = createApiClient('https://api.stagewise.io');
// Health check
const { data } = await api.v1.health.get();
console.log(data); // { status: 'ok', timestamp: '...' }Usage
Creating a Client
import { createApiClient } from '@stagewise/api-client';
const api = createApiClient('https://api.stagewise.io', {
// Static headers
headers: {
Authorization: 'Bearer <token>',
},
});Dynamic Headers
Pass a function to compute headers per-request (useful for auth tokens that refresh):
const api = createApiClient('https://api.stagewise.io', {
headers: () => ({
Authorization: `Bearer ${getAccessToken()}`,
}),
});Custom Fetch
Provide your own fetch implementation (handy for testing or server-side usage):
const api = createApiClient('https://api.stagewise.io', {
fetch: customFetch,
});API Namespaces
All endpoints live under the v1 namespace, mirroring the backend route structure:
const api = createApiClient('https://api.stagewise.io');
// All calls go through api.v1.*
api.v1.health.get();
api.v1.billing.plan.get();
api.v1.ai.chat.completions.post({ ... });Health
// Basic health check
const { data } = await api.v1.health.get();
// Database health check
const { data: dbHealth } = await api.v1.health.db.get();AI — Chat Completions & Image Generation
// Chat completion
const { data } = await api.v1.ai.chat.completions.post({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello!' }],
stream: false,
});
// Image generation
const { data: image } = await api.v1.ai.images.generations.post({
model: 'dall-e-3',
prompt: 'A futuristic city skyline',
});Billing
// Get current plan
const { data: plan } = await api.v1.billing.plan.get();
// Get available prices
const { data: prices } = await api.v1.billing.prices.get();
// Create checkout session
const { data: checkout } = await api.v1.billing.checkout.post({
plan: 'pro',
successUrl: 'https://example.com/success',
cancelUrl: 'https://example.com/cancel',
});
// Open customer portal
const { data: portal } = await api.v1.billing.portal.post({
returnUrl: 'https://example.com/settings',
});
// Get prepaid credit balance
const { data: credits } = await api.v1.billing.credits.get();
// Purchase extra credits
const { data: purchase } = await api.v1.billing.credits.purchase.post({
successUrl: 'https://example.com/success',
cancelUrl: 'https://example.com/cancel',
});
// List invoices
const { data: invoices } = await api.v1.billing.invoices.get();Usage
// Current usage stats
const { data: current } = await api.v1.usage.current.get();
// Plan limits
const { data: limits } = await api.v1.usage.limits.get();
// Usage history (last 30 days)
const { data: history } = await api.v1.usage.history.get({
query: { days: 30 },
});Inspiration
// List inspiration websites (paginated, filterable)
const { data: sites } = await api.v1.inspiration.index.get({
query: { limit: 20, offset: 0 },
});
// List all tags
const { data: tags } = await api.v1.inspiration.tags.get();Context7
// Search libraries
const { data: results } = await api.v1.context7.search.get({
query: { query: 'react state management' },
});
// Get documentation
const { data: docs } = await api.v1.context7.docs.get({
query: { libraryId: '...', topic: 'hooks' },
});Types
The client is fully typed. Import types directly:
import type { App, ApiClient } from '@stagewise/api-client';
// ApiClient is the full treaty client type
// App is the raw ElysiaJS app type (for advanced use cases)Every call returns { data, error, status } — Eden Treaty's standard response shape. TypeScript will narrow data and error based on the status code:
const { data, error } = await api.v1.billing.plan.get();
if (error) {
// error is typed per status code
console.error(error);
return;
}
// data is fully typed here
console.log(data.plan, data.status);Error Handling
Eden Treaty returns errors as values rather than throwing:
const { data, error, status } = await api.v1.billing.plan.get();
if (error) {
switch (status) {
case 401:
console.error('Unauthorized');
break;
case 403:
console.error('Forbidden');
break;
case 429:
console.error('Rate limited');
break;
default:
console.error('Unexpected error:', error);
}
return;
}
// data is safely narrowed
console.log(data);Migration from v2 (tRPC)
Version 3 replaces the tRPC-based client with Eden Treaty. Key differences:
| v2 (tRPC) | v3 (Eden Treaty) |
|---|---|
| client.health.query() | api.v1.health.get() |
| client.agent.streamText.mutate({...}) | api.v1.ai.chat.completions.post({...}) |
| Throws TRPCClientError | Returns { data, error, status } |
| createNodeApiClient() | createApiClient(baseUrl) |
| API_URL / API_ACCESS_KEY env vars | Pass baseUrl and headers explicitly |
License
MIT
