@omirion/orbit-sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -29
- package/dist/index.cjs +5 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -36
- package/dist/index.d.ts +35 -36
- package/dist/index.js +5 -9
- package/dist/index.js.map +1 -1
- package/examples/device-rpc-flow/README.md +43 -0
- package/examples/device-rpc-flow/index.tsx +502 -0
- package/examples/device-rpc-flow/package.json +23 -0
- package/examples/device-rpc-flow/tsconfig.json +14 -0
- package/examples/webhook-listener/README.md +41 -0
- package/examples/webhook-listener/index.ts +110 -0
- package/examples/webhook-listener/package.json +19 -0
- package/examples/webhook-listener/tsconfig.json +13 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# @omirion/orbit-sdk
|
|
2
2
|
|
|
3
|
-
Official TypeScript SDK for the [Omirion Orbit](https://orbit.omirion.com)
|
|
4
|
-
public API (`/api/v1`). Works in Node 18+, Deno, Bun, Cloudflare Workers, and
|
|
5
|
-
browsers. ESM + CJS, fully typed, zero runtime dependencies (the fetch client is
|
|
6
|
-
bundled).
|
|
3
|
+
Official TypeScript SDK for the [Omirion Orbit](https://orbit.omirion.com) 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).
|
|
7
4
|
|
|
8
5
|
## Install
|
|
9
6
|
|
|
@@ -33,15 +30,18 @@ for await (const device of orbit.devices.iterate({ status: 'online' })) {
|
|
|
33
30
|
}
|
|
34
31
|
```
|
|
35
32
|
|
|
36
|
-
`OrbitClient` wraps the generated transport client with bearer auth, automatic
|
|
37
|
-
retries (429/502/503/504 + network) with backoff, response unwrapping, cursor
|
|
38
|
-
auto-pagination, and **typed errors** you can `catch`:
|
|
33
|
+
`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`:
|
|
39
34
|
|
|
40
35
|
```ts
|
|
41
36
|
import { InsufficientScopeError, DeviceRpcError } from '@omirion/orbit-sdk'
|
|
42
37
|
|
|
43
38
|
try {
|
|
44
|
-
|
|
39
|
+
// Commands are declared per device type, a name plus typed key/value args, no shell.
|
|
40
|
+
// `orbit.commands.manifest(deviceId)` lists what this device accepts.
|
|
41
|
+
const result = await orbit.commands.exec(deviceId, { name: 'state-request', timeoutMs: 10_000 })
|
|
42
|
+
if (result.queued) {
|
|
43
|
+
// Store-and-forward device: poll orbit.commands.get(deviceId, result.invocationId)
|
|
44
|
+
}
|
|
45
45
|
} catch (err) {
|
|
46
46
|
if (err instanceof InsufficientScopeError) {/* token missing api:command:exec */}
|
|
47
47
|
else if (err instanceof DeviceRpcError) {/* device offline / transport failed */}
|
|
@@ -51,32 +51,29 @@ try {
|
|
|
51
51
|
|
|
52
52
|
### Surface
|
|
53
53
|
|
|
54
|
-
- `
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
- `orbit.
|
|
58
|
-
- `orbit.
|
|
59
|
-
- `orbit.
|
|
60
|
-
- `orbit.
|
|
61
|
-
- `
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
54
|
+
Every collection has a cursor-paginated `list(params?)` and a lazy `iterate(params?)` async-generator twin that walks all pages.
|
|
55
|
+
|
|
56
|
+
- `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 valid `projectId` values.
|
|
57
|
+
- `orbit.projects`. `list` / `iterate` / `get(id)`, plus `appToken.create(projectId)` / `appToken.rotate(projectId)` (the provisioning token is returned once and never again).
|
|
58
|
+
- `orbit.deviceTypes`. `list` / `iterate` / `get(projectId, slug)` / `create` / `update` / `delete`, the models a fleet identifies as, with their telemetry and command manifests.
|
|
59
|
+
- `orbit.devices`. `list` / `iterate` / `get(id)` / `delete(id)` / `resetToken(id)`.
|
|
60
|
+
- `orbit.admissions`. `list` / `iterate` / `get(id)` / `accept` / `reject` / `dismiss`, the fleet-join requests.
|
|
61
|
+
- `orbit.telemetry`. `latest(deviceId)`, `history(deviceId, { hours? })`, `manifest(deviceId)`.
|
|
62
|
+
- `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`.
|
|
63
|
+
- `orbit.commands`. `exec(deviceId, { name, args?, timeoutMs? })`, `get(deviceId, invocationId)` (the pull path for a queued dispatch), `manifest(deviceId)`.
|
|
64
|
+
- `orbit.webhooks`. `list` / `iterate` / `create` / `get` / `update` / `delete` / `deliveries` / `iterateDeliveries`. Receiver-side helpers `verifyWebhookSignature` and `parseWebhookEvent` validate incoming deliveries (HMAC + replay window).
|
|
65
|
+
- `orbit.usb` / `orbit.terminal`. Single-use ticket minting for the USB/IP and device-shell WebSocket planes (`api:usb:attach` / `api:terminal:open`).
|
|
66
|
+
- `decodeSample(sample, manifest)` / `decodeSamples(...)`, labelled telemetry rows.
|
|
67
|
+
- Errors: `OrbitError` + `AuthenticationError`, `InsufficientScopeError`, `ResourceNotFoundError`, `BadRequestError`, `ValidationError`, `ConflictError`, `BundleExistsError`, `DeviceRpcError`, `RateLimitError`, `ServerError`, `NetworkError`
|
|
65
68
|
|
|
66
69
|
The raw generated transport client is still available under `import { raw } from '@omirion/orbit-sdk'`.
|
|
67
70
|
|
|
68
|
-
##
|
|
71
|
+
## Examples
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
pnpm install --ignore-workspace
|
|
72
|
-
pnpm generate # regenerate src/generated/ from ../spec/openapi.json
|
|
73
|
-
pnpm typecheck
|
|
74
|
-
pnpm test # vitest (ergonomics layer)
|
|
75
|
-
pnpm build # tsup → dist/ (ESM + CJS + .d.ts)
|
|
76
|
-
```
|
|
73
|
+
Two runnable examples ship in this package under `examples/`. Copy a folder anywhere, `pnpm install`, and follow its README.
|
|
77
74
|
|
|
78
|
-
`
|
|
79
|
-
|
|
75
|
+
- `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.
|
|
76
|
+
- `examples/webhook-listener`. The smallest useful webhook receiver, verifies every delivery's signature with `parseWebhookEvent`, dedupes on the event id, and prints each event.
|
|
80
77
|
|
|
81
78
|
## License
|
|
82
79
|
|
package/dist/index.cjs
CHANGED
|
@@ -1109,7 +1109,9 @@ var ValidationError = class extends OrbitError {
|
|
|
1109
1109
|
this.fieldErrors = options.fieldErrors ?? [];
|
|
1110
1110
|
}
|
|
1111
1111
|
};
|
|
1112
|
-
var
|
|
1112
|
+
var ConflictError = class extends OrbitError {
|
|
1113
|
+
};
|
|
1114
|
+
var BundleExistsError = class extends ConflictError {
|
|
1113
1115
|
};
|
|
1114
1116
|
var DeviceRpcError = class extends OrbitError {
|
|
1115
1117
|
};
|
|
@@ -1127,12 +1129,6 @@ var RateLimitError = class extends OrbitError {
|
|
|
1127
1129
|
function extractErrorFields(body) {
|
|
1128
1130
|
if (!body || typeof body !== "object") return {};
|
|
1129
1131
|
const record = body;
|
|
1130
|
-
if (typeof record.error === "string") {
|
|
1131
|
-
return {
|
|
1132
|
-
code: record.error,
|
|
1133
|
-
message: typeof record.message === "string" ? record.message : record.error
|
|
1134
|
-
};
|
|
1135
|
-
}
|
|
1136
1132
|
if (Array.isArray(record.errors) && record.errors.length > 0) {
|
|
1137
1133
|
const first = record.errors[0];
|
|
1138
1134
|
return {
|
|
@@ -1184,7 +1180,7 @@ function normalizeError(status, body, response) {
|
|
|
1184
1180
|
case 404:
|
|
1185
1181
|
return new ResourceNotFoundError(msg, base);
|
|
1186
1182
|
case 409:
|
|
1187
|
-
return new BundleExistsError(msg, base);
|
|
1183
|
+
return code === "E_BUNDLE_ALREADY_EXISTS" ? new BundleExistsError(msg, base) : new ConflictError(msg, base);
|
|
1188
1184
|
case 422:
|
|
1189
1185
|
return new ValidationError(msg, { ...base, fieldErrors: extractFieldErrors(body) });
|
|
1190
1186
|
case 429:
|
|
@@ -1661,6 +1657,7 @@ __export(generated_exports, {
|
|
|
1661
1657
|
exports.AuthenticationError = AuthenticationError;
|
|
1662
1658
|
exports.BadRequestError = BadRequestError;
|
|
1663
1659
|
exports.BundleExistsError = BundleExistsError;
|
|
1660
|
+
exports.ConflictError = ConflictError;
|
|
1664
1661
|
exports.DeviceRpcError = DeviceRpcError;
|
|
1665
1662
|
exports.InsufficientScopeError = InsufficientScopeError;
|
|
1666
1663
|
exports.NetworkError = NetworkError;
|