@alfredmouelle/create-stack 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -40
- package/_stack/apps/next-base/src/emails/components/components.tsx +2 -0
- package/_stack/apps/next-base/src/emails/components/context.tsx +2 -0
- package/_stack/apps/tanstack-base/src/server/better-auth/session.ts +13 -5
- package/index.mjs +6 -0
- package/lib/build.mjs +1 -1
- package/lib/scaffold.mjs +57 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,56 +1,122 @@
|
|
|
1
1
|
# create-stack
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
counterpart of the `bootstrap` skill's CREATE mode. It forks a base app
|
|
5
|
-
(`apps/tanstack-base` or `apps/next-base`) and strips it down to your selection.
|
|
3
|
+
> `@alfredmouelle/create-stack`
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
Interactive, **deterministic** project installer. It forks a fully-wired base app
|
|
6
|
+
(**Next.js App Router** or **TanStack Start**) and strips it down to exactly the
|
|
7
|
+
foundations and provider you pick — Drizzle, tRPC, better-auth, data tables and a
|
|
8
|
+
mailer — then stamps identity, generates `.env`, initializes git and verifies the
|
|
9
|
+
result (typecheck + Biome).
|
|
10
|
+
|
|
11
|
+
No template guesswork: the output is a real, buildable app from day one.
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
8
14
|
|
|
9
15
|
```bash
|
|
10
|
-
|
|
11
|
-
|
|
16
|
+
pnpm dlx @alfredmouelle/create-stack my-app
|
|
17
|
+
# or, using the create-* convention:
|
|
18
|
+
pnpm create @alfredmouelle/stack my-app
|
|
19
|
+
# npm / yarn:
|
|
20
|
+
npm create @alfredmouelle/stack my-app
|
|
21
|
+
yarn create @alfredmouelle/stack my-app
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Run with no extra flags → an **interactive wizard** asks every question. Pass any
|
|
25
|
+
selection flag → **non-interactive** mode (scriptable / CI).
|
|
26
|
+
|
|
27
|
+
## Requirements
|
|
28
|
+
|
|
29
|
+
- **Node** ≥ 22
|
|
30
|
+
- **pnpm** (the generated project is a pnpm project)
|
|
31
|
+
- **git** and **rsync** available on `PATH` (macOS/Linux ship both)
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
12
34
|
|
|
13
|
-
# from the stack repo
|
|
14
|
-
pnpm create-stack my-app
|
|
15
35
|
```
|
|
36
|
+
create-stack [project] [flags]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`project` is the target directory (and default package name). It must be empty or
|
|
40
|
+
not exist yet. In non-interactive mode it is required.
|
|
16
41
|
|
|
17
|
-
|
|
42
|
+
### Flags
|
|
18
43
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
44
|
+
| Flag | Values | Default | Description |
|
|
45
|
+
| --- | --- | --- | --- |
|
|
46
|
+
| `--framework` | `tanstack` \| `next` | `tanstack` | Base app to fork. |
|
|
47
|
+
| `--foundations` | csv of `drizzle,trpc,better-auth,data-table` | all | Foundations to keep; the rest are stripped. |
|
|
48
|
+
| `--mailer` | `resend` \| `brevo` \| `ses` \| `none` | `resend` | Mailer provider. `none` is rejected when `better-auth` is kept. |
|
|
49
|
+
| `--caps` | csv of capability names | — | Extra capabilities to add afterwards via `add-capability` (see below). |
|
|
50
|
+
| `--no-install` | — | install on | Skip `pnpm install` + verification. |
|
|
51
|
+
| `--yes`, `-y` | — | — | Non-interactive with all defaults. |
|
|
25
52
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
53
|
+
Passing any of `--framework`, `--foundations`, `--mailer`, `--caps` or
|
|
54
|
+
`--no-install` (or `--yes`) switches the CLI to non-interactive mode; missing
|
|
55
|
+
values fall back to the defaults above.
|
|
29
56
|
|
|
30
|
-
|
|
57
|
+
### Dependency resolution
|
|
31
58
|
|
|
32
|
-
|
|
33
|
-
the `patterns/*/pattern.json` manifests drive deps/scripts/env/file lists.
|
|
34
|
-
- **Deterministic strip**: whole-directory deletes + dep/env/script diffs from the
|
|
35
|
-
manifests, plus a few hardcoded code *seams* (tRPC↔auth context, root provider
|
|
36
|
-
wiring) handled via shipped reduced variants in `templates/`.
|
|
37
|
-
- If you edit a seam file in a base app (`server/api/trpc.ts`, the root
|
|
38
|
-
`router.tsx` / `__root.tsx` / `layout.tsx`, the schema barrel), update the
|
|
39
|
-
matching transform in `lib/strip.mjs` or the `templates/` variant.
|
|
59
|
+
Selections are normalized for you:
|
|
40
60
|
|
|
41
|
-
|
|
61
|
+
- `trpc` ⇒ pulls in `drizzle`
|
|
62
|
+
- `better-auth` ⇒ pulls in `drizzle` **and** forces a real mailer (not `none`)
|
|
63
|
+
|
|
64
|
+
### Examples
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Full interactive wizard
|
|
68
|
+
pnpm dlx @alfredmouelle/create-stack my-app
|
|
42
69
|
|
|
70
|
+
# Everything, defaults (TanStack Start + all foundations + Resend), no questions
|
|
71
|
+
pnpm dlx @alfredmouelle/create-stack my-app --yes
|
|
72
|
+
|
|
73
|
+
# Next.js with just Drizzle + tRPC, Amazon SES mailer, don't install
|
|
74
|
+
pnpm dlx @alfredmouelle/create-stack api --framework next \
|
|
75
|
+
--foundations drizzle,trpc --mailer ses --no-install
|
|
76
|
+
|
|
77
|
+
# Minimal: Drizzle only, no mailer
|
|
78
|
+
pnpm dlx @alfredmouelle/create-stack db-svc --foundations drizzle --mailer none
|
|
79
|
+
|
|
80
|
+
# TanStack + auth, and queue up extra capabilities for later
|
|
81
|
+
pnpm dlx @alfredmouelle/create-stack app --foundations drizzle,trpc,better-auth \
|
|
82
|
+
--caps storage,jobs
|
|
43
83
|
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
84
|
+
|
|
85
|
+
## What you get
|
|
86
|
+
|
|
87
|
+
- **Framework** — Next.js App Router *or* TanStack Start, fully wired (SSR, routing).
|
|
88
|
+
- **Drizzle ORM** — Postgres client, schema barrel, keyset pagination, seed harness.
|
|
89
|
+
- **tRPC v11** — typed API, SSR/RSC integration, health router.
|
|
90
|
+
- **better-auth** — email+password + verification, optional Google OAuth, session
|
|
91
|
+
guards, auth UI pages.
|
|
92
|
+
- **Mailer** — Resend / Brevo / SES behind one port; React Email templates.
|
|
93
|
+
- **Data tables** — TanStack Table primitives (DataTable, InfiniteDataTable, …).
|
|
94
|
+
- **Baseline** — Tailwind v4 + shadcn, Geist, theme toggle, strict Biome, typed
|
|
95
|
+
env (`src/env.ts`), Dockerfile, a generated `.gitignore` and `.env`/`.env.example`.
|
|
96
|
+
|
|
97
|
+
Unselected foundations are removed cleanly (files, deps, env vars and wiring),
|
|
98
|
+
and the project is left **bootable and green** (typecheck + Biome).
|
|
99
|
+
|
|
100
|
+
## Extra capabilities
|
|
101
|
+
|
|
102
|
+
`--caps` lists capabilities that aren't baked into the base (storage, jobs, cache,
|
|
103
|
+
logger, analytics, error-tracking, http). They are **not** scaffolded by this CLI;
|
|
104
|
+
the final report prints the follow-up to add them with the `add-capability` skill.
|
|
105
|
+
Mailer is the exception — it's built in and chosen via `--mailer`.
|
|
106
|
+
|
|
107
|
+
## After scaffolding
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cd my-app
|
|
111
|
+
pnpm install # only if you passed --no-install
|
|
112
|
+
cp .env.example .env # fill in the values
|
|
113
|
+
pnpm dev
|
|
56
114
|
```
|
|
115
|
+
|
|
116
|
+
## Notes
|
|
117
|
+
|
|
118
|
+
- The published package is **self-contained**: the base apps, pattern manifests
|
|
119
|
+
and mailer adapters are bundled at publish time, so `pnpm dlx` needs nothing but
|
|
120
|
+
this package.
|
|
121
|
+
- The generated project is a fresh git repo (`git init`, files staged) — make your
|
|
122
|
+
first commit when ready.
|
|
@@ -2,8 +2,16 @@ import { createServerFn } from '@tanstack/react-start'
|
|
|
2
2
|
import { getRequest } from '@tanstack/react-start/server'
|
|
3
3
|
import { auth } from '.'
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Server-function: resolves the better-auth session from the current request
|
|
7
|
+
* headers. Use it in route loaders / `beforeLoad`.
|
|
8
|
+
*
|
|
9
|
+
* The server-only `getRequest` call lives INSIDE the handler on purpose: the
|
|
10
|
+
* TanStack Start plugin extracts the handler server-side and strips this import
|
|
11
|
+
* from the client bundle. A standalone module-scope helper that calls
|
|
12
|
+
* `getRequest` would leak `@tanstack/react-start/server` into client code (it's
|
|
13
|
+
* imported transitively by routes) and trip the import-protection plugin.
|
|
14
|
+
*/
|
|
15
|
+
export const getServerSession = createServerFn({ method: 'GET' }).handler(() =>
|
|
16
|
+
auth.api.getSession({ headers: getRequest().headers }),
|
|
17
|
+
)
|
package/index.mjs
CHANGED
|
@@ -173,6 +173,12 @@ function execute(a, patterns) {
|
|
|
173
173
|
)
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
+
// Initialize a fresh repo (also satisfies Biome's vcs.useIgnoreFile).
|
|
177
|
+
if (run('git', ['init', '-q'], { cwd: projectDir })) {
|
|
178
|
+
run('git', ['-C', projectDir, 'add', '-A'])
|
|
179
|
+
p.log.step('git initialized')
|
|
180
|
+
}
|
|
181
|
+
|
|
176
182
|
const keptMailer = a.mailerProvider !== 'none'
|
|
177
183
|
const lines = [
|
|
178
184
|
`Framework: ${a.framework === 'next' ? 'Next.js' : 'TanStack Start'}`,
|
package/lib/build.mjs
CHANGED
|
@@ -30,7 +30,7 @@ export function buildProject({
|
|
|
30
30
|
const keptMailer = mailerProvider !== 'none'
|
|
31
31
|
|
|
32
32
|
forkBase(framework, projectDir)
|
|
33
|
-
makeStandalone(projectDir, projectName)
|
|
33
|
+
makeStandalone(projectDir, projectName, framework)
|
|
34
34
|
|
|
35
35
|
const strip = stripFoundations({ projectDir, framework, kept, keptMailer, patterns })
|
|
36
36
|
const mailer = keptMailer
|
package/lib/scaffold.mjs
CHANGED
|
@@ -22,6 +22,58 @@ const PNPM_WORKSPACE = `allowBuilds:
|
|
|
22
22
|
lightningcss: true
|
|
23
23
|
`
|
|
24
24
|
|
|
25
|
+
// Generated explicitly: npm strips `.gitignore` from published tarballs, so we
|
|
26
|
+
// can't rely on the bundled base app's copy surviving. Both keep `.env.example`.
|
|
27
|
+
const GITIGNORE = {
|
|
28
|
+
tanstack: `node_modules
|
|
29
|
+
.DS_Store
|
|
30
|
+
dist
|
|
31
|
+
dist-ssr
|
|
32
|
+
*.local
|
|
33
|
+
.env
|
|
34
|
+
.nitro
|
|
35
|
+
.tanstack
|
|
36
|
+
.wrangler
|
|
37
|
+
.output
|
|
38
|
+
.vinxi
|
|
39
|
+
__unconfig*
|
|
40
|
+
`,
|
|
41
|
+
next: `# dependencies
|
|
42
|
+
/node_modules
|
|
43
|
+
/.pnp
|
|
44
|
+
.pnp.*
|
|
45
|
+
|
|
46
|
+
# testing
|
|
47
|
+
/coverage
|
|
48
|
+
|
|
49
|
+
# next.js
|
|
50
|
+
/.next/
|
|
51
|
+
/out/
|
|
52
|
+
|
|
53
|
+
# production
|
|
54
|
+
/build
|
|
55
|
+
|
|
56
|
+
# misc
|
|
57
|
+
.DS_Store
|
|
58
|
+
*.pem
|
|
59
|
+
|
|
60
|
+
# debug
|
|
61
|
+
npm-debug.log*
|
|
62
|
+
.pnpm-debug.log*
|
|
63
|
+
|
|
64
|
+
# env files (keep .env.example committed)
|
|
65
|
+
.env
|
|
66
|
+
.env*.local
|
|
67
|
+
|
|
68
|
+
# vercel
|
|
69
|
+
.vercel
|
|
70
|
+
|
|
71
|
+
# typescript
|
|
72
|
+
*.tsbuildinfo
|
|
73
|
+
next-env.d.ts
|
|
74
|
+
`,
|
|
75
|
+
}
|
|
76
|
+
|
|
25
77
|
/** Copy the base app into projectDir, minus build output & generated files. */
|
|
26
78
|
export function forkBase(framework, projectDir) {
|
|
27
79
|
const base = join(STACK_ROOT, 'apps', framework === 'next' ? 'next-base' : 'tanstack-base')
|
|
@@ -32,11 +84,14 @@ export function forkBase(framework, projectDir) {
|
|
|
32
84
|
if (!run('rsync', args)) throw new Error('rsync failed while forking the base app')
|
|
33
85
|
}
|
|
34
86
|
|
|
35
|
-
/** Make the fork standalone (Biome, pnpm workspace,
|
|
36
|
-
export function makeStandalone(projectDir, projectName) {
|
|
87
|
+
/** Make the fork standalone (Biome, pnpm workspace, .gitignore, identity). */
|
|
88
|
+
export function makeStandalone(projectDir, projectName, framework) {
|
|
37
89
|
// A fork needs its own Biome config (the base inherits the monorepo root's).
|
|
38
90
|
copy(join(STACK_ROOT, 'patterns/_baseline/biome.jsonc'), join(projectDir, 'biome.jsonc'))
|
|
39
91
|
|
|
92
|
+
// Biome's vcs.useIgnoreFile needs a .gitignore; also good project hygiene.
|
|
93
|
+
write(join(projectDir, '.gitignore'), GITIGNORE[framework === 'next' ? 'next' : 'tanstack'])
|
|
94
|
+
|
|
40
95
|
// Avoid ERR_PNPM_IGNORED_BUILDS on a fresh install (native build scripts).
|
|
41
96
|
write(join(projectDir, 'pnpm-workspace.yaml'), PNPM_WORKSPACE)
|
|
42
97
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfredmouelle/create-stack",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive, deterministic installer for the personal reference stack — forks a base app (Next.js / TanStack Start) and strips it to your selection.",
|
|
6
6
|
"author": {
|