befly 2.3.3 → 3.0.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.
Files changed (87) hide show
  1. package/checks/conflict.ts +329 -0
  2. package/checks/table.ts +252 -0
  3. package/config/env.ts +218 -0
  4. package/config/fields.ts +55 -0
  5. package/config/regexAliases.ts +51 -0
  6. package/config/reserved.ts +96 -0
  7. package/main.ts +47 -0
  8. package/package.json +26 -11
  9. package/plugins/db.ts +60 -0
  10. package/plugins/logger.ts +28 -0
  11. package/plugins/redis.ts +47 -0
  12. package/scripts/syncDb/apply.ts +171 -0
  13. package/scripts/syncDb/constants.ts +71 -0
  14. package/scripts/syncDb/ddl.ts +189 -0
  15. package/scripts/syncDb/helpers.ts +173 -0
  16. package/scripts/syncDb/index.ts +203 -0
  17. package/scripts/syncDb/schema.ts +199 -0
  18. package/scripts/syncDb/sqlite.ts +50 -0
  19. package/scripts/syncDb/state.ts +106 -0
  20. package/scripts/syncDb/table.ts +214 -0
  21. package/scripts/syncDb/tableCreate.ts +148 -0
  22. package/scripts/syncDb/tests/constants.test.ts +105 -0
  23. package/scripts/syncDb/tests/ddl.test.ts +134 -0
  24. package/scripts/syncDb/tests/helpers.test.ts +70 -0
  25. package/scripts/syncDb/types.ts +92 -0
  26. package/scripts/syncDb/version.ts +73 -0
  27. package/scripts/syncDb.ts +10 -0
  28. package/tsconfig.json +58 -0
  29. package/types/addon.d.ts +53 -0
  30. package/types/api.d.ts +249 -0
  31. package/types/befly.d.ts +230 -0
  32. package/types/common.d.ts +215 -0
  33. package/types/context.d.ts +7 -0
  34. package/types/crypto.d.ts +23 -0
  35. package/types/database.d.ts +273 -0
  36. package/types/index.d.ts +450 -0
  37. package/types/index.ts +438 -0
  38. package/types/jwt.d.ts +99 -0
  39. package/types/logger.d.ts +43 -0
  40. package/types/plugin.d.ts +109 -0
  41. package/types/redis.d.ts +46 -0
  42. package/types/tool.d.ts +67 -0
  43. package/types/validator.d.ts +43 -0
  44. package/types/validator.ts +43 -0
  45. package/utils/colors.ts +221 -0
  46. package/utils/crypto.ts +308 -0
  47. package/utils/database.ts +348 -0
  48. package/utils/dbHelper.ts +713 -0
  49. package/utils/helper.ts +812 -0
  50. package/utils/index.ts +33 -0
  51. package/utils/jwt.ts +493 -0
  52. package/utils/logger.ts +191 -0
  53. package/utils/redisHelper.ts +321 -0
  54. package/utils/requestContext.ts +167 -0
  55. package/utils/sqlBuilder.ts +611 -0
  56. package/utils/validate.ts +493 -0
  57. package/utils/{xml.js → xml.ts} +100 -74
  58. package/.npmrc +0 -3
  59. package/.prettierignore +0 -2
  60. package/.prettierrc +0 -11
  61. package/apis/health/info.js +0 -49
  62. package/apis/tool/tokenCheck.js +0 -29
  63. package/bin/befly.js +0 -109
  64. package/bunfig.toml +0 -3
  65. package/checks/table.js +0 -206
  66. package/config/env.js +0 -64
  67. package/main.js +0 -579
  68. package/plugins/db.js +0 -46
  69. package/plugins/logger.js +0 -14
  70. package/plugins/redis.js +0 -32
  71. package/plugins/tool.js +0 -8
  72. package/scripts/syncDb.js +0 -752
  73. package/scripts/syncDev.js +0 -96
  74. package/system.js +0 -118
  75. package/tables/common.json +0 -16
  76. package/tables/tool.json +0 -6
  77. package/utils/api.js +0 -27
  78. package/utils/colors.js +0 -83
  79. package/utils/crypto.js +0 -260
  80. package/utils/index.js +0 -334
  81. package/utils/jwt.js +0 -387
  82. package/utils/logger.js +0 -143
  83. package/utils/redisHelper.js +0 -74
  84. package/utils/sqlBuilder.js +0 -498
  85. package/utils/sqlManager.js +0 -471
  86. package/utils/tool.js +0 -31
  87. package/utils/validate.js +0 -226
@@ -1,96 +0,0 @@
1
- /**
2
- * 同步开发管理员账号脚本
3
- * - 账号: dev
4
- * - 密码: Crypto2.hmacMd5(Crypto2.md5(Env.DEV_PASSWORD), Env.MD5_SALT)
5
- * - 行为: 若存在则更新密码与 updated_at;不存在则插入新记录
6
- */
7
-
8
- import { Env } from '../config/env.js';
9
- import { Logger } from '../utils/logger.js';
10
- import { createSqlClient } from '../utils/index.js';
11
- import { Crypto2 } from '../utils/crypto.js';
12
-
13
- // 命令行参数(保持与 syncDb.js 一致的 plan 行为)
14
- const ARGV = Array.isArray(process.argv) ? process.argv : [];
15
- const CLI = { DRY_RUN: ARGV.includes('--plan') };
16
-
17
- // 执行器封装
18
- const exec = async (client, query, params = []) => {
19
- if (params && params.length > 0) return await client.unsafe(query, params);
20
- return await client.unsafe(query);
21
- };
22
-
23
- /**
24
- * 同步开发管理员账号
25
- * @param {import('bun').SQL | null} client 可选,复用已有 SQL 客户端;不传则内部创建与关闭
26
- */
27
- export async function SyncDev(client = null) {
28
- let ownClient = false;
29
- try {
30
- if (CLI.DRY_RUN) {
31
- Logger.info('[计划] 同步完成后将初始化/更新 admin.dev 账号(plan 模式不执行)');
32
- return true;
33
- }
34
-
35
- if (!Env.DEV_PASSWORD || !Env.MD5_SALT) {
36
- Logger.warn('跳过开发管理员初始化:缺少 DEV_PASSWORD 或 MD5_SALT 配置');
37
- return false;
38
- }
39
-
40
- if (!client) {
41
- client = await createSqlClient({ max: 1 });
42
- ownClient = true;
43
- }
44
-
45
- // 检查 admin 表是否存在
46
- const [exist] = await exec(client, 'SELECT COUNT(*) AS cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? LIMIT 1', [Env.DB_NAME || '', 'admin']);
47
- if (!exist || Number(exist.cnt) === 0) {
48
- Logger.warn('跳过开发管理员初始化:未检测到 admin 表');
49
- return false;
50
- }
51
-
52
- const nowTs = Date.now();
53
- const hashed = Crypto2.hmacMd5(Crypto2.md5(Env.DEV_PASSWORD), Env.MD5_SALT);
54
-
55
- // 更新存在的 dev 账号
56
- const updateRes = await exec(client, 'UPDATE `admin` SET `password` = ?, `updated_at` = ? WHERE `account` = ? LIMIT 1', [hashed, nowTs, 'dev']);
57
- const affected = updateRes?.affectedRows ?? updateRes?.rowsAffected ?? 0;
58
-
59
- if (!affected || affected === 0) {
60
- // 插入新账号
61
- const id = nowTs;
62
- await exec(client, 'INSERT INTO `admin` (`id`, `created_at`, `updated_at`, `deleted_at`, `state`, `account`, `password`) VALUES (?, ?, ?, 0, 0, ?, ?)', [id, nowTs, nowTs, 'dev', hashed]);
63
- Logger.info('开发管理员已初始化:account=dev');
64
- } else {
65
- Logger.info('开发管理员已更新密码并刷新更新时间:account=dev');
66
- }
67
-
68
- return true;
69
- } catch (e) {
70
- Logger.warn(`开发管理员初始化步骤出错:${e.message}`);
71
- return false;
72
- } finally {
73
- if (ownClient && client) {
74
- try {
75
- await client.close();
76
- } catch (e) {
77
- Logger.warn('关闭数据库连接时出错:', e.message);
78
- }
79
- }
80
- }
81
- }
82
-
83
- // 允许直接运行该脚本
84
- if (import.meta.url === `file://${process.argv[1]}`) {
85
- SyncDev()
86
- .then((ok) => {
87
- if (CLI.DRY_RUN) {
88
- process.exit(0);
89
- }
90
- process.exit(ok ? 0 : 1);
91
- })
92
- .catch((err) => {
93
- console.error('❌ 开发管理员同步失败:', err);
94
- process.exit(1);
95
- });
96
- }
package/system.js DELETED
@@ -1,118 +0,0 @@
1
- import { fileURLToPath } from 'node:url';
2
- import { dirname, join, resolve, relative } from 'node:path';
3
-
4
- /**
5
- * Befly 框架系统路径定义
6
- * 提供统一的路径变量,供整个框架使用
7
- */
8
-
9
- // 当前文件的路径信息
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
-
13
- // Befly 框架根目录
14
- const __dirroot = __dirname;
15
-
16
- // 各个重要目录的路径
17
- const __dirscript = join(__dirroot, 'scripts');
18
- const __dirbin = join(__dirroot, 'bin');
19
- const __dirutils = join(__dirroot, 'utils');
20
- const __dirconfig = join(__dirroot, 'config');
21
- const __dirtables = join(__dirroot, 'tables');
22
- const __dirchecks = join(__dirroot, 'checks');
23
- const __dirapis = join(__dirroot, 'apis');
24
- const __dirplugins = join(__dirroot, 'plugins');
25
- const __dirlibs = join(__dirroot, 'libs');
26
- const __dirtests = join(__dirroot, 'tests');
27
-
28
- // 获取项目根目录(befly 框架的使用方项目)
29
- const getProjectRoot = () => {
30
- return process.cwd();
31
- };
32
-
33
- // 获取项目中的特定目录
34
- const getProjectDir = (subdir = '') => {
35
- return subdir ? join(getProjectRoot(), subdir) : getProjectRoot();
36
- };
37
-
38
- // 创建路径解析器,基于 befly 根目录
39
- const resolveBeflyPath = (...paths) => {
40
- return resolve(__dirroot, ...paths);
41
- };
42
-
43
- // 创建路径解析器,基于项目根目录
44
- const resolveProjectPath = (...paths) => {
45
- return resolve(getProjectRoot(), ...paths);
46
- };
47
-
48
- // 获取相对于 befly 根目录的相对路径
49
- const getRelativeBeflyPath = (targetPath) => {
50
- return relative(__dirroot, targetPath);
51
- };
52
-
53
- // 获取相对于项目根目录的相对路径
54
- const getRelativeProjectPath = (targetPath) => {
55
- return relative(getProjectRoot(), targetPath);
56
- };
57
-
58
- // 导出所有路径变量和工具函数
59
- export {
60
- // 基础路径变量
61
- __filename,
62
- __dirname,
63
- __dirroot,
64
-
65
- // Befly 框架目录
66
- __dirscript,
67
- __dirbin,
68
- __dirutils,
69
- __dirconfig,
70
- __dirtables,
71
- __dirchecks,
72
- __dirapis,
73
- __dirplugins,
74
- __dirlibs,
75
- __dirtests,
76
-
77
- // 项目路径工具函数
78
- getProjectRoot,
79
- getProjectDir,
80
-
81
- // 路径解析工具函数
82
- resolveBeflyPath,
83
- resolveProjectPath,
84
- getRelativeBeflyPath,
85
- getRelativeProjectPath
86
- };
87
-
88
- // 默认导出包含所有路径信息的对象
89
- export default {
90
- // 基础路径变量
91
- __filename,
92
- __dirname,
93
- __dirroot,
94
-
95
- // Befly 框架目录
96
- paths: {
97
- script: __dirscript,
98
- bin: __dirbin,
99
- utils: __dirutils,
100
- config: __dirconfig,
101
- tables: __dirtables,
102
- checks: __dirchecks,
103
- apis: __dirapis,
104
- plugins: __dirplugins,
105
- libs: __dirlibs,
106
- tests: __dirtests
107
- },
108
-
109
- // 工具函数
110
- utils: {
111
- getProjectRoot,
112
- getProjectDir,
113
- resolveBeflyPath,
114
- resolveProjectPath,
115
- getRelativeBeflyPath,
116
- getRelativeProjectPath
117
- }
118
- };
@@ -1,16 +0,0 @@
1
- {
2
- "email": "邮箱⚡string⚡5⚡100⚡''⚡1⚡^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
3
- "phone": "手机号⚡string⚡11⚡11⚡''⚡1⚡^1[3-9]\\d{9}$",
4
- "page": "页码⚡number⚡1⚡9999⚡1⚡0⚡null",
5
- "limit": "每页数量⚡number⚡1⚡100⚡10⚡0⚡null",
6
- "title": "标题⚡string⚡1⚡200⚡''⚡0⚡null",
7
- "description": "描述⚡string⚡0⚡500⚡''⚡0⚡null",
8
- "keyword": "关键词⚡string⚡1⚡50⚡''⚡1⚡null",
9
- "status": "状态⚡string⚡1⚡20⚡active⚡1⚡^(active|inactive|pending|suspended)$",
10
- "enabled": "启用状态⚡number⚡0⚡1⚡1⚡0⚡^(0|1)$",
11
- "date": "日期⚡string⚡10⚡10⚡''⚡0⚡^\\d{4}-\\d{2}-\\d{2}$",
12
- "datetime": "日期时间⚡string⚡19⚡25⚡''⚡0⚡^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}",
13
- "filename": "文件名⚡string⚡1⚡255⚡''⚡0⚡null",
14
- "url": "网址⚡string⚡5⚡500⚡''⚡0⚡^https?://",
15
- "tag": "标签⚡array⚡0⚡10⚡''⚡0⚡null"
16
- }
package/tables/tool.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "filename": "文件名⚡string⚡1⚡255⚡''⚡1⚡null",
3
- "content": "内容⚡string⚡0⚡100⚡''⚡0⚡null",
4
- "type": "类型⚡string⚡0⚡50⚡file⚡1⚡^(file|folder|link)$",
5
- "path": "路径⚡string⚡1⚡500⚡''⚡0⚡null"
6
- }
package/utils/api.js DELETED
@@ -1,27 +0,0 @@
1
- import { Logger } from './logger.js';
2
- import { RYes, RNo } from './index.js';
3
- export class Api {
4
- // GET 方法
5
- static GET(name, auth = false, fields = {}, required = [], handler) {
6
- return {
7
- method: 'GET',
8
- name: name,
9
- auth: auth,
10
- fields: fields,
11
- required: required,
12
- handler: async (befly, ctx, req) => await handler(befly, ctx, req)
13
- };
14
- }
15
-
16
- // POST 方法
17
- static POST(name, auth = false, fields = {}, required = [], handler) {
18
- return {
19
- method: 'POST',
20
- name: name,
21
- auth: auth,
22
- fields: fields,
23
- required: required,
24
- handler: async (befly, ctx, req) => await handler(befly, ctx, req)
25
- };
26
- }
27
- }
package/utils/colors.js DELETED
@@ -1,83 +0,0 @@
1
- const p = process || {},
2
- argv = p.argv || [],
3
- env = p.env || {};
4
- const isColorSupported = !(!!env.NO_COLOR || argv.includes('--no-color')) && (!!env.FORCE_COLOR || argv.includes('--color') || p.platform === 'win32' || ((p.stdout || {}).isTTY && env.TERM !== 'dumb') || !!env.CI);
5
-
6
- const formatter =
7
- (open, close, replace = open) =>
8
- (input) => {
9
- let string = '' + input,
10
- index = string.indexOf(close, open.length);
11
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
12
- };
13
-
14
- const replaceClose = (string, close, replace, index) => {
15
- let result = '',
16
- cursor = 0;
17
- do {
18
- result += string.substring(cursor, index) + replace;
19
- cursor = index + close.length;
20
- index = string.indexOf(close, cursor);
21
- } while (~index);
22
- return result + string.substring(cursor);
23
- };
24
-
25
- const createColors = (enabled = isColorSupported) => {
26
- let f = enabled ? formatter : () => String;
27
- return {
28
- isColorSupported: enabled,
29
- reset: f('\x1b[0m', '\x1b[0m'),
30
- bold: f('\x1b[1m', '\x1b[22m', '\x1b[22m\x1b[1m'),
31
- dim: f('\x1b[2m', '\x1b[22m', '\x1b[22m\x1b[2m'),
32
- italic: f('\x1b[3m', '\x1b[23m'),
33
- underline: f('\x1b[4m', '\x1b[24m'),
34
- inverse: f('\x1b[7m', '\x1b[27m'),
35
- hidden: f('\x1b[8m', '\x1b[28m'),
36
- strikethrough: f('\x1b[9m', '\x1b[29m'),
37
-
38
- black: f('\x1b[30m', '\x1b[39m'),
39
- red: f('\x1b[31m', '\x1b[39m'),
40
- green: f('\x1b[32m', '\x1b[39m'),
41
- yellow: f('\x1b[33m', '\x1b[39m'),
42
- blue: f('\x1b[34m', '\x1b[39m'),
43
- magenta: f('\x1b[35m', '\x1b[39m'),
44
- cyan: f('\x1b[36m', '\x1b[39m'),
45
- white: f('\x1b[37m', '\x1b[39m'),
46
- gray: f('\x1b[90m', '\x1b[39m'),
47
-
48
- bgBlack: f('\x1b[40m', '\x1b[49m'),
49
- bgRed: f('\x1b[41m', '\x1b[49m'),
50
- bgGreen: f('\x1b[42m', '\x1b[49m'),
51
- bgYellow: f('\x1b[43m', '\x1b[49m'),
52
- bgBlue: f('\x1b[44m', '\x1b[49m'),
53
- bgMagenta: f('\x1b[45m', '\x1b[49m'),
54
- bgCyan: f('\x1b[46m', '\x1b[49m'),
55
- bgWhite: f('\x1b[47m', '\x1b[49m'),
56
-
57
- blackBright: f('\x1b[90m', '\x1b[39m'),
58
- redBright: f('\x1b[91m', '\x1b[39m'),
59
- greenBright: f('\x1b[92m', '\x1b[39m'),
60
- yellowBright: f('\x1b[93m', '\x1b[39m'),
61
- blueBright: f('\x1b[94m', '\x1b[39m'),
62
- magentaBright: f('\x1b[95m', '\x1b[39m'),
63
- cyanBright: f('\x1b[96m', '\x1b[39m'),
64
- whiteBright: f('\x1b[97m', '\x1b[39m'),
65
-
66
- bgBlackBright: f('\x1b[100m', '\x1b[49m'),
67
- bgRedBright: f('\x1b[101m', '\x1b[49m'),
68
- bgGreenBright: f('\x1b[102m', '\x1b[49m'),
69
- bgYellowBright: f('\x1b[103m', '\x1b[49m'),
70
- bgBlueBright: f('\x1b[104m', '\x1b[49m'),
71
- bgMagentaBright: f('\x1b[105m', '\x1b[49m'),
72
- bgCyanBright: f('\x1b[106m', '\x1b[49m'),
73
- bgWhiteBright: f('\x1b[107m', '\x1b[49m')
74
- };
75
- };
76
-
77
- const colors = createColors();
78
- colors.info = colors.blue('i');
79
- colors.success = colors.green('√');
80
- colors.warn = colors.yellow('‼');
81
- colors.error = colors.red('x');
82
-
83
- export { colors };
package/utils/crypto.js DELETED
@@ -1,260 +0,0 @@
1
- import { createSign } from 'node:crypto';
2
-
3
- export class Crypto2 {
4
- /**
5
- * MD5 哈希
6
- * @param {string|Uint8Array} data - 要哈希的数据
7
- * @param {string} encoding - 输出编码 ('hex', 'base64')
8
- * @returns {string} MD5 哈希值
9
- */
10
- static md5(data, encoding = 'hex') {
11
- const hasher = new Bun.CryptoHasher('md5');
12
- hasher.update(data);
13
- return hasher.digest(encoding);
14
- }
15
-
16
- /**
17
- * HMAC-MD5 签名
18
- * @param {string|Uint8Array} key - 密钥
19
- * @param {string|Uint8Array} data - 要签名的数据
20
- * @param {string} encoding - 输出编码 ('hex', 'base64')
21
- * @returns {string} HMAC-MD5 签名
22
- */
23
- static hmacMd5(key, data, encoding = 'hex') {
24
- const hasher = new Bun.CryptoHasher('md5', key);
25
- hasher.update(data);
26
- return hasher.digest(encoding);
27
- }
28
-
29
- /**
30
- * SHA-1 哈希
31
- * @param {string|Uint8Array} data - 要哈希的数据
32
- * @param {string} encoding - 输出编码 ('hex', 'base64')
33
- * @returns {string} SHA-1 哈希值
34
- */
35
- static sha1(data, encoding = 'hex') {
36
- const hasher = new Bun.CryptoHasher('sha1');
37
- hasher.update(data);
38
- return hasher.digest(encoding);
39
- }
40
-
41
- /**
42
- * HMAC-SHA1 签名
43
- * @param {string|Uint8Array} key - 密钥
44
- * @param {string|Uint8Array} data - 要签名的数据
45
- * @param {string} encoding - 输出编码 ('hex', 'base64')
46
- * @returns {string} HMAC-SHA1 签名
47
- */
48
- static hmacSha1(key, data, encoding = 'hex') {
49
- const hasher = new Bun.CryptoHasher('sha1', key);
50
- hasher.update(data);
51
- return hasher.digest(encoding);
52
- }
53
-
54
- /**
55
- * SHA-256 哈希
56
- * @param {string|Uint8Array} data - 要哈希的数据
57
- * @param {string} encoding - 输出编码 ('hex', 'base64')
58
- * @returns {string} SHA-256 哈希值
59
- */
60
- static sha256(data, encoding = 'hex') {
61
- const hasher = new Bun.CryptoHasher('sha256');
62
- hasher.update(data);
63
- return hasher.digest(encoding);
64
- }
65
-
66
- static rsaSha256(data, privateKey, encoding = 'hex') {
67
- const sign = createSign('RSA-SHA256');
68
- sign.update(data);
69
- const signature = sign.sign(privateKey, encoding);
70
- return signature;
71
- }
72
-
73
- /**
74
- * HMAC-SHA256 签名
75
- * @param {string|Uint8Array} key - 密钥
76
- * @param {string|Uint8Array} data - 要签名的数据
77
- * @param {string} encoding - 输出编码 ('hex', 'base64')
78
- * @returns {string} HMAC-SHA256 签名
79
- */
80
- static hmacSha256(key, data, encoding = 'hex') {
81
- const hasher = new Bun.CryptoHasher('sha256', key);
82
- hasher.update(data);
83
- return hasher.digest(encoding);
84
- }
85
-
86
- /**
87
- * SHA-512 哈希
88
- * @param {string|Uint8Array} data - 要哈希的数据
89
- * @param {string} encoding - 输出编码 ('hex', 'base64')
90
- * @returns {string} SHA-512 哈希值
91
- */
92
- static sha512(data, encoding = 'hex') {
93
- const hasher = new Bun.CryptoHasher('sha512');
94
- hasher.update(data);
95
- return hasher.digest(encoding);
96
- }
97
-
98
- /**
99
- * HMAC-SHA512 签名
100
- * @param {string|Uint8Array} key - 密钥
101
- * @param {string|Uint8Array} data - 要签名的数据
102
- * @param {string} encoding - 输出编码 ('hex', 'base64')
103
- * @returns {string} HMAC-SHA512 签名
104
- */
105
- static hmacSha512(key, data, encoding = 'hex') {
106
- const hasher = new Bun.CryptoHasher('sha512', key);
107
- hasher.update(data);
108
- return hasher.digest(encoding);
109
- }
110
-
111
- /**
112
- * 通用哈希方法
113
- * @param {string} algorithm - 算法名称 ('md5', 'sha1', 'sha256', 'sha512')
114
- * @param {string|Uint8Array} data - 要哈希的数据
115
- * @param {string} encoding - 输出编码 ('hex', 'base64')
116
- * @returns {string} 哈希值
117
- */
118
- static hash(algorithm, data, encoding = 'hex') {
119
- const hasher = new Bun.CryptoHasher(algorithm);
120
- hasher.update(data);
121
- return hasher.digest(encoding);
122
- }
123
-
124
- /**
125
- * 通用 HMAC 方法
126
- * @param {string} algorithm - 算法名称 ('md5', 'sha1', 'sha256', 'sha512')
127
- * @param {string|Uint8Array} key - 密钥
128
- * @param {string|Uint8Array} data - 要签名的数据
129
- * @param {string} encoding - 输出编码 ('hex', 'base64')
130
- * @returns {string} HMAC 签名
131
- */
132
- static hmac(algorithm, key, data, encoding = 'hex') {
133
- const hasher = new Bun.CryptoHasher(algorithm, key);
134
- hasher.update(data);
135
- return hasher.digest(encoding);
136
- }
137
-
138
- /**
139
- * 文件哈希
140
- * @param {string} filePath - 文件路径
141
- * @param {string} algorithm - 算法名称 (默认 'sha256')
142
- * @param {string} encoding - 输出编码 ('hex', 'base64')
143
- * @returns {Promise<string>} 文件哈希值
144
- */
145
- static async hashFile(filePath, algorithm = 'sha256', encoding = 'hex') {
146
- const file = Bun.file(filePath);
147
- const hasher = new Bun.CryptoHasher(algorithm);
148
-
149
- const stream = file.stream();
150
- const reader = stream.getReader();
151
-
152
- try {
153
- while (true) {
154
- const { done, value } = await reader.read();
155
- if (done) break;
156
- hasher.update(value);
157
- }
158
- return hasher.digest(encoding);
159
- } finally {
160
- reader.releaseLock();
161
- }
162
- }
163
-
164
- /**
165
- * 创建流式哈希器
166
- * @param {string} algorithm - 算法名称
167
- * @param {string|Uint8Array} key - 可选的 HMAC 密钥
168
- * @returns {StreamHasher} 流式哈希器实例
169
- */
170
- static createHasher(algorithm, key = null) {
171
- return new StreamHasher(algorithm, key);
172
- }
173
-
174
- /**
175
- * 密码哈希 (使用 Argon2)
176
- * @param {string} password - 密码
177
- * @param {object} options - 选项
178
- * @returns {Promise<string>} 哈希后的密码
179
- */
180
- static async hashPassword(password, options = {}) {
181
- return await Bun.password.hash(password, options);
182
- }
183
-
184
- /**
185
- * 验证密码
186
- * @param {string} password - 原始密码
187
- * @param {string} hash - 哈希值
188
- * @returns {Promise<boolean>} 验证结果
189
- */
190
- static async verifyPassword(password, hash) {
191
- return await Bun.password.verify(password, hash);
192
- }
193
-
194
- /**
195
- * 快速哈希 (非密码学)
196
- * @param {string|Uint8Array} data - 数据
197
- * @param {number} seed - 种子值
198
- * @returns {number} 64位哈希值
199
- */
200
- static fastHash(data, seed = 0) {
201
- return Bun.hash(data, seed);
202
- }
203
- }
204
-
205
- /**
206
- * 流式哈希器类
207
- */
208
- class StreamHasher {
209
- constructor(algorithm, key = null) {
210
- this.hasher = new Bun.CryptoHasher(algorithm, key);
211
- this.finalized = false;
212
- }
213
-
214
- /**
215
- * 更新数据
216
- * @param {string|Uint8Array} data - 数据
217
- * @returns {StreamHasher} 支持链式调用
218
- */
219
- update(data) {
220
- if (this.finalized) {
221
- throw new Error('哈希器已经完成,不能再更新数据');
222
- }
223
- this.hasher.update(data);
224
- return this;
225
- }
226
-
227
- /**
228
- * 生成最终哈希值
229
- * @param {string} encoding - 输出编码
230
- * @returns {string} 哈希值
231
- */
232
- digest(encoding = 'hex') {
233
- if (this.finalized) {
234
- throw new Error('哈希器已经完成');
235
- }
236
- this.finalized = true;
237
- return this.hasher.digest(encoding);
238
- }
239
-
240
- /**
241
- * 复制哈希器
242
- * @returns {StreamHasher} 新的哈希器实例
243
- */
244
- copy() {
245
- if (this.finalized) {
246
- throw new Error('不能复制已完成的哈希器');
247
- }
248
- const newHasher = new StreamHasher();
249
- newHasher.hasher = this.hasher.copy();
250
- return newHasher;
251
- }
252
- }
253
-
254
- // 使用示例:
255
- // const md5Hash = Crypto.md5('hello world');
256
- // const hmacMd5 = Crypto.hmacMd5('secret-key', 'hello world');
257
- // const sha256Hash = Crypto.sha256('hello world');
258
- // const fileHash = await Crypto.hashFile('./file.txt', 'md5');
259
- // const hasher = Crypto.createHasher('md5').update('hello').update(' world');
260
- // const result = hasher.digest('hex');