TypeScript SDK
Configure the TypeScript client, query data, paginate, cancel requests, and handle errors.
Install and configure
Install from the private registry configured for your organization:
pnpm add @combined/contextimport { ContextOS } from "@combined/context";
const context = new ContextOS({
token: process.env.COMBINED_TOKEN,
baseUrl: process.env.COMBINED_API_URL,
timeoutMs: 30_000,
});token, baseUrl, timeoutMs, and a custom Fetch implementation are supported. When omitted, credentials and origin come from COMBINED_TOKEN and COMBINED_API_URL.
Discover and query
const catalogue = await context.catalog.list(accountId);
const result = await context.sql.query({
accountId,
sql: `
SELECT channel_name, COUNT(*) AS messages
FROM slack_messages
WHERE sent_at >= ?
GROUP BY channel_name
ORDER BY messages DESC
LIMIT 20
`,
parameters: ["2026-08-01T00:00:00Z"],
maxRows: 20,
});
console.log(result.columns, result.rows, result.truncated);Catalogue logical names are the only supported SQL relations. Parameterize values; SQL identifiers cannot be parameters and must come from trusted catalogue metadata.
Pagination
let cursor: string | undefined;
do {
const page = await context.sources.list(accountId, { limit: 100, cursor });
for (const source of page.data) console.log(source.name, source.state);
cursor = page.page.nextCursor ?? undefined;
} while (cursor);Pages contain data, page: { hasMore, nextCursor }, and correlationId. Cursors are opaque and tied to the list shape; restart pagination after changing filters.
Cancellation and idempotency
const controller = new AbortController();
const run = context.sources.run(accountId, sourceId, "manual", {
signal: controller.signal,
idempotencyKey: crypto.randomUUID(),
});RequestOptions accepts signal and idempotencyKey. The client generates a key for mutations when omitted. Reuse an explicit key only for the identical operation and body.
Error handling
import { ContextOSError } from "@combined/context";
try {
await context.sql.query({ accountId, sql, parameters, maxRows: 100 });
} catch (error) {
if (error instanceof ContextOSError) {
console.error(error.status, error.code, error.correlationId, error.details);
}
throw error;
}GET retries are bounded to one attempt after the original request. SQL and mutations are intentionally not retried because the caller must decide whether a repeated action remains safe.