@tomorrowos/sdk 0.9.25 → 0.9.27
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 +2 -2
- package/VERCEL_SETUP.md +317 -119
- package/package.json +1 -1
- package/templates/cms-starter/package.json +2 -2
package/README.md
CHANGED
|
@@ -73,8 +73,8 @@ IF any step contradicts Vercel, adapt to settings that Vercel can accept.
|
|
|
73
73
|
|
|
74
74
|
That wizard asks: database (**Supabase** → **Neon** → SQLite demo), media (**Cloudinary** → **Vercel Blob** → local),
|
|
75
75
|
branding (manual fields or **website URL → `brand.json` only**, no login unless asked). Preview may use a thin **Next.js reverse proxy**;
|
|
76
|
-
**Publish stays pure Node** `TomorrowOS.listen` (
|
|
77
|
-
|
|
76
|
+
**Publish stays pure Node** `TomorrowOS.listen` (Scheme A: root `server.ts`, Next in `preview/`, `GET /status` must be JSON). Cloudinary uses **one Env popup** (all fields).
|
|
77
|
+
Neon/Supabase: agent auto-sets `TOMORROWOS_STORE` + `DATABASE_SSL`. Sets `cms.hostingTarget` to `"vercel"`.
|
|
78
78
|
|
|
79
79
|
### Replit upgrade (existing CMS)
|
|
80
80
|
|
package/VERCEL_SETUP.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
>
|
|
6
6
|
> **On Vercel, this file is the setup questionnaire** (not `REPLIT_SETUP.md`, not `LLM_PROMPT.md`).
|
|
7
7
|
>
|
|
8
|
-
> Protocol id: `vercel-setup/1.
|
|
8
|
+
> Protocol id: `vercel-setup/1.6` — pairs with `@tomorrowos/sdk` packages that ship `templates/cms-starter` and this file.
|
|
9
9
|
|
|
10
10
|
## User trigger (copy-paste)
|
|
11
11
|
|
|
@@ -19,6 +19,7 @@ If any step contradicts Vercel, adapt to settings Vercel can accept (document th
|
|
|
19
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
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
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), startCommand must run TomorrowOS Node, GET /status on the production URL must return JSON (not HTML), and GET / must return the Control Panel (not 404 NOT_FOUND).
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
Alternate triggers:
|
|
@@ -44,6 +45,7 @@ TomorrowOS CMS is **one Node process** that serves:
|
|
|
44
45
|
| Required | Forbidden |
|
|
45
46
|
|----------|-----------|
|
|
46
47
|
| Single **Node HTTP server** entry (`tsx server.ts` / exported `http.Server` from `listen()`) | **Next.js as the Production CMS** (`next start`, Next App Router as the live app) |
|
|
48
|
+
| **Framework Preset = Other / `null`** (dashboard **and** project settings API) | Leaving Framework Preset as **Next.js** (causes `404: NOT_FOUND`) |
|
|
47
49
|
| **Fluid compute** enabled (needed for WebSockets on Vercel) | Classic short-lived serverless with no WebSocket / no Fluid |
|
|
48
50
|
| Durable store = **Postgres** (Supabase or Neon, pooled URL) | **SQLite / `data/*.db` as production store** on Vercel (ephemeral filesystem) |
|
|
49
51
|
| Media = **Cloudinary** or **Vercel Blob** (durable HTTPS URLs) | Relying on local `public/uploads` alone for production fleets |
|
|
@@ -52,6 +54,57 @@ TomorrowOS CMS is **one Node process** that serves:
|
|
|
52
54
|
|
|
53
55
|
**Publish / Production Deploy** must run **`TomorrowOS.listen(...)`** directly. Do **not** put Next.js in front of Production traffic.
|
|
54
56
|
|
|
57
|
+
### Publish `404: NOT_FOUND` — mandatory prevention (read before every deploy)
|
|
58
|
+
|
|
59
|
+
The production URL showing:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
404: NOT_FOUND
|
|
63
|
+
Code: NOT_FOUND
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
almost always means **Vercel still thinks this is a Next.js / static deploy**, not a Node TomorrowOS server.
|
|
67
|
+
|
|
68
|
+
**Before every Production deploy, you MUST verify all of the following:**
|
|
69
|
+
|
|
70
|
+
1. **Project → Settings → General → Framework Preset = Other** (or unset / null).
|
|
71
|
+
If it still says **Next.js**, patch it via Vercel API / CLI / dashboard **before** redeploying.
|
|
72
|
+
`"framework": null` in `vercel.json` alone is **not enough** if the dashboard still says Next.js.
|
|
73
|
+
2. **Install Command** = `npm install` / `pnpm install` / `yarn` (normal install).
|
|
74
|
+
3. **Build Command** = a **no-op that exits 0** (e.g. `node -e "process.exit(0)"` or `npm run build` where `build` is that no-op).
|
|
75
|
+
**Never** run `next build` for Production.
|
|
76
|
+
4. **Start / Dev Command for Production** = `npm run start` / `pnpm start` → **`tsx server.ts`** (or `.mts`) that calls `TomorrowOS.listen` and **`export default server`**.
|
|
77
|
+
5. **Output Directory** = **empty / unset**. Do **not** set `outputDirectory: "."` as a fake static site.
|
|
78
|
+
6. **Do not** create a root `api/index.ts` that exports a raw `http.Server` and catch-all `routes` to “fix” 404 — Vercel Fluid does **not** treat that as a supported handler for this CMS. That pattern causes more 404s.
|
|
79
|
+
7. If Preview needs Next, keep Next files **isolated** so Production auto-detect cannot latch onto them:
|
|
80
|
+
- Prefer `preview/` (or similar) for `next.config.*`, `app/`, `pages/` used only by v0 Preview, **or**
|
|
81
|
+
- Ensure Production Framework Preset is forced to **Other** and Start Command never runs `next`.
|
|
82
|
+
|
|
83
|
+
**Setup is NOT complete** while Production `GET /` returns `404: NOT_FOUND`. Fix Framework Preset + Start Command and redeploy.
|
|
84
|
+
|
|
85
|
+
### Publish static trap — `public/` served without Node (read this)
|
|
86
|
+
|
|
87
|
+
A common **worse** failure mode than `404: NOT_FOUND`:
|
|
88
|
+
|
|
89
|
+
- `GET /` loads the Control Panel HTML (from static `public/index.html`)
|
|
90
|
+
- `GET /status`, `/devices`, etc. return **HTML** (Vercel 404 page)
|
|
91
|
+
- The panel shows **CMS unreachable** and console:
|
|
92
|
+
`Unexpected token 'T', "The page c"... is not valid JSON`
|
|
93
|
+
|
|
94
|
+
**Root cause:** Vercel deployed `public/` as a **static site** (Output Directory = `public` or Framework=Other default *“public if it exists”*). **No Node process** is running `tsx server.ts`, so API routes never hit `TomorrowOS`.
|
|
95
|
+
|
|
96
|
+
**Fix (Scheme A — see dedicated section below):** force Vercel to run the **root `server.ts` Node entry** with Fluid. `public/` must be served **at runtime** via `staticRoot` in `listen()`, **not** as the build output directory.
|
|
97
|
+
|
|
98
|
+
**Publish gate (mandatory):** after deploy, `GET /status` must return **JSON** starting with `{`, not HTML starting with `<` or `The page`.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
curl -s https://YOUR-PROJECT.vercel.app/status | head -c 80
|
|
102
|
+
# Expected: {"status":"success",...}
|
|
103
|
+
# Failure: The page could not be found OR <!DOCTYPE html>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Setup is NOT complete** while `/status` returns HTML or the panel shows the JSON parse error.
|
|
107
|
+
|
|
55
108
|
### Preview (v0 / Vercel Agent sandbox) — Next.js shell allowed
|
|
56
109
|
|
|
57
110
|
v0 Preview is often a **Next.js runtime** hardwired to `next dev`. A raw `tsx server.ts` may listen successfully while Preview still shows a blank page, because the sandbox intercepts the public port with Next before requests reach TomorrowOS.
|
|
@@ -87,6 +140,7 @@ Ask **only** these questions, in **this exact order**:
|
|
|
87
140
|
|
|
88
141
|
- ❌ OpenAI / Anthropic / Gemini / any LLM API key (`sk-…`, etc.)
|
|
89
142
|
- ❌ “AI pairing”, “AI feature logic”, or inventing auth that needs an LLM key
|
|
143
|
+
- ❌ Asking the user to type `TOMORROWOS_STORE` or `DATABASE_SSL` after they already chose Neon/Supabase — **you set those automatically**
|
|
90
144
|
- ❌ Any secret not listed in Questions 1–3 (DB URL, media credentials, brand)
|
|
91
145
|
|
|
92
146
|
TomorrowOS pairing and Control Panel logic live in `@tomorrowos/sdk`. They do **not** call OpenAI.
|
|
@@ -104,9 +158,9 @@ Then ask **Question 1**.
|
|
|
104
158
|
## Hard rules
|
|
105
159
|
|
|
106
160
|
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.
|
|
107
|
-
2. **
|
|
161
|
+
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.
|
|
108
162
|
3. **Do not invent** Cloudinary credentials, database URLs, Vercel Blob tokens, brand colours, **or LLM API keys**.
|
|
109
|
-
4. **Postgres env naming:** prefer **`SUPABASE_URL`** when using Supabase; prefer **`DATABASE_URL`**
|
|
163
|
+
4. **Postgres env naming:** prefer **`SUPABASE_URL`** when using Supabase; prefer **`DATABASE_URL`** when using Neon. `createTomorrowOSStore` accepts `SUPABASE_URL` then `DATABASE_URL`.
|
|
110
164
|
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).
|
|
111
165
|
6. **Prefer `npx @tomorrowos/sdk init`** (or `templates/cms-starter`) as the seed. Do not rebuild pairing / WebSocket / playlist APIs.
|
|
112
166
|
7. **Never commit secrets.** Use Vercel Environment Variables (+ optional non-secret flags in committed `.env.example`).
|
|
@@ -118,20 +172,148 @@ Then ask **Question 1**.
|
|
|
118
172
|
13. After Q&A: **configure → install → run/deploy → minimal verify** (Control Panel at `/`). Do not run a long test suite.
|
|
119
173
|
14. **No inventing CMS login.** A branding URL never means “build auth.” Only add login if the user **explicitly** requests it.
|
|
120
174
|
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.
|
|
175
|
+
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.
|
|
176
|
+
17. **Publish gate:** do not mark setup complete while Production returns `404: NOT_FOUND` **or** `/status` returns HTML (static `public/` trap).
|
|
177
|
+
18. **Scheme A is doc-driven:** achieve Production Node Publish by **project layout + `vercel.json` + dashboard settings** during setup — **no SDK code changes** required (see **Scheme A** section).
|
|
121
178
|
|
|
122
179
|
**Question order:** Q1 → Q2 → Q3 → execution checklist.
|
|
123
180
|
|
|
124
181
|
---
|
|
125
182
|
|
|
183
|
+
## Scheme A — Standard Node Publish (mandatory for Production)
|
|
184
|
+
|
|
185
|
+
> **Goal:** Preview may use Next + proxy; **Publish** runs **only** root `server.ts` + `TomorrowOS.listen` on Vercel Fluid.
|
|
186
|
+
> **Scope:** This section is implemented entirely during setup (move files, write `vercel.json`, patch dashboard). **Do not** change `@tomorrowos/sdk` source.
|
|
187
|
+
|
|
188
|
+
### Why Scheme A exists
|
|
189
|
+
|
|
190
|
+
| Layer | Preview (v0) | Publish (Production) |
|
|
191
|
+
|-------|----------------|----------------------|
|
|
192
|
+
| Host | Next.js shell + HTTP proxy | **Node `server.ts`** only |
|
|
193
|
+
| `public/` | Proxied from TomorrowOS | Served by **`staticRoot`** inside `listen()` — **not** as Vercel Output Directory |
|
|
194
|
+
| WebSocket | Optional / may fail in Preview | Required on same origin (`wss://`) |
|
|
195
|
+
| Next files | Allowed under `preview/` | **Must not** live at project root |
|
|
196
|
+
|
|
197
|
+
### A1 — Project layout (Agent must enforce)
|
|
198
|
+
|
|
199
|
+
**At project root (Production):**
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
server.ts ← REQUIRED name at root (or server.mts)
|
|
203
|
+
vercel.json
|
|
204
|
+
package.json
|
|
205
|
+
brand.json
|
|
206
|
+
public/ ← CMS static UI; NOT the Vercel output directory
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Preview only (when v0 needs Next) — move ALL of these under `preview/`:**
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
preview/
|
|
213
|
+
next.config.mjs
|
|
214
|
+
app/ ← Next proxy routes
|
|
215
|
+
postcss.config.mjs
|
|
216
|
+
next-env.d.ts
|
|
217
|
+
tsconfig.json ← Next/tsconfig if separate from server
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Remove from project root after move:** `next.config.mjs`, `app/`, root Next `tsconfig` plugin config, `postcss.config.mjs`, `next-env.d.ts`.
|
|
221
|
+
|
|
222
|
+
**Do NOT:**
|
|
223
|
+
|
|
224
|
+
- ❌ Leave `next.config.mjs` + `app/` at root while claiming Production is Node-only
|
|
225
|
+
- ❌ Create root `api/index.ts` exporting `http.Server` + `routes` catch-all
|
|
226
|
+
- ❌ Set Output Directory to `public` or `.`
|
|
227
|
+
|
|
228
|
+
**Update `package.json` scripts when Preview uses `preview/`:**
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"scripts": {
|
|
233
|
+
"dev": "tsx watch server.ts",
|
|
234
|
+
"dev:preview": "concurrently -k \"npm:dev:tomorrowos\" \"npm:dev:next\"",
|
|
235
|
+
"dev:tomorrowos": "cross-env TOMORROWOS_INTERNAL_PORT=3001 tsx watch server.ts",
|
|
236
|
+
"dev:next": "cd preview && next dev -p 3000",
|
|
237
|
+
"start": "tsx server.ts",
|
|
238
|
+
"build": "node -e \"process.exit(0)\""
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### A2 — `server.ts` entry (Vercel zero-config Node detection)
|
|
244
|
+
|
|
245
|
+
Vercel detects a **root** `server.ts` / `server.mts` and routes traffic to it when:
|
|
246
|
+
|
|
247
|
+
1. The file lives at **project root** (not only under `api/`)
|
|
248
|
+
2. **`listen()` runs at module load** (top-level, not inside an unexported function)
|
|
249
|
+
3. The file **`export default server`** (the `http.Server` from `tomorrowos.listen`)
|
|
250
|
+
|
|
251
|
+
Use the pattern in **Runtime & Vercel deploy rules** below. On Publish, **do not** set `TOMORROWOS_INTERNAL_PORT` — let Vercel inject `PORT`.
|
|
252
|
+
|
|
253
|
+
### A3 — `vercel.json` (Production)
|
|
254
|
+
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"fluid": true,
|
|
258
|
+
"framework": null,
|
|
259
|
+
"installCommand": "npm install",
|
|
260
|
+
"buildCommand": "npm run build",
|
|
261
|
+
"startCommand": "npm run start",
|
|
262
|
+
"outputDirectory": null
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Use `pnpm` / `yarn` equivalents if the project uses them.
|
|
267
|
+
|
|
268
|
+
**Critical:**
|
|
269
|
+
|
|
270
|
+
- `"outputDirectory": null` — **never** `"public"`, `"."`, or `"public if exists"`
|
|
271
|
+
- `"startCommand"` must be explicit when the dashboard keeps defaulting to static
|
|
272
|
+
- `"buildCommand"` must be the no-op `npm run build` — **never** `next build` for Production
|
|
273
|
+
|
|
274
|
+
### A4 — Vercel Project Settings (dashboard or API — mandatory)
|
|
275
|
+
|
|
276
|
+
`vercel.json` alone is **not enough** if the dashboard still shows Framework = **Next.js** or Output = `public`.
|
|
277
|
+
|
|
278
|
+
| Setting | Required value |
|
|
279
|
+
|---------|----------------|
|
|
280
|
+
| Framework Preset | **Other** / null — **not Next.js** |
|
|
281
|
+
| Install Command | `npm install` (or pnpm/yarn) |
|
|
282
|
+
| Build Command | `npm run build` (no-op exit 0) |
|
|
283
|
+
| **Output Directory** | **empty / null** — **NOT `public`** |
|
|
284
|
+
| **Start Command** | `npm run start` → `tsx server.ts` |
|
|
285
|
+
| Fluid compute | **On** |
|
|
286
|
+
|
|
287
|
+
If Framework Preset still shows **Next.js** after `vercel.json`: **patch via Vercel API / CLI / dashboard**, then redeploy.
|
|
288
|
+
|
|
289
|
+
### A5 — Publish acceptance (all must pass before “setup complete”)
|
|
290
|
+
|
|
291
|
+
1. Deploy logs show Node starting / `[TomorrowOS] listening on ...` (not only “Uploading static files”)
|
|
292
|
+
2. `curl -s https://PROD/status` → JSON (`{"status":...}`)
|
|
293
|
+
3. `curl -s https://PROD/` → Control Panel HTML
|
|
294
|
+
4. Control Panel **does not** show `Unexpected token 'T'` / CMS unreachable
|
|
295
|
+
5. Framework Preset = Other; Fluid on
|
|
296
|
+
|
|
297
|
+
If (2) fails but (3) passes → **static `public/` trap**. Re-apply A3 + A4; confirm `startCommand`; redeploy. **Do not** add `api/` catch-all.
|
|
298
|
+
|
|
299
|
+
### A6 — What Scheme A does **not** require
|
|
300
|
+
|
|
301
|
+
- ❌ No changes to `@tomorrowos/sdk` package code
|
|
302
|
+
- ❌ No `(req, res)` handler refactor
|
|
303
|
+
- ❌ No `next build` / `next start` on Production
|
|
304
|
+
- ❌ No root `api/` directory for the CMS server
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
126
308
|
## Runtime & Vercel deploy rules (mandatory)
|
|
127
309
|
|
|
128
310
|
### Production runtime (Publish)
|
|
129
311
|
|
|
130
|
-
- Serve with **`tsx server.ts`** (or compiled Node that still calls `TomorrowOS.listen` with `staticRoot`).
|
|
312
|
+
- Serve with **`tsx server.ts`** (or `server.mts` / compiled Node that still calls `TomorrowOS.listen` with `staticRoot`).
|
|
131
313
|
- Keep **`@tomorrowos/sdk`** and put **`tsx` in `dependencies`** (not only `devDependencies`) if production runs via `tsx`.
|
|
132
314
|
- Node **20+**.
|
|
133
315
|
- **Do not** replace the SDK with a hand-rolled server that drops WebSocket upgrades.
|
|
134
|
-
- **Forbidden as the Production Deploy entrypoint:** `next start`, static export only, or any command that does not start `TomorrowOS.listen(...)`.
|
|
316
|
+
- **Forbidden as the Production Deploy entrypoint:** `next start`, static export only, root `api/` fake catch-all for raw `http.Server`, or any command that does not start `TomorrowOS.listen(...)`.
|
|
135
317
|
|
|
136
318
|
### Expected `package.json` scripts
|
|
137
319
|
|
|
@@ -143,7 +325,7 @@ Then ask **Question 1**.
|
|
|
143
325
|
"dev:tomorrowos": "cross-env PORT=3001 TOMORROWOS_INTERNAL_PORT=3001 tsx watch server.ts",
|
|
144
326
|
"dev:next": "next dev -p 3000",
|
|
145
327
|
"start": "tsx server.ts",
|
|
146
|
-
"build": "
|
|
328
|
+
"build": "node -e \"process.exit(0)\""
|
|
147
329
|
}
|
|
148
330
|
}
|
|
149
331
|
```
|
|
@@ -151,6 +333,7 @@ Then ask **Question 1**.
|
|
|
151
333
|
Adapt script names / process runners as needed. **Invariant:**
|
|
152
334
|
|
|
153
335
|
- **`npm start` / Production** = TomorrowOS Node only.
|
|
336
|
+
- **`build`** = no-op exit 0 (never `next build` for Production).
|
|
154
337
|
- **Preview / v0** = Next on public port + TomorrowOS on internal port + proxy.
|
|
155
338
|
|
|
156
339
|
### Minimal dependencies (Production)
|
|
@@ -172,7 +355,8 @@ Adapt script names / process runners as needed. **Invariant:**
|
|
|
172
355
|
},
|
|
173
356
|
"scripts": {
|
|
174
357
|
"dev": "tsx watch server.ts",
|
|
175
|
-
"start": "tsx server.ts"
|
|
358
|
+
"start": "tsx server.ts",
|
|
359
|
+
"build": "node -e \"process.exit(0)\""
|
|
176
360
|
}
|
|
177
361
|
}
|
|
178
362
|
```
|
|
@@ -185,6 +369,8 @@ For Preview shell only, add as needed: `next`, `react`, `react-dom`, and a proce
|
|
|
185
369
|
|
|
186
370
|
### `server.ts` pattern (Vercel-adapted — Production)
|
|
187
371
|
|
|
372
|
+
Keep the server at **project root** (e.g. `server.ts` / `server.mts`). Do **not** move Production into `api/` solely to satisfy Vercel routing myths.
|
|
373
|
+
|
|
188
374
|
```ts
|
|
189
375
|
import "dotenv/config";
|
|
190
376
|
import { readFileSync } from "fs";
|
|
@@ -230,12 +416,12 @@ Load env with `dotenv` for local/`vercel dev`. On production Deploy, Vercel inje
|
|
|
230
416
|
|
|
231
417
|
Detect Preview / v0 (Next already present, or Preview blank while TomorrowOS logs “listening”). Then:
|
|
232
418
|
|
|
233
|
-
1. Keep a **minimal** Next app (
|
|
419
|
+
1. Keep a **minimal** Next app **isolated when possible** (e.g. under `preview/`) so Production Framework detection does not latch onto root `next.config.*`.
|
|
234
420
|
2. TomorrowOS listens on **`127.0.0.1:TOMORROWOS_INTERNAL_PORT`** (default **3001**).
|
|
235
421
|
3. Add a **catch-all** Next route (or middleware) that proxies HTTP to TomorrowOS:
|
|
236
422
|
|
|
237
423
|
```ts
|
|
238
|
-
// Example: app
|
|
424
|
+
// Example: preview app proxy handler
|
|
239
425
|
// Forward method, headers, and body to http://127.0.0.1:3001/<path>
|
|
240
426
|
// Return the upstream status, headers, and body to the browser.
|
|
241
427
|
```
|
|
@@ -250,24 +436,43 @@ Preferred UX: proxy **`/`** itself (rewrites) so the Preview URL shows the Contr
|
|
|
250
436
|
- Making Next the Production CMS or the only server after Publish.
|
|
251
437
|
- Deleting TomorrowOS `server.ts` because Preview needed Next.
|
|
252
438
|
- Claiming setup complete if Production entrypoint is still `next start`.
|
|
439
|
+
- Claiming setup complete if Production `GET /` is `404: NOT_FOUND`.
|
|
440
|
+
- Creating root `api/index.*` + `routes` catch-all that exports a raw `http.Server` “to fix 404”.
|
|
253
441
|
|
|
254
|
-
### `vercel.json` (
|
|
442
|
+
### `vercel.json` (Production — explicit Node, not Next)
|
|
255
443
|
|
|
256
|
-
|
|
444
|
+
Write `vercel.json` so Production cannot be mistaken for Next. Minimum:
|
|
257
445
|
|
|
258
446
|
```json
|
|
259
447
|
{
|
|
260
|
-
"fluid": true
|
|
448
|
+
"fluid": true,
|
|
449
|
+
"framework": null,
|
|
450
|
+
"installCommand": "npm install",
|
|
451
|
+
"buildCommand": "npm run build",
|
|
452
|
+
"startCommand": "npm run start",
|
|
453
|
+
"outputDirectory": null
|
|
261
454
|
}
|
|
262
455
|
```
|
|
263
456
|
|
|
264
|
-
|
|
457
|
+
Use `pnpm` / `yarn` variants of install/build/start if that is the project’s package manager.
|
|
265
458
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
459
|
+
**Also force Project Settings (dashboard or Vercel API) — this is mandatory (see Scheme A4):**
|
|
460
|
+
|
|
461
|
+
| Setting | Required value |
|
|
462
|
+
|---------|----------------|
|
|
463
|
+
| Framework Preset | **Other** / null — **not Next.js** |
|
|
464
|
+
| Install Command | `npm install` (or pnpm/yarn) |
|
|
465
|
+
| Build Command | `npm run build` (no-op exit 0) |
|
|
466
|
+
| Output Directory | **empty / null** — **NOT `public`** |
|
|
467
|
+
| Start Command | `npm run start` → `tsx server.ts` (or `.mts`) — **explicit in `vercel.json` too** |
|
|
468
|
+
| Fluid compute | **On** |
|
|
469
|
+
|
|
470
|
+
If `next` / `next.config.*` exist for Preview and the dashboard still auto-selects Next.js:
|
|
471
|
+
|
|
472
|
+
1. Patch Framework Preset to **Other** via API/CLI/dashboard.
|
|
473
|
+
2. Redeploy.
|
|
474
|
+
3. Hit Production `GET /status` — must be **JSON**, not HTML.
|
|
475
|
+
4. Hit Production `GET /` — must be Control Panel HTML, not `404: NOT_FOUND`.
|
|
271
476
|
|
|
272
477
|
If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a single long-lived Node HTTP server with WebSocket upgrade on `/` for Production**. Document the adaptation in the final summary.
|
|
273
478
|
|
|
@@ -282,6 +487,7 @@ If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a s
|
|
|
282
487
|
|
|
283
488
|
- ❌ `.replit`, `.replit-artifact`
|
|
284
489
|
- ❌ Next.js as the **Production** CMS (App Router replacing TomorrowOS)
|
|
490
|
+
- ❌ Root `api/` catch-all exporting raw `http.Server` to “fix” Publish 404
|
|
285
491
|
- ❌ Separate “API project” without the Control Panel
|
|
286
492
|
- ❌ Committing database passwords, Cloudinary secrets, or Blob tokens
|
|
287
493
|
|
|
@@ -307,52 +513,47 @@ If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a s
|
|
|
307
513
|
|
|
308
514
|
### Step B — If **1 / Supabase**
|
|
309
515
|
|
|
310
|
-
**Ask exactly:**
|
|
516
|
+
**Ask exactly (connection string only):**
|
|
311
517
|
|
|
312
|
-
> Paste your Supabase Postgres connection string. I will store it as
|
|
518
|
+
> Paste your Supabase Postgres connection string. I will store it as **`SUPABASE_URL`**.
|
|
313
519
|
>
|
|
314
520
|
> In Supabase: **Project Settings → Database → Connection string → Connection pooling** (Session mode).
|
|
315
521
|
> Preferred shape:
|
|
316
522
|
> `postgresql://postgres.[PROJECT]:[PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres`
|
|
317
523
|
>
|
|
318
|
-
> **Do not** use the direct host `db.*.supabase.co:5432` for Vercel
|
|
319
|
-
>
|
|
320
|
-
> Confirm SSL is required (usually **yes** for Supabase).
|
|
524
|
+
> **Do not** use the direct host `db.*.supabase.co:5432` for Vercel.
|
|
321
525
|
|
|
322
|
-
**You must then:**
|
|
526
|
+
**You must then (automatic — do NOT ask the user to type these):**
|
|
323
527
|
|
|
324
|
-
1. Set Vercel Env Vars
|
|
325
|
-
- `SUPABASE_URL=<pooler string>`
|
|
326
|
-
- `TOMORROWOS_STORE=supabase`
|
|
327
|
-
- `DATABASE_SSL=true` (unless user
|
|
528
|
+
1. Set Vercel Env Vars:
|
|
529
|
+
- `SUPABASE_URL=<user pooler string>`
|
|
530
|
+
- `TOMORROWOS_STORE=supabase` ← **agent sets this**
|
|
531
|
+
- `DATABASE_SSL=true` ← **agent sets this** (unless user already said SSL is off)
|
|
328
532
|
2. Wire `server.ts` as in **Runtime & Vercel deploy rules**.
|
|
329
|
-
3. Optional committed `.env.example` with **placeholders only
|
|
533
|
+
3. Optional committed `.env.example` with **placeholders only**.
|
|
330
534
|
4. **Do not** commit the real connection string.
|
|
331
|
-
5. **
|
|
535
|
+
5. **Do not** open a second form asking for `TOMORROWOS_STORE` or `DATABASE_SSL`.
|
|
332
536
|
|
|
333
537
|
### Step C — If **2 / Neon**
|
|
334
538
|
|
|
335
|
-
**Ask exactly:**
|
|
539
|
+
**Ask exactly (connection string only):**
|
|
336
540
|
|
|
337
|
-
> Paste your **Neon pooled** Postgres connection string. I will store it as **`DATABASE_URL
|
|
541
|
+
> Paste your **Neon pooled** Postgres connection string. I will store it as **`DATABASE_URL`**.
|
|
338
542
|
>
|
|
339
|
-
> In Neon: **Dashboard → Connection details → Pooled connection
|
|
543
|
+
> In Neon: **Dashboard → Connection details → Pooled connection**.
|
|
340
544
|
> Typical shape:
|
|
341
|
-
> `postgresql://[user]:[password]@[endpoint]
|
|
342
|
-
>
|
|
343
|
-
> **Do not** use the direct (non-pooled) connection string for Vercel serverless unless Neon docs explicitly say otherwise for your plan.
|
|
344
|
-
>
|
|
345
|
-
> Confirm SSL (`sslmode=require`) is on (usually **yes**).
|
|
545
|
+
> `postgresql://[user]:[password]@[endpoint]-pooler.[region].aws.neon.tech/[dbname]?sslmode=require`
|
|
346
546
|
|
|
347
|
-
**You must then:**
|
|
547
|
+
**You must then (automatic — do NOT ask the user to type these):**
|
|
348
548
|
|
|
349
549
|
1. Set Vercel Env Vars:
|
|
350
|
-
- `DATABASE_URL=<pooled
|
|
351
|
-
- `TOMORROWOS_STORE=postgres`
|
|
352
|
-
- `DATABASE_SSL=true`
|
|
550
|
+
- `DATABASE_URL=<user pooled string>`
|
|
551
|
+
- `TOMORROWOS_STORE=postgres` ← **agent sets this**
|
|
552
|
+
- `DATABASE_SSL=true` ← **agent sets this**
|
|
353
553
|
2. Wire `server.ts` — `createTomorrowOSStore` uses `PostgresStore` for `postgres` / `supabase` drivers.
|
|
354
554
|
3. **Do not** commit the real connection string.
|
|
355
|
-
4.
|
|
555
|
+
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.
|
|
556
|
+
5. If you see `ENETUNREACH` on `:5432`, switch to Neon’s **pooled** URL.
|
|
356
557
|
|
|
357
558
|
### Step D — If **3 / SQLite**
|
|
358
559
|
|
|
@@ -362,9 +563,9 @@ If Vercel’s UI and this file disagree on bundling, **prefer whatever keeps a s
|
|
|
362
563
|
|
|
363
564
|
Only proceed after the user explicitly confirms.
|
|
364
565
|
|
|
365
|
-
**You must then:**
|
|
566
|
+
**You must then (automatic):**
|
|
366
567
|
|
|
367
|
-
1. Set `TOMORROWOS_STORE=sqlite` (
|
|
568
|
+
1. Set `TOMORROWOS_STORE=sqlite` yourself (do not ask the user to type it).
|
|
368
569
|
2. Keep `sqlitePath` in `server.ts` for `data/tomorrowos.db`.
|
|
369
570
|
3. Warn again in the final summary that they should move to Supabase or Neon for real devices.
|
|
370
571
|
|
|
@@ -391,46 +592,33 @@ Only proceed after the user explicitly confirms.
|
|
|
391
592
|
>
|
|
392
593
|
> Reply with **1**, **2**, or **3** (or “Cloudinary” / “Vercel Blob” / “local”).
|
|
393
594
|
|
|
394
|
-
### Step B — If **1 / Cloudinary** (same Question 2 —
|
|
395
|
-
|
|
396
|
-
> **Critical UX rule:** Collect Cloudinary credentials in **separate messages**. Never ask for API key and API secret in the same message or the same form field group.
|
|
595
|
+
### Step B — If **1 / Cloudinary** (same Question 2 — **one Env popup**)
|
|
397
596
|
|
|
398
|
-
|
|
597
|
+
> **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.
|
|
399
598
|
|
|
400
|
-
**
|
|
401
|
-
|
|
402
|
-
> Paste your Cloudinary **Cloud name** only (`CLOUDINARY_CLOUD_NAME`).
|
|
403
|
-
> Find it at [cloudinary.com/console](https://cloudinary.com/console) → Dashboard.
|
|
404
|
-
|
|
405
|
-
Save as Vercel Env Var `CLOUDINARY_CLOUD_NAME`. Do **not** ask for key or secret yet.
|
|
406
|
-
|
|
407
|
-
#### B2 — API key (ask alone — after B1 is saved)
|
|
408
|
-
|
|
409
|
-
**Ask exactly:**
|
|
599
|
+
**Preferred:** Vercel Env Vars UI (or Agent secrets form) with these fields together:
|
|
410
600
|
|
|
411
|
-
|
|
412
|
-
|
|
601
|
+
| Field | Env name | Required |
|
|
602
|
+
|-------|----------|----------|
|
|
603
|
+
| Cloud name | `CLOUDINARY_CLOUD_NAME` | Yes |
|
|
604
|
+
| API Key | `CLOUDINARY_API_KEY` | Yes |
|
|
605
|
+
| API Secret | `CLOUDINARY_API_SECRET` | Yes |
|
|
606
|
+
| Folder (optional) | `CLOUDINARY_FOLDER` | No (e.g. `tomorrowos`) |
|
|
413
607
|
|
|
414
|
-
|
|
608
|
+
**If a multi-field popup is unavailable, ask once in a single message** (still not three turns):
|
|
415
609
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
>
|
|
421
|
-
>
|
|
422
|
-
|
|
423
|
-
Save as Vercel Env Var `CLOUDINARY_API_SECRET`.
|
|
424
|
-
|
|
425
|
-
Optional fourth message (only if useful):
|
|
426
|
-
|
|
427
|
-
> Optional: Cloudinary folder name (`CLOUDINARY_FOLDER`, e.g. `tomorrowos`). Press Enter to skip.
|
|
610
|
+
> Paste Cloudinary credentials from [cloudinary.com/console](https://cloudinary.com/console) (I will store them as Vercel Env Vars):
|
|
611
|
+
>
|
|
612
|
+
> 1. `CLOUDINARY_CLOUD_NAME`
|
|
613
|
+
> 2. `CLOUDINARY_API_KEY`
|
|
614
|
+
> 3. `CLOUDINARY_API_SECRET`
|
|
615
|
+
> 4. optional `CLOUDINARY_FOLDER`
|
|
428
616
|
|
|
429
617
|
**You must then:**
|
|
430
618
|
|
|
431
|
-
1.
|
|
619
|
+
1. Save all three required Env Vars for Production + Preview + Development as appropriate.
|
|
432
620
|
2. **Do not** invent placeholders.
|
|
433
|
-
3. **Do not** proceed to Question 3 until all three exist.
|
|
621
|
+
3. **Do not** proceed to Question 3 until all three required vars exist.
|
|
434
622
|
4. **Do not** run a formal Cloudinary upload test unless the user asks.
|
|
435
623
|
|
|
436
624
|
The SDK auto-detects these env vars.
|
|
@@ -448,7 +636,7 @@ The SDK auto-detects these env vars.
|
|
|
448
636
|
|
|
449
637
|
**You must then:**
|
|
450
638
|
|
|
451
|
-
1. Set Vercel Env Var: `BLOB_READ_WRITE_TOKEN=<token>` (if not auto-injected).
|
|
639
|
+
1. Set Vercel Env Var: `BLOB_READ_WRITE_TOKEN=<token>` (if not auto-injected). Prefer the Env popup when available.
|
|
452
640
|
2. `npm install @vercel/blob` (add to `dependencies`).
|
|
453
641
|
3. Wire uploads so media returns **absolute HTTPS Blob URLs** stored in `uploaded_assets` (players need stable public URLs).
|
|
454
642
|
- The SDK **natively auto-detects Cloudinary** today. For Vercel Blob, add a thin upload bridge in the CMS project (e.g. custom route or middleware that calls `put()` from `@vercel/blob` and persists the returned `url` the same way Cloudinary URLs are stored).
|
|
@@ -574,28 +762,27 @@ npx @tomorrowos/sdk@latest init .
|
|
|
574
762
|
# npx @tomorrowos/sdk@latest init . --force
|
|
575
763
|
```
|
|
576
764
|
|
|
577
|
-
Then:
|
|
765
|
+
Then (**Scheme A — mandatory for Publish**):
|
|
578
766
|
|
|
579
|
-
1. Keep
|
|
580
|
-
2. If
|
|
581
|
-
3.
|
|
582
|
-
4.
|
|
583
|
-
5. Do **not** add `.
|
|
584
|
-
6.
|
|
767
|
+
1. Keep **`server.ts`** at **project root** with top-level `listen()` + `export default server`.
|
|
768
|
+
2. If Preview needs Next: **move** `next.config.*`, `app/`, Next `tsconfig` / `postcss` / `next-env.d.ts` into **`preview/`** — remove them from root so Production is not mistaken for Next/static.
|
|
769
|
+
3. Write `vercel.json` per **Scheme A3** (`fluid`, `framework: null`, `startCommand`, `outputDirectory: null`).
|
|
770
|
+
4. **Force Project Settings** per **Scheme A4** (Framework = Other, Output Directory empty, Start = `npm run start`, Fluid on). Patch dashboard via API if it still says Next.js.
|
|
771
|
+
5. Do **not** add root `api/` catch-all for raw `http.Server`.
|
|
772
|
+
6. Do **not** add `.replit*`.
|
|
773
|
+
7. If Q2 = Vercel Blob: install `@vercel/blob` and wire the upload bridge.
|
|
585
774
|
|
|
586
775
|
### B. Environment Variables (Vercel dashboard + local)
|
|
587
776
|
|
|
588
|
-
| Name | Required |
|
|
589
|
-
|
|
590
|
-
| `SUPABASE_URL` | If Q1 = Supabase |
|
|
591
|
-
| `DATABASE_URL` | If Q1 = Neon |
|
|
592
|
-
| `TOMORROWOS_STORE` | Yes | `supabase
|
|
593
|
-
| `DATABASE_SSL` | Yes
|
|
594
|
-
| `
|
|
595
|
-
| `
|
|
596
|
-
| `
|
|
597
|
-
| `BLOB_READ_WRITE_TOKEN` | If Q2 = Vercel Blob | From Vercel Blob store |
|
|
598
|
-
| `TOMORROWOS_INTERNAL_PORT` | Preview only | e.g. `3001` when Next owns `:3000` |
|
|
777
|
+
| Name | Required | Who fills it |
|
|
778
|
+
|------|----------|--------------|
|
|
779
|
+
| `SUPABASE_URL` | If Q1 = Supabase | User pastes URL |
|
|
780
|
+
| `DATABASE_URL` | If Q1 = Neon | User pastes URL |
|
|
781
|
+
| `TOMORROWOS_STORE` | Yes | **Agent auto-sets** (`supabase` / `postgres` / `sqlite`) |
|
|
782
|
+
| `DATABASE_SSL` | Yes for Postgres | **Agent auto-sets** `true` |
|
|
783
|
+
| `CLOUDINARY_*` | If Q2 = Cloudinary | User via **one Env popup** (all fields) |
|
|
784
|
+
| `BLOB_READ_WRITE_TOKEN` | If Q2 = Vercel Blob | User / Blob link |
|
|
785
|
+
| `TOMORROWOS_INTERNAL_PORT` | Preview only | Agent (e.g. `3001`) |
|
|
599
786
|
| `PORT` | Optional | Vercel injects for Production |
|
|
600
787
|
|
|
601
788
|
Mirror non-secrets in `.env` for local `npm run dev` if helpful; never commit secrets.
|
|
@@ -621,12 +808,17 @@ vercel --prod
|
|
|
621
808
|
# or git push → Vercel Git integration
|
|
622
809
|
```
|
|
623
810
|
|
|
624
|
-
|
|
811
|
+
**Publish acceptance checklist (all must pass — Scheme A5):**
|
|
812
|
+
|
|
813
|
+
1. Framework Preset = **Other** / null (dashboard confirms — not Next.js)
|
|
814
|
+
2. Output Directory = **empty** (not `public`)
|
|
815
|
+
3. Start Command = Node `TomorrowOS.listen` (`npm run start` / `tsx server.ts`)
|
|
816
|
+
4. Fluid compute on
|
|
817
|
+
5. Env Vars present for Production
|
|
818
|
+
6. Production `GET /status` returns **JSON** — **not** HTML (`Unexpected token 'T'` means this failed)
|
|
819
|
+
7. Production `GET /` returns Control Panel HTML — **not** `404: NOT_FOUND`
|
|
625
820
|
|
|
626
|
-
|
|
627
|
-
2. **Not** `next start` as Production
|
|
628
|
-
3. Fluid compute on
|
|
629
|
-
4. Env Vars present for Production environment
|
|
821
|
+
If step 6 fails but step 7 passes: **static `public/` trap** — Vercel is not running Node. Re-apply Scheme A3–A4; do **not** invent `api/` + `routes`.
|
|
630
822
|
|
|
631
823
|
Tell the user:
|
|
632
824
|
|
|
@@ -638,11 +830,12 @@ Tell the user:
|
|
|
638
830
|
|
|
639
831
|
**Do:**
|
|
640
832
|
|
|
641
|
-
1. Preview: Control Panel HTML at `/` (via Next proxy if applicable)
|
|
642
|
-
2. Publish:
|
|
643
|
-
3.
|
|
644
|
-
4.
|
|
645
|
-
5.
|
|
833
|
+
1. Preview: Control Panel HTML at `/` (via Next proxy in `preview/` if applicable)
|
|
834
|
+
2. Publish: `GET /status` → JSON; `GET /` → Control Panel from **Node** TomorrowOS
|
|
835
|
+
3. Publish: panel does **not** show `Unexpected token 'T'` / CMS unreachable
|
|
836
|
+
4. Server status: Media OK when Cloudinary or Blob configured
|
|
837
|
+
5. Database: if ERROR shows **`ENETUNREACH` … IPv6 … `:5432`**, switch to **pooled** URL (Supabase `:6543` or Neon pooler) and redeploy — call this out explicitly to the user
|
|
838
|
+
6. Fluid compute on for Production
|
|
646
839
|
|
|
647
840
|
**Do not block** on long WebSocket/device pairing tests unless the user asks. Prefer pairing against **Publish**, not Preview.
|
|
648
841
|
|
|
@@ -652,6 +845,10 @@ Tell the user:
|
|
|
652
845
|
|
|
653
846
|
| Symptom | Likely cause | Fix |
|
|
654
847
|
|---------|--------------|-----|
|
|
848
|
+
| Publish `404: NOT_FOUND` | Framework Preset still **Next.js** / no Node start | Scheme A: Framework = **Other**, Start = `npm run start`, Output empty, Fluid on; redeploy |
|
|
849
|
+
| Panel loads but **CMS unreachable** / `Unexpected token 'T', "The page c"...` | **`public/` deployed as static site** — no Node running | Scheme A: `outputDirectory: null`, explicit `startCommand`, move Next to `preview/`; verify `GET /status` returns JSON |
|
|
850
|
+
| `vercel inspect` shows Output = `public if it exists` | Framework=Other static default | Force Output Directory **empty** in dashboard + `outputDirectory: null`; ensure root `server.ts` + `startCommand` |
|
|
851
|
+
| Build runs `next build` / missing routes-manifest | Next auto-detected from root `next.config` / `app/` | Move Next to `preview/`; Framework null/Other; `build` = no-op |
|
|
655
852
|
| Preview blank but logs show TomorrowOS listening | v0 Next intercepts public port | Add Next reverse proxy → internal TomorrowOS port |
|
|
656
853
|
| Preview works, Publish broken / Next-only | Production still on Next | Switch Production entry to `tsx server.ts` / `export default server` |
|
|
657
854
|
| `ENETUNREACH` / IPv6 / `:5432` | Direct Postgres URL | Use **pooled** URL (Supabase `:6543` or Neon pooler) |
|
|
@@ -660,12 +857,12 @@ Tell the user:
|
|
|
660
857
|
| Blob uploads 401 / missing token | Blob not linked | Vercel Storage → Blob + `BLOB_READ_WRITE_TOKEN` |
|
|
661
858
|
| WebSocket fails on Publish | Fluid off / static-only / Next as Production | Enable Fluid; sole Node `listen()` for Publish |
|
|
662
859
|
| Devices fail only on Preview | Next proxy cannot upgrade `wss` | Expected — pair on Publish URL |
|
|
663
|
-
| Agent
|
|
664
|
-
|
|
|
665
|
-
| Replit files present | Copied wrong protocol | Delete `.replit*`; use this file |
|
|
666
|
-
| Brand colours wrong from URL | SPA / blocked fetch | Manual Option B for colours + logo |
|
|
860
|
+
| Agent asked user to fill `TOMORROWOS_STORE` / `DATABASE_SSL` | Off-protocol | Agent must auto-set those after Neon/Supabase choice |
|
|
861
|
+
| Agent asked Cloudinary key/secret in three chat turns | Off-protocol | Use **one Env popup** with all Cloudinary fields |
|
|
667
862
|
| 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 |
|
|
668
863
|
| 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` |
|
|
864
|
+
| Secrets in git | Mistake | Rotate keys; move to Vercel Env Vars |
|
|
865
|
+
| Replit files present | Copied wrong protocol | Delete `.replit*`; use this file |
|
|
669
866
|
|
|
670
867
|
---
|
|
671
868
|
|
|
@@ -674,12 +871,12 @@ Tell the user:
|
|
|
674
871
|
| Topic | Replit | Vercel |
|
|
675
872
|
|-------|--------|--------|
|
|
676
873
|
| Secrets | Replit Secrets | Vercel Environment Variables |
|
|
677
|
-
| Deploy config | `.replit`, artifact `kind=web` | `vercel.json` + Fluid; **no** `.replit` |
|
|
874
|
+
| Deploy config | `.replit`, artifact `kind=web` | `vercel.json` + Fluid; **Framework = Other**; **no** `.replit` |
|
|
678
875
|
| `hostingTarget` | `"here"` | `"vercel"` |
|
|
679
876
|
| Database | Supabase (primary) | Supabase **or Neon** (pooled); SQLite demo only |
|
|
680
877
|
| Media | Cloudinary or Replit Object Storage | Cloudinary **or Vercel Blob** |
|
|
681
878
|
| Preview | Replit Preview / Autoscale Node | **Next shell + proxy** when v0 hardwires Next |
|
|
682
|
-
| Publish | Long-lived Node | **Node `TomorrowOS.listen` only** (not Next) |
|
|
879
|
+
| Publish | Long-lived Node | **Node `TomorrowOS.listen` only** (not Next); gate on no `404 NOT_FOUND` |
|
|
683
880
|
| Brand from URL | Not in Replit protocol | **Option A** — infer **`brand.json` only**; never invent login |
|
|
684
881
|
|
|
685
882
|
---
|
|
@@ -689,18 +886,19 @@ Tell the user:
|
|
|
689
886
|
After setup, report:
|
|
690
887
|
|
|
691
888
|
1. **Live URL** (Production Publish)
|
|
692
|
-
2. **
|
|
693
|
-
3. **
|
|
694
|
-
4. **
|
|
695
|
-
5. **
|
|
696
|
-
6. **
|
|
697
|
-
7. **
|
|
698
|
-
8. **
|
|
889
|
+
2. **Publish health:** Framework = Other; Output ≠ `public`; `GET /status` → JSON; `GET /` OK
|
|
890
|
+
3. **Preview note:** Next proxy shell used / not needed
|
|
891
|
+
4. **Env Vars set** (names only — never values); note which were auto-set (`TOMORROWOS_STORE`, `DATABASE_SSL`)
|
|
892
|
+
5. **Store:** Supabase pooler / Neon pooled / SQLite (with warning)
|
|
893
|
+
6. **Media:** Cloudinary, Vercel Blob, or local (with warning)
|
|
894
|
+
7. **Brand:** name + `hostingTarget: vercel` (+ note if derived from website URL)
|
|
895
|
+
8. **Runtime split:** Preview = … ; Publish = Node TomorrowOS (confirm **not** Next)
|
|
896
|
+
9. **Open action:** if Database still ERROR, paste the pooler instruction again
|
|
699
897
|
|
|
700
898
|
Protocol complete when:
|
|
701
899
|
|
|
702
900
|
- **Preview** shows the Control Panel at `/` (via Next proxy if required), **and**
|
|
703
|
-
- **Publish**
|
|
901
|
+
- **Publish** returns Control Panel at `/` **and** `/status` JSON from pure Node `TomorrowOS.listen` with Fluid (not static `public/`, not `404: NOT_FOUND`, not `Unexpected token 'T'`), **and**
|
|
704
902
|
- Q1–Q3 configuration is saved
|
|
705
903
|
|
|
706
904
|
— even if a sandbox DB probe still flakes **after** the pooled URL is correctly set for Production.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.27",
|
|
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.
|
|
3
|
+
"version": "0.9.27",
|
|
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.
|
|
16
|
+
"@tomorrowos/sdk": "^0.9.27",
|
|
17
17
|
"dotenv": "^17.2.3",
|
|
18
18
|
"tsx": "^4.19.0"
|
|
19
19
|
},
|