create-softeneers-app 0.1.0 → 0.2.0

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 (81) hide show
  1. package/README.html +56 -0
  2. package/README.md +16 -8
  3. package/dist/args.js +33 -4
  4. package/dist/args.js.map +1 -1
  5. package/dist/fragments.js +127 -0
  6. package/dist/fragments.js.map +1 -0
  7. package/dist/index.js +18 -7
  8. package/dist/index.js.map +1 -1
  9. package/dist/prompts.js +27 -1
  10. package/dist/prompts.js.map +1 -1
  11. package/dist/templates.js +33 -8
  12. package/dist/templates.js.map +1 -1
  13. package/package.json +2 -2
  14. package/templates/express-api/.env.example +13 -0
  15. package/templates/express-api/README.md +77 -0
  16. package/templates/express-api/docker-compose.yml +15 -0
  17. package/templates/express-api/package.json +36 -0
  18. package/templates/express-api/softeneers.template.json +17 -0
  19. package/templates/express-api/src/auth/auth.ts +11 -0
  20. package/templates/express-api/src/cars/routes.ts +58 -0
  21. package/templates/express-api/src/cars/store.ts +92 -0
  22. package/templates/express-api/src/cars/types.ts +8 -0
  23. package/templates/express-api/src/cars/validate.ts +16 -0
  24. package/templates/express-api/src/db.ts +13 -0
  25. package/templates/express-api/src/env.ts +23 -0
  26. package/templates/express-api/src/index.ts +55 -0
  27. package/templates/express-api/src/scripts/migrate.ts +13 -0
  28. package/templates/express-api/src/scripts/seed.ts +25 -0
  29. package/templates/express-api/test/validate.test.ts +25 -0
  30. package/templates/express-api/tsconfig.json +14 -0
  31. package/templates/hono-api/.env.example +13 -0
  32. package/templates/hono-api/README.md +77 -0
  33. package/templates/hono-api/docker-compose.yml +15 -0
  34. package/templates/hono-api/package.json +34 -0
  35. package/templates/hono-api/softeneers.template.json +17 -0
  36. package/templates/hono-api/src/auth/auth.ts +11 -0
  37. package/templates/hono-api/src/cars/routes.ts +43 -0
  38. package/templates/hono-api/src/cars/store.ts +92 -0
  39. package/templates/hono-api/src/cars/types.ts +8 -0
  40. package/templates/hono-api/src/cars/validate.ts +16 -0
  41. package/templates/hono-api/src/db.ts +13 -0
  42. package/templates/hono-api/src/env.ts +23 -0
  43. package/templates/hono-api/src/index.ts +44 -0
  44. package/templates/hono-api/src/scripts/migrate.ts +13 -0
  45. package/templates/hono-api/src/scripts/seed.ts +25 -0
  46. package/templates/hono-api/test/validate.test.ts +25 -0
  47. package/templates/hono-api/tsconfig.json +14 -0
  48. package/templates/minimal/.env.example +2 -0
  49. package/templates/minimal/README.md +33 -0
  50. package/templates/minimal/package.json +22 -0
  51. package/templates/minimal/src/index.ts +20 -0
  52. package/templates/minimal/test/greet.test.ts +12 -0
  53. package/templates/minimal/tsconfig.json +15 -0
  54. package/templates/tanstack-start/.env.example +11 -0
  55. package/templates/tanstack-start/README.md +73 -0
  56. package/templates/tanstack-start/docker-compose.yml +15 -0
  57. package/templates/tanstack-start/package.json +56 -0
  58. package/templates/tanstack-start/public/favicon.ico +0 -0
  59. package/templates/tanstack-start/public/logo192.png +0 -0
  60. package/templates/tanstack-start/public/logo512.png +0 -0
  61. package/templates/tanstack-start/public/manifest.json +25 -0
  62. package/templates/tanstack-start/public/robots.txt +3 -0
  63. package/templates/tanstack-start/softeneers.template.json +17 -0
  64. package/templates/tanstack-start/src/cars/types.ts +8 -0
  65. package/templates/tanstack-start/src/cars/validate.ts +16 -0
  66. package/templates/tanstack-start/src/router.tsx +19 -0
  67. package/templates/tanstack-start/src/routes/__root.tsx +54 -0
  68. package/templates/tanstack-start/src/routes/api/auth/$.ts +14 -0
  69. package/templates/tanstack-start/src/routes/cars.tsx +87 -0
  70. package/templates/tanstack-start/src/routes/index.tsx +20 -0
  71. package/templates/tanstack-start/src/server/auth.ts +11 -0
  72. package/templates/tanstack-start/src/server/cars.ts +27 -0
  73. package/templates/tanstack-start/src/server/db.ts +12 -0
  74. package/templates/tanstack-start/src/server/env.ts +22 -0
  75. package/templates/tanstack-start/src/server/scripts/migrate.ts +13 -0
  76. package/templates/tanstack-start/src/server/scripts/seed.ts +25 -0
  77. package/templates/tanstack-start/src/server/store.ts +79 -0
  78. package/templates/tanstack-start/src/styles.css +17 -0
  79. package/templates/tanstack-start/tsconfig.json +28 -0
  80. package/templates/tanstack-start/tsr.config.json +3 -0
  81. package/templates/tanstack-start/vite.config.ts +14 -0
package/README.html ADDED
@@ -0,0 +1,56 @@
1
+ <!doctype html>
2
+ <html lang="en"><head><meta charset="utf-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1">
4
+ <title>create-softeneers-app (CLI) — Softeneers Framework</title>
5
+ <style>
6
+ :root { color-scheme: light dark; }
7
+ * { box-sizing: border-box; }
8
+ body { font: 16px/1.6 -apple-system, system-ui, sans-serif; max-width: 820px;
9
+ margin: 0 auto; padding: 2rem 1.25rem 4rem; color: #1a1a1a; background: #fff; }
10
+ @media (prefers-color-scheme: dark) { body { color: #e6e6e6; background: #141414; } }
11
+ .bar { display: flex; flex-wrap: wrap; gap: .9rem; align-items: baseline;
12
+ padding-bottom: 1rem; margin-bottom: 1.5rem; border-bottom: 1px solid #8884; font-size: .9rem; }
13
+ .bar .spacer { flex: 1; }
14
+ .bar a { text-decoration: none; }
15
+ .src { color: #8889; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85rem; }
16
+ h1, h2, h3 { line-height: 1.25; }
17
+ h2 { margin-top: 2rem; border-bottom: 1px solid #8883; padding-bottom: .3rem; }
18
+ a { color: #2563eb; } @media (prefers-color-scheme: dark) { a { color: #6ea8fe; } }
19
+ code { background: #8882; padding: .1em .35em; border-radius: 4px; font-size: .9em; }
20
+ pre { background: #8881; padding: 1rem; border-radius: 8px; overflow-x: auto; }
21
+ pre code { background: none; padding: 0; }
22
+ table { border-collapse: collapse; width: 100%; margin: 1rem 0; font-size: .92rem; }
23
+ th, td { border: 1px solid #8884; padding: .4rem .6rem; text-align: left; }
24
+ blockquote { border-left: 3px solid #8886; margin: 1rem 0; padding: .2rem 1rem; color: #8889; }
25
+ footer { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid #8884; font-size: .85rem; color: #8889; }
26
+ .groups { display: grid; gap: 1.5rem; }
27
+ .group h2 { margin-top: 1.5rem; }
28
+ .group ul { list-style: none; padding: 0; margin: .5rem 0; }
29
+ .group li { margin: .35rem 0; }
30
+ .group .meta { color: #8889; font-size: .85rem; }
31
+ </style></head>
32
+ <body>
33
+ <div class="bar"><a href="../../index.html">← All docs</a><span class="spacer"></span><a class="src" href="./README.md">view README.md source</a></div>
34
+ <main><h1>create-softeneers-app</h1>
35
+ <p>The Softeneers Framework project generator. Run it to scaffold a new project from one of the bundled templates:</p>
36
+ <pre><code>npx create-softeneers-app@latest my-app</code></pre>
37
+ <h2>Templates</h2>
38
+ <p>Five templates, each for a different kind of user, with composable toggles:</p>
39
+ <table><thead><tr><th>Template</th><th>What you get</th><th>Toggles</th></tr></thead><tbody>
40
+ <tr><td><code>next-fullstack</code></td><td>Next.js web + Express/Sequelize/MySQL API</td><td>(all-in)</td></tr>
41
+ <tr><td><code>express-api</code></td><td>Express 5 + TypeScript REST API (cars CRUD)</td><td>db · auth · docker</td></tr>
42
+ <tr><td><code>hono-api</code></td><td>Hono + TypeScript API (cars CRUD)</td><td>db · auth · docker</td></tr>
43
+ <tr><td><code>tanstack-start</code></td><td>TanStack Start fullstack React app</td><td>db · auth · docker</td></tr>
44
+ <tr><td><code>minimal</code></td><td>Zero-framework Node + TypeScript starter</td><td>(none)</td></tr>
45
+ </tbody></table>
46
+ <pre><code>npx create-softeneers-app@latest my-app # interactive
47
+ npx create-softeneers-app@latest api -t express-api --yes # all defaults
48
+ npx create-softeneers-app@latest api -t hono-api --no-auth --no-docker</code></pre>
49
+ <p>Flags: <code>--template &lt;slug&gt;</code>, <code>--yes</code>/<code>-y</code>, <code>--db</code>/<code>--no-db</code>, <code>--auth</code>/<code>--no-auth</code>, <code>--docker</code>/<code>--no-docker</code>, <code>--no-install</code>, <code>--no-git</code>, <code>--pm &lt;pnpm|npm|yarn&gt;</code>, <code>--help</code>, <code>--version</code>. See <a href="../../docs/CLI-SPEC.html"><code>../../docs/CLI-SPEC.md</code></a> for the full contract.</p>
50
+ <h2>Local development</h2>
51
+ <pre><code>npm run build -w create-softeneers-app # tsc + bundle templates → dist/ + templates/
52
+ node apps/cli/dist/index.js my-app --yes # run the built CLI
53
+ npm run dev -w create-softeneers-app -- my-app # run from source via tsx</code></pre></main>
54
+ <footer>Softeneers Framework — human view generated from the canonical Markdown.
55
+ Do not edit by hand; run <code>npm run build</code> (the <code>.md</code> is the source of truth).</footer>
56
+ </body></html>
package/README.md CHANGED
@@ -7,19 +7,27 @@ from one of the bundled templates:
7
7
  npx create-softeneers-app@latest my-app
8
8
  ```
9
9
 
10
- ## Status
10
+ ## Templates
11
11
 
12
- **Implemented** for the `next-fullstack` template: interactive wizard, copy +
13
- transform, `git init`, dependency install, and next-step output. Other templates
14
- are listed in the wizard as "coming soon".
12
+ Five templates, each for a different kind of user, with composable toggles:
13
+
14
+ | Template | What you get | Toggles |
15
+ | ---------------- | ----------------------------------------- | ------------------ |
16
+ | `next-fullstack` | Next.js web + Express/Sequelize/MySQL API | (all-in) |
17
+ | `express-api` | Express 5 + TypeScript REST API (cars CRUD) | db · auth · docker |
18
+ | `hono-api` | Hono + TypeScript API (cars CRUD) | db · auth · docker |
19
+ | `tanstack-start` | TanStack Start fullstack React app | db · auth · docker |
20
+ | `minimal` | Zero-framework Node + TypeScript starter | (none) |
15
21
 
16
22
  ```bash
17
- npx create-softeneers-app@latest my-app # interactive
18
- npx create-softeneers-app@latest my-app --yes --pm npm # non-interactive
23
+ npx create-softeneers-app@latest my-app # interactive
24
+ npx create-softeneers-app@latest api -t express-api --yes # all defaults
25
+ npx create-softeneers-app@latest api -t hono-api --no-auth --no-docker
19
26
  ```
20
27
 
21
- Flags: `--template <slug>`, `--yes`/`-y`, `--no-install`, `--no-git`,
22
- `--pm <pnpm|npm|yarn>`, `--help`, `--version`. See
28
+ Flags: `--template <slug>`, `--yes`/`-y`, `--db`/`--no-db`, `--auth`/`--no-auth`,
29
+ `--docker`/`--no-docker`, `--no-install`, `--no-git`, `--pm <pnpm|npm|yarn>`,
30
+ `--help`, `--version`. See
23
31
  [`../../docs/CLI-SPEC.md`](../../docs/CLI-SPEC.md) for the full contract.
24
32
 
25
33
  ## Local development
package/dist/args.js CHANGED
@@ -36,6 +36,24 @@ export function parseArgs(argv) {
36
36
  case "--no-git":
37
37
  opts.git = false;
38
38
  break;
39
+ case "--db":
40
+ opts.db = true;
41
+ break;
42
+ case "--no-db":
43
+ opts.db = false;
44
+ break;
45
+ case "--auth":
46
+ opts.auth = true;
47
+ break;
48
+ case "--no-auth":
49
+ opts.auth = false;
50
+ break;
51
+ case "--docker":
52
+ opts.docker = true;
53
+ break;
54
+ case "--no-docker":
55
+ opts.docker = false;
56
+ break;
39
57
  case "--help":
40
58
  case "-h":
41
59
  opts.help = true;
@@ -80,17 +98,28 @@ Usage:
80
98
  npx create-softeneers-app@latest [directory|.] [options]
81
99
 
82
100
  Options:
83
- -t, --template <name> Template to use (default: prompt; only "next-fullstack" for now)
101
+ -t, --template <name> Template to use (default: prompt)
84
102
  -y, --yes Accept defaults, no prompts
103
+ --db / --no-db Include a database layer (template default if unset)
104
+ --auth / --no-auth Include authentication (template default if unset)
105
+ --docker / --no-docker Include a Docker recipe (template default if unset)
85
106
  --no-install Don't install dependencies
86
107
  --no-git Don't run "git init"
87
108
  --pm <npm|pnpm|yarn> Package manager (default: auto-detected, else npm)
88
109
  -h, --help Show this help
89
110
  -v, --version Show version
90
111
 
112
+ Templates:
113
+ next-fullstack Next.js web + Express/Sequelize/MySQL API (db, auth, docker)
114
+ express-api Express + TypeScript REST API (db, auth, docker)
115
+ hono-api Hono + TypeScript API (db, auth, docker)
116
+ tanstack-start TanStack Start fullstack React app (db, auth, docker)
117
+ minimal Zero-framework Node + TypeScript starter (no toggles)
118
+
91
119
  Examples:
92
- npx create-softeneers-app@latest my-app # scaffold into ./my-app
93
- npx create-softeneers-app@latest . # scaffold into the current directory
94
- npm create softeneers-app@latest my-app -- --yes
120
+ npx create-softeneers-app@latest my-app # interactive
121
+ npx create-softeneers-app@latest api -t express-api --yes # all defaults
122
+ npx create-softeneers-app@latest api -t hono-api --no-auth --no-docker
123
+ npx create-softeneers-app@latest . # current directory
95
124
  `;
96
125
  //# sourceMappingURL=args.js.map
package/dist/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAqBvE,MAAM,GAAG,GAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;AAEtD;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC;IACnD,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,IAAI,GAAe;QACvB,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,IAAI;QACT,cAAc,EAAE,oBAAoB,EAAE;QACtC,IAAI,EAAE,KAAK;QACX,OAAO,EAAE,KAAK;KACf,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,SAAS;YAAE,SAAS;QAChC,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,OAAO,CAAC;YACb,KAAK,IAAI;gBACP,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;gBAChB,MAAM;YACR,KAAK,cAAc;gBACjB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;gBACrB,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC;gBACjB,MAAM;YACR,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;gBACjB,MAAM;YACR,KAAK,WAAW,CAAC;YACjB,KAAK,IAAI;gBACP,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,MAAM;YACR,KAAK,YAAY,CAAC;YAClB,KAAK,IAAI;gBACP,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC1B,MAAM;YACR,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACrB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAoB,CAAC,EAAE,CAAC;oBACxC,MAAM,IAAI,QAAQ,CAAC,wBAAwB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;gBAC7E,CAAC;gBACD,IAAI,CAAC,cAAc,GAAG,EAAoB,CAAC;gBAC3C,MAAM;YACR,CAAC;YACD;gBACE,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,IAAI,QAAQ,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;gBAC/C,CAAC;gBACD,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;oBACjC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;gBACvB,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,QAAQ,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;gBACpD,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+DAA+D;AAC/D,MAAM,OAAO,QAAS,SAAQ,KAAK;CAAG;AAEtC,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;CAmBxB,CAAC"}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ // Fragment/toggle engine. A template may ship a `softeneers.template.json`
2
+ // manifest declaring optional features (db / auth / docker). When a feature is
3
+ // toggled OFF, the scaffold removes that fragment's files, package.json deps and
4
+ // scripts, and strips `#if`/`#endif` marker blocks from text files. Templates
5
+ // without a manifest (e.g. `minimal`) support no toggles and are copied as-is.
6
+ import { basename, join } from "node:path";
7
+ import { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
+ export const TOGGLE_KEYS = ["db", "auth", "docker"];
9
+ const MANIFEST_NAME = "softeneers.template.json";
10
+ export function readManifest(dir) {
11
+ const p = join(dir, MANIFEST_NAME);
12
+ if (!existsSync(p))
13
+ return null;
14
+ return JSON.parse(readFileSync(p, "utf8"));
15
+ }
16
+ /** Supported toggles + their default values (empty object when no manifest). */
17
+ export function templateToggleDefaults(dir) {
18
+ return readManifest(dir)?.toggles ?? {};
19
+ }
20
+ const TEXT_EXT = new Set([
21
+ "ts", "tsx", "js", "jsx", "mjs", "cjs", "md", "mdx", "yml", "yaml",
22
+ "css", "scss", "html", "txt", "sh", "env", "example", "toml", "gitignore",
23
+ ]);
24
+ function isTextFile(name) {
25
+ if (name === "Dockerfile" || name.startsWith(".env"))
26
+ return true;
27
+ const ext = name.includes(".") ? name.split(".").pop() : "";
28
+ return TEXT_EXT.has(ext);
29
+ }
30
+ function walkFiles(dir, out = []) {
31
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
32
+ if (entry.name === "node_modules" || entry.name === ".git")
33
+ continue;
34
+ const full = join(dir, entry.name);
35
+ if (entry.isDirectory())
36
+ walkFiles(full, out);
37
+ else
38
+ out.push(full);
39
+ }
40
+ return out;
41
+ }
42
+ /**
43
+ * Strip conditional blocks from a text file. A block opens with a line
44
+ * containing `#if <key>` or `#if !<key>` and closes with `#endif` (the comment
45
+ * style around them is irrelevant — `//`, `#`, `<!-- -->` all work). The marker
46
+ * lines themselves are always removed; the body is kept only if the condition
47
+ * holds. Blocks nest.
48
+ */
49
+ export function processMarkers(content, toggles) {
50
+ const lines = content.split("\n");
51
+ const out = [];
52
+ const stack = [];
53
+ const emitting = () => stack.every(Boolean);
54
+ for (const line of lines) {
55
+ const open = line.match(/#if\s+(!)?\s*([A-Za-z_]\w*)/);
56
+ if (open) {
57
+ const negated = open[1] === "!";
58
+ const value = toggles[open[2]] ?? false;
59
+ stack.push(negated ? !value : value);
60
+ continue;
61
+ }
62
+ if (/#endif/.test(line)) {
63
+ stack.pop();
64
+ continue;
65
+ }
66
+ if (emitting())
67
+ out.push(line);
68
+ }
69
+ return out.join("\n");
70
+ }
71
+ function prunePackageJson(file, removeDeps, removeScripts) {
72
+ const pkg = JSON.parse(readFileSync(file, "utf8"));
73
+ for (const field of ["dependencies", "devDependencies", "peerDependencies"]) {
74
+ const deps = pkg[field];
75
+ if (deps)
76
+ for (const name of removeDeps)
77
+ delete deps[name];
78
+ }
79
+ if (pkg.scripts)
80
+ for (const name of removeScripts)
81
+ delete pkg.scripts[name];
82
+ writeFileSync(file, JSON.stringify(pkg, null, 2) + "\n");
83
+ }
84
+ /**
85
+ * Apply the resolved toggles to a freshly-copied template: delete OFF fragments'
86
+ * paths, prune their deps/scripts from every package.json, strip marker blocks,
87
+ * and remove the manifest from the generated project.
88
+ */
89
+ export function applyToggles(targetDir, toggles) {
90
+ const manifest = readManifest(targetDir);
91
+ const removeDeps = new Set();
92
+ const removeScripts = new Set();
93
+ if (manifest?.fragments) {
94
+ for (const key of TOGGLE_KEYS) {
95
+ if (toggles[key])
96
+ continue; // only prune a fragment when its toggle is OFF
97
+ const fragment = manifest.fragments[key];
98
+ if (!fragment)
99
+ continue;
100
+ for (const rel of fragment.removePaths ?? []) {
101
+ rmSync(join(targetDir, rel), { recursive: true, force: true });
102
+ }
103
+ for (const dep of fragment.removeDeps ?? [])
104
+ removeDeps.add(dep);
105
+ for (const script of fragment.removeScripts ?? [])
106
+ removeScripts.add(script);
107
+ }
108
+ }
109
+ for (const file of walkFiles(targetDir)) {
110
+ const name = basename(file);
111
+ if (name === MANIFEST_NAME)
112
+ continue;
113
+ if (name === "package.json") {
114
+ if (removeDeps.size || removeScripts.size)
115
+ prunePackageJson(file, removeDeps, removeScripts);
116
+ continue;
117
+ }
118
+ if (!isTextFile(name))
119
+ continue;
120
+ const content = readFileSync(file, "utf8");
121
+ if (!content.includes("#if") && !content.includes("#endif"))
122
+ continue;
123
+ writeFileSync(file, processMarkers(content, toggles));
124
+ }
125
+ rmSync(join(targetDir, MANIFEST_NAME), { force: true });
126
+ }
127
+ //# sourceMappingURL=fragments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragments.js","sourceRoot":"","sources":["../src/fragments.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,7 +3,8 @@ import { createRequire } from "node:module";
3
3
  import { basename, resolve } from "node:path";
4
4
  import { intro, log, note, outro, spinner } from "@clack/prompts";
5
5
  import { CliError, HELP_TEXT, parseArgs } from "./args.js";
6
- import { promptProjectName, promptTemplate } from "./prompts.js";
6
+ import { applyToggles, templateToggleDefaults } from "./fragments.js";
7
+ import { promptProjectName, promptTemplate, promptToggles } from "./prompts.js";
7
8
  import { assertTargetUsable, copyTemplate, gitInit, installDeps, toPackageName, transform, } from "./scaffold.js";
8
9
  import { DEFAULT_TEMPLATE, findTemplate, resolveTemplateDir } from "./templates.js";
9
10
  function version() {
@@ -44,12 +45,23 @@ async function main() {
44
45
  if (!templateDir) {
45
46
  throw new CliError(`Could not locate template files for "${slug}".`);
46
47
  }
47
- // 3. Generate.
48
+ // 3. Feature toggles (db / auth / docker) — only those the template supports.
49
+ const toggleDefaults = templateToggleDefaults(templateDir);
50
+ const overrides = { db: opts.db, auth: opts.auth, docker: opts.docker };
51
+ const toggles = opts.yes
52
+ ? {
53
+ db: overrides.db ?? toggleDefaults.db ?? false,
54
+ auth: overrides.auth ?? toggleDefaults.auth ?? false,
55
+ docker: overrides.docker ?? toggleDefaults.docker ?? false,
56
+ }
57
+ : await promptToggles(toggleDefaults, overrides);
58
+ // 4. Generate.
48
59
  assertTargetUsable(targetDir);
49
60
  const pkgName = toPackageName(targetDir);
50
61
  const s = spinner();
51
62
  s.start(`Creating ${projectName}`);
52
63
  copyTemplate(templateDir, targetDir);
64
+ applyToggles(targetDir, toggles);
53
65
  transform(targetDir, projectName, pkgName, opts.packageManager);
54
66
  s.stop(`Created ${projectName}`);
55
67
  if (opts.git) {
@@ -68,18 +80,17 @@ async function main() {
68
80
  inst.stop("Dependency install failed — run it manually.");
69
81
  }
70
82
  }
71
- // 4. Next steps.
83
+ // 5. Next steps — conditional on the toggles that ended up enabled.
72
84
  const pm = opts.packageManager;
73
85
  const steps = [
74
86
  ...(inCurrentDir ? [] : [`cd ${rawTarget}`]),
75
87
  ...(opts.install ? [] : [`${pm} install`]),
76
- "docker compose up -d # start MySQL",
77
- `${pm} run db:migrate`,
78
- `${pm} run db:seed`,
88
+ ...(toggles.docker ? ["docker compose up -d # start services"] : []),
89
+ ...(toggles.db ? [`${pm} run db:migrate`, `${pm} run db:seed`] : []),
79
90
  `${pm} run dev`,
80
91
  ].join("\n");
81
92
  note(steps, "Next steps");
82
- outro("Web: http://localhost:3000 API: http://localhost:4000");
93
+ outro(template.outro ?? "Happy hacking!");
83
94
  }
84
95
  main().catch((err) => {
85
96
  if (err instanceof CliError) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/prompts.js CHANGED
@@ -1,4 +1,5 @@
1
- import { cancel, isCancel, select, text } from "@clack/prompts";
1
+ import { cancel, confirm, isCancel, select, text } from "@clack/prompts";
2
+ import {} from "./fragments.js";
2
3
  import { DEFAULT_TEMPLATE, TEMPLATES } from "./templates.js";
3
4
  function bail(value) {
4
5
  if (isCancel(value)) {
@@ -28,4 +29,29 @@ export async function promptTemplate() {
28
29
  });
29
30
  return bail(value);
30
31
  }
32
+ const TOGGLE_LABELS = {
33
+ db: "Include a database? (CRUD persisted to MySQL via Sequelize)",
34
+ auth: "Include authentication? (email + password via better-auth)",
35
+ docker: "Include a Docker recipe? (docker-compose for local services)",
36
+ };
37
+ /**
38
+ * Ask for each toggle the template supports (a key present in `defaults`).
39
+ * A toggle already fixed on the command line (`overrides[key] !== undefined`)
40
+ * skips its prompt. Unsupported toggles resolve to `false`.
41
+ */
42
+ export async function promptToggles(defaults, overrides) {
43
+ const result = { db: false, auth: false, docker: false };
44
+ for (const key of Object.keys(defaults)) {
45
+ if (overrides[key] !== undefined) {
46
+ result[key] = overrides[key];
47
+ continue;
48
+ }
49
+ const value = await confirm({
50
+ message: TOGGLE_LABELS[key],
51
+ initialValue: defaults[key] ?? false,
52
+ });
53
+ result[key] = bail(value);
54
+ }
55
+ return result;
56
+ }
31
57
  //# sourceMappingURL=prompts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE7D,SAAS,IAAI,CAAI,KAAiB;IAChC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,YAAY,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAgB;IACtD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;QACvB,OAAO,EAAE,eAAe;QACxB,WAAW,EAAE,QAAQ;QACrB,YAAY,EAAE,OAAO;QACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CAAC;KACtF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;QACzB,OAAO,EAAE,mCAAmC;QAC5C,YAAY,EAAE,gBAAgB;QAC9B,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,KAAK,EAAE,CAAC,CAAC,IAAI;YACb,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,sBAAsB;SAC7D,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAAgC,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE7D,SAAS,IAAI,CAAI,KAAiB;IAChC,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,CAAC,YAAY,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAgB;IACtD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;QACvB,OAAO,EAAE,eAAe;QACxB,WAAW,EAAE,QAAQ;QACrB,YAAY,EAAE,OAAO;QACrB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,SAAS,CAAC;KACtF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;QACzB,OAAO,EAAE,mCAAmC;QAC5C,YAAY,EAAE,gBAAgB;QAC9B,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7B,KAAK,EAAE,CAAC,CAAC,IAAI;YACb,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,sBAAsB;SAC7D,CAAC,CAAC;KACJ,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,aAAa,GAA8B;IAC/C,EAAE,EAAE,6DAA6D;IACjE,IAAI,EAAE,4DAA4D;IAClE,MAAM,EAAE,8DAA8D;CACvE,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAA0B,EAC1B,SAA2B;IAE3B,MAAM,MAAM,GAAY,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAClE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAgB,EAAE,CAAC;QACvD,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAE,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC;YAC1B,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC;YAC3B,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,KAAK;SACrC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/templates.js CHANGED
@@ -2,21 +2,46 @@ import { existsSync, statSync } from "node:fs";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  /**
5
- * The template registry. Only `next-fullstack` is generatable today; the rest
6
- * are advertised so the wizard reflects the intended menu (docs/CLI-SPEC.md)
7
- * and light up as they land.
5
+ * The template registry. Each entry targets a different kind of user; the
6
+ * db/auth/docker toggles (where supported) are declared per template in its
7
+ * `softeneers.template.json` manifest.
8
8
  */
9
9
  export const TEMPLATES = [
10
10
  {
11
11
  slug: "next-fullstack",
12
12
  label: "Fullstack (Next.js + Express + Sequelize + MySQL)",
13
- hint: "web + server monorepo, Docker MySQL",
13
+ hint: "web + server monorepo",
14
14
  available: true,
15
+ outro: "Web: http://localhost:3000 API: http://localhost:4000",
16
+ },
17
+ {
18
+ slug: "express-api",
19
+ label: "Express API (TypeScript REST)",
20
+ hint: "API only · db/auth/docker toggles",
21
+ available: true,
22
+ outro: "API: http://localhost:4000",
23
+ },
24
+ {
25
+ slug: "hono-api",
26
+ label: "Hono API (TypeScript, fast)",
27
+ hint: "API only · db/auth/docker toggles",
28
+ available: true,
29
+ outro: "API: http://localhost:4000",
30
+ },
31
+ {
32
+ slug: "tanstack-start",
33
+ label: "TanStack Start (fullstack React)",
34
+ hint: "app + server routes · db/auth/docker toggles",
35
+ available: true,
36
+ outro: "App: http://localhost:3000",
37
+ },
38
+ {
39
+ slug: "minimal",
40
+ label: "Minimal (Node + TypeScript starter)",
41
+ hint: "zero-framework blank slate",
42
+ available: true,
43
+ outro: "Run: npm run dev",
15
44
  },
16
- { slug: "tanstack-start", label: "TanStack Start", hint: "coming soon", available: false },
17
- { slug: "hono-api", label: "Hono API only", hint: "coming soon", available: false },
18
- { slug: "express-api", label: "Express API only", hint: "coming soon", available: false },
19
- { slug: "minimal", label: "Minimal", hint: "coming soon", available: false },
20
45
  ];
21
46
  export const DEFAULT_TEMPLATE = "next-fullstack";
22
47
  export function findTemplate(slug) {
@@ -1 +1 @@
1
- {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAUzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAmB;IACvC;QACE,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,mDAAmD;QAC1D,IAAI,EAAE,qCAAqC;QAC3C,SAAS,EAAE,IAAI;KAChB;IACD,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE;IAC1F,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE;IACnF,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE;IACzF,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,EAAE;CAC7E,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAEjD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,8BAA8B;IACpF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,WAAW;IAChD,MAAM,UAAU,GAAG;QACjB,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC;QACnC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC;KAChD,CAAC;IACF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAClF,CAAC"}
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAYzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAmB;IACvC;QACE,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,mDAAmD;QAC1D,IAAI,EAAE,uBAAuB;QAC7B,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,yDAAyD;KACjE;IACD;QACE,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,+BAA+B;QACtC,IAAI,EAAE,mCAAmC;QACzC,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,4BAA4B;KACpC;IACD;QACE,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,6BAA6B;QACpC,IAAI,EAAE,mCAAmC;QACzC,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,4BAA4B;KACpC;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,kCAAkC;QACzC,IAAI,EAAE,8CAA8C;QACpD,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,4BAA4B;KACpC;IACD;QACE,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,qCAAqC;QAC5C,IAAI,EAAE,4BAA4B;QAClC,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,kBAAkB;KAC1B;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAEjD,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,8BAA8B;IACpF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,WAAW;IAChD,MAAM,UAAU,GAAG;QACjB,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC;QACnC,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC;KAChD,CAAC;IACF,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAClF,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-softeneers-app",
3
- "version": "0.1.0",
4
- "description": "Scaffold a new Softeneers Framework project from a template.",
3
+ "version": "0.2.0",
4
+ "description": "Scaffold a new Softeneers Framework project: 5 templates (next-fullstack, express-api, hono-api, tanstack-start, minimal) with db/auth/docker toggles.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "create-softeneers-app": "dist/index.js"
@@ -0,0 +1,13 @@
1
+ PORT=4000
2
+ CORS_ORIGIN=http://localhost:3000
3
+ # #if db
4
+ DB_HOST=127.0.0.1
5
+ DB_PORT=3306
6
+ DB_NAME=app_dev
7
+ DB_USER=root
8
+ DB_PASSWORD=
9
+ # #endif
10
+ # #if auth
11
+ AUTH_SECRET=dev-secret-change-me-to-a-long-random-string
12
+ AUTH_BASE_URL=http://localhost:4000
13
+ # #endif
@@ -0,0 +1,77 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ An **Express 5 + TypeScript** REST API generated by
4
+ [`create-softeneers-app`](https://www.npmjs.com/package/create-softeneers-app),
5
+ with a full cars CRUD example.
6
+
7
+ ## Scripts
8
+
9
+ ```bash
10
+ npm run dev # watch-run src/index.ts (tsx)
11
+ npm run build # type-check + emit dist/ (tsc)
12
+ npm start # run the built server
13
+ npm run typecheck # tsc --noEmit
14
+ npm test # node:test suite (via tsx)
15
+ # #if db
16
+ npm run db:migrate # create/sync tables
17
+ npm run db:seed # insert sample cars
18
+ npm run db:reset # drop, recreate, reseed
19
+ # #endif
20
+ ```
21
+
22
+ ## API
23
+
24
+ | Method | Path | Description |
25
+ | ------ | ---------------- | ------------------ |
26
+ | GET | `/health` | Liveness check |
27
+ | GET | `/api/cars` | List cars |
28
+ | GET | `/api/cars/:id` | Get one car |
29
+ | POST | `/api/cars` | Create a car |
30
+ | PUT | `/api/cars/:id` | Update a car |
31
+ | DELETE | `/api/cars/:id` | Delete a car |
32
+ # #if auth
33
+ | ALL | `/api/auth/*` | better-auth routes |
34
+ # #endif
35
+
36
+ ```bash
37
+ curl localhost:4000/api/cars
38
+ curl -X POST localhost:4000/api/cars -H 'content-type: application/json' \
39
+ -d '{"brand":"Tesla","model":"Model 3","year":2023}'
40
+ ```
41
+ # #if db
42
+
43
+ ## Database
44
+
45
+ Persistence is MySQL via Sequelize ([`@softeneers/db`](https://www.npmjs.com/package/@softeneers/db)).
46
+ Configure `DB_*` in `.env`, then:
47
+
48
+ ```bash
49
+ # #if docker
50
+ docker compose up -d # start MySQL
51
+ # #endif
52
+ npm run db:migrate && npm run db:seed
53
+ ```
54
+
55
+ Toggle the database off at generation time (`--no-db`) to swap in a dependency-free
56
+ in-memory store — the CRUD API behaves identically.
57
+ # #endif
58
+ # #if auth
59
+
60
+ ## Authentication
61
+
62
+ Email + password auth via better-auth ([`@softeneers/auth`](https://www.npmjs.com/package/@softeneers/auth)),
63
+ mounted at `/api/auth/*`. Set a strong `AUTH_SECRET` in `.env` before deploying.
64
+ # #endif
65
+
66
+ ## Getting started
67
+
68
+ ```bash
69
+ npm install
70
+ # #if docker
71
+ docker compose up -d
72
+ # #endif
73
+ # #if db
74
+ npm run db:migrate && npm run db:seed
75
+ # #endif
76
+ npm run dev
77
+ ```
@@ -0,0 +1,15 @@
1
+ services:
2
+ db:
3
+ image: mysql:8
4
+ restart: unless-stopped
5
+ environment:
6
+ MYSQL_DATABASE: ${DB_NAME:-app_dev}
7
+ MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-}
8
+ MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
9
+ ports:
10
+ - "${DB_PORT:-3306}:3306"
11
+ volumes:
12
+ - db_data:/var/lib/mysql
13
+
14
+ volumes:
15
+ db_data: