@tomorrowos/sdk 0.9.54 → 0.9.56
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 +327 -123
- package/REPLIT_SETUP.md +24 -57
- package/REPLIT_UPGRADE.md +2 -2
- package/VERCEL_QUESTIONS.md +21 -26
- package/VERCEL_SETUP.md +49 -62
- package/package.json +1 -4
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter/policy.example.json +6 -7
- package/templates/cms-starter-v0/package.json +2 -2
- package/templates/cms-starter-v0/policy.example.json +6 -7
- package/BUILD_GUARDRAILS.md +0 -350
- package/LOVABLE_SETUP.md +0 -462
package/README.md
CHANGED
|
@@ -1,124 +1,296 @@
|
|
|
1
1
|
# @tomorrowos/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@tomorrowos/sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@tomorrowos/sdk)
|
|
5
|
+
[](#protocol-version)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Build and own your digital signage CMS.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
An open-source SDK and player runtime for digital signage. One server-side API drives commercial signage panels — you write the CMS, we handle device sessions, pairing, and the wire protocol.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Apache 2.0. Build a proprietary CMS on top of it and sell it as your own — no royalty, no permission needed.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
| | |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Node.js | **18** or newer (`engines.node` in this package) |
|
|
20
|
+
| npm | 9 or newer (or a compatible client) |
|
|
21
|
+
| OS | macOS, Linux, Windows (WSL2 recommended on Windows) |
|
|
22
|
+
| Network | CMS host reachable from your screens — a public HTTPS address in production |
|
|
23
|
+
|
|
24
|
+
Screens connect to your CMS over the network. For real panels, deploy to a public host (Railway, Render, Fly, Vercel Fluid, Replit, your own server), or use a tunnel while developing locally.
|
|
25
|
+
|
|
26
|
+
There is no required TomorrowOS cloud. Your screens talk to *your* server.
|
|
12
27
|
|
|
13
28
|
---
|
|
14
29
|
|
|
15
|
-
##
|
|
30
|
+
## Choose your path
|
|
16
31
|
|
|
17
|
-
|
|
32
|
+
Three ways to build with this SDK. Pick one and follow it through.
|
|
18
33
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
6. **Read `BUILD_GUARDRAILS.md`** — mandatory components every generated CMS must include
|
|
25
|
-
7. **Read `brand.schema.json`** — validated shape of `brand.json`
|
|
26
|
-
8. Run **`npx tomorrowos init`** (Replit / Lovable→Node host) or **`npx tomorrowos init --hosting v0`** (Vercel / v0) — minimal CMS server seed
|
|
27
|
-
9. **Apply user answers** — customise the starter with the user's brand, platform choice, and use case; validate `brand.json` against `brand.schema.json`
|
|
28
|
-
10. **Show `PLAYER_INSTALL.md`** — after the CMS is working, show how to build and install the player on a screen
|
|
34
|
+
| | You are | Start here |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| **1** | Building with an AI tool on **Replit** (recommended) or **Vercel / v0** | [Build with an AI tool](#1-build-with-an-ai-tool) |
|
|
37
|
+
| **2** | Writing the CMS yourself | [Build it yourself](#2-build-it-yourself) |
|
|
38
|
+
| **3** | Adding screen management to an existing SaaS or web app | [Add to an existing app](#3-add-to-an-existing-app) |
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
All three end in the same place: a running CMS with a paired screen. From there, go to [Connect a screen](#connect-a-screen).
|
|
31
41
|
|
|
32
42
|
---
|
|
33
43
|
|
|
34
|
-
##
|
|
44
|
+
## 1. Build with an AI tool
|
|
45
|
+
|
|
46
|
+
Guided setup is supported for **Replit** and **Vercel / v0** only. **Replit is recommended** for the fastest path to a live WebSocket CMS.
|
|
47
|
+
|
|
48
|
+
The SDK ships an elicitation protocol so the agent asks the right questions before it writes anything. Skipping it reliably produces a CMS that doesn't run.
|
|
49
|
+
|
|
50
|
+
### Replit (recommended)
|
|
51
|
+
|
|
52
|
+
Paste into Replit Agent:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
Follow NPM package @tomorrowos/sdk REPLIT_SETUP.md and set up my TomorrowOS CMS.
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
On Replit, Supabase must use the `SUPABASE_URL` secret. `DATABASE_URL` is reserved by Replit for its built-in PostgreSQL.
|
|
59
|
+
|
|
60
|
+
Upgrading an existing Replit CMS instead:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
Follow NPM package @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
That protocol diffs and merges against the current templates. It must never run `init --force` or delete `data/` or `public/uploads/`.
|
|
67
|
+
|
|
68
|
+
### Vercel / v0
|
|
69
|
+
|
|
70
|
+
Paste into Vercel Agent:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
Follow @tomorrowos/sdk (an NPM package) VERCEL_SETUP.md and set up my TomorrowOS CMS from scratch.
|
|
74
|
+
|
|
75
|
+
Open VERCEL_QUESTIONS.md first.
|
|
76
|
+
For Q1, Q2, Q3: paste each question block VERBATIM. Do not rephrase options.
|
|
77
|
+
After Q1 database choice, YOU set TOMORROWOS_STORE and DATABASE_SSL. Do not ask me to fill those.
|
|
78
|
+
After Q2 media storage choice, YOU set TOMORROWOS_MEDIA. Do not ask me to fill those.
|
|
79
|
+
Run: npx @tomorrowos/sdk init . --hosting v0 --force
|
|
80
|
+
Keep cms-starter-v0 layout.
|
|
81
|
+
Apply the NON-NEGOTIABLE VERCEL RUNTIME CONTRACT exactly:
|
|
82
|
+
one TomorrowOS instance only
|
|
83
|
+
never create a second TomorrowOS in api/ws.ts
|
|
84
|
+
never use public/ as Vercel Output Directory
|
|
85
|
+
Preview Next only under preview/
|
|
86
|
+
Publish must be the Fluid Function
|
|
87
|
+
after deploy verify: GET /status → JSON, GET / → Control Panel, WebSocket on / or /api → 101
|
|
88
|
+
pair devices against the Production URL only
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Agents must paste questions from [`VERCEL_QUESTIONS.md`](./VERCEL_QUESTIONS.md) verbatim. WebSockets require Fluid compute. The agent sets `cms.hostingTarget` to `"vercel"`.
|
|
92
|
+
|
|
93
|
+
<details>
|
|
94
|
+
<summary><strong>Agent workflow (for the agent, not you)</strong></summary>
|
|
95
|
+
|
|
96
|
+
Supported hosts: **Replit** and **Vercel / v0**.
|
|
97
|
+
|
|
98
|
+
1. Follow the host setup doc for this request (`REPLIT_SETUP.md` / `REPLIT_UPGRADE.md`, or `VERCEL_SETUP.md` + `VERCEL_QUESTIONS.md`).
|
|
99
|
+
2. On Vercel: paste Q1–Q3 **verbatim** from `VERCEL_QUESTIONS.md`; after database choice set `TOMORROWOS_STORE` and `DATABASE_SSL` yourself; after media choice set `TOMORROWOS_MEDIA` yourself.
|
|
100
|
+
3. Read `brand.schema.json` for the validated shape of `brand.json`.
|
|
101
|
+
4. Scaffold with the correct template:
|
|
102
|
+
- Replit / self-host style: `npx @tomorrowos/sdk@0.9.56 init` (default `cms-starter`)
|
|
103
|
+
- Vercel / v0: `npx @tomorrowos/sdk@0.9.56 init . --hosting v0 --force` (`cms-starter-v0`)
|
|
104
|
+
5. Apply the user’s answers — brand and use case. Validate `brand.json`. On Vercel, apply the **NON-NEGOTIABLE VERCEL RUNTIME CONTRACT** from `VERCEL_SETUP.md`.
|
|
105
|
+
6. Point the user at `PLAYER_INSTALL.md` and the Control Panel **Download Players** UI once the CMS is running.
|
|
106
|
+
|
|
107
|
+
Do not write WebSocket transport, pairing wire format, or platform-specific player bridge code. The SDK handles server-side device sessions and HTTP helpers. Customise the UI, the branding, and how you call the SDK.
|
|
108
|
+
|
|
109
|
+
</details>
|
|
35
110
|
|
|
36
|
-
|
|
111
|
+
**Next:** [Connect a screen](#connect-a-screen).
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 2. Build it yourself
|
|
37
116
|
|
|
38
117
|
```bash
|
|
39
118
|
npm install @tomorrowos/sdk
|
|
40
119
|
```
|
|
41
120
|
|
|
42
|
-
Scaffold
|
|
121
|
+
Scaffold, install, run:
|
|
43
122
|
|
|
44
123
|
```bash
|
|
45
|
-
# Replit
|
|
46
|
-
npx tomorrowos init
|
|
124
|
+
# Default template (good for Replit, Railway, Render, Fly.io, self-host)
|
|
125
|
+
npx tomorrowos init my-cms
|
|
47
126
|
|
|
48
|
-
# Vercel / v0 Publish (cms-panel + vercel.json + optional Next
|
|
49
|
-
npx tomorrowos init --hosting v0
|
|
127
|
+
# Vercel / v0 Publish (cms-panel + vercel.json + optional Next preview)
|
|
128
|
+
npx tomorrowos init my-cms --hosting v0
|
|
50
129
|
|
|
51
|
-
cd my-
|
|
130
|
+
cd my-cms
|
|
52
131
|
npm install
|
|
53
132
|
npm run dev
|
|
54
133
|
```
|
|
55
134
|
|
|
56
|
-
`
|
|
57
|
-
schema. The starter server uses that SQLite database by default, so pairings,
|
|
58
|
-
playlists, and device assignments survive normal server restarts.
|
|
135
|
+
`init` creates `data/tomorrowos.db` with the TomorrowOS SQLite schema. The starter server uses it by default, so pairings, playlists, and device assignments survive restarts.
|
|
59
136
|
|
|
60
|
-
|
|
137
|
+
**Recommended deploy hosts** for this path (long-lived Node + WebSockets):
|
|
61
138
|
|
|
62
|
-
|
|
139
|
+
| Host | Notes |
|
|
140
|
+
|---|---|
|
|
141
|
+
| **Railway** | Simple Node deploy; good default for self-built CMS |
|
|
142
|
+
| **Render** | Web Service with persistent process |
|
|
143
|
+
| **Fly.io** | Global edge VMs; hold WebSockets cleanly |
|
|
144
|
+
| **Replit** | Fastest AI-assisted path — see [Build with an AI tool](#1-build-with-an-ai-tool) |
|
|
145
|
+
| **Vercel Fluid** | Use `--hosting v0` and follow [`VERCEL_SETUP.md`](./VERCEL_SETUP.md) |
|
|
63
146
|
|
|
64
|
-
|
|
65
|
-
Follow @tomorrowos/sdk REPLIT_SETUP.md and set up my TomorrowOS CMS.
|
|
66
|
-
Ask me the questions in order. Do not skip steps.
|
|
67
|
-
Q1 database order: Supabase (Recommended), then Built-in Replit PostgreSQL, then SQLite.
|
|
68
|
-
If Supabase: SUPABASE_URL Secrets input immediately after choice (once only).
|
|
69
|
-
If Cloudinary: all CLOUDINARY_* Secrets in one multi-field dialog immediately after choice.
|
|
70
|
-
Q3: one stacked dialog with all seven branding fields (optional; blanks keep brand.json defaults).
|
|
71
|
-
```
|
|
147
|
+
Avoid classic short-lived serverless without WebSocket support.
|
|
72
148
|
|
|
73
|
-
|
|
74
|
-
**`SUPABASE_URL`** (not the reserved `DATABASE_URL` — that is for built-in Replit PostgreSQL).
|
|
149
|
+
You now have a CMS serving:
|
|
75
150
|
|
|
76
|
-
|
|
151
|
+
- pairing HTTP helpers (`POST /pairing/verify`, `POST /pairing/unpair`)
|
|
152
|
+
- `GET /brand.json` for player branding
|
|
153
|
+
- a WebSocket device channel
|
|
154
|
+
- media upload helpers (`/media/upload`, and Cloudinary direct upload when configured)
|
|
155
|
+
- `GET /players/brightsign.zip` — BrightSign package with `config.js` `cmsEndpoint` set to this CMS origin
|
|
156
|
+
- a minimal admin panel (static UI under `staticRoot`)
|
|
77
157
|
|
|
78
|
-
|
|
158
|
+
Deploy it to a public HTTPS address before pairing a production screen. While developing locally, a tunnel is the fastest way to get one.
|
|
79
159
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
160
|
+
**Next:** [Connect a screen](#connect-a-screen).
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 3. Add to an existing app
|
|
165
|
+
|
|
166
|
+
If you already have a SaaS or web app and want screen management as a feature inside it, you don't need the starter. Import the SDK into your existing server.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npm install @tomorrowos/sdk
|
|
88
170
|
```
|
|
89
171
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
must still run on a **Node host** (Railway / Render / Fly, or Vercel Fluid via `VERCEL_SETUP.md`) —
|
|
93
|
-
Lovable Cloud Publish alone is not a WebSocket CMS.
|
|
172
|
+
```ts
|
|
173
|
+
import { createTomorrowOSStore, TomorrowOS } from "@tomorrowos/sdk";
|
|
94
174
|
|
|
95
|
-
|
|
175
|
+
const store = createTomorrowOSStore({
|
|
176
|
+
// Prefer SUPABASE_URL on Replit; DATABASE_URL elsewhere / fallback
|
|
177
|
+
databaseUrl: process.env.SUPABASE_URL || process.env.DATABASE_URL
|
|
178
|
+
});
|
|
96
179
|
|
|
97
|
-
|
|
180
|
+
const tomorrowos = new TomorrowOS({ brand, store });
|
|
98
181
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
182
|
+
const server = tomorrowos.listen({
|
|
183
|
+
port: Number(process.env.PORT) || 3000,
|
|
184
|
+
host: "0.0.0.0",
|
|
185
|
+
staticRoot: "./public" // optional Control Panel + uploads
|
|
186
|
+
});
|
|
102
187
|
```
|
|
103
188
|
|
|
104
|
-
|
|
105
|
-
branding (manual fields or **website URL → `brand.json` only**, no login unless asked). Preview may use a thin **Next.js reverse proxy**;
|
|
106
|
-
**Publish stays a Fluid Vercel Function** (`api/index.ts` + `export default server`, WebSockets per Vercel docs). Cloudinary uses **one Env popup** (all fields).
|
|
107
|
-
Neon/Supabase: agent auto-sets `TOMORROWOS_STORE` + `DATABASE_SSL`. Sets `cms.hostingTarget` to `"vercel"`.
|
|
189
|
+
What you keep from your app: your auth, your users, your tenancy model, your UI. What the SDK adds: device sessions, the pairing handshake, playlist/policy delivery, and optional static CMS helpers.
|
|
108
190
|
|
|
109
|
-
|
|
191
|
+
Points to plan for:
|
|
110
192
|
|
|
111
|
-
|
|
193
|
+
- **Multi-tenancy.** Devices belong to whatever tenant model you already have. The SDK does not impose one — map device IDs to your own tenant records.
|
|
194
|
+
- **Auth.** Pairing is a device-side flow. Your admin routes stay behind your existing auth.
|
|
195
|
+
- **Store.** Use `createTomorrowOSStore` / `TOMORROWOS_STORE` for SQLite, Postgres, or Supabase, or pass a custom `TomorrowOSStore`.
|
|
196
|
+
- **WebSockets.** Your host must hold long-lived connections. Most serverless platforms terminate idle sockets — check before you commit (Vercel needs Fluid compute).
|
|
112
197
|
|
|
113
|
-
|
|
114
|
-
|
|
198
|
+
**Next:** [Connect a screen](#connect-a-screen).
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Architecture
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
┌─────────────────┐ WebSocket ┌─────────────────┐
|
|
206
|
+
│ Your CMS │ ◄────────────────────────►│ TomorrowOS │
|
|
207
|
+
│ (your server) │ │ Player on │
|
|
208
|
+
│ │ │ screen │
|
|
209
|
+
│ imports │ │ │
|
|
210
|
+
│ @tomorrowos │ │ unified API │
|
|
211
|
+
│ /sdk │ │ across panels │
|
|
212
|
+
└─────────────────┘ └─────────────────┘
|
|
115
213
|
```
|
|
116
214
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
215
|
+
You own the CMS: the UI, the branding, the business logic, the data. The SDK owns the device session, the pairing handshake, and the wire protocol.
|
|
216
|
+
|
|
217
|
+
You should not need to write WebSocket transport, pairing wire format, or platform-specific player bridge code. If you find yourself doing that, open an issue — it means the SDK has a gap.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Connect a screen
|
|
222
|
+
|
|
223
|
+
Your CMS is running. This is what happens next, in order.
|
|
224
|
+
|
|
225
|
+
1. **Deploy the CMS to a public HTTPS address** (or tunnel for local tests). Screens must reach it from their network.
|
|
226
|
+
2. **Get a player package** for your platform (see below and [`PLAYER_INSTALL.md`](./PLAYER_INSTALL.md)).
|
|
227
|
+
Note: `npx tomorrowos build --platform …` is still a **placeholder** in this package — packaging lives in the player repos / prebuilt downloads, not in the CLI yet.
|
|
228
|
+
3. **Install the player on the panel.**
|
|
229
|
+
4. **Pair.** The player shows a 6-character code. Enter it in the Control Panel. The device appears in your device list.
|
|
230
|
+
5. **Publish content.** Assign playlists / push a content policy. The screen updates without reloading the app.
|
|
231
|
+
|
|
232
|
+
### Samsung Tizen
|
|
233
|
+
|
|
234
|
+
Supported target: **Tizen 6.5+** commercial displays (see Control Panel captions and [`PLAYER_INSTALL.md`](./PLAYER_INSTALL.md)).
|
|
235
|
+
|
|
236
|
+
**Fastest path for many setups — URL Launcher / prebuilt package**
|
|
237
|
+
|
|
238
|
+
- From a running Control Panel, use **Download Players → Samsung**, or fetch the published Tizen package from TomorrowOS distribution (`https://tmr.sh/app/tizen/…`).
|
|
239
|
+
- Or host / sideload a `.wgt` as described in [`PLAYER_INSTALL.md`](./PLAYER_INSTALL.md).
|
|
240
|
+
|
|
241
|
+
On the panel, enter the CMS HTTPS URL (or the player package URL your install path requires). The player shows a pairing code.
|
|
242
|
+
|
|
243
|
+
Signed packages need a Samsung distributor certificate for production distribution. Unsigned / URL Launcher paths are fine for testing when your environment allows them.
|
|
244
|
+
|
|
245
|
+
### BrightSign
|
|
246
|
+
|
|
247
|
+
Supported target: **Series 5 / 6** (as labeled in the Control Panel). Older series may work but should be validated on your hardware before fleet rollout.
|
|
248
|
+
|
|
249
|
+
**Recommended download path**
|
|
250
|
+
|
|
251
|
+
1. Open your live CMS Control Panel → **Download Players → BrightSign**.
|
|
252
|
+
2. That hits `GET /players/brightsign.zip` on *this* CMS.
|
|
253
|
+
3. The SDK fetches the mother zip and rewrites `config.js` so:
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
cmsEndpoint: "https://your-cms-host/"
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
matches the CMS you downloaded from (for example `https://testcms2.replit.app/`).
|
|
260
|
+
|
|
261
|
+
4. Unzip, copy the **contents** to a microSD card (files at the card root, including `autorun.brs` and `config.js`).
|
|
262
|
+
5. Insert the card and power on. Pair with the on-screen code.
|
|
263
|
+
|
|
264
|
+
Override the mother zip URL with `TOMORROWOS_BRIGHTSIGN_ZIP_URL` if you host your own package.
|
|
265
|
+
|
|
266
|
+
### Coming soon
|
|
267
|
+
|
|
268
|
+
Android, LG webOS, and Windows are on the roadmap. They are not validated for production in this SDK release.
|
|
269
|
+
|
|
270
|
+
If you are building for one of those platforms later: build your CMS against the same server API now. Server-side code does not need to change when a new player package lands — only the installable player does.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Platform support
|
|
275
|
+
|
|
276
|
+
| Platform | Status | Install |
|
|
277
|
+
|---|---|---|
|
|
278
|
+
| Samsung Tizen 6.5+ | V1 supported | Control Panel download / `.wgt` / URL Launcher — see `PLAYER_INSTALL.md` |
|
|
279
|
+
| BrightSign Series 5, 6 | V1 supported | Control Panel `GET /players/brightsign.zip` → microSD autorun |
|
|
280
|
+
| BrightSign older series | Validate on hardware | Same autorun zip flow |
|
|
281
|
+
| Android | Roadmap | — |
|
|
282
|
+
| LG webOS | Roadmap | — |
|
|
283
|
+
| Windows | Roadmap | — |
|
|
284
|
+
|
|
285
|
+
Treat a platform as production-ready only after you have validated it on your panels.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Configuration
|
|
120
290
|
|
|
121
|
-
|
|
291
|
+
### Database
|
|
292
|
+
|
|
293
|
+
SQLite by default (no configuration required for the starter). To switch:
|
|
122
294
|
|
|
123
295
|
```bash
|
|
124
296
|
TOMORROWOS_STORE=supabase
|
|
@@ -127,11 +299,11 @@ DATABASE_SSL=true
|
|
|
127
299
|
# DATABASE_URL=... # optional fallback outside Replit
|
|
128
300
|
```
|
|
129
301
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
302
|
+
Supported store drivers: `sqlite`, `postgres`, `supabase`, `memory`.
|
|
303
|
+
|
|
304
|
+
Use `memory` for throwaway demos only — nothing survives a restart.
|
|
133
305
|
|
|
134
|
-
|
|
306
|
+
### Migrating between stores
|
|
135
307
|
|
|
136
308
|
```bash
|
|
137
309
|
npx tomorrowos migrate \
|
|
@@ -141,83 +313,115 @@ npx tomorrowos migrate \
|
|
|
141
313
|
--to-database-url "$DATABASE_URL"
|
|
142
314
|
```
|
|
143
315
|
|
|
144
|
-
|
|
145
|
-
direction. It migrates TomorrowOS database records only; copy `public/uploads`
|
|
146
|
-
or object-storage media separately.
|
|
316
|
+
Works in either direction across `sqlite`, `postgres`, and `supabase`. It moves database records only — copy `public/uploads` or object-storage / Cloudinary media separately.
|
|
147
317
|
|
|
148
|
-
|
|
318
|
+
### Media
|
|
149
319
|
|
|
150
|
-
|
|
151
|
-
|
|
320
|
+
- **Local / Object Storage:** `POST /media/upload` when `staticRoot` is set (files under `public/uploads`).
|
|
321
|
+
- **Cloudinary:** set `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, `CLOUDINARY_API_SECRET` (optional `CLOUDINARY_FOLDER`). The Control Panel uses **browser → Cloudinary** direct upload (`/media/upload-sign` + `/media/register`) when Cloudinary is configured, which avoids host request-body limits on platforms like Replit.
|
|
322
|
+
|
|
323
|
+
Cloudinary account plans still enforce their own max file sizes (for example Free plan video caps).
|
|
324
|
+
|
|
325
|
+
### Branding
|
|
326
|
+
|
|
327
|
+
Pass a brand object to the constructor (usually loaded from `brand.json`):
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
const tomorrowos = new TomorrowOS({ brand, store });
|
|
152
331
|
```
|
|
153
332
|
|
|
154
|
-
|
|
333
|
+
It is served at `GET /brand.json` on the same host as `listen`. Players fetch it for colours, logos, and display defaults.
|
|
155
334
|
|
|
156
|
-
|
|
335
|
+
Validate against [`brand.schema.json`](./brand.schema.json). A complete example is in [`brand.example.json`](./brand.example.json).
|
|
336
|
+
|
|
337
|
+
### Content policy and scheduling
|
|
157
338
|
|
|
158
339
|
```
|
|
159
|
-
|
|
160
|
-
│ Your CMS │ ◄────────────────────────►│ TomorrowOS │
|
|
161
|
-
│ (your server) │ │ Player on │
|
|
162
|
-
│ │ │ screen │
|
|
163
|
-
│ imports │ │ │
|
|
164
|
-
│ @tomorrowos │ │ unified API │
|
|
165
|
-
│ /sdk │ │ across OSes │
|
|
166
|
-
└─────────────────┘ └─────────────────┘
|
|
340
|
+
POST /device/{deviceId}/content/set-policy
|
|
167
341
|
```
|
|
168
342
|
|
|
169
|
-
|
|
343
|
+
```json
|
|
344
|
+
{
|
|
345
|
+
"policy": {
|
|
346
|
+
"playlists": [],
|
|
347
|
+
"fallback": { "type": "brand" }
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
170
351
|
|
|
171
|
-
|
|
352
|
+
Each playlist may include optional `schedule`, evaluated in **device local time**. The run window is **one continuous period**:
|
|
172
353
|
|
|
173
|
-
**
|
|
354
|
+
**from** `startDate` + `start` **→ until** `endDate` + `end` (until is exclusive).
|
|
174
355
|
|
|
175
356
|
| Field | Format | Notes |
|
|
176
|
-
|
|
177
|
-
| `startDate` / `endDate` | `YYYY-MM-DD` |
|
|
178
|
-
| `
|
|
179
|
-
|
|
357
|
+
|---|---|---|
|
|
358
|
+
| `startDate` / `endDate` | `YYYY-MM-DD` | Combined with `start` / `end`; omit bounds for open-ended |
|
|
359
|
+
| `start` / `end` | `HH:mm` | Clock times on those dates |
|
|
360
|
+
|
|
361
|
+
This is **not** a daily-repeat schedule inside a date range. Leave schedule empty for always-on. Example shape: [`templates/cms-starter/policy.example.json`](./templates/cms-starter/policy.example.json) (ignore legacy `daysOfWeek` if present).
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Troubleshooting
|
|
366
|
+
|
|
367
|
+
**Screen won't pair.**
|
|
368
|
+
The player must reach your CMS. Confirm a public HTTPS (or reachable tunnel) URL, DNS, firewall, and that the panel has network access. A CMS only on `localhost` will not pair from a real display.
|
|
180
369
|
|
|
181
|
-
|
|
370
|
+
**Paired, but the screen is black (BrightSign).**
|
|
371
|
+
Common causes: media the player cannot decode (codec / profile / unexpected tracks), or HTML video surface alpha / HTML widget timing in `autorun.brs`. Re-encode to a supported profile and confirm `config.js` points at the correct CMS. Check player logs on the device.
|
|
372
|
+
|
|
373
|
+
**Paired, but the screen is black (other).**
|
|
374
|
+
Fetch `GET /brand.json` from the panel’s network. A live WebSocket with a black screen usually means no playable policy item — check published playlists, absolute media URLs, and fallback.
|
|
375
|
+
|
|
376
|
+
**Media 404s on the screen but loads in your browser.**
|
|
377
|
+
Policy URLs must be absolute and reachable from the screen. Relative paths or hosts only visible on your laptop will fail on the panel.
|
|
378
|
+
|
|
379
|
+
**Upload fails with HTTP 413 on Replit (or similar hosts).**
|
|
380
|
+
The file was posted through the CMS host body limit. With Cloudinary configured, use an SDK/Control Panel version that supports direct browser upload. Otherwise upload smaller files or raise the host limit.
|
|
381
|
+
|
|
382
|
+
**BrightSign zip has empty `cmsEndpoint`.**
|
|
383
|
+
You downloaded the mother zip from a static CDN instead of **this** CMS’s `/players/brightsign.zip`. Use Control Panel → Download Players → BrightSign on the deployed CMS.
|
|
384
|
+
|
|
385
|
+
**WebSocket disconnects on a serverless host.**
|
|
386
|
+
Most serverless platforms terminate idle connections. Vercel requires Fluid compute. Prefer a long-lived Node host (Railway, Render, Fly, Replit) if your platform cannot hold sockets.
|
|
387
|
+
|
|
388
|
+
**Database changes don't persist.**
|
|
389
|
+
You are probably on `TOMORROWOS_STORE=memory`. Switch to `sqlite` or Postgres/Supabase.
|
|
182
390
|
|
|
183
391
|
---
|
|
184
392
|
|
|
185
|
-
##
|
|
393
|
+
## Getting help
|
|
186
394
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
| Samsung Tizen | V1 target | `.wgt` |
|
|
190
|
-
| BrightSign | V1 target | autorun zip |
|
|
191
|
-
| Others | See docs | varies |
|
|
395
|
+
- **Package docs:** the Markdown files listed below ship inside `@tomorrowos/sdk`
|
|
396
|
+
- **npm:** [https://www.npmjs.com/package/@tomorrowos/sdk](https://www.npmjs.com/package/@tomorrowos/sdk)
|
|
192
397
|
|
|
193
|
-
|
|
398
|
+
If something in this README doesn't match what the package actually does, treat that as a bug and report it — documentation drift matters as much as a code defect.
|
|
194
399
|
|
|
195
400
|
---
|
|
196
401
|
|
|
197
402
|
## Documentation in this package
|
|
198
403
|
|
|
199
404
|
| File | Purpose |
|
|
200
|
-
|
|
201
|
-
| `
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `
|
|
206
|
-
| `
|
|
207
|
-
| `
|
|
208
|
-
| `
|
|
209
|
-
| `
|
|
210
|
-
| `
|
|
211
|
-
| `templates/cms-starter/` | Minimal Node + TypeScript server seed |
|
|
212
|
-
| `templates/cms-starter/policy.example.json` | Example `setPolicy` payload with date schedule |
|
|
213
|
-
| `templates/style-tokens/` | CSS tokens and UI pattern notes |
|
|
405
|
+
|---|---|
|
|
406
|
+
| [`PLAYER_INSTALL.md`](./PLAYER_INSTALL.md) | Player install and pairing notes |
|
|
407
|
+
| [`brand.schema.json`](./brand.schema.json) | JSON Schema for `brand.json` |
|
|
408
|
+
| [`brand.example.json`](./brand.example.json) | Complete example `brand.json` |
|
|
409
|
+
| [`REPLIT_SETUP.md`](./REPLIT_SETUP.md) | Replit Agent guided setup |
|
|
410
|
+
| [`REPLIT_UPGRADE.md`](./REPLIT_UPGRADE.md) | Upgrading an existing Replit CMS |
|
|
411
|
+
| [`VERCEL_SETUP.md`](./VERCEL_SETUP.md) | Vercel / v0 guided setup |
|
|
412
|
+
| [`VERCEL_QUESTIONS.md`](./VERCEL_QUESTIONS.md) | Verbatim Q1–Q3 text for Vercel agents |
|
|
413
|
+
| [`templates/cms-starter/`](./templates/cms-starter/) | Minimal Node + TypeScript server seed |
|
|
414
|
+
| [`templates/cms-starter-v0/`](./templates/cms-starter-v0/) | Vercel / v0 starter (Fluid + cms-panel) |
|
|
415
|
+
| [`templates/style-tokens/`](./templates/style-tokens/) | CSS tokens and UI pattern notes |
|
|
214
416
|
|
|
215
417
|
---
|
|
216
418
|
|
|
217
419
|
## License
|
|
218
420
|
|
|
219
|
-
Apache 2.0.
|
|
421
|
+
Apache 2.0 (see `license` in `package.json`).
|
|
422
|
+
|
|
423
|
+
You can use TomorrowOS commercially, modify it, and build closed-source products on top of it. You can ship a proprietary CMS built on this SDK and sell it under your own brand. You do not owe a fee, a licence, or a mention.
|
|
220
424
|
|
|
221
425
|
## Protocol version
|
|
222
426
|
|
|
223
|
-
Wire protocol
|
|
427
|
+
Wire protocol **1.0** (see `protocolVersion` in [`brand.example.json`](./brand.example.json) and the TomorrowOS player/CMS contract).
|