npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@relay-x/device-sdk

v0.1.3

Published

A SDK to deploy on devices to connect to the RelayX Network

Readme

RelayX Device SDK for JavaScript

Official JavaScript SDK for connecting IoT devices to the RelayX platform.

View Full Documentation →

Installation

npm install @relay-x/device-sdk

Quick Start

import { RelayDevice } from "@relay-x/device-sdk";

const device = new RelayDevice({
  api_key: "<YOUR_API_KEY>",
  secret: "<YOUR_SECRET>",
  mode: RelayDevice.PRODUCTION_MODE, // or RelayDevice.TEST_MODE
});

await device.connect();

// Publish telemetry
await device.telemetry.publish("temperature", 22.5);

// Emit logs (batched to NATS, mirrored to console)
device.log.info("device booted");
device.log.warn("disk usage at", 87, "%");

// Listen for RPC calls
await device.rpc.listen("reboot", (req) => {
  console.log("Reboot requested:", req.payload);
  req.respond({ status: "rebooting" });
});

// Listen for commands
await device.command.listen("firmware_update", (msg) => {
  console.log("Firmware update:", msg.payload);
  msg.ack();
});

// Disconnect when done
await device.disconnect();

Configuration

const device = new RelayDevice({
  api_key: "<YOUR_API_KEY>", // JWT issued by RelayX
  secret: "<YOUR_SECRET>", // NKEY seed
  mode: "production", // 'production' | 'test'
});

Functionality

Connection

await device.connect(); // returns true on success, false if already connected or failed
await device.disconnect(); // drains NATS connection, cleans up consumers

// Listen for connection status changes
device.connection.listeners((event) => {
  // event.type: 'connected' | 'disconnected' | 'reconnecting' | 'reconnected' | 'auth_failed'
  console.log("Status:", event.type);
});

Telemetry

Fire-and-forget sensor data publishing. Readings are validated against the device schema fetched on connect.

await device.telemetry.publish("temperature", 22.5); // number
await device.telemetry.publish("status", "online"); // string
await device.telemetry.publish("active", true); // boolean
await device.telemetry.publish("metadata", { fw: "1.2" }); // json

Each message is published with a server-synced timestamp.

Schema validation: On connect, the SDK fetches the device schema from the server. If a schema exists, publish() will throw a ValidationError if the metric name is not in the schema or the reading type does not match.

Remote Procedure Calls (RPC)

Register handlers for incoming RPC calls.

// Register a handler
await device.rpc.listen("get_status", (req) => {
  console.log("Payload:", req.payload);

  // Respond with success
  req.respond({ uptime: 12345 });

  // Or respond with error
  // req.error({ code: 'UNAVAILABLE', message: 'Device busy' });
});

// Unregister
await device.rpc.off("get_status");

Duplicate listeners for the same name throw DuplicateListenerError.

Commands

One-way commands delivered for long running tasks and that do not require a status update

await device.command.listen("firmware_update", (msg) => {
  console.log("Command:", msg.payload);

  // Process based on data...
});

await device.command.off("firmware_update");

Config

Get and set device configuration

// Fetch current config
const config = await device.config.get();
console.log(config);

// Update config
const success = await device.config.set({ interval: 10000, name: "sensor-1" });

Events

Fire-and-forget event publishing of events (fault codes, etc)

await device.event.send("door_opened", {
  door_id: "front",
  timestamp: Date.now(),
});

Logs

Structured device logging with three levels (info, warn, error). Each call accepts a variadic argument list — strings, numbers, booleans, plain objects, arrays, dates, null/undefined, and Error instances are all accepted; functions and other non-serializable values throw ValidationError.

device.log.info("hello world");
device.log.info("a number reading", 42);
device.log.warn("careful — disk usage at 87%");
device.log.error("parse failed", new SyntaxError("bad json"));
device.log.info("an object", { port: 8080, retries: 3 });

Locally, each call also mirrors to console.info / console.warn / console.error so you keep your normal dev experience.

Batching. Entries are buffered in memory and flushed to the backend either when 15 entries accumulate or after 5 seconds, whichever comes first. disconnect() flushes any pending buffer.

Time

NTP-synchronized clock. Syncs with time.google.com on connect and every 3 hours. Auto-resyncs on reconnect if stale.

// Initialize (called automatically on connect)
await device.time.init();

// Get current server-corrected timestamp (ms)
const now = device.time.now();

// Convert SDK timestamp to Date
const date = device.time.toDate(now);

// Convert Date to SDK timestamp
const ts = device.time.toTimestamp(new Date());

// Set timezone for display
device.time.setTimezone("America/New_York");

Error Handling

The SDK exports four error types:

import {
  NotConnectedError, // Operation attempted while disconnected
  DuplicateListenerError, // rpc.listen() or command.listen() called twice for same name
  ValidationError, // Invalid arguments or schema mismatch
  TimeoutError, // Request/reply timed out
} from "@relay-x/device-sdk";

Offline Behavior

  • Telemetry & Events (publish): Messages are buffered in memory while disconnected and flushed automatically on reconnect.
  • Logs (device.log.*): Entries are buffered and flushed on the same 15-entry / 5-second policy. Any buffer left at disconnect() is flushed before the connection drains.
  • RPC & Commands (listen): Throw NotConnectedError if transport is disconnected.
  • Config (get/set): Throw NotConnectedError if transport is disconnected.

Testing

npm test

The SDK is designed for full unit testability. All subsystems accept a transport dependency that can be mocked:

import { RelayDevice } from "@relay-x/device-sdk";

const mockTransport = {
  /* mock methods */
};
const device = RelayDevice._createForTest(
  { api_key: "test", secret: "test", mode: "test" },
  mockTransport,
);

License

Apache-2.0