@tomorrowos/sdk 0.9.31 → 0.9.32

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/package.json CHANGED
@@ -1,51 +1,51 @@
1
- {
2
- "name": "@tomorrowos/sdk",
3
- "version": "0.9.31",
4
- "description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- }
13
- },
14
- "bin": {
15
- "tomorrowos": "./dist/cli.js"
16
- },
17
- "files": [
18
- "dist",
19
- "templates",
20
- "README.md",
21
- "LLM_PROMPT.md",
22
- "REPLIT_SETUP.md",
23
- "VERCEL_SETUP.md",
24
- "REPLIT_UPGRADE.md",
25
- "BUILD_GUARDRAILS.md",
26
- "PLAYER_INSTALL.md",
27
- "brand.schema.json",
28
- "brand.example.json"
29
- ],
30
- "scripts": {
31
- "build": "tsc",
32
- "prepublishOnly": "npm run build"
33
- },
34
- "engines": {
35
- "node": ">=18"
36
- },
37
- "dependencies": {
38
- "better-sqlite3": "^12.11.1",
39
- "cloudinary": "^2.10.0",
40
- "pg": "^8.22.0",
41
- "ws": "^8.21.0"
42
- },
43
- "devDependencies": {
44
- "@types/better-sqlite3": "^7.6.13",
45
- "@types/node": "^20.19.41",
46
- "@types/pg": "^8.20.0",
47
- "@types/ws": "^8.5.10",
48
- "typescript": "^5.5.0"
49
- },
50
- "license": "Apache-2.0"
51
- }
1
+ {
2
+ "name": "@tomorrowos/sdk",
3
+ "version": "0.9.32",
4
+ "description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "bin": {
15
+ "tomorrowos": "./dist/cli.js"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "templates",
20
+ "README.md",
21
+ "LLM_PROMPT.md",
22
+ "REPLIT_SETUP.md",
23
+ "VERCEL_SETUP.md",
24
+ "REPLIT_UPGRADE.md",
25
+ "BUILD_GUARDRAILS.md",
26
+ "PLAYER_INSTALL.md",
27
+ "brand.schema.json",
28
+ "brand.example.json"
29
+ ],
30
+ "scripts": {
31
+ "build": "tsc",
32
+ "prepublishOnly": "npm run build"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "dependencies": {
38
+ "better-sqlite3": "^12.11.1",
39
+ "cloudinary": "^2.10.0",
40
+ "pg": "^8.22.0",
41
+ "ws": "^8.21.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/better-sqlite3": "^7.6.13",
45
+ "@types/node": "^20.19.41",
46
+ "@types/pg": "^8.20.0",
47
+ "@types/ws": "^8.5.10",
48
+ "typescript": "^5.5.0"
49
+ },
50
+ "license": "Apache-2.0"
51
+ }
@@ -1,25 +1,25 @@
1
- {
2
- "name": "my-cms",
3
- "version": "0.9.31",
4
- "description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
5
- "private": true,
6
- "type": "module",
7
- "engines": {
8
- "node": ">=20"
9
- },
10
- "scripts": {
11
- "dev": "tsx watch server.ts",
12
- "start": "tsx server.ts",
13
- "build-player": "tomorrowos build --platform tizen"
14
- },
15
- "dependencies": {
16
- "@tomorrowos/sdk": "^0.9.31",
17
- "dotenv": "^17.2.3",
18
- "tsx": "^4.19.0"
19
- },
20
- "devDependencies": {
21
- "@types/node": "^20.0.0",
22
- "typescript": "^5.5.0"
23
- }
24
- }
25
-
1
+ {
2
+ "name": "my-cms",
3
+ "version": "0.9.32",
4
+ "description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
5
+ "private": true,
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "scripts": {
11
+ "dev": "tsx watch server.ts",
12
+ "start": "tsx server.ts",
13
+ "build-player": "tomorrowos build --platform tizen"
14
+ },
15
+ "dependencies": {
16
+ "@tomorrowos/sdk": "^0.9.32",
17
+ "dotenv": "^17.2.3",
18
+ "tsx": "^4.19.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^20.0.0",
22
+ "typescript": "^5.5.0"
23
+ }
24
+ }
25
+
@@ -1,8 +1,14 @@
1
1
  # TomorrowOS CMS Starter (Vercel / v0)
2
2
 
3
- - **Publish:** Fluid Function `api/index.ts` `export default server` (WebSockets)
4
- - **Preview (v0):** root Next.js shell proxies HTTP → TomorrowOS on `:3001`
5
- - **`cms-panel/`** Control Panel static files (not `public/`)
3
+ This starter is for **Vercel Publish** and **v0**. It follows
4
+ [Vercel Functions WebSockets](https://vercel.com/docs/functions/websockets):
5
+
6
+ - **`cms-app.ts`** — shared `TomorrowOS.listen` + `export const server`
7
+ - **`api/index.ts`** — Production Function: `export default server` (Fluid)
8
+ - **`server.ts`** — local / Preview: same server (`npm start`)
9
+ - **`cms-panel/`** — Control Panel static files (not `public/`)
10
+ - **`preview/`** — Next.js shell for v0 Preview only
11
+ - **`vercel.json`** — `fluid`, rewrites → `/api`, `maxDuration`
6
12
 
7
13
  ## Scaffold
8
14
 
@@ -10,26 +16,35 @@
10
16
  npx @tomorrowos/sdk init my-cms --hosting v0
11
17
  ```
12
18
 
13
- ## Local / v0 Preview
19
+ ## Local development
14
20
 
15
21
  ```bash
16
22
  npm install
17
23
  npm run dev
18
24
  ```
19
25
 
20
- `npm run dev` starts **both**:
26
+ Open `http://localhost:3000`. Pairing uses `ws://localhost:3000/` (root path).
27
+
28
+ ### v0-style Preview
29
+
30
+ ```bash
31
+ npm run dev:preview
32
+ ```
21
33
 
22
- 1. TomorrowOS on `http://127.0.0.1:3001`
23
- 2. Next on `http://localhost:3000` → proxies `/` to TomorrowOS
34
+ Pair devices against the **Publish URL**, not Preview.
24
35
 
25
- Open Preview at `http://localhost:3000` — you should see the Control Panel, **not** “Your v0 generation will show here”.
36
+ ## Production acceptance
26
37
 
27
- ## Production
38
+ 1. `GET /status` → JSON
39
+ 2. `GET /` → Control Panel
40
+ 3. WebSocket upgrade on `/` or `/api` → **101** (not 200 HTML)
28
41
 
29
- Unchanged: `vercel.json` + `api/index.ts`. Acceptance: `/status` JSON + WebSocket **101**.
42
+ TV endpoint: `https://YOUR.vercel.app/` (players also try `/api` on `*.vercel.app`).
30
43
 
31
44
  ## Replit / Railway
32
45
 
46
+ Use the default starter (unchanged Node listen, no `api/` Function):
47
+
33
48
  ```bash
34
49
  npx @tomorrowos/sdk init my-cms --hosting replit
35
50
  ```
@@ -1,35 +1,35 @@
1
- {
2
- "name": "my-cms",
3
- "version": "0.9.31",
4
- "description": "TomorrowOS CMS for Vercel / v0 (Fluid Function Publish + Next Preview proxy).",
5
- "private": true,
6
- "type": "module",
7
- "engines": {
8
- "node": ">=20"
9
- },
10
- "scripts": {
11
- "dev": "npm run dev:preview",
12
- "dev:tomorrowos": "cross-env TOMORROWOS_INTERNAL_PORT=3001 tsx watch server.ts",
13
- "dev:next": "next dev -p 3000",
14
- "dev:preview": "concurrently -k -n cms,next -c cyan,magenta \"npm:dev:tomorrowos\" \"npm:dev:next\"",
15
- "start": "tsx server.ts",
16
- "build": "node -e \"process.exit(0)\"",
17
- "build-player": "tomorrowos build --platform tizen"
18
- },
19
- "dependencies": {
20
- "@tomorrowos/sdk": "^0.9.31",
21
- "concurrently": "^9.1.2",
22
- "cross-env": "^7.0.3",
23
- "dotenv": "^17.2.3",
24
- "next": "^15.1.0",
25
- "react": "^19.0.0",
26
- "react-dom": "^19.0.0",
27
- "tsx": "^4.19.0"
28
- },
29
- "devDependencies": {
30
- "@types/node": "^20.0.0",
31
- "@types/react": "^19.0.0",
32
- "@types/react-dom": "^19.0.0",
33
- "typescript": "^5.5.0"
34
- }
35
- }
1
+ {
2
+ "name": "my-cms",
3
+ "version": "0.9.32",
4
+ "description": "TomorrowOS CMS for Vercel / v0 Publish (Fluid Function + WebSockets + optional Next Preview).",
5
+ "private": true,
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "scripts": {
11
+ "dev": "tsx watch server.ts",
12
+ "dev:tomorrowos": "cross-env TOMORROWOS_INTERNAL_PORT=3001 tsx watch server.ts",
13
+ "dev:next": "cd preview && next dev -p 3000",
14
+ "dev:preview": "concurrently -k \"npm:dev:tomorrowos\" \"npm:dev:next\"",
15
+ "start": "tsx server.ts",
16
+ "build": "node -e \"process.exit(0)\"",
17
+ "build-player": "tomorrowos build --platform tizen"
18
+ },
19
+ "dependencies": {
20
+ "@tomorrowos/sdk": "^0.9.32",
21
+ "dotenv": "^17.2.3",
22
+ "tsx": "^4.19.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/node": "^20.0.0",
26
+ "@types/react": "^19.0.0",
27
+ "@types/react-dom": "^19.0.0",
28
+ "concurrently": "^9.1.2",
29
+ "cross-env": "^7.0.3",
30
+ "next": "^15.1.0",
31
+ "react": "^19.0.0",
32
+ "react-dom": "^19.0.0",
33
+ "typescript": "^5.5.0"
34
+ }
35
+ }
@@ -0,0 +1,11 @@
1
+ export default function RootLayout({
2
+ children
3
+ }: {
4
+ children: React.ReactNode;
5
+ }) {
6
+ return (
7
+ <html lang="en">
8
+ <body>{children}</body>
9
+ </html>
10
+ );
11
+ }
@@ -0,0 +1,3 @@
1
+ export default function PreviewShellPage() {
2
+ return null;
3
+ }
@@ -0,0 +1,2 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
@@ -0,0 +1,18 @@
1
+ const internalUrl =
2
+ process.env.TOMORROWOS_INTERNAL_URL || "http://127.0.0.1:3001";
3
+
4
+ /** @type {import('next').NextConfig} */
5
+ const nextConfig = {
6
+ async rewrites() {
7
+ return {
8
+ fallback: [
9
+ {
10
+ source: "/:path*",
11
+ destination: `${internalUrl}/:path*`
12
+ }
13
+ ]
14
+ };
15
+ }
16
+ };
17
+
18
+ export default nextConfig;
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [{ "name": "next" }]
17
+ },
18
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
19
+ "exclude": ["node_modules"]
20
+ }
@@ -9,6 +9,5 @@
9
9
  "noEmit": true,
10
10
  "types": ["node"]
11
11
  },
12
- "include": ["server.ts", "cms-app.ts", "api/**/*.ts"],
13
- "exclude": ["app", "node_modules", ".next"]
12
+ "include": ["server.ts"]
14
13
  }
@@ -1,89 +0,0 @@
1
- /**
2
- * v0 / local Preview shell — proxies all HTTP to TomorrowOS on :3001.
3
- * Production Publish does NOT use this file; traffic goes to api/index.ts (Fluid).
4
- */
5
-
6
- const INTERNAL =
7
- process.env.TOMORROWOS_INTERNAL_URL || "http://127.0.0.1:3001";
8
-
9
- const HOP_BY_HOP = new Set([
10
- "connection",
11
- "keep-alive",
12
- "proxy-authenticate",
13
- "proxy-authorization",
14
- "te",
15
- "trailers",
16
- "transfer-encoding",
17
- "upgrade",
18
- "host",
19
- "content-length"
20
- ]);
21
-
22
- async function proxyToTomorrowOS(req: Request): Promise<Response> {
23
- const incoming = new URL(req.url);
24
- const target = new URL(incoming.pathname + incoming.search, INTERNAL);
25
-
26
- const headers = new Headers();
27
- req.headers.forEach((value, key) => {
28
- if (!HOP_BY_HOP.has(key.toLowerCase())) headers.set(key, value);
29
- });
30
-
31
- const init: RequestInit = {
32
- method: req.method,
33
- headers,
34
- redirect: "manual"
35
- };
36
-
37
- if (req.method !== "GET" && req.method !== "HEAD") {
38
- init.body = req.body;
39
- // @ts-expect-error Node fetch duplex for streaming bodies
40
- init.duplex = "half";
41
- }
42
-
43
- try {
44
- const upstream = await fetch(target, init);
45
- const outHeaders = new Headers();
46
- upstream.headers.forEach((value, key) => {
47
- if (!HOP_BY_HOP.has(key.toLowerCase())) outHeaders.set(key, value);
48
- });
49
- return new Response(upstream.body, {
50
- status: upstream.status,
51
- statusText: upstream.statusText,
52
- headers: outHeaders
53
- });
54
- } catch {
55
- const html = `<!DOCTYPE html>
56
- <html lang="en">
57
- <head>
58
- <meta charset="utf-8" />
59
- <title>TomorrowOS Preview</title>
60
- <style>
61
- body { font-family: system-ui, sans-serif; max-width: 40rem; margin: 3rem auto; padding: 0 1rem; line-height: 1.5; }
62
- code { background: #f4f4f5; padding: 0.1em 0.35em; border-radius: 4px; }
63
- </style>
64
- </head>
65
- <body>
66
- <h1>TomorrowOS Preview</h1>
67
- <p>The Next.js shell is running, but TomorrowOS is not reachable at <code>${INTERNAL}</code>.</p>
68
- <p>Start both processes:</p>
69
- <pre><code>npm run dev</code></pre>
70
- <p>(runs TomorrowOS on :3001 and Next on :3000). Publish / Production does not use this shell.</p>
71
- </body>
72
- </html>`;
73
- return new Response(html, {
74
- status: 502,
75
- headers: { "content-type": "text/html; charset=utf-8" }
76
- });
77
- }
78
- }
79
-
80
- export const dynamic = "force-dynamic";
81
- export const runtime = "nodejs";
82
-
83
- export const GET = proxyToTomorrowOS;
84
- export const POST = proxyToTomorrowOS;
85
- export const PUT = proxyToTomorrowOS;
86
- export const PATCH = proxyToTomorrowOS;
87
- export const DELETE = proxyToTomorrowOS;
88
- export const HEAD = proxyToTomorrowOS;
89
- export const OPTIONS = proxyToTomorrowOS;
@@ -1,15 +0,0 @@
1
- /**
2
- * Minimal layout so the App Router can boot for v0 Preview.
3
- * All real UI is proxied from TomorrowOS via app/[[...slug]]/route.ts.
4
- */
5
- export default function RootLayout({
6
- children
7
- }: {
8
- children: React.ReactNode;
9
- }) {
10
- return (
11
- <html lang="en">
12
- <body style={{ margin: 0 }}>{children}</body>
13
- </html>
14
- );
15
- }
@@ -1,4 +0,0 @@
1
- /// <reference types="next" />
2
- /// <reference types="next/image-types/global" />
3
-
4
- // NOTE: This file should not be edited — see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -1,15 +0,0 @@
1
- /**
2
- * Preview-only Next config. Production Publish ignores this
3
- * (`vercel.json` → framework: null + api/index.ts Fluid Function).
4
- *
5
- * HTTP proxy lives in `app/[[...slug]]/route.ts` (not rewrites) so POST
6
- * uploads and custom 502 pages work when TomorrowOS is down.
7
- *
8
- * @type {import('next').NextConfig}
9
- */
10
- const nextConfig = {
11
- // Do not add a root page.tsx that returns null — v0 shows
12
- // "Your v0 generation will show here" instead of the Control Panel.
13
- };
14
-
15
- export default nextConfig;