@tomorrowos/sdk 0.1.1 → 0.1.3

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 CHANGED
@@ -61,6 +61,8 @@ npx tomorrowos build --platform tizen
61
61
 
62
62
  TomorrowOS has no required cloud service. Your CMS talks to your screens over your network.
63
63
 
64
+ **Player branding:** `GET /brand.json` returns the `brand` object passed to `new TomorrowOS({ brand })` (same host/port as `listen`). TomorrowOS players can fetch it to apply `backgroundColor`, logos, etc., without a separate static file server.
65
+
64
66
  ---
65
67
 
66
68
  ## Supported platforms (roadmap)
@@ -18,6 +18,7 @@ export interface ListenOptions {
18
18
  * If set, GET requests serve files from this directory (e.g. CMS UI assets).
19
19
  * `GET /` serves `staticIndex` (default `index.html`) under this root.
20
20
  * WebSocket upgrades on `/` are unchanged.
21
+ * Note: `GET /brand.json` is always served from the `brand` passed to the constructor (not from this folder).
21
22
  */
22
23
  staticRoot?: string;
23
24
  /**
@@ -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;AAKxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD,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;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAmDD,qBAAa,UAAW,SAAQ,YAAY;IAC1C,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,eAAe,CAAgB;gBAE3B,OAAO,EAAE,iBAAiB;IAMtC,oEAAoE;IAC9D,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAiChE,OAAO;uBACU,MAAM;sBAlCgC,MAAM;;MAmC3D;IAEF,MAAM,CAAC,QAAQ,EAAE,MAAM;oBAGD,CAAC,oBACT,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;;IAU5E,OAAO,CAAC,mBAAmB;IA6D3B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC,MAAM;YAgD7B,cAAc;YAmCd,UAAU;YAyCV,gBAAgB;IAgE9B,OAAO,CAAC,gBAAgB;CA8EzB"}
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;AAKxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxD,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;AAmDD,qBAAa,UAAW,SAAQ,YAAY;IAC1C,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,eAAe,CAAgB;gBAE3B,OAAO,EAAE,iBAAiB;IAMtC,oEAAoE;IAC9D,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAiChE,OAAO;uBACU,MAAM;sBAlCgC,MAAM;;MAmC3D;IAEF,MAAM,CAAC,QAAQ,EAAE,MAAM;oBAGD,CAAC,oBACT,MAAM,WACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;;IAU5E,OAAO,CAAC,mBAAmB;IA6D3B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAAC,MAAM;YAgD7B,cAAc;YAmCd,UAAU;YAgDV,gBAAgB;IAgE9B,OAAO,CAAC,gBAAgB;CA8EzB"}
@@ -216,6 +216,12 @@ export class TomorrowOS extends EventEmitter {
216
216
  try {
217
217
  const url = new URL(req.url ?? "/", "http://localhost");
218
218
  const pathname = url.pathname;
219
+ /** Same-origin brand for TomorrowOS players (e.g. GET /brand.json + applyBrand). */
220
+ if (req.method === "GET" && pathname === "/brand.json") {
221
+ res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
222
+ res.end(JSON.stringify(this.brand));
223
+ return;
224
+ }
219
225
  if (req.method === "GET" && this.staticRoot) {
220
226
  const served = await this.tryServeStatic(pathname, res);
221
227
  if (served)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
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,4 +1,4 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="160" height="40" viewBox="0 0 160 40" role="img" aria-label="Logo placeholder">
2
- <rect width="160" height="40" rx="6" fill="#FF8A3D"/>
3
- <text x="80" y="26" text-anchor="middle" fill="#ffffff" font-family="system-ui,sans-serif" font-size="14" font-weight="600">Your logo</text>
4
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="160" height="40" viewBox="0 0 160 40" role="img" aria-label="Logo placeholder">
2
+ <rect width="160" height="40" rx="6" fill="#FF8A3D"/>
3
+ <text x="80" y="26" text-anchor="middle" fill="#ffffff" font-family="system-ui,sans-serif" font-size="14" font-weight="600">Your logo</text>
4
+ </svg>
@@ -1,6 +1,6 @@
1
1
  {
2
- "name": "my-tomorrowos-cms",
3
- "version": "0.1.1",
2
+ "name": "my-cms",
3
+ "version": "0.1.3",
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.1.1"
13
+ "@tomorrowos/sdk": "^0.1.3"
14
14
  },
15
15
  "devDependencies": {
16
16
  "@types/node": "^20.0.0",
@@ -0,0 +1,58 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>TomorrowOS SDK Smoke</title>
6
+ </head>
7
+ <body style="font-family: sans-serif; padding: 40px;">
8
+ <h1>TomorrowOS SDK Smoke Panel</h1>
9
+ <p>Same-origin API as this server — open this page after <code>npm start</code>.</p>
10
+
11
+ <h2>Pair Device</h2>
12
+ <input id="code" maxlength="6" placeholder="Enter 6 digit code" />
13
+ <button onclick="verify()">Verify</button>
14
+ <input type="hidden" id="deviceId" />
15
+
16
+ <h2>Get Device Info</h2>
17
+ <button onclick="getInfo()">Get Info</button>
18
+
19
+ <h2>Get Capabilities</h2>
20
+ <button onclick="getCapabilities()">Get Capabilities</button>
21
+
22
+ <h2>Reboot Device</h2>
23
+ <button onclick="reboot()">Reboot</button>
24
+
25
+ <h2>Set Content</h2>
26
+ <button onclick="setContent()">Set</button>
27
+
28
+ <h3>Set Policy JSON (required)</h3>
29
+ <textarea
30
+ id="policyJson"
31
+ rows="16"
32
+ cols="100"
33
+ placeholder='{
34
+ "policy": {
35
+ "playlists": [
36
+ {
37
+ "id": "default",
38
+ "items": [
39
+ { "url": "https://example.com/a.jpg", "type": "image", "durationMs": 8000 },
40
+ { "url": "https://example.com/b.mp4", "type": "video", "durationMs": 30000 }
41
+ ]
42
+ }
43
+ ],
44
+ "fallback": { "type": "brand" }
45
+ }
46
+ }'></textarea>
47
+
48
+ <h2>Clear Content</h2>
49
+ <button onclick="clearContent()">Clear</button>
50
+
51
+ <br />
52
+ <br />
53
+
54
+ <pre id="result"></pre>
55
+
56
+ <script src="./methods.js" defer></script>
57
+ </body>
58
+ </html>
@@ -0,0 +1,124 @@
1
+ async function verify() {
2
+ const code = document.getElementById("code").value;
3
+
4
+ const res = await fetch("/pairing/verify", {
5
+ method: "POST",
6
+ headers: { "Content-Type": "application/json" },
7
+ body: JSON.stringify({ code })
8
+ });
9
+
10
+ const data = await res.json();
11
+
12
+ document.getElementById("result").textContent = JSON.stringify(data, null, 2);
13
+
14
+ if (data.deviceId) {
15
+ document.getElementById("deviceId").value = data.deviceId;
16
+ }
17
+ }
18
+
19
+ async function getInfo() {
20
+ const deviceId = document.getElementById("deviceId").value;
21
+
22
+ if (!deviceId) {
23
+ alert("Please pair a device first.");
24
+ return;
25
+ }
26
+
27
+ const res = await fetch("/device/" + deviceId + "/get-info", {
28
+ method: "POST"
29
+ });
30
+
31
+ const data = await res.json();
32
+
33
+ document.getElementById("result").textContent = JSON.stringify(data, null, 2);
34
+ }
35
+
36
+ async function getCapabilities() {
37
+ const deviceId = document.getElementById("deviceId").value;
38
+
39
+ if (!deviceId) {
40
+ alert("Please pair a device first.");
41
+ return;
42
+ }
43
+
44
+ const res = await fetch(`/device/${deviceId}/get-capabilities`, {
45
+ method: "POST"
46
+ });
47
+
48
+ const data = await res.json();
49
+ document.getElementById("result").textContent = JSON.stringify(data, null, 2);
50
+ }
51
+
52
+ async function reboot() {
53
+ const deviceId = document.getElementById("deviceId").value;
54
+
55
+ if (!deviceId) {
56
+ alert("Please pair a device first.");
57
+ return;
58
+ }
59
+
60
+ if (!confirm("Are you sure you want to reboot this device?")) {
61
+ return;
62
+ }
63
+
64
+ const res = await fetch("/device/" + deviceId + "/reboot", {
65
+ method: "POST"
66
+ });
67
+
68
+ const data = await res.json();
69
+
70
+ document.getElementById("result").textContent = JSON.stringify(data, null, 2);
71
+ }
72
+
73
+ async function setContent() {
74
+ const deviceId = document.getElementById("deviceId").value;
75
+ const policyJsonText = document.getElementById("policyJson")?.value?.trim();
76
+
77
+ if (!deviceId) {
78
+ alert("Please pair a device first.");
79
+ return;
80
+ }
81
+
82
+ if (!policyJsonText) {
83
+ alert("Please enter policy JSON object.");
84
+ return;
85
+ }
86
+
87
+ let payload = null;
88
+ try {
89
+ payload = JSON.parse(policyJsonText);
90
+ } catch (err) {
91
+ alert("Policy JSON is invalid: " + err.message);
92
+ return;
93
+ }
94
+
95
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
96
+ alert("Policy payload must be a JSON object.");
97
+ return;
98
+ }
99
+
100
+ const res = await fetch(`/device/${deviceId}/content/set-policy`, {
101
+ method: "POST",
102
+ headers: { "Content-Type": "application/json" },
103
+ body: JSON.stringify(payload)
104
+ });
105
+
106
+ const data = await res.json();
107
+ document.getElementById("result").textContent = JSON.stringify(data, null, 2);
108
+ }
109
+
110
+ async function clearContent() {
111
+ const deviceId = document.getElementById("deviceId").value;
112
+
113
+ if (!deviceId) {
114
+ alert("Please pair a device first.");
115
+ return;
116
+ }
117
+
118
+ const res = await fetch(`/device/${deviceId}/content/clear`, {
119
+ method: "POST"
120
+ });
121
+
122
+ const data = await res.json();
123
+ document.getElementById("result").textContent = JSON.stringify(data, null, 2);
124
+ }
@@ -15,7 +15,8 @@ const tomorrowos = new TomorrowOS({ brand });
15
15
 
16
16
  tomorrowos.listen({
17
17
  port: Number(process.env.PORT) || 3000,
18
- host: "0.0.0.0"
18
+ host: "0.0.0.0",
19
+ staticRoot: join(__dirname,"public"),
19
20
  });
20
21
 
21
22
  tomorrowos.on("device.paired", (event) => {