@tomorrowos/sdk 0.6.7 → 0.6.9

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.
@@ -52,9 +52,13 @@ export interface DeviceListItem {
52
52
  name: string;
53
53
  version: number;
54
54
  publishedAt: string;
55
+ schedule?: {
56
+ startDate?: string;
57
+ endDate?: string;
58
+ start?: string;
59
+ end?: string;
60
+ };
55
61
  }>;
56
- currentPlaylistId: string | null;
57
- currentPlaylistName: string | null;
58
62
  latestErrorAt: string | null;
59
63
  latestErrorMessage: string | null;
60
64
  }
@@ -80,7 +84,6 @@ export declare class TomorrowOS extends EventEmitter {
80
84
  private readonly devices;
81
85
  private readonly pendingDeviceMeta;
82
86
  private readonly deviceLogs;
83
- private readonly livePlaybackByDevice;
84
87
  private httpServer;
85
88
  private wss;
86
89
  private staticRoot;
@@ -112,7 +115,6 @@ export declare class TomorrowOS extends EventEmitter {
112
115
  };
113
116
  /** List paired devices with live connection + timing fields for the CMS panel. */
114
117
  listDevices(): Promise<DeviceListItem[]>;
115
- private refreshLivePlaybackState;
116
118
  setDeviceName(deviceId: string, deviceName: string): Promise<{
117
119
  deviceId: string;
118
120
  deviceName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
@@ -186,7 +186,6 @@ export class TomorrowOS extends EventEmitter {
186
186
  devices = new Map();
187
187
  pendingDeviceMeta = new Map();
188
188
  deviceLogs = new Map();
189
- livePlaybackByDevice = new Map();
190
189
  httpServer = null;
191
190
  wss = null;
192
191
  staticRoot = null;
@@ -313,13 +312,6 @@ export class TomorrowOS extends EventEmitter {
313
312
  const connected = this.isDeviceConnected(deviceId);
314
313
  const reg = await this.store.getDeviceRegistry(deviceId);
315
314
  const assignments = await this.store.getDeviceAssignments(deviceId);
316
- if (connected) {
317
- await this.refreshLivePlaybackState(deviceId);
318
- }
319
- else {
320
- this.livePlaybackByDevice.delete(deviceId);
321
- }
322
- const playback = this.livePlaybackByDevice.get(deviceId);
323
315
  let screenOnlineActive = false;
324
316
  let screenOnlineLabel = "Not active";
325
317
  if (connected && record.lastBootAt) {
@@ -339,10 +331,9 @@ export class TomorrowOS extends EventEmitter {
339
331
  playlistId: a.playlistId,
340
332
  name: a.snapshot.name,
341
333
  version: a.publishedVersion,
342
- publishedAt: a.publishedAt
334
+ publishedAt: a.publishedAt,
335
+ schedule: a.snapshot.schedule
343
336
  })),
344
- currentPlaylistId: playback?.playlistId ?? null,
345
- currentPlaylistName: playback?.playlistName ?? null,
346
337
  connected,
347
338
  deviceName: record.deviceName ?? null,
348
339
  platform: record.platform ?? null,
@@ -362,35 +353,6 @@ export class TomorrowOS extends EventEmitter {
362
353
  };
363
354
  }));
364
355
  }
365
- async refreshLivePlaybackState(deviceId) {
366
- const ws = this.devices.get(deviceId);
367
- if (!ws || ws.readyState !== WebSocket.OPEN)
368
- return;
369
- try {
370
- const result = await this.sendCommandToSocket(ws, deviceId, "device.info.get", {}, 5_000);
371
- if (result.status !== "success" || !result.data || typeof result.data !== "object") {
372
- return;
373
- }
374
- const info = result.data;
375
- const playback = info.currentPlayback && typeof info.currentPlayback === "object"
376
- ? info.currentPlayback
377
- : info;
378
- const playlistId = typeof playback.activePlaylistId === "string" && playback.activePlaylistId.trim()
379
- ? playback.activePlaylistId.trim()
380
- : null;
381
- const playlistName = typeof playback.activePlaylistName === "string" && playback.activePlaylistName.trim()
382
- ? playback.activePlaylistName.trim()
383
- : null;
384
- this.livePlaybackByDevice.set(deviceId, {
385
- playlistId,
386
- playlistName,
387
- updatedAt: new Date().toISOString()
388
- });
389
- }
390
- catch {
391
- // Best-effort only; keep previous value on intermittent timeouts.
392
- }
393
- }
394
356
  async setDeviceName(deviceId, deviceName) {
395
357
  const id = String(deviceId || "").trim();
396
358
  if (!id) {
@@ -1428,6 +1390,7 @@ export class TomorrowOS extends EventEmitter {
1428
1390
  if (level === "error") {
1429
1391
  console.error(`[TomorrowOS][device-log][${deviceId}] ${message}`);
1430
1392
  }
1393
+ return;
1431
1394
  }
1432
1395
  });
1433
1396
  ws.on("close", () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
4
4
  "description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
5
5
  "private": true,
6
6
  "type": "module",
@@ -10,7 +10,7 @@
10
10
  "build-player": "tomorrowos build --platform tizen"
11
11
  },
12
12
  "dependencies": {
13
- "@tomorrowos/sdk": "^0.6.7",
13
+ "@tomorrowos/sdk": "^0.6.9",
14
14
  "dotenv": "^17.2.3"
15
15
  },
16
16
  "devDependencies": {
@@ -503,6 +503,58 @@ function loadScheduleIntoForm(schedule) {
503
503
  document.getElementById("scheduleEndTime").value = s.end || "";
504
504
  }
505
505
 
506
+ function parseScheduleDateTimeMs(dateStr, timeStr, defaultTime) {
507
+ const date = String(dateStr || "").trim();
508
+ if (!date) return null;
509
+ const time = String(timeStr || "").trim() || defaultTime;
510
+ const value = new Date(`${date}T${time}:00`);
511
+ const ms = value.getTime();
512
+ return Number.isNaN(ms) ? null : ms;
513
+ }
514
+
515
+ function getPublishedPlaylistStartMs(playlist) {
516
+ const schedule = playlist?.schedule;
517
+ if (!schedule) return null;
518
+ return parseScheduleDateTimeMs(schedule.startDate, schedule.start, "00:00");
519
+ }
520
+
521
+ function getPublishedPlaylistEndMs(playlist) {
522
+ const schedule = playlist?.schedule;
523
+ if (!schedule) return null;
524
+ return parseScheduleDateTimeMs(schedule.endDate, schedule.end, "23:59");
525
+ }
526
+
527
+ function isPublishedPlaylistActiveNow(playlist, now = new Date()) {
528
+ const schedule = playlist?.schedule;
529
+ if (!schedule) return true;
530
+ const nowMs = now.getTime();
531
+ const startMs = getPublishedPlaylistStartMs(playlist);
532
+ const endMs = getPublishedPlaylistEndMs(playlist);
533
+ if (startMs !== null && nowMs < startMs) return false;
534
+ if (endMs !== null && nowMs >= endMs) return false;
535
+ return true;
536
+ }
537
+
538
+ function pickScheduledPlaylistForIndicator(playlists, now = new Date()) {
539
+ const active = (Array.isArray(playlists) ? playlists : []).filter((playlist) =>
540
+ isPublishedPlaylistActiveNow(playlist, now)
541
+ );
542
+ if (!active.length) return null;
543
+
544
+ active.sort((a, b) => {
545
+ const aStart = getPublishedPlaylistStartMs(a);
546
+ const bStart = getPublishedPlaylistStartMs(b);
547
+ const aScore = aStart === null ? -Infinity : aStart;
548
+ const bScore = bStart === null ? -Infinity : bStart;
549
+ if (aScore !== bScore) return bScore - aScore;
550
+ const aPublished = new Date(a?.publishedAt || 0).getTime() || 0;
551
+ const bPublished = new Date(b?.publishedAt || 0).getTime() || 0;
552
+ return bPublished - aPublished;
553
+ });
554
+
555
+ return active[0] || null;
556
+ }
557
+
506
558
  function getSelectedPlaylist() {
507
559
  return playlistsCatalog.find((p) => p.id === selectedPlaylistId) || null;
508
560
  }
@@ -902,8 +954,8 @@ function renderDeviceCards() {
902
954
  const published = document.createElement("ul");
903
955
  published.className = "device-published-list";
904
956
  const pubs = Array.isArray(device.publishedPlaylists) ? device.publishedPlaylists : [];
905
- const activePlaylistId = typeof device.currentPlaylistId === "string" ? device.currentPlaylistId : "";
906
- const activePlaylistName = typeof device.currentPlaylistName === "string" ? device.currentPlaylistName : "";
957
+ const indicatorPlaylist = pickScheduledPlaylistForIndicator(pubs);
958
+ const indicatorPlaylistId = indicatorPlaylist?.playlistId || "";
907
959
  if (pubs.length === 0) {
908
960
  const li = document.createElement("li");
909
961
  li.textContent = "No playlists published";
@@ -914,13 +966,11 @@ function renderDeviceCards() {
914
966
  const label = document.createElement("span");
915
967
  label.className = "device-published-label";
916
968
  label.textContent = p.name;
917
- const isPlaying =
918
- (activePlaylistId && p.playlistId === activePlaylistId) ||
919
- (!activePlaylistId && activePlaylistName && p.name === activePlaylistName);
969
+ const isPlaying = !!indicatorPlaylistId && p.playlistId === indicatorPlaylistId;
920
970
  if (isPlaying) {
921
971
  const playingLight = document.createElement("span");
922
972
  playingLight.className = "playlist-playing-light";
923
- playingLight.title = "Currently playing";
973
+ playingLight.title = "Active now by schedule";
924
974
  label.appendChild(playingLight);
925
975
  }
926
976
  const rm = document.createElement("button");