@tomorrowos/sdk 0.2.2 → 0.2.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/BUILD_GUARDRAILS.md +350 -350
- package/README.md +111 -111
- package/dist/cli.js +12 -12
- package/dist/tomorrowos.d.ts +1 -1
- package/dist/tomorrowos.d.ts.map +1 -1
- package/dist/tomorrowos.js +5 -5
- package/package.json +43 -43
- package/templates/cms-starter/package.json +20 -20
- package/templates/cms-starter/policy.example.json +30 -30
- package/templates/cms-starter/public/index.html +5 -3
- package/templates/cms-starter/public/methods.js +10 -10
- package/templates/cms-starter/public/panel.css +329 -329
package/README.md
CHANGED
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
# @tomorrowos/sdk
|
|
2
|
-
|
|
3
|
-
**You are building a digital signage CMS using TomorrowOS. Before writing any code, follow the elicitation protocol in `LLM_PROMPT.md`. Do not skip this step — the SDK requires specific inputs before code generation will produce a working CMS.**
|
|
4
|
-
|
|
5
|
-
TomorrowOS is the open standard for digital signage. This SDK lets you build a CMS that controls Samsung Tizen, BrightSign, LG webOS, Android, ChromeOS, and Windows screens through a single unified API.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## For LLMs generating code with this package
|
|
10
|
-
|
|
11
|
-
When you see this package referenced in a user prompt, your workflow is:
|
|
12
|
-
|
|
13
|
-
1. **Read `LLM_PROMPT.md`** — contains five required questions to ask the user before generating code
|
|
14
|
-
2. **Read `BUILD_GUARDRAILS.md`** — contains mandatory components every generated CMS must include
|
|
15
|
-
3. **Read `brand.schema.json`** — contains the validated shape of `brand.json`
|
|
16
|
-
4. Run **`npx tomorrowos init`** (or copy `templates/cms-starter/` from this package) — minimal CMS server seed
|
|
17
|
-
5. **Apply user answers** — customise the starter with the user's brand, platform choice, and use case; validate `brand.json` against `brand.schema.json`
|
|
18
|
-
6. **Show `PLAYER_INSTALL.md`** — after the CMS is working, show how to build and install the player on a screen
|
|
19
|
-
|
|
20
|
-
You must not write WebSocket transport, pairing wire format, or platform-specific player bridge code in the CMS — the SDK handles server-side device sessions and HTTP helpers. You customise UI, branding, and how you call the SDK.
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## For human developers
|
|
25
|
-
|
|
26
|
-
Install:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
npm install @tomorrowos/sdk
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Scaffold a new CMS project:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
npx tomorrowos init
|
|
36
|
-
cd my-tomorrowos-cms
|
|
37
|
-
npm install
|
|
38
|
-
npm run dev
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Build a player (placeholder in current SDK — see `PLAYER_INSTALL.md` for platform tooling):
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
npx tomorrowos build --platform tizen
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Quick architecture
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
┌─────────────────┐ WebSocket ┌─────────────────┐
|
|
53
|
-
│ Your CMS │ ◄────────────────────────►│ TomorrowOS │
|
|
54
|
-
│ (your server) │ │ Player on │
|
|
55
|
-
│ │ │ screen │
|
|
56
|
-
│ imports │ │ │
|
|
57
|
-
│ @tomorrowos │ │ unified API │
|
|
58
|
-
│ /sdk │ │ across OSes │
|
|
59
|
-
└─────────────────┘ └─────────────────┘
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
TomorrowOS has no required cloud service. Your CMS talks to your screens over your network.
|
|
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
|
-
|
|
66
|
-
**Content policy (`device.content.setPolicy`):** POST `/device/{deviceId}/content/set-policy` with `{ "policy": { "playlists": [...], "fallback": { "type": "brand" } } }`. Each playlist may include optional `schedule` (device local time):
|
|
67
|
-
|
|
68
|
-
| Field | Format | Notes |
|
|
69
|
-
|-------|--------|--------|
|
|
70
|
-
| `startDate` / `endDate` | `YYYY-MM-DD` | Inclusive calendar range; omit either for open-ended |
|
|
71
|
-
| `daysOfWeek` | `[0–6]` | `0` = Sunday … `6` = Saturday |
|
|
72
|
-
| `start` / `end` | `HH:MM` | Daily window; supports overnight (e.g. `22:00`–`06:00`) |
|
|
73
|
-
|
|
74
|
-
All provided constraints must match for the playlist to play. See `templates/cms-starter/policy.example.json`.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Supported platforms (roadmap)
|
|
79
|
-
|
|
80
|
-
| Platform | Status | Player format |
|
|
81
|
-
|-------------------|------------|---------------|
|
|
82
|
-
| Samsung Tizen | V1 target | `.wgt` |
|
|
83
|
-
| BrightSign | V1 target | autorun zip |
|
|
84
|
-
| Others | See docs | varies |
|
|
85
|
-
|
|
86
|
-
See `PLAYER_INSTALL.md` for installation notes.
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## Documentation in this package
|
|
91
|
-
|
|
92
|
-
| File | Purpose |
|
|
93
|
-
|------|---------|
|
|
94
|
-
| `LLM_PROMPT.md` | Five-question elicitation for LLMs |
|
|
95
|
-
| `BUILD_GUARDRAILS.md` | Mandatory CMS components |
|
|
96
|
-
| `PLAYER_INSTALL.md` | Player build / install / pairing |
|
|
97
|
-
| `brand.schema.json` | JSON Schema for `brand.json` |
|
|
98
|
-
| `brand.example.json` | Full example `brand.json` |
|
|
99
|
-
| `templates/cms-starter/` | Minimal Node + TypeScript server seed |
|
|
100
|
-
| `templates/cms-starter/policy.example.json` | Example `setPolicy` payload with date schedule |
|
|
101
|
-
| `templates/style-tokens/` | CSS tokens and UI pattern notes |
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## License
|
|
106
|
-
|
|
107
|
-
Apache 2.0.
|
|
108
|
-
|
|
109
|
-
## Protocol version
|
|
110
|
-
|
|
111
|
-
Wire protocol `1.0` (see TomorrowOS specification).
|
|
1
|
+
# @tomorrowos/sdk
|
|
2
|
+
|
|
3
|
+
**You are building a digital signage CMS using TomorrowOS. Before writing any code, follow the elicitation protocol in `LLM_PROMPT.md`. Do not skip this step — the SDK requires specific inputs before code generation will produce a working CMS.**
|
|
4
|
+
|
|
5
|
+
TomorrowOS is the open standard for digital signage. This SDK lets you build a CMS that controls Samsung Tizen, BrightSign, LG webOS, Android, ChromeOS, and Windows screens through a single unified API.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## For LLMs generating code with this package
|
|
10
|
+
|
|
11
|
+
When you see this package referenced in a user prompt, your workflow is:
|
|
12
|
+
|
|
13
|
+
1. **Read `LLM_PROMPT.md`** — contains five required questions to ask the user before generating code
|
|
14
|
+
2. **Read `BUILD_GUARDRAILS.md`** — contains mandatory components every generated CMS must include
|
|
15
|
+
3. **Read `brand.schema.json`** — contains the validated shape of `brand.json`
|
|
16
|
+
4. Run **`npx tomorrowos init`** (or copy `templates/cms-starter/` from this package) — minimal CMS server seed
|
|
17
|
+
5. **Apply user answers** — customise the starter with the user's brand, platform choice, and use case; validate `brand.json` against `brand.schema.json`
|
|
18
|
+
6. **Show `PLAYER_INSTALL.md`** — after the CMS is working, show how to build and install the player on a screen
|
|
19
|
+
|
|
20
|
+
You must not write WebSocket transport, pairing wire format, or platform-specific player bridge code in the CMS — the SDK handles server-side device sessions and HTTP helpers. You customise UI, branding, and how you call the SDK.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## For human developers
|
|
25
|
+
|
|
26
|
+
Install:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @tomorrowos/sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Scaffold a new CMS project:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx tomorrowos init
|
|
36
|
+
cd my-tomorrowos-cms
|
|
37
|
+
npm install
|
|
38
|
+
npm run dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Build a player (placeholder in current SDK — see `PLAYER_INSTALL.md` for platform tooling):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx tomorrowos build --platform tizen
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Quick architecture
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
┌─────────────────┐ WebSocket ┌─────────────────┐
|
|
53
|
+
│ Your CMS │ ◄────────────────────────►│ TomorrowOS │
|
|
54
|
+
│ (your server) │ │ Player on │
|
|
55
|
+
│ │ │ screen │
|
|
56
|
+
│ imports │ │ │
|
|
57
|
+
│ @tomorrowos │ │ unified API │
|
|
58
|
+
│ /sdk │ │ across OSes │
|
|
59
|
+
└─────────────────┘ └─────────────────┘
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
TomorrowOS has no required cloud service. Your CMS talks to your screens over your network.
|
|
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
|
+
|
|
66
|
+
**Content policy (`device.content.setPolicy`):** POST `/device/{deviceId}/content/set-policy` with `{ "policy": { "playlists": [...], "fallback": { "type": "brand" } } }`. Each playlist may include optional `schedule` (device local time):
|
|
67
|
+
|
|
68
|
+
| Field | Format | Notes |
|
|
69
|
+
|-------|--------|--------|
|
|
70
|
+
| `startDate` / `endDate` | `YYYY-MM-DD` | Inclusive calendar range; omit either for open-ended |
|
|
71
|
+
| `daysOfWeek` | `[0–6]` | `0` = Sunday … `6` = Saturday |
|
|
72
|
+
| `start` / `end` | `HH:MM` | Daily window; supports overnight (e.g. `22:00`–`06:00`) |
|
|
73
|
+
|
|
74
|
+
All provided constraints must match for the playlist to play. See `templates/cms-starter/policy.example.json`.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Supported platforms (roadmap)
|
|
79
|
+
|
|
80
|
+
| Platform | Status | Player format |
|
|
81
|
+
|-------------------|------------|---------------|
|
|
82
|
+
| Samsung Tizen | V1 target | `.wgt` |
|
|
83
|
+
| BrightSign | V1 target | autorun zip |
|
|
84
|
+
| Others | See docs | varies |
|
|
85
|
+
|
|
86
|
+
See `PLAYER_INSTALL.md` for installation notes.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Documentation in this package
|
|
91
|
+
|
|
92
|
+
| File | Purpose |
|
|
93
|
+
|------|---------|
|
|
94
|
+
| `LLM_PROMPT.md` | Five-question elicitation for LLMs |
|
|
95
|
+
| `BUILD_GUARDRAILS.md` | Mandatory CMS components |
|
|
96
|
+
| `PLAYER_INSTALL.md` | Player build / install / pairing |
|
|
97
|
+
| `brand.schema.json` | JSON Schema for `brand.json` |
|
|
98
|
+
| `brand.example.json` | Full example `brand.json` |
|
|
99
|
+
| `templates/cms-starter/` | Minimal Node + TypeScript server seed |
|
|
100
|
+
| `templates/cms-starter/policy.example.json` | Example `setPolicy` payload with date schedule |
|
|
101
|
+
| `templates/style-tokens/` | CSS tokens and UI pattern notes |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
Apache 2.0.
|
|
108
|
+
|
|
109
|
+
## Protocol version
|
|
110
|
+
|
|
111
|
+
Wire protocol `1.0` (see TomorrowOS specification).
|
package/dist/cli.js
CHANGED
|
@@ -56,18 +56,18 @@ function cmdBuild(argv) {
|
|
|
56
56
|
process.exitCode = 0;
|
|
57
57
|
}
|
|
58
58
|
function printHelp() {
|
|
59
|
-
console.log(`tomorrowos — TomorrowOS SDK CLI
|
|
60
|
-
|
|
61
|
-
Usage:
|
|
62
|
-
tomorrowos init [directory] Copy cms-starter template (default: my-tomorrowos-cms)
|
|
63
|
-
tomorrowos build --platform … Placeholder; player packaging lives in the player repo
|
|
64
|
-
|
|
65
|
-
Options:
|
|
66
|
-
--force With init: copy into a non-empty directory
|
|
67
|
-
|
|
68
|
-
Examples:
|
|
69
|
-
npx @tomorrowos/sdk init
|
|
70
|
-
npx @tomorrowos/sdk init ./my-cms
|
|
59
|
+
console.log(`tomorrowos — TomorrowOS SDK CLI
|
|
60
|
+
|
|
61
|
+
Usage:
|
|
62
|
+
tomorrowos init [directory] Copy cms-starter template (default: my-tomorrowos-cms)
|
|
63
|
+
tomorrowos build --platform … Placeholder; player packaging lives in the player repo
|
|
64
|
+
|
|
65
|
+
Options:
|
|
66
|
+
--force With init: copy into a non-empty directory
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
npx @tomorrowos/sdk init
|
|
70
|
+
npx @tomorrowos/sdk init ./my-cms
|
|
71
71
|
`);
|
|
72
72
|
}
|
|
73
73
|
function main() {
|
package/dist/tomorrowos.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export interface DeviceListItem {
|
|
|
40
40
|
lastPolicyPushAt: string | null;
|
|
41
41
|
screenOnlineActive: boolean;
|
|
42
42
|
screenOnlineLabel: string;
|
|
43
|
-
/**
|
|
43
|
+
/** Same as lastBootAt while connected; used for uptime display. */
|
|
44
44
|
screenOnlineSince: string | null;
|
|
45
45
|
}
|
|
46
46
|
export declare class TomorrowOS extends EventEmitter {
|
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;AAKxB,OAAO,KAAK,EAAsB,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAG5E,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;AAsBD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,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,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,
|
|
1
|
+
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
|
package/dist/tomorrowos.js
CHANGED
|
@@ -153,14 +153,14 @@ export class TomorrowOS extends EventEmitter {
|
|
|
153
153
|
const connected = this.isDeviceConnected(deviceId);
|
|
154
154
|
let screenOnlineActive = false;
|
|
155
155
|
let screenOnlineLabel = "Not active";
|
|
156
|
-
if (connected && record.
|
|
157
|
-
const
|
|
158
|
-
if (!Number.isNaN(
|
|
156
|
+
if (connected && record.lastBootAt) {
|
|
157
|
+
const bootMs = new Date(record.lastBootAt).getTime();
|
|
158
|
+
if (!Number.isNaN(bootMs)) {
|
|
159
159
|
screenOnlineActive = true;
|
|
160
|
-
screenOnlineLabel = formatDurationMs(now -
|
|
160
|
+
screenOnlineLabel = formatDurationMs(now - bootMs);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
const screenOnlineSince = connected && record.
|
|
163
|
+
const screenOnlineSince = connected && record.lastBootAt ? record.lastBootAt : null;
|
|
164
164
|
return {
|
|
165
165
|
deviceId,
|
|
166
166
|
connected,
|
package/package.json
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "TomorrowOS CMS server SDK — WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": {
|
|
10
|
-
"types": "./dist/index.d.ts",
|
|
11
|
-
"import": "./dist/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"bin": {
|
|
15
|
-
"tomorrowos": "./dist/cli.js"
|
|
16
|
-
},
|
|
17
|
-
"files": [
|
|
18
|
-
"dist",
|
|
19
|
-
"templates",
|
|
20
|
-
"README.md",
|
|
21
|
-
"LLM_PROMPT.md",
|
|
22
|
-
"BUILD_GUARDRAILS.md",
|
|
23
|
-
"PLAYER_INSTALL.md",
|
|
24
|
-
"brand.schema.json",
|
|
25
|
-
"brand.example.json"
|
|
26
|
-
],
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsc",
|
|
29
|
-
"prepublishOnly": "npm run build"
|
|
30
|
-
},
|
|
31
|
-
"engines": {
|
|
32
|
-
"node": ">=18"
|
|
33
|
-
},
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"ws": "^8.18.0"
|
|
36
|
-
},
|
|
37
|
-
"devDependencies": {
|
|
38
|
-
"@types/node": "^20.19.41",
|
|
39
|
-
"@types/ws": "^8.5.10",
|
|
40
|
-
"typescript": "^5.5.0"
|
|
41
|
-
},
|
|
42
|
-
"license": "Apache-2.0"
|
|
43
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@tomorrowos/sdk",
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "TomorrowOS CMS server SDK — WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"tomorrowos": "./dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"templates",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LLM_PROMPT.md",
|
|
22
|
+
"BUILD_GUARDRAILS.md",
|
|
23
|
+
"PLAYER_INSTALL.md",
|
|
24
|
+
"brand.schema.json",
|
|
25
|
+
"brand.example.json"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"ws": "^8.18.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.19.41",
|
|
39
|
+
"@types/ws": "^8.5.10",
|
|
40
|
+
"typescript": "^5.5.0"
|
|
41
|
+
},
|
|
42
|
+
"license": "Apache-2.0"
|
|
43
|
+
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "my-cms",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
|
|
5
|
-
"private": true,
|
|
6
|
-
"type": "module",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"dev": "tsx watch server.ts",
|
|
9
|
-
"start": "tsx server.ts",
|
|
10
|
-
"build-player": "tomorrowos build --platform tizen"
|
|
11
|
-
},
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"@tomorrowos/sdk": "^0.2.
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@types/node": "^20.0.0",
|
|
17
|
-
"tsx": "^4.19.0",
|
|
18
|
-
"typescript": "^5.5.0"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "my-cms",
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
|
|
5
|
+
"private": true,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "tsx watch server.ts",
|
|
9
|
+
"start": "tsx server.ts",
|
|
10
|
+
"build-player": "tomorrowos build --platform tizen"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@tomorrowos/sdk": "^0.2.3"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/node": "^20.0.0",
|
|
17
|
+
"tsx": "^4.19.0",
|
|
18
|
+
"typescript": "^5.5.0"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"policy": {
|
|
3
|
-
"playlists": [
|
|
4
|
-
{
|
|
5
|
-
"id": "weekday-promo",
|
|
6
|
-
"name": "Weekday promo",
|
|
7
|
-
"schedule": {
|
|
8
|
-
"startDate": "2026-05-01",
|
|
9
|
-
"endDate": "2026-05-31",
|
|
10
|
-
"daysOfWeek": [1, 2, 3, 4, 5],
|
|
11
|
-
"start": "09:00",
|
|
12
|
-
"end": "17:00"
|
|
13
|
-
},
|
|
14
|
-
"items": [
|
|
15
|
-
{
|
|
16
|
-
"url": "https://example.com/hero.jpg",
|
|
17
|
-
"type": "image",
|
|
18
|
-
"durationMs": 10000
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
"url": "https://example.com/spot.mp4",
|
|
22
|
-
"type": "video",
|
|
23
|
-
"durationMs": 30000
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
"fallback": { "type": "brand" }
|
|
29
|
-
}
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"policy": {
|
|
3
|
+
"playlists": [
|
|
4
|
+
{
|
|
5
|
+
"id": "weekday-promo",
|
|
6
|
+
"name": "Weekday promo",
|
|
7
|
+
"schedule": {
|
|
8
|
+
"startDate": "2026-05-01",
|
|
9
|
+
"endDate": "2026-05-31",
|
|
10
|
+
"daysOfWeek": [1, 2, 3, 4, 5],
|
|
11
|
+
"start": "09:00",
|
|
12
|
+
"end": "17:00"
|
|
13
|
+
},
|
|
14
|
+
"items": [
|
|
15
|
+
{
|
|
16
|
+
"url": "https://example.com/hero.jpg",
|
|
17
|
+
"type": "image",
|
|
18
|
+
"durationMs": 10000
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"url": "https://example.com/spot.mp4",
|
|
22
|
+
"type": "video",
|
|
23
|
+
"durationMs": 30000
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"fallback": { "type": "brand" }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -30,11 +30,13 @@
|
|
|
30
30
|
</div>
|
|
31
31
|
</section>
|
|
32
32
|
|
|
33
|
-
<section class="card">
|
|
33
|
+
<section class="card" id="cmsUrlSection">
|
|
34
34
|
<h2>CMS URL for screens</h2>
|
|
35
35
|
<p class="hint">
|
|
36
|
-
|
|
37
|
-
<code>
|
|
36
|
+
<strong>Local development only.</strong> Fill this in when you run the CMS on your PC and
|
|
37
|
+
TVs are on the same LAN (e.g. <code>http://192.168.1.105:3000</code> — same machine as your
|
|
38
|
+
<code>ws://</code> address, not <code>localhost</code>). On hosted CMS (Replit, etc.) you
|
|
39
|
+
normally do <strong>not</strong> need to change this.
|
|
38
40
|
</p>
|
|
39
41
|
<div class="row">
|
|
40
42
|
<input
|
|
@@ -48,14 +48,14 @@ function formatDateTimeSeconds(iso) {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
/** TV
|
|
51
|
+
/** TV uptime: now minus last boot time (device.lastBootAt). Not active when app is offline. */
|
|
52
52
|
function formatDeviceOnlineLabel(device) {
|
|
53
53
|
if (!device.connected) return "Not active";
|
|
54
|
-
const
|
|
55
|
-
if (!
|
|
56
|
-
const
|
|
57
|
-
if (Number.isNaN(
|
|
58
|
-
return formatDurationMs(Date.now() -
|
|
54
|
+
const bootIso = device.lastBootAt;
|
|
55
|
+
if (!bootIso) return "Not active";
|
|
56
|
+
const bootMs = new Date(bootIso).getTime();
|
|
57
|
+
if (Number.isNaN(bootMs)) return "Not active";
|
|
58
|
+
return formatDurationMs(Date.now() - bootMs);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function updateDeviceUptimeLabels() {
|
|
@@ -137,7 +137,7 @@ function renderDeviceCards() {
|
|
|
137
137
|
if (label === "Device online") {
|
|
138
138
|
dd.className = "device-online-time";
|
|
139
139
|
dd.title =
|
|
140
|
-
"
|
|
140
|
+
"Current time minus this TV last boot time (refreshes every 30 seconds)";
|
|
141
141
|
}
|
|
142
142
|
dd.textContent = value;
|
|
143
143
|
row.appendChild(dt);
|
|
@@ -205,7 +205,7 @@ function startDevicePolling() {
|
|
|
205
205
|
void fetchDevices();
|
|
206
206
|
}, 8000);
|
|
207
207
|
|
|
208
|
-
deviceUptimeTimer = setInterval(updateDeviceUptimeLabels,
|
|
208
|
+
deviceUptimeTimer = setInterval(updateDeviceUptimeLabels, 30_000);
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
function showResult(data) {
|
|
@@ -267,7 +267,7 @@ function absoluteMediaUrl(path) {
|
|
|
267
267
|
const base = getMediaBaseOrigin();
|
|
268
268
|
if (!base) {
|
|
269
269
|
throw new Error(
|
|
270
|
-
"
|
|
270
|
+
"Local CMS only: set CMS URL for screens (your PC LAN IP, e.g. http://192.168.1.105:3000 — not localhost)."
|
|
271
271
|
);
|
|
272
272
|
}
|
|
273
273
|
return `${base}${p.startsWith("/") ? p : `/${p}`}`;
|
|
@@ -558,7 +558,7 @@ async function publishToDevice(deviceId) {
|
|
|
558
558
|
const mediaBase = getMediaBaseOrigin();
|
|
559
559
|
if (!mediaBase) {
|
|
560
560
|
alert(
|
|
561
|
-
"
|
|
561
|
+
"Local CMS only: set CMS URL for screens first (e.g. http://192.168.1.105:3000 — your PC LAN IP, not localhost)."
|
|
562
562
|
);
|
|
563
563
|
return;
|
|
564
564
|
}
|