@omirion/orbit-sdk
v0.5.0
Published
Official TypeScript SDK for the Omirion Orbit public API (/api/v1).
Readme
@omirion/orbit-sdk
Official TypeScript SDK for the Omirion Orbit public API (/api/v1). Works in Node 18+, Deno, Bun, Cloudflare Workers, and browsers. ESM + CJS, fully typed, zero runtime dependencies (the fetch client is bundled).
Install
npm install @omirion/orbit-sdk # or pnpm add / yarn addQuickstart
Create a token in the dashboard (Account → API tokens), then:
import { OrbitClient, decodeSample } from '@omirion/orbit-sdk'
const orbit = new OrbitClient({ token: process.env.ORBIT_TOKEN! })
// baseUrl defaults to https://orbit.omirion.com; sends `Authorization: Bearer oat_…`
// Cursor pagination is automatic, iterate every device, online only:
for await (const device of orbit.devices.iterate({ status: 'online' })) {
const sample = await orbit.telemetry.latest(device.id)
if (!sample) continue
// Join abbreviated metric keys to their labels/units via the manifest:
const manifest = await orbit.telemetry.manifest(device.id)
const rows = manifest ? decodeSample(sample, manifest) : []
for (const r of rows) console.log(`${device.name} · ${r.label}: ${r.value}${r.unit ?? ''}`)
}OrbitClient wraps the generated transport client with bearer auth, automatic retries (429/502/503/504 + network) with backoff, response unwrapping, cursor auto-pagination, and typed errors you can catch:
import { InsufficientScopeError, DeviceRpcError } from '@omirion/orbit-sdk'
try {
// Commands are declared per device type, a name plus typed key/value args, no shell.
// `orbit.commands.manifest(deviceId)` lists what this device accepts.
const requestId = crypto.randomUUID() // Save before sending; reuse for retries of this command.
const result = await orbit.commands.exec(deviceId, { name: 'state-request', requestId, timeoutMs: 10_000 })
if (result.queued) {
// Store-and-forward device: poll orbit.commands.get(deviceId, result.invocationId)
}
} catch (err) {
if (err instanceof InsufficientScopeError) {/* token missing api:command:exec */}
else if (err instanceof DeviceRpcError) {/* device offline / transport failed */}
else throw err
}Command submissions require a caller-generated requestId UUID. Persist it before sending when recovery must survive a restart. Reuse it with the same device, issuing user and command body for retries; generate a new ID for a new intended action. HTTP retries within one SDK call preserve the body. commands.getByRequestId(deviceId, requestId) recovers an accepted command without resubmitting it.
Surface
Every collection has a cursor-paginated list(params?) and a lazy iterate(params?) async-generator twin that walks all pages.
orbit.me(). Who the token authenticates as, its abilities and project scope, and the projects it reaches. Requires no ability. The cheapest way to verify a token works and to discover validprojectIdvalues.orbit.projects.list/iterate/get(id), plusappToken.create(projectId)/appToken.rotate(projectId)(the provisioning token is returned once and never again).orbit.deviceTypes.list/iterate/get(projectId, slug)/create/update/delete, the models a fleet identifies as, with their telemetry and command manifests.orbit.devices.list/iterate/get(id)/delete(id)/resetToken(id).orbit.admissions.list/iterate/get(id)/accept/reject/dismiss, the fleet-join requests.orbit.telemetry.latest(deviceId),history(deviceId, { hours? }),manifest(deviceId).orbit.firmware.upload({ file, projectId, kind?, version?, compatible?, description? })(version and target are decoded from the binary where it carries them),deleteBundle(id),bundles.list/iterate/get,deployments.trigger/list/iterate/get/cancel/rollback.orbit.commands.exec(deviceId, { name, args?, timeoutMs? }),get(deviceId, invocationId)(the pull path for a queued dispatch),manifest(deviceId).orbit.webhooks.list/iterate/create/get/update/delete/deliveries/iterateDeliveries. Receiver-side helpersverifyWebhookSignatureandparseWebhookEventvalidate incoming deliveries (HMAC + replay window).orbit.usb/orbit.terminal. Single-use ticket minting for the USB/IP and device-shell WebSocket planes (api:usb:attach/api:terminal:open).decodeSample(sample, manifest)/decodeSamples(...), labelled telemetry rows.- Errors:
OrbitError+AuthenticationError,InsufficientScopeError,ResourceNotFoundError,BadRequestError,ValidationError,ConflictError,BundleExistsError,DeviceRpcError,RateLimitError,ServerError,NetworkError
The raw generated transport client is still available under import { raw } from '@omirion/orbit-sdk'.
Examples
Two runnable examples ship in this package under examples/. Copy a folder anywhere, pnpm install, and follow its README.
examples/device-rpc-flow. An Ink terminal UI walking the full read-then-act loop, list devices, decode their latest telemetry via the type manifest, then drive a device through a sequence of declared commands.examples/webhook-listener. The smallest useful webhook receiver, verifies every delivery's signature withparseWebhookEvent, dedupes on the event id, and prints each event.
License
MIT
