create-surf-app 1.0.0-alpha.33 → 1.0.0-alpha.35

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 ADDED
@@ -0,0 +1,64 @@
1
+ # create-surf-app
2
+
3
+ Scaffold a Surf app pre-wired with [`@surf-ai/sdk`](../sdk).
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npm create surf-app@latest [project-name] [--template <vite|nextjs>]
9
+ ```
10
+
11
+ - `project-name` — directory to create (defaults to current directory)
12
+ - `--template` — `vite` (default) or `nextjs`
13
+
14
+ Examples:
15
+
16
+ ```bash
17
+ npm create surf-app@latest my-app
18
+ npm create surf-app@latest my-app --template nextjs
19
+ npm create surf-app@latest . # scaffold into current dir
20
+ ```
21
+
22
+ ## Templates
23
+
24
+ | Template | Stack |
25
+ | --- | --- |
26
+ | `vite` (default) | Vite + React + Express backend using `@surf-ai/sdk/server` |
27
+ | `nextjs` | Next.js App Router with API route handlers using `@surf-ai/sdk/server` |
28
+
29
+ ## Environment variables
30
+
31
+ `SURF_API_KEY` is the only secret you need to provide. Everything else has a sensible default — but `BASE_PATH` must be **defined** (empty string is fine and means root) because the scaffolds read it unconditionally.
32
+
33
+ ### `vite` template
34
+
35
+ `backend/.env`:
36
+
37
+ | Var | Required | Default | Purpose |
38
+ | --- | --- | --- | --- |
39
+ | `SURF_API_KEY` | yes (non-empty) | — | Bearer token for Surf upstream + protected runtime endpoints |
40
+ | `BACKEND_PORT` | no | `3001` | Express server port |
41
+ | `SURF_API_BASE_URL` | no | `https://api.asksurf.ai/gateway/v1` | Override Surf API base URL |
42
+
43
+ `frontend/.env`:
44
+
45
+ | Var | Required | Default | Purpose |
46
+ | --- | --- | --- | --- |
47
+ | `BASE_PATH` | yes (empty OK) | — | Vite base path (e.g. `/preview/abc/`); empty means root |
48
+ | `PORT` | no | `5173` | Vite dev server port |
49
+ | `BACKEND_PORT` | no | `3001` | Backend port the dev server proxies `/api` to |
50
+
51
+ ### `nextjs` template
52
+
53
+ `.env`:
54
+
55
+ | Var | Required | Default | Purpose |
56
+ | --- | --- | --- | --- |
57
+ | `SURF_API_KEY` | yes (non-empty) | — | Bearer token for Surf upstream + protected runtime endpoints |
58
+ | `BASE_PATH` | yes (empty OK) | — | Next.js `basePath` (e.g. `/preview/abc`); empty means root |
59
+ | `PORT` | no | `3000` | Next.js server port |
60
+ | `SURF_API_BASE_URL` | no | `https://api.asksurf.ai/gateway/v1` | Override Surf API base URL |
61
+
62
+ `SURF_API_KEY` is enforced at **dev/start** time, not build time — `npm run build` succeeds without it so CI builds don't need the secret.
63
+
64
+ See [`@surf-ai/sdk` README](../sdk/README.md) for full SDK configuration and runtime details.
@@ -69,27 +69,43 @@ exports.users = pgTable("users", {
69
69
 
70
70
  Tables are auto-created on startup and when `schema.js` changes (file watcher).
71
71
 
72
- Query the database in routes using `@surf-ai/sdk/db` **not** Drizzle ORM query builder:
72
+ Query the database in routes with `dbQuery(sql, params)` from `@surf-ai/sdk/db`. Drizzle ORM is **only** used to declare the schema — there is no Drizzle client, no `req.db` middleware, and no direct connection pool. `dbQuery` returns a pg-style result `{ rows, rowCount, fields }`, so destructure `rows`:
73
73
 
74
74
  ```js
75
75
  const { dbQuery } = require("@surf-ai/sdk/db");
76
76
 
77
77
  router.get("/", async (req, res) => {
78
- const rows = await dbQuery("SELECT * FROM users ORDER BY created_at DESC");
78
+ const { rows } = await dbQuery(
79
+ "SELECT * FROM users ORDER BY created_at DESC"
80
+ );
79
81
  res.json(rows);
80
82
  });
81
83
 
82
84
  router.post("/", async (req, res) => {
83
85
  const { name } = req.body;
84
- const [row] = await dbQuery(
86
+ const { rows } = await dbQuery(
85
87
  "INSERT INTO users (name) VALUES ($1) RETURNING *",
86
88
  [name]
87
89
  );
88
- res.json(row);
90
+ res.json(rows[0]);
89
91
  });
90
92
  ```
91
93
 
92
- Database runs through an HTTP proxy — there is no direct `db` connection object or `req.db` middleware. Use `dbQuery(sql, params)` for all reads and writes.
94
+ ### Environment variables
95
+
96
+ Only variables prefixed with `VITE_` are exposed to the Vite frontend (`import.meta.env.VITE_FOO`). To use a plain env var (e.g. `APP_TITLE`) in the UI, read it in a backend route and fetch it from the frontend:
97
+
98
+ ```js
99
+ // backend/routes/config.js
100
+ const express = require("express");
101
+ const router = express.Router();
102
+
103
+ router.get("/", (_req, res) => {
104
+ res.json({ title: process.env.APP_TITLE || "App" });
105
+ });
106
+
107
+ module.exports = router;
108
+ ```
93
109
 
94
110
  ## Do NOT modify
95
111
 
@@ -5,7 +5,7 @@
5
5
  "dev": "node scripts/check-env.js node --watch server.js"
6
6
  },
7
7
  "dependencies": {
8
- "@surf-ai/sdk": "1.0.0-alpha.33",
8
+ "@surf-ai/sdk": "1.0.0-alpha.35",
9
9
  "express": "4.22.1"
10
10
  }
11
11
  }
@@ -72,27 +72,31 @@ export const users = pgTable("users", {
72
72
 
73
73
  Tables are auto-synced on server start and when `db/schema.ts` changes in dev mode.
74
74
 
75
- Query the database in API routes using `@surf-ai/sdk/db` **not** Drizzle ORM query builder:
75
+ Query the database in API routes using the `db()` helper re-exported from `@/db`. Drizzle ORM is **only** used to declare the schema — there is no Drizzle client and no direct connection pool. `db(sql, params)` returns a pg-style result `{ rows, rowCount, fields }`, so destructure `rows`:
76
76
 
77
77
  ```ts
78
- import { dbQuery } from "@surf-ai/sdk/db";
78
+ import { db } from "@/db";
79
79
 
80
80
  export async function GET() {
81
- const rows = await dbQuery("SELECT * FROM users ORDER BY created_at DESC");
81
+ const { rows } = await db(
82
+ "SELECT * FROM users ORDER BY created_at DESC"
83
+ );
82
84
  return Response.json(rows);
83
85
  }
84
86
 
85
87
  export async function POST(request: Request) {
86
88
  const { name } = await request.json();
87
- const [row] = await dbQuery(
89
+ const { rows } = await db(
88
90
  "INSERT INTO users (name) VALUES ($1) RETURNING *",
89
91
  [name]
90
92
  );
91
- return Response.json(row);
93
+ return Response.json(rows[0]);
92
94
  }
93
95
  ```
94
96
 
95
- Database runs through an HTTP proxy — there is no direct `db` connection object or `req.db` middleware. Use `dbQuery(sql, params)` for all reads and writes.
97
+ ### Environment variables
98
+
99
+ Only variables prefixed with `NEXT_PUBLIC_` are exposed to the browser. To use a plain env var (e.g. `APP_TITLE`) in a client component, either read it in a server component / route handler and pass it down as a prop, or expose it through a backend route.
96
100
 
97
101
  ## Do NOT modify
98
102
 
@@ -3,6 +3,6 @@
3
3
  //
4
4
  // Usage in route handlers:
5
5
  // import { db } from '@/db'
6
- // const result = await db('SELECT * FROM users')
6
+ // const { rows } = await db('SELECT * FROM users')
7
7
 
8
8
  export { dbQuery as db, dbProvision, dbTables, dbTableSchema, dbStatus } from '@surf-ai/sdk/db'
@@ -8,7 +8,7 @@
8
8
  "type-check": "tsc --noEmit --incremental"
9
9
  },
10
10
  "dependencies": {
11
- "@surf-ai/sdk": "1.0.0-alpha.33",
11
+ "@surf-ai/sdk": "1.0.0-alpha.35",
12
12
  "@surf-ai/theme": "latest",
13
13
  "next": "15.5.14",
14
14
  "react": "19.2.4",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-surf-app",
3
- "version": "1.0.0-alpha.33",
3
+ "version": "1.0.0-alpha.35",
4
4
  "description": "Scaffold a Surf app — Vite + React + Express + @surf-ai/sdk",
5
5
  "type": "module",
6
6
  "bin": {