@h-ai/core 0.1.0-alpha9 → 1.0.0-beta.10
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 +820 -0
- package/README.ja.md +820 -0
- package/README.md +715 -317
- package/dist/browser.d.ts +11 -31
- package/dist/browser.js +114 -26
- package/dist/browser.js.map +1 -1
- package/dist/{chunk-FVCFFZP6.js → chunk-MYNB4HIZ.js} +9786 -3163
- package/dist/chunk-MYNB4HIZ.js.map +1 -0
- package/dist/core-types-DM_AiIaS.d.ts +2885 -0
- package/dist/node.d.ts +13 -70
- package/dist/node.js +750 -88
- package/dist/node.js.map +1 -1
- package/package.json +23 -16
- package/dist/chunk-FVCFFZP6.js.map +0 -1
- package/dist/core-util-module-B-wH5_ZT.d.ts +0 -1626
|
@@ -0,0 +1,2885 @@
|
|
|
1
|
+
import { z, ZodType } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @h-ai/core — 访问条件与请求策略配置;Schema 可在构建工具中使用,不依赖 Node API。
|
|
5
|
+
* @module core-access-config
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 可信代理列表;auto 仅在受管的私有容器入口中使用本容器网段,普通宿主忽略转发头。
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { TrustedProxiesSchema } from '@h-ai/core'
|
|
13
|
+
* const proxies = TrustedProxiesSchema.parse(['192.0.2.10'])
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare const TrustedProxiesSchema: z.ZodUnion<readonly [z.ZodLiteral<"auto">, z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>]>;
|
|
17
|
+
/**
|
|
18
|
+
* 可复用的可信 IP 与时间窗口条件;空列表不限制对应维度。
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { AccessConditionSchema } from '@h-ai/core'
|
|
22
|
+
* const condition = AccessConditionSchema.parse({ allowIps: ['192.0.2.0/24'], timezone: 'Asia/Shanghai' })
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare const AccessConditionSchema: z.ZodObject<{
|
|
26
|
+
allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
27
|
+
denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
28
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
29
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
30
|
+
days: z.ZodArray<z.ZodNumber>;
|
|
31
|
+
start: z.ZodString;
|
|
32
|
+
end: z.ZodString;
|
|
33
|
+
}, z.core.$strict>>>;
|
|
34
|
+
}, z.core.$strict>;
|
|
35
|
+
/**
|
|
36
|
+
* 每次请求的访问策略:全局条件与所有命中规则必须同时满足;未命中规则不受该规则限制。
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { RequestAccessPolicySchema } from '@h-ai/core'
|
|
40
|
+
* const policy = RequestAccessPolicySchema.parse({ rules: [{ id: 'external', paths: ['/api/v1/external/**'], allowIps: ['192.0.2.0/24'] }] })
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare const RequestAccessPolicySchema: z.ZodObject<{
|
|
44
|
+
global: z.ZodOptional<z.ZodObject<{
|
|
45
|
+
allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
46
|
+
denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
47
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
48
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
49
|
+
days: z.ZodArray<z.ZodNumber>;
|
|
50
|
+
start: z.ZodString;
|
|
51
|
+
end: z.ZodString;
|
|
52
|
+
}, z.core.$strict>>>;
|
|
53
|
+
}, z.core.$strict>>;
|
|
54
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
55
|
+
allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
56
|
+
denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
57
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
58
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
59
|
+
days: z.ZodArray<z.ZodNumber>;
|
|
60
|
+
start: z.ZodString;
|
|
61
|
+
end: z.ZodString;
|
|
62
|
+
}, z.core.$strict>>>;
|
|
63
|
+
id: z.ZodString;
|
|
64
|
+
paths: z.ZodArray<z.ZodString>;
|
|
65
|
+
methods: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
66
|
+
GET: "GET";
|
|
67
|
+
HEAD: "HEAD";
|
|
68
|
+
POST: "POST";
|
|
69
|
+
PUT: "PUT";
|
|
70
|
+
PATCH: "PATCH";
|
|
71
|
+
DELETE: "DELETE";
|
|
72
|
+
OPTIONS: "OPTIONS";
|
|
73
|
+
CONNECT: "CONNECT";
|
|
74
|
+
TRACE: "TRACE";
|
|
75
|
+
}>>>;
|
|
76
|
+
encryption: z.ZodOptional<z.ZodEnum<{
|
|
77
|
+
required: "required";
|
|
78
|
+
disabled: "disabled";
|
|
79
|
+
}>>;
|
|
80
|
+
}, z.core.$strict>>>;
|
|
81
|
+
}, z.core.$strict>;
|
|
82
|
+
/**
|
|
83
|
+
* 关闭策略、内联策略或单个独立 YAML 文件;文件与内联规则不能混合。
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { RequestAccessConfigSchema } from '@h-ai/core'
|
|
87
|
+
* const config = RequestAccessConfigSchema.parse({ file: './config/security/request-access.yml' })
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare const RequestAccessConfigSchema: z.ZodUnion<readonly [z.ZodLiteral<false>, z.ZodObject<{
|
|
91
|
+
file: z.ZodString;
|
|
92
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
93
|
+
global: z.ZodOptional<z.ZodObject<{
|
|
94
|
+
allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
95
|
+
denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
96
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
97
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
98
|
+
days: z.ZodArray<z.ZodNumber>;
|
|
99
|
+
start: z.ZodString;
|
|
100
|
+
end: z.ZodString;
|
|
101
|
+
}, z.core.$strict>>>;
|
|
102
|
+
}, z.core.$strict>>;
|
|
103
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
104
|
+
allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
105
|
+
denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
|
|
106
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
107
|
+
windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
108
|
+
days: z.ZodArray<z.ZodNumber>;
|
|
109
|
+
start: z.ZodString;
|
|
110
|
+
end: z.ZodString;
|
|
111
|
+
}, z.core.$strict>>>;
|
|
112
|
+
id: z.ZodString;
|
|
113
|
+
paths: z.ZodArray<z.ZodString>;
|
|
114
|
+
methods: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
115
|
+
GET: "GET";
|
|
116
|
+
HEAD: "HEAD";
|
|
117
|
+
POST: "POST";
|
|
118
|
+
PUT: "PUT";
|
|
119
|
+
PATCH: "PATCH";
|
|
120
|
+
DELETE: "DELETE";
|
|
121
|
+
OPTIONS: "OPTIONS";
|
|
122
|
+
CONNECT: "CONNECT";
|
|
123
|
+
TRACE: "TRACE";
|
|
124
|
+
}>>>;
|
|
125
|
+
encryption: z.ZodOptional<z.ZodEnum<{
|
|
126
|
+
required: "required";
|
|
127
|
+
disabled: "disabled";
|
|
128
|
+
}>>;
|
|
129
|
+
}, z.core.$strict>>>;
|
|
130
|
+
}, z.core.$strict>]>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @h-ai/core — 核心配置 Schema
|
|
134
|
+
*
|
|
135
|
+
* 核心模块的配置 Schema 定义(使用 Zod 校验)
|
|
136
|
+
* @module core-config
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 环境类型 Schema。
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import { EnvSchema } from '@h-ai/core'
|
|
144
|
+
* const config = EnvSchema.parse('production')
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
declare const EnvSchema: z.ZodEnum<{
|
|
148
|
+
development: "development";
|
|
149
|
+
production: "production";
|
|
150
|
+
test: "test";
|
|
151
|
+
staging: "staging";
|
|
152
|
+
}>;
|
|
153
|
+
/**
|
|
154
|
+
* 日志级别 Schema。
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* import { LogLevelSchema } from '@h-ai/core'
|
|
158
|
+
* const config = LogLevelSchema.parse('info')
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
declare const LogLevelSchema: z.ZodEnum<{
|
|
162
|
+
error: "error";
|
|
163
|
+
trace: "trace";
|
|
164
|
+
debug: "debug";
|
|
165
|
+
info: "info";
|
|
166
|
+
warn: "warn";
|
|
167
|
+
fatal: "fatal";
|
|
168
|
+
}>;
|
|
169
|
+
/**
|
|
170
|
+
* 日志格式 Schema。
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* import { LogFormatSchema } from '@h-ai/core'
|
|
174
|
+
* const config = LogFormatSchema.parse('json')
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
declare const LogFormatSchema: z.ZodEnum<{
|
|
178
|
+
json: "json";
|
|
179
|
+
pretty: "pretty";
|
|
180
|
+
}>;
|
|
181
|
+
/**
|
|
182
|
+
* 日志配置 Schema。
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* import { LoggingConfigSchema } from '@h-ai/core'
|
|
186
|
+
* const config = LoggingConfigSchema.parse({ level: 'warn', format: 'json', redact: ['password'] })
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
declare const LoggingConfigSchema: z.ZodObject<{
|
|
190
|
+
level: z.ZodDefault<z.ZodEnum<{
|
|
191
|
+
error: "error";
|
|
192
|
+
trace: "trace";
|
|
193
|
+
debug: "debug";
|
|
194
|
+
info: "info";
|
|
195
|
+
warn: "warn";
|
|
196
|
+
fatal: "fatal";
|
|
197
|
+
}>>;
|
|
198
|
+
format: z.ZodDefault<z.ZodEnum<{
|
|
199
|
+
json: "json";
|
|
200
|
+
pretty: "pretty";
|
|
201
|
+
}>>;
|
|
202
|
+
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
203
|
+
redact: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
204
|
+
}, z.core.$strip>;
|
|
205
|
+
/**
|
|
206
|
+
* Core 配置 Schema。
|
|
207
|
+
*
|
|
208
|
+
* 描述应用的基础元数据和日志配置,通常通过 `_core.yml` 加载。
|
|
209
|
+
* 未声明的字段拒绝加载;业务配置放独立 app.yml 并使用应用 Schema 校验。
|
|
210
|
+
* ID 长度/前缀由每次 core.id 调用参数决定,不存在全局 ID 配置。
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* import { CoreConfigSchema } from '@h-ai/core'
|
|
214
|
+
* const config = CoreConfigSchema.parse({ name: 'orders', env: 'production', logging: { level: 'info' } })
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
declare const CoreConfigSchema: z.ZodObject<{
|
|
218
|
+
name: z.ZodDefault<z.ZodString>;
|
|
219
|
+
version: z.ZodDefault<z.ZodString>;
|
|
220
|
+
env: z.ZodDefault<z.ZodEnum<{
|
|
221
|
+
development: "development";
|
|
222
|
+
production: "production";
|
|
223
|
+
test: "test";
|
|
224
|
+
staging: "staging";
|
|
225
|
+
}>>;
|
|
226
|
+
logging: z.ZodOptional<z.ZodObject<{
|
|
227
|
+
level: z.ZodDefault<z.ZodEnum<{
|
|
228
|
+
error: "error";
|
|
229
|
+
trace: "trace";
|
|
230
|
+
debug: "debug";
|
|
231
|
+
info: "info";
|
|
232
|
+
warn: "warn";
|
|
233
|
+
fatal: "fatal";
|
|
234
|
+
}>>;
|
|
235
|
+
format: z.ZodDefault<z.ZodEnum<{
|
|
236
|
+
json: "json";
|
|
237
|
+
pretty: "pretty";
|
|
238
|
+
}>>;
|
|
239
|
+
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
240
|
+
redact: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
241
|
+
}, z.core.$strip>>;
|
|
242
|
+
defaultLocale: z.ZodDefault<z.ZodString>;
|
|
243
|
+
}, z.core.$strict>;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 校验消息 key 集合(locale 无关的标识符)。
|
|
247
|
+
*
|
|
248
|
+
* 调用方负责把每个 key 映射到自己模块的 i18n 字典(例如 kit 的
|
|
249
|
+
* `kit_validationStringMin`、serv 的 `serv_validationStringMin`)。
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```ts
|
|
253
|
+
* const key: ZodValidationMessageKey = 'validationRequired'
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
/**
|
|
257
|
+
* 创建按固定前缀派生消息 key 的 `ZodMessageGetter`。
|
|
258
|
+
*
|
|
259
|
+
* 适用于模块消息键遵循 `{prefix}_{ZodValidationMessageKey}` 命名约定的场景,
|
|
260
|
+
* 例如 `serv_validationRequired`、`kit_validationEmail`。
|
|
261
|
+
*
|
|
262
|
+
* @param prefix - 模块消息前缀,如 `serv`、`kit`
|
|
263
|
+
* @param getMessage - 实际消息获取函数,接收带前缀的消息 key
|
|
264
|
+
* @returns 可注入给 `core.zodValidation.*` 的 `ZodMessageGetter`
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* const getMessage = createPrefixedZodMessageGetter<string>(
|
|
269
|
+
* 'serv',
|
|
270
|
+
* (messageKey, params) => `${messageKey}:${params?.min ?? ''}`,
|
|
271
|
+
* )
|
|
272
|
+
*
|
|
273
|
+
* getMessage('validationStringMin', { min: 3 })
|
|
274
|
+
* // 'serv_validationStringMin:3'
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
declare function createPrefixedZodMessageGetter<TMessageKey extends string>(prefix: string, getMessage: (messageKey: TMessageKey, params?: Record<string, string | number>) => string): ZodMessageGetter;
|
|
278
|
+
/**
|
|
279
|
+
* 一步把 Zod SafeParseError / ZodError 转为扁平 `ValidationFormError[]`。
|
|
280
|
+
*
|
|
281
|
+
* @param error - Zod `SafeParseError`、`ZodError` 或兼容的错误对象
|
|
282
|
+
* @param getMessage - 调用方注入的消息获取器
|
|
283
|
+
* @returns 扁平化后的表单错误列表
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* ```ts
|
|
287
|
+
* const errors = mapZodErrorToFormErrors(
|
|
288
|
+
* {
|
|
289
|
+
* issues: [
|
|
290
|
+
* { path: ['email'], code: 'invalid_format', format: 'email', message: 'Invalid email address' },
|
|
291
|
+
* ],
|
|
292
|
+
* },
|
|
293
|
+
* key => key === 'validationEmail' ? '请输入合法邮箱地址' : '输入不合法',
|
|
294
|
+
* )
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
declare function mapZodErrorToFormErrors(error: unknown, getMessage: ZodMessageGetter): ValidationFormError[];
|
|
298
|
+
/**
|
|
299
|
+
* Zod 校验 i18n 工具集合(通过 `core.zodValidation` 暴露)。
|
|
300
|
+
*
|
|
301
|
+
* 按最小知识原则,仅暴露调用方真正需要的两个入口:
|
|
302
|
+
* 1. `createPrefixedZodMessageGetter()`:把模块前缀与消息获取器适配起来
|
|
303
|
+
* 2. `mapZodErrorToFormErrors()`:一步完成 ZodError → 本地化扁平错误列表
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* import { core } from '@h-ai/core'
|
|
307
|
+
* const tools = core.zodValidation
|
|
308
|
+
* tools.mapZodErrorToFormErrors({ issues: [{ path: ['name'], code: 'invalid_type', expected: 'string', message: 'Invalid input' }] }, key => key)
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
declare const zodValidation: {
|
|
312
|
+
createPrefixedZodMessageGetter: typeof createPrefixedZodMessageGetter;
|
|
313
|
+
mapZodErrorToFormErrors: typeof mapZodErrorToFormErrors;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @h-ai/core — 配置管理(浏览器占位实现)
|
|
318
|
+
*
|
|
319
|
+
* 浏览器环境没有文件系统,不能加载 / 监听 YAML 配置文件。
|
|
320
|
+
* 该实现保持 `core.config` API 形态与 Node.js 一致,但所有文件相关操作
|
|
321
|
+
* 都返回明确的 SERVICE_UNAVAILABLE,避免运行时出现 `core.config` 为 undefined。
|
|
322
|
+
* @module core-function-config.browser
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* 浏览器端 config 占位对象,API 与 Node.js config 保持一致。
|
|
327
|
+
* @example 模块内部上下文
|
|
328
|
+
* ```ts
|
|
329
|
+
* const result = config.load('app', '/srv/app/config/app.yml')
|
|
330
|
+
* if (!result.success) result.error.message
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
declare const config$1: {
|
|
334
|
+
loadEnvFiles(_options: {
|
|
335
|
+
mode: string;
|
|
336
|
+
envDir?: string;
|
|
337
|
+
}): HaiResult<Record<string, string>>;
|
|
338
|
+
load<T>(_name: string, _filePath: string, _schema?: ZodType<T>): HaiResult<T>;
|
|
339
|
+
validate<T>(_name: string, _schema: ZodType<T>): HaiResult<T>;
|
|
340
|
+
get<T>(_name: string): T | undefined;
|
|
341
|
+
getOrThrow<T>(_name: string): T;
|
|
342
|
+
reload(_name: string): HaiResult<unknown>;
|
|
343
|
+
has(_name: string): boolean;
|
|
344
|
+
clear(_name?: string): void;
|
|
345
|
+
keys(): string[];
|
|
346
|
+
watch<T = unknown>(_name: string, callback: WatchCallback<T>): () => void;
|
|
347
|
+
unwatch(_name?: string): void;
|
|
348
|
+
isWatching(_name: string): boolean;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
/** 通用环境配置:来源合并、结构覆盖与无损 dotenv 编解码,不依赖业务模块。 */
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 单个环境来源中的字面变量,undefined 表示未设置。
|
|
355
|
+
* @example 模块内部上下文
|
|
356
|
+
* ```ts
|
|
357
|
+
* const values: Environment = { HAI_APP_NAME: 'Example' }
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
type Environment = Record<string, string | undefined>;
|
|
361
|
+
/**
|
|
362
|
+
* 从低到高合并来源;高来源父项删除旧细项,同来源始终先父后子。
|
|
363
|
+
* @example 模块内部上下文
|
|
364
|
+
* ```ts
|
|
365
|
+
* const values = mergeEnv([{ HAI_APP_NAME: 'base' }, { HAI_APP_NAME: 'test' }])
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
declare function mergeEnv(layers: readonly Environment[]): Record<string, string>;
|
|
369
|
+
/**
|
|
370
|
+
* dotenv 使用 Node 字面规则;补齐生成器双引号的 JSON 转义,拒绝同文件重复键。
|
|
371
|
+
* @example 模块内部上下文
|
|
372
|
+
* ```ts
|
|
373
|
+
* const values = parseEnvironment('HAI_APP_NAME=Example\n')
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
declare function parseEnvironment(text: string): Record<string, string>;
|
|
377
|
+
/**
|
|
378
|
+
* 所有值均按字面量编码;排序让模块 JSON 位于其细项之前。
|
|
379
|
+
* @example 模块内部上下文
|
|
380
|
+
* ```ts
|
|
381
|
+
* const text = stringifyEnv({ HAI_APP_NAME: 'Example' })
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
declare function stringifyEnv(values: Record<string, string>, options?: {
|
|
385
|
+
target?: 'node' | 'compose';
|
|
386
|
+
}): string;
|
|
387
|
+
/**
|
|
388
|
+
* 在给定结构上解析环境变量;父对象提供基础值,具体路径继续覆盖。
|
|
389
|
+
* @example 模块内部上下文
|
|
390
|
+
* ```ts
|
|
391
|
+
* const result = resolveEnvironment({ name: 'app', value: { name: 'Example' }, environment: { HAI_APP_NAME: 'Test' } })
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
declare function resolveEnvironment(options: {
|
|
395
|
+
name: string;
|
|
396
|
+
value: unknown;
|
|
397
|
+
environment?: Environment;
|
|
398
|
+
schema?: ZodType;
|
|
399
|
+
shape?: Readonly<Record<string, unknown>>;
|
|
400
|
+
missing?: 'error' | 'empty';
|
|
401
|
+
}, literal?: boolean): HaiResult<unknown>;
|
|
402
|
+
/**
|
|
403
|
+
* 默认展开对象,数组与动态键字典保留 JSON;不做模块名称判断。
|
|
404
|
+
* @example 模块内部上下文
|
|
405
|
+
* ```ts
|
|
406
|
+
* const values = toEnv({ prefix: 'HAI_APP', value: { name: 'Example', tags: ['demo'] } })
|
|
407
|
+
* ```
|
|
408
|
+
*/
|
|
409
|
+
declare function toEnv(options: {
|
|
410
|
+
prefix: string;
|
|
411
|
+
value: unknown;
|
|
412
|
+
schema?: ZodType;
|
|
413
|
+
shape?: Readonly<Record<string, unknown>>;
|
|
414
|
+
}): Record<string, string>;
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* 配置管理对象。
|
|
418
|
+
* @example 模块内部上下文
|
|
419
|
+
* ```ts
|
|
420
|
+
* const result = config.load('app', '/srv/app/config/app.yml')
|
|
421
|
+
* if (!result.success) result.error.message
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
declare const config: {
|
|
425
|
+
/**
|
|
426
|
+
* 合并从低到高的环境来源;高来源父项替换旧节点,同来源细项覆盖父 JSON。
|
|
427
|
+
* @param layers - 按优先级排列的字面变量。
|
|
428
|
+
* @returns 合并后的变量,可能含秘密。
|
|
429
|
+
* @example
|
|
430
|
+
* ```ts
|
|
431
|
+
* import { core } from '@h-ai/core'
|
|
432
|
+
* const value = core.config.mergeEnv([{ HAI_APP_NAME: 'base' }, { HAI_APP_NAME: 'test' }])
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
mergeEnv: typeof mergeEnv;
|
|
436
|
+
/**
|
|
437
|
+
* 解析 dotenv 字面文本,拒绝重复键,不执行 shell 或变量展开。
|
|
438
|
+
* @param text - dotenv 文本,可能包含秘密。
|
|
439
|
+
* @returns 字面变量;重复键抛出不含变量值的错误。
|
|
440
|
+
* @example
|
|
441
|
+
* ```ts
|
|
442
|
+
* import { core } from '@h-ai/core'
|
|
443
|
+
* const value = core.config.parseEnv('HAI_APP_NAME=Example\n')
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
parseEnv: typeof parseEnvironment;
|
|
447
|
+
/**
|
|
448
|
+
* 无损编码 dotenv,父变量排在细项前;含秘密时只能写入受保护文件。
|
|
449
|
+
* @param values - 字面变量,不进行脱敏。
|
|
450
|
+
* @param options - 输出语法目标,默认 Node dotenv。
|
|
451
|
+
* @param options.target - Compose 目标同时处理其美元符号插值规则。
|
|
452
|
+
* @returns dotenv 文本;非法变量名抛错。
|
|
453
|
+
* @example
|
|
454
|
+
* ```ts
|
|
455
|
+
* import { core } from '@h-ai/core'
|
|
456
|
+
* const value = core.config.stringifyEnv({ HAI_APP_NAME: 'Example' })
|
|
457
|
+
* ```
|
|
458
|
+
*/
|
|
459
|
+
stringifyEnv: typeof stringifyEnv;
|
|
460
|
+
/**
|
|
461
|
+
* 按已有结构或 Schema 解析父 JSON 和细项,不修改缓存或进程环境。
|
|
462
|
+
* @param options - 配置名、原始结构、变量、可选 Schema 和缺失插值规则。
|
|
463
|
+
* @returns 解析结果;调用方仍须执行最终 Schema 校验。
|
|
464
|
+
* @example
|
|
465
|
+
* ```ts
|
|
466
|
+
* import { core } from '@h-ai/core'
|
|
467
|
+
* const value = core.config.resolve({ name: 'app', value: { name: 'Example' }, environment: { HAI_APP_NAME: 'Test' } })
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
resolve: (options: Parameters<typeof resolveEnvironment>[0]) => HaiResult<unknown>;
|
|
471
|
+
/**
|
|
472
|
+
* 默认将对象展开为细项;数组、动态字典和空对象保留 JSON。
|
|
473
|
+
* @param options - 完整变量前缀、配置值和可选 Schema。
|
|
474
|
+
* @returns 字面环境变量,不脱敏;非法名称抛错。
|
|
475
|
+
* @example
|
|
476
|
+
* ```ts
|
|
477
|
+
* import { core } from '@h-ai/core'
|
|
478
|
+
* const value = core.config.toEnv({ prefix: 'HAI_APP', value: { name: 'Example', tags: ['demo'] } })
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
toEnv: typeof toEnv;
|
|
482
|
+
/**
|
|
483
|
+
* 读取 dotenv 文件并按统一顺序合并,不修改进程环境。
|
|
484
|
+
*
|
|
485
|
+
* 优先级:已有进程环境 > .env.<mode>.local > .env.local > .env.<mode> > .env。
|
|
486
|
+
* development/production 分别映射到 dev/prod;不存在的文件跳过。
|
|
487
|
+
* 返回值可能包含私有配置,仅在 Node 启动/构建边界注入,不下发浏览器。
|
|
488
|
+
* @param options - 文件所在目录及环境模式
|
|
489
|
+
* @param options.mode - dev/test/prod 或 Vite 的 development/production
|
|
490
|
+
* @param options.envDir - dotenv 所在目录,默认进程工作目录
|
|
491
|
+
* @returns 已合并的变量;非法模式或读取失败返回配置错误,不包含文件内容
|
|
492
|
+
* @example
|
|
493
|
+
* ```ts
|
|
494
|
+
* const env = core.config.loadEnvFiles({ mode: 'dev', envDir: '.' })
|
|
495
|
+
* if (!env.success) throw new Error(env.error.message)
|
|
496
|
+
* Object.assign(process.env, env.data)
|
|
497
|
+
* core.init({ configDir: './config' })
|
|
498
|
+
* ```
|
|
499
|
+
*/
|
|
500
|
+
loadEnvFiles(options: {
|
|
501
|
+
mode: string;
|
|
502
|
+
envDir?: string;
|
|
503
|
+
}): HaiResult<Record<string, string>>;
|
|
504
|
+
/**
|
|
505
|
+
* 加载配置到缓存。
|
|
506
|
+
*
|
|
507
|
+
* 加载 YAML 文件并可选地用 Zod Schema 校验,成功后写入缓存。
|
|
508
|
+
*
|
|
509
|
+
* @param name - 配置名称(缓存 key)
|
|
510
|
+
* @param filePath - YAML 文件路径
|
|
511
|
+
* @param schema - 可选 Zod Schema(不传则跳过校验)
|
|
512
|
+
* @returns 成功时返回解析后的配置数据;失败时返回 HaiError
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```ts
|
|
516
|
+
* const result = config.load('core', './config/_core.yml', CoreConfigSchema)
|
|
517
|
+
* if (result.success) {
|
|
518
|
+
* // result.data 为校验后的配置
|
|
519
|
+
* }
|
|
520
|
+
* ```
|
|
521
|
+
*/
|
|
522
|
+
load<T>(name: string, filePath: string, schema?: ZodType<T>): HaiResult<T>;
|
|
523
|
+
/**
|
|
524
|
+
* 验证已加载的配置数据。
|
|
525
|
+
*
|
|
526
|
+
* 对缓存中的配置数据重新用 Schema 校验,校验通过后更新缓存。
|
|
527
|
+
*
|
|
528
|
+
* @param name - 配置名称
|
|
529
|
+
* @param schema - Zod 验证模式
|
|
530
|
+
* @returns 校验结果;未加载时返回 NOT_LOADED,格式错误返回 VALIDATION_ERROR
|
|
531
|
+
*
|
|
532
|
+
* @example
|
|
533
|
+
* ```ts
|
|
534
|
+
* const result = config.validate('app', AppSchema)
|
|
535
|
+
* if (!result.success) {
|
|
536
|
+
* // result.error.code 可能为 NOT_LOADED 或 VALIDATION_ERROR
|
|
537
|
+
* }
|
|
538
|
+
* ```
|
|
539
|
+
*/
|
|
540
|
+
validate<T>(name: string, schema: ZodType<T>): HaiResult<T>;
|
|
541
|
+
/**
|
|
542
|
+
* 获取已加载的配置。
|
|
543
|
+
*
|
|
544
|
+
* @param name - 配置名称
|
|
545
|
+
* @returns 配置数据;未加载时返回 undefined
|
|
546
|
+
*
|
|
547
|
+
* @example
|
|
548
|
+
* ```ts
|
|
549
|
+
* const cfg = config.get<CoreConfig>('core')
|
|
550
|
+
* if (cfg) {
|
|
551
|
+
* // 使用 cfg
|
|
552
|
+
* }
|
|
553
|
+
* ```
|
|
554
|
+
*/
|
|
555
|
+
get<T>(name: string): T | undefined;
|
|
556
|
+
/**
|
|
557
|
+
* 获取配置,不存在时抛出错误。
|
|
558
|
+
*
|
|
559
|
+
* @param name - 配置名称
|
|
560
|
+
* @returns 配置数据
|
|
561
|
+
* @throws 配置未加载时抛出 Error
|
|
562
|
+
*
|
|
563
|
+
* @example
|
|
564
|
+
* ```ts
|
|
565
|
+
* try {
|
|
566
|
+
* const cfg = config.getOrThrow<CoreConfig>('core')
|
|
567
|
+
* } catch (e) {
|
|
568
|
+
* // 配置未加载
|
|
569
|
+
* }
|
|
570
|
+
* ```
|
|
571
|
+
*/
|
|
572
|
+
getOrThrow<T>(name: string): T;
|
|
573
|
+
/**
|
|
574
|
+
* 重新加载配置。
|
|
575
|
+
*
|
|
576
|
+
* 从磁盘重新读取配置文件并更新缓存,同时通知所有 watch 回调。
|
|
577
|
+
*
|
|
578
|
+
* @param name - 配置名称
|
|
579
|
+
* @returns 重载结果;未加载时返回 NOT_LOADED
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```ts
|
|
583
|
+
* const result = config.reload('app')
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
reload(name: string): HaiResult<unknown>;
|
|
587
|
+
/**
|
|
588
|
+
* 检查配置是否已加载。
|
|
589
|
+
*
|
|
590
|
+
* @param name - 配置名称
|
|
591
|
+
* @returns 是否已加载到缓存
|
|
592
|
+
*
|
|
593
|
+
* @example
|
|
594
|
+
* ```ts
|
|
595
|
+
* if (config.has('db')) {
|
|
596
|
+
* const dbCfg = config.get('db')
|
|
597
|
+
* }
|
|
598
|
+
* ```
|
|
599
|
+
*/
|
|
600
|
+
has(name: string): boolean;
|
|
601
|
+
/**
|
|
602
|
+
* 清除配置缓存(同时停止对应监听)。
|
|
603
|
+
*
|
|
604
|
+
* @param name - 配置名称;不传则清除全部
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* ```ts
|
|
608
|
+
* config.clear('app') // 清除单个
|
|
609
|
+
* config.clear() // 清除全部
|
|
610
|
+
* ```
|
|
611
|
+
*/
|
|
612
|
+
clear(name?: string): void;
|
|
613
|
+
/**
|
|
614
|
+
* 获取所有已加载的配置名称。
|
|
615
|
+
*
|
|
616
|
+
* @returns 配置名称数组
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* ```ts
|
|
620
|
+
* const names = config.keys() // ['core', 'db', 'app']
|
|
621
|
+
* ```
|
|
622
|
+
*/
|
|
623
|
+
keys(): string[];
|
|
624
|
+
/**
|
|
625
|
+
* 监听配置文件变更并自动重载。
|
|
626
|
+
*
|
|
627
|
+
* 普通写入、原子替换及删除重建均触发重载;失败保留最近成功的缓存并通知错误。
|
|
628
|
+
* 配置未加载时立即回调 NOT_LOADED 错误。
|
|
629
|
+
*
|
|
630
|
+
* @param name - 配置名称
|
|
631
|
+
* @param callback - 配置变更回调,接收新配置或错误
|
|
632
|
+
* @returns 取消监听函数
|
|
633
|
+
*
|
|
634
|
+
* @example
|
|
635
|
+
* ```ts
|
|
636
|
+
* const unwatch = config.watch('app', (cfg, error) => {
|
|
637
|
+
* if (error) { core.logger.error('reload failed', { error }); return }
|
|
638
|
+
* core.logger.info('config updated', { cfg })
|
|
639
|
+
* })
|
|
640
|
+
* // 取消监听
|
|
641
|
+
* unwatch()
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
watch<T = unknown>(name: string, callback: WatchCallback<T>): () => void;
|
|
645
|
+
/**
|
|
646
|
+
* 停止配置文件监听。
|
|
647
|
+
*
|
|
648
|
+
* @param name - 配置名称;不传则停止所有监听
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* config.unwatch('app') // 停止单个
|
|
653
|
+
* config.unwatch() // 停止全部
|
|
654
|
+
* ```
|
|
655
|
+
*/
|
|
656
|
+
unwatch(name?: string): void;
|
|
657
|
+
/**
|
|
658
|
+
* 检查是否正在监听某个配置。
|
|
659
|
+
*
|
|
660
|
+
* @param name - 配置名称
|
|
661
|
+
* @returns 是否有活跃的 watcher
|
|
662
|
+
*
|
|
663
|
+
* @example
|
|
664
|
+
* ```ts
|
|
665
|
+
* if (config.isWatching('app')) {
|
|
666
|
+
* config.unwatch('app')
|
|
667
|
+
* }
|
|
668
|
+
* ```
|
|
669
|
+
*/
|
|
670
|
+
isWatching(name: string): boolean;
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* @h-ai/core — ID 生成器
|
|
675
|
+
*
|
|
676
|
+
* 基于 nanoid 的 ID 生成工具。
|
|
677
|
+
* @module core-function-id
|
|
678
|
+
*/
|
|
679
|
+
/**
|
|
680
|
+
* ID 生成工具对象。
|
|
681
|
+
* @example
|
|
682
|
+
* ```ts
|
|
683
|
+
* import { core } from '@h-ai/core'
|
|
684
|
+
* const tools = core.id
|
|
685
|
+
* tools.withPrefix('order_')
|
|
686
|
+
* ```
|
|
687
|
+
*/
|
|
688
|
+
declare const id: {
|
|
689
|
+
/**
|
|
690
|
+
* 生成标准 nanoid(默认 21 字符)。
|
|
691
|
+
*
|
|
692
|
+
* @param length - ID 长度
|
|
693
|
+
* @returns nanoid 字符串
|
|
694
|
+
*
|
|
695
|
+
* @example
|
|
696
|
+
* ```ts
|
|
697
|
+
* const id = core.id.generate(16)
|
|
698
|
+
* ```
|
|
699
|
+
*/
|
|
700
|
+
generate(length?: number): string;
|
|
701
|
+
/**
|
|
702
|
+
* 生成短 ID(10 字符)。
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```ts
|
|
706
|
+
* const shortId = core.id.short()
|
|
707
|
+
* ```
|
|
708
|
+
*/
|
|
709
|
+
short(): string;
|
|
710
|
+
/**
|
|
711
|
+
* 生成带前缀的 ID。
|
|
712
|
+
*
|
|
713
|
+
* @param prefix - 前缀
|
|
714
|
+
* @param length - ID 长度
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* ```ts
|
|
718
|
+
* const userId = core.id.withPrefix('user_')
|
|
719
|
+
* ```
|
|
720
|
+
*/
|
|
721
|
+
withPrefix(prefix: string, length?: number): string;
|
|
722
|
+
/**
|
|
723
|
+
* 生成 Trace ID。
|
|
724
|
+
*
|
|
725
|
+
* @example
|
|
726
|
+
* ```ts
|
|
727
|
+
* const traceId = core.id.trace()
|
|
728
|
+
* ```
|
|
729
|
+
*/
|
|
730
|
+
trace(): string;
|
|
731
|
+
/**
|
|
732
|
+
* 生成 Request ID。
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* ```ts
|
|
736
|
+
* const requestId = core.id.request()
|
|
737
|
+
* ```
|
|
738
|
+
*/
|
|
739
|
+
request(): string;
|
|
740
|
+
/**
|
|
741
|
+
* 生成 UUID v4。
|
|
742
|
+
*
|
|
743
|
+
* @example
|
|
744
|
+
* ```ts
|
|
745
|
+
* const uuid = core.id.uuid()
|
|
746
|
+
* ```
|
|
747
|
+
*/
|
|
748
|
+
uuid(): string;
|
|
749
|
+
/**
|
|
750
|
+
* 验证是否为有效的 UUID v4。
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```ts
|
|
754
|
+
* core.id.isValidUUID('f47ac10b-58cc-4372-a567-0e02b2c3d479')
|
|
755
|
+
* ```
|
|
756
|
+
*/
|
|
757
|
+
isValidUUID(uuid: string): boolean;
|
|
758
|
+
/**
|
|
759
|
+
* 验证是否为有效的 nanoid。
|
|
760
|
+
*
|
|
761
|
+
* @param str - 待验证字符串
|
|
762
|
+
* @param length - 期望长度
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* ```ts
|
|
766
|
+
* core.id.isValidNanoId('abc', 3)
|
|
767
|
+
* ```
|
|
768
|
+
*/
|
|
769
|
+
isValidNanoId(str: string, length?: number): boolean;
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* @h-ai/core — i18n 国际化工具
|
|
774
|
+
*
|
|
775
|
+
* 国际化核心实现,为 JSON 消息字典提供通用类型支持。
|
|
776
|
+
* @module core-i18n-utils
|
|
777
|
+
*/
|
|
778
|
+
|
|
779
|
+
declare function getGlobalLocale(): Locale;
|
|
780
|
+
declare function setGlobalLocale(locale: Locale): void;
|
|
781
|
+
/**
|
|
782
|
+
* 在独立的 Node 请求语言上下文中运行操作,异步子任务继承当前语言。
|
|
783
|
+
*
|
|
784
|
+
* 显式 MessageOptions.locale 优先于请求语言,请求结束不会改变进程启动默认值。
|
|
785
|
+
*
|
|
786
|
+
* @param locale - 当前请求的语言
|
|
787
|
+
* @param operation - 请求处理或 SSR 操作;保留原同步值或 Promise 返回类型
|
|
788
|
+
* @returns operation 的原始返回值
|
|
789
|
+
* @throws 浏览器入口没有 Node 请求上下文时抛出错误;浏览器使用 setGlobalLocale。
|
|
790
|
+
* @example
|
|
791
|
+
* ```ts
|
|
792
|
+
* const response = await core.i18n.runWithLocale('en-US', async () => {
|
|
793
|
+
* await loadData()
|
|
794
|
+
* return renderPage()
|
|
795
|
+
* })
|
|
796
|
+
* ```
|
|
797
|
+
*/
|
|
798
|
+
declare function runWithLocale<T>(locale: Locale, operation: () => T): T;
|
|
799
|
+
/**
|
|
800
|
+
* 创建消息获取函数。
|
|
801
|
+
*
|
|
802
|
+
* 各模块通过此函数创建消息获取器,依次读取显式 locale、Node 请求语言和应用默认语言。
|
|
803
|
+
* 若指定的 locale 不支持,回退到默认语言;key 不存在时返回 key 本身。
|
|
804
|
+
*
|
|
805
|
+
* @param messages - 多语言消息对象
|
|
806
|
+
* @returns 消息获取函数
|
|
807
|
+
*
|
|
808
|
+
* @example
|
|
809
|
+
* ```ts
|
|
810
|
+
* const getMessage = createMessageGetter({
|
|
811
|
+
* 'zh-CN': { hello: '你好' },
|
|
812
|
+
* 'en-US': { hello: 'Hello' },
|
|
813
|
+
* })
|
|
814
|
+
* getMessage('hello') // '你好'
|
|
815
|
+
* getMessage('hello', { locale: 'en-US' }) // 'Hello'
|
|
816
|
+
* getMessage('msg', { params: { name: 'World' } }) // 插值
|
|
817
|
+
* ```
|
|
818
|
+
*/
|
|
819
|
+
declare function createMessageGetter<K extends string>(messages: LocaleMessages<K>): (key: K, options?: MessageOptions) => string;
|
|
820
|
+
/**
|
|
821
|
+
* 语言上下文、字典消息获取与插值工具;Node 请求通过 runWithLocale 隔离语言。
|
|
822
|
+
* @example
|
|
823
|
+
* ```ts
|
|
824
|
+
* import { core } from '@h-ai/core'
|
|
825
|
+
* const tools = core.i18n
|
|
826
|
+
* const message = tools.createMessageGetter({ 'en-US': { hello: 'Hello' }, 'zh-CN': { hello: '你好' } })
|
|
827
|
+
* message('hello', { locale: 'en-US' })
|
|
828
|
+
* ```
|
|
829
|
+
*/
|
|
830
|
+
declare const i18n: {
|
|
831
|
+
DEFAULT_LOCALES: LocaleInfo[];
|
|
832
|
+
DEFAULT_LOCALE: string;
|
|
833
|
+
setGlobalLocale: typeof setGlobalLocale;
|
|
834
|
+
getGlobalLocale: typeof getGlobalLocale;
|
|
835
|
+
runWithLocale: typeof runWithLocale;
|
|
836
|
+
createMessageGetter: typeof createMessageGetter;
|
|
837
|
+
coreM: (key: "$schema" | "core_errorUnknown" | "core_errorNetwork" | "core_errorTimeout" | "core_errorNotFound" | "core_errorUnauthorized" | "core_errorForbidden" | "core_errorValidation" | "core_errorInternal" | "core_actionConfirm" | "core_actionCancel" | "core_actionSave" | "core_actionDelete" | "core_actionEdit" | "core_actionCreate" | "core_actionUpdate" | "core_actionSearch" | "core_actionReset" | "core_actionSubmit" | "core_actionLoading" | "core_actionRetry" | "core_statusSuccess" | "core_statusFailed" | "core_statusPending" | "core_statusProcessing" | "core_statusCompleted" | "core_statusCancelled" | "core_validationRequired" | "core_validationMinLength" | "core_validationMaxLength" | "core_validationEmail" | "core_validationUrl" | "core_validationNumber" | "core_validationInteger" | "core_validationPositive" | "core_validationPattern" | "core_timeJustNow" | "core_timeSecondsAgo" | "core_timeMinutesAgo" | "core_timeHoursAgo" | "core_timeDaysAgo" | "core_timeWeeksAgo" | "core_timeMonthsAgo" | "core_timeYearsAgo" | "core_browserFeatureUnsupported" | "core_configEnvVarMissing" | "core_configFileNotExist" | "core_configParseFailed" | "core_configValidationFailed" | "core_configNotLoaded" | "core_configUnsupportedInBrowser" | "core_cryptoRandomUnavailable" | "core_parallelConcurrencyInvalid" | "core_runtimeStartFailed" | "core_runtimeCloseFailed" | "core_runtimeEnvMissing" | "core_runtimeConfigInvalid" | "core_runtimeConfigProblem" | "core_runtimeErrorCode" | "core_requestAccessDenied", options?: MessageOptions) => string;
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* @h-ai/core — 数组操作工具
|
|
842
|
+
* @module core-util-array
|
|
843
|
+
*/
|
|
844
|
+
/**
|
|
845
|
+
* 数组去重。
|
|
846
|
+
* @param arr - 输入数组
|
|
847
|
+
* @returns 去重后的新数组
|
|
848
|
+
* @remarks 保留首次出现的顺序;空数组返回空数组。
|
|
849
|
+
*
|
|
850
|
+
* @example
|
|
851
|
+
* ```ts
|
|
852
|
+
* array.unique([1, 1, 2]) // [1, 2]
|
|
853
|
+
* ```
|
|
854
|
+
*/
|
|
855
|
+
declare function unique<T>(arr: T[]): T[];
|
|
856
|
+
/**
|
|
857
|
+
* 按条件分组。
|
|
858
|
+
* @param arr - 输入数组
|
|
859
|
+
* @param fn - 分组键生成函数
|
|
860
|
+
* @returns 分组结果对象
|
|
861
|
+
* @remarks 当数组为空时返回空对象;原型同名键也作为独立的自有分组。
|
|
862
|
+
*
|
|
863
|
+
* @example
|
|
864
|
+
* ```ts
|
|
865
|
+
* array.groupBy([{ r: 'a' }, { r: 'b' }], item => item.r)
|
|
866
|
+
* ```
|
|
867
|
+
*/
|
|
868
|
+
declare function groupBy<T, K extends string | number>(arr: T[], fn: (item: T) => K): Record<K, T[]>;
|
|
869
|
+
/**
|
|
870
|
+
* 分割为指定大小的块。
|
|
871
|
+
* @param arr - 输入数组
|
|
872
|
+
* @param size - 每块大小(应为正整数)
|
|
873
|
+
* @returns 分块后的二维数组
|
|
874
|
+
* @remarks size <= 0 时结果为空数组。
|
|
875
|
+
*
|
|
876
|
+
* @example
|
|
877
|
+
* ```ts
|
|
878
|
+
* array.chunk([1, 2, 3], 2) // [[1,2],[3]]
|
|
879
|
+
* ```
|
|
880
|
+
*/
|
|
881
|
+
declare function chunk<T>(arr: T[], size: number): T[][];
|
|
882
|
+
/**
|
|
883
|
+
* 获取第一个元素。
|
|
884
|
+
* @param arr - 输入数组
|
|
885
|
+
* @returns 第一个元素或 undefined
|
|
886
|
+
* @remarks 空数组返回 undefined。
|
|
887
|
+
*
|
|
888
|
+
* @example
|
|
889
|
+
* ```ts
|
|
890
|
+
* array.first([1, 2, 3]) // 1
|
|
891
|
+
* ```
|
|
892
|
+
*/
|
|
893
|
+
declare function first<T>(arr: T[]): T | undefined;
|
|
894
|
+
/**
|
|
895
|
+
* 获取最后一个元素。
|
|
896
|
+
* @param arr - 输入数组
|
|
897
|
+
* @returns 最后一个元素或 undefined
|
|
898
|
+
* @remarks 空数组返回 undefined。
|
|
899
|
+
*
|
|
900
|
+
* @example
|
|
901
|
+
* ```ts
|
|
902
|
+
* array.last([1, 2, 3]) // 3
|
|
903
|
+
* ```
|
|
904
|
+
*/
|
|
905
|
+
declare function last<T>(arr: T[]): T | undefined;
|
|
906
|
+
/**
|
|
907
|
+
* 数组扁平化。
|
|
908
|
+
* @param arr - 二维数组
|
|
909
|
+
* @returns 扁平化后的数组
|
|
910
|
+
* @remarks 仅扁平一层。
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* ```ts
|
|
914
|
+
* array.flatten([[1], [2, 3]]) // [1, 2, 3]
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
declare function flatten<T>(arr: T[][]): T[];
|
|
918
|
+
/**
|
|
919
|
+
* 过滤掉 null 和 undefined。
|
|
920
|
+
* @param arr - 输入数组
|
|
921
|
+
* @returns 过滤后的数组
|
|
922
|
+
* @remarks 会保留 0、false、'' 等假值。
|
|
923
|
+
*
|
|
924
|
+
* @example
|
|
925
|
+
* ```ts
|
|
926
|
+
* array.compact([0, null, 1]) // [0, 1]
|
|
927
|
+
* ```
|
|
928
|
+
*/
|
|
929
|
+
declare function compact<T>(arr: (T | null | undefined)[]): T[];
|
|
930
|
+
/**
|
|
931
|
+
* 随机打乱数组。
|
|
932
|
+
* @param arr - 输入数组
|
|
933
|
+
* @returns 打乱后的新数组
|
|
934
|
+
* @remarks 不修改原数组。
|
|
935
|
+
*
|
|
936
|
+
* @example
|
|
937
|
+
* ```ts
|
|
938
|
+
* const shuffled = array.shuffle([1, 2, 3])
|
|
939
|
+
* ```
|
|
940
|
+
*/
|
|
941
|
+
declare function shuffle<T>(arr: T[]): T[];
|
|
942
|
+
/**
|
|
943
|
+
* 取数组交集。
|
|
944
|
+
* @param arr1 - 数组 1
|
|
945
|
+
* @param arr2 - 数组 2
|
|
946
|
+
* @returns 交集数组
|
|
947
|
+
* @remarks 保持 arr1 中的顺序。
|
|
948
|
+
*
|
|
949
|
+
* @example
|
|
950
|
+
* ```ts
|
|
951
|
+
* array.intersection([1, 2], [2, 3]) // [2]
|
|
952
|
+
* ```
|
|
953
|
+
*/
|
|
954
|
+
declare function intersection<T>(arr1: T[], arr2: T[]): T[];
|
|
955
|
+
/**
|
|
956
|
+
* 取数组差集。
|
|
957
|
+
* @param arr1 - 数组 1
|
|
958
|
+
* @param arr2 - 数组 2
|
|
959
|
+
* @returns 差集数组(arr1 中存在且 arr2 不存在)
|
|
960
|
+
* @remarks 保持 arr1 中的顺序。
|
|
961
|
+
*
|
|
962
|
+
* @example
|
|
963
|
+
* ```ts
|
|
964
|
+
* array.difference([1, 2, 3], [2]) // [1, 3]
|
|
965
|
+
* ```
|
|
966
|
+
*/
|
|
967
|
+
declare function difference<T>(arr1: T[], arr2: T[]): T[];
|
|
968
|
+
/**
|
|
969
|
+
* 数组操作工具对象。
|
|
970
|
+
* @example
|
|
971
|
+
* ```ts
|
|
972
|
+
* import { core } from '@h-ai/core'
|
|
973
|
+
* const tools = core.array
|
|
974
|
+
* tools.chunk([1, 2, 3], 2)
|
|
975
|
+
* ```
|
|
976
|
+
*/
|
|
977
|
+
declare const array: {
|
|
978
|
+
unique: typeof unique;
|
|
979
|
+
groupBy: typeof groupBy;
|
|
980
|
+
chunk: typeof chunk;
|
|
981
|
+
first: typeof first;
|
|
982
|
+
last: typeof last;
|
|
983
|
+
flatten: typeof flatten;
|
|
984
|
+
compact: typeof compact;
|
|
985
|
+
shuffle: typeof shuffle;
|
|
986
|
+
intersection: typeof intersection;
|
|
987
|
+
difference: typeof difference;
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
/**
|
|
991
|
+
* @h-ai/core — 异步操作工具
|
|
992
|
+
* @module core-util-async
|
|
993
|
+
*/
|
|
994
|
+
/**
|
|
995
|
+
* 延迟执行。
|
|
996
|
+
*
|
|
997
|
+
* @param ms - 延迟毫秒数
|
|
998
|
+
* @returns 延迟完成后的 Promise
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```ts
|
|
1002
|
+
* await async.delay(1000)
|
|
1003
|
+
* ```
|
|
1004
|
+
*/
|
|
1005
|
+
declare function delay(ms: number): Promise<void>;
|
|
1006
|
+
/**
|
|
1007
|
+
* 添加超时限制。
|
|
1008
|
+
*
|
|
1009
|
+
* @param promise - 目标 Promise
|
|
1010
|
+
* @param ms - 超时时间(毫秒)
|
|
1011
|
+
* @returns 原 Promise 的结果
|
|
1012
|
+
* @throws 超时将抛出错误
|
|
1013
|
+
*
|
|
1014
|
+
* @example
|
|
1015
|
+
* ```ts
|
|
1016
|
+
* await async.withTimeout(fetch('/api'), 5000)
|
|
1017
|
+
* ```
|
|
1018
|
+
*/
|
|
1019
|
+
declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
|
|
1020
|
+
/**
|
|
1021
|
+
* 重试操作。
|
|
1022
|
+
*
|
|
1023
|
+
* @param fn - 待重试函数
|
|
1024
|
+
* @param options - 重试配置
|
|
1025
|
+
* @param options.maxRetries - 最大重试次数
|
|
1026
|
+
* @param options.delay - 重试间隔(毫秒)
|
|
1027
|
+
* @returns 成功的结果
|
|
1028
|
+
* @throws 重试耗尽后抛出最后一次错误
|
|
1029
|
+
*
|
|
1030
|
+
* @example
|
|
1031
|
+
* ```ts
|
|
1032
|
+
* await async.retry(() => fetch('/api'), { maxRetries: 3, delay: 500 })
|
|
1033
|
+
* ```
|
|
1034
|
+
*/
|
|
1035
|
+
declare function retry<T>(fn: () => Promise<T>, options?: {
|
|
1036
|
+
maxRetries?: number;
|
|
1037
|
+
delay?: number;
|
|
1038
|
+
}): Promise<T>;
|
|
1039
|
+
/**
|
|
1040
|
+
* 并行执行,限制并发数。
|
|
1041
|
+
*
|
|
1042
|
+
* @param items - 输入列表
|
|
1043
|
+
* @param fn - 处理函数
|
|
1044
|
+
* @param concurrency - 最大并发数,必须为大于 0 的安全整数
|
|
1045
|
+
* @returns 处理结果列表
|
|
1046
|
+
* @remarks 结果顺序与输入顺序一致。
|
|
1047
|
+
* @throws 并发数非法时拒绝为 RangeError,不执行任何任务;任务异常原样传播。
|
|
1048
|
+
*
|
|
1049
|
+
* @example
|
|
1050
|
+
* ```ts
|
|
1051
|
+
* await async.parallel([1, 2, 3], async n => n * 2, 2)
|
|
1052
|
+
* ```
|
|
1053
|
+
*/
|
|
1054
|
+
declare function parallel<T, R>(items: T[], fn: (item: T, index: number) => Promise<R>, concurrency?: number): Promise<R[]>;
|
|
1055
|
+
/**
|
|
1056
|
+
* 串行执行。
|
|
1057
|
+
*
|
|
1058
|
+
* @param items - 输入列表
|
|
1059
|
+
* @param fn - 处理函数
|
|
1060
|
+
* @returns 处理结果列表
|
|
1061
|
+
*
|
|
1062
|
+
* @example
|
|
1063
|
+
* ```ts
|
|
1064
|
+
* await async.serial([1, 2], async n => n * 2)
|
|
1065
|
+
* ```
|
|
1066
|
+
*/
|
|
1067
|
+
declare function serial<T, R>(items: T[], fn: (item: T, index: number) => Promise<R>): Promise<R[]>;
|
|
1068
|
+
/**
|
|
1069
|
+
* 防抖。
|
|
1070
|
+
*
|
|
1071
|
+
* @param fn - 目标函数
|
|
1072
|
+
* @param ms - 延迟毫秒数
|
|
1073
|
+
* @returns 防抖后的函数
|
|
1074
|
+
* @remarks 只会在最后一次调用后执行。
|
|
1075
|
+
*
|
|
1076
|
+
* @example
|
|
1077
|
+
* ```ts
|
|
1078
|
+
* const onInput = async.debounce(() => {}, 300)
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
declare function debounce<Args extends unknown[]>(fn: (...args: Args) => unknown, ms: number): (...args: Args) => void;
|
|
1082
|
+
/**
|
|
1083
|
+
* 节流。
|
|
1084
|
+
*
|
|
1085
|
+
* @param fn - 目标函数
|
|
1086
|
+
* @param ms - 间隔毫秒数
|
|
1087
|
+
* @returns 节流后的函数
|
|
1088
|
+
* @remarks 在时间窗口内最多触发一次。
|
|
1089
|
+
*
|
|
1090
|
+
* @example
|
|
1091
|
+
* ```ts
|
|
1092
|
+
* const onScroll = async.throttle(() => {}, 200)
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
declare function throttle<Args extends unknown[]>(fn: (...args: Args) => unknown, ms: number): (...args: Args) => void;
|
|
1096
|
+
/**
|
|
1097
|
+
* 异步操作工具对象。
|
|
1098
|
+
* @example
|
|
1099
|
+
* ```ts
|
|
1100
|
+
* import { core } from '@h-ai/core'
|
|
1101
|
+
* const tools = core.async
|
|
1102
|
+
* await tools.retry(async () => 'ready', { maxRetries: 2 })
|
|
1103
|
+
* ```
|
|
1104
|
+
*/
|
|
1105
|
+
declare const async: {
|
|
1106
|
+
delay: typeof delay;
|
|
1107
|
+
withTimeout: typeof withTimeout;
|
|
1108
|
+
retry: typeof retry;
|
|
1109
|
+
parallel: typeof parallel;
|
|
1110
|
+
serial: typeof serial;
|
|
1111
|
+
debounce: typeof debounce;
|
|
1112
|
+
throttle: typeof throttle;
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* 生产进程默认要求跨主机共享状态;显式E2E测试可使用测试替身。
|
|
1117
|
+
* @param environment - 服务端实际进程环境,不接受请求参数
|
|
1118
|
+
* @param environment.NODE_ENV - 实际运行环境
|
|
1119
|
+
* @param environment.HAI_CORE_ENV - 框架环境文件声明的运行环境
|
|
1120
|
+
* @param environment.HAI_E2E - 显式真实端到端测试标记
|
|
1121
|
+
* @param environment.HAI_E2E_MOCK - 显式模拟端到端测试标记
|
|
1122
|
+
* @returns 是否拒绝仅本机/进程有效的状态后端
|
|
1123
|
+
* @example
|
|
1124
|
+
* ```ts
|
|
1125
|
+
* import { core } from '@h-ai/core'
|
|
1126
|
+
* const production = core.module.requiresSharedState({ HAI_CORE_ENV: 'production' }) // true
|
|
1127
|
+
* const test = core.module.requiresSharedState({ NODE_ENV: 'production', HAI_E2E: '1' }) // false
|
|
1128
|
+
* ```
|
|
1129
|
+
*/
|
|
1130
|
+
declare function requiresSharedState(environment: {
|
|
1131
|
+
NODE_ENV?: string;
|
|
1132
|
+
HAI_CORE_ENV?: string;
|
|
1133
|
+
HAI_E2E?: string;
|
|
1134
|
+
HAI_E2E_MOCK?: string;
|
|
1135
|
+
}): boolean;
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* @h-ai/core — 对象操作工具
|
|
1139
|
+
* @module core-util-object
|
|
1140
|
+
*/
|
|
1141
|
+
/**
|
|
1142
|
+
* 深度克隆对象。
|
|
1143
|
+
* 使用 structuredClone(Node 17+ / 现代浏览器),支持 Date、Map、Set、RegExp、
|
|
1144
|
+
* ArrayBuffer、循环引用等 JSON 方案无法处理的类型。
|
|
1145
|
+
*
|
|
1146
|
+
* @param obj - 目标对象
|
|
1147
|
+
* @returns 深度克隆结果
|
|
1148
|
+
*
|
|
1149
|
+
* @example
|
|
1150
|
+
* ```ts
|
|
1151
|
+
* const cloned = object.deepClone({ a: 1, d: new Date() })
|
|
1152
|
+
* ```
|
|
1153
|
+
*/
|
|
1154
|
+
declare function deepClone<T>(obj: T): T;
|
|
1155
|
+
/**
|
|
1156
|
+
* 深度合并多个对象。
|
|
1157
|
+
* @param objects - 需要合并的对象列表
|
|
1158
|
+
* @returns 合并后的新对象
|
|
1159
|
+
* @remarks 仅递归合并普通对象字段;数组、Date、Map、Set 和类实例由后值直接覆盖,不修改输入。
|
|
1160
|
+
*
|
|
1161
|
+
* @example
|
|
1162
|
+
* ```ts
|
|
1163
|
+
* const merged = object.deepMerge({ a: 1 }, { b: 2 })
|
|
1164
|
+
* ```
|
|
1165
|
+
*/
|
|
1166
|
+
declare function deepMerge<T extends Record<string, unknown>>(...objects: Partial<T>[]): T;
|
|
1167
|
+
/**
|
|
1168
|
+
* 从对象中选取指定的键。
|
|
1169
|
+
* @param obj - 目标对象
|
|
1170
|
+
* @param keys - 要选取的键列表
|
|
1171
|
+
* @returns 仅包含指定键的新对象
|
|
1172
|
+
*
|
|
1173
|
+
* @example
|
|
1174
|
+
* ```ts
|
|
1175
|
+
* object.pick({ a: 1, b: 2 }, ['a'])
|
|
1176
|
+
* ```
|
|
1177
|
+
*/
|
|
1178
|
+
declare function pick<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
|
|
1179
|
+
/**
|
|
1180
|
+
* 从对象中排除指定的键。
|
|
1181
|
+
* @param obj - 目标对象
|
|
1182
|
+
* @param keys - 要排除的键列表
|
|
1183
|
+
* @returns 排除指定键后的新对象
|
|
1184
|
+
*
|
|
1185
|
+
* @example
|
|
1186
|
+
* ```ts
|
|
1187
|
+
* object.omit({ a: 1, b: 2 }, ['b'])
|
|
1188
|
+
* ```
|
|
1189
|
+
*/
|
|
1190
|
+
declare function omit<T extends Record<string, unknown>, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
|
|
1191
|
+
/**
|
|
1192
|
+
* 获取对象的所有键。
|
|
1193
|
+
* @param obj - 目标对象
|
|
1194
|
+
* @returns 键列表
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```ts
|
|
1198
|
+
* object.keys({ a: 1, b: 2 })
|
|
1199
|
+
* ```
|
|
1200
|
+
*/
|
|
1201
|
+
declare function keys<T extends Record<string, unknown>>(obj: T): (keyof T)[];
|
|
1202
|
+
/**
|
|
1203
|
+
* 获取对象的所有值。
|
|
1204
|
+
* @param obj - 目标对象
|
|
1205
|
+
* @returns 值列表
|
|
1206
|
+
*
|
|
1207
|
+
* @example
|
|
1208
|
+
* ```ts
|
|
1209
|
+
* object.values({ a: 1, b: 2 })
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
declare function values<T extends Record<string, unknown>>(obj: T): T[keyof T][];
|
|
1213
|
+
/**
|
|
1214
|
+
* 获取对象的键值对数组。
|
|
1215
|
+
* @param obj - 目标对象
|
|
1216
|
+
* @returns 键值对数组
|
|
1217
|
+
*
|
|
1218
|
+
* @example
|
|
1219
|
+
* ```ts
|
|
1220
|
+
* object.entries({ a: 1 })
|
|
1221
|
+
* ```
|
|
1222
|
+
*/
|
|
1223
|
+
declare function entries<T extends Record<string, unknown>>(obj: T): [keyof T, T[keyof T]][];
|
|
1224
|
+
/**
|
|
1225
|
+
* 从键值对数组创建对象。
|
|
1226
|
+
* @param entries - 键值对数组
|
|
1227
|
+
* @returns 生成的对象
|
|
1228
|
+
*
|
|
1229
|
+
* @example
|
|
1230
|
+
* ```ts
|
|
1231
|
+
* object.fromEntries([['a', 1]])
|
|
1232
|
+
* ```
|
|
1233
|
+
*/
|
|
1234
|
+
declare function fromEntries<K extends string, V>(entries: [K, V][]): Record<K, V>;
|
|
1235
|
+
/**
|
|
1236
|
+
* 对象操作工具对象。
|
|
1237
|
+
* @example
|
|
1238
|
+
* ```ts
|
|
1239
|
+
* import { core } from '@h-ai/core'
|
|
1240
|
+
* const tools = core.object
|
|
1241
|
+
* tools.pick({ id: 'order-1', password: 'example-only' }, ['id'])
|
|
1242
|
+
* ```
|
|
1243
|
+
*/
|
|
1244
|
+
declare const object: {
|
|
1245
|
+
deepClone: typeof deepClone;
|
|
1246
|
+
deepMerge: typeof deepMerge;
|
|
1247
|
+
pick: typeof pick;
|
|
1248
|
+
omit: typeof omit;
|
|
1249
|
+
keys: typeof keys;
|
|
1250
|
+
values: typeof values;
|
|
1251
|
+
entries: typeof entries;
|
|
1252
|
+
fromEntries: typeof fromEntries;
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1255
|
+
/** 顺序启动、反序关闭的薄编排,不持有模块配置、依赖容器或业务服务。 */
|
|
1256
|
+
|
|
1257
|
+
/**
|
|
1258
|
+
* 编排宿主明确拥有的模块和业务钩子,不推断模块类型或初始化参数。
|
|
1259
|
+
* start/close 合并并发;启动失败反序回滚;关闭失败保留依赖和清理义务,下次 close/start 会重试。
|
|
1260
|
+
* @param definitions - 按真实依赖顺序声明的初始化和关闭动作。
|
|
1261
|
+
* @returns 不抛业务异常的生命周期控制器;仅报告安全诊断,配置失败附带原因和处理建议。
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```ts
|
|
1264
|
+
* import { core, ok } from '@h-ai/core'
|
|
1265
|
+
* const runtime = core.module.createRuntime([
|
|
1266
|
+
* { name: 'application', start: () => ok(undefined), close: () => ok(undefined) },
|
|
1267
|
+
* ])
|
|
1268
|
+
* const started = await runtime.start()
|
|
1269
|
+
* if (started.success) await runtime.close()
|
|
1270
|
+
* ```
|
|
1271
|
+
*/
|
|
1272
|
+
declare function createRuntime(definitions: readonly RuntimeStep[]): ModuleRuntime;
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* 清理诊断文本中的显式凭据、URL 凭据及调用方已知的秘密值;不猜测无标签的任意文本。
|
|
1276
|
+
* @example
|
|
1277
|
+
* ```ts
|
|
1278
|
+
* import { core } from '@h-ai/core'
|
|
1279
|
+
* const safe = core.sanitize.sanitizeText('verificationCode=123456')
|
|
1280
|
+
* ```
|
|
1281
|
+
*/
|
|
1282
|
+
declare function sanitizeText(text: string, secretValues?: readonly string[]): string;
|
|
1283
|
+
/**
|
|
1284
|
+
* 判断键名是否属于敏感字段
|
|
1285
|
+
* @param key - 原始字段名;会统一 camelCase、kebab-case 与 snake_case。
|
|
1286
|
+
* @param matcher - 自定义规则;省略时使用凭证字段默认规则。
|
|
1287
|
+
* @returns 当前字段名是否被匹配为敏感字段。
|
|
1288
|
+
* @example
|
|
1289
|
+
* ```ts
|
|
1290
|
+
* import { core } from '@h-ai/core'
|
|
1291
|
+
* const safe = core.sanitize.isSensitiveKey('apiKey')
|
|
1292
|
+
* ```
|
|
1293
|
+
*/
|
|
1294
|
+
declare function isSensitiveKey(key: string, matcher?: SensitiveKeyMatcher): boolean;
|
|
1295
|
+
/**
|
|
1296
|
+
* 遮蔽 URL 的用户名、密码及敏感查询参数;OAuth 风格 fragment 按查询参数处理。
|
|
1297
|
+
*
|
|
1298
|
+
* 解析失败返回固定占位符,避免畸形地址把凭据原样写入日志。
|
|
1299
|
+
*
|
|
1300
|
+
* @param url - 待记录的绝对 URL
|
|
1301
|
+
* @param options - 与对象脱敏一致的匹配规则和替换值
|
|
1302
|
+
* @returns 可安全用于结构化日志的 URL
|
|
1303
|
+
* @example
|
|
1304
|
+
* ```ts
|
|
1305
|
+
* import { core } from '@h-ai/core'
|
|
1306
|
+
* const safe = core.sanitize.sanitizeUrl('https://service.example/path?token=example-only')
|
|
1307
|
+
* ```
|
|
1308
|
+
*/
|
|
1309
|
+
declare function sanitizeUrl(url: string, options?: SanitizeSensitiveFieldsOptions): string;
|
|
1310
|
+
/**
|
|
1311
|
+
* 递归脱敏单个值。
|
|
1312
|
+
*
|
|
1313
|
+
* @param value - 原始值
|
|
1314
|
+
* @param key - 当前字段名;根节点传 null
|
|
1315
|
+
* @param options - 脱敏选项
|
|
1316
|
+
* @param cache - 循环引用 / 重复引用缓存
|
|
1317
|
+
* @returns 脱敏数据副本;类实例不保留原型和方法,普通对象循环保留,Error 规范化为有界诊断树,原值不被修改。
|
|
1318
|
+
* @example
|
|
1319
|
+
* ```ts
|
|
1320
|
+
* import { core } from '@h-ai/core'
|
|
1321
|
+
* const safe = core.sanitize.sanitizeSensitiveValue('example-only', 'password')
|
|
1322
|
+
* ```
|
|
1323
|
+
*/
|
|
1324
|
+
declare function sanitizeSensitiveValue(value: unknown, key: string | null, options?: SanitizeSensitiveFieldsOptions, cache?: WeakMap<object, unknown>): unknown;
|
|
1325
|
+
/**
|
|
1326
|
+
* 对对象中的敏感字段执行递归脱敏,并自动处理 URL/endpoint 字段中的内嵌凭证。
|
|
1327
|
+
* Error 保留 name/message/stack/cause、aggregate errors 与枚举上下文;错误子图循环和过深路径用固定标记,普通对象循环保留。
|
|
1328
|
+
* 诊断文本不会自动解析自由文本中的秘密;记录前仍需调用方清理,或配置明确的 redact 路径。
|
|
1329
|
+
*
|
|
1330
|
+
* @param value - 原始对象/数组/值
|
|
1331
|
+
* @param options - 脱敏选项
|
|
1332
|
+
* 类实例只复制自有可枚举数据属性;不保留原型、访问器和 toJSON。Date 转 ISO 字符串,URL 转脱敏字符串。
|
|
1333
|
+
* @returns 用于诊断的脱敏副本,不作为原类实例使用。
|
|
1334
|
+
* @example
|
|
1335
|
+
* ```ts
|
|
1336
|
+
* import { core } from '@h-ai/core'
|
|
1337
|
+
* const safe = core.sanitize.sanitizeSensitiveFields({ password: 'example-only', id: 'order-1' })
|
|
1338
|
+
* ```
|
|
1339
|
+
*/
|
|
1340
|
+
declare function sanitizeSensitiveFields<T>(value: T, options?: SanitizeSensitiveFieldsOptions): T;
|
|
1341
|
+
/**
|
|
1342
|
+
* 脱敏工具对象。
|
|
1343
|
+
* @example
|
|
1344
|
+
* ```ts
|
|
1345
|
+
* import { core } from '@h-ai/core'
|
|
1346
|
+
* const tools = core.sanitize
|
|
1347
|
+
* tools.sanitizeSensitiveFields({ apiKey: 'example-only', id: 'order-1' })
|
|
1348
|
+
* ```
|
|
1349
|
+
*/
|
|
1350
|
+
declare const sanitize: {
|
|
1351
|
+
defaultSensitiveKeyRegex: RegExp;
|
|
1352
|
+
defaultSensitiveReplacement: string;
|
|
1353
|
+
isSensitiveKey: typeof isSensitiveKey;
|
|
1354
|
+
sanitizeUrl: typeof sanitizeUrl;
|
|
1355
|
+
sanitizeText: typeof sanitizeText;
|
|
1356
|
+
sanitizeSensitiveValue: typeof sanitizeSensitiveValue;
|
|
1357
|
+
sanitizeSensitiveFields: typeof sanitizeSensitiveFields;
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
/**
|
|
1361
|
+
* @h-ai/core — 字符串操作工具
|
|
1362
|
+
* @module core-util-string
|
|
1363
|
+
*/
|
|
1364
|
+
/**
|
|
1365
|
+
* 首字母大写。
|
|
1366
|
+
* @param str - 输入字符串
|
|
1367
|
+
* @returns 首字母大写后的字符串
|
|
1368
|
+
* @remarks 空字符串返回空字符串。
|
|
1369
|
+
*
|
|
1370
|
+
* @example
|
|
1371
|
+
* ```ts
|
|
1372
|
+
* string.capitalize('hello') // 'Hello'
|
|
1373
|
+
* ```
|
|
1374
|
+
*/
|
|
1375
|
+
declare function capitalize(str: string): string;
|
|
1376
|
+
/**
|
|
1377
|
+
* 转换为 kebab-case。
|
|
1378
|
+
* @param str - 输入字符串
|
|
1379
|
+
* @returns kebab-case 字符串
|
|
1380
|
+
* @remarks 支持连续大写字母拆分(如 `getHTTPSUrl` → `get-https-url`)。
|
|
1381
|
+
*
|
|
1382
|
+
* @example
|
|
1383
|
+
* ```ts
|
|
1384
|
+
* string.kebabCase('helloWorld') // 'hello-world'
|
|
1385
|
+
* string.kebabCase('getHTTPSUrl') // 'get-https-url'
|
|
1386
|
+
* ```
|
|
1387
|
+
*/
|
|
1388
|
+
declare function kebabCase(str: string): string;
|
|
1389
|
+
/**
|
|
1390
|
+
* 转换为 camelCase。
|
|
1391
|
+
* @param str - 输入字符串
|
|
1392
|
+
* @returns camelCase 字符串
|
|
1393
|
+
* @remarks 仅处理包含 '-' 的字符串。
|
|
1394
|
+
*
|
|
1395
|
+
* @example
|
|
1396
|
+
* ```ts
|
|
1397
|
+
* string.camelCase('hello-world') // 'helloWorld'
|
|
1398
|
+
* ```
|
|
1399
|
+
*/
|
|
1400
|
+
declare function camelCase(str: string): string;
|
|
1401
|
+
/**
|
|
1402
|
+
* 截断字符串。
|
|
1403
|
+
* @param str - 输入字符串
|
|
1404
|
+
* @param length - 最大长度(小于等于 0 时返回原字符串)
|
|
1405
|
+
* @param suffix - 超出长度时的后缀
|
|
1406
|
+
* @returns 截断后的字符串
|
|
1407
|
+
*
|
|
1408
|
+
* @example
|
|
1409
|
+
* ```ts
|
|
1410
|
+
* string.truncate('hello world', 5) // 'hello...'
|
|
1411
|
+
* ```
|
|
1412
|
+
*/
|
|
1413
|
+
declare function truncate(str: string, length: number, suffix?: string): string;
|
|
1414
|
+
/**
|
|
1415
|
+
* 转换为 snake_case。
|
|
1416
|
+
* @param str - 输入字符串
|
|
1417
|
+
* @returns snake_case 字符串
|
|
1418
|
+
* @remarks 支持连续大写字母拆分(如 `getHTTPSUrl` → `get_https_url`)。
|
|
1419
|
+
*
|
|
1420
|
+
* @example
|
|
1421
|
+
* ```ts
|
|
1422
|
+
* string.snakeCase('helloWorld') // 'hello_world'
|
|
1423
|
+
* string.snakeCase('getHTTPSUrl') // 'get_https_url'
|
|
1424
|
+
* ```
|
|
1425
|
+
*/
|
|
1426
|
+
declare function snakeCase(str: string): string;
|
|
1427
|
+
/**
|
|
1428
|
+
* 转换为 PascalCase。
|
|
1429
|
+
* @param str - 输入字符串
|
|
1430
|
+
* @returns PascalCase 字符串
|
|
1431
|
+
* @remarks 支持 '-' 与 '_' 分隔。
|
|
1432
|
+
*
|
|
1433
|
+
* @example
|
|
1434
|
+
* ```ts
|
|
1435
|
+
* string.pascalCase('hello-world') // 'HelloWorld'
|
|
1436
|
+
* ```
|
|
1437
|
+
*/
|
|
1438
|
+
declare function pascalCase(str: string): string;
|
|
1439
|
+
/**
|
|
1440
|
+
* 移除字符串两端的空白。
|
|
1441
|
+
* @param str - 输入字符串
|
|
1442
|
+
* @returns 去除两端空白后的字符串
|
|
1443
|
+
*
|
|
1444
|
+
* @example
|
|
1445
|
+
* ```ts
|
|
1446
|
+
* string.trim(' hi ') // 'hi'
|
|
1447
|
+
* ```
|
|
1448
|
+
*/
|
|
1449
|
+
declare function trim(str: string): string;
|
|
1450
|
+
/**
|
|
1451
|
+
* 检查字符串是否为空或只包含空白。
|
|
1452
|
+
* @param str - 输入字符串
|
|
1453
|
+
* @returns 是否为空或全空白
|
|
1454
|
+
*
|
|
1455
|
+
* @example
|
|
1456
|
+
* ```ts
|
|
1457
|
+
* string.isBlank(' ') // true
|
|
1458
|
+
* ```
|
|
1459
|
+
*/
|
|
1460
|
+
declare function isBlank(str: string): boolean;
|
|
1461
|
+
/**
|
|
1462
|
+
* 检查字符串是否不为空。
|
|
1463
|
+
* @param str - 输入字符串
|
|
1464
|
+
* @returns 是否非空
|
|
1465
|
+
*
|
|
1466
|
+
* @example
|
|
1467
|
+
* ```ts
|
|
1468
|
+
* string.isNotBlank('ok') // true
|
|
1469
|
+
* ```
|
|
1470
|
+
*/
|
|
1471
|
+
declare function isNotBlank(str: string): boolean;
|
|
1472
|
+
/**
|
|
1473
|
+
* 填充字符串到指定长度(左侧)。
|
|
1474
|
+
* @param str - 输入字符串
|
|
1475
|
+
* @param length - 目标长度
|
|
1476
|
+
* @param char - 填充字符
|
|
1477
|
+
* @returns 填充后的字符串
|
|
1478
|
+
*
|
|
1479
|
+
* @example
|
|
1480
|
+
* ```ts
|
|
1481
|
+
* string.padStart('1', 3, '0') // '001'
|
|
1482
|
+
* ```
|
|
1483
|
+
*/
|
|
1484
|
+
declare function padStart(str: string, length: number, char?: string): string;
|
|
1485
|
+
/**
|
|
1486
|
+
* 填充字符串到指定长度(右侧)。
|
|
1487
|
+
* @param str - 输入字符串
|
|
1488
|
+
* @param length - 目标长度
|
|
1489
|
+
* @param char - 填充字符
|
|
1490
|
+
* @returns 填充后的字符串
|
|
1491
|
+
*
|
|
1492
|
+
* @example
|
|
1493
|
+
* ```ts
|
|
1494
|
+
* string.padEnd('1', 3, '0') // '100'
|
|
1495
|
+
* ```
|
|
1496
|
+
*/
|
|
1497
|
+
declare function padEnd(str: string, length: number, char?: string): string;
|
|
1498
|
+
/**
|
|
1499
|
+
* 无内容提前返回的字符串比较;Node 入口使用原生 timingSafeEqual 覆盖此实现。
|
|
1500
|
+
*
|
|
1501
|
+
* 浏览器 JavaScript 引擎不提供恒时保证,不能将此实现当作服务端凭证校验的安全边界。
|
|
1502
|
+
*
|
|
1503
|
+
* @param a - 字符串 a
|
|
1504
|
+
* @param b - 字符串 b
|
|
1505
|
+
* @returns 是否相等
|
|
1506
|
+
*
|
|
1507
|
+
* @example
|
|
1508
|
+
* ```ts
|
|
1509
|
+
* string.constantTimeEqual('abc', 'abc') // true
|
|
1510
|
+
* string.constantTimeEqual('abc', 'abd') // false
|
|
1511
|
+
* ```
|
|
1512
|
+
*/
|
|
1513
|
+
declare function constantTimeEqual(a: string, b: string): boolean;
|
|
1514
|
+
/**
|
|
1515
|
+
* 字符串操作工具对象。
|
|
1516
|
+
* @example
|
|
1517
|
+
* ```ts
|
|
1518
|
+
* import { core } from '@h-ai/core'
|
|
1519
|
+
* const tools = core.string
|
|
1520
|
+
* tools.camelCase('order-created')
|
|
1521
|
+
* ```
|
|
1522
|
+
*/
|
|
1523
|
+
declare const string: {
|
|
1524
|
+
capitalize: typeof capitalize;
|
|
1525
|
+
kebabCase: typeof kebabCase;
|
|
1526
|
+
camelCase: typeof camelCase;
|
|
1527
|
+
truncate: typeof truncate;
|
|
1528
|
+
snakeCase: typeof snakeCase;
|
|
1529
|
+
pascalCase: typeof pascalCase;
|
|
1530
|
+
trim: typeof trim;
|
|
1531
|
+
isBlank: typeof isBlank;
|
|
1532
|
+
isNotBlank: typeof isNotBlank;
|
|
1533
|
+
padStart: typeof padStart;
|
|
1534
|
+
padEnd: typeof padEnd;
|
|
1535
|
+
constantTimeEqual: typeof constantTimeEqual;
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
/**
|
|
1539
|
+
* @h-ai/core — 时间操作工具
|
|
1540
|
+
* @module core-util-time
|
|
1541
|
+
*/
|
|
1542
|
+
/**
|
|
1543
|
+
* 格式化日期。
|
|
1544
|
+
* @param date - 日期对象
|
|
1545
|
+
* @param format - 格式模板(默认 YYYY-MM-DD)
|
|
1546
|
+
* @returns 格式化后的字符串
|
|
1547
|
+
*
|
|
1548
|
+
* @example
|
|
1549
|
+
* ```ts
|
|
1550
|
+
* time.formatDate(new Date(), 'YYYY-MM-DD')
|
|
1551
|
+
* ```
|
|
1552
|
+
*/
|
|
1553
|
+
declare function formatDate(date: Date, format?: string): string;
|
|
1554
|
+
/**
|
|
1555
|
+
* 相对时间描述。
|
|
1556
|
+
* @param date - 目标日期
|
|
1557
|
+
* @returns 相对时间文案
|
|
1558
|
+
* @remarks 使用 i18n 消息返回结果。
|
|
1559
|
+
*
|
|
1560
|
+
* @example
|
|
1561
|
+
* ```ts
|
|
1562
|
+
* time.timeAgo(new Date(Date.now() - 60000))
|
|
1563
|
+
* ```
|
|
1564
|
+
*/
|
|
1565
|
+
declare function timeAgo(date: Date): string;
|
|
1566
|
+
/**
|
|
1567
|
+
* 获取当前时间戳(毫秒)。
|
|
1568
|
+
* @returns 当前时间戳(毫秒)
|
|
1569
|
+
*
|
|
1570
|
+
* @example
|
|
1571
|
+
* ```ts
|
|
1572
|
+
* const ts = time.now()
|
|
1573
|
+
* ```
|
|
1574
|
+
*/
|
|
1575
|
+
declare function now(): number;
|
|
1576
|
+
/**
|
|
1577
|
+
* 获取当前时间戳(秒)。
|
|
1578
|
+
* @returns 当前时间戳(秒)
|
|
1579
|
+
*
|
|
1580
|
+
* @example
|
|
1581
|
+
* ```ts
|
|
1582
|
+
* const ts = time.nowSeconds()
|
|
1583
|
+
* ```
|
|
1584
|
+
*/
|
|
1585
|
+
declare function nowSeconds(): number;
|
|
1586
|
+
/**
|
|
1587
|
+
* 解析日期字符串。
|
|
1588
|
+
* @param dateStr - 日期字符串
|
|
1589
|
+
* @returns Date 对象
|
|
1590
|
+
* @remarks 无效字符串将生成 Invalid Date。
|
|
1591
|
+
*
|
|
1592
|
+
* @example
|
|
1593
|
+
* ```ts
|
|
1594
|
+
* const date = time.parseDate('2024-01-01')
|
|
1595
|
+
* ```
|
|
1596
|
+
*/
|
|
1597
|
+
declare function parseDate(dateStr: string): Date;
|
|
1598
|
+
/**
|
|
1599
|
+
* 判断是否为有效日期。
|
|
1600
|
+
* @param date - Date 对象
|
|
1601
|
+
* @returns 是否为有效日期
|
|
1602
|
+
*
|
|
1603
|
+
* @example
|
|
1604
|
+
* ```ts
|
|
1605
|
+
* time.isValidDate(new Date('invalid')) // false
|
|
1606
|
+
* ```
|
|
1607
|
+
*/
|
|
1608
|
+
declare function isValidDate(date: Date): boolean;
|
|
1609
|
+
/**
|
|
1610
|
+
* 添加天数。
|
|
1611
|
+
* @param date - 原始日期
|
|
1612
|
+
* @param days - 增加天数(可为负数)
|
|
1613
|
+
* @returns 新的日期对象
|
|
1614
|
+
*
|
|
1615
|
+
* @example
|
|
1616
|
+
* ```ts
|
|
1617
|
+
* time.addDays(new Date(), 7)
|
|
1618
|
+
* ```
|
|
1619
|
+
*/
|
|
1620
|
+
declare function addDays(date: Date, days: number): Date;
|
|
1621
|
+
/**
|
|
1622
|
+
* 添加小时。
|
|
1623
|
+
* @param date - 原始日期
|
|
1624
|
+
* @param hours - 增加小时(可为负数)
|
|
1625
|
+
* @returns 新的日期对象
|
|
1626
|
+
*
|
|
1627
|
+
* @example
|
|
1628
|
+
* ```ts
|
|
1629
|
+
* time.addHours(new Date(), 1)
|
|
1630
|
+
* ```
|
|
1631
|
+
*/
|
|
1632
|
+
declare function addHours(date: Date, hours: number): Date;
|
|
1633
|
+
/**
|
|
1634
|
+
* 获取日期的开始时间(00:00:00)。
|
|
1635
|
+
* @param date - 目标日期
|
|
1636
|
+
* @returns 当天开始时间
|
|
1637
|
+
*
|
|
1638
|
+
* @example
|
|
1639
|
+
* ```ts
|
|
1640
|
+
* time.startOfDay(new Date())
|
|
1641
|
+
* ```
|
|
1642
|
+
*/
|
|
1643
|
+
declare function startOfDay(date: Date): Date;
|
|
1644
|
+
/**
|
|
1645
|
+
* 获取日期的结束时间(23:59:59)。
|
|
1646
|
+
* @param date - 目标日期
|
|
1647
|
+
* @returns 当天结束时间
|
|
1648
|
+
*
|
|
1649
|
+
* @example
|
|
1650
|
+
* ```ts
|
|
1651
|
+
* time.endOfDay(new Date())
|
|
1652
|
+
* ```
|
|
1653
|
+
*/
|
|
1654
|
+
declare function endOfDay(date: Date): Date;
|
|
1655
|
+
/**
|
|
1656
|
+
* 时间操作工具对象。
|
|
1657
|
+
* @example
|
|
1658
|
+
* ```ts
|
|
1659
|
+
* import { core } from '@h-ai/core'
|
|
1660
|
+
* const tools = core.time
|
|
1661
|
+
* tools.addDays(new Date('2026-01-01T00:00:00Z'), 1)
|
|
1662
|
+
* ```
|
|
1663
|
+
*/
|
|
1664
|
+
declare const time: {
|
|
1665
|
+
formatDate: typeof formatDate;
|
|
1666
|
+
timeAgo: typeof timeAgo;
|
|
1667
|
+
now: typeof now;
|
|
1668
|
+
nowSeconds: typeof nowSeconds;
|
|
1669
|
+
parseDate: typeof parseDate;
|
|
1670
|
+
isValidDate: typeof isValidDate;
|
|
1671
|
+
addDays: typeof addDays;
|
|
1672
|
+
addHours: typeof addHours;
|
|
1673
|
+
startOfDay: typeof startOfDay;
|
|
1674
|
+
endOfDay: typeof endOfDay;
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* @h-ai/core — 类型检查工具
|
|
1679
|
+
* @module core-util-type
|
|
1680
|
+
*/
|
|
1681
|
+
/**
|
|
1682
|
+
* 检查值是否已定义(非 null 和 undefined)。
|
|
1683
|
+
* @param value - 待检查值
|
|
1684
|
+
* @returns 是否已定义
|
|
1685
|
+
*
|
|
1686
|
+
* @example
|
|
1687
|
+
* ```ts
|
|
1688
|
+
* typeUtils.isDefined(0) // true
|
|
1689
|
+
* ```
|
|
1690
|
+
*/
|
|
1691
|
+
declare function isDefined<T>(value: T | undefined | null): value is T;
|
|
1692
|
+
/**
|
|
1693
|
+
* 检查值是否为纯对象(排除数组)。
|
|
1694
|
+
* @param value - 待检查值
|
|
1695
|
+
* @returns 是否为纯对象
|
|
1696
|
+
*
|
|
1697
|
+
* @example
|
|
1698
|
+
* ```ts
|
|
1699
|
+
* typeUtils.isObject({}) // true
|
|
1700
|
+
* ```
|
|
1701
|
+
*/
|
|
1702
|
+
declare function isObject(value: unknown): value is Record<string, unknown>;
|
|
1703
|
+
/**
|
|
1704
|
+
* 检查值是否为函数。
|
|
1705
|
+
* @param value - 待检查值
|
|
1706
|
+
* @returns 是否为函数
|
|
1707
|
+
*
|
|
1708
|
+
* @example
|
|
1709
|
+
* ```ts
|
|
1710
|
+
* typeUtils.isFunction(() => {}) // true
|
|
1711
|
+
* ```
|
|
1712
|
+
*/
|
|
1713
|
+
declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
|
|
1714
|
+
/**
|
|
1715
|
+
* 检查值是否为 Promise。
|
|
1716
|
+
* @param value - 待检查值
|
|
1717
|
+
* @returns 是否为 Promise
|
|
1718
|
+
*
|
|
1719
|
+
* @example
|
|
1720
|
+
* ```ts
|
|
1721
|
+
* typeUtils.isPromise(Promise.resolve()) // true
|
|
1722
|
+
* ```
|
|
1723
|
+
*/
|
|
1724
|
+
declare function isPromise<T>(value: unknown): value is Promise<T>;
|
|
1725
|
+
/**
|
|
1726
|
+
* 检查值是否为字符串。
|
|
1727
|
+
* @param value - 待检查值
|
|
1728
|
+
* @returns 是否为字符串
|
|
1729
|
+
*
|
|
1730
|
+
* @example
|
|
1731
|
+
* ```ts
|
|
1732
|
+
* typeUtils.isString('a') // true
|
|
1733
|
+
* ```
|
|
1734
|
+
*/
|
|
1735
|
+
declare function isString(value: unknown): value is string;
|
|
1736
|
+
/**
|
|
1737
|
+
* 检查值是否为数字。
|
|
1738
|
+
* @param value - 待检查值
|
|
1739
|
+
* @returns 是否为数字(排除 NaN)
|
|
1740
|
+
*
|
|
1741
|
+
* @example
|
|
1742
|
+
* ```ts
|
|
1743
|
+
* typeUtils.isNumber(1) // true
|
|
1744
|
+
* ```
|
|
1745
|
+
*/
|
|
1746
|
+
declare function isNumber(value: unknown): value is number;
|
|
1747
|
+
/**
|
|
1748
|
+
* 检查值是否为布尔值。
|
|
1749
|
+
* @param value - 待检查值
|
|
1750
|
+
* @returns 是否为布尔值
|
|
1751
|
+
*
|
|
1752
|
+
* @example
|
|
1753
|
+
* ```ts
|
|
1754
|
+
* typeUtils.isBoolean(false) // true
|
|
1755
|
+
* ```
|
|
1756
|
+
*/
|
|
1757
|
+
declare function isBoolean(value: unknown): value is boolean;
|
|
1758
|
+
/**
|
|
1759
|
+
* 检查值是否为数组。
|
|
1760
|
+
* @param value - 待检查值
|
|
1761
|
+
* @returns 是否为数组
|
|
1762
|
+
*
|
|
1763
|
+
* @example
|
|
1764
|
+
* ```ts
|
|
1765
|
+
* typeUtils.isArray([1, 2]) // true
|
|
1766
|
+
* ```
|
|
1767
|
+
*/
|
|
1768
|
+
declare function isArray<T = unknown>(value: unknown): value is T[];
|
|
1769
|
+
/**
|
|
1770
|
+
* 类型检查工具对象。
|
|
1771
|
+
* @example
|
|
1772
|
+
* ```ts
|
|
1773
|
+
* import { core } from '@h-ai/core'
|
|
1774
|
+
* const tools = core.typeUtils
|
|
1775
|
+
* const value: unknown = 'order-1'
|
|
1776
|
+
* if (tools.isString(value)) value.toUpperCase()
|
|
1777
|
+
* ```
|
|
1778
|
+
*/
|
|
1779
|
+
declare const typeUtils: {
|
|
1780
|
+
isDefined: typeof isDefined;
|
|
1781
|
+
isObject: typeof isObject;
|
|
1782
|
+
isFunction: typeof isFunction;
|
|
1783
|
+
isPromise: typeof isPromise;
|
|
1784
|
+
isString: typeof isString;
|
|
1785
|
+
isNumber: typeof isNumber;
|
|
1786
|
+
isBoolean: typeof isBoolean;
|
|
1787
|
+
isArray: typeof isArray;
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* @h-ai/core — 错误注册与处理
|
|
1792
|
+
*
|
|
1793
|
+
* 提供统一的错误定义生成与实例化能力。
|
|
1794
|
+
*
|
|
1795
|
+
* @module core-function-error
|
|
1796
|
+
*/
|
|
1797
|
+
|
|
1798
|
+
/**
|
|
1799
|
+
* 错误提示末尾显示关联标识;重复格式化不会重复追加。
|
|
1800
|
+
* @example
|
|
1801
|
+
* ```ts
|
|
1802
|
+
* import { core } from '@h-ai/core'
|
|
1803
|
+
* const message = core.error.formatMessage({ message: '保存失败', traceId: 'request-1' })
|
|
1804
|
+
* ```
|
|
1805
|
+
*/
|
|
1806
|
+
declare function formatMessage(error: Pick<HaiError, 'message' | 'traceId'>): string;
|
|
1807
|
+
/**
|
|
1808
|
+
* HTTP/UI 边界仅公开安全消息和关联标识;内部异常及扩展信息留在脱敏日志。
|
|
1809
|
+
* @example
|
|
1810
|
+
* ```ts
|
|
1811
|
+
* import { core } from '@h-ai/core'
|
|
1812
|
+
* const safe = core.error.toPublic({ code: 'app:failed', message: 'Internal detail', httpStatus: 500 }, 'request-1')
|
|
1813
|
+
* ```
|
|
1814
|
+
*/
|
|
1815
|
+
declare function toPublic(error: HaiError, traceId?: string, locale?: string): HaiError;
|
|
1816
|
+
/**
|
|
1817
|
+
* 根据模块错误映射生成标准错误定义对象。
|
|
1818
|
+
*
|
|
1819
|
+
* 将错误信息映射(如 `{ CONFIG_NOT_FOUND: '010:500' }`)转换为结构化的 HaiErrorDef,
|
|
1820
|
+
* 自动组装完整的错误码(格式:`system:module:code`)以及对应的 HTTP 状态码。
|
|
1821
|
+
*
|
|
1822
|
+
* @template T - 错误信息映射的类型
|
|
1823
|
+
*
|
|
1824
|
+
* @param module - 模块名称(如 'core'、'db'、'api'),会作为错误码的第二段
|
|
1825
|
+
* @param errorInfo - 错误信息映射对象,值格式为 `'错误码数字:HTTP状态码'`(如 `'010:500'`)
|
|
1826
|
+
* @param system - 系统标识,默认 'hai',会作为错误码的第一段
|
|
1827
|
+
*
|
|
1828
|
+
* @returns 返回同类型的错误定义对象,每个 key 对应一个 HaiErrorDef 对象
|
|
1829
|
+
*
|
|
1830
|
+
* @example
|
|
1831
|
+
* ```ts
|
|
1832
|
+
* const ConfigErrorInfo = {
|
|
1833
|
+
* FILE_NOT_FOUND: '010:500',
|
|
1834
|
+
* PARSE_ERROR: '011:500',
|
|
1835
|
+
* VALIDATION_ERROR: '012:500',
|
|
1836
|
+
* } as const
|
|
1837
|
+
*
|
|
1838
|
+
* const ConfigError = buildHaiErrorsDef('core', ConfigErrorInfo)
|
|
1839
|
+
* // =>
|
|
1840
|
+
* // ConfigError.FILE_NOT_FOUND = {
|
|
1841
|
+
* // code: 'hai:core:010',
|
|
1842
|
+
* // httpStatus: 500,
|
|
1843
|
+
* // system: 'hai',
|
|
1844
|
+
* // module: 'core',
|
|
1845
|
+
* // }
|
|
1846
|
+
* ```
|
|
1847
|
+
*/
|
|
1848
|
+
declare function buildHaiErrorsDef<T extends Record<string, string>>(module: string, errorInfo: T, system?: string): {
|
|
1849
|
+
[K in keyof T]: HaiErrorDef;
|
|
1850
|
+
};
|
|
1851
|
+
/**
|
|
1852
|
+
* 根据错误定义创建错误实例。
|
|
1853
|
+
*
|
|
1854
|
+
* 将 HaiErrorDef(错误定义)扩展为 HaiError(运行时错误实例),
|
|
1855
|
+
* 添加具体的错误消息、原因和建议等运行时信息。
|
|
1856
|
+
*
|
|
1857
|
+
* @param def - 错误定义对象(通常由 buildHaiErrorsDef 生成)
|
|
1858
|
+
* @param message - 错误消息(描述此次具体发生了什么)
|
|
1859
|
+
* @param cause - 原始错误原因(可选,用于链式错误追踪)
|
|
1860
|
+
* @param suggestion - 用户可采取的建议(可选,如 "'请检查配置文件格式')
|
|
1861
|
+
*
|
|
1862
|
+
* @returns 返回完整的 HaiError 实例,包含错误码、HTTP 状态、消息、原因和建议
|
|
1863
|
+
*
|
|
1864
|
+
* @example
|
|
1865
|
+
* ```ts
|
|
1866
|
+
* const err = buildHaiErrorInst(
|
|
1867
|
+
* HaiConfigError.FILE_NOT_FOUND,
|
|
1868
|
+
* 'config.yml 文件不存在',
|
|
1869
|
+
* new Error('ENOENT: no such file'),
|
|
1870
|
+
* '请确保 _core.yml 在项目根目录'
|
|
1871
|
+
* )
|
|
1872
|
+
* // => {
|
|
1873
|
+
* // code: 'hai:core:010',
|
|
1874
|
+
* // httpStatus: 500,
|
|
1875
|
+
* // system: 'hai',
|
|
1876
|
+
* // module: 'core',
|
|
1877
|
+
* // message: 'config.yml 文件不存在',
|
|
1878
|
+
* // cause: Error('ENOENT: no such file'),
|
|
1879
|
+
* // suggestion: '请确保 _core.yml 在项目根目录'
|
|
1880
|
+
* // }
|
|
1881
|
+
* ```
|
|
1882
|
+
*/
|
|
1883
|
+
declare function buildHaiErrorInst(def: HaiErrorDef, message: string, cause?: unknown, suggestion?: string): HaiError;
|
|
1884
|
+
/**
|
|
1885
|
+
* 错误定义生成及错误实例组装工具;通过 core.error 使用。
|
|
1886
|
+
* @example
|
|
1887
|
+
* ```ts
|
|
1888
|
+
* import { core } from '@h-ai/core'
|
|
1889
|
+
* const tools = core.error
|
|
1890
|
+
* tools.buildHaiErrorsDef('orders', { NOT_FOUND: '001:404' })
|
|
1891
|
+
* ```
|
|
1892
|
+
*/
|
|
1893
|
+
declare const error: {
|
|
1894
|
+
buildHaiErrorsDef: typeof buildHaiErrorsDef;
|
|
1895
|
+
buildHaiErrorInst: typeof buildHaiErrorInst;
|
|
1896
|
+
formatMessage: typeof formatMessage;
|
|
1897
|
+
toPublic: typeof toPublic;
|
|
1898
|
+
};
|
|
1899
|
+
|
|
1900
|
+
/**
|
|
1901
|
+
* Zod 校验错误使用的稳定消息键。
|
|
1902
|
+
* @example
|
|
1903
|
+
* ```ts
|
|
1904
|
+
* import type { ZodValidationMessageKey } from '@h-ai/core'
|
|
1905
|
+
* const value: ZodValidationMessageKey = 'validationRequired'
|
|
1906
|
+
* ```
|
|
1907
|
+
*/
|
|
1908
|
+
type ZodValidationMessageKey = 'validationFailed' | 'validationRequired' | 'validationInvalid' | 'validationInvalidType' | 'validationUnexpectedFields' | 'validationStringMin' | 'validationStringMax' | 'validationNumberMin' | 'validationNumberMax' | 'validationArrayMin' | 'validationArrayMax' | 'validationTooSmall' | 'validationTooBig' | 'validationEmail' | 'validationUrl' | 'validationUuid' | 'validationEnum';
|
|
1909
|
+
/**
|
|
1910
|
+
* 把校验消息键及插值参数转换为显示文本的函数。
|
|
1911
|
+
* @example
|
|
1912
|
+
* ```ts
|
|
1913
|
+
* import type { ZodMessageGetter } from '@h-ai/core'
|
|
1914
|
+
* const message: ZodMessageGetter = (key, params) => key === 'validationRequired' ? 'Required' : `${key}: ${String(params?.field ?? '')}`
|
|
1915
|
+
* message('validationRequired')
|
|
1916
|
+
* ```
|
|
1917
|
+
*/
|
|
1918
|
+
type ZodMessageGetter = (key: ZodValidationMessageKey, params?: Record<string, string | number>) => string;
|
|
1919
|
+
/**
|
|
1920
|
+
* 可绑定表单字段路径的本地化错误。
|
|
1921
|
+
* @example
|
|
1922
|
+
* ```ts
|
|
1923
|
+
* import type { ValidationFormError } from '@h-ai/core'
|
|
1924
|
+
* const value: ValidationFormError = { field: 'email', message: 'Enter an email address' }
|
|
1925
|
+
* ```
|
|
1926
|
+
*/
|
|
1927
|
+
interface ValidationFormError {
|
|
1928
|
+
field: string;
|
|
1929
|
+
message: string;
|
|
1930
|
+
}
|
|
1931
|
+
/**
|
|
1932
|
+
* 共享 Zod 错误映射契约;业务自定义消息保持原文。
|
|
1933
|
+
* @example
|
|
1934
|
+
* ```ts
|
|
1935
|
+
* import { core, type ZodValidationFn } from '@h-ai/core'
|
|
1936
|
+
* import { z } from 'zod'
|
|
1937
|
+
* const validator: ZodValidationFn = core.zodValidation
|
|
1938
|
+
* const input = z.object({ email: z.email() }).safeParse({ email: 'invalid' })
|
|
1939
|
+
* if (!input.success) validator.mapZodErrorToFormErrors(input.error, key => key)
|
|
1940
|
+
* ```
|
|
1941
|
+
*/
|
|
1942
|
+
interface ZodValidationFn {
|
|
1943
|
+
readonly createPrefixedZodMessageGetter: <TMessageKey extends string>(prefix: string, getMessage: (messageKey: TMessageKey, params?: Record<string, string | number>) => string) => ZodMessageGetter;
|
|
1944
|
+
readonly mapZodErrorToFormErrors: (error: unknown, getMessage: ZodMessageGetter) => ValidationFormError[];
|
|
1945
|
+
}
|
|
1946
|
+
/**
|
|
1947
|
+
* 业务操作的成功数据或标准失败;访问 data/error 前必须按 success 收窄。
|
|
1948
|
+
* @example
|
|
1949
|
+
* ```ts
|
|
1950
|
+
* import { ok, type HaiResult } from '@h-ai/core'
|
|
1951
|
+
* const result: HaiResult<{ id: string }> = ok({ id: 'order-1' })
|
|
1952
|
+
* const label = result.success ? result.data.id : result.error.message
|
|
1953
|
+
* ```
|
|
1954
|
+
*/
|
|
1955
|
+
type HaiResult<T> = {
|
|
1956
|
+
success: true;
|
|
1957
|
+
data: T;
|
|
1958
|
+
} | {
|
|
1959
|
+
success: false;
|
|
1960
|
+
error: HaiError;
|
|
1961
|
+
};
|
|
1962
|
+
/**
|
|
1963
|
+
* 创建成功结果;不会自动捕获后续操作异常。
|
|
1964
|
+
* @param data - 成功分支的数据;保留原类型和对象引用。
|
|
1965
|
+
* @returns success 为 true、data 为输入值的结果。
|
|
1966
|
+
* @example
|
|
1967
|
+
* ```ts
|
|
1968
|
+
* import { ok } from '@h-ai/core'
|
|
1969
|
+
* const result = ok({ id: 'order-1' })
|
|
1970
|
+
* if (result.success) result.data.id.toUpperCase()
|
|
1971
|
+
* ```
|
|
1972
|
+
*/
|
|
1973
|
+
declare function ok<T>(data: T): HaiResult<T>;
|
|
1974
|
+
/**
|
|
1975
|
+
* 创建失败结果;支持标准错误定义、已有 HaiError 与原生 Error。
|
|
1976
|
+
* @param errorOrDef - 已定义的错误、已有业务错误或原生异常。
|
|
1977
|
+
* @param message - 从错误定义创建实例时使用的消息。
|
|
1978
|
+
* @param cause - 原始原因;对外展示前应按边界脱敏。
|
|
1979
|
+
* @param suggestion - 可选的处理建议。
|
|
1980
|
+
* @returns success 为 false、error 为标准业务错误的结果。
|
|
1981
|
+
* @example
|
|
1982
|
+
* ```ts
|
|
1983
|
+
* import { err, HaiCommonError } from '@h-ai/core'
|
|
1984
|
+
* const result = err(HaiCommonError.NOT_FOUND, 'Order not found')
|
|
1985
|
+
* if (!result.success) result.error.httpStatus
|
|
1986
|
+
* ```
|
|
1987
|
+
*/
|
|
1988
|
+
declare function err(errorOrDef: HaiErrorDef | HaiError | Error, message?: string, cause?: unknown, suggestion?: string): HaiResult<never>;
|
|
1989
|
+
/**
|
|
1990
|
+
* HaiResult 模式匹配处理器。
|
|
1991
|
+
*
|
|
1992
|
+
* 提供对 HaiResult 的模式匹配能力,分别处理成功和失败两种情况。
|
|
1993
|
+
*
|
|
1994
|
+
* @template T - 成功数据类型
|
|
1995
|
+
* @template R1 - ok 分支返回类型
|
|
1996
|
+
* @template R2 - err 分支返回类型
|
|
1997
|
+
* @example
|
|
1998
|
+
* ```ts
|
|
1999
|
+
* import { type MatchHandlers, ok } from '@h-ai/core'
|
|
2000
|
+
* const handlers: MatchHandlers<number, string, string> = { ok: n => String(n + 1), err: error => error.message }
|
|
2001
|
+
* const result = ok(2)
|
|
2002
|
+
* const label = result.success ? handlers.ok(result.data) : handlers.err(result.error)
|
|
2003
|
+
* ```
|
|
2004
|
+
*/
|
|
2005
|
+
interface MatchHandlers<T, R1, R2> {
|
|
2006
|
+
/** 成功分支处理器 */
|
|
2007
|
+
ok: (data: T) => R1;
|
|
2008
|
+
/** 失败分支处理器 */
|
|
2009
|
+
err: (error: HaiError) => R2;
|
|
2010
|
+
}
|
|
2011
|
+
/**
|
|
2012
|
+
* 错误信息值格式:`错误码数字段:HTTP状态码`,例如 `001:500`。
|
|
2013
|
+
* @example
|
|
2014
|
+
* ```ts
|
|
2015
|
+
* import type { ErrorInfoValue } from '@h-ai/core'
|
|
2016
|
+
* const value: ErrorInfoValue = '001:500'
|
|
2017
|
+
* ```
|
|
2018
|
+
*/
|
|
2019
|
+
type ErrorInfoValue = `${string}:${string}`;
|
|
2020
|
+
/**
|
|
2021
|
+
* 模块错误信息映射。
|
|
2022
|
+
* @example
|
|
2023
|
+
* ```ts
|
|
2024
|
+
* import type { ErrorInfo } from '@h-ai/core'
|
|
2025
|
+
* const value: ErrorInfo = { NOT_READY: '001:503' }
|
|
2026
|
+
* ```
|
|
2027
|
+
*/
|
|
2028
|
+
type ErrorInfo = Record<string, ErrorInfoValue>;
|
|
2029
|
+
/**
|
|
2030
|
+
* 稳定的错误码与 HTTP 映射;消息在创建错误实例时填入。
|
|
2031
|
+
* @example
|
|
2032
|
+
* ```ts
|
|
2033
|
+
* import type { HaiErrorDef } from '@h-ai/core'
|
|
2034
|
+
* const value: HaiErrorDef = { code: 'app:orders:001', httpStatus: 409, system: 'app', module: 'orders' }
|
|
2035
|
+
* ```
|
|
2036
|
+
*/
|
|
2037
|
+
interface HaiErrorDef {
|
|
2038
|
+
code: string | number;
|
|
2039
|
+
httpStatus: number;
|
|
2040
|
+
system: string;
|
|
2041
|
+
module: string;
|
|
2042
|
+
}
|
|
2043
|
+
/**
|
|
2044
|
+
* 可跨业务边界传递的错误;cause/ext 对外展示前仍需脱敏。
|
|
2045
|
+
* @example
|
|
2046
|
+
* ```ts
|
|
2047
|
+
* import type { HaiError } from '@h-ai/core'
|
|
2048
|
+
* const value: HaiError = { code: 'app:orders:001', message: 'Order already exists', httpStatus: 409 }
|
|
2049
|
+
* ```
|
|
2050
|
+
*/
|
|
2051
|
+
interface HaiError {
|
|
2052
|
+
code: string | number;
|
|
2053
|
+
message: string;
|
|
2054
|
+
/** 用户提示与前后端诊断共用的关联标识。 */
|
|
2055
|
+
traceId?: string;
|
|
2056
|
+
httpStatus?: number;
|
|
2057
|
+
system?: string;
|
|
2058
|
+
module?: string;
|
|
2059
|
+
cause?: unknown;
|
|
2060
|
+
suggestion?: string;
|
|
2061
|
+
ext?: Record<string, unknown>;
|
|
2062
|
+
/** 由服务端明确批准公开的业务进度;边界转换为 ext,内部 ext 默认不公开。 */
|
|
2063
|
+
publicExt?: Record<string, unknown>;
|
|
2064
|
+
}
|
|
2065
|
+
/**
|
|
2066
|
+
* 跨模块通用错误定义及 HTTP 状态映射。
|
|
2067
|
+
* @example
|
|
2068
|
+
* ```ts
|
|
2069
|
+
* import { err, HaiCommonError } from '@h-ai/core'
|
|
2070
|
+
* const result = err(HaiCommonError.UNAUTHORIZED, 'Authentication required')
|
|
2071
|
+
* if (!result.success) result.error.code
|
|
2072
|
+
* ```
|
|
2073
|
+
*/
|
|
2074
|
+
declare const HaiCommonError: {
|
|
2075
|
+
readonly NOT_INITIALIZED: HaiErrorDef;
|
|
2076
|
+
readonly INIT_FAILED: HaiErrorDef;
|
|
2077
|
+
readonly INIT_IN_PROGRESS: HaiErrorDef;
|
|
2078
|
+
readonly UNAUTHORIZED: HaiErrorDef;
|
|
2079
|
+
readonly FORBIDDEN: HaiErrorDef;
|
|
2080
|
+
readonly TOKEN_EXPIRED: HaiErrorDef;
|
|
2081
|
+
readonly TOKEN_INVALID: HaiErrorDef;
|
|
2082
|
+
readonly REQUEST_ACCESS_DENIED: HaiErrorDef;
|
|
2083
|
+
readonly VALIDATION_ERROR: HaiErrorDef;
|
|
2084
|
+
readonly INVALID_REQUEST: HaiErrorDef;
|
|
2085
|
+
readonly PARAMETER_MISSING: HaiErrorDef;
|
|
2086
|
+
readonly NOT_FOUND: HaiErrorDef;
|
|
2087
|
+
readonly ALREADY_EXISTS: HaiErrorDef;
|
|
2088
|
+
readonly CONFLICT: HaiErrorDef;
|
|
2089
|
+
readonly API_ERROR: HaiErrorDef;
|
|
2090
|
+
readonly NETWORK_ERROR: HaiErrorDef;
|
|
2091
|
+
readonly TIMEOUT: HaiErrorDef;
|
|
2092
|
+
readonly SERVICE_UNAVAILABLE: HaiErrorDef;
|
|
2093
|
+
readonly INTERNAL_ERROR: HaiErrorDef;
|
|
2094
|
+
readonly DATABASE_ERROR: HaiErrorDef;
|
|
2095
|
+
readonly UNKNOWN_ERROR: HaiErrorDef;
|
|
2096
|
+
};
|
|
2097
|
+
/**
|
|
2098
|
+
* 文件配置加载、校验、环境缺失及缓存读取的错误定义。
|
|
2099
|
+
* @example
|
|
2100
|
+
* ```ts
|
|
2101
|
+
* import { err, HaiConfigError } from '@h-ai/core'
|
|
2102
|
+
* const result = err(HaiConfigError.CONFIG_NOT_LOADED, 'App configuration is unavailable')
|
|
2103
|
+
* if (!result.success) result.error.message
|
|
2104
|
+
* ```
|
|
2105
|
+
*/
|
|
2106
|
+
declare const HaiConfigError: {
|
|
2107
|
+
readonly CONFIG_FILE_NOT_FOUND: HaiErrorDef;
|
|
2108
|
+
readonly CONFIG_PARSE_ERROR: HaiErrorDef;
|
|
2109
|
+
readonly CONFIG_VALIDATION_ERROR: HaiErrorDef;
|
|
2110
|
+
readonly CONFIG_ENV_VAR_MISSING: HaiErrorDef;
|
|
2111
|
+
readonly CONFIG_NOT_LOADED: HaiErrorDef;
|
|
2112
|
+
};
|
|
2113
|
+
/**
|
|
2114
|
+
* 分页参数输入(可选字段,未提供时使用默认值)。
|
|
2115
|
+
* @example
|
|
2116
|
+
* ```ts
|
|
2117
|
+
* import type { PaginationOptionsInput } from '@h-ai/core'
|
|
2118
|
+
* const value: PaginationOptionsInput = { page: 2, pageSize: 20 }
|
|
2119
|
+
* ```
|
|
2120
|
+
*/
|
|
2121
|
+
interface PaginationOptionsInput {
|
|
2122
|
+
/** 页码(从 1 开始,默认 1) */
|
|
2123
|
+
page?: number;
|
|
2124
|
+
/** 每页数量(默认由业务层决定) */
|
|
2125
|
+
pageSize?: number;
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* 分页参数(必填,已确定具体值)。
|
|
2129
|
+
* @example
|
|
2130
|
+
* ```ts
|
|
2131
|
+
* import type { PaginationOptions } from '@h-ai/core'
|
|
2132
|
+
* const value: PaginationOptions = { page: 1, pageSize: 20 }
|
|
2133
|
+
* ```
|
|
2134
|
+
*/
|
|
2135
|
+
interface PaginationOptions {
|
|
2136
|
+
/** 页码(从 1 开始) */
|
|
2137
|
+
page: number;
|
|
2138
|
+
/** 每页数量 */
|
|
2139
|
+
pageSize: number;
|
|
2140
|
+
}
|
|
2141
|
+
/**
|
|
2142
|
+
* 分页结果。
|
|
2143
|
+
*
|
|
2144
|
+
* @template T - 数据项类型
|
|
2145
|
+
* @example
|
|
2146
|
+
* ```ts
|
|
2147
|
+
* import type { PaginatedResult } from '@h-ai/core'
|
|
2148
|
+
* const page: PaginatedResult<{ id: string }> = { items: [{ id: 'order-1' }], total: 1, page: 1, pageSize: 20 }
|
|
2149
|
+
* const ids = page.items.map(item => item.id)
|
|
2150
|
+
* ```
|
|
2151
|
+
*/
|
|
2152
|
+
interface PaginatedResult<T> {
|
|
2153
|
+
/** 当前页数据 */
|
|
2154
|
+
items: T[];
|
|
2155
|
+
/** 总数量 */
|
|
2156
|
+
total: number;
|
|
2157
|
+
/** 页码(从 1 开始) */
|
|
2158
|
+
page: number;
|
|
2159
|
+
/** 每页数量 */
|
|
2160
|
+
pageSize: number;
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* 日志上下文。
|
|
2164
|
+
* @example
|
|
2165
|
+
* ```ts
|
|
2166
|
+
* import type { LogContext } from '@h-ai/core'
|
|
2167
|
+
* const value: LogContext = { requestId: 'request-1', level: 'info' }
|
|
2168
|
+
* ```
|
|
2169
|
+
*/
|
|
2170
|
+
interface LogContext {
|
|
2171
|
+
timestamp?: Date;
|
|
2172
|
+
level?: LogLevel;
|
|
2173
|
+
message?: string;
|
|
2174
|
+
[key: string]: unknown;
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* 可信关联范围,不包含访问令牌。Node 异步请求/任务隔离,浏览器仅同步作用域。
|
|
2178
|
+
* @example
|
|
2179
|
+
* ```ts
|
|
2180
|
+
* import type { RequestContext } from '@h-ai/core'
|
|
2181
|
+
* const context: RequestContext = { requestId: 'request-1', scopeId: 'tenant-1', userId: 'user-1' }
|
|
2182
|
+
* ```
|
|
2183
|
+
*/
|
|
2184
|
+
interface RequestContext {
|
|
2185
|
+
readonly requestId?: string;
|
|
2186
|
+
readonly traceId?: string;
|
|
2187
|
+
readonly scopeId?: string;
|
|
2188
|
+
readonly userId?: string;
|
|
2189
|
+
readonly jobId?: string;
|
|
2190
|
+
/** 内部采集/存储路径可暂停观察回调,常规日志输出仍执行。 */
|
|
2191
|
+
readonly suppressLogObservers?: boolean;
|
|
2192
|
+
}
|
|
2193
|
+
/**
|
|
2194
|
+
* 经过当前级别和脱敏策略的日志,不代表日志已持久化。
|
|
2195
|
+
* @example
|
|
2196
|
+
* ```ts
|
|
2197
|
+
* import type { LogRecord } from '@h-ai/core'
|
|
2198
|
+
* const record: LogRecord = { timestamp: 1, level: 'error', message: 'Request failed', context: { requestId: 'request-1' } }
|
|
2199
|
+
* ```
|
|
2200
|
+
*/
|
|
2201
|
+
interface LogRecord {
|
|
2202
|
+
readonly timestamp: number;
|
|
2203
|
+
readonly level: LogLevel;
|
|
2204
|
+
readonly message: string;
|
|
2205
|
+
readonly context: Readonly<LogContext>;
|
|
2206
|
+
}
|
|
2207
|
+
/**
|
|
2208
|
+
* 同步日志观察者;只做有界内存收集,I/O 由消费者异步处理。
|
|
2209
|
+
* @example
|
|
2210
|
+
* ```ts
|
|
2211
|
+
* import { core, type LogObserver } from '@h-ai/core'
|
|
2212
|
+
* const observer: LogObserver = record => { const requestId = record.context.requestId }
|
|
2213
|
+
* const unsubscribe = core.logger.observe(observer)
|
|
2214
|
+
* unsubscribe()
|
|
2215
|
+
* ```
|
|
2216
|
+
*/
|
|
2217
|
+
type LogObserver = (record: LogRecord) => void;
|
|
2218
|
+
/**
|
|
2219
|
+
* 日志选项。
|
|
2220
|
+
* @example
|
|
2221
|
+
* ```ts
|
|
2222
|
+
* import type { LoggerOptions } from '@h-ai/core'
|
|
2223
|
+
* const value: LoggerOptions = { name: 'orders', level: 'debug', context: { service: 'api' } }
|
|
2224
|
+
* ```
|
|
2225
|
+
*/
|
|
2226
|
+
interface LoggerOptions {
|
|
2227
|
+
name?: string;
|
|
2228
|
+
/** 显式级别保持不变;未指定时动态继承全局配置。 */
|
|
2229
|
+
level?: LogLevel;
|
|
2230
|
+
/** 显式格式保持不变;未指定时动态继承全局配置。 */
|
|
2231
|
+
format?: LogFormat;
|
|
2232
|
+
/** 固定上下文覆盖当前全局上下文,调用时上下文可进一步覆盖。 */
|
|
2233
|
+
context?: Record<string, unknown>;
|
|
2234
|
+
}
|
|
2235
|
+
/**
|
|
2236
|
+
* Logger 接口。
|
|
2237
|
+
* 统一的日志记录接口,具体实现由 Provider 提供。
|
|
2238
|
+
* @example
|
|
2239
|
+
* ```ts
|
|
2240
|
+
* import { core, type Logger } from '@h-ai/core'
|
|
2241
|
+
* const logger: Logger = core.logger.child({ service: 'orders' })
|
|
2242
|
+
* logger.info('Order created', { orderId: 'order-1' })
|
|
2243
|
+
* ```
|
|
2244
|
+
*/
|
|
2245
|
+
interface Logger {
|
|
2246
|
+
trace: (message: string, context?: LogContext) => void;
|
|
2247
|
+
debug: (message: string, context?: LogContext) => void;
|
|
2248
|
+
info: (message: string, context?: LogContext) => void;
|
|
2249
|
+
warn: (message: string, context?: LogContext) => void;
|
|
2250
|
+
error: (message: string, context?: LogContext) => void;
|
|
2251
|
+
fatal: (message: string, context?: LogContext) => void;
|
|
2252
|
+
child: (context: Record<string, unknown>) => Logger;
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* Core 公共 Logger — Logger 实例 + 管理方法。
|
|
2256
|
+
* @example
|
|
2257
|
+
* ```ts
|
|
2258
|
+
* import { core, type CoreLogger } from '@h-ai/core'
|
|
2259
|
+
* const logger: CoreLogger = core.logger
|
|
2260
|
+
* logger.configure({ level: 'warn', redact: ['password'] })
|
|
2261
|
+
* logger.child({ component: 'worker' }).warn('Retry scheduled')
|
|
2262
|
+
* ```
|
|
2263
|
+
*/
|
|
2264
|
+
interface CoreLogger extends Logger {
|
|
2265
|
+
/**
|
|
2266
|
+
* 观察通过日志级别与脱敏策略的记录,返回取消函数;异常与同步重入被隔离。
|
|
2267
|
+
* @example
|
|
2268
|
+
* ```ts
|
|
2269
|
+
* import { core } from '@h-ai/core'
|
|
2270
|
+
* const records: string[] = []
|
|
2271
|
+
* const unsubscribe = core.logger.observe(record => { records.push(record.message) })
|
|
2272
|
+
* core.logger.info('Application ready')
|
|
2273
|
+
* unsubscribe()
|
|
2274
|
+
* ```
|
|
2275
|
+
*/
|
|
2276
|
+
observe: (observer: LogObserver) => () => void;
|
|
2277
|
+
/** 创建新的 Logger 实例 */
|
|
2278
|
+
create: (options?: LoggerOptions) => Logger;
|
|
2279
|
+
/** 配置全局 Logger 选项,后续输出同时应用到已有默认、模块与 child Logger。 */
|
|
2280
|
+
configure: (config: Partial<LoggingConfig>) => void;
|
|
2281
|
+
/** 设置全局日志级别 */
|
|
2282
|
+
setLevel: (level: LogLevel) => void;
|
|
2283
|
+
/** 获取当前全局日志级别 */
|
|
2284
|
+
getLevel: () => LogLevel;
|
|
2285
|
+
}
|
|
2286
|
+
/**
|
|
2287
|
+
* Logger 函数组合(平台实现依赖)。
|
|
2288
|
+
*
|
|
2289
|
+
* 由各平台(Node.js / Browser)提供具体实现,通过 `createCore()` 注入。
|
|
2290
|
+
* @example
|
|
2291
|
+
* ```ts
|
|
2292
|
+
* import { core, type LoggerFunctions } from '@h-ai/core'
|
|
2293
|
+
* const platform: LoggerFunctions = { createLogger: options => core.logger.create(options), getLogger: name => core.logger.create({ name }), configureLogger: config => core.logger.configure(config), setLogLevel: level => core.logger.setLevel(level), getLogLevel: () => core.logger.getLevel() }
|
|
2294
|
+
* platform.createLogger({ name: 'worker' }).info('Worker ready')
|
|
2295
|
+
* ```
|
|
2296
|
+
*/
|
|
2297
|
+
interface LoggerFunctions {
|
|
2298
|
+
/** 创建新的 Logger 实例 */
|
|
2299
|
+
createLogger: (options?: LoggerOptions) => Logger;
|
|
2300
|
+
/** 获取默认或命名 Logger 实例(单例) */
|
|
2301
|
+
getLogger: (name?: string) => Logger;
|
|
2302
|
+
/** 配置全局 Logger 选项(级别、格式、上下文等) */
|
|
2303
|
+
configureLogger: (config: Partial<LoggingConfig>) => void;
|
|
2304
|
+
/** 设置全局日志级别 */
|
|
2305
|
+
setLogLevel: (level: LogLevel) => void;
|
|
2306
|
+
/** 获取当前全局日志级别 */
|
|
2307
|
+
getLogLevel: () => LogLevel;
|
|
2308
|
+
}
|
|
2309
|
+
/**
|
|
2310
|
+
* Core 配置选项。
|
|
2311
|
+
* @example
|
|
2312
|
+
* ```ts
|
|
2313
|
+
* import type { CoreOptions } from '@h-ai/core'
|
|
2314
|
+
* const value: CoreOptions = { configDir: './config', watchConfig: false }
|
|
2315
|
+
* ```
|
|
2316
|
+
*/
|
|
2317
|
+
interface CoreOptions {
|
|
2318
|
+
/** 日志配置 */
|
|
2319
|
+
logging?: Partial<LoggingConfig>;
|
|
2320
|
+
/**
|
|
2321
|
+
* 配置目录(约定优于配置模式)
|
|
2322
|
+
*
|
|
2323
|
+
* 指定后会自动扫描目录中的 yml/yaml 文件:
|
|
2324
|
+
* - `_core.yml` → 自动使用 CoreConfigSchema 校验
|
|
2325
|
+
* - `_xx.yml` → 加载为 'xx'(各模块自行调用 `config.validate` 校验)
|
|
2326
|
+
* - `app.yml` → 加载为 'app'(需使用方自行校验)
|
|
2327
|
+
* 项目构建和部署配置位于根目录 hai.json,不参与运行时 YAML 扫描。
|
|
2328
|
+
*
|
|
2329
|
+
* 单项加载返回失败时记日志并继续;必需配置须检查 `config.validate` 的 success。
|
|
2330
|
+
* 目录扫描等文件系统异常仍可能向调用方传播。
|
|
2331
|
+
*
|
|
2332
|
+
* @example
|
|
2333
|
+
* ```ts
|
|
2334
|
+
* core.init({ configDir: './config' })
|
|
2335
|
+
* ```
|
|
2336
|
+
*/
|
|
2337
|
+
configDir?: string;
|
|
2338
|
+
/** 宿主显式提供模块 Schema,供扫描时识别可选字段和环境变量类型;Core 不注册业务模块。 */
|
|
2339
|
+
configSchemas?: Readonly<Record<string, z.ZodType>>;
|
|
2340
|
+
/** 是否启用配置文件监听(默认 false) */
|
|
2341
|
+
watchConfig?: boolean;
|
|
2342
|
+
}
|
|
2343
|
+
/**
|
|
2344
|
+
* 语言代码(ISO 639-1 + 地区代码)。
|
|
2345
|
+
* @example
|
|
2346
|
+
* ```ts
|
|
2347
|
+
* import type { Locale } from '@h-ai/core'
|
|
2348
|
+
* const value: Locale = 'en-US'
|
|
2349
|
+
* ```
|
|
2350
|
+
*/
|
|
2351
|
+
type Locale = string;
|
|
2352
|
+
/**
|
|
2353
|
+
* 语言信息。
|
|
2354
|
+
* @example
|
|
2355
|
+
* ```ts
|
|
2356
|
+
* import type { LocaleInfo } from '@h-ai/core'
|
|
2357
|
+
* const value: LocaleInfo = { code: 'en-US', label: 'English' }
|
|
2358
|
+
* ```
|
|
2359
|
+
*/
|
|
2360
|
+
interface LocaleInfo {
|
|
2361
|
+
/** 语言代码(如 'zh-CN'、'en-US') */
|
|
2362
|
+
code: Locale;
|
|
2363
|
+
/** 显示名称(如 '简体中文'、'English') */
|
|
2364
|
+
label: string;
|
|
2365
|
+
/** 是否为从右到左书写的语言(如阿拉伯语),默认 false */
|
|
2366
|
+
rtl?: boolean;
|
|
2367
|
+
}
|
|
2368
|
+
/**
|
|
2369
|
+
* 插值参数类型。
|
|
2370
|
+
*
|
|
2371
|
+
* 用于 i18n 消息模板中的 `{key}` 占位符替换。
|
|
2372
|
+
* @example
|
|
2373
|
+
* ```ts
|
|
2374
|
+
* import type { InterpolationParams } from '@h-ai/core'
|
|
2375
|
+
* const value: InterpolationParams = { name: 'Alice', count: 2 }
|
|
2376
|
+
* ```
|
|
2377
|
+
*/
|
|
2378
|
+
type InterpolationParams = Record<string, string | number | boolean>;
|
|
2379
|
+
/**
|
|
2380
|
+
* 消息字典类型(单语言的 key-value 映射)。
|
|
2381
|
+
* @example
|
|
2382
|
+
* ```ts
|
|
2383
|
+
* import type { MessageDictionary } from '@h-ai/core'
|
|
2384
|
+
* const value: MessageDictionary = { greeting: 'Hello, {name}!' }
|
|
2385
|
+
* ```
|
|
2386
|
+
*/
|
|
2387
|
+
type MessageDictionary = Record<string, string>;
|
|
2388
|
+
/**
|
|
2389
|
+
* 多语言消息集合。
|
|
2390
|
+
*
|
|
2391
|
+
* 以 locale 为键,每个 locale 下包含该语言的所有消息 key-value。
|
|
2392
|
+
*
|
|
2393
|
+
* @template K - 消息 key 的联合类型
|
|
2394
|
+
* @example
|
|
2395
|
+
* ```ts
|
|
2396
|
+
* import { core, type LocaleMessages } from '@h-ai/core'
|
|
2397
|
+
* const messages: LocaleMessages<'hello'> = { 'en-US': { hello: 'Hello, {name}!' }, 'zh-CN': { hello: '你好,{name}!' } }
|
|
2398
|
+
* const message = core.i18n.createMessageGetter(messages)
|
|
2399
|
+
* message('hello', { locale: 'en-US', params: { name: 'Alice' } })
|
|
2400
|
+
* ```
|
|
2401
|
+
*/
|
|
2402
|
+
type LocaleMessages<K extends string = string> = Record<Locale, Record<K, string>>;
|
|
2403
|
+
/**
|
|
2404
|
+
* 消息获取选项。
|
|
2405
|
+
* @example
|
|
2406
|
+
* ```ts
|
|
2407
|
+
* import type { MessageOptions } from '@h-ai/core'
|
|
2408
|
+
* const value: MessageOptions = { locale: 'en-US', params: { name: 'Alice' } }
|
|
2409
|
+
* ```
|
|
2410
|
+
*/
|
|
2411
|
+
interface MessageOptions {
|
|
2412
|
+
/** 指定 locale(不传时依次读取 Node 请求上下文、应用默认语言) */
|
|
2413
|
+
locale?: Locale;
|
|
2414
|
+
/** 插值参数 */
|
|
2415
|
+
params?: InterpolationParams;
|
|
2416
|
+
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Core 服务聚合接口(createCore 返回类型)
|
|
2419
|
+
* @example
|
|
2420
|
+
* ```ts
|
|
2421
|
+
* import { core, type CoreFunctions } from '@h-ai/core'
|
|
2422
|
+
* function createRequestId(tools: CoreFunctions): string { return tools.id.request() }
|
|
2423
|
+
* const requestId = createRequestId(core)
|
|
2424
|
+
* ```
|
|
2425
|
+
*/
|
|
2426
|
+
interface CoreFunctions {
|
|
2427
|
+
/**
|
|
2428
|
+
* Node 中跨 await 隔离请求关联,浏览器仅同步作用域;不向下游注入任何凭据。
|
|
2429
|
+
* @example
|
|
2430
|
+
* ```ts
|
|
2431
|
+
* import { core } from '@h-ai/core'
|
|
2432
|
+
* await core.context.run({ requestId: 'request-1' }, async () => {
|
|
2433
|
+
* await Promise.resolve()
|
|
2434
|
+
* core.logger.info('Work completed')
|
|
2435
|
+
* })
|
|
2436
|
+
* const outside = core.context.get()
|
|
2437
|
+
* ```
|
|
2438
|
+
*/
|
|
2439
|
+
readonly context: {
|
|
2440
|
+
readonly get: () => Readonly<RequestContext>;
|
|
2441
|
+
readonly run: <T>(context: RequestContext, operation: () => T) => T;
|
|
2442
|
+
};
|
|
2443
|
+
/** 默认 Logger(懒加载单例),同时提供日志管理方法 */
|
|
2444
|
+
readonly logger: CoreLogger;
|
|
2445
|
+
/** 国际化工具 */
|
|
2446
|
+
readonly i18n: I18nFn;
|
|
2447
|
+
/** Zod 校验错误 → i18n 消息映射工具(kit / serv / api-client 共享) */
|
|
2448
|
+
readonly zodValidation: typeof zodValidation;
|
|
2449
|
+
/** ID 生成工具 */
|
|
2450
|
+
readonly id: IdFn;
|
|
2451
|
+
/** 类型检查工具 */
|
|
2452
|
+
readonly typeUtils: TypeUtilFn;
|
|
2453
|
+
/** 对象操作工具 */
|
|
2454
|
+
readonly object: ObjectFn;
|
|
2455
|
+
/** 脱敏工具 */
|
|
2456
|
+
readonly sanitize: SanitizeFn;
|
|
2457
|
+
/** 字符串操作工具 */
|
|
2458
|
+
readonly string: StringFn;
|
|
2459
|
+
/** 数组操作工具 */
|
|
2460
|
+
readonly array: ArrayFn;
|
|
2461
|
+
/** 异步操作工具 */
|
|
2462
|
+
readonly async: AsyncFn;
|
|
2463
|
+
/** 时间操作工具 */
|
|
2464
|
+
readonly time: TimeFn;
|
|
2465
|
+
/** 错误工具 */
|
|
2466
|
+
readonly error: ErrorFn;
|
|
2467
|
+
/** 模块基础工具 */
|
|
2468
|
+
readonly module: ModuleFn;
|
|
2469
|
+
}
|
|
2470
|
+
/**
|
|
2471
|
+
* Node 专属访问工具,通过 core.access 调用;浏览器不提供该能力。
|
|
2472
|
+
* @example
|
|
2473
|
+
* ```ts
|
|
2474
|
+
* import { core, type AccessFunctions } from '@h-ai/core'
|
|
2475
|
+
* const tools: AccessFunctions = core.access
|
|
2476
|
+
* const check = tools.createRequestCheck(false)
|
|
2477
|
+
* const decision = check('/api/v1/sync', 'POST', '192.0.2.10')
|
|
2478
|
+
* ```
|
|
2479
|
+
*/
|
|
2480
|
+
interface AccessFunctions {
|
|
2481
|
+
/** 规范化可信宿主地址;非法 IP 返回 undefined。 */
|
|
2482
|
+
normalizeClientIp: (value?: string) => string | undefined;
|
|
2483
|
+
/** 启动编译可信代理;第二参数必须来自 socket 或受信平台。auto 只在受管私有代理部署生效。 */
|
|
2484
|
+
createClientIpResolver: (trustedProxies?: TrustedProxies | readonly string[]) => (request: Request, remoteAddress?: string) => string | undefined;
|
|
2485
|
+
/** 编译共享的 IP/时间条件,供登录许可和其他可信服务端流程使用。 */
|
|
2486
|
+
createConditionCheck: (condition: AccessCondition) => (ip?: string) => AccessDecision;
|
|
2487
|
+
/** 启动读取和编译请求策略;检查期间无文件 I/O、CIDR 解析或全规则扫描。 */
|
|
2488
|
+
createRequestCheck: (input?: RequestAccessConfigInput) => RequestAccessCheck;
|
|
2489
|
+
/** 启动读取最大 1 MiB 的 YAML;相对路径按服务工作目录或显式目录解析,配置失败抛出安全错误。 */
|
|
2490
|
+
loadPolicy: (input?: RequestAccessConfigInput, baseDirectory?: string) => RequestAccessPolicy | false;
|
|
2491
|
+
}
|
|
2492
|
+
/**
|
|
2493
|
+
* Node 入口的完整 Core 形态;访问检查和文件配置不属于浏览器运行时。
|
|
2494
|
+
* @example
|
|
2495
|
+
* ```ts
|
|
2496
|
+
* import { core, type NodeCoreFunctions } from '@h-ai/core'
|
|
2497
|
+
* const tools: NodeCoreFunctions = core
|
|
2498
|
+
* tools.init({ logging: { level: 'info' } })
|
|
2499
|
+
* ```
|
|
2500
|
+
*/
|
|
2501
|
+
interface NodeCoreFunctions extends CoreFunctions {
|
|
2502
|
+
readonly access: AccessFunctions;
|
|
2503
|
+
readonly config: ConfigFn;
|
|
2504
|
+
readonly init: (options?: CoreOptions) => void;
|
|
2505
|
+
}
|
|
2506
|
+
/**
|
|
2507
|
+
* 浏览器 Core 形态;文件配置方法明确返回不可用,不包含 Node 的 access 能力。
|
|
2508
|
+
* @example
|
|
2509
|
+
* ```ts
|
|
2510
|
+
* import type { BrowserCoreFunctions } from '@h-ai/core'
|
|
2511
|
+
* function nextId(tools: BrowserCoreFunctions) { return tools.id.request() }
|
|
2512
|
+
* ```
|
|
2513
|
+
*/
|
|
2514
|
+
interface BrowserCoreFunctions extends CoreFunctions {
|
|
2515
|
+
readonly config: BrowserConfigFn;
|
|
2516
|
+
readonly init: (options?: CoreOptions) => void;
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* 运行环境标识;不会自行设置进程环境或初始化模块。
|
|
2520
|
+
* @example
|
|
2521
|
+
* ```ts
|
|
2522
|
+
* import type { Env } from '@h-ai/core'
|
|
2523
|
+
* const value: Env = 'production'
|
|
2524
|
+
* ```
|
|
2525
|
+
*/
|
|
2526
|
+
type Env = z.infer<typeof EnvSchema>;
|
|
2527
|
+
/**
|
|
2528
|
+
* 日志输出级别;未显式配置的 Logger 动态继承全局级别。
|
|
2529
|
+
* @example
|
|
2530
|
+
* ```ts
|
|
2531
|
+
* import type { LogLevel } from '@h-ai/core'
|
|
2532
|
+
* const value: LogLevel = 'warn'
|
|
2533
|
+
* ```
|
|
2534
|
+
*/
|
|
2535
|
+
type LogLevel = z.infer<typeof LogLevelSchema>;
|
|
2536
|
+
/**
|
|
2537
|
+
* 日志输出格式:JSON 或适合终端阅读的 pretty。
|
|
2538
|
+
* @example
|
|
2539
|
+
* ```ts
|
|
2540
|
+
* import type { LogFormat } from '@h-ai/core'
|
|
2541
|
+
* const value: LogFormat = 'json'
|
|
2542
|
+
* ```
|
|
2543
|
+
*/
|
|
2544
|
+
type LogFormat = z.infer<typeof LogFormatSchema>;
|
|
2545
|
+
/**
|
|
2546
|
+
* 经过默认值填充的 Logger 配置;redact 是输出脱敏路径。
|
|
2547
|
+
* @example
|
|
2548
|
+
* ```ts
|
|
2549
|
+
* import { LoggingConfigSchema, type LoggingConfig } from '@h-ai/core'
|
|
2550
|
+
* const config: LoggingConfig = LoggingConfigSchema.parse({})
|
|
2551
|
+
* ```
|
|
2552
|
+
*/
|
|
2553
|
+
type LoggingConfig = z.infer<typeof LoggingConfigSchema>;
|
|
2554
|
+
/**
|
|
2555
|
+
* 严格校验后的 Core 配置;业务配置使用独立 Schema。
|
|
2556
|
+
* @example
|
|
2557
|
+
* ```ts
|
|
2558
|
+
* import { CoreConfigSchema, type CoreConfig } from '@h-ai/core'
|
|
2559
|
+
* const config: CoreConfig = CoreConfigSchema.parse({})
|
|
2560
|
+
* ```
|
|
2561
|
+
*/
|
|
2562
|
+
type CoreConfig = z.infer<typeof CoreConfigSchema>;
|
|
2563
|
+
/**
|
|
2564
|
+
* 可信代理配置;空数组显式忽略全部转发头。
|
|
2565
|
+
* @example
|
|
2566
|
+
* ```ts
|
|
2567
|
+
* import type { TrustedProxies } from '@h-ai/core'
|
|
2568
|
+
* const proxies: TrustedProxies = []
|
|
2569
|
+
* ```
|
|
2570
|
+
*/
|
|
2571
|
+
type TrustedProxies = z.infer<typeof TrustedProxiesSchema>;
|
|
2572
|
+
/**
|
|
2573
|
+
* 已补齐默认值的 IP/时间条件。
|
|
2574
|
+
* @example
|
|
2575
|
+
* ```ts
|
|
2576
|
+
* import { AccessConditionSchema, type AccessCondition } from '@h-ai/core'
|
|
2577
|
+
* const condition: AccessCondition = AccessConditionSchema.parse({})
|
|
2578
|
+
* ```
|
|
2579
|
+
*/
|
|
2580
|
+
type AccessCondition = z.infer<typeof AccessConditionSchema>;
|
|
2581
|
+
/**
|
|
2582
|
+
* 已验证的请求策略。
|
|
2583
|
+
* @example
|
|
2584
|
+
* ```ts
|
|
2585
|
+
* import { RequestAccessPolicySchema, type RequestAccessPolicy } from '@h-ai/core'
|
|
2586
|
+
* const policy: RequestAccessPolicy = RequestAccessPolicySchema.parse({ rules: [] })
|
|
2587
|
+
* ```
|
|
2588
|
+
*/
|
|
2589
|
+
type RequestAccessPolicy = z.infer<typeof RequestAccessPolicySchema>;
|
|
2590
|
+
/**
|
|
2591
|
+
* 请求访问策略的输入;默认关闭由宿主配置决定。
|
|
2592
|
+
* @example
|
|
2593
|
+
* ```ts
|
|
2594
|
+
* import type { RequestAccessConfigInput } from '@h-ai/core'
|
|
2595
|
+
* const input: RequestAccessConfigInput = { rules: [{ id: 'external', paths: ['/api/v1/external/**'], allowIps: ['192.0.2.10'] }] }
|
|
2596
|
+
* ```
|
|
2597
|
+
*/
|
|
2598
|
+
type RequestAccessConfigInput = z.input<typeof RequestAccessConfigSchema>;
|
|
2599
|
+
/**
|
|
2600
|
+
* 路径的应用层加解密要求;不改变 TLS、身份鉴别或访问条件。
|
|
2601
|
+
* @example
|
|
2602
|
+
* ```ts
|
|
2603
|
+
* import type { RequestEncryptionMode } from '@h-ai/core'
|
|
2604
|
+
* const mode: RequestEncryptionMode = 'disabled'
|
|
2605
|
+
* ```
|
|
2606
|
+
*/
|
|
2607
|
+
type RequestEncryptionMode = NonNullable<RequestAccessPolicy['rules'][number]['encryption']>;
|
|
2608
|
+
/**
|
|
2609
|
+
* 启动编译后的请求检查器;加密选择只查路径索引,不重新计算 IP 或时间条件。
|
|
2610
|
+
* @example
|
|
2611
|
+
* ```ts
|
|
2612
|
+
* import { core, type RequestAccessCheck } from '@h-ai/core'
|
|
2613
|
+
* const check: RequestAccessCheck = core.access.createRequestCheck({ rules: [{ id: 'partner', paths: ['/api/v1/partner/**'], encryption: 'disabled' }] })
|
|
2614
|
+
* const mode = check.encryption('/api/v1/partner/sync', 'POST')
|
|
2615
|
+
* const decision = check('/api/v1/partner/sync', 'POST', '192.0.2.10')
|
|
2616
|
+
* ```
|
|
2617
|
+
*/
|
|
2618
|
+
interface RequestAccessCheck {
|
|
2619
|
+
(pathname: string, method: string, ip?: string): AccessDecision;
|
|
2620
|
+
/** 是否存在强制加密的规则;宿主未装配加密时必须拒绝启动。 */
|
|
2621
|
+
readonly requiresEncryption: boolean;
|
|
2622
|
+
/** 选取路径及方法对应的模式;undefined 表示沿用宿主;无请求期 I/O 或全规则扫描。 */
|
|
2623
|
+
readonly encryption: (pathname: string, method: string) => RequestEncryptionMode | undefined;
|
|
2624
|
+
}
|
|
2625
|
+
/**
|
|
2626
|
+
* 安全判断只携带原因类别及规则编号,不向调用方复制策略内容。
|
|
2627
|
+
* @example
|
|
2628
|
+
* ```ts
|
|
2629
|
+
* import type { AccessDecision } from '@h-ai/core'
|
|
2630
|
+
* const decision: AccessDecision = { allowed: false, reason: 'address', ruleId: 'external' }
|
|
2631
|
+
* ```
|
|
2632
|
+
*/
|
|
2633
|
+
type AccessDecision = Readonly<{
|
|
2634
|
+
allowed: true;
|
|
2635
|
+
} | {
|
|
2636
|
+
allowed: false;
|
|
2637
|
+
reason: 'address' | 'time' | 'path';
|
|
2638
|
+
ruleId?: string;
|
|
2639
|
+
}>;
|
|
2640
|
+
/**
|
|
2641
|
+
* id 子工具类型
|
|
2642
|
+
* @example
|
|
2643
|
+
* ```ts
|
|
2644
|
+
* import { core, type IdFn } from '@h-ai/core'
|
|
2645
|
+
* const tools: IdFn = core.id
|
|
2646
|
+
* tools.withPrefix('order_')
|
|
2647
|
+
* ```
|
|
2648
|
+
*/
|
|
2649
|
+
type IdFn = typeof id;
|
|
2650
|
+
/**
|
|
2651
|
+
* error 子工具类型
|
|
2652
|
+
* @example 模块内部上下文
|
|
2653
|
+
* ```ts
|
|
2654
|
+
* const tools: ErrorFn = error
|
|
2655
|
+
* tools.buildHaiErrorsDef('orders', { NOT_FOUND: '001:404' })
|
|
2656
|
+
* ```
|
|
2657
|
+
*/
|
|
2658
|
+
type ErrorFn = typeof error;
|
|
2659
|
+
/**
|
|
2660
|
+
* 监听回调类型。
|
|
2661
|
+
*
|
|
2662
|
+
* @template T - 配置数据类型
|
|
2663
|
+
* @example 模块内部上下文
|
|
2664
|
+
* ```ts
|
|
2665
|
+
* const callback: WatchCallback<{ enabled: boolean }> = (config, failure) => {
|
|
2666
|
+
* if (failure) { messages.push(failure.message); return }
|
|
2667
|
+
* if (config) messages.push(String(config.enabled))
|
|
2668
|
+
* }
|
|
2669
|
+
* const messages: string[] = []
|
|
2670
|
+
* ```
|
|
2671
|
+
*/
|
|
2672
|
+
type WatchCallback<T = unknown> = (config: T | null, error?: HaiError) => void;
|
|
2673
|
+
/**
|
|
2674
|
+
* config 子工具类型
|
|
2675
|
+
* @example
|
|
2676
|
+
* ```ts
|
|
2677
|
+
* import { core, type ConfigFn } from '@h-ai/core'
|
|
2678
|
+
* const result = core.config.load('app', '/srv/app/config/app.yml')
|
|
2679
|
+
* if (!result.success) result.error.message
|
|
2680
|
+
* ```
|
|
2681
|
+
*/
|
|
2682
|
+
type ConfigFn = typeof config;
|
|
2683
|
+
/**
|
|
2684
|
+
* config 子工具类型
|
|
2685
|
+
* @example
|
|
2686
|
+
* ```ts
|
|
2687
|
+
* import { core, type BrowserConfigFn } from '@h-ai/core'
|
|
2688
|
+
* const result = core.config.load('app', '/srv/app/config/app.yml')
|
|
2689
|
+
* if (!result.success) result.error.message
|
|
2690
|
+
* ```
|
|
2691
|
+
*/
|
|
2692
|
+
type BrowserConfigFn = typeof config$1;
|
|
2693
|
+
/**
|
|
2694
|
+
* i18n 子工具类型
|
|
2695
|
+
* @example
|
|
2696
|
+
* ```ts
|
|
2697
|
+
* import { core, type I18nFn } from '@h-ai/core'
|
|
2698
|
+
* const tools: I18nFn = core.i18n
|
|
2699
|
+
* const message = tools.createMessageGetter({ 'en-US': { hello: 'Hello' }, 'zh-CN': { hello: '你好' } })
|
|
2700
|
+
* message('hello', { locale: 'en-US' })
|
|
2701
|
+
* ```
|
|
2702
|
+
*/
|
|
2703
|
+
type I18nFn = typeof i18n;
|
|
2704
|
+
/**
|
|
2705
|
+
* array 子工具类型
|
|
2706
|
+
* @example
|
|
2707
|
+
* ```ts
|
|
2708
|
+
* import { core, type ArrayFn } from '@h-ai/core'
|
|
2709
|
+
* const tools: ArrayFn = core.array
|
|
2710
|
+
* tools.chunk([1, 2, 3], 2)
|
|
2711
|
+
* ```
|
|
2712
|
+
*/
|
|
2713
|
+
type ArrayFn = typeof array;
|
|
2714
|
+
/**
|
|
2715
|
+
* async 子工具类型
|
|
2716
|
+
* @example
|
|
2717
|
+
* ```ts
|
|
2718
|
+
* import { core, type AsyncFn } from '@h-ai/core'
|
|
2719
|
+
* const tools: AsyncFn = core.async
|
|
2720
|
+
* await tools.retry(async () => 'ready', { maxRetries: 2 })
|
|
2721
|
+
* ```
|
|
2722
|
+
*/
|
|
2723
|
+
type AsyncFn = typeof async;
|
|
2724
|
+
/**
|
|
2725
|
+
* object 子工具类型
|
|
2726
|
+
* @example
|
|
2727
|
+
* ```ts
|
|
2728
|
+
* import { core, type ObjectFn } from '@h-ai/core'
|
|
2729
|
+
* const tools: ObjectFn = core.object
|
|
2730
|
+
* tools.pick({ id: 'order-1', password: 'example-only' }, ['id'])
|
|
2731
|
+
* ```
|
|
2732
|
+
*/
|
|
2733
|
+
type ObjectFn = typeof object;
|
|
2734
|
+
/**
|
|
2735
|
+
* string 子工具类型
|
|
2736
|
+
* @example
|
|
2737
|
+
* ```ts
|
|
2738
|
+
* import { core, type StringFn } from '@h-ai/core'
|
|
2739
|
+
* const tools: StringFn = core.string
|
|
2740
|
+
* tools.camelCase('order-created')
|
|
2741
|
+
* ```
|
|
2742
|
+
*/
|
|
2743
|
+
type StringFn = typeof string;
|
|
2744
|
+
/**
|
|
2745
|
+
* time 子工具类型
|
|
2746
|
+
* @example
|
|
2747
|
+
* ```ts
|
|
2748
|
+
* import { core, type TimeFn } from '@h-ai/core'
|
|
2749
|
+
* const tools: TimeFn = core.time
|
|
2750
|
+
* tools.addDays(new Date('2026-01-01T00:00:00Z'), 1)
|
|
2751
|
+
* ```
|
|
2752
|
+
*/
|
|
2753
|
+
type TimeFn = typeof time;
|
|
2754
|
+
/**
|
|
2755
|
+
* typeUtils 子工具类型
|
|
2756
|
+
* @example
|
|
2757
|
+
* ```ts
|
|
2758
|
+
* import { core, type TypeUtilFn } from '@h-ai/core'
|
|
2759
|
+
* const tools: TypeUtilFn = core.typeUtils
|
|
2760
|
+
* const value: unknown = 'order-1'
|
|
2761
|
+
* if (tools.isString(value)) value.toUpperCase()
|
|
2762
|
+
* ```
|
|
2763
|
+
*/
|
|
2764
|
+
type TypeUtilFn = typeof typeUtils;
|
|
2765
|
+
/**
|
|
2766
|
+
* 未初始化工具集返回类型。
|
|
2767
|
+
*
|
|
2768
|
+
* 提供错误创建、HaiResult 包装和 Proxy 代理等能力,
|
|
2769
|
+
* 用于模块未初始化时的安全回退。
|
|
2770
|
+
*
|
|
2771
|
+
* @template E - 模块错误类型(必须继承 HaiError)
|
|
2772
|
+
* @example
|
|
2773
|
+
* ```ts
|
|
2774
|
+
* import { core, type HaiError, type NotInitializedKit } from '@h-ai/core'
|
|
2775
|
+
* const state: NotInitializedKit<HaiError> = core.module.createNotInitializedKit({ code: 'app:orders:001', httpStatus: 503, system: 'app', module: 'orders' }, () => 'Orders unavailable')
|
|
2776
|
+
* const result = state.result<string>()
|
|
2777
|
+
* if (!result.success) result.error.message
|
|
2778
|
+
* ```
|
|
2779
|
+
*/
|
|
2780
|
+
interface NotInitializedKit<E extends HaiError> {
|
|
2781
|
+
/** 创建未初始化错误对象 */
|
|
2782
|
+
error: () => E;
|
|
2783
|
+
/** 创建包含未初始化错误的失败 HaiResult */
|
|
2784
|
+
result: <T>() => HaiResult<T>;
|
|
2785
|
+
/**
|
|
2786
|
+
* 创建 Proxy 代理,拦截所有方法调用并返回未初始化错误。
|
|
2787
|
+
*
|
|
2788
|
+
* @param mode - 'async'(默认)所有方法返回 `Promise<HaiResult>`;'sync' 所有方法返回 `HaiResult`
|
|
2789
|
+
*/
|
|
2790
|
+
proxy: <T>(mode?: 'async' | 'sync') => T;
|
|
2791
|
+
}
|
|
2792
|
+
/** module 子工具类型 */
|
|
2793
|
+
/**
|
|
2794
|
+
* 未初始化代理的两个重载:错误定义或具体错误码。
|
|
2795
|
+
* @example
|
|
2796
|
+
* ```ts
|
|
2797
|
+
* import { core, type CreateNotInitializedKitFn } from '@h-ai/core'
|
|
2798
|
+
* const create: CreateNotInitializedKitFn = core.module.createNotInitializedKit
|
|
2799
|
+
* const state = create({ code: 'app:orders:001', httpStatus: 503, system: 'app', module: 'orders' }, () => 'Orders unavailable')
|
|
2800
|
+
* const result = state.result<string>()
|
|
2801
|
+
* if (!result.success) result.error.code
|
|
2802
|
+
* ```
|
|
2803
|
+
*/
|
|
2804
|
+
interface CreateNotInitializedKitFn {
|
|
2805
|
+
(codeOrDef: HaiErrorDef, messageFn: () => string): NotInitializedKit<HaiError>;
|
|
2806
|
+
<E extends HaiError>(codeOrDef: E['code'], messageFn: () => string): NotInitializedKit<E>;
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* 模块初始化占位与生产共享状态要求的工具契约。
|
|
2810
|
+
* @example 模块内部上下文
|
|
2811
|
+
* ```ts
|
|
2812
|
+
* function createHostRuntime(tools: ModuleFn) { return tools.createRuntime([]) }
|
|
2813
|
+
* ```
|
|
2814
|
+
*/
|
|
2815
|
+
interface ModuleFn {
|
|
2816
|
+
/** 顺序启动和反序关闭真实模块;不持有业务配置。 */
|
|
2817
|
+
createRuntime: typeof createRuntime;
|
|
2818
|
+
createNotInitializedKit: CreateNotInitializedKitFn;
|
|
2819
|
+
/** 生产共享状态要求;浏览器工具为纯函数,不隐式读取进程环境。 */
|
|
2820
|
+
requiresSharedState: typeof requiresSharedState;
|
|
2821
|
+
}
|
|
2822
|
+
/**
|
|
2823
|
+
* 敏感字段匹配器
|
|
2824
|
+
* @example
|
|
2825
|
+
* ```ts
|
|
2826
|
+
* import { core, type SensitiveKeyMatcher } from '@h-ai/core'
|
|
2827
|
+
* const matcher: SensitiveKeyMatcher = ['password', 'credential']
|
|
2828
|
+
* const safe = core.sanitize.sanitizeSensitiveFields({ credential: 'example-only', id: 'order-1' }, { matcher })
|
|
2829
|
+
* ```
|
|
2830
|
+
*/
|
|
2831
|
+
type SensitiveKeyMatcher = RegExp | string[] | ((key: string) => boolean);
|
|
2832
|
+
/**
|
|
2833
|
+
* 敏感字段脱敏选项
|
|
2834
|
+
* @example
|
|
2835
|
+
* ```ts
|
|
2836
|
+
* import { core, type SanitizeSensitiveFieldsOptions } from '@h-ai/core'
|
|
2837
|
+
* const options: SanitizeSensitiveFieldsOptions = { matcher: ['credential'], replacement: '[HIDDEN]' }
|
|
2838
|
+
* const safe = core.sanitize.sanitizeSensitiveFields({ credential: 'example-only' }, options)
|
|
2839
|
+
* ```
|
|
2840
|
+
*/
|
|
2841
|
+
interface SanitizeSensitiveFieldsOptions {
|
|
2842
|
+
/** 自定义敏感字段匹配规则 */
|
|
2843
|
+
matcher?: SensitiveKeyMatcher;
|
|
2844
|
+
/** 自定义脱敏替换值 */
|
|
2845
|
+
replacement?: unknown;
|
|
2846
|
+
}
|
|
2847
|
+
/**
|
|
2848
|
+
* sanitize 子工具类型
|
|
2849
|
+
* @example
|
|
2850
|
+
* ```ts
|
|
2851
|
+
* import { core, type SanitizeFn } from '@h-ai/core'
|
|
2852
|
+
* const tools: SanitizeFn = core.sanitize
|
|
2853
|
+
* tools.sanitizeSensitiveFields({ apiKey: 'example-only', id: 'order-1' })
|
|
2854
|
+
* ```
|
|
2855
|
+
*/
|
|
2856
|
+
type SanitizeFn = typeof sanitize;
|
|
2857
|
+
/**
|
|
2858
|
+
* 单个真实模块或业务钩子的资源所有权;close 应可重试。
|
|
2859
|
+
* @example 模块内部上下文
|
|
2860
|
+
* ```ts
|
|
2861
|
+
* const step: RuntimeStep = { name: 'example', start: () => {}, close: () => {} }
|
|
2862
|
+
* ```
|
|
2863
|
+
*/
|
|
2864
|
+
interface RuntimeStep {
|
|
2865
|
+
name: string;
|
|
2866
|
+
enabled?: () => boolean;
|
|
2867
|
+
start: () => void | HaiResult<unknown> | Promise<void | HaiResult<unknown>>;
|
|
2868
|
+
close: () => void | HaiResult<unknown> | Promise<void | HaiResult<unknown>>;
|
|
2869
|
+
}
|
|
2870
|
+
/**
|
|
2871
|
+
* 初始化和关闭合并并发调用;失败关闭保留自身及尚未关闭的依赖,供下次重试。
|
|
2872
|
+
* @example
|
|
2873
|
+
* ```ts
|
|
2874
|
+
* import { core, type ModuleRuntime } from '@h-ai/core'
|
|
2875
|
+
* const runtime: ModuleRuntime = core.module.createRuntime([])
|
|
2876
|
+
* await runtime.close()
|
|
2877
|
+
* ```
|
|
2878
|
+
*/
|
|
2879
|
+
interface ModuleRuntime {
|
|
2880
|
+
readonly isInitialized: boolean;
|
|
2881
|
+
start: () => Promise<HaiResult<void>>;
|
|
2882
|
+
close: () => Promise<HaiResult<void>>;
|
|
2883
|
+
}
|
|
2884
|
+
|
|
2885
|
+
export { type PaginationOptionsInput as $, type AccessCondition as A, type BrowserCoreFunctions as B, type ConfigFn as C, LogFormatSchema as D, type Env as E, type LogLevel as F, LogLevelSchema as G, HaiCommonError as H, type I18nFn as I, type LogObserver as J, type LogRecord as K, type Locale as L, type Logger as M, type LoggerFunctions as N, type LoggerOptions as O, type LoggingConfig as P, LoggingConfigSchema as Q, type MatchHandlers as R, type MessageDictionary as S, type MessageOptions as T, type ModuleFn as U, type ModuleRuntime as V, type NodeCoreFunctions as W, type NotInitializedKit as X, type ObjectFn as Y, type PaginatedResult as Z, type PaginationOptions as _, AccessConditionSchema as a, type RequestAccessCheck as a0, type RequestAccessConfigInput as a1, RequestAccessConfigSchema as a2, type RequestAccessPolicy as a3, RequestAccessPolicySchema as a4, type RequestContext as a5, type RequestEncryptionMode as a6, type RuntimeStep as a7, type SanitizeFn as a8, type SanitizeSensitiveFieldsOptions as a9, type SensitiveKeyMatcher as aa, type StringFn as ab, type TimeFn as ac, type TrustedProxies as ad, TrustedProxiesSchema as ae, type TypeUtilFn as af, type ValidationFormError as ag, type WatchCallback as ah, type ZodMessageGetter as ai, type ZodValidationFn as aj, type ZodValidationMessageKey as ak, err as al, ok as am, type AccessDecision as b, type AccessFunctions as c, type ArrayFn as d, type AsyncFn as e, type BrowserConfigFn as f, type CoreConfig as g, CoreConfigSchema as h, type CoreFunctions as i, type CoreLogger as j, type CoreOptions as k, type CreateNotInitializedKitFn as l, EnvSchema as m, type ErrorFn as n, type ErrorInfo as o, type ErrorInfoValue as p, HaiConfigError as q, type HaiError as r, type HaiErrorDef as s, type HaiResult as t, type IdFn as u, type InterpolationParams as v, type LocaleInfo as w, type LocaleMessages as x, type LogContext as y, type LogFormat as z };
|