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

@flxsense/flexsignal-sdk

v1.1.0

Published

SDK for the FlexSignal API

Downloads

1,114

Readme

@flxsense/flexsignal-sdk

TypeScript SDK for the FlexSignal API.

This package wraps the FlexSignal HTTP API with typed resources for authentication, account management, notifications, geocoding, devices, assets, units, spaces, and storage data.

Installation

pnpm add @flxsense/flexsignal-sdk

Requirements

  • Node.js with fetch, FormData, and URL support
  • FlexSignal client credentials for client-authenticated endpoints

Quick Start

import { FlexsignalClient } from '@flxsense/flexsignal-sdk';

const client = new FlexsignalClient({
  client_id: process.env.FLEXSIGNAL_CLIENT_ID,
  client_secret: process.env.FLEXSIGNAL_CLIENT_SECRET,
});

const auth = await client.auth.login_password({
  email: '[email protected]',
  password: 'secret',
});

if (auth.kind !== 'ready') {
  throw new Error(`Login failed: ${auth.kind}`);
}

const session = auth.session;
const units = await session.units.list();

if (!units.ok) {
  throw new Error(units.error.message);
}

console.log(units.data);

Client Setup

import { FlexsignalClient } from '@flxsense/flexsignal-sdk';

const client = new FlexsignalClient({
  client_id: process.env.FLEXSIGNAL_CLIENT_ID,
  client_secret: process.env.FLEXSIGNAL_CLIENT_SECRET,
  url: 'https://api.flexdevel.com/',
  version: 'v1',
  ident: 'my-app',
  dev: false,
});

Available options:

  • client_id: client id used for basic-auth protected endpoints
  • client_secret: client secret used for basic-auth protected endpoints
  • url: API base URL, default https://api.flexdevel.com/
  • version: API version path, default v1
  • ident: client identifier used by notification endpoints, default flexsignal-js
  • token_expires_in: optional access token lifetime override
  • auto_refresh_tokens: automatically refreshes tracked session bearer tokens on 401, default true
  • dev: enables debug logging and defaults token lifetime to 300 seconds

The client also exposes lower-level hooks from @jeppech/typed-fetcher:

  • client.use(handler) for middleware
  • client.on_error(handler) for fetcher error observers
  • client.retry(handler, options) for retry behavior

Authentication

Password Login

const result = await client.auth.login_password({
  email: '[email protected]',
  password: 'secret',
});

switch (result.kind) {
  case 'ready':
    console.log(result.tokens.access_token);
    break;
  case 'mfa_required':
    console.log('Request TOTP passcode from the user');
    break;
  case 'invalid_credentials':
    console.error(result.message);
    break;
  case 'error':
    console.error(result.error);
    break;
}

Password + TOTP Login

const result = await client.auth.login_password_otp({
  email: '[email protected]',
  password: 'secret',
  passcode: '123456',
});

Restore a Session From Existing Tokens

const restored = client.auth.restore_session({
  access_token,
  refresh_token,
  access_expires_at,
  refresh_expires_at,
});

if (!restored.ok) {
  throw new Error(restored.error.message);
}

const session = restored.data;

restore_session(...) accepts the same TokenBundle shape returned from login and refresh calls, so you can persist result.tokens directly and restore from that object later.

const savedTokens = result.tokens;

const restored = client.auth.restore_session(savedTokens);

Refresh a Session

const refreshed = await session.refresh();

if (!refreshed.ok) {
  throw new Error(refreshed.error.message);
}

console.log(session.tokens);
console.log(session.tokens.access_expires_at);
console.log(session.tokens.refresh_expires_at);

When auto_refresh_tokens is enabled, session-backed requests also retry automatically once after a 401 by refreshing the tracked session's bearer token.

Automatic refresh only applies to tracked AuthenticatedSession instances created through login, session restore, or client.create_session(...).

Dispose a Session

For long-lived server processes, call session.dispose() when the session is no longer needed to stop SDK tracking and automatic refresh attempts.

const auth = await client.auth.login_password({
  email: '[email protected]',
  password: 'secret',
});

if (auth.kind !== 'ready') {
  throw new Error(`Login failed: ${auth.kind}`);
}

const session = auth.session;

try {
  const units = await session.units.list();

  if (!units.ok) {
    throw new Error(units.error.message);
  }

  console.log(units.data);
} finally {
  session.dispose();
}

Notes:

  • calling dispose() more than once is safe
  • disposed sessions are no longer auto-refreshed or tracked by the client
  • session.refresh() returns an invalid_token error after disposal
  • dispose() does not revoke tokens on the server

Session Resources

Authenticated sessions expose these resource groups:

  • session.account
  • session.assets
  • session.devices
  • session.spaces
  • session.storage
  • session.units

Account

const totp = await session.account.setup_totp({ qr_size_px: 256 });
const recoveryCodes = await session.account.list_recovery_codes({ count: 10 });
const tokenInfo = await session.account.introspect_access_token();

Available methods:

  • list_recovery_codes({ count? })
  • setup_totp({ qr_size_px? })
  • enable_totp({ passcode })
  • introspect_access_token()

Units

const created = await session.units.create({
  name: 'Trailer sensors',
  device_ids: ['e9c41094-f691-4d39-9e2b-06cc9bc6b137', 'b7613970-75fe-44b3-a86d-fee456b94b98'],
});

const units = await session.units.list();

Available methods:

  • list()
  • get({ unit_id })
  • create({ name, device_ids })
  • update({ unit_id, name, device_ids })
  • delete({ unit_id })

Assets

const assets = await session.assets.list();
const latestLocation = await session.assets.get_last_location({ asset_id: '1468b6f8-e750-43b4-9ffd-8caa01107ed5' });

Available methods:

  • list()
  • get({ asset_id })
  • create({ name, unit_ids })
  • update({ asset_id, name, unit_ids })
  • delete({ asset_id })
  • list_locations({ asset_id })
  • get_last_location({ asset_id })

Devices

const devices = await session.devices.list();

Available methods:

  • list()

Spaces

await session.spaces.create_or_get({
  namespace: 'app',
  key: 'theme',
  value: 'dark',
});

Available methods:

  • create({ namespace, key, value })
  • get({ namespace, key })
  • create_or_get({ namespace, key, value })
  • update({ namespace, key, value })
  • delete({ namespace, key })

Storage

Supported storage keys:

  • location
  • various
  • temp
  • wind
  • rain
  • humid
  • event

Supported groups for grouped queries:

  • device
  • unit
  • asset
const latest = await session.storage.list_latest({ type: 'location' });

const history = await session.storage.list_range({
  group: 'unit',
  type: ['temp', 'humid'],
  id: 'e9c41094-f691-4d39-9e2b-06cc9bc6b137',
  begin: '2026-01-01T00:00:00Z',
  end: '2026-01-02T00:00:00Z',
});

Available methods:

  • list_latest({ type })
  • list_last({ group, type, id })
  • list_range({ group, type, id, begin, end })

Client Resources

The root client exposes resources that do not require an authenticated session.

Accounts

const account = await client.accounts.register({
  email: '[email protected]',
  password: 'secret',
  username: 'user',
});

Available methods:

  • create({ email, password, username? })
  • register({ email, password, username? })
  • change_password({ email, password })

Notifications

await client.notifications.send_email_template({
  sender: '[email protected]',
  to: '[email protected]',
  template_name: 'welcome',
  subject: 'Welcome',
  template_data: { firstName: 'Jane' },
});

await client.notifications.send_sms({
  sender: 'FlexSignal',
  to: '+4512345678',
  message: 'Alert triggered',
});

Available methods:

  • send_email_template({ sender, to, template_name, subject, template_data?, language_bcp_47? })
  • send_sms({ sender, to, message, transport? })

Geocoding

const geocode = await client.geocode.lookup([
  { identifier: 1, lat: 55.6761, lon: 12.5683 },
]);

Error Handling

Most SDK methods return ApiResult<T>:

const result = await session.assets.list();

if (!result.ok) {
  console.error(result.error.type, result.error.message);
  process.exit(1);
}

console.log(result.data);

ApiError.type can be:

  • fetch
  • http
  • parse
  • invalid_token
  • unexpected_state

Authentication methods use AuthResult, which is a discriminated union with the states:

  • ready
  • mfa_required
  • invalid_credentials
  • error

Exported Types

The package exports the main client classes, endpoint definitions, and response types, including:

  • FlexsignalClient
  • AuthenticatedSession
  • flexsignal_endpoints
  • ApiResult, ApiError, AuthResult, TokenBundle
  • schema types such as AccountData, AssetItem, DeviceItem, GeocodeItem, UnitItem, and storage item types

Development

Scripts:

pnpm format
pnpm lint
pnpm build

The build output is written to lib/.