@tomorrowos/sdk 0.4.1 → 0.4.2
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
CHANGED
|
@@ -52,6 +52,15 @@ export interface DeviceListItem {
|
|
|
52
52
|
version: number;
|
|
53
53
|
publishedAt: string;
|
|
54
54
|
}>;
|
|
55
|
+
latestErrorAt: string | null;
|
|
56
|
+
latestErrorMessage: string | null;
|
|
57
|
+
}
|
|
58
|
+
export interface DeviceLogEntry {
|
|
59
|
+
timestamp: string;
|
|
60
|
+
level: "info" | "warn" | "error";
|
|
61
|
+
message: string;
|
|
62
|
+
source?: string;
|
|
63
|
+
details?: unknown;
|
|
55
64
|
}
|
|
56
65
|
export declare class TomorrowOS extends EventEmitter {
|
|
57
66
|
readonly brand: TomorrowOSBrand;
|
|
@@ -59,6 +68,7 @@ export declare class TomorrowOS extends EventEmitter {
|
|
|
59
68
|
readonly playlists: PlaylistCatalog;
|
|
60
69
|
private readonly devices;
|
|
61
70
|
private readonly pendingDeviceMeta;
|
|
71
|
+
private readonly deviceLogs;
|
|
62
72
|
private httpServer;
|
|
63
73
|
private wss;
|
|
64
74
|
private staticRoot;
|
|
@@ -90,6 +100,8 @@ export declare class TomorrowOS extends EventEmitter {
|
|
|
90
100
|
};
|
|
91
101
|
/** List paired devices with live connection + timing fields for the CMS panel. */
|
|
92
102
|
listDevices(): Promise<DeviceListItem[]>;
|
|
103
|
+
private pushDeviceLog;
|
|
104
|
+
private getDeviceLogs;
|
|
93
105
|
private isDeviceConnected;
|
|
94
106
|
private captureHelloMeta;
|
|
95
107
|
private getOrCreatePermanentPairingCode;
|
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;AAQ1B,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;AAwBD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kBAAkB,EAAE,KAAK,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
|
package/dist/tomorrowos.js
CHANGED
|
@@ -132,6 +132,7 @@ export class TomorrowOS extends EventEmitter {
|
|
|
132
132
|
playlists;
|
|
133
133
|
devices = new Map();
|
|
134
134
|
pendingDeviceMeta = new Map();
|
|
135
|
+
deviceLogs = new Map();
|
|
135
136
|
httpServer = null;
|
|
136
137
|
wss = null;
|
|
137
138
|
staticRoot = null;
|
|
@@ -267,6 +268,8 @@ export class TomorrowOS extends EventEmitter {
|
|
|
267
268
|
}
|
|
268
269
|
}
|
|
269
270
|
const screenOnlineSince = connected && record.lastBootAt ? record.lastBootAt : null;
|
|
271
|
+
const logs = this.deviceLogs.get(deviceId) ?? [];
|
|
272
|
+
const latestError = [...logs].reverse().find((entry) => entry.level === "error");
|
|
270
273
|
return {
|
|
271
274
|
deviceId,
|
|
272
275
|
pairingCode: reg?.permanentPairingCode ?? null,
|
|
@@ -288,10 +291,28 @@ export class TomorrowOS extends EventEmitter {
|
|
|
288
291
|
lastPolicyPushAt: record.lastPolicyPushAt ?? null,
|
|
289
292
|
screenOnlineActive,
|
|
290
293
|
screenOnlineLabel,
|
|
291
|
-
screenOnlineSince
|
|
294
|
+
screenOnlineSince,
|
|
295
|
+
latestErrorAt: latestError?.timestamp ?? null,
|
|
296
|
+
latestErrorMessage: latestError?.message ?? null
|
|
292
297
|
};
|
|
293
298
|
}));
|
|
294
299
|
}
|
|
300
|
+
pushDeviceLog(deviceId, entry) {
|
|
301
|
+
const key = String(deviceId || "").trim();
|
|
302
|
+
if (!key)
|
|
303
|
+
return;
|
|
304
|
+
const existing = this.deviceLogs.get(key) ?? [];
|
|
305
|
+
existing.push(entry);
|
|
306
|
+
if (existing.length > 80)
|
|
307
|
+
existing.splice(0, existing.length - 80);
|
|
308
|
+
this.deviceLogs.set(key, existing);
|
|
309
|
+
}
|
|
310
|
+
getDeviceLogs(deviceId) {
|
|
311
|
+
const key = String(deviceId || "").trim();
|
|
312
|
+
if (!key)
|
|
313
|
+
return [];
|
|
314
|
+
return [...(this.deviceLogs.get(key) ?? [])].reverse();
|
|
315
|
+
}
|
|
295
316
|
isDeviceConnected(deviceId) {
|
|
296
317
|
const ws = this.devices.get(deviceId);
|
|
297
318
|
return !!ws && ws.readyState === WebSocket.OPEN;
|
|
@@ -710,6 +731,12 @@ export class TomorrowOS extends EventEmitter {
|
|
|
710
731
|
sendJson(res, 200, { status: "success", assignments });
|
|
711
732
|
return;
|
|
712
733
|
}
|
|
734
|
+
const deviceLogsGet = /^\/device\/([^/]+)\/logs$/.exec(pathname);
|
|
735
|
+
if (req.method === "GET" && deviceLogsGet) {
|
|
736
|
+
const deviceId = decodeURIComponent(deviceLogsGet[1]);
|
|
737
|
+
sendJson(res, 200, { status: "success", logs: this.getDeviceLogs(deviceId) });
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
713
740
|
if (req.method === "DELETE" && deviceAssignmentsGet) {
|
|
714
741
|
const deviceId = decodeURIComponent(deviceAssignmentsGet[1]);
|
|
715
742
|
try {
|
|
@@ -971,6 +998,26 @@ export class TomorrowOS extends EventEmitter {
|
|
|
971
998
|
console.error("[TomorrowOS] pushLatestPolicy on resume failed:", err);
|
|
972
999
|
});
|
|
973
1000
|
})();
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
if (type === "device.log") {
|
|
1004
|
+
const deviceId = ws.deviceId;
|
|
1005
|
+
if (!deviceId)
|
|
1006
|
+
return;
|
|
1007
|
+
const rawLevel = String(msg.level ?? "info").toLowerCase();
|
|
1008
|
+
const level = rawLevel === "error" || rawLevel === "warn" ? rawLevel : "info";
|
|
1009
|
+
const message = String(msg.message ?? "").trim();
|
|
1010
|
+
if (!message)
|
|
1011
|
+
return;
|
|
1012
|
+
const source = typeof msg.source === "string" ? msg.source : undefined;
|
|
1013
|
+
const details = msg.details;
|
|
1014
|
+
const timestamp = typeof msg.timestamp === "string" && msg.timestamp.trim()
|
|
1015
|
+
? msg.timestamp
|
|
1016
|
+
: new Date().toISOString();
|
|
1017
|
+
this.pushDeviceLog(deviceId, { timestamp, level, message, source, details });
|
|
1018
|
+
if (level === "error") {
|
|
1019
|
+
console.error(`[TomorrowOS][device-log][${deviceId}] ${message}`);
|
|
1020
|
+
}
|
|
974
1021
|
}
|
|
975
1022
|
});
|
|
976
1023
|
ws.on("close", () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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.4.
|
|
3
|
+
"version": "0.4.2",
|
|
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.4.
|
|
13
|
+
"@tomorrowos/sdk": "^0.4.2"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/node": "^20.0.0",
|
|
@@ -657,7 +657,9 @@ function renderDeviceCards() {
|
|
|
657
657
|
["System", device.system || device.platform || "—"],
|
|
658
658
|
["Device online", formatDeviceOnlineLabel(device)],
|
|
659
659
|
["Last boot", formatDateTimeSeconds(device.lastBootAt)],
|
|
660
|
-
["Latest push", formatDateTimeSeconds(device.lastPolicyPushAt)]
|
|
660
|
+
["Latest push", formatDateTimeSeconds(device.lastPolicyPushAt)],
|
|
661
|
+
["Latest error", device.latestErrorMessage || "—"],
|
|
662
|
+
["Error at", formatDateTimeSeconds(device.latestErrorAt)]
|
|
661
663
|
];
|
|
662
664
|
for (const [label, value] of rows) {
|
|
663
665
|
const row = document.createElement("div");
|
|
@@ -702,6 +704,11 @@ function renderDeviceCards() {
|
|
|
702
704
|
clearBtn.textContent = "Clear";
|
|
703
705
|
clearBtn.addEventListener("click", () => deviceAction(device.deviceId, "content/clear"));
|
|
704
706
|
|
|
707
|
+
const logsBtn = document.createElement("button");
|
|
708
|
+
logsBtn.type = "button";
|
|
709
|
+
logsBtn.textContent = "Logs";
|
|
710
|
+
logsBtn.addEventListener("click", () => viewDeviceLogs(device.deviceId));
|
|
711
|
+
|
|
705
712
|
const unpairBtn = document.createElement("button");
|
|
706
713
|
unpairBtn.type = "button";
|
|
707
714
|
unpairBtn.className = "danger";
|
|
@@ -713,6 +720,7 @@ function renderDeviceCards() {
|
|
|
713
720
|
actions.appendChild(capBtn);
|
|
714
721
|
actions.appendChild(rebootBtn);
|
|
715
722
|
actions.appendChild(clearBtn);
|
|
723
|
+
actions.appendChild(logsBtn);
|
|
716
724
|
actions.appendChild(unpairBtn);
|
|
717
725
|
|
|
718
726
|
card.appendChild(header);
|
|
@@ -933,6 +941,17 @@ async function deviceAction(deviceId, action) {
|
|
|
933
941
|
if (action === "reboot" || action === "content/clear") await fetchDevices();
|
|
934
942
|
}
|
|
935
943
|
|
|
944
|
+
async function viewDeviceLogs(deviceId) {
|
|
945
|
+
if (!deviceId) return;
|
|
946
|
+
const res = await fetch(`/device/${encodeURIComponent(deviceId)}/logs`);
|
|
947
|
+
const data = await res.json();
|
|
948
|
+
showResult({ deviceId, logs: data.logs || [] });
|
|
949
|
+
if (!res.ok) {
|
|
950
|
+
alert(data.error || "Failed to load logs");
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
936
955
|
function startDevicePolling() {
|
|
937
956
|
if (devicePollTimer) clearInterval(devicePollTimer);
|
|
938
957
|
void fetchDevices();
|