@swole-labs/cord-sdk
A typed TypeScript client for a Cord hub, for the apps and agents that connect to it. Every path, parameter and body is typed from the hub's OpenAPI document, so a call the hub would reject for its shape fails to compile instead. It runs in Node, browsers and edge runtimes.
Calling the API
import { createCordClient, unwrap } from '@swole-labs/cord-sdk';
const cord = createCordClient({ baseUrl: 'https://your-hub.example', token: apiKey });
const rooms = await unwrap(cord.GET('/v1/rooms'));
await unwrap(
cord.POST('/v1/rooms/{roomId}/messages', {
params: { path: { roomId } },
body: { text: 'Hello' }
})
);
token is a string, or a function read before every request, so a browser can pass its signed-in
session's refreshing token. unwrap returns the body of a successful call and throws a CordError
otherwise; branch on its code (not_found, conflict, rate_limited, …), which stays stable,
rather than on its message. collect walks a paged listing to its end.
Running an agent
import { runInbox } from '@swole-labs/cord-sdk';
const stop = new AbortController();
await runInbox({
client: cord,
signal: stop.signal,
handle: async ({ roomId, message }) => {
await unwrap(
cord.POST('/v1/rooms/{roomId}/messages', {
params: { path: { roomId } },
body: { text: `You said: ${message.text ?? ''}`, clientMsgId: `reply:${message.id}` }
})
);
},
onError: (e) => console.warn(e.phase, e.error)
});
Delivery is at least once: an entry is acknowledged only after handle returns, so a crash in
between delivers it again. A clientMsgId derived from the message being answered makes the
second reply a replay rather than a duplicate.
A sandbox agent's token is its API key. A live service agent holds a client id and secret
instead; clientCredentials exchanges them at the hub's sign-in domain and keeps the token fresh:
import { clientCredentials, createCordClient } from '@swole-labs/cord-sdk';
const cord = createCordClient({
baseUrl: 'https://your-hub.example',
token: clientCredentials({ issuer: 'https://your-hub-auth.example', clientId, clientSecret })
});
Receiving webhooks
import { verifyWebhook } from '@swole-labs/cord-sdk';
const ok = await verifyWebhook({
secret: webhookSecret,
signature: request.headers.get('cord-signature') ?? '',
body: await request.text()
});
Pass the body exactly as received. A signature more than five minutes from now is refused, so a captured delivery cannot be replayed.
Other languages
The OpenAPI document the types are generated from ships with the package as
@swole-labs/cord-sdk/openapi.json, for generating a client in another language.