@tomorrowos/sdk 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERCEL_QUESTIONS.md +13 -7
- package/VERCEL_SETUP.md +181 -44
- package/package.json +1 -1
- package/templates/cms-starter/package-lock.json +3 -3
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter-v0/README.md +2 -0
- package/templates/cms-starter-v0/package-lock.json +3 -3
- package/templates/cms-starter-v0/package.json +2 -2
package/VERCEL_QUESTIONS.md
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
# Vercel / v0 - Verbatim question bank
|
|
2
2
|
|
|
3
|
-
> **Protocol:** `vercel-questions/1.
|
|
3
|
+
> **Protocol:** `vercel-questions/1.7` (pairs with `VERCEL_SETUP.md` 1.18+ / `@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.
|
|
7
|
-
> **Q1 and Q2 are choice questions
|
|
7
|
+
> **Q1 and Q2 are choice questions — present them as a clickable choice UI** (buttons / radio / option cards) using the exact option labels below. Do **not** ask the user to type `1` or `2` in chat when a choice UI is available (chat typing is fallback only).
|
|
8
|
+
> **Q3 is a form only - never a multiple-choice question. Q4 is optional CMS password (`CMS_PASSWORD`).**
|
|
8
9
|
> **HARD STOP on Q3:** show the form, then **wait** for the user's reply. Optional fields do **not** mean you may auto-skip.
|
|
9
|
-
> **Q4 is optional:** blank/skip is valid; they can set `CMS_PASSWORD` later.
|
|
10
|
+
> **Q4 is optional:** blank/skip is valid; they can set `CMS_PASSWORD` later.
|
|
11
|
+
> **After Q4 (or after Q3 if you deferred Q4):** run `VERCEL_SETUP.md` **IRON GATE — v0 Preview hygiene** before debugging Neon/Postgres or Blob.
|
|
10
12
|
|
|
11
13
|
---
|
|
12
14
|
|
|
13
|
-
## Q1 - Database (paste
|
|
15
|
+
## Q1 - Database (clickable choice UI — paste option text exactly)
|
|
16
|
+
|
|
17
|
+
**UX:** Open a **clickable choice UI** (two option buttons / radio cards). Labels must match the bold titles below.
|
|
14
18
|
|
|
15
19
|
Which database should TomorrowOS use on Vercel?
|
|
16
20
|
|
|
@@ -18,7 +22,7 @@ Which database should TomorrowOS use on Vercel?
|
|
|
18
22
|
|
|
19
23
|
**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).
|
|
20
24
|
|
|
21
|
-
Reply with **1** or **2** (or "Supabase" / "Neon").
|
|
25
|
+
**Fallback only** (no choice UI available): Reply with **1** or **2** (or "Supabase" / "Neon").
|
|
22
26
|
|
|
23
27
|
---
|
|
24
28
|
|
|
@@ -33,7 +37,9 @@ Never show blank Env fields for `TOMORROWOS_STORE` or `DATABASE_SSL`.
|
|
|
33
37
|
|
|
34
38
|
---
|
|
35
39
|
|
|
36
|
-
## Q2 - Media (
|
|
40
|
+
## Q2 - Media (clickable choice UI — same pattern as Q1)
|
|
41
|
+
|
|
42
|
+
**UX:** Open a **clickable choice UI** (two option buttons / radio cards). **Forbidden when UI exists:** chat-only “Reply with **1** or **2**”.
|
|
37
43
|
|
|
38
44
|
How should playlist media (images/videos) be stored?
|
|
39
45
|
|
|
@@ -41,7 +47,7 @@ How should playlist media (images/videos) be stored?
|
|
|
41
47
|
|
|
42
48
|
**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
49
|
|
|
44
|
-
Reply with **1** or **2** (or "Cloudinary" / "Vercel Blob").
|
|
50
|
+
**Fallback only** (no choice UI available): Reply with **1** or **2** (or "Cloudinary" / "Vercel Blob").
|
|
45
51
|
|
|
46
52
|
**Forbidden replacements (never ask these):** Vercel Blob as recommended #1; Supabase Storage; S3 / R2 / B2 / `MEDIA_S3_*`; "no media storage" / disable uploads; local disk only.
|
|
47
53
|
|
package/VERCEL_SETUP.md
CHANGED
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
>
|
|
6
6
|
> **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`).
|
|
7
7
|
>
|
|
8
|
-
> Protocol id: `vercel-setup/1.
|
|
8
|
+
> Protocol id: `vercel-setup/1.18` - 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
|
-
> **Q1/Q2 = choice
|
|
11
|
+
> **Q1/Q2 = clickable choice UI (same pattern):** open a **button / radio / option-card UI** with the two fixed choices. Do **not** ask the user to type `1` or `2` in chat when a choice UI is available. Chat “reply 1 or 2” is fallback only.
|
|
12
|
+
> **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**.
|
|
12
13
|
> **Q4 = optional `CMS_PASSWORD`:** blank/skip is valid; can set later. Control Panel auth only — never Vercel Deployment Protection / whole-site password.
|
|
14
|
+
> **After Q&A (before debugging DB):** run **IRON GATE — v0 Preview hygiene** (clear root Next leftovers, restart supervised `dev`, prove `GET /status` is TomorrowOS JSON). Do **not** spend turns “fixing Neon/Blob” while port 3000 is still a stale Next/Turbopack process.
|
|
15
|
+
> **Publish Output Directory:** must stay **empty / unset**. Build error `Output Directory "public" is empty` means the dashboard still points at `public/` — **clear it**; do **not** “fix” by stuffing `public/robots.txt` while leaving Output = `public`.
|
|
13
16
|
> **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).
|
|
14
17
|
> **`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.
|
|
15
18
|
|
|
@@ -19,6 +22,7 @@ The following rules are **mandatory acceptance criteria**, not suggestions. The
|
|
|
19
22
|
|
|
20
23
|
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.
|
|
21
24
|
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`.
|
|
25
|
+
2a. **Build error `The Output Directory "public" is empty`:** This is **not** fixed by adding `public/robots.txt` as the primary solution. It means Project Settings still has Output Directory = `public`. **Clear/unset Output Directory**, confirm Framework = Other, Fluid Function `api/index.ts` + rewrites, then redeploy. Filling `public/` only papers over a wrong static-output setting.
|
|
22
26
|
3. **Preview may use Next only as an isolated reverse-proxy shell under `preview/`.** Preview must not replace TomorrowOS or determine the Production runtime.
|
|
23
27
|
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.
|
|
24
28
|
5. **After every Production deployment, verify all three gates before saying setup is complete:**
|
|
@@ -38,10 +42,14 @@ When a human pastes a prompt like this, **read this file and start Question 1 im
|
|
|
38
42
|
Follow @tomorrowos/sdk (an NPM package) VERCEL_SETUP.md and set up my TomorrowOS CMS from scratch.
|
|
39
43
|
|
|
40
44
|
Open VERCEL_QUESTIONS.md first.
|
|
41
|
-
For Q1
|
|
45
|
+
For Q1 and Q2: open a **clickable choice UI** (buttons / radio / option cards) using the verbatim options from VERCEL_QUESTIONS.md. Do not ask me to type 1 or 2 in chat when UI is available.
|
|
46
|
+
For Q1, Q2, Q3: use exact option wording from VERCEL_QUESTIONS.md. Do not rephrase options.
|
|
42
47
|
For Q3: DO NOT ask a branding choice. Open one form with ALL SEVEN optional inputs at once, then HARD STOP and WAIT for my submit or "skip". Never auto-continue with defaults without my reply. Never only Name + Primary colour. Logo = Upload above Logo URL.
|
|
48
|
+
After Q3, paste Q4 (optional CMS password). Blank/skip is valid.
|
|
43
49
|
After Q1 database choice, YOU set TOMORROWOS_STORE and DATABASE_SSL. Do not ask me to fill those.
|
|
44
50
|
After Q2 media storage choice, YOU set TOMORROWOS_MEDIA. Do not ask me to fill those.
|
|
51
|
+
After answers: run IRON GATE v0 Preview hygiene BEFORE debugging Postgres/media — clear root Next leftovers, restart supervised dev, prove GET /status is TomorrowOS JSON.
|
|
52
|
+
Before Publish: Output Directory must be empty/unset (NOT public). If build says Output Directory public is empty, CLEAR Output Directory — do not stuff public/robots.txt as the fix.
|
|
45
53
|
Run: npx @tomorrowos/sdk@latest init . --hosting v0 --force
|
|
46
54
|
Keep cms-starter-v0 layout.
|
|
47
55
|
Apply the NON-NEGOTIABLE VERCEL RUNTIME CONTRACT exactly:
|
|
@@ -114,18 +122,37 @@ almost always means **Vercel still thinks this is a Next.js / static deploy**, n
|
|
|
114
122
|
|
|
115
123
|
**Setup is NOT complete** while Production `GET /` returns `404: NOT_FOUND` or WebSocket upgrade returns 200 HTML.
|
|
116
124
|
|
|
117
|
-
### Publish static trap
|
|
125
|
+
### Publish static trap — `public/` served without Node (read this)
|
|
118
126
|
|
|
119
|
-
A common
|
|
120
|
-
|
|
121
|
-
- `GET /` loads the Control Panel HTML (from static `public/index.html`)
|
|
127
|
+
**Symptom A — wrong runtime (common worse failure than `404: NOT_FOUND`):**
|
|
128
|
+
- `GET /` loads the Control Panel HTML (from static files)
|
|
122
129
|
- `GET /status`, `/devices`, etc. return **HTML** (Vercel 404 page)
|
|
123
130
|
- The panel shows **CMS unreachable** and console:
|
|
124
131
|
`Unexpected token 'T', "The page c"... is not valid JSON`
|
|
125
132
|
|
|
126
|
-
**Root cause:** Vercel deployed `public/` as a **static site** (Output Directory = `public` or Framework=Other default
|
|
133
|
+
**Root cause A:** Vercel deployed `public/` as a **static site** (Output Directory = `public` or Framework=Other default “public if it exists”). **No Function** is running TomorrowOS.
|
|
134
|
+
|
|
135
|
+
**Symptom B — build fails before deploy:**
|
|
136
|
+
```text
|
|
137
|
+
Error: The Output Directory "public" is empty.
|
|
138
|
+
```
|
|
139
|
+
**Root cause B:** Project Settings **Output Directory is still `public`**, but this CMS has **no** (or empty) static export folder — UI lives in `cms-panel/` and is served by the Fluid Function.
|
|
140
|
+
|
|
141
|
+
**Correct fix (mandatory for A and B):**
|
|
142
|
+
|
|
143
|
+
1. Set **Output Directory** = **empty / unset** (dashboard and/or project settings API).
|
|
144
|
+
2. Framework Preset = **Other** / null; Fluid on; `api/index.ts` + rewrites per Scheme A.
|
|
145
|
+
3. Redeploy. Verify `GET /status` is **JSON** and WebSocket is **101**.
|
|
127
146
|
|
|
128
|
-
**
|
|
147
|
+
**Forbidden “fixes”:**
|
|
148
|
+
|
|
149
|
+
- Adding `public/robots.txt` / `.gitkeep` **so a static Output Directory = `public` build passes** — that leaves Production on the static trap path.
|
|
150
|
+
- Setting Output Directory to `cms-panel`, `.`, or `public`.
|
|
151
|
+
- Claiming Publish succeeded because the build log turned green while Output is still `public`.
|
|
152
|
+
|
|
153
|
+
**Optional:** If some tooling creates an empty `public/` folder, delete it or ignore it — **never** point Output Directory at it.
|
|
154
|
+
|
|
155
|
+
**Scheme A reminder:** use `cms-panel/` (not `public/`), Fluid Function `api/index.ts` + rewrites, Output Directory empty. Static UI is served **at runtime** via `staticRoot` in `listen()`.
|
|
129
156
|
|
|
130
157
|
**Publish gate (mandatory):** after deploy, `GET /status` must return **JSON** starting with `{`, not HTML starting with `<` or `The page`. **And** WebSocket upgrade on `/` or `/api` must return **101**.
|
|
131
158
|
|
|
@@ -203,7 +230,8 @@ Then ask **Question 1**.
|
|
|
203
230
|
|
|
204
231
|
## Hard rules
|
|
205
232
|
|
|
206
|
-
1. **Open `VERCEL_QUESTIONS.md` first.**
|
|
233
|
+
1. **Open `VERCEL_QUESTIONS.md` first.** Ask Q1 → configure → Q2 → configure → Q3 → Q4. Never paraphrase question options. Never use `REPLIT_SETUP.md` as the questionnaire. **Never** ask for OpenAI or other LLM API keys.
|
|
234
|
+
1a. **Q1 and Q2 UX:** Prefer a **clickable choice UI** (same pattern for both): two option buttons/cards matching the verbatim labels. **Forbidden when UI exists:** chat-only “Reply with 1 or 2”. Chat typing is fallback only if the platform cannot render choices.
|
|
207
235
|
2. **Question 2 options are fixed:** (1) Cloudinary **(recommended)**, (2) Vercel Blob. Do not reorder; do not invent Supabase Storage, local disk, or disable-uploads.
|
|
208
236
|
3. **Cloudinary:** open **one** Vercel Env popup with **all** Cloudinary fields together. Do **not** quiz one credential at a time.
|
|
209
237
|
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`. **Do not offer SQLite as a questionnaire choice** ? it is ephemeral on Vercel and unsuitable for production.
|
|
@@ -221,13 +249,76 @@ Then ask **Question 1**.
|
|
|
221
249
|
16. **No inventing CMS login** from a branding URL.
|
|
222
250
|
17. **Skip → invent.** Stay on Q1–Q4 only.
|
|
223
251
|
18. **Publish gate:** `/status` JSON + WebSocket 101; no static `public/` trap.
|
|
224
|
-
19. **Q3 is a form, not a question
|
|
252
|
+
19. **Q3 is a form, not a question — and you must WAIT.** After Q2, open one dialog with **all seven** optional inputs visible together, then **stop and wait** for submit or explicit **"skip"**. **Never** auto-continue because fields are optional. **Never** ask a preliminary branding choice. **Never** show only Product Name + Primary colour. **Never** use multiple-choice / Option A-B for branding. Logo = **Upload** above **Logo URL**.
|
|
253
|
+
20. **IRON GATE after Q&A:** Before blaming Neon / Blob / migrations, complete **IRON GATE — v0 Preview hygiene** below. Preview 500s are usually leftover root Next or a stale supervised `next-server`, not a bad Q1/Q2 choice.
|
|
254
|
+
|
|
255
|
+
**Question order:** Q1 -> (auto-set store env) -> Q2 -> Q3 form (**wait for user**) -> Q4 optional `CMS_PASSWORD` -> **IRON GATE** -> execution checklist.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## IRON GATE — v0 Preview hygiene (run after Q&A, before DB rabbit holes)
|
|
260
|
+
|
|
261
|
+
> **Why this exists:** On v0, agents often answer Q1–Q3, run `init`, then spend a long time “fixing Postgres” while port **3000** is still the original **Next/Turbopack** starter (or a manually spawned `tsx` without injected env). Neon vs Blob choices are **not** the usual cause.
|
|
262
|
+
|
|
263
|
+
### Do this in order — stop when each check passes
|
|
264
|
+
|
|
265
|
+
1. **Identify what owns `:3000` (empirical, 30 seconds)**
|
|
266
|
+
- If process/logs look like `next-server` / Turbopack / `ENOENT .../app` → you are **not** talking to TomorrowOS yet.
|
|
267
|
+
- If `GET /status` returns TomorrowOS **JSON** (`{"status":...}`) → proceed.
|
|
268
|
+
- **Forbidden:** debugging `DATABASE_URL` / Neon pooler while `/status` is HTML, Next error overlay, or Turbopack crash.
|
|
269
|
+
|
|
270
|
+
2. **Clear forbidden root Next leftovers (from the original v0 starter)**
|
|
271
|
+
Remove from **project root** (keep the SDK shell under `preview/`):
|
|
272
|
+
`app/`, `pages/`, root `next.config.*`, root `next-env.d.ts`, root `postcss.config.*`, leftover `components/` / `lib/` from the starter, `components.json` — anything that makes Framework detection or v0 Preview latch onto Next at root.
|
|
273
|
+
**Do not** delete `preview/` (that is the sanctioned Next reverse-proxy shell).
|
|
274
|
+
Empty leftover dirs after deleting files.
|
|
275
|
+
|
|
276
|
+
3. **Confirm scripts + layout**
|
|
277
|
+
- Root `package.json` `"dev"` / `"start"` run TomorrowOS (`tsx` …), not `next dev` at root.
|
|
278
|
+
- `preview/` exists if Preview stays Next-hardwired; use `dev:preview` (Next public + TomorrowOS on **3001**) when required.
|
|
279
|
+
- `cms-panel/` (or template static root) is TomorrowOS UI — **not** Vercel Output Directory `public/`.
|
|
280
|
+
|
|
281
|
+
4. **Restart the platform-supervised `dev` — do not double-bind**
|
|
282
|
+
- After rewriting `package.json` scripts, the **old** supervised `next-server` may still hold `:3000`. Kill/restart so the supervisor re-execs the **new** `dev` script.
|
|
283
|
+
- **Forbidden:** spawning a second manual `pnpm dev` / `tsx` that fights the supervised process (`EADDRINUSE`) **and** lacks v0-injected env.
|
|
284
|
+
- Prefer the **v0/Vercel managed** process (it inherits injected secrets). Only start TomorrowOS yourself if you also load the same env (see **Env loading trap**).
|
|
285
|
+
|
|
286
|
+
5. **Prove TomorrowOS before touching DB**
|
|
287
|
+
- `GET /status` → **200 JSON** from TomorrowOS (not Next HTML, not `The page could not be found`).
|
|
288
|
+
- `GET /` → Control Panel HTML (or CMS login HTML if `CMS_PASSWORD` set).
|
|
289
|
+
- Only **then** interpret Database/Media connector errors as real store/media issues.
|
|
290
|
+
|
|
291
|
+
### Env loading trap (v0 / Preview vs Production)
|
|
292
|
+
|
|
293
|
+
| Context | How secrets arrive | What `import "dotenv/config"` sees |
|
|
294
|
+
|---------|-------------------|-------------------------------------|
|
|
295
|
+
| **Production Deploy** | Vercel injects into `process.env` | N/A — platform env wins |
|
|
296
|
+
| **v0 / Agent Preview** | Often written to **`.env.development.local`** (and/or injected only into the **supervised** Node process) | **Only `.env`** by default — **not** `.env.development.local` |
|
|
297
|
+
| **Manual Bash `pnpm dev`** | Usually **no** injected `DATABASE_URL` / Blob token unless you export them | Easy false “Postgres broken” |
|
|
298
|
+
|
|
299
|
+
**Rules:**
|
|
300
|
+
|
|
301
|
+
- Non-secret flags may live in committed `.env` (`TOMORROWOS_STORE`, `DATABASE_SSL`, `TOMORROWOS_MEDIA`).
|
|
302
|
+
- Secrets (`DATABASE_URL`, `SUPABASE_URL`, `BLOB_READ_WRITE_TOKEN`, `CMS_PASSWORD`, Cloudinary keys) belong in **Vercel Env** / v0 injection — never commit them.
|
|
303
|
+
- If logs say store=`postgres` but `DATABASE_URL` is missing in a **manual** process: load `.env` **and** `.env.development.local`, or restart the **supervised** server — do **not** immediately change Neon URLs.
|
|
304
|
+
- Preview flakes ≠ Production failure. Fix Preview hygiene first; do not “repair” Production Framework because Preview 500’d.
|
|
225
305
|
|
|
226
|
-
|
|
306
|
+
### Preview decision tree (after hygiene)
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
Is GET /status TomorrowOS JSON on the Preview URL?
|
|
310
|
+
YES → continue checklist (Publish gates still required).
|
|
311
|
+
NO → What owns the public port?
|
|
312
|
+
next-server / Turbopack / ENOENT app/ → clear root Next + restart supervised dev (steps 2–4).
|
|
313
|
+
tsx TomorrowOS listening but Preview blank → v0 still hardwires Next: use preview/ reverse-proxy + TOMORROWOS_INTERNAL_PORT=3001 + dev:preview.
|
|
314
|
+
EADDRINUSE :3000 → kill stale Next/tsx; one process only.
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Reminder:** Q1 Neon / Q2 Blob are valid protocol choices. A long Preview outage after those answers is almost always **process/layout/env injection**, not “wrong database/media product.”
|
|
227
318
|
|
|
228
319
|
---
|
|
229
320
|
|
|
230
|
-
## Scheme A
|
|
321
|
+
## Scheme A — Vercel Functions + WebSockets (mandatory for Production)
|
|
231
322
|
|
|
232
323
|
> **Goal:** Preview may use Next + proxy; **Publish** runs TomorrowOS as a **Vercel Function** (`api/index.ts`) on **Fluid**, with WebSocket support per [Vercel WebSockets docs](https://vercel.com/docs/functions/websockets).
|
|
233
324
|
> **Scope:** Layout + `vercel.json` + dashboard. Prefer `npx @tomorrowos/sdk@latest init --hosting v0` (`cms-starter-v0`).
|
|
@@ -351,16 +442,20 @@ SDK behaviour (0.9.32+):
|
|
|
351
442
|
- `"buildCommand"` = no-op ??**never** `next build` for Production
|
|
352
443
|
- Dashboard Output Directory must stay **empty**
|
|
353
444
|
|
|
354
|
-
### A4
|
|
445
|
+
### A4 — Vercel Project Settings (dashboard — mandatory)
|
|
355
446
|
|
|
356
447
|
| Setting | Required value |
|
|
357
448
|
|---------|----------------|
|
|
358
|
-
| Framework Preset | **Other** / null
|
|
449
|
+
| Framework Preset | **Other** / null — **not Next.js** |
|
|
359
450
|
| Install Command | `npm install` |
|
|
360
451
|
| Build Command | `npm run build` (no-op) |
|
|
361
|
-
| **Output Directory** | **empty** |
|
|
452
|
+
| **Output Directory** | **empty / unset** — **never `public`** |
|
|
362
453
|
| Fluid compute | **On** |
|
|
363
|
-
| WebSockets | Account must allow Functions WebSockets (see docs
|
|
454
|
+
| WebSockets | Account must allow Functions WebSockets (see docs — Permissions Required) |
|
|
455
|
+
|
|
456
|
+
**If Publish build fails with `The Output Directory "public" is empty`:** the dashboard still has Output = `public`. **Clear/unset it** via Project Settings (or settings API), then redeploy. Do **not** add `public/robots.txt` (or any static filler) as the primary fix while Output stays `public`.
|
|
457
|
+
|
|
458
|
+
**`vercel.json` must not set `outputDirectory`.** Leaving it out is correct; dashboard Output must still be forced empty because Framework=Other may default to “public if it exists”.
|
|
364
459
|
|
|
365
460
|
### A5 ??Publish acceptance (all must pass)
|
|
366
461
|
|
|
@@ -511,12 +606,14 @@ const server = tomorrowos.listen({
|
|
|
511
606
|
export default server;
|
|
512
607
|
```
|
|
513
608
|
|
|
514
|
-
- **Production:** `PORT` from Vercel
|
|
609
|
+
- **Production:** `PORT` from Vercel — TomorrowOS listens on that port (no Next).
|
|
515
610
|
- **Preview:** set `TOMORROWOS_INTERNAL_PORT=3001` (or similar) so Next can own `:3000` and proxy inward.
|
|
516
611
|
|
|
517
|
-
Load env with `dotenv` for local/`vercel dev
|
|
612
|
+
Load env with `dotenv` for local/`vercel dev` (loads **`.env` only**). On production Deploy, Vercel injects Environment Variables natively.
|
|
613
|
+
|
|
614
|
+
**v0 / Preview caveat:** platform secrets often land in **`.env.development.local`** or only in the **supervised** process env. TomorrowOS `import "dotenv/config"` does **not** auto-load `.env.development.local`. See **IRON GATE — Env loading trap**. Never treat a manual Bash server missing `DATABASE_URL` as proof that Neon is misconfigured.
|
|
518
615
|
|
|
519
|
-
### Preview adapter (v0 / Next reverse proxy)
|
|
616
|
+
### Preview adapter (v0 / Next reverse proxy) — required when Preview is Next-hardwired
|
|
520
617
|
|
|
521
618
|
Detect Preview / v0 (Next already present, or Preview blank while TomorrowOS logs ?listening??. Then:
|
|
522
619
|
|
|
@@ -612,17 +709,26 @@ If Vercel?s UI and this file disagree on bundling, **prefer whatever keeps a sin
|
|
|
612
709
|
|
|
613
710
|
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.
|
|
614
711
|
|
|
615
|
-
### Step A
|
|
712
|
+
### Step A — Ask database choice (**clickable UI required**)
|
|
616
713
|
|
|
617
|
-
**
|
|
714
|
+
**UX:** Open a **choice UI** the user can **click** — two option buttons / radio cards / select list. Labels must match the verbatim options below. Same clickable pattern as Q2.
|
|
715
|
+
|
|
716
|
+
| # | Exact option label (UI) |
|
|
717
|
+
|---|-------------------------|
|
|
718
|
+
| 1 | **Supabase Postgres (recommended)** |
|
|
719
|
+
| 2 | **Neon Postgres** |
|
|
720
|
+
|
|
721
|
+
Supporting copy under each option may match `VERCEL_QUESTIONS.md`. **Do not** default to a chat message that only says “Reply with 1 or 2” when the platform can render choices.
|
|
722
|
+
|
|
723
|
+
**Ask exactly (wording / option text must match):**
|
|
618
724
|
|
|
619
725
|
> Which database should TomorrowOS use on Vercel?
|
|
620
726
|
>
|
|
621
|
-
> **1. Supabase Postgres (recommended)**
|
|
727
|
+
> **1. Supabase Postgres (recommended)** — durable pairing/playlists; use the **Session pooler** URL (`*.pooler.supabase.com:6543`).
|
|
622
728
|
>
|
|
623
|
-
> **2. Neon Postgres**
|
|
624
|
-
|
|
625
|
-
|
|
729
|
+
> **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).
|
|
730
|
+
|
|
731
|
+
**Fallback only** (no choice UI available): allow chat reply **1** / **2** / "Supabase" / "Neon".
|
|
626
732
|
|
|
627
733
|
### Step B ??If **1 / Supabase**
|
|
628
734
|
|
|
@@ -678,19 +784,26 @@ If you open an Env configuration UI for Q1, fields visible to the user may inclu
|
|
|
678
784
|
> 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
785
|
> **Copy the two options below verbatim.** Wrong examples that must **never** appear: "Vercel Blob (recommended)", "Supabase Storage", "No media storage / disable uploads", "local disk only".
|
|
680
786
|
|
|
681
|
-
### Step A
|
|
787
|
+
### Step A — Ask storage choice (**clickable UI required — same as Q1**)
|
|
788
|
+
|
|
789
|
+
**UX:** Open a **choice UI** the user can **click** — two option buttons / radio cards. **Forbidden when UI exists:** chat-only “Reply with **1** or **2**”.
|
|
682
790
|
|
|
683
|
-
|
|
791
|
+
| # | Exact option label (UI) |
|
|
792
|
+
|---|-------------------------|
|
|
793
|
+
| 1 | **Cloudinary (recommended)** |
|
|
794
|
+
| 2 | **Vercel Blob** |
|
|
795
|
+
|
|
796
|
+
**Ask exactly (wording must match — Cloudinary is recommended):**
|
|
684
797
|
|
|
685
798
|
> How should playlist media (images/videos) be stored?
|
|
686
799
|
>
|
|
687
|
-
> **1. Cloudinary (recommended)**
|
|
688
|
-
>
|
|
689
|
-
> **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.
|
|
800
|
+
> **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.**
|
|
690
801
|
>
|
|
691
|
-
>
|
|
802
|
+
> **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.
|
|
803
|
+
|
|
804
|
+
**Fallback only** (no choice UI): chat reply **1** / **2** / "Cloudinary" / "Vercel Blob".
|
|
692
805
|
|
|
693
|
-
If you catch yourself about to offer Blob-as-recommended, Supabase Storage, local disk, or "no media"
|
|
806
|
+
If you catch yourself about to offer Blob-as-recommended, Supabase Storage, local disk, or "no media" — **stop and use the block above instead**.
|
|
694
807
|
|
|
695
808
|
### Step B ??If **1 / Cloudinary** (same Question 2 ??**one Env popup**)
|
|
696
809
|
|
|
@@ -874,26 +987,36 @@ Set `cmsEndpoint` only if they already know the public `https://?vercel.app` URL
|
|
|
874
987
|
|
|
875
988
|
---
|
|
876
989
|
|
|
877
|
-
## After all answers
|
|
990
|
+
## After all answers — execution checklist
|
|
991
|
+
|
|
992
|
+
### A0. IRON GATE first (mandatory)
|
|
993
|
+
|
|
994
|
+
Complete **IRON GATE — v0 Preview hygiene** before long Postgres/media debugging:
|
|
995
|
+
|
|
996
|
+
1. Prove `GET /status` is TomorrowOS JSON (or clear root Next + restart supervised `dev` until it is).
|
|
997
|
+
2. Remove root `app/` / `next.config.*` leftovers; keep `preview/` only for the proxy shell.
|
|
998
|
+
3. Do not spawn a second manual server that lacks injected env / fights `:3000`.
|
|
999
|
+
4. Only then treat Database/Media connector errors as real.
|
|
878
1000
|
|
|
879
1001
|
### A. Seed the project
|
|
880
1002
|
|
|
881
1003
|
```bash
|
|
882
|
-
npx @tomorrowos/sdk@latest init .
|
|
1004
|
+
npx @tomorrowos/sdk@latest init . --hosting v0
|
|
883
1005
|
# If not empty and user confirms starter overwrite:
|
|
884
|
-
# npx @tomorrowos/sdk@latest init . --force
|
|
1006
|
+
# npx @tomorrowos/sdk@latest init . --hosting v0 --force
|
|
885
1007
|
```
|
|
886
1008
|
|
|
887
|
-
Then (**Scheme A
|
|
1009
|
+
Then (**Scheme A — mandatory for Publish**):
|
|
888
1010
|
|
|
889
1011
|
1. Keep **`server.ts`** at **project root** with top-level `listen()` + `export default server`.
|
|
890
|
-
2.
|
|
891
|
-
3. Write `vercel.json` per **Scheme A3** (`fluid`, `framework: null`, no-op `buildCommand`
|
|
892
|
-
4. **Force Project Settings** per **Scheme A4** (Framework = Other, Output Directory empty
|
|
1012
|
+
2. **Immediately** move leftover v0 Next from root into **`preview/`** or delete root Next files (`next.config.*`, `app/`, Next `tsconfig` / `postcss` / `next-env.d.ts`, starter `components/`). Production must not see root Next.
|
|
1013
|
+
3. Write `vercel.json` per **Scheme A3** (`fluid`, `framework: null`, no-op `buildCommand` — **no** `startCommand`).
|
|
1014
|
+
4. **Force Project Settings** per **Scheme A4** (Framework = Other, Output Directory **empty/unset**, Start = `npm run start`, Fluid on). Patch dashboard via API if it still says Next.js **or** Output = `public`.
|
|
1015
|
+
4a. **Pre-Publish Output check:** If settings show Output Directory = `public` (or build fails with `Output Directory "public" is empty`), **clear Output Directory** and redeploy. Do **not** add `public/robots.txt` to satisfy a static output path.
|
|
893
1016
|
5. Do **not** add root `api/` catch-all for raw `http.Server`.
|
|
894
1017
|
6. Do **not** add `.replit*`.
|
|
895
1018
|
7. If Q2 = Vercel Blob: set `BLOB_READ_WRITE_TOKEN` + `TOMORROWOS_MEDIA=vercel-blob` (SDK-native; no custom bridge).
|
|
896
|
-
|
|
1019
|
+
8. **Restart** the platform-supervised Preview `dev` after script/layout changes (stale `next-server` is the #1 false “DB failure”).
|
|
897
1020
|
### B. Environment Variables (Vercel dashboard + local)
|
|
898
1021
|
|
|
899
1022
|
| Name | Required | Who fills it |
|
|
@@ -909,14 +1032,16 @@ Then (**Scheme A ??mandatory for Publish**):
|
|
|
909
1032
|
| `PORT` | Optional | Vercel injects for Production |
|
|
910
1033
|
| `CMS_PASSWORD` | Optional (Q4) | User if set; blank/skip = omit (can add later) |
|
|
911
1034
|
|
|
912
|
-
Mirror non-secrets in `.env` for local `npm run
|
|
1035
|
+
Mirror non-secrets in `.env` for local `npm run start` if helpful; never commit secrets.
|
|
1036
|
+
On v0 Preview, secrets may exist only in **`.env.development.local`** / supervised env — see **Env loading trap**. Do not “fix Neon” until the process that serves `/status` actually has `DATABASE_URL` / `SUPABASE_URL`.
|
|
913
1037
|
|
|
914
1038
|
### C. Install and run
|
|
915
1039
|
|
|
916
1040
|
```bash
|
|
917
1041
|
npm install
|
|
918
1042
|
npm run start
|
|
919
|
-
# Preview / v0: npm run dev:preview (Next + TomorrowOS
|
|
1043
|
+
# Preview / v0 when Next-hardwired: npm run dev:preview (Next :3000 + TomorrowOS :3001)
|
|
1044
|
+
# After changing package.json "dev": restart the supervised process — do not leave stale next-server on :3000
|
|
920
1045
|
```
|
|
921
1046
|
|
|
922
1047
|
Confirm logs: `[TomorrowOS] listening on http://0.0.0.0:?`
|
|
@@ -994,6 +1119,14 @@ More detail: https://docs.tomorrowos.org/docs/os/tizen and https://docs.tomorrow
|
|
|
994
1119
|
|
|
995
1120
|
| Symptom | Likely cause | Fix |
|
|
996
1121
|
|---------|--------------|-----|
|
|
1122
|
+
| Build: `Output Directory "public" is empty` | Dashboard Output Directory still = `public` on a Function/CMS app | **Unset Output Directory**; Framework Other; Fluid `api/index.ts`; redeploy. Do **not** primary-fix with `public/robots.txt` |
|
|
1123
|
+
| Agent asked Q2 as chat “type 1 or 2” while choice UI available | Off-protocol Q2 UX | Re-ask Q2 with **clickable** Cloudinary / Vercel Blob options (same pattern as Q1) |
|
|
1124
|
+
| Preview 500 / Turbopack / `ENOENT .../app` after Q1–Q3 | Leftover **root** Next from v0 starter; not Neon/Blob | **IRON GATE:** delete/move root `app/` + `next.config.*`; keep `preview/`; restart supervised `dev`; prove `/status` JSON |
|
|
1125
|
+
| `Internal Server Error` + logs blame missing `DATABASE_URL` in a **manual** Bash server | `dotenv` loaded `.env` only; secret is in `.env.development.local` / supervised env | Restart **supervised** Preview process; or load both env files — do **not** immediately change Neon URL |
|
|
1126
|
+
| `EADDRINUSE :3000` while debugging | Second `pnpm dev` / stale `next-server` after script rewrite | Kill stale Next/tsx; one process; let supervisor re-exec new `"dev"` |
|
|
1127
|
+
| Preview still Next after `package.json` `"dev"` → `tsx` | Supervised process never restarted | Kill old tree; wait for supervisor / restart Preview |
|
|
1128
|
+
| Agent spent many turns on Postgres before `/status` JSON | Skipped IRON GATE | Stop; run hygiene steps 1–5; only then debug store |
|
|
1129
|
+
| Q1=Neon / Q2=Blob then long Preview outage | Usually **not** the product choice | Same as root-Next / env-injection failures; choices are valid |
|
|
997
1130
|
| Publish `404: NOT_FOUND` | Framework Preset still **Next.js** / no Function | Scheme A: Framework = **Other**, Fluid on, `api/index.ts` + rewrites; redeploy |
|
|
998
1131
|
| Panel loads but **CMS unreachable** / `Unexpected token 'T', "The page c"...` | **`public/` deployed as static site** ??no Function | Rename to `cms-panel/`; Output empty; Scheme A Function entry; **Path B** if needed |
|
|
999
1132
|
| Only `/api/status` returns JSON, `/status` is 404 | Missing **rewrites** to `/api` | Add Scheme A3 rewrite `/(.*) ??/api` (exclude existing `/api/`); redeploy |
|
|
@@ -1069,7 +1202,11 @@ Protocol complete when:
|
|
|
1069
1202
|
|
|
1070
1203
|
## Protocol version
|
|
1071
1204
|
|
|
1072
|
-
`vercel-setup/1.
|
|
1205
|
+
`vercel-setup/1.18` - pairs with `@tomorrowos/sdk` 0.9.70+ and `VERCEL_QUESTIONS.md` 1.7.
|
|
1206
|
+
|
|
1207
|
+
**Changelog 1.18:** Q1/Q2 must use **clickable choice UI** (not chat “type 1 or 2” when UI exists). Publish build error `Output Directory "public" is empty` → **clear Output Directory** (forbidden primary fix: stuff `public/robots.txt` while Output stays `public`). Strengthens static-output trap docs.
|
|
1208
|
+
|
|
1209
|
+
**Changelog 1.17:** After Q&A, agents **must** run **IRON GATE — v0 Preview hygiene** before DB rabbit holes: clear root Next leftovers, restart supervised `dev`, prove `GET /status` is TomorrowOS JSON. Documents `.env` vs `.env.development.local` / supervised-env trap. Preview decision tree + cheat-sheet rows for Turbopack/`ENOENT`, missing `DATABASE_URL` in manual Bash, `EADDRINUSE`, stale `next-server`. Neon/Blob choices are not the usual Preview failure cause.
|
|
1073
1210
|
|
|
1074
1211
|
**Changelog 1.16:** Question 4 is optional Control Panel Env `CMS_PASSWORD` (blank/skip allowed; can set later). Do not use Vercel Deployment Protection / whole-site password for devices.
|
|
1075
1212
|
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "my-cms",
|
|
9
|
-
"version": "1.1.
|
|
9
|
+
"version": "1.1.3",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@tomorrowos/sdk": "^1.1.
|
|
11
|
+
"@tomorrowos/sdk": "^1.1.3",
|
|
12
12
|
"dotenv": "^17.2.3",
|
|
13
13
|
"tsx": "^4.19.0"
|
|
14
14
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
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",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"start": "tsx server.ts"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@tomorrowos/sdk": "^1.1.
|
|
15
|
+
"@tomorrowos/sdk": "^1.1.3",
|
|
16
16
|
"dotenv": "^17.2.3",
|
|
17
17
|
"tsx": "^4.19.0"
|
|
18
18
|
},
|
|
@@ -10,6 +10,8 @@ This starter is for **Vercel Publish** and **v0**. It follows
|
|
|
10
10
|
- **`preview/`** — Next.js shell for v0 Preview only
|
|
11
11
|
- **`vercel.json`** — `fluid`, rewrites → `/api`, `maxDuration`
|
|
12
12
|
|
|
13
|
+
**Publish setting (critical):** Vercel **Output Directory** must stay **empty / unset**. If the build fails with `The Output Directory "public" is empty`, clear Output Directory in Project Settings — do **not** add filler files under `public/` while Output is still set to `public`.
|
|
14
|
+
|
|
13
15
|
## Scaffold
|
|
14
16
|
|
|
15
17
|
```bash
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "my-cms",
|
|
9
|
-
"version": "1.1.
|
|
9
|
+
"version": "1.1.3",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@tomorrowos/sdk": "^1.1.
|
|
11
|
+
"@tomorrowos/sdk": "^1.1.3",
|
|
12
12
|
"dotenv": "^17.2.3",
|
|
13
13
|
"tsx": "^4.19.0"
|
|
14
14
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"build": "node -e \"process.exit(0)\""
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@tomorrowos/sdk": "^1.1.
|
|
19
|
+
"@tomorrowos/sdk": "^1.1.3",
|
|
20
20
|
"dotenv": "^17.2.3",
|
|
21
21
|
"tsx": "^4.19.0"
|
|
22
22
|
},
|