@h-ai/audit 0.1.0-alpha5
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/LICENSE +202 -0
- package/README.md +113 -0
- package/dist/index.d.ts +365 -0
- package/dist/index.js +594 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [2026] [idealworld.group]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# @h-ai/audit
|
|
2
|
+
|
|
3
|
+
统一审计日志模块,通过 `audit` 对象提供审计日志的记录、查询、清理与统计功能,基于 `@h-ai/reldb` 实现持久化。
|
|
4
|
+
|
|
5
|
+
## 依赖
|
|
6
|
+
|
|
7
|
+
- `@h-ai/reldb` — 数据库(审计日志持久化),**需在 audit.init() 前初始化**
|
|
8
|
+
|
|
9
|
+
## 适用场景
|
|
10
|
+
|
|
11
|
+
- 用户操作审计(登录、登出、注册、密码重置等)
|
|
12
|
+
- CRUD 操作审计(创建、读取、更新、删除资源)
|
|
13
|
+
- 安全事件追踪与合规审计
|
|
14
|
+
- 运营数据统计(操作频次、活跃用户等)
|
|
15
|
+
|
|
16
|
+
## 快速开始
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { audit } from '@h-ai/audit'
|
|
20
|
+
import { reldb } from '@h-ai/reldb'
|
|
21
|
+
|
|
22
|
+
// 1. 初始化依赖
|
|
23
|
+
await reldb.init({ type: 'sqlite', database: './data.db' })
|
|
24
|
+
|
|
25
|
+
// 2. 初始化审计模块(自动使用已初始化的 reldb 单例)
|
|
26
|
+
const result = await audit.init()
|
|
27
|
+
if (!result.success) {
|
|
28
|
+
throw new Error(result.error.message)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 3. 记录审计日志
|
|
32
|
+
await audit.log({
|
|
33
|
+
userId: 'user_1',
|
|
34
|
+
action: 'login',
|
|
35
|
+
resource: 'auth',
|
|
36
|
+
ipAddress: '127.0.0.1',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// 4. 使用便捷方法
|
|
40
|
+
await audit.helper.login('user_1', '127.0.0.1')
|
|
41
|
+
await audit.helper.crud({ userId: 'user_1', action: 'create', resource: 'users', resourceId: 'user_2', details: { name: '张三' } })
|
|
42
|
+
|
|
43
|
+
// 5. 查询日志
|
|
44
|
+
const logs = await audit.list({ pageSize: 20, action: 'login' })
|
|
45
|
+
|
|
46
|
+
// 6. 获取统计
|
|
47
|
+
const stats = await audit.getStats(7) // 最近 7 天
|
|
48
|
+
|
|
49
|
+
// 7. 清理旧日志
|
|
50
|
+
await audit.cleanup(90) // 清理 90 天前的日志
|
|
51
|
+
|
|
52
|
+
// 8. 关闭
|
|
53
|
+
await audit.close()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 初始化配置
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
// 默认配置(无需传参)
|
|
60
|
+
await audit.init()
|
|
61
|
+
|
|
62
|
+
// 自定义用户表映射
|
|
63
|
+
await audit.init({
|
|
64
|
+
userTable: 'hai_iam_users', // 用户表名(默认 'hai_iam_users')
|
|
65
|
+
userIdColumn: 'id', // 用户表主键列名(默认 'id')
|
|
66
|
+
userNameColumn: 'username', // 用户表用户名列名(默认 'username')
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
审计日志固定存储在 `hai_audit_logs` 表中,依赖 `@h-ai/reldb` 已初始化。
|
|
71
|
+
|
|
72
|
+
## API 概览
|
|
73
|
+
|
|
74
|
+
- `audit.init(config)` - 初始化审计模块
|
|
75
|
+
- `audit.log(input)` - 记录审计日志
|
|
76
|
+
- `audit.list(options)` - 分页查询审计日志(含用户名 JOIN)
|
|
77
|
+
- `audit.getUserRecent(userId, limit)` - 获取用户最近活动
|
|
78
|
+
- `audit.cleanup(days)` - 清理旧日志
|
|
79
|
+
- `audit.getStats(days)` - 获取操作统计
|
|
80
|
+
- `audit.helper.login/logout/register/...` - 便捷记录器
|
|
81
|
+
- `audit.close()` - 关闭模块
|
|
82
|
+
|
|
83
|
+
### 输入约束
|
|
84
|
+
|
|
85
|
+
- `audit.log(input)`:`action` / `resource` 必须为非空字符串,且长度不超过 256。
|
|
86
|
+
- `audit.list(options)`:若同时传 `startDate` 与 `endDate`,必须满足 `startDate <= endDate`。
|
|
87
|
+
- `audit.getUserRecent(userId, limit)`:`userId` 必须为非空字符串;`limit`(如传入)必须为正整数。
|
|
88
|
+
- `audit.cleanup(days)`:`days`(如传入)必须为非负整数。
|
|
89
|
+
- `audit.getStats(days)`:`days`(如传入)必须为非负整数。
|
|
90
|
+
|
|
91
|
+
## 错误码
|
|
92
|
+
|
|
93
|
+
所有操作返回 `HaiResult<T>`,常用错误码如下:
|
|
94
|
+
|
|
95
|
+
| 错误码 | code | 说明 |
|
|
96
|
+
| -------------------------------- | --------------- | ------------ |
|
|
97
|
+
| `HaiAuditError.LOG_FAILED` | `hai:audit:001` | 记录失败 |
|
|
98
|
+
| `HaiAuditError.QUERY_FAILED` | `hai:audit:002` | 查询失败 |
|
|
99
|
+
| `HaiAuditError.CLEANUP_FAILED` | `hai:audit:003` | 清理失败 |
|
|
100
|
+
| `HaiAuditError.STATS_FAILED` | `hai:audit:004` | 统计失败 |
|
|
101
|
+
| `HaiAuditError.INIT_IN_PROGRESS` | `hai:audit:005` | 初始化进行中 |
|
|
102
|
+
| `HaiAuditError.NOT_INITIALIZED` | `hai:audit:010` | 模块未初始化 |
|
|
103
|
+
| `HaiAuditError.CONFIG_ERROR` | `hai:audit:012` | 配置错误 |
|
|
104
|
+
|
|
105
|
+
## 测试
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
pnpm --filter @h-ai/audit test
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## License
|
|
112
|
+
|
|
113
|
+
Apache-2.0
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import * as _h_ai_core from '@h-ai/core';
|
|
3
|
+
import { HaiResult } from '@h-ai/core';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @h-ai/audit — 错误码与配置
|
|
7
|
+
*
|
|
8
|
+
* 定义审计模块的错误码常量与初始化配置类型。
|
|
9
|
+
* @module audit-config
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 审计模块初始化配置 Schema(Zod)
|
|
14
|
+
*
|
|
15
|
+
* 所有字段均有默认值,可直接调用 `audit.init()` 无需传参。
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { audit } from '@h-ai/audit'
|
|
20
|
+
* import { reldb } from '@h-ai/reldb'
|
|
21
|
+
*
|
|
22
|
+
* await audit.init()
|
|
23
|
+
*
|
|
24
|
+
* // 自定义用户表映射
|
|
25
|
+
* await audit.init({
|
|
26
|
+
* userTable: 'sys_users',
|
|
27
|
+
* userIdColumn: 'user_id',
|
|
28
|
+
* userNameColumn: 'name',
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare const AuditInitConfigSchema: z.ZodObject<{
|
|
33
|
+
userTable: z.ZodDefault<z.ZodString>;
|
|
34
|
+
userIdColumn: z.ZodDefault<z.ZodString>;
|
|
35
|
+
userNameColumn: z.ZodDefault<z.ZodString>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
/** 审计模块初始化配置(解析后) */
|
|
38
|
+
type AuditInitConfig = z.output<typeof AuditInitConfigSchema>;
|
|
39
|
+
/** 审计模块初始化配置(传入参数) */
|
|
40
|
+
type AuditInitConfigInput = z.input<typeof AuditInitConfigSchema>;
|
|
41
|
+
|
|
42
|
+
declare const HaiAuditError: {
|
|
43
|
+
readonly LOG_FAILED: _h_ai_core.HaiErrorDef;
|
|
44
|
+
readonly QUERY_FAILED: _h_ai_core.HaiErrorDef;
|
|
45
|
+
readonly CLEANUP_FAILED: _h_ai_core.HaiErrorDef;
|
|
46
|
+
readonly STATS_FAILED: _h_ai_core.HaiErrorDef;
|
|
47
|
+
readonly INIT_IN_PROGRESS: _h_ai_core.HaiErrorDef;
|
|
48
|
+
readonly NOT_INITIALIZED: _h_ai_core.HaiErrorDef;
|
|
49
|
+
readonly CONFIG_ERROR: _h_ai_core.HaiErrorDef;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* 审计日志记录
|
|
53
|
+
*
|
|
54
|
+
* 表示一条已持久化的审计日志条目。
|
|
55
|
+
*/
|
|
56
|
+
interface AuditLog {
|
|
57
|
+
/** 审计日志 ID,格式为 `audit_` 前缀 + 随机串 */
|
|
58
|
+
id: string;
|
|
59
|
+
/** 操作用户 ID;系统操作时为 null */
|
|
60
|
+
userId: string | null;
|
|
61
|
+
/** 操作类型(如 login / logout / create / update / delete) */
|
|
62
|
+
action: string;
|
|
63
|
+
/** 资源类型(如 auth / users / roles) */
|
|
64
|
+
resource: string;
|
|
65
|
+
/** 资源 ID;不涉及特定资源时为 null */
|
|
66
|
+
resourceId: string | null;
|
|
67
|
+
/** 操作详情(JSON 字符串);无详情时为 null */
|
|
68
|
+
details: string | null;
|
|
69
|
+
/** 客户端 IP 地址;未知时为 null */
|
|
70
|
+
ipAddress: string | null;
|
|
71
|
+
/** 客户端 User-Agent;未知时为 null */
|
|
72
|
+
userAgent: string | null;
|
|
73
|
+
/** 创建时间 */
|
|
74
|
+
createdAt: Date;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 审计日志记录(含用户名)
|
|
78
|
+
*
|
|
79
|
+
* 通过 LEFT JOIN 用户表获取 username 字段,用于列表展示。
|
|
80
|
+
*/
|
|
81
|
+
interface AuditLogWithUser extends AuditLog {
|
|
82
|
+
/** 操作用户的用户名;用户不存在或系统操作时为 null */
|
|
83
|
+
username: string | null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 创建审计日志输入
|
|
87
|
+
*
|
|
88
|
+
* 调用 {@link AuditFunctions.log} 时传入的参数。
|
|
89
|
+
* 仅 `action` 和 `resource` 为必填。
|
|
90
|
+
*/
|
|
91
|
+
interface CreateAuditLogInput {
|
|
92
|
+
/** 操作用户 ID;系统操作可省略 */
|
|
93
|
+
userId?: string | null;
|
|
94
|
+
/** 操作类型(如 login / create / update / delete) */
|
|
95
|
+
action: string;
|
|
96
|
+
/** 资源类型(如 auth / users / roles) */
|
|
97
|
+
resource: string;
|
|
98
|
+
/** 资源 ID;不涉及特定资源时可省略 */
|
|
99
|
+
resourceId?: string | null;
|
|
100
|
+
/** 操作详情对象,会被 JSON 序列化存储 */
|
|
101
|
+
details?: Record<string, unknown> | null;
|
|
102
|
+
/** 客户端 IP 地址 */
|
|
103
|
+
ipAddress?: string | null;
|
|
104
|
+
/** 客户端 User-Agent */
|
|
105
|
+
userAgent?: string | null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 审计日志列表查询选项
|
|
109
|
+
*
|
|
110
|
+
* 所有字段均为可选,不传则不过滤。
|
|
111
|
+
*/
|
|
112
|
+
interface ListAuditLogsOptions {
|
|
113
|
+
/** 按用户 ID 过滤 */
|
|
114
|
+
userId?: string;
|
|
115
|
+
/** 按操作类型过滤(精确匹配) */
|
|
116
|
+
action?: string;
|
|
117
|
+
/** 按资源类型过滤(精确匹配) */
|
|
118
|
+
resource?: string;
|
|
119
|
+
/** 起始时间(含),只返回此时间之后的日志 */
|
|
120
|
+
startDate?: Date;
|
|
121
|
+
/** 结束时间(含),只返回此时间之前的日志 */
|
|
122
|
+
endDate?: Date;
|
|
123
|
+
/** 页码,从 1 开始 */
|
|
124
|
+
page?: number;
|
|
125
|
+
/**
|
|
126
|
+
* 每页条数
|
|
127
|
+
*
|
|
128
|
+
* @default 20
|
|
129
|
+
*/
|
|
130
|
+
pageSize?: number;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 审计统计结果项
|
|
134
|
+
*
|
|
135
|
+
* 按操作类型(action)分组的统计条目。
|
|
136
|
+
*/
|
|
137
|
+
interface AuditStatItem {
|
|
138
|
+
/** 操作类型 */
|
|
139
|
+
action: string;
|
|
140
|
+
/** 该操作在统计时间范围内的次数 */
|
|
141
|
+
count: number;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* CRUD 审计操作输入
|
|
145
|
+
*
|
|
146
|
+
* 调用 {@link AuditHelper.crud} 时传入的参数。
|
|
147
|
+
*/
|
|
148
|
+
interface CrudAuditInput {
|
|
149
|
+
/** 操作用户 ID(系统操作传 null) */
|
|
150
|
+
userId?: string | null;
|
|
151
|
+
/** 操作类型 */
|
|
152
|
+
action: 'create' | 'read' | 'update' | 'delete';
|
|
153
|
+
/** 资源类型(如 users / roles) */
|
|
154
|
+
resource: string;
|
|
155
|
+
/** 资源 ID(可选) */
|
|
156
|
+
resourceId?: string;
|
|
157
|
+
/** 操作详情对象(可选) */
|
|
158
|
+
details?: Record<string, unknown>;
|
|
159
|
+
/** 客户端 IP(可选) */
|
|
160
|
+
ip?: string;
|
|
161
|
+
/** 客户端 User-Agent(可选) */
|
|
162
|
+
ua?: string;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 审计便捷记录器
|
|
166
|
+
*
|
|
167
|
+
* 封装常见审计场景(认证、CRUD),简化调用方代码。
|
|
168
|
+
* 通过 {@link AuditFunctions.helper} 访问。
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```ts
|
|
172
|
+
* await audit.helper.login('user_1', '127.0.0.1', 'Mozilla/5.0')
|
|
173
|
+
* await audit.helper.crud({ userId: 'user_1', action: 'create', resource: 'users', resourceId: 'user_2' })
|
|
174
|
+
* ```
|
|
175
|
+
*/
|
|
176
|
+
interface AuditHelper {
|
|
177
|
+
/**
|
|
178
|
+
* 记录用户登录
|
|
179
|
+
*
|
|
180
|
+
* @param userId - 登录用户 ID
|
|
181
|
+
* @param ip - 客户端 IP(可选)
|
|
182
|
+
* @param ua - 客户端 User-Agent(可选)
|
|
183
|
+
*/
|
|
184
|
+
login: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>;
|
|
185
|
+
/**
|
|
186
|
+
* 记录用户登出
|
|
187
|
+
*
|
|
188
|
+
* @param userId - 登出用户 ID
|
|
189
|
+
* @param ip - 客户端 IP(可选)
|
|
190
|
+
* @param ua - 客户端 User-Agent(可选)
|
|
191
|
+
*/
|
|
192
|
+
logout: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>;
|
|
193
|
+
/**
|
|
194
|
+
* 记录用户注册
|
|
195
|
+
*
|
|
196
|
+
* @param userId - 注册用户 ID
|
|
197
|
+
* @param ip - 客户端 IP(可选)
|
|
198
|
+
* @param ua - 客户端 User-Agent(可选)
|
|
199
|
+
*/
|
|
200
|
+
register: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>;
|
|
201
|
+
/**
|
|
202
|
+
* 记录密码重置请求
|
|
203
|
+
*
|
|
204
|
+
* @param email - 请求重置的邮箱地址
|
|
205
|
+
* @param ip - 客户端 IP(可选)
|
|
206
|
+
* @param ua - 客户端 User-Agent(可选)
|
|
207
|
+
*/
|
|
208
|
+
passwordResetRequest: (email: string, ip?: string, ua?: string) => Promise<HaiResult<void>>;
|
|
209
|
+
/**
|
|
210
|
+
* 记录密码重置完成
|
|
211
|
+
*
|
|
212
|
+
* @param userId - 重置密码的用户 ID(匿名重置场景传 null)
|
|
213
|
+
* @param ip - 客户端 IP(可选)
|
|
214
|
+
* @param ua - 客户端 User-Agent(可选)
|
|
215
|
+
*/
|
|
216
|
+
passwordResetComplete: (userId: string | null, ip?: string, ua?: string) => Promise<HaiResult<void>>;
|
|
217
|
+
/**
|
|
218
|
+
* 记录 CRUD 操作
|
|
219
|
+
*
|
|
220
|
+
* @param input - CRUD 审计输入(action 和 resource 为必填)
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* await audit.helper.crud({ userId: 'user_1', action: 'create', resource: 'users', resourceId: 'user_2' })
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
crud: (input: CrudAuditInput) => Promise<HaiResult<void>>;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* 审计模块函数接口
|
|
231
|
+
*
|
|
232
|
+
* 统一的审计日志访问入口。
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* import { audit } from '@h-ai/audit'
|
|
237
|
+
* import { reldb } from '@h-ai/reldb'
|
|
238
|
+
*
|
|
239
|
+
* await reldb.init({ type: 'sqlite', database: './data.db' })
|
|
240
|
+
* await audit.init()
|
|
241
|
+
*
|
|
242
|
+
* await audit.log({ userId: 'user_1', action: 'login', resource: 'auth' })
|
|
243
|
+
* const logs = await audit.list({ pageSize: 10 })
|
|
244
|
+
* await audit.close()
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
interface AuditFunctions {
|
|
248
|
+
/**
|
|
249
|
+
* 初始化审计模块
|
|
250
|
+
*
|
|
251
|
+
* @param config - 初始化配置(可选,所有字段均有默认值)
|
|
252
|
+
* @returns 成功时返回 ok(undefined);失败时返回 CONFIG_ERROR
|
|
253
|
+
*/
|
|
254
|
+
init: (config?: AuditInitConfigInput) => Promise<HaiResult<void>>;
|
|
255
|
+
/**
|
|
256
|
+
* 关闭审计模块,释放内部状态
|
|
257
|
+
*/
|
|
258
|
+
close: () => Promise<void>;
|
|
259
|
+
/** 当前是否已初始化 */
|
|
260
|
+
readonly isInitialized: boolean;
|
|
261
|
+
/**
|
|
262
|
+
* 记录一条审计日志
|
|
263
|
+
*
|
|
264
|
+
* @param input - 日志内容(action 和 resource 为必填)
|
|
265
|
+
* @returns 成功时返回创建的 AuditLog;失败时返回 LOG_FAILED
|
|
266
|
+
*/
|
|
267
|
+
log: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>;
|
|
268
|
+
/**
|
|
269
|
+
* 分页查询审计日志列表(含用户名 LEFT JOIN)
|
|
270
|
+
*
|
|
271
|
+
* @param options - 查询过滤与分页选项
|
|
272
|
+
* @returns 成功时返回 { items, total };失败时返回 QUERY_FAILED
|
|
273
|
+
*/
|
|
274
|
+
list: (options?: ListAuditLogsOptions) => Promise<HaiResult<{
|
|
275
|
+
items: AuditLogWithUser[];
|
|
276
|
+
total: number;
|
|
277
|
+
}>>;
|
|
278
|
+
/**
|
|
279
|
+
* 获取指定用户的最近活动记录
|
|
280
|
+
*
|
|
281
|
+
* @param userId - 用户 ID
|
|
282
|
+
* @param limit - 最大返回条数,默认 10
|
|
283
|
+
* @returns 成功时返回 AuditLog 数组;失败时返回 QUERY_FAILED
|
|
284
|
+
*/
|
|
285
|
+
getUserRecent: (userId: string, limit?: number) => Promise<HaiResult<AuditLog[]>>;
|
|
286
|
+
/**
|
|
287
|
+
* 清理指定天数之前的旧日志
|
|
288
|
+
*
|
|
289
|
+
* @param olderThanDays - 保留天数,默认 90;清理此天数之前的日志
|
|
290
|
+
* @returns 成功时返回删除的记录数;失败时返回 CLEANUP_FAILED
|
|
291
|
+
*/
|
|
292
|
+
cleanup: (olderThanDays?: number) => Promise<HaiResult<number>>;
|
|
293
|
+
/**
|
|
294
|
+
* 获取指定天数内的操作统计(按 action 分组计数)
|
|
295
|
+
*
|
|
296
|
+
* @param days - 统计天数,默认 7
|
|
297
|
+
* @returns 成功时返回 AuditStatItem 数组;失败时返回 STATS_FAILED
|
|
298
|
+
*/
|
|
299
|
+
getStats: (days?: number) => Promise<HaiResult<AuditStatItem[]>>;
|
|
300
|
+
/**
|
|
301
|
+
* 便捷记录器,封装常见审计场景
|
|
302
|
+
*
|
|
303
|
+
* 未初始化时调用任意方法均返回 NOT_INITIALIZED 错误。
|
|
304
|
+
*/
|
|
305
|
+
readonly helper: AuditHelper;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @h-ai/audit — 审计便捷记录器
|
|
310
|
+
*
|
|
311
|
+
* 封装常见审计操作(登录、登出、注册、密码重置、CRUD),简化调用方代码。
|
|
312
|
+
* @module audit-helper
|
|
313
|
+
*/
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* 创建便捷记录器
|
|
317
|
+
*
|
|
318
|
+
* 封装常见审计操作(登录、登出、注册、密码重置、CRUD),
|
|
319
|
+
* 简化调用方代码。每个方法内部调用 logFn 并将 AuditLog 结果映射为 void。
|
|
320
|
+
*
|
|
321
|
+
* @param logFn - 底层日志记录函数(通常为 currentRepo.log)
|
|
322
|
+
* @returns 便捷记录器接口
|
|
323
|
+
*/
|
|
324
|
+
declare function createHelper(logFn: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>): AuditHelper;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* @h-ai/audit — 审计日志服务主入口
|
|
328
|
+
*
|
|
329
|
+
* 本文件提供统一的 `audit` 对象,聚合所有审计日志操作功能。
|
|
330
|
+
* @module audit-main
|
|
331
|
+
*/
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* 审计日志服务对象
|
|
335
|
+
*
|
|
336
|
+
* 统一的审计日志访问入口,提供以下功能:
|
|
337
|
+
* - `audit.init()` — 初始化审计模块
|
|
338
|
+
* - `audit.close()` — 关闭模块
|
|
339
|
+
* - `audit.log()` — 记录审计日志
|
|
340
|
+
* - `audit.list()` — 查询审计日志列表
|
|
341
|
+
* - `audit.getUserRecent()` — 获取用户最近活动
|
|
342
|
+
* - `audit.cleanup()` — 清理旧日志
|
|
343
|
+
* - `audit.getStats()` — 获取统计数据
|
|
344
|
+
* - `audit.helper` — 便捷记录器
|
|
345
|
+
* - `audit.isInitialized` — 初始化状态
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* import { audit } from '@h-ai/audit'
|
|
350
|
+
* import { reldb } from '@h-ai/reldb'
|
|
351
|
+
*
|
|
352
|
+
* await reldb.init({ type: 'sqlite', database: ':memory:' })
|
|
353
|
+
* const result = await audit.init()
|
|
354
|
+
* if (!result.success) {
|
|
355
|
+
* // 处理初始化错误
|
|
356
|
+
* }
|
|
357
|
+
*
|
|
358
|
+
* await audit.helper.login('user_1', '127.0.0.1')
|
|
359
|
+
* const logs = await audit.list({ pageSize: 10 })
|
|
360
|
+
* await audit.close()
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
declare const audit: AuditFunctions;
|
|
364
|
+
|
|
365
|
+
export { type AuditFunctions, type AuditHelper, type AuditInitConfig, type AuditInitConfigInput, AuditInitConfigSchema, type AuditLog, type AuditLogWithUser, type AuditStatItem, type CreateAuditLogInput, type CrudAuditInput, HaiAuditError, type ListAuditLogsOptions, audit, createHelper };
|