@telemetryos/sdk 1.0.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 ADDED
@@ -0,0 +1,588 @@
1
+ # TelemetryOS Applications SDK
2
+
3
+ Welcome to the TelemetryOS Applications SDK! This document will guide you through building applications for TelemetryOS.
4
+
5
+ ## What is TelemetryOS?
6
+
7
+ 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.
8
+
9
+ Key features of the platform include:
10
+
11
+ - Run single-page applications on display devices.
12
+ - Support containers that run alongside applications.
13
+ - Run worker scripts that operate continuously in the background.
14
+ - Compose content with our Freeform Editor for visual layouts.
15
+ - Support content playlists and scheduling.
16
+ - Manage devices at scale.
17
+
18
+ ## Standard Applications in TelemetryOS
19
+
20
+ Standard applications are web applications that run within TelemetryOS's Freeform Editor. The Freeform Editor is our default visual content composition tool that allows users to create layouts by positioning applications alongside media, text, and other visual elements.
21
+
22
+ Your standard application will be embedded as an iframe within the Freeform Editor and can be positioned, resized, and scheduled as part of content playlists that display on physical devices like digital signage and kiosks.
23
+
24
+ ### Mount Points
25
+
26
+ Standard applications define mount points in their `telemetry.config.json` file:
27
+
28
+ - `settings` - The configuration interface that appears in the Freeform Editor's sidebar when your application is selected. This runs in the [administration UI][admin-ui] where customers configure your app.
29
+ - `render` - The actual content that displays on devices and in the Freeform Editor's canvas. This is what end users see.
30
+
31
+ And optionally a worker script:
32
+
33
+ - `background` - A worker that runs continuously in the background, even when your application is not currently visible in the playlist rotation.
34
+
35
+ ### Integration with Freeform Editor
36
+
37
+ Since your application runs within the Freeform Editor, you get additional capabilities:
38
+
39
+ - **Control playlist navigation** - Move between playlist pages or modify page timing
40
+ - **Trigger content overrides** - Display emergency alerts or priority content that interrupts the normal playlist flow
41
+ - **Communicate with other applications** - Discover and embed other applications within your own interface
42
+
43
+ ## Getting Started
44
+
45
+ To get started, add the SDK to your project:
46
+
47
+ ### Installation
48
+
49
+ With npm:
50
+
51
+ ```bash
52
+ npm install @telemetryos/sdk
53
+ ```
54
+
55
+ Or include it directly in your HTML:
56
+
57
+ ```html
58
+ <script src="https://cdn.jsdelivr.net/npm/@telemetryos/sdk"></script>
59
+ ```
60
+
61
+ ### Basic Configuration
62
+
63
+ Import and configure the SDK with your application name:
64
+
65
+ ```javascript
66
+ import { configure } from '@telemetryos/sdk';
67
+
68
+ // Initialize the SDK - call this early in your application lifecycle
69
+ // The application name must match the name in your telemetry.config.json
70
+ configure('myAppName')
71
+ ```
72
+
73
+ Or using the global object if you included the script directly:
74
+
75
+ ```javascript
76
+ telemetry.configure('myAppName')
77
+ ```
78
+
79
+ The SDK automatically extracts the application ID from URL parameters, which is essential for proper functioning of the store's local and deviceLocal scopes.
80
+
81
+ ## Core SDK Features
82
+
83
+ ### Storage API
84
+
85
+ The SDK provides a powerful storage system with multiple scopes:
86
+
87
+ - **Global** - Shared across all instances of your application within an account. Use for app-wide settings like branding or global configuration.
88
+ - **Local** - Specific to this application instance (uses applicationId). Perfect for settings ↔ render communication since both mount points share the same instance.
89
+ - **DeviceLocal** - Stored only on the current device, never synced across devices. Survives device restarts. Ideal for kiosk interactions or device-specific calibration.
90
+ - **Shared** - Inter-application communication using namespace strings. Applications can coordinate by agreeing on namespace and key conventions.
91
+
92
+ The `applicationId` is automatically provided when your application is embedded, ensuring that multiple instances of your app maintain separate configurations.
93
+
94
+ Example usage:
95
+
96
+ ```javascript
97
+ import { store } from '@telemetryos/sdk';
98
+
99
+ // Global scope - shared across all instances of your app
100
+ await store().global.set('companyBranding', { logo: 'url', colors: {...} });
101
+
102
+ // Local scope - specific to this app instance
103
+ await store().local.set('city', 'New York');
104
+
105
+ // DeviceLocal scope - stays on this device only
106
+ await store().deviceLocal.set('calibrationData', { brightness: 0.8 });
107
+
108
+ // Shared scope - communicate with other applications
109
+ await store().shared.set('weather-data', 'temperature', '72°F');
110
+
111
+ // Subscribe to changes for real-time updates
112
+ const cityHandler = (newCity) => {
113
+ console.log(`City updated to: ${newCity}`);
114
+ updateWeatherDisplay(newCity);
115
+ };
116
+
117
+ store().local.subscribe('city', cityHandler);
118
+
119
+ // Clean up subscriptions when no longer needed
120
+ store().local.unsubscribe('city', cityHandler);
121
+ ```
122
+
123
+ 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.
124
+
125
+ ### Application Discovery
126
+
127
+ Applications can discover and embed other applications:
128
+
129
+ ```javascript
130
+ import { applications } from '@telemetryos/sdk';
131
+
132
+ // Find all applications with a specific mount point
133
+ const widgets = await applications().getAllByMountPoint('dashboard-widget');
134
+
135
+ // Get URL for embedding an application
136
+ const url = await applications().getUrl('weather-app', 'render');
137
+
138
+ // Use this URL in an iframe to embed the application
139
+ const iframe = document.createElement('iframe');
140
+ iframe.src = url;
141
+ document.body.appendChild(iframe);
142
+ ```
143
+
144
+ ### Media Access
145
+
146
+ Access media content uploaded to TelemetryOS:
147
+
148
+ ```javascript
149
+ import { media } from '@telemetryos/sdk';
150
+
151
+ // Get media folders by tag
152
+ const folders = await media().getFoldersByTag('marketing');
153
+
154
+ // Get content from a folder
155
+ const content = await media().getMediaContentByFolderId(folderId);
156
+
157
+ // Access the media file URLs
158
+ const mediaItem = await media().getMediaContentById(mediaId);
159
+
160
+ // Use this URL to display/play the media
161
+ const publicUrl = mediaItem.publicUrls[0];
162
+ ```
163
+
164
+ ### Account and User Information
165
+
166
+ Access information about the current account and user:
167
+
168
+ ```javascript
169
+ import { accounts, users } from '@telemetryos/sdk';
170
+
171
+ // Get current account
172
+ const account = await accounts().getCurrent();
173
+
174
+ // Get current user
175
+ const userResult = await users().getCurrent();
176
+ const userId = userResult.user.id;
177
+ ```
178
+
179
+ ### Playlist Control
180
+
181
+ Control the Freeform Editor's playlist state, allowing your application to navigate through playlist pages and modify timing:
182
+
183
+ ```javascript
184
+ import { playlist } from '@telemetryos/sdk';
185
+
186
+ // Move to the next page in the playlist
187
+ await playlist().nextPage();
188
+
189
+ // Move to the previous page in the playlist
190
+ await playlist().previousPage();
191
+
192
+ // Set the duration for the current page (in seconds)
193
+ await playlist().setDuration(30);
194
+ ```
195
+
196
+ ### Content Overrides
197
+
198
+ Manage content overrides within the Freeform Editor to temporarily display specific content:
199
+
200
+ ```javascript
201
+ import { overrides } from '@telemetryos/sdk';
202
+
203
+ // Set an override to display specific content
204
+ await overrides().setOverride('emergency-alert');
205
+
206
+ // Clear an existing override
207
+ await overrides().clearOverride('emergency-alert');
208
+ ```
209
+
210
+ ## Communication Patterns
211
+
212
+ The SDK uses a request-response pattern for most operations. All requests have a 30-second timeout by default to prevent hanging promises:
213
+
214
+ ```javascript
215
+ try {
216
+ const result = await someAsyncSdkOperation();
217
+ // Handle successful result
218
+ } catch (error) {
219
+ // Handle timeout or other errors
220
+ console.error('Operation failed:', error.message);
221
+ }
222
+ ```
223
+
224
+ ## Offline Support
225
+
226
+ Your applications automatically work offline without any additional code. TelemetryOS handles caching for you:
227
+
228
+ - **Applications are cached locally** on devices for offline operation
229
+ - **Store system works offline** - all data reads and writes continue normally, syncing when back online
230
+ - **External API calls are cached** - HTTP requests to external services work offline using cached responses
231
+ - **No configuration needed** - offline support is completely automatic
232
+
233
+ This means users can interact with your application even when devices lose internet connectivity.
234
+
235
+ ## Advanced Features
236
+
237
+ ### Worker Scripts
238
+
239
+ Worker scripts run in the background even when your application isn't currently visible in the playlist rotation. For standard applications, they start automatically when a playlist containing your application is loaded (on devices) or opened for editing (in the administration UI). Define them in your `telemetry.config.json`:
240
+
241
+ ```json
242
+ {
243
+ "name": "my-application",
244
+ "version": "1.0.0",
245
+ "workers": [
246
+ {
247
+ "script": "./workers/background-sync.js"
248
+ }
249
+ ]
250
+ }
251
+ ```
252
+
253
+ Worker scripts can access the SDK by importing and configuring it just like the main application. They're ideal for:
254
+
255
+ - Periodic data synchronization.
256
+ - Processing background tasks.
257
+ - Maintaining real-time connections.
258
+ - Updating shared state even when the main app is not in view.
259
+
260
+ ### Containers
261
+
262
+ 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.
263
+
264
+ Define containers in your `telemetry.config.json`:
265
+
266
+ ```json
267
+ {
268
+ "name": "my-application",
269
+ "version": "1.0.0",
270
+ "containers": [
271
+ {
272
+ "name": "my-backend",
273
+ "image": "mybackend:latest",
274
+ "port": 3000
275
+ }
276
+ ]
277
+ }
278
+ ```
279
+
280
+ Access the container from your application (containers only run on devices):
281
+
282
+ ```javascript
283
+ // Container name becomes hostname - requests to my-backend are routed to your container
284
+ fetch('https://my-backend/api/data')
285
+ .then(response => response.json())
286
+ .then(data => console.log(data));
287
+
288
+ // Your app should handle cases where containers aren't available (e.g., in administration UI)
289
+ ```
290
+
291
+ ## `telemetry.config.json` Configuration
292
+
293
+ Your application must include a `telemetry.config.json` file at the root level:
294
+
295
+ ```json
296
+ {
297
+ "name": "my-application",
298
+ "version": "1.0.0",
299
+ "displayName": "My Application",
300
+ "description": "A TelemetryOS application that does amazing things",
301
+ "mountPoints": {
302
+ "render": {
303
+ "path": "/render"
304
+ },
305
+ "settings": {
306
+ "path": "/settings"
307
+ }
308
+ },
309
+ "workers": [
310
+ {
311
+ "name": "background",
312
+ "script": "./workers/background.js"
313
+ }
314
+ ],
315
+ "containers": []
316
+ }
317
+ ```
318
+
319
+ This configuration:
320
+
321
+ 1. Defines your application name and metadata
322
+ 2. Specifies mount points for different application contexts
323
+ 3. Configures background workers
324
+ 4. Sets up containers if needed
325
+
326
+ ## Best Practices
327
+
328
+ 1. **Store Usage**
329
+ - Use the appropriate store scope for your data
330
+ - Always subscribe to changes for real-time updates rather than polling
331
+ - Consider data persistence requirements when choosing a scope
332
+
333
+ 2. **Application Structure**
334
+ - Clearly separate your settings UI from your render UI using mount points
335
+ - Handle settings changes gracefully in the render view
336
+ - Consider using a state management library with the SDK for complex applications
337
+
338
+ 3. **Performance**
339
+ - Optimize your application for performance on TelemetryOS
340
+ - Use worker scripts for background tasks and to maintain state during playlist transitions
341
+ - Implement efficient rendering patterns to minimize resource usage
342
+
343
+ 4. **Error Handling**
344
+ - Implement robust error handling for all SDK operations
345
+ - Account for timeout scenarios (30-second default)
346
+ - Provide fallback content when network operations fail
347
+
348
+ 5. **Responsive Design**
349
+ - Design your application to adapt to different screen sizes and orientations
350
+ - Test your application on different device types
351
+ - Consider touch interaction for kiosk deployments
352
+
353
+ ## Development Workflow
354
+
355
+ 1. Develop and test your application locally
356
+ 2. Package your application with its config file
357
+ 3. Upload to TelemetryOS
358
+ 4. Add your application to a playlist
359
+ 5. Assign your playlist to one or more devices
360
+
361
+ ## Implementation Patterns and Examples
362
+
363
+ This section provides structured examples of common implementation patterns to help you build effective TelemetryOS applications.
364
+
365
+ ### SDK Architecture Overview
366
+
367
+ - **Core Communication**: The SDK uses the `postMessage` API for communication with TelemetryOS.
368
+ - **Message Flow**: Messages flow between applications and TelemetryOS via the parent window.
369
+ - **Resource APIs**: Domain-specific APIs (store, media, applications, etc.) are built on top of the core messaging APIs.
370
+ - **Configuration Flow**: Applications must call `configure()` before using any SDK features.
371
+
372
+ ### Common Implementation Patterns
373
+
374
+ #### 1. Fetching and Displaying Media
375
+
376
+ ```javascript
377
+ import { media } from '@telemetryos/sdk';
378
+
379
+ async function displayMedia(mediaId) {
380
+ const mediaItem = await media().getMediaContentById(mediaId);
381
+ const mediaElement = document.createElement('img');
382
+ mediaElement.src = mediaItem.publicUrls[0];
383
+ document.body.appendChild(mediaElement);
384
+ }
385
+ ```
386
+
387
+ #### 2. Settings Communication Between Mount Points
388
+
389
+ ```javascript
390
+ import { store } from '@telemetryos/sdk';
391
+
392
+ // In settings mount point
393
+ async function saveSettings(city) {
394
+ await store().local.set('city', city);
395
+ }
396
+
397
+ // In render mount point
398
+ function setupSettingsListener() {
399
+ store().local.subscribe('city', (city) => {
400
+ updateWeatherDisplay(city);
401
+ });
402
+
403
+ // Initial load
404
+ store().local.get('city').then(city => {
405
+ if (city) updateWeatherDisplay(city);
406
+ });
407
+ }
408
+ ```
409
+
410
+ #### 3. Embedding Another Application
411
+
412
+ ```javascript
413
+ import { applications } from '@telemetryos/sdk';
414
+
415
+ async function embedWeatherWidget(containerId) {
416
+ const url = await applications().getUrl('weather-app', 'render');
417
+ const container = document.getElementById(containerId);
418
+
419
+ const iframe = document.createElement('iframe');
420
+ iframe.src = url;
421
+ iframe.style.border = 'none';
422
+ iframe.style.width = '100%';
423
+ iframe.style.height = '100%';
424
+
425
+ container.appendChild(iframe);
426
+ }
427
+ ```
428
+
429
+ #### 4. Implementing a Background Worker
430
+
431
+ ```javascript
432
+ // In worker.js - defined in telemetry.config.json
433
+ import { configure, store } from '@telemetryos/sdk';
434
+
435
+ configure('myApp');
436
+
437
+ // Run periodic synchronization
438
+ async function syncData() {
439
+ try {
440
+ const data = await fetchExternalData();
441
+ await store().global.set('latestData', data);
442
+ } catch (error) {
443
+ console.error('Sync failed:', error);
444
+ }
445
+
446
+ // Schedule next sync
447
+ setTimeout(syncData, 60000);
448
+ }
449
+
450
+ // Start sync process
451
+ syncData();
452
+ ```
453
+
454
+ #### 5. Robust Error Handling
455
+
456
+ Always implement proper error handling for SDK operations:
457
+
458
+ ```javascript
459
+ try {
460
+ const result = await media().getFoldersByTag('marketing');
461
+ displayFolders(result);
462
+ } catch (error) {
463
+ // Check for timeout errors
464
+ if (error.message.includes('timed out')) {
465
+ showTimeoutMessage();
466
+ } else {
467
+ showGenericError();
468
+ }
469
+
470
+ // Provide fallback content or retry strategy
471
+ displayCachedContent();
472
+ }
473
+ ```
474
+
475
+ ### Complete Application Examples
476
+
477
+ #### Weather Application
478
+
479
+ ```javascript
480
+ // In settings.js (settings mount point)
481
+ import { configure, store } from '@telemetryos/sdk';
482
+
483
+ configure('weather-app');
484
+
485
+ document.getElementById('cityForm').addEventListener('submit', async (e) => {
486
+ e.preventDefault();
487
+ const city = document.getElementById('cityInput').value;
488
+ await store().local.set('city', city);
489
+ showSuccessMessage('City saved successfully');
490
+ });
491
+
492
+ // Initial load of current value
493
+ store().local.get('city').then(city => {
494
+ if (city) {
495
+ document.getElementById('cityInput').value = city;
496
+ }
497
+ });
498
+ ```
499
+
500
+ ```javascript
501
+ // In render.js (render mount point)
502
+ import { configure, store } from '@telemetryos/sdk';
503
+
504
+ configure('weather-app');
505
+
506
+ // Subscribe to city changes
507
+ store().local.subscribe('city', (city) => {
508
+ if (city) {
509
+ fetchAndDisplayWeather(city);
510
+ } else {
511
+ showConfigurationMessage();
512
+ }
513
+ });
514
+
515
+ // Initial load
516
+ store().local.get('city').then(city => {
517
+ if (city) {
518
+ fetchAndDisplayWeather(city);
519
+ } else {
520
+ showConfigurationMessage();
521
+ }
522
+ });
523
+
524
+ async function fetchAndDisplayWeather(city) {
525
+ try {
526
+ const weather = await fetchWeatherData(city);
527
+ renderWeatherUI(weather);
528
+ } catch (error) {
529
+ showErrorMessage('Could not load weather data');
530
+ }
531
+ }
532
+ ```
533
+
534
+ #### Dashboard Container Application
535
+
536
+ ```javascript
537
+ import { configure, applications } from '@telemetryos/sdk';
538
+
539
+ configure('dashboard-app');
540
+
541
+ async function initializeDashboard() {
542
+ try {
543
+ // Discover all dashboard widget applications
544
+ const widgets = await applications().getAllByMountPoint('dashboard-widget');
545
+
546
+ if (widgets.length === 0) {
547
+ showNoWidgetsMessage();
548
+ return;
549
+ }
550
+
551
+ const container = document.getElementById('widgetsContainer');
552
+
553
+ // Create a grid layout for widgets
554
+ for (const widget of widgets) {
555
+ const widgetElement = document.createElement('div');
556
+ widgetElement.className = 'widget-container';
557
+
558
+ // Get embeddable URL for this widget
559
+ const url = await applications().getUrl(widget.name, 'dashboard-widget');
560
+
561
+ // Create and configure iframe
562
+ const iframe = document.createElement('iframe');
563
+ iframe.src = url;
564
+ iframe.title = widget.name;
565
+ iframe.frameBorder = '0';
566
+ iframe.style.width = '100%';
567
+ iframe.style.height = '100%';
568
+
569
+ widgetElement.appendChild(iframe);
570
+ container.appendChild(widgetElement);
571
+ }
572
+ } catch (error) {
573
+ console.error('Failed to initialize dashboard:', error);
574
+ showErrorMessage();
575
+ }
576
+ }
577
+
578
+ // Initialize dashboard when DOM is ready
579
+ document.addEventListener('DOMContentLoaded', initializeDashboard);
580
+ ```
581
+
582
+ ## Support and Resources
583
+
584
+ For more information or support, please visit our documentation or contact our support team.
585
+
586
+ Happy building!
587
+
588
+ [admin-ui]: https://app.telemetryos.ai
@@ -0,0 +1,7 @@
1
+ import { Client as RootClient } from '@telemetryos/root-sdk';
2
+ import { Overrides } from './overrides.js';
3
+ import { Playlist } from './playlist.js';
4
+ export declare class Client extends RootClient {
5
+ get playlist(): Playlist;
6
+ get overrides(): Overrides;
7
+ }