fexapi 0.1.0 → 0.1.2

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.
Files changed (50) hide show
  1. package/README.md +142 -1
  2. package/dist/cli/args.d.ts +24 -0
  3. package/dist/cli/args.d.ts.map +1 -0
  4. package/dist/cli/args.js +98 -0
  5. package/dist/cli/help.d.ts +2 -0
  6. package/dist/cli/help.d.ts.map +1 -0
  7. package/dist/cli/help.js +51 -0
  8. package/dist/commands/dev.d.ts +7 -0
  9. package/dist/commands/dev.d.ts.map +1 -0
  10. package/dist/commands/dev.js +114 -0
  11. package/dist/commands/generate.d.ts +2 -0
  12. package/dist/commands/generate.d.ts.map +1 -0
  13. package/dist/commands/generate.js +81 -0
  14. package/dist/commands/init.d.ts +4 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +250 -0
  17. package/dist/commands/serve.d.ts +12 -0
  18. package/dist/commands/serve.d.ts.map +1 -0
  19. package/dist/commands/serve.js +68 -0
  20. package/dist/config/generated-spec.d.ts +3 -0
  21. package/dist/config/generated-spec.d.ts.map +1 -0
  22. package/dist/config/generated-spec.js +26 -0
  23. package/dist/config/runtime-config.d.ts +3 -0
  24. package/dist/config/runtime-config.d.ts.map +1 -0
  25. package/dist/config/runtime-config.js +97 -0
  26. package/dist/config/schema-definitions.d.ts +3 -0
  27. package/dist/config/schema-definitions.d.ts.map +1 -0
  28. package/dist/config/schema-definitions.js +90 -0
  29. package/dist/constants.d.ts +2 -0
  30. package/dist/constants.d.ts.map +1 -0
  31. package/dist/constants.js +4 -0
  32. package/dist/index.js +74 -411
  33. package/dist/project/detect.d.ts +4 -0
  34. package/dist/project/detect.d.ts.map +1 -0
  35. package/dist/project/detect.js +113 -0
  36. package/dist/project/paths.d.ts +3 -0
  37. package/dist/project/paths.d.ts.map +1 -0
  38. package/dist/project/paths.js +28 -0
  39. package/dist/schema.d.ts.map +1 -1
  40. package/dist/schema.js +4 -6
  41. package/dist/server.d.ts +5 -1
  42. package/dist/server.d.ts.map +1 -1
  43. package/dist/server.js +123 -43
  44. package/dist/types/config.d.ts +20 -0
  45. package/dist/types/config.d.ts.map +1 -0
  46. package/dist/types/config.js +2 -0
  47. package/dist/types/project.d.ts +7 -0
  48. package/dist/types/project.d.ts.map +1 -0
  49. package/dist/types/project.js +2 -0
  50. package/package.json +56 -51
package/README.md CHANGED
@@ -3,15 +3,156 @@
3
3
  Frontend Experience API - Mock API generation CLI tool for local development and testing.
4
4
 
5
5
  ## Installation
6
+
6
7
  ```bash
7
8
  npm install -g fexapi
8
9
  ```
9
10
 
10
11
  ## Usage
12
+
11
13
  ```bash
12
14
  fexapi [options]
13
15
  ```
14
16
 
17
+ ## Prisma-like Flow (Dynamic)
18
+
19
+ ### 1) Initialize
20
+
21
+ ```bash
22
+ pnpm dlx fexapi init
23
+ ```
24
+
25
+ `fexapi init` runs an interactive setup wizard and asks:
26
+
27
+ - What port? (default: 3000)
28
+ - Enable CORS? (Y/n)
29
+ - Generate sample schemas? (Y/n)
30
+
31
+ Creates:
32
+
33
+ - `fexapi/schema.fexapi`
34
+ - `fexapi.config.json`
35
+ - `fexapi.config.js`
36
+ - `schemas/user.yaml` and `schemas/post.yaml` (if sample schemas are enabled)
37
+
38
+ ### 2) Edit schema file
39
+
40
+ `fexapi/schema.fexapi` uses a simple DSL with only `:` and `,` (no semicolons):
41
+
42
+ ```txt
43
+ # Server
44
+ port: 4100
45
+
46
+ # Routes
47
+ GET /users: id:uuid,name:name,email:email,age:number,phone:phone,pic:url,courseName:string
48
+ GET /courses: id:uuid,courseName:string,mentor:name
49
+ ```
50
+
51
+ ### 3) Generate artifacts (updates migration)
52
+
53
+ ```bash
54
+ npx fexapi generate
55
+ ```
56
+
57
+ Generates:
58
+
59
+ - `fexapi/generated.api.json`
60
+ - `fexapi/migrations/schema.json`
61
+
62
+ ### 4) Start server
63
+
64
+ ```bash
65
+ npx fexapi run
66
+ # or
67
+ npx fexapi serve
68
+ # request/response logging
69
+ npx fexapi serve --log
70
+ # or dev watch mode (nodemon-like)
71
+ npx fexapi dev --watch
72
+ # watch mode + request logs
73
+ npx fexapi dev --watch --log
74
+ # or (inside local workspace package)
75
+ npm run serve
76
+ ```
77
+
78
+ Server port is read from `schema.fexapi` unless overridden by CLI `--port`.
79
+
80
+ `fexapi dev --watch` auto-reloads when these files change:
81
+
82
+ - `fexapi/schema.fexapi`
83
+ - `fexapi/generated.api.json`
84
+ - `fexapi.config.js`
85
+ - `fexapi.config.json`
86
+ - `schemas/*.yaml`
87
+
88
+ `fexapi serve --log` prints request logs like:
89
+
90
+ - `[GET] /users/1 → 200 (45ms)`
91
+ - `[POST] /posts → 201 (12ms)`
92
+
93
+ ## Configuration File Support
94
+
95
+ Create a `fexapi.config.js` in your project root:
96
+
97
+ ```js
98
+ // fexapi.config.js
99
+ module.exports = {
100
+ port: 3000,
101
+ routes: {
102
+ "/users": { count: 50, schema: "user" },
103
+ "/posts": { count: 100, schema: "post" },
104
+ },
105
+ cors: true,
106
+ delay: 200,
107
+ };
108
+ ```
109
+
110
+ Then run:
111
+
112
+ ```bash
113
+ fexapi serve
114
+ ```
115
+
116
+ Notes:
117
+
118
+ - `port` sets the default server port (CLI `--port` still has priority).
119
+ - `routes` maps endpoint paths to generated payload settings.
120
+ - `schema` maps to files under `schemas/` (for example `schema: "user"` -> `schemas/user.yaml`); unknown names fall back to a generic record.
121
+ - `cors: true` enables CORS headers and OPTIONS preflight handling.
122
+ - `delay` adds response latency in milliseconds.
123
+
124
+ ## Custom Schema Definitions
125
+
126
+ You can define custom schemas in YAML files under `schemas/`.
127
+
128
+ ```yaml
129
+ # schemas/user.yaml
130
+ name:
131
+ type: string
132
+ faker: person.fullName
133
+ email:
134
+ type: string
135
+ faker: internet.email
136
+ age:
137
+ type: number
138
+ min: 18
139
+ max: 80
140
+ ```
141
+
142
+ Then reference it in `fexapi.config.js`:
143
+
144
+ ```js
145
+ routes: {
146
+ "/users": { count: 50, schema: "user" }
147
+ }
148
+ ```
149
+
150
+ Notes:
151
+
152
+ - Supported file extensions: `.yaml`, `.yml`
153
+ - Schema name is taken from filename (for example `schemas/user.yaml` -> `schema: "user"`)
154
+ - `faker` values map to Faker paths like `person.fullName`, `internet.email`
155
+
15
156
  ## Features
16
157
 
17
158
  - Schema-based mock API generation
@@ -21,4 +162,4 @@ fexapi [options]
21
162
 
22
163
  ## License
23
164
 
24
- MIT
165
+ MIT
@@ -0,0 +1,24 @@
1
+ export declare const parseInitOptions: (initArgs: string[]) => {
2
+ force: boolean;
3
+ } | {
4
+ error: string;
5
+ };
6
+ export declare const parseGenerateOptions: (generateArgs: string[]) => {
7
+ error?: string;
8
+ };
9
+ export declare const parseServeOptions: (serveArgs: string[]) => {
10
+ host: string;
11
+ port?: number;
12
+ logEnabled: boolean;
13
+ } | {
14
+ error: string;
15
+ };
16
+ export declare const parseDevOptions: (devArgs: string[]) => {
17
+ host: string;
18
+ port?: number;
19
+ watchEnabled: boolean;
20
+ logEnabled: boolean;
21
+ } | {
22
+ error: string;
23
+ };
24
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAC3B,UAAU,MAAM,EAAE,KACjB;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAWtC,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,cAAc,MAAM,EAAE,KACrB;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAQlB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EAAE,KAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAkDxE,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EAAE,KAEf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,GAC3E;IAAE,KAAK,EAAE,MAAM,CAAA;CAwDlB,CAAC"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDevOptions = exports.parseServeOptions = exports.parseGenerateOptions = exports.parseInitOptions = void 0;
4
+ const parseInitOptions = (initArgs) => {
5
+ const validFlags = new Set(["--force"]);
6
+ const invalidFlags = initArgs.filter((value) => value.startsWith("-") && !validFlags.has(value));
7
+ if (invalidFlags.length > 0) {
8
+ return { error: `Unknown option(s): ${invalidFlags.join(", ")}` };
9
+ }
10
+ return { force: initArgs.includes("--force") };
11
+ };
12
+ exports.parseInitOptions = parseInitOptions;
13
+ const parseGenerateOptions = (generateArgs) => {
14
+ const invalidFlags = generateArgs.filter((value) => value.startsWith("-"));
15
+ if (invalidFlags.length > 0) {
16
+ return { error: `Unknown option(s): ${invalidFlags.join(", ")}` };
17
+ }
18
+ return {};
19
+ };
20
+ exports.parseGenerateOptions = parseGenerateOptions;
21
+ const parseServeOptions = (serveArgs) => {
22
+ const getFlagValue = (flagName) => {
23
+ const index = serveArgs.indexOf(flagName);
24
+ if (index === -1) {
25
+ return undefined;
26
+ }
27
+ const value = serveArgs[index + 1];
28
+ if (!value || value.startsWith("-")) {
29
+ return { error: `Missing value for ${flagName}` };
30
+ }
31
+ return value;
32
+ };
33
+ const unknownFlags = serveArgs.filter((value) => value.startsWith("-") &&
34
+ value !== "--host" &&
35
+ value !== "--port" &&
36
+ value !== "--log");
37
+ if (unknownFlags.length > 0) {
38
+ return { error: `Unknown option(s): ${unknownFlags.join(", ")}` };
39
+ }
40
+ const hostValue = getFlagValue("--host");
41
+ if (hostValue && typeof hostValue !== "string") {
42
+ return hostValue;
43
+ }
44
+ const portValue = getFlagValue("--port");
45
+ if (portValue && typeof portValue !== "string") {
46
+ return portValue;
47
+ }
48
+ const host = hostValue ?? "127.0.0.1";
49
+ const port = portValue ? Number(portValue) : undefined;
50
+ if (port !== undefined &&
51
+ (!Number.isInteger(port) || port < 1 || port > 65535)) {
52
+ return { error: `Invalid port: ${portValue ?? ""}`.trim() };
53
+ }
54
+ return { host, port, logEnabled: serveArgs.includes("--log") };
55
+ };
56
+ exports.parseServeOptions = parseServeOptions;
57
+ const parseDevOptions = (devArgs) => {
58
+ const getFlagValue = (flagName) => {
59
+ const index = devArgs.indexOf(flagName);
60
+ if (index === -1) {
61
+ return undefined;
62
+ }
63
+ const value = devArgs[index + 1];
64
+ if (!value || value.startsWith("-")) {
65
+ return { error: `Missing value for ${flagName}` };
66
+ }
67
+ return value;
68
+ };
69
+ const unknownFlags = devArgs.filter((value) => value.startsWith("-") &&
70
+ value !== "--host" &&
71
+ value !== "--port" &&
72
+ value !== "--watch" &&
73
+ value !== "--log");
74
+ if (unknownFlags.length > 0) {
75
+ return { error: `Unknown option(s): ${unknownFlags.join(", ")}` };
76
+ }
77
+ const hostValue = getFlagValue("--host");
78
+ if (hostValue && typeof hostValue !== "string") {
79
+ return hostValue;
80
+ }
81
+ const portValue = getFlagValue("--port");
82
+ if (portValue && typeof portValue !== "string") {
83
+ return portValue;
84
+ }
85
+ const host = hostValue ?? "127.0.0.1";
86
+ const port = portValue ? Number(portValue) : undefined;
87
+ if (port !== undefined &&
88
+ (!Number.isInteger(port) || port < 1 || port > 65535)) {
89
+ return { error: `Invalid port: ${portValue ?? ""}`.trim() };
90
+ }
91
+ return {
92
+ host,
93
+ port,
94
+ watchEnabled: devArgs.includes("--watch"),
95
+ logEnabled: devArgs.includes("--log"),
96
+ };
97
+ };
98
+ exports.parseDevOptions = parseDevOptions;
@@ -0,0 +1,2 @@
1
+ export declare const printHelp: () => void;
2
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,YAgDrB,CAAC"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.printHelp = void 0;
4
+ 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 dev [--watch] [--host <host>] [--port <number>] [--log]");
11
+ console.log(" fexapi serve [--host <host>] [--port <number>] [--log]");
12
+ console.log(" fexapi run [--host <host>] [--port <number>] [--log]");
13
+ console.log(" fexapi [--host <host>] [--port <number>] [--log]");
14
+ console.log(" fexapi --help");
15
+ console.log("");
16
+ console.log("Examples:");
17
+ console.log(" fexapi init");
18
+ console.log(" fexapi init --force");
19
+ console.log(" fexapi generate");
20
+ console.log(" fexapi dev --watch");
21
+ console.log(" fexapi dev --watch --log");
22
+ console.log(" fexapi serve --log");
23
+ console.log(" fexapi serve --host 127.0.0.1 --port 5000");
24
+ console.log(" fexapi --port 4000");
25
+ console.log("");
26
+ console.log("Package manager usage:");
27
+ console.log(" npx fexapi init");
28
+ console.log(" pnpm dlx fexapi init");
29
+ console.log(" yarn dlx fexapi init");
30
+ console.log("");
31
+ console.log("`fexapi init` creates:");
32
+ console.log(" fexapi.config.json");
33
+ console.log(" fexapi.config.js");
34
+ console.log(" fexapi/schema.fexapi");
35
+ console.log(" schemas/*.yaml (optional, via wizard)");
36
+ console.log("");
37
+ console.log("Init wizard asks:");
38
+ console.log(" What port? (default: 3000)");
39
+ console.log(" Enable CORS? (Y/n)");
40
+ console.log(" Generate sample schemas? (Y/n)");
41
+ console.log("");
42
+ console.log("Then run:");
43
+ console.log(" # edit fexapi/schema.fexapi");
44
+ console.log(" fexapi generate");
45
+ console.log(" fexapi run");
46
+ console.log("");
47
+ console.log("Generate output:");
48
+ console.log(" fexapi/generated.api.json");
49
+ console.log(" fexapi/migrations/schema.json");
50
+ };
51
+ exports.printHelp = printHelp;
@@ -0,0 +1,7 @@
1
+ export declare const runDevCommand: ({ host, port, watchEnabled, logEnabled, }: {
2
+ host: string;
3
+ port?: number;
4
+ watchEnabled: boolean;
5
+ logEnabled: boolean;
6
+ }) => number;
7
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +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,MAuHH,CAAC"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runDevCommand = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const paths_1 = require("../project/paths");
7
+ const serve_1 = require("./serve");
8
+ const WATCH_DEBOUNCE_MS = 150;
9
+ const normalizePath = (pathValue) => {
10
+ return pathValue.replace(/\\/g, "/").toLowerCase();
11
+ };
12
+ const isWatchedPath = (projectRoot, changedPath) => {
13
+ const relativePath = normalizePath((0, node_path_1.relative)(projectRoot, changedPath));
14
+ if (relativePath === "fexapi.config.js" ||
15
+ relativePath === "fexapi.config.json") {
16
+ return true;
17
+ }
18
+ if (relativePath.startsWith("fexapi/")) {
19
+ return true;
20
+ }
21
+ return (relativePath.startsWith("schemas/") &&
22
+ (relativePath.endsWith(".yaml") || relativePath.endsWith(".yml")));
23
+ };
24
+ const runDevCommand = ({ host, port, watchEnabled, logEnabled, }) => {
25
+ if (!watchEnabled) {
26
+ return (0, serve_1.serveProject)({ host, port, logEnabled });
27
+ }
28
+ const projectRoot = (0, paths_1.resolveProjectRoot)();
29
+ if (!projectRoot) {
30
+ console.error("Could not find package.json in this directory or parent directories.");
31
+ return 1;
32
+ }
33
+ let currentServer = (0, serve_1.createProjectServer)({ host, port, logEnabled });
34
+ if (!currentServer) {
35
+ return 1;
36
+ }
37
+ console.log("Watch mode enabled. Restarting on config/schema changes...");
38
+ let restartTimer;
39
+ let restartQueued = false;
40
+ let restartInProgress = false;
41
+ const restartServer = async (reason) => {
42
+ if (!currentServer) {
43
+ return;
44
+ }
45
+ if (restartInProgress) {
46
+ restartQueued = true;
47
+ return;
48
+ }
49
+ restartInProgress = true;
50
+ console.log(`\n[watch] change detected (${reason})`);
51
+ await new Promise((resolve) => {
52
+ currentServer?.close(() => {
53
+ resolve();
54
+ });
55
+ });
56
+ currentServer = (0, serve_1.createProjectServer)({ host, port, logEnabled });
57
+ restartInProgress = false;
58
+ if (restartQueued) {
59
+ restartQueued = false;
60
+ await restartServer("queued changes");
61
+ }
62
+ };
63
+ const scheduleRestart = (reason) => {
64
+ if (restartTimer) {
65
+ clearTimeout(restartTimer);
66
+ }
67
+ restartTimer = setTimeout(() => {
68
+ void restartServer(reason);
69
+ }, WATCH_DEBOUNCE_MS);
70
+ };
71
+ const activeWatchers = [];
72
+ const watchTargets = [
73
+ (0, node_path_1.join)(projectRoot, "fexapi"),
74
+ (0, node_path_1.join)(projectRoot, "schemas"),
75
+ projectRoot,
76
+ ];
77
+ for (const watchTarget of watchTargets) {
78
+ if (!(0, node_fs_1.existsSync)(watchTarget)) {
79
+ continue;
80
+ }
81
+ const watcher = (0, node_fs_1.watch)(watchTarget, { recursive: true }, (_event, file) => {
82
+ if (!file) {
83
+ scheduleRestart("unknown file");
84
+ return;
85
+ }
86
+ const changedPath = (0, node_path_1.join)(watchTarget, file.toString());
87
+ if (isWatchedPath(projectRoot, changedPath)) {
88
+ scheduleRestart((0, node_path_1.relative)(projectRoot, changedPath));
89
+ }
90
+ });
91
+ activeWatchers.push(watcher);
92
+ }
93
+ const cleanupAndExit = async () => {
94
+ if (restartTimer) {
95
+ clearTimeout(restartTimer);
96
+ restartTimer = undefined;
97
+ }
98
+ for (const watcher of activeWatchers) {
99
+ watcher.close();
100
+ }
101
+ await new Promise((resolve) => {
102
+ currentServer?.close(() => resolve());
103
+ });
104
+ process.exit(0);
105
+ };
106
+ process.on("SIGINT", () => {
107
+ void cleanupAndExit();
108
+ });
109
+ process.on("SIGTERM", () => {
110
+ void cleanupAndExit();
111
+ });
112
+ return 0;
113
+ };
114
+ exports.runDevCommand = runDevCommand;
@@ -0,0 +1,2 @@
1
+ export declare const generateFromSchema: () => number;
2
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,kBAAkB,QAAO,MAyGrC,CAAC"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateFromSchema = void 0;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const constants_1 = require("../constants");
7
+ const paths_1 = require("../project/paths");
8
+ const schema_1 = require("../schema");
9
+ const generateFromSchema = () => {
10
+ const projectRoot = (0, paths_1.resolveProjectRoot)();
11
+ if (!projectRoot) {
12
+ console.error("Could not find package.json in this directory or parent directories.");
13
+ return 1;
14
+ }
15
+ const schemaPath = (0, node_path_1.join)(projectRoot, "fexapi", "schema.fexapi");
16
+ const generatedPath = (0, node_path_1.join)(projectRoot, "fexapi", "generated.api.json");
17
+ const migrationsDirectoryPath = (0, node_path_1.join)(projectRoot, "fexapi", "migrations");
18
+ const configPath = (0, node_path_1.join)(projectRoot, "fexapi.config.json");
19
+ if (!(0, node_fs_1.existsSync)(schemaPath)) {
20
+ console.error(`Schema file not found: ${schemaPath}`);
21
+ console.error("Run `fexapi init` first.");
22
+ return 1;
23
+ }
24
+ const schemaText = (0, node_fs_1.readFileSync)(schemaPath, "utf-8");
25
+ const parsed = (0, schema_1.parseFexapiSchema)(schemaText);
26
+ if (parsed.errors.length > 0 || !parsed.schema) {
27
+ console.error("Failed to generate API from schema.fexapi");
28
+ for (const error of parsed.errors) {
29
+ console.error(`- ${error}`);
30
+ }
31
+ return 1;
32
+ }
33
+ const generated = {
34
+ schemaVersion: 1,
35
+ generatedAt: new Date().toISOString(),
36
+ port: parsed.schema.port,
37
+ routes: parsed.schema.routes,
38
+ };
39
+ (0, node_fs_1.mkdirSync)(migrationsDirectoryPath, { recursive: true });
40
+ const existingMigrationFiles = (0, node_fs_1.readdirSync)(migrationsDirectoryPath, {
41
+ withFileTypes: true,
42
+ })
43
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
44
+ .map((entry) => (0, node_path_1.join)(migrationsDirectoryPath, entry.name));
45
+ for (const migrationFilePath of existingMigrationFiles) {
46
+ (0, node_fs_1.unlinkSync)(migrationFilePath);
47
+ }
48
+ const migrationId = new Date().toISOString().replace(/[.:]/g, "-");
49
+ const migrationPath = (0, node_path_1.join)(migrationsDirectoryPath, "schema.json");
50
+ const migration = {
51
+ migrationId,
52
+ sourceSchema: "fexapi/schema.fexapi",
53
+ createdAt: generated.generatedAt,
54
+ port: parsed.schema.port,
55
+ routes: parsed.schema.routes,
56
+ };
57
+ (0, node_fs_1.writeFileSync)(generatedPath, `${JSON.stringify(generated, null, 2)}\n`, "utf-8");
58
+ (0, node_fs_1.writeFileSync)(migrationPath, `${JSON.stringify(migration, null, 2)}\n`, "utf-8");
59
+ let existingConfig = {};
60
+ if ((0, node_fs_1.existsSync)(configPath)) {
61
+ try {
62
+ existingConfig = JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
63
+ }
64
+ catch {
65
+ existingConfig = {};
66
+ }
67
+ }
68
+ const updatedConfig = {
69
+ ...existingConfig,
70
+ schemaPath: "fexapi/schema.fexapi",
71
+ generatedPath: constants_1.GENERATED_SPEC_RELATIVE_PATH,
72
+ lastGeneratedAt: new Date().toISOString(),
73
+ };
74
+ (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}`);
79
+ return 0;
80
+ };
81
+ exports.generateFromSchema = generateFromSchema;
@@ -0,0 +1,4 @@
1
+ export declare const initializeProject: ({ force, }: {
2
+ force: boolean;
3
+ }) => Promise<number>;
4
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAwKA,eAAO,MAAM,iBAAiB,GAAU,YAErC;IACD,KAAK,EAAE,OAAO,CAAC;CAChB,KAAG,OAAO,CAAC,MAAM,CAmJjB,CAAC"}