create-apiagex 0.6.2 → 0.6.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.
package/README.md CHANGED
@@ -15,18 +15,20 @@ Current CLI behavior:
15
15
  - Supports `--dry-run` to show the scaffold plan without writing files.
16
16
  - Creates a small starter scaffold when the target folder is missing or empty.
17
17
 
18
- Interactive setup asks for setup mode, package manager, dependency install preference, git init preference, and owner bootstrap preference.
18
+ Interactive setup asks for setup mode, SQLite database path, host, port, package manager, dependency install preference, git init preference, and optional first owner bootstrap credentials. Postgres and MySQL are planned providers, but SQLite is the supported provider today.
19
19
 
20
20
  Generated starter files:
21
21
 
22
22
  - `package.json`
23
23
  - `.gitignore`
24
+ - `.env`
24
25
  - `.env.example`
25
26
  - `apiagex.config.json`
27
+ - `src/index.js`
26
28
  - `README.md`
27
29
  - `docs/README.md`
28
30
 
29
- The generated `.env.example` documents `APIAGEX_DATABASE_PATH=.apiagex/apiagex.sqlite` and `APIAGEX_UPLOADS_PATH=.apiagex/uploads` for local persistence.
31
+ The generated `.env` stores local setup values such as `APIAGEX_DATABASE_PROVIDER`, `APIAGEX_DATABASE_PATH`, `APIAGEX_UPLOADS_PATH`, `APIAGEX_SECRET`, `HOST`, and `PORT`. If owner bootstrap is enabled, `.env` also contains `APIAGEX_OWNER_EMAIL` and `APIAGEX_OWNER_PASSWORD`; remove the password after the first successful start.
30
32
 
31
33
  The generated `package.json` depends on `@apiagex/server` and exposes `npm run dev`, `npm run start`, `npm run smoke`, and `npm run build`.
32
34
 
@@ -78,18 +80,20 @@ Current CLI behavior:
78
80
  - `--dry-run` scaffold plan dikhata hai bina files likhe.
79
81
  - Target folder missing ya empty ho to small starter scaffold create hota hai.
80
82
 
81
- Interactive setup setup mode, package manager, dependency install preference, git init preference, aur owner bootstrap preference puchta hai.
83
+ Interactive setup setup mode, SQLite database path, host, port, package manager, dependency install preference, git init preference, aur optional first owner bootstrap credentials puchta hai. Postgres aur MySQL planned providers hain, lekin aaj SQLite supported provider hai.
82
84
 
83
85
  Generated starter files:
84
86
 
85
87
  - `package.json`
86
88
  - `.gitignore`
89
+ - `.env`
87
90
  - `.env.example`
88
91
  - `apiagex.config.json`
92
+ - `src/index.js`
89
93
  - `README.md`
90
94
  - `docs/README.md`
91
95
 
92
- Generated `.env.example` local persistence ke liye `APIAGEX_DATABASE_PATH=.apiagex/apiagex.sqlite` aur `APIAGEX_UPLOADS_PATH=.apiagex/uploads` document karta hai.
96
+ Generated `.env` local setup values store karta hai, jaise `APIAGEX_DATABASE_PROVIDER`, `APIAGEX_DATABASE_PATH`, `APIAGEX_UPLOADS_PATH`, `APIAGEX_SECRET`, `HOST`, aur `PORT`. Owner bootstrap enable ho to `.env` me `APIAGEX_OWNER_EMAIL` aur `APIAGEX_OWNER_PASSWORD` bhi hota hai; first successful start ke baad password hata do.
93
97
 
94
98
  Generated `package.json` `@apiagex/server` par depend karta hai aur `npm run dev`, `npm run start`, `npm run smoke`, aur `npm run build` expose karta hai.
95
99
 
@@ -1 +1 @@
1
- {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,0BAA0B,CAAC;AAEtF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG,MAAM,CA6B7D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKtE"}
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA+C,MAAM,0BAA0B,CAAC;AAExG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,GAAG,MAAM,CAiE7D;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKtE"}
package/dist/args.js CHANGED
@@ -22,6 +22,56 @@ export function parseArgs(args) {
22
22
  options.bootstrapOwner = true;
23
23
  else if (arg === "--no-owner")
24
24
  options.bootstrapOwner = false;
25
+ else if (arg === "--database") {
26
+ const value = args[index + 1];
27
+ if (!isDatabaseProvider(value))
28
+ return "Use --database sqlite. Postgres and MySQL are planned but not available yet.";
29
+ options.databaseProvider = value;
30
+ index += 1;
31
+ }
32
+ else if (arg === "--database-path") {
33
+ const value = args[index + 1];
34
+ if (!value)
35
+ return "Use --database-path with a SQLite database path.";
36
+ options.databasePath = value;
37
+ index += 1;
38
+ }
39
+ else if (arg === "--host") {
40
+ const value = args[index + 1];
41
+ if (!value)
42
+ return "Use --host with a host value.";
43
+ options.host = value;
44
+ index += 1;
45
+ }
46
+ else if (arg === "--port") {
47
+ const value = args[index + 1];
48
+ if (!value || !/^\d+$/.test(value))
49
+ return "Use --port with a numeric port.";
50
+ options.port = value;
51
+ index += 1;
52
+ }
53
+ else if (arg === "--app-secret") {
54
+ const value = args[index + 1];
55
+ if (!value)
56
+ return "Use --app-secret with a non-empty secret.";
57
+ options.appSecret = value;
58
+ index += 1;
59
+ }
60
+ else if (arg === "--owner-email") {
61
+ const value = args[index + 1];
62
+ if (!value)
63
+ return "Use --owner-email with an email address.";
64
+ options.ownerEmail = value;
65
+ index += 1;
66
+ }
67
+ else if (arg === "--owner-password") {
68
+ const value = args[index + 1];
69
+ if (!value)
70
+ return "Use --owner-password with a password.";
71
+ options.ownerPassword = value;
72
+ index += 1;
73
+ options.bootstrapOwner = true;
74
+ }
25
75
  else if (arg === "--package-manager") {
26
76
  const value = args[index + 1];
27
77
  if (!isPackageManager(value))
@@ -57,6 +107,9 @@ export function validateProjectSlug(target) {
57
107
  function isPackageManager(value) {
58
108
  return value === "npm" || value === "pnpm" || value === "yarn";
59
109
  }
110
+ function isDatabaseProvider(value) {
111
+ return value === "sqlite";
112
+ }
60
113
  function isSetupMode(value) {
61
114
  return value === "quickstart" || value === "custom";
62
115
  }
@@ -1,13 +1,21 @@
1
1
  import type { Readable, Writable } from "node:stream";
2
2
  export type PackageManager = "npm" | "pnpm" | "yarn";
3
3
  export type SetupMode = "custom" | "quickstart";
4
+ export type DatabaseProvider = "sqlite";
4
5
  export type CliOptions = {
6
+ appSecret?: string;
5
7
  bootstrapOwner?: boolean;
8
+ databasePath?: string;
9
+ databaseProvider?: DatabaseProvider;
6
10
  dryRun: boolean;
7
11
  help: boolean;
12
+ host?: string;
8
13
  initGit?: boolean;
9
14
  installDependencies?: boolean;
15
+ ownerEmail?: string;
16
+ ownerPassword?: string;
10
17
  packageManager?: PackageManager;
18
+ port?: string;
11
19
  setupMode?: SetupMode;
12
20
  target?: string;
13
21
  version: boolean;
@@ -30,10 +38,17 @@ export type RunCliOptions = {
30
38
  stdout?: Writable;
31
39
  };
32
40
  export type ScaffoldAnswers = {
41
+ appSecret: string;
33
42
  bootstrapOwner: boolean;
43
+ databasePath: string;
44
+ databaseProvider: DatabaseProvider;
45
+ host: string;
34
46
  initGit: boolean;
35
47
  installDependencies: boolean;
48
+ ownerEmail?: string;
49
+ ownerPassword?: string;
36
50
  packageManager: PackageManager;
51
+ port: string;
37
52
  setupMode: SetupMode;
38
53
  target: string;
39
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"create-apiagex.type.d.ts","sourceRoot":"","sources":["../src/create-apiagex.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEhD,MAAM,MAAM,UAAU,GAAG;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAErE,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
1
+ {"version":3,"file":"create-apiagex.type.d.ts","sourceRoot":"","sources":["../src/create-apiagex.type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;AAChD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;AAExC,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAErE,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,cAAc,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC"}
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
7
7
  import { parseArgs, validateProjectSlug } from "./args.js";
8
8
  import { resolveAnswers } from "./prompts.js";
9
9
  import { createScaffoldFiles, renderPlan } from "./scaffold.js";
10
- const packageVersion = "0.6.2";
10
+ const packageVersion = "0.6.3";
11
11
  export async function runCli(args, cwd = process.cwd(), io = {}) {
12
12
  const parsed = parseArgs(args);
13
13
  if (typeof parsed === "string")
@@ -53,10 +53,17 @@ Usage:
53
53
 
54
54
  Options:
55
55
  --setup quickstart|custom Choose starter setup mode.
56
+ --database sqlite Choose database provider. Postgres and MySQL are planned.
57
+ --database-path <path> Set the SQLite database path.
58
+ --host <host> Set the server host.
59
+ --port <port> Set the server port.
60
+ --app-secret <secret> Set APIAGEX_SECRET instead of generating one.
61
+ --owner-email <email> Set first owner email when owner bootstrap is enabled.
62
+ --owner-password <password> Set first owner password and enable owner bootstrap.
56
63
  --package-manager npm|pnpm|yarn
57
64
  --install, --no-install Record whether dependencies should be installed after scaffold.
58
65
  --git, --no-git Record whether git should be initialized after scaffold.
59
- --owner, --no-owner Record whether owner setup should happen now or in Admin UI.
66
+ --owner, --no-owner Configure first owner bootstrap on first server start.
60
67
  --dry-run Print the scaffold plan without writing files.
61
68
  -y, --yes Use defaults for missing options.
62
69
  -h, --help Show help.
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EAEV,aAAa,EACb,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAE,aAAkB,GAAG,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC,CAenH"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,UAAU,EAEV,aAAa,EACb,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC,wBAAsB,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,GAAE,aAAkB,GAAG,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC,CAkCnH"}
package/dist/prompts.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { createInterface } from "node:readline/promises";
2
+ import { randomBytes } from "node:crypto";
2
3
  export async function resolveAnswers(options, io = {}) {
3
4
  const prompt = io.prompt ?? nodePrompt(io);
4
5
  const canAsk = Boolean((io.interactive || io.prompt) && !options.yes);
@@ -6,12 +7,31 @@ export async function resolveAnswers(options, io = {}) {
6
7
  if (!target)
7
8
  return "Target folder is required. Run create-apiagex --help for usage.";
8
9
  const setupMode = options.setupMode ?? await choiceAnswer(prompt, canAsk, "Setup mode", "quickstart", ["quickstart", "custom"]);
10
+ const databaseProvider = options.databaseProvider ?? "sqlite";
11
+ const databasePath = options.databasePath ?? await setupAnswer(prompt, canAsk, setupMode, "SQLite database path", ".apiagex/apiagex.sqlite");
12
+ const host = options.host ?? await setupAnswer(prompt, canAsk, setupMode, "Server host", "127.0.0.1");
13
+ const port = options.port ?? await setupAnswer(prompt, canAsk, setupMode, "Server port", "4000");
14
+ const appSecret = options.appSecret ?? generateSecret();
9
15
  const packageManager = options.packageManager ?? await choiceAnswer(prompt, canAsk, "Package manager", "npm", ["npm", "pnpm", "yarn"]);
16
+ const bootstrapOwner = await boolAnswer(prompt, canAsk, "Create first owner during first server start?", options.bootstrapOwner, false);
17
+ const ownerEmail = bootstrapOwner
18
+ ? options.ownerEmail ?? await setupAnswer(prompt, canAsk, setupMode, "Owner email", "owner@apiagex.local")
19
+ : undefined;
20
+ const ownerPassword = bootstrapOwner
21
+ ? options.ownerPassword ?? await setupAnswer(prompt, canAsk, setupMode, "Owner password", generatePassword())
22
+ : undefined;
10
23
  return {
11
- bootstrapOwner: await boolAnswer(prompt, canAsk, "Bootstrap owner during scaffold?", options.bootstrapOwner, false),
24
+ appSecret,
25
+ bootstrapOwner,
26
+ databasePath,
27
+ databaseProvider,
28
+ host,
12
29
  initGit: await boolAnswer(prompt, canAsk, "Initialize git repository?", options.initGit, true),
13
30
  installDependencies: await boolAnswer(prompt, canAsk, "Install dependencies after scaffold?", options.installDependencies, false),
31
+ ...(ownerEmail === undefined ? {} : { ownerEmail }),
32
+ ...(ownerPassword === undefined ? {} : { ownerPassword }),
14
33
  packageManager,
34
+ port,
15
35
  setupMode,
16
36
  target,
17
37
  };
@@ -28,10 +48,21 @@ async function choiceAnswer(prompt, canAsk, message, defaultValue, allowed) {
28
48
  const answer = await ask(prompt, `${message} (${allowed.join("/")})`, defaultValue);
29
49
  return allowed.includes(answer) ? answer : defaultValue;
30
50
  }
51
+ async function setupAnswer(prompt, canAsk, setupMode, message, defaultValue) {
52
+ if (!canAsk || setupMode !== "custom")
53
+ return defaultValue;
54
+ return ask(prompt, message, defaultValue);
55
+ }
31
56
  async function ask(prompt, message, defaultValue) {
32
57
  const answer = (await prompt({ defaultValue, message })).trim();
33
58
  return answer || defaultValue;
34
59
  }
60
+ function generateSecret() {
61
+ return randomBytes(32).toString("base64url");
62
+ }
63
+ function generatePassword() {
64
+ return `Apiagex-${randomBytes(9).toString("base64url")}1!`;
65
+ }
35
66
  function nodePrompt(io) {
36
67
  return async ({ defaultValue, message }) => {
37
68
  const input = io.stdin ?? process.stdin;
@@ -1 +1 @@
1
- {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE9E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,YAAY,EAAE,CAoD5E;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CAuB3I"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE9E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,YAAY,EAAE,CAiE5E;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,GAAG,MAAM,CA0B3I"}
package/dist/scaffold.js CHANGED
@@ -8,13 +8,13 @@ export function createScaffoldFiles(answers) {
8
8
  private: true,
9
9
  type: "module",
10
10
  scripts: {
11
- dev: "apiagex dev",
12
- start: "apiagex start",
11
+ dev: "node --env-file=.env src/index.js",
12
+ start: "node --env-file=.env src/index.js",
13
13
  build: "apiagex build",
14
14
  smoke: "apiagex smoke",
15
15
  },
16
16
  dependencies: {
17
- "@apiagex/server": "^0.6.2",
17
+ "@apiagex/server": "^0.6.3",
18
18
  },
19
19
  }, null, 2)}\n`,
20
20
  },
@@ -26,17 +26,30 @@ export function createScaffoldFiles(answers) {
26
26
  path: ".gitignore",
27
27
  content: "node_modules\n.env\ndist\n.apiagex\n",
28
28
  },
29
+ {
30
+ path: ".env",
31
+ content: envFile(answers, true),
32
+ },
29
33
  {
30
34
  path: ".env.example",
31
- content: "APIAGEX_DATABASE_PATH=.apiagex/apiagex.sqlite\nAPIAGEX_UPLOADS_PATH=.apiagex/uploads\nPORT=4000\nHOST=127.0.0.1\n",
35
+ content: envFile(answers, false),
32
36
  },
33
37
  {
34
38
  path: "apiagex.config.json",
35
39
  content: `${JSON.stringify({
36
- database: { provider: "sqlite", url: "file:.apiagex/apiagex.sqlite" },
37
- project: { packageManager: answers.packageManager, setupMode: answers.setupMode },
40
+ database: { provider: answers.databaseProvider, path: answers.databasePath },
41
+ project: {
42
+ appSecretEnv: "APIAGEX_SECRET",
43
+ packageManager: answers.packageManager,
44
+ setupMode: answers.setupMode,
45
+ },
46
+ server: { host: answers.host, port: Number(answers.port) },
38
47
  }, null, 2)}\n`,
39
48
  },
49
+ {
50
+ path: "src/index.js",
51
+ content: serverEntryFile(),
52
+ },
40
53
  {
41
54
  path: "docs/README.md",
42
55
  content: docsReadme(),
@@ -52,10 +65,13 @@ export function renderPlan(projectName, targetDir, files, answers, dryRun) {
52
65
  "",
53
66
  "Selected setup:",
54
67
  `- Setup mode: ${answers.setupMode}`,
68
+ `- Database: ${answers.databaseProvider}`,
69
+ `- SQLite path: ${answers.databasePath}`,
70
+ `- Server: http://${answers.host}:${answers.port}`,
55
71
  `- Package manager: ${answers.packageManager}`,
56
72
  `- Install dependencies: ${answers.installDependencies ? "yes" : "no"}`,
57
73
  `- Initialize git: ${answers.initGit ? "yes" : "no"}`,
58
- `- Owner setup: ${answers.bootstrapOwner ? "create now" : "create from Admin UI"}`,
74
+ `- Owner setup: ${answers.bootstrapOwner ? "create from .env on first start" : "create from Admin UI"}`,
59
75
  "",
60
76
  "Files:",
61
77
  fileList,
@@ -86,28 +102,32 @@ ${runCommand(answers.packageManager, "dev")}
86
102
  \`\`\`
87
103
 
88
104
  Open http://127.0.0.1:4000/adminui to create the first owner. Open /doc for API docs and /readme for the readable project summary.
105
+ If .env contains APIAGEX_OWNER_EMAIL and APIAGEX_OWNER_PASSWORD, the first owner is created automatically on first server start. Remove APIAGEX_OWNER_PASSWORD from .env after the first successful start.
89
106
 
90
107
  ## Scripts
91
108
 
92
- - \`${runCommand(answers.packageManager, "dev")}\`: start the local Apiagex server.
93
- - \`${runCommand(answers.packageManager, "start")}\`: start the server for regular runtime use.
109
+ - \`${runCommand(answers.packageManager, "dev")}\`: start src/index.js with .env.
110
+ - \`${runCommand(answers.packageManager, "start")}\`: start src/index.js with .env.
94
111
  - \`${runCommand(answers.packageManager, "smoke")}\`: verify the runtime health route.
95
112
  - \`${runCommand(answers.packageManager, "build")}\`: print runtime build guidance.
96
113
 
97
114
  ## Environment
98
115
 
99
- Copy .env.example to .env if you need custom paths.
116
+ The installer creates .env for local use. Copy .env.example to .env again if you need to reset local settings.
100
117
 
118
+ - APIAGEX_DATABASE_PROVIDER: sqlite today. Postgres and MySQL are planned.
101
119
  - APIAGEX_DATABASE_PATH: SQLite database path. Default .apiagex/apiagex.sqlite.
102
120
  - APIAGEX_UPLOADS_PATH: upload folder. Default .apiagex/uploads.
121
+ - APIAGEX_SECRET: app secret generated during setup.
103
122
  - PORT: server port. Default 4000.
104
123
  - HOST: server host. Default 127.0.0.1.
124
+ - APIAGEX_OWNER_EMAIL and APIAGEX_OWNER_PASSWORD: optional first owner bootstrap values. Remove the password after first start.
105
125
 
106
126
  ## Practical flow
107
127
 
108
128
  English:
109
129
 
110
- 1. Create the first owner from /adminui.
130
+ 1. Start the server. If owner env values exist, Apiagex creates the first owner automatically; otherwise create it from /adminui.
111
131
  2. Create a schema, for example Article with a required title field.
112
132
  3. Create entries from Entries or call POST /api/content/article.
113
133
  4. Create Content Roles, save permissions, then create users or API tokens.
@@ -115,7 +135,7 @@ English:
115
135
 
116
136
  Hinglish:
117
137
 
118
- 1. /adminui se first owner create karo.
138
+ 1. Server start karo. Owner env values hain to Apiagex first owner automatic create karega; nahi hain to /adminui se create karo.
119
139
  2. Schema banao, jaise required title field ke saath Article.
120
140
  3. Entries screen se entry banao ya POST /api/content/article call karo.
121
141
  4. Content Roles banao, permissions save karo, phir users ya API tokens create karo.
@@ -144,7 +164,7 @@ Use /doc for generated API docs and /readme for the project summary.
144
164
 
145
165
  English: Open /adminui, create the first owner, then use the same page for later logins.
146
166
 
147
- Hinglish: /adminui open karo, first owner create karo, phir later login ke liye same page use karo.
167
+ Hinglish: /adminui open karo, first owner create karo ya .env owner bootstrap use karo, phir later login ke liye same page use karo.
148
168
 
149
169
  ## Generated APIs
150
170
 
@@ -167,6 +187,38 @@ Hinglish: Webhooks content change ke baad external URLs call karte hain. Realtim
167
187
  Relation docs: /doc explains relation field types, entry payloads, populate query options, Admin UI entry pickers, and common errors.
168
188
  `;
169
189
  }
190
+ function envFile(answers, includeSecrets) {
191
+ const lines = [
192
+ `APIAGEX_DATABASE_PROVIDER=${answers.databaseProvider}`,
193
+ `APIAGEX_DATABASE_PATH=${answers.databasePath}`,
194
+ "APIAGEX_UPLOADS_PATH=.apiagex/uploads",
195
+ `APIAGEX_SECRET=${includeSecrets ? answers.appSecret : "change-me"}`,
196
+ `HOST=${answers.host}`,
197
+ `PORT=${answers.port}`,
198
+ ];
199
+ if (answers.bootstrapOwner) {
200
+ lines.push(`APIAGEX_OWNER_EMAIL=${answers.ownerEmail ?? "owner@apiagex.local"}`, `APIAGEX_OWNER_PASSWORD=${includeSecrets ? answers.ownerPassword ?? "" : "change-me-after-first-start"}`);
201
+ }
202
+ else {
203
+ lines.push("# APIAGEX_OWNER_EMAIL=owner@apiagex.local", "# APIAGEX_OWNER_PASSWORD=change-me-after-first-start");
204
+ }
205
+ return `${lines.join("\n")}\n`;
206
+ }
207
+ function serverEntryFile() {
208
+ return `import { startApiagex } from "@apiagex/server";
209
+
210
+ const ownerEmail = process.env.APIAGEX_OWNER_EMAIL;
211
+ const ownerPassword = process.env.APIAGEX_OWNER_PASSWORD;
212
+
213
+ await startApiagex({
214
+ host: process.env.HOST ?? "127.0.0.1",
215
+ port: Number(process.env.PORT ?? 4000),
216
+ initialOwner: ownerEmail && ownerPassword
217
+ ? { email: ownerEmail, password: ownerPassword }
218
+ : undefined,
219
+ });
220
+ `;
221
+ }
170
222
  function installCommand(packageManager) {
171
223
  return packageManager === "yarn" ? "yarn install" : `${packageManager} install`;
172
224
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-apiagex",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Installer CLI for creating Apiagex CMS projects.",
5
5
  "type": "module",
6
6
  "license": "MIT",