befly 3.17.12 → 3.17.14

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.
@@ -2,7 +2,6 @@ import { UAParser } from "ua-parser-js";
2
2
 
3
3
  import adminTable from "../../tables/admin.json";
4
4
  import { toSessionTtlSeconds } from "../../utils/toSessionTtlSeconds.js";
5
- import { isString } from "../../utils/is.js";
6
5
 
7
6
  export default {
8
7
  name: "管理员登录",
package/checks/table.js CHANGED
@@ -8,10 +8,8 @@ z.config(z.locales.zhCN());
8
8
 
9
9
  const lowerCamelRegex = /^_?[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
10
10
  const noTrimString = z.string().refine(isNoTrimStringAllowEmpty, "不允许首尾空格");
11
- const FIELD_NAME_REGEX_SOURCE = "^[\\u4e00-\\u9fa5a-zA-Z0-9_]+$";
12
11
  const INPUT_TYPES = ["number", "integer", "string", "char", "array", "array_number", "array_integer", "json", "json_number", "json_integer"];
13
12
 
14
- const fieldNameRegex = new RegExp(FIELD_NAME_REGEX_SOURCE);
15
13
  const inputRegexLiteral = /^\/.*?\/[gimsuy]*$/;
16
14
  const inputEnumRegex = /^[^/].*\|.*$/;
17
15
  const inputAliasRegex = /^@.+$/;
package/hooks/auth.js CHANGED
@@ -3,7 +3,7 @@ import { toSessionTtlSeconds } from "../utils/toSessionTtlSeconds.js";
3
3
  export default {
4
4
  deps: [],
5
5
  handler: async (befly, ctx) => {
6
- const authHeader = ctx.req.headers.get("authorization");
6
+ const authHeader = ctx.headers.get("authorization");
7
7
  const ttlSeconds = toSessionTtlSeconds(befly.config?.session?.expireDays);
8
8
 
9
9
  if (authHeader && authHeader.startsWith("Bearer ")) {
package/hooks/parser.js CHANGED
@@ -15,36 +15,25 @@ const xmlParser = new XMLParser();
15
15
  export default {
16
16
  deps: ["auth"],
17
17
  handler: async (befly, ctx) => {
18
- if (!ctx.apiPath) {
19
- return;
20
- }
21
-
22
- // body=raw 模式:跳过解析,保留原始请求供 handler 自行处理
18
+ // apiBody=raw 模式:跳过解析,保留原始请求供 handler 自行处理
23
19
  // 适用于:微信回调、支付回调、webhook 等需要手动解密/验签的场景
24
- if (ctx.body === "raw") {
20
+ if (ctx.apiBody === "raw") {
25
21
  ctx.body = {};
26
22
  return;
27
23
  }
28
-
24
+ const queryParams = Object.fromEntries(new URL(ctx.url).searchParams);
25
+ const contentType = ctx.headers.get("content-type") || "";
29
26
  // GET 请求:解析查询参数
30
- if (ctx.req.method === "GET") {
31
- const url = new URL(ctx.req.url);
32
- const params = Object.fromEntries(url.searchParams);
33
- ctx.body = params;
34
- } else if (ctx.req.method === "POST") {
27
+ if (ctx.method === "GET") {
28
+ ctx.body = queryParams;
29
+ } else if (ctx.method === "POST") {
35
30
  // POST 请求:解析请求体
36
- const contentType = ctx.req.headers.get("content-type") || "";
37
- // 获取 URL 查询参数(POST 请求也可能带参数)
38
- const url = new URL(ctx.req.url);
39
- const queryParams = Object.fromEntries(url.searchParams);
40
-
41
31
  try {
42
32
  // JSON 格式
43
33
  if (contentType.includes("application/json")) {
44
34
  const body = await ctx.req.json();
45
35
  // 合并 URL 参数和请求体(请求体优先)
46
- const merged = Object.assign({}, queryParams, body);
47
- ctx.body = merged;
36
+ ctx.body = Object.assign({}, queryParams, body);
48
37
  } else if (contentType.includes("application/xml") || contentType.includes("text/xml")) {
49
38
  // XML 格式
50
39
  const text = await ctx.req.text();
@@ -53,8 +42,7 @@ export default {
53
42
  const rootKey = Object.keys(parsed)[0];
54
43
  const body = rootKey && typeof parsed[rootKey] === "object" ? parsed[rootKey] : parsed;
55
44
  // 合并 URL 参数和请求体(请求体优先)
56
- const merged = Object.assign({}, queryParams, body);
57
- ctx.body = merged;
45
+ ctx.body = Object.assign({}, queryParams, body);
58
46
  } else {
59
47
  // 不支持的 Content-Type
60
48
  ctx.response = ErrorResponse(
@@ -1,8 +1,7 @@
1
1
  import { CacheKeys } from "../lib/cacheKeys.js";
2
- import { Logger } from "../lib/logger.js";
3
2
  // 相对导入
4
3
  import { ErrorResponse } from "../utils/response.js";
5
- import { isNonEmptyString, isString, isValidPositiveInt } from "../utils/is.js";
4
+ import { isValidPositiveInt } from "../utils/is.js";
6
5
 
7
6
  /**
8
7
  * 权限检查钩子
@@ -16,7 +15,7 @@ export default {
16
15
  deps: ["validator"],
17
16
  handler: async (befly, ctx) => {
18
17
  // 1. 接口无需权限
19
- if (ctx.auth === false) {
18
+ if (ctx.apiAuth === false) {
20
19
  return;
21
20
  }
22
21
 
@@ -31,8 +30,8 @@ export default {
31
30
  return;
32
31
  }
33
32
 
34
- // 3.5 auth 为角色类型白名单时,仅做 ctx.roleType 校验
35
- if (Array.isArray(ctx.auth) && ctx.auth.includes(ctx.roleType) === false) {
33
+ // 3.5 apiAuth 为角色类型白名单时,仅做 ctx.roleType 校验
34
+ if (Array.isArray(ctx.apiAuth) && ctx.apiAuth.includes(ctx.roleType) === false) {
36
35
  ctx.response = ErrorResponse(
37
36
  ctx,
38
37
  `无权访问 ${ctx.apiName} 接口`,
@@ -15,7 +15,7 @@ export default {
15
15
  const rawBody = isPlainObject(ctx.body) ? ctx.body : {};
16
16
  const nextBody = {};
17
17
 
18
- for (const [field] of Object.entries(ctx.fields)) {
18
+ for (const [field] of Object.entries(ctx.apiFields)) {
19
19
  let value = rawBody[field];
20
20
 
21
21
  if (value === undefined) {
@@ -33,7 +33,7 @@ export default {
33
33
  ctx.body = nextBody;
34
34
 
35
35
  // 验证参数
36
- const result = Validator.validate(ctx.body, ctx.fields, ctx.required || []);
36
+ const result = Validator.validate(ctx.body, ctx.apiFields, ctx.apiRequired);
37
37
 
38
38
  if (result.code !== 0) {
39
39
  ctx.response = ErrorResponse(ctx, result.firstError || "参数验证失败", 1, null, result.fieldErrors, "validator");
package/index.js CHANGED
@@ -32,7 +32,6 @@ import { calcPerfTime } from "./utils/calcPerfTime.js";
32
32
  import { scanSources } from "./utils/scanSources.js";
33
33
  import { isPrimaryProcess } from "./utils/is.js";
34
34
  import { deepMerge } from "./utils/deepMerge.js";
35
- import { omit } from "./utils/util.js";
36
35
  import { sortModules } from "./utils/sortModules.js";
37
36
 
38
37
  function prefixMenuPaths(menus, prefix) {
package/lib/connect.js CHANGED
@@ -87,7 +87,7 @@ export class Connect {
87
87
  };
88
88
 
89
89
  // Called when disconnected from Redis server
90
- this.redisClient.onclose = (error) => {
90
+ this.redisClient.onclose = () => {
91
91
  Logger.warn("Redis 断开连接");
92
92
  };
93
93
  } catch (error) {
@@ -1,4 +1,4 @@
1
- import { isNullable, isNumber } from "../../utils/is.js";
1
+ import { isNumber } from "../../utils/is.js";
2
2
  import { snakeCase } from "../../utils/util.js";
3
3
  import { Logger } from "../logger.js";
4
4
  import { SqlBuilder } from "../sqlBuilder/index.js";
package/lib/logger.js CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { createWriteStream, existsSync, mkdirSync } from "node:fs";
6
6
  import { stat } from "node:fs/promises";
7
- import { isAbsolute as nodePathIsAbsolute, join as nodePathJoin, resolve as nodePathResolve } from "node:path";
7
+ import { join as nodePathJoin, resolve as nodePathResolve } from "node:path";
8
8
 
9
9
  import { formatYmdHms } from "../utils/formatYmdHms.js";
10
10
  import { buildSensitiveKeyMatcher, sanitizeLogObject } from "../utils/loggerUtils.js";
@@ -5,7 +5,6 @@
5
5
 
6
6
  import { Connect } from "./connect.js";
7
7
  import { Logger } from "./logger.js";
8
- import { isFiniteNumber, isNonEmptyString, isString } from "../utils/is.js";
9
8
 
10
9
  /**
11
10
  * Redis 助手类
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly",
3
- "version": "3.17.12",
4
- "gitHead": "098baa90ed47149819a515c6169b29072e4840bb",
3
+ "version": "3.17.14",
4
+ "gitHead": "c71ecec269032dcc0aa8ca995da4918f99f5ee0e",
5
5
  "private": false,
6
6
  "description": "Befly - 为 Bun 专属打造的 JavaScript API 接口框架核心引擎",
7
7
  "keywords": [
package/router/api.js CHANGED
@@ -20,6 +20,7 @@ export function apiHandler(apis, hooks, context) {
20
20
  return async (req, server) => {
21
21
  // 1. 生成请求 ID
22
22
  const requestId = genShortId();
23
+ const now = Date.now();
23
24
 
24
25
  const corsHeaders = setCorsOptions(req, context.config?.cors || {});
25
26
  corsHeaders["X-Request-ID"] = requestId;
@@ -55,6 +56,7 @@ export function apiHandler(apis, hooks, context) {
55
56
  const ctx = {
56
57
  // 请求的参数
57
58
  method: req.method,
59
+ url: req.url,
58
60
  body: {},
59
61
  req: req,
60
62
  now: now,
@@ -65,13 +67,13 @@ export function apiHandler(apis, hooks, context) {
65
67
  // 接口的参数
66
68
  apiPath: apiData.apiPath,
67
69
  apiName: apiData.name,
68
- filePath: apiData.filePath,
69
- handler: apiData.handler,
70
- method: apiData.method,
71
- body: apiData.body,
72
- auth: apiData.auth,
73
- fields: apiData.fields,
74
- required: apiData.required
70
+ apiMethod: apiData.method,
71
+ apiBody: apiData.body,
72
+ apiHandler: apiData.handler,
73
+ apiAuth: apiData.auth,
74
+ apiFields: apiData.fields,
75
+ apiRequired: apiData.required,
76
+ apiFile: apiData.filePath
75
77
  };
76
78
 
77
79
  try {
@@ -107,7 +109,7 @@ export function apiHandler(apis, hooks, context) {
107
109
  Logger.info("请求", logData);
108
110
 
109
111
  // 5. 执行 API handler
110
- const result = await ctx.handler(context, ctx);
112
+ const result = await ctx.apiHandler(context, ctx);
111
113
 
112
114
  if (result instanceof Response) {
113
115
  ctx.response = result;
@@ -119,9 +121,8 @@ export function apiHandler(apis, hooks, context) {
119
121
  return FinalResponse(ctx);
120
122
  } catch (err) {
121
123
  // 全局错误处理
122
- const errorPath = ctx.apiPath ? ctx.apiPath : req.url;
123
124
  Logger.error("请求错误", err, {
124
- path: errorPath,
125
+ path: ctx.apiPath,
125
126
  requestId: requestId,
126
127
  method: req.method,
127
128
  apiPath: ctx.apiPath,
@@ -57,7 +57,7 @@ export function buildSyncDbDiff(groupedDbColumns, existingTableMap) {
57
57
  const missingFields = [];
58
58
  for (const columnMeta of columns) {
59
59
  const fieldInfo = toSyncDbFieldDef(columnMeta);
60
- if (Object.prototype.hasOwnProperty.call(existingFields, fieldInfo.fieldName)) {
60
+ if (Object.hasOwn(existingFields, fieldInfo.fieldName)) {
61
61
  continue;
62
62
  }
63
63
 
@@ -1,14 +1,3 @@
1
- function getValueByPath(source, path) {
2
- if (!Array.isArray(path)) return undefined;
3
-
4
- let current = source;
5
- for (const segment of path) {
6
- if (current === null || current === undefined) return undefined;
7
- current = current[segment];
8
- }
9
- return current;
10
- }
11
-
12
1
  function formatValue(value) {
13
2
  if (value === undefined) return "undefined";
14
3
  if (value === null) return "null";
@@ -1,5 +1,3 @@
1
- import { join } from "pathe";
2
-
3
1
  import {
4
2
  //
5
3
  coreTableDir,