@tomorrowos/sdk 0.9.69 → 0.9.71

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.
@@ -1,6 +1,6 @@
1
1
  # Vercel / v0 - Verbatim question bank
2
2
 
3
- > **Protocol:** `vercel-questions/1.5` (pairs with `VERCEL_SETUP.md` 1.14+ / `@tomorrowos/sdk` 0.9.69+)
3
+ > **Protocol:** `vercel-questions/1.5` (pairs with `VERCEL_SETUP.md` 1.14+ / `@tomorrowos/sdk` 0.9.70+)
4
4
  > **For Agents:** When asking the user a setup question, **copy-paste the block below for that step EXACTLY**.
5
5
  > Do **not** paraphrase, reorder, rename options, or invent alternatives (no S3, no Supabase Storage, no "Blob recommended", no "disable media").
6
6
  > After each answer, configure per `VERCEL_SETUP.md`, then paste the **next** block.
package/VERCEL_SETUP.md CHANGED
@@ -5,7 +5,7 @@
5
5
  >
6
6
  > **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`).
7
7
  >
8
- > Protocol id: `vercel-setup/1.14` - pairs with `@tomorrowos/sdk` **0.9.69+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
8
+ > Protocol id: `vercel-setup/1.14` - pairs with `@tomorrowos/sdk` **0.9.70+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
9
9
  >
10
10
  > **Questions source of truth:** `VERCEL_QUESTIONS.md` - Agents must **open that file and paste each Q block verbatim**. Do not paraphrase.
11
11
  > **Q1/Q2 = choice questions. Q3 = form only:** open **all seven optional inputs at once**, then **HARD STOP and WAIT** for submit or "skip". Never auto-skip because fields are optional. Never ask a branding choice first. Never show only Name + Primary colour. Logo = **Upload** above **Logo URL**.
@@ -465,7 +465,7 @@ Adapt script names / process runners as needed. **Invariant:**
465
465
 
466
466
  Use the latest published `@tomorrowos/sdk` when scaffolding (do not invent versions).
467
467
 
468
- Add nothing extra for Blob when using `@tomorrowos/sdk@0.9.69+` (`@vercel/blob` is bundled). Only ensure `BLOB_READ_WRITE_TOKEN` + `TOMORROWOS_MEDIA=vercel-blob` when the user chooses **Vercel Blob** in Question 2.
468
+ Add nothing extra for Blob when using `@tomorrowos/sdk@0.9.70+` (`@vercel/blob` is bundled). Only ensure `BLOB_READ_WRITE_TOKEN` + `TOMORROWOS_MEDIA=vercel-blob` when the user chooses **Vercel Blob** in Question 2.
469
469
 
470
470
  For Preview shell only, add as needed: `next`, `react`, `react-dom`, and a process runner (`concurrently` or equivalent). These must **not** become the Production CMS.
471
471
 
@@ -736,7 +736,7 @@ The SDK auto-detects these env vars.
736
736
 
737
737
  1. Set Vercel Env Var: `BLOB_READ_WRITE_TOKEN=<token>` (if not auto-injected). Prefer the Env popup when available.
738
738
  2. Set Vercel Env Var yourself (agent-owned): `TOMORROWOS_MEDIA=vercel-blob`. **Do not** ask the user to type this.
739
- 3. Ensure `@tomorrowos/sdk@0.9.69+` is installed (`@vercel/blob` is a transitive dependency ? no project-level Blob bridge / custom `put()` middleware).
739
+ 3. Ensure `@tomorrowos/sdk@0.9.70+` is installed (`@vercel/blob` is a transitive dependency ? no project-level Blob bridge / custom `put()` middleware).
740
740
  4. The SDK **natively** uploads via Vercel Blob when the token is present (same HTTP routes as local: `/media/upload` and chunked complete). Returned asset URLs are absolute `https://*.public.blob.vercel-storage.com/...`.
741
741
  5. Confirm Control Panel **Media Server** shows provider **Blob** (not Local). Do **not** invent status copy about "Blob bridge" or paste the URL pattern as a status detail.
742
742
  6. Do **not** proceed to Question 3 until `BLOB_READ_WRITE_TOKEN` exists (or Blob is linked and token is confirmed in the Vercel dashboard).
@@ -1013,7 +1013,7 @@ Protocol complete when:
1013
1013
 
1014
1014
  ## Protocol version
1015
1015
 
1016
- `vercel-setup/1.14` - pairs with `@tomorrowos/sdk` 0.9.69+ and `VERCEL_QUESTIONS.md` 1.5.
1016
+ `vercel-setup/1.14` - pairs with `@tomorrowos/sdk` 0.9.70+ and `VERCEL_QUESTIONS.md` 1.5.
1017
1017
 
1018
1018
  **Changelog 1.14:** Vercel Blob is **SDK-native** (`BLOB_READ_WRITE_TOKEN` + `TOMORROWOS_MEDIA=vercel-blob`). No project Blob bridge. Status providers use display names (Neon, Supabase, Blob, Cloudinary, Replit Object Storage). Forbidden marketing status copy about blob URL patterns.
1019
1019
 
package/dist/cli.js CHANGED
@@ -85,6 +85,7 @@ function copyStarter(destDir, force, hosting) {
85
85
  console.log(`[tomorrowos] Template: ${templateName} (--hosting ${hosting})`);
86
86
  console.log(`[tomorrowos] @tomorrowos/sdk dependency: ^${sdkVer}`);
87
87
  console.log(`[tomorrowos] Initialized SQLite database: ${dbPath}`);
88
+ console.log(`[tomorrowos] Env template: ${path.join(resolved, ".env.example")}`);
88
89
  if (hosting === "replit") {
89
90
  console.log("Next: npm install, then npm start (see REPLIT_SETUP.md on Replit)");
90
91
  }
@@ -102,10 +103,12 @@ function parseHostingFlag(argv) {
102
103
  }
103
104
  function cmdBuild(argv) {
104
105
  const platformIdx = argv.indexOf("--platform");
105
- const platform = platformIdx >= 0 && argv[platformIdx + 1] ? argv[platformIdx + 1] : "tizen";
106
- console.log(`[tomorrowos] Player packaging for "${platform}" is not bundled in @tomorrowos/sdk yet.`);
107
- console.log("Use your TomorrowOS player repository (assemble Web app + config), then run the platform SDK (e.g. Tizen CLI tizen package) from the build output directory.");
108
- process.exitCode = 0;
106
+ const platform = platformIdx >= 0 && argv[platformIdx + 1] ? argv[platformIdx + 1] : "(unspecified)";
107
+ console.error(`[tomorrowos] "tomorrowos build" does not package players. No file was produced for platform "${platform}".`);
108
+ console.error("Download a verified prebuilt player from your running Control Panel (Download Players), or from the player repositories.");
109
+ console.error("Tizen: Control Panel → Download Players → Samsung (or https://tmr.sh/app/tizen/). BrightSign: Control Panel → Download Players → BrightSign (GET /players/brightsign.zip).");
110
+ console.error("See PLAYER_INSTALL.md for install and pairing steps.");
111
+ process.exit(1);
109
112
  }
110
113
  function optionValue(argv, name) {
111
114
  const withEquals = `${name}=`;
@@ -194,7 +197,6 @@ function printHelp() {
194
197
  Usage:
195
198
  tomorrowos init [directory] Copy cms-starter template (default: Replit / Railway)
196
199
  tomorrowos migrate [options] Migrate TomorrowOS data between supported databases
197
- tomorrowos build --platform … Placeholder; player packaging lives in the player repo
198
200
 
199
201
  Options:
200
202
  --hosting replit|v0|vercel init template: replit (default) or Vercel/v0 (cms-starter-v0)
@@ -205,6 +207,8 @@ Examples:
205
207
  npx @tomorrowos/sdk@latest init ./my-cms --hosting replit
206
208
  npx @tomorrowos/sdk@latest init ./my-cms --hosting v0
207
209
  npx @tomorrowos/sdk@latest migrate --from sqlite --from-sqlite ./data/tomorrowos.db --to supabase --to-database-url "$DATABASE_URL"
210
+
211
+ Player packages are not built by this CLI. Use Control Panel → Download Players, or see PLAYER_INSTALL.md.
208
212
  `);
209
213
  }
210
214
  function printMigrateHelp() {
@@ -8,9 +8,6 @@ export interface SavePlaylistInput {
8
8
  export interface BuiltDevicePolicy {
9
9
  policy: {
10
10
  playlists: PublishedPlaylistSnapshot[];
11
- fallback: {
12
- type: "brand";
13
- };
14
11
  revision?: number;
15
12
  syncMode?: "latest" | "snapshot";
16
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"playlist-catalog.d.ts","sourceRoot":"","sources":["../src/playlist-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,SAAS,EAAE,yBAAyB,EAAE,CAAC;QACvC,QAAQ,EAAE;YAAE,IAAI,EAAE,OAAO,CAAA;SAAE,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyDD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAE7C,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK1C,6BAA6B,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI1D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI5D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IA8B/D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcnD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAIhC,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;IAiEvB,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAO7B,mFAAmF;IAC7E,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAKjF;;;OAGG;IACG,+BAA+B,CACnC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;IA4BrD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;YAKf,0BAA0B;IAgCxC,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGpE"}
1
+ {"version":3,"file":"playlist-catalog.d.ts","sourceRoot":"","sources":["../src/playlist-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,SAAS,EAAE,yBAAyB,EAAE,CAAC;QACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyDD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAE7C,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK1C,6BAA6B,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI1D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI5D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IA8B/D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcnD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAIhC,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;IAiEvB,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAO7B,mFAAmF;IAC7E,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAKjF;;;OAGG;IACG,+BAA+B,CACnC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;IA4BrD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;YAKf,0BAA0B;IA+BxC,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGpE"}
@@ -219,7 +219,6 @@ export class PlaylistCatalog {
219
219
  return {
220
220
  policy: {
221
221
  playlists,
222
- fallback: { type: "brand" },
223
222
  revision: Date.now(),
224
223
  syncMode: useLatest ? "latest" : "snapshot"
225
224
  }
@@ -1663,7 +1663,7 @@ export class TomorrowOS extends EventEmitter {
1663
1663
  return this.getLegacyDeviceScreenshot(deviceId);
1664
1664
  }
1665
1665
  async captureDeviceScreenshot(deviceId) {
1666
- const result = await this.sendDeviceCommand(deviceId, "device.captureScreen", {});
1666
+ const result = await this.sendDeviceCommand(deviceId, "device.telemetry.captureScreen", {});
1667
1667
  if (result.status === "failed") {
1668
1668
  throw new Error(String(result.error ?? "Screenshot failed"));
1669
1669
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "0.9.69",
4
- "description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
3
+ "version": "0.9.71",
4
+ "description": "Server SDK for building and self-hosting digital signage CMS products with TomorrowOS players.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "prepublishOnly": "npm run build"
33
33
  },
34
34
  "engines": {
35
- "node": ">=18"
35
+ "node": ">=20"
36
36
  },
37
37
  "dependencies": {
38
38
  "@replit/object-storage": "^1.0.0",
@@ -0,0 +1,19 @@
1
+ # Default: SQLite.
2
+ # TOMORROWOS_STORE=sqlite
3
+ # TOMORROWOS_DB_PATH=./data/tomorrowos.db
4
+
5
+ # Supabase/Postgres.
6
+ # On Replit use SUPABASE_URL — DATABASE_URL is often a reserved Secret.
7
+ # TOMORROWOS_STORE=supabase
8
+ # SUPABASE_URL=postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres
9
+ # DATABASE_SSL=true
10
+ # DATABASE_URL=postgresql://... # optional fallback outside Replit
11
+
12
+ # Optional: upload media to Cloudinary instead of local / Object Storage.
13
+ # CLOUDINARY_CLOUD_NAME=
14
+ # CLOUDINARY_API_KEY=
15
+ # CLOUDINARY_API_SECRET=
16
+ # CLOUDINARY_FOLDER=tomorrowos
17
+
18
+ # Optional: override the default deterministic pairing-code secret.
19
+ # PAIRING_CODE_SECRET=
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "0.9.69",
3
+ "version": "0.9.71",
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",
@@ -9,11 +9,10 @@
9
9
  },
10
10
  "scripts": {
11
11
  "dev": "tsx watch server.ts",
12
- "start": "tsx server.ts",
13
- "build-player": "tomorrowos build --platform tizen"
12
+ "start": "tsx server.ts"
14
13
  },
15
14
  "dependencies": {
16
- "@tomorrowos/sdk": "^0.9.69",
15
+ "@tomorrowos/sdk": "^0.9.71",
17
16
  "dotenv": "^17.2.3",
18
17
  "tsx": "^4.19.0"
19
18
  },
@@ -23,7 +23,6 @@
23
23
  }
24
24
  ]
25
25
  }
26
- ],
27
- "fallback": { "type": "brand" }
26
+ ]
28
27
  }
29
28
  }
@@ -231,11 +231,15 @@
231
231
  <p class="hint">Current installed SDK version:</p>
232
232
  <p class="update-sdk-version" id="updateSdkVersionLabel">Loading…</p>
233
233
  <p class="hint">
234
- To upgrade on AI agent platforms (Replit, Vercel, etc.), paste this prompt into the Agent chat:
234
+ To upgrade on AI agent platforms, paste the matching prompt into the Agent chat:
235
235
  </p>
236
- <pre class="update-sdk-prompt" id="updateSdkPromptText">Follow @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
236
+ <p class="update-sdk-prompt-label">Replit</p>
237
+ <pre class="update-sdk-prompt" id="updateSdkPromptReplit">Follow NPM package @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
238
+ <p class="update-sdk-prompt-label">Vercel</p>
239
+ <pre class="update-sdk-prompt" id="updateSdkPromptVercel">Follow NPM package @tomorrowos/sdk VERCEL_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
237
240
  <div class="modal-actions update-sdk-modal-actions">
238
- <button type="button" id="copyUpdateSdkPromptBtn" class="primary">Copy prompt</button>
241
+ <button type="button" id="copyUpdateSdkPromptReplitBtn" class="primary">Copy Replit prompt</button>
242
+ <button type="button" id="copyUpdateSdkPromptVercelBtn" class="primary">Copy Vercel prompt</button>
239
243
  <button type="button" data-close-update-sdk-modal="1">Close</button>
240
244
  </div>
241
245
  </div>
@@ -33,8 +33,10 @@ let cachedSdkVersion = "";
33
33
  /** @type {number|null} CMS server boot time (ms) from GET /devices. */
34
34
  let serverStartedAtMs = null;
35
35
 
36
- const UPDATE_SDK_PROMPT =
37
- "Follow @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.";
36
+ const UPDATE_SDK_PROMPT_REPLIT =
37
+ "Follow NPM package @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.";
38
+ const UPDATE_SDK_PROMPT_VERCEL =
39
+ "Follow NPM package @tomorrowos/sdk VERCEL_UPGRADE.md to upgrade my CMS with the latest SDK.";
38
40
  /** @type {ReturnType<typeof setTimeout>|null} */
39
41
  let reconnectGraceTimer = null;
40
42
  let uploadQueue = [];
@@ -2364,8 +2366,10 @@ function setUpdateSdkVersionLabel(version) {
2364
2366
 
2365
2367
  async function openUpdateSdkModal() {
2366
2368
  const modal = document.getElementById("updateSdkModal");
2367
- const promptEl = document.getElementById("updateSdkPromptText");
2368
- if (promptEl) promptEl.textContent = UPDATE_SDK_PROMPT;
2369
+ const replitEl = document.getElementById("updateSdkPromptReplit");
2370
+ const vercelEl = document.getElementById("updateSdkPromptVercel");
2371
+ if (replitEl) replitEl.textContent = UPDATE_SDK_PROMPT_REPLIT;
2372
+ if (vercelEl) vercelEl.textContent = UPDATE_SDK_PROMPT_VERCEL;
2369
2373
  setUpdateSdkVersionLabel(cachedSdkVersion || "Loading…");
2370
2374
  modal?.classList.remove("hidden");
2371
2375
 
@@ -2379,18 +2383,21 @@ function closeUpdateSdkModal() {
2379
2383
  document.getElementById("updateSdkModal")?.classList.add("hidden");
2380
2384
  }
2381
2385
 
2382
- async function copyUpdateSdkPrompt() {
2386
+ async function copyUpdateSdkPrompt(which) {
2387
+ const isVercel = which === "vercel";
2383
2388
  const text =
2384
- document.getElementById("updateSdkPromptText")?.textContent?.trim() ||
2385
- UPDATE_SDK_PROMPT;
2389
+ document.getElementById(isVercel ? "updateSdkPromptVercel" : "updateSdkPromptReplit")
2390
+ ?.textContent?.trim() ||
2391
+ (isVercel ? UPDATE_SDK_PROMPT_VERCEL : UPDATE_SDK_PROMPT_REPLIT);
2392
+ const btnId = isVercel ? "copyUpdateSdkPromptVercelBtn" : "copyUpdateSdkPromptReplitBtn";
2386
2393
  try {
2387
2394
  await navigator.clipboard.writeText(text);
2388
- const btn = document.getElementById("copyUpdateSdkPromptBtn");
2395
+ const btn = document.getElementById(btnId);
2389
2396
  if (btn) {
2390
2397
  const prev = btn.textContent;
2391
2398
  btn.textContent = "Copied";
2392
2399
  setTimeout(() => {
2393
- btn.textContent = prev || "Copy prompt";
2400
+ btn.textContent = prev || (isVercel ? "Copy Vercel prompt" : "Copy Replit prompt");
2394
2401
  }, 1200);
2395
2402
  }
2396
2403
  } catch {
@@ -2679,8 +2686,11 @@ document.addEventListener("DOMContentLoaded", () => {
2679
2686
  el.addEventListener("click", closeUpdateSdkModal);
2680
2687
  });
2681
2688
  document
2682
- .getElementById("copyUpdateSdkPromptBtn")
2683
- ?.addEventListener("click", () => void copyUpdateSdkPrompt());
2689
+ .getElementById("copyUpdateSdkPromptReplitBtn")
2690
+ ?.addEventListener("click", () => void copyUpdateSdkPrompt("replit"));
2691
+ document
2692
+ .getElementById("copyUpdateSdkPromptVercelBtn")
2693
+ ?.addEventListener("click", () => void copyUpdateSdkPrompt("vercel"));
2684
2694
 
2685
2695
  document.getElementById("addAssetBtn")?.addEventListener("click", () => {
2686
2696
  if (uploadInProgress) return;
@@ -1034,6 +1034,14 @@ button.danger {
1034
1034
  color: #0a0908;
1035
1035
  }
1036
1036
 
1037
+ .update-sdk-prompt-label {
1038
+ margin: 0.85rem 0 0.35rem;
1039
+ font-size: 0.8rem;
1040
+ font-weight: 600;
1041
+ letter-spacing: 0.02em;
1042
+ color: #5d554d;
1043
+ }
1044
+
1037
1045
  .update-sdk-prompt {
1038
1046
  margin: 0;
1039
1047
  padding: 0.75rem 0.85rem;
@@ -1049,6 +1057,8 @@ button.danger {
1049
1057
 
1050
1058
  .update-sdk-modal-actions {
1051
1059
  justify-content: flex-end;
1060
+ flex-wrap: wrap;
1061
+ gap: 0.5rem;
1052
1062
  }
1053
1063
 
1054
1064
  .download-players-modal-card {
@@ -0,0 +1,19 @@
1
+ # Default: SQLite.
2
+ # TOMORROWOS_STORE=sqlite
3
+ # TOMORROWOS_DB_PATH=./data/tomorrowos.db
4
+
5
+ # Supabase/Postgres.
6
+ # On Replit use SUPABASE_URL — DATABASE_URL is often a reserved Secret.
7
+ # TOMORROWOS_STORE=supabase
8
+ # SUPABASE_URL=postgresql://postgres:[PASSWORD]@[HOST]:5432/postgres
9
+ # DATABASE_SSL=true
10
+ # DATABASE_URL=postgresql://... # optional fallback outside Replit
11
+
12
+ # Optional: upload media to Cloudinary instead of local / Object Storage.
13
+ # CLOUDINARY_CLOUD_NAME=
14
+ # CLOUDINARY_API_KEY=
15
+ # CLOUDINARY_API_SECRET=
16
+ # CLOUDINARY_FOLDER=tomorrowos
17
+
18
+ # Optional: override the default deterministic pairing-code secret.
19
+ # PAIRING_CODE_SECRET=
@@ -231,11 +231,15 @@
231
231
  <p class="hint">Current installed SDK version:</p>
232
232
  <p class="update-sdk-version" id="updateSdkVersionLabel">Loading…</p>
233
233
  <p class="hint">
234
- To upgrade on AI agent platforms (Replit, Vercel, etc.), paste this prompt into the Agent chat:
234
+ To upgrade on AI agent platforms, paste the matching prompt into the Agent chat:
235
235
  </p>
236
- <pre class="update-sdk-prompt" id="updateSdkPromptText">Follow @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
236
+ <p class="update-sdk-prompt-label">Replit</p>
237
+ <pre class="update-sdk-prompt" id="updateSdkPromptReplit">Follow NPM package @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
238
+ <p class="update-sdk-prompt-label">Vercel</p>
239
+ <pre class="update-sdk-prompt" id="updateSdkPromptVercel">Follow NPM package @tomorrowos/sdk VERCEL_UPGRADE.md to upgrade my CMS with the latest SDK.</pre>
237
240
  <div class="modal-actions update-sdk-modal-actions">
238
- <button type="button" id="copyUpdateSdkPromptBtn" class="primary">Copy prompt</button>
241
+ <button type="button" id="copyUpdateSdkPromptReplitBtn" class="primary">Copy Replit prompt</button>
242
+ <button type="button" id="copyUpdateSdkPromptVercelBtn" class="primary">Copy Vercel prompt</button>
239
243
  <button type="button" data-close-update-sdk-modal="1">Close</button>
240
244
  </div>
241
245
  </div>
@@ -33,8 +33,10 @@ let cachedSdkVersion = "";
33
33
  /** @type {number|null} CMS server boot time (ms) from GET /devices. */
34
34
  let serverStartedAtMs = null;
35
35
 
36
- const UPDATE_SDK_PROMPT =
37
- "Follow @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.";
36
+ const UPDATE_SDK_PROMPT_REPLIT =
37
+ "Follow NPM package @tomorrowos/sdk REPLIT_UPGRADE.md to upgrade my CMS with the latest SDK.";
38
+ const UPDATE_SDK_PROMPT_VERCEL =
39
+ "Follow NPM package @tomorrowos/sdk VERCEL_UPGRADE.md to upgrade my CMS with the latest SDK.";
38
40
  /** @type {ReturnType<typeof setTimeout>|null} */
39
41
  let reconnectGraceTimer = null;
40
42
  let uploadQueue = [];
@@ -2364,8 +2366,10 @@ function setUpdateSdkVersionLabel(version) {
2364
2366
 
2365
2367
  async function openUpdateSdkModal() {
2366
2368
  const modal = document.getElementById("updateSdkModal");
2367
- const promptEl = document.getElementById("updateSdkPromptText");
2368
- if (promptEl) promptEl.textContent = UPDATE_SDK_PROMPT;
2369
+ const replitEl = document.getElementById("updateSdkPromptReplit");
2370
+ const vercelEl = document.getElementById("updateSdkPromptVercel");
2371
+ if (replitEl) replitEl.textContent = UPDATE_SDK_PROMPT_REPLIT;
2372
+ if (vercelEl) vercelEl.textContent = UPDATE_SDK_PROMPT_VERCEL;
2369
2373
  setUpdateSdkVersionLabel(cachedSdkVersion || "Loading…");
2370
2374
  modal?.classList.remove("hidden");
2371
2375
 
@@ -2379,18 +2383,21 @@ function closeUpdateSdkModal() {
2379
2383
  document.getElementById("updateSdkModal")?.classList.add("hidden");
2380
2384
  }
2381
2385
 
2382
- async function copyUpdateSdkPrompt() {
2386
+ async function copyUpdateSdkPrompt(which) {
2387
+ const isVercel = which === "vercel";
2383
2388
  const text =
2384
- document.getElementById("updateSdkPromptText")?.textContent?.trim() ||
2385
- UPDATE_SDK_PROMPT;
2389
+ document.getElementById(isVercel ? "updateSdkPromptVercel" : "updateSdkPromptReplit")
2390
+ ?.textContent?.trim() ||
2391
+ (isVercel ? UPDATE_SDK_PROMPT_VERCEL : UPDATE_SDK_PROMPT_REPLIT);
2392
+ const btnId = isVercel ? "copyUpdateSdkPromptVercelBtn" : "copyUpdateSdkPromptReplitBtn";
2386
2393
  try {
2387
2394
  await navigator.clipboard.writeText(text);
2388
- const btn = document.getElementById("copyUpdateSdkPromptBtn");
2395
+ const btn = document.getElementById(btnId);
2389
2396
  if (btn) {
2390
2397
  const prev = btn.textContent;
2391
2398
  btn.textContent = "Copied";
2392
2399
  setTimeout(() => {
2393
- btn.textContent = prev || "Copy prompt";
2400
+ btn.textContent = prev || (isVercel ? "Copy Vercel prompt" : "Copy Replit prompt");
2394
2401
  }, 1200);
2395
2402
  }
2396
2403
  } catch {
@@ -2679,8 +2686,11 @@ document.addEventListener("DOMContentLoaded", () => {
2679
2686
  el.addEventListener("click", closeUpdateSdkModal);
2680
2687
  });
2681
2688
  document
2682
- .getElementById("copyUpdateSdkPromptBtn")
2683
- ?.addEventListener("click", () => void copyUpdateSdkPrompt());
2689
+ .getElementById("copyUpdateSdkPromptReplitBtn")
2690
+ ?.addEventListener("click", () => void copyUpdateSdkPrompt("replit"));
2691
+ document
2692
+ .getElementById("copyUpdateSdkPromptVercelBtn")
2693
+ ?.addEventListener("click", () => void copyUpdateSdkPrompt("vercel"));
2684
2694
 
2685
2695
  document.getElementById("addAssetBtn")?.addEventListener("click", () => {
2686
2696
  if (uploadInProgress) return;
@@ -1034,6 +1034,14 @@ button.danger {
1034
1034
  color: #0a0908;
1035
1035
  }
1036
1036
 
1037
+ .update-sdk-prompt-label {
1038
+ margin: 0.85rem 0 0.35rem;
1039
+ font-size: 0.8rem;
1040
+ font-weight: 600;
1041
+ letter-spacing: 0.02em;
1042
+ color: #5d554d;
1043
+ }
1044
+
1037
1045
  .update-sdk-prompt {
1038
1046
  margin: 0;
1039
1047
  padding: 0.75rem 0.85rem;
@@ -1049,6 +1057,8 @@ button.danger {
1049
1057
 
1050
1058
  .update-sdk-modal-actions {
1051
1059
  justify-content: flex-end;
1060
+ flex-wrap: wrap;
1061
+ gap: 0.5rem;
1052
1062
  }
1053
1063
 
1054
1064
  .download-players-modal-card {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "0.9.69",
3
+ "version": "0.9.71",
4
4
  "description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
5
5
  "private": true,
6
6
  "type": "module",
@@ -13,11 +13,10 @@
13
13
  "dev:next": "cd preview && next dev -p 3000",
14
14
  "dev:preview": "concurrently -k \"npm:dev:tomorrowos\" \"npm:dev:next\"",
15
15
  "start": "tsx server.ts",
16
- "build": "node -e \"process.exit(0)\"",
17
- "build-player": "tomorrowos build --platform tizen"
16
+ "build": "node -e \"process.exit(0)\""
18
17
  },
19
18
  "dependencies": {
20
- "@tomorrowos/sdk": "^0.9.69",
19
+ "@tomorrowos/sdk": "^0.9.71",
21
20
  "dotenv": "^17.2.3",
22
21
  "tsx": "^4.19.0"
23
22
  },
@@ -23,7 +23,6 @@
23
23
  }
24
24
  ]
25
25
  }
26
- ],
27
- "fallback": { "type": "brand" }
26
+ ]
28
27
  }
29
28
  }