Client Overview
@hedystia/client is the companion package for consuming a Hedystia server. It provides a fully typed proxy-based client that mirrors your server's route structure.
Installation
bash
bun add @hedystia/clientCreating a Client
ts
import { createClient } from '@hedystia/client'
import type { app } from './server' // import just the type
const client = createClient<typeof app>('http://localhost:3000')If the server is in a separate package or binary, use buildTypes on the server side and import the generated types:
ts
import { createClient } from '@hedystia/client'
type AppRoutes = [
{ method: "GET"; path: "/ping"; response: { pong: boolean }; status: 200 }
]
const client = createClient<AppRoutes>('http://localhost:3000')Making HTTP Requests
The client proxy mirrors your route path. Each path segment becomes a property; dynamic params become function calls.
GET Request
ts
import { createClient } from '@hedystia/client'
import type { app } from './server'
const client = createClient<typeof app>('http://localhost:3000')
// GET /ping
const { data, error } = await client.ping.get()GET with Path Params
ts
import { createClient } from '@hedystia/client'
import type { app } from './server'
const client = createClient<typeof app>('http://localhost:3000')
// GET /users/123
const { data, error } = await client.users.id(123).get()POST Request
ts
import { createClient } from '@hedystia/client'
import type { app } from './server'
const client = createClient<typeof app>('http://localhost:3000')
// POST /users with body
const { data, error } = await client.users.post({
body: { name: 'Alice', email: 'alice@example.com' },
})PUT Request
ts
import { createClient } from '@hedystia/client'
import type { app } from './server'
const client = createClient<typeof app>('http://localhost:3000')
// PUT /users/123
const { data, error } = await client.users.id(123).put({
body: { name: 'Bob' },
})DELETE Request
ts
import { createClient } from '@hedystia/client'
import type { app } from './server'
const client = createClient<typeof app>('http://localhost:3000')
// DELETE /users/123
const { data, error } = await client.users.id(123).delete()Response Shape
Every HTTP call returns:
typescript
{
data: T | null // typed response data (null on error)
error: E | null // typed error (null on success)
status: number // HTTP status code
ok: boolean // true if status 2xx
}ts
import { createClient } from '@hedystia/client'
const client = createClient<any>('http://localhost:3000')
const { data, error, status, ok } = await client.users.id(1).get()
if (ok) {
console.log(data?.name) // fully typed
} else {
console.log(error?.message) // typed error
}Query Parameters
ts
import { createClient } from '@hedystia/client'
const client = createClient<any>('http://localhost:3000')
// GET /search?q=hedystia&page=1
const { data } = await client.search.get({
query: { q: 'hedystia', page: 1 },
})Custom Headers
Per-request headers:
ts
import { createClient } from '@hedystia/client'
const client = createClient<any>('http://localhost:3000')
const { data } = await client.me.get({
headers: { Authorization: 'Bearer my-token' },
})Global headers for all requests:
ts
import { createClient } from '@hedystia/client'
const client = createClient<any>('http://localhost:3000', {
headers: { 'x-api-key': 'abc' },
})Client Options
ts
import { createClient } from '@hedystia/client'
const client = createClient<any>('http://localhost:3000', {
credentials: 'include', // 'omit' | 'same-origin' | 'include'
headers: {}, // Default headers for all requests
sse: false, // Use SSE instead of WebSocket for subscriptions
debugLevel: 'none', // Logging level
})Subscribing to Real-Time Data
Use .subscribe() at the end of a path chain to open a subscription:
ts
import Hedystia, { h } from 'hedystia'
import { createClient } from '@hedystia/client'
const app = new Hedystia().subscription('/guild/:id', async () => ({ ok: true }), {
params: h.object({ id: h.string() }),
data: h.object({ ok: h.boolean() })
})
const client = createClient<typeof app>('')
// Subscribe to /guild/123
const unsub = client.guild.id('123').subscribe(({ data, error }) => {
if (data) console.log('Update:', data)
if (error) console.log('Error:', error)
})
// Later: stop listening
unsub()The callback receives an object with data and error, each typed based on the server's subscription schema.
Sending Messages in Subscriptions
typescript
const subscription = client.commands.subscribe(({ data }) => {
console.log('Response:', data)
})
// Optionally send data to the server through the subscription
// (via the subscription's message mechanism)Response Format
By default, responses are parsed as JSON. You can override this:
ts
import { createClient } from '@hedystia/client'
const client = createClient<any>('')
const { data } = await client.file.get({
responseFormat: 'text', // 'json' | 'text' | 'blob' | 'arrayBuffer'
})