fexapi 0.2.2 → 0.2.4
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/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +5 -4
- package/dist/cli/ui.d.ts +1 -0
- package/dist/cli/ui.d.ts.map +1 -1
- package/dist/cli/ui.js +50 -17
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +1 -2
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +0 -51
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +23 -47
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +10 -0
- package/dist/index.js +7 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +14 -12
- package/package.json +1 -1
package/dist/cli/help.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,SAAS,YAiErB,CAAC"}
|
package/dist/cli/help.js
CHANGED
|
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.printHelp = void 0;
|
|
4
4
|
const ui_1 = require("./ui");
|
|
5
5
|
const printHelp = () => {
|
|
6
|
+
const version = (0, ui_1.getCliVersion)();
|
|
6
7
|
(0, ui_1.printBanner)();
|
|
8
|
+
console.log(ui_1.ui.dim(`version ${version}`));
|
|
7
9
|
(0, ui_1.printSpacer)();
|
|
8
10
|
console.log(ui_1.ui.bold("Usage"));
|
|
9
11
|
console.log(` ${(0, ui_1.formatCommand)("fexapi init [--force]")}`);
|
|
@@ -13,6 +15,7 @@ const printHelp = () => {
|
|
|
13
15
|
console.log(` ${(0, ui_1.formatCommand)("fexapi serve [--host <host>] [--port <number>] [--log]")}`);
|
|
14
16
|
console.log(` ${(0, ui_1.formatCommand)("fexapi run [--host <host>] [--port <number>] [--log]")}`);
|
|
15
17
|
console.log(` ${(0, ui_1.formatCommand)("fexapi [--host <host>] [--port <number>] [--log]")}`);
|
|
18
|
+
console.log(` ${(0, ui_1.formatCommand)("fexapi --version")}`);
|
|
16
19
|
console.log(` ${(0, ui_1.formatCommand)("fexapi --help")}`);
|
|
17
20
|
(0, ui_1.printSpacer)();
|
|
18
21
|
console.log(ui_1.ui.bold("Examples"));
|
|
@@ -23,7 +26,7 @@ const printHelp = () => {
|
|
|
23
26
|
console.log(` ${(0, ui_1.formatCommand)("fexapi dev --watch")}`);
|
|
24
27
|
console.log(` ${(0, ui_1.formatCommand)("fexapi dev --watch --log")}`);
|
|
25
28
|
console.log(` ${(0, ui_1.formatCommand)("fexapi serve --log")}`);
|
|
26
|
-
console.log(` ${(0, ui_1.formatCommand)("fexapi serve --host
|
|
29
|
+
console.log(` ${(0, ui_1.formatCommand)("fexapi serve --host localhost --port 5000")}`);
|
|
27
30
|
console.log(` ${(0, ui_1.formatCommand)("fexapi --port 4000")}`);
|
|
28
31
|
(0, ui_1.printSpacer)();
|
|
29
32
|
console.log(ui_1.ui.bold("Package Manager Usage"));
|
|
@@ -32,13 +35,12 @@ const printHelp = () => {
|
|
|
32
35
|
console.log(` ${(0, ui_1.formatCommand)("yarn dlx fexapi init")}`);
|
|
33
36
|
(0, ui_1.printSpacer)();
|
|
34
37
|
console.log(ui_1.ui.bold("fexapi init creates"));
|
|
35
|
-
console.log(` ${ui_1.ui.dim("fexapi.config.json")}`);
|
|
36
38
|
console.log(` ${ui_1.ui.dim("fexapi.config.js")}`);
|
|
37
39
|
console.log(` ${ui_1.ui.dim("fexapi/schema.fexapi")}`);
|
|
38
40
|
console.log(` ${ui_1.ui.dim("fexapi/schemas/*.yaml (optional, via wizard)")}`);
|
|
39
41
|
(0, ui_1.printSpacer)();
|
|
40
42
|
console.log(ui_1.ui.bold("Init wizard asks"));
|
|
41
|
-
console.log(` ${ui_1.ui.dim("What port? (default:
|
|
43
|
+
console.log(` ${ui_1.ui.dim("What port? (default: 4000)")}`);
|
|
42
44
|
console.log(` ${ui_1.ui.dim("Enable CORS? (Y/n)")}`);
|
|
43
45
|
console.log(` ${ui_1.ui.dim("Generate sample schemas? (Y/n)")}`);
|
|
44
46
|
(0, ui_1.printSpacer)();
|
|
@@ -49,6 +51,5 @@ const printHelp = () => {
|
|
|
49
51
|
(0, ui_1.printSpacer)();
|
|
50
52
|
console.log(ui_1.ui.bold("Generate output"));
|
|
51
53
|
console.log(` ${ui_1.ui.dim("fexapi/generated.api.json")}`);
|
|
52
|
-
console.log(` ${ui_1.ui.dim("fexapi/migrations/schema.json")}`);
|
|
53
54
|
};
|
|
54
55
|
exports.printHelp = printHelp;
|
package/dist/cli/ui.d.ts
CHANGED
|
@@ -32,5 +32,6 @@ export declare const logWarn: (message: string) => void;
|
|
|
32
32
|
export declare const logError: (message: string) => void;
|
|
33
33
|
export declare const logStep: (message: string) => void;
|
|
34
34
|
export declare const formatCommand: (command: string) => string;
|
|
35
|
+
export declare const getCliVersion: () => string;
|
|
35
36
|
export {};
|
|
36
37
|
//# sourceMappingURL=ui.d.ts.map
|
package/dist/cli/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,EAAE;iBACA,MAAM,KAAG,MAAM;gBAChB,MAAM,KAAG,MAAM;iBACd,MAAM,KAAG,MAAM;oBACZ,MAAM,KAAG,MAAM;iBAClB,MAAM,KAAG,MAAM;kBACd,MAAM,KAAG,MAAM;mBACd,MAAM,KAAG,MAAM;gBAClB,MAAM,KAAG,MAAM;iBACd,MAAM,KAAG,MAAM;kBACd,MAAM,KAAG,MAAM;CAC9B,CAAC;AA4DF,KAAK,iBAAiB,GAAG;IACvB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,KAAG,iBA0ClD,CAAC;AAEF,eAAO,MAAM,KAAK,QAAO,MAAoB,CAAC;AAE9C,eAAO,MAAM,cAAc,GAAI,SAAS,MAAM,KAAG,MAQhD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,MAAM,EACb,MAAM,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,KAC5C,IAgEF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,IAkBhD,CAAC;AAEF,eAAO,MAAM,WAAW,QAAO,IAO9B,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;AAEF,eAAO,MAAM,aAAa,QAAO,MAyBhC,CAAC"}
|
package/dist/cli/ui.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
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.printGroupHeader = exports.printSummaryCard = exports.formatDuration = exports.nowMs = exports.startSpinner = exports.ui = void 0;
|
|
3
|
+
exports.getCliVersion = exports.formatCommand = exports.logStep = exports.logError = exports.logWarn = exports.logSuccess = exports.logInfo = exports.printSpacer = exports.printBanner = exports.printGroupHeader = exports.printSummaryCard = exports.formatDuration = exports.nowMs = exports.startSpinner = exports.ui = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
4
6
|
const shouldUseColor = () => {
|
|
5
7
|
return Boolean(process.stdout.isTTY);
|
|
6
8
|
};
|
|
@@ -26,7 +28,7 @@ exports.ui = {
|
|
|
26
28
|
white: (text) => paint("97", text),
|
|
27
29
|
};
|
|
28
30
|
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
29
|
-
const ANSI_REGEX =
|
|
31
|
+
const ANSI_REGEX = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
30
32
|
const stripAnsi = (text) => text.replace(ANSI_REGEX, "");
|
|
31
33
|
const visibleLength = (text) => stripAnsi(text).length;
|
|
32
34
|
const getTerminalWidth = () => {
|
|
@@ -120,48 +122,57 @@ const printSummaryCard = (title, rows) => {
|
|
|
120
122
|
const terminalWidth = getTerminalWidth();
|
|
121
123
|
const compactMode = terminalWidth < 64;
|
|
122
124
|
if (compactMode) {
|
|
123
|
-
console.log(exports.ui.gray(
|
|
125
|
+
console.log(exports.ui.gray(`+-- ${title} --+`));
|
|
124
126
|
for (const row of rows) {
|
|
125
|
-
console.log(`${exports.ui.dim(row.label)}
|
|
127
|
+
console.log(`${exports.ui.dim(row.label)} ${exports.ui.gray("::")} ${styleCardValue(row.value)}`);
|
|
126
128
|
}
|
|
127
|
-
console.log(exports.ui.gray("
|
|
129
|
+
console.log(exports.ui.gray("+----------------+"));
|
|
128
130
|
return;
|
|
129
131
|
}
|
|
130
132
|
const safeRows = rows.map((row) => ({
|
|
131
133
|
label: row.label,
|
|
132
134
|
value: row.value,
|
|
133
135
|
}));
|
|
134
|
-
const
|
|
136
|
+
const maxCardWidth = 96;
|
|
137
|
+
const naturalInnerWidth = Math.max(36, visibleLength(title) + 2, ...safeRows.map((row) => visibleLength(row.label) + visibleLength(row.value) + 7));
|
|
138
|
+
const cardWidth = Math.max(40, Math.min(maxCardWidth, terminalWidth - 2, naturalInnerWidth + 2));
|
|
135
139
|
const innerWidth = cardWidth - 2;
|
|
136
140
|
const labelWidth = Math.min(20, Math.max(10, ...safeRows.map((row) => visibleLength(row.label))));
|
|
137
|
-
const valueSpace = Math.max(8, innerWidth -
|
|
141
|
+
const valueSpace = Math.max(8, innerWidth - 7 - labelWidth);
|
|
142
|
+
const renderBoxLine = (content) => {
|
|
143
|
+
const remaining = Math.max(0, innerWidth - 2 - visibleLength(content));
|
|
144
|
+
return `│ ${content}${" ".repeat(remaining)} │`;
|
|
145
|
+
};
|
|
138
146
|
const topBorder = `┌${"─".repeat(innerWidth)}┐`;
|
|
139
147
|
const divider = `├${"─".repeat(innerWidth)}┤`;
|
|
140
148
|
const bottomBorder = `└${"─".repeat(innerWidth)}┘`;
|
|
141
149
|
console.log(exports.ui.gray(topBorder));
|
|
142
150
|
const renderedTitle = truncateText(title, innerWidth - 2);
|
|
143
|
-
|
|
144
|
-
console.log(`│ ${exports.ui.bold(exports.ui.cyan(renderedTitle))}${titlePadding} │`);
|
|
151
|
+
console.log(renderBoxLine(exports.ui.bold(exports.ui.cyan(renderedTitle))));
|
|
145
152
|
console.log(exports.ui.gray(divider));
|
|
146
153
|
for (const row of safeRows) {
|
|
147
154
|
const rawValue = stripAnsi(row.value);
|
|
148
155
|
const value = truncateText(rawValue, valueSpace);
|
|
149
156
|
const label = row.label.padEnd(labelWidth, " ");
|
|
150
157
|
const styledValue = styleCardValue(value);
|
|
151
|
-
|
|
152
|
-
console.log(`│ ${exports.ui.dim(label)} ${exports.ui.gray("::")} ${styledValue}${spaces}│`);
|
|
158
|
+
console.log(renderBoxLine(`${exports.ui.dim(label)} ${exports.ui.gray("::")} ${styledValue}`));
|
|
153
159
|
}
|
|
154
160
|
console.log(exports.ui.gray(bottomBorder));
|
|
155
161
|
};
|
|
156
162
|
exports.printSummaryCard = printSummaryCard;
|
|
157
163
|
const printGroupHeader = (title) => {
|
|
158
164
|
const terminalWidth = getTerminalWidth();
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
+
const compactMode = terminalWidth < 64;
|
|
166
|
+
if (compactMode) {
|
|
167
|
+
console.log(exports.ui.gray(`-- ${title} --`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const innerWidth = terminalWidth - 2;
|
|
171
|
+
const renderedTitle = truncateText(title, Math.max(1, innerWidth - 6));
|
|
172
|
+
const rawPrefix = `── ${renderedTitle} `;
|
|
173
|
+
const fill = Math.max(0, innerWidth - visibleLength(rawPrefix));
|
|
174
|
+
const prefix = `${exports.ui.gray("── ")}${exports.ui.bold(exports.ui.cyan(renderedTitle))} `;
|
|
175
|
+
console.log(`${exports.ui.gray("┌")}${prefix}${exports.ui.gray("─".repeat(fill))}${exports.ui.gray("┐")}`);
|
|
165
176
|
};
|
|
166
177
|
exports.printGroupHeader = printGroupHeader;
|
|
167
178
|
const printBanner = () => {
|
|
@@ -199,3 +210,25 @@ const formatCommand = (command) => {
|
|
|
199
210
|
return exports.ui.bold(command);
|
|
200
211
|
};
|
|
201
212
|
exports.formatCommand = formatCommand;
|
|
213
|
+
const getCliVersion = () => {
|
|
214
|
+
const packageCandidates = [
|
|
215
|
+
(0, node_path_1.join)(__dirname, "..", "..", "package.json"),
|
|
216
|
+
(0, node_path_1.join)(__dirname, "..", "package.json"),
|
|
217
|
+
];
|
|
218
|
+
for (const packagePath of packageCandidates) {
|
|
219
|
+
if (!(0, node_fs_1.existsSync)(packagePath)) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packagePath, "utf-8"));
|
|
224
|
+
if (packageJson.version) {
|
|
225
|
+
return packageJson.version;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return "unknown";
|
|
233
|
+
};
|
|
234
|
+
exports.getCliVersion = getCliVersion;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AA8BA,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"}
|
package/dist/commands/dev.js
CHANGED
|
@@ -12,8 +12,7 @@ const normalizePath = (pathValue) => {
|
|
|
12
12
|
};
|
|
13
13
|
const isWatchedPath = (projectRoot, changedPath) => {
|
|
14
14
|
const relativePath = normalizePath((0, node_path_1.relative)(projectRoot, changedPath));
|
|
15
|
-
if (relativePath === "fexapi.config.js"
|
|
16
|
-
relativePath === "fexapi.config.json") {
|
|
15
|
+
if (relativePath === "fexapi.config.js") {
|
|
17
16
|
return true;
|
|
18
17
|
}
|
|
19
18
|
if (relativePath.startsWith("fexapi/")) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,kBAAkB,QAAO,MA8GrC,CAAC"}
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.generateFromSchema = void 0;
|
|
4
4
|
const node_fs_1 = require("node:fs");
|
|
5
5
|
const node_path_1 = require("node:path");
|
|
6
|
-
const constants_1 = require("../constants");
|
|
7
6
|
const ui_1 = require("../cli/ui");
|
|
8
7
|
const paths_1 = require("../project/paths");
|
|
9
8
|
const schema_1 = require("../schema");
|
|
@@ -22,8 +21,6 @@ const generateFromSchema = () => {
|
|
|
22
21
|
}
|
|
23
22
|
const schemaPath = (0, node_path_1.join)(projectRoot, "fexapi", "schema.fexapi");
|
|
24
23
|
const generatedPath = (0, node_path_1.join)(projectRoot, "fexapi", "generated.api.json");
|
|
25
|
-
const migrationsDirectoryPath = (0, node_path_1.join)(projectRoot, "fexapi", "migrations");
|
|
26
|
-
const configPath = (0, node_path_1.join)(projectRoot, "fexapi.config.json");
|
|
27
24
|
if (!(0, node_fs_1.existsSync)(schemaPath)) {
|
|
28
25
|
(0, ui_1.logError)(`Schema file not found: ${schemaPath}`);
|
|
29
26
|
(0, ui_1.logError)("Run `fexapi init` first.");
|
|
@@ -67,52 +64,12 @@ const generateFromSchema = () => {
|
|
|
67
64
|
port: parsed.schema.port,
|
|
68
65
|
routes: parsed.schema.routes,
|
|
69
66
|
};
|
|
70
|
-
(0, node_fs_1.mkdirSync)(migrationsDirectoryPath, { recursive: true });
|
|
71
|
-
const migrationPath = (0, node_path_1.join)(migrationsDirectoryPath, "schema.json");
|
|
72
|
-
const migration = {
|
|
73
|
-
migrationId: new Date().toISOString().replace(/[.:]/g, "-"),
|
|
74
|
-
sourceSchema: "fexapi/schema.fexapi",
|
|
75
|
-
createdAt: generated.generatedAt,
|
|
76
|
-
port: parsed.schema.port,
|
|
77
|
-
routes: parsed.schema.routes,
|
|
78
|
-
};
|
|
79
67
|
let generatedStatus = "cached";
|
|
80
|
-
let migrationStatus = "cached";
|
|
81
68
|
if (schemaChanged || !(0, node_fs_1.existsSync)(generatedPath)) {
|
|
82
69
|
generationSpinner.update("Writing generated API spec");
|
|
83
70
|
(0, node_fs_1.writeFileSync)(generatedPath, `${JSON.stringify(generated, null, 2)}\n`, "utf-8");
|
|
84
71
|
generatedStatus = "changed";
|
|
85
72
|
}
|
|
86
|
-
if (schemaChanged || !(0, node_fs_1.existsSync)(migrationPath)) {
|
|
87
|
-
generationSpinner.update("Updating migration snapshot");
|
|
88
|
-
(0, node_fs_1.writeFileSync)(migrationPath, `${JSON.stringify(migration, null, 2)}\n`, "utf-8");
|
|
89
|
-
migrationStatus = "changed";
|
|
90
|
-
}
|
|
91
|
-
let existingConfig = {};
|
|
92
|
-
if ((0, node_fs_1.existsSync)(configPath)) {
|
|
93
|
-
try {
|
|
94
|
-
existingConfig = JSON.parse((0, node_fs_1.readFileSync)(configPath, "utf-8"));
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
97
|
-
existingConfig = {};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const updatedConfig = {
|
|
101
|
-
...existingConfig,
|
|
102
|
-
schemaPath: "fexapi/schema.fexapi",
|
|
103
|
-
generatedPath: constants_1.GENERATED_SPEC_RELATIVE_PATH,
|
|
104
|
-
...(schemaChanged ? { lastGeneratedAt: new Date().toISOString() } : {}),
|
|
105
|
-
};
|
|
106
|
-
generationSpinner.update("Syncing project config");
|
|
107
|
-
const nextConfigText = `${JSON.stringify(updatedConfig, null, 2)}\n`;
|
|
108
|
-
const previousConfigText = (0, node_fs_1.existsSync)(configPath)
|
|
109
|
-
? (0, node_fs_1.readFileSync)(configPath, "utf-8")
|
|
110
|
-
: undefined;
|
|
111
|
-
let configStatus = "cached";
|
|
112
|
-
if (previousConfigText !== nextConfigText) {
|
|
113
|
-
(0, node_fs_1.writeFileSync)(configPath, nextConfigText, "utf-8");
|
|
114
|
-
configStatus = "changed";
|
|
115
|
-
}
|
|
116
73
|
generationSpinner.succeed(`Generate complete (${schemaChanged ? "changed" : "cached"})`);
|
|
117
74
|
(0, ui_1.printSpacer)();
|
|
118
75
|
(0, ui_1.printGroupHeader)("Summary");
|
|
@@ -133,14 +90,6 @@ const generateFromSchema = () => {
|
|
|
133
90
|
label: "generated.api.json",
|
|
134
91
|
value: generatedStatus,
|
|
135
92
|
},
|
|
136
|
-
{
|
|
137
|
-
label: "migration",
|
|
138
|
-
value: migrationStatus,
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
label: "config",
|
|
142
|
-
value: configStatus,
|
|
143
|
-
},
|
|
144
93
|
{
|
|
145
94
|
label: "time",
|
|
146
95
|
value: (0, ui_1.formatDuration)(startedAtMs),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAgOA,eAAO,MAAM,iBAAiB,GAAU,YAErC;IACD,KAAK,EAAE,OAAO,CAAC;CAChB,KAAG,OAAO,CAAC,MAAM,CA8KjB,CAAC"}
|
package/dist/commands/init.js
CHANGED
|
@@ -5,7 +5,6 @@ const node_fs_1 = require("node:fs");
|
|
|
5
5
|
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
|
-
const constants_1 = require("../constants");
|
|
9
8
|
const ui_1 = require("../cli/ui");
|
|
10
9
|
const detect_1 = require("../project/detect");
|
|
11
10
|
const paths_1 = require("../project/paths");
|
|
@@ -32,10 +31,18 @@ const askInitWizardQuestions = async () => {
|
|
|
32
31
|
};
|
|
33
32
|
}
|
|
34
33
|
const questionInterface = (0, promises_1.createInterface)({ input: node_process_1.stdin, output: node_process_1.stdout });
|
|
34
|
+
const totalSteps = 3;
|
|
35
|
+
const formatWizardPrompt = (step, question, hint, defaultValue) => {
|
|
36
|
+
return `${ui_1.ui.cyan("?")} ${ui_1.ui.bold(`[${step}/${totalSteps}]`)} ${ui_1.ui.white(question)} ${ui_1.ui.gray(`(${hint})`)} ${ui_1.ui.dim(`default: ${defaultValue}`)} ${ui_1.ui.gray("› ")}`;
|
|
37
|
+
};
|
|
35
38
|
try {
|
|
39
|
+
(0, ui_1.printSpacer)();
|
|
40
|
+
(0, ui_1.printGroupHeader)("Setup Wizard");
|
|
41
|
+
console.log(ui_1.ui.dim("Press Enter to accept defaults."));
|
|
42
|
+
(0, ui_1.printSpacer)();
|
|
36
43
|
let port = DEFAULT_INIT_PORT;
|
|
37
44
|
while (true) {
|
|
38
|
-
const answer = await questionInterface.question(
|
|
45
|
+
const answer = await questionInterface.question(formatWizardPrompt(1, "What port should FexAPI use?", "1-65535", String(DEFAULT_INIT_PORT)));
|
|
39
46
|
if (!answer.trim()) {
|
|
40
47
|
break;
|
|
41
48
|
}
|
|
@@ -46,29 +53,35 @@ const askInitWizardQuestions = async () => {
|
|
|
46
53
|
port = parsedPort;
|
|
47
54
|
break;
|
|
48
55
|
}
|
|
49
|
-
console.log("Please enter a valid port
|
|
56
|
+
console.log(`${ui_1.ui.red("✕")} ${ui_1.ui.white("Please enter a valid port between 1 and 65535.")}`);
|
|
57
|
+
(0, ui_1.printSpacer)();
|
|
50
58
|
}
|
|
59
|
+
console.log(`${ui_1.ui.green("✓")} ${ui_1.ui.dim("Port")}: ${ui_1.ui.bold(String(port))}`);
|
|
51
60
|
let cors = true;
|
|
52
61
|
while (true) {
|
|
53
|
-
const answer = await questionInterface.question("Enable CORS?
|
|
62
|
+
const answer = await questionInterface.question(formatWizardPrompt(2, "Enable CORS?", "Y/n", "Y"));
|
|
54
63
|
const parsed = parseYesNo(answer, true);
|
|
55
64
|
if (parsed !== undefined) {
|
|
56
65
|
cors = parsed;
|
|
57
66
|
break;
|
|
58
67
|
}
|
|
59
|
-
console.log("Please answer with Y/Yes or N/No
|
|
68
|
+
console.log(`${ui_1.ui.red("✕")} ${ui_1.ui.white("Please answer with Y/Yes or N/No.")}`);
|
|
69
|
+
(0, ui_1.printSpacer)();
|
|
60
70
|
}
|
|
71
|
+
console.log(`${ui_1.ui.green("✓")} ${ui_1.ui.dim("CORS")}: ${cors ? ui_1.ui.green("enabled") : ui_1.ui.gray("disabled")}`);
|
|
61
72
|
let generateSampleSchemas = true;
|
|
62
73
|
while (true) {
|
|
63
|
-
const answer = await questionInterface.question("Generate sample schemas?
|
|
74
|
+
const answer = await questionInterface.question(formatWizardPrompt(3, "Generate sample schemas?", "Y/n", "Y"));
|
|
64
75
|
const parsed = parseYesNo(answer, true);
|
|
65
76
|
if (parsed !== undefined) {
|
|
66
77
|
generateSampleSchemas = parsed;
|
|
67
78
|
break;
|
|
68
79
|
}
|
|
69
|
-
console.log("Please answer with Y/Yes or N/No
|
|
80
|
+
console.log(`${ui_1.ui.red("✕")} ${ui_1.ui.white("Please answer with Y/Yes or N/No.")}`);
|
|
81
|
+
(0, ui_1.printSpacer)();
|
|
70
82
|
}
|
|
71
|
-
console.log("");
|
|
83
|
+
console.log(`${ui_1.ui.green("✓")} ${ui_1.ui.dim("Sample schemas")}: ${generateSampleSchemas ? ui_1.ui.green("enabled") : ui_1.ui.gray("disabled")}`);
|
|
84
|
+
(0, ui_1.printSpacer)();
|
|
72
85
|
return {
|
|
73
86
|
port,
|
|
74
87
|
cors,
|
|
@@ -79,21 +92,12 @@ const askInitWizardQuestions = async () => {
|
|
|
79
92
|
questionInterface.close();
|
|
80
93
|
}
|
|
81
94
|
};
|
|
82
|
-
const getRuntimeConfigTemplate = ({ port, cors,
|
|
83
|
-
const routeSection = includeSampleRoutes
|
|
84
|
-
? [
|
|
85
|
-
" routes: {",
|
|
86
|
-
' "/users": { count: 10, schema: "user" },',
|
|
87
|
-
' "/posts": { count: 20, schema: "post" },',
|
|
88
|
-
" },",
|
|
89
|
-
]
|
|
90
|
-
: [];
|
|
95
|
+
const getRuntimeConfigTemplate = ({ port, cors, }) => {
|
|
91
96
|
return [
|
|
92
97
|
"module.exports = {",
|
|
93
98
|
` port: ${port},`,
|
|
94
99
|
` cors: ${cors},`,
|
|
95
100
|
" delay: 0,",
|
|
96
|
-
...routeSection,
|
|
97
101
|
"};",
|
|
98
102
|
].join("\n");
|
|
99
103
|
};
|
|
@@ -151,7 +155,6 @@ const initializeProject = async ({ force, }) => {
|
|
|
151
155
|
const detectedProject = (0, detect_1.detectProject)(packageJsonPath, projectRoot);
|
|
152
156
|
const fexapiDirectoryPath = (0, node_path_1.join)(projectRoot, "fexapi");
|
|
153
157
|
const schemaPath = (0, node_path_1.join)(fexapiDirectoryPath, "schema.fexapi");
|
|
154
|
-
const configPath = (0, node_path_1.join)(projectRoot, "fexapi.config.json");
|
|
155
158
|
const runtimeConfigPath = (0, node_path_1.join)(projectRoot, "fexapi.config.js");
|
|
156
159
|
const schemasDirectoryPath = (0, node_path_1.join)(projectRoot, "fexapi", "schemas");
|
|
157
160
|
const userSchemaPath = (0, node_path_1.join)(schemasDirectoryPath, "user.yaml");
|
|
@@ -160,23 +163,7 @@ const initializeProject = async ({ force, }) => {
|
|
|
160
163
|
(0, ui_1.printGroupHeader)("Init");
|
|
161
164
|
const initSpinner = (0, ui_1.startSpinner)("Scaffolding fexapi project files");
|
|
162
165
|
(0, node_fs_1.mkdirSync)(fexapiDirectoryPath, { recursive: true });
|
|
163
|
-
const configExists = (0, node_fs_1.existsSync)(configPath);
|
|
164
166
|
const schemaExists = (0, node_fs_1.existsSync)(schemaPath);
|
|
165
|
-
const config = {
|
|
166
|
-
framework: detectedProject.primaryFramework,
|
|
167
|
-
frameworks: detectedProject.frameworks,
|
|
168
|
-
tooling: detectedProject.tooling,
|
|
169
|
-
schemaPath: "fexapi/schema.fexapi",
|
|
170
|
-
generatedPath: constants_1.GENERATED_SPEC_RELATIVE_PATH,
|
|
171
|
-
defaultPort: wizardAnswers.port,
|
|
172
|
-
corsEnabled: wizardAnswers.cors,
|
|
173
|
-
sampleSchemasGenerated: wizardAnswers.generateSampleSchemas,
|
|
174
|
-
createdAt: new Date().toISOString(),
|
|
175
|
-
};
|
|
176
|
-
if (!configExists || force) {
|
|
177
|
-
initSpinner.update("Writing fexapi.config.json");
|
|
178
|
-
(0, node_fs_1.writeFileSync)(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
|
|
179
|
-
}
|
|
180
167
|
if (!schemaExists || force) {
|
|
181
168
|
initSpinner.update("Writing fexapi/schema.fexapi");
|
|
182
169
|
(0, node_fs_1.writeFileSync)(schemaPath, `${(0, detect_1.getSchemaTemplate)(detectedProject.primaryFramework, wizardAnswers.port)}\n`, "utf-8");
|
|
@@ -187,7 +174,6 @@ const initializeProject = async ({ force, }) => {
|
|
|
187
174
|
(0, node_fs_1.writeFileSync)(runtimeConfigPath, `${getRuntimeConfigTemplate({
|
|
188
175
|
port: wizardAnswers.port,
|
|
189
176
|
cors: wizardAnswers.cors,
|
|
190
|
-
includeSampleRoutes: wizardAnswers.generateSampleSchemas,
|
|
191
177
|
})}\n`, "utf-8");
|
|
192
178
|
}
|
|
193
179
|
let userSchemaStatus = "skipped";
|
|
@@ -222,15 +208,6 @@ const initializeProject = async ({ force, }) => {
|
|
|
222
208
|
}
|
|
223
209
|
(0, ui_1.printSpacer)();
|
|
224
210
|
(0, ui_1.printGroupHeader)("Files");
|
|
225
|
-
if (configExists && !force) {
|
|
226
|
-
(0, ui_1.logWarn)(`Exists ${configPath}`);
|
|
227
|
-
}
|
|
228
|
-
else if (configExists && force) {
|
|
229
|
-
(0, ui_1.logSuccess)(`Overwritten ${configPath}`);
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
(0, ui_1.logSuccess)(`Created ${configPath}`);
|
|
233
|
-
}
|
|
234
211
|
if (schemaExists && !force) {
|
|
235
212
|
(0, ui_1.logWarn)(`Exists ${schemaPath}`);
|
|
236
213
|
}
|
|
@@ -273,12 +250,11 @@ const initializeProject = async ({ force, }) => {
|
|
|
273
250
|
(0, ui_1.logWarn)("Sample schemas were skipped.");
|
|
274
251
|
}
|
|
275
252
|
if (detectedProject.primaryFramework === "unknown") {
|
|
276
|
-
(0, ui_1.logWarn)("No known framework dependency found. Update fexapi.config.
|
|
253
|
+
(0, ui_1.logWarn)("No known framework dependency found. Update fexapi.config.js and schema.fexapi if needed.");
|
|
277
254
|
}
|
|
278
255
|
(0, ui_1.printSpacer)();
|
|
279
256
|
(0, ui_1.printGroupHeader)("Summary");
|
|
280
257
|
const createdFiles = [
|
|
281
|
-
!configExists || force,
|
|
282
258
|
!schemaExists || force,
|
|
283
259
|
!runtimeConfigExists || force,
|
|
284
260
|
userSchemaStatus === "created" || userSchemaStatus === "overwritten",
|
|
@@ -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;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,
|
|
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,SA+EZ,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"}
|
package/dist/commands/serve.js
CHANGED
|
@@ -24,9 +24,19 @@ const createProjectServer = ({ host, port, logEnabled = false, }) => {
|
|
|
24
24
|
? (0, generated_spec_1.loadGeneratedApiSpec)(projectRoot)
|
|
25
25
|
: undefined;
|
|
26
26
|
const effectivePort = port ?? runtimeConfig?.port ?? generatedSpec?.port ?? 4000;
|
|
27
|
+
const configuredRoutePaths = Object.keys(runtimeConfig?.routes ?? {});
|
|
28
|
+
const generatedRoutePaths = new Set((generatedSpec?.routes ?? []).map((route) => route.path));
|
|
29
|
+
const overlappingPaths = configuredRoutePaths.filter((path) => generatedRoutePaths.has(path));
|
|
27
30
|
if (runtimeConfig?.routes && Object.keys(runtimeConfig.routes).length > 0) {
|
|
28
31
|
(0, ui_1.logInfo)(`Using routes from fexapi.config.js (${Object.keys(runtimeConfig.routes).length})`);
|
|
29
32
|
}
|
|
33
|
+
if (overlappingPaths.length > 0) {
|
|
34
|
+
const sample = overlappingPaths.slice(0, 5).join(", ");
|
|
35
|
+
const more = overlappingPaths.length > 5
|
|
36
|
+
? ` (+${overlappingPaths.length - 5} more)`
|
|
37
|
+
: "";
|
|
38
|
+
(0, ui_1.logInfo)(`Both schema and config define: ${sample}${more}. Schema routes take precedence; remove duplicates in fexapi.config.js to keep behavior clear.`);
|
|
39
|
+
}
|
|
30
40
|
if (Object.keys(schemaDefinitions).length > 0) {
|
|
31
41
|
(0, ui_1.logInfo)(`Loaded custom schemas from fexapi/schemas (${Object.keys(schemaDefinitions).length})`);
|
|
32
42
|
}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,12 @@ const serve_1 = require("./commands/serve");
|
|
|
12
12
|
const args = process.argv.slice(2);
|
|
13
13
|
const [firstArg, ...restArgs] = args;
|
|
14
14
|
const main = async () => {
|
|
15
|
+
if (firstArg === "--version" || firstArg === "-v" || firstArg === "version") {
|
|
16
|
+
(0, ui_1.printBanner)();
|
|
17
|
+
(0, ui_1.printSpacer)();
|
|
18
|
+
console.log((0, ui_1.getCliVersion)());
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
15
21
|
if (firstArg === "init") {
|
|
16
22
|
if (restArgs.includes("--help") || restArgs.includes("-h")) {
|
|
17
23
|
(0, ui_1.printBanner)();
|
|
@@ -35,7 +41,7 @@ const main = async () => {
|
|
|
35
41
|
(0, ui_1.printBanner)();
|
|
36
42
|
(0, ui_1.printSpacer)();
|
|
37
43
|
(0, ui_1.logInfo)(`Usage: ${(0, ui_1.formatCommand)("fexapi generate")}`);
|
|
38
|
-
console.log("Reads fexapi/schema.fexapi and updates generated API artifacts
|
|
44
|
+
console.log("Reads fexapi/schema.fexapi and updates generated API artifacts.");
|
|
39
45
|
process.exit(0);
|
|
40
46
|
}
|
|
41
47
|
const generateOptions = (0, args_1.parseGenerateOptions)(restArgs);
|
package/dist/server.d.ts.map
CHANGED
|
@@ -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;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,
|
|
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,wFA0JpB,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -191,17 +191,6 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
|
|
|
191
191
|
response.end();
|
|
192
192
|
return;
|
|
193
193
|
}
|
|
194
|
-
if (request.method === "GET") {
|
|
195
|
-
const configuredRoute = configuredRoutes[pathname];
|
|
196
|
-
if (configuredRoute) {
|
|
197
|
-
const count = getCountOverrideFromUrl(request.url) ?? configuredRoute.count;
|
|
198
|
-
const payloadKey = toCollectionKey(pathname);
|
|
199
|
-
sendJson(response, 200, {
|
|
200
|
-
[payloadKey]: Array.from({ length: count }, () => createRecordFromSchemaName(configuredRoute.schema, schemaDefinitions)),
|
|
201
|
-
}, { cors: corsEnabled, delay: responseDelay });
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
194
|
if (apiSpec) {
|
|
206
195
|
const matchedRoute = apiSpec.routes.find((route) => route.method === request.method && route.path === pathname);
|
|
207
196
|
if (matchedRoute) {
|
|
@@ -228,7 +217,9 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
|
|
|
228
217
|
requestBody = JSON.parse(raw);
|
|
229
218
|
}
|
|
230
219
|
}
|
|
231
|
-
catch {
|
|
220
|
+
catch {
|
|
221
|
+
requestBody = {};
|
|
222
|
+
}
|
|
232
223
|
const generatedRecord = createRecordFromRoute(matchedRoute);
|
|
233
224
|
const merged = { ...generatedRecord, ...requestBody };
|
|
234
225
|
const statusCode = method === "POST" ? 201 : 200;
|
|
@@ -240,6 +231,17 @@ const startServer = ({ host = DEFAULT_HOST, port = DEFAULT_PORT, apiSpec, runtim
|
|
|
240
231
|
return;
|
|
241
232
|
}
|
|
242
233
|
}
|
|
234
|
+
if (request.method === "GET") {
|
|
235
|
+
const configuredRoute = configuredRoutes[pathname];
|
|
236
|
+
if (configuredRoute) {
|
|
237
|
+
const count = getCountOverrideFromUrl(request.url) ?? configuredRoute.count;
|
|
238
|
+
const payloadKey = toCollectionKey(pathname);
|
|
239
|
+
sendJson(response, 200, {
|
|
240
|
+
[payloadKey]: Array.from({ length: count }, () => createRecordFromSchemaName(configuredRoute.schema, schemaDefinitions)),
|
|
241
|
+
}, { cors: corsEnabled, delay: responseDelay });
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
243
245
|
sendJson(response, 404, {
|
|
244
246
|
message: "Route not found",
|
|
245
247
|
availableRoutes,
|