create-quadrokit 0.2.6 → 0.2.8

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 CHANGED
@@ -16,17 +16,18 @@ bun create-quadrokit/src/index.ts --template dashboard --dir /path/to/my-app
16
16
  | `--template <name>` | `dashboard` \| `website` \| `ecommerce` \| `admin-shell` |
17
17
  | `--dir <path>` | Target directory relative to cwd (created; must be empty if it already exists) |
18
18
  | `--name <name>` | Same as `--dir` (project folder name); ignored if `--dir` is set |
19
- | `-y` / `--yes` | Non-interactive: requires `--template`; uses `quadro-<template>` as the directory unless `--dir` / `--name` is set; runs git init and install without prompting (override with `--no-git` / `--no-install`) |
19
+ | `-y` / `--yes` | Non-interactive: requires `--template`; uses `quadro-<template>` as the directory unless `--dir` / `--name` is set; copies `.env.example` → `.env`, runs git init and install without prompting (override with `--no-copy-env` / `--no-git` / `--no-install`) |
20
20
  | `-h` / `--help` | Print usage and exit |
21
21
  | `--keep-workspace` | Keep `workspace:*` in `package.json` (for development inside the QuadroKit monorepo only) |
22
22
  | `--git` / `--no-git` | Initialize a git repo after scaffolding (skip the prompt) |
23
23
  | `--install` / `--no-install` | Run `bun install` or `npm install` after scaffolding (skip the prompt) |
24
+ | `--copy-env` / `--no-copy-env` | Copy `.env.example` to `.env` after scaffolding (skip the prompt) |
24
25
 
25
26
  The banner shows **create-quadrokit**’s package version (e.g. `v0.2.2`).
26
27
 
27
28
  On start, the CLI prints a short **prerequisites** check (Node.js, Bun, Git). Node 18+ is required; Bun is optional (falls back to npm for installs). Git is only needed if you choose to init a repository.
28
29
 
29
- Interactive mode: run without `--template` / `--dir` / `--name` to be prompted. If the project directory already exists and is **not empty**, you are asked again for a different name. You are then asked about **git** and **install** unless `-y` or the explicit flags above apply.
30
+ Interactive mode: run without `--template` / `--dir` / `--name` to be prompted. If the project directory already exists and is **not empty**, you are asked again for a different name. You are then asked whether to copy **`.env.example` → `.env`**, then about **git** and **install**, unless `-y` or the explicit flags above apply.
30
31
 
31
32
  ## What it does
32
33
 
@@ -36,7 +37,8 @@ Interactive mode: run without `--template` / `--dir` / `--name` to be prompted.
36
37
  4. Removes `@quadrokit/sample-client` and rewrites `workspace:*` on `@quadrokit/*` deps to `^<version>` matching **create-quadrokit**’s own `package.json` `version` (run `bun run version:set` at repo root to bump public packages) unless `--keep-workspace`.
37
38
  5. Writes `QUADROKIT.md` with proxy and `quadrokit:generate` instructions. Does **not** copy `.quadrokit/generated` — run `bun run quadrokit:generate` after install.
38
39
  6. Adds a root `.gitignore` (unless the template already shipped one).
39
- 7. Optionally runs `git init` and installs dependencies (`bun` if available, otherwise `npm`).
40
+ 7. Optionally copies `.env.example` to `.env` (prompt, or defaults with `-y`; use `--no-copy-env` to skip).
41
+ 8. Optionally runs `git init` and installs dependencies (`bun` if available, otherwise `npm`).
40
42
 
41
43
  ## Published usage (future)
42
44
 
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawnSync } from 'node:child_process';
3
3
  import { readFileSync } from 'node:fs';
4
- import { readdir, readFile, stat, writeFile } from 'node:fs/promises';
4
+ import { copyFile, readdir, readFile, stat, writeFile } from 'node:fs/promises';
5
5
  import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import prompts from 'prompts';
@@ -63,11 +63,14 @@ Options:
63
63
  --dir <path> Project directory (relative to cwd; must not exist or be empty)
64
64
  --name <name> Same as --dir when --dir is omitted
65
65
  -y, --yes Non-interactive: requires --template; uses quadro-<template> as directory
66
- unless --dir / --name; runs git init + install (override with --no-git / --no-install)
66
+ unless --dir / --name; copies .env.example → .env, runs git init + install
67
+ (override with --no-copy-env / --no-git / --no-install)
67
68
  --git Initialize a git repository (skips prompt)
68
69
  --no-git Do not run git init
69
70
  --install Install dependencies after scaffold (skips prompt)
70
71
  --no-install Do not install dependencies
72
+ --copy-env Copy .env.example to .env (skips prompt)
73
+ --no-copy-env Do not copy .env.example to .env
71
74
  --keep-workspace Keep workspace:* @quadrokit deps (monorepo development only)
72
75
  -h, --help Show this help
73
76
 
@@ -130,6 +133,7 @@ function parseArgs(argv) {
130
133
  /** `undefined` = prompt later (unless yes) */
131
134
  let initGit;
132
135
  let installDeps;
136
+ let copyEnvFile;
133
137
  for (let i = 0; i < argv.length; i++) {
134
138
  const a = argv[i];
135
139
  if (a === '--template' && argv[i + 1]) {
@@ -159,11 +163,17 @@ function parseArgs(argv) {
159
163
  else if (a === '--no-install') {
160
164
  installDeps = false;
161
165
  }
166
+ else if (a === '--copy-env') {
167
+ copyEnvFile = true;
168
+ }
169
+ else if (a === '--no-copy-env') {
170
+ copyEnvFile = false;
171
+ }
162
172
  }
163
173
  if (!dir && name) {
164
174
  dir = name;
165
175
  }
166
- return { template, dir, keepWorkspace, yes, initGit, installDeps };
176
+ return { template, dir, keepWorkspace, yes, initGit, installDeps, copyEnvFile };
167
177
  }
168
178
  async function pathExists(p) {
169
179
  try {
@@ -334,7 +344,7 @@ Created with **create-quadrokit** (template: \`${template}\`).
334
344
  ## Next steps
335
345
 
336
346
  1. \`cd ${path.basename(dest)}\` and install dependencies (\`bun install\` or \`npm install\`).
337
- 2. Copy \`.env.example\` to \`.env\` and set \`VITE_4D_ORIGIN\` to your 4D web server (used for the dev proxy and as the default catalog origin for generate).
347
+ 2. If \`.env\` is missing, copy \`.env.example\` to \`.env\`. Set \`VITE_4D_ORIGIN\` to your 4D web server (used for the dev proxy and as the default catalog origin for generate). The scaffold CLI can copy this file for you when asked.
338
348
 
339
349
  3. Generate the typed REST client (required before \`dev\` / \`build\`). The CLI is \`quadrokit-client\` from \`@quadrokit/client\` (reads \`.env\` in the project cwd for defaults):
340
350
 
@@ -344,7 +354,7 @@ Created with **create-quadrokit** (template: \`${template}\`).
344
354
 
345
355
  Same as \`quadrokit-client generate\`. One-off (no local install): \`bunx -p @quadrokit/client quadrokit-client generate\` (or \`bunx quadrokit-client generate\`).
346
356
 
347
- Default catalog URL: \`\${VITE_4D_ORIGIN}/rest/\\$catalog\`, or \`http://127.0.0.1:7080/rest/\\$catalog\` if unset. Generator-only \`.env\` keys (not used by the browser):
357
+ Default catalog URL: \`\${VITE_4D_ORIGIN}/rest/\\$catalog/\\$all\`, or \`http://127.0.0.1:7080/rest/\\$catalog/\\$all\` if unset (plain \`/rest/\\$catalog\` omits attributes — use \`/\\$all\`). Generator-only \`.env\` keys (not used by the browser):
348
358
 
349
359
  - \`QUADROKIT_ACCESS_KEY\` — multipart \`accessKey\` to \`/api/login\`; then \`4DAdminSID\` for the catalog request.
350
360
  - \`QUADROKIT_LOGIN_URL\` — full login URL if not \`\${catalog origin}/api/login\`.
@@ -358,6 +368,22 @@ Production: serve the SPA and reverse-proxy \`/rest\` to 4D on the **same host**
358
368
  `;
359
369
  await writeFile(path.join(dest, 'QUADROKIT.md'), text, 'utf8');
360
370
  }
371
+ /** Copy `.env.example` → `.env` when the latter does not exist. */
372
+ async function copyEnvExampleToEnv(dest) {
373
+ const from = path.join(dest, '.env.example');
374
+ const to = path.join(dest, '.env');
375
+ if (!(await pathExists(from))) {
376
+ console.warn(' ⚠️ .env.example missing — skipped env copy.\n');
377
+ return false;
378
+ }
379
+ if (await pathExists(to)) {
380
+ console.log(' ⚠️ .env already exists — skipped copying .env.example.\n');
381
+ return false;
382
+ }
383
+ await copyFile(from, to);
384
+ console.log(' ✅ Copied .env.example → .env\n');
385
+ return true;
386
+ }
361
387
  async function writeGitignore(dest) {
362
388
  const p = path.join(dest, '.gitignore');
363
389
  if (await pathExists(p)) {
@@ -385,7 +411,7 @@ async function main() {
385
411
  printHelp(readPackageVersion());
386
412
  process.exit(0);
387
413
  }
388
- const { template: tArg, dir: dirArg, keepWorkspace, yes: yesFlag, initGit: gitFlag, installDeps: installFlag, } = parseArgs(argv);
414
+ const { template: tArg, dir: dirArg, keepWorkspace, yes: yesFlag, initGit: gitFlag, installDeps: installFlag, copyEnvFile: copyEnvFlag, } = parseArgs(argv);
389
415
  printWelcome(readPackageVersion());
390
416
  const prereqs = checkPrereqs();
391
417
  printPrereqReport(prereqs);
@@ -427,6 +453,28 @@ async function main() {
427
453
  await writeReadme(dest, template);
428
454
  await writeGitignore(dest);
429
455
  console.log(`\n 🎉 Project files are ready at ${'\u001b[1m'}${dest}${'\u001b[0m'}\n`);
456
+ let copyEnv = copyEnvFlag;
457
+ if (copyEnv === undefined) {
458
+ if (yesFlag) {
459
+ copyEnv = true;
460
+ }
461
+ else {
462
+ const envPrompt = await prompts({
463
+ type: 'confirm',
464
+ name: 'v',
465
+ message: 'Copy .env.example to .env?',
466
+ initial: true,
467
+ });
468
+ if (typeof envPrompt.v !== 'boolean') {
469
+ process.exit(1);
470
+ }
471
+ copyEnv = envPrompt.v;
472
+ }
473
+ }
474
+ let envCopiedOk = false;
475
+ if (copyEnv) {
476
+ envCopiedOk = await copyEnvExampleToEnv(dest);
477
+ }
430
478
  let initGit = gitFlag;
431
479
  if (initGit === undefined) {
432
480
  if (yesFlag) {
@@ -493,10 +541,21 @@ async function main() {
493
541
  const pm = prereqs.bunOk ? 'bun' : 'npm';
494
542
  const runDev = prereqs.bunOk ? 'bun run dev' : 'npm run dev';
495
543
  const installLine = installDeps ? ` → ${runDev}` : ` → ${pm} install\n → ${runDev}`;
544
+ const hasEnvFile = await pathExists(path.join(dest, '.env'));
545
+ let envHint;
546
+ if (envCopiedOk || hasEnvFile) {
547
+ envHint = ` → Set VITE_4D_ORIGIN in .env (if needed)`;
548
+ }
549
+ else if (!copyEnv) {
550
+ envHint = ` → Copy .env.example → .env and set VITE_4D_ORIGIN`;
551
+ }
552
+ else {
553
+ envHint = ` → Create .env from .env.example and set VITE_4D_ORIGIN`;
554
+ }
496
555
  console.log(` 🚀🚀 Next steps
497
556
  → cd ${path.basename(dest)}
498
557
  ${installLine}
499
- → Copy .env.example → .env and set VITE_4D_ORIGIN
558
+ ${envHint}
500
559
 
501
560
  Happy building! ✨
502
561
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-quadrokit",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Scaffold a QuadroKit Vite + React app from a template",
5
5
  "type": "module",
6
6
  "bin": "./dist/index.mjs",
@@ -1,7 +1,7 @@
1
1
  # Origin of your 4D web server (REST). The Vite dev server proxies /rest here.
2
2
  VITE_4D_ORIGIN=http://127.0.0.1:7080
3
3
 
4
- # Generator only (quadrokit:generate): multipart accessKey → 4DAdminSID cookie for fetching /rest/$catalog.
4
+ # Generator only (quadrokit:generate): multipart accessKey → 4DAdminSID cookie for fetching /rest/$catalog/$all.
5
5
  # Not used by the browser runtime.
6
6
  # QUADROKIT_ACCESS_KEY=
7
7
  # QUADROKIT_LOGIN_URL=https://127.0.0.1:7443/api/login