vafast 0.3.4 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +230 -239
- package/dist/index.js.map +1 -1
- package/dist/monitoring/index.js +40 -12
- package/dist/monitoring/index.js.map +1 -1
- package/dist/monitoring/native-monitor.js +40 -12
- package/dist/monitoring/native-monitor.js.map +1 -1
- package/dist/server/index.js +40 -12
- package/dist/server/index.js.map +1 -1
- package/dist/server/server-factory.js +40 -12
- package/dist/server/server-factory.js.map +1 -1
- package/dist/server/server.d.ts +2 -0
- package/dist/server/server.js +40 -12
- package/dist/server/server.js.map +1 -1
- package/dist/utils/create-handler.js +34 -146
- package/dist/utils/create-handler.js.map +1 -1
- package/dist/utils/formats.d.ts +40 -0
- package/dist/utils/formats.js +116 -0
- package/dist/utils/formats.js.map +1 -0
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +187 -226
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/request-validator.d.ts +1 -1
- package/dist/utils/request-validator.js +26 -112
- package/dist/utils/request-validator.js.map +1 -1
- package/dist/utils/validators/validators.d.ts +44 -36
- package/dist/utils/validators/validators.js +43 -39
- package/dist/utils/validators/validators.js.map +1 -1
- package/package.json +4 -4
- package/dist/utils/validators/schema-validator.d.ts +0 -70
- package/dist/utils/validators/schema-validator.js +0 -241
- package/dist/utils/validators/schema-validator.js.map +0 -1
- package/dist/utils/validators/schema-validators-ultra.d.ts +0 -54
- package/dist/utils/validators/schema-validators-ultra.js +0 -266
- package/dist/utils/validators/schema-validators-ultra.js.map +0 -1
package/README.md
CHANGED
|
@@ -445,6 +445,51 @@ precompileSchemas([UserSchema, PostSchema, CommentSchema]);
|
|
|
445
445
|
|
|
446
446
|
**性能效果:首次编译后,10000 次验证仅需 ~5ms**
|
|
447
447
|
|
|
448
|
+
### 内置 Format 验证器
|
|
449
|
+
|
|
450
|
+
Vafast 内置 30+ 常用 format 验证器,**导入框架时自动注册**,对标 Zod 的内置验证:
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
import { Type, createHandler } from 'vafast';
|
|
454
|
+
|
|
455
|
+
// 直接使用内置 format,无需手动注册
|
|
456
|
+
const UserSchema = Type.Object({
|
|
457
|
+
email: Type.String({ format: 'email' }),
|
|
458
|
+
phone: Type.String({ format: 'phone' }), // 中国手机号
|
|
459
|
+
website: Type.String({ format: 'url' }),
|
|
460
|
+
avatar: Type.String({ format: 'uuid' }),
|
|
461
|
+
createdAt: Type.String({ format: 'date-time' }),
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
const handler = createHandler({ body: UserSchema }, ({ body }) => {
|
|
465
|
+
return { success: true, user: body };
|
|
466
|
+
});
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**支持的 Format 列表:**
|
|
470
|
+
|
|
471
|
+
| 分类 | Format | 说明 |
|
|
472
|
+
|------|--------|------|
|
|
473
|
+
| **标识符** | `email`, `uuid`, `cuid`, `cuid2`, `ulid`, `nanoid`, `objectid`, `slug` | 各种 ID 格式 |
|
|
474
|
+
| **网络** | `url`, `uri`, `ipv4`, `ipv6`, `ip`, `cidr`, `hostname` | 网络地址 |
|
|
475
|
+
| **日期时间** | `date`, `time`, `date-time`, `datetime`, `duration` | ISO 8601 格式 |
|
|
476
|
+
| **手机号** | `phone` (中国), `phone-cn`, `phone-e164` (国际) | 电话号码 |
|
|
477
|
+
| **编码** | `base64`, `base64url`, `jwt` | 编码格式 |
|
|
478
|
+
| **颜色** | `hex-color`, `rgb-color`, `color` | 颜色值 |
|
|
479
|
+
| **其他** | `emoji`, `semver`, `credit-card` | 特殊格式 |
|
|
480
|
+
|
|
481
|
+
**自定义 Format:**
|
|
482
|
+
|
|
483
|
+
```typescript
|
|
484
|
+
import { registerFormat, Patterns } from 'vafast';
|
|
485
|
+
|
|
486
|
+
// 注册自定义 format
|
|
487
|
+
registerFormat('order-id', (v) => /^ORD-\d{8}$/.test(v));
|
|
488
|
+
|
|
489
|
+
// 使用内置正则(供外部使用)
|
|
490
|
+
const isEmail = Patterns.EMAIL.test('test@example.com');
|
|
491
|
+
```
|
|
492
|
+
|
|
448
493
|
### 中间件预编译
|
|
449
494
|
|
|
450
495
|
Vafast 自动在路由注册时预编译中间件链,消除运行时组合开销:
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,8 @@ export { getLocals, setLocals } from './utils/handle.js';
|
|
|
12
12
|
export { createRequestValidator, parseAndValidateRequest, parseRequest, validateRequest } from './utils/request-validator.js';
|
|
13
13
|
export { HtmlRenderer } from './utils/html-renderer.js';
|
|
14
14
|
export { DependencyManager } from './utils/dependency-manager.js';
|
|
15
|
-
export { createValidator, getValidatorCacheStats, precompileSchemas, validateFast, validateSchema } from './utils/validators/validators.js';
|
|
15
|
+
export { SchemaConfig, ValidationError, ValidationResult, createValidator, getValidatorCacheStats, precompileSchemas, validateAllSchemas, validateFast, validateSchema, validateSchemaOrThrow } from './utils/validators/validators.js';
|
|
16
|
+
export { Patterns, hasFormat, registerFormat, registerFormats } from './utils/formats.js';
|
|
16
17
|
export { flattenNestedRoutes, normalizePath } from './router.js';
|
|
17
18
|
export { requireAuth } from './middleware/authMiddleware.js';
|
|
18
19
|
export { rateLimit } from './middleware/rateLimit.js';
|
|
@@ -25,6 +26,5 @@ export { BaseRouteConfig, CompatibleRoute, ExtendedRouteConfig, NestedRouteConfi
|
|
|
25
26
|
export { ComponentRoute, FlattenedComponentRoute, NestedComponentRoute } from './types/component-route.js';
|
|
26
27
|
export { HandlerContext, HandlerContextWithExtra, InferSchema, RouteSchema, TypedHandler, TypedRouteConfig } from './types/schema.js';
|
|
27
28
|
export { FetchHandler, ServeOptions, ServeResult, serve } from './node-server/serve.js';
|
|
28
|
-
export { Type } from '@sinclair/typebox';
|
|
29
|
-
import './utils/validators/schema-validators-ultra.js';
|
|
29
|
+
export { FormatRegistry, Type } from '@sinclair/typebox';
|
|
30
30
|
import 'node:http';
|
package/dist/index.js
CHANGED
|
@@ -551,6 +551,23 @@ var Server = class extends BaseServer {
|
|
|
551
551
|
if (end === -1) end = url.length;
|
|
552
552
|
return url.substring(pathStart, end) || "/";
|
|
553
553
|
}
|
|
554
|
+
/** 生成 404/405 响应 */
|
|
555
|
+
createErrorResponse(method, pathname) {
|
|
556
|
+
const allowedMethods = this.router.getAllowedMethods(pathname);
|
|
557
|
+
if (allowedMethods.length > 0) {
|
|
558
|
+
return json(
|
|
559
|
+
{
|
|
560
|
+
success: false,
|
|
561
|
+
error: "Method Not Allowed",
|
|
562
|
+
message: `Method ${method} not allowed for this endpoint`,
|
|
563
|
+
allowedMethods
|
|
564
|
+
},
|
|
565
|
+
405,
|
|
566
|
+
{ Allow: allowedMethods.join(", ") }
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
return json({ success: false, error: "Not Found" }, 404);
|
|
570
|
+
}
|
|
554
571
|
/** 处理请求 */
|
|
555
572
|
fetch = async (req) => {
|
|
556
573
|
const pathname = this.extractPathname(req.url);
|
|
@@ -565,20 +582,31 @@ var Server = class extends BaseServer {
|
|
|
565
582
|
const handler = composeMiddleware(allMiddleware, match.handler);
|
|
566
583
|
return handler(req);
|
|
567
584
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
585
|
+
if (method === "OPTIONS") {
|
|
586
|
+
const allowedMethods = this.router.getAllowedMethods(pathname);
|
|
587
|
+
if (allowedMethods.length > 0) {
|
|
588
|
+
const anyMatch = this.router.match(
|
|
589
|
+
allowedMethods[0],
|
|
590
|
+
pathname
|
|
591
|
+
);
|
|
592
|
+
const routeMiddleware = anyMatch?.middleware || [];
|
|
593
|
+
const allMiddleware = [...this.globalMiddleware, ...routeMiddleware];
|
|
594
|
+
const optionsHandler = () => new Response(null, {
|
|
595
|
+
status: 204,
|
|
596
|
+
headers: { Allow: allowedMethods.join(", ") }
|
|
597
|
+
});
|
|
598
|
+
const handler = composeMiddleware(allMiddleware, optionsHandler);
|
|
599
|
+
return handler(req);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (this.globalMiddleware.length > 0) {
|
|
603
|
+
const handler = composeMiddleware(
|
|
604
|
+
this.globalMiddleware,
|
|
605
|
+
() => this.createErrorResponse(method, pathname)
|
|
579
606
|
);
|
|
607
|
+
return handler(req);
|
|
580
608
|
}
|
|
581
|
-
return
|
|
609
|
+
return this.createErrorResponse(method, pathname);
|
|
582
610
|
};
|
|
583
611
|
addRoute(route) {
|
|
584
612
|
const flattenedRoute = {
|
|
@@ -1125,142 +1153,91 @@ function goAwait(promise) {
|
|
|
1125
1153
|
return promise.then((data) => [null, data]).catch((err) => [err instanceof Error ? err : new Error(String(err)), void 0]);
|
|
1126
1154
|
}
|
|
1127
1155
|
|
|
1128
|
-
// src/utils/validators/
|
|
1156
|
+
// src/utils/validators/validators.ts
|
|
1157
|
+
import { Type } from "@sinclair/typebox";
|
|
1129
1158
|
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
1130
|
-
var
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
// 2
|
|
1135
|
-
PARAMS: 1 << 2,
|
|
1136
|
-
// 4
|
|
1137
|
-
HEADERS: 1 << 3,
|
|
1138
|
-
// 8
|
|
1139
|
-
COOKIES: 1 << 4
|
|
1140
|
-
// 16
|
|
1141
|
-
};
|
|
1142
|
-
var ultraSchemaCache = /* @__PURE__ */ new Map();
|
|
1143
|
-
var schemaCacheHits = /* @__PURE__ */ new Map();
|
|
1144
|
-
var errorPool = [];
|
|
1145
|
-
var ERROR_POOL_SIZE = 200;
|
|
1146
|
-
var errorMessagePool = /* @__PURE__ */ new Map();
|
|
1147
|
-
var commonMessages = [
|
|
1148
|
-
"\u8BF7\u6C42\u4F53\u9A8C\u8BC1\u5931\u8D25",
|
|
1149
|
-
"Query\u53C2\u6570\u9A8C\u8BC1\u5931\u8D25",
|
|
1150
|
-
"\u8DEF\u5F84\u53C2\u6570\u9A8C\u8BC1\u5931\u8D25",
|
|
1151
|
-
"\u8BF7\u6C42\u5934\u9A8C\u8BC1\u5931\u8D25",
|
|
1152
|
-
"Cookie\u9A8C\u8BC1\u5931\u8D25",
|
|
1153
|
-
"\u7C7B\u578B\u9A8C\u8BC1\u5931\u8D25",
|
|
1154
|
-
"Schema\u7F16\u8BD1\u5931\u8D25",
|
|
1155
|
-
"\u672A\u77E5\u9519\u8BEF"
|
|
1156
|
-
];
|
|
1157
|
-
commonMessages.forEach((msg) => errorMessagePool.set(msg, msg));
|
|
1158
|
-
for (let i = 0; i < ERROR_POOL_SIZE; i++) {
|
|
1159
|
-
errorPool.push(new Error());
|
|
1160
|
-
}
|
|
1161
|
-
var errorPoolIndex = 0;
|
|
1162
|
-
function getErrorFromPool(message) {
|
|
1163
|
-
const error = errorPool[errorPoolIndex];
|
|
1164
|
-
error.message = message;
|
|
1165
|
-
errorPoolIndex = (errorPoolIndex + 1) % ERROR_POOL_SIZE;
|
|
1166
|
-
return error;
|
|
1167
|
-
}
|
|
1168
|
-
function getPooledString(key) {
|
|
1169
|
-
let pooled = errorMessagePool.get(key);
|
|
1170
|
-
if (!pooled) {
|
|
1171
|
-
pooled = key;
|
|
1172
|
-
errorMessagePool.set(key, key);
|
|
1173
|
-
}
|
|
1174
|
-
return pooled;
|
|
1175
|
-
}
|
|
1176
|
-
function getUltraSchemaCompiler(schema) {
|
|
1177
|
-
let compiler = ultraSchemaCache.get(schema);
|
|
1178
|
-
if (compiler) {
|
|
1179
|
-
schemaCacheHits.set(schema, (schemaCacheHits.get(schema) || 0) + 1);
|
|
1180
|
-
return compiler;
|
|
1181
|
-
}
|
|
1182
|
-
try {
|
|
1159
|
+
var compilerCache = /* @__PURE__ */ new WeakMap();
|
|
1160
|
+
function getCompiledValidator(schema) {
|
|
1161
|
+
let compiler = compilerCache.get(schema);
|
|
1162
|
+
if (!compiler) {
|
|
1183
1163
|
compiler = TypeCompiler.Compile(schema);
|
|
1184
|
-
|
|
1185
|
-
return compiler;
|
|
1186
|
-
} catch (error) {
|
|
1187
|
-
return null;
|
|
1164
|
+
compilerCache.set(schema, compiler);
|
|
1188
1165
|
}
|
|
1166
|
+
return compiler;
|
|
1189
1167
|
}
|
|
1190
|
-
function
|
|
1191
|
-
let flags = 0;
|
|
1192
|
-
if (config.body) flags |= SCHEMA_FLAGS.BODY;
|
|
1193
|
-
if (config.query) flags |= SCHEMA_FLAGS.QUERY;
|
|
1194
|
-
if (config.params) flags |= SCHEMA_FLAGS.PARAMS;
|
|
1195
|
-
if (config.headers) flags |= SCHEMA_FLAGS.HEADERS;
|
|
1196
|
-
if (config.cookies) flags |= SCHEMA_FLAGS.COOKIES;
|
|
1197
|
-
return flags;
|
|
1198
|
-
}
|
|
1199
|
-
function validateSchemaUltra(schema, data, context) {
|
|
1200
|
-
if (!schema) return data;
|
|
1168
|
+
function validateSchema(schema, data) {
|
|
1201
1169
|
try {
|
|
1202
|
-
|
|
1203
|
-
if (
|
|
1204
|
-
|
|
1205
|
-
compiler = TypeCompiler.Compile(schema);
|
|
1206
|
-
ultraSchemaCache.set(schema, compiler);
|
|
1207
|
-
} catch (error) {
|
|
1208
|
-
const message = getPooledString(`${context}\u9A8C\u8BC1\u5931\u8D25: Schema\u7F16\u8BD1\u5931\u8D25`);
|
|
1209
|
-
throw getErrorFromPool(message);
|
|
1210
|
-
}
|
|
1170
|
+
const compiler = getCompiledValidator(schema);
|
|
1171
|
+
if (compiler.Check(data)) {
|
|
1172
|
+
return { success: true, data };
|
|
1211
1173
|
}
|
|
1212
|
-
const
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1174
|
+
const errors = [];
|
|
1175
|
+
for (const error of compiler.Errors(data)) {
|
|
1176
|
+
errors.push({
|
|
1177
|
+
path: error.path,
|
|
1178
|
+
message: error.message,
|
|
1179
|
+
code: "VALIDATION_FAILED",
|
|
1180
|
+
value: error.value
|
|
1181
|
+
});
|
|
1216
1182
|
}
|
|
1217
|
-
return
|
|
1183
|
+
return { success: false, errors };
|
|
1218
1184
|
} catch (error) {
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1185
|
+
return {
|
|
1186
|
+
success: false,
|
|
1187
|
+
errors: [
|
|
1188
|
+
{
|
|
1189
|
+
path: "",
|
|
1190
|
+
message: error instanceof Error ? error.message : "\u9A8C\u8BC1\u5F02\u5E38",
|
|
1191
|
+
code: "VALIDATION_EXCEPTION"
|
|
1192
|
+
}
|
|
1193
|
+
]
|
|
1194
|
+
};
|
|
1226
1195
|
}
|
|
1227
1196
|
}
|
|
1228
|
-
function
|
|
1229
|
-
const
|
|
1230
|
-
if (
|
|
1231
|
-
|
|
1232
|
-
}
|
|
1233
|
-
if (flags & SCHEMA_FLAGS.QUERY) {
|
|
1234
|
-
validateSchemaUltra(config.query, data.query, "Query\u53C2\u6570");
|
|
1235
|
-
}
|
|
1236
|
-
if (flags & SCHEMA_FLAGS.PARAMS) {
|
|
1237
|
-
validateSchemaUltra(config.params, data.params, "\u8DEF\u5F84\u53C2\u6570");
|
|
1238
|
-
}
|
|
1239
|
-
if (flags & SCHEMA_FLAGS.HEADERS) {
|
|
1240
|
-
validateSchemaUltra(config.headers, data.headers, "\u8BF7\u6C42\u5934");
|
|
1241
|
-
}
|
|
1242
|
-
if (flags & SCHEMA_FLAGS.COOKIES) {
|
|
1243
|
-
validateSchemaUltra(config.cookies, data.cookies, "Cookie");
|
|
1197
|
+
function validateSchemaOrThrow(schema, data, context) {
|
|
1198
|
+
const compiler = getCompiledValidator(schema);
|
|
1199
|
+
if (!compiler.Check(data)) {
|
|
1200
|
+
throw new Error(`${context}\u9A8C\u8BC1\u5931\u8D25`);
|
|
1244
1201
|
}
|
|
1245
1202
|
return data;
|
|
1246
1203
|
}
|
|
1247
|
-
function
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
|
|
1204
|
+
function validateFast(schema, data) {
|
|
1205
|
+
const compiler = getCompiledValidator(schema);
|
|
1206
|
+
return compiler.Check(data);
|
|
1207
|
+
}
|
|
1208
|
+
function validateAllSchemas(config, data) {
|
|
1209
|
+
if (config.body) {
|
|
1210
|
+
validateSchemaOrThrow(config.body, data.body, "\u8BF7\u6C42\u4F53");
|
|
1251
1211
|
}
|
|
1252
|
-
if (
|
|
1253
|
-
|
|
1212
|
+
if (config.query) {
|
|
1213
|
+
validateSchemaOrThrow(config.query, data.query, "Query\u53C2\u6570");
|
|
1254
1214
|
}
|
|
1255
|
-
if (
|
|
1256
|
-
|
|
1215
|
+
if (config.params) {
|
|
1216
|
+
validateSchemaOrThrow(config.params, data.params, "\u8DEF\u5F84\u53C2\u6570");
|
|
1257
1217
|
}
|
|
1258
|
-
if (
|
|
1259
|
-
|
|
1218
|
+
if (config.headers) {
|
|
1219
|
+
validateSchemaOrThrow(config.headers, data.headers, "\u8BF7\u6C42\u5934");
|
|
1260
1220
|
}
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1221
|
+
if (config.cookies) {
|
|
1222
|
+
validateSchemaOrThrow(config.cookies, data.cookies, "Cookie");
|
|
1263
1223
|
}
|
|
1224
|
+
return data;
|
|
1225
|
+
}
|
|
1226
|
+
function precompileSchemas(config) {
|
|
1227
|
+
if (config.body) getCompiledValidator(config.body);
|
|
1228
|
+
if (config.query) getCompiledValidator(config.query);
|
|
1229
|
+
if (config.params) getCompiledValidator(config.params);
|
|
1230
|
+
if (config.headers) getCompiledValidator(config.headers);
|
|
1231
|
+
if (config.cookies) getCompiledValidator(config.cookies);
|
|
1232
|
+
}
|
|
1233
|
+
function createValidator(schema) {
|
|
1234
|
+
return (data) => validateSchema(schema, data);
|
|
1235
|
+
}
|
|
1236
|
+
function getValidatorCacheStats() {
|
|
1237
|
+
return {
|
|
1238
|
+
cacheType: "WeakMap",
|
|
1239
|
+
note: "WeakMap \u7F13\u5B58\u4F1A\u968F Schema \u5BF9\u8C61\u81EA\u52A8\u6E05\u7406\uFF0C\u65E0\u5185\u5B58\u6CC4\u6F0F\u98CE\u9669"
|
|
1240
|
+
};
|
|
1264
1241
|
}
|
|
1265
1242
|
|
|
1266
1243
|
// src/utils/create-handler.ts
|
|
@@ -1335,7 +1312,7 @@ function createHandler(schemaOrHandler, maybeHandler) {
|
|
|
1335
1312
|
const schema = hasSchema ? schemaOrHandler : {};
|
|
1336
1313
|
const handler = hasSchema ? maybeHandler : schemaOrHandler;
|
|
1337
1314
|
if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
|
|
1338
|
-
|
|
1315
|
+
precompileSchemas(schema);
|
|
1339
1316
|
}
|
|
1340
1317
|
return async (req) => {
|
|
1341
1318
|
try {
|
|
@@ -1350,7 +1327,7 @@ function createHandler(schemaOrHandler, maybeHandler) {
|
|
|
1350
1327
|
}
|
|
1351
1328
|
const data = { body, query, params, headers, cookies };
|
|
1352
1329
|
if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
|
|
1353
|
-
|
|
1330
|
+
validateAllSchemas(schema, data);
|
|
1354
1331
|
}
|
|
1355
1332
|
const result = await handler({
|
|
1356
1333
|
req,
|
|
@@ -1374,7 +1351,7 @@ function createHandlerWithExtra(schemaOrHandler, maybeHandler) {
|
|
|
1374
1351
|
const schema = hasSchema ? schemaOrHandler : {};
|
|
1375
1352
|
const handler = hasSchema ? maybeHandler : schemaOrHandler;
|
|
1376
1353
|
if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
|
|
1377
|
-
|
|
1354
|
+
precompileSchemas(schema);
|
|
1378
1355
|
}
|
|
1379
1356
|
return async (req) => {
|
|
1380
1357
|
try {
|
|
@@ -1389,7 +1366,7 @@ function createHandlerWithExtra(schemaOrHandler, maybeHandler) {
|
|
|
1389
1366
|
}
|
|
1390
1367
|
const data = { body, query, params, headers, cookies };
|
|
1391
1368
|
if (schema.body || schema.query || schema.params || schema.headers || schema.cookies) {
|
|
1392
|
-
|
|
1369
|
+
validateAllSchemas(schema, data);
|
|
1393
1370
|
}
|
|
1394
1371
|
const extras = req.__locals ?? {};
|
|
1395
1372
|
const result = await handler({
|
|
@@ -1461,7 +1438,7 @@ async function parseRequest(request, params) {
|
|
|
1461
1438
|
}
|
|
1462
1439
|
function validateRequest(config, requestData) {
|
|
1463
1440
|
try {
|
|
1464
|
-
const validatedData =
|
|
1441
|
+
const validatedData = validateAllSchemas(config, requestData);
|
|
1465
1442
|
return {
|
|
1466
1443
|
success: true,
|
|
1467
1444
|
data: validatedData
|
|
@@ -1500,90 +1477,115 @@ function createRequestValidator(config) {
|
|
|
1500
1477
|
};
|
|
1501
1478
|
}
|
|
1502
1479
|
|
|
1503
|
-
// src/utils/
|
|
1504
|
-
import {
|
|
1505
|
-
|
|
1506
|
-
var
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1480
|
+
// src/utils/formats.ts
|
|
1481
|
+
import { FormatRegistry } from "@sinclair/typebox";
|
|
1482
|
+
var EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
1483
|
+
var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1484
|
+
var UUID_ANY_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1485
|
+
var CUID_REGEX = /^c[^\s-]{8,}$/i;
|
|
1486
|
+
var CUID2_REGEX = /^[0-9a-z]+$/;
|
|
1487
|
+
var ULID_REGEX = /^[0-9A-HJKMNP-TV-Z]{26}$/i;
|
|
1488
|
+
var NANOID_REGEX = /^[A-Za-z0-9_-]{21}$/;
|
|
1489
|
+
var URL_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b[-a-zA-Z0-9()@:%_+.~#?&/=]*$/;
|
|
1490
|
+
var IPV4_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
1491
|
+
var IPV6_REGEX = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,7}:$|^(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}$|^(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}$|^(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}$/;
|
|
1492
|
+
var CIDR_REGEX = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(?:3[0-2]|[12]?[0-9])$/;
|
|
1493
|
+
var DATE_REGEX = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])$/;
|
|
1494
|
+
var TIME_REGEX = /^(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\.\d{1,3})?$/;
|
|
1495
|
+
var DATE_TIME_REGEX = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])T(?:[01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](?:\.\d{1,3})?(?:Z|[+-](?:[01][0-9]|2[0-3]):[0-5][0-9])?$/;
|
|
1496
|
+
var DURATION_REGEX = /^P(?:\d+Y)?(?:\d+M)?(?:\d+W)?(?:\d+D)?(?:T(?:\d+H)?(?:\d+M)?(?:\d+(?:\.\d+)?S)?)?$/;
|
|
1497
|
+
var HOSTNAME_REGEX = /^(?=.{1,253}$)(?:(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)*(?!-)[a-zA-Z0-9-]{1,63}(?<!-)$/;
|
|
1498
|
+
var PHONE_CN_REGEX = /^1[3-9]\d{9}$/;
|
|
1499
|
+
var PHONE_E164_REGEX = /^\+[1-9]\d{6,14}$/;
|
|
1500
|
+
var OBJECTID_REGEX = /^[0-9a-fA-F]{24}$/;
|
|
1501
|
+
var HEX_COLOR_REGEX = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
|
|
1502
|
+
var RGB_COLOR_REGEX = /^rgba?\(\s*(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s*,\s*(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\s*,\s*(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/;
|
|
1503
|
+
var BASE64_REGEX = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
1504
|
+
var BASE64URL_REGEX = /^[A-Za-z0-9_-]+$/;
|
|
1505
|
+
var JWT_REGEX = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
|
|
1506
|
+
var EMOJI_REGEX = /^[\p{Emoji}]+$/u;
|
|
1507
|
+
var SLUG_REGEX = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1508
|
+
var SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
1509
|
+
function isValidCreditCard(value) {
|
|
1510
|
+
const digits = value.replace(/\D/g, "");
|
|
1511
|
+
if (digits.length < 13 || digits.length > 19) return false;
|
|
1512
|
+
let sum = 0;
|
|
1513
|
+
let isEven = false;
|
|
1514
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
1515
|
+
let digit = parseInt(digits[i], 10);
|
|
1516
|
+
if (isEven) {
|
|
1517
|
+
digit *= 2;
|
|
1518
|
+
if (digit > 9) digit -= 9;
|
|
1519
|
+
}
|
|
1520
|
+
sum += digit;
|
|
1521
|
+
isEven = !isEven;
|
|
1522
|
+
}
|
|
1523
|
+
return sum % 10 === 0;
|
|
1524
|
+
}
|
|
1525
|
+
var isRegistered = false;
|
|
1526
|
+
function registerFormats() {
|
|
1527
|
+
if (isRegistered) return;
|
|
1528
|
+
isRegistered = true;
|
|
1529
|
+
FormatRegistry.Set("email", (v) => EMAIL_REGEX.test(v));
|
|
1530
|
+
FormatRegistry.Set("uuid", (v) => UUID_REGEX.test(v));
|
|
1531
|
+
FormatRegistry.Set("uuid-any", (v) => UUID_ANY_REGEX.test(v));
|
|
1532
|
+
FormatRegistry.Set("cuid", (v) => CUID_REGEX.test(v));
|
|
1533
|
+
FormatRegistry.Set("cuid2", (v) => CUID2_REGEX.test(v) && v.length >= 1);
|
|
1534
|
+
FormatRegistry.Set("ulid", (v) => ULID_REGEX.test(v));
|
|
1535
|
+
FormatRegistry.Set("nanoid", (v) => NANOID_REGEX.test(v));
|
|
1536
|
+
FormatRegistry.Set("objectid", (v) => OBJECTID_REGEX.test(v));
|
|
1537
|
+
FormatRegistry.Set("slug", (v) => SLUG_REGEX.test(v));
|
|
1538
|
+
FormatRegistry.Set("url", (v) => URL_REGEX.test(v));
|
|
1539
|
+
FormatRegistry.Set("uri", (v) => URL_REGEX.test(v));
|
|
1540
|
+
FormatRegistry.Set("ipv4", (v) => IPV4_REGEX.test(v));
|
|
1541
|
+
FormatRegistry.Set("ipv6", (v) => IPV6_REGEX.test(v));
|
|
1542
|
+
FormatRegistry.Set("ip", (v) => IPV4_REGEX.test(v) || IPV6_REGEX.test(v));
|
|
1543
|
+
FormatRegistry.Set("cidr", (v) => CIDR_REGEX.test(v));
|
|
1544
|
+
FormatRegistry.Set("hostname", (v) => HOSTNAME_REGEX.test(v));
|
|
1545
|
+
FormatRegistry.Set("date", (v) => DATE_REGEX.test(v));
|
|
1546
|
+
FormatRegistry.Set("time", (v) => TIME_REGEX.test(v));
|
|
1547
|
+
FormatRegistry.Set("date-time", (v) => DATE_TIME_REGEX.test(v));
|
|
1548
|
+
FormatRegistry.Set("datetime", (v) => DATE_TIME_REGEX.test(v));
|
|
1549
|
+
FormatRegistry.Set("duration", (v) => DURATION_REGEX.test(v));
|
|
1550
|
+
FormatRegistry.Set("phone", (v) => PHONE_CN_REGEX.test(v));
|
|
1551
|
+
FormatRegistry.Set("phone-cn", (v) => PHONE_CN_REGEX.test(v));
|
|
1552
|
+
FormatRegistry.Set("phone-e164", (v) => PHONE_E164_REGEX.test(v));
|
|
1553
|
+
FormatRegistry.Set("base64", (v) => BASE64_REGEX.test(v));
|
|
1554
|
+
FormatRegistry.Set("base64url", (v) => BASE64URL_REGEX.test(v));
|
|
1555
|
+
FormatRegistry.Set("jwt", (v) => JWT_REGEX.test(v));
|
|
1556
|
+
FormatRegistry.Set("hex-color", (v) => HEX_COLOR_REGEX.test(v));
|
|
1557
|
+
FormatRegistry.Set("rgb-color", (v) => RGB_COLOR_REGEX.test(v));
|
|
1558
|
+
FormatRegistry.Set(
|
|
1559
|
+
"color",
|
|
1560
|
+
(v) => HEX_COLOR_REGEX.test(v) || RGB_COLOR_REGEX.test(v)
|
|
1561
|
+
);
|
|
1562
|
+
FormatRegistry.Set("emoji", (v) => EMOJI_REGEX.test(v));
|
|
1563
|
+
FormatRegistry.Set("semver", (v) => SEMVER_REGEX.test(v));
|
|
1564
|
+
FormatRegistry.Set("credit-card", isValidCreditCard);
|
|
1565
|
+
}
|
|
1566
|
+
function registerFormat(name, validator) {
|
|
1567
|
+
FormatRegistry.Set(name, validator);
|
|
1568
|
+
}
|
|
1569
|
+
function hasFormat(name) {
|
|
1570
|
+
return FormatRegistry.Has(name);
|
|
1571
|
+
}
|
|
1572
|
+
var Patterns = {
|
|
1573
|
+
EMAIL: EMAIL_REGEX,
|
|
1574
|
+
UUID: UUID_REGEX,
|
|
1575
|
+
URL: URL_REGEX,
|
|
1576
|
+
IPV4: IPV4_REGEX,
|
|
1577
|
+
IPV6: IPV6_REGEX,
|
|
1578
|
+
DATE: DATE_REGEX,
|
|
1579
|
+
TIME: TIME_REGEX,
|
|
1580
|
+
DATE_TIME: DATE_TIME_REGEX,
|
|
1581
|
+
PHONE_CN: PHONE_CN_REGEX,
|
|
1582
|
+
PHONE_E164: PHONE_E164_REGEX,
|
|
1583
|
+
OBJECTID: OBJECTID_REGEX,
|
|
1584
|
+
HEX_COLOR: HEX_COLOR_REGEX,
|
|
1585
|
+
SLUG: SLUG_REGEX,
|
|
1586
|
+
SEMVER: SEMVER_REGEX,
|
|
1587
|
+
JWT: JWT_REGEX
|
|
1588
|
+
};
|
|
1587
1589
|
|
|
1588
1590
|
// src/middleware/authMiddleware.ts
|
|
1589
1591
|
var requireAuth = async (req, next) => {
|
|
@@ -2125,12 +2127,15 @@ function serve(options, callback) {
|
|
|
2125
2127
|
}
|
|
2126
2128
|
|
|
2127
2129
|
// src/index.ts
|
|
2128
|
-
import { Type as Type2 } from "@sinclair/typebox";
|
|
2130
|
+
import { Type as Type2, FormatRegistry as FormatRegistry2 } from "@sinclair/typebox";
|
|
2131
|
+
registerFormats();
|
|
2129
2132
|
export {
|
|
2130
2133
|
BaseServer,
|
|
2131
2134
|
ComponentServer,
|
|
2132
2135
|
DependencyManager,
|
|
2136
|
+
FormatRegistry2 as FormatRegistry,
|
|
2133
2137
|
HtmlRenderer,
|
|
2138
|
+
Patterns,
|
|
2134
2139
|
Server,
|
|
2135
2140
|
ServerFactory,
|
|
2136
2141
|
TokenError,
|
|
@@ -2160,6 +2165,7 @@ export {
|
|
|
2160
2165
|
getTokenTimeRemaining,
|
|
2161
2166
|
getValidatorCacheStats,
|
|
2162
2167
|
goAwait,
|
|
2168
|
+
hasFormat,
|
|
2163
2169
|
html,
|
|
2164
2170
|
isTokenExpired,
|
|
2165
2171
|
isTypedRoute,
|
|
@@ -2178,15 +2184,19 @@ export {
|
|
|
2178
2184
|
rateLimit,
|
|
2179
2185
|
redirect,
|
|
2180
2186
|
refreshToken,
|
|
2187
|
+
registerFormat,
|
|
2188
|
+
registerFormats,
|
|
2181
2189
|
requireAuth,
|
|
2182
2190
|
serve,
|
|
2183
2191
|
setLocals,
|
|
2184
2192
|
simpleHandler,
|
|
2185
2193
|
stream,
|
|
2186
2194
|
text,
|
|
2195
|
+
validateAllSchemas,
|
|
2187
2196
|
validateFast,
|
|
2188
2197
|
validateRequest,
|
|
2189
2198
|
validateSchema,
|
|
2199
|
+
validateSchemaOrThrow,
|
|
2190
2200
|
verifyToken
|
|
2191
2201
|
};
|
|
2192
2202
|
/**
|
|
@@ -2197,25 +2207,6 @@ export {
|
|
|
2197
2207
|
* @version 1.0.0
|
|
2198
2208
|
* @license MIT
|
|
2199
2209
|
*/
|
|
2200
|
-
/**
|
|
2201
|
-
* 超优化版Schema验证器 v5.0.0
|
|
2202
|
-
*
|
|
2203
|
-
* 使用经过验证的优化技术,确保极致性能
|
|
2204
|
-
* - 内联函数调用
|
|
2205
|
-
* - 预编译缓存优化
|
|
2206
|
-
* - 内存池优化
|
|
2207
|
-
* - 位运算优化
|
|
2208
|
-
* - 类型特化优化
|
|
2209
|
-
* - 循环展开优化
|
|
2210
|
-
* - 位掩码优化
|
|
2211
|
-
* - 字符串池优化
|
|
2212
|
-
* - 内联缓存优化
|
|
2213
|
-
* - 内存对齐优化
|
|
2214
|
-
*
|
|
2215
|
-
* @author Framework Team
|
|
2216
|
-
* @version 5.0.0
|
|
2217
|
-
* @license MIT
|
|
2218
|
-
*/
|
|
2219
2210
|
/**
|
|
2220
2211
|
* 类型安全的路由处理器工厂
|
|
2221
2212
|
*
|