create-apollo-monorepo 0.9.1 → 0.9.2

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.
Files changed (3) hide show
  1. package/README.md +7 -7
  2. package/index.mjs +196 -39
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -6,15 +6,15 @@ mounted as a **git submodule** backend (read-only — pull updates only).
6
6
  ## Usage
7
7
 
8
8
  ```bash
9
- npx create-apollo-monorepo thamc-new
9
+ npx create-apollo-monorepo my-site
10
10
  ```
11
11
 
12
12
  With flags:
13
13
 
14
14
  ```bash
15
- npx create-apollo-monorepo thamc-new \
16
- --frontend-name "@thamc/frontend" \
17
- --db "postgresql://user:pass@localhost:5432/thamc" \
15
+ npx create-apollo-monorepo my-site \
16
+ --frontend-name "@my-site/frontend" \
17
+ --db "postgresql://user:pass@localhost:5432/my-site" \
18
18
  --url "http://localhost:3000" \
19
19
  --locale th
20
20
  ```
@@ -22,9 +22,9 @@ npx create-apollo-monorepo thamc-new \
22
22
  ## Result
23
23
 
24
24
  ```
25
- thamc-new/
25
+ my-site/
26
26
  ├── apps/
27
- │ ├── frontend/ ← @thamc/frontend (Next.js skeleton)
27
+ │ ├── frontend/ ← @my-site/frontend (Next.js skeleton)
28
28
  │ └── backend/ ← git submodule → apollo-cms
29
29
  ├── package.json ← root workspace
30
30
  ├── pnpm-workspace.yaml
@@ -89,7 +89,7 @@ subdomains (e.g. `cms.example.com` + `example.com`).
89
89
  ## After install
90
90
 
91
91
  ```bash
92
- cd thamc-new
92
+ cd my-site
93
93
  pnpm backend:setup # push schema + seed apollo-cms
94
94
  pnpm dev # frontend :3001 + backend :3000 in parallel
95
95
  ```
package/index.mjs CHANGED
@@ -29,6 +29,13 @@ const FRONTEND_PATH = "apps/frontend";
29
29
  const PROXY_PATH = "apps/proxy";
30
30
  const MIN_NODE_MAJOR = 20;
31
31
 
32
+ // Default dev ports. Kept in sync with scripts/with-env.mjs and the proxy
33
+ // template. .env.local is the runtime source of truth — these are the
34
+ // installer-side fallbacks for computing initial URL defaults.
35
+ const DEFAULT_PROXY_PORT = 3030;
36
+ const DEFAULT_FRONTEND_PORT = 3001;
37
+ const DEFAULT_BACKEND_PORT = 3002;
38
+
32
39
  const COLORS = {
33
40
  reset: "\x1b[0m",
34
41
  bold: "\x1b[1m",
@@ -46,9 +53,9 @@ ${COLORS.bold}Usage:${COLORS.reset}
46
53
  npx create-apollo-monorepo <directory> [flags]
47
54
 
48
55
  ${COLORS.bold}Examples:${COLORS.reset}
49
- npx create-apollo-monorepo thamc-new
50
- npx create-apollo-monorepo thamc-new --frontend-name "@thamc/frontend"
51
- npx create-apollo-monorepo thamc-new --backend-branch develop --skip-install
56
+ npx create-apollo-monorepo my-site
57
+ npx create-apollo-monorepo my-site --frontend-name "@my-site/frontend"
58
+ npx create-apollo-monorepo my-site --backend-branch develop --skip-install
52
59
 
53
60
  ${COLORS.bold}Flags:${COLORS.reset}
54
61
  --frontend-name <name> Frontend package name (default: "@<dir>/frontend")
@@ -283,7 +290,14 @@ async function gatherEnv(flags, { singleOrigin }) {
283
290
  let dbUrl = flags.db;
284
291
  // In single-origin mode the frontend is the public entry → default :3001.
285
292
  // In separate-origins mode the backend is the public CMS URL → default :3000.
286
- const defaultSiteUrl = singleOrigin ? "http://localhost:3001" : "http://localhost:3000";
293
+ // Public origin = frontend in single-origin mode (frontend rewrites /admin/*,
294
+ // /api/*, /uploads/* to the backend), backend in separate-origins mode.
295
+ // For `pnpm dev:rp` switch this to http://localhost:${PROXY_PORT} in .env.local.
296
+ // Derived from the PORT constants so changing a default updates both the
297
+ // .env.local seed and the prompt's suggested value.
298
+ const defaultSiteUrl = singleOrigin
299
+ ? `http://localhost:${DEFAULT_FRONTEND_PORT}`
300
+ : `http://localhost:${DEFAULT_BACKEND_PORT}`;
287
301
  let siteUrl = flags.url ?? defaultSiteUrl;
288
302
  let locale = flags.locale ?? "en";
289
303
 
@@ -355,16 +369,17 @@ function writeRootPackageJson(targetDir, dirName) {
355
369
  // rebuild and the backend's plugin loader picks up the fresh
356
370
  // dist/server.mjs on next request.
357
371
  dev:
358
- "pnpm predev:setup && concurrently -k -n FE,BE,PL -c blue,magenta,yellow \"pnpm --filter ./apps/frontend dev\" \"pnpm --filter ./apps/backend exec next dev\" \"pnpm cms-plugins:dev\"",
372
+ "pnpm predev:setup && concurrently -k -n FE,BE,PL -c blue,magenta,yellow \"pnpm dev:frontend\" \"pnpm dev:backend\" \"pnpm cms-plugins:dev\"",
359
373
  // Optional single-origin dev: same as `pnpm dev` but adds a Node.js
360
- // reverse proxy on :3030 that fronts FE :3001 + BE :3000. Use it when
361
- // you want one URL, shared cookies, and no CORS — without nginx.
374
+ // reverse proxy on :3030 (PROXY_PORT) that fronts FE :3001 (FRONTEND_PORT)
375
+ // + BE :3002 (BACKEND_PORT). Ports come from .env.local; override there.
362
376
  "dev:rp":
363
- "pnpm predev:setup && concurrently -k -n FE,BE,PL,PX -c blue,magenta,yellow,cyan \"pnpm --filter ./apps/frontend dev\" \"pnpm --filter ./apps/backend exec next dev\" \"pnpm cms-plugins:dev\" \"pnpm dev:proxy\"",
364
- "dev:proxy": "node apps/proxy/server.mjs",
365
- "dev:frontend": "pnpm --filter ./apps/frontend dev",
377
+ "pnpm predev:setup && concurrently -k -n FE,BE,PL,PX -c blue,magenta,yellow,cyan \"pnpm dev:frontend\" \"pnpm dev:backend\" \"pnpm cms-plugins:dev\" \"pnpm dev:proxy\"",
378
+ "dev:proxy": "node scripts/with-env.mjs node apps/proxy/server.mjs",
379
+ "dev:frontend":
380
+ "node scripts/with-env.mjs --port=FRONTEND_PORT pnpm --filter ./apps/frontend exec next dev",
366
381
  "dev:backend":
367
- "pnpm predev:setup && pnpm --filter ./apps/backend exec next dev",
382
+ "pnpm predev:setup && node scripts/with-env.mjs --port=BACKEND_PORT pnpm --filter ./apps/backend exec next dev",
368
383
  "dev:cron": "pnpm --filter ./apps/backend exec bun scripts/dev-cron.ts",
369
384
  // Build pipeline: cms-plugins → apollo-cms's own plugins → backend → frontend.
370
385
  // `prebuild` runs first (npm/pnpm convention) and fails fast if the
@@ -375,17 +390,19 @@ function writeRootPackageJson(targetDir, dirName) {
375
390
  "build:backend":
376
391
  "pnpm cms-plugins:build && pnpm --filter ./apps/backend exec bun run plugins:build && pnpm --filter ./apps/backend build",
377
392
  "build:frontend": "pnpm --filter ./apps/frontend build",
378
- // Production start. Runs FE :3001 + BE :3000 in parallel via
379
- // \`next start\`. Run \`pnpm backend:upgrade\` BEFORE this — start does
380
- // NOT run migrations on boot (zero-downtime restart safety).
393
+ // Production start. Runs FE :FRONTEND_PORT + BE :BACKEND_PORT (defaults
394
+ // 3001 + 3002 from .env.local). Run \`pnpm backend:upgrade\` BEFORE this —
395
+ // start does NOT run migrations on boot (zero-downtime restart safety).
381
396
  start:
382
- "concurrently -k -n FE,BE -c blue,magenta \"pnpm --filter ./apps/frontend start\" \"pnpm --filter ./apps/backend exec next start\"",
383
- // Single-origin production: FE + BE + Node reverse proxy on :3030.
397
+ "concurrently -k -n FE,BE -c blue,magenta \"pnpm start:frontend\" \"pnpm start:backend\"",
398
+ // Single-origin production: FE + BE + Node reverse proxy on :PROXY_PORT.
384
399
  "start:rp":
385
- "concurrently -k -n FE,BE,PX -c blue,magenta,cyan \"pnpm --filter ./apps/frontend start\" \"pnpm --filter ./apps/backend exec next start\" \"pnpm start:proxy\"",
386
- "start:proxy": "NODE_ENV=production node apps/proxy/server.mjs",
387
- "start:frontend": "pnpm --filter ./apps/frontend start",
388
- "start:backend": "pnpm --filter ./apps/backend exec next start",
400
+ "concurrently -k -n FE,BE,PX -c blue,magenta,cyan \"pnpm start:frontend\" \"pnpm start:backend\" \"pnpm start:proxy\"",
401
+ "start:proxy": "NODE_ENV=production node scripts/with-env.mjs node apps/proxy/server.mjs",
402
+ "start:frontend":
403
+ "node scripts/with-env.mjs --port=FRONTEND_PORT pnpm --filter ./apps/frontend exec next start",
404
+ "start:backend":
405
+ "node scripts/with-env.mjs --port=BACKEND_PORT pnpm --filter ./apps/backend exec next start",
389
406
  // Self-hosted scheduler fallback. Vercel deploys use Vercel Cron via
390
407
  // apps/backend/vercel.json — skip this on Vercel. For Docker / VPS
391
408
  // you can either run \`pnpm start:cron\` alongside \`pnpm start\` (PM2
@@ -545,10 +562,43 @@ function writeProxyApp(targetDir, dirName, adminPrefix) {
545
562
 
546
563
  import http from "node:http";
547
564
  import net from "node:net";
565
+ import { readFileSync, existsSync } from "node:fs";
566
+ import { resolve, dirname } from "node:path";
567
+ import { fileURLToPath } from "node:url";
548
568
 
549
- const PORT = Number(process.env.PORT ?? 3030);
550
- const BACKEND = parseTarget(process.env.BACKEND ?? "http://127.0.0.1:3000");
551
- const FRONTEND = parseTarget(process.env.FRONTEND ?? "http://127.0.0.1:3001");
569
+ // Load root .env.local so the proxy honors PROXY_PORT/FRONTEND_PORT/BACKEND_PORT
570
+ // alongside the frontend & backend. Process env still wins (12-factor friendly).
571
+ (function loadRootEnv() {
572
+ try {
573
+ const here = dirname(fileURLToPath(import.meta.url));
574
+ const envPath = resolve(here, "../../.env.local");
575
+ if (!existsSync(envPath)) return;
576
+ for (const raw of readFileSync(envPath, "utf8").split(/\\r?\\n/)) {
577
+ const line = raw.trim();
578
+ if (!line || line.startsWith("#")) continue;
579
+ const eq = line.indexOf("=");
580
+ if (eq < 0) continue;
581
+ const key = line.slice(0, eq).trim();
582
+ if (!/^[A-Z_][A-Z0-9_]*$/i.test(key)) continue;
583
+ if (process.env[key] !== undefined) continue;
584
+ let val = line.slice(eq + 1).trim();
585
+ if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
586
+ val = val.slice(1, -1);
587
+ }
588
+ process.env[key] = val;
589
+ }
590
+ } catch {
591
+ // Best-effort. The proxy still runs on its hardcoded fallbacks.
592
+ }
593
+ })();
594
+
595
+ // Backward-compatible: PROXY_PORT/FRONTEND_PORT/BACKEND_PORT are the new names;
596
+ // PORT/FRONTEND/BACKEND are still honored if explicitly set in process.env.
597
+ const PORT = Number(process.env.PROXY_PORT ?? process.env.PORT ?? 3030);
598
+ const BACKEND_HOST = process.env.BACKEND ?? \`http://127.0.0.1:\${process.env.BACKEND_PORT ?? 3002}\`;
599
+ const FRONTEND_HOST = process.env.FRONTEND ?? \`http://127.0.0.1:\${process.env.FRONTEND_PORT ?? 3001}\`;
600
+ const BACKEND = parseTarget(BACKEND_HOST);
601
+ const FRONTEND = parseTarget(FRONTEND_HOST);
552
602
 
553
603
  const ADMIN_PREFIX = process.env.ADMIN_PREFIX ?? "${prefix}";
554
604
  // Pipe-separated list of /api/<segment> paths that route to the backend.
@@ -830,6 +880,10 @@ The Node proxy is intended for dev and small self-hosted deploys.
830
880
  }
831
881
 
832
882
  function writeRootGitignore(targetDir) {
883
+ // NOTE: .env.local is intentionally NOT ignored — it holds shared dev port
884
+ // defaults (PROXY_PORT/FRONTEND_PORT/BACKEND_PORT) and other non-secret
885
+ // workspace knobs that should travel with the repo. Keep real secrets in
886
+ // .env (ignored) or apps/backend/.env.local (ignored by the submodule).
833
887
  const ignore = [
834
888
  "node_modules",
835
889
  ".pnpm-store",
@@ -838,8 +892,6 @@ function writeRootGitignore(targetDir) {
838
892
  "dist",
839
893
  "build",
840
894
  ".env",
841
- ".env.local",
842
- ".env*.local",
843
895
  "*.log",
844
896
  ".DS_Store",
845
897
  "",
@@ -851,12 +903,12 @@ function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecre
851
903
  const header = adminPrefix
852
904
  ? [
853
905
  "# Single-origin monorepo dev env",
854
- "# Public origin = frontend (apps/frontend on :3001). Frontend rewrites /admin/*,",
855
- "# /api/*, /uploads/*, and the asset prefix to the backend (apps/backend on :3000).",
906
+ `# Public origin = frontend (apps/frontend on :${DEFAULT_FRONTEND_PORT}). Frontend rewrites /admin/*,`,
907
+ `# /api/*, /uploads/*, and the asset prefix to the backend (apps/backend on :${DEFAULT_BACKEND_PORT}).`,
856
908
  ]
857
909
  : [
858
910
  "# Separate-origins monorepo dev env",
859
- "# Backend runs at http://localhost:3000, frontend at http://localhost:3001.",
911
+ `# Backend runs at http://localhost:${DEFAULT_BACKEND_PORT}, frontend at http://localhost:${DEFAULT_FRONTEND_PORT}.`,
860
912
  "# To switch to single-origin: set APOLLO_ASSET_PREFIX (default: /admin) and",
861
913
  "# BACKEND_INTERNAL_URL, then add rewrites() to apps/frontend/next.config.ts.",
862
914
  ];
@@ -864,10 +916,25 @@ function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecre
864
916
  const lines = [
865
917
  ...header,
866
918
  "",
919
+ "# ── Dev server ports ─────────────────────────────────────────────",
920
+ "# Single source of truth for local ports. Consumed by:",
921
+ "# • apps/proxy/server.mjs (PROXY_PORT, FRONTEND_PORT, BACKEND_PORT)",
922
+ "# • scripts/with-env.mjs (maps FRONTEND_PORT/BACKEND_PORT → PORT",
923
+ "# when launching apps/frontend & apps/backend,",
924
+ "# and derives NEXT_PUBLIC_SITE_URL /",
925
+ "# BACKEND_INTERNAL_URL when those are unset)",
926
+ "# Override any of these; the proxy/frontend/backend will follow.",
927
+ `PROXY_PORT=${DEFAULT_PROXY_PORT}`,
928
+ `FRONTEND_PORT=${DEFAULT_FRONTEND_PORT}`,
929
+ `BACKEND_PORT=${DEFAULT_BACKEND_PORT}`,
930
+ "",
867
931
  "# ── Shared (consumed by both apps) ───────────────────────────────",
868
932
  `DATABASE_URL=${dbUrl}`,
869
933
  `APOLLO_SECRET=${authSecret}`,
870
934
  `CRON_SECRET=${cronSecret}`,
935
+ "# Public origin. In dev, leave blank to auto-derive from FRONTEND_PORT",
936
+ "# (single-origin) or BACKEND_PORT (separate-origins) via scripts/with-env.mjs.",
937
+ "# In prod set to the real domain (e.g. https://cms.example.com).",
871
938
  `NEXT_PUBLIC_SITE_URL=${siteUrl}`,
872
939
  `NEXT_PUBLIC_DEFAULT_LOCALE=${locale}`,
873
940
  "",
@@ -884,6 +951,9 @@ function writeRootEnv(targetDir, { dbUrl, siteUrl, locale, authSecret, cronSecre
884
951
  `APOLLO_EXTRA_PLUGINS_DIR=../cms-plugins`,
885
952
  "",
886
953
  "# ── Frontend (apps/frontend) ─────────────────────────────────────",
954
+ "# Where the frontend's rewrites point internally. In dev, leave blank",
955
+ "# to auto-derive http://127.0.0.1:${BACKEND_PORT} via scripts/with-env.mjs.",
956
+ "# In prod set to a private hostname (e.g. http://backend.internal:3000).",
887
957
  `BACKEND_INTERNAL_URL=${backendInternalUrl}`,
888
958
  "",
889
959
  );
@@ -913,9 +983,12 @@ function writeFrontendApp(targetDir, frontendName, siteUrl, adminPrefix, backend
913
983
  version: "0.0.0",
914
984
  private: true,
915
985
  scripts: {
916
- dev: "next dev -p 3001",
986
+ // No -p flag: Next.js reads PORT from env. The repo-root scripts use
987
+ // scripts/with-env.mjs --port=FRONTEND_PORT to inject the right value
988
+ // from .env.local (default 3001).
989
+ dev: "next dev",
917
990
  build: "next build",
918
- start: "next start -p 3001",
991
+ start: "next start",
919
992
  lint: "next lint",
920
993
  typecheck: "tsc --noEmit",
921
994
  },
@@ -1045,7 +1118,8 @@ export default config;
1045
1118
 
1046
1119
  writeFileSync(
1047
1120
  resolve(dir, ".gitignore"),
1048
- ["node_modules", ".next", "dist", ".env.local", ""].join("\n"),
1121
+ // .env.local is intentionally committed — it only contains dev port hints.
1122
+ ["node_modules", ".next", "dist", ""].join("\n"),
1049
1123
  );
1050
1124
 
1051
1125
  // Vercel project config for the frontend. Skip cron + region pinning is
@@ -1273,6 +1347,88 @@ console.log(\`Run: pnpm install && pnpm cms-plugins:build && pnpm dev:backend\`)
1273
1347
  writeFileSync(resolve(scriptsDir, "new-cms-plugin.mjs"), script);
1274
1348
  }
1275
1349
 
1350
+ // Small launcher that loads root .env.local, applies port defaults
1351
+ // (PROXY_PORT=3030 / FRONTEND_PORT=3001 / BACKEND_PORT=3002), optionally maps
1352
+ // one of them onto PORT (Next.js reads PORT), and execs the rest of argv.
1353
+ //
1354
+ // Usage:
1355
+ // node scripts/with-env.mjs [--port=VAR_NAME] <command> [args...]
1356
+ function writeWithEnvScript(targetDir) {
1357
+ const scriptsDir = resolve(targetDir, "scripts");
1358
+ mkdirSync(scriptsDir, { recursive: true });
1359
+ const script = `#!/usr/bin/env node
1360
+ // Loads <repo-root>/.env.local so frontend / backend / proxy all share one
1361
+ // source of truth for ports. Process env still wins.
1362
+ //
1363
+ // Usage:
1364
+ // node scripts/with-env.mjs [--port=VAR_NAME] <command> [args...]
1365
+ // --port=FRONTEND_PORT copies process.env.FRONTEND_PORT onto PORT before exec,
1366
+ // so \`next dev\` and \`next start\` pick up the right port without --port flags.
1367
+
1368
+ import { existsSync, readFileSync } from "node:fs";
1369
+ import { spawn } from "node:child_process";
1370
+ import { dirname, resolve } from "node:path";
1371
+ import { fileURLToPath } from "node:url";
1372
+
1373
+ const here = dirname(fileURLToPath(import.meta.url));
1374
+ const envPath = resolve(here, "../.env.local");
1375
+
1376
+ if (existsSync(envPath)) {
1377
+ for (const raw of readFileSync(envPath, "utf8").split(/\\r?\\n/)) {
1378
+ const line = raw.trim();
1379
+ if (!line || line.startsWith("#")) continue;
1380
+ const eq = line.indexOf("=");
1381
+ if (eq < 0) continue;
1382
+ const k = line.slice(0, eq).trim();
1383
+ if (!/^[A-Z_][A-Z0-9_]*$/i.test(k)) continue;
1384
+ if (process.env[k] !== undefined) continue;
1385
+ let v = line.slice(eq + 1).trim();
1386
+ if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
1387
+ v = v.slice(1, -1);
1388
+ }
1389
+ process.env[k] = v;
1390
+ }
1391
+ }
1392
+
1393
+ // Fallbacks — keep in sync with apps/proxy/server.mjs and PM2 config.
1394
+ process.env.PROXY_PORT ||= "3030";
1395
+ process.env.FRONTEND_PORT ||= "3001";
1396
+ process.env.BACKEND_PORT ||= "3002";
1397
+
1398
+ // Derive URL vars from PORTs when unset. Dev-friendly: edit a port and
1399
+ // everything follows. Prod-friendly: set these explicitly to real hostnames
1400
+ // (e.g. https://cms.example.com, http://backend.internal:3000) and the
1401
+ // derivation is bypassed.
1402
+ //
1403
+ // NEXT_PUBLIC_SITE_URL is the public origin — defaults to the frontend port
1404
+ // (frontend rewrites /admin, /api, /uploads to the backend). For \`pnpm dev:rp\`
1405
+ // set it to http://localhost:\${PROXY_PORT} so Better Auth / OAuth callbacks
1406
+ // land on the unified origin.
1407
+ process.env.NEXT_PUBLIC_SITE_URL ||= \`http://localhost:\${process.env.FRONTEND_PORT}\`;
1408
+ process.env.BACKEND_INTERNAL_URL ||= \`http://127.0.0.1:\${process.env.BACKEND_PORT}\`;
1409
+
1410
+ const args = process.argv.slice(2);
1411
+ if (args[0]?.startsWith("--port=")) {
1412
+ const name = args.shift().slice(7);
1413
+ if (process.env[name]) process.env.PORT = process.env[name];
1414
+ }
1415
+
1416
+ if (!args.length) {
1417
+ console.error("Usage: node scripts/with-env.mjs [--port=VAR] <command> [args...]");
1418
+ process.exit(2);
1419
+ }
1420
+
1421
+ const [cmd, ...rest] = args;
1422
+ const child = spawn(cmd, rest, {
1423
+ stdio: "inherit",
1424
+ env: process.env,
1425
+ shell: process.platform === "win32",
1426
+ });
1427
+ child.on("exit", (code, sig) => process.exit(sig ? 1 : code ?? 0));
1428
+ `;
1429
+ writeFileSync(resolve(scriptsDir, "with-env.mjs"), script);
1430
+ }
1431
+
1276
1432
  // Pre-build env check. Fails the build before \`next build\` runs if backend
1277
1433
  // required vars are missing, so users don't sit through a 30s build only to
1278
1434
  // hit a runtime error on first request.
@@ -1349,7 +1505,7 @@ module.exports = {
1349
1505
  cwd: "./apps/frontend",
1350
1506
  script: "node_modules/next/dist/bin/next",
1351
1507
  args: "start",
1352
- env: { NODE_ENV: "production", PORT: 3001 },
1508
+ env: { NODE_ENV: "production", PORT: Number(process.env.FRONTEND_PORT) || 3001 },
1353
1509
  max_memory_restart: "1G",
1354
1510
  autorestart: true,
1355
1511
  },
@@ -1358,7 +1514,7 @@ module.exports = {
1358
1514
  cwd: "./apps/backend",
1359
1515
  script: "node_modules/next/dist/bin/next",
1360
1516
  args: "start",
1361
- env: { NODE_ENV: "production", PORT: 3000 },
1517
+ env: { NODE_ENV: "production", PORT: Number(process.env.BACKEND_PORT) || 3002 },
1362
1518
  max_memory_restart: "1G",
1363
1519
  autorestart: true,
1364
1520
  },
@@ -1367,9 +1523,9 @@ module.exports = {
1367
1523
  script: "./apps/proxy/server.mjs",
1368
1524
  env: {
1369
1525
  NODE_ENV: "production",
1370
- PORT: 3030,
1371
- BACKEND: "http://127.0.0.1:3000",
1372
- FRONTEND: "http://127.0.0.1:3001",
1526
+ PROXY_PORT: Number(process.env.PROXY_PORT) || 3030,
1527
+ FRONTEND_PORT: Number(process.env.FRONTEND_PORT) || 3001,
1528
+ BACKEND_PORT: Number(process.env.BACKEND_PORT) || 3002,
1373
1529
  ${singleOrigin ? `ADMIN_PREFIX: "${adminPrefix}",` : ""}
1374
1530
  },
1375
1531
  max_memory_restart: "256M",
@@ -1758,7 +1914,7 @@ async function main() {
1758
1914
 
1759
1915
  if (!flags.directory) {
1760
1916
  log(HELP_TEXT);
1761
- fatal("Please provide a directory name.\n Example: npx create-apollo-monorepo thamc-new");
1917
+ fatal("Please provide a directory name.\n Example: npx create-apollo-monorepo my-site");
1762
1918
  }
1763
1919
 
1764
1920
  log(`\n${COLORS.bold}${COLORS.cyan} Apollo CMS Monorepo Installer${COLORS.reset}\n`);
@@ -1777,7 +1933,7 @@ async function main() {
1777
1933
  // Required by apollo-cms's /api/cron route and scripts/dev-cron.ts in dev.
1778
1934
  // Without it the dev cron loop hits 403 "CRON_SECRET not configured".
1779
1935
  const cronSecret = randomBytes(24).toString("hex");
1780
- const backendInternalUrl = "http://localhost:3000";
1936
+ const backendInternalUrl = `http://localhost:${DEFAULT_BACKEND_PORT}`;
1781
1937
  success(`Frontend pkg name: ${frontendName}`);
1782
1938
  success(`Admin prefix: ${adminPrefix || "(disabled — separate origins)"}`);
1783
1939
 
@@ -1794,11 +1950,12 @@ async function main() {
1794
1950
  if (adminPrefix) writeNginxSample(targetDir, adminPrefix);
1795
1951
  writeProxyApp(targetDir, dirName, adminPrefix);
1796
1952
  writeCheckEnvScript(targetDir);
1953
+ writeWithEnvScript(targetDir);
1797
1954
  writePm2Config(targetDir, dirName, adminPrefix);
1798
1955
  success(
1799
1956
  `package.json, pnpm-workspace.yaml, .gitignore, .env.local, README.md, CLAUDE.md${
1800
1957
  adminPrefix ? ", nginx.conf.sample" : ""
1801
- }, apps/proxy, ecosystem.config.cjs, scripts/check-env.mjs`,
1958
+ }, apps/proxy, ecosystem.config.cjs, scripts/check-env.mjs, scripts/with-env.mjs`,
1802
1959
  );
1803
1960
 
1804
1961
  // ── Step 4: git init ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-apollo-monorepo",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
4
4
  "description": "Scaffold a monorepo with a frontend app and Apollo CMS as a git submodule backend (single-origin via Next.js rewrites + assetPrefix)",
5
5
  "bin": {
6
6
  "create-apollo-monorepo": "index.mjs"
@@ -21,7 +21,7 @@
21
21
  ],
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "https://github.com/5Lab-Group-Co-Ltd/apollo-cms.git",
24
+ "url": "git+https://github.com/5Lab-Group-Co-Ltd/apollo-cms.git",
25
25
  "directory": "installer-monorepo"
26
26
  },
27
27
  "license": "MIT"