spfn 0.2.0-beta.65 → 0.2.0-beta.67
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 +114 -5
- package/dist/index.js +513 -393
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -5,6 +5,11 @@ architecture. It can scaffold either a core-only backend or a production baselin
|
|
|
5
5
|
authentication, internationalization, and an agent-facing MCP endpoint, then runs the
|
|
6
6
|
dev/build/start lifecycle, database tooling, RPC codegen, and environment validation.
|
|
7
7
|
|
|
8
|
+
Consistent is the point rather than a nicety: what it scaffolds is one fixed shape per
|
|
9
|
+
feature, so a coding agent has no architecture left to invent and the codebase does not
|
|
10
|
+
acquire several. That problem has a name —
|
|
11
|
+
[architecture drift](https://superfunction.xyz/architecture-drift).
|
|
12
|
+
|
|
8
13
|
> Beta: install with the `@beta` tag (`spfn@beta`). The binary is `spfn`.
|
|
9
14
|
|
|
10
15
|
## Install
|
|
@@ -20,7 +25,8 @@ Or add it as a project dependency (`spfn init`/`spfn create` do this for you), t
|
|
|
20
25
|
call it via `pnpm spfn <command>` / `npm run spfn:<script>`.
|
|
21
26
|
|
|
22
27
|
Requirements: Node.js 18.18+ for bare mode, Node.js 20+ for full mode's MCP server,
|
|
23
|
-
Next.js
|
|
28
|
+
Next.js 16.2.11+ (App Router, `src/` dir), PostgreSQL 14+ (Redis optional). Next.js 15
|
|
29
|
+
is not supported — see [the root README](../../README.md#what-do-i-need-installed).
|
|
24
30
|
|
|
25
31
|
## Usage
|
|
26
32
|
|
|
@@ -48,7 +54,7 @@ with `--pm`. In a pnpm workspace, `create` installs from the workspace root.
|
|
|
48
54
|
## Commands
|
|
49
55
|
|
|
50
56
|
Registered top-level commands: `create`, `init`, `add`, `dev`, `build`, `start`,
|
|
51
|
-
`
|
|
57
|
+
`provision`, `codegen`, `contract`, `key`, `setup`, `db`, `env`, `secret`.
|
|
52
58
|
|
|
53
59
|
### `spfn create <name>`
|
|
54
60
|
|
|
@@ -101,6 +107,23 @@ How it works: if not already present it installs the package, then reads the pac
|
|
|
101
107
|
function migrations to `DATABASE_URL`. If `DATABASE_URL` is unset, migration is skipped
|
|
102
108
|
with a hint to run `spfn db push` later. Works with published and workspace packages.
|
|
103
109
|
|
|
110
|
+
### `spfn add vercel`
|
|
111
|
+
|
|
112
|
+
`vercel` is not a package — it is a built-in target, and the one argument to `add` that is
|
|
113
|
+
not a scoped package name. It scaffolds the three files a Next.js + SPFN app needs to run
|
|
114
|
+
its backend as Vercel Functions:
|
|
115
|
+
|
|
116
|
+
| File | What it is |
|
|
117
|
+
|------|------------|
|
|
118
|
+
| `src/app/api/backend/[[...route]]/route.ts` | `hono/vercel` adapter, mounts the SPFN app under `/api/backend` |
|
|
119
|
+
| `vercel.json` | build config (`pnpm spfn:build`) |
|
|
120
|
+
| `.npmrc` | `@spfn` registry auth, reading `GITEA_NPM_TOKEN` from the environment — never committed |
|
|
121
|
+
|
|
122
|
+
Existing files are never overwritten; they are reported and skipped. The runtime behind
|
|
123
|
+
the adapter is `createServerlessApp()` from `@spfn/core/server`. Afterwards, point
|
|
124
|
+
`SPFN_API_URL` at `https://<your-domain>/api/backend`, and make sure `hono` is a direct
|
|
125
|
+
dependency of the app so `hono/vercel` resolves.
|
|
126
|
+
|
|
104
127
|
### `spfn dev`
|
|
105
128
|
|
|
106
129
|
Starts the SPFN server + Next.js (and a codegen watcher). The server must report ready
|
|
@@ -176,6 +199,43 @@ export default defineConfig({
|
|
|
176
199
|
});
|
|
177
200
|
```
|
|
178
201
|
|
|
202
|
+
### `spfn contract`
|
|
203
|
+
|
|
204
|
+
Manages the route contract — what a **separately deployed** client (a mobile app, an external
|
|
205
|
+
API consumer) is promised. A web client needs none of this: it derives its types from
|
|
206
|
+
`AppRouter` in the same build, so a broken response already fails the compile.
|
|
207
|
+
|
|
208
|
+
Requires the `@spfn/core:contract` generator in `.spfnrc.ts`. Every command regenerates the
|
|
209
|
+
contract from the router first, so a stale `contracts/current.json` is never what gets checked
|
|
210
|
+
or released.
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# Regenerate and compare against the newest released snapshot
|
|
214
|
+
spfn contract check
|
|
215
|
+
|
|
216
|
+
# Cut a release — writes contracts/released/1.3.0.json. Commit it.
|
|
217
|
+
spfn contract release 1.3.0
|
|
218
|
+
|
|
219
|
+
# List released snapshots
|
|
220
|
+
spfn contract list
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
| Subcommand | Description | Exit code |
|
|
224
|
+
|------------|-------------|-----------|
|
|
225
|
+
| `contract check` | Compares the current contract against the newest released snapshot | 1 when a promise is broken |
|
|
226
|
+
| `contract release <version>` | Writes the snapshot every later build is compared against | 1 when the contract is broken, the version already exists, or it is not newer than the newest one |
|
|
227
|
+
| `contract list` (`ls`) | Lists released snapshots | 0 |
|
|
228
|
+
|
|
229
|
+
`--dir <path>` overrides the contracts directory; by default it comes from the generator's
|
|
230
|
+
`outputDir` in `.spfnrc.ts`.
|
|
231
|
+
|
|
232
|
+
**`spfn build` runs the same gate.** A broken contract fails the build with a non-zero exit
|
|
233
|
+
code — that is the point of hanging the check off codegen rather than leaving it to a
|
|
234
|
+
separate step.
|
|
235
|
+
|
|
236
|
+
See [`@spfn/core` contract docs](../core/src/contract/README.md) for the case table and the
|
|
237
|
+
removal rules.
|
|
238
|
+
|
|
179
239
|
### `spfn db`
|
|
180
240
|
|
|
181
241
|
Wraps Drizzle Kit with auto-generated config. Most commands read `DATABASE_URL` from the
|
|
@@ -186,6 +246,7 @@ loaded `.env` chain.
|
|
|
186
246
|
| `db generate` (`g`) | Generate migrations from schema changes (timestamp-prefixed) |
|
|
187
247
|
| `db push` | Diff with Drizzle Kit's current PostgreSQL engine and apply the selected DDL atomically. Destructive changes need confirmation; `--force` applies them, `--dry-run` previews |
|
|
188
248
|
| `db migrate` (`m`) | Run pending migrations. `--with-backup` snapshots first |
|
|
249
|
+
| `db status` | Show which migrations are applied and which are pending, for the project and for each installed function package |
|
|
189
250
|
| `db studio` | Open Drizzle Studio. `-p, --port` (auto-finds a free port) |
|
|
190
251
|
| `db check` | Verify the database connection |
|
|
191
252
|
| `db drop` | Drop all tables — **destructive**, double-prompts (see [Pitfalls](#pitfalls)) |
|
|
@@ -396,7 +457,16 @@ the SPFN API with cookie forwarding and interceptors, resolving routes via the g
|
|
|
396
457
|
|
|
397
458
|
## Deployment
|
|
398
459
|
|
|
399
|
-
|
|
460
|
+
Two targets, both shipping from the same repository.
|
|
461
|
+
|
|
462
|
+
**Vercel — serverless, one origin, no container.** Run `spfn add vercel` (above) and
|
|
463
|
+
deploy. Frontend and backend share a single Vercel origin. One caveat: the in-process job
|
|
464
|
+
worker does not run there, so enqueuing works but nothing drains the queue — schedule a
|
|
465
|
+
route that processes a batch (Vercel Cron), or run jobs on an always-on target.
|
|
466
|
+
|
|
467
|
+
**Always-on — a long-lived process.** `spfn build` then `spfn start`, or the generated
|
|
468
|
+
Docker files. Background jobs, WebSocket events and the periodic database health check all
|
|
469
|
+
need this path.
|
|
400
470
|
|
|
401
471
|
```bash
|
|
402
472
|
# Build + run locally
|
|
@@ -423,6 +493,42 @@ type ships from `spfn` (`@type {import('spfn').SpfnConfig}`).
|
|
|
423
493
|
|
|
424
494
|
---
|
|
425
495
|
|
|
496
|
+
## FAQ
|
|
497
|
+
|
|
498
|
+
**`create` or `init` — which one?**
|
|
499
|
+
`create` starts a new project: it runs `create-next-app` with SPFN's flags and then runs
|
|
500
|
+
`init` inside it. `init` adds SPFN to a Next.js app that already exists. If you built
|
|
501
|
+
something with an AI coding agent and now want a real backend under it, `init` is the one.
|
|
502
|
+
|
|
503
|
+
**`bare` or `full`?**
|
|
504
|
+
`full` is the recommended baseline: core, auth, i18n and MCP wired together, so you get a
|
|
505
|
+
working authenticated app on day one. `bare` is core only — the architecture with nothing
|
|
506
|
+
else decided. Automation should always pass `--mode` explicitly, because a `--yes` run
|
|
507
|
+
without one still produces `bare` for backward compatibility.
|
|
508
|
+
|
|
509
|
+
**Why doesn't my server restart when I edit a file?**
|
|
510
|
+
Because hot reload is off by default. `spfn dev --watch` restarts the server on `src/server`
|
|
511
|
+
changes. Next.js reloads on its own either way.
|
|
512
|
+
|
|
513
|
+
**Do I have to use Docker?**
|
|
514
|
+
No. Vercel is a first-class target and needs no container. Docker is the always-on path,
|
|
515
|
+
and `docker compose up -d` is also the convenient way to get PostgreSQL and Redis locally —
|
|
516
|
+
pointing at your own PostgreSQL works too. PostgreSQL itself is not optional.
|
|
517
|
+
|
|
518
|
+
**Which Node version do I need?**
|
|
519
|
+
18.18 or later for bare mode, 20 or later for full mode, because full mode includes the
|
|
520
|
+
MCP server.
|
|
521
|
+
|
|
522
|
+
**When do I have to run codegen by hand?**
|
|
523
|
+
Whenever routes change outside `spfn dev`, which runs a codegen watcher for you. A stale or
|
|
524
|
+
missing `src/generated/route-map.ts` makes the RPC proxy answer 404 — run `spfn codegen run`
|
|
525
|
+
and commit the result.
|
|
526
|
+
|
|
527
|
+
**Where do secrets go?**
|
|
528
|
+
`.env.server` (gitignored, server-only) for backend values, `.env.local` for the session
|
|
529
|
+
cookie secret that the Next.js runtime itself needs. Never `spfn.config.js` — that file is
|
|
530
|
+
committed.
|
|
531
|
+
|
|
426
532
|
## Pitfalls
|
|
427
533
|
|
|
428
534
|
- **`.env.server` is gitignored and server-only.** Put backend-only DB/secret values there,
|
|
@@ -441,7 +547,8 @@ type ships from `spfn` (`@type {import('spfn').SpfnConfig}`).
|
|
|
441
547
|
destructive ones unless `--force`/confirmed. Prefer `db generate` + `db migrate` for
|
|
442
548
|
production; `db push` is dev-only.
|
|
443
549
|
- **`spfn add` requires a scoped package name** (must contain `/`) and only applies
|
|
444
|
-
migrations when `DATABASE_URL` is set — otherwise it skips with a hint.
|
|
550
|
+
migrations when `DATABASE_URL` is set — otherwise it skips with a hint. The single
|
|
551
|
+
exception is `spfn add vercel`, a built-in target rather than a package.
|
|
445
552
|
- **Package manager is auto-detected from lockfiles.** If detection is wrong (e.g. mixed
|
|
446
553
|
lockfiles), pass `--pm` to `create`. In a pnpm workspace, `create` installs from the
|
|
447
554
|
workspace root, not the new project dir.
|
|
@@ -456,5 +563,7 @@ type ships from `spfn` (`@type {import('spfn').SpfnConfig}`).
|
|
|
456
563
|
|
|
457
564
|
## Related
|
|
458
565
|
|
|
459
|
-
- `@spfn/core` — server, route DSL, codegen, db, client runtime.
|
|
566
|
+
- [`@spfn/core`](../core/README.md) — server, route DSL, codegen, db, client runtime.
|
|
567
|
+
- [`@spfn/auth`](../auth/README.md) — what `--mode full` wires in for accounts and roles.
|
|
568
|
+
- [`@spfn/mcp`](../mcp/README.md) — what `--mode full` wires in for operating the app.
|
|
460
569
|
- Project root README — framework overview and getting started.
|