@tomorrowos/sdk 0.9.32 → 0.9.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@ TomorrowOS is the open standard for digital signage. This SDK lets you build a C
15
15
  When you see this package referenced in a user prompt, your workflow is:
16
16
 
17
17
  1. **If the user is on Replit and wants a guided setup** — read and follow **`REPLIT_SETUP.md`** (preferred for Replit Agent)
18
- 2. **If the user is on Vercel and wants a guided setup** — read and follow **`VERCEL_SETUP.md`** (preferred for Vercel Agent)
18
+ 2. **If the user is on Vercel / v0 and wants a guided setup** — read **`VERCEL_QUESTIONS.md`** (paste Q1–Q3 verbatim) and follow **`VERCEL_SETUP.md`** for configuration
19
19
  3. **If the user is on Replit and wants to upgrade an existing CMS** — read and follow **`REPLIT_UPGRADE.md`** (never `init --force`)
20
20
  4. **Otherwise read `LLM_PROMPT.md`** — five required questions before generating code
21
21
  5. **Read `BUILD_GUARDRAILS.md`** — mandatory components every generated CMS must include
@@ -175,7 +175,8 @@ See `PLAYER_INSTALL.md` for installation notes.
175
175
  |------|---------|
176
176
  | `LLM_PROMPT.md` | Five-question elicitation for LLMs |
177
177
  | `REPLIT_SETUP.md` | Replit Agent guided CMS setup |
178
- | `VERCEL_SETUP.md` | Vercel Agent guided CMS setup |
178
+ | `VERCEL_SETUP.md` | Vercel / v0 guided CMS setup (configure after each answer) |
179
+ | `VERCEL_QUESTIONS.md` | Verbatim Q1–Q3 text Agents must paste (do not paraphrase) |
179
180
  | `REPLIT_UPGRADE.md` | Replit Agent upgrade to latest SDK (no init) |
180
181
  | `BUILD_GUARDRAILS.md` | Mandatory CMS components |
181
182
  | `PLAYER_INSTALL.md` | Player build / install / pairing |
@@ -0,0 +1,70 @@
1
+ # Vercel / v0 — Verbatim question bank
2
+
3
+ > **Protocol:** `vercel-questions/1.0` (pairs with `VERCEL_SETUP.md` 1.9+ / `@tomorrowos/sdk` 0.9.34+)
4
+ > **For Agents:** When asking the user a setup question, **copy-paste the block below for that step EXACTLY**.
5
+ > Do **not** paraphrase, reorder, rename options, or invent alternatives (no S3, no Supabase Storage, no “Blob recommended”, no “disable media”).
6
+ > After each answer, configure per `VERCEL_SETUP.md`, then paste the **next** block.
7
+
8
+ ---
9
+
10
+ ## Q1 — Database (paste this entire block)
11
+
12
+ Which database should TomorrowOS use on Vercel?
13
+
14
+ **1. Supabase Postgres (recommended)** — durable pairing/playlists; use the **Session pooler** URL (`*.pooler.supabase.com:6543`).
15
+
16
+ **2. Neon Postgres** — serverless Postgres native to Vercel; use Neon’s **pooled** connection string from the Neon dashboard (not the direct un-pooled host for serverless).
17
+
18
+ **3. SQLite (`data/tomorrowos.db`)** — **demo / local only on Vercel.** The filesystem is ephemeral; pairings and playlists will not survive redeploys. Only choose this if you understand the limitation.
19
+
20
+ Reply with **1**, **2**, or **3** (or “Supabase” / “Neon” / “SQLite”).
21
+
22
+ ---
23
+
24
+ ## After Q1 — agent only (do not ask the user)
25
+
26
+ | Choice | You set silently | User only provides |
27
+ |--------|------------------|--------------------|
28
+ | 1 Supabase | `TOMORROWOS_STORE=supabase`, `DATABASE_SSL=true` | `SUPABASE_URL` (pooler) |
29
+ | 2 Neon | `TOMORROWOS_STORE=postgres`, `DATABASE_SSL=true` | `DATABASE_URL` (pooled) |
30
+ | 3 SQLite | `TOMORROWOS_STORE=sqlite` | confirmation |
31
+
32
+ Never show blank Env fields for `TOMORROWOS_STORE` or `DATABASE_SSL`.
33
+
34
+ ---
35
+
36
+ ## Q2 — Media (paste this entire block)
37
+
38
+ How should playlist media (images/videos) be stored?
39
+
40
+ **1. Cloudinary (recommended)** — durable public HTTPS URLs (`https://res.cloudinary.com/...`). Works out of the box with `@tomorrowos/sdk` auto-detection. **Prefer this on Vercel.**
41
+
42
+ **2. Vercel Blob** — Vercel-native object storage; durable `https://*.public.blob.vercel-storage.com/...` URLs. Use when you want media on the same Vercel project without a Cloudinary account.
43
+
44
+ **3. Local disk only** — `cms-panel/uploads` or `public/uploads` (OK for quick local tests; **not** for production Vercel fleets — files are ephemeral).
45
+
46
+ Reply with **1**, **2**, or **3** (or “Cloudinary” / “Vercel Blob” / “local”).
47
+
48
+ **Forbidden replacements (never ask these):** Vercel Blob as recommended #1; Supabase Storage; S3 / R2 / B2 / `MEDIA_S3_*`; “no media storage” / disable uploads.
49
+
50
+ ---
51
+
52
+ ## Q3 — Brand (paste this entire block)
53
+
54
+ Let’s brand your TomorrowOS experience. Choose **one**:
55
+
56
+ **Option A — Website URL (recommended if you have a site)**
57
+ Paste **one public website URL**. I will use it **only** to fill **`brand.json`**: product name, tagline, primary / secondary / **background** / text colours, fonts, and logo.
58
+ I will **not** rebuild that website or add login — unless you explicitly ask for login/auth later.
59
+
60
+ **Option B — Manual brand fields**
61
+ Send as many of these as you can (name + at least one colour + logo is ideal):
62
+ 1. **Product / venue name** (required)
63
+ 2. **Tagline** (optional)
64
+ 3. **Primary colour** (hex, e.g. `#FF8A3D`)
65
+ 4. **Background colour** (hex — page / panel background)
66
+ 5. **Text colour** (hex, optional — default `#0A0908`)
67
+ 6. **Secondary / accent colour** (hex, optional)
68
+ 7. **Logo** — upload SVG/PNG into the project, or a public image URL I can fetch into `./assets/`
69
+
70
+ Reply with a URL **or** the manual fields. Do not send only a name with no colours/logo unless you want defaults (I will confirm defaults before writing).
package/VERCEL_SETUP.md CHANGED
@@ -5,7 +5,28 @@
5
5
  >
6
6
  > **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`, not `LLM_PROMPT.md`).
7
7
  >
8
- > Protocol id: `vercel-setup/1.8` — pairs with `@tomorrowos/sdk` **0.9.32+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
8
+ > Protocol id: `vercel-setup/1.9` — pairs with `@tomorrowos/sdk` **0.9.34+** (`templates/cms-starter-v0`, Fluid Functions WebSockets).
9
+ >
10
+ > **Questions source of truth:** `VERCEL_QUESTIONS.md` — Agents must **open that file and paste each Q block verbatim**. Do not paraphrase.
11
+ > **Copy questions verbatim from `VERCEL_QUESTIONS.md`.** Do not invent alternate Q2 options (no “Supabase Storage”, no S3, no “disable media”, no making Blob the recommended option).
12
+ > **`TOMORROWOS_STORE` and `DATABASE_SSL` are agent-only** — set them automatically after Q1; never put them in a user-facing Env form for the customer to type.
13
+
14
+ ## NON-NEGOTIABLE VERCEL RUNTIME CONTRACT
15
+
16
+ The following rules are **mandatory acceptance criteria**, not suggestions. The Agent must preserve them throughout setup, Preview, Publish, fixes, and upgrades:
17
+
18
+ 1. **One TomorrowOS instance only.** Use the shared instance exported through `api/index.ts`. **Never create a second `TomorrowOS` instance in `api/ws.ts`** or any other route.
19
+ 2. **Never use `public/` as the Vercel Output Directory.** The dashboard Output Directory must be **empty / unset**. Serve the Control Panel at runtime from `cms-panel/` through TomorrowOS `staticRoot`.
20
+ 3. **Preview may use Next only as an isolated reverse-proxy shell under `preview/`.** Preview must not replace TomorrowOS or determine the Production runtime.
21
+ 4. **Publish must use the Fluid Function.** Production must run `api/index.ts` → the shared exported `http.Server`, with Fluid compute enabled. It must not use `next start`, a static export, or a bare `(req, res)` handler.
22
+ 5. **After every Production deployment, verify all three gates before saying setup is complete:**
23
+ - `GET /status` returns TomorrowOS **JSON**, not HTML.
24
+ - `GET /` returns the TomorrowOS **Control Panel**.
25
+ - WebSocket upgrade on `/` or `/api` returns **`101 Switching Protocols`**, not `200` HTML.
26
+ 6. **Pair devices only against the Production URL.** Do not instruct users to pair against v0 Preview or a local/internal URL.
27
+ 7. If any gate fails, **fix and redeploy**. Never describe a deployment as successful based only on the Control Panel loading.
28
+
29
+ These rules override any platform-generated recommendation that conflicts with them.
9
30
 
10
31
  ## User trigger (copy-paste)
11
32
 
@@ -13,15 +34,11 @@ When a human pastes a prompt like this, **read this file and start Question 1 im
13
34
 
14
35
  ```text
15
36
  Follow @tomorrowos/sdk VERCEL_SETUP.md and set up my TomorrowOS CMS.
16
- Ask only the questions listed in VERCEL_SETUP.md, in order. Do not use LLM_PROMPT.md or REPLIT_SETUP.md.
17
- Do not ask for OpenAI / Anthropic / any LLM API keys TomorrowOS CMS setup does not require them.
18
- If any step contradicts Vercel, adapt to settings Vercel can accept (document the adaptation).
19
- After all setup questions are answered (including Cloudinary or Vercel Blob Env Vars if you chose those), configure and deploy — minimal verification only (Control Panel at /). Prefer Supabase Session pooler URL or Neon pooled URL. Do not treat sandbox ENETUNREACH / IPv6 :5432 errors as a hard setup failure when a pooler URL is configured for production.
20
- Question 3 only updates brand.json from colours/logo/name (a website URL is brand reference only do not add CMS login/auth unless the user explicitly asks). Do not skip steps.
21
- Use Next.js only as a v0/Preview shell with a reverse proxy; Production Publish must remain pure Node TomorrowOS.listen (not Next).
22
- Before claiming Publish works: Framework Preset must be Other/null (not Next.js), Fluid on, GET /status on the production URL must return JSON (not HTML), GET / must return the Control Panel, and WebSocket upgrade on / or /api must return 101 (not 200 HTML).
23
- Do not put startCommand or processes in vercel.json (v0 schema rejects them).
24
- Use cms-starter-v0 layout: cms-app.ts + api/index.ts (export default server) + cms-panel/ + rewrites to /api. Do not create a second TomorrowOS instance in api/ws.ts.
37
+ First open VERCEL_QUESTIONS.md. For Q1, Q2, Q3: paste each question block VERBATIM (character-for-character). Do not rephrase options.
38
+ Q2 must show Cloudinary (recommended) as option 1never Blob-as-recommended, never S3, never Supabase Storage.
39
+ After database choice, YOU set TOMORROWOS_STORE and DATABASE_SSL do not ask me to fill those.
40
+ Do not use LLM_PROMPT.md or REPLIT_SETUP.md. No OpenAI/LLM API keys.
41
+ Apply the NON-NEGOTIABLE VERCEL RUNTIME CONTRACT exactly: one TomorrowOS instance; no public/ Output Directory; Preview Next only under preview/; Publish through the Fluid Function; verify /status JSON, / Control Panel, and WebSocket 101; pair devices only with the Production URL.
25
42
  ```
26
43
 
27
44
  Alternate triggers:
@@ -128,30 +145,43 @@ v0 Preview is often a **Next.js runtime** hardwired to `next dev`. A raw `tsx se
128
145
 
129
146
  ## Questionnaire scope (STRICT)
130
147
 
131
- Ask **only** these questions, in **this exact order**:
148
+ Ask **only** these questions, in **this exact order**. **Copy the “Ask exactly” blocks verbatim** — do not paraphrase options.
132
149
 
133
150
  | Step | Section | When |
134
151
  |------|---------|------|
135
152
  | 1 | **Question 1** — Database (Supabase → Neon → SQLite) | Always |
136
- | 2 | **Question 2** — Media storage (Cloudinary → Vercel Blob → local) | Always (after Q1) |
153
+ | 2 | **Question 2** — Media (**Cloudinary recommended** → Vercel Blob → local) | Always (after Q1) |
137
154
  | 3 | **Question 3** — Brand / TomorrowOS look (`brand.json` only) | Always last |
138
155
 
139
156
  **That is the complete list.** Do **not** ask how many screens / devices.
140
157
 
158
+ **Forbidden invented Question 2 options (never offer these in chat or UI):**
159
+
160
+ - ❌ “Vercel Blob **(recommended)**” as option 1 — Blob is option **2**, not recommended over Cloudinary
161
+ - ❌ “Supabase Storage” / S3 bucket / `SUPABASE_SERVICE_ROLE_KEY` for media
162
+ - ❌ “No media storage” / “disable media uploads” / “remote URLs only” as a numbered choice
163
+ - ❌ Any media list that does not start with **Cloudinary (recommended)**
164
+
165
+ **Forbidden Env UX after Question 1:**
166
+
167
+ - ❌ Showing the user empty fields for `TOMORROWOS_STORE` or `DATABASE_SSL` to fill
168
+ - ❌ Asking in chat “what should TOMORROWOS_STORE be?”
169
+ - ✅ After DB choice + URL paste: **you** write those two vars silently (see Q1 Steps B/C/D)
170
+
141
171
  **Forbidden extra questions (never ask, even if the user skips a step):**
142
172
 
143
173
  - ❌ OpenAI / Anthropic / Gemini / any LLM API key (`sk-…`, etc.)
144
174
  - ❌ “AI pairing”, “AI feature logic”, or inventing auth that needs an LLM key
145
- - ❌ Asking the user to type `TOMORROWOS_STORE` or `DATABASE_SSL` after they already chose Neon/Supabase — **you set those automatically**
175
+ - ❌ Asking the user to type `TOMORROWOS_STORE` or `DATABASE_SSL`
146
176
  - ❌ Any secret not listed in Questions 1–3 (DB URL, media credentials, brand)
147
177
 
148
178
  TomorrowOS pairing and Control Panel logic live in `@tomorrowos/sdk`. They do **not** call OpenAI.
149
179
 
150
- If the user **skips** a Question 2 option, do **not** invent a substitute question. Re-state Question 2 choices, or proceed with a documented default (e.g. local uploads with a warning) — never pivot to LLM keys.
180
+ If the user **skips** a Question 2 option, do **not** invent a substitute question. Re-state Question 2 choices **verbatim**, or proceed with local uploads + warning — never pivot to LLM keys or Supabase Storage.
151
181
 
152
182
  If the user says “just set it up, don’t ask questions,” respond:
153
183
 
154
- > I need a few quick answers from VERCEL_SETUP.md (database — Supabase or Neon preferred — media storage, and branding). It takes about a minute and ensures the CMS works on Vercel.
184
+ > I need a few quick answers from VERCEL_SETUP.md (database — Supabase or Neon preferred — media storage with Cloudinary recommended, and branding). It takes about a minute and ensures the CMS works on Vercel.
155
185
 
156
186
  Then ask **Question 1**.
157
187
 
@@ -159,26 +189,26 @@ Then ask **Question 1**.
159
189
 
160
190
  ## Hard rules
161
191
 
162
- 1. **Ask only VERCEL_SETUP.md questions 1–3.** Never use `LLM_PROMPT.md` or `REPLIT_SETUP.md` as the questionnaire. **Never** ask for OpenAI or other LLM API keys.
163
- 2. **Cloudinary:** open **one** Vercel Env configuration popup / form with **all** Cloudinary fields together (cloud name + API key + API secret). Do **not** quiz the user one credential at a time in chat.
164
- 3. **Do not invent** Cloudinary credentials, database URLs, Vercel Blob tokens, brand colours, **or LLM API keys**.
165
- 4. **Postgres env naming:** prefer **`SUPABASE_URL`** when using Supabase; prefer **`DATABASE_URL`** when using Neon. `createTomorrowOSStore` accepts `SUPABASE_URL` then `DATABASE_URL`.
166
- 5. **Always prefer pooled connection strings** (Supabase Session pooler port **6543**; Neon pooled host). Direct `:5432` URLs commonly fail on Vercel/sandbox with **`ENETUNREACH`** (often IPv6).
167
- 6. **Prefer `npx @tomorrowos/sdk init --hosting v0`** (template `cms-starter-v0`: `cms-app.ts`, `api/index.ts`, `cms-panel/`, Fluid + rewrites). For Replit/Railway use default `init` (`cms-starter`). Do not rebuild pairing / WebSocket / playlist APIs.
168
- 7. **Never commit secrets.** Use Vercel Environment Variables (+ optional non-secret flags in committed `.env.example`).
169
- 8. **Skip Replit-only files:** do **not** create `.replit`, `.replit-artifact`, or Replit `deploymentTarget`.
170
- 9. **SQLite is not a production store on Vercel.** Offer it only as option **3** after explicit warning. Keep `sqlitePath` as local-dev fallback in `createTomorrowOSStore`.
171
- 10. **Enable Fluid compute** for Production WebSockets ([docs](https://vercel.com/docs/functions/websockets)). Confirm Project settings after scaffold.
172
- 11. **Production:** one Vercel Function exports `http.Server` from `TomorrowOS.listen` (`api/index.ts`). **Do not** make `next start` the Production entrypoint. **Do not** spin a second TomorrowOS in `api/ws.ts`.
173
- 12. **Preview:** if the environment is v0 / Next-hardwired, install the Next reverse-proxy shell (see **Preview adapter**). Do not leave Preview broken.
174
- 13. After Q&A: **configure → install → run/deploy minimal verify** (Control Panel at `/` + WS 101). Do not run a long test suite.
175
- 14. **No inventing CMS login.** A branding URL never means “build auth.” Only add login if the user **explicitly** requests it.
176
- 15. **Skip invent.** If the user skips media choice or a credential, do not replace it with OpenAI/auth/login questions. Stay on Q1–Q3 only.
177
- 16. **Neon / Supabase helpers are agent-owned.** After the user pastes the DB URL, **you** set `TOMORROWOS_STORE` and `DATABASE_SSL` automatically — **do not** ask the user to fill those two.
178
- 17. **Publish gate:** do not mark setup complete while Production returns `404: NOT_FOUND`, `/status` returns HTML, **or** WebSocket upgrade returns 200 HTML instead of 101.
179
- 18. **Scheme A is doc-driven:** Production = Fluid Function + `export default server` per Vercel WebSockets docs — Replit starter stays unchanged.
180
-
181
- **Question order:** Q1 → Q2 → Q3 → execution checklist.
192
+ 1. **Open `VERCEL_QUESTIONS.md` first.** Paste Q1 → configure → paste Q2 → configure → paste Q3. Never paraphrase question options. Never use `LLM_PROMPT.md` or `REPLIT_SETUP.md` as the questionnaire. **Never** ask for OpenAI or other LLM API keys.
193
+ 2. **Question 2 options are fixed:** (1) Cloudinary **(recommended)**, (2) Vercel Blob, (3) local disk. Do not reorder; do not invent Supabase Storage / disable-uploads.
194
+ 3. **Cloudinary:** open **one** Vercel Env popup with **all** Cloudinary fields together. Do **not** quiz one credential at a time.
195
+ 4. **`TOMORROWOS_STORE` + `DATABASE_SSL` = agent-owned.** After Q1 choice (and URL if needed), set them yourself in Vercel Env Vars. **Never** include them as blank fields for the customer. Mapping: Supabase `TOMORROWOS_STORE=supabase` + `DATABASE_SSL=true`; Neon `TOMORROWOS_STORE=postgres` + `DATABASE_SSL=true`; SQLite → `TOMORROWOS_STORE=sqlite` (no `DATABASE_SSL` required).
196
+ 5. **Do not invent** Cloudinary credentials, database URLs, Vercel Blob tokens, brand colours, **or LLM API keys**.
197
+ 6. **Postgres env naming:** prefer **`SUPABASE_URL`** for Supabase; prefer **`DATABASE_URL`** for Neon.
198
+ 7. **Always prefer pooled connection strings** (Supabase Session pooler **6543**; Neon pooled host).
199
+ 8. **Prefer `npx @tomorrowos/sdk init --hosting v0`**. For Replit/Railway use default `init`. Do not rebuild pairing / WebSocket APIs.
200
+ 9. **Never commit secrets.** Use Vercel Environment Variables.
201
+ 10. **Skip Replit-only files.**
202
+ 11. **SQLite is not a production store on Vercel.**
203
+ 12. **Enable Fluid compute** for Production WebSockets.
204
+ 13. **Production:** `api/index.ts` exports `http.Server` from `TomorrowOS.listen`. Not `next start`. No second TomorrowOS in `api/ws.ts`.
205
+ 14. **Preview:** Next reverse-proxy shell when v0 is Next-hardwired.
206
+ 15. After Q&A: **configure install deploy minimal verify**.
207
+ 16. **No inventing CMS login** from a branding URL.
208
+ 17. **Skip invent.** Stay on Q1–Q3 only.
209
+ 18. **Publish gate:** `/status` JSON + WebSocket 101; no static `public/` trap.
210
+
211
+ **Question order:** Q1 → (auto-set store env) → Q2 → Q3 → execution checklist.
182
212
 
183
213
  ---
184
214
 
@@ -554,7 +584,18 @@ If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a s
554
584
 
555
585
  ## Question 1 — Database (always)
556
586
 
557
- > **Do not** ask screen counts. Present all three options; recommend **Supabase** for Vercel fleets.
587
+ > **Do not** ask screen counts. Present all three options; recommend **Supabase** for Vercel fleets.
588
+ > **After the user picks a database:** collect the URL if needed, then **you** set `TOMORROWOS_STORE` + `DATABASE_SSL` (see mapping below). The customer must **never** be asked to type those two names or values.
589
+
590
+ ### Agent-owned env mapping (mandatory)
591
+
592
+ | User chose | You set (silently) | User only provides |
593
+ |------------|--------------------|--------------------|
594
+ | 1 Supabase | `TOMORROWOS_STORE=supabase`, `DATABASE_SSL=true` | `SUPABASE_URL` (pooler string) |
595
+ | 2 Neon | `TOMORROWOS_STORE=postgres`, `DATABASE_SSL=true` | `DATABASE_URL` (pooled string) |
596
+ | 3 SQLite | `TOMORROWOS_STORE=sqlite` | Confirmation only |
597
+
598
+ If you open an Env configuration UI for Q1, fields visible to the user may include **only** `SUPABASE_URL` or `DATABASE_URL`. **Do not** show blank `TOMORROWOS_STORE` / `DATABASE_SSL` inputs — write those yourself in the same step.
558
599
 
559
600
  ### Step A — Ask storage choice
560
601
 
@@ -572,9 +613,9 @@ If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a s
572
613
 
573
614
  ### Step B — If **1 / Supabase**
574
615
 
575
- **Ask exactly (connection string only):**
616
+ **Ask exactly (connection string only — not TOMORROWOS_STORE / DATABASE_SSL):**
576
617
 
577
- > Paste your Supabase Postgres connection string. I will store it as **`SUPABASE_URL`**.
618
+ > Paste your Supabase Postgres connection string. I will store it as **`SUPABASE_URL`**. I will set **`TOMORROWOS_STORE`** and **`DATABASE_SSL`** for you automatically.
578
619
  >
579
620
  > In Supabase: **Project Settings → Database → Connection string → Connection pooling** (Session mode).
580
621
  > Preferred shape:
@@ -582,36 +623,36 @@ If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a s
582
623
  >
583
624
  > **Do not** use the direct host `db.*.supabase.co:5432` for Vercel.
584
625
 
585
- **You must then (automatic — do NOT ask the user to type these):**
626
+ **You must then (automatic — do NOT ask the user to type store/ssl vars):**
586
627
 
587
- 1. Set Vercel Env Vars:
588
- - `SUPABASE_URL=<user pooler string>`
589
- - `TOMORROWOS_STORE=supabase` ← **agent sets this**
590
- - `DATABASE_SSL=true` ← **agent sets this** (unless user already said SSL is off)
591
- 2. Wire `server.ts` as in **Runtime & Vercel deploy rules**.
628
+ 1. Set Vercel Env Vars in one step:
629
+ - `SUPABASE_URL=<user pooler string>` ← from user
630
+ - `TOMORROWOS_STORE=supabase` ← **you set; never ask**
631
+ - `DATABASE_SSL=true` ← **you set; never ask**
632
+ 2. Wire `cms-app.ts` / `server.ts` store as in **Runtime & Vercel deploy rules**.
592
633
  3. Optional committed `.env.example` with **placeholders only**.
593
634
  4. **Do not** commit the real connection string.
594
- 5. **Do not** open a second form asking for `TOMORROWOS_STORE` or `DATABASE_SSL`.
635
+ 5. **Do not** open a form whose blank fields include `TOMORROWOS_STORE` or `DATABASE_SSL`.
595
636
 
596
637
  ### Step C — If **2 / Neon**
597
638
 
598
639
  **Ask exactly (connection string only):**
599
640
 
600
- > Paste your **Neon pooled** Postgres connection string. I will store it as **`DATABASE_URL`**.
641
+ > Paste your **Neon pooled** Postgres connection string. I will store it as **`DATABASE_URL`**. I will set **`TOMORROWOS_STORE`** and **`DATABASE_SSL`** for you automatically.
601
642
  >
602
643
  > In Neon: **Dashboard → Connection details → Pooled connection**.
603
644
  > Typical shape:
604
645
  > `postgresql://[user]:[password]@[endpoint]-pooler.[region].aws.neon.tech/[dbname]?sslmode=require`
605
646
 
606
- **You must then (automatic — do NOT ask the user to type these):**
647
+ **You must then (automatic):**
607
648
 
608
649
  1. Set Vercel Env Vars:
609
- - `DATABASE_URL=<user pooled string>`
610
- - `TOMORROWOS_STORE=postgres` ← **agent sets this**
611
- - `DATABASE_SSL=true` ← **agent sets this**
612
- 2. Wire `server.ts` — `createTomorrowOSStore` uses `PostgresStore` for `postgres` / `supabase` drivers.
650
+ - `DATABASE_URL=<user pooled string>` ← from user
651
+ - `TOMORROWOS_STORE=postgres` ← **you set; never ask**
652
+ - `DATABASE_SSL=true` ← **you set; never ask**
653
+ 2. Wire `createTomorrowOSStore` for Postgres.
613
654
  3. **Do not** commit the real connection string.
614
- 4. **Do not** ask the user to fill `TOMORROWOS_STORE` or `DATABASE_SSL` in chat or in an Env popup. Those are derived from choosing Neon.
655
+ 4. **Do not** ask the user to fill `TOMORROWOS_STORE` or `DATABASE_SSL` in chat or Env UI.
615
656
  5. If you see `ENETUNREACH` on `:5432`, switch to Neon’s **pooled** URL.
616
657
 
617
658
  ### Step D — If **3 / SQLite**
@@ -625,7 +666,7 @@ Only proceed after the user explicitly confirms.
625
666
  **You must then (automatic):**
626
667
 
627
668
  1. Set `TOMORROWOS_STORE=sqlite` yourself (do not ask the user to type it).
628
- 2. Keep `sqlitePath` in `server.ts` for `data/tomorrowos.db`.
669
+ 2. Keep `sqlitePath` for `data/tomorrowos.db`.
629
670
  3. Warn again in the final summary that they should move to Supabase or Neon for real devices.
630
671
 
631
672
  **Later in Question 3:** set `cms.hostingTarget` to **`"vercel"`** (all Q1 branches).
@@ -635,22 +676,25 @@ Only proceed after the user explicitly confirms.
635
676
  ## Question 2 — Media storage
636
677
 
637
678
  > **This question is only about media files (images/videos).**
638
- > It is **not** about OpenAI, AI pairing, or LLM keys. If you are about to ask for an `sk-` key, **stop** — you are off-protocol.
679
+ > It is **not** about OpenAI, AI pairing, or LLM keys. If you are about to ask for an `sk-` key, **stop** — you are off-protocol.
680
+ > **Copy the three options below verbatim.** Wrong examples that must **never** appear: “Vercel Blob (recommended)”, “Supabase Storage”, “No media storage / disable uploads”.
639
681
 
640
682
  ### Step A — Ask storage choice
641
683
 
642
- **Ask exactly:**
684
+ **Ask exactly (wording must match — Cloudinary is recommended):**
643
685
 
644
686
  > How should playlist media (images/videos) be stored?
645
687
  >
646
- > **1. Cloudinary (recommended)** — durable public HTTPS URLs (`https://res.cloudinary.com/...`). Works out of the box with `@tomorrowos/sdk` auto-detection.
688
+ > **1. Cloudinary (recommended)** — durable public HTTPS URLs (`https://res.cloudinary.com/...`). Works out of the box with `@tomorrowos/sdk` auto-detection. **Prefer this on Vercel.**
647
689
  >
648
- > **2. Vercel Blob** — Vercel-native object storage; durable `https://*.public.blob.vercel-storage.com/...` URLs. Good when you want media on the same Vercel project without a Cloudinary account.
690
+ > **2. Vercel Blob** — Vercel-native object storage; durable `https://*.public.blob.vercel-storage.com/...` URLs. Use when you want media on the same Vercel project without a Cloudinary account.
649
691
  >
650
- > **3. Local disk only** — `public/uploads` (OK for quick local tests; **not** for production Vercel fleets — files are ephemeral).
692
+ > **3. Local disk only** — `cms-panel/uploads` or `public/uploads` (OK for quick local tests; **not** for production Vercel fleets — files are ephemeral).
651
693
  >
652
694
  > Reply with **1**, **2**, or **3** (or “Cloudinary” / “Vercel Blob” / “local”).
653
695
 
696
+ If you catch yourself about to offer Blob-as-recommended, Supabase Storage, or “no media”, **stop and paste the block above instead**.
697
+
654
698
  ### Step B — If **1 / Cloudinary** (same Question 2 — **one Env popup**)
655
699
 
656
700
  > **Critical UX rule:** Immediately open the **Vercel Environment Variables configuration popup / form** with **all Cloudinary fields in one UI**. Do **not** ask for cloud name, then key, then secret in separate chat messages.
@@ -837,8 +881,8 @@ Then (**Scheme A — mandatory for Publish**):
837
881
  |------|----------|--------------|
838
882
  | `SUPABASE_URL` | If Q1 = Supabase | User pastes URL |
839
883
  | `DATABASE_URL` | If Q1 = Neon | User pastes URL |
840
- | `TOMORROWOS_STORE` | Yes | **Agent auto-sets** (`supabase` / `postgres` / `sqlite`) |
841
- | `DATABASE_SSL` | Yes for Postgres | **Agent auto-sets** `true` |
884
+ | `TOMORROWOS_STORE` | Yes | **Agent auto-sets only** — never a blank field for the user (`supabase` / `postgres` / `sqlite`) |
885
+ | `DATABASE_SSL` | Yes for Postgres | **Agent auto-sets only** — never a blank field for the user (`true`) |
842
886
  | `CLOUDINARY_*` | If Q2 = Cloudinary | User via **one Env popup** (all fields) |
843
887
  | `BLOB_READ_WRITE_TOKEN` | If Q2 = Vercel Blob | User / Blob link |
844
888
  | `TOMORROWOS_INTERNAL_PORT` | Preview only | Agent (e.g. `3001`) |
@@ -920,7 +964,8 @@ Tell the user:
920
964
  | Blob uploads 401 / missing token | Blob not linked | Vercel Storage → Blob + `BLOB_READ_WRITE_TOKEN` |
921
965
  | WebSocket fails on Publish | Fluid off / static-only / Next as Production / no Function WS | Enable Fluid; Scheme A; test 101 upgrade |
922
966
  | Devices fail only on Preview | Next proxy cannot upgrade `wss` | Expected — pair on Publish URL |
923
- | Agent asked user to fill `TOMORROWOS_STORE` / `DATABASE_SSL` | Off-protocol | Agent must auto-set those after Neon/Supabase choice |
967
+ | Agent asked user to fill `TOMORROWOS_STORE` / `DATABASE_SSL` | Off-protocol | Agent must auto-set after DB choice; remove those fields from user Env forms |
968
+ | Agent offered Blob-as-recommended / Supabase Storage / “no media” for Q2 | Invented options | Re-ask Q2 verbatim: **1 Cloudinary (recommended)**, 2 Blob, 3 local |
924
969
  | Agent asked Cloudinary key/secret in three chat turns | Off-protocol | Use **one Env popup** with all Cloudinary fields |
925
970
  | Agent asked for OpenAI / `sk-` key during setup | Hallucinated “AI pairing” requirement | **Refuse.** TomorrowOS does not need LLM keys. Return to Q2 media choices only |
926
971
  | Agent built a login page after user pasted a URL | Misread brand reference as product scope | Remove login; keep starter Control Panel; apply URL only to `brand.json` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomorrowos/sdk",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
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",
@@ -21,6 +21,7 @@
21
21
  "LLM_PROMPT.md",
22
22
  "REPLIT_SETUP.md",
23
23
  "VERCEL_SETUP.md",
24
+ "VERCEL_QUESTIONS.md",
24
25
  "REPLIT_UPGRADE.md",
25
26
  "BUILD_GUARDRAILS.md",
26
27
  "PLAYER_INSTALL.md",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
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.32",
16
+ "@tomorrowos/sdk": "^0.9.34",
17
17
  "dotenv": "^17.2.3",
18
18
  "tsx": "^4.19.0"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-cms",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
4
4
  "description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
5
5
  "private": true,
6
6
  "type": "module",
@@ -17,7 +17,7 @@
17
17
  "build-player": "tomorrowos build --platform tizen"
18
18
  },
19
19
  "dependencies": {
20
- "@tomorrowos/sdk": "^0.9.32",
20
+ "@tomorrowos/sdk": "^0.9.34",
21
21
  "dotenv": "^17.2.3",
22
22
  "tsx": "^4.19.0"
23
23
  },