@h-ai/audit 0.1.0-alpha.72 → 0.1.0-alpha.73
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.en.md +71 -13
- package/README.ja.md +71 -13
- package/README.md +72 -14
- package/dist/index.d.ts +257 -8
- package/dist/index.js +1050 -149
- package/dist/index.js.map +1 -1
- package/package.json +23 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/audit-config.ts","../src/audit-helper.ts","../messages/en-US.json","../messages/ja-JP.json","../messages/zh-CN.json","../src/audit-i18n.ts","../src/audit-types.ts","../src/audit-repository-log.ts","../src/audit-main.ts"],"names":["core","ok","logger","err"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/audit — 错误码与配置\n *\n * 定义审计模块的错误码常量与初始化配置类型。\n * @module audit-config\n */\n\nimport { z } from 'zod'\n\n// ─── 初始化配置 ───\n\n/**\n * 审计模块初始化配置 Schema(Zod)\n *\n * 所有字段均有默认值,可直接调用 `audit.init()` 无需传参。\n * @example\n * ```ts\n * import { AuditInitConfigSchema } from '@h-ai/audit'\n * const config = AuditInitConfigSchema.parse({ userTable: 'app_users' })\n * // 这里只校验字段映射;实际初始化前必须已有可用的 RelDB。\n * ```\n */\nexport const AuditInitConfigSchema = z.object({\n /** 用户表名,用于 list 查询时 LEFT JOIN 获取用户名 */\n userTable: z.string().default('hai_iam_users'),\n /** 用户表主键列名,用于 JOIN 条件 */\n userIdColumn: z.string().default('id'),\n /** 用户表用户名列名,用于 SELECT 输出 */\n userNameColumn: z.string().default('username'),\n})\n\n/**\n * 审计模块初始化配置(解析后)\n * @example\n * ```ts\n * import { AuditInitConfigSchema, type AuditInitConfig } from '@h-ai/audit'\n * const config: AuditInitConfig = AuditInitConfigSchema.parse({ userTable: 'app_users' })\n * ```\n */\nexport type AuditInitConfig = z.output<typeof AuditInitConfigSchema>\n\n/**\n * 审计模块初始化配置(传入参数)\n * @example\n * ```ts\n * import type { AuditInitConfigInput } from '@h-ai/audit'\n * const record: AuditInitConfigInput = { userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' }\n * ```\n */\nexport type AuditInitConfigInput = z.input<typeof AuditInitConfigSchema>\n","/**\n * @h-ai/audit — 审计便捷记录器\n *\n * 封装常见审计操作(登录、登出、注册、密码重置、CRUD),简化调用方代码。\n * @module audit-helper\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n AuditHelper,\n AuditLog,\n CreateAuditLogInput,\n CrudAuditInput,\n} from './audit-types.js'\n\nimport { ok } from '@h-ai/core'\n\n/**\n * 将 log 结果映射为 void 返回\n *\n * @param result - log 操作结果\n * @returns 成功返回 ok(undefined);失败透传原始错误\n */\nfunction toVoid(result: HaiResult<AuditLog>): HaiResult<void> {\n if (!result.success) {\n return result\n }\n return ok(undefined)\n}\n\n/**\n * 创建便捷记录器\n *\n * 封装常见审计操作(登录、登出、注册、密码重置、CRUD),\n * 简化调用方代码。每个方法内部调用 logFn 并将 AuditLog 结果映射为 void。\n *\n * @param logFn - 底层日志记录函数(通常为 currentRepo.log)\n * @returns 便捷记录器接口\n * @example 模块内部上下文\n * ```ts\n * function buildHelper(logFn: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>): AuditHelper {\n * return createHelper(logFn)\n * }\n * // logFn 由实际仓储/模块提供;helper 将失败原样传递,不接管数据库生命周期。\n * ```\n */\nexport function createHelper(logFn: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>): AuditHelper {\n return {\n async login(userId: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, action: 'login', resource: 'auth', ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async logout(userId: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, action: 'logout', resource: 'auth', ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async register(userId: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, action: 'register', resource: 'auth', resourceId: userId, ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async passwordResetRequest(email: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({\n action: 'password_reset_request',\n resource: 'auth',\n details: { email },\n ipAddress: ip,\n userAgent: ua,\n })\n return toVoid(result)\n },\n\n async passwordResetComplete(userId: string | null, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, action: 'password_reset', resource: 'auth', ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async crud(\n input: CrudAuditInput,\n ): Promise<HaiResult<void>> {\n const result = await logFn({\n userId: input.userId,\n action: input.action,\n resource: input.resource,\n resourceId: input.resourceId,\n details: input.details,\n ipAddress: input.ip,\n userAgent: input.ua,\n })\n return toVoid(result)\n },\n }\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"audit_notInitialized\": \"Audit module not initialized, call audit.init() first\",\n \"audit_initFailed\": \"Audit module initialization failed: {error}\",\n \"audit_logFailed\": \"Failed to record audit log: {error}\",\n \"audit_queryFailed\": \"Failed to query audit logs: {error}\",\n \"audit_cleanupFailed\": \"Failed to cleanup audit logs: {error}\",\n \"audit_statsFailed\": \"Failed to query audit statistics: {error}\",\n \"audit_invalidStatCount\": \"Audit count is outside the valid range and cannot be displayed safely\",\n \"audit_configError\": \"Audit config validation failed: {error}\",\n \"audit_initInProgress\": \"Audit module initialization is already in progress\",\n \"audit_invalidInput\": \"Invalid audit input for {field}: {reason}\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"audit_notInitialized\": \"監査モジュールが初期化されていません。先にaudit.init()を呼び出してください\",\n \"audit_initFailed\": \"監査モジュールの初期化に失敗しました: {error}\",\n \"audit_logFailed\": \"監査ログの記録に失敗しました: {error}\",\n \"audit_queryFailed\": \"監査ログの取得に失敗しました: {error}\",\n \"audit_cleanupFailed\": \"監査ログのクリーンアップに失敗しました: {error}\",\n \"audit_statsFailed\": \"監査統計の取得に失敗しました: {error}\",\n \"audit_invalidStatCount\": \"監査件数が有効範囲を超えているため、安全に表示できません\",\n \"audit_configError\": \"監査設定の検証に失敗しました: {error}\",\n \"audit_initInProgress\": \"監査モジュールの初期化は既に実行中です\",\n \"audit_invalidInput\": \"{field}の監査入力が無効です: {reason}\"\n}\n","{\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"audit_notInitialized\": \"审计模块尚未初始化,请先调用 audit.init()\",\n \"audit_initFailed\": \"审计模块初始化失败:{error}\",\n \"audit_logFailed\": \"审计日志记录失败:{error}\",\n \"audit_queryFailed\": \"审计日志查询失败:{error}\",\n \"audit_cleanupFailed\": \"审计日志清理失败:{error}\",\n \"audit_statsFailed\": \"审计统计查询失败:{error}\",\n \"audit_invalidStatCount\": \"审计统计数量超出有效范围,无法安全显示\",\n \"audit_configError\": \"审计配置校验失败:{error}\",\n \"audit_initInProgress\": \"审计模块正在初始化中,请勿并发调用\",\n \"audit_invalidInput\": \"审计输入参数无效({field}):{reason}\"\n}\n","/**\n * @h-ai/audit — i18n\n *\n * 本文件提供审计模块的 i18n 文案访问入口。\n * @module audit-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesJaJP from '../messages/ja-JP.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n// ─── i18n ───\n\n/**\n * 审计模块文案 Key 类型\n * @example 模块内部上下文\n * ```ts\n * const key: AuditMessageKey = 'audit_notInitialized'\n * const message = auditM(key)\n * ```\n */\ntype AuditMessageKey = keyof typeof messagesZhCN\n\n/**\n * 获取审计模块文案。\n *\n * @param key - 文案 Key(以 `audit_` 为前缀)\n * @param options - 插值参数与格式化选项\n * @returns 本地化后的文案字符串\n * @remarks 具体参数结构与 core.i18n.createMessageGetter 保持一致。\n * @example 模块内部上下文\n * ```ts\n * const message = auditM('audit_logFailed', { locale: 'en-US', params: { error: 'database unavailable' } })\n * ```\n */\nexport const auditM = core.i18n.createMessageGetter<AuditMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n 'ja-JP': messagesJaJP,\n})\n","/**\n * @h-ai/audit — 公共类型定义\n *\n * 审计模块对外类型:错误接口、实体类型、操作接口、函数接口。\n * @module audit-types\n */\n\nimport type { ErrorInfo, HaiResult, PaginatedResult, PaginationOptionsInput } from '@h-ai/core'\nimport type { AuditInitConfigInput } from './audit-config.js'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\nconst AuditErrorInfo = {\n LOG_FAILED: '001:500',\n QUERY_FAILED: '002:500',\n CLEANUP_FAILED: '003:500',\n STATS_FAILED: '004:500',\n INIT_IN_PROGRESS: '005:409',\n NOT_INITIALIZED: '010:500',\n CONFIG_ERROR: '012:500',\n} as const satisfies ErrorInfo\n\n/**\n * 审计初始化、写入、查询和清理失败的稳定错误定义。\n * @example\n * ```ts\n * import { HaiAuditError } from '@h-ai/audit'\n * import { err } from '@h-ai/core'\n * const failed = err(HaiAuditError.NOT_INITIALIZED, 'Audit is not initialized')\n * if (!failed.success) failed.error.code\n * ```\n */\nexport const HaiAuditError = core.error.buildHaiErrorsDef('audit', AuditErrorInfo)\n\n// ─── 实体类型 ───\n\n/**\n * 审计日志记录\n *\n * 表示一条已持久化的审计日志条目。\n * @example\n * ```ts\n * import type { AuditLog } from '@h-ai/audit'\n * const record: AuditLog = { id: 'audit_example', userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: null, ipAddress: null, userAgent: null, createdAt: new Date() }\n * ```\n */\nexport interface AuditLog {\n /** 审计日志 ID,格式为 `audit_` 前缀 + 随机串 */\n id: string\n /** 操作用户 ID;系统操作时为 null */\n userId: string | null\n /** 操作类型(如 login / logout / create / update / delete) */\n action: string\n /** 资源类型(如 auth / users / roles) */\n resource: string\n /** 资源 ID;不涉及特定资源时为 null */\n resourceId: string | null\n /** 操作详情(JSON 字符串);无详情时为 null */\n details: string | null\n /** 客户端 IP 地址;未知时为 null */\n ipAddress: string | null\n /** 客户端 User-Agent;未知时为 null */\n userAgent: string | null\n /** 创建时间 */\n createdAt: Date\n}\n\n/**\n * 审计日志记录(含用户名)\n *\n * 通过 LEFT JOIN 用户表获取 username 字段,用于列表展示。\n * @example\n * ```ts\n * import type { AuditLogWithUser } from '@h-ai/audit'\n * const record: AuditLogWithUser = { id: 'audit_example', userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: null, ipAddress: null, userAgent: null, createdAt: new Date() , username: 'alice' }\n * ```\n */\nexport interface AuditLogWithUser extends AuditLog {\n /** 操作用户的用户名;用户不存在或系统操作时为 null */\n username: string | null\n}\n\n/**\n * 创建审计日志输入\n *\n * 调用 {@link AuditFunctions.log} 时传入的参数。\n * 仅 `action` 和 `resource` 为必填。\n * @example\n * ```ts\n * import type { CreateAuditLogInput } from '@h-ai/audit'\n * const record: CreateAuditLogInput = { userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: { status: 'pending' } }\n * ```\n */\nexport interface CreateAuditLogInput {\n /** 操作用户 ID;系统操作可省略 */\n userId?: string | null\n /** 操作类型(如 login / create / update / delete) */\n action: string\n /** 资源类型(如 auth / users / roles) */\n resource: string\n /** 资源 ID;不涉及特定资源时可省略 */\n resourceId?: string | null\n /** 操作详情对象;密码、token、secret 等凭证类字段会先自动脱敏,再 JSON 序列化存储 */\n details?: Record<string, unknown> | null\n /** 客户端 IP 地址 */\n ipAddress?: string | null\n /** 客户端 User-Agent */\n userAgent?: string | null\n}\n\n/**\n * 审计日志列表查询选项\n *\n * 所有字段均为可选,不传则不过滤。\n * @example\n * ```ts\n * import type { ListAuditLogsOptions } from '@h-ai/audit'\n * const record: ListAuditLogsOptions = { action: 'create', resource: 'orders', page: 1, pageSize: 20 }\n * ```\n */\nexport interface ListAuditLogsOptions extends PaginationOptionsInput {\n /** 按用户 ID 过滤 */\n userId?: string\n /** 按操作类型过滤(精确匹配) */\n action?: string\n /** 按资源类型过滤(精确匹配) */\n resource?: string\n /** 起始时间(含),只返回此时间之后的日志 */\n startDate?: Date\n /** 结束时间(含),只返回此时间之前的日志 */\n endDate?: Date\n}\n\n/**\n * 审计统计结果项\n *\n * 按操作类型(action)分组的统计条目。\n * @example\n * ```ts\n * import type { AuditStatItem } from '@h-ai/audit'\n * const record: AuditStatItem = { action: 'create', count: 12 }\n * ```\n */\nexport interface AuditStatItem {\n /** 操作类型 */\n action: string\n /** 该操作在统计时间范围内的次数 */\n count: number\n}\n\n/**\n * CRUD 审计操作输入\n *\n * 调用 {@link AuditHelper.crud} 时传入的参数。\n * @example\n * ```ts\n * import type { CrudAuditInput } from '@h-ai/audit'\n * const record: CrudAuditInput = { userId: 'user_1', action: 'update', resource: 'orders', resourceId: 'order_1', details: { status: 'paid' } }\n * ```\n */\nexport interface CrudAuditInput {\n /** 操作用户 ID(系统操作传 null) */\n userId?: string | null\n /** 操作类型 */\n action: 'create' | 'read' | 'update' | 'delete'\n /** 资源类型(如 users / roles) */\n resource: string\n /** 资源 ID(可选) */\n resourceId?: string\n /** 操作详情对象(可选) */\n details?: Record<string, unknown>\n /** 客户端 IP(可选) */\n ip?: string\n /** 客户端 User-Agent(可选) */\n ua?: string\n}\n\n// ─── 便捷操作接口 ───\n\n/**\n * 审计便捷记录器\n *\n * 封装常见审计场景(认证、CRUD),简化调用方代码。\n * 通过 {@link AuditFunctions.helper} 访问。\n * @example\n * ```ts\n * import type { AuditHelper } from '@h-ai/audit'\n * // helper 来自已初始化的 audit;数据库生命周期归调用方。\n * async function recordLogin(helper: AuditHelper) {\n * const result = await helper.login('user_1', '127.0.0.1')\n * return result.success ? 'recorded' : result.error.message\n * }\n * ```\n */\nexport interface AuditHelper {\n /**\n * 记录用户登录\n *\n * @param userId - 登录用户 ID\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n login: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录用户登出\n *\n * @param userId - 登出用户 ID\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n logout: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录用户注册\n *\n * @param userId - 注册用户 ID\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n register: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录密码重置请求\n *\n * @param email - 请求重置的邮箱地址\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n passwordResetRequest: (email: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录密码重置完成\n *\n * @param userId - 重置密码的用户 ID(匿名重置场景传 null)\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n passwordResetComplete: (userId: string | null, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录 CRUD 操作\n *\n * @param input - CRUD 审计输入(action 和 resource 为必填)\n *\n * @example\n * ```ts\n * await audit.helper.crud({ userId: 'user_1', action: 'create', resource: 'users', resourceId: 'user_2' })\n * ```\n */\n crud: (input: CrudAuditInput) => Promise<HaiResult<void>>\n}\n\n// ─── 函数接口 ───\n\n/**\n * 审计模块函数接口\n *\n * 统一的审计日志访问入口。\n * @example\n * ```ts\n * import { audit } from '@h-ai/audit'\n * import { core } from '@h-ai/core'\n * import { reldb, type ReldbConfigInput } from '@h-ai/reldb'\n * async function recordCreation(config: ReldbConfigInput) {\n * const database = await reldb.init(config)\n * if (!database.success) return database\n * try {\n * const initialized = await audit.init()\n * if (!initialized.success) return initialized\n * const logged = await audit.log({ action: 'create', resource: 'orders', resourceId: 'order_1' })\n * if (logged.success) core.logger.info('Audit recorded', { id: logged.data.id })\n * return logged\n * } finally {\n * const auditClosed = await audit.close()\n * if (!auditClosed.success) return auditClosed // 保留依赖连接,修复后重试关闭。\n * const databaseClosed = await reldb.close()\n * if (!databaseClosed.success) return databaseClosed\n * }\n * }\n * ```\n */\nexport interface AuditFunctions {\n /**\n * 初始化审计模块\n *\n * @param config - 初始化配置(可选,所有字段均有默认值)\n * @returns 成功时返回 ok(undefined);失败时返回 CONFIG_ERROR\n */\n init: (config?: AuditInitConfigInput) => Promise<HaiResult<void>>\n /**\n * 关闭审计模块,释放内部状态\n */\n close: () => Promise<HaiResult<void>>\n /** 当前是否已初始化 */\n readonly isInitialized: boolean\n /**\n * 记录一条审计日志\n *\n * @param input - 日志内容(action 和 resource 为必填)\n * @returns 成功时返回创建的 AuditLog;失败时返回 LOG_FAILED\n */\n log: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>\n /**\n * 分页查询审计日志列表(含用户名 LEFT JOIN)\n *\n * @param options - 查询过滤与分页选项\n * @returns 成功时返回 PaginatedResult(items/total/page/pageSize);失败时返回 QUERY_FAILED\n */\n list: (options?: ListAuditLogsOptions) => Promise<HaiResult<PaginatedResult<AuditLogWithUser>>>\n /**\n * 获取指定用户的最近活动记录\n *\n * @param userId - 用户 ID\n * @param limit - 最大返回条数,默认 10\n * @returns 成功时返回 AuditLog 数组;失败时返回 QUERY_FAILED\n */\n getUserRecent: (userId: string, limit?: number) => Promise<HaiResult<AuditLog[]>>\n /**\n * 清理指定天数之前的旧日志\n *\n * @param olderThanDays - 保留天数,默认 90;清理此天数之前的日志\n * @returns 成功时返回删除的记录数;失败时返回 CLEANUP_FAILED\n */\n cleanup: (olderThanDays?: number) => Promise<HaiResult<number>>\n /**\n * 获取指定天数内的操作统计(按 action 分组计数)\n *\n * @param days - 统计天数,默认 7\n * @returns 成功时返回 AuditStatItem 数组;失败时返回 STATS_FAILED\n */\n getStats: (days?: number) => Promise<HaiResult<AuditStatItem[]>>\n /**\n * 便捷记录器,封装常见审计场景\n *\n * 未初始化时调用任意方法均返回 NOT_INITIALIZED 错误。\n */\n readonly helper: AuditHelper\n}\n","/**\n * @h-ai/audit — 审计日志仓库\n *\n * 基于 @h-ai/reldb BaseReldbCrudRepository 实现审计日志的持久化与查询。 仅在需要 JOIN / 聚合时使用自定义 SQL,其余 CRUD 操作由基类处理。\n * @module audit-repository\n */\n\nimport type { HaiResult, PaginatedResult } from '@h-ai/core'\nimport type { AuditLog, AuditLogWithUser, AuditStatItem, ListAuditLogsOptions } from './audit-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { BaseReldbCrudRepository, reldb } from '@h-ai/reldb'\nimport { auditM } from './audit-i18n.js'\nimport { HaiAuditError } from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'repository' })\n\n// ─── 仓库配置 ───\n\n/** 审计日志表名(固定值) */\nconst AUDIT_TABLE = 'hai_audit_logs'\n\n/**\n * 原始 SQL 与基类映射的日期、JSON 返回值可能不同,在审计边界统一。\n * @example 模块内部上下文\n * ```ts\n * const row: AuditReadRow = { id: 'audit_example', userId: null, action: 'login', resource: 'auth', resourceId: null, details: { source: 'web' }, ipAddress: null, userAgent: null, createdAt: Date.now() }\n * const record = normalizeAuditLog(row)\n * ```\n */\ntype AuditReadRow = Omit<AuditLog, 'details' | 'createdAt'> & {\n details: unknown\n createdAt: Date | string | number\n}\n\n/** 保持公开审计契约:Date、JSON 字符串和显式 null。 */\nfunction normalizeAuditLog(row: AuditReadRow): AuditLog {\n return {\n ...row,\n userId: row.userId ?? null,\n resourceId: row.resourceId ?? null,\n details: row.details == null ? null : typeof row.details === 'string' ? row.details : JSON.stringify(row.details) ?? null,\n ipAddress: row.ipAddress ?? null,\n userAgent: row.userAgent ?? null,\n createdAt: row.createdAt instanceof Date ? row.createdAt : new Date(row.createdAt),\n }\n}\n\n/**\n * 审计仓储内部的用户表关联映射;由已校验的初始化配置构造。\n * @example 模块内部上下文\n * ```ts\n * const config: AuditRepositoryConfig = { userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' }\n * const userTable = config.userTable\n * ```\n */\ninterface AuditRepositoryConfig {\n /** 用户表名 */\n userTable: string\n /** 用户表主键列名 */\n userIdColumn: string\n /** 用户表用户名列名 */\n userNameColumn: string\n}\n\n// ─── 仓库 ───\n\n/**\n * 审计日志仓库\n *\n * 通过 BaseReldbCrudRepository 自动建表、字段映射与类型转换,\n * 仅在需要 JOIN / 聚合时使用自定义 SQL。\n *\n * @remarks 此类仅供 audit-main.ts 内部使用,不通过 index.ts 对外导出。\n * @example 模块内部上下文\n * ```ts\n * // 共享 reldb 已初始化,连接生命周期由创建者管理。\n * const repository = new AuditLogRepository({ userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' })\n * const ready = await repository.ready()\n * if (ready.success) {\n * const stats = await repository.getStats(7)\n * if (stats.success) stats.data.map(item => item.count)\n * }\n * ```\n */\nexport class AuditLogRepository extends BaseReldbCrudRepository<AuditLog> {\n private readonly repoConfig: AuditRepositoryConfig\n private readonly isSqlite: boolean\n\n /**\n * @param config - 仓库配置(用户表映射)\n */\n constructor(config: AuditRepositoryConfig) {\n super(reldb, {\n table: AUDIT_TABLE,\n idColumn: 'id',\n generateId: () => core.id.withPrefix('audit_'),\n fields: [\n { fieldName: 'id', columnName: 'id', def: { type: 'TEXT', primaryKey: true }, select: true, create: true, update: false },\n { fieldName: 'userId', columnName: 'user_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'action', columnName: 'action', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: false },\n { fieldName: 'resource', columnName: 'resource', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: false },\n { fieldName: 'resourceId', columnName: 'resource_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'details', columnName: 'details', def: { type: 'JSON' }, select: true, create: true, update: false },\n { fieldName: 'ipAddress', columnName: 'ip_address', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'userAgent', columnName: 'user_agent', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'createdAt', columnName: 'created_at', def: { type: 'TIMESTAMP' }, select: true, create: true, update: false },\n ],\n })\n this.repoConfig = config\n this.isSqlite = this.db.config?.type === 'sqlite'\n }\n\n /**\n * 等待基类完成建表及字段校验;init和自定义SQL共享此屏障,失败不发布仓库。\n * @returns 建表结果,失败由调用方映射到对应审计错误\n * @example const ready = await repository.ready(); if (!ready.success) return ready\n */\n ready(): Promise<HaiResult<void>> {\n return this.ensureReady()\n }\n\n /**\n * 将 Date 转为适合当前数据库类型的 SQL 参数\n *\n * 与基类写入保持一致:SQLite 使用毫秒,其他数据库由驱动转换 Date。\n *\n * @param date - 要转换的日期\n * @returns SQLite 返回毫秒时间戳,其他返回 Date\n */\n private toDateParam(date: Date): number | Date {\n return this.isSqlite ? date.getTime() : date\n }\n\n /**\n * 记录一条审计日志\n *\n * @param input - 日志内容\n * @param input.userId - 操作用户 ID(系统操作可省略)\n * @param input.action - 操作类型(如 login / create)\n * @param input.resource - 资源类型(如 auth / users)\n * @param input.resourceId - 资源 ID(可选)\n * @param input.details - 操作详情对象(可选)\n * @param input.ipAddress - 客户端 IP(可选)\n * @param input.userAgent - 客户端 User-Agent(可选)\n * @returns 成功时返回创建的 AuditLog;失败时返回 LOG_FAILED\n */\n async log(input: {\n userId?: string | null\n action: string\n resource: string\n resourceId?: string | null\n details?: Record<string, unknown> | null\n ipAddress?: string | null\n userAgent?: string | null\n }): Promise<HaiResult<AuditLog>> {\n logger.debug('Recording audit log', { action: input.action, resource: input.resource })\n\n const id = core.id.withPrefix('audit_')\n const now = new Date()\n const data: Record<string, unknown> = {\n id,\n userId: input.userId ?? null,\n action: input.action,\n resource: input.resource,\n resourceId: input.resourceId ?? null,\n details: input.details ?? null,\n ipAddress: input.ipAddress ?? null,\n userAgent: input.userAgent ?? null,\n createdAt: now,\n }\n\n try {\n const createResult = await this.create(data)\n if (!createResult.success) {\n logger.error('Failed to record audit log', { action: input.action, error: createResult.error.message })\n return err(\n HaiAuditError.LOG_FAILED,\n auditM('audit_logFailed', { params: { error: createResult.error.message } }),\n createResult.error,\n )\n }\n\n const auditLog: AuditLog = {\n id,\n userId: input.userId ?? null,\n action: input.action,\n resource: input.resource,\n resourceId: input.resourceId ?? null,\n details: input.details ? JSON.stringify(input.details) : null,\n ipAddress: input.ipAddress ?? null,\n userAgent: input.userAgent ?? null,\n createdAt: now,\n }\n\n logger.info('Audit log recorded', { id, action: input.action, resource: input.resource })\n return ok(auditLog)\n }\n catch (error) {\n logger.error('Failed to record audit log', { action: input.action, error })\n return err(\n HaiAuditError.LOG_FAILED,\n auditM('audit_logFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 分页查询日志列表(含用户名 LEFT JOIN)\n *\n * @param options - 过滤条件与分页参数\n * @returns 成功时返回 PaginatedResult(items/total/page/pageSize);失败时返回 QUERY_FAILED\n */\n async listWithUser(options: ListAuditLogsOptions = {}): Promise<HaiResult<PaginatedResult<AuditLogWithUser>>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n logger.debug('Querying audit logs', { userId: options.userId, action: options.action, resource: options.resource })\n\n const conditions: string[] = []\n const params: unknown[] = []\n const { userTable, userIdColumn, userNameColumn } = this.repoConfig\n // 配置标识符已由 init 校验;别名加引号防止 PostgreSQL 折叠大小写。\n const quote = this.db.config?.type === 'mysql' ? '`' : '\"'\n const identifier = (name: string) => `${quote}${name.replaceAll(quote, quote + quote)}${quote}`\n\n if (options.userId) {\n conditions.push('a.user_id = ?')\n params.push(options.userId)\n }\n if (options.action) {\n conditions.push('a.action = ?')\n params.push(options.action)\n }\n if (options.resource) {\n conditions.push('a.resource = ?')\n params.push(options.resource)\n }\n if (options.startDate) {\n conditions.push('a.created_at >= ?')\n params.push(this.toDateParam(options.startDate))\n }\n if (options.endDate) {\n conditions.push('a.created_at <= ?')\n params.push(this.toDateParam(options.endDate))\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n\n try {\n const result = await this.sql().queryPage<AuditReadRow & { username: string | null }>({\n sql: `SELECT a.id, a.user_id AS ${identifier('userId')}, a.action, a.resource, a.resource_id AS ${identifier('resourceId')},\n a.details, a.ip_address AS ${identifier('ipAddress')}, a.user_agent AS ${identifier('userAgent')},\n a.created_at AS ${identifier('createdAt')}, u.${identifier(userNameColumn)} AS username\n FROM ${AUDIT_TABLE} a\n LEFT JOIN ${identifier(userTable)} u ON a.user_id = u.${identifier(userIdColumn)}\n ${whereClause}\n ORDER BY a.created_at DESC`,\n params,\n pagination: { page: options.page, pageSize: options.pageSize },\n overrides: { defaultPageSize: 20 },\n })\n\n if (!result.success) {\n logger.error('Failed to query audit logs', { error: result.error.message })\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n return ok({ ...result.data, items: result.data.items.map(row => ({ ...normalizeAuditLog(row), username: row.username ?? null })) })\n }\n catch (error) {\n logger.error('Failed to query audit logs', { error })\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 获取指定用户的最近活动\n *\n * @param userId - 用户 ID\n * @param limit - 最大返回条数,默认 10\n * @returns 成功时返回 AuditLog 数组(按时间倒序);失败时返回 QUERY_FAILED\n */\n async getUserRecent(userId: string, limit = 10): Promise<HaiResult<AuditLog[]>> {\n logger.debug('Getting user recent activity', { userId, limit })\n\n try {\n const result = await this.findAll({\n where: 'user_id = ?',\n params: [userId],\n orderBy: 'created_at DESC',\n limit,\n })\n\n if (!result.success) {\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n return ok(result.data.map(normalizeAuditLog))\n }\n catch (error) {\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 清理指定天数之前的旧日志\n *\n * @param olderThanDays - 保留天数,默认 90;清理此天数之前的日志\n * @returns 成功时返回删除的记录数;失败时返回 CLEANUP_FAILED\n */\n async cleanupOld(olderThanDays = 90): Promise<HaiResult<number>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n logger.debug('Cleaning up old audit logs', { olderThanDays })\n\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - olderThanDays)\n\n try {\n const result = await this.sql().execute(\n `DELETE FROM ${AUDIT_TABLE} WHERE created_at < ?`,\n [this.toDateParam(cutoff)],\n )\n\n if (!result.success) {\n logger.error('Failed to cleanup audit logs', { error: result.error.message })\n return err(\n HaiAuditError.CLEANUP_FAILED,\n auditM('audit_cleanupFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n const deleted = result.data.changes\n logger.info('Audit logs cleaned up', { olderThanDays, deleted })\n return ok(deleted)\n }\n catch (error) {\n logger.error('Failed to cleanup audit logs', { error })\n return err(\n HaiAuditError.CLEANUP_FAILED,\n auditM('audit_cleanupFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 获取指定天数内的操作统计(按 action 分组计数)\n *\n * @param days - 统计天数,默认 7\n * @returns 成功时返回 AuditStatItem 数组(按 count 倒序);失败时返回 STATS_FAILED\n */\n async getStats(days = 7): Promise<HaiResult<AuditStatItem[]>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n logger.debug('Getting audit statistics', { days })\n\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - days)\n\n try {\n const result = await this.sql().query<{ action: string, count: number | string | bigint }>(\n `SELECT action, COUNT(*) as count\n FROM ${AUDIT_TABLE}\n WHERE created_at >= ?\n GROUP BY action\n ORDER BY count DESC`,\n [this.toDateParam(cutoff)],\n )\n\n if (!result.success) {\n logger.error('Failed to query audit statistics', { error: result.error.message })\n return err(\n HaiAuditError.STATS_FAILED,\n auditM('audit_statsFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n const statistics = result.data.map(item => ({ action: item.action, count: Number(item.count) }))\n if (statistics.some(item => !Number.isSafeInteger(item.count) || item.count < 0))\n return err(HaiAuditError.STATS_FAILED, auditM('audit_invalidStatCount'))\n return ok(statistics)\n }\n catch (error) {\n logger.error('Failed to query audit statistics', { error })\n return err(\n HaiAuditError.STATS_FAILED,\n auditM('audit_statsFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n}\n","/**\n * @h-ai/audit — 审计日志服务主入口\n *\n * 本文件提供统一的 `audit` 对象,聚合所有审计日志操作功能。\n * @module audit-main\n */\n\nimport type { HaiResult, PaginatedResult } from '@h-ai/core'\nimport type { AuditInitConfigInput } from './audit-config.js'\nimport type {\n AuditFunctions,\n AuditHelper,\n AuditLog,\n AuditLogWithUser,\n AuditStatItem,\n CreateAuditLogInput,\n ListAuditLogsOptions,\n} from './audit-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { validateIdentifiers } from '@h-ai/reldb'\nimport { AuditInitConfigSchema } from './audit-config.js'\nimport { createHelper } from './audit-helper.js'\n\nimport { auditM } from './audit-i18n.js'\nimport { AuditLogRepository } from './audit-repository-log.js'\nimport {\n HaiAuditError,\n} from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'main' })\n\n// ─── 输入校验 ───\n\n/** 字符串字段最大长度(防止异常大输入) */\nconst MAX_TEXT_LENGTH = 256\n\n/** 审计详情中的敏感字段统一脱敏为此占位值 */\nconst REDACTED_AUDIT_DETAIL_VALUE = '[REDACTED]'\n\n/**\n * 判断值是否为非空字符串\n *\n * @param value - 待校验值\n */\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\n/**\n * 校验字符串长度是否在限制内\n *\n * @param value - 待校验字符串\n * @param maxLength - 允许最大长度\n */\nfunction isValidTextLength(value: string, maxLength = MAX_TEXT_LENGTH): boolean {\n return value.length <= maxLength\n}\n\n/**\n * 对审计详情执行统一脱敏\n *\n * @param details - 原始详情对象\n */\nfunction sanitizeAuditDetails(details?: Record<string, unknown> | null): Record<string, unknown> | null {\n if (!details) {\n return details ?? null\n }\n\n return core.sanitize.sanitizeSensitiveFields(details, {\n matcher: core.sanitize.defaultSensitiveKeyRegex,\n replacement: REDACTED_AUDIT_DETAIL_VALUE,\n }) as Record<string, unknown>\n}\n\n// ─── 内部状态 ───\n\n/** 当前审计日志仓库实例;init 后赋值,close 后置 null */\nlet currentRepo: AuditLogRepository | null = null\n\n/** 缓存的便捷记录器实例;init 时创建,close 时置 null */\nlet currentHelper: AuditHelper | null = null\n\n/** 并发初始化防护标志 */\nlet initInProgress = false\n\n/** close使尚未完成DDL的初始化失效,防止迟到发布。 */\nlet lifecycleGeneration = 0\n\n// ─── 未初始化占位 ───\n\n/**\n * 未初始化时的错误工具集\n *\n * 调用 audit.log / audit.list 等方法时,\n * 若模块未初始化则返回 { success: false, error: { code: NOT_INITIALIZED } }\n */\nconst notInitialized = core.module.createNotInitializedKit(\n HaiAuditError.NOT_INITIALIZED,\n () => auditM('audit_notInitialized'),\n)\n\n// ─── 便捷记录器占位 ───\n\n/** 未初始化时的便捷记录器占位 */\nconst notInitializedHelper = notInitialized.proxy<AuditHelper>()\n\n// ─── 审计服务对象 ───\n\n/**\n * 审计日志服务对象\n *\n * 统一的审计日志访问入口,提供以下功能:\n * - `audit.init()` — 初始化审计模块\n * - `audit.close()` — 关闭模块\n * - `audit.log()` — 记录审计日志\n * - `audit.list()` — 查询审计日志列表\n * - `audit.getUserRecent()` — 获取用户最近活动\n * - `audit.cleanup()` — 清理旧日志\n * - `audit.getStats()` — 获取统计数据\n * - `audit.helper` — 便捷记录器\n * - `audit.isInitialized` — 初始化状态\n * @example\n * ```ts\n * import { audit } from '@h-ai/audit'\n * import { core } from '@h-ai/core'\n * import { reldb, type ReldbConfigInput } from '@h-ai/reldb'\n * async function recordCreation(config: ReldbConfigInput) {\n * const database = await reldb.init(config)\n * if (!database.success) return database\n * try {\n * const initialized = await audit.init()\n * if (!initialized.success) return initialized\n * const logged = await audit.log({ action: 'create', resource: 'orders', resourceId: 'order_1' })\n * if (logged.success) core.logger.info('Audit recorded', { id: logged.data.id })\n * return logged\n * } finally {\n * const auditClosed = await audit.close()\n * if (!auditClosed.success) return auditClosed // 保留依赖连接,修复后重试关闭。\n * const databaseClosed = await reldb.close()\n * if (!databaseClosed.success) return databaseClosed\n * }\n * }\n * ```\n */\nexport const audit: AuditFunctions = {\n /**\n * 初始化审计模块\n *\n * 会先关闭已有实例(如已初始化),再用新配置重新初始化。\n * 等待 AuditLogRepository / BaseReldbCrudRepository 完成建表后才发布实例。\n * 依赖 @h-ai/reldb 已初始化。\n *\n * @param config - 初始化配置(可选,所有字段均有默认值)\n * @returns 成功时返回 ok(undefined);失败时返回 CONFIG_ERROR\n *\n * @example\n * ```ts\n * const result = await audit.init()\n * if (!result.success) {\n * logger.error('Audit init failed', { error: result.error.message })\n * }\n * ```\n */\n async init(config?: AuditInitConfigInput): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Audit init already in progress, skipping concurrent call')\n return err(\n HaiAuditError.INIT_IN_PROGRESS,\n auditM('audit_initInProgress'),\n )\n }\n initInProgress = true\n const generation = ++lifecycleGeneration\n\n try {\n if (currentRepo) {\n logger.warn('Audit module is already initialized, reinitializing')\n currentRepo = null\n currentHelper = null\n }\n\n logger.info('Initializing audit module')\n\n const parseResult = AuditInitConfigSchema.safeParse(config ?? {})\n if (!parseResult.success) {\n logger.error('Audit config validation failed', { error: parseResult.error.message })\n return err(\n HaiAuditError.CONFIG_ERROR,\n auditM('audit_configError', { params: { error: parseResult.error.message } }),\n parseResult.error,\n )\n }\n const parsed = parseResult.data\n\n const identifierResult = validateIdentifiers([parsed.userTable, parsed.userIdColumn, parsed.userNameColumn])\n if (!identifierResult.success) {\n logger.error('Audit config contains invalid identifiers', { error: identifierResult.error.message })\n return err(\n HaiAuditError.CONFIG_ERROR,\n auditM('audit_configError', { params: { error: identifierResult.error.message } }),\n identifierResult.error,\n )\n }\n\n const candidate = new AuditLogRepository({\n userTable: parsed.userTable,\n userIdColumn: parsed.userIdColumn,\n userNameColumn: parsed.userNameColumn,\n })\n const ready = await candidate.ready()\n if (!ready.success) {\n return err(HaiAuditError.CONFIG_ERROR, auditM('audit_initFailed', { params: { error: ready.error.message } }), ready.error)\n }\n if (generation !== lifecycleGeneration)\n return err(HaiAuditError.NOT_INITIALIZED, auditM('audit_notInitialized'))\n // 候选仓库只拥有schema就绪Promise,不拥有共享reldb连接;成功屏障后才发布。\n currentRepo = candidate\n currentHelper = createHelper(input => audit.log(input))\n\n logger.info('Audit module initialized')\n return ok(undefined)\n }\n catch (error) {\n logger.error('Audit module initialization failed', { error })\n return err(\n HaiAuditError.CONFIG_ERROR,\n auditM('audit_initFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n finally {\n initInProgress = false\n }\n },\n\n /** 当前是否已初始化 */\n get isInitialized(): boolean {\n return currentRepo !== null\n },\n\n /**\n * 记录一条审计日志\n *\n * @param input - 日志内容(action 和 resource 为必填)\n * @returns 成功时返回创建的 AuditLog;未初始化时返回 NOT_INITIALIZED\n */\n log(input: CreateAuditLogInput): Promise<HaiResult<AuditLog>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n const sanitizedInput: CreateAuditLogInput = {\n ...input,\n details: sanitizeAuditDetails(input.details),\n }\n\n if (!isNonEmptyString(sanitizedInput.action) || !isNonEmptyString(sanitizedInput.resource)) {\n return Promise.resolve(err(\n HaiAuditError.LOG_FAILED,\n auditM('audit_invalidInput', { params: { field: 'action/resource', reason: 'must be non-empty string' } }),\n ))\n }\n\n if (!isValidTextLength(sanitizedInput.action) || !isValidTextLength(sanitizedInput.resource)) {\n return Promise.resolve(err(\n HaiAuditError.LOG_FAILED,\n auditM('audit_invalidInput', { params: { field: 'action/resource', reason: 'exceeds max length' } }),\n ))\n }\n\n return currentRepo.log(sanitizedInput)\n },\n\n /**\n * 分页查询审计日志列表(含用户名 LEFT JOIN)\n *\n * @param options - 过滤条件与分页参数\n * @returns 成功时返回 PaginatedResult(items/total/page/pageSize);未初始化时返回 NOT_INITIALIZED\n */\n list(options?: ListAuditLogsOptions): Promise<HaiResult<PaginatedResult<AuditLogWithUser>>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n if (options?.startDate && options?.endDate && options.startDate > options.endDate) {\n return Promise.resolve(err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_invalidInput', { params: { field: 'dateRange', reason: 'startDate must be before endDate' } }),\n ))\n }\n\n return currentRepo.listWithUser(options)\n },\n\n /**\n * 获取指定用户的最近活动记录\n *\n * @param userId - 用户 ID\n * @param limit - 最大返回条数,默认 10\n * @returns 成功时返回 AuditLog 数组;未初始化时返回 NOT_INITIALIZED\n */\n getUserRecent(userId: string, limit?: number): Promise<HaiResult<AuditLog[]>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n if (!isNonEmptyString(userId)) {\n return Promise.resolve(err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_invalidInput', { params: { field: 'userId', reason: 'must be non-empty string' } }),\n ))\n }\n\n if (typeof limit === 'number' && (!Number.isInteger(limit) || limit <= 0)) {\n return Promise.resolve(err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_invalidInput', { params: { field: 'limit', reason: 'must be a positive integer' } }),\n ))\n }\n\n return currentRepo.getUserRecent(userId, limit)\n },\n\n /**\n * 清理指定天数之前的旧日志\n *\n * @param olderThanDays - 保留天数,默认 90\n * @returns 成功时返回删除的记录数;未初始化时返回 NOT_INITIALIZED\n */\n cleanup(olderThanDays?: number): Promise<HaiResult<number>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n if (typeof olderThanDays === 'number' && (!Number.isInteger(olderThanDays) || olderThanDays < 0)) {\n return Promise.resolve(err(\n HaiAuditError.CLEANUP_FAILED,\n auditM('audit_invalidInput', { params: { field: 'olderThanDays', reason: 'must be a non-negative integer' } }),\n ))\n }\n\n return currentRepo.cleanupOld(olderThanDays)\n },\n\n /**\n * 获取指定天数内的操作统计(按 action 分组计数)\n *\n * @param days - 统计天数,默认 7\n * @returns 成功时返回 AuditStatItem 数组;未初始化时返回 NOT_INITIALIZED\n */\n getStats(days?: number): Promise<HaiResult<AuditStatItem[]>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n if (typeof days === 'number' && (!Number.isInteger(days) || days < 0)) {\n return Promise.resolve(err(\n HaiAuditError.STATS_FAILED,\n auditM('audit_invalidInput', { params: { field: 'days', reason: 'must be a non-negative integer' } }),\n ))\n }\n\n return currentRepo.getStats(days)\n },\n\n /**\n * 便捷记录器\n *\n * 未初始化时调用任意方法均返回 NOT_INITIALIZED 错误。\n */\n get helper(): AuditHelper {\n if (!currentHelper) {\n return notInitializedHelper\n }\n return currentHelper\n },\n\n /**\n * 关闭审计模块,释放内部状态\n */\n async close(): Promise<HaiResult<void>> {\n lifecycleGeneration++\n if (!currentRepo) {\n logger.info('Audit module already closed, skipping')\n return ok(undefined)\n }\n\n logger.info('Closing audit module')\n currentRepo = null\n currentHelper = null\n logger.info('Audit module closed')\n return ok(undefined)\n },\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/audit-config.ts","../src/audit-context.ts","../messages/en-US.json","../messages/ja-JP.json","../messages/zh-CN.json","../src/audit-i18n.ts","../src/audit-types.ts","../src/audit-database-time.ts","../src/audit-alert-functions.ts","../src/audit-log-functions.ts","../src/audit-backup-format.ts","../src/audit-backup-functions.ts","../src/audit-helper.ts","../src/audit-migration.ts","../src/audit-repository-log.ts","../src/audit-main.ts"],"names":["core","err","reldb","ok","logger","z","hash","createHash","table"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/audit — 错误码与配置\n *\n * 定义审计模块的错误码常量与初始化配置类型。\n * @module audit-config\n */\n\nimport type { ReachFunctions } from '@h-ai/reach'\nimport type { StorageFunctions } from '@h-ai/storage'\nimport { z } from 'zod'\n\n// ─── 初始化配置 ───\n\n/**\n * 审计模块初始化配置 Schema(Zod)\n *\n * 所有字段均有默认值,可直接调用 `audit.init()` 无需传参。\n * @example\n * ```ts\n * import { AuditInitConfigSchema } from '@h-ai/audit'\n * const config = AuditInitConfigSchema.parse({ userTable: 'app_users' })\n * // 这里只校验字段映射;实际初始化前必须已有可用的 RelDB。\n * ```\n */\nexport const AuditInitConfigSchema = z.object({\n /** 以固定时间窗口统计已提交事件;目标和事件由应用配置,不内置业务角色。 */\n alerts: z.object({\n enabled: z.boolean().default(false),\n maxNotificationsPerCheck: z.number().int().min(1).max(1000).default(100),\n rules: z.array(z.object({\n id: z.string().regex(/^[\\w-]{1,64}$/),\n actions: z.array(z.string().trim().min(1).max(128)).min(1).max(50),\n resource: z.string().trim().min(1).max(256).optional(),\n outcomes: z.array(z.enum(['success', 'failure', 'denied'])).max(3).default(['failure', 'denied']),\n minimumSeverity: z.enum(['info', 'warning', 'error', 'critical']).default('info'),\n severity: z.enum(['warning', 'error', 'critical']).default('warning'),\n threshold: z.number().int().min(1).max(1000000000).default(1),\n windowSeconds: z.number().int().min(60).max(86400).default(300),\n targets: z.array(z.object({\n id: z.string().regex(/^[\\w-]{1,64}$/),\n provider: z.string().trim().min(1).max(128),\n to: z.string().trim().min(1).max(1000),\n })).min(1).max(20).refine(targets => new Set(targets.map(target => target.id)).size === targets.length),\n })).max(20).default([]).refine(rules => new Set(rules.map(rule => rule.id)).size === rules.length),\n schedule: z.object({\n enabled: z.boolean().default(false),\n cron: z.string().trim().min(1).max(128).default('* * * * *'),\n timezone: z.string().trim().min(1).max(128).default('UTC'),\n }).default({ enabled: false, cron: '* * * * *', timezone: 'UTC' }),\n }).default({ enabled: false, maxNotificationsPerCheck: 100, rules: [], schedule: { enabled: false, cron: '* * * * *', timezone: 'UTC' } }).refine(alerts => !alerts.enabled || alerts.rules.length > 0),\n /** 可选的流式归档;自动执行由宿主现有 Scheduler 装配。 */\n backup: z.object({\n enabled: z.boolean().default(false),\n batchSize: z.number().int().min(1).max(1000).default(200),\n maxRecordBytes: z.number().int().min(1024).max(64 * 1024 * 1024).default(1024 * 1024),\n schedule: z.object({\n enabled: z.boolean().default(false),\n cron: z.string().trim().min(1).max(128).default('0 2 * * *'),\n timezone: z.string().trim().min(1).max(128).default('UTC'),\n }).default({ enabled: false, cron: '0 2 * * *', timezone: 'UTC' }),\n }).default({ enabled: false, batchSize: 200, maxRecordBytes: 1024 * 1024, schedule: { enabled: false, cron: '0 2 * * *', timezone: 'UTC' } }),\n /** 框架入口自动采集;显式 audit.log 不受此开关影响。 */\n capture: z.object({\n enabled: z.boolean().default(true),\n includeReads: z.boolean().default(false),\n }).default({ enabled: true, includeReads: false }),\n /** 未传时沿用数据库保留设置;显式关闭才解除保护。 */\n retention: z.object({\n enabled: z.boolean().default(false),\n minDays: z.number().int().min(1).max(36500).default(90),\n }).optional(),\n /** 凭据始终脱敏;此开关仅控制业务隐私字段。 */\n privacy: z.object({\n enabled: z.boolean().default(true),\n fields: z.array(z.string().trim().min(1).max(256)).max(1000).default([]),\n }).default({ enabled: true, fields: [] }),\n /** 用户表名,用于 list 查询时 LEFT JOIN 获取用户名 */\n userTable: z.string().default('hai_iam_users'),\n /** 用户表主键列名,用于 JOIN 条件 */\n userIdColumn: z.string().default('id'),\n /** 用户表用户名列名,用于 SELECT 输出 */\n userNameColumn: z.string().default('username'),\n})\n\n/**\n * 审计模块初始化配置(解析后)\n * @example\n * ```ts\n * import { AuditInitConfigSchema, type AuditInitConfig } from '@h-ai/audit'\n * const config: AuditInitConfig = AuditInitConfigSchema.parse({ userTable: 'app_users' })\n * ```\n */\nexport type AuditInitConfig = z.output<typeof AuditInitConfigSchema>\n\n/**\n * 审计模块初始化配置(传入参数)\n * @example\n * ```ts\n * import type { AuditInitConfigInput } from '@h-ai/audit'\n * const record: AuditInitConfigInput = { userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' }\n * ```\n */\nexport type AuditInitConfigInput = z.input<typeof AuditInitConfigSchema> & {\n /** 开启备份时注入已初始化且私有访问的存储;audit 不拥有它的生命周期。 */\n storage?: StorageFunctions\n /** 开启告警时注入已初始化的 Reach;通知人员/目标仍由应用配置。 */\n reach?: ReachFunctions\n}\n","/** 审计身份仅在当前异步请求中传播,不进入全局授权状态或通用日志上下文。 */\nimport type { AuditContext } from './audit-types.js'\nimport { AsyncLocalStorage } from 'node:async_hooks'\n\nconst storage = new AsyncLocalStorage<Readonly<AuditContext>>()\n\n/**\n * 模块内部读取上下文;无请求时返回空对象。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const requestId = getAuditContext().requestId\n * ```\n */\nexport function getAuditContext(): Readonly<AuditContext> {\n return storage.getStore() ?? {}\n}\n\n/**\n * 复制身份及角色数组,防止调用者后续修改污染事件快照。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const id = withAuditContext({ requestId: 'request-1' }, () => getAuditContext().requestId)\n * ```\n */\nexport function withAuditContext<T>(context: AuditContext, operation: () => T): T {\n const previous = getAuditContext()\n const actor = Object.hasOwn(context, 'actor') ? context.actor : previous.actor\n const snapshot = actor ? { ...actor, ...(actor.roles ? { roles: [...actor.roles] } : {}) } : actor\n return storage.run({ ...previous, ...context, actor: snapshot }, operation)\n}\n","{\n \"audit_eventFieldsInvalid\": \"Invalid event fields\",\n \"audit_identityMismatch\": \"Actor snapshot does not match the event identity\",\n \"audit_queryInvalid\": \"Invalid filters or dates\",\n \"audit_eventProcessingFailed\": \"Event processing failed\",\n \"audit_sortInvalid\": \"Invalid sort field or direction\",\n \"audit_retentionPolicyFailed\": \"Unable to read or update the audit retention policy\",\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"audit_notInitialized\": \"Audit module not initialized, call audit.init() first\",\n \"audit_initFailed\": \"Audit module initialization failed: {error}\",\n \"audit_logFailed\": \"Failed to record audit log: {error}\",\n \"audit_queryFailed\": \"Failed to query audit logs: {error}\",\n \"audit_cleanupFailed\": \"Failed to cleanup audit logs: {error}\",\n \"audit_statsFailed\": \"Failed to query audit statistics: {error}\",\n \"audit_invalidStatCount\": \"Audit count is outside the valid range and cannot be displayed safely\",\n \"audit_configError\": \"Audit config validation failed: {error}\",\n \"audit_initInProgress\": \"Audit module initialization is already in progress\",\n \"audit_invalidInput\": \"Invalid audit input for {field}: {reason}\",\n \"audit_backupDisabled\": \"Audit backup is disabled\",\n \"audit_backupFailed\": \"Audit backup operation failed\",\n \"audit_backupInvalid\": \"Invalid audit backup input\",\n \"audit_backupConflict\": \"This backup ID belongs to a different export request\",\n \"audit_backupStorageRequired\": \"Audit backups require initialized storage\",\n \"audit_backupPrivateStorageRequired\": \"Audit backups require private storage; remove the public base URL and restrict archive reads\",\n \"audit_backupVerificationFailed\": \"Audit archive verification could not complete\",\n \"audit_backupTaskName\": \"Audit log backup\",\n \"audit_alertsDisabled\": \"Audit alerts are disabled\",\n \"audit_alertsFailed\": \"Audit alert check or notification failed\",\n \"audit_alertReachRequired\": \"Alerts require initialized Reach and valid notification providers\",\n \"audit_alertSubject\": \"[{severity}] Security alert: {rule}\",\n \"audit_alertTaskName\": \"Audit anomaly alert check\",\n \"audit_unknownTask\": \"Unknown audit scheduled task\",\n \"audit_eventTimeUnavailable\": \"A valid database audit time is unavailable\"\n}\n","{\n \"audit_eventFieldsInvalid\": \"イベント項目が無効です\",\n \"audit_identityMismatch\": \"身元スナップショットと操作者が一致しません\",\n \"audit_queryInvalid\": \"検索条件または日付が無効です\",\n \"audit_eventProcessingFailed\": \"イベント処理に失敗しました\",\n \"audit_sortInvalid\": \"並べ替え項目または方向が無効です\",\n \"audit_retentionPolicyFailed\": \"監査の最低保持ポリシーを読み取りまたは更新できません\",\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"audit_notInitialized\": \"監査モジュールが初期化されていません。先にaudit.init()を呼び出してください\",\n \"audit_initFailed\": \"監査モジュールの初期化に失敗しました: {error}\",\n \"audit_logFailed\": \"監査ログの記録に失敗しました: {error}\",\n \"audit_queryFailed\": \"監査ログの取得に失敗しました: {error}\",\n \"audit_cleanupFailed\": \"監査ログのクリーンアップに失敗しました: {error}\",\n \"audit_statsFailed\": \"監査統計の取得に失敗しました: {error}\",\n \"audit_invalidStatCount\": \"監査件数が有効範囲を超えているため、安全に表示できません\",\n \"audit_configError\": \"監査設定の検証に失敗しました: {error}\",\n \"audit_initInProgress\": \"監査モジュールの初期化は既に実行中です\",\n \"audit_invalidInput\": \"{field}の監査入力が無効です: {reason}\",\n \"audit_backupDisabled\": \"監査バックアップは無効です\",\n \"audit_backupFailed\": \"監査バックアップ操作に失敗しました\",\n \"audit_backupInvalid\": \"監査バックアップの入力が無効です\",\n \"audit_backupConflict\": \"このバックアップ ID は異なるエクスポート条件で使用されています\",\n \"audit_backupStorageRequired\": \"監査バックアップには初期化済みストレージが必要です\",\n \"audit_backupPrivateStorageRequired\": \"監査バックアップには非公開ストレージが必要です。公開 URL を削除し、アーカイブの読取を制限してください\",\n \"audit_backupVerificationFailed\": \"監査アーカイブの検証を完了できませんでした\",\n \"audit_backupTaskName\": \"監査ログのバックアップ\",\n \"audit_alertsDisabled\": \"監査アラートは無効です\",\n \"audit_alertsFailed\": \"監査アラートの確認または通知に失敗しました\",\n \"audit_alertReachRequired\": \"初期化済みの Reach と有効な通知チャネルが必要です\",\n \"audit_alertSubject\": \"[{severity}] セキュリティアラート:{rule}\",\n \"audit_alertTaskName\": \"監査異常アラート確認\",\n \"audit_unknownTask\": \"不明な監査定期タスクです\",\n \"audit_eventTimeUnavailable\": \"有効な監査用 DB 時刻を取得できません\"\n}\n","{\n \"audit_eventFieldsInvalid\": \"事件字段无效\",\n \"audit_identityMismatch\": \"身份快照与操作者不一致\",\n \"audit_queryInvalid\": \"筛选条件或日期无效\",\n \"audit_eventProcessingFailed\": \"事件处理失败\",\n \"audit_sortInvalid\": \"排序字段或方向无效\",\n \"audit_retentionPolicyFailed\": \"无法读取或更新审计最低保留策略\",\n \"$schema\": \"https://inlang.com/schema/inlang-message-format\",\n \"audit_notInitialized\": \"审计模块尚未初始化,请先调用 audit.init()\",\n \"audit_initFailed\": \"审计模块初始化失败:{error}\",\n \"audit_logFailed\": \"审计日志记录失败:{error}\",\n \"audit_queryFailed\": \"审计日志查询失败:{error}\",\n \"audit_cleanupFailed\": \"审计日志清理失败:{error}\",\n \"audit_statsFailed\": \"审计统计查询失败:{error}\",\n \"audit_invalidStatCount\": \"审计统计数量超出有效范围,无法安全显示\",\n \"audit_configError\": \"审计配置校验失败:{error}\",\n \"audit_initInProgress\": \"审计模块正在初始化中,请勿并发调用\",\n \"audit_invalidInput\": \"审计输入参数无效({field}):{reason}\",\n \"audit_backupDisabled\": \"审计备份未启用\",\n \"audit_backupFailed\": \"审计备份操作失败\",\n \"audit_backupInvalid\": \"审计备份参数无效\",\n \"audit_backupConflict\": \"此备份编号已用于不同的导出条件\",\n \"audit_backupStorageRequired\": \"启用审计备份需要已初始化的存储\",\n \"audit_backupPrivateStorageRequired\": \"审计备份需要私有存储,请移除公开访问基础 URL 并限制归档读取\",\n \"audit_backupVerificationFailed\": \"无法完成审计归档校验\",\n \"audit_backupTaskName\": \"审计日志备份\",\n \"audit_alertsDisabled\": \"审计告警未启用\",\n \"audit_alertsFailed\": \"审计告警检查或通知失败\",\n \"audit_alertReachRequired\": \"告警需要已初始化的 Reach 和有效通知渠道\",\n \"audit_alertSubject\": \"[{severity}] 安全告警:{rule}\",\n \"audit_alertTaskName\": \"审计异常告警检查\",\n \"audit_unknownTask\": \"未知审计定时任务\",\n \"audit_eventTimeUnavailable\": \"无法取得有效的数据库审计时间\"\n}\n","/**\n * @h-ai/audit — i18n\n *\n * 本文件提供审计模块的 i18n 文案访问入口。\n * @module audit-i18n\n */\n\nimport { core } from '@h-ai/core'\nimport messagesEnUS from '../messages/en-US.json'\nimport messagesJaJP from '../messages/ja-JP.json'\nimport messagesZhCN from '../messages/zh-CN.json'\n\n// ─── i18n ───\n\n/**\n * 审计模块文案 Key 类型\n * @example 模块内部上下文\n * ```ts\n * const key: AuditMessageKey = 'audit_notInitialized'\n * const message = auditM(key)\n * ```\n */\ntype AuditMessageKey = keyof typeof messagesZhCN\n\n/**\n * 获取审计模块文案。\n *\n * @param key - 文案 Key(以 `audit_` 为前缀)\n * @param options - 插值参数与格式化选项\n * @returns 本地化后的文案字符串\n * @remarks 具体参数结构与 core.i18n.createMessageGetter 保持一致。\n * @example 模块内部上下文\n * ```ts\n * const message = auditM('audit_logFailed', { locale: 'en-US', params: { error: 'database unavailable' } })\n * ```\n */\nexport const auditM = core.i18n.createMessageGetter<AuditMessageKey>({\n 'zh-CN': messagesZhCN,\n 'en-US': messagesEnUS,\n 'ja-JP': messagesJaJP,\n})\n","/**\n * @h-ai/audit — 公共类型定义\n *\n * 审计模块对外类型:错误接口、实体类型、操作接口、函数接口。\n * @module audit-types\n */\n\nimport type { ErrorInfo, HaiResult, PaginatedResult, PaginationOptionsInput } from '@h-ai/core'\nimport type { DmlWithTxOperations } from '@h-ai/reldb'\nimport type { SchedulerInitInput } from '@h-ai/scheduler'\nimport type { AuditInitConfigInput } from './audit-config.js'\nimport { core } from '@h-ai/core'\n\n// ─── 错误定义(照 @h-ai/core 范式) ───\n\nconst AuditErrorInfo = {\n LOG_FAILED: '001:500',\n QUERY_FAILED: '002:500',\n CLEANUP_FAILED: '003:500',\n STATS_FAILED: '004:500',\n INIT_IN_PROGRESS: '005:409',\n NOT_INITIALIZED: '010:500',\n CONFIG_ERROR: '012:500',\n BACKUP_DISABLED: '020:403',\n BACKUP_FAILED: '021:500',\n BACKUP_INVALID: '022:400',\n BACKUP_CONFLICT: '023:409',\n ALERTS_DISABLED: '024:403',\n ALERTS_FAILED: '025:500',\n} as const satisfies ErrorInfo\n\n/**\n * 审计初始化、写入、查询和清理失败的稳定错误定义。\n * @example\n * ```ts\n * import { HaiAuditError } from '@h-ai/audit'\n * import { err } from '@h-ai/core'\n * const failed = err(HaiAuditError.NOT_INITIALIZED, 'Audit is not initialized')\n * if (!failed.success) failed.error.code\n * ```\n */\nexport const HaiAuditError = core.error.buildHaiErrorsDef('audit', AuditErrorInfo)\n\n// ─── 实体类型 ───\n\n/**\n * 事件发生时的最小身份快照,不承载授权真值或凭据。\n * @example\n * ```ts\n * import type { AuditActorSnapshot } from '@h-ai/audit'\n * const actor: AuditActorSnapshot = { id: 'user-1', username: 'alice', roles: ['auditor'] }\n * ```\n */\nexport interface AuditActorSnapshot {\n id: string\n username?: string\n displayName?: string\n roles?: string[]\n}\n\n/**\n * 异步请求的审计上下文;不替代会话校验或权限守卫。\n * @example\n * ```ts\n * import type { AuditContext } from '@h-ai/audit'\n * const context: AuditContext = { requestId: 'request-1', actor: { id: 'user-1', username: 'alice' }, ipAddress: '192.0.2.8' }\n * ```\n */\nexport interface AuditContext {\n actor?: AuditActorSnapshot | null\n category?: 'system' | 'business'\n requestId?: string\n traceId?: string\n scopeId?: string\n ipAddress?: string\n userAgent?: string\n}\n\n/**\n * 分类、结果、等级及事件身份;旧记录升级前未知的值保持 null。\n * @example\n * ```ts\n * import type { AuditEventFields } from '@h-ai/audit'\n * const fields: AuditEventFields = { category: 'system', outcome: 'denied', severity: 'warning', requestId: 'request-1' }\n * ```\n */\nexport interface AuditEventFields {\n category?: 'system' | 'business' | null\n outcome?: 'success' | 'failure' | 'denied' | null\n severity?: 'info' | 'warning' | 'error' | 'critical' | null\n requestId?: string | null\n traceId?: string | null\n scopeId?: string | null\n actorSnapshot?: AuditActorSnapshot | null\n}\n\n/**\n * 审计日志记录\n *\n * 表示一条已持久化的审计日志条目。\n * @example\n * ```ts\n * import type { AuditLog } from '@h-ai/audit'\n * const record: AuditLog = { id: 'audit_example', userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: null, ipAddress: null, userAgent: null, createdAt: new Date() }\n * ```\n */\nexport interface AuditLog extends AuditEventFields {\n /** 审计日志 ID,格式为 `audit_` 前缀 + 随机串 */\n id: string\n /** 操作用户 ID;系统操作时为 null */\n userId: string | null\n /** 操作类型(如 login / logout / create / update / delete) */\n action: string\n /** 资源类型(如 auth / users / roles) */\n resource: string\n /** 资源 ID;不涉及特定资源时为 null */\n resourceId: string | null\n /** 操作详情(JSON 字符串);无详情时为 null */\n details: string | null\n /** 客户端 IP 地址;未知时为 null */\n ipAddress: string | null\n /** 客户端 User-Agent;未知时为 null */\n userAgent: string | null\n /** 创建时间 */\n createdAt: Date\n}\n\n/**\n * 审计日志记录(含用户名)\n *\n * 新记录使用事件时身份快照;无快照的历史记录才保留旧的用户表关联展示。\n * @example\n * ```ts\n * import type { AuditLogWithUser } from '@h-ai/audit'\n * const record: AuditLogWithUser = { id: 'audit_example', userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: null, ipAddress: null, userAgent: null, createdAt: new Date() , username: 'alice' }\n * ```\n */\nexport interface AuditLogWithUser extends AuditLog {\n /** 操作用户的用户名;用户不存在或系统操作时为 null */\n username: string | null\n}\n\n/**\n * 创建审计日志输入\n *\n * 调用 {@link AuditFunctions.log} 时传入的参数。\n * 仅 `action` 和 `resource` 为必填。\n * @example\n * ```ts\n * import type { CreateAuditLogInput } from '@h-ai/audit'\n * const record: CreateAuditLogInput = { userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: { status: 'pending' } }\n * ```\n */\nexport interface CreateAuditLogInput extends AuditEventFields {\n /** 操作用户 ID;系统操作可省略 */\n userId?: string | null\n /** 操作类型(如 login / create / update / delete) */\n action: string\n /** 资源类型(如 auth / users / roles) */\n resource: string\n /** 资源 ID;不涉及特定资源时可省略 */\n resourceId?: string | null\n /** 操作详情对象;密码、token、secret 等凭证类字段会先自动脱敏,再 JSON 序列化存储 */\n details?: Record<string, unknown> | null\n /** 客户端 IP 地址 */\n ipAddress?: string | null\n /** 客户端 User-Agent */\n userAgent?: string | null\n}\n\n/**\n * 审计日志列表查询选项\n *\n * 所有字段均为可选,不传则不过滤。\n * @example\n * ```ts\n * import type { ListAuditLogsOptions } from '@h-ai/audit'\n * const record: ListAuditLogsOptions = { action: 'create', resource: 'orders', page: 1, pageSize: 20 }\n * ```\n */\nexport interface ListAuditLogsOptions extends PaginationOptionsInput {\n /** 按可信入口生成或校验的请求/追踪编号定位关联事件。 */\n requestId?: string\n traceId?: string\n category?: 'system' | 'business'\n outcome?: 'success' | 'failure' | 'denied'\n severity?: 'info' | 'warning' | 'error' | 'critical'\n scopeId?: string\n sortBy?: 'createdAt' | 'action' | 'resource' | 'category' | 'outcome' | 'severity'\n sortDirection?: 'asc' | 'desc'\n /** 按用户 ID 过滤 */\n userId?: string\n /** 按操作类型过滤(精确匹配) */\n action?: string\n /** 按资源类型过滤(精确匹配) */\n resource?: string\n /** 起始时间(含),只返回此时间之后的日志 */\n startDate?: Date\n /** 结束时间(含),只返回此时间之前的日志 */\n endDate?: Date\n}\n\n/**\n * 审计统计结果项\n *\n * 按操作类型(action)分组的统计条目。\n * @example\n * ```ts\n * import type { AuditStatItem } from '@h-ai/audit'\n * const record: AuditStatItem = { action: 'create', count: 12 }\n * ```\n */\nexport interface AuditStatItem {\n /** 操作类型 */\n action: string\n /** 该操作在统计时间范围内的次数 */\n count: number\n}\n\n/**\n * CRUD 审计操作输入\n *\n * 调用 {@link AuditHelper.crud} 时传入的参数。\n * @example\n * ```ts\n * import type { CrudAuditInput } from '@h-ai/audit'\n * const record: CrudAuditInput = { userId: 'user_1', action: 'update', resource: 'orders', resourceId: 'order_1', details: { status: 'paid' } }\n * ```\n */\nexport interface CrudAuditInput extends AuditEventFields {\n /** 操作用户 ID(系统操作传 null) */\n userId?: string | null\n /** 操作类型 */\n action: 'create' | 'read' | 'update' | 'delete'\n /** 资源类型(如 users / roles) */\n resource: string\n /** 资源 ID(可选) */\n resourceId?: string\n /** 操作详情对象(可选) */\n details?: Record<string, unknown>\n /** 客户端 IP(可选) */\n ip?: string\n /** 客户端 User-Agent(可选) */\n ua?: string\n}\n\n// ─── 便捷操作接口 ───\n\n/**\n * 审计便捷记录器\n *\n * 封装常见审计场景(认证、CRUD),简化调用方代码。\n * 通过 {@link AuditFunctions.helper} 访问。\n * @example\n * ```ts\n * import type { AuditHelper } from '@h-ai/audit'\n * // helper 来自已初始化的 audit;数据库生命周期归调用方。\n * async function recordLogin(helper: AuditHelper) {\n * const result = await helper.login('user_1', '127.0.0.1')\n * return result.success ? 'recorded' : result.error.message\n * }\n * ```\n */\nexport interface AuditHelper {\n /**\n * 记录用户登录\n *\n * @param userId - 登录用户 ID\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n login: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录用户登出\n *\n * @param userId - 登出用户 ID\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n logout: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录用户注册\n *\n * @param userId - 注册用户 ID\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n register: (userId: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录密码重置请求\n *\n * @param email - 请求重置的邮箱地址\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n passwordResetRequest: (email: string, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录密码重置完成\n *\n * @param userId - 重置密码的用户 ID(匿名重置场景传 null)\n * @param ip - 客户端 IP(可选)\n * @param ua - 客户端 User-Agent(可选)\n */\n passwordResetComplete: (userId: string | null, ip?: string, ua?: string) => Promise<HaiResult<void>>\n /**\n * 记录 CRUD 操作\n *\n * @param input - CRUD 审计输入(action 和 resource 为必填)\n *\n * @example\n * ```ts\n * await audit.helper.crud({ userId: 'user_1', action: 'create', resource: 'users', resourceId: 'user_2' })\n * ```\n */\n crud: (input: CrudAuditInput) => Promise<HaiResult<void>>\n}\n\n// ─── 函数接口 ───\n\n/**\n * 审计模块函数接口\n *\n * 统一的审计日志访问入口。\n * @example\n * ```ts\n * import { audit } from '@h-ai/audit'\n * import { core } from '@h-ai/core'\n * import { reldb, type ReldbConfigInput } from '@h-ai/reldb'\n * async function recordCreation(config: ReldbConfigInput) {\n * const database = await reldb.init(config)\n * if (!database.success) return database\n * try {\n * const initialized = await audit.init()\n * if (!initialized.success) return initialized\n * const logged = await audit.log({ action: 'create', resource: 'orders', resourceId: 'order_1' })\n * if (logged.success) core.logger.info('Audit recorded', { id: logged.data.id })\n * return logged\n * } finally {\n * const auditClosed = await audit.close()\n * if (!auditClosed.success) return auditClosed // 保留依赖连接,修复后重试关闭。\n * const databaseClosed = await reldb.close()\n * if (!databaseClosed.success) return databaseClosed\n * }\n * }\n * ```\n */\nexport interface AuditFunctions {\n /** 手动流式归档与完整性核对,关闭后返回未初始化。 */\n readonly backup: AuditBackupOperations\n /** 宿主显式装配的备份/告警任务计划;没有启用自动任务时为 null。 */\n readonly schedulerPlan: Required<Pick<SchedulerInitInput, 'tasks' | 'hooks'>> | null\n /** 检查已提交事件的本窗口和前一窗口;每个规则/目标/窗口只尝试一次外部通知。 */\n checkAlerts: (options?: { signal?: AbortSignal }) => Promise<HaiResult<AuditAlertReport>>\n /**\n * 在异步隔离的审计上下文中执行操作;同步或异步结果原样返回,调用方异常原样传播。\n * @param context - 可信宿主解析的关联字段与身份快照。\n * @param operation - 业务操作,内部 audit.log 自动补齐未显式指定的字段。\n * @returns 业务操作的原始返回值或 Promise。\n */\n withContext: <T>(context: AuditContext, operation: () => T) => T\n /**\n * 初始化审计模块\n *\n * @param config - 初始化配置(可选,所有字段均有默认值)\n * @returns 成功时返回 ok(undefined);失败时返回 CONFIG_ERROR\n */\n init: (config?: AuditInitConfigInput) => Promise<HaiResult<void>>\n /**\n * 关闭审计模块,释放内部状态\n */\n close: () => Promise<HaiResult<void>>\n /** 当前是否已初始化 */\n readonly isInitialized: boolean\n /**\n * 记录一条审计日志\n *\n * @param input - 日志内容(action 和 resource 为必填)\n * @param tx - 可选的调用者事务;提交或回滚同时决定事件,不在此提交事务。\n * @returns 成功时返回创建的 AuditLog;失败时返回 LOG_FAILED\n */\n log: (input: CreateAuditLogInput, tx?: DmlWithTxOperations) => Promise<HaiResult<AuditLog>>\n /**\n * 框架入口自动记录。模块未初始化或关闭自动采集时跳过;默认跳过成功读取。\n * 不改变原业务结果;调用方仍须检查记录失败,避免静默丢失审计。\n * @param input - 仅包含安全的事件字段,不应复制请求体或凭据。\n * @param options - 入口是否属于读取操作;失败和拒绝的读取始终采集。\n * @param options.read - 读取标志;默认 false。\n * @param options.tx - 可选的调用者事务;回滚不会留下成功变更事件。\n * @returns 持久化成功或按配置跳过时成功,否则返回审计错误。\n */\n capture: (input: CreateAuditLogInput, options?: { read?: boolean, tx?: DmlWithTxOperations }) => Promise<HaiResult<void>>\n /**\n * 分页查询审计日志列表(含用户名 LEFT JOIN)\n *\n * @param options - 查询过滤与分页选项\n * @returns 成功时返回 PaginatedResult(items/total/page/pageSize);失败时返回 QUERY_FAILED\n */\n list: (options?: ListAuditLogsOptions) => Promise<HaiResult<PaginatedResult<AuditLogWithUser>>>\n /**\n * 获取指定用户的最近活动记录\n *\n * @param userId - 用户 ID\n * @param limit - 最大返回条数,默认 10\n * @returns 成功时返回 AuditLog 数组;失败时返回 QUERY_FAILED\n */\n getUserRecent: (userId: string, limit?: number) => Promise<HaiResult<AuditLog[]>>\n /**\n * 清理指定天数之前的旧日志\n *\n * @param olderThanDays - 保留天数,默认 90;清理此天数之前的日志\n * @returns 成功时返回删除的记录数;失败时返回 CLEANUP_FAILED\n */\n cleanup: (olderThanDays?: number) => Promise<HaiResult<number>>\n /**\n * 获取指定天数内的操作统计(按 action 分组计数)\n *\n * @param days - 统计天数,默认 7\n * @returns 成功时返回 AuditStatItem 数组;失败时返回 STATS_FAILED\n */\n getStats: (days?: number, filters?: Pick<ListAuditLogsOptions, 'category' | 'outcome' | 'severity' | 'scopeId' | 'userId' | 'resource'>) => Promise<HaiResult<AuditStatItem[]>>\n /**\n * 便捷记录器,封装常见审计场景\n *\n * 未初始化时调用任意方法均返回 NOT_INITIALIZED 错误。\n */\n readonly helper: AuditHelper\n}\n\n/**\n * 私有归档键前缀;宿主公开文件入口须拒绝此命名空间,即使备份策略已关闭。\n * @example\n * ```ts\n * import { AUDIT_BACKUP_PREFIX } from '@h-ai/audit'\n * const key = `${AUDIT_BACKUP_PREFIX}daily-archive.jsonl`\n * ```\n */\nexport const AUDIT_BACKUP_PREFIX = 'hai-private/audit-backups/'\n\n/**\n * 归档扫描条件。缺省截止时刻在开始时固定,过程中新增日志交给下一次归档。\n * @example\n * ```ts\n * import type { AuditBackupOptions } from '@h-ai/audit'\n * const options: AuditBackupOptions = { id: 'daily-archive', from: new Date('2026-01-01T00:00:00Z') }\n * ```\n */\nexport interface AuditBackupOptions {\n /** 同一业务执行使用稳定 ID;省略时生成随机 ID。已有 ID 仅核对并复用完整归档。 */\n id?: string\n from?: Date\n to?: Date\n signal?: AbortSignal\n}\n\n/**\n * 完整归档回执;SHA-256 校验内容完整性,不能替代独立存储权限或真实性认证。\n * @example\n * ```ts\n * import { audit, type AuditBackupInfo } from '@h-ai/audit'\n * // 宿主已初始化 RelDB、私有 Storage 和 Audit。\n * const result = await audit.backup.run()\n * if (result.success) { const receipt: AuditBackupInfo = result.data; void receipt.sha256 }\n * ```\n */\nexport interface AuditBackupInfo {\n id: string\n key: string\n recordCount: number\n sha256: string\n createdAt: Date\n cutoff: Date\n}\n\n/**\n * 备份不覆盖在线审计。JSONL 归档可核对后用于离线恢复/独立查询存储。\n * @example\n * ```ts\n * import { audit, type AuditBackupOperations } from '@h-ai/audit'\n * const operations: AuditBackupOperations = audit.backup\n * const result = await operations.run({ id: 'daily-archive' })\n * if (!result.success) result.error.code\n * ```\n */\nexport interface AuditBackupOperations {\n /** 创建或核对并复用同一 ID 的完整归档;已有归档不覆盖,输入无效、取消或存储失败返回失败。 */\n run: (options?: AuditBackupOptions) => Promise<HaiResult<AuditBackupInfo>>\n /** 有界流式核对规范、记录数和校验和;只允许读取私有归档命名空间。 */\n verify: (key: string, options?: { signal?: AbortSignal }) => Promise<HaiResult<AuditBackupInfo>>\n}\n\n/**\n * 本次检查的通知提交回执;submitted 不证明收件人已阅读,queued 仅表示 Reach 持久入队。\n * @example\n * ```ts\n * import { audit, type AuditAlertReport } from '@h-ai/audit'\n * const result = await audit.checkAlerts()\n * if (result.success) { const report: AuditAlertReport = result.data; void report.failed }\n * ```\n */\nexport interface AuditAlertReport {\n submitted: number\n queued: number\n failed: number\n /** 已达到单轮通知上限,后续检查继续领取未尝试目标。 */\n more: boolean\n}\n","/** 审计写入、归档截止和告警窗口共用数据库时钟,不使用各节点系统时间作为共享真值。 */\nimport type { HaiResult } from '@h-ai/core'\nimport type { DmlOperations } from '@h-ai/reldb'\nimport { err, ok } from '@h-ai/core'\nimport { reldb } from '@h-ai/reldb'\nimport { auditM } from './audit-i18n.js'\nimport { HaiAuditError } from './audit-types.js'\n\n/**\n * 仅由已初始化的数据库类型选择固定 SQL,绝不接受配置 SQL。\n * @example 模块内部上下文\n * ```ts\n * const expression = auditClockSql() // RelDB 已初始化。\n * const result = await reldb.sql.get(`SELECT ${expression} AS now_ms`)\n * if (!result.success) result.error.code\n * ```\n */\nexport function auditClockSql(): string {\n return reldb.config?.type === 'sqlite'\n ? 'CAST(ROUND((julianday(\\'now\\')-2440587.5)*86400000) AS INTEGER)'\n : reldb.config?.type === 'postgresql' ? 'CAST(EXTRACT(EPOCH FROM clock_timestamp())*1000 AS BIGINT)' : 'CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3))*1000 AS SIGNED)'\n}\n\n/**\n * 在调用者当前连接/事务读取存储端毫秒时刻;异常由调用的业务边界转换。\n * @example 模块内部上下文\n * ```ts\n * const time = await readAuditTime() // RelDB 已初始化。\n * if (time.success) time.data.toISOString()\n * ```\n */\nexport async function readAuditTime(sql: DmlOperations = reldb.sql): Promise<HaiResult<Date>> {\n const result = await sql.get<{ now_ms: number | string }>(`SELECT ${auditClockSql()} AS now_ms`)\n if (!result.success)\n return err(HaiAuditError.LOG_FAILED, auditM('audit_eventTimeUnavailable'), result.error)\n const value = Number(result.data?.now_ms)\n if (!Number.isSafeInteger(value) || value < 0 || !Number.isFinite(new Date(value).getTime()))\n return err(HaiAuditError.LOG_FAILED, auditM('audit_eventTimeUnavailable'))\n return ok(new Date(value))\n}\n","/** 固定窗口告警:只查询已提交事件,持久领取先于外部通知,无隐式重试队列。 */\nimport type { HaiResult } from '@h-ai/core'\nimport type { ReachFunctions } from '@h-ai/reach'\nimport type { SchedulerInitInput } from '@h-ai/scheduler'\nimport type { AuditInitConfig } from './audit-config.js'\nimport type { AuditAlertReport, AuditFunctions } from './audit-types.js'\nimport { createHash } from 'node:crypto'\nimport { core, err, ok } from '@h-ai/core'\nimport { reldb } from '@h-ai/reldb'\nimport { withAuditContext } from './audit-context.js'\nimport { auditClockSql, readAuditTime } from './audit-database-time.js'\nimport { auditM } from './audit-i18n.js'\nimport { HaiAuditError } from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'alerts' })\nconst levels = ['info', 'warning', 'error', 'critical'] as const\nconst table = 'hai_audit_alert_claims'\nconst hash = (value: unknown) => createHash('sha256').update(JSON.stringify(value)).digest('hex')\n\n/**\n * 模块内部告警实现;Reach 和共享数据库由宿主拥有,close 只排空自己的检查。\n * @example 模块内部上下文\n * ```ts\n * async function check(input: Parameters<typeof createAuditAlerts>[0]) {\n * const service = createAuditAlerts(input)\n * try { return await service.check() }\n * finally { await service.close() }\n * }\n * ```\n */\nexport function createAuditAlerts(input: { config: AuditInitConfig['alerts'], reach?: ReachFunctions, log: AuditFunctions['log'] }) {\n let active = true\n const controllers = new Set<AbortController>()\n const pending = new Set<Promise<HaiResult<AuditAlertReport>>>()\n\n async function run(signal: AbortSignal): Promise<HaiResult<AuditAlertReport>> {\n if (!input.config.enabled)\n return err(HaiAuditError.ALERTS_DISABLED, auditM('audit_alertsDisabled'))\n signal.throwIfAborted()\n const type = reldb.config?.type\n const clock = auditClockSql()\n const time = await readAuditTime()\n if (!time.success)\n return time\n const now = time.data.getTime()\n const report: AuditAlertReport = { submitted: 0, queued: 0, failed: 0, more: false }\n let attempted = 0\n for (const rule of input.config.rules) {\n const duration = rule.windowSeconds * 1000\n const current = Math.floor(now / duration) * duration\n // 本窗口加前一窗口:避免阈值刚好在调度边界前达到时漏报;停机超过两窗不补发历史风暴。\n for (const start of [current - duration, current]) {\n signal.throwIfAborted()\n const end = Math.min(start + duration, now + 1)\n const actions = [...new Set(rule.actions)].sort()\n const outcomes = [...new Set(rule.outcomes)].sort()\n const severities = levels.slice(levels.indexOf(rule.minimumSeverity))\n const date = (value: number) => type === 'sqlite' ? value : new Date(value)\n const conditions = ['created_at >= ?', 'created_at < ?', 'resource <> ?', `action IN (${actions.map(() => '?').join(',')})`]\n const params: unknown[] = [date(start), date(end), 'audit.alert', ...actions]\n if (outcomes.length) {\n conditions.push(`outcome IN (${outcomes.map(() => '?').join(',')})`)\n params.push(...outcomes)\n }\n if (rule.minimumSeverity !== 'info') {\n conditions.push(`severity IN (${severities.map(() => '?').join(',')})`)\n params.push(...severities)\n }\n if (rule.resource) {\n conditions.push('resource = ?')\n params.push(rule.resource)\n }\n const counted = await reldb.sql.get<{ count: number | string }>(`SELECT COUNT(*) AS count FROM hai_audit_logs WHERE ${conditions.join(' AND ')}`, params)\n if (!counted.success)\n return counted\n const count = Number(counted.data?.count)\n if (!Number.isSafeInteger(count) || count < 0)\n return err(HaiAuditError.ALERTS_FAILED, auditM('audit_alertsFailed'))\n if (count < rule.threshold)\n continue\n for (const target of rule.targets) {\n signal.throwIfAborted()\n const id = hash({ rule: { ...rule, actions, outcomes, targets: undefined }, target, start })\n if (attempted >= input.config.maxNotificationsPerCheck) {\n const existing = await reldb.sql.get<{ id: string }>(`SELECT id FROM ${table} WHERE id=?`, [id])\n if (!existing.success)\n return existing\n if (!existing.data)\n report.more = true\n continue\n }\n // 最终领取使用存储端执行时钟;检查暂停或锁等待后不能重新领取已过期、已清理的旧窗口。\n const selection = `SELECT ?, ?, ?, ?, 'claimed' WHERE ? <= ${clock} AND ? > ${clock}`\n const statement = type === 'mysql'\n ? `INSERT IGNORE INTO ${table} (id, rule_id, target_id, window_start, status) ${selection}`\n : `INSERT INTO ${table} (id, rule_id, target_id, window_start, status) ${selection} ON CONFLICT(id) DO NOTHING`\n const claimed = await reldb.sql.execute(statement, [id, rule.id, target.id, start, start, start + duration * 2])\n if (!claimed.success)\n return claimed\n if (claimed.data.changes === 0)\n continue\n attempted++\n const details = { ruleId: rule.id, targetId: target.id, count, windowStart: new Date(start).toISOString(), windowEnd: new Date(start + duration).toISOString(), level: rule.severity }\n const recorded = await input.log({ action: 'audit.alert.claimed', resource: 'audit.alert', resourceId: id, category: 'system', severity: rule.severity, outcome: 'success', details })\n if (!recorded.success)\n return recorded\n // 领取后取消仍保留 claimed,不能把未知外部效果重新当作从未执行。\n signal.throwIfAborted()\n // 首次 INSERT 或审计写入也可能等待;发送前再以数据库时钟确认,sending/unknown 不自动清除。\n const sending = await reldb.sql.execute(`UPDATE ${table} SET status='sending' WHERE id=? AND status='claimed' AND ? > ${clock}`, [id, start + duration * 2])\n if (!sending.success)\n return sending\n if (sending.data.changes !== 1)\n continue\n const sent = await input.reach!.send({ provider: target.provider, to: target.to, subject: auditM('audit_alertSubject', { params: { severity: rule.severity, rule: rule.id } }), body: JSON.stringify(details), idempotencyKey: id })\n const accepted = sent.success && sent.data.success\n const status = accepted ? (sent.data.deferred ? 'queued' : 'submitted') : 'unknown'\n const updated = await reldb.sql.execute(`UPDATE ${table} SET status=?, queue_id=?, error_code=? WHERE id=? AND status='sending'`, [status, sent.success && sent.data.deferred ? sent.data.queueId : null, sent.success ? null : sent.error.code, id])\n if (!updated.success || updated.data.changes !== 1)\n return err(HaiAuditError.ALERTS_FAILED, auditM('audit_alertsFailed'), updated.success ? undefined : updated.error)\n if (status === 'queued')\n report.queued++\n else if (status === 'submitted')\n report.submitted++\n else\n report.failed++\n const outcome = await input.log({ action: 'audit.alert.notification', resource: 'audit.alert', resourceId: id, category: 'system', severity: rule.severity, outcome: accepted ? 'success' : 'failure', details: { ...details, status, ...(sent.success ? {} : { reasonCode: sent.error.code }), ...(sent.success && sent.data.deferred ? { queueId: sent.data.queueId } : {}) } })\n if (!outcome.success)\n return outcome\n if (!accepted)\n logger.error('Audit alert notification outcome requires review', { id, ruleId: rule.id, targetId: target.id, errorCode: sent.success ? undefined : sent.error.code })\n }\n }\n }\n // 只删除查询范围外的领取。当前/前一窗口永远不会因清理重新发送。\n const oldest = now - Math.max(...input.config.rules.map(rule => rule.windowSeconds * 1000)) * 3\n const cleaned = await reldb.sql.execute(`DELETE FROM ${table} WHERE window_start < ? AND status IN ('submitted', 'queued')`, [oldest])\n return cleaned.success ? ok(report) : cleaned\n }\n\n const check: AuditFunctions['checkAlerts'] = (options) => {\n if (!active)\n return Promise.resolve(err(HaiAuditError.NOT_INITIALIZED, auditM('audit_notInitialized')))\n if (options?.signal !== undefined && !(options.signal instanceof AbortSignal))\n return Promise.resolve(err(HaiAuditError.ALERTS_FAILED, auditM('audit_alertsFailed')))\n const controller = new AbortController()\n const cancel = () => controller.abort()\n options?.signal?.addEventListener('abort', cancel, { once: true })\n if (options?.signal?.aborted)\n cancel()\n controllers.add(controller)\n const operation = withAuditContext({ actor: { id: 'system:audit-alerts', username: 'scheduler' }, category: 'system' }, () => run(controller.signal)).catch((error: unknown) => {\n logger.error('Audit alert check failed', { error })\n return err(HaiAuditError.ALERTS_FAILED, auditM('audit_alertsFailed'), error)\n })\n pending.add(operation)\n void operation.finally(() => {\n controllers.delete(controller)\n pending.delete(operation)\n options?.signal?.removeEventListener('abort', cancel)\n })\n return operation\n }\n let schedule: Required<Pick<SchedulerInitInput, 'tasks' | 'hooks'>> | null = null\n if (input.config.enabled && input.config.schedule.enabled) {\n schedule = {\n tasks: [{ id: 'hai-audit-alerts', name: auditM('audit_alertTaskName'), idempotent: true, cron: input.config.schedule.cron, timezone: input.config.schedule.timezone }],\n hooks: { onTaskExecute: async ({ context, signal }) => {\n if (context.taskId !== 'hai-audit-alerts')\n throw core.error.buildHaiErrorInst(HaiAuditError.ALERTS_FAILED, auditM('audit_alertsFailed'))\n const result = await check({ signal })\n if (!result.success || result.data.failed > 0)\n throw core.error.buildHaiErrorInst(HaiAuditError.ALERTS_FAILED, auditM('audit_alertsFailed'), result.success ? undefined : result.error)\n return result.data\n } },\n }\n }\n return {\n check,\n schedule,\n async close() {\n active = false\n controllers.forEach(controller => controller.abort())\n await Promise.allSettled([...pending])\n },\n }\n}\n","/** 审计写入的统一字段、身份、隐私及失败边界。 */\nimport type { AuditInitConfig } from './audit-config.js'\nimport type { AuditLogRepository } from './audit-repository-log.js'\nimport type { AuditActorSnapshot, AuditFunctions } from './audit-types.js'\nimport { core, err } from '@h-ai/core'\nimport { z } from 'zod'\nimport { getAuditContext } from './audit-context.js'\nimport { auditM } from './audit-i18n.js'\nimport { HaiAuditError } from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'writer' })\nconst actorSchema = z.object({ id: z.string().min(1).max(256), username: z.string().max(256).optional(), displayName: z.string().max(256).optional(), roles: z.array(z.string().max(256)).max(1000).optional() })\nconst detailsSchema = z.record(z.string(), z.unknown())\nconst inputSchema = z.object({\n userId: z.string().min(1).max(256).nullable().optional(),\n actorSnapshot: actorSchema.nullable().optional(),\n action: z.string().trim().min(1).max(256),\n resource: z.string().trim().min(1).max(256),\n resourceId: z.string().max(256).nullable().optional(),\n category: z.enum(['system', 'business']).nullable().optional(),\n outcome: z.enum(['success', 'failure', 'denied']).nullable().optional(),\n severity: z.enum(['info', 'warning', 'error', 'critical']).nullable().optional(),\n requestId: z.string().max(256).nullable().optional(),\n traceId: z.string().max(256).nullable().optional(),\n scopeId: z.string().max(256).nullable().optional(),\n ipAddress: z.string().max(256).nullable().optional(),\n userAgent: z.string().max(4096).nullable().optional(),\n details: detailsSchema.nullable().optional(),\n})\nconst querySchema = z.object({\n requestId: z.string().min(1).max(256).optional(),\n traceId: z.string().min(1).max(256).optional(),\n userId: z.string().min(1).max(256).optional(),\n resource: z.string().min(1).max(256).optional(),\n action: z.string().min(1).max(256).optional(),\n scopeId: z.string().min(1).max(256).optional(),\n category: z.enum(['system', 'business']).optional(),\n outcome: z.enum(['success', 'failure', 'denied']).optional(),\n severity: z.enum(['info', 'warning', 'error', 'critical']).optional(),\n sortBy: z.enum(['createdAt', 'action', 'resource', 'category', 'outcome', 'severity']).optional(),\n sortDirection: z.enum(['asc', 'desc']).optional(),\n startDate: z.date().optional(),\n endDate: z.date().optional(),\n})\n\n/**\n * 列表与统计的公开筛选参数做运行时校验,分页由 RelDB 的统一分页器处理。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const valid = validAuditQuery({ category: 'system', sortBy: 'createdAt' })\n * ```\n */\nexport function validAuditQuery(options: unknown): boolean {\n return querySchema.safeParse(options ?? {}).success\n}\n\n/**\n * 数据库 JSON 与调用输入共用最小身份白名单。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const actor = readAuditActor({ id: 'user-1', roles: ['auditor'] })\n * ```\n */\nexport function readAuditActor(value: unknown): AuditActorSnapshot | null {\n if (value == null)\n return null\n const parsed = actorSchema.safeParse(typeof value === 'string' ? JSON.parse(value) : value)\n if (!parsed.success)\n throw new Error('Invalid audit actor snapshot')\n return parsed.data\n}\n\n/**\n * 创建当前初始化代次的写入函数;未成功持久化的事件始终返回失败并记录诊断。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * function writer(repository: AuditLogRepository, config: AuditInitConfig) {\n * return createAuditWriter(repository, config)\n * }\n * ```\n */\nexport function createAuditWriter(repository: AuditLogRepository, config: AuditInitConfig): AuditFunctions['log'] {\n const fields = new Set(config.privacy.fields.map(field => field.toLowerCase()))\n const businessPrivacy = /email|phone|mobile|idcard|identitynumber|bankaccount|shippingaddress|billingaddress|realname|identifier|recipient|邮箱|手机|电话|身份证|银行卡|地址|真实姓名|客户姓名/i\n return async (input, tx) => {\n try {\n const parsed = inputSchema.safeParse(input)\n if (!parsed.success) {\n logger.error('Audit input rejected', { issues: parsed.error.issues.map(issue => issue.path.join('.')) })\n return err(HaiAuditError.LOG_FAILED, auditM('audit_invalidInput', { params: { field: 'event', reason: auditM('audit_eventFieldsInvalid') } }))\n }\n const value = parsed.data\n const context = getAuditContext()\n const correlation = core.context.get()\n const actor = Object.hasOwn(value, 'actorSnapshot') ? value.actorSnapshot : context.actor\n const userId = value.userId !== undefined ? value.userId : actor?.id ?? correlation.userId ?? null\n if (value.actorSnapshot && value.actorSnapshot.id !== userId) {\n logger.error('Audit actor snapshot rejected', { reason: auditM('audit_identityMismatch') })\n return err(HaiAuditError.LOG_FAILED, auditM('audit_invalidInput', { params: { field: 'actorSnapshot', reason: auditM('audit_identityMismatch') } }))\n }\n const snapshot = actor?.id === userId ? readAuditActor(actor) : userId ? await repository.captureActor(userId, tx) : null\n const outcome = value.outcome ?? 'success'\n // 先获得最终 JSON 形态,类实例和 toJSON 生成的凭据字段也必须经过脱敏。\n const jsonDetails: unknown = value.details == null\n ? null\n : JSON.parse(JSON.stringify(value.details, (key: string, entry: unknown) => {\n // 审计字段表示实际数据;命中对象/数组时整体遮盖,不沿用配置日志保留对象块的规则。\n const sensitive = core.sanitize.isSensitiveKey(key) || (config.privacy.enabled && (businessPrivacy.test(key) || fields.has(key.toLowerCase())))\n return sensitive ? '[REDACTED]' : entry\n }))\n const normalizedDetails = jsonDetails == null ? null : detailsSchema.parse(jsonDetails)\n const credentialSafe = normalizedDetails == null ? null : core.sanitize.sanitizeSensitiveFields(normalizedDetails, { replacement: '[REDACTED]' })\n const details = !config.privacy.enabled || credentialSafe == null\n ? credentialSafe\n : core.sanitize.sanitizeSensitiveFields(credentialSafe, {\n matcher: key => businessPrivacy.test(key) || fields.has(key.toLowerCase()),\n replacement: '[REDACTED]',\n })\n const result = await repository.log({\n ...value,\n category: value.category ?? context.category ?? 'business',\n outcome,\n severity: value.severity ?? (outcome === 'denied' ? 'warning' : outcome === 'failure' ? 'error' : 'info'),\n userId,\n actorSnapshot: snapshot,\n requestId: value.requestId ?? context.requestId ?? correlation.requestId ?? null,\n traceId: value.traceId ?? context.traceId ?? correlation.traceId ?? correlation.requestId ?? null,\n scopeId: value.scopeId ?? context.scopeId ?? correlation.scopeId ?? null,\n ipAddress: value.ipAddress ?? context.ipAddress ?? null,\n userAgent: value.userAgent ?? context.userAgent ?? null,\n details,\n }, tx)\n if (!result.success)\n logger.error('Audit event persistence failed', { action: value.action, resource: value.resource, requestId: value.requestId ?? context.requestId, error: result.error })\n return result\n }\n catch (error) {\n logger.error('Audit event processing failed', { requestId: getAuditContext().requestId, error })\n return err(HaiAuditError.LOG_FAILED, auditM('audit_logFailed', { params: { error: auditM('audit_eventProcessingFailed') } }), error)\n }\n }\n}\n","/** JSONL 归档格式与有界校验;不向在线审计表导入或覆盖数据。 */\nimport type { AuditBackupInfo } from './audit-types.js'\nimport { Buffer } from 'node:buffer'\nimport { createHash } from 'node:crypto'\nimport { z } from 'zod'\nimport { readAuditActor } from './audit-log-functions.js'\nimport { AUDIT_BACKUP_PREFIX } from './audit-types.js'\n\n/**\n * 安全的稳定归档执行编号。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const parsed = backupIdSchema.safeParse('daily-archive')\n * ```\n */\nexport const backupIdSchema = z.string().regex(/^[a-z0-9][\\w-]{0,127}$/i)\nconst digestSchema = z.string().regex(/^[a-f0-9]{64}$/)\n/**\n * 可移植归档头;关联指纹用于同一执行复用核对。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const parsed = backupHeaderSchema.safeParse({ type: 'header', format: 'hai-audit', version: 1, id: 'preview', createdAt: new Date().toISOString(), cutoff: new Date().toISOString(), from: null, requestHash: 'a'.repeat(64) })\n * ```\n */\nexport const backupHeaderSchema = z.object({\n type: z.literal('header'),\n format: z.literal('hai-audit'),\n version: z.literal(1),\n id: backupIdSchema,\n createdAt: z.iso.datetime(),\n cutoff: z.iso.datetime(),\n from: z.iso.datetime().nullable(),\n requestHash: digestSchema,\n})\nconst footerSchema = z.object({ type: z.literal('footer'), recordCount: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER), sha256: digestSchema })\nconst entrySchema = z.object({ type: z.literal('entry'), record: z.object({ id: z.string().min(1), action: z.string().min(1), resource: z.string().min(1), createdAt: z.iso.datetime(), actorSnapshot: z.unknown().optional() }).passthrough() })\n\n/**\n * 按字节限制每条记录,包含换行;过大时拒绝归档,不截断审计证据。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const line = archiveLine({ type: 'footer', recordCount: 0, sha256: 'a'.repeat(64) }, 1024)\n * ```\n */\nexport function archiveLine(value: unknown, maxRecordBytes: number): Buffer {\n const encoded = Buffer.from(`${JSON.stringify(value)}\\n`, 'utf8')\n if (encoded.byteLength > maxRecordBytes)\n throw new Error('Audit archive record exceeds size limit')\n return encoded\n}\n\n/** 分片中跨 UTF-8 字符或换行的输入也保持原始字节;无换行的大输入不会无限累计。 */\nasync function* lines(source: AsyncIterable<Uint8Array>, maxBytes: number, signal?: AbortSignal): AsyncGenerator<Buffer> {\n let fragments: Uint8Array[] = []\n let length = 0\n for await (const chunk of source) {\n signal?.throwIfAborted()\n const buffer = Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength)\n let offset = 0\n while (offset < buffer.byteLength) {\n const newline = buffer.indexOf(10, offset)\n const end = newline === -1 ? buffer.byteLength : newline + 1\n const part = buffer.subarray(offset, end)\n length += part.byteLength\n if (length > maxBytes)\n throw new Error('Audit archive record exceeds size limit')\n fragments.push(part)\n offset = end\n if (newline !== -1) {\n yield Buffer.concat(fragments, length)\n fragments = []\n length = 0\n }\n }\n }\n signal?.throwIfAborted()\n if (length !== 0)\n throw new Error('Audit archive is truncated')\n}\n\n/**\n * 内部流式读取器;格式/校验/读取错误由公开备份边界转为 HaiResult。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const header = archiveLine({ type: 'header', format: 'hai-audit', version: 1, id: 'preview', createdAt: new Date().toISOString(), cutoff: new Date().toISOString(), from: null, requestHash: 'a'.repeat(64) }, 1024)\n * const footer = archiveLine({ type: 'footer', recordCount: 0, sha256: createHash('sha256').update(header).digest('hex') }, 1024)\n * const content = (async function* () { yield header; yield footer })()\n * const verified = await verifyArchive(content, { key: `${AUDIT_BACKUP_PREFIX}preview.jsonl`, maxRecordBytes: 1024 })\n * ```\n */\nexport async function verifyArchive(source: AsyncIterable<Uint8Array>, options: { key: string, maxRecordBytes: number, signal?: AbortSignal }): Promise<{ info: AuditBackupInfo, requestHash: string }> {\n const hash = createHash('sha256')\n const decoder = new TextDecoder('utf-8', { fatal: true })\n let header: z.output<typeof backupHeaderSchema> | undefined\n let footer: z.output<typeof footerSchema> | undefined\n let count = 0\n for await (const line of lines(source, options.maxRecordBytes, options.signal)) {\n if (footer)\n throw new Error('Audit archive has trailing records')\n const value: unknown = JSON.parse(decoder.decode(line))\n if (!header) {\n header = backupHeaderSchema.parse(value)\n if (options.key !== `${AUDIT_BACKUP_PREFIX}${header.id}.jsonl`)\n throw new Error('Audit archive identity mismatch')\n hash.update(line)\n continue\n }\n const end = footerSchema.safeParse(value)\n if (end.success) {\n footer = end.data\n if (footer.recordCount !== count || footer.sha256 !== hash.digest('hex'))\n throw new Error('Audit archive checksum or count mismatch')\n continue\n }\n const entry = entrySchema.parse(value)\n readAuditActor(entry.record.actorSnapshot)\n if (!Number.isSafeInteger(++count))\n throw new Error('Audit archive record count exceeds safe range')\n hash.update(line)\n }\n if (!header || !footer)\n throw new Error('Audit archive is incomplete')\n return { info: { id: header.id, key: options.key, recordCount: footer.recordCount, sha256: footer.sha256, createdAt: new Date(header.createdAt), cutoff: new Date(header.cutoff) }, requestHash: header.requestHash }\n}\n","/** 归档编排复用 Storage 的流式条件写;不拥有存储或调度器的生命周期。 */\nimport type { HaiResult } from '@h-ai/core'\nimport type { SchedulerInitInput } from '@h-ai/scheduler'\nimport type { StorageFunctions } from '@h-ai/storage'\nimport type { AuditInitConfig } from './audit-config.js'\nimport type { AuditLogRepository } from './audit-repository-log.js'\nimport type { AuditBackupInfo, AuditBackupOperations, AuditFunctions } from './audit-types.js'\nimport { createHash } from 'node:crypto'\nimport { core, err, ok } from '@h-ai/core'\nimport { reldb } from '@h-ai/reldb'\nimport { z } from 'zod'\nimport { archiveLine, backupIdSchema, verifyArchive } from './audit-backup-format.js'\nimport { withAuditContext } from './audit-context.js'\nimport { readAuditTime } from './audit-database-time.js'\nimport { auditM } from './audit-i18n.js'\nimport { AUDIT_BACKUP_PREFIX, HaiAuditError } from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'backup' })\nconst optionsSchema = z.object({ id: backupIdSchema.optional(), from: z.date().optional(), to: z.date().optional(), signal: z.instanceof(AbortSignal).optional() })\n\n/**\n * 内部归档服务;close 取消并等待本代操作,不会关闭宿主的 Storage。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * async function saveArchive(input: Parameters<typeof createAuditBackup>[0]) {\n * const service = createAuditBackup(input)\n * try { return await service.operations.run({ id: 'daily-archive' }) }\n * finally { await service.close() }\n * }\n * ```\n */\nexport function createAuditBackup(input: { repository: AuditLogRepository, config: AuditInitConfig['backup'], storage?: StorageFunctions, capture: AuditFunctions['capture'] }) {\n let active = true\n const controllers = new Set<AbortController>()\n const pending = new Set<Promise<HaiResult<AuditBackupInfo>>>()\n\n function track(operation: (signal: AbortSignal) => Promise<HaiResult<AuditBackupInfo>>, event: { action: string, resourceId?: string, read?: boolean }, parent?: AbortSignal): Promise<HaiResult<AuditBackupInfo>> {\n if (!active)\n return Promise.resolve(err(HaiAuditError.NOT_INITIALIZED, auditM('audit_notInitialized')))\n const controller = new AbortController()\n const signal = parent ? AbortSignal.any([parent, controller.signal]) : controller.signal\n controllers.add(controller)\n const promise = Promise.resolve().then(async () => {\n if (!input.config.enabled || !input.storage?.isInitialized)\n return err(HaiAuditError.BACKUP_DISABLED, auditM('audit_backupDisabled'))\n signal.throwIfAborted()\n return operation(signal)\n }).catch((error: unknown) => {\n logger.error('Audit backup operation failed', { error })\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'), error)\n }).then(async (result) => {\n const recorded = await input.capture({\n action: event.action,\n resource: 'audit',\n resourceId: result.success ? result.data.id : event.resourceId,\n category: 'system',\n outcome: result.success ? 'success' : result.error.httpStatus === 403 ? 'denied' : 'failure',\n details: result.success ? { key: result.data.key, recordCount: result.data.recordCount, sha256: result.data.sha256 } : { reasonCode: result.error.code },\n }, { read: event.read })\n if (!recorded.success)\n logger.error('Audit backup event failed', { action: event.action, error: recorded.error })\n return result\n }).finally(() => {\n controllers.delete(controller)\n pending.delete(promise)\n })\n pending.add(promise)\n return promise\n }\n\n async function read(key: string, signal: AbortSignal) {\n const opened = await input.storage!.file.getStream(key, { signal })\n if (!opened.success)\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'), opened.error)\n try {\n return ok(await verifyArchive(opened.data, { key, maxRecordBytes: input.config.maxRecordBytes, signal }))\n }\n catch (error) {\n logger.error('Audit archive verification failed', { error })\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupVerificationFailed'), error)\n }\n }\n\n async function reuse(key: string, requestHash: string, signal: AbortSignal): Promise<HaiResult<AuditBackupInfo>> {\n const previous = await read(key, signal)\n if (!previous.success)\n return previous\n return previous.data.requestHash === requestHash\n ? ok(previous.data.info)\n : err(HaiAuditError.BACKUP_CONFLICT, auditM('audit_backupConflict'))\n }\n\n const operations: AuditBackupOperations = {\n run(options) {\n const parsed = optionsSchema.safeParse(options ?? {})\n if (!parsed.success)\n return Promise.resolve(err(HaiAuditError.BACKUP_INVALID, auditM('audit_backupInvalid')))\n const values = parsed.data\n const id = values.id ?? core.id.uuid()\n const from = values.from ? new Date(values.from.getTime()) : undefined\n const key = `${AUDIT_BACKUP_PREFIX}${id}.jsonl`\n const database = reldb.config\n const source = database?.type === 'sqlite' ? { type: database.type, database: database.database } : { type: database?.type, host: database?.host, port: database?.port, database: database?.database }\n const requestHash = createHash('sha256').update(JSON.stringify({ source, from: from?.toISOString() ?? null, to: values.to?.toISOString() ?? null })).digest('hex')\n return track(async (signal) => {\n const time = await readAuditTime()\n if (!time.success)\n return time\n const createdAt = time.data\n const cutoff = new Date(values.to?.getTime() ?? createdAt.getTime())\n if (cutoff > createdAt || (from && from > cutoff))\n return err(HaiAuditError.BACKUP_INVALID, auditM('audit_backupInvalid'))\n const exists = await input.storage!.file.exists(key)\n if (!exists.success)\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'), exists.error)\n if (exists.data)\n return reuse(key, requestHash, signal)\n let completed: AuditBackupInfo | undefined\n async function* content() {\n const hash = createHash('sha256')\n const header = archiveLine({ type: 'header', format: 'hai-audit', version: 1, id, createdAt: createdAt.toISOString(), cutoff: cutoff.toISOString(), from: from?.toISOString() ?? null, requestHash }, input.config.maxRecordBytes)\n hash.update(header)\n yield header\n let afterId: string | undefined\n let count = 0\n while (true) {\n signal.throwIfAborted()\n const page = await input.repository.archivePage({ afterId, from, cutoff, limit: input.config.batchSize })\n if (!page.success)\n throw core.error.buildHaiErrorInst(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'), page.error)\n for (const record of page.data) {\n signal.throwIfAborted()\n const line = archiveLine({ type: 'entry', record }, input.config.maxRecordBytes)\n hash.update(line)\n yield line\n if (!Number.isSafeInteger(++count))\n throw new Error('Audit archive record count exceeds safe range')\n afterId = record.id\n }\n if (page.data.length < input.config.batchSize)\n break\n }\n const sha256 = hash.digest('hex')\n yield archiveLine({ type: 'footer', recordCount: count, sha256 }, input.config.maxRecordBytes)\n completed = { id, key, recordCount: count, sha256, createdAt, cutoff }\n }\n const stream = content()\n let uploaded: Awaited<ReturnType<StorageFunctions['file']['put']>>\n try {\n uploaded = await input.storage!.file.put(key, stream, { ifNoneMatch: '*', contentType: 'application/x-ndjson', cacheControl: 'private, no-store', signal })\n }\n finally {\n await stream.return(undefined)\n }\n if (!uploaded.success) {\n // 外部写入结果不明或并发竞争时,以实际完整对象核对,不能盲目覆盖。\n const stored = await input.storage!.file.exists(key)\n if (stored.success && stored.data)\n return reuse(key, requestHash, signal)\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'), uploaded.error)\n }\n if (!completed)\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'))\n return ok(completed)\n }, { action: 'audit.backup', resourceId: id }, values.signal)\n },\n verify(key, options) {\n if (typeof key !== 'string' || !key.startsWith(AUDIT_BACKUP_PREFIX) || !key.endsWith('.jsonl') || !backupIdSchema.safeParse(key.slice(AUDIT_BACKUP_PREFIX.length, -6)).success)\n return Promise.resolve(err(HaiAuditError.BACKUP_INVALID, auditM('audit_backupInvalid')))\n const parsed = optionsSchema.pick({ signal: true }).safeParse(options ?? {})\n if (!parsed.success)\n return Promise.resolve(err(HaiAuditError.BACKUP_INVALID, auditM('audit_backupInvalid')))\n return track(async (signal) => {\n const result = await read(key, signal)\n return result.success ? ok(result.data.info) : result\n }, { action: 'audit.backup.verify', read: true }, parsed.data.signal)\n },\n }\n let schedule: Required<Pick<SchedulerInitInput, 'tasks' | 'hooks'>> | null = null\n if (input.config.enabled && input.config.schedule.enabled) {\n schedule = {\n tasks: [{ id: 'hai-audit-backup', name: auditM('audit_backupTaskName'), idempotent: true, cron: input.config.schedule.cron, timezone: input.config.schedule.timezone }],\n hooks: { onTaskExecute: async ({ context, signal }) => {\n if (context.taskId !== 'hai-audit-backup' || !context.occurrenceId)\n throw core.error.buildHaiErrorInst(HaiAuditError.BACKUP_INVALID, auditM('audit_backupInvalid'))\n // 回调由可信调度器调用;显式抛错才能使 Scheduler 正确记录失败,而非返回失败对象后算成功。\n const result = await withAuditContext({ actor: { id: 'system:audit-backup', username: 'scheduler' }, requestId: context.occurrenceId }, () => operations.run({ id: context.occurrenceId, signal }))\n if (!result.success)\n throw core.error.buildHaiErrorInst(HaiAuditError.BACKUP_FAILED, result.error.message, result.error)\n return result.data\n } },\n }\n }\n return {\n operations,\n schedule,\n async close() {\n active = false\n for (const controller of controllers)\n controller.abort()\n await Promise.allSettled([...pending])\n },\n }\n}\n","/**\n * @h-ai/audit — 审计便捷记录器\n *\n * 封装常见审计操作(登录、登出、注册、密码重置、CRUD),简化调用方代码。\n * @module audit-helper\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type {\n AuditHelper,\n AuditLog,\n CreateAuditLogInput,\n CrudAuditInput,\n} from './audit-types.js'\n\nimport { ok } from '@h-ai/core'\n\n/**\n * 将 log 结果映射为 void 返回\n *\n * @param result - log 操作结果\n * @returns 成功返回 ok(undefined);失败透传原始错误\n */\nfunction toVoid(result: HaiResult<AuditLog>): HaiResult<void> {\n if (!result.success) {\n return result\n }\n return ok(undefined)\n}\n\n/**\n * 创建便捷记录器\n *\n * 封装常见审计操作(登录、登出、注册、密码重置、CRUD),\n * 简化调用方代码。每个方法内部调用 logFn 并将 AuditLog 结果映射为 void。\n *\n * @param logFn - 底层日志记录函数(通常为 currentRepo.log)\n * @returns 便捷记录器接口\n * @example 模块内部上下文\n * ```ts\n * function buildHelper(logFn: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>): AuditHelper {\n * return createHelper(logFn)\n * }\n * // logFn 由实际仓储/模块提供;helper 将失败原样传递,不接管数据库生命周期。\n * ```\n */\nexport function createHelper(logFn: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>): AuditHelper {\n return {\n async login(userId: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, category: 'system', action: 'login', resource: 'auth', ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async logout(userId: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, category: 'system', action: 'logout', resource: 'auth', ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async register(userId: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, category: 'system', action: 'register', resource: 'auth', resourceId: userId, ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async passwordResetRequest(email: string, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({\n action: 'password_reset_request',\n category: 'system',\n resource: 'auth',\n details: { email },\n ipAddress: ip,\n userAgent: ua,\n })\n return toVoid(result)\n },\n\n async passwordResetComplete(userId: string | null, ip?: string, ua?: string): Promise<HaiResult<void>> {\n const result = await logFn({ userId, category: 'system', action: 'password_reset', resource: 'auth', ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n\n async crud(\n input: CrudAuditInput,\n ): Promise<HaiResult<void>> {\n const { ip, ua, ...fields } = input\n const result = await logFn({ ...fields, ipAddress: ip, userAgent: ua })\n return toVoid(result)\n },\n }\n}\n","/** 审计结构升级及数据库原生保留保护;旧记录未知字段保持空值。 */\nimport type { HaiResult } from '@h-ai/core'\nimport type { DmlOperations, SchemaMigration } from '@h-ai/reldb'\nimport type { AuditInitConfig } from './audit-config.js'\nimport { err, ok } from '@h-ai/core'\nimport { migrateSchema, reldb, schemaColumns } from '@h-ai/reldb'\nimport { auditM } from './audit-i18n.js'\nimport { HaiAuditError } from './audit-types.js'\n\nconst columns = { category: 'VARCHAR(16)', outcome: 'VARCHAR(16)', severity: 'VARCHAR(16)', request_id: 'TEXT', trace_id: 'TEXT', scope_id: 'TEXT', actor_snapshot: 'JSON' }\nconst triggers = ['hai_audit_protect_update', 'hai_audit_protect_delete', 'hai_audit_protect_insert']\n\nasync function existingTriggers(sql: DmlOperations): Promise<HaiResult<string[]>> {\n const result = reldb.config?.type === 'sqlite'\n ? await sql.query<{ name: string }>('SELECT name FROM sqlite_master WHERE type=\\'trigger\\' AND tbl_name=\\'hai_audit_logs\\'')\n : await sql.query<{ name: string }>(`SELECT trigger_name AS name FROM information_schema.triggers WHERE trigger_schema=${reldb.config?.type === 'mysql' ? 'DATABASE()' : 'current_schema()'} AND event_object_table='hai_audit_logs'`)\n return result.success ? ok(result.data.map(row => row.name)) : result\n}\n\nconst steps: SchemaMigration[] = [{\n version: 1,\n name: 'event-context-and-identity',\n async needed(sql) {\n const found = await schemaColumns(reldb, 'hai_audit_logs', sql)\n return found.success ? ok(found.data.length > 0 && Object.keys(columns).some(name => !found.data.includes(name))) : found\n },\n async apply(sql) {\n const found = await schemaColumns(reldb, 'hai_audit_logs', sql)\n if (!found.success)\n return found\n for (const [name, definition] of Object.entries(columns)) {\n if (found.data.includes(name))\n continue\n const added = await sql.execute(`ALTER TABLE hai_audit_logs ADD COLUMN ${name} ${definition}`)\n if (!added.success)\n return added\n }\n return ok(undefined)\n },\n}, {\n version: 2,\n name: 'persistent-retention-policy',\n async needed(sql) {\n const found = await schemaColumns(reldb, 'hai_audit_policy', sql)\n if (!found.success || found.data.length === 0)\n return found.success ? ok(true) : found\n const row = await sql.get<{ id: number }>('SELECT id FROM hai_audit_policy WHERE id=1')\n return row.success ? ok(!row.data) : row\n },\n async apply(sql) {\n const created = await sql.execute('CREATE TABLE IF NOT EXISTS hai_audit_policy (id INTEGER PRIMARY KEY, enabled INTEGER NOT NULL, min_days INTEGER NOT NULL)')\n if (!created.success)\n return created\n return sql.execute(reldb.config?.type === 'mysql'\n ? 'INSERT IGNORE INTO hai_audit_policy (id, enabled, min_days) VALUES (1, 0, 90)'\n : 'INSERT INTO hai_audit_policy (id, enabled, min_days) VALUES (1, 0, 90) ON CONFLICT(id) DO NOTHING')\n },\n}, {\n version: 3,\n name: 'retention-write-guards',\n async needed(sql) {\n const table = await schemaColumns(reldb, 'hai_audit_logs', sql)\n if (!table.success || !table.data.length)\n return table.success ? ok(false) : table\n const found = await existingTriggers(sql)\n return found.success ? ok(triggers.some(name => !found.data.includes(name))) : found\n },\n async apply(sql) {\n const found = await existingTriggers(sql)\n if (!found.success)\n return found\n const enabled = 'COALESCE((SELECT enabled FROM hai_audit_policy WHERE id=1),1)=1'\n const days = 'COALESCE((SELECT min_days FROM hai_audit_policy WHERE id=1),90)'\n const cutoff = reldb.config?.type === 'sqlite'\n ? `CAST((julianday('now')-2440587.5)*86400000 AS INTEGER) - ${days}*86400000`\n : reldb.config?.type === 'postgresql'\n ? `CURRENT_TIMESTAMP - (${days} * INTERVAL '1 day')`\n : `TIMESTAMPADD(DAY, -${days}, CURRENT_TIMESTAMP(3))`\n const existingProtected = `${enabled} AND EXISTS(SELECT 1 FROM hai_audit_logs a WHERE a.id=NEW.id AND a.created_at >= ${cutoff})`\n if (reldb.config?.type === 'postgresql') {\n const fn = await sql.execute(`CREATE OR REPLACE FUNCTION hai_audit_protect() RETURNS trigger AS $$ BEGIN IF TG_OP='INSERT' THEN IF ${existingProtected} THEN RAISE EXCEPTION 'Audit record is protected by retention policy'; END IF; RETURN NEW; END IF; IF ${enabled} AND OLD.created_at >= ${cutoff} THEN RAISE EXCEPTION 'Audit record is protected by retention policy'; END IF; IF TG_OP='DELETE' THEN RETURN OLD; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql`)\n if (!fn.success)\n return fn\n }\n for (const [index, operation] of ['UPDATE', 'DELETE', 'INSERT'].entries()) {\n const name = triggers[index]!\n if (found.data.includes(name))\n continue\n // INSERT 冲突保护同时覆盖 SQLite 未开启递归删除触发器时的 INSERT OR REPLACE。\n const protectedRow = operation === 'INSERT' ? existingProtected : `${enabled} AND OLD.created_at >= ${cutoff}`\n const statement = reldb.config?.type === 'sqlite'\n ? `CREATE TRIGGER ${name} BEFORE ${operation} ON hai_audit_logs WHEN ${protectedRow} BEGIN SELECT RAISE(ABORT, 'Audit record is protected by retention policy'); END`\n : reldb.config?.type === 'postgresql'\n ? `CREATE TRIGGER ${name} BEFORE ${operation} ON hai_audit_logs FOR EACH ROW EXECUTE FUNCTION hai_audit_protect()`\n : `CREATE TRIGGER ${name} BEFORE ${operation} ON hai_audit_logs FOR EACH ROW BEGIN IF ${protectedRow} THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='Audit record is protected by retention policy'; END IF; END`\n // MySQL 的 CREATE TRIGGER 不支持服务端预处理;仍在迁移锁的同一连接执行固定 DDL。\n const created = reldb.config?.type === 'mysql' ? await sql.query(statement) : await sql.execute(statement)\n if (!created.success)\n return created\n }\n return ok(undefined)\n },\n}, {\n version: 4,\n name: 'millisecond-event-time',\n async needed(sql) {\n if (reldb.config?.type !== 'mysql')\n return ok(false)\n const column = await sql.get<{ fractional_digits: number | null }>('SELECT DATETIME_PRECISION AS fractional_digits FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name=? AND column_name=?', ['hai_audit_logs', 'created_at'])\n return column.success ? ok(Boolean(column.data && Number(column.data.fractional_digits ?? 0) < 3)) : column\n },\n async apply(sql) {\n // 框架旧 MySQL DATETIME(0) 会把 .800 舍入到下一秒;保留既有值并让新事件保留毫秒。\n const changed = await sql.execute('ALTER TABLE hai_audit_logs MODIFY COLUMN created_at DATETIME(3)')\n return changed.success ? ok(undefined) : changed\n },\n}, {\n version: 5,\n name: 'alert-notification-claims',\n async needed(sql) {\n const found = await schemaColumns(reldb, 'hai_audit_alert_claims', sql)\n return found.success ? ok(found.data.length === 0) : found\n },\n async apply(sql) {\n // 领取在外部效果前持久化;崩溃或结果未知时不盲目重发。地址与正文不在此表保存。\n const created = await sql.execute('CREATE TABLE IF NOT EXISTS hai_audit_alert_claims (id VARCHAR(64) PRIMARY KEY, rule_id VARCHAR(64) NOT NULL, target_id VARCHAR(64) NOT NULL, window_start BIGINT NOT NULL, status VARCHAR(16) NOT NULL, queue_id VARCHAR(64), error_code VARCHAR(128))')\n return created.success ? ok(undefined) : created\n },\n}, {\n version: 6,\n name: 'event-time-index',\n async needed(sql) {\n const table = await schemaColumns(reldb, 'hai_audit_logs', sql)\n if (!table.success || !table.data.length)\n return table.success ? ok(false) : table\n const found = reldb.config?.type === 'sqlite'\n ? await sql.get('SELECT name FROM sqlite_master WHERE type=\\'index\\' AND name=\\'hai_audit_event_time_idx\\'')\n : reldb.config?.type === 'postgresql'\n ? await sql.get('SELECT indexname FROM pg_indexes WHERE schemaname=current_schema() AND tablename=\\'hai_audit_logs\\' AND indexname=\\'hai_audit_event_time_idx\\'')\n : await sql.get('SELECT index_name FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name=\\'hai_audit_logs\\' AND index_name=\\'hai_audit_event_time_idx\\' LIMIT 1')\n return found.success ? ok(!found.data) : found\n },\n async apply(sql) {\n const created = await sql.execute('CREATE INDEX hai_audit_event_time_idx ON hai_audit_logs (created_at)')\n return created.success ? ok(undefined) : created\n },\n}]\n\n/**\n * 只读预检或迁移审计字段、保留设置和写入保护;升级前停旧写入并备份。\n * @example\n * ```ts\n * import { migrateAudit } from '@h-ai/audit'\n * const plan = await migrateAudit({ dryRun: true }) // RelDB 已初始化;不改写记录。\n * ```\n */\nexport function migrateAudit(options: { dryRun?: boolean } = {}) {\n return migrateSchema(reldb, 'audit', steps, options)\n}\n\n/**\n * 仅显式配置更新持久策略;未传时保留既有保护,所有节点使用同一策略行。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * // 共享数据库与策略表已由迁移初始化。\n * const configured = await configureAuditRetention({ enabled: true, minDays: 90 })\n * if (!configured.success) configured.error.code\n * ```\n */\nexport async function configureAuditRetention(policy: AuditInitConfig['retention']): Promise<HaiResult<void>> {\n if (!policy)\n return ok(undefined)\n const result = await reldb.sql.execute('UPDATE hai_audit_policy SET enabled=?, min_days=? WHERE id=1', [Number(policy.enabled), policy.minDays])\n return result.success && result.data.changes === 1 ? ok(undefined) : err(HaiAuditError.CONFIG_ERROR, auditM('audit_retentionPolicyFailed'), result.success ? undefined : result.error)\n}\n\n/**\n * 清理入口从共享数据库读取最低天数,不把进程内旧配置当作保护真值。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const retained = await auditRetentionDays()\n * if (retained.success) retained.data\n * ```\n */\nexport async function auditRetentionDays(): Promise<HaiResult<number>> {\n const result = await reldb.sql.get<{ enabled: number, min_days: number }>('SELECT enabled, min_days FROM hai_audit_policy WHERE id=1')\n if (!result.success || !result.data || ![0, 1].includes(Number(result.data.enabled)) || !Number.isInteger(Number(result.data.min_days)) || Number(result.data.min_days) < 1)\n return err(HaiAuditError.CLEANUP_FAILED, auditM('audit_retentionPolicyFailed'))\n return ok(Number(result.data.enabled) === 1 ? Number(result.data.min_days) : 0)\n}\n","/**\n * @h-ai/audit — 审计日志仓库\n *\n * 基于 @h-ai/reldb BaseReldbCrudRepository 实现审计日志的持久化与查询。 仅在需要 JOIN / 聚合时使用自定义 SQL,其余 CRUD 操作由基类处理。\n * @module audit-repository\n */\n\nimport type { HaiResult, PaginatedResult } from '@h-ai/core'\nimport type { DmlWithTxOperations } from '@h-ai/reldb'\nimport type { AuditActorSnapshot, AuditLog, AuditLogWithUser, AuditStatItem, CreateAuditLogInput, ListAuditLogsOptions } from './audit-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { BaseReldbCrudRepository, reldb } from '@h-ai/reldb'\nimport { readAuditTime } from './audit-database-time.js'\nimport { auditM } from './audit-i18n.js'\nimport { readAuditActor } from './audit-log-functions.js'\nimport { auditRetentionDays } from './audit-migration.js'\nimport { HaiAuditError } from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'repository' })\n\n// ─── 仓库配置 ───\n\n/** 审计日志表名(固定值) */\nconst AUDIT_TABLE = 'hai_audit_logs'\n\n/**\n * 原始 SQL 与基类映射的日期、JSON 返回值可能不同,在审计边界统一。\n * @example 模块内部上下文\n * ```ts\n * const row: AuditReadRow = { id: 'audit_example', userId: null, action: 'login', resource: 'auth', resourceId: null, details: { source: 'web' }, ipAddress: null, userAgent: null, createdAt: Date.now() }\n * const record = normalizeAuditLog(row)\n * ```\n */\ntype AuditReadRow = Omit<AuditLog, 'details' | 'createdAt' | 'actorSnapshot'> & {\n details: unknown\n actorSnapshot?: unknown\n createdAt: Date | string | number\n}\n\n/** 保持公开审计契约:Date、JSON 字符串和显式 null。 */\nfunction normalizeAuditLog(row: AuditReadRow): AuditLog {\n return {\n ...row,\n actorSnapshot: readAuditActor(row.actorSnapshot),\n userId: row.userId ?? null,\n resourceId: row.resourceId ?? null,\n details: row.details == null ? null : typeof row.details === 'string' ? row.details : JSON.stringify(row.details) ?? null,\n ipAddress: row.ipAddress ?? null,\n userAgent: row.userAgent ?? null,\n createdAt: row.createdAt instanceof Date ? row.createdAt : new Date(row.createdAt),\n }\n}\n\n/**\n * 审计仓储内部的用户表关联映射;由已校验的初始化配置构造。\n * @example 模块内部上下文\n * ```ts\n * const config: AuditRepositoryConfig = { userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' }\n * const userTable = config.userTable\n * ```\n */\ninterface AuditRepositoryConfig {\n /** 用户表名 */\n userTable: string\n /** 用户表主键列名 */\n userIdColumn: string\n /** 用户表用户名列名 */\n userNameColumn: string\n}\n\n// ─── 仓库 ───\n\n/**\n * 审计日志仓库\n *\n * 通过 BaseReldbCrudRepository 自动建表、字段映射与类型转换,\n * 仅在需要 JOIN / 聚合时使用自定义 SQL。\n *\n * @remarks 此类仅供 audit-main.ts 内部使用,不通过 index.ts 对外导出。\n * @example 模块内部上下文\n * ```ts\n * // 共享 reldb 已初始化,连接生命周期由创建者管理。\n * const repository = new AuditLogRepository({ userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' })\n * const ready = await repository.ready()\n * if (ready.success) {\n * const stats = await repository.getStats(7)\n * if (stats.success) stats.data.map(item => item.count)\n * }\n * ```\n */\nexport class AuditLogRepository extends BaseReldbCrudRepository<AuditLog> {\n private readonly repoConfig: AuditRepositoryConfig\n private readonly isSqlite: boolean\n\n /**\n * @param config - 仓库配置(用户表映射)\n */\n constructor(config: AuditRepositoryConfig) {\n super(reldb, {\n table: AUDIT_TABLE,\n idColumn: 'id',\n generateId: () => core.id.withPrefix('audit_'),\n fields: [\n { fieldName: 'id', columnName: 'id', def: { type: 'TEXT', primaryKey: true }, select: true, create: true, update: false },\n { fieldName: 'userId', columnName: 'user_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'action', columnName: 'action', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: false },\n { fieldName: 'resource', columnName: 'resource', def: { type: 'TEXT', notNull: true }, select: true, create: true, update: false },\n { fieldName: 'resourceId', columnName: 'resource_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'details', columnName: 'details', def: { type: 'JSON' }, select: true, create: true, update: false },\n { fieldName: 'ipAddress', columnName: 'ip_address', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'userAgent', columnName: 'user_agent', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'category', columnName: 'category', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'outcome', columnName: 'outcome', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'severity', columnName: 'severity', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'requestId', columnName: 'request_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'traceId', columnName: 'trace_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'scopeId', columnName: 'scope_id', def: { type: 'TEXT' }, select: true, create: true, update: false },\n { fieldName: 'actorSnapshot', columnName: 'actor_snapshot', def: { type: 'JSON' }, select: true, create: true, update: false },\n { fieldName: 'createdAt', columnName: 'created_at', def: { type: 'TIMESTAMP' }, select: true, create: true, update: false },\n ],\n })\n this.repoConfig = config\n this.isSqlite = this.db.config?.type === 'sqlite'\n }\n\n /**\n * 等待基类完成建表及字段校验;init和自定义SQL共享此屏障,失败不发布仓库。\n * @returns 建表结果,失败由调用方映射到对应审计错误\n * @example const ready = await repository.ready(); if (!ready.success) return ready\n */\n ready(): Promise<HaiResult<void>> {\n return this.ensureReady()\n }\n\n /**\n * 将 Date 转为适合当前数据库类型的 SQL 参数\n *\n * 与基类写入保持一致:SQLite 使用毫秒,其他数据库由驱动转换 Date。\n *\n * @param date - 要转换的日期\n * @returns SQLite 返回毫秒时间戳,其他返回 Date\n */\n private toDateParam(date: Date): number | Date {\n return this.isSqlite ? date.getTime() : date\n }\n\n /** 身份映射可选;名称读失败仍写入明确缺少名称的身份,并留下可观察诊断。 */\n async captureActor(userId: string, tx?: DmlWithTxOperations): Promise<AuditActorSnapshot> {\n const quote = this.db.config?.type === 'mysql' ? '`' : '\"'\n const identifier = (name: string) => `${quote}${name}${quote}`\n const { userTable, userIdColumn, userNameColumn } = this.repoConfig\n const result = await this.sql(tx).get<{ username: string | null }>(`SELECT ${identifier(userNameColumn)} AS username FROM ${identifier(userTable)} WHERE ${identifier(userIdColumn)}=?`, [userId])\n if (!result.success) {\n logger.warn('Audit actor name unavailable', { userId, error: result.error })\n return { id: userId }\n }\n return { id: userId, ...(result.data?.username ? { username: result.data.username } : {}) }\n }\n\n private filters(options: ListAuditLogsOptions): { conditions: string[], params: unknown[] } {\n const conditions: string[] = []\n const params: unknown[] = []\n for (const [field, column] of [['userId', 'user_id'], ['action', 'action'], ['resource', 'resource'], ['category', 'category'], ['outcome', 'outcome'], ['severity', 'severity'], ['scopeId', 'scope_id'], ['requestId', 'request_id'], ['traceId', 'trace_id']] as const) {\n if (options[field] !== undefined) {\n conditions.push(`a.${column} = ?`)\n params.push(options[field])\n }\n }\n if (options.startDate) {\n conditions.push('a.created_at >= ?')\n params.push(this.toDateParam(options.startDate))\n }\n if (options.endDate) {\n conditions.push('a.created_at <= ?')\n params.push(this.toDateParam(options.endDate))\n }\n return { conditions, params }\n }\n\n /**\n * 记录一条审计日志\n *\n * @param input - 日志内容\n * @param input.userId - 操作用户 ID(系统操作可省略)\n * @param input.action - 操作类型(如 login / create)\n * @param input.resource - 资源类型(如 auth / users)\n * @param input.resourceId - 资源 ID(可选)\n * @param input.details - 操作详情对象(可选)\n * @param input.ipAddress - 客户端 IP(可选)\n * @param input.userAgent - 客户端 User-Agent(可选)\n * @returns 成功时返回创建的 AuditLog;失败时返回 LOG_FAILED\n */\n async log(input: CreateAuditLogInput, tx?: DmlWithTxOperations): Promise<HaiResult<AuditLog>> {\n logger.debug('Recording audit log', { action: input.action, resource: input.resource })\n\n const id = core.id.withPrefix('audit_')\n const time = await readAuditTime(this.sql(tx))\n if (!time.success)\n return time\n const now = time.data\n const context = { category: input.category ?? null, outcome: input.outcome ?? null, severity: input.severity ?? null, requestId: input.requestId ?? null, traceId: input.traceId ?? null, scopeId: input.scopeId ?? null, actorSnapshot: input.actorSnapshot ?? null }\n const data: Record<string, unknown> = {\n ...context,\n id,\n userId: input.userId ?? null,\n action: input.action,\n resource: input.resource,\n resourceId: input.resourceId ?? null,\n details: input.details ?? null,\n ipAddress: input.ipAddress ?? null,\n userAgent: input.userAgent ?? null,\n createdAt: now,\n }\n\n try {\n const createResult = await this.create(data, tx)\n if (!createResult.success) {\n logger.error('Failed to record audit log', { action: input.action, error: createResult.error.message })\n return err(\n HaiAuditError.LOG_FAILED,\n auditM('audit_logFailed', { params: { error: createResult.error.message } }),\n createResult.error,\n )\n }\n\n const auditLog: AuditLog = {\n ...context,\n id,\n userId: input.userId ?? null,\n action: input.action,\n resource: input.resource,\n resourceId: input.resourceId ?? null,\n details: input.details ? JSON.stringify(input.details) : null,\n ipAddress: input.ipAddress ?? null,\n userAgent: input.userAgent ?? null,\n createdAt: now,\n }\n\n logger.info('Audit log recorded', { id, action: input.action, resource: input.resource })\n return ok(auditLog)\n }\n catch (error) {\n logger.error('Failed to record audit log', { action: input.action, error })\n return err(\n HaiAuditError.LOG_FAILED,\n auditM('audit_logFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 分页查询日志列表(含用户名 LEFT JOIN)\n *\n * @param options - 过滤条件与分页参数\n * @returns 成功时返回 PaginatedResult(items/total/page/pageSize);失败时返回 QUERY_FAILED\n */\n async listWithUser(options: ListAuditLogsOptions = {}): Promise<HaiResult<PaginatedResult<AuditLogWithUser>>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n logger.debug('Querying audit logs', { userId: options.userId, action: options.action, resource: options.resource })\n\n const { conditions, params } = this.filters(options)\n const { userTable, userIdColumn, userNameColumn } = this.repoConfig\n // 配置标识符已由 init 校验;别名加引号防止 PostgreSQL 折叠大小写。\n const quote = this.db.config?.type === 'mysql' ? '`' : '\"'\n const identifier = (name: string) => `${quote}${name.replaceAll(quote, quote + quote)}${quote}`\n\n const sortColumns = { createdAt: 'created_at', action: 'action', resource: 'resource', category: 'category', outcome: 'outcome', severity: 'severity' }\n const sortBy = options.sortBy ?? 'createdAt'\n const direction = options.sortDirection ?? 'desc'\n if (!Object.hasOwn(sortColumns, sortBy) || !['asc', 'desc'].includes(direction))\n return err(HaiAuditError.QUERY_FAILED, auditM('audit_invalidInput', { params: { field: 'sort', reason: auditM('audit_sortInvalid') } }))\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n\n try {\n const result = await this.sql().queryPage<AuditReadRow & { username: string | null }>({\n sql: `SELECT a.id, a.user_id AS ${identifier('userId')}, a.action, a.resource, a.resource_id AS ${identifier('resourceId')},\n a.details, a.ip_address AS ${identifier('ipAddress')}, a.user_agent AS ${identifier('userAgent')},\n a.created_at AS ${identifier('createdAt')}, a.category, a.outcome, a.severity,\n a.request_id AS ${identifier('requestId')}, a.trace_id AS ${identifier('traceId')}, a.scope_id AS ${identifier('scopeId')}, a.actor_snapshot AS ${identifier('actorSnapshot')}, u.${identifier(userNameColumn)} AS username\n FROM ${AUDIT_TABLE} a\n LEFT JOIN ${identifier(userTable)} u ON a.user_id = u.${identifier(userIdColumn)}\n ${whereClause}\n ORDER BY a.${sortColumns[sortBy]} ${direction.toUpperCase()}, a.id ${direction.toUpperCase()}`,\n params,\n pagination: { page: options.page, pageSize: options.pageSize },\n overrides: { defaultPageSize: 20 },\n })\n\n if (!result.success) {\n logger.error('Failed to query audit logs', { error: result.error.message })\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n return ok({ ...result.data, items: result.data.items.map(row => ({ ...normalizeAuditLog(row), username: readAuditActor(row.actorSnapshot)?.username ?? (row.actorSnapshot == null ? row.username ?? null : null) })) })\n }\n catch (error) {\n logger.error('Failed to query audit logs', { error })\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /** 归档使用主键游标有界扫描,不关联当前用户名称或改写历史身份。 */\n async archivePage(options: { afterId?: string, from?: Date, cutoff: Date, limit: number }): Promise<HaiResult<AuditLog[]>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n const quote = this.db.config?.type === 'mysql' ? '`' : '\"'\n const fields = [\n ['id', 'id'],\n ['user_id', 'userId'],\n ['action', 'action'],\n ['resource', 'resource'],\n ['resource_id', 'resourceId'],\n ['details', 'details'],\n ['ip_address', 'ipAddress'],\n ['user_agent', 'userAgent'],\n ['created_at', 'createdAt'],\n ['category', 'category'],\n ['outcome', 'outcome'],\n ['severity', 'severity'],\n ['request_id', 'requestId'],\n ['trace_id', 'traceId'],\n ['scope_id', 'scopeId'],\n ['actor_snapshot', 'actorSnapshot'],\n ].map(([column, alias]) => `${column} AS ${quote}${alias}${quote}`).join(', ')\n const conditions = ['created_at <= ?']\n const params: unknown[] = [this.toDateParam(options.cutoff)]\n if (options.from) {\n conditions.push('created_at >= ?')\n params.push(this.toDateParam(options.from))\n }\n if (options.afterId) {\n conditions.push('id > ?')\n params.push(options.afterId)\n }\n params.push(options.limit)\n const result = await this.sql().query<AuditReadRow>(`SELECT ${fields} FROM ${AUDIT_TABLE} WHERE ${conditions.join(' AND ')} ORDER BY id ASC LIMIT ?`, params)\n if (!result.success)\n return result\n try {\n return ok(result.data.map(normalizeAuditLog))\n }\n catch (error) {\n return err(HaiAuditError.BACKUP_FAILED, auditM('audit_backupFailed'), error)\n }\n }\n\n /**\n * 获取指定用户的最近活动\n *\n * @param userId - 用户 ID\n * @param limit - 最大返回条数,默认 10\n * @returns 成功时返回 AuditLog 数组(按时间倒序);失败时返回 QUERY_FAILED\n */\n async getUserRecent(userId: string, limit = 10): Promise<HaiResult<AuditLog[]>> {\n logger.debug('Getting user recent activity', { userId, limit })\n\n try {\n const result = await this.findAll({\n where: 'user_id = ?',\n params: [userId],\n orderBy: 'created_at DESC',\n limit,\n })\n\n if (!result.success) {\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n return ok(result.data.map(normalizeAuditLog))\n }\n catch (error) {\n return err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_queryFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 清理指定天数之前的旧日志\n *\n * @param olderThanDays - 保留天数,默认 90;清理此天数之前的日志\n * @returns 成功时返回删除的记录数;失败时返回 CLEANUP_FAILED\n */\n async cleanupOld(olderThanDays = 90): Promise<HaiResult<number>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n const minimum = await auditRetentionDays()\n if (!minimum.success)\n return minimum\n olderThanDays = Math.max(olderThanDays, minimum.data)\n logger.debug('Cleaning up old audit logs', { olderThanDays })\n\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - olderThanDays)\n\n try {\n const result = await this.sql().execute(\n `DELETE FROM ${AUDIT_TABLE} WHERE created_at < ?`,\n [this.toDateParam(cutoff)],\n )\n\n if (!result.success) {\n logger.error('Failed to cleanup audit logs', { error: result.error.message })\n return err(\n HaiAuditError.CLEANUP_FAILED,\n auditM('audit_cleanupFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n const deleted = result.data.changes\n logger.info('Audit logs cleaned up', { olderThanDays, deleted })\n return ok(deleted)\n }\n catch (error) {\n logger.error('Failed to cleanup audit logs', { error })\n return err(\n HaiAuditError.CLEANUP_FAILED,\n auditM('audit_cleanupFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n\n /**\n * 获取指定天数内的操作统计(按 action 分组计数)\n *\n * @param days - 统计天数,默认 7\n * @returns 成功时返回 AuditStatItem 数组(按 count 倒序);失败时返回 STATS_FAILED\n */\n async getStats(days = 7, filters?: Pick<ListAuditLogsOptions, 'category' | 'outcome' | 'severity' | 'scopeId' | 'userId' | 'resource'>): Promise<HaiResult<AuditStatItem[]>> {\n const ready = await this.ready()\n if (!ready.success)\n return ready\n logger.debug('Getting audit statistics', { days })\n\n const cutoff = new Date()\n cutoff.setDate(cutoff.getDate() - days)\n const { conditions, params } = this.filters({ ...filters, startDate: cutoff })\n\n try {\n const result = await this.sql().query<{ action: string, count: number | string | bigint }>(\n `SELECT action, COUNT(*) as count\n FROM ${AUDIT_TABLE} a\n WHERE ${conditions.join(' AND ')}\n GROUP BY action\n ORDER BY count DESC`,\n params,\n )\n\n if (!result.success) {\n logger.error('Failed to query audit statistics', { error: result.error.message })\n return err(\n HaiAuditError.STATS_FAILED,\n auditM('audit_statsFailed', { params: { error: result.error.message } }),\n result.error,\n )\n }\n\n const statistics = result.data.map(item => ({ action: item.action, count: Number(item.count) }))\n if (statistics.some(item => !Number.isSafeInteger(item.count) || item.count < 0))\n return err(HaiAuditError.STATS_FAILED, auditM('audit_invalidStatCount'))\n return ok(statistics)\n }\n catch (error) {\n logger.error('Failed to query audit statistics', { error })\n return err(\n HaiAuditError.STATS_FAILED,\n auditM('audit_statsFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n }\n}\n","/**\n * @h-ai/audit — 审计日志服务主入口\n *\n * 本文件提供统一的 `audit` 对象,聚合所有审计日志操作功能。\n * @module audit-main\n */\n\nimport type { HaiResult, PaginatedResult } from '@h-ai/core'\nimport type { DmlWithTxOperations } from '@h-ai/reldb'\nimport type { AuditInitConfig, AuditInitConfigInput } from './audit-config.js'\nimport type {\n AuditBackupOperations,\n AuditFunctions,\n AuditHelper,\n AuditLog,\n AuditLogWithUser,\n AuditStatItem,\n CreateAuditLogInput,\n ListAuditLogsOptions,\n} from './audit-types.js'\nimport { core, err, ok } from '@h-ai/core'\nimport { validateIdentifiers } from '@h-ai/reldb'\nimport { createAuditAlerts } from './audit-alert-functions.js'\nimport { createAuditBackup } from './audit-backup-functions.js'\nimport { AuditInitConfigSchema } from './audit-config.js'\nimport { withAuditContext } from './audit-context.js'\nimport { createHelper } from './audit-helper.js'\nimport { auditM } from './audit-i18n.js'\nimport { createAuditWriter, validAuditQuery } from './audit-log-functions.js'\n\nimport { configureAuditRetention, migrateAudit } from './audit-migration.js'\nimport { AuditLogRepository } from './audit-repository-log.js'\nimport {\n HaiAuditError,\n} from './audit-types.js'\n\nconst logger = core.logger.child({ module: 'audit', scope: 'main' })\n\n// ─── 输入校验 ───\n\n/**\n * 判断值是否为非空字符串\n *\n * @param value - 待校验值\n */\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\n// ─── 内部状态 ───\n\n/** 当前审计日志仓库实例;init 后赋值,close 后置 null */\nlet currentRepo: AuditLogRepository | null = null\nlet currentWriter: AuditFunctions['log'] | null = null\nlet capturePolicy: AuditInitConfig['capture'] | null = null\nlet currentBackup: ReturnType<typeof createAuditBackup> | null = null\nlet currentAlerts: ReturnType<typeof createAuditAlerts> | null = null\n/** 只追踪当前进程在途操作,安全记录真值仍在共享数据库。 */\nconst inFlightWrites = new Set<Promise<HaiResult<AuditLog>>>()\n\n/** 缓存的便捷记录器实例;init 时创建,close 时置 null */\nlet currentHelper: AuditHelper | null = null\n\n/** 并发初始化防护标志 */\nlet initInProgress = false\n\n/** close使尚未完成DDL的初始化失效,防止迟到发布。 */\nlet lifecycleGeneration = 0\n\n// ─── 未初始化占位 ───\n\n/**\n * 未初始化时的错误工具集\n *\n * 调用 audit.log / audit.list 等方法时,\n * 若模块未初始化则返回 { success: false, error: { code: NOT_INITIALIZED } }\n */\nconst notInitialized = core.module.createNotInitializedKit(\n HaiAuditError.NOT_INITIALIZED,\n () => auditM('audit_notInitialized'),\n)\n\n// ─── 便捷记录器占位 ───\n\n/** 未初始化时的便捷记录器占位 */\nconst notInitializedHelper = notInitialized.proxy<AuditHelper>()\nconst notInitializedBackup = notInitialized.proxy<AuditBackupOperations>()\n\n// ─── 审计服务对象 ───\n\n/**\n * 审计日志服务对象\n *\n * 统一的审计日志访问入口,提供以下功能:\n * - `audit.init()` — 初始化审计模块\n * - `audit.close()` — 关闭模块\n * - `audit.log()` — 记录审计日志\n * - `audit.list()` — 查询审计日志列表\n * - `audit.getUserRecent()` — 获取用户最近活动\n * - `audit.cleanup()` — 清理旧日志\n * - `audit.getStats()` — 获取统计数据\n * - `audit.helper` — 便捷记录器\n * - `audit.isInitialized` — 初始化状态\n * @example\n * ```ts\n * import { audit } from '@h-ai/audit'\n * import { core } from '@h-ai/core'\n * import { reldb, type ReldbConfigInput } from '@h-ai/reldb'\n * async function recordCreation(config: ReldbConfigInput) {\n * const database = await reldb.init(config)\n * if (!database.success) return database\n * try {\n * const initialized = await audit.init()\n * if (!initialized.success) return initialized\n * const logged = await audit.log({ action: 'create', resource: 'orders', resourceId: 'order_1' })\n * if (logged.success) core.logger.info('Audit recorded', { id: logged.data.id })\n * return logged\n * } finally {\n * const auditClosed = await audit.close()\n * if (!auditClosed.success) return auditClosed // 保留依赖连接,修复后重试关闭。\n * const databaseClosed = await reldb.close()\n * if (!databaseClosed.success) return databaseClosed\n * }\n * }\n * ```\n */\nexport const audit: AuditFunctions = {\n withContext: withAuditContext,\n /**\n * 初始化审计模块\n *\n * 会先关闭已有实例(如已初始化),再用新配置重新初始化。\n * 等待 AuditLogRepository / BaseReldbCrudRepository 完成建表后才发布实例。\n * 依赖 @h-ai/reldb 已初始化。\n *\n * @param config - 初始化配置(可选,所有字段均有默认值)\n * @returns 成功时返回 ok(undefined);失败时返回 CONFIG_ERROR\n *\n * @example\n * ```ts\n * const result = await audit.init()\n * if (!result.success) {\n * logger.error('Audit init failed', { error: result.error.message })\n * }\n * ```\n */\n async init(config?: AuditInitConfigInput): Promise<HaiResult<void>> {\n // 并发初始化防护:避免多次 init 同时执行导致资源泄漏\n if (initInProgress) {\n logger.warn('Audit init already in progress, skipping concurrent call')\n return err(\n HaiAuditError.INIT_IN_PROGRESS,\n auditM('audit_initInProgress'),\n )\n }\n initInProgress = true\n const generation = ++lifecycleGeneration\n\n try {\n if (currentRepo) {\n logger.warn('Audit module is already initialized, reinitializing')\n currentRepo = null\n currentWriter = null\n capturePolicy = null\n currentHelper = null\n const closingBackup = currentBackup\n currentBackup = null\n const closingAlerts = currentAlerts\n currentAlerts = null\n await closingAlerts?.close()\n await closingBackup?.close()\n await Promise.allSettled([...inFlightWrites])\n }\n\n logger.info('Initializing audit module')\n\n const parseResult = AuditInitConfigSchema.safeParse(config ?? {})\n if (!parseResult.success) {\n logger.error('Audit config validation failed', { error: parseResult.error.message })\n return err(\n HaiAuditError.CONFIG_ERROR,\n auditM('audit_configError', { params: { error: parseResult.error.message } }),\n parseResult.error,\n )\n }\n const parsed = parseResult.data\n if (parsed.alerts.enabled && (!config?.reach?.isInitialized || parsed.alerts.rules.some(rule => rule.targets.some(target => !config.reach?.config?.providers.some(provider => provider.name === target.provider)))))\n return err(HaiAuditError.CONFIG_ERROR, auditM('audit_alertReachRequired'))\n if (parsed.backup.enabled && !config?.storage?.isInitialized)\n return err(HaiAuditError.CONFIG_ERROR, auditM('audit_backupStorageRequired'))\n if (parsed.backup.enabled && config?.storage?.config?.type === 's3' && config.storage.config.publicUrl)\n return err(HaiAuditError.CONFIG_ERROR, auditM('audit_backupPrivateStorageRequired'))\n\n const identifierResult = validateIdentifiers([parsed.userTable, parsed.userIdColumn, parsed.userNameColumn])\n if (!identifierResult.success) {\n logger.error('Audit config contains invalid identifiers', { error: identifierResult.error.message })\n return err(\n HaiAuditError.CONFIG_ERROR,\n auditM('audit_configError', { params: { error: identifierResult.error.message } }),\n identifierResult.error,\n )\n }\n\n const migrated = await migrateAudit()\n if (!migrated.success)\n return migrated\n const candidate = new AuditLogRepository({\n userTable: parsed.userTable,\n userIdColumn: parsed.userIdColumn,\n userNameColumn: parsed.userNameColumn,\n })\n const ready = await candidate.ready()\n if (!ready.success) {\n return err(HaiAuditError.CONFIG_ERROR, auditM('audit_initFailed', { params: { error: ready.error.message } }), ready.error)\n }\n const protection = await migrateAudit()\n if (!protection.success)\n return protection\n const configured = await configureAuditRetention(parsed.retention)\n if (!configured.success)\n return configured\n if (generation !== lifecycleGeneration)\n return err(HaiAuditError.NOT_INITIALIZED, auditM('audit_notInitialized'))\n // 候选仓库只拥有schema就绪Promise,不拥有共享reldb连接;成功屏障后才发布。\n currentRepo = candidate\n currentWriter = createAuditWriter(candidate, parsed)\n capturePolicy = parsed.capture\n currentHelper = createHelper(input => audit.log(input))\n currentBackup = createAuditBackup({ repository: candidate, config: parsed.backup, storage: config?.storage, capture: (input, options) => audit.capture(input, options) })\n currentAlerts = createAuditAlerts({ config: parsed.alerts, reach: config?.reach, log: currentWriter })\n\n logger.info('Audit module initialized')\n return ok(undefined)\n }\n catch (error) {\n logger.error('Audit module initialization failed', { error })\n return err(\n HaiAuditError.CONFIG_ERROR,\n auditM('audit_initFailed', { params: { error: error instanceof Error ? error.message : String(error) } }),\n error,\n )\n }\n finally {\n initInProgress = false\n }\n },\n\n /** 当前是否已初始化 */\n get isInitialized(): boolean {\n return currentRepo !== null\n },\n\n /**\n * 记录一条审计日志\n *\n * @param input - 日志内容(action 和 resource 为必填)\n * @returns 成功时返回创建的 AuditLog;未初始化时返回 NOT_INITIALIZED\n */\n log(input: CreateAuditLogInput, tx?: DmlWithTxOperations): Promise<HaiResult<AuditLog>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n const operation = currentWriter!(input, tx)\n inFlightWrites.add(operation)\n void operation.then(() => inFlightWrites.delete(operation), () => inFlightWrites.delete(operation))\n return operation\n },\n\n async capture(input, options): Promise<HaiResult<void>> {\n if (!currentRepo)\n return notInitialized.result()\n if (!capturePolicy?.enabled || (options?.read && !capturePolicy.includeReads && (!input.outcome || input.outcome === 'success')))\n return ok(undefined)\n const written = await audit.log(input, options?.tx)\n return written.success ? ok(undefined) : written\n },\n\n /**\n * 分页查询审计日志列表(含用户名 LEFT JOIN)\n *\n * @param options - 过滤条件与分页参数\n * @returns 成功时返回 PaginatedResult(items/total/page/pageSize);未初始化时返回 NOT_INITIALIZED\n */\n list(options?: ListAuditLogsOptions): Promise<HaiResult<PaginatedResult<AuditLogWithUser>>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n if (!validAuditQuery(options))\n return Promise.resolve(err(HaiAuditError.QUERY_FAILED, auditM('audit_invalidInput', { params: { field: 'query', reason: auditM('audit_queryInvalid') } })))\n\n if (options?.startDate && options?.endDate && options.startDate > options.endDate) {\n return Promise.resolve(err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_invalidInput', { params: { field: 'dateRange', reason: 'startDate must be before endDate' } }),\n ))\n }\n\n return currentRepo.listWithUser(options)\n },\n\n /**\n * 获取指定用户的最近活动记录\n *\n * @param userId - 用户 ID\n * @param limit - 最大返回条数,默认 10\n * @returns 成功时返回 AuditLog 数组;未初始化时返回 NOT_INITIALIZED\n */\n getUserRecent(userId: string, limit?: number): Promise<HaiResult<AuditLog[]>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n if (!isNonEmptyString(userId)) {\n return Promise.resolve(err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_invalidInput', { params: { field: 'userId', reason: 'must be non-empty string' } }),\n ))\n }\n\n if (typeof limit === 'number' && (!Number.isInteger(limit) || limit <= 0)) {\n return Promise.resolve(err(\n HaiAuditError.QUERY_FAILED,\n auditM('audit_invalidInput', { params: { field: 'limit', reason: 'must be a positive integer' } }),\n ))\n }\n\n return currentRepo.getUserRecent(userId, limit)\n },\n\n /**\n * 清理指定天数之前的旧日志\n *\n * @param olderThanDays - 保留天数,默认 90\n * @returns 成功时返回删除的记录数;未初始化时返回 NOT_INITIALIZED\n */\n cleanup(olderThanDays?: number): Promise<HaiResult<number>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n\n if (typeof olderThanDays === 'number' && (!Number.isInteger(olderThanDays) || olderThanDays < 0)) {\n return Promise.resolve(err(\n HaiAuditError.CLEANUP_FAILED,\n auditM('audit_invalidInput', { params: { field: 'olderThanDays', reason: 'must be a non-negative integer' } }),\n ))\n }\n\n return currentRepo.cleanupOld(olderThanDays)\n },\n\n /**\n * 获取指定天数内的操作统计(按 action 分组计数)\n *\n * @param days - 统计天数,默认 7\n * @returns 成功时返回 AuditStatItem 数组;未初始化时返回 NOT_INITIALIZED\n */\n getStats(days?: number, filters?: Pick<ListAuditLogsOptions, 'category' | 'outcome' | 'severity' | 'scopeId' | 'userId' | 'resource'>): Promise<HaiResult<AuditStatItem[]>> {\n if (!currentRepo) {\n return Promise.resolve(notInitialized.result())\n }\n if (!validAuditQuery(filters))\n return Promise.resolve(err(HaiAuditError.STATS_FAILED, auditM('audit_invalidInput', { params: { field: 'query', reason: auditM('audit_queryInvalid') } })))\n\n if (typeof days === 'number' && (!Number.isInteger(days) || days < 0)) {\n return Promise.resolve(err(\n HaiAuditError.STATS_FAILED,\n auditM('audit_invalidInput', { params: { field: 'days', reason: 'must be a non-negative integer' } }),\n ))\n }\n\n return currentRepo.getStats(days, filters)\n },\n\n /**\n * 便捷记录器\n *\n * 未初始化时调用任意方法均返回 NOT_INITIALIZED 错误。\n */\n get helper(): AuditHelper {\n if (!currentHelper) {\n return notInitializedHelper\n }\n return currentHelper\n },\n\n get backup(): AuditBackupOperations {\n return currentBackup?.operations ?? notInitializedBackup\n },\n\n checkAlerts(options) {\n return currentAlerts ? currentAlerts.check(options) : Promise.resolve(notInitialized.result())\n },\n\n get schedulerPlan(): AuditFunctions['schedulerPlan'] {\n const backup = currentBackup?.schedule\n const alerts = currentAlerts?.schedule\n if (!backup && !alerts)\n return null\n return {\n tasks: [...(backup?.tasks ?? []), ...(alerts?.tasks ?? [])].map(task => ({ ...task })),\n hooks: { onTaskExecute: async (input) => {\n if (input.context.taskId === 'hai-audit-backup' && backup)\n return backup.hooks.onTaskExecute!(input)\n if (input.context.taskId === 'hai-audit-alerts' && alerts)\n return alerts.hooks.onTaskExecute!(input)\n throw core.error.buildHaiErrorInst(HaiAuditError.CONFIG_ERROR, auditM('audit_unknownTask'))\n } },\n }\n },\n\n /**\n * 关闭审计模块,释放内部状态\n */\n async close(): Promise<HaiResult<void>> {\n lifecycleGeneration++\n logger.info('Closing audit module')\n currentRepo = null\n currentWriter = null\n capturePolicy = null\n currentHelper = null\n const closingBackup = currentBackup\n currentBackup = null\n const closingAlerts = currentAlerts\n currentAlerts = null\n await closingAlerts?.close()\n await closingBackup?.close()\n await Promise.allSettled([...inFlightWrites])\n logger.info('Audit module closed')\n return ok(undefined)\n },\n}\n"]}
|