create-basalt 1.0.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.
- package/LICENSE +21 -0
- package/README.md +256 -0
- package/dist/chunk-RFS7HGZ6.js +1079 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +157 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +10 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Machize Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# create-basalt
|
|
2
|
+
|
|
3
|
+
Basalt project generator: a single command (`npm create basalt my-app`) creates a complete, ready-to-run SaaS application — typed API, authentication, multi-tenancy, and optionally billing, a web frontend, and the `basalt` CLI. It's the framework's starting point: use it whenever you want to start a new project.
|
|
4
|
+
|
|
5
|
+
## What this module solves
|
|
6
|
+
|
|
7
|
+
Starting a backend project from scratch involves dozens of decisions and files before you write the first useful line: setting up TypeScript, choosing the HTTP server, organizing folders, wiring up authentication, preparing tests… A **scaffolder** (project generator) does that work for you: it generates the initial structure with good practices already applied, so you can start building your product right away.
|
|
8
|
+
|
|
9
|
+
`create-basalt` generates a **SaaS** application (Software as a Service — software sold by subscription, usually with several customers/organizations in the same installation) shaped the way mature Basalt projects look in production: typed routes with Zod validation, structured logging, domain events, and, depending on the options, **multi-tenancy** (several isolated customers in the same application), authentication (register/login/refresh), subscriptions with plans, a React frontend, and the `basalt` command-line tool with code generators.
|
|
10
|
+
|
|
11
|
+
It works in two ways: interactive mode (answers questions in the terminal) or direct mode with flags (ideal for scripts). It doesn't install dependencies or touch git unless you ask it to (`--install`, `--git`).
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
You don't need to install anything — your package manager's `create` command downloads and runs the package on the spot:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm create basalt my-app
|
|
19
|
+
# or
|
|
20
|
+
pnpm create basalt my-app
|
|
21
|
+
# or
|
|
22
|
+
yarn create basalt my-app
|
|
23
|
+
# or
|
|
24
|
+
bun create basalt my-app
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> Requirements: Node.js 18+ and a package manager. Projects with `--ui` require **pnpm** (explained below).
|
|
28
|
+
|
|
29
|
+
## Get started in 5 minutes
|
|
30
|
+
|
|
31
|
+
1. Create the project (interactive mode — run without a name and answer the questions):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm create basalt
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Project name: my-app
|
|
39
|
+
Multi-tenancy? (Y/n) y
|
|
40
|
+
Authentication? (Y/n) y
|
|
41
|
+
Subscriptions / billing? (y/N) n
|
|
42
|
+
Web UI (React + shadcn)? (y/N) n
|
|
43
|
+
'basalt' CLI (code generators)? (y/N) n
|
|
44
|
+
Install dependencies now? (y/N) y
|
|
45
|
+
Initialize a git repository? (y/N) y
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
2. Go into the folder and start it up:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd my-app
|
|
52
|
+
npm install # if you didn't choose to install in the previous step
|
|
53
|
+
npm run dev # API at http://localhost:3000
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
3. Try it out:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
curl http://localhost:3000/ # index listing the available endpoints
|
|
60
|
+
curl http://localhost:3000/health # { ok: true, requestId: ..., tenant: null }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
4. Run the included tests:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm test
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Usage guide
|
|
70
|
+
|
|
71
|
+
### All CLI flags
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Usage: npm create basalt <name> [options]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
| Flag | Default | What it does |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `<name>` | — (asked in interactive mode) | Project name (and folder name, unless `--dir`) |
|
|
80
|
+
| `--dir=<path>` | `./<name>` | Destination folder |
|
|
81
|
+
| `--no-tenancy` | tenancy **on** | Removes multi-tenancy (`@basaltkit/tenancy`) |
|
|
82
|
+
| `--no-auth` | auth **on** | Removes authentication (`@basaltkit/auth`, `APP_SECRET`, `/auth/*` routes) |
|
|
83
|
+
| `--billing` | off | Includes subscriptions/plans (`@basaltkit/subscriptions`, example `free` and `pro` plans) |
|
|
84
|
+
| `--ui` | off | Generates the `web/` frontend (React + shadcn via `@basaltkit/admin-shadcn` + `@basaltkit/sdk`). **Forces pnpm** — see note below |
|
|
85
|
+
| `--cli` | off | Generates the `basalt` CLI (`bin/basalt.ts`, `pnpm basalt` script, `make:*` generators from `@basaltkit/generator`) |
|
|
86
|
+
| `--install` | off | Installs dependencies at the end (with the detected/chosen manager) |
|
|
87
|
+
| `--git` | off | Runs `git init` + first commit ("Initial commit from create-basalt") |
|
|
88
|
+
| `--pm=<manager>` | autodetect | Package manager: `pnpm` \| `npm` \| `yarn` \| `bun` |
|
|
89
|
+
| `-y`, `--yes` | — | Skips the questions and accepts the defaults |
|
|
90
|
+
| `-h`, `--help` | — | Shows help and exits |
|
|
91
|
+
|
|
92
|
+
Behavior notes (faithful to the code):
|
|
93
|
+
|
|
94
|
+
- **Package manager detection**: by default, detects who invoked the command via the `npm_config_user_agent` variable (set by npm/pnpm/yarn/bun); unknown managers fall back to `npm`. `--pm=` overrides this.
|
|
95
|
+
- **`--ui` forces pnpm**: the `web/` frontend is a member of a pnpm *workspace* (declared in the generated `pnpm-workspace.yaml`). npm, yarn, and bun can't install or run that structure, so if you request `--ui` with another manager, you'll see `Note: --ui projects are pnpm workspaces — using pnpm instead of <manager>.` and pnpm is used.
|
|
96
|
+
- **Interactive mode**: only happens when you don't pass a name, you're in a terminal (TTY), and you didn't use `--yes`. Ctrl+C during a question ends cleanly with "Cancelled." (exit code 130).
|
|
97
|
+
- **Occupied folder**: if the destination folder exists and isn't empty, the command refuses with `Target directory "<dir>" already exists and is not empty.` and exits with code 1.
|
|
98
|
+
- At the end, it prints the created files and the "Next steps" appropriate to your choices.
|
|
99
|
+
|
|
100
|
+
### Invocation examples
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Full project, no questions, with everything:
|
|
104
|
+
pnpm create basalt my-app --billing --ui --cli --install --git
|
|
105
|
+
|
|
106
|
+
# Minimal API (no tenancy or auth), in another folder:
|
|
107
|
+
npm create basalt service-api --no-tenancy --no-auth --dir=./apps/service-api
|
|
108
|
+
|
|
109
|
+
# Accept all defaults with no questions:
|
|
110
|
+
npm create basalt my-app -y
|
|
111
|
+
|
|
112
|
+
# Force yarn as the manager:
|
|
113
|
+
npm create basalt my-app --pm=yarn --install
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### What gets generated
|
|
117
|
+
|
|
118
|
+
Always:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
my-app/
|
|
122
|
+
├── package.json # scripts: dev, start, test, typecheck (+ basalt with --cli)
|
|
123
|
+
├── tsconfig.json # strict TypeScript, ESM
|
|
124
|
+
├── .env.example # PORT, HOST, LOG_LEVEL, NODE_ENV (+ APP_SECRET with auth)
|
|
125
|
+
├── .gitignore
|
|
126
|
+
├── README.md # instructions adapted to the chosen options
|
|
127
|
+
├── pnpm-workspace.yaml # esbuild allowBuilds (+ "web" member with --ui)
|
|
128
|
+
├── src/
|
|
129
|
+
│ ├── env.ts # environment variables validated with Zod (@basaltkit/env)
|
|
130
|
+
│ ├── app.ts # buildApp() with the chosen plugins
|
|
131
|
+
│ ├── routes.ts # GET / (friendly index) and GET /health
|
|
132
|
+
│ └── server.ts # startup + clean shutdown on SIGINT/SIGTERM
|
|
133
|
+
└── tests/app.test.ts # smoke test adapted to the options
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
With `--cli`, adds `bin/basalt.ts` and the `"basalt": "tsx bin/basalt.ts"` script. With `--ui`, adds the `web/` folder (Vite + React + Tailwind + shadcn, with `web/src/api.ts` built on top of `@basaltkit/sdk`; with auth on it includes a login/register screen).
|
|
137
|
+
|
|
138
|
+
### With `--ui`: running the API and frontend
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
pnpm install
|
|
142
|
+
pnpm dev # terminal 1 — API on :3000
|
|
143
|
+
pnpm --filter my-app-web dev # terminal 2 — UI at http://localhost:5180
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Vite's dev server proxies `/api` to the API — there's no CORS to configure.
|
|
147
|
+
|
|
148
|
+
### With `--cli`: the `basalt` command line
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pnpm basalt list # available commands
|
|
152
|
+
pnpm basalt routes # registered HTTP routes
|
|
153
|
+
pnpm basalt make:resource Project # generates schema → repository → service → plugin → routes → test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Programmatic usage (Advanced)
|
|
157
|
+
|
|
158
|
+
The package also exports the API used by the executable, for your own scripts:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { createProject, detectPackageManager, TargetNotEmptyError } from 'create-basalt'
|
|
162
|
+
|
|
163
|
+
const result = await createProject({
|
|
164
|
+
name: 'my-app',
|
|
165
|
+
dir: './output/my-app', // optional; default: ./<name>
|
|
166
|
+
tenancy: true,
|
|
167
|
+
auth: true,
|
|
168
|
+
billing: false,
|
|
169
|
+
ui: false,
|
|
170
|
+
cli: true,
|
|
171
|
+
})
|
|
172
|
+
console.log(result.dir) // absolute path created
|
|
173
|
+
console.log(result.files) // relative paths, sorted
|
|
174
|
+
console.log(detectPackageManager()) // 'pnpm' | 'npm' | 'yarn' | 'bun'
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Note: `createProject` **only writes files** — it doesn't install dependencies or initialize git (that's the executable's job, with `--install`/`--git`).
|
|
178
|
+
|
|
179
|
+
## API reference
|
|
180
|
+
|
|
181
|
+
Exported from `create-basalt` (in addition to the `create-basalt` executable):
|
|
182
|
+
|
|
183
|
+
### `createProject(input): Promise<CreateProjectResult>`
|
|
184
|
+
|
|
185
|
+
`CreateProjectInput`:
|
|
186
|
+
|
|
187
|
+
| Field | Type | Required? | Default | Description |
|
|
188
|
+
| --- | --- | --- | --- | --- |
|
|
189
|
+
| `name` | `string` | Yes | — | Project name |
|
|
190
|
+
| `dir` | `string` | No | `./<name>` (relative to cwd) | Destination folder |
|
|
191
|
+
| `tenancy` | `boolean` | No | `true` | Include multi-tenancy |
|
|
192
|
+
| `auth` | `boolean` | No | `true` | Include authentication |
|
|
193
|
+
| `billing` | `boolean` | No | `false` | Include subscriptions |
|
|
194
|
+
| `ui` | `boolean` | No | `false` | Generate the `web/` frontend |
|
|
195
|
+
| `cli` | `boolean` | No | `false` | Generate the `basalt` CLI |
|
|
196
|
+
|
|
197
|
+
`CreateProjectResult`:
|
|
198
|
+
|
|
199
|
+
| Field | Type | Description |
|
|
200
|
+
| --- | --- | --- |
|
|
201
|
+
| `dir` | `string` | Absolute path of the created folder |
|
|
202
|
+
| `files` | `string[]` | Files written (relative, sorted) |
|
|
203
|
+
| `options` | `ProjectOptions` | The options actually applied (with defaults resolved) |
|
|
204
|
+
|
|
205
|
+
Throws `TargetNotEmptyError` if the destination folder exists and isn't empty.
|
|
206
|
+
|
|
207
|
+
### `detectPackageManager(userAgent?): PackageManager`
|
|
208
|
+
|
|
209
|
+
Detects the manager that invoked the command from `npm_config_user_agent` (or the string passed in). Returns `'pnpm' | 'yarn' | 'bun'` when recognized; otherwise `'npm'`.
|
|
210
|
+
|
|
211
|
+
### `TargetNotEmptyError`
|
|
212
|
+
|
|
213
|
+
Error (extends `Error`) with the message `Target directory "<dir>" already exists and is not empty.`
|
|
214
|
+
|
|
215
|
+
### Exported types
|
|
216
|
+
|
|
217
|
+
| Type | Description |
|
|
218
|
+
| --- | --- |
|
|
219
|
+
| `PackageManager` | `'pnpm' \| 'npm' \| 'yarn' \| 'bun'` |
|
|
220
|
+
| `ProjectOptions` | `{ name, tenancy, auth, billing, ui, cli }` — all resolved (no optionals) |
|
|
221
|
+
| `CreateProjectInput`, `CreateProjectResult` | Described above |
|
|
222
|
+
|
|
223
|
+
## Common errors and solutions (FAQ)
|
|
224
|
+
|
|
225
|
+
**I created a project with `--ui` and `npm install` fails (`web/` dependencies don't resolve).**
|
|
226
|
+
This is the classic error: the `web/` frontend is a member of a **pnpm** *workspace* (`pnpm-workspace.yaml`). npm (like yarn and bun) doesn't read that file, so it doesn't install `web/`'s dependencies or manage to launch its dev server. Solution: use pnpm in that project — `pnpm install` at the root and `pnpm --filter <name>-web dev` for the UI. (This is why the CLI itself switches to pnpm when you request `--ui` with another manager.)
|
|
227
|
+
|
|
228
|
+
**`Target directory "…" already exists and is not empty.`**
|
|
229
|
+
The destination folder already has content. Choose another name, point to another folder with `--dir=`, or empty it first. The generator never overwrites anything.
|
|
230
|
+
|
|
231
|
+
**I ran the command in a script/CI and it hung or didn't ask anything.**
|
|
232
|
+
Outside an interactive terminal (no TTY) the questions are skipped. Always pass the name and flags explicitly — and use `-y` to make sure no prompt appears.
|
|
233
|
+
|
|
234
|
+
**`(skipped — git unavailable or already a repo)` after `--git`.**
|
|
235
|
+
`git init`/commit failed — either git isn't installed, or the folder already belongs to a repository. The project is still created; handle git by hand.
|
|
236
|
+
|
|
237
|
+
**`(install failed — run "pnpm install" yourself)`.**
|
|
238
|
+
Automatic installation failed (network, Node version, etc.). Go into the folder and run `pnpm install` (or the indicated manager) to see the real error.
|
|
239
|
+
|
|
240
|
+
**I started the app and `GET /auth/login` gives a secret error.**
|
|
241
|
+
With auth on, `src/env.ts` requires `APP_SECRET` with at least 16 characters (there's a development default `change-me-in-production--`). Copy `.env.example` to `.env` and set your own secret before going to production.
|
|
242
|
+
|
|
243
|
+
**I want to change my mind after generating (e.g. add billing).**
|
|
244
|
+
There's no "re-scaffold" command. Either generate a new project with the right flags and compare, or add it by hand: install `@basaltkit/subscriptions` and add the `subscriptionsPlugin` to `src/app.ts` (the generated README and the templates serve as reference).
|
|
245
|
+
|
|
246
|
+
## How it connects to other modules
|
|
247
|
+
|
|
248
|
+
`create-basalt` isn't used *by* the application — it writes the application that uses the other packages:
|
|
249
|
+
|
|
250
|
+
- **`@basaltkit/core`, `@basaltkit/config`, `@basaltkit/env`, `@basaltkit/events`, `@basaltkit/fastify`, `@basaltkit/logger`** — the foundation of any generated project (`createApp` + plugins in `src/app.ts`).
|
|
251
|
+
- **`@basaltkit/tenancy`** — included by default (remove with `--no-tenancy`): header and subdomain resolvers, with a demo `MemoryTenantSource`.
|
|
252
|
+
- **`@basaltkit/auth`** — included by default (remove with `--no-auth`): `/auth/*` routes and `APP_SECRET` validated in `env.ts`.
|
|
253
|
+
- **`@basaltkit/subscriptions`** — with `--billing`: example `free`/`pro` plans with trial and feature limits.
|
|
254
|
+
- **`@basaltkit/cli` + `@basaltkit/generator`** — with `--cli`: `bin/basalt.ts` calls `runCli`, and `commandsPlugin(generatorCommands())` registers the `make:*` generators.
|
|
255
|
+
- **`@basaltkit/sdk` + `@basaltkit/admin-shadcn` + `@basaltkit/admin`** — with `--ui`: the `web/` frontend calls the API through a typed client and uses the shadcn components.
|
|
256
|
+
- **`@basaltkit/testing`** — always present in `devDependencies`, with a generated smoke test in `tests/app.test.ts`.
|