rtls-sdk
v0.6.2-alpha.0
Published
TypeScript SDK for the RTLS REST API (async, isomorphic port of the Python rtls-sdk)
Maintainers
Readme
rtls-sdk (TypeScript)
An async, isomorphic (Node + browser) TypeScript port of the Python
rtls-sdk. The wire protocol is identical; the surface is
idiomatic TS: every method returns a Promise, models are zod-validated and
frozen, and the original server payload is available on .raw.
Status: feature-complete port. All 28 resource sub-clients, the compound sagas (tags/zones/groups/nodes/users/auth/system), the async pagination + reports (PWS/heatmap/CSV), the
contextaggregation,lsborchestration, and the WebSocket streaming layer are ported and tested.
Documentation
Full documentation lives in docs/: install,
quickstart, per-entity pages (overview),
guides (errors, pagination, scopes, timestamps, compound
workflows…), and advanced topics. The generated API reference is in
docs/api/ (regenerate with npm run docs:api).
Resources
client. exposes: tags, sites, areas, floorplans, anchors, zones, groups,
nodes, anchorAssociations, tagAssociations, users, projects, companies,
alarms, events, reports, notifications, subscribers, auth, system, context,
messaging, userMessages, logger, schedules, lsb, network, ws.
Stack
| Concern | Choice |
|---|---|
| HTTP | ky (fetch-based; Node ≥18 + browser) |
| Validation / models | zod via a defineModel / fromWire helper |
| Auth | lazy login + single 401-replay, coalesced through one in-flight promise |
| Tests | vitest + msw (HTTP mocking) |
| Build | tsup (ESM + CJS + .d.ts) |
Naming
Canonical field names are camelCase (idiomatic TS): the wire key
notification_type surfaces as notificationType, location_uid → siteUid,
sublocation_uid → areaUid, mac → macAddress. The untouched wire payload
is always on .raw. (This differs from the Python SDK's snake_case surface — a
deliberate idiom choice, revisit if strict cross-language parity is preferred.)
Example
import { RtlsClient } from "rtls-sdk";
const client = new RtlsClient({
username: process.env.RTLS_USERNAME!,
password: process.env.RTLS_PASSWORD!,
baseUrl: process.env.RTLS_BASE_URL!,
projectUid: process.env.RTLS_PROJECT_UID,
});
// Reads return frozen, typed models (wire keys mapped to camelCase).
const tags = await client.tags.list();
// Lazy pagination — HTTP fires only as you iterate; `break` stops early.
for await (const event of client.events.iterPws({ tagUids: "t-1", start, end })) {
console.log(event.tagUid, event.zoneUid);
}
// Live WebSocket stream.
const session = await client.ws.subscribe(["pos", "alarm"]);
for await (const msg of session) {
if (msg.channel === "pos") console.log((msg as any).tagUid);
break;
}
session.close();
client.close();See examples/quickstart.ts for a runnable script.
Scripts
npm run typecheck # tsc --noEmit (strict)
npm test # vitest run (offline, msw mocks)
npm run test:live # live suite against a real server (needs RTLS_LIVE_* / RTLS_* env)
npm run lint # eslint
npm run build # tsup → dist/
npm run docs:api # typedoc → docs/api/