@faapi/faapi 6.26.0 → 6.27.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/dist/cli/index.js +12 -43
- package/dist/cli/index.js.map +1 -1
- package/dist/{contextTypes-gYf84EXF.d.ts → contextTypes-CBE86AO2.d.ts} +7 -23
- package/dist/index.d.ts +4 -26
- package/dist/index.js +63 -92
- package/dist/index.js.map +1 -1
- package/dist/{routeTypes-DlD6nnbT.d.ts → routeTypes-DVSnH0jk.d.ts} +1 -1
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +45 -76
- package/dist/testing.js.map +1 -1
- package/dist/workerEntry.d.ts +1 -1
- package/package.json +1 -1
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FaapiContext } from './contextTypes-
|
|
2
|
-
import { F as FaapiMiddleware, I as InjectorMap, R as RouteManifest, W as WsRouteManifest, C as CorsOptions, H as HelmetOptions } from './routeTypes-
|
|
1
|
+
import { F as FaapiContext } from './contextTypes-CBE86AO2.js';
|
|
2
|
+
import { F as FaapiMiddleware, I as InjectorMap, R as RouteManifest, W as WsRouteManifest, C as CorsOptions, H as HelmetOptions } from './routeTypes-DVSnH0jk.js';
|
|
3
3
|
import { Server } from 'node:http';
|
|
4
4
|
import { WebSocket } from 'ws';
|
|
5
5
|
|
|
@@ -30,7 +30,7 @@ interface CreateTestContextOptions {
|
|
|
30
30
|
* 运行时资源根目录(可选)
|
|
31
31
|
*
|
|
32
32
|
* 传入时同时做两件事:绑定全局 readResource 读取根(handler 直调
|
|
33
|
-
* `readResource('x.md')`
|
|
33
|
+
* `readResource('x.md')` 依赖);ctx 上无 resourcesDir 数据字段(已删除)
|
|
34
34
|
*/
|
|
35
35
|
resourcesDir?: string;
|
|
36
36
|
/** 请求方法,默认 'GET' */
|
package/dist/testing.js
CHANGED
|
@@ -312,14 +312,14 @@ var ValidationError = class extends FaapiError {
|
|
|
312
312
|
issues;
|
|
313
313
|
};
|
|
314
314
|
var RouteNotFoundError = class extends FaapiError {
|
|
315
|
-
constructor(
|
|
316
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${
|
|
315
|
+
constructor(path17) {
|
|
316
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path17}`, 404);
|
|
317
317
|
this.name = "RouteNotFoundError";
|
|
318
318
|
}
|
|
319
319
|
};
|
|
320
320
|
var MethodNotAllowedError = class extends FaapiError {
|
|
321
|
-
constructor(method,
|
|
322
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${
|
|
321
|
+
constructor(method, path17, allowedMethods) {
|
|
322
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path17}`, 405);
|
|
323
323
|
this.allowedMethods = allowedMethods;
|
|
324
324
|
this.name = "MethodNotAllowedError";
|
|
325
325
|
}
|
|
@@ -628,18 +628,10 @@ function formatSetCookie(name, value, options) {
|
|
|
628
628
|
if (options?.sameSite) cookie += `; SameSite=${options.sameSite}`;
|
|
629
629
|
return cookie;
|
|
630
630
|
}
|
|
631
|
-
function createContext(request, params, config = {}, ip = "", registries
|
|
632
|
-
return createContextFromUrl(
|
|
633
|
-
request,
|
|
634
|
-
new URL(request.url),
|
|
635
|
-
params,
|
|
636
|
-
config,
|
|
637
|
-
ip,
|
|
638
|
-
registries,
|
|
639
|
-
resourcesDir
|
|
640
|
-
);
|
|
631
|
+
function createContext(request, params, config = {}, ip = "", registries) {
|
|
632
|
+
return createContextFromUrl(request, new URL(request.url), params, config, ip, registries);
|
|
641
633
|
}
|
|
642
|
-
function createContextFromUrl(request, url, params, config = {}, ip = "", registries
|
|
634
|
+
function createContextFromUrl(request, url, params, config = {}, ip = "", registries) {
|
|
643
635
|
const meta = { headers: {}, setCookies: [] };
|
|
644
636
|
const parsedCookies = parseCookies(request.headers.get("cookie") ?? "");
|
|
645
637
|
const cookiesObj = {};
|
|
@@ -667,9 +659,6 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
|
|
|
667
659
|
ua: request.headers.get("user-agent") ?? "",
|
|
668
660
|
cookies: cookiesObj,
|
|
669
661
|
config,
|
|
670
|
-
// 运行时资源根目录(HTTP/WS 链路由 createServer/handleWsUpgrade 传入;
|
|
671
|
-
// testing 直调未传时为 undefined,见 contextTypes.resourcesDir 注释)
|
|
672
|
-
resourcesDir,
|
|
673
662
|
meta,
|
|
674
663
|
setStatus(status) {
|
|
675
664
|
meta.status = status;
|
|
@@ -775,7 +764,7 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
|
|
|
775
764
|
function createTestContext(options) {
|
|
776
765
|
const {
|
|
777
766
|
method = "GET",
|
|
778
|
-
path:
|
|
767
|
+
path: path17,
|
|
779
768
|
query,
|
|
780
769
|
headers,
|
|
781
770
|
params = {},
|
|
@@ -784,7 +773,7 @@ function createTestContext(options) {
|
|
|
784
773
|
registries,
|
|
785
774
|
resourcesDir
|
|
786
775
|
} = options;
|
|
787
|
-
const url = new URL(`http://localhost${
|
|
776
|
+
const url = new URL(`http://localhost${path17}`);
|
|
788
777
|
if (query) {
|
|
789
778
|
for (const [key, value] of Object.entries(query)) {
|
|
790
779
|
if (Array.isArray(value)) {
|
|
@@ -803,7 +792,7 @@ function createTestContext(options) {
|
|
|
803
792
|
if (resourcesDir) {
|
|
804
793
|
setActiveResourcesDir(resourcesDir);
|
|
805
794
|
}
|
|
806
|
-
return createContext(request, params, config, ip, registries
|
|
795
|
+
return createContext(request, params, config, ip, registries);
|
|
807
796
|
}
|
|
808
797
|
|
|
809
798
|
// src/response/pendingMeta.ts
|
|
@@ -1386,9 +1375,9 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
|
|
|
1386
1375
|
}
|
|
1387
1376
|
|
|
1388
1377
|
// src/testServer.ts
|
|
1389
|
-
import
|
|
1378
|
+
import path16 from "path";
|
|
1390
1379
|
import os from "os";
|
|
1391
|
-
import
|
|
1380
|
+
import fs13 from "fs/promises";
|
|
1392
1381
|
|
|
1393
1382
|
// src/router/scanRoutes.ts
|
|
1394
1383
|
import fg from "fast-glob";
|
|
@@ -1400,9 +1389,9 @@ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
|
1400
1389
|
var HTTP_METHOD_SET = new Set(HTTP_METHODS);
|
|
1401
1390
|
|
|
1402
1391
|
// src/utils/normalizePath.ts
|
|
1403
|
-
function normalizePath(
|
|
1404
|
-
if (!
|
|
1405
|
-
let result =
|
|
1392
|
+
function normalizePath(path17) {
|
|
1393
|
+
if (!path17) return "";
|
|
1394
|
+
let result = path17.replace(/\\/g, "/");
|
|
1406
1395
|
result = result.replace(/\/+/g, "/");
|
|
1407
1396
|
result = result.replace(/\/+$/, "");
|
|
1408
1397
|
if (result && !result.startsWith("/")) {
|
|
@@ -3851,9 +3840,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
3851
3840
|
function mapZodIssues(error) {
|
|
3852
3841
|
return error.issues.map((issue) => {
|
|
3853
3842
|
const code = mapZodCode(issue);
|
|
3854
|
-
const
|
|
3843
|
+
const path17 = issue.path.map(String).join(".") || "";
|
|
3855
3844
|
return {
|
|
3856
|
-
path:
|
|
3845
|
+
path: path17,
|
|
3857
3846
|
code,
|
|
3858
3847
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
3859
3848
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -3903,7 +3892,7 @@ import {
|
|
|
3903
3892
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
3904
3893
|
import { readFileSync } from "fs";
|
|
3905
3894
|
import { Readable as Readable2 } from "stream";
|
|
3906
|
-
import
|
|
3895
|
+
import path15 from "path";
|
|
3907
3896
|
|
|
3908
3897
|
// src/router/matchRoute.ts
|
|
3909
3898
|
var httpIndexCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -3945,25 +3934,25 @@ function getWsIndex(routes) {
|
|
|
3945
3934
|
wsIndexCache.set(routes, index);
|
|
3946
3935
|
return index;
|
|
3947
3936
|
}
|
|
3948
|
-
function matchRoute(routes, method,
|
|
3937
|
+
function matchRoute(routes, method, path17) {
|
|
3949
3938
|
const index = getHttpIndex(routes);
|
|
3950
3939
|
const upper = method.toUpperCase();
|
|
3951
|
-
const hit = matchByMethod(index, upper,
|
|
3940
|
+
const hit = matchByMethod(index, upper, path17);
|
|
3952
3941
|
if (hit) return hit;
|
|
3953
3942
|
if (upper === "HEAD") {
|
|
3954
|
-
return matchByMethod(index, "GET",
|
|
3943
|
+
return matchByMethod(index, "GET", path17);
|
|
3955
3944
|
}
|
|
3956
3945
|
return null;
|
|
3957
3946
|
}
|
|
3958
|
-
function matchByMethod(index, method,
|
|
3959
|
-
const staticHit = index.static.get(`${method}|${
|
|
3947
|
+
function matchByMethod(index, method, path17) {
|
|
3948
|
+
const staticHit = index.static.get(`${method}|${path17}`);
|
|
3960
3949
|
if (staticHit) {
|
|
3961
3950
|
return { route: staticHit, params: {} };
|
|
3962
3951
|
}
|
|
3963
3952
|
if (index.dynamics.length === 0) {
|
|
3964
3953
|
return null;
|
|
3965
3954
|
}
|
|
3966
|
-
const pathSegments =
|
|
3955
|
+
const pathSegments = path17.split("/").filter(Boolean);
|
|
3967
3956
|
for (const entry of index.dynamics) {
|
|
3968
3957
|
const route = entry.route;
|
|
3969
3958
|
if (route.method !== method) {
|
|
@@ -3976,31 +3965,31 @@ function matchByMethod(index, method, path18) {
|
|
|
3976
3965
|
}
|
|
3977
3966
|
return null;
|
|
3978
3967
|
}
|
|
3979
|
-
function matchWsRoute(wsRoutes,
|
|
3968
|
+
function matchWsRoute(wsRoutes, path17) {
|
|
3980
3969
|
const index = getWsIndex(wsRoutes);
|
|
3981
|
-
const staticHit = index.static.get(
|
|
3970
|
+
const staticHit = index.static.get(path17);
|
|
3982
3971
|
if (staticHit) {
|
|
3983
3972
|
return { route: staticHit, params: {} };
|
|
3984
3973
|
}
|
|
3985
3974
|
for (const route of index.dynamics) {
|
|
3986
|
-
const params = matchDynamicPath(route.urlPath,
|
|
3975
|
+
const params = matchDynamicPath(route.urlPath, path17, route.paramNames, route.isCatchAll);
|
|
3987
3976
|
if (params !== null) {
|
|
3988
3977
|
return { route, params };
|
|
3989
3978
|
}
|
|
3990
3979
|
}
|
|
3991
3980
|
return null;
|
|
3992
3981
|
}
|
|
3993
|
-
function findAllowedMethods(routes,
|
|
3982
|
+
function findAllowedMethods(routes, path17) {
|
|
3994
3983
|
const index = getHttpIndex(routes);
|
|
3995
3984
|
const methods = /* @__PURE__ */ new Set();
|
|
3996
|
-
const staticMethods = index.methodsByStaticPath.get(
|
|
3985
|
+
const staticMethods = index.methodsByStaticPath.get(path17);
|
|
3997
3986
|
if (staticMethods) {
|
|
3998
3987
|
for (const method of staticMethods) {
|
|
3999
3988
|
methods.add(method);
|
|
4000
3989
|
}
|
|
4001
3990
|
}
|
|
4002
3991
|
if (index.dynamics.length > 0) {
|
|
4003
|
-
const pathSegments =
|
|
3992
|
+
const pathSegments = path17.split("/").filter(Boolean);
|
|
4004
3993
|
for (const entry of index.dynamics) {
|
|
4005
3994
|
const params = matchSegments(
|
|
4006
3995
|
entry.segments,
|
|
@@ -4018,10 +4007,10 @@ function findAllowedMethods(routes, path18) {
|
|
|
4018
4007
|
}
|
|
4019
4008
|
return Array.from(methods);
|
|
4020
4009
|
}
|
|
4021
|
-
function matchDynamicPath(pattern,
|
|
4010
|
+
function matchDynamicPath(pattern, path17, paramNames, isCatchAll) {
|
|
4022
4011
|
return matchSegments(
|
|
4023
4012
|
pattern.split("/").filter(Boolean),
|
|
4024
|
-
|
|
4013
|
+
path17.split("/").filter(Boolean),
|
|
4025
4014
|
paramNames,
|
|
4026
4015
|
isCatchAll
|
|
4027
4016
|
);
|
|
@@ -4643,17 +4632,9 @@ function logger(options = {}) {
|
|
|
4643
4632
|
}
|
|
4644
4633
|
|
|
4645
4634
|
// src/server/handleWsUpgrade.ts
|
|
4646
|
-
import
|
|
4635
|
+
import fs12 from "fs";
|
|
4647
4636
|
import { WebSocketServer, WebSocket } from "ws";
|
|
4648
|
-
import path15 from "path";
|
|
4649
|
-
|
|
4650
|
-
// src/cli/copyResources.ts
|
|
4651
4637
|
import path14 from "path";
|
|
4652
|
-
import fs12 from "fs";
|
|
4653
|
-
var RESOURCES_OUTPUT_DIR = "resources";
|
|
4654
|
-
function resolveResourcesDir(rootDir, dist) {
|
|
4655
|
-
return path14.resolve(rootDir, dist, RESOURCES_OUTPUT_DIR);
|
|
4656
|
-
}
|
|
4657
4638
|
|
|
4658
4639
|
// src/server/serverUtils.ts
|
|
4659
4640
|
function nodeHttpToWebHeaders(req) {
|
|
@@ -4711,7 +4692,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
|
|
|
4711
4692
|
const dist = getDevDist();
|
|
4712
4693
|
if (dist) {
|
|
4713
4694
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
4714
|
-
if (sourcePath &&
|
|
4695
|
+
if (sourcePath && fs12.existsSync(sourcePath)) {
|
|
4715
4696
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
4716
4697
|
}
|
|
4717
4698
|
}
|
|
@@ -4809,7 +4790,6 @@ function attachWebSocket(options) {
|
|
|
4809
4790
|
trustedProxy = false,
|
|
4810
4791
|
registries
|
|
4811
4792
|
} = options;
|
|
4812
|
-
const resourcesDir = resolveResourcesDir(rootDir, dist);
|
|
4813
4793
|
const wss = new WebSocketServer({ noServer: true });
|
|
4814
4794
|
server.on("upgrade", async (req, socket, head) => {
|
|
4815
4795
|
try {
|
|
@@ -4841,19 +4821,12 @@ function attachWebSocket(options) {
|
|
|
4841
4821
|
const host = req.headers.host ?? "localhost";
|
|
4842
4822
|
const fullUrl = new URL(`http://${host}${req.url ?? "/"}`);
|
|
4843
4823
|
const request = new Request(fullUrl.toString(), { method: "GET", headers });
|
|
4844
|
-
const ctx = createContext(
|
|
4845
|
-
request,
|
|
4846
|
-
params,
|
|
4847
|
-
config,
|
|
4848
|
-
getClientIp(req, trustedProxy),
|
|
4849
|
-
registries,
|
|
4850
|
-
resourcesDir
|
|
4851
|
-
);
|
|
4824
|
+
const ctx = createContext(request, params, config, getClientIp(req, trustedProxy), registries);
|
|
4852
4825
|
const meta = ctx.meta;
|
|
4853
4826
|
let upgraded = false;
|
|
4854
4827
|
const finalHandler = async () => {
|
|
4855
4828
|
const schemaPath = getRuntimeSchemaPath(route.filePath, dist, rootDir);
|
|
4856
|
-
if (
|
|
4829
|
+
if (fs12.existsSync(schemaPath)) {
|
|
4857
4830
|
if (isDevOnDemandEnabled()) {
|
|
4858
4831
|
const devDist = getDevDist();
|
|
4859
4832
|
if (devDist) {
|
|
@@ -4892,7 +4865,7 @@ function attachWebSocket(options) {
|
|
|
4892
4865
|
}
|
|
4893
4866
|
let handlers;
|
|
4894
4867
|
try {
|
|
4895
|
-
const absoluteFilePath =
|
|
4868
|
+
const absoluteFilePath = path14.resolve(rootDir, route.filePath);
|
|
4896
4869
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
4897
4870
|
} catch (err) {
|
|
4898
4871
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -5051,7 +5024,6 @@ function createServer(options) {
|
|
|
5051
5024
|
trustedProxy = false
|
|
5052
5025
|
} = options;
|
|
5053
5026
|
const routesRef = { current: routes, wsCurrent: wsRoutes ?? [] };
|
|
5054
|
-
const resourcesDir = resolveResourcesDir(rootDir, dist);
|
|
5055
5027
|
const configMiddlewares = [];
|
|
5056
5028
|
if (compressionOption) {
|
|
5057
5029
|
const compOpts = typeof compressionOption === "object" ? compressionOption : {};
|
|
@@ -5098,8 +5070,7 @@ function createServer(options) {
|
|
|
5098
5070
|
bodyLimit,
|
|
5099
5071
|
trustedProxy,
|
|
5100
5072
|
registries,
|
|
5101
|
-
routesRef.wsCurrent
|
|
5102
|
-
resourcesDir
|
|
5073
|
+
routesRef.wsCurrent
|
|
5103
5074
|
).catch((err) => {
|
|
5104
5075
|
console.error("[faapi] Request pipeline failed after error response attempt:", err);
|
|
5105
5076
|
try {
|
|
@@ -5125,7 +5096,7 @@ function createServer(options) {
|
|
|
5125
5096
|
});
|
|
5126
5097
|
return { server, routesRef };
|
|
5127
5098
|
}
|
|
5128
|
-
function prepareRequest(req, request, url, config, trustedProxy, registries, preMatched
|
|
5099
|
+
function prepareRequest(req, request, url, config, trustedProxy, registries, preMatched) {
|
|
5129
5100
|
const method = request.method.toUpperCase();
|
|
5130
5101
|
const urlPath = url.pathname;
|
|
5131
5102
|
const ctx = createContextFromUrl(
|
|
@@ -5134,8 +5105,7 @@ function prepareRequest(req, request, url, config, trustedProxy, registries, pre
|
|
|
5134
5105
|
preMatched?.params ?? {},
|
|
5135
5106
|
config,
|
|
5136
5107
|
getClientIp(req, trustedProxy),
|
|
5137
|
-
registries
|
|
5138
|
-
resourcesDir
|
|
5108
|
+
registries
|
|
5139
5109
|
);
|
|
5140
5110
|
const meta = ctx.meta;
|
|
5141
5111
|
return { request, url, ctx, meta, method, urlPath };
|
|
@@ -5154,7 +5124,7 @@ function getRoutePaths(route, rootDir, dist) {
|
|
|
5154
5124
|
let cached = routePathCache.get(route);
|
|
5155
5125
|
if (!cached) {
|
|
5156
5126
|
cached = {
|
|
5157
|
-
absFilePath:
|
|
5127
|
+
absFilePath: path15.resolve(rootDir, route.filePath),
|
|
5158
5128
|
schemaPath: getRuntimeSchemaPath(route.filePath, dist, rootDir)
|
|
5159
5129
|
};
|
|
5160
5130
|
routePathCache.set(route, cached);
|
|
@@ -5277,7 +5247,7 @@ async function sendErrorResponse(err, meta, res, onError, ctx) {
|
|
|
5277
5247
|
}
|
|
5278
5248
|
}
|
|
5279
5249
|
}
|
|
5280
|
-
async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares, onError, config, globalInjectors, bodyLimit, trustedProxy, registries, wsRoutes
|
|
5250
|
+
async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares, onError, config, globalInjectors, bodyLimit, trustedProxy, registries, wsRoutes) {
|
|
5281
5251
|
let meta = { headers: {}, setCookies: [] };
|
|
5282
5252
|
let ctx;
|
|
5283
5253
|
let sseEarlySent = false;
|
|
@@ -5297,8 +5267,7 @@ async function handleRequest(routes, rootDir, dist, req, res, outerMiddlewares,
|
|
|
5297
5267
|
config,
|
|
5298
5268
|
trustedProxy,
|
|
5299
5269
|
registries,
|
|
5300
|
-
preMatched
|
|
5301
|
-
resourcesDir
|
|
5270
|
+
preMatched
|
|
5302
5271
|
);
|
|
5303
5272
|
ctx = prepared.ctx;
|
|
5304
5273
|
meta = prepared.meta;
|
|
@@ -5363,7 +5332,7 @@ async function createTestServer(options) {
|
|
|
5363
5332
|
} = options;
|
|
5364
5333
|
const { routes, wsRoutes } = await scanRoutes(rootDir, patterns);
|
|
5365
5334
|
const sorted = sortRoutes(routes);
|
|
5366
|
-
const schemaDist = dist ?
|
|
5335
|
+
const schemaDist = dist ? path16.isAbsolute(dist) ? dist : path16.resolve(rootDir, dist) : await fs13.mkdtemp(path16.join(os.tmpdir(), "faapi-test-schema-"));
|
|
5367
5336
|
await generateSchemaFiles(sorted, rootDir, schemaDist);
|
|
5368
5337
|
const { server } = createServer({
|
|
5369
5338
|
routes: sorted,
|
|
@@ -5395,7 +5364,7 @@ async function createTestServer(options) {
|
|
|
5395
5364
|
await new Promise((resolve) => {
|
|
5396
5365
|
server.close(() => resolve());
|
|
5397
5366
|
});
|
|
5398
|
-
await
|
|
5367
|
+
await fs13.rm(schemaDist, { recursive: true, force: true }).catch(() => {
|
|
5399
5368
|
});
|
|
5400
5369
|
invalidateSchemaCache();
|
|
5401
5370
|
}
|