@clubedge/create-clubedge-app 0.24.0 → 0.24.1
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/CHANGELOG.md +7 -0
- package/README.md +10 -10
- package/dist/deploy.js +15 -7
- package/dist/utils/process.js +19 -9
- package/package.json +3 -3
- package/template/.github/workflows/ci.yml +8 -1
- package/template/.github/workflows/deploy.yml +2 -0
- package/template/Dockerfile +6 -0
- package/template/SETUP.md +1 -1
- package/template/apps/start/package.json +1 -1
- package/template/apps/web/package.json +1 -1
- package/template/fly.toml +4 -0
- package/template/package.json +1 -1
- package/template/packages/auth/package.json +1 -1
- package/template/packages/auth-better-auth/package.json +1 -1
- package/template/packages/auth-supabase/package.json +1 -1
- package/template/packages/cache/package.json +1 -1
- package/template/packages/cache-redis/package.json +1 -1
- package/template/packages/core/package.json +1 -1
- package/template/packages/db/package.json +1 -1
- package/template/packages/email/package.json +1 -1
- package/template/packages/email-resend/package.json +1 -1
- package/template/packages/email-smtp/package.json +1 -1
- package/template/packages/jobs/package.json +1 -1
- package/template/packages/jobs-pg-boss/package.json +1 -1
- package/template/packages/local-db/package.json +1 -1
- package/template/packages/observability/package.json +1 -1
- package/template/packages/observability-otel/package.json +1 -1
- package/template/packages/observability-sentry/package.json +1 -1
- package/template/packages/payments/package.json +1 -1
- package/template/packages/payments-stripe/package.json +1 -1
- package/template/packages/storage/package.json +1 -1
- package/template/packages/storage-s3/package.json +1 -1
- package/template/packages/storage-supabase/package.json +1 -1
- package/template/packages/ui/package.json +1 -1
- package/template.lock.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `create-clubedge-app` are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.24.1
|
|
6
|
+
|
|
7
|
+
- Default to Starter `v0.17.1` (#65), which fixes deployed Next.js apps sending sign-in email links and Stripe return URLs to `http://localhost:3000`: the Dockerfile now takes `NEXT_PUBLIC_APP_URL` as a build argument, which Railway and Render pass from the service's variables. `pnpm clubedge deploy` already sets it on Railway.
|
|
8
|
+
- `deploy` lists the settings still unset before the build instead of after the release, and asks whether to deploy anyway (#64).
|
|
9
|
+
- No more Node DEP0190 warning on Windows: commands that need the shell get one quoted command line (#64).
|
|
10
|
+
- The showcase is re-recorded after each release (#63).
|
|
11
|
+
|
|
5
12
|
## 0.24.0
|
|
6
13
|
|
|
7
14
|
- Default to Starter `v0.17.0` (#61), which adds:
|
package/README.md
CHANGED
|
@@ -127,7 +127,7 @@ pnpm dlx @clubedge/create-clubedge-app my-app --yes --no-git --framework tanstac
|
|
|
127
127
|
pnpm dlx @clubedge/create-clubedge-app my-app --ref main
|
|
128
128
|
|
|
129
129
|
# Reproduce a specific Starter release or commit
|
|
130
|
-
pnpm dlx @clubedge/create-clubedge-app my-app --ref v0.17.
|
|
130
|
+
pnpm dlx @clubedge/create-clubedge-app my-app --ref v0.17.1
|
|
131
131
|
pnpm dlx @clubedge/create-clubedge-app my-app --ref <commit-sha>
|
|
132
132
|
|
|
133
133
|
# Test local Starter changes before releasing them
|
|
@@ -146,7 +146,7 @@ pnpm clubedge add email resend payments stripe # several modules as
|
|
|
146
146
|
pnpm clubedge remove storage payments
|
|
147
147
|
pnpm dlx @clubedge/create-clubedge-app add infra local --dry-run
|
|
148
148
|
pnpm dlx @clubedge/create-clubedge-app@latest upgrade # to the newest CLI's Starter release
|
|
149
|
-
pnpm dlx @clubedge/create-clubedge-app upgrade --ref v0.17.
|
|
149
|
+
pnpm dlx @clubedge/create-clubedge-app upgrade --ref v0.17.1 # or a specific tag, branch, or commit
|
|
150
150
|
```
|
|
151
151
|
|
|
152
152
|
The CLI renders the project twice, from the Starter commit and modules recorded in your `package.json` and from the new state, and merges the difference into your project. The new state has other modules for `add` and `remove`, and the newer Starter with the same modules for `upgrade`. Modules a newer Starter introduces start as `none` where possible, so an upgrade never adds a service on its own.
|
|
@@ -206,27 +206,27 @@ With [Railway's CLI](https://docs.railway.com/cli) (the installed `railway`, or
|
|
|
206
206
|
Each CLI release is tested against one specific Starter release:
|
|
207
207
|
|
|
208
208
|
```text
|
|
209
|
-
create-clubedge-app v0.24.
|
|
209
|
+
create-clubedge-app v0.24.1
|
|
210
210
|
|
|
|
211
211
|
v
|
|
212
|
-
Clubedge Starter v0.17.
|
|
213
|
-
commit
|
|
212
|
+
Clubedge Starter v0.17.1
|
|
213
|
+
commit d9d787b6750e862b9de81a3f8f36b7aa07757f7a
|
|
214
214
|
```
|
|
215
215
|
|
|
216
216
|
The current relationship is:
|
|
217
217
|
|
|
218
218
|
| CLI release | Default Starter release | Meaning |
|
|
219
219
|
| --- | --- | --- |
|
|
220
|
-
| `create-clubedge-app@0.24.
|
|
220
|
+
| `create-clubedge-app@0.24.1` | `clubedge-starter@v0.17.1` | The CLI's required, tested default |
|
|
221
221
|
|
|
222
222
|
This means the same CLI version always scaffolds the same Starter revision by default. The CLI does not silently follow Starter `main`.
|
|
223
223
|
|
|
224
|
-
The `v0.17.
|
|
225
|
-
`
|
|
224
|
+
The `v0.17.1` tag is expected to resolve to commit
|
|
225
|
+
`d9d787b6750e862b9de81a3f8f36b7aa07757f7a`. The CLI verifies this before
|
|
226
226
|
scaffolding with the default reference and fails rather than silently using a
|
|
227
227
|
moved tag.
|
|
228
228
|
|
|
229
|
-
When the Starter changes, its maintainers first publish a new versioned release, such as `v0.17.
|
|
229
|
+
When the Starter changes, its maintainers first publish a new versioned release, such as `v0.17.1`. The CLI is then updated to use that release, all generated-project checks must pass, and a new CLI version is published. This keeps Starter and CLI releases independently versioned while preserving a tested compatibility relationship.
|
|
230
230
|
|
|
231
231
|
Every generated project records its CLI version, Starter repository, Starter ref, Starter commit, framework, and modules in `package.json` and `README.md`.
|
|
232
232
|
|
|
@@ -281,7 +281,7 @@ CI packs the CLI with `npm pack`, scaffolds clean projects from the packed tarba
|
|
|
281
281
|
1. Make and validate changes in `clubedge-starter`.
|
|
282
282
|
2. Run lint, typecheck, unit tests, browser tests, and production build.
|
|
283
283
|
3. Update the Starter package versions.
|
|
284
|
-
4. Commit `main`, create a release tag such as `v0.17.
|
|
284
|
+
4. Commit `main`, create a release tag such as `v0.17.1`, and publish the Starter release.
|
|
285
285
|
|
|
286
286
|
### CLI maintainers
|
|
287
287
|
|
package/dist/deploy.js
CHANGED
|
@@ -15,7 +15,7 @@ import { readProject } from "./core/project.js";
|
|
|
15
15
|
import { cliCommand } from "./modify.js";
|
|
16
16
|
import { resolvePnpm } from "./steps/install.js";
|
|
17
17
|
import { pathExists } from "./utils/fs.js";
|
|
18
|
-
import { run } from "./utils/process.js";
|
|
18
|
+
import { run, spawnCommand } from "./utils/process.js";
|
|
19
19
|
const railwayTermsUrl = "https://railway.com/legal/terms";
|
|
20
20
|
const deployDocsUrl = "https://starter.clubedge.live/docs/starter/deploy";
|
|
21
21
|
const windows = process.platform === "win32";
|
|
@@ -23,7 +23,7 @@ const binaryName = windows ? "railway.exe" : "railway";
|
|
|
23
23
|
async function cliVersion(command, shell) {
|
|
24
24
|
return await new Promise((resolveVersion) => {
|
|
25
25
|
const [file, ...args] = command;
|
|
26
|
-
const child =
|
|
26
|
+
const child = spawnCommand(file, [...args, "--version"], { stdio: ["ignore", "pipe", "ignore"] }, shell);
|
|
27
27
|
let out = "";
|
|
28
28
|
child.stdout?.on("data", (chunk) => (out += chunk.toString()));
|
|
29
29
|
child.once("error", () => resolveVersion(null));
|
|
@@ -89,11 +89,7 @@ async function railwayCli() {
|
|
|
89
89
|
async function railway(cli, args, options = {}) {
|
|
90
90
|
const [command, ...prefix] = cli.command;
|
|
91
91
|
return await new Promise((resolvePromise, reject) => {
|
|
92
|
-
const child =
|
|
93
|
-
shell: cli.shell,
|
|
94
|
-
env: { ...process.env, _: cli.executable },
|
|
95
|
-
stdio: options.inherit ? "inherit" : ["pipe", "pipe", "pipe"],
|
|
96
|
-
});
|
|
92
|
+
const child = spawnCommand(command, [...prefix, ...args], { env: { ...process.env, _: cli.executable }, stdio: options.inherit ? "inherit" : ["pipe", "pipe", "pipe"] }, cli.shell);
|
|
97
93
|
let stdout = "";
|
|
98
94
|
let stderr = "";
|
|
99
95
|
child.stdout?.on("data", (chunk) => (stdout += chunk.toString()));
|
|
@@ -243,6 +239,18 @@ export async function deployProject(args) {
|
|
|
243
239
|
if (changed.length) {
|
|
244
240
|
log.info(`Commit ${changed.join(", ")}: Railway reads the service's settings from ${railwayIacPath} now. railway.json is no longer needed (Railway stops reading it on 2026-12-01).`);
|
|
245
241
|
}
|
|
242
|
+
// Before the build, not after it: the app starts without these, but the features that use them
|
|
243
|
+
// fail until they are set, and a build takes minutes.
|
|
244
|
+
if (plan.unset.length) {
|
|
245
|
+
log.warn(`Not set on the service: ${plan.unset.join(", ")}. The app starts without them, but the features that use them fail until they are set: pass --env-file, or run railway variable set KEY --stdin --service ${service}.`);
|
|
246
|
+
if (process.stdin.isTTY && !args.yes) {
|
|
247
|
+
const proceed = await confirm({ message: "Deploy anyway?", initialValue: true });
|
|
248
|
+
if (isCancel(proceed) || !proceed) {
|
|
249
|
+
cancel("Nothing was deployed. Set them, then run deploy again: it reuses everything.");
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
246
254
|
// Start the deploy detached, then follow its status: `railway up` can return before the build
|
|
247
255
|
// ends, and only Railway's final status says whether the release went live.
|
|
248
256
|
const deploying = spinner();
|
package/dist/utils/process.js
CHANGED
|
@@ -2,10 +2,23 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
// Package manager shims on Windows are .cmd files, which need a shell to start.
|
|
4
4
|
const useShell = process.platform === "win32";
|
|
5
|
+
/** An argument as one word for cmd.exe: plain words as they are, anything else in double quotes. */
|
|
6
|
+
export function quoteForCmd(argument) {
|
|
7
|
+
return /^[\w@+=:,./\\-]+$/.test(argument) ? argument : `"${argument.replaceAll('"', '""')}"`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Starts a command, through the shell on Windows. There it passes one quoted command line, not an
|
|
11
|
+
* argument list: Node warns (DEP0190) when arguments are only concatenated for a shell.
|
|
12
|
+
*/
|
|
13
|
+
export function spawnCommand(command, args, options, shell = useShell) {
|
|
14
|
+
if (!shell)
|
|
15
|
+
return spawn(command, args, options);
|
|
16
|
+
return spawn([command, ...args].map(quoteForCmd).join(" "), { ...options, shell: true });
|
|
17
|
+
}
|
|
5
18
|
/** Runs a command with inherited output. Rejects on a non-zero exit. */
|
|
6
19
|
export async function run(command, args, cwd) {
|
|
7
20
|
await new Promise((resolve, reject) => {
|
|
8
|
-
const child =
|
|
21
|
+
const child = spawnCommand(command, args, { cwd, stdio: "inherit" });
|
|
9
22
|
child.once("error", reject);
|
|
10
23
|
child.once("exit", (code, signal) => {
|
|
11
24
|
if (code === 0)
|
|
@@ -18,17 +31,14 @@ export async function run(command, args, cwd) {
|
|
|
18
31
|
/** Runs a command and returns trimmed stdout. Rejects with stderr on a non-zero exit. */
|
|
19
32
|
export async function runCapture(command, args, cwd) {
|
|
20
33
|
return await new Promise((resolve, reject) => {
|
|
21
|
-
const child =
|
|
22
|
-
cwd,
|
|
23
|
-
shell: useShell,
|
|
24
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
25
|
-
});
|
|
34
|
+
const child = spawnCommand(command, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
26
35
|
let stdout = "";
|
|
27
36
|
let stderr = "";
|
|
28
|
-
child.stdout
|
|
29
|
-
child.stderr
|
|
37
|
+
child.stdout?.on("data", (chunk) => (stdout += chunk.toString()));
|
|
38
|
+
child.stderr?.on("data", (chunk) => (stderr += chunk.toString()));
|
|
30
39
|
child.once("error", reject);
|
|
31
|
-
|
|
40
|
+
// close, not exit: it fires once stdout and stderr are fully read.
|
|
41
|
+
child.once("close", (code, signal) => {
|
|
32
42
|
if (code === 0) {
|
|
33
43
|
resolve(stdout.trim());
|
|
34
44
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clubedge/create-clubedge-app",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Create a Next.js or TanStack Start application from the Clubedge Starter reference implementation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.9.0",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"clubedge": {
|
|
24
24
|
"starterRepository": "Clubedge/clubedge-starter",
|
|
25
|
-
"starterRef": "v0.17.
|
|
26
|
-
"starterCommit": "
|
|
25
|
+
"starterRef": "v0.17.1",
|
|
26
|
+
"starterCommit": "d9d787b6750e862b9de81a3f8f36b7aa07757f7a"
|
|
27
27
|
},
|
|
28
28
|
"license": "Apache-2.0",
|
|
29
29
|
"repository": {
|
|
@@ -72,7 +72,14 @@ jobs:
|
|
|
72
72
|
steps:
|
|
73
73
|
- uses: actions/checkout@v7
|
|
74
74
|
- name: Build the production image
|
|
75
|
-
|
|
75
|
+
# A public URL of its own, to check that it reaches the build.
|
|
76
|
+
run: docker build --build-arg NEXT_PUBLIC_APP_URL=https://app.ci.invalid --tag app:ci .
|
|
77
|
+
# clubedge:if framework=next
|
|
78
|
+
- name: Check that the public URL is compiled into the build
|
|
79
|
+
# Next.js inlines NEXT_PUBLIC_* at build time, server code included; without the build
|
|
80
|
+
# argument, sign-in links and Stripe return URLs would point at localhost.
|
|
81
|
+
run: docker run --rm --entrypoint sh app:ci -c 'grep -rlq "https://app.ci.invalid" /app/apps/web/.next/server'
|
|
82
|
+
# clubedge:end
|
|
76
83
|
- name: Run the image's migrations twice; the second run changes nothing
|
|
77
84
|
run: |
|
|
78
85
|
set -euo pipefail
|
|
@@ -37,6 +37,8 @@ jobs:
|
|
|
37
37
|
push: true
|
|
38
38
|
tags: ${{ steps.meta.outputs.tags }}
|
|
39
39
|
labels: ${{ steps.meta.outputs.labels }}
|
|
40
|
+
# Compiled into the Next.js build: set the repository variable to your public URL.
|
|
41
|
+
build-args: NEXT_PUBLIC_APP_URL=${{ vars.NEXT_PUBLIC_APP_URL }}
|
|
40
42
|
# clubedge:end
|
|
41
43
|
# clubedge:if deploy=fly
|
|
42
44
|
fly:
|
package/template/Dockerfile
CHANGED
|
@@ -17,6 +17,12 @@ COPY --from=pruner /app/out/json/ .
|
|
|
17
17
|
RUN pnpm install --frozen-lockfile
|
|
18
18
|
COPY --from=pruner /app/out/full/ .
|
|
19
19
|
COPY tsconfig.base.json ./
|
|
20
|
+
# Next.js compiles NEXT_PUBLIC_* values into the build, server code included (sign-in email links,
|
|
21
|
+
# Stripe return URLs), so the public URL is a build argument. Railway and Render pass it from the
|
|
22
|
+
# service's variables; elsewhere, --build-arg NEXT_PUBLIC_APP_URL=https://your.domain. Unset, the
|
|
23
|
+
# app falls back to http://localhost:3000.
|
|
24
|
+
ARG NEXT_PUBLIC_APP_URL
|
|
25
|
+
ENV NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL}
|
|
20
26
|
RUN pnpm build
|
|
21
27
|
# The production migrator (node /app/migrate.mjs): one bundled file plus every package's
|
|
22
28
|
# migrations, so release commands can migrate before a new version starts.
|
package/template/SETUP.md
CHANGED
|
@@ -438,7 +438,7 @@ Netlify runs no worker for [background jobs](#background-jobs). Set `JOBS_WORKER
|
|
|
438
438
|
Production needs these variables:
|
|
439
439
|
|
|
440
440
|
- `DATABASE_URL`, pointing at a managed PostgreSQL database.
|
|
441
|
-
- `NEXT_PUBLIC_APP_URL`, the deployed origin. <!-- clubedge:only framework=next -->
|
|
441
|
+
- `NEXT_PUBLIC_APP_URL`, the deployed origin. Next.js compiles it into the build, server code included (sign-in links, Stripe return URLs), so it must be set when the image is built: Railway and Render pass the service's variable to the Docker build; on Fly.io set it under `[build.args]` in `fly.toml`; with the Docker workflow, set the repository variable `NEXT_PUBLIC_APP_URL`. <!-- clubedge:only framework=next -->
|
|
442
442
|
- `APP_URL`, the deployed origin. <!-- clubedge:only framework=tanstack-start -->
|
|
443
443
|
- `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY`, from the Supabase project. <!-- clubedge:only framework=next && auth=supabase -->
|
|
444
444
|
- `SUPABASE_URL` and `SUPABASE_PUBLISHABLE_KEY`, from the Supabase project. <!-- clubedge:only framework=tanstack-start && auth=supabase -->
|
package/template/fly.toml
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
# and adds its name and region here; set secrets with `fly secrets set`, then run `fly deploy`.
|
|
3
3
|
[build]
|
|
4
4
|
dockerfile = "Dockerfile"
|
|
5
|
+
# Next.js compiles NEXT_PUBLIC_APP_URL into the build (sign-in links, Stripe return URLs), so a
|
|
6
|
+
# Next.js app sets it here rather than as a secret:
|
|
7
|
+
# [build.args]
|
|
8
|
+
# NEXT_PUBLIC_APP_URL = "https://<app>.fly.dev"
|
|
5
9
|
|
|
6
10
|
# Runs in a temporary machine with the new image before it replaces the running one.
|
|
7
11
|
[deploy]
|
package/template/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clubedge/observability",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Observability interface: error reports and spans for @clubedge/core's telemetry hooks, and an in-memory provider for tests.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"license": "Apache-2.0",
|
package/template.lock.json
CHANGED