TypeScript SDK
@hlix/sdk is the first-party TypeScript client. Its request and response types come from the published OpenAPI contract, while the SDK adds credentials, explicit workspace selection, typed errors, bounded retry, bundle transfer, and Server-Sent Events.
Prerequisites
Section titled “Prerequisites”- Node.js 20 or later
- An hlix API key
- A workspace ID
- TypeScript is recommended, but the package also exposes ESM JavaScript
Install
Section titled “Install”Install
npm install @hlix/sdkPin the version in CI so a build never picks up a client you have not tested against:
npm install @hlix/sdk@0.2.0Current versions reports the same state for all three hlix packages, and names the gate each one still has to pass.
Until the package ships, generate a typed client from the public OpenAPI contract — it is the same document this SDK is built from, and it downloads without authentication. The shapes below describe the client hlix will publish; the generated client exposes the same operations with generated names.
Create a client
Section titled “Create a client”import { createHlix, apiKeyCredential } from '@hlix/sdk'
const hlix = createHlix({ baseUrl: 'https://server.hlix.ai', credential: apiKeyCredential(process.env.HLIX_API_KEY!), organizationId: process.env.HLIX_WORKSPACE_ID!,})An API key authenticates a user; it does not imply a workspace. Always pass organizationId in server-side automation so a prior browser session cannot select the tenant implicitly.
Runnable happy path
Section titled “Runnable happy path”List projects and inspect a task:
import { createHlix, apiKeyCredential, HlixNotFoundError,} from '@hlix/sdk'
const hlix = createHlix({ baseUrl: process.env.HLIX_BASE_URL ?? 'https://server.hlix.ai', credential: apiKeyCredential(process.env.HLIX_API_KEY!), organizationId: process.env.HLIX_WORKSPACE_ID!,})
const projects = await hlix.projects.list()console.log(projects)
try { const task = await hlix.tasks.get(process.env.HLIX_TASK_ID!) console.log(task)} catch (error) { if (error instanceof HlixNotFoundError) { console.error('Task is absent or not visible to this caller') } else { throw error }}Expected result: the project list is scoped to the selected workspace. A hidden resource and an absent resource both produce HlixNotFoundError; the API does not reveal cross-tenant existence.
Stream task status
Section titled “Stream task status”const controller = new AbortController()
for await (const event of hlix.tasks.stream(taskId, { signal: controller.signal,})) { console.log(event.event, JSON.parse(event.data))}Streaming does not retry automatically. A reconnected stream could replay events the consumer has already acted on, so reconnection belongs in application logic with its own checkpoint policy.
Error classes
Section titled “Error classes”| Class | Meaning |
|---|---|
HlixValidationError |
400 schema failure; exposes decoded issues |
HlixBadRequestError |
other 400 response |
HlixAuthenticationError |
401 |
HlixPermissionError |
403 |
HlixNotFoundError |
404, including not visible |
HlixConflictError |
409 compare-and-swap or state conflict |
HlixRateLimitError |
429; exposes retryAfter |
HlixNotImplementedError |
501 permanent refusal |
HlixServerError |
other 5xx |
HlixTransportError |
no HTTP response |
Every HTTP error also carries the status, parsed body, and request ID when the server provides one.
Retry policy
Section titled “Retry policy”The default uses bounded exponential backoff with jitter and honors Retry-After. Only idempotent verbs are eligible. POST and PATCH are never retried automatically because the client may not know whether the server already performed the mutation.
Disable retry:
const hlix = createHlix({ baseUrl, credential, organizationId, retry: { attempts: 1 },})Imports and revisions
Section titled “Imports and revisions”The SDK exposes the same low-level import and revision primitives used by the CLI:
hlix.imports.create,get,uploadBundle, andfinalizehlix.revisions.head,createUpload,uploadBundle,finalize,downloadBundle, andprotectedFiles
These are multi-step protocols. Preserve the server-issued upload identity, declare exact hashes and sizes, and finalize only with protected data that exactly matches the manifest. For ordinary local-to-cloud use, prefer the CLI—it owns scanning, snapshot construction, integrity verification, and local revision state.
Raw transport
Section titled “Raw transport”hlix.raw exposes the generated openapi-fetch client for published operations not wrapped by the opinionated facade:
const { data, error } = await hlix.raw.GET('/v1/api/projects')The raw client returns { data, error }; it does not apply the SDK’s throwing error model.
Verify your integration
Section titled “Verify your integration”HLIX_API_KEY='…' \HLIX_WORKSPACE_ID='<workspace-id>' \node dist/example.jsUse a secret manager in CI and avoid printing environment variables. Confirm the result against hlix projects list --json or the web app in the same workspace.
If the client fails
Section titled “If the client fails”Cannot find module '@hlix/sdk'— the workspace package is not built. Runbun install --frozen-lockfilethenbun run --cwd packages/sdk build. There is no registry install yet; see Current versions.HlixAuthenticationError— the key is missing or rejected. It authenticates a user, so a valid key with noorganizationIdcan still fail the next check.HlixPermissionError— the user cannot act in the selected workspace. ConfirmorganizationIdis the one you meant.HlixNotFoundErroron a resource you can see in the dashboard — you are pointed at a different workspace. Absent and not-visible are deliberately the same answer; do not infer cross-tenant existence from it.HlixConflictErroron a revision call — the expected revision or generation is stale. Read the head again before retrying.HlixTransportError— no HTTP response at all. CheckbaseUrl, DNS, and TLS before suspecting credentials.- A
POSTthat seems to have run twice — it did not retry.POSTandPATCHare never retried automatically, precisely because the client cannot know whether the server already applied the mutation. - A stream that stops silently — streaming does not retry. Reconnection belongs in your code, with its own checkpoint policy, because a replayed event can be acted on twice.