create-softeneers-app 0.2.2 → 0.2.3

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 (51) hide show
  1. package/README.html +4 -4
  2. package/README.md +6 -6
  3. package/dist/args.js +23 -2
  4. package/dist/args.js.map +1 -1
  5. package/dist/fragments.js +1 -1
  6. package/dist/fragments.js.map +1 -1
  7. package/dist/index.js +10 -7
  8. package/dist/index.js.map +1 -1
  9. package/dist/prompts.js +12 -2
  10. package/dist/prompts.js.map +1 -1
  11. package/package.json +1 -1
  12. package/templates/express-api/.env.example +23 -0
  13. package/templates/express-api/README.md +68 -1
  14. package/templates/express-api/package.json +3 -0
  15. package/templates/express-api/softeneers.template.json +20 -1
  16. package/templates/express-api/src/email/mailer.ts +6 -0
  17. package/templates/express-api/src/email/routes.ts +26 -0
  18. package/templates/express-api/src/env.ts +18 -0
  19. package/templates/express-api/src/index.ts +23 -0
  20. package/templates/express-api/src/payments/routes.ts +44 -0
  21. package/templates/express-api/src/payments/stripe.ts +6 -0
  22. package/templates/express-api/src/payments/webhook.ts +43 -0
  23. package/templates/express-api/src/storage/routes.ts +28 -0
  24. package/templates/express-api/src/storage/store.ts +13 -0
  25. package/templates/hono-api/.env.example +23 -0
  26. package/templates/hono-api/README.md +69 -2
  27. package/templates/hono-api/package.json +3 -0
  28. package/templates/hono-api/softeneers.template.json +20 -1
  29. package/templates/hono-api/src/email/mailer.ts +6 -0
  30. package/templates/hono-api/src/email/routes.ts +24 -0
  31. package/templates/hono-api/src/env.ts +18 -0
  32. package/templates/hono-api/src/index.ts +20 -0
  33. package/templates/hono-api/src/payments/routes.ts +41 -0
  34. package/templates/hono-api/src/payments/stripe.ts +6 -0
  35. package/templates/hono-api/src/payments/webhook.ts +36 -0
  36. package/templates/hono-api/src/storage/routes.ts +29 -0
  37. package/templates/hono-api/src/storage/store.ts +13 -0
  38. package/templates/tanstack-start/.env.example +23 -0
  39. package/templates/tanstack-start/README.md +58 -3
  40. package/templates/tanstack-start/package.json +4 -0
  41. package/templates/tanstack-start/softeneers.template.json +28 -3
  42. package/templates/tanstack-start/src/lib/auth-client.ts +4 -0
  43. package/templates/tanstack-start/src/routes/account.tsx +47 -0
  44. package/templates/tanstack-start/src/routes/api/webhooks/stripe.ts +43 -0
  45. package/templates/tanstack-start/src/routes/billing.tsx +59 -0
  46. package/templates/tanstack-start/src/routes/index.tsx +15 -6
  47. package/templates/tanstack-start/src/routes/login.tsx +77 -0
  48. package/templates/tanstack-start/src/server/email.ts +27 -0
  49. package/templates/tanstack-start/src/server/env.ts +18 -0
  50. package/templates/tanstack-start/src/server/payments.ts +40 -0
  51. package/templates/tanstack-start/src/server/storage.ts +36 -0
package/README.html CHANGED
@@ -38,15 +38,15 @@ footer { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid #8884; font-
38
38
  <p>Five templates, each for a different kind of user, with composable toggles:</p>
39
39
  <table><thead><tr><th>Template</th><th>What you get</th><th>Toggles</th></tr></thead><tbody>
40
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>
41
+ <tr><td><code>express-api</code></td><td>Express 5 + TypeScript REST API (cars CRUD)</td><td>db · auth · docker · email · storage · payments</td></tr>
42
+ <tr><td><code>hono-api</code></td><td>Hono + TypeScript API (cars CRUD)</td><td>db · auth · docker · email · storage · payments</td></tr>
43
+ <tr><td><code>tanstack-start</code></td><td>TanStack Start fullstack React app (+ auth/billing UI)</td><td>db · auth · docker · email · storage · payments</td></tr>
44
44
  <tr><td><code>minimal</code></td><td>Zero-framework Node + TypeScript starter</td><td>(none)</td></tr>
45
45
  </tbody></table>
46
46
  <pre><code>npx create-softeneers-app@latest my-app # interactive
47
47
  npx create-softeneers-app@latest api -t express-api --yes # all defaults
48
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>
49
+ <p>Flags: <code>--template &lt;slug&gt;</code>, <code>--yes</code>/<code>-y</code>, <code>--db</code>, <code>--auth</code>, <code>--docker</code>, <code>--email</code>, <code>--storage</code>, <code>--payments</code> (each with a <code>--no-*</code> form), <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
50
  <h2>Local development</h2>
51
51
  <pre><code>npm run build -w create-softeneers-app # tsc + bundle templates → dist/ + templates/
52
52
  node apps/cli/dist/index.js my-app --yes # run the built CLI
package/README.md CHANGED
@@ -14,9 +14,9 @@ Five templates, each for a different kind of user, with composable toggles:
14
14
  | Template | What you get | Toggles |
15
15
  | ---------------- | ----------------------------------------- | ------------------ |
16
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 |
17
+ | `express-api` | Express 5 + TypeScript REST API (cars CRUD) | db · auth · docker · email · storage · payments |
18
+ | `hono-api` | Hono + TypeScript API (cars CRUD) | db · auth · docker · email · storage · payments |
19
+ | `tanstack-start` | TanStack Start fullstack React app (+ auth/billing UI) | db · auth · docker · email · storage · payments |
20
20
  | `minimal` | Zero-framework Node + TypeScript starter | (none) |
21
21
 
22
22
  ```bash
@@ -25,9 +25,9 @@ npx create-softeneers-app@latest api -t express-api --yes # all defaults
25
25
  npx create-softeneers-app@latest api -t hono-api --no-auth --no-docker
26
26
  ```
27
27
 
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
28
+ Flags: `--template <slug>`, `--yes`/`-y`, `--db`, `--auth`, `--docker`, `--email`,
29
+ `--storage`, `--payments` (each with a `--no-*` form), `--no-install`, `--no-git`,
30
+ `--pm <pnpm|npm|yarn>`, `--help`, `--version`. See
31
31
  [`../../docs/CLI-SPEC.md`](../../docs/CLI-SPEC.md) for the full contract.
32
32
 
33
33
  ## Local development
package/dist/args.js CHANGED
@@ -54,6 +54,24 @@ export function parseArgs(argv) {
54
54
  case "--no-docker":
55
55
  opts.docker = false;
56
56
  break;
57
+ case "--email":
58
+ opts.email = true;
59
+ break;
60
+ case "--no-email":
61
+ opts.email = false;
62
+ break;
63
+ case "--storage":
64
+ opts.storage = true;
65
+ break;
66
+ case "--no-storage":
67
+ opts.storage = false;
68
+ break;
69
+ case "--payments":
70
+ opts.payments = true;
71
+ break;
72
+ case "--no-payments":
73
+ opts.payments = false;
74
+ break;
57
75
  case "--help":
58
76
  case "-h":
59
77
  opts.help = true;
@@ -101,8 +119,11 @@ Options:
101
119
  -t, --template <name> Template to use (default: prompt)
102
120
  -y, --yes Accept defaults, no prompts
103
121
  --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)
122
+ --auth / --no-auth Include authentication + UI (template default if unset)
123
+ --docker / --no-docker Include a Docker recipe
124
+ --email / --no-email Include transactional email (@softeneers/email)
125
+ --storage / --no-storage Include object storage (@softeneers/storage)
126
+ --payments / --no-payments Include Stripe payments (@softeneers/payments)
106
127
  --no-install Don't install dependencies
107
128
  --no-git Don't run "git init"
108
129
  --pm <npm|pnpm|yarn> Package manager (default: auto-detected, else npm)
package/dist/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
package/dist/fragments.js CHANGED
@@ -5,7 +5,7 @@
5
5
  // without a manifest (e.g. `minimal`) support no toggles and are copied as-is.
6
6
  import { basename, join } from "node:path";
7
7
  import { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
- export const TOGGLE_KEYS = ["db", "auth", "docker"];
8
+ export const TOGGLE_KEYS = ["db", "auth", "docker", "email", "storage", "payments"];
9
9
  const MANIFEST_NAME = "softeneers.template.json";
10
10
  export function readManifest(dir) {
11
11
  const p = join(dir, MANIFEST_NAME);
@@ -1 +1 @@
1
- {"version":3,"file":"fragments.js","sourceRoot":"","sources":["../src/fragments.ts"],"names":[],"mappings":"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"}
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,7 @@ 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 { applyToggles, templateToggleDefaults } from "./fragments.js";
6
+ import { applyToggles, TOGGLE_KEYS, templateToggleDefaults } from "./fragments.js";
7
7
  import { promptProjectName, promptTemplate, promptToggles } from "./prompts.js";
8
8
  import { assertTargetUsable, copyTemplate, gitInit, installDeps, toPackageName, transform, } from "./scaffold.js";
9
9
  import { DEFAULT_TEMPLATE, findTemplate, resolveTemplateDir } from "./templates.js";
@@ -47,13 +47,16 @@ async function main() {
47
47
  }
48
48
  // 3. Feature toggles (db / auth / docker) — only those the template supports.
49
49
  const toggleDefaults = templateToggleDefaults(templateDir);
50
- const overrides = { db: opts.db, auth: opts.auth, docker: opts.docker };
50
+ const overrides = {
51
+ db: opts.db,
52
+ auth: opts.auth,
53
+ docker: opts.docker,
54
+ email: opts.email,
55
+ storage: opts.storage,
56
+ payments: opts.payments,
57
+ };
51
58
  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
- }
59
+ ? Object.fromEntries(TOGGLE_KEYS.map((key) => [key, overrides[key] ?? toggleDefaults[key] ?? false]))
57
60
  : await promptToggles(toggleDefaults, overrides);
58
61
  // 4. Generate.
59
62
  assertTargetUsable(targetDir);
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
@@ -31,8 +31,11 @@ export async function promptTemplate() {
31
31
  }
32
32
  const TOGGLE_LABELS = {
33
33
  db: "Include a database? (CRUD persisted to MySQL via Sequelize)",
34
- auth: "Include authentication? (email + password via better-auth)",
34
+ auth: "Include authentication? (email + password via better-auth, with UI)",
35
35
  docker: "Include a Docker recipe? (docker-compose for local services)",
36
+ email: "Include transactional email? (Resend + React Email)",
37
+ storage: "Include object storage? (S3 / R2 / MinIO uploads)",
38
+ payments: "Include Stripe payments? (checkout, subscriptions, webhooks)",
36
39
  };
37
40
  /**
38
41
  * Ask for each toggle the template supports (a key present in `defaults`).
@@ -40,7 +43,14 @@ const TOGGLE_LABELS = {
40
43
  * skips its prompt. Unsupported toggles resolve to `false`.
41
44
  */
42
45
  export async function promptToggles(defaults, overrides) {
43
- const result = { db: false, auth: false, docker: false };
46
+ const result = {
47
+ db: false,
48
+ auth: false,
49
+ docker: false,
50
+ email: false,
51
+ storage: false,
52
+ payments: false,
53
+ };
44
54
  for (const key of Object.keys(defaults)) {
45
55
  if (overrides[key] !== undefined) {
46
56
  result[key] = overrides[key];
@@ -1 +1 @@
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"}
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,qEAAqE;IAC3E,MAAM,EAAE,8DAA8D;IACtE,KAAK,EAAE,qDAAqD;IAC5D,OAAO,EAAE,mDAAmD;IAC5D,QAAQ,EAAE,8DAA8D;CACzE,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAA0B,EAC1B,SAA2B;IAE3B,MAAM,MAAM,GAAY;QACtB,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,KAAK;QACb,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,KAAK;KAChB,CAAC;IACF,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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-softeneers-app",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
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": {
@@ -11,3 +11,26 @@ DB_PASSWORD=
11
11
  AUTH_SECRET=dev-secret-change-me-to-a-long-random-string
12
12
  AUTH_BASE_URL=http://localhost:4000
13
13
  # #endif
14
+ # #if email
15
+ # Get a key at https://resend.com — the app boots without it; sending needs it.
16
+ RESEND_API_KEY=re_set_me
17
+ EMAIL_FROM=onboarding@resend.dev
18
+ # #endif
19
+ # #if storage
20
+ # S3-compatible storage (AWS S3 / Cloudflare R2 / MinIO).
21
+ S3_ACCESS_KEY_ID=
22
+ S3_SECRET_ACCESS_KEY=
23
+ S3_BUCKET=uploads
24
+ S3_REGION=auto
25
+ S3_ENDPOINT=
26
+ # #endif
27
+ # #if payments
28
+ # Stripe — the ONLY thing you must set for payments to work. Test keys from
29
+ # https://dashboard.stripe.com/test/apikeys ; webhook secret from `stripe listen`
30
+ # or the dashboard. Create two Prices and paste their ids below.
31
+ APP_URL=http://localhost:4000
32
+ STRIPE_SECRET_KEY=sk_test_set_me
33
+ STRIPE_WEBHOOK_SECRET=whsec_set_me
34
+ STRIPE_PRICE_ID=price_set_me
35
+ STRIPE_SUBSCRIPTION_PRICE_ID=price_set_me
36
+ # #endif
@@ -32,6 +32,20 @@ npm run db:reset # drop, recreate, reseed
32
32
  # #if auth
33
33
  | ALL | `/api/auth/*` | better-auth routes |
34
34
  # #endif
35
+ # #if email
36
+ | POST | `/api/email/welcome` | Send a welcome email |
37
+ # #endif
38
+ # #if storage
39
+ | POST | `/api/files/:key` | Upload an object |
40
+ | GET | `/api/files/:key/url`| Signed download URL |
41
+ | DELETE | `/api/files/:key` | Delete an object |
42
+ # #endif
43
+ # #if payments
44
+ | POST | `/api/payments/checkout` | One-time Stripe checkout |
45
+ | POST | `/api/payments/subscribe` | Subscription checkout |
46
+ | POST | `/api/payments/portal` | Billing portal |
47
+ | POST | `/api/webhooks/stripe` | Stripe webhook (verified) |
48
+ # #endif
35
49
 
36
50
  ```bash
37
51
  curl localhost:4000/api/cars
@@ -61,7 +75,60 @@ npm run db:migrate && npm run db:seed
61
75
  ## Authentication
62
76
 
63
77
  Email + password auth via better-auth ([`@softeneers/auth`](https://www.npmjs.com/package/@softeneers/auth)),
64
- mounted at `/api/auth/*`. Set a strong `AUTH_SECRET` in `.env` before deploying.
78
+ mounted at `/api/auth/*` (`sign-up/email`, `sign-in/email`, `get-session`, …).
79
+ Set a strong `AUTH_SECRET` in `.env` before deploying.
80
+ # #endif
81
+ # #if email
82
+
83
+ ## Email
84
+
85
+ Transactional email via Resend ([`@softeneers/email`](https://www.npmjs.com/package/@softeneers/email)).
86
+ Set `RESEND_API_KEY` (and `EMAIL_FROM`) in `.env`, then:
87
+
88
+ ```bash
89
+ curl -X POST localhost:4000/api/email/welcome -H 'content-type: application/json' \
90
+ -d '{"to":"you@example.com","name":"Ada"}'
91
+ ```
92
+ # #endif
93
+ # #if storage
94
+
95
+ ## Storage
96
+
97
+ S3-compatible uploads ([`@softeneers/storage`](https://www.npmjs.com/package/@softeneers/storage))
98
+ — works with AWS S3, Cloudflare R2, and MinIO. Set the `S3_*` keys in `.env`, then:
99
+
100
+ ```bash
101
+ curl -X POST --data-binary @photo.png localhost:4000/api/files/photo.png
102
+ curl localhost:4000/api/files/photo.png/url # → a signed download URL
103
+ ```
104
+ # #endif
105
+ # #if payments
106
+
107
+ ## Payments (Stripe)
108
+
109
+ Stripe checkout, subscriptions, the billing portal, and a verified webhook
110
+ ([`@softeneers/payments`](https://www.npmjs.com/package/@softeneers/payments)) —
111
+ **all pre-wired**. The only thing you do is paste your keys into `.env`:
112
+
113
+ ```
114
+ STRIPE_SECRET_KEY=sk_test_…
115
+ STRIPE_WEBHOOK_SECRET=whsec_…
116
+ STRIPE_PRICE_ID=price_… # one-time price
117
+ STRIPE_SUBSCRIPTION_PRICE_ID=price_… # recurring price
118
+ ```
119
+
120
+ Get test keys at <https://dashboard.stripe.com/test/apikeys> and create two
121
+ Prices. Locally, forward webhooks with the Stripe CLI (this also prints the
122
+ `whsec_…` secret):
123
+
124
+ ```bash
125
+ stripe listen --forward-to localhost:4000/api/webhooks/stripe
126
+ ```
127
+
128
+ Then `POST /api/payments/checkout` (or `/subscribe`) returns a Stripe URL to
129
+ redirect the customer to. The webhook handles `checkout.session.completed` and
130
+ the `customer.subscription.*` events — add your fulfilment logic in
131
+ `src/payments/webhook.ts`.
65
132
  # #endif
66
133
 
67
134
  ## Getting started
@@ -20,7 +20,10 @@
20
20
  "dependencies": {
21
21
  "@softeneers/auth": "^0.1.0",
22
22
  "@softeneers/db": "^0.1.0",
23
+ "@softeneers/email": "^0.1.0",
23
24
  "@softeneers/env": "^0.1.0",
25
+ "@softeneers/payments": "^0.1.0",
26
+ "@softeneers/storage": "^0.1.0",
24
27
  "cors": "^2.8.5",
25
28
  "dotenv": "^16.4.5",
26
29
  "express": "^5.0.0",
@@ -1,5 +1,12 @@
1
1
  {
2
- "toggles": { "db": false, "auth": false, "docker": false },
2
+ "toggles": {
3
+ "db": false,
4
+ "auth": false,
5
+ "docker": false,
6
+ "email": false,
7
+ "storage": false,
8
+ "payments": false
9
+ },
3
10
  "fragments": {
4
11
  "db": {
5
12
  "removePaths": ["src/db.ts", "src/scripts", "docker-compose.yml"],
@@ -12,6 +19,18 @@
12
19
  },
13
20
  "docker": {
14
21
  "removePaths": ["docker-compose.yml"]
22
+ },
23
+ "email": {
24
+ "removePaths": ["src/email"],
25
+ "removeDeps": ["@softeneers/email"]
26
+ },
27
+ "storage": {
28
+ "removePaths": ["src/storage"],
29
+ "removeDeps": ["@softeneers/storage"]
30
+ },
31
+ "payments": {
32
+ "removePaths": ["src/payments"],
33
+ "removeDeps": ["@softeneers/payments"]
15
34
  }
16
35
  }
17
36
  }
@@ -0,0 +1,6 @@
1
+ import { createEmailClient } from "@softeneers/email";
2
+
3
+ import { env } from "../env.js";
4
+
5
+ // A Resend client. No network call until you send.
6
+ export const mailer = createEmailClient(env.RESEND_API_KEY);
@@ -0,0 +1,26 @@
1
+ import { Router } from "express";
2
+
3
+ import { sendEmail } from "@softeneers/email";
4
+
5
+ import { env } from "../env.js";
6
+ import { mailer } from "./mailer.js";
7
+
8
+ export const emailRouter = Router();
9
+
10
+ // Demo: send a welcome email. POST { "to": "a@b.com", "name": "Ada" }
11
+ emailRouter.post("/welcome", async (req, res) => {
12
+ const to = typeof req.body?.to === "string" ? req.body.to : "";
13
+ const name = typeof req.body?.name === "string" ? req.body.name : "there";
14
+ if (!to) {
15
+ res.status(400).json({ message: "to (email address) is required." });
16
+ return;
17
+ }
18
+ await sendEmail(mailer, {
19
+ from: env.EMAIL_FROM,
20
+ to,
21
+ subject: "Welcome!",
22
+ html: `<h1>Welcome, ${name}!</h1><p>Thanks for joining.</p>`,
23
+ text: `Welcome, ${name}! Thanks for joining.`,
24
+ });
25
+ res.json({ sent: true });
26
+ });
@@ -19,5 +19,23 @@ export const env = createEnv({
19
19
  AUTH_SECRET: z.string().min(16).default("dev-secret-change-me-to-a-long-random-string"),
20
20
  AUTH_BASE_URL: z.string().default("http://localhost:4000"),
21
21
  // #endif
22
+ // #if email
23
+ RESEND_API_KEY: z.string().default("re_set_me_in_dotenv"),
24
+ EMAIL_FROM: z.string().default("onboarding@resend.dev"),
25
+ // #endif
26
+ // #if storage
27
+ S3_ACCESS_KEY_ID: z.string().default(""),
28
+ S3_SECRET_ACCESS_KEY: z.string().default(""),
29
+ S3_BUCKET: z.string().default("uploads"),
30
+ S3_REGION: z.string().default("auto"),
31
+ S3_ENDPOINT: z.string().default(""),
32
+ // #endif
33
+ // #if payments
34
+ APP_URL: z.string().default("http://localhost:4000"),
35
+ STRIPE_SECRET_KEY: z.string().default("sk_test_set_me_in_dotenv"),
36
+ STRIPE_WEBHOOK_SECRET: z.string().default("whsec_set_me_in_dotenv"),
37
+ STRIPE_PRICE_ID: z.string().default("price_set_me_in_dotenv"),
38
+ STRIPE_SUBSCRIPTION_PRICE_ID: z.string().default("price_set_me_in_dotenv"),
39
+ // #endif
22
40
  },
23
41
  });
@@ -8,6 +8,16 @@ import { toNodeHandler } from "@softeneers/auth";
8
8
 
9
9
  import { auth } from "./auth/auth.js";
10
10
  // #endif
11
+ // #if email
12
+ import { emailRouter } from "./email/routes.js";
13
+ // #endif
14
+ // #if storage
15
+ import { storageRouter } from "./storage/routes.js";
16
+ // #endif
17
+ // #if payments
18
+ import { paymentsRouter } from "./payments/routes.js";
19
+ import { stripeWebhookHandler } from "./payments/webhook.js";
20
+ // #endif
11
21
 
12
22
  const app = express();
13
23
 
@@ -15,6 +25,10 @@ const app = express();
15
25
  // better-auth handles its own body parsing, so mount it before express.json().
16
26
  app.all("/api/auth/*splat", toNodeHandler(auth));
17
27
  // #endif
28
+ // #if payments
29
+ // Stripe webhook signature verification needs the raw body — mount before express.json().
30
+ app.post("/api/webhooks/stripe", express.raw({ type: "application/json" }), stripeWebhookHandler);
31
+ // #endif
18
32
 
19
33
  app.use(cors({ origin: env.CORS_ORIGIN }));
20
34
  app.use(express.json());
@@ -24,6 +38,15 @@ app.get("/health", (_req, res) => {
24
38
  });
25
39
 
26
40
  app.use("/api/cars", carRouter);
41
+ // #if email
42
+ app.use("/api/email", emailRouter);
43
+ // #endif
44
+ // #if storage
45
+ app.use("/api/files", storageRouter);
46
+ // #endif
47
+ // #if payments
48
+ app.use("/api/payments", paymentsRouter);
49
+ // #endif
27
50
 
28
51
  app.use(
29
52
  (error: unknown, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
@@ -0,0 +1,44 @@
1
+ import { Router } from "express";
2
+
3
+ import { createBillingPortalSession, createCheckoutSession } from "@softeneers/payments";
4
+
5
+ import { env } from "../env.js";
6
+ import { stripe } from "./stripe.js";
7
+
8
+ export const paymentsRouter = Router();
9
+
10
+ // One-time purchase → returns a Stripe Checkout URL to redirect the browser to.
11
+ paymentsRouter.post("/checkout", async (_req, res) => {
12
+ const session = await createCheckoutSession(stripe, {
13
+ mode: "payment",
14
+ priceId: env.STRIPE_PRICE_ID,
15
+ successUrl: `${env.APP_URL}/?paid=1`,
16
+ cancelUrl: `${env.APP_URL}/?canceled=1`,
17
+ });
18
+ res.json({ url: session.url });
19
+ });
20
+
21
+ // Subscription checkout.
22
+ paymentsRouter.post("/subscribe", async (_req, res) => {
23
+ const session = await createCheckoutSession(stripe, {
24
+ mode: "subscription",
25
+ priceId: env.STRIPE_SUBSCRIPTION_PRICE_ID,
26
+ successUrl: `${env.APP_URL}/?subscribed=1`,
27
+ cancelUrl: `${env.APP_URL}/?canceled=1`,
28
+ });
29
+ res.json({ url: session.url });
30
+ });
31
+
32
+ // Billing portal so a customer can manage their subscription. Pass ?customer=cus_…
33
+ paymentsRouter.post("/portal", async (req, res) => {
34
+ const customer = String(req.query.customer ?? "");
35
+ if (!customer) {
36
+ res.status(400).json({ message: "A Stripe customer id (?customer=cus_…) is required." });
37
+ return;
38
+ }
39
+ const session = await createBillingPortalSession(stripe, {
40
+ customer,
41
+ returnUrl: `${env.APP_URL}/`,
42
+ });
43
+ res.json({ url: session.url });
44
+ });
@@ -0,0 +1,6 @@
1
+ import { createStripe } from "@softeneers/payments";
2
+
3
+ import { env } from "../env.js";
4
+
5
+ // A Stripe client. No network call until you actually create a session.
6
+ export const stripe = createStripe(env.STRIPE_SECRET_KEY);
@@ -0,0 +1,43 @@
1
+ import type { Request, Response } from "express";
2
+
3
+ import { constructWebhookEvent } from "@softeneers/payments";
4
+
5
+ import { env } from "../env.js";
6
+ import { stripe } from "./stripe.js";
7
+
8
+ // Stripe webhook. Mounted with express.raw() in index.ts because signature
9
+ // verification needs the raw request body. Handles both the one-time-payment
10
+ // and subscription event sets.
11
+ export function stripeWebhookHandler(req: Request, res: Response): void {
12
+ const signature = req.headers["stripe-signature"];
13
+ if (typeof signature !== "string") {
14
+ res.status(400).send("Missing stripe-signature header.");
15
+ return;
16
+ }
17
+
18
+ let event;
19
+ try {
20
+ event = constructWebhookEvent(stripe, req.body, signature, env.STRIPE_WEBHOOK_SECRET);
21
+ } catch (error) {
22
+ console.error("Stripe webhook signature verification failed:", error);
23
+ res.status(400).send("Invalid signature.");
24
+ return;
25
+ }
26
+
27
+ switch (event.type) {
28
+ case "checkout.session.completed":
29
+ // TODO: fulfil the order / mark the user as paid.
30
+ console.log("✓ checkout.session.completed", event.data.object.id);
31
+ break;
32
+ case "customer.subscription.created":
33
+ case "customer.subscription.updated":
34
+ case "customer.subscription.deleted":
35
+ // TODO: sync the subscription state to your database.
36
+ console.log(`✓ ${event.type}`, event.data.object.id);
37
+ break;
38
+ default:
39
+ console.log("Unhandled Stripe event:", event.type);
40
+ }
41
+
42
+ res.json({ received: true });
43
+ }
@@ -0,0 +1,28 @@
1
+ import { Router, raw } from "express";
2
+
3
+ import { deleteFile, getSignedDownloadUrl, uploadFile } from "@softeneers/storage";
4
+
5
+ import { storage } from "./store.js";
6
+
7
+ export const storageRouter = Router();
8
+
9
+ // Upload raw bytes: PUT/POST the file body to /api/files/:key
10
+ storageRouter.post("/:key", raw({ type: "*/*", limit: "10mb" }), async (req, res) => {
11
+ await uploadFile(storage, {
12
+ key: req.params.key,
13
+ body: req.body as Buffer,
14
+ contentType: req.headers["content-type"],
15
+ });
16
+ res.status(201).json({ key: req.params.key });
17
+ });
18
+
19
+ // Get a time-limited download URL for an object.
20
+ storageRouter.get("/:key/url", async (req, res) => {
21
+ res.json({ url: await getSignedDownloadUrl(storage, req.params.key) });
22
+ });
23
+
24
+ // Delete an object.
25
+ storageRouter.delete("/:key", async (req, res) => {
26
+ await deleteFile(storage, req.params.key);
27
+ res.status(204).end();
28
+ });