@faapi/faapi 1.2.0 → 1.2.1
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/index.js +40 -40
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +241 -238
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1505,9 +1505,14 @@ function getVitestImportActual() {
|
|
|
1505
1505
|
if (typeof vi?.importActual !== "function") return void 0;
|
|
1506
1506
|
return vi.importActual.bind(vi);
|
|
1507
1507
|
}
|
|
1508
|
-
async function importWithCacheBust(filePath) {
|
|
1508
|
+
async function importWithCacheBust(filePath, bustViteCache = false) {
|
|
1509
1509
|
const importActual = getVitestImportActual();
|
|
1510
1510
|
if (importActual) {
|
|
1511
|
+
if (bustViteCache) {
|
|
1512
|
+
let url2 = pathToFileURL(filePath).href;
|
|
1513
|
+
url2 += `?t=${Date.now()}`;
|
|
1514
|
+
return await import(url2);
|
|
1515
|
+
}
|
|
1511
1516
|
return await importActual(filePath);
|
|
1512
1517
|
}
|
|
1513
1518
|
let url = pathToFileURL(filePath).href;
|
|
@@ -2134,7 +2139,7 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
|
|
|
2134
2139
|
// src/testServer.ts
|
|
2135
2140
|
import path12 from "path";
|
|
2136
2141
|
import os from "os";
|
|
2137
|
-
import
|
|
2142
|
+
import fs11 from "fs/promises";
|
|
2138
2143
|
|
|
2139
2144
|
// src/router/scanRoutes.ts
|
|
2140
2145
|
import fg from "fast-glob";
|
|
@@ -2398,205 +2403,6 @@ init_generateSchemaFiles();
|
|
|
2398
2403
|
|
|
2399
2404
|
// src/validator/validateInput.ts
|
|
2400
2405
|
init_schemaName();
|
|
2401
|
-
var moduleCache = /* @__PURE__ */ new Map();
|
|
2402
|
-
function invalidateSchemaCache() {
|
|
2403
|
-
moduleCache.clear();
|
|
2404
|
-
}
|
|
2405
|
-
async function loadSchemaModule(schemaPath) {
|
|
2406
|
-
let mod = moduleCache.get(schemaPath);
|
|
2407
|
-
if (!mod) {
|
|
2408
|
-
mod = await importWithCacheBust(schemaPath);
|
|
2409
|
-
moduleCache.set(schemaPath, mod);
|
|
2410
|
-
}
|
|
2411
|
-
return mod;
|
|
2412
|
-
}
|
|
2413
|
-
async function validateInput(schemaPath, method, inputType, input) {
|
|
2414
|
-
const schemaName = getSchemaName(method, inputType);
|
|
2415
|
-
const schemaKey = `${schemaName}Schema`;
|
|
2416
|
-
let mod;
|
|
2417
|
-
try {
|
|
2418
|
-
mod = await loadSchemaModule(schemaPath);
|
|
2419
|
-
} catch (err) {
|
|
2420
|
-
const reason = err instanceof Error ? err.message : String(err);
|
|
2421
|
-
throw new InternalError(`Schema \u6A21\u5757\u52A0\u8F7D\u5931\u8D25: ${schemaPath}: ${reason}`);
|
|
2422
|
-
}
|
|
2423
|
-
const schema = mod[schemaKey];
|
|
2424
|
-
if (schema === void 0 || schema === null) {
|
|
2425
|
-
const data = typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
|
|
2426
|
-
return { valid: true, issues: [], data };
|
|
2427
|
-
}
|
|
2428
|
-
if (typeof schema !== "object" || typeof schema.safeParse !== "function") {
|
|
2429
|
-
throw new InternalError(`Schema \u4E0D\u662F\u6709\u6548\u7684 zod schema: ${schemaPath}#${schemaName}`);
|
|
2430
|
-
}
|
|
2431
|
-
const inputObj = typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
|
|
2432
|
-
const zodSchema = schema;
|
|
2433
|
-
const result = zodSchema.safeParse(inputObj);
|
|
2434
|
-
if (result.success) {
|
|
2435
|
-
const data = typeof result.data === "object" && result.data !== null && !Array.isArray(result.data) ? result.data : {};
|
|
2436
|
-
return { valid: true, issues: [], data };
|
|
2437
|
-
}
|
|
2438
|
-
const issues = mapZodIssues(result.error);
|
|
2439
|
-
return { valid: false, issues, data: inputObj };
|
|
2440
|
-
}
|
|
2441
|
-
function mapZodIssues(error) {
|
|
2442
|
-
return error.issues.map((issue) => {
|
|
2443
|
-
const code = mapZodCode(issue.code, issue.message);
|
|
2444
|
-
const path15 = issue.path.map(String).join(".") || "";
|
|
2445
|
-
return {
|
|
2446
|
-
path: path15,
|
|
2447
|
-
code,
|
|
2448
|
-
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
2449
|
-
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
2450
|
-
message: issue.message
|
|
2451
|
-
};
|
|
2452
|
-
});
|
|
2453
|
-
}
|
|
2454
|
-
function mapZodCode(zodCode, message) {
|
|
2455
|
-
switch (zodCode) {
|
|
2456
|
-
case "invalid_type":
|
|
2457
|
-
case "invalid_union":
|
|
2458
|
-
case "invalid_union_discriminator":
|
|
2459
|
-
return "TYPE_MISMATCH";
|
|
2460
|
-
case "unrecognized_keys":
|
|
2461
|
-
return "INVALID_FORMAT";
|
|
2462
|
-
case "invalid_value":
|
|
2463
|
-
case "invalid_string":
|
|
2464
|
-
case "too_small":
|
|
2465
|
-
case "too_big":
|
|
2466
|
-
case "invalid_intersection_types":
|
|
2467
|
-
case "not_multiple_of":
|
|
2468
|
-
return "INVALID_VALUE";
|
|
2469
|
-
case "custom":
|
|
2470
|
-
return "INVALID_VALUE";
|
|
2471
|
-
default:
|
|
2472
|
-
if (message.includes("Required") || message.includes("required")) {
|
|
2473
|
-
return "MISSING_FIELD";
|
|
2474
|
-
}
|
|
2475
|
-
return "INVALID_VALUE";
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
function mapExpectedFromMessage(message) {
|
|
2479
|
-
const match = message.match(/Expected\s+(\w+)/i);
|
|
2480
|
-
return match ? match[1].toLowerCase() : "unknown";
|
|
2481
|
-
}
|
|
2482
|
-
function mapReceivedFromMessage(message) {
|
|
2483
|
-
const match = message.match(/received\s+(\w+)/i);
|
|
2484
|
-
return match ? match[1].toLowerCase() : "unknown";
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
|
-
// src/server/createServer.ts
|
|
2488
|
-
import {
|
|
2489
|
-
createServer as createHttpServer
|
|
2490
|
-
} from "http";
|
|
2491
|
-
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
2492
|
-
import { readFileSync } from "fs";
|
|
2493
|
-
import { Readable as Readable2 } from "stream";
|
|
2494
|
-
import path11 from "path";
|
|
2495
|
-
|
|
2496
|
-
// src/router/matchRoute.ts
|
|
2497
|
-
function matchRoute(routes, method, path15) {
|
|
2498
|
-
for (const route of routes) {
|
|
2499
|
-
if (route.method !== method) {
|
|
2500
|
-
continue;
|
|
2501
|
-
}
|
|
2502
|
-
if (!route.isDynamic) {
|
|
2503
|
-
if (route.urlPath === path15) {
|
|
2504
|
-
return { route, params: {} };
|
|
2505
|
-
}
|
|
2506
|
-
continue;
|
|
2507
|
-
}
|
|
2508
|
-
const params = matchDynamicPath(route.urlPath, path15, route.paramNames, route.isCatchAll);
|
|
2509
|
-
if (params !== null) {
|
|
2510
|
-
return { route, params };
|
|
2511
|
-
}
|
|
2512
|
-
}
|
|
2513
|
-
return null;
|
|
2514
|
-
}
|
|
2515
|
-
function matchWsRoute(wsRoutes, path15) {
|
|
2516
|
-
for (const route of wsRoutes) {
|
|
2517
|
-
if (!route.isDynamic) {
|
|
2518
|
-
if (route.urlPath === path15) {
|
|
2519
|
-
return { route, params: {} };
|
|
2520
|
-
}
|
|
2521
|
-
continue;
|
|
2522
|
-
}
|
|
2523
|
-
const params = matchDynamicPath(route.urlPath, path15, route.paramNames, route.isCatchAll);
|
|
2524
|
-
if (params !== null) {
|
|
2525
|
-
return { route, params };
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
return null;
|
|
2529
|
-
}
|
|
2530
|
-
function matchDynamicPath(pattern, path15, paramNames, isCatchAll) {
|
|
2531
|
-
const patternSegments = pattern.split("/").filter(Boolean);
|
|
2532
|
-
const pathSegments = path15.split("/").filter(Boolean);
|
|
2533
|
-
if (isCatchAll) {
|
|
2534
|
-
const nonCatchAllCount = patternSegments.length - 1;
|
|
2535
|
-
if (pathSegments.length <= nonCatchAllCount) {
|
|
2536
|
-
return null;
|
|
2537
|
-
}
|
|
2538
|
-
const params2 = {};
|
|
2539
|
-
for (let i = 0; i < nonCatchAllCount; i++) {
|
|
2540
|
-
const patternSeg = patternSegments[i];
|
|
2541
|
-
const pathSeg = pathSegments[i];
|
|
2542
|
-
if (patternSeg.startsWith(":")) {
|
|
2543
|
-
const paramName = patternSeg.slice(1);
|
|
2544
|
-
params2[paramName] = pathSeg;
|
|
2545
|
-
} else if (patternSeg !== pathSeg) {
|
|
2546
|
-
return null;
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
const catchAllValue = pathSegments.slice(nonCatchAllCount).join("/");
|
|
2550
|
-
const catchAllParamName = patternSegments[nonCatchAllCount].slice(4);
|
|
2551
|
-
params2[catchAllParamName] = catchAllValue;
|
|
2552
|
-
if (Object.keys(params2).length !== paramNames.length) {
|
|
2553
|
-
return null;
|
|
2554
|
-
}
|
|
2555
|
-
return params2;
|
|
2556
|
-
}
|
|
2557
|
-
if (patternSegments.length !== pathSegments.length) {
|
|
2558
|
-
return null;
|
|
2559
|
-
}
|
|
2560
|
-
const params = {};
|
|
2561
|
-
for (let i = 0; i < patternSegments.length; i++) {
|
|
2562
|
-
const patternSeg = patternSegments[i];
|
|
2563
|
-
const pathSeg = pathSegments[i];
|
|
2564
|
-
if (patternSeg.startsWith(":")) {
|
|
2565
|
-
const paramName = patternSeg.slice(1);
|
|
2566
|
-
params[paramName] = pathSeg;
|
|
2567
|
-
} else if (patternSeg !== pathSeg) {
|
|
2568
|
-
return null;
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
if (Object.keys(params).length !== paramNames.length) {
|
|
2572
|
-
return null;
|
|
2573
|
-
}
|
|
2574
|
-
return params;
|
|
2575
|
-
}
|
|
2576
|
-
|
|
2577
|
-
// src/loader/resolveExports.ts
|
|
2578
|
-
function resolveExport(module, exportName) {
|
|
2579
|
-
if (exportName in module && typeof module[exportName] !== "undefined") {
|
|
2580
|
-
return module[exportName];
|
|
2581
|
-
}
|
|
2582
|
-
const defaultExport = module.default;
|
|
2583
|
-
if (defaultExport !== null && typeof defaultExport === "object") {
|
|
2584
|
-
const value = defaultExport[exportName];
|
|
2585
|
-
if (value !== void 0) {
|
|
2586
|
-
return value;
|
|
2587
|
-
}
|
|
2588
|
-
}
|
|
2589
|
-
return void 0;
|
|
2590
|
-
}
|
|
2591
|
-
|
|
2592
|
-
// src/loader/validateRouteModule.ts
|
|
2593
|
-
function validateRouteModule(value, method, filePath) {
|
|
2594
|
-
if (typeof value !== "function") {
|
|
2595
|
-
throw new Error(
|
|
2596
|
-
`Route module "${filePath}" does not export a valid handler for method "${method}". Expected a function, got ${typeof value}.`
|
|
2597
|
-
);
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
2406
|
|
|
2601
2407
|
// src/cli/compileOnDemand.ts
|
|
2602
2408
|
import path9 from "path";
|
|
@@ -2945,32 +2751,232 @@ function getDevDist() {
|
|
|
2945
2751
|
return devDistDir;
|
|
2946
2752
|
}
|
|
2947
2753
|
|
|
2948
|
-
// src/
|
|
2949
|
-
|
|
2950
|
-
|
|
2754
|
+
// src/validator/validateInput.ts
|
|
2755
|
+
var moduleCache = /* @__PURE__ */ new Map();
|
|
2756
|
+
function invalidateSchemaCache() {
|
|
2757
|
+
moduleCache.clear();
|
|
2758
|
+
}
|
|
2759
|
+
async function loadSchemaModule(schemaPath) {
|
|
2760
|
+
let mod = moduleCache.get(schemaPath);
|
|
2761
|
+
if (!mod) {
|
|
2762
|
+
mod = await importWithCacheBust(schemaPath, isDevOnDemandEnabled());
|
|
2763
|
+
moduleCache.set(schemaPath, mod);
|
|
2764
|
+
}
|
|
2765
|
+
return mod;
|
|
2766
|
+
}
|
|
2767
|
+
async function validateInput(schemaPath, method, inputType, input) {
|
|
2768
|
+
const schemaName = getSchemaName(method, inputType);
|
|
2769
|
+
const schemaKey = `${schemaName}Schema`;
|
|
2770
|
+
let mod;
|
|
2951
2771
|
try {
|
|
2952
|
-
|
|
2772
|
+
mod = await loadSchemaModule(schemaPath);
|
|
2953
2773
|
} catch (err) {
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2774
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
2775
|
+
throw new InternalError(`Schema \u6A21\u5757\u52A0\u8F7D\u5931\u8D25: ${schemaPath}: ${reason}`);
|
|
2776
|
+
}
|
|
2777
|
+
const schema = mod[schemaKey];
|
|
2778
|
+
if (schema === void 0 || schema === null) {
|
|
2779
|
+
const data = typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
|
|
2780
|
+
return { valid: true, issues: [], data };
|
|
2781
|
+
}
|
|
2782
|
+
if (typeof schema !== "object" || typeof schema.safeParse !== "function") {
|
|
2783
|
+
throw new InternalError(`Schema \u4E0D\u662F\u6709\u6548\u7684 zod schema: ${schemaPath}#${schemaName}`);
|
|
2784
|
+
}
|
|
2785
|
+
const inputObj = typeof input === "object" && input !== null && !Array.isArray(input) ? input : {};
|
|
2786
|
+
const zodSchema = schema;
|
|
2787
|
+
const result = zodSchema.safeParse(inputObj);
|
|
2788
|
+
if (result.success) {
|
|
2789
|
+
const data = typeof result.data === "object" && result.data !== null && !Array.isArray(result.data) ? result.data : {};
|
|
2790
|
+
return { valid: true, issues: [], data };
|
|
2791
|
+
}
|
|
2792
|
+
const issues = mapZodIssues(result.error);
|
|
2793
|
+
return { valid: false, issues, data: inputObj };
|
|
2794
|
+
}
|
|
2795
|
+
function mapZodIssues(error) {
|
|
2796
|
+
return error.issues.map((issue) => {
|
|
2797
|
+
const code = mapZodCode(issue.code, issue.message);
|
|
2798
|
+
const path15 = issue.path.map(String).join(".") || "";
|
|
2799
|
+
return {
|
|
2800
|
+
path: path15,
|
|
2801
|
+
code,
|
|
2802
|
+
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
2803
|
+
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
2804
|
+
message: issue.message
|
|
2805
|
+
};
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
function mapZodCode(zodCode, message) {
|
|
2809
|
+
switch (zodCode) {
|
|
2810
|
+
case "invalid_type":
|
|
2811
|
+
case "invalid_union":
|
|
2812
|
+
case "invalid_union_discriminator":
|
|
2813
|
+
return "TYPE_MISMATCH";
|
|
2814
|
+
case "unrecognized_keys":
|
|
2815
|
+
return "INVALID_FORMAT";
|
|
2816
|
+
case "invalid_value":
|
|
2817
|
+
case "invalid_string":
|
|
2818
|
+
case "too_small":
|
|
2819
|
+
case "too_big":
|
|
2820
|
+
case "invalid_intersection_types":
|
|
2821
|
+
case "not_multiple_of":
|
|
2822
|
+
return "INVALID_VALUE";
|
|
2823
|
+
case "custom":
|
|
2824
|
+
return "INVALID_VALUE";
|
|
2825
|
+
default:
|
|
2826
|
+
if (message.includes("Required") || message.includes("required")) {
|
|
2827
|
+
return "MISSING_FIELD";
|
|
2828
|
+
}
|
|
2829
|
+
return "INVALID_VALUE";
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
function mapExpectedFromMessage(message) {
|
|
2833
|
+
const match = message.match(/Expected\s+(\w+)/i);
|
|
2834
|
+
return match ? match[1].toLowerCase() : "unknown";
|
|
2835
|
+
}
|
|
2836
|
+
function mapReceivedFromMessage(message) {
|
|
2837
|
+
const match = message.match(/received\s+(\w+)/i);
|
|
2838
|
+
return match ? match[1].toLowerCase() : "unknown";
|
|
2839
|
+
}
|
|
2840
|
+
|
|
2841
|
+
// src/server/createServer.ts
|
|
2842
|
+
import {
|
|
2843
|
+
createServer as createHttpServer
|
|
2844
|
+
} from "http";
|
|
2845
|
+
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
2846
|
+
import { readFileSync } from "fs";
|
|
2847
|
+
import { Readable as Readable2 } from "stream";
|
|
2848
|
+
import path11 from "path";
|
|
2849
|
+
|
|
2850
|
+
// src/router/matchRoute.ts
|
|
2851
|
+
function matchRoute(routes, method, path15) {
|
|
2852
|
+
for (const route of routes) {
|
|
2853
|
+
if (route.method !== method) {
|
|
2854
|
+
continue;
|
|
2855
|
+
}
|
|
2856
|
+
if (!route.isDynamic) {
|
|
2857
|
+
if (route.urlPath === path15) {
|
|
2858
|
+
return { route, params: {} };
|
|
2859
|
+
}
|
|
2860
|
+
continue;
|
|
2861
|
+
}
|
|
2862
|
+
const params = matchDynamicPath(route.urlPath, path15, route.paramNames, route.isCatchAll);
|
|
2863
|
+
if (params !== null) {
|
|
2864
|
+
return { route, params };
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
function matchWsRoute(wsRoutes, path15) {
|
|
2870
|
+
for (const route of wsRoutes) {
|
|
2871
|
+
if (!route.isDynamic) {
|
|
2872
|
+
if (route.urlPath === path15) {
|
|
2873
|
+
return { route, params: {} };
|
|
2874
|
+
}
|
|
2875
|
+
continue;
|
|
2876
|
+
}
|
|
2877
|
+
const params = matchDynamicPath(route.urlPath, path15, route.paramNames, route.isCatchAll);
|
|
2878
|
+
if (params !== null) {
|
|
2879
|
+
return { route, params };
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
return null;
|
|
2883
|
+
}
|
|
2884
|
+
function matchDynamicPath(pattern, path15, paramNames, isCatchAll) {
|
|
2885
|
+
const patternSegments = pattern.split("/").filter(Boolean);
|
|
2886
|
+
const pathSegments = path15.split("/").filter(Boolean);
|
|
2887
|
+
if (isCatchAll) {
|
|
2888
|
+
const nonCatchAllCount = patternSegments.length - 1;
|
|
2889
|
+
if (pathSegments.length <= nonCatchAllCount) {
|
|
2890
|
+
return null;
|
|
2891
|
+
}
|
|
2892
|
+
const params2 = {};
|
|
2893
|
+
for (let i = 0; i < nonCatchAllCount; i++) {
|
|
2894
|
+
const patternSeg = patternSegments[i];
|
|
2895
|
+
const pathSeg = pathSegments[i];
|
|
2896
|
+
if (patternSeg.startsWith(":")) {
|
|
2897
|
+
const paramName = patternSeg.slice(1);
|
|
2898
|
+
params2[paramName] = pathSeg;
|
|
2899
|
+
} else if (patternSeg !== pathSeg) {
|
|
2900
|
+
return null;
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
const catchAllValue = pathSegments.slice(nonCatchAllCount).join("/");
|
|
2904
|
+
const catchAllParamName = patternSegments[nonCatchAllCount].slice(4);
|
|
2905
|
+
params2[catchAllParamName] = catchAllValue;
|
|
2906
|
+
if (Object.keys(params2).length !== paramNames.length) {
|
|
2907
|
+
return null;
|
|
2908
|
+
}
|
|
2909
|
+
return params2;
|
|
2910
|
+
}
|
|
2911
|
+
if (patternSegments.length !== pathSegments.length) {
|
|
2912
|
+
return null;
|
|
2913
|
+
}
|
|
2914
|
+
const params = {};
|
|
2915
|
+
for (let i = 0; i < patternSegments.length; i++) {
|
|
2916
|
+
const patternSeg = patternSegments[i];
|
|
2917
|
+
const pathSeg = pathSegments[i];
|
|
2918
|
+
if (patternSeg.startsWith(":")) {
|
|
2919
|
+
const paramName = patternSeg.slice(1);
|
|
2920
|
+
params[paramName] = pathSeg;
|
|
2921
|
+
} else if (patternSeg !== pathSeg) {
|
|
2922
|
+
return null;
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
if (Object.keys(params).length !== paramNames.length) {
|
|
2926
|
+
return null;
|
|
2927
|
+
}
|
|
2928
|
+
return params;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
// src/loader/loadRouteModule.ts
|
|
2932
|
+
import fs9 from "fs";
|
|
2933
|
+
|
|
2934
|
+
// src/loader/resolveExports.ts
|
|
2935
|
+
function resolveExport(module, exportName) {
|
|
2936
|
+
if (exportName in module && typeof module[exportName] !== "undefined") {
|
|
2937
|
+
return module[exportName];
|
|
2938
|
+
}
|
|
2939
|
+
const defaultExport = module.default;
|
|
2940
|
+
if (defaultExport !== null && typeof defaultExport === "object") {
|
|
2941
|
+
const value = defaultExport[exportName];
|
|
2942
|
+
if (value !== void 0) {
|
|
2943
|
+
return value;
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
return void 0;
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
// src/loader/validateRouteModule.ts
|
|
2950
|
+
function validateRouteModule(value, method, filePath) {
|
|
2951
|
+
if (typeof value !== "function") {
|
|
2952
|
+
throw new Error(
|
|
2953
|
+
`Route module "${filePath}" does not export a valid handler for method "${method}". Expected a function, got ${typeof value}.`
|
|
2954
|
+
);
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
|
|
2958
|
+
// src/loader/loadRouteModule.ts
|
|
2959
|
+
async function loadRouteModule(filePath, method, rootDir) {
|
|
2960
|
+
if (isDevOnDemandEnabled() && rootDir) {
|
|
2961
|
+
const dist = getDevDist();
|
|
2962
|
+
if (dist) {
|
|
2963
|
+
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
2964
|
+
if (sourcePath && fs9.existsSync(sourcePath)) {
|
|
2958
2965
|
try {
|
|
2959
|
-
|
|
2960
|
-
if (compiled) {
|
|
2961
|
-
module = await importWithCacheBust(filePath);
|
|
2962
|
-
const handler2 = resolveExport(module, method);
|
|
2963
|
-
validateRouteModule(handler2, method, filePath);
|
|
2964
|
-
return { handler: handler2, method };
|
|
2965
|
-
}
|
|
2966
|
+
await ensureCompiled(sourcePath, rootDir, dist);
|
|
2966
2967
|
} catch (compileErr) {
|
|
2967
|
-
const
|
|
2968
|
-
throw new Error(`Failed to compile route module "${sourcePath}": ${
|
|
2968
|
+
const reason = compileErr instanceof Error ? compileErr.message : String(compileErr);
|
|
2969
|
+
throw new Error(`Failed to compile route module "${sourcePath}": ${reason}`, {
|
|
2969
2970
|
cause: compileErr
|
|
2970
2971
|
});
|
|
2971
2972
|
}
|
|
2972
2973
|
}
|
|
2973
2974
|
}
|
|
2975
|
+
}
|
|
2976
|
+
let module;
|
|
2977
|
+
try {
|
|
2978
|
+
module = await importWithCacheBust(filePath, isDevOnDemandEnabled());
|
|
2979
|
+
} catch (err) {
|
|
2974
2980
|
const reason = err instanceof Error ? err.message : String(err);
|
|
2975
2981
|
throw new Error(`Failed to load route module "${filePath}": ${reason}`, { cause: err });
|
|
2976
2982
|
}
|
|
@@ -3105,6 +3111,7 @@ function getClientIp(req) {
|
|
|
3105
3111
|
}
|
|
3106
3112
|
|
|
3107
3113
|
// src/server/handleWsUpgrade.ts
|
|
3114
|
+
import fs10 from "fs";
|
|
3108
3115
|
import { WebSocketServer, WebSocket } from "ws";
|
|
3109
3116
|
import path10 from "path";
|
|
3110
3117
|
|
|
@@ -3204,24 +3211,16 @@ function getPathname(req) {
|
|
|
3204
3211
|
return idx >= 0 ? url.slice(0, idx) : url;
|
|
3205
3212
|
}
|
|
3206
3213
|
async function loadWsHandler(filePath, ctx, rootDir) {
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
if (dist) {
|
|
3214
|
-
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3215
|
-
const compiled = await ensureCompiled(sourcePath, rootDir, dist);
|
|
3216
|
-
if (compiled) {
|
|
3217
|
-
module = await importWithCacheBust(filePath);
|
|
3218
|
-
}
|
|
3214
|
+
if (isDevOnDemandEnabled() && rootDir) {
|
|
3215
|
+
const dist = getDevDist();
|
|
3216
|
+
if (dist) {
|
|
3217
|
+
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3218
|
+
if (sourcePath && fs10.existsSync(sourcePath)) {
|
|
3219
|
+
await ensureCompiled(sourcePath, rootDir, dist);
|
|
3219
3220
|
}
|
|
3220
3221
|
}
|
|
3221
|
-
if (!module) {
|
|
3222
|
-
throw err;
|
|
3223
|
-
}
|
|
3224
3222
|
}
|
|
3223
|
+
const module = await importWithCacheBust(filePath, isDevOnDemandEnabled());
|
|
3225
3224
|
const handler = module["WS"];
|
|
3226
3225
|
if (typeof handler !== "function") {
|
|
3227
3226
|
throw new Error(`WS export not found in ${filePath}`);
|
|
@@ -3569,7 +3568,7 @@ async function createTestServer(options) {
|
|
|
3569
3568
|
} = options;
|
|
3570
3569
|
const { routes, wsRoutes } = await scanRoutes(rootDir, patterns);
|
|
3571
3570
|
const sorted = sortRoutes(routes);
|
|
3572
|
-
const schemaDist = dist ? path12.isAbsolute(dist) ? dist : path12.resolve(rootDir, dist) : await
|
|
3571
|
+
const schemaDist = dist ? path12.isAbsolute(dist) ? dist : path12.resolve(rootDir, dist) : await fs11.mkdtemp(path12.join(os.tmpdir(), "faapi-test-schema-"));
|
|
3573
3572
|
await generateSchemaFiles(sorted, rootDir, schemaDist);
|
|
3574
3573
|
const { server } = createServer({
|
|
3575
3574
|
routes: sorted,
|
|
@@ -3602,7 +3601,7 @@ async function createTestServer(options) {
|
|
|
3602
3601
|
await new Promise((resolve) => {
|
|
3603
3602
|
server.close(() => resolve());
|
|
3604
3603
|
});
|
|
3605
|
-
await
|
|
3604
|
+
await fs11.rm(schemaDist, { recursive: true, force: true }).catch(() => {
|
|
3606
3605
|
});
|
|
3607
3606
|
invalidateSchemaCache();
|
|
3608
3607
|
}
|
|
@@ -3744,7 +3743,7 @@ async function connectWs(baseUrl, pathname, options = {}) {
|
|
|
3744
3743
|
}
|
|
3745
3744
|
|
|
3746
3745
|
// src/cli/createAppCore.ts
|
|
3747
|
-
import
|
|
3746
|
+
import fs13 from "fs";
|
|
3748
3747
|
import path14 from "path";
|
|
3749
3748
|
import { PassThrough } from "stream";
|
|
3750
3749
|
|
|
@@ -3802,7 +3801,7 @@ function applyPluginWrappers(server, handlerWrappers, upgradeWrappers) {
|
|
|
3802
3801
|
}
|
|
3803
3802
|
|
|
3804
3803
|
// src/cli/generateRoutes.ts
|
|
3805
|
-
import
|
|
3804
|
+
import fs12 from "fs";
|
|
3806
3805
|
import path13 from "path";
|
|
3807
3806
|
async function hydrateRoutes(manifest) {
|
|
3808
3807
|
const hydrateRoute = (serialized) => ({
|
|
@@ -3910,7 +3909,7 @@ async function createAppBase(options) {
|
|
|
3910
3909
|
const rootDir = options?.rootDir ?? process.cwd();
|
|
3911
3910
|
const dist = options?.dist ?? process.env.FAAPI_DIST ?? DEFAULT_DIST;
|
|
3912
3911
|
const routesPath = path14.resolve(rootDir, dist, ROUTES_FILE);
|
|
3913
|
-
if (!
|
|
3912
|
+
if (!fs13.existsSync(routesPath)) {
|
|
3914
3913
|
throw new Error(
|
|
3915
3914
|
`[faapi] ${dist}/${ROUTES_FILE} \u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u6267\u884C \`faapi build\`\uFF08\u6216 \`faapi dev\`\uFF09\u751F\u6210\u4EA7\u7269\u3002`
|
|
3916
3915
|
);
|
|
@@ -4083,6 +4082,10 @@ async function createAppBase(options) {
|
|
|
4083
4082
|
if (config?.lifecycle?.onClose) {
|
|
4084
4083
|
await config.lifecycle.onClose({ rootDir, routes: sorted, server });
|
|
4085
4084
|
}
|
|
4085
|
+
if (!server.listening) {
|
|
4086
|
+
app.server = null;
|
|
4087
|
+
return;
|
|
4088
|
+
}
|
|
4086
4089
|
return new Promise((resolve) => {
|
|
4087
4090
|
server.close((err) => {
|
|
4088
4091
|
if (err) console.error("Error closing server:", err);
|