fexapi 0.1.5 → 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 CHANGED
@@ -33,7 +33,7 @@ Creates:
33
33
  - `fexapi/schema.fexapi`
34
34
  - `fexapi.config.json`
35
35
  - `fexapi.config.js`
36
- - `schemas/user.yaml` and `schemas/post.yaml` (if sample schemas are enabled)
36
+ - `fexapi/schemas/user.yaml` and `fexapi/schemas/post.yaml` (if sample schemas are enabled)
37
37
 
38
38
  ### 2) Edit schema file
39
39
 
@@ -141,16 +141,16 @@ Notes:
141
141
 
142
142
  - `port` sets the default server port (CLI `--port` still has priority).
143
143
  - `routes` maps endpoint paths to generated payload settings.
144
- - `schema` maps to files under `schemas/` (for example `schema: "user"` -> `schemas/user.yaml`); unknown names fall back to a generic record.
144
+ - `schema` maps to files under `fexapi/schemas/` (for example `schema: "user"` -> `fexapi/schemas/user.yaml`); unknown names fall back to a generic record.
145
145
  - `cors: true` enables CORS headers and OPTIONS preflight handling.
146
146
  - `delay` adds response latency in milliseconds.
147
147
 
148
148
  ## Custom Schema Definitions
149
149
 
150
- You can define custom schemas in YAML files under `schemas/`.
150
+ You can define custom schemas in YAML files under `fexapi/schemas/`.
151
151
 
152
152
  ```yaml
153
- # schemas/user.yaml
153
+ # fexapi/schemas/user.yaml
154
154
  name:
155
155
  type: string
156
156
  faker: person.fullName
@@ -174,7 +174,7 @@ routes: {
174
174
  Notes:
175
175
 
176
176
  - Supported file extensions: `.yaml`, `.yml`
177
- - Schema name is taken from filename (for example `schemas/user.yaml` -> `schema: "user"`)
177
+ - Schema name is taken from filename (for example `fexapi/schemas/user.yaml` -> `schema: "user"`)
178
178
  - `faker` values map to Faker paths like `person.fullName`, `internet.email`
179
179
 
180
180
  ## Features
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,YAkDrB,CAAC"}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,SAAS,YAgErB,CAAC"}
package/dist/cli/help.js CHANGED
@@ -1,53 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.printHelp = void 0;
4
+ const ui_1 = require("./ui");
4
5
  const printHelp = () => {
5
- console.log("fexapi-cli");
6
- console.log("");
7
- console.log("Usage:");
8
- console.log(" fexapi init [--force]");
9
- console.log(" fexapi generate");
10
- console.log(" fexapi format");
11
- console.log(" fexapi dev [--watch] [--host <host>] [--port <number>] [--log]");
12
- console.log(" fexapi serve [--host <host>] [--port <number>] [--log]");
13
- console.log(" fexapi run [--host <host>] [--port <number>] [--log]");
14
- console.log(" fexapi [--host <host>] [--port <number>] [--log]");
15
- console.log(" fexapi --help");
16
- console.log("");
17
- console.log("Examples:");
18
- console.log(" fexapi init");
19
- console.log(" fexapi init --force");
20
- console.log(" fexapi generate");
21
- console.log(" fexapi format");
22
- console.log(" fexapi dev --watch");
23
- console.log(" fexapi dev --watch --log");
24
- console.log(" fexapi serve --log");
25
- console.log(" fexapi serve --host 127.0.0.1 --port 5000");
26
- console.log(" fexapi --port 4000");
27
- console.log("");
28
- console.log("Package manager usage:");
29
- console.log(" npx fexapi init");
30
- console.log(" pnpm dlx fexapi init");
31
- console.log(" yarn dlx fexapi init");
32
- console.log("");
33
- console.log("`fexapi init` creates:");
34
- console.log(" fexapi.config.json");
35
- console.log(" fexapi.config.js");
36
- console.log(" fexapi/schema.fexapi");
37
- console.log(" fexapi/schemas/*.yaml (optional, via wizard)");
38
- console.log("");
39
- console.log("Init wizard asks:");
40
- console.log(" What port? (default: 3000)");
41
- console.log(" Enable CORS? (Y/n)");
42
- console.log(" Generate sample schemas? (Y/n)");
43
- console.log("");
44
- console.log("Then run:");
45
- console.log(" # edit fexapi/schema.fexapi");
46
- console.log(" fexapi generate");
47
- console.log(" fexapi run");
48
- console.log("");
49
- console.log("Generate output:");
50
- console.log(" fexapi/generated.api.json");
51
- console.log(" fexapi/migrations/schema.json");
6
+ (0, ui_1.printBanner)();
7
+ (0, ui_1.printSpacer)();
8
+ console.log(ui_1.ui.bold("Usage"));
9
+ console.log(` ${(0, ui_1.formatCommand)("fexapi init [--force]")}`);
10
+ console.log(` ${(0, ui_1.formatCommand)("fexapi generate")}`);
11
+ console.log(` ${(0, ui_1.formatCommand)("fexapi format")}`);
12
+ console.log(` ${(0, ui_1.formatCommand)("fexapi dev [--watch] [--host <host>] [--port <number>] [--log]")}`);
13
+ console.log(` ${(0, ui_1.formatCommand)("fexapi serve [--host <host>] [--port <number>] [--log]")}`);
14
+ console.log(` ${(0, ui_1.formatCommand)("fexapi run [--host <host>] [--port <number>] [--log]")}`);
15
+ console.log(` ${(0, ui_1.formatCommand)("fexapi [--host <host>] [--port <number>] [--log]")}`);
16
+ console.log(` ${(0, ui_1.formatCommand)("fexapi --help")}`);
17
+ (0, ui_1.printSpacer)();
18
+ console.log(ui_1.ui.bold("Examples"));
19
+ console.log(` ${(0, ui_1.formatCommand)("fexapi init")}`);
20
+ console.log(` ${(0, ui_1.formatCommand)("fexapi init --force")}`);
21
+ console.log(` ${(0, ui_1.formatCommand)("fexapi generate")}`);
22
+ console.log(` ${(0, ui_1.formatCommand)("fexapi format")}`);
23
+ console.log(` ${(0, ui_1.formatCommand)("fexapi dev --watch")}`);
24
+ console.log(` ${(0, ui_1.formatCommand)("fexapi dev --watch --log")}`);
25
+ console.log(` ${(0, ui_1.formatCommand)("fexapi serve --log")}`);
26
+ console.log(` ${(0, ui_1.formatCommand)("fexapi serve --host 127.0.0.1 --port 5000")}`);
27
+ console.log(` ${(0, ui_1.formatCommand)("fexapi --port 4000")}`);
28
+ (0, ui_1.printSpacer)();
29
+ console.log(ui_1.ui.bold("Package Manager Usage"));
30
+ console.log(` ${(0, ui_1.formatCommand)("npx fexapi init")}`);
31
+ console.log(` ${(0, ui_1.formatCommand)("pnpm dlx fexapi init")}`);
32
+ console.log(` ${(0, ui_1.formatCommand)("yarn dlx fexapi init")}`);
33
+ (0, ui_1.printSpacer)();
34
+ console.log(ui_1.ui.bold("fexapi init creates"));
35
+ console.log(` ${ui_1.ui.dim("fexapi.config.json")}`);
36
+ console.log(` ${ui_1.ui.dim("fexapi.config.js")}`);
37
+ console.log(` ${ui_1.ui.dim("fexapi/schema.fexapi")}`);
38
+ console.log(` ${ui_1.ui.dim("fexapi/schemas/*.yaml (optional, via wizard)")}`);
39
+ (0, ui_1.printSpacer)();
40
+ console.log(ui_1.ui.bold("Init wizard asks"));
41
+ console.log(` ${ui_1.ui.dim("What port? (default: 3000)")}`);
42
+ console.log(` ${ui_1.ui.dim("Enable CORS? (Y/n)")}`);
43
+ console.log(` ${ui_1.ui.dim("Generate sample schemas? (Y/n)")}`);
44
+ (0, ui_1.printSpacer)();
45
+ console.log(ui_1.ui.bold("Then run"));
46
+ console.log(` ${ui_1.ui.dim("# edit fexapi/schema.fexapi")}`);
47
+ console.log(` ${(0, ui_1.formatCommand)("fexapi generate")}`);
48
+ console.log(` ${(0, ui_1.formatCommand)("fexapi run")}`);
49
+ (0, ui_1.printSpacer)();
50
+ console.log(ui_1.ui.bold("Generate output"));
51
+ console.log(` ${ui_1.ui.dim("fexapi/generated.api.json")}`);
52
+ console.log(` ${ui_1.ui.dim("fexapi/migrations/schema.json")}`);
52
53
  };
53
54
  exports.printHelp = printHelp;
@@ -0,0 +1,19 @@
1
+ export declare const ui: {
2
+ bold: (text: string) => string;
3
+ dim: (text: string) => string;
4
+ cyan: (text: string) => string;
5
+ blue: (text: string) => string;
6
+ green: (text: string) => string;
7
+ yellow: (text: string) => string;
8
+ red: (text: string) => string;
9
+ gray: (text: string) => string;
10
+ };
11
+ export declare const printBanner: () => void;
12
+ export declare const printSpacer: () => void;
13
+ export declare const logInfo: (message: string) => void;
14
+ export declare const logSuccess: (message: string) => void;
15
+ export declare const logWarn: (message: string) => void;
16
+ export declare const logError: (message: string) => void;
17
+ export declare const logStep: (message: string) => void;
18
+ export declare const formatCommand: (command: string) => string;
19
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,EAAE;iBACA,MAAM,KAAG,MAAM;gBAChB,MAAM,KAAG,MAAM;iBACd,MAAM,KAAG,MAAM;iBACf,MAAM,KAAG,MAAM;kBACd,MAAM,KAAG,MAAM;mBACd,MAAM,KAAG,MAAM;gBAClB,MAAM,KAAG,MAAM;iBACd,MAAM,KAAG,MAAM;CAC7B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAE9B,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,IAEzC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAS,MAAM,KAAG,IAE5C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,IAEzC,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,SAAS,MAAM,KAAG,IAE1C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,IAEzC,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,KAAG,MAE/C,CAAC"}
package/dist/cli/ui.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatCommand = exports.logStep = exports.logError = exports.logWarn = exports.logSuccess = exports.logInfo = exports.printSpacer = exports.printBanner = exports.ui = void 0;
4
+ const shouldUseColor = () => {
5
+ return Boolean(process.stdout.isTTY);
6
+ };
7
+ const colorEnabled = shouldUseColor();
8
+ const paint = (code, text) => {
9
+ if (!colorEnabled) {
10
+ return text;
11
+ }
12
+ return `\u001b[${code}m${text}\u001b[0m`;
13
+ };
14
+ exports.ui = {
15
+ bold: (text) => paint("1", text),
16
+ dim: (text) => paint("2", text),
17
+ cyan: (text) => paint("36", text),
18
+ blue: (text) => paint("94", text),
19
+ green: (text) => paint("32", text),
20
+ yellow: (text) => paint("33", text),
21
+ red: (text) => paint("31", text),
22
+ gray: (text) => paint("90", text),
23
+ };
24
+ const printBanner = () => {
25
+ console.log(exports.ui.bold(exports.ui.cyan("fexapi")) + exports.ui.gray(" mock api toolkit"));
26
+ };
27
+ exports.printBanner = printBanner;
28
+ const printSpacer = () => {
29
+ console.log("");
30
+ };
31
+ exports.printSpacer = printSpacer;
32
+ const logInfo = (message) => {
33
+ console.log(`${exports.ui.blue("info")} ${message}`);
34
+ };
35
+ exports.logInfo = logInfo;
36
+ const logSuccess = (message) => {
37
+ console.log(`${exports.ui.green("ok ")} ${message}`);
38
+ };
39
+ exports.logSuccess = logSuccess;
40
+ const logWarn = (message) => {
41
+ console.log(`${exports.ui.yellow("warn")} ${message}`);
42
+ };
43
+ exports.logWarn = logWarn;
44
+ const logError = (message) => {
45
+ console.error(`${exports.ui.red("err ")} ${message}`);
46
+ };
47
+ exports.logError = logError;
48
+ const logStep = (message) => {
49
+ console.log(`${exports.ui.cyan("->")} ${message}`);
50
+ };
51
+ exports.logStep = logStep;
52
+ const formatCommand = (command) => {
53
+ return exports.ui.bold(command);
54
+ };
55
+ exports.formatCommand = formatCommand;
@@ -1 +1 @@
1
- {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAgCA,eAAO,MAAM,aAAa,GAAI,2CAK3B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB,KAAG,MAsHH,CAAC"}
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,aAAa,GAAI,2CAK3B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB,KAAG,MAmHH,CAAC"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runDevCommand = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
+ const ui_1 = require("../cli/ui");
6
7
  const paths_1 = require("../project/paths");
7
8
  const serve_1 = require("./serve");
8
9
  const WATCH_DEBOUNCE_MS = 150;
@@ -27,14 +28,14 @@ const runDevCommand = ({ host, port, watchEnabled, logEnabled, }) => {
27
28
  }
28
29
  const projectRoot = (0, paths_1.resolveProjectRoot)();
29
30
  if (!projectRoot) {
30
- console.error("Could not find package.json in this directory or parent directories.");
31
+ (0, ui_1.logError)("Could not find package.json in this directory or parent directories.");
31
32
  return 1;
32
33
  }
33
34
  let currentServer = (0, serve_1.createProjectServer)({ host, port, logEnabled });
34
35
  if (!currentServer) {
35
36
  return 1;
36
37
  }
37
- console.log("Watch mode enabled. Restarting on config/schema changes...");
38
+ (0, ui_1.logInfo)("Watch mode enabled. Restarting on config/schema changes...");
38
39
  let restartTimer;
39
40
  let restartQueued = false;
40
41
  let restartInProgress = false;
@@ -47,7 +48,7 @@ const runDevCommand = ({ host, port, watchEnabled, logEnabled, }) => {
47
48
  return;
48
49
  }
49
50
  restartInProgress = true;
50
- console.log(`\n[watch] change detected (${reason})`);
51
+ (0, ui_1.logInfo)(`[watch] change detected (${reason})`);
51
52
  await new Promise((resolve) => {
52
53
  currentServer?.close(() => {
53
54
  resolve();
@@ -69,10 +70,7 @@ const runDevCommand = ({ host, port, watchEnabled, logEnabled, }) => {
69
70
  }, WATCH_DEBOUNCE_MS);
70
71
  };
71
72
  const activeWatchers = [];
72
- const watchTargets = [
73
- (0, node_path_1.join)(projectRoot, "fexapi"),
74
- projectRoot,
75
- ];
73
+ const watchTargets = [(0, node_path_1.join)(projectRoot, "fexapi"), projectRoot];
76
74
  for (const watchTarget of watchTargets) {
77
75
  if (!(0, node_fs_1.existsSync)(watchTarget)) {
78
76
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,kBAAkB,QAAO,MAyGrC,CAAC"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,kBAAkB,QAAO,MA0GrC,CAAC"}
@@ -4,12 +4,13 @@ exports.generateFromSchema = void 0;
4
4
  const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
6
  const constants_1 = require("../constants");
7
+ const ui_1 = require("../cli/ui");
7
8
  const paths_1 = require("../project/paths");
8
9
  const schema_1 = require("../schema");
9
10
  const generateFromSchema = () => {
10
11
  const projectRoot = (0, paths_1.resolveProjectRoot)();
11
12
  if (!projectRoot) {
12
- console.error("Could not find package.json in this directory or parent directories.");
13
+ (0, ui_1.logError)("Could not find package.json in this directory or parent directories.");
13
14
  return 1;
14
15
  }
15
16
  const schemaPath = (0, node_path_1.join)(projectRoot, "fexapi", "schema.fexapi");
@@ -17,16 +18,16 @@ const generateFromSchema = () => {
17
18
  const migrationsDirectoryPath = (0, node_path_1.join)(projectRoot, "fexapi", "migrations");
18
19
  const configPath = (0, node_path_1.join)(projectRoot, "fexapi.config.json");
19
20
  if (!(0, node_fs_1.existsSync)(schemaPath)) {
20
- console.error(`Schema file not found: ${schemaPath}`);
21
- console.error("Run `fexapi init` first.");
21
+ (0, ui_1.logError)(`Schema file not found: ${schemaPath}`);
22
+ (0, ui_1.logInfo)("Run `fexapi init` first.");
22
23
  return 1;
23
24
  }
24
25
  const schemaText = (0, node_fs_1.readFileSync)(schemaPath, "utf-8");
25
26
  const parsed = (0, schema_1.parseFexapiSchema)(schemaText);
26
27
  if (parsed.errors.length > 0 || !parsed.schema) {
27
- console.error("Failed to generate API from schema.fexapi");
28
+ (0, ui_1.logError)("Failed to generate API from schema.fexapi");
28
29
  for (const error of parsed.errors) {
29
- console.error(`- ${error}`);
30
+ (0, ui_1.logError)(`- ${error}`);
30
31
  }
31
32
  return 1;
32
33
  }
@@ -72,10 +73,11 @@ const generateFromSchema = () => {
72
73
  lastGeneratedAt: new Date().toISOString(),
73
74
  };
74
75
  (0, node_fs_1.writeFileSync)(configPath, `${JSON.stringify(updatedConfig, null, 2)}\n`, "utf-8");
75
- console.log(`Generated API spec at ${generatedPath}`);
76
- console.log(`Migration updated at ${migrationPath}`);
77
- console.log(`Routes generated: ${parsed.schema.routes.length}`);
78
- console.log(`Configured server port: ${parsed.schema.port}`);
76
+ (0, ui_1.logSuccess)(`Generated API spec at ${generatedPath}`);
77
+ (0, ui_1.logSuccess)(`Migration updated at ${migrationPath}`);
78
+ (0, ui_1.printSpacer)();
79
+ (0, ui_1.logInfo)(`Routes generated: ${parsed.schema.routes.length}`);
80
+ (0, ui_1.logInfo)(`Configured server port: ${parsed.schema.port}`);
79
81
  return 0;
80
82
  };
81
83
  exports.generateFromSchema = generateFromSchema;
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AA0LA,eAAO,MAAM,iBAAiB,GAAU,YAErC;IACD,KAAK,EAAE,OAAO,CAAC;CAChB,KAAG,OAAO,CAAC,MAAM,CAmJjB,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAkMA,eAAO,MAAM,iBAAiB,GAAU,YAErC;IACD,KAAK,EAAE,OAAO,CAAC;CAChB,KAAG,OAAO,CAAC,MAAM,CA0JjB,CAAC"}
@@ -6,6 +6,7 @@ const node_path_1 = require("node:path");
6
6
  const promises_1 = require("node:readline/promises");
7
7
  const node_process_1 = require("node:process");
8
8
  const constants_1 = require("../constants");
9
+ const ui_1 = require("../cli/ui");
9
10
  const detect_1 = require("../project/detect");
10
11
  const paths_1 = require("../project/paths");
11
12
  const DEFAULT_INIT_PORT = 3000;
@@ -142,7 +143,7 @@ const SAMPLE_POST_SCHEMA = [
142
143
  const initializeProject = async ({ force, }) => {
143
144
  const packageJsonPath = (0, paths_1.findClosestPackageJson)(process.cwd());
144
145
  if (!packageJsonPath) {
145
- console.error("Could not find package.json in this directory or parent directories.");
146
+ (0, ui_1.logError)("Could not find package.json in this directory or parent directories.");
146
147
  return 1;
147
148
  }
148
149
  const projectRoot = (0, node_path_1.dirname)(packageJsonPath);
@@ -204,65 +205,68 @@ const initializeProject = async ({ force, }) => {
204
205
  postSchemaStatus = "exists";
205
206
  }
206
207
  }
207
- console.log(`Initialized Fexapi in ${projectRoot}`);
208
- console.log(`Detected framework: ${detectedProject.primaryFramework}`);
209
- console.log(`Detected frameworks: ${detectedProject.frameworks.join(", ")}`);
208
+ (0, ui_1.logSuccess)(`Initialized fexapi in ${projectRoot}`);
209
+ (0, ui_1.logInfo)(`Detected framework: ${detectedProject.primaryFramework}`);
210
+ (0, ui_1.logInfo)(`Detected frameworks: ${detectedProject.frameworks.join(", ")}`);
210
211
  if (detectedProject.tooling.length > 0) {
211
- console.log(`Detected tooling: ${detectedProject.tooling.join(", ")}`);
212
+ (0, ui_1.logInfo)(`Detected tooling: ${detectedProject.tooling.join(", ")}`);
212
213
  }
214
+ (0, ui_1.printSpacer)();
213
215
  if (configExists && !force) {
214
- console.log(`Exists ${configPath}`);
216
+ (0, ui_1.logWarn)(`Exists ${configPath}`);
215
217
  }
216
218
  else if (configExists && force) {
217
- console.log(`Overwritten ${configPath}`);
219
+ (0, ui_1.logSuccess)(`Overwritten ${configPath}`);
218
220
  }
219
221
  else {
220
- console.log(`Created ${configPath}`);
222
+ (0, ui_1.logSuccess)(`Created ${configPath}`);
221
223
  }
222
224
  if (schemaExists && !force) {
223
- console.log(`Exists ${schemaPath}`);
225
+ (0, ui_1.logWarn)(`Exists ${schemaPath}`);
224
226
  }
225
227
  else if (schemaExists && force) {
226
- console.log(`Overwritten ${schemaPath}`);
228
+ (0, ui_1.logSuccess)(`Overwritten ${schemaPath}`);
227
229
  }
228
230
  else {
229
- console.log(`Created ${schemaPath}`);
231
+ (0, ui_1.logSuccess)(`Created ${schemaPath}`);
230
232
  }
231
233
  if (runtimeConfigExists && !force) {
232
- console.log(`Exists ${runtimeConfigPath}`);
234
+ (0, ui_1.logWarn)(`Exists ${runtimeConfigPath}`);
233
235
  }
234
236
  else if (runtimeConfigExists && force) {
235
- console.log(`Overwritten ${runtimeConfigPath}`);
237
+ (0, ui_1.logSuccess)(`Overwritten ${runtimeConfigPath}`);
236
238
  }
237
239
  else {
238
- console.log(`Created ${runtimeConfigPath}`);
240
+ (0, ui_1.logSuccess)(`Created ${runtimeConfigPath}`);
239
241
  }
240
242
  if (wizardAnswers.generateSampleSchemas) {
241
243
  if (userSchemaStatus === "exists") {
242
- console.log(`Exists ${userSchemaPath}`);
244
+ (0, ui_1.logWarn)(`Exists ${userSchemaPath}`);
243
245
  }
244
246
  else if (userSchemaStatus === "overwritten") {
245
- console.log(`Overwritten ${userSchemaPath}`);
247
+ (0, ui_1.logSuccess)(`Overwritten ${userSchemaPath}`);
246
248
  }
247
249
  else if (userSchemaStatus === "created") {
248
- console.log(`Created ${userSchemaPath}`);
250
+ (0, ui_1.logSuccess)(`Created ${userSchemaPath}`);
249
251
  }
250
252
  if (postSchemaStatus === "exists") {
251
- console.log(`Exists ${postSchemaPath}`);
253
+ (0, ui_1.logWarn)(`Exists ${postSchemaPath}`);
252
254
  }
253
255
  else if (postSchemaStatus === "overwritten") {
254
- console.log(`Overwritten ${postSchemaPath}`);
256
+ (0, ui_1.logSuccess)(`Overwritten ${postSchemaPath}`);
255
257
  }
256
258
  else if (postSchemaStatus === "created") {
257
- console.log(`Created ${postSchemaPath}`);
259
+ (0, ui_1.logSuccess)(`Created ${postSchemaPath}`);
258
260
  }
259
261
  }
260
262
  else {
261
- console.log("Sample schemas were skipped.");
263
+ (0, ui_1.logWarn)("Sample schemas were skipped.");
262
264
  }
263
265
  if (detectedProject.primaryFramework === "unknown") {
264
- console.log("No known framework dependency found. Update fexapi.config.json and schema.fexapi if needed.");
266
+ (0, ui_1.logWarn)("No known framework dependency found. Update fexapi.config.json and schema.fexapi if needed.");
265
267
  }
268
+ (0, ui_1.printSpacer)();
269
+ (0, ui_1.logInfo)(`Next: ${(0, ui_1.formatCommand)("fexapi generate")} then ${(0, ui_1.formatCommand)("fexapi serve")}`);
266
270
  return 0;
267
271
  };
268
272
  exports.initializeProject = initializeProject;
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAQxC,eAAO,MAAM,mBAAmB,GAAI,6BAIjC;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,KAAG,MAAM,GAAG,SA2DZ,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,6BAI1B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,KAAG,MAsBH,CAAC"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AASxC,eAAO,MAAM,mBAAmB,GAAI,6BAIjC;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,KAAG,MAAM,GAAG,SA2DZ,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,6BAI1B;IACD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,KAAG,MAsBH,CAAC"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.serveProject = exports.createProjectServer = void 0;
4
+ const ui_1 = require("../cli/ui");
4
5
  const constants_1 = require("../constants");
5
6
  const generated_spec_1 = require("../config/generated-spec");
6
7
  const runtime_config_1 = require("../config/runtime-config");
@@ -10,7 +11,7 @@ const server_1 = require("../server");
10
11
  const createProjectServer = ({ host, port, logEnabled = false, }) => {
11
12
  const projectRoot = (0, paths_1.resolveProjectRoot)();
12
13
  if (!projectRoot) {
13
- console.error("Could not find package.json in this directory or parent directories.");
14
+ (0, ui_1.logError)("Could not find package.json in this directory or parent directories.");
14
15
  return undefined;
15
16
  }
16
17
  const runtimeConfig = projectRoot
@@ -24,18 +25,18 @@ const createProjectServer = ({ host, port, logEnabled = false, }) => {
24
25
  : undefined;
25
26
  const effectivePort = port ?? runtimeConfig?.port ?? generatedSpec?.port ?? 4000;
26
27
  if (runtimeConfig?.routes && Object.keys(runtimeConfig.routes).length > 0) {
27
- console.log(`Using routes from fexapi.config.js (${Object.keys(runtimeConfig.routes).length})`);
28
+ (0, ui_1.logInfo)(`Using routes from fexapi.config.js (${Object.keys(runtimeConfig.routes).length})`);
28
29
  }
29
30
  if (Object.keys(schemaDefinitions).length > 0) {
30
- console.log(`Loaded custom schemas from /schemas (${Object.keys(schemaDefinitions).length})`);
31
+ (0, ui_1.logInfo)(`Loaded custom schemas from fexapi/schemas (${Object.keys(schemaDefinitions).length})`);
31
32
  }
32
33
  if (generatedSpec &&
33
34
  !(runtimeConfig?.routes && Object.keys(runtimeConfig.routes).length > 0)) {
34
- console.log(`Using generated schema routes (${generatedSpec.routes.length}) from ${constants_1.GENERATED_SPEC_RELATIVE_PATH}`);
35
+ (0, ui_1.logInfo)(`Using generated schema routes (${generatedSpec.routes.length}) from ${constants_1.GENERATED_SPEC_RELATIVE_PATH}`);
35
36
  }
36
37
  else if (!runtimeConfig?.routes ||
37
38
  Object.keys(runtimeConfig.routes).length === 0) {
38
- console.log("No generated schema found. Run `fexapi generate` to serve schema-defined endpoints.");
39
+ (0, ui_1.logWarn)("No generated schema found. Run `fexapi generate` to serve schema-defined endpoints.");
39
40
  }
40
41
  return (0, server_1.startServer)({
41
42
  host,
@@ -55,7 +56,7 @@ const serveProject = ({ host, port, logEnabled, }) => {
55
56
  const shutdown = () => {
56
57
  server.close((error) => {
57
58
  if (error) {
58
- console.error("Error while shutting down server", error);
59
+ (0, ui_1.logError)(`Error while shutting down server: ${String(error)}`);
59
60
  process.exit(1);
60
61
  }
61
62
  process.exit(0);
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const args_1 = require("./cli/args");
5
5
  const dev_1 = require("./commands/dev");
6
6
  const help_1 = require("./cli/help");
7
+ const ui_1 = require("./cli/ui");
7
8
  const format_1 = require("./commands/format");
8
9
  const generate_1 = require("./commands/generate");
9
10
  const init_1 = require("./commands/init");
@@ -13,61 +14,69 @@ const [firstArg, ...restArgs] = args;
13
14
  const main = async () => {
14
15
  if (firstArg === "init") {
15
16
  if (restArgs.includes("--help") || restArgs.includes("-h")) {
16
- console.log("Usage: fexapi init [--force]");
17
+ (0, ui_1.printBanner)();
18
+ (0, ui_1.printSpacer)();
19
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi init [--force]")}`);
17
20
  console.log("Runs an interactive setup wizard and creates fexapi config/schema files.");
18
21
  console.log("Use --force to overwrite existing files.");
19
22
  process.exit(0);
20
23
  }
21
24
  const initOptions = (0, args_1.parseInitOptions)(restArgs);
22
25
  if ("error" in initOptions) {
23
- console.error(initOptions.error);
24
- console.log("");
25
- console.log("Usage: fexapi init [--force]");
26
+ (0, ui_1.logError)(initOptions.error);
27
+ (0, ui_1.printSpacer)();
28
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi init [--force]")}`);
26
29
  process.exit(1);
27
30
  }
28
31
  process.exit(await (0, init_1.initializeProject)({ force: initOptions.force }));
29
32
  }
30
33
  else if (firstArg === "generate") {
31
34
  if (restArgs.includes("--help") || restArgs.includes("-h")) {
32
- console.log("Usage: fexapi generate");
35
+ (0, ui_1.printBanner)();
36
+ (0, ui_1.printSpacer)();
37
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi generate")}`);
33
38
  console.log("Reads fexapi/schema.fexapi and updates generated API artifacts + migration.");
34
39
  process.exit(0);
35
40
  }
36
41
  const generateOptions = (0, args_1.parseGenerateOptions)(restArgs);
37
42
  if (generateOptions.error) {
38
- console.error(generateOptions.error);
39
- console.log("");
40
- console.log("Usage: fexapi generate");
43
+ (0, ui_1.logError)(generateOptions.error);
44
+ (0, ui_1.printSpacer)();
45
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi generate")}`);
41
46
  process.exit(1);
42
47
  }
43
48
  process.exit((0, generate_1.generateFromSchema)());
44
49
  }
45
50
  else if (firstArg === "format") {
46
51
  if (restArgs.includes("--help") || restArgs.includes("-h")) {
47
- console.log("Usage: fexapi format");
52
+ (0, ui_1.printBanner)();
53
+ (0, ui_1.printSpacer)();
54
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi format")}`);
48
55
  console.log("Reformats fexapi/schema.fexapi to use readable multi-line field formatting.");
49
56
  process.exit(0);
50
57
  }
51
58
  const formatOptions = (0, args_1.parseFormatOptions)(restArgs);
52
59
  if (formatOptions.error) {
53
- console.error(formatOptions.error);
54
- console.log("");
55
- console.log("Usage: fexapi format");
60
+ (0, ui_1.logError)(formatOptions.error);
61
+ (0, ui_1.printSpacer)();
62
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi format")}`);
56
63
  process.exit(1);
57
64
  }
58
65
  process.exit((0, format_1.formatSchema)());
59
66
  }
60
67
  else if (firstArg === "dev") {
61
68
  if (restArgs.includes("--help") || restArgs.includes("-h")) {
62
- console.log("Usage: fexapi dev [--watch] [--host <host>] [--port <number>] [--log]");
69
+ (0, ui_1.printBanner)();
70
+ (0, ui_1.printSpacer)();
71
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi dev [--watch] [--host <host>] [--port <number>] [--log]")}`);
63
72
  console.log("Starts development server and optionally auto-reloads when config/schema files change.");
64
73
  process.exit(0);
65
74
  }
66
75
  const devOptions = (0, args_1.parseDevOptions)(restArgs);
67
76
  if ("error" in devOptions) {
68
- console.error(devOptions.error);
69
- console.log("");
70
- console.log("Usage: fexapi dev [--watch] [--host <host>] [--port <number>] [--log]");
77
+ (0, ui_1.logError)(devOptions.error);
78
+ (0, ui_1.printSpacer)();
79
+ (0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi dev [--watch] [--host <host>] [--port <number>] [--log]")}`);
71
80
  process.exit(1);
72
81
  }
73
82
  const exitCode = (0, dev_1.runDevCommand)(devOptions);
@@ -86,8 +95,8 @@ const main = async () => {
86
95
  }
87
96
  const options = (0, args_1.parseServeOptions)(serveArgs);
88
97
  if ("error" in options) {
89
- console.error(options.error);
90
- console.log("");
98
+ (0, ui_1.logError)(options.error);
99
+ (0, ui_1.printSpacer)();
91
100
  (0, help_1.printHelp)();
92
101
  process.exit(1);
93
102
  }
@@ -101,14 +110,14 @@ const main = async () => {
101
110
  process.exit(0);
102
111
  }
103
112
  else {
104
- console.error(`Unknown command: ${firstArg}`);
105
- console.log("");
113
+ (0, ui_1.logError)(`Unknown command: ${firstArg}`);
114
+ (0, ui_1.printSpacer)();
106
115
  (0, help_1.printHelp)();
107
116
  process.exit(1);
108
117
  }
109
118
  };
110
119
  void main().catch((error) => {
111
120
  const message = error instanceof Error ? error.message : String(error);
112
- console.error(`Unexpected error: ${message}`);
121
+ (0, ui_1.logError)(`Unexpected error: ${message}`);
113
122
  process.exit(1);
114
123
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EAExB,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,iBAAiB,CAAC,EAAE,uBAAuB,CAAC;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,CAAC;AAyLF,eAAO,MAAM,WAAW,GAAI,0EAOzB,aAAkB,wFAuIpB,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAe,WAAW,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EAExB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,iBAAiB,CAAC,EAAE,uBAAuB,CAAC;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,CAAC;AAgMF,eAAO,MAAM,WAAW,GAAI,0EAOzB,aAAkB,wFAwJpB,CAAC"}
package/dist/server.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.startServer = void 0;
4
4
  const faker_1 = require("@faker-js/faker");
5
5
  const node_http_1 = require("node:http");
6
+ const ui_1 = require("./cli/ui");
6
7
  const DEFAULT_HOST = "127.0.0.1";
7
8
  const DEFAULT_PORT = 4000;
8
9
  const sendJson = (response, statusCode, payload, options) => {
@@ -132,16 +133,20 @@ const createRecordFromSchemaName = (schemaName, schemaDefinitions) => {
132
133
  createdAt: faker_1.faker.date.recent({ days: 7 }).toISOString(),
133
134
  };
134
135
  };
135
- const getCountFromUrl = (urlText, fallback = 5) => {
136
+ const getCountOverrideFromUrl = (urlText) => {
136
137
  if (!urlText) {
137
- return fallback;
138
+ return undefined;
138
139
  }
139
140
  const url = new URL(urlText, "http://localhost");
140
- const rawCount = Number(url.searchParams.get("count") ?? fallback);
141
- if (!Number.isFinite(rawCount)) {
142
- return fallback;
141
+ const rawCount = url.searchParams.get("count");
142
+ if (rawCount === null) {
143
+ return undefined;
143
144
  }
144
- return Math.min(Math.max(Math.floor(rawCount), 1), 50);
145
+ const parsedCount = Number(rawCount);
146
+ if (!Number.isFinite(parsedCount)) {
147
+ return undefined;
148
+ }
149
+ return Math.min(Math.max(Math.floor(parsedCount), 1), 50);
145
150
  };
146
151
  const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtimeConfig, schemaDefinitions = {}, logRequests = false, } = {}) => {
147
152
  const corsEnabled = runtimeConfig?.cors ?? false;
@@ -162,7 +167,19 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
162
167
  const method = request.method ?? "UNKNOWN";
163
168
  const durationMs = Date.now() - requestStartedAt;
164
169
  const statusCode = response.statusCode;
165
- console.log(`[${method}] ${pathname} ${statusCode} (${durationMs}ms)`);
170
+ const statusLabel = statusCode >= 500
171
+ ? ui_1.ui.red(String(statusCode))
172
+ : statusCode >= 400
173
+ ? ui_1.ui.yellow(String(statusCode))
174
+ : ui_1.ui.green(String(statusCode));
175
+ const methodLabel = method === "GET"
176
+ ? ui_1.ui.cyan(method)
177
+ : method === "POST"
178
+ ? ui_1.ui.green(method)
179
+ : method === "DELETE"
180
+ ? ui_1.ui.red(method)
181
+ : ui_1.ui.blue(method);
182
+ console.log(`${ui_1.ui.gray("req")} ${methodLabel} ${pathname} ${statusLabel} ${ui_1.ui.dim(`(${durationMs}ms)`)}`);
166
183
  });
167
184
  }
168
185
  if (corsEnabled && request.method === "OPTIONS") {
@@ -177,9 +194,10 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
177
194
  if (request.method === "GET") {
178
195
  const configuredRoute = configuredRoutes[pathname];
179
196
  if (configuredRoute) {
197
+ const count = getCountOverrideFromUrl(request.url) ?? configuredRoute.count;
180
198
  const payloadKey = toCollectionKey(pathname);
181
199
  sendJson(response, 200, {
182
- [payloadKey]: Array.from({ length: configuredRoute.count }, () => createRecordFromSchemaName(configuredRoute.schema, schemaDefinitions)),
200
+ [payloadKey]: Array.from({ length: count }, () => createRecordFromSchemaName(configuredRoute.schema, schemaDefinitions)),
183
201
  }, { cors: corsEnabled, delay: responseDelay });
184
202
  return;
185
203
  }
@@ -189,7 +207,7 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
189
207
  if (matchedRoute) {
190
208
  const method = request.method ?? "GET";
191
209
  if (method === "GET") {
192
- const count = getCountFromUrl(request.url, 5);
210
+ const count = getCountOverrideFromUrl(request.url) ?? 5;
193
211
  const payloadKey = toCollectionKey(matchedRoute.path);
194
212
  sendJson(response, 200, {
195
213
  [payloadKey]: Array.from({ length: count }, () => createRecordFromRoute(matchedRoute)),
@@ -210,8 +228,7 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
210
228
  requestBody = JSON.parse(raw);
211
229
  }
212
230
  }
213
- catch {
214
- }
231
+ catch { }
215
232
  const generatedRecord = createRecordFromRoute(matchedRoute);
216
233
  const merged = { ...generatedRecord, ...requestBody };
217
234
  const statusCode = method === "POST" ? 201 : 200;
@@ -229,7 +246,7 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
229
246
  }, { cors: corsEnabled, delay: responseDelay });
230
247
  });
231
248
  server.listen(port, host, () => {
232
- console.log(`Mock API running at http://${host}:${port}`);
249
+ console.log(`${ui_1.ui.green("ready")} Mock API running at ${ui_1.ui.bold(`http://${host}:${port}`)}`);
233
250
  });
234
251
  return server;
235
252
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fexapi",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Mock API generation CLI tool for local development and testing",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",