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

@telemetryos/root-sdk

v1.16.1

Published

The official TelemetryOS root application sdk package. Provides types and apis for building root TelemetryOS applications.

Readme

TelemetryOS Root Applications SDK

Welcome to the TelemetryOS Root Applications SDK! This document will guide you through building root applications for TelemetryOS.

What is TelemetryOS?

TelemetryOS is a platform for running web applications on devices connected to displays, such as TVs and touch screen kiosks. It can manage thousands of devices per account, enabling organizations to create, manage, and deploy dynamic content and interactive applications across their physical locations.

Key features of the platform include:

  • Run single-page applications on display devices.
  • Support containers that run alongside applications.
  • Run worker scripts that operate continuously in the background.
  • Compose content with our Freeform Editor for visual layouts.
  • Support content playlists and scheduling.
  • Manage devices at scale.

Root Applications in TelemetryOS

Root applications are advanced web applications that replace TelemetryOS's default Freeform Editor entirely. When you build a root application, you're creating a complete custom interface that runs directly on devices.

Important: Most developers should use the standard SDK (@telemetryos/sdk) instead. Root applications are for specialized use cases that require complete control over the device experience.

Example Use Cases

Root applications could be used for scenarios like:

  • IPTV Set-Top Box Interface - Custom UI for channel navigation, program guides, and proprietary video decoding with specialized hardware integration
  • Industrial Control Dashboards - Real-time monitoring and control interfaces for manufacturing equipment or building systems
  • Interactive Kiosk Systems - Completely custom navigation flows for specific business processes (beyond standard digital signage)
  • Point-of-Sale Terminals - Custom checkout interfaces with payment processing and inventory integration
  • Educational Interactive Displays - Specialized learning interfaces with custom interaction patterns

How Root Applications Work

Your root application runs as an iframe directly within TelemetryOS's infrastructure, completely replacing the Freeform Editor. You're responsible for building:

  • Complete Device Interface - The entire user experience that displays on physical devices
  • Custom Administration Interface - Configuration tools integrated into TelemetryOS's administration UI
  • Administration Navigation - Custom sidebar navigation items in the TelemetryOS administration UI for managing your specialized resources

Mount Points

Root applications define specialized mount points in their telemetry.config.json file:

  • rootRender - The main interface that displays on physical devices. This replaces the Freeform Editor entirely.
  • rootSettings - The main configuration interface in TelemetryOS's administration UI where customers configure your root application.

And specialized worker scripts:

  • rootSettingsNavigation - Registers custom navigation items in TelemetryOS's administration UI sidebar, allowing you to add specialized management interfaces (e.g., "Channel Management", "Hardware Settings", "Custom Reports").
  • rootSettingsDeviceContentAssignment - Configures custom options when customers assign your root application to devices.

Administration UI Integration

Root applications can integrate deeply with TelemetryOS's administration interface by registering custom navigation items:

// Register custom sidebar navigation for your root application
import { rootSettingsNavigation } from '@telemetryos/root-sdk';

await rootSettingsNavigation().register([
  { label: 'Channel Management', path: '/admin/channels' },
  { label: 'Hardware Configuration', path: '/admin/hardware' },
  { label: 'Viewing Analytics', path: '/admin/analytics' }
]);

This allows customers to manage your specialized resources alongside their standard TelemetryOS configuration.

Embedding Other Applications (Optional)

Root applications can also discover and embed other TelemetryOS applications if needed:

// Discover applications by mount point  
const widgets = await applications().getAllByMountPoint('status-widget');

// Create custom composition interface
const iframe = document.createElement('iframe');
iframe.src = await applications().getUrl('system-monitor', 'render');

Getting Started

To get started, add the SDK to your project:

Installation

With npm:

npm install @telemetryos/root-sdk

Or include it directly in your HTML:

<script src="https://cdn.jsdelivr.net/npm/@telemetryos/root-sdk"></script>

Basic Configuration

Import and configure the SDK with your application name:

import { configure } from '@telemetryos/root-sdk';

// Initialize the SDK - call this early in your application lifecycle
// The application name must match the name in your telemetry.config.json
configure('myAppName')

Or using the global object if you included the script directly:

telemetry.configure('myAppName')

The SDK automatically extracts the application ID from URL parameters, which is essential for proper functioning of the store's local and deviceLocal scopes.

Core SDK Features

Storage API

The SDK provides a powerful storage system with multiple scopes:

  • Global - Shared across all instances of your application within an account. Use for app-wide settings like branding or global configuration.
  • Local - Specific to this application instance (uses applicationId). Perfect for settings ↔ render communication since both mount points share the same instance.
  • DeviceLocal - Stored only on the current device, never synced across devices. Survives device restarts. Ideal for device-specific calibration or state.
  • Shared - Inter-application communication using namespace strings. Applications can coordinate by agreeing on namespace and key conventions.

The applicationId is automatically provided when your application is embedded, ensuring that multiple instances of your app maintain separate configurations.

Example usage:

import { store } from '@telemetryos/root-sdk';

// Global scope - shared across all instances of your app
await store().global.set('systemConfig', { theme: 'dark', language: 'en' });

// Local scope - specific to this app instance
await store().local.set('currentChannel', 'HBO');

// DeviceLocal scope - stays on this device only
await store().deviceLocal.set('hardwareConfig', { audioLevel: 0.8 });

// Shared scope - communicate with other applications
await store().shared.set('system-status', 'currentMode', 'interactive');

// Subscribe to changes for real-time updates
const channelHandler = (newChannel) => {
  console.log(`Channel updated to: ${newChannel}`);
  switchToChannel(newChannel);
};

store().local.subscribe('currentChannel', channelHandler);

// Clean up subscriptions when no longer needed
store().local.unsubscribe('currentChannel', channelHandler);

Store subscriptions are essential for real-time applications. When a setting is changed (e.g., in the settings mount point), the render mount point will receive immediate updates through store subscriptions.

Application Discovery

Applications can discover and embed other applications:

import { applications } from '@telemetryos/root-sdk';

// Find all applications with a specific mount point
const widgets = await applications().getAllByMountPoint('dashboard-widget');

// Get URL for embedding an application
const url = await applications().getUrl('weather-app', 'render');

// Use this URL in an iframe to embed the application
const iframe = document.createElement('iframe');
iframe.src = url;
document.body.appendChild(iframe);

Message Interceptors

Root applications can intercept messages from embedded sub-applications using message interceptors. This allows you to handle client messages before they bubble up to the parent window, enabling custom communication patterns:

import { applications } from '@telemetryos/root-sdk';

// Register an interceptor to provide color scheme to sub-applications
applications().bind('theme.getColorScheme', (data) => {
  // Get the current color scheme from settings or state
  const colors = getCurrentColorScheme();

  // Return a bridge message that will be sent to handlers and child frames
  return {
    name: 'theme.colorScheme',
    data: { primary: colors.primary, secondary: colors.secondary }
  };
});

// The interceptor transforms client messages into bridge messages
// that are handled locally and forwarded to child applications

Interceptors are useful for:

  • Theme Coordination - Provide consistent color schemes and styling across embedded applications
  • State Synchronization - Coordinate state changes across multiple embedded applications
  • Custom Routing - Implement application-specific message routing logic
  • Data Transformation - Normalize or transform message data before distribution

Media Access

Access media content uploaded to TelemetryOS:

import { media } from '@telemetryos/root-sdk';

// Get all media folders
const folders = await media().getAllFolders();

// Get all content in a specific folder
const content = await media().getAllByFolderId(folderId);

// Get content by tag
const taggedContent = await media().getAllByTag('marketing');

// Get a specific content item by ID
const mediaItem = await media().getById(mediaId);

// Use the public URL to display/play the media
const publicUrl = mediaItem.publicUrls[0];

Account and User Information

Access information about the current account and user:

import { accounts, users } from '@telemetryos/root-sdk';

// Get current account
const account = await accounts().getCurrent();

// Get current user
const user = await users().getCurrent();
const userId = user.id;

Device Information

Access information about the device the application is running on:

import { devices } from '@telemetryos/root-sdk';

// Get current device information
const device = await devices().getCurrent();
console.log(`Device: ${device.name}`);

// Get hardware information
const hardwareInfo = await devices().getInformation();
console.log(`Device: ${hardwareInfo.deviceManufacturer} ${hardwareInfo.deviceModel}`);

// Subscribe to device changes
await devices().subscribeCurrent((data) => {
  if (data.type === 'device_changed') {
    console.log('Device updated:', data.device);
  } else if (data.type === 'device_removed') {
    console.log('Device removed:', data.device.id);
  }
});

// Unsubscribe when done
await devices().unsubscribeCurrent(myHandler);

Proxy API

Fetch external content through the TelemetryOS proxy service:

import { proxy } from '@telemetryos/root-sdk';

// Fetch JSON from an external API
const response = await proxy().fetch('https://api.example.com/data');
const data = await response.json();

// POST data to an external API
const response = await proxy().fetch('https://api.example.com/submit', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ key: 'value' })
});

// Fetch an image through the proxy
const response = await proxy().fetch('https://example.com/image.jpg');
const blob = await response.blob();
const imageUrl = URL.createObjectURL(blob);

Weather API

Access weather data including current conditions, forecasts, and alerts. Weather data is sourced from WeatherBit and uses city IDs for location lookup.

import { weather } from '@telemetryos/root-sdk';

// Search for cities to get a cityId
const cities = await weather().getCities({ search: 'New York', countryCode: 'US' });
const cityId = cities[0].cityId;

// Get current weather conditions
const conditions = await weather().getConditions({ cityId });
console.log(`${conditions.temperatureC}°C / ${conditions.temperatureF}°F`);
console.log(`Wind: ${conditions.windSpeedKph} kph`);
console.log(`Humidity: ${conditions.humidity}%`);

// Get daily forecast (up to 16 days)
const daily = await weather().getDailyForecast({ cityId, days: 7 });
daily.data.forEach(day => {
  console.log(`${day.forecastDate}: ${day.weatherDescription}`);
  console.log(`High: ${day.maxTemperatureC}°C, Low: ${day.minTemperatureC}°C`);
});

// Get hourly forecast (up to 120 hours)
const hourly = await weather().getHourlyForecast({ cityId, hours: 24 });
hourly.data.forEach(hour => {
  console.log(`${hour.forecastTimeLocal}: ${hour.temperatureC}°C`);
});

// Get weather alerts
const alerts = await weather().getAlerts({ cityId });
alerts.alerts.forEach(alert => {
  console.log(`${alert.severity}: ${alert.title}`);
});

All weather responses include dual units (Celsius/Fahrenheit, kph/mph, mb/inHg, km/mi) so you can display data in the user's preferred format. An optional language parameter is available on all methods for localized weather descriptions.

Navigation API

The Navigation class provides browser-style navigation control for views embedded in iframes, used primarily by the web mount point. It intercepts pushState, replaceState, and popstate events and relays location changes to the host window via postMessage.

import { Navigation } from '@telemetryos/root-sdk';

Application developers using SPA routing frameworks (React Router, Vue Router, etc.) get navigation support automatically — the SDK intercepts history changes transparently. The host window (dev server or web host) displays an address bar with back/forward controls that communicate with the embedded view. Manual instantiation of Navigation is only needed for advanced or custom embedding scenarios.

Currency API

Access currency exchange rates and symbols:

import { currency } from '@telemetryos/root-sdk';

// Get all available currency symbols
const symbols = await currency().getSymbols();
// { "USD": "United States Dollar", "EUR": "Euro", ... }

// Get exchange rates for a base currency
const rates = await currency().getRates({
  base: 'USD',
  symbols: 'EUR,GBP,JPY'
});
// { "EUR": 0.92, "GBP": 0.79, "JPY": 149.50 }

Communication Patterns

The SDK uses a request-response pattern for most operations. All requests have a 30-second timeout by default to prevent hanging promises:

try {
  const result = await someAsyncSdkOperation();
  // Handle successful result
} catch (error) {
  // Handle timeout or other errors
  console.error('Operation failed:', error.message);
}

Offline Support

Your applications automatically work offline without any additional code. TelemetryOS handles caching for you:

  • Applications are cached locally on devices for offline operation
  • Store system works offline - all data reads and writes continue normally, syncing when back online
  • External API calls are cached - HTTP requests to external services work offline using cached responses
  • No configuration needed - offline support is completely automatic

This means users can interact with your application even when devices lose internet connectivity.

Advanced Features

Worker Scripts

Worker scripts run in the background continuously for root applications. On devices, they start when your root application is assigned and run until it's replaced. In the administration UI, they start when the page loads for any enabled root applications. Define them in your telemetry.config.json:

{
  "name": "my-application",
  "version": "1.0.0",
  "backgroundWorkers": {
    "background": "workers/background-sync.js"
  }
}

Worker scripts can access the SDK by importing and configuring it just like the main application. They're ideal for:

  • Periodic data synchronization.
  • Processing background tasks.
  • Maintaining real-time connections.
  • Updating shared state even when the main app is not in view.

Containers

Containers allow you to run more complex backend services alongside your application. They run in a local Docker instance, with traffic to specific hostnames automatically tunneled to the appropriate container.

Define containers in your telemetry.config.json:

{
  "name": "my-application",
  "version": "1.0.0",
  "containers": [
    {
      "name": "my-backend",
      "image": "mybackend:latest",
      "port": 3000
    }
  ]
}

Access the container from your application (containers only run on devices):

// Container name becomes hostname - requests to my-backend are routed to your container
fetch('https://my-backend/api/data')
  .then(response => response.json())
  .then(data => console.log(data));

// Your app should handle cases where containers aren't available (e.g., in administration UI)

telemetry.config.json Configuration

Your application must include a telemetry.config.json file at the root level:

{
  "name": "my-application",
  "version": "1.0.0",
  "displayName": "My Application",
  "description": "A TelemetryOS root application",
  "mountPoints": {
    "rootRender": "/root-render",
    "rootSettings": "/root-settings"
  },
  "backgroundWorkers": {
    "background": "workers/background.js"
  },
  "devServer": {
    "runCommand": "vite --port 3000",
    "url": "http://localhost:3000"
  }
}

This configuration:

  1. Defines your application name and metadata
  2. Specifies mount points for different application contexts
  3. Configures background workers
  4. Sets up containers if needed

Best Practices

  1. Store Usage

    • Use the appropriate store scope for your data
    • Always subscribe to changes for real-time updates rather than polling
    • Consider data persistence requirements when choosing a scope
  2. Application Structure

    • Clearly separate your settings UI from your render UI using mount points
    • Handle settings changes gracefully in the render view
    • Consider using a state management library with the SDK for complex applications
  3. Performance

    • Optimize your application for performance on TelemetryOS
    • Use worker scripts for background tasks and to maintain state during playlist transitions
    • Implement efficient rendering patterns to minimize resource usage
  4. Error Handling

    • Implement robust error handling for all SDK operations
    • Account for timeout scenarios (30-second default)
    • Provide fallback content when network operations fail
  5. Responsive Design

    • Design your application to adapt to different screen sizes and orientations
    • Test your application on different device types
    • Consider touch interaction for kiosk deployments

Development Workflow

  1. Develop and test your application locally
  2. Package your application with its config file
  3. Upload to TelemetryOS
  4. Enable your root application in account settings
  5. Assign your root application to specific devices in the devices list view

Implementation Patterns and Examples

This section provides structured examples of common implementation patterns to help you build effective TelemetryOS applications.

SDK Architecture Overview

  • Core Communication: The SDK uses the postMessage API for communication with TelemetryOS.
  • Message Flow: Messages flow between applications and TelemetryOS via the parent window.
  • Resource APIs: Domain-specific APIs (store, media, applications, etc.) are built on top of the core messaging APIs.
  • Configuration Flow: Applications must call configure() before using any SDK features.

Common Implementation Patterns

1. Fetching and Displaying Media

import { media } from '@telemetryos/root-sdk';

async function displayMedia(mediaId) {
  const mediaItem = await media().getById(mediaId);
  const mediaElement = document.createElement('img');
  mediaElement.src = mediaItem.publicUrls[0];
  document.body.appendChild(mediaElement);
}

2. Settings Communication Between Mount Points

import { store } from '@telemetryos/root-sdk';

// In settings mount point
async function saveSettings(city) {
  await store().local.set('city', city);
}

// In render mount point
function setupSettingsListener() {
  store().local.subscribe('city', (city) => {
    updateWeatherDisplay(city);
  });
  
  // Initial load
  store().local.get('city').then(city => {
    if (city) updateWeatherDisplay(city);
  });
}

3. Embedding Another Application

import { applications } from '@telemetryos/root-sdk';

async function embedWeatherWidget(containerId) {
  const url = await applications().getUrl('weather-app', 'render');
  const container = document.getElementById(containerId);
  
  const iframe = document.createElement('iframe');
  iframe.src = url;
  iframe.style.border = 'none';
  iframe.style.width = '100%';
  iframe.style.height = '100%';
  
  container.appendChild(iframe);
}

4. Implementing a Background Worker

// In worker.js - defined in telemetry.config.json
import { configure, store } from '@telemetryos/root-sdk';

configure('myApp');

// Run periodic synchronization
async function syncData() {
  try {
    const data = await fetchExternalData();
    await store().global.set('latestData', data);
  } catch (error) {
    console.error('Sync failed:', error);
  }
  
  // Schedule next sync
  setTimeout(syncData, 60000);
}

// Start sync process
syncData();

5. Robust Error Handling

Always implement proper error handling for SDK operations:

try {
  const result = await media().getAllByTag('marketing');
  displayContent(result);
} catch (error) {
  // Check for timeout errors
  if (error.message.includes('timed out')) {
    showTimeoutMessage();
  } else {
    showGenericError();
  }

  // Provide fallback content or retry strategy
  displayCachedContent();
}

Complete Application Examples

Weather Application

// In settings.js (settings mount point)
import { configure, store } from '@telemetryos/root-sdk';

configure('weather-app');

document.getElementById('cityForm').addEventListener('submit', async (e) => {
  e.preventDefault();
  const city = document.getElementById('cityInput').value;
  await store().local.set('city', city);
  showSuccessMessage('City saved successfully');
});

// Initial load of current value
store().local.get('city').then(city => {
  if (city) {
    document.getElementById('cityInput').value = city;
  }
});
// In render.js (render mount point)
import { configure, store } from '@telemetryos/root-sdk';

configure('weather-app');

// Subscribe to city changes
store().local.subscribe('city', (city) => {
  if (city) {
    fetchAndDisplayWeather(city);
  } else {
    showConfigurationMessage();
  }
});

// Initial load
store().local.get('city').then(city => {
  if (city) {
    fetchAndDisplayWeather(city);
  } else {
    showConfigurationMessage();
  }
});

async function fetchAndDisplayWeather(city) {
  try {
    const weather = await fetchWeatherData(city);
    renderWeatherUI(weather);
  } catch (error) {
    showErrorMessage('Could not load weather data');
  }
}

Dashboard Container Application

import { configure, applications } from '@telemetryos/root-sdk';

configure('dashboard-app');

async function initializeDashboard() {
  try {
    // Discover all dashboard widget applications
    const widgets = await applications().getAllByMountPoint('dashboard-widget');
    
    if (widgets.length === 0) {
      showNoWidgetsMessage();
      return;
    }
    
    const container = document.getElementById('widgetsContainer');
    
    // Create a grid layout for widgets
    for (const widget of widgets) {
      const widgetElement = document.createElement('div');
      widgetElement.className = 'widget-container';
      
      // Get embeddable URL for this widget
      const url = await applications().getUrl(widget.name, 'dashboard-widget');
      
      // Create and configure iframe
      const iframe = document.createElement('iframe');
      iframe.src = url;
      iframe.title = widget.name;
      iframe.frameBorder = '0';
      iframe.style.width = '100%';
      iframe.style.height = '100%';
      
      widgetElement.appendChild(iframe);
      container.appendChild(widgetElement);
    }
  } catch (error) {
    console.error('Failed to initialize dashboard:', error);
    showErrorMessage();
  }
}

// Initialize dashboard when DOM is ready
document.addEventListener('DOMContentLoaded', initializeDashboard);

Support and Resources

For more information or support, please visit our documentation or contact our support team.

Happy building!