create-blixis 0.1.1 → 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.
- package/README.md +3 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +129 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,9 @@ curl http://localhost:3000/hello/world # {"message":"Hello, world!"}
|
|
|
20
20
|
|
|
21
21
|
| Option | |
|
|
22
22
|
|---|---|
|
|
23
|
-
| `--
|
|
23
|
+
| `--deploy <target>` | also set up deployment: `docker`, `vercel`, `netlify` or `cloudflare`. Installs `@blixis-io/cli` and `@blixis-io/deploy` and runs `blix deploy init` |
|
|
24
|
+
| `--ci <provider>` | with `--deploy`: also write the pipeline (`github`, `gitlab` or `bitbucket`) |
|
|
25
|
+
| `--no-install` | write the files only and print the install commands (with `--deploy`, including the deploy ones) |
|
|
24
26
|
|
|
25
27
|
The target directory must not exist or must be empty. Nested paths work (`apps/api`); the package is named after the last segment. No `@blixis-io/*` runtime dependency.
|
|
26
28
|
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface CreateOptions {
|
|
|
14
14
|
install?: InstallRunner;
|
|
15
15
|
}
|
|
16
16
|
export declare function detectPackageManager(userAgent: string | undefined): PackageManager;
|
|
17
|
+
/** `"pnpm@11.25.0"` from an `npm_config_user_agent` like `pnpm/11.25.0 npm/? node/v24.0.0`, for the `packageManager` field. Bun isn't managed by corepack, so it gets none. */
|
|
18
|
+
export declare function packageManagerPin(userAgent: string | undefined): string | undefined;
|
|
17
19
|
/** The whole CLI as a function of argv + environment — no process.exit()/console.log(), so it is directly testable. */
|
|
18
20
|
export declare function runCreate(argv: readonly string[], options: CreateOptions): Promise<CreateResult>;
|
|
19
21
|
//#endregion
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";YAoBY;iBAEK;EACf;EACA;EACA;;;YAIU,iBAAiB,iBAAiB,yBAAyB,gBAAgB;iBAEtE;EACf;;EAEA;EACA,UAAU;;wBAGI,qBAAqB,gCAAgC;;wBAMrD,kBAAkB;;wBAwFZ,UAAU,yBAAyB,SAAS,gBAAgB,QAAQ"}
|
package/dist/index.js
CHANGED
|
@@ -5,13 +5,14 @@ import { basename, dirname, join, relative, resolve } from "node:path";
|
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
//#region src/template.ts
|
|
7
7
|
/** Every file of the generated app, keyed by path relative to the project root. */
|
|
8
|
-
function templateFiles(packageName) {
|
|
8
|
+
function templateFiles(packageName, packageManagerPin) {
|
|
9
9
|
return {
|
|
10
10
|
"package.json": `${JSON.stringify({
|
|
11
11
|
name: packageName,
|
|
12
12
|
version: "0.0.0",
|
|
13
13
|
private: true,
|
|
14
14
|
type: "module",
|
|
15
|
+
...packageManagerPin ? { packageManager: packageManagerPin } : {},
|
|
15
16
|
engines: { node: ">=24" },
|
|
16
17
|
scripts: {
|
|
17
18
|
dev: "tsc -p tsconfig.json && concurrently -k -n tsc,app \"tsc -p tsconfig.json --watch --preserveWatchOutput\" \"node --watch dist/main.js\"",
|
|
@@ -104,6 +105,8 @@ const RUNTIME_DEPENDENCIES = [
|
|
|
104
105
|
"@blixis-io/di",
|
|
105
106
|
"@blixis-io/http"
|
|
106
107
|
];
|
|
108
|
+
/** Added only with --deploy: the CLI and its deploy plugin. */
|
|
109
|
+
const DEPLOY_DEPENDENCIES = ["@blixis-io/cli", "@blixis-io/deploy"];
|
|
107
110
|
const DEV_DEPENDENCIES = [
|
|
108
111
|
"typescript",
|
|
109
112
|
"@types/node",
|
|
@@ -119,12 +122,12 @@ var ScaffoldError = class extends Error {
|
|
|
119
122
|
}
|
|
120
123
|
};
|
|
121
124
|
/** Writes the starter app into `cwd/<target>`. The directory may not exist yet, or must be empty. */
|
|
122
|
-
function scaffold(cwd, target) {
|
|
125
|
+
function scaffold(cwd, target, packageManagerPin) {
|
|
123
126
|
const directory = resolve(cwd, target);
|
|
124
127
|
const packageName = basename(directory);
|
|
125
128
|
if (!PACKAGE_NAME.test(packageName)) throw new ScaffoldError(`"${packageName}" is not a valid package name — use lowercase letters, digits, "-", "." or "_", starting with a letter or digit.`);
|
|
126
129
|
if (existsSync(directory) && readdirSync(directory).length > 0) throw new ScaffoldError(`${target} already exists and is not empty.`);
|
|
127
|
-
const files = Object.entries(templateFiles(packageName));
|
|
130
|
+
const files = Object.entries(templateFiles(packageName, packageManagerPin));
|
|
128
131
|
for (const [path, content] of files) {
|
|
129
132
|
const absolute = join(directory, path);
|
|
130
133
|
mkdirSync(dirname(absolute), { recursive: true });
|
|
@@ -138,17 +141,26 @@ function scaffold(cwd, target) {
|
|
|
138
141
|
}
|
|
139
142
|
//#endregion
|
|
140
143
|
//#region src/index.ts
|
|
141
|
-
const USAGE = `create-blixis <directory> [--no-install]
|
|
144
|
+
const USAGE = `create-blixis <directory> [--deploy <target>] [--ci <provider>] [--no-install]
|
|
142
145
|
|
|
143
146
|
pnpm create blixis my-app
|
|
144
147
|
npm create blixis@latest my-app
|
|
148
|
+
pnpm create blixis my-app --deploy docker --ci github
|
|
145
149
|
|
|
146
|
-
--
|
|
150
|
+
--deploy <target> also set up deployment (docker, vercel, netlify or cloudflare): installs
|
|
151
|
+
@blixis-io/cli and @blixis-io/deploy and runs \`blix deploy init\`
|
|
152
|
+
--ci <provider> with --deploy: also write the CI pipeline (github, gitlab or bitbucket)
|
|
153
|
+
--no-install write the files only; print the install commands instead
|
|
147
154
|
`;
|
|
148
155
|
function detectPackageManager(userAgent) {
|
|
149
156
|
const name = userAgent?.split("/")[0];
|
|
150
157
|
return name === "pnpm" || name === "yarn" || name === "bun" ? name : "npm";
|
|
151
158
|
}
|
|
159
|
+
/** `"pnpm@11.25.0"` from an `npm_config_user_agent` like `pnpm/11.25.0 npm/? node/v24.0.0`, for the `packageManager` field. Bun isn't managed by corepack, so it gets none. */
|
|
160
|
+
function packageManagerPin(userAgent) {
|
|
161
|
+
const match = /^(pnpm|npm|yarn)\/(\d+\.\d+\.\d+)/.exec(userAgent ?? "");
|
|
162
|
+
return match ? `${match[1]}@${match[2]}` : void 0;
|
|
163
|
+
}
|
|
152
164
|
function addArgs(pm, dev, packages) {
|
|
153
165
|
return [
|
|
154
166
|
pm === "npm" ? "install" : "add",
|
|
@@ -156,6 +168,63 @@ function addArgs(pm, dev, packages) {
|
|
|
156
168
|
...packages
|
|
157
169
|
];
|
|
158
170
|
}
|
|
171
|
+
/** The command that runs a locally installed binary (`blix`), per package manager. */
|
|
172
|
+
function execBlix(pm, args) {
|
|
173
|
+
switch (pm) {
|
|
174
|
+
case "pnpm": return {
|
|
175
|
+
command: "pnpm",
|
|
176
|
+
args: [
|
|
177
|
+
"exec",
|
|
178
|
+
"blix",
|
|
179
|
+
...args
|
|
180
|
+
]
|
|
181
|
+
};
|
|
182
|
+
case "npm": return {
|
|
183
|
+
command: "npx",
|
|
184
|
+
args: ["blix", ...args]
|
|
185
|
+
};
|
|
186
|
+
case "yarn": return {
|
|
187
|
+
command: "yarn",
|
|
188
|
+
args: ["blix", ...args]
|
|
189
|
+
};
|
|
190
|
+
case "bun": return {
|
|
191
|
+
command: "bunx",
|
|
192
|
+
args: ["blix", ...args]
|
|
193
|
+
};
|
|
194
|
+
/* v8 ignore start -- @preserve: exhaustiveness guard, unreachable while every package manager has a case */
|
|
195
|
+
default: throw new Error(`Unknown package manager ${String(pm)}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const VALUE_FLAGS = /* @__PURE__ */ new Set(["deploy", "ci"]);
|
|
199
|
+
function parseArgs(argv) {
|
|
200
|
+
const parsed = {
|
|
201
|
+
positionals: [],
|
|
202
|
+
noInstall: false,
|
|
203
|
+
help: false
|
|
204
|
+
};
|
|
205
|
+
for (let index = 0; index < argv.length; index++) {
|
|
206
|
+
const arg = argv[index];
|
|
207
|
+
if (arg === void 0) continue;
|
|
208
|
+
if (arg === "--help" || arg === "-h") parsed.help = true;
|
|
209
|
+
else if (arg === "--no-install") parsed.noInstall = true;
|
|
210
|
+
else if (arg.startsWith("--")) {
|
|
211
|
+
const [name = "", inline] = arg.slice(2).split(/=(.*)/s);
|
|
212
|
+
if (!VALUE_FLAGS.has(name)) {
|
|
213
|
+
parsed.error ??= `Unknown option "${arg}"`;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const value = inline ?? argv[++index];
|
|
217
|
+
if (value === void 0 || value.startsWith("-")) {
|
|
218
|
+
parsed.error ??= `--${name} needs a value`;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (name === "deploy") parsed.deploy = value;
|
|
222
|
+
else parsed.ci = value;
|
|
223
|
+
} else if (arg.startsWith("-")) parsed.error ??= `Unknown option "${arg}"`;
|
|
224
|
+
else parsed.positionals.push(arg);
|
|
225
|
+
}
|
|
226
|
+
return parsed;
|
|
227
|
+
}
|
|
159
228
|
const runWithInheritedStdio = (command, args, cwd) => new Promise((resolve, reject) => {
|
|
160
229
|
const child = spawn(command, args, {
|
|
161
230
|
cwd,
|
|
@@ -169,27 +238,31 @@ const runWithInheritedStdio = (command, args, cwd) => new Promise((resolve, reje
|
|
|
169
238
|
});
|
|
170
239
|
/** The whole CLI as a function of argv + environment — no process.exit()/console.log(), so it is directly testable. */
|
|
171
240
|
async function runCreate(argv, options) {
|
|
172
|
-
const
|
|
173
|
-
const [target, ...extra] =
|
|
174
|
-
if (
|
|
241
|
+
const parsed = parseArgs(argv);
|
|
242
|
+
const [target, ...extra] = parsed.positionals;
|
|
243
|
+
if (parsed.help) return {
|
|
175
244
|
exitCode: 0,
|
|
176
245
|
stdout: USAGE,
|
|
177
246
|
stderr: ""
|
|
178
247
|
};
|
|
179
|
-
|
|
180
|
-
if (unknown) return {
|
|
248
|
+
if (parsed.error) return {
|
|
181
249
|
exitCode: 1,
|
|
182
250
|
stdout: "",
|
|
183
|
-
stderr:
|
|
251
|
+
stderr: `${parsed.error}\n\n${USAGE}`
|
|
184
252
|
};
|
|
185
253
|
if (!target || extra.length > 0) return {
|
|
186
254
|
exitCode: 1,
|
|
187
255
|
stdout: "",
|
|
188
256
|
stderr: `Usage: ${USAGE}`
|
|
189
257
|
};
|
|
258
|
+
if (parsed.ci && !parsed.deploy) return {
|
|
259
|
+
exitCode: 1,
|
|
260
|
+
stdout: "",
|
|
261
|
+
stderr: `--ci only makes sense with --deploy <target>.\n\n${USAGE}`
|
|
262
|
+
};
|
|
190
263
|
let result;
|
|
191
264
|
try {
|
|
192
|
-
result = scaffold(options.cwd, target);
|
|
265
|
+
result = scaffold(options.cwd, target, packageManagerPin(options.userAgent));
|
|
193
266
|
} catch (error) {
|
|
194
267
|
if (error instanceof ScaffoldError) return {
|
|
195
268
|
exitCode: 1,
|
|
@@ -201,20 +274,55 @@ async function runCreate(argv, options) {
|
|
|
201
274
|
const pm = detectPackageManager(options.userAgent);
|
|
202
275
|
const runtime = addArgs(pm, false, RUNTIME_DEPENDENCIES);
|
|
203
276
|
const dev = addArgs(pm, true, DEV_DEPENDENCIES);
|
|
277
|
+
const deployDev = addArgs(pm, true, DEPLOY_DEPENDENCIES);
|
|
278
|
+
const blixInit = execBlix(pm, parsed.deploy ? [
|
|
279
|
+
"deploy",
|
|
280
|
+
"init",
|
|
281
|
+
"--target",
|
|
282
|
+
parsed.deploy,
|
|
283
|
+
...parsed.ci ? ["--ci", parsed.ci] : []
|
|
284
|
+
] : []);
|
|
204
285
|
const dir = relative(options.cwd, result.directory) || ".";
|
|
205
286
|
let stdout = `Created ${result.packageName} in ${dir}\n`;
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
287
|
+
if (parsed.noInstall) {
|
|
288
|
+
stdout += `\nNext:\n cd ${dir}\n ${pm} ${runtime.join(" ")}\n ${pm} ${dev.join(" ")}\n`;
|
|
289
|
+
if (parsed.deploy) stdout += ` ${pm} ${deployDev.join(" ")}\n ${blixInit.command} ${blixInit.args.join(" ")}\n`;
|
|
290
|
+
return {
|
|
291
|
+
exitCode: 0,
|
|
292
|
+
stdout,
|
|
293
|
+
stderr: ""
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
const install = options.install ?? runWithInheritedStdio;
|
|
297
|
+
const steps = [
|
|
298
|
+
{
|
|
299
|
+
command: pm,
|
|
300
|
+
args: runtime
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
command: pm,
|
|
304
|
+
args: dev
|
|
305
|
+
},
|
|
306
|
+
...parsed.deploy ? [{
|
|
307
|
+
command: pm,
|
|
308
|
+
args: deployDev
|
|
309
|
+
}, blixInit] : []
|
|
310
|
+
];
|
|
311
|
+
for (const step of steps) {
|
|
312
|
+
const code = await install(step.command, step.args, result.directory);
|
|
313
|
+
if (code !== 0) {
|
|
314
|
+
const isInit = parsed.deploy !== void 0 && step === steps.at(-1);
|
|
315
|
+
return {
|
|
212
316
|
exitCode: code,
|
|
213
317
|
stdout,
|
|
214
|
-
stderr: `\n"${
|
|
318
|
+
stderr: `\n"${step.command} ${step.args.join(" ")}" failed (exit ${code}). The files are in ${dir}; ${isInit ? "run `blix deploy init` yourself (the app itself is ready)." : "run the install yourself."}\n`
|
|
215
319
|
};
|
|
216
320
|
}
|
|
217
|
-
|
|
321
|
+
}
|
|
322
|
+
stdout += `\nNext:\n cd ${dir}\n ${pm === "npm" ? "npm run" : pm} dev\n curl http://localhost:3000/hello/world\n`;
|
|
323
|
+
if (parsed.deploy) {
|
|
324
|
+
const dryRun = execBlix(pm, ["deploy", "--dry-run"]);
|
|
325
|
+
stdout += `\nDeploy (${parsed.deploy}${parsed.ci ? `, ${parsed.ci}` : ""}):\n review blix.config.ts, then\n ${dryRun.command} ${dryRun.args.join(" ")}\n`;
|
|
218
326
|
}
|
|
219
327
|
return {
|
|
220
328
|
exitCode: 0,
|
|
@@ -234,6 +342,6 @@ if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.ar
|
|
|
234
342
|
}
|
|
235
343
|
/* v8 ignore stop */
|
|
236
344
|
//#endregion
|
|
237
|
-
export { detectPackageManager, runCreate };
|
|
345
|
+
export { detectPackageManager, packageManagerPin, runCreate };
|
|
238
346
|
|
|
239
347
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/template.ts","../src/scaffold.ts","../src/index.ts"],"sourcesContent":["/** Every file of the generated app, keyed by path relative to the project root. */\nexport function templateFiles(packageName: string): Record<string, string> {\n return {\n \"package.json\": `${JSON.stringify(\n {\n name: packageName,\n version: \"0.0.0\",\n private: true,\n type: \"module\",\n engines: { node: \">=24\" },\n scripts: {\n // Decorators need tsc (esbuild/tsx drop the metadata), so dev is \"compile once, then\n // recompile on change while node restarts on the new output\".\n dev: 'tsc -p tsconfig.json && concurrently -k -n tsc,app \"tsc -p tsconfig.json --watch --preserveWatchOutput\" \"node --watch dist/main.js\"',\n build: \"tsc -p tsconfig.json\",\n start: \"node dist/main.js\",\n typecheck: \"tsc --noEmit -p tsconfig.json\",\n },\n },\n null,\n 2,\n )}\\n`,\n\n \"tsconfig.json\": `${JSON.stringify(\n {\n compilerOptions: {\n target: \"es2023\",\n lib: [\"es2023\"],\n types: [\"node\"],\n module: \"nodenext\",\n moduleResolution: \"nodenext\",\n strict: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n useDefineForClassFields: false,\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: \"dist\",\n rootDir: \"src\",\n },\n include: [\"src\"],\n },\n null,\n 2,\n )}\\n`,\n\n \".gitignore\": \"node_modules\\ndist\\n\",\n\n \"README.md\": `# ${packageName}\n\nA [Blixis](https://blixis-io.github.io/framework/) app.\n\n\\`\\`\\`bash\nnpm run dev # rebuilds and restarts on every change\n# or: npm run build && npm start\ncurl http://localhost:3000/hello/world\n\\`\\`\\`\n\nDecorators need \\`tsc\\` (not tsx/esbuild) — see the\n[installation notes](https://blixis-io.github.io/framework/start-here/installation/).\n`,\n\n \"src/hello.service.ts\": `import { Injectable } from \"@blixis-io/di\";\n\n@Injectable()\nexport class HelloService {\n greet(name: string): string {\n return \\`Hello, \\${name}!\\`;\n }\n}\n`,\n\n \"src/hello.controller.ts\": `import { Controller, Get, Param } from \"@blixis-io/http\";\nimport { HelloService } from \"./hello.service.js\";\n\n@Controller(\"hello\")\nexport class HelloController {\n constructor(private readonly hello: HelloService) {}\n\n @Get(\":name\")\n greet(@Param(\"name\") name: string) {\n return { message: this.hello.greet(name) };\n }\n}\n`,\n\n \"src/app.module.ts\": `import { Module } from \"@blixis-io/core\";\nimport { HelloController } from \"./hello.controller.js\";\nimport { HelloService } from \"./hello.service.js\";\n\n@Module({\n providers: [HelloService],\n controllers: [HelloController],\n})\nexport class AppModule {}\n`,\n\n \"src/main.ts\": `import { createHttpApplication } from \"@blixis-io/http\";\nimport { AppModule } from \"./app.module.js\";\n\nconst app = await createHttpApplication(AppModule);\nconst port = Number(process.env[\"PORT\"] ?? 3000);\nawait app.listen(port);\n\nconsole.log(\\`Listening on http://localhost:\\${port}\\`);\n\nprocess.on(\"SIGTERM\", () => {\n void app.close(\"SIGTERM\").then(() => process.exit(0));\n});\n`,\n };\n}\n\nexport const RUNTIME_DEPENDENCIES = [\"@blixis-io/core\", \"@blixis-io/di\", \"@blixis-io/http\"] as const;\nexport const DEV_DEPENDENCIES = [\"typescript\", \"@types/node\", \"concurrently\"] as const;\n","import { existsSync, mkdirSync, readdirSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { templateFiles } from \"./template.js\";\n\nconst PACKAGE_NAME = /^[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport class ScaffoldError extends Error {\n override readonly name = \"ScaffoldError\";\n}\n\nexport interface ScaffoldResult {\n directory: string;\n packageName: string;\n files: string[];\n}\n\n/** Writes the starter app into `cwd/<target>`. The directory may not exist yet, or must be empty. */\nexport function scaffold(cwd: string, target: string): ScaffoldResult {\n const directory = resolve(cwd, target);\n const packageName = basename(directory);\n\n if (!PACKAGE_NAME.test(packageName)) {\n throw new ScaffoldError(\n `\"${packageName}\" is not a valid package name — use lowercase letters, digits, \"-\", \".\" or \"_\", starting with a letter or digit.`,\n );\n }\n if (existsSync(directory) && readdirSync(directory).length > 0) {\n throw new ScaffoldError(`${target} already exists and is not empty.`);\n }\n\n const files = Object.entries(templateFiles(packageName));\n for (const [path, content] of files) {\n const absolute = join(directory, path);\n mkdirSync(dirname(absolute), { recursive: true });\n writeFileSync(absolute, content);\n }\n\n return { directory, packageName, files: files.map(([path]) => path) };\n}\n","#!/usr/bin/env node\nimport { spawn } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { relative } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { ScaffoldError, scaffold } from \"./scaffold.js\";\nimport { DEV_DEPENDENCIES, RUNTIME_DEPENDENCIES } from \"./template.js\";\n\nconst USAGE = `create-blixis <directory> [--no-install]\n\n pnpm create blixis my-app\n npm create blixis@latest my-app\n\n --no-install write the files only; print the install commands instead\n`;\n\nexport type PackageManager = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\n\nexport interface CreateResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n/** Runs one package-manager command; resolves with its exit code. Injected so tests never touch the network. */\nexport type InstallRunner = (command: string, args: readonly string[], cwd: string) => Promise<number>;\n\nexport interface CreateOptions {\n cwd: string;\n /** `npm_config_user_agent` — tells us which package manager invoked `create`. */\n userAgent?: string | undefined;\n install?: InstallRunner;\n}\n\nexport function detectPackageManager(userAgent: string | undefined): PackageManager {\n const name = userAgent?.split(\"/\")[0];\n return name === \"pnpm\" || name === \"yarn\" || name === \"bun\" ? name : \"npm\";\n}\n\nfunction addArgs(pm: PackageManager, dev: boolean, packages: readonly string[]): string[] {\n const verb = pm === \"npm\" ? \"install\" : \"add\";\n const devFlag = pm === \"bun\" ? \"-d\" : \"-D\";\n return [verb, ...(dev ? [devFlag] : []), ...packages];\n}\n\nconst runWithInheritedStdio: InstallRunner = (command, args, cwd) =>\n new Promise((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: \"inherit\", shell: process.platform === \"win32\" });\n child.once(\"error\", reject);\n child.once(\"close\", (code) => {\n resolve(code ?? 1);\n });\n });\n\n/** The whole CLI as a function of argv + environment — no process.exit()/console.log(), so it is directly testable. */\nexport async function runCreate(argv: readonly string[], options: CreateOptions): Promise<CreateResult> {\n const flags = argv.filter((arg) => arg.startsWith(\"-\"));\n const [target, ...extra] = argv.filter((arg) => !arg.startsWith(\"-\"));\n\n if (flags.includes(\"--help\") || flags.includes(\"-h\")) {\n return { exitCode: 0, stdout: USAGE, stderr: \"\" };\n }\n const unknown = flags.find((flag) => flag !== \"--no-install\");\n if (unknown) {\n return { exitCode: 1, stdout: \"\", stderr: `Unknown option \"${unknown}\"\\n\\n${USAGE}` };\n }\n if (!target || extra.length > 0) {\n return { exitCode: 1, stdout: \"\", stderr: `Usage: ${USAGE}` };\n }\n\n let result;\n try {\n result = scaffold(options.cwd, target);\n } catch (error) {\n if (error instanceof ScaffoldError) {\n return { exitCode: 1, stdout: \"\", stderr: `${error.message}\\n` };\n }\n throw error;\n }\n\n const pm = detectPackageManager(options.userAgent);\n const runtime = addArgs(pm, false, RUNTIME_DEPENDENCIES);\n const dev = addArgs(pm, true, DEV_DEPENDENCIES);\n const dir = relative(options.cwd, result.directory) || \".\";\n let stdout = `Created ${result.packageName} in ${dir}\\n`;\n\n if (flags.includes(\"--no-install\")) {\n stdout += `\\nNext:\\n cd ${dir}\\n ${pm} ${runtime.join(\" \")}\\n ${pm} ${dev.join(\" \")}\\n`;\n } else {\n const install = options.install ?? runWithInheritedStdio;\n for (const args of [runtime, dev]) {\n const code = await install(pm, args, result.directory);\n if (code !== 0) {\n return {\n exitCode: code,\n stdout,\n stderr: `\\n\"${pm} ${args.join(\" \")}\" failed (exit ${code}). The files are in ${dir}; run the install yourself.\\n`,\n };\n }\n }\n const run = pm === \"npm\" ? \"npm run\" : pm;\n stdout += `\\nNext:\\n cd ${dir}\\n ${run} dev\\n curl http://localhost:3000/hello/world\\n`;\n }\n\n return { exitCode: 0, stdout, stderr: \"\" };\n}\n\n// Same entry-point check as @blixis-io/cli: pathToFileURL(realpathSync(...)) so a\n// bin shim's symlink and a path with spaces both still match import.meta.url.\n/* v8 ignore start -- @preserve: process wiring, exercised by index.test.ts spawning the real built binary */\nif (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) {\n const result = await runCreate(process.argv.slice(2), {\n cwd: process.cwd(),\n userAgent: process.env[\"npm_config_user_agent\"],\n });\n if (result.stdout) {\n process.stdout.write(result.stdout);\n }\n if (result.stderr) {\n process.stderr.write(result.stderr);\n }\n process.exitCode = result.exitCode;\n}\n/* v8 ignore stop */\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["unreachable"],"sources":["../src/template.ts","../src/scaffold.ts","../src/index.ts"],"sourcesContent":["/** Every file of the generated app, keyed by path relative to the project root. */\nexport function templateFiles(packageName: string, packageManagerPin?: string): Record<string, string> {\n return {\n \"package.json\": `${JSON.stringify(\n {\n name: packageName,\n version: \"0.0.0\",\n private: true,\n type: \"module\",\n // Pins the package manager (corepack honours it), so a Docker image or CI job installs with the same\n // major version the project was created with instead of whatever is newest.\n ...(packageManagerPin ? { packageManager: packageManagerPin } : {}),\n engines: { node: \">=24\" },\n scripts: {\n // Decorators need tsc (esbuild/tsx drop the metadata), so dev is \"compile once, then\n // recompile on change while node restarts on the new output\".\n dev: 'tsc -p tsconfig.json && concurrently -k -n tsc,app \"tsc -p tsconfig.json --watch --preserveWatchOutput\" \"node --watch dist/main.js\"',\n build: \"tsc -p tsconfig.json\",\n start: \"node dist/main.js\",\n typecheck: \"tsc --noEmit -p tsconfig.json\",\n },\n },\n null,\n 2,\n )}\\n`,\n\n \"tsconfig.json\": `${JSON.stringify(\n {\n compilerOptions: {\n target: \"es2023\",\n lib: [\"es2023\"],\n types: [\"node\"],\n module: \"nodenext\",\n moduleResolution: \"nodenext\",\n strict: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n useDefineForClassFields: false,\n esModuleInterop: true,\n skipLibCheck: true,\n outDir: \"dist\",\n rootDir: \"src\",\n },\n include: [\"src\"],\n },\n null,\n 2,\n )}\\n`,\n\n \".gitignore\": \"node_modules\\ndist\\n\",\n\n \"README.md\": `# ${packageName}\n\nA [Blixis](https://blixis-io.github.io/framework/) app.\n\n\\`\\`\\`bash\nnpm run dev # rebuilds and restarts on every change\n# or: npm run build && npm start\ncurl http://localhost:3000/hello/world\n\\`\\`\\`\n\nDecorators need \\`tsc\\` (not tsx/esbuild) — see the\n[installation notes](https://blixis-io.github.io/framework/start-here/installation/).\n`,\n\n \"src/hello.service.ts\": `import { Injectable } from \"@blixis-io/di\";\n\n@Injectable()\nexport class HelloService {\n greet(name: string): string {\n return \\`Hello, \\${name}!\\`;\n }\n}\n`,\n\n \"src/hello.controller.ts\": `import { Controller, Get, Param } from \"@blixis-io/http\";\nimport { HelloService } from \"./hello.service.js\";\n\n@Controller(\"hello\")\nexport class HelloController {\n constructor(private readonly hello: HelloService) {}\n\n @Get(\":name\")\n greet(@Param(\"name\") name: string) {\n return { message: this.hello.greet(name) };\n }\n}\n`,\n\n \"src/app.module.ts\": `import { Module } from \"@blixis-io/core\";\nimport { HelloController } from \"./hello.controller.js\";\nimport { HelloService } from \"./hello.service.js\";\n\n@Module({\n providers: [HelloService],\n controllers: [HelloController],\n})\nexport class AppModule {}\n`,\n\n \"src/main.ts\": `import { createHttpApplication } from \"@blixis-io/http\";\nimport { AppModule } from \"./app.module.js\";\n\nconst app = await createHttpApplication(AppModule);\nconst port = Number(process.env[\"PORT\"] ?? 3000);\nawait app.listen(port);\n\nconsole.log(\\`Listening on http://localhost:\\${port}\\`);\n\nprocess.on(\"SIGTERM\", () => {\n void app.close(\"SIGTERM\").then(() => process.exit(0));\n});\n`,\n };\n}\n\nexport const RUNTIME_DEPENDENCIES = [\"@blixis-io/core\", \"@blixis-io/di\", \"@blixis-io/http\"] as const;\n/** Added only with --deploy: the CLI and its deploy plugin. */\nexport const DEPLOY_DEPENDENCIES = [\"@blixis-io/cli\", \"@blixis-io/deploy\"] as const;\nexport const DEV_DEPENDENCIES = [\"typescript\", \"@types/node\", \"concurrently\"] as const;\n","import { existsSync, mkdirSync, readdirSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { templateFiles } from \"./template.js\";\n\nconst PACKAGE_NAME = /^[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport class ScaffoldError extends Error {\n override readonly name = \"ScaffoldError\";\n}\n\nexport interface ScaffoldResult {\n directory: string;\n packageName: string;\n files: string[];\n}\n\n/** Writes the starter app into `cwd/<target>`. The directory may not exist yet, or must be empty. */\nexport function scaffold(cwd: string, target: string, packageManagerPin?: string): ScaffoldResult {\n const directory = resolve(cwd, target);\n const packageName = basename(directory);\n\n if (!PACKAGE_NAME.test(packageName)) {\n throw new ScaffoldError(\n `\"${packageName}\" is not a valid package name — use lowercase letters, digits, \"-\", \".\" or \"_\", starting with a letter or digit.`,\n );\n }\n if (existsSync(directory) && readdirSync(directory).length > 0) {\n throw new ScaffoldError(`${target} already exists and is not empty.`);\n }\n\n const files = Object.entries(templateFiles(packageName, packageManagerPin));\n for (const [path, content] of files) {\n const absolute = join(directory, path);\n mkdirSync(dirname(absolute), { recursive: true });\n writeFileSync(absolute, content);\n }\n\n return { directory, packageName, files: files.map(([path]) => path) };\n}\n","#!/usr/bin/env node\nimport { spawn } from \"node:child_process\";\nimport { realpathSync } from \"node:fs\";\nimport { relative } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { ScaffoldError, scaffold } from \"./scaffold.js\";\nimport { DEPLOY_DEPENDENCIES, DEV_DEPENDENCIES, RUNTIME_DEPENDENCIES } from \"./template.js\";\n\nconst USAGE = `create-blixis <directory> [--deploy <target>] [--ci <provider>] [--no-install]\n\n pnpm create blixis my-app\n npm create blixis@latest my-app\n pnpm create blixis my-app --deploy docker --ci github\n\n --deploy <target> also set up deployment (docker, vercel, netlify or cloudflare): installs\n @blixis-io/cli and @blixis-io/deploy and runs \\`blix deploy init\\`\n --ci <provider> with --deploy: also write the CI pipeline (github, gitlab or bitbucket)\n --no-install write the files only; print the install commands instead\n`;\n\nexport type PackageManager = \"pnpm\" | \"npm\" | \"yarn\" | \"bun\";\n\nexport interface CreateResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\n/** Runs one package-manager command; resolves with its exit code. Injected so tests never touch the network. */\nexport type InstallRunner = (command: string, args: readonly string[], cwd: string) => Promise<number>;\n\nexport interface CreateOptions {\n cwd: string;\n /** `npm_config_user_agent` — tells us which package manager invoked `create`. */\n userAgent?: string | undefined;\n install?: InstallRunner;\n}\n\nexport function detectPackageManager(userAgent: string | undefined): PackageManager {\n const name = userAgent?.split(\"/\")[0];\n return name === \"pnpm\" || name === \"yarn\" || name === \"bun\" ? name : \"npm\";\n}\n\n/** `\"pnpm@11.25.0\"` from an `npm_config_user_agent` like `pnpm/11.25.0 npm/? node/v24.0.0`, for the `packageManager` field. Bun isn't managed by corepack, so it gets none. */\nexport function packageManagerPin(userAgent: string | undefined): string | undefined {\n const match = /^(pnpm|npm|yarn)\\/(\\d+\\.\\d+\\.\\d+)/.exec(userAgent ?? \"\");\n return match ? `${match[1]}@${match[2]}` : undefined;\n}\n\nfunction addArgs(pm: PackageManager, dev: boolean, packages: readonly string[]): string[] {\n const verb = pm === \"npm\" ? \"install\" : \"add\";\n const devFlag = pm === \"bun\" ? \"-d\" : \"-D\";\n return [verb, ...(dev ? [devFlag] : []), ...packages];\n}\n\n/** The command that runs a locally installed binary (`blix`), per package manager. */\nfunction execBlix(pm: PackageManager, args: readonly string[]): { command: string; args: string[] } {\n switch (pm) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"exec\", \"blix\", ...args] };\n case \"npm\":\n return { command: \"npx\", args: [\"blix\", ...args] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"blix\", ...args] };\n case \"bun\":\n return { command: \"bunx\", args: [\"blix\", ...args] };\n /* v8 ignore start -- @preserve: exhaustiveness guard, unreachable while every package manager has a case */\n default: {\n const unreachable: never = pm;\n throw new Error(`Unknown package manager ${String(unreachable)}`);\n }\n /* v8 ignore stop */\n }\n}\n\ninterface ParsedArgs {\n positionals: string[];\n noInstall: boolean;\n help: boolean;\n deploy?: string | undefined;\n ci?: string | undefined;\n error?: string | undefined;\n}\n\nconst VALUE_FLAGS = new Set([\"deploy\", \"ci\"]);\n\nfunction parseArgs(argv: readonly string[]): ParsedArgs {\n const parsed: ParsedArgs = { positionals: [], noInstall: false, help: false };\n for (let index = 0; index < argv.length; index++) {\n const arg = argv[index];\n if (arg === undefined) {\n continue;\n }\n if (arg === \"--help\" || arg === \"-h\") {\n parsed.help = true;\n } else if (arg === \"--no-install\") {\n parsed.noInstall = true;\n } else if (arg.startsWith(\"--\")) {\n const [name = \"\", inline] = arg.slice(2).split(/=(.*)/s);\n if (!VALUE_FLAGS.has(name)) {\n parsed.error ??= `Unknown option \"${arg}\"`;\n continue;\n }\n const value = inline ?? argv[++index];\n if (value === undefined || value.startsWith(\"-\")) {\n parsed.error ??= `--${name} needs a value`;\n continue;\n }\n if (name === \"deploy\") {\n parsed.deploy = value;\n } else {\n parsed.ci = value;\n }\n } else if (arg.startsWith(\"-\")) {\n parsed.error ??= `Unknown option \"${arg}\"`;\n } else {\n parsed.positionals.push(arg);\n }\n }\n return parsed;\n}\n\nconst runWithInheritedStdio: InstallRunner = (command, args, cwd) =>\n new Promise((resolve, reject) => {\n const child = spawn(command, args, { cwd, stdio: \"inherit\", shell: process.platform === \"win32\" });\n child.once(\"error\", reject);\n child.once(\"close\", (code) => {\n resolve(code ?? 1);\n });\n });\n\n/** The whole CLI as a function of argv + environment — no process.exit()/console.log(), so it is directly testable. */\nexport async function runCreate(argv: readonly string[], options: CreateOptions): Promise<CreateResult> {\n const parsed = parseArgs(argv);\n const [target, ...extra] = parsed.positionals;\n\n if (parsed.help) {\n return { exitCode: 0, stdout: USAGE, stderr: \"\" };\n }\n if (parsed.error) {\n return { exitCode: 1, stdout: \"\", stderr: `${parsed.error}\\n\\n${USAGE}` };\n }\n if (!target || extra.length > 0) {\n return { exitCode: 1, stdout: \"\", stderr: `Usage: ${USAGE}` };\n }\n if (parsed.ci && !parsed.deploy) {\n return { exitCode: 1, stdout: \"\", stderr: `--ci only makes sense with --deploy <target>.\\n\\n${USAGE}` };\n }\n\n let result;\n try {\n result = scaffold(options.cwd, target, packageManagerPin(options.userAgent));\n } catch (error) {\n if (error instanceof ScaffoldError) {\n return { exitCode: 1, stdout: \"\", stderr: `${error.message}\\n` };\n }\n throw error;\n }\n\n const pm = detectPackageManager(options.userAgent);\n const runtime = addArgs(pm, false, RUNTIME_DEPENDENCIES);\n const dev = addArgs(pm, true, DEV_DEPENDENCIES);\n const deployDev = addArgs(pm, true, DEPLOY_DEPENDENCIES);\n const initArgs = parsed.deploy ? [\"deploy\", \"init\", \"--target\", parsed.deploy, ...(parsed.ci ? [\"--ci\", parsed.ci] : [])] : [];\n const blixInit = execBlix(pm, initArgs);\n const dir = relative(options.cwd, result.directory) || \".\";\n let stdout = `Created ${result.packageName} in ${dir}\\n`;\n\n if (parsed.noInstall) {\n stdout += `\\nNext:\\n cd ${dir}\\n ${pm} ${runtime.join(\" \")}\\n ${pm} ${dev.join(\" \")}\\n`;\n if (parsed.deploy) {\n stdout += ` ${pm} ${deployDev.join(\" \")}\\n ${blixInit.command} ${blixInit.args.join(\" \")}\\n`;\n }\n return { exitCode: 0, stdout, stderr: \"\" };\n }\n\n const install = options.install ?? runWithInheritedStdio;\n const steps: { command: string; args: readonly string[] }[] = [\n { command: pm, args: runtime },\n { command: pm, args: dev },\n ...(parsed.deploy ? [{ command: pm, args: deployDev }, blixInit] : []),\n ];\n for (const step of steps) {\n const code = await install(step.command, step.args, result.directory);\n if (code !== 0) {\n const isInit = parsed.deploy !== undefined && step === steps.at(-1);\n return {\n exitCode: code,\n stdout,\n stderr: `\\n\"${step.command} ${step.args.join(\" \")}\" failed (exit ${code}). The files are in ${dir}; ${\n isInit ? \"run `blix deploy init` yourself (the app itself is ready).\" : \"run the install yourself.\"\n }\\n`,\n };\n }\n }\n\n const run = pm === \"npm\" ? \"npm run\" : pm;\n stdout += `\\nNext:\\n cd ${dir}\\n ${run} dev\\n curl http://localhost:3000/hello/world\\n`;\n if (parsed.deploy) {\n const dryRun = execBlix(pm, [\"deploy\", \"--dry-run\"]);\n stdout += `\\nDeploy (${parsed.deploy}${parsed.ci ? `, ${parsed.ci}` : \"\"}):\\n review blix.config.ts, then\\n ${dryRun.command} ${dryRun.args.join(\" \")}\\n`;\n }\n return { exitCode: 0, stdout, stderr: \"\" };\n}\n\n// Same entry-point check as @blixis-io/cli: pathToFileURL(realpathSync(...)) so a\n// bin shim's symlink and a path with spaces both still match import.meta.url.\n/* v8 ignore start -- @preserve: process wiring, exercised by index.test.ts spawning the real built binary */\nif (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href) {\n const result = await runCreate(process.argv.slice(2), {\n cwd: process.cwd(),\n userAgent: process.env[\"npm_config_user_agent\"],\n });\n if (result.stdout) {\n process.stdout.write(result.stdout);\n }\n if (result.stderr) {\n process.stderr.write(result.stderr);\n }\n process.exitCode = result.exitCode;\n}\n/* v8 ignore stop */\n"],"mappings":"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"}
|
package/package.json
CHANGED