spfn 0.2.0-beta.52 → 0.2.0-beta.56
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 +49 -7
- package/bin/spfn.js +10 -3
- package/dist/index.js +1763 -692
- package/dist/templates/README.md +81 -0
- package/package.json +19 -12
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Requirements: Node.js 18.18+, Next.js 15+ (App Router, `src/` dir), PostgreSQL (
|
|
|
27
27
|
npx spfn@beta create my-app
|
|
28
28
|
cd my-app
|
|
29
29
|
docker compose up -d # Postgres + Redis
|
|
30
|
-
|
|
30
|
+
# .env.local & .env.server are generated — put server secrets in .env.server
|
|
31
31
|
pnpm spfn:dev # Next.js :3790 + SPFN API :8790
|
|
32
32
|
|
|
33
33
|
# Add SPFN to an existing Next.js project
|
|
@@ -61,7 +61,9 @@ Tailwind, import alias `@/*`, no ESLint), sets up SVGR icons, then runs `init`.
|
|
|
61
61
|
|
|
62
62
|
Adds SPFN to an existing Next.js project: copies the server templates, wires the RPC
|
|
63
63
|
proxy route, Docker files, deploy + codegen config, updates `package.json` scripts/deps,
|
|
64
|
-
and installs.
|
|
64
|
+
and installs. With auth enabled it also adds the `/_auth/:path*` → SPFN API rewrite to
|
|
65
|
+
`next.config` (OAuth callbacks return to the app origin; merged manually if a `rewrites()`
|
|
66
|
+
already exists). See [Scaffold structure](#scaffold-structure) for what lands on disk.
|
|
65
67
|
|
|
66
68
|
| Option | Description |
|
|
67
69
|
|--------|-------------|
|
|
@@ -212,6 +214,45 @@ Options: `-l, --list`, `-b, --bytes <n>` (1–128), `-e, --env <name>`, `-c, --c
|
|
|
212
214
|
The command prints the value to stdout for you to paste into an env file — it does **not**
|
|
213
215
|
write any file.
|
|
214
216
|
|
|
217
|
+
### `spfn secret`
|
|
218
|
+
|
|
219
|
+
Unified secret management: local secrets live in the OS keychain, deployed secrets in
|
|
220
|
+
encrypted SOPS files. The runtime never sees a reference — `spfn dev` injects local
|
|
221
|
+
values into the server process and GitOps injects them in production, so the app always
|
|
222
|
+
reads plain `process.env`.
|
|
223
|
+
|
|
224
|
+
| Subcommand | Description |
|
|
225
|
+
|------------|-------------|
|
|
226
|
+
| `secret set [key]` | Store a value (masked prompt). `--env local` → keychain; other envs → SOPS |
|
|
227
|
+
| `secret list` | List declared secrets and their status per env (never prints values) |
|
|
228
|
+
| `secret generate [key]` | Mint values for schema secrets with a `generate` strategy (`-a/--all`) |
|
|
229
|
+
| `secret rotate [key]` | Rotate values; external secrets are flagged for manual reissue (`-a/--all`) |
|
|
230
|
+
| `secret keygen` | Generate an age key pair for the SOPS no-cloud backend |
|
|
231
|
+
| `secret recipients <add\|remove\|list> [age1…]` | Manage `.sops.yaml` recipients + re-encrypt |
|
|
232
|
+
| `secret check` | Static lint — flag plaintext secret leaks |
|
|
233
|
+
|
|
234
|
+
Options: `-e, --env <env>` (`local` default; also `development`/`staging`/`production`),
|
|
235
|
+
`-p, --package <pkg>` (schema source, default `@spfn/core`).
|
|
236
|
+
|
|
237
|
+
**Local (keychain).** `spfn secret set DB_URL` stores the value in the OS keychain
|
|
238
|
+
(macOS `security`, Windows Credential Manager via optional `@napi-rs/keyring`, Linux
|
|
239
|
+
libsecret) and writes a `secret:keychain:spfn_DB_URL` reference into `.env.server`. The
|
|
240
|
+
reference is not sensitive; the real value never lands in the repo. `spfn dev` resolves
|
|
241
|
+
and injects it. Note: injection happens only when the server is started via `spfn dev` —
|
|
242
|
+
running the app another way (a bare `node`, tests) would see the raw reference, so use
|
|
243
|
+
`spfn dev` locally (a runtime resolver for other runners is planned).
|
|
244
|
+
|
|
245
|
+
**Deployed (SOPS).** `spfn secret set DB_URL --env production` writes the value into
|
|
246
|
+
`secrets/production.enc.json`, encrypted by SOPS. The backend (age / GCP KMS / AWS KMS)
|
|
247
|
+
is chosen by `.sops.yaml` creation rules — KMS needs no local key file (IAM + cloud
|
|
248
|
+
auth), age is the no-cloud fallback (`secret keygen` + `secret recipients add`). Commit
|
|
249
|
+
the encrypted file; your GitOps step decrypts it into env at deploy time. `sops`/`age`
|
|
250
|
+
are needed only for the deployed envs, never for local keychain use.
|
|
251
|
+
|
|
252
|
+
Schema-driven: a secret declared with `envSecret({ generate: 'base64url32' })` can be
|
|
253
|
+
minted/rotated automatically (`secret generate`/`rotate`); one without `generate` is an
|
|
254
|
+
external value you paste in (`secret set`).
|
|
255
|
+
|
|
215
256
|
### `spfn setup icons`
|
|
216
257
|
|
|
217
258
|
Install and configure SVGR for SVG-as-component imports (Next.js only).
|
|
@@ -241,9 +282,10 @@ spfn.config.js # deployment config (subdomain/region/domai
|
|
|
241
282
|
docker-compose.yml # Postgres + Redis (dev)
|
|
242
283
|
docker-compose.production.yml
|
|
243
284
|
Dockerfile, .dockerignore
|
|
244
|
-
.
|
|
245
|
-
.env.
|
|
246
|
-
.env.
|
|
285
|
+
next.config.ts # patched when auth is enabled: /_auth/:path* rewrite → SPFN API
|
|
286
|
+
.env.example # committed reference — every key, placeholder values
|
|
287
|
+
.env.local # generated, gitignored (Next.js-facing URLs)
|
|
288
|
+
.env.server # generated, gitignored (server secrets: DB, cache)
|
|
247
289
|
```
|
|
248
290
|
|
|
249
291
|
`init` also patches `package.json` (scripts: `spfn:dev`, `spfn:server`, `spfn:next`,
|
|
@@ -328,8 +370,8 @@ type ships from `spfn` (`@type {import('spfn').SpfnConfig}`).
|
|
|
328
370
|
|
|
329
371
|
- **`.env.server` is gitignored and server-only.** Put DB/secret values there, not in
|
|
330
372
|
`.env` (committed) and not in `.env.local` (that's Next.js's local file). There is no
|
|
331
|
-
`.env.server.local`.
|
|
332
|
-
standard dotenv chain ending with `.env.server`.
|
|
373
|
+
`.env.server.local`. `spfn init` generates `.env.server`; put DB/secret values there.
|
|
374
|
+
Load order is the standard dotenv chain ending with `.env.server`.
|
|
333
375
|
- **Never commit secrets in `spfn.config.js`.** It's checked into Git; its `env` block is
|
|
334
376
|
for non-sensitive values only. Use CI/CD secret management for credentials.
|
|
335
377
|
- **`spfn dev` does not hot-reload by default.** Add `--watch` to restart on `src/server`
|
package/bin/spfn.js
CHANGED
|
@@ -28,13 +28,20 @@ else
|
|
|
28
28
|
|
|
29
29
|
async function tryRelaunchWithTsx()
|
|
30
30
|
{
|
|
31
|
-
//
|
|
32
|
-
|
|
31
|
+
// Resolve tsx to an absolute URL from THIS package's location. A bare
|
|
32
|
+
// '--import tsx' is resolved by Node against the child's CWD, so running
|
|
33
|
+
// outside a project (no node_modules/tsx up the tree) crashes the child
|
|
34
|
+
// with ERR_MODULE_NOT_FOUND even though the guard import above succeeds
|
|
35
|
+
// (it resolves package-relative). Resolving here also doubles as the
|
|
36
|
+
// availability check — a throw falls back to running without tsx.
|
|
37
|
+
const { createRequire } = await import('module');
|
|
38
|
+
const { pathToFileURL } = await import('url');
|
|
39
|
+
const tsxUrl = pathToFileURL(createRequire(import.meta.url).resolve(TSX_MODULE)).href;
|
|
33
40
|
|
|
34
41
|
const { spawn } = await import('child_process');
|
|
35
42
|
const child = spawn(
|
|
36
43
|
process.execPath,
|
|
37
|
-
[TSX_FLAG,
|
|
44
|
+
[TSX_FLAG, tsxUrl, ...process.execArgv, process.argv[1], ...process.argv.slice(2)],
|
|
38
45
|
{ stdio: 'inherit' },
|
|
39
46
|
);
|
|
40
47
|
|