@tomorrowos/sdk 0.3.6 → 0.3.8
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/dist/tomorrowos.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,IAAI,MAAM,MAAM,CAAC;AAUxB,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,EAIV,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAO1B,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAC;IACvB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
|
package/dist/tomorrowos.js
CHANGED
|
@@ -26,6 +26,52 @@ function formatDurationMs(ms) {
|
|
|
26
26
|
parts.push(`${seconds}s`);
|
|
27
27
|
return parts.join(" ");
|
|
28
28
|
}
|
|
29
|
+
function parseBootIsoMs(iso) {
|
|
30
|
+
if (!iso)
|
|
31
|
+
return null;
|
|
32
|
+
const ms = new Date(iso).getTime();
|
|
33
|
+
return Number.isFinite(ms) ? ms : null;
|
|
34
|
+
}
|
|
35
|
+
function parseBootUptimeSec(msg) {
|
|
36
|
+
const raw = msg.bootUptimeSec ?? msg.bootUptimeSeconds;
|
|
37
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0)
|
|
38
|
+
return raw;
|
|
39
|
+
if (typeof raw === "string" && raw.trim()) {
|
|
40
|
+
const n = Number(raw);
|
|
41
|
+
if (Number.isFinite(n) && n >= 0)
|
|
42
|
+
return n;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/** Derive boot instant from device uptime + CMS clock (avoids wrong TV wall clock). */
|
|
47
|
+
function bootAtFromUptimeSec(uptimeSec) {
|
|
48
|
+
return new Date(Date.now() - uptimeSec * 1000).toISOString();
|
|
49
|
+
}
|
|
50
|
+
function lastBootAtFromHandshake(msg, existing) {
|
|
51
|
+
const uptimeSec = parseBootUptimeSec(msg);
|
|
52
|
+
if (uptimeSec != null) {
|
|
53
|
+
return resolveLastBootAt(bootAtFromUptimeSec(uptimeSec), existing);
|
|
54
|
+
}
|
|
55
|
+
const bootedAt = typeof msg.bootedAt === "string" ? msg.bootedAt : undefined;
|
|
56
|
+
return resolveLastBootAt(bootedAt, existing);
|
|
57
|
+
}
|
|
58
|
+
/** Merge device-reported boot time with stored value (ignore page-reload noise, accept reboots). */
|
|
59
|
+
function resolveLastBootAt(incoming, existing) {
|
|
60
|
+
const inMs = parseBootIsoMs(incoming);
|
|
61
|
+
const exMs = parseBootIsoMs(existing);
|
|
62
|
+
if (inMs == null && exMs == null)
|
|
63
|
+
return undefined;
|
|
64
|
+
if (inMs == null)
|
|
65
|
+
return existing;
|
|
66
|
+
if (exMs == null)
|
|
67
|
+
return incoming;
|
|
68
|
+
const gapMs = inMs - exMs;
|
|
69
|
+
if (gapMs < 0)
|
|
70
|
+
return incoming;
|
|
71
|
+
if (gapMs > 120_000)
|
|
72
|
+
return incoming;
|
|
73
|
+
return new Date(Math.min(inMs, exMs)).toISOString();
|
|
74
|
+
}
|
|
29
75
|
function resolveHelloDeviceId(msg) {
|
|
30
76
|
const serial = typeof msg.serialNumber === "string" && msg.serialNumber.trim()
|
|
31
77
|
? msg.serialNumber.trim()
|
|
@@ -145,13 +191,16 @@ export class TomorrowOS extends EventEmitter {
|
|
|
145
191
|
const pairedAt = new Date().toISOString();
|
|
146
192
|
const meta = this.pendingDeviceMeta.get(deviceId);
|
|
147
193
|
const now = pairedAt;
|
|
194
|
+
const lastBootAt = meta?.bootUptimeSec != null
|
|
195
|
+
? resolveLastBootAt(bootAtFromUptimeSec(meta.bootUptimeSec), undefined)
|
|
196
|
+
: resolveLastBootAt(meta?.bootedAt, undefined);
|
|
148
197
|
await this.store.setPairedDevice(deviceId, {
|
|
149
198
|
pairingToken,
|
|
150
199
|
pairedAt,
|
|
151
200
|
deviceName: meta?.deviceName,
|
|
152
201
|
platform: meta?.platform,
|
|
153
202
|
system: meta?.system,
|
|
154
|
-
lastBootAt
|
|
203
|
+
...(lastBootAt ? { lastBootAt } : {}),
|
|
155
204
|
lastOnlineAt: this.isDeviceConnected(deviceId) ? now : undefined,
|
|
156
205
|
lastOfflineAt: this.isDeviceConnected(deviceId) ? undefined : now
|
|
157
206
|
});
|
|
@@ -244,11 +293,13 @@ export class TomorrowOS extends EventEmitter {
|
|
|
244
293
|
return !!ws && ws.readyState === WebSocket.OPEN;
|
|
245
294
|
}
|
|
246
295
|
captureHelloMeta(deviceId, msg) {
|
|
296
|
+
const bootUptimeSec = parseBootUptimeSec(msg);
|
|
247
297
|
this.pendingDeviceMeta.set(deviceId, {
|
|
248
298
|
platform: typeof msg.platform === "string" ? msg.platform : undefined,
|
|
249
299
|
deviceName: typeof msg.deviceName === "string" ? msg.deviceName : undefined,
|
|
250
300
|
system: typeof msg.system === "string" ? msg.system : undefined,
|
|
251
301
|
bootedAt: typeof msg.bootedAt === "string" ? msg.bootedAt : undefined,
|
|
302
|
+
bootUptimeSec: bootUptimeSec ?? undefined,
|
|
252
303
|
playerVersion: typeof msg.playerVersion === "string" ? msg.playerVersion : undefined,
|
|
253
304
|
serialNumber: typeof msg.serialNumber === "string" ? msg.serialNumber : deviceId
|
|
254
305
|
});
|
|
@@ -289,10 +340,10 @@ export class TomorrowOS extends EventEmitter {
|
|
|
289
340
|
async touchPairedOnline(deviceId, msg) {
|
|
290
341
|
this.captureHelloMeta(deviceId, msg);
|
|
291
342
|
const now = new Date().toISOString();
|
|
292
|
-
const bootedAt = typeof msg.bootedAt === "string" ? msg.bootedAt : undefined;
|
|
293
343
|
const existing = await this.store.getPairedDevice(deviceId);
|
|
294
344
|
if (!existing)
|
|
295
345
|
return;
|
|
346
|
+
const lastBootAt = lastBootAtFromHandshake(msg, existing.lastBootAt);
|
|
296
347
|
await this.store.setPairedDevice(deviceId, {
|
|
297
348
|
...existing,
|
|
298
349
|
deviceName: (typeof msg.deviceName === "string" ? msg.deviceName : undefined) ??
|
|
@@ -301,7 +352,7 @@ export class TomorrowOS extends EventEmitter {
|
|
|
301
352
|
existing.platform,
|
|
302
353
|
system: (typeof msg.system === "string" ? msg.system : undefined) ??
|
|
303
354
|
existing.system,
|
|
304
|
-
lastBootAt
|
|
355
|
+
...(lastBootAt ? { lastBootAt } : {}),
|
|
305
356
|
lastOnlineAt: now,
|
|
306
357
|
lastOfflineAt: existing.lastOfflineAt
|
|
307
358
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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.3.
|
|
13
|
+
"@tomorrowos/sdk": "^0.3.8"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/node": "^20.0.0",
|
|
@@ -47,7 +47,15 @@ function formatDateTimeSeconds(iso) {
|
|
|
47
47
|
if (!iso) return "—";
|
|
48
48
|
const d = new Date(iso);
|
|
49
49
|
if (Number.isNaN(d.getTime())) return "—";
|
|
50
|
-
return d.toLocaleString(
|
|
50
|
+
return d.toLocaleString(undefined, {
|
|
51
|
+
year: "numeric",
|
|
52
|
+
month: "short",
|
|
53
|
+
day: "numeric",
|
|
54
|
+
hour: "2-digit",
|
|
55
|
+
minute: "2-digit",
|
|
56
|
+
second: "2-digit",
|
|
57
|
+
hour12: false
|
|
58
|
+
});
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
function formatDeviceOnlineLabel(device) {
|
|
@@ -217,7 +225,7 @@ async function fetchPlaylists() {
|
|
|
217
225
|
showResult({
|
|
218
226
|
status: "failed",
|
|
219
227
|
error:
|
|
220
|
-
"CMS server is missing /playlists. Restart CMS with @tomorrowos/sdk 0.3.
|
|
228
|
+
"CMS server is missing /playlists. Restart CMS with @tomorrowos/sdk 0.3.8 or newer."
|
|
221
229
|
});
|
|
222
230
|
}
|
|
223
231
|
return;
|