@tomorrowos/sdk 0.9.4 → 0.9.5

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/REPLIT_SETUP.md CHANGED
@@ -12,7 +12,7 @@ When a human pastes a prompt like this, **read this file and start Question 1 im
12
12
  ```text
13
13
  Follow @tomorrowos/sdk REPLIT_SETUP.md and set up my TomorrowOS CMS.
14
14
  Ask only the questions listed in REPLIT_SETUP.md, in order. Do not use LLM_PROMPT.md.
15
- Artifact kind must be **web** (never **api**). Question 4 only updates **brand.json**.
15
+ Artifact kind must be **web** (never **api**). Question 3 only updates **brand.json**.
16
16
  After all setup questions are answered (including Cloudinary Secrets if you chose Cloudinary), configure and start — minimal verification only (Web app type + Preview at /). **Never test Supabase connection** — save `SUPABASE_URL` and move on. No Supabase or WebSocket tests.
17
17
  Do not skip steps.
18
18
  ```
@@ -58,21 +58,20 @@ Replit Agent must ask **only** the questions defined in **this file**, in **this
58
58
 
59
59
  | Step | Section | When |
60
60
  |------|---------|------|
61
- | 1 | **Question 1** — How many screens / devices? | Always |
62
- | 2 | **Question 2** — Supabase connection | Only if answer to Q1 is **> 5** |
63
- | 3 | **Question 3** — Media storage (+ Cloudinary Secrets if chosen) | Always (after Q1 or Q2) |
64
- | 4 | **Question 4** — Brand / TomorrowOS app look | Always last, before execution |
61
+ | 1 | **Question 1** — Supabase connection string | Always |
62
+ | 2 | **Question 2** — Media storage (+ Cloudinary Secrets if chosen) | Always (after Q1) |
63
+ | 3 | **Question 3** — Brand / TomorrowOS app look | Always last, before execution |
65
64
 
66
- **That is the complete list.** There are no other setup questions. There is **no** “Question 3b” — Cloudinary credentials are collected **inside Question 3**, immediately after the user chooses Cloudinary.
65
+ **That is the complete list.** There are no other setup questions. **Do not** ask how many screens / devices. There is **no** “Question 2b” — Cloudinary credentials are collected **inside Question 2**, immediately after the user chooses Cloudinary.
67
66
 
68
- **Critical:** Question 3 is **not complete** when the user says “Cloudinary” or “yes”. You **must** immediately show the Cloudinary Secrets input (same step — do **not** label a new question) and collect `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, and `CLOUDINARY_API_SECRET` **before** Question 4. Do **not** skip to branding with placeholder or invented credentials.
67
+ **Critical:** Question 2 is **not complete** when the user says “Cloudinary” or “yes”. You **must** immediately show the Cloudinary Secrets input (same step — do **not** label a new question) and collect `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, and `CLOUDINARY_API_SECRET` **before** Question 3. Do **not** skip to branding with placeholder or invented credentials.
69
68
 
70
69
 
71
- If the user volunteers extra info early (e.g. brand name before Q4), **record it** and still ask the current question’s required fields you do not yet have. Do not skip ahead to execution until Q1–Q4 are complete (Question 3 includes Cloudinary Secrets when applicable).
70
+ If the user volunteers extra info early (e.g. brand name before Q3), **record it** and still ask the current question’s required fields you do not yet have. Do not skip ahead to execution until Q1–Q3 are complete (Question 2 includes Cloudinary Secrets when applicable).
72
71
 
73
72
  If the user says “just set it up, don’t ask questions,” respond:
74
73
 
75
- > I need a few quick answers from REPLIT_SETUP.md (screen count, media storage — plus Cloudinary credentials if you choose Cloudinary — and branding). It takes about a minute and ensures the CMS deploys correctly on Replit.
74
+ > I need a few quick answers from REPLIT_SETUP.md (Supabase connection string, media storage — plus Cloudinary credentials if you choose Cloudinary — and branding). It takes about a minute and ensures the CMS deploys correctly on Replit.
76
75
 
77
76
  Then ask **Question 1** — do not switch to `LLM_PROMPT.md`.
78
77
 
@@ -80,9 +79,9 @@ Then ask **Question 1** — do not switch to `LLM_PROMPT.md`.
80
79
 
81
80
  ## Hard rules
82
81
 
83
- 1. **Ask only REPLIT_SETUP.md questions 1–4** (see **Questionnaire scope**). Never use `LLM_PROMPT.md` on Replit.
84
- 2. **One question at a time.** Wait for the user’s answer before asking the next question (unless they already answered several in one message). **Exception:** If the user chooses Cloudinary in Question 3, **stay on Question 3** and immediately show the Secrets form — do **not** open a separate “3b” step or announce a new question number.
85
- 3. **Do not invent** screen counts, Cloudinary credentials, Supabase URLs, or brand colours.
82
+ 1. **Ask only REPLIT_SETUP.md questions 1–3** (see **Questionnaire scope**). Never use `LLM_PROMPT.md` on Replit.
83
+ 2. **One question at a time.** Wait for the user’s answer before asking the next question (unless they already answered several in one message). **Exception:** If the user chooses Cloudinary in Question 2, **stay on Question 2** and immediately show the Secrets form — do **not** open a separate “2b” step or announce a new question number.
84
+ 3. **Do not invent** Cloudinary credentials, Supabase URLs, or brand colours. **Do not ask** screen / device count.
86
85
  4. **Do not use Replit’s reserved `DATABASE_URL` Secret for Supabase.** On Replit, `DATABASE_URL` is often pre-claimed. Always use **`SUPABASE_URL`** for TomorrowOS ↔ Supabase.
87
86
  5. **Prefer `npx @tomorrowos/sdk init`** (or the package’s `templates/cms-starter`) as the project seed. Do not rebuild pairing, WebSocket, or playlist APIs from scratch.
88
87
  6. **Never commit secrets** into git. Put credentials only in Replit **Secrets** (and optionally mirror non-secret flags in `.env` that reference env vars).
@@ -91,12 +90,11 @@ Then ask **Question 1** — do not switch to `LLM_PROMPT.md`.
91
90
  9. **Supabase: configure only — never test.** Save `SUPABASE_URL` + `TOMORROWOS_STORE=supabase` and proceed. **Do not** ping Postgres, run `psql`, start the server solely to verify DB connectivity, or treat log errors like `ENOTFOUND` / `database connection failure` in **Replit dev / Preview** as a failed setup. Supabase often works only after **Publish** (production networking), not in the dev shell.
92
91
  10. **Artifact kind = `web` only.** **`kind = "api"` is forbidden** for the TomorrowOS CMS artifact. See **IRON RULE** above. Setup is incomplete if Publish would still see an `api` artifact.
93
92
 
94
- **Question order after Q1:**
93
+ **Question order (always):**
95
94
 
96
- - If **≤ 5 screens:** Q1 → Q3Q4 → execution checklist
97
- - If **> 5 screens:** Q1 → Q2 → Q3 → Q4 → execution checklist
95
+ - Q1 → Q2Q3 → execution checklist
98
96
 
99
- Never insert extra questions between these steps. When the user chooses Cloudinary, **Question 3 continues** with the Secrets form immediately — then proceed to Q4 only after secrets are saved.
97
+ Never insert extra questions between these steps. When the user chooses Cloudinary, **Question 2 continues** with the Secrets form immediately — then proceed to Q3 only after secrets are saved.
100
98
 
101
99
  ---
102
100
 
@@ -232,7 +230,7 @@ Allowed extras (optional): `"build-player": "tomorrowos build --platform tizen"`
232
230
  "node": ">=20"
233
231
  },
234
232
  "dependencies": {
235
- "@tomorrowos/sdk": "^0.9.4",
233
+ "@tomorrowos/sdk": "^0.9.5",
236
234
  "dotenv": "^17.2.3",
237
235
  "tsx": "^4.19.0"
238
236
  },
@@ -330,13 +328,13 @@ Replace `YOUR-REPLIT-DOMAIN` with the actual published hostname (e.g. `my-cms.re
330
328
 
331
329
  ## Post-Q&A: minimal verification only
332
330
 
333
- After Questions 1–4, **configure → `npm install` → `npm run start` → done.**
331
+ After Questions 1–3, **configure → `npm install` → `npm run start` → done.**
334
332
 
335
333
  ### Supabase: never test in Replit dev (mandatory)
336
334
 
337
- When the user chose Supabase (>5 screens), setup is **save credentials + wire `server.ts` + start** — **nothing else**.
335
+ Setup always uses Supabase: **save credentials + wire `server.ts` + start** — **nothing else**.
338
336
 
339
- **Forbidden after Q&A (and after Question 2):**
337
+ **Forbidden after Q&A (and after Question 1):**
340
338
 
341
339
  - ❌ “Testing Supabase connection…”
342
340
  - ❌ `psql`, `pg`, Prisma `db pull`, or any one-off DB probe script
@@ -374,34 +372,17 @@ Then (and only then) check: API vs Web type → `.replit` ports/`deploymentTarge
374
372
 
375
373
  ---
376
374
 
377
- ## Question 1 — How many screens / devices?
375
+ ## Question 1 — Supabase connection (always)
378
376
 
379
- > **This is the first and only “screen count” question.** Do not re-ask later.
377
+ > **This is the first setup question.** Always configure Supabase. **Do not** ask how many screens / devices.
380
378
 
381
- **Ask exactly (copy wording; do not substitute LLM_PROMPT questions):**
382
-
383
- > How many TomorrowOS screens (devices) do you expect to manage with this CMS?
384
- >
385
- > - **5 or fewer** → I’ll use the default **SQLite** database (simple, good for demos and small venues).
386
- > - **More than 5** → I’ll configure **Supabase (Postgres)** so pairings and playlists scale more reliably.
387
-
388
- **Branching:**
389
-
390
- | Answer | Store driver | Next |
391
- |--------|--------------|------|
392
- | ≤ 5 | `TOMORROWOS_STORE=sqlite` | Skip Question 2 → go to Question 3 |
393
- | > 5 | `TOMORROWOS_STORE=supabase` | Ask Question 2 |
394
- | Unclear | Ask again | Do not proceed |
379
+ **Preferred on Replit:** open an **input / Secrets** UI where the user pastes the connection string into a field for:
395
380
 
396
- **Store in `brand.json`:** `cms.expectedScreens` (number), `cms.hostingTarget`: `"here"`.
381
+ - `SUPABASE_URL`
397
382
 
398
- ---
399
-
400
- ## Question 2 — Supabase connection (only if > 5 screens)
401
-
402
- **Ask exactly:**
383
+ **Ask exactly (copy wording; do not substitute LLM_PROMPT questions):**
403
384
 
404
- > Paste your Supabase Postgres connection string. I will store it as the Replit Secret **`SUPABASE_URL`** (not `DATABASE_URL` — that name is often reserved by Replit).
385
+ > Paste your Supabase Postgres connection string below. I will store it as the Replit Secret **`SUPABASE_URL`** (not `DATABASE_URL` — that name is often reserved by Replit).
405
386
  >
406
387
  > Example shape: `postgresql://postgres.[PROJECT]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres`
407
388
  >
@@ -449,13 +430,16 @@ DATABASE_SSL=true
449
430
  ```
450
431
 
451
432
  5. **Do not** write the real password into committed files.
452
- 6. **Do not** test the Supabase connection after saving the Secret — **configuration only**. No probe, no `npm run start` just to verify DB, no fixing “connection failure” in dev. Saving `SUPABASE_URL` completes Question 2.
433
+ 6. **Do not** test the Supabase connection after saving the Secret — **configuration only**. No probe, no `npm run start` just to verify DB, no fixing “connection failure” in dev. Saving `SUPABASE_URL` completes Question 1.
434
+ 7. **Do not** proceed to Question 2 until `SUPABASE_URL` is saved.
453
435
 
454
- If the user refuses Supabase but chose > 5 screens, warn them SQLite on Replit is fragile for fleets, then offer SQLite only after they confirm.
436
+ If the user refuses Supabase, warn that Replit fleets need a durable Postgres store, then offer SQLite only after they explicitly confirm.
437
+
438
+ **Store in `brand.json` later (Question 3):** `cms.hostingTarget`: `"here"`. Do **not** ask for `expectedScreens`; leave a default (e.g. `5`) when writing `brand.json`.
455
439
 
456
440
  ---
457
441
 
458
- ## Question 3 — Media storage (uploads / thumbnails)
442
+ ## Question 2 — Media storage (uploads / thumbnails)
459
443
 
460
444
  ### Step A — Ask storage choice
461
445
 
@@ -471,9 +455,9 @@ If the user refuses Supabase but chose > 5 screens, warn them SQLite on Replit i
471
455
  >
472
456
  > Do you want me to set up **Cloudinary**? (yes / no)
473
457
 
474
- ### Step B — If YES / Cloudinary (same Question 3 — no “3b”, no extra question)
458
+ ### Step B — If YES / Cloudinary (same Question 2 — no “2b”, no extra question)
475
459
 
476
- **Do this immediately** when the user chooses Cloudinary. **Do not** say “Question 3b”, “next step”, or “Great — I’ll use Cloudinary” as a separate message before the form. **Go straight to the Secrets input.**
460
+ **Do this immediately** when the user chooses Cloudinary. **Do not** say “Question 2b”, “next step”, or “Great — I’ll use Cloudinary” as a separate message before the form. **Go straight to the Secrets input.**
477
461
 
478
462
  **Preferred on Replit:** open the **Replit Secrets** UI with fields for:
479
463
 
@@ -497,10 +481,10 @@ If the user refuses Supabase but chose > 5 screens, warn them SQLite on Replit i
497
481
  1. Save Replit Secrets: `CLOUDINARY_CLOUD_NAME`, `CLOUDINARY_API_KEY`, `CLOUDINARY_API_SECRET` (and optional `CLOUDINARY_FOLDER`).
498
482
  2. **Do not** write real secrets into committed files.
499
483
  3. **Do not** invent or placeholder credentials.
500
- 4. **Do not** proceed to Question 4 until all three required Secrets exist.
484
+ 4. **Do not** proceed to Question 3 until all three required Secrets exist.
501
485
  5. **Do not** run a Cloudinary upload test — configuration only.
502
486
 
503
- **If the user does not have a Cloudinary account yet:** tell them to sign up at cloudinary.com and return with API keys. **Wait** on Question 3 — do not skip to Question 4.
487
+ **If the user does not have a Cloudinary account yet:** tell them to sign up at cloudinary.com and return with API keys. **Wait** on Question 2 — do not skip to Question 3.
504
488
 
505
489
  The SDK auto-detects these env vars and uploads media to Cloudinary. New uploads will return `https://res.cloudinary.com/...` URLs.
506
490
 
@@ -513,17 +497,15 @@ The SDK auto-detects these env vars and uploads media to Cloudinary. New uploads
513
497
  3. Warn: if Object Storage IAM denies `storage.objects.create`, uploads will fail with a Google Cloud Storage permission error — fix Object Storage permissions or switch to Cloudinary.
514
498
  4. Do **not** invent Cloudinary credentials.
515
499
 
516
- **Also persist metadata:** keep `data/tomorrowos.db` (SQLite path) on durable storage when using SQLite.
517
-
518
500
  ---
519
501
 
520
- ## Question 4 — Brand / TomorrowOS app look (`brand.json` only)
502
+ ## Question 3 — Brand / TomorrowOS app look (`brand.json` only)
521
503
 
522
- > **Scope:** Question 4 answers **only** update **`brand.json`** — colours, name, tagline, logo path, `cms.expectedScreens`, etc. They configure how the **TomorrowOS player app** looks and metadata flags.
504
+ > **Scope:** Question 3 answers **only** update **`brand.json`** — colours, name, tagline, logo path, etc. They configure how the **TomorrowOS player app** looks and metadata flags.
523
505
  >
524
- > **Question 4 does NOT affect:** Replit Publish, artifact `kind`, `.replit`, `server.ts`, Secrets, Supabase, Cloudinary, ports, deployment target, or CMS server wiring. **Never** change deploy/runtime config based on branding answers.
506
+ > **Question 3 does NOT affect:** Replit Publish, artifact `kind`, `.replit`, `server.ts`, Secrets, Supabase, Cloudinary, ports, deployment target, or CMS server wiring. **Never** change deploy/runtime config based on branding answers.
525
507
 
526
- > **This is the only branding / platform / use-case question block.** Do not ask separate LLM_PROMPT “target platform”, “use case”, or “hosting” questions before this.
508
+ > **This is the only branding / platform / use-case question block.** Do not ask separate LLM_PROMPT “target platform”, “use case”, or “hosting” questions before this. **Do not** ask screen count.
527
509
 
528
510
  **Ask exactly (one message; user may answer in one reply):**
529
511
 
@@ -568,7 +550,7 @@ If the user only gives a name and primary colour, use defaults for the rest and
568
550
  }
569
551
  ```
570
552
 
571
- Set `cms.expectedScreens` from Question 1 (do not ask screen count again). Always set `cms.hostingTarget` to `"here"` on Replit without asking. Set `cmsEndpoint` only if the user already knows their public `wss://…replit.app` URL; otherwise leave it out and tell them to pair TVs using the published HTTPS URL (player converts `https://` → `wss://`).
553
+ Do **not** ask for screen count. Keep a default `cms.expectedScreens` (e.g. `5`) unless the user already volunteered a number. Always set `cms.hostingTarget` to `"here"` on Replit without asking. Set `cmsEndpoint` only if the user already knows their public `wss://…replit.app` URL; otherwise leave it out and tell them to pair TVs using the published HTTPS URL (player converts `https://` → `wss://`).
572
554
 
573
555
  ---
574
556
 
@@ -593,14 +575,7 @@ If `init` is inappropriate (existing customised project), merge carefully:
593
575
 
594
576
  ### B. Apply store + media Secrets
595
577
 
596
- **SQLite (≤5):**
597
-
598
- ```env
599
- TOMORROWOS_STORE=sqlite
600
- TOMORROWOS_DB_PATH=./data/tomorrowos.db
601
- ```
602
-
603
- **Supabase (>5):**
578
+ **Supabase (always from Question 1):**
604
579
 
605
580
  ```env
606
581
  TOMORROWOS_STORE=supabase
@@ -669,8 +644,8 @@ Only investigate further if Preview is empty, server crashed, or user reports Pu
669
644
 
670
645
  ### Forbidden questionnaire sources
671
646
 
672
- - **`LLM_PROMPT.md`** — not used on Replit setup; its five questions are **replaced** by REPLIT_SETUP Questions 1–4
673
- - Standalone “target platform” / “hosting target” / “use case” prompts outside Question 4
647
+ - **`LLM_PROMPT.md`** — not used on Replit setup; its questions are **replaced** by REPLIT_SETUP Questions 1–3
648
+ - Standalone “target platform” / “hosting target” / “use case” / **screen count** prompts outside Question 3
674
649
 
675
650
  Do **not** ask the user how to implement:
676
651
 
@@ -685,24 +660,23 @@ Do **not**:
685
660
  - Change the production start command away from `tsx server.ts` / `npm run start`
686
661
  - Point Supabase at Replit’s reserved `DATABASE_URL` when `SUPABASE_URL` should be used
687
662
  - Skip Cloudinary recommendation without stating the persistence tradeoff
688
- - **Skip Cloudinary Secrets** after the user chooses Cloudinary — always collect `CLOUDINARY_*` inside Question 3 before Question 4
689
- - **Announce “Question 3b”** or a separate follow-up question — show the Secrets form immediately instead
663
+ - **Skip Cloudinary Secrets** after the user chooses Cloudinary — always collect `CLOUDINARY_*` inside Question 2 before Question 3
664
+ - **Announce “Question 2b”** or a separate follow-up question — show the Secrets form immediately instead
690
665
  - Claim uploads are “permanent” on Replit local disk without Object Storage or Cloudinary
691
666
  - Leave `tsx` only in `devDependencies` if the Deploy pipeline installs production deps only
692
667
  - Use Canvas preview as the primary CMS verification surface
693
668
  - Serve a different app or API-only response at `/` instead of the Control Panel
694
669
  - Create the Repl as **API-only** or publish with **Static Deployment** only
695
670
  - Set or leave artifact **`kind = "api"`** for the TomorrowOS CMS
696
- - Change `.replit`, `server.ts`, Secrets, or deployment config based on **Question 4** branding answers (those go in **`brand.json` only**)
671
+ - Change `.replit`, `server.ts`, Secrets, or deployment config based on **Question 3** branding answers (those go in **`brand.json` only**)
697
672
  - Omit `[[ports]]` / `deploymentTarget` from `.replit` when setting up for Publish
698
673
  - Run **Supabase connection tests**, **WebSocket console tests**, or other post-setup smoke tests unless Preview fails or the user asks
699
674
  - **Debug or “fix” Supabase** because dev logs show `getaddrinfo ENOTFOUND` or `database connection failure` — save config and finish setup instead
675
+ - Ask how many screens / devices (≤5 vs >5) — always start with Supabase
700
676
 
701
677
  ---
702
678
 
703
- ## SQLite path (≤5) — `server.ts` reference
704
-
705
- Default starter is fine:
679
+ ## SQLite fallback — `server.ts` reference (only if user refuses Supabase)
706
680
 
707
681
  ```ts
708
682
  const store = createTomorrowOSStore({
@@ -738,14 +712,16 @@ TOMORROWOS_STORE=sqlite
738
712
 
739
713
  ## Protocol version
740
714
 
741
- `replit-setup/1.7` — aligned with TomorrowOS protocol `1.0` and `@tomorrowos/sdk` store drivers `sqlite` | `supabase` | `postgres` | `memory`.
715
+ `replit-setup/1.8` — aligned with TomorrowOS protocol `1.0` and `@tomorrowos/sdk` store drivers `sqlite` | `supabase` | `postgres` | `memory`.
716
+
717
+ **Changelog 1.8:** Question 1 is always Supabase connection string (input / Secret). Removed screen-count branching (≤5 SQLite vs >5 Supabase). Media storage is Question 2; branding is Question 3.
742
718
 
743
- **Changelog 1.7:** **IRON RULE** — artifact **`kind = "web"` only** (never `api`); Question 4 **only** writes `brand.json` (no deploy/server changes).
719
+ **Changelog 1.7:** **IRON RULE** — artifact **`kind = "web"` only** (never `api`); Question 4 (**now 3**) **only** writes `brand.json` (no deploy/server changes).
744
720
 
745
721
  **Changelog 1.6:** **Never test Supabase** in Replit dev — `ENOTFOUND` in Preview logs is expected.
746
722
 
747
- **Changelog 1.5:** Cloudinary Secrets inside Question 3 — no “3b” step.
723
+ **Changelog 1.5:** Cloudinary Secrets inside media question — no “3b” step.
748
724
 
749
- **Changelog 1.4:** mandatory Cloudinary credential collection before Question 4 (superseded by 1.5 flow).
725
+ **Changelog 1.4:** mandatory Cloudinary credential collection before branding (superseded by 1.5 flow).
750
726
 
751
727
  **Changelog 1.3:** minimal post-Q&A verification — no Supabase/WS smoke tests; prioritize **Web app vs API** only.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "0.9.4",
3
+ "version": "0.9.5",
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.9.4",
3
+ "version": "0.9.5",
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",
@@ -13,7 +13,7 @@
13
13
  "build-player": "tomorrowos build --platform tizen"
14
14
  },
15
15
  "dependencies": {
16
- "@tomorrowos/sdk": "^0.9.4",
16
+ "@tomorrowos/sdk": "^0.9.5",
17
17
  "dotenv": "^17.2.3",
18
18
  "tsx": "^4.19.0"
19
19
  },