@h-ai/iam 0.1.0-alpha.66 → 0.1.0-alpha.68

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.
@@ -0,0 +1,2320 @@
1
+ import { z } from 'zod';
2
+ import * as _h_ai_core from '@h-ai/core';
3
+ import { HaiResult, PaginationOptionsInput, PaginatedResult } from '@h-ai/core';
4
+ import { ReachFunctions } from '@h-ai/reach';
5
+ import { DmlWithTxOperations } from '@h-ai/reldb';
6
+
7
+ /**
8
+ * @h-ai/iam — 配置 Schema
9
+ *
10
+ * 本文件定义 IAM 模块的配置结构,使用 Zod 进行运行时校验。
11
+ * @module iam-config
12
+ */
13
+
14
+ /**
15
+ * 认证策略类型
16
+ *
17
+ * 支持的认证方式:
18
+ * - `password` - 用户名/邮箱 + 密码
19
+ * - `otp` - 邮箱/短信 + 验证码
20
+ * - `ldap` - LDAP 目录认证
21
+ * - `apikey` - API Key 认证并按 scopes 收敛权限
22
+ * @example
23
+ * ```ts
24
+ * import { AuthStrategyTypeSchema } from '@h-ai/iam'
25
+ * const result = AuthStrategyTypeSchema.safeParse('password')
26
+ * if (result.success) {
27
+ * result.data // 输出已应用 Schema 默认值。
28
+ * }
29
+ * ```
30
+ */
31
+ declare const AuthStrategyTypeSchema: z.ZodEnum<{
32
+ password: "password";
33
+ otp: "otp";
34
+ ldap: "ldap";
35
+ apikey: "apikey";
36
+ }>;
37
+ /**
38
+ * 认证策略类型
39
+ * @example
40
+ * ```ts
41
+ * import { AuthStrategyTypeSchema, type AuthStrategyType } from '@h-ai/iam'
42
+ * const value: AuthStrategyType = AuthStrategyTypeSchema.parse('password')
43
+ * ```
44
+ */
45
+ type AuthStrategyType = z.infer<typeof AuthStrategyTypeSchema>;
46
+ /**
47
+ * 密码配置 Schema
48
+ * @example
49
+ * ```ts
50
+ * import { PasswordConfigSchema } from '@h-ai/iam'
51
+ * const result = PasswordConfigSchema.safeParse({ minLength: 12, requireSpecialChar: true })
52
+ * if (result.success) {
53
+ * result.data // 输出已应用 Schema 默认值。
54
+ * }
55
+ * ```
56
+ */
57
+ declare const PasswordConfigSchema: z.ZodObject<{
58
+ minLength: z.ZodDefault<z.ZodNumber>;
59
+ maxLength: z.ZodDefault<z.ZodNumber>;
60
+ requireUppercase: z.ZodDefault<z.ZodBoolean>;
61
+ requireLowercase: z.ZodDefault<z.ZodBoolean>;
62
+ requireNumber: z.ZodDefault<z.ZodBoolean>;
63
+ requireSpecialChar: z.ZodDefault<z.ZodBoolean>;
64
+ expirationDays: z.ZodDefault<z.ZodNumber>;
65
+ }, z.core.$strip>;
66
+ /**
67
+ * 密码配置类型
68
+ * @example
69
+ * ```ts
70
+ * import { PasswordConfigSchema, type PasswordConfig } from '@h-ai/iam'
71
+ * const value: PasswordConfig = PasswordConfigSchema.parse({ minLength: 12, requireSpecialChar: true })
72
+ * ```
73
+ */
74
+ type PasswordConfig = z.infer<typeof PasswordConfigSchema>;
75
+ /**
76
+ * OTP 配置 Schema
77
+ * @example
78
+ * ```ts
79
+ * import { OtpConfigSchema } from '@h-ai/iam'
80
+ * const result = OtpConfigSchema.safeParse({ email: true, sms: false, length: 6 })
81
+ * if (result.success) {
82
+ * result.data // 输出已应用 Schema 默认值。
83
+ * }
84
+ * ```
85
+ */
86
+ declare const OtpConfigSchema: z.ZodObject<{
87
+ email: z.ZodDefault<z.ZodBoolean>;
88
+ sms: z.ZodDefault<z.ZodBoolean>;
89
+ length: z.ZodDefault<z.ZodNumber>;
90
+ expiresIn: z.ZodDefault<z.ZodNumber>;
91
+ maxAttempts: z.ZodDefault<z.ZodNumber>;
92
+ resendInterval: z.ZodDefault<z.ZodNumber>;
93
+ }, z.core.$strip>;
94
+ /**
95
+ * OTP 配置类型
96
+ * @example
97
+ * ```ts
98
+ * import { OtpConfigSchema, type OtpConfig } from '@h-ai/iam'
99
+ * const value: OtpConfig = OtpConfigSchema.parse({ email: true, sms: false, length: 6 })
100
+ * ```
101
+ */
102
+ type OtpConfig = z.infer<typeof OtpConfigSchema>;
103
+ /**
104
+ * 密码重置配置 Schema
105
+ * @example
106
+ * ```ts
107
+ * import { PasswordResetConfigSchema } from '@h-ai/iam'
108
+ * const result = PasswordResetConfigSchema.safeParse({ enabled: true, mode: 'email', resetUrl: 'https://app.example.com/reset-password' })
109
+ * if (result.success) {
110
+ * result.data // 输出已应用 Schema 默认值。
111
+ * }
112
+ * ```
113
+ */
114
+ declare const PasswordResetConfigSchema: z.ZodObject<{
115
+ mode: z.ZodDefault<z.ZodEnum<{
116
+ email: "email";
117
+ phone: "phone";
118
+ }>>;
119
+ resetUrl: z.ZodOptional<z.ZodURL>;
120
+ enabled: z.ZodDefault<z.ZodBoolean>;
121
+ tokenExpiresIn: z.ZodDefault<z.ZodNumber>;
122
+ maxAttempts: z.ZodDefault<z.ZodNumber>;
123
+ }, z.core.$strip>;
124
+ /**
125
+ * 密码重置配置类型
126
+ * @example
127
+ * ```ts
128
+ * import { PasswordResetConfigSchema, type PasswordResetConfig } from '@h-ai/iam'
129
+ * const value: PasswordResetConfig = PasswordResetConfigSchema.parse({ enabled: true, mode: 'email', resetUrl: 'https://app.example.com/reset-password' })
130
+ * ```
131
+ */
132
+ type PasswordResetConfig = z.infer<typeof PasswordResetConfigSchema>;
133
+ /**
134
+ * LDAP 配置 Schema
135
+ * @example
136
+ * ```ts
137
+ * import { LdapConfigSchema } from '@h-ai/iam'
138
+ * const bindPassword = process.env.LDAP_BIND_PASSWORD
139
+ * if (bindPassword) {
140
+ * const result = LdapConfigSchema.safeParse({ url: 'ldaps://directory.example.com', bindDn: 'cn=service,dc=example,dc=com', bindPassword: bindPassword, searchBase: 'ou=users,dc=example,dc=com' })
141
+ * if (result.success)
142
+ * result.data.searchBase
143
+ * }
144
+ * ```
145
+ */
146
+ declare const LdapConfigSchema: z.ZodObject<{
147
+ url: z.ZodURL;
148
+ bindDn: z.ZodString;
149
+ bindPassword: z.ZodString;
150
+ searchBase: z.ZodString;
151
+ searchFilter: z.ZodDefault<z.ZodString>;
152
+ usernameAttribute: z.ZodDefault<z.ZodString>;
153
+ emailAttribute: z.ZodDefault<z.ZodString>;
154
+ displayNameAttribute: z.ZodDefault<z.ZodString>;
155
+ useTls: z.ZodDefault<z.ZodBoolean>;
156
+ connectTimeout: z.ZodDefault<z.ZodNumber>;
157
+ }, z.core.$strip>;
158
+ /**
159
+ * LDAP 配置类型
160
+ * @example
161
+ * ```ts
162
+ * import { LdapConfigSchema, type LdapConfig } from '@h-ai/iam'
163
+ * const bindPassword = process.env.LDAP_BIND_PASSWORD
164
+ * if (bindPassword) {
165
+ * const value: LdapConfig = LdapConfigSchema.parse({ url: 'ldaps://directory.example.com', bindDn: 'cn=service,dc=example,dc=com', bindPassword: bindPassword, searchBase: 'ou=users,dc=example,dc=com' })
166
+ * value.url
167
+ * }
168
+ * ```
169
+ */
170
+ type LdapConfig = z.infer<typeof LdapConfigSchema>;
171
+ /**
172
+ * API Key 配置 Schema
173
+ * @example
174
+ * ```ts
175
+ * import { ApiKeyConfigSchema } from '@h-ai/iam'
176
+ * const result = ApiKeyConfigSchema.safeParse({ maxKeysPerUser: 5, defaultExpirationDays: 30 })
177
+ * if (result.success) {
178
+ * result.data // 输出已应用 Schema 默认值。
179
+ * }
180
+ * ```
181
+ */
182
+ declare const ApiKeyConfigSchema: z.ZodObject<{
183
+ maxKeysPerUser: z.ZodDefault<z.ZodNumber>;
184
+ defaultExpirationDays: z.ZodDefault<z.ZodNumber>;
185
+ prefix: z.ZodDefault<z.ZodString>;
186
+ }, z.core.$strip>;
187
+ /**
188
+ * API Key 配置类型
189
+ * @example
190
+ * ```ts
191
+ * import { ApiKeyConfigSchema, type ApiKeyConfig } from '@h-ai/iam'
192
+ * const value: ApiKeyConfig = ApiKeyConfigSchema.parse({ maxKeysPerUser: 5, defaultExpirationDays: 30 })
193
+ * ```
194
+ */
195
+ type ApiKeyConfig = z.infer<typeof ApiKeyConfigSchema>;
196
+ /**
197
+ * 登录类型启用配置
198
+ * @example
199
+ * ```ts
200
+ * import { LoginConfigSchema } from '@h-ai/iam'
201
+ * const result = LoginConfigSchema.safeParse({ password: true, otp: false })
202
+ * if (result.success) {
203
+ * result.data // 输出已应用 Schema 默认值。
204
+ * }
205
+ * ```
206
+ */
207
+ declare const LoginConfigSchema: z.ZodObject<{
208
+ password: z.ZodDefault<z.ZodBoolean>;
209
+ otp: z.ZodDefault<z.ZodBoolean>;
210
+ ldap: z.ZodDefault<z.ZodBoolean>;
211
+ apikey: z.ZodDefault<z.ZodBoolean>;
212
+ }, z.core.$strip>;
213
+ /**
214
+ * 登录方式开关配置。
215
+ * @example
216
+ * ```ts
217
+ * import { LoginConfigSchema, type LoginConfig } from '@h-ai/iam'
218
+ * const value: LoginConfig = LoginConfigSchema.parse({ password: true, otp: false })
219
+ * ```
220
+ */
221
+ type LoginConfig = z.infer<typeof LoginConfigSchema>;
222
+ /**
223
+ * 注册配置
224
+ * @example
225
+ * ```ts
226
+ * import { RegisterConfigSchema } from '@h-ai/iam'
227
+ * const result = RegisterConfigSchema.safeParse({ enabled: false })
228
+ * if (result.success) {
229
+ * result.data // 输出已应用 Schema 默认值。
230
+ * }
231
+ * ```
232
+ */
233
+ declare const RegisterConfigSchema: z.ZodObject<{
234
+ enabled: z.ZodDefault<z.ZodBoolean>;
235
+ defaultEnabled: z.ZodDefault<z.ZodBoolean>;
236
+ }, z.core.$strip>;
237
+ /**
238
+ * 注册开关及新用户默认状态。
239
+ * @example
240
+ * ```ts
241
+ * import { RegisterConfigSchema, type RegisterConfig } from '@h-ai/iam'
242
+ * const value: RegisterConfig = RegisterConfigSchema.parse({ enabled: false })
243
+ * ```
244
+ */
245
+ type RegisterConfig = z.infer<typeof RegisterConfigSchema>;
246
+ /**
247
+ * 安全策略配置
248
+ * @example
249
+ * ```ts
250
+ * import { SecurityConfigSchema } from '@h-ai/iam'
251
+ * const result = SecurityConfigSchema.safeParse({ maxLoginAttempts: 5, lockoutDuration: 900 })
252
+ * if (result.success) {
253
+ * result.data // 输出已应用 Schema 默认值。
254
+ * }
255
+ * ```
256
+ */
257
+ declare const SecurityConfigSchema: z.ZodObject<{
258
+ maxLoginAttempts: z.ZodDefault<z.ZodNumber>;
259
+ lockoutDuration: z.ZodDefault<z.ZodNumber>;
260
+ }, z.core.$strip>;
261
+ /**
262
+ * 服务端账户失败计数与锁定策略。
263
+ * @example
264
+ * ```ts
265
+ * import { SecurityConfigSchema, type SecurityConfig } from '@h-ai/iam'
266
+ * const value: SecurityConfig = SecurityConfigSchema.parse({ maxLoginAttempts: 5, lockoutDuration: 900 })
267
+ * ```
268
+ */
269
+ type SecurityConfig = z.infer<typeof SecurityConfigSchema>;
270
+ /**
271
+ * 协议展示配置
272
+ * @example
273
+ * ```ts
274
+ * import { AgreementConfigSchema } from '@h-ai/iam'
275
+ * const result = AgreementConfigSchema.safeParse({ userAgreementUrl: 'https://app.example.com/terms', showOnRegister: true })
276
+ * if (result.success) {
277
+ * result.data // 输出已应用 Schema 默认值。
278
+ * }
279
+ * ```
280
+ */
281
+ declare const AgreementConfigSchema: z.ZodObject<{
282
+ userAgreementMarkdown: z.ZodOptional<z.ZodString>;
283
+ privacyPolicyMarkdown: z.ZodOptional<z.ZodString>;
284
+ userAgreementUrl: z.ZodOptional<z.ZodURL>;
285
+ privacyPolicyUrl: z.ZodOptional<z.ZodURL>;
286
+ showOnRegister: z.ZodDefault<z.ZodBoolean>;
287
+ showOnLogin: z.ZodDefault<z.ZodBoolean>;
288
+ }, z.core.$strip>;
289
+ /**
290
+ * 登录和注册的协议展示设置。
291
+ * @example
292
+ * ```ts
293
+ * import { AgreementConfigSchema, type AgreementConfig } from '@h-ai/iam'
294
+ * const value: AgreementConfig = AgreementConfigSchema.parse({ userAgreementUrl: 'https://app.example.com/terms', showOnRegister: true })
295
+ * ```
296
+ */
297
+ type AgreementConfig = z.infer<typeof AgreementConfigSchema>;
298
+ /**
299
+ * 认证页面外观 Schema;图片仅接受 HTTP(S) 或站内路径,输出包含默认展示模式。
300
+ * @example
301
+ * ```ts
302
+ * import { AuthUiConfigSchema } from '@h-ai/iam'
303
+ * const result = AuthUiConfigSchema.safeParse({ variant: 'split', logoUrl: '/logo.svg' })
304
+ * if (result.success) {
305
+ * result.data // 输出已应用 Schema 默认值。
306
+ * }
307
+ * ```
308
+ */
309
+ declare const AuthUiConfigSchema: z.ZodObject<{
310
+ variant: z.ZodDefault<z.ZodEnum<{
311
+ card: "card";
312
+ split: "split";
313
+ }>>;
314
+ title: z.ZodOptional<z.ZodString>;
315
+ subtitle: z.ZodOptional<z.ZodString>;
316
+ brandTitle: z.ZodOptional<z.ZodString>;
317
+ brandText: z.ZodOptional<z.ZodString>;
318
+ logoUrl: z.ZodOptional<z.ZodString>;
319
+ illustrationUrl: z.ZodOptional<z.ZodString>;
320
+ }, z.core.$strip>;
321
+ /**
322
+ * 认证页外观设置;不包含服务端秘密。
323
+ * @example
324
+ * ```ts
325
+ * import { AuthUiConfigSchema, type AuthUiConfig } from '@h-ai/iam'
326
+ * const value: AuthUiConfig = AuthUiConfigSchema.parse({ variant: 'split', logoUrl: '/logo.svg' })
327
+ * ```
328
+ */
329
+ type AuthUiConfig = z.infer<typeof AuthUiConfigSchema>;
330
+ /**
331
+ * 会话配置 Schema
332
+ * @example
333
+ * ```ts
334
+ * import { SessionConfigSchema } from '@h-ai/iam'
335
+ * const result = SessionConfigSchema.safeParse({ maxAge: 3600, refreshTokenMaxAge: 604800 })
336
+ * if (result.success) {
337
+ * result.data // 输出已应用 Schema 默认值。
338
+ * }
339
+ * ```
340
+ */
341
+ declare const SessionConfigSchema: z.ZodObject<{
342
+ maxAge: z.ZodDefault<z.ZodNumber>;
343
+ sliding: z.ZodDefault<z.ZodBoolean>;
344
+ singleDevice: z.ZodDefault<z.ZodBoolean>;
345
+ refreshTokenMaxAge: z.ZodDefault<z.ZodNumber>;
346
+ }, z.core.$strip>;
347
+ /**
348
+ * 会话配置类型
349
+ * @example
350
+ * ```ts
351
+ * import { SessionConfigSchema, type SessionConfig } from '@h-ai/iam'
352
+ * const value: SessionConfig = SessionConfigSchema.parse({ maxAge: 3600, refreshTokenMaxAge: 604800 })
353
+ * ```
354
+ */
355
+ type SessionConfig = z.infer<typeof SessionConfigSchema>;
356
+ /**
357
+ * RBAC 配置 Schema
358
+ * @example
359
+ * ```ts
360
+ * import { RbacConfigSchema } from '@h-ai/iam'
361
+ * const result = RbacConfigSchema.safeParse({ enabled: true, defaultRole: 'user' })
362
+ * if (result.success) {
363
+ * result.data // 输出已应用 Schema 默认值。
364
+ * }
365
+ * ```
366
+ */
367
+ declare const RbacConfigSchema: z.ZodObject<{
368
+ enabled: z.ZodDefault<z.ZodBoolean>;
369
+ superAdminRole: z.ZodDefault<z.ZodString>;
370
+ defaultRole: z.ZodDefault<z.ZodString>;
371
+ }, z.core.$strip>;
372
+ /**
373
+ * RBAC 配置类型
374
+ * @example
375
+ * ```ts
376
+ * import { RbacConfigSchema, type RbacConfig } from '@h-ai/iam'
377
+ * const value: RbacConfig = RbacConfigSchema.parse({ enabled: true, defaultRole: 'user' })
378
+ * ```
379
+ */
380
+ type RbacConfig = z.infer<typeof RbacConfigSchema>;
381
+ /**
382
+ * IAM 统一配置 Schema
383
+ * @example
384
+ * ```ts
385
+ * import { IamConfigSchema } from '@h-ai/iam'
386
+ * const result = IamConfigSchema.safeParse({ seedDefaultData: false, session: { maxAge: 3600 } })
387
+ * if (result.success) {
388
+ * result.data // 输出已应用 Schema 默认值。
389
+ * }
390
+ * ```
391
+ */
392
+ declare const IamConfigSchema: z.ZodObject<{
393
+ ui: z.ZodOptional<z.ZodObject<{
394
+ variant: z.ZodDefault<z.ZodEnum<{
395
+ card: "card";
396
+ split: "split";
397
+ }>>;
398
+ title: z.ZodOptional<z.ZodString>;
399
+ subtitle: z.ZodOptional<z.ZodString>;
400
+ brandTitle: z.ZodOptional<z.ZodString>;
401
+ brandText: z.ZodOptional<z.ZodString>;
402
+ logoUrl: z.ZodOptional<z.ZodString>;
403
+ illustrationUrl: z.ZodOptional<z.ZodString>;
404
+ }, z.core.$strip>>;
405
+ password: z.ZodOptional<z.ZodObject<{
406
+ minLength: z.ZodDefault<z.ZodNumber>;
407
+ maxLength: z.ZodDefault<z.ZodNumber>;
408
+ requireUppercase: z.ZodDefault<z.ZodBoolean>;
409
+ requireLowercase: z.ZodDefault<z.ZodBoolean>;
410
+ requireNumber: z.ZodDefault<z.ZodBoolean>;
411
+ requireSpecialChar: z.ZodDefault<z.ZodBoolean>;
412
+ expirationDays: z.ZodDefault<z.ZodNumber>;
413
+ }, z.core.$strip>>;
414
+ otp: z.ZodOptional<z.ZodObject<{
415
+ email: z.ZodDefault<z.ZodBoolean>;
416
+ sms: z.ZodDefault<z.ZodBoolean>;
417
+ length: z.ZodDefault<z.ZodNumber>;
418
+ expiresIn: z.ZodDefault<z.ZodNumber>;
419
+ maxAttempts: z.ZodDefault<z.ZodNumber>;
420
+ resendInterval: z.ZodDefault<z.ZodNumber>;
421
+ }, z.core.$strip>>;
422
+ ldap: z.ZodOptional<z.ZodObject<{
423
+ url: z.ZodURL;
424
+ bindDn: z.ZodString;
425
+ bindPassword: z.ZodString;
426
+ searchBase: z.ZodString;
427
+ searchFilter: z.ZodDefault<z.ZodString>;
428
+ usernameAttribute: z.ZodDefault<z.ZodString>;
429
+ emailAttribute: z.ZodDefault<z.ZodString>;
430
+ displayNameAttribute: z.ZodDefault<z.ZodString>;
431
+ useTls: z.ZodDefault<z.ZodBoolean>;
432
+ connectTimeout: z.ZodDefault<z.ZodNumber>;
433
+ }, z.core.$strip>>;
434
+ apikey: z.ZodOptional<z.ZodObject<{
435
+ maxKeysPerUser: z.ZodDefault<z.ZodNumber>;
436
+ defaultExpirationDays: z.ZodDefault<z.ZodNumber>;
437
+ prefix: z.ZodDefault<z.ZodString>;
438
+ }, z.core.$strip>>;
439
+ passwordReset: z.ZodOptional<z.ZodObject<{
440
+ mode: z.ZodDefault<z.ZodEnum<{
441
+ email: "email";
442
+ phone: "phone";
443
+ }>>;
444
+ resetUrl: z.ZodOptional<z.ZodURL>;
445
+ enabled: z.ZodDefault<z.ZodBoolean>;
446
+ tokenExpiresIn: z.ZodDefault<z.ZodNumber>;
447
+ maxAttempts: z.ZodDefault<z.ZodNumber>;
448
+ }, z.core.$strip>>;
449
+ login: z.ZodDefault<z.ZodObject<{
450
+ password: z.ZodDefault<z.ZodBoolean>;
451
+ otp: z.ZodDefault<z.ZodBoolean>;
452
+ ldap: z.ZodDefault<z.ZodBoolean>;
453
+ apikey: z.ZodDefault<z.ZodBoolean>;
454
+ }, z.core.$strip>>;
455
+ register: z.ZodDefault<z.ZodObject<{
456
+ enabled: z.ZodDefault<z.ZodBoolean>;
457
+ defaultEnabled: z.ZodDefault<z.ZodBoolean>;
458
+ }, z.core.$strip>>;
459
+ agreements: z.ZodDefault<z.ZodObject<{
460
+ userAgreementMarkdown: z.ZodOptional<z.ZodString>;
461
+ privacyPolicyMarkdown: z.ZodOptional<z.ZodString>;
462
+ userAgreementUrl: z.ZodOptional<z.ZodURL>;
463
+ privacyPolicyUrl: z.ZodOptional<z.ZodURL>;
464
+ showOnRegister: z.ZodDefault<z.ZodBoolean>;
465
+ showOnLogin: z.ZodDefault<z.ZodBoolean>;
466
+ }, z.core.$strip>>;
467
+ security: z.ZodDefault<z.ZodObject<{
468
+ maxLoginAttempts: z.ZodDefault<z.ZodNumber>;
469
+ lockoutDuration: z.ZodDefault<z.ZodNumber>;
470
+ }, z.core.$strip>>;
471
+ session: z.ZodOptional<z.ZodObject<{
472
+ maxAge: z.ZodDefault<z.ZodNumber>;
473
+ sliding: z.ZodDefault<z.ZodBoolean>;
474
+ singleDevice: z.ZodDefault<z.ZodBoolean>;
475
+ refreshTokenMaxAge: z.ZodDefault<z.ZodNumber>;
476
+ }, z.core.$strip>>;
477
+ rbac: z.ZodDefault<z.ZodObject<{
478
+ enabled: z.ZodDefault<z.ZodBoolean>;
479
+ superAdminRole: z.ZodDefault<z.ZodString>;
480
+ defaultRole: z.ZodDefault<z.ZodString>;
481
+ }, z.core.$strip>>;
482
+ seedDefaultData: z.ZodDefault<z.ZodBoolean>;
483
+ }, z.core.$strip>;
484
+ /**
485
+ * IAM 配置类型
486
+ * @example
487
+ * ```ts
488
+ * import { IamConfigSchema, type IamConfig } from '@h-ai/iam'
489
+ * const value: IamConfig = IamConfigSchema.parse({ seedDefaultData: false, session: { maxAge: 3600 } })
490
+ * ```
491
+ */
492
+ type IamConfig = z.infer<typeof IamConfigSchema>;
493
+ /**
494
+ * IAM 配置设置输入类型(仅设置字段,不含运行时依赖)
495
+ *
496
+ * 说明:Zod 的 default 会让输入端字段可省略,但输出端字段为必填。
497
+ * @example
498
+ * ```ts
499
+ * import type { IamConfigSettingsInput } from '@h-ai/iam'
500
+ * const value: IamConfigSettingsInput = { session: { maxAge: 3600 }, seedDefaultData: false }
501
+ * ```
502
+ */
503
+ type IamConfigSettingsInput = z.input<typeof IamConfigSchema>;
504
+
505
+ /**
506
+ * @h-ai/iam — API Key 类型定义
507
+ *
508
+ * 包含 API Key 实体、创建选项、查询选项等类型。
509
+ * @module iam-authn-apikey-types
510
+ */
511
+
512
+ /**
513
+ * API Key 实体(对外展示)
514
+ *
515
+ * 不含密钥哈希等敏感信息。
516
+ * @example
517
+ * ```ts
518
+ * import { iam, type ApiKey } from '@h-ai/iam'
519
+ * // 已初始化依赖和 IAM,并启用 login.apikey。
520
+ * const result = await iam.apiKey.getApiKey('key-1')
521
+ * if (result.success && result.data) {
522
+ * const key: ApiKey = result.data
523
+ * key.keyPrefix // 展示前缀,不包含 rawKey 或哈希。
524
+ * }
525
+ * ```
526
+ */
527
+ interface ApiKey {
528
+ /** API Key ID */
529
+ id: string;
530
+ /** 所属用户 ID */
531
+ userId: string;
532
+ /** API Key 名称(用户自定义标识) */
533
+ name: string;
534
+ /** 密钥前缀(用于展示,如 'hai_abc1****') */
535
+ keyPrefix: string;
536
+ /** 是否启用 */
537
+ enabled: boolean;
538
+ /** 过期时间(null 表示永不过期) */
539
+ expiresAt: Date | null;
540
+ /** 创建时间 */
541
+ createdAt: Date;
542
+ /** 最后使用时间 */
543
+ lastUsedAt: Date | null;
544
+ /** 权限代码范围,支持 * / 命名空间 :*;空数组无操作权限,* 不超出主体权限。 */
545
+ scopes: string[];
546
+ }
547
+ /**
548
+ * 创建 API Key 的返回结果
549
+ *
550
+ * 仅在创建时返回明文密钥,之后无法再获取。
551
+ * @example
552
+ * ```ts
553
+ * import { iam, type CreateApiKeyResult } from '@h-ai/iam'
554
+ * // 已初始化依赖和 IAM、启用 login.apikey;user-1 为已存在的用户。
555
+ * const created = await iam.apiKey.createApiKey('user-1', { name: 'report-reader', scopes: ['report:read'] })
556
+ * if (created.success) {
557
+ * const value: CreateApiKeyResult = created.data
558
+ * const oneTimeSecret = value.rawKey // 仅本次交给调用者安全保存,不能写日志。
559
+ * }
560
+ * ```
561
+ */
562
+ interface CreateApiKeyResult {
563
+ /** API Key 元数据 */
564
+ apiKey: ApiKey;
565
+ /** 明文密钥(仅此一次展示) */
566
+ rawKey: string;
567
+ }
568
+ /**
569
+ * 创建 API Key 选项
570
+ * @example
571
+ * ```ts
572
+ * import type { CreateApiKeyOptions } from '@h-ai/iam'
573
+ * const value: CreateApiKeyOptions = { name: 'report-reader', expirationDays: 30, scopes: ['report:read'] }
574
+ * ```
575
+ */
576
+ interface CreateApiKeyOptions {
577
+ /** API Key 名称 */
578
+ name: string;
579
+ /** 有效期天数(0 或不传表示永不过期) */
580
+ expirationDays?: number;
581
+ /** 权限代码范围;默认空数组。受限 key 不保留角色授权入口,使用 permission 守卫。 */
582
+ scopes?: string[];
583
+ }
584
+ /**
585
+ * API Key 列表允许的服务端排序字段。
586
+ * @example
587
+ * ```ts
588
+ * import type { ApiKeySortField } from '@h-ai/iam'
589
+ * const value: ApiKeySortField = 'createdAt'
590
+ * ```
591
+ */
592
+ type ApiKeySortField = 'name' | 'createdAt' | 'lastUsedAt' | 'expiresAt';
593
+ /**
594
+ * API Key 列表排序方向。
595
+ * @example
596
+ * ```ts
597
+ * import type { ApiKeySortDirection } from '@h-ai/iam'
598
+ * const value: ApiKeySortDirection = 'desc'
599
+ * ```
600
+ */
601
+ type ApiKeySortDirection = 'asc' | 'desc';
602
+ /**
603
+ * API Key 列表查询选项
604
+ * @example
605
+ * ```ts
606
+ * import type { ListApiKeysOptions } from '@h-ai/iam'
607
+ * const value: ListApiKeysOptions = { page: 1, pageSize: 20, enabled: true, sortBy: 'createdAt', sortDirection: 'desc' }
608
+ * ```
609
+ */
610
+ interface ListApiKeysOptions extends PaginationOptionsInput {
611
+ /** 搜索关键字(模糊匹配名称与密钥前缀) */
612
+ search?: string;
613
+ /** 按启用状态过滤,不传则返回全部 */
614
+ enabled?: boolean;
615
+ /** 服务端排序字段;未指定时保持按创建时间倒序的历史行为。 */
616
+ sortBy?: ApiKeySortField;
617
+ /** 服务端排序方向;仅在指定 sortBy 时生效,默认 desc。 */
618
+ sortDirection?: ApiKeySortDirection;
619
+ }
620
+ /**
621
+ * API Key 管理操作接口
622
+ * @example
623
+ * ```ts
624
+ * import { iam, type ApiKeyOperations } from '@h-ai/iam'
625
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化,并启用 login.apikey。
626
+ * const operations: ApiKeyOperations = iam.apiKey
627
+ * const result = await operations.listApiKeys('user-1', { page: 1, pageSize: 20 })
628
+ * if (!result.success) {
629
+ * result.error.code // 调用方将失败交给统一错误边界。
630
+ * }
631
+ * else {
632
+ * result.data
633
+ * }
634
+ * ```
635
+ */
636
+ interface ApiKeyOperations {
637
+ /**
638
+ * 创建 API Key
639
+ *
640
+ * @param userId - 用户 ID
641
+ * @param options - 创建选项
642
+ * @returns 成功返回 API Key 元数据和明文密钥
643
+ */
644
+ createApiKey: (userId: string, options: CreateApiKeyOptions) => Promise<HaiResult<CreateApiKeyResult>>;
645
+ /**
646
+ * 分页列出用户的 API Key
647
+ *
648
+ * @param userId - 用户 ID
649
+ * @param options - 分页、搜索、过滤与排序选项
650
+ * @returns 分页 API Key 列表(不含密钥哈希)
651
+ */
652
+ listApiKeys: (userId: string, options?: ListApiKeysOptions) => Promise<HaiResult<PaginatedResult<ApiKey>>>;
653
+ /**
654
+ * 获取 API Key 详情
655
+ *
656
+ * @param keyId - API Key ID
657
+ * @returns API Key 详情
658
+ */
659
+ getApiKey: (keyId: string) => Promise<HaiResult<ApiKey | null>>;
660
+ /**
661
+ * 吊销/删除 API Key
662
+ *
663
+ * @param keyId - API Key ID
664
+ * @returns 操作结果
665
+ */
666
+ revokeApiKey: (keyId: string) => Promise<HaiResult<void>>;
667
+ /**
668
+ * 验证 API Key 并返回关联用户 ID
669
+ *
670
+ * @param rawKey - 明文 API Key
671
+ * @returns 成功返回 API Key 实体(含用户 ID),失败返回错误码
672
+ */
673
+ verifyApiKey: (rawKey: string) => Promise<HaiResult<ApiKey>>;
674
+ }
675
+
676
+ /**
677
+ * @h-ai/iam — 授权子功能类型定义(RBAC)
678
+ *
679
+ * @module iam-authz-types
680
+ */
681
+
682
+ /**
683
+ * 权限类型
684
+ *
685
+ * - menu:菜单/导航可见性控制
686
+ * - api:接口级访问控制
687
+ * - button:操作按钮显隐控制
688
+ * @example
689
+ * ```ts
690
+ * import type { PermissionType } from '@h-ai/iam'
691
+ * const value: PermissionType = 'api'
692
+ * ```
693
+ */
694
+ type PermissionType = 'menu' | 'api' | 'button';
695
+ /**
696
+ * 权限查询参数
697
+ *
698
+ * 扩展分页参数,支持按类型和关键字筛选。
699
+ * @example
700
+ * ```ts
701
+ * import type { PermissionQueryOptions } from '@h-ai/iam'
702
+ * const value: PermissionQueryOptions = { page: 1, pageSize: 20, type: 'api', search: 'report' }
703
+ * ```
704
+ */
705
+ interface PermissionQueryOptions extends PaginationOptionsInput {
706
+ /** 按权限类型筛选 */
707
+ type?: PermissionType;
708
+ /** 按关键字搜索(匹配 code 或 name) */
709
+ search?: string;
710
+ }
711
+ /**
712
+ * 权限
713
+ * @example
714
+ * ```ts
715
+ * import type { Permission } from '@h-ai/iam'
716
+ * const value: Permission = { id: 'permission-1', code: 'report:read', name: '查看报表', type: 'api', createdAt: new Date(), updatedAt: new Date() }
717
+ * ```
718
+ */
719
+ interface Permission {
720
+ /** 权限 ID */
721
+ id: string;
722
+ /** 权限代码(如 users:read, posts:write) */
723
+ code: string;
724
+ /** 权限名称 */
725
+ name: string;
726
+ /** 权限描述 */
727
+ description?: string;
728
+ /** 权限类型(menu / api / button) */
729
+ type?: PermissionType;
730
+ /** 资源类型 */
731
+ resource?: string;
732
+ /** 操作类型(create/read/update/delete) */
733
+ action?: string;
734
+ /** 创建时间 */
735
+ createdAt: Date;
736
+ /** 更新时间 */
737
+ updatedAt: Date;
738
+ }
739
+ /**
740
+ * 角色
741
+ * @example
742
+ * ```ts
743
+ * import type { Role } from '@h-ai/iam'
744
+ * const value: Role = { id: 'role-1', code: 'report_reader', name: '报表读者', createdAt: new Date(), updatedAt: new Date() }
745
+ * ```
746
+ */
747
+ interface Role {
748
+ /** 角色 ID */
749
+ id: string;
750
+ /** 角色代码 */
751
+ code: string;
752
+ /** 角色名称 */
753
+ name: string;
754
+ /** 角色描述 */
755
+ description?: string;
756
+ /** 是否系统角色(不可删除) */
757
+ isSystem?: boolean;
758
+ /** 创建时间 */
759
+ createdAt: Date;
760
+ /** 更新时间 */
761
+ updatedAt: Date;
762
+ }
763
+ /**
764
+ * 授权子功能接口
765
+ * @example
766
+ * ```ts
767
+ * import { iam, type AuthzOperations } from '@h-ai/iam'
768
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化。
769
+ * const operations: AuthzOperations = iam.authz
770
+ * const result = await operations.checkPermission('user-1', 'report:read')
771
+ * if (!result.success) {
772
+ * result.error.code // 调用方将失败交给统一错误边界。
773
+ * }
774
+ * else {
775
+ * result.data
776
+ * }
777
+ * ```
778
+ */
779
+ interface AuthzOperations {
780
+ /** 查询当前角色与权限代码,一次读取角色并批量聚合权限,不依赖会话缓存。 */
781
+ getUserAuthorization: (userId: string) => Promise<HaiResult<Pick<Session, 'roles' | 'permissions'>>>;
782
+ /**
783
+ * 检查权限
784
+ *
785
+ * 超级管理员角色自动拥有所有权限。
786
+ * 支持通配符匹配(如 `user:*` 匹配 `user:read`)。
787
+ *
788
+ * **数据来源**:角色列表和权限代码均从数据库实时查询。
789
+ *
790
+ * @param userId - 用户 ID
791
+ * @param permission - 权限代码(如 `user:read`)
792
+ * @returns 成功返回 true/false
793
+ */
794
+ checkPermission: (userId: string, permission: string) => Promise<HaiResult<boolean>>;
795
+ /**
796
+ * 获取用户权限列表
797
+ *
798
+ * 通过用户角色聚合所有权限(自动去重)。
799
+ *
800
+ * **数据来源**:直接查询数据库,返回最新数据。
801
+ *
802
+ * @param userId - 用户 ID
803
+ * @returns 成功返回去重后的权限列表
804
+ */
805
+ getUserPermissions: (userId: string) => Promise<HaiResult<Permission[]>>;
806
+ /**
807
+ * 获取用户角色列表
808
+ *
809
+ * **数据来源**:直接查询数据库,返回最新数据。
810
+ *
811
+ * @param userId - 用户 ID
812
+ * @returns 成功返回角色列表
813
+ */
814
+ getUserRoles: (userId: string) => Promise<HaiResult<Role[]>>;
815
+ /**
816
+ * 分配角色给用户
817
+ *
818
+ * @param userId - 用户 ID
819
+ * @param roleId - 角色 ID
820
+ * @returns 成功返回 ok;角色不存在返回 ROLE_NOT_FOUND
821
+ */
822
+ assignRole: (userId: string, roleId: string, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
823
+ /**
824
+ * 移除用户角色
825
+ *
826
+ * @param userId - 用户 ID
827
+ * @param roleId - 角色 ID
828
+ * @returns 成功返回 ok
829
+ */
830
+ removeRole: (userId: string, roleId: string, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
831
+ /**
832
+ * 同步用户角色(替换为目标角色列表)
833
+ *
834
+ * 自动计算当前角色与目标角色的差集,批量移除多余角色、添加缺失角色,
835
+ * 最终同步一次会话权限。若目标与当前一致则跳过操作。
836
+ *
837
+ * @param userId - 用户 ID
838
+ * @param roleIds - 目标角色 ID 列表
839
+ * @returns 成功返回 ok
840
+ */
841
+ syncRoles: (userId: string, roleIds: string[], tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
842
+ /**
843
+ * 创建角色
844
+ *
845
+ * @param role - 角色数据(code、name、description、isSystem)
846
+ * @returns 成功返回创建的角色(含 id 和时间戳)
847
+ */
848
+ createRole: (role: Omit<Role, 'id' | 'createdAt' | 'updatedAt'> & {
849
+ permissionIds?: string[];
850
+ }, tx?: DmlWithTxOperations) => Promise<HaiResult<Role>>;
851
+ /**
852
+ * 获取角色
853
+ *
854
+ * @param roleId - 角色 ID
855
+ * @returns 成功返回角色或 null(不存在时)
856
+ */
857
+ getRole: (roleId: string) => Promise<HaiResult<Role | null>>;
858
+ /**
859
+ * 根据角色代码获取角色
860
+ *
861
+ * @param code - 角色代码(如 'admin'、'user')
862
+ * @returns 成功返回角色或 null(不存在时)
863
+ */
864
+ getRoleByCode: (code: string) => Promise<HaiResult<Role | null>>;
865
+ /**
866
+ * 获取所有角色(分页)
867
+ *
868
+ * @param options - 分页参数,可选
869
+ * @returns 成功返回分页角色列表
870
+ */
871
+ getAllRoles: (options?: PaginationOptionsInput) => Promise<HaiResult<PaginatedResult<Role>>>;
872
+ /** 批量统计角色成员数;成功时无关联返回 0,查询失败返回错误 */
873
+ getRoleUserCounts: (roleIds: string[]) => Promise<HaiResult<Map<string, number>>>;
874
+ /**
875
+ * 更新角色
876
+ *
877
+ * @param roleId - 角色 ID
878
+ * @param data - 要更新的字段;permissionIds 在同一事务内全量替换,未传则保持权限不变
879
+ * @returns 成功返回更新后的角色;角色不存在返回 ROLE_NOT_FOUND
880
+ */
881
+ updateRole: (roleId: string, data: Partial<Omit<Role, 'id' | 'createdAt' | 'updatedAt'>> & {
882
+ permissionIds?: string[];
883
+ }, tx?: DmlWithTxOperations) => Promise<HaiResult<Role>>;
884
+ /**
885
+ * 删除角色
886
+ *
887
+ * 级联删除用户-角色、角色-权限关联,并同步受影响用户的会话。
888
+ *
889
+ * @param roleId - 角色 ID
890
+ * @returns 成功返回 ok;角色不存在返回 ROLE_NOT_FOUND
891
+ */
892
+ deleteRole: (roleId: string, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
893
+ /**
894
+ * 创建权限
895
+ *
896
+ * @param permission - 权限数据(code、name、resource、action)
897
+ * @returns 成功返回创建的权限(含 id 和时间戳)
898
+ */
899
+ createPermission: (permission: Omit<Permission, 'id' | 'createdAt' | 'updatedAt'>, tx?: DmlWithTxOperations) => Promise<HaiResult<Permission>>;
900
+ /**
901
+ * 获取权限
902
+ *
903
+ * @param permissionId - 权限 ID
904
+ * @returns 成功返回权限或 null(不存在时)
905
+ */
906
+ getPermission: (permissionId: string) => Promise<HaiResult<Permission | null>>;
907
+ /**
908
+ * 根据权限代码获取权限
909
+ *
910
+ * @param code - 权限代码(如 `user:read`)
911
+ * @returns 成功返回权限或 null(不存在时)
912
+ */
913
+ getPermissionByCode: (code: string) => Promise<HaiResult<Permission | null>>;
914
+ /**
915
+ * 获取所有权限(分页)
916
+ *
917
+ * 支持按权限类型(menu/api/button)和关键字(code/name)筛选。
918
+ *
919
+ * @param options - 分页及筛选参数,可选
920
+ * @returns 成功返回分页权限列表
921
+ */
922
+ getAllPermissions: (options?: PermissionQueryOptions) => Promise<HaiResult<PaginatedResult<Permission>>>;
923
+ /**
924
+ * 删除权限
925
+ *
926
+ * 级联删除角色-权限关联,并同步受影响用户的会话。
927
+ *
928
+ * @param permissionId - 权限 ID
929
+ * @returns 成功返回 ok;权限不存在返回 PERMISSION_NOT_FOUND
930
+ */
931
+ deletePermission: (permissionId: string, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
932
+ /**
933
+ * 为角色分配权限
934
+ *
935
+ * @param roleId - 角色 ID
936
+ * @param permissionId - 权限 ID
937
+ * @returns 成功返回 ok;角色/权限不存在返回对应错误码
938
+ */
939
+ assignPermissionToRole: (roleId: string, permissionId: string, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
940
+ /**
941
+ * 移除角色权限
942
+ *
943
+ * @param roleId - 角色 ID
944
+ * @param permissionId - 权限 ID
945
+ * @returns 成功返回 ok;权限不存在返回 PERMISSION_NOT_FOUND
946
+ */
947
+ removePermissionFromRole: (roleId: string, permissionId: string, tx?: DmlWithTxOperations) => Promise<HaiResult<void>>;
948
+ /**
949
+ * 获取角色的权限列表
950
+ *
951
+ * **数据来源**:直接查询数据库,返回最新数据。
952
+ *
953
+ * @param roleId - 角色 ID
954
+ * @returns 成功返回角色关联的权限列表
955
+ */
956
+ getRolePermissions: (roleId: string) => Promise<HaiResult<Permission[]>>;
957
+ /**
958
+ * 批量获取多个用户的角色列表
959
+ *
960
+ * 单次查询替代 N 次 getUserRoles 调用,避免 N+1 问题。
961
+ * 返回 Map:key 为 userId,value 为该用户的角色列表;无角色的用户返回空数组。
962
+ *
963
+ * **数据来源**:直接查询数据库,返回最新数据。
964
+ *
965
+ * @param userIds - 用户 ID 列表
966
+ * @returns Map<userId, Role[]>
967
+ */
968
+ getUserRolesForMany: (userIds: string[]) => Promise<HaiResult<Map<string, Role[]>>>;
969
+ /**
970
+ * 批量获取多个角色的权限列表
971
+ *
972
+ * 单次查询替代 N 次 getRolePermissions 调用,避免 N+1 问题。
973
+ * 返回 Map:key 为 roleId,value 为该角色的权限列表;无权限的角色返回空数组。
974
+ *
975
+ * **数据来源**:直接查询数据库,返回最新数据。
976
+ *
977
+ * @param roleIds - 角色 ID 列表
978
+ * @returns Map<roleId, Permission[]>
979
+ */
980
+ getRolePermissionsForMany: (roleIds: string[]) => Promise<HaiResult<Map<string, Permission[]>>>;
981
+ }
982
+
983
+ /**
984
+ * @h-ai/iam — 用户相关类型定义
985
+ *
986
+ * 包含: - 用户基础类型(User、StoredUser) - 注册选项(RegisterOptions) - 协议展示类型(AgreementDisplay) - 用户操作接口(UserOperations)
987
+ * @module iam-user-types
988
+ */
989
+
990
+ /**
991
+ * 用户列表允许的服务端排序字段。
992
+ * @example
993
+ * ```ts
994
+ * import type { UserSortField } from '@h-ai/iam'
995
+ * const value: UserSortField = 'username'
996
+ * ```
997
+ */
998
+ type UserSortField = 'username' | 'email' | 'displayName' | 'enabled' | 'createdAt';
999
+ /**
1000
+ * 用户列表排序方向。
1001
+ * @example
1002
+ * ```ts
1003
+ * import type { UserSortDirection } from '@h-ai/iam'
1004
+ * const value: UserSortDirection = 'asc'
1005
+ * ```
1006
+ */
1007
+ type UserSortDirection = 'asc' | 'desc';
1008
+ /**
1009
+ * 用户列表查询选项
1010
+ * @example
1011
+ * ```ts
1012
+ * import type { ListUsersOptions } from '@h-ai/iam'
1013
+ * const value: ListUsersOptions = { page: 1, pageSize: 20, enabled: true, roleCode: 'user', include: ['roles'] }
1014
+ * ```
1015
+ */
1016
+ interface ListUsersOptions extends PaginationOptionsInput {
1017
+ /** 角色 code 精确筛选,在数据库分页前执行。 */
1018
+ roleCode?: string;
1019
+ /** 搜索关键字(模糊匹配用户名、邮箱、手机号、显示名称) */
1020
+ search?: string;
1021
+ /** 按启用状态过滤,不传则返回全部 */
1022
+ enabled?: boolean;
1023
+ /** 服务端排序字段;未指定时保持按创建时间倒序的历史行为。 */
1024
+ sortBy?: UserSortField;
1025
+ /** 服务端排序方向;仅在指定 sortBy 时生效,默认 desc。 */
1026
+ sortDirection?: UserSortDirection;
1027
+ /** 包含关联数据(如 'roles' 表示同时返回用户角色列表) */
1028
+ include?: ('roles')[];
1029
+ }
1030
+ /**
1031
+ * 用户基础信息
1032
+ * @example
1033
+ * ```ts
1034
+ * import type { User } from '@h-ai/iam'
1035
+ * const value: User = { id: 'user-1', username: 'alice', enabled: true, createdAt: new Date(), updatedAt: new Date() }
1036
+ * ```
1037
+ */
1038
+ interface User {
1039
+ /** 用户 ID */
1040
+ id: string;
1041
+ /** 用户名 */
1042
+ username: string;
1043
+ /** 邮箱 */
1044
+ email?: string;
1045
+ /** 手机号 */
1046
+ phone?: string;
1047
+ /** 显示名称 */
1048
+ displayName?: string;
1049
+ /** 头像 URL */
1050
+ avatarUrl?: string;
1051
+ /** 是否启用 */
1052
+ enabled: boolean;
1053
+ /** 是否邮箱验证 */
1054
+ emailVerified?: boolean;
1055
+ /** 是否手机验证 */
1056
+ phoneVerified?: boolean;
1057
+ /** 创建时间 */
1058
+ createdAt: Date;
1059
+ /** 更新时间 */
1060
+ updatedAt: Date;
1061
+ /** 扩展属性 */
1062
+ metadata?: Record<string, unknown>;
1063
+ /** 用户角色列表(仅在 include: ['roles'] 时返回) */
1064
+ roles?: Role[];
1065
+ }
1066
+ /**
1067
+ * 用户协议/隐私协议展示配置
1068
+ * @example
1069
+ * ```ts
1070
+ * import type { AgreementDisplay } from '@h-ai/iam'
1071
+ * const value: AgreementDisplay = { userAgreementUrl: 'https://app.example.com/terms', showOnRegister: true, showOnLogin: false }
1072
+ * ```
1073
+ */
1074
+ interface AgreementDisplay {
1075
+ /** 用户协议 Markdown 正文,显示优先于 URL。 */
1076
+ userAgreementMarkdown?: string;
1077
+ /** 隐私协议 Markdown 正文,显示优先于 URL。 */
1078
+ privacyPolicyMarkdown?: string;
1079
+ /** 用户协议 URL */
1080
+ userAgreementUrl?: string;
1081
+ /** 隐私协议 URL */
1082
+ privacyPolicyUrl?: string;
1083
+ /** 注册时展示协议 */
1084
+ showOnRegister: boolean;
1085
+ /** 登录时展示协议 */
1086
+ showOnLogin: boolean;
1087
+ }
1088
+ /**
1089
+ * 内部存储用户(包含密码哈希等敏感信息)
1090
+ * @example
1091
+ * ```ts
1092
+ * import type { StoredUser } from '@h-ai/iam'
1093
+ * // 服务端存储类型;不得直接序列化给浏览器。
1094
+ * function credentialVersion(row: StoredUser): string {
1095
+ * return row.credentialVersion ?? ''
1096
+ * }
1097
+ * ```
1098
+ */
1099
+ interface StoredUser extends User {
1100
+ /** 密码凭据代际;密码提交时原子推进,旧会话及迟到认证不得复用。 */
1101
+ credentialVersion?: string;
1102
+ /** 密码重置操作的独立代际;发布/尝试推进,不影响现有登录。 */
1103
+ resetVersion?: string;
1104
+ /** 当前重置令牌的 SM3 摘要,仅内部存储。 */
1105
+ resetHash?: string;
1106
+ /** 重置令牌的 Unix 毫秒过期时间,由数据库时钟核验。 */
1107
+ resetExpiresAt?: number;
1108
+ /** 当前重置令牌已使用的尝试次数。 */
1109
+ resetAttempts?: number;
1110
+ /** 密码哈希 */
1111
+ passwordHash?: string;
1112
+ /** 密码更新时间 */
1113
+ passwordUpdatedAt?: Date;
1114
+ /** 登录失败次数 */
1115
+ loginFailedCount?: number;
1116
+ /** 最后登录失败时间 */
1117
+ lastLoginFailedAt?: Date;
1118
+ /** 锁定截止时间 */
1119
+ lockedUntil?: Date;
1120
+ }
1121
+ /**
1122
+ * 用户注册选项
1123
+ * @example
1124
+ * ```ts
1125
+ * import type { RegisterOptions } from '@h-ai/iam'
1126
+ * const value: RegisterOptions = { username: 'alice', email: 'alice@example.com', password: 'ExampleOnly123!' }
1127
+ * ```
1128
+ */
1129
+ interface RegisterOptions {
1130
+ /** 用户名 */
1131
+ username: string;
1132
+ /** 邮箱 */
1133
+ email?: string;
1134
+ /** 手机号 */
1135
+ phone?: string;
1136
+ /** 密码 */
1137
+ password: string;
1138
+ /** 显示名称 */
1139
+ displayName?: string;
1140
+ /** 扩展属性 */
1141
+ metadata?: Record<string, unknown>;
1142
+ }
1143
+ /**
1144
+ * 注册结果
1145
+ * @example
1146
+ * ```ts
1147
+ * import { iam, type RegisterResult } from '@h-ai/iam'
1148
+ * const result = await iam.user.register({ username: 'alice', password: 'ExampleOnly123!' })
1149
+ * if (result.success) {
1150
+ * const registered: RegisterResult = result.data
1151
+ * registered.user.id
1152
+ * }
1153
+ * ```
1154
+ */
1155
+ interface RegisterResult {
1156
+ /** 用户信息 */
1157
+ user: User;
1158
+ /** 协议展示信息(可选) */
1159
+ agreements?: AgreementDisplay;
1160
+ }
1161
+ /**
1162
+ * 当前登录用户可自行修改的字段白名单
1163
+ *
1164
+ * 仅允许修改个人资料相关字段,禁止修改安全字段(enabled、emailVerified、roles 等)。
1165
+ * @example
1166
+ * ```ts
1167
+ * import type { UpdateCurrentUserInput } from '@h-ai/iam'
1168
+ * const value: UpdateCurrentUserInput = { displayName: 'Alice', avatarUrl: 'https://app.example.com/avatar/alice.png' }
1169
+ * ```
1170
+ */
1171
+ interface UpdateCurrentUserInput {
1172
+ /** 用户名 */
1173
+ username?: string;
1174
+ /** 邮箱 */
1175
+ email?: string;
1176
+ /** 显示名称 */
1177
+ displayName?: string;
1178
+ /** 头像 URL */
1179
+ avatarUrl?: string;
1180
+ /** 手机号 */
1181
+ phone?: string;
1182
+ /** 扩展属性 */
1183
+ metadata?: Record<string, unknown>;
1184
+ }
1185
+ /**
1186
+ * 用户子功能接口
1187
+ * @example
1188
+ * ```ts
1189
+ * import { iam, type UserOperations } from '@h-ai/iam'
1190
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化。
1191
+ * const operations: UserOperations = iam.user
1192
+ * const result = await operations.listUsers({ page: 1, pageSize: 20, include: ['roles'] })
1193
+ * if (!result.success) {
1194
+ * result.error.code // 调用方将失败交给统一错误边界。
1195
+ * }
1196
+ * else {
1197
+ * result.data
1198
+ * }
1199
+ * ```
1200
+ */
1201
+ interface UserOperations {
1202
+ /** 批量查询最多 1000 个用户 ID,去重并保持输入顺序,忽略不存在的 ID;可批量包含角色。 */
1203
+ getUsers: (userIds: readonly string[], options?: {
1204
+ include?: ('roles')[];
1205
+ }) => Promise<HaiResult<User[]>>;
1206
+ /** 管理端创建账户,不受自助注册开关限制;调用端必须执行管理员授权。 */
1207
+ createUser: (options: RegisterOptions) => Promise<HaiResult<RegisterResult>>;
1208
+ /**
1209
+ * 注册用户
1210
+ *
1211
+ * 校验注册开关、密码强度、用户名/邮箱唯一性后,
1212
+ * 在事务中创建用户并分配默认角色。
1213
+ *
1214
+ * @param options - 注册选项(用户名、密码、邮箱等)
1215
+ * @returns 成功返回用户信息及可选的协议展示;失败返回对应错误码
1216
+ */
1217
+ register: (options: RegisterOptions) => Promise<HaiResult<RegisterResult>>;
1218
+ /**
1219
+ * 获取当前用户
1220
+ *
1221
+ * 通过访问令牌验证会话后查询用户信息。
1222
+ *
1223
+ * @param accessToken - 访问令牌
1224
+ * @returns 成功返回用户信息;令牌无效/过期返回错误
1225
+ */
1226
+ getCurrentUser: (accessToken: string) => Promise<HaiResult<User>>;
1227
+ /**
1228
+ * 更新当前登录用户信息(通过 accessToken 识别用户)
1229
+ *
1230
+ * 仅允许修改白名单字段(username、email、displayName、avatarUrl、phone、metadata),
1231
+ * 禁止修改安全字段(enabled、emailVerified 等)。修改 username/email 时自动校验唯一性。
1232
+ *
1233
+ * @param accessToken - 访问令牌
1234
+ * @param data - 要更新的字段(仅白名单字段)
1235
+ * @returns 成功返回更新后的用户信息
1236
+ */
1237
+ updateCurrentUser: (accessToken: string, data: UpdateCurrentUserInput) => Promise<HaiResult<User>>;
1238
+ /**
1239
+ * 获取用户信息
1240
+ *
1241
+ * @param userId - 用户 ID
1242
+ * @param options - 查询选项(可选 include: ['roles'] 同时返回角色列表)
1243
+ * @param options.include - 指定需要额外展开的关联字段;传入 ['roles'] 时同时返回角色列表
1244
+ * @returns 成功返回用户信息或 null(用户不存在时)
1245
+ */
1246
+ getUser: (userId: string, options?: {
1247
+ include?: ('roles')[];
1248
+ }) => Promise<HaiResult<User | null>>;
1249
+ /**
1250
+ * 获取用户列表(分页 + 搜索 + 过滤)
1251
+ *
1252
+ * @param options - 查询选项(页码、每页数量、搜索关键字、启用状态过滤)
1253
+ * @returns 成功返回分页用户列表
1254
+ */
1255
+ listUsers: (options?: ListUsersOptions) => Promise<HaiResult<PaginatedResult<User>>>;
1256
+ /**
1257
+ * 更新用户信息
1258
+ *
1259
+ * 空更新(无有效字段)时直接返回当前用户信息。
1260
+ *
1261
+ * @param userId - 用户 ID
1262
+ * @param data - 要更新的字段(displayName、email 等)
1263
+ * @returns 成功返回更新后的用户信息;用户不存在返回 USER_NOT_FOUND
1264
+ */
1265
+ updateUser: (userId: string, data: Partial<User>) => Promise<HaiResult<User>>;
1266
+ /**
1267
+ * 删除用户
1268
+ *
1269
+ * 同时清理用户的角色关联数据。
1270
+ *
1271
+ * @param userId - 用户 ID
1272
+ * @returns 成功返回 ok;用户不存在返回 USER_NOT_FOUND
1273
+ */
1274
+ deleteUser: (userId: string) => Promise<HaiResult<void>>;
1275
+ /**
1276
+ * 管理员重置用户密码
1277
+ *
1278
+ * 无需旧密码,直接设置新密码(仅限管理员操作)。
1279
+ *
1280
+ * @param userId - 用户 ID
1281
+ * @param newPassword - 新密码
1282
+ * @returns 成功返回 ok;用户不存在返回 USER_NOT_FOUND,密码不合规返回 PASSWORD_POLICY_VIOLATION
1283
+ */
1284
+ adminResetPassword: (userId: string, newPassword: string) => Promise<HaiResult<void>>;
1285
+ /**
1286
+ * 修改密码
1287
+ *
1288
+ * 验证旧密码 → 校验新密码强度 → 哈希并更新。
1289
+ *
1290
+ * @param userId - 用户 ID
1291
+ * @param oldPassword - 旧密码
1292
+ * @param newPassword - 新密码
1293
+ * @returns 成功返回 ok;旧密码错误返回 INVALID_CREDENTIALS,新密码不合规返回 PASSWORD_POLICY_VIOLATION
1294
+ */
1295
+ changePassword: (userId: string, oldPassword: string, newPassword: string) => Promise<HaiResult<void>>;
1296
+ /**
1297
+ * 当前登录用户修改密码
1298
+ *
1299
+ * 通过访问令牌识别用户 → 验证旧密码 → 校验新密码强度 → 哈希并更新 → 清除该用户所有会话。
1300
+ *
1301
+ * @param accessToken - 当前用户的访问令牌
1302
+ * @param oldPassword - 旧密码
1303
+ * @param newPassword - 新密码
1304
+ * @returns 成功返回 ok;旧密码错误返回 INVALID_CREDENTIALS,新密码不合规返回 PASSWORD_POLICY_VIOLATION
1305
+ */
1306
+ changeCurrentUserPassword: (accessToken: string, oldPassword: string, newPassword: string) => Promise<HaiResult<void>>;
1307
+ /**
1308
+ * 请求密码重置
1309
+ *
1310
+ * 查找用户 → 条件发布重置令牌(用户数据库行、SM3 摘要及 resetVersion)→ 通知业务层。
1311
+ * 即使用户不存在也返回 ok(防止用户枚举攻击)。
1312
+ *
1313
+ * @param identifier - 用户标识(邮箱)
1314
+ * @returns 用户不存在返回 ok;发布冲突、存储故障或投递未知返回失败,通知不自动重发。
1315
+ * @example
1316
+ * ```ts
1317
+ * import { iam } from '@h-ai/iam'
1318
+ * const requested = await iam.user.requestPasswordReset('alice@example.com')
1319
+ * if (!requested.success)
1320
+ * requested.error.code // 投递未知不能当作成功或由调用端擅自重发通知。
1321
+ * ```
1322
+ */
1323
+ requestPasswordReset: (identifier: string) => Promise<HaiResult<void>>;
1324
+ /**
1325
+ * 确认密码重置
1326
+ *
1327
+ * 条件计次并取得代际 → 验证密码策略 → 最终 SQL 同时校验代际/有效期/状态并改密、消费令牌。
1328
+ * 凭据代际已在数据库推进,后续缓存清理失败也不能重新授权旧会话。
1329
+ *
1330
+ * @param token - 重置令牌(明文,由 requestPasswordReset 生成并由业务层发送给用户)
1331
+ * @param newPassword - 新密码
1332
+ * @returns 成功返回 ok;令牌无效/过期返回 RESET_TOKEN_INVALID,尝试超限返回 RESET_TOKEN_MAX_ATTEMPTS
1333
+ * @example
1334
+ * ```ts
1335
+ * import { iam } from '@h-ai/iam'
1336
+ * const result = await iam.user.confirmPasswordReset('token-from-recovery-link', 'ExampleOnly123!')
1337
+ * if (!result.success)
1338
+ * result.error.code
1339
+ * ```
1340
+ */
1341
+ confirmPasswordReset: (token: string, newPassword: string) => Promise<HaiResult<void>>;
1342
+ /**
1343
+ * 验证密码强度(同步方法)
1344
+ *
1345
+ * 根据密码策略校验长度、大小写、数字、特殊字符等要求。
1346
+ *
1347
+ * @param password - 待校验的密码
1348
+ * @returns 通过返回 ok;不合规返回 PASSWORD_POLICY_VIOLATION
1349
+ */
1350
+ validatePassword: (password: string) => HaiResult<void>;
1351
+ }
1352
+
1353
+ /**
1354
+ * @h-ai/iam — 会话相关类型定义
1355
+ *
1356
+ * 包含: - 认证结果(AuthResult) - 会话类型(Session) - 会话子功能接口(SessionOperations)
1357
+ * @module iam-session-types
1358
+ */
1359
+
1360
+ /**
1361
+ * 认证令牌对(登录成功返回)
1362
+ *
1363
+ * 所有端(Web SSR / H5 SPA / Capacitor App / 未来小程序)
1364
+ * 使用完全相同的 Bearer Token 认证流程。
1365
+ * @example
1366
+ * ```ts
1367
+ * import { iam, type TokenPair } from '@h-ai/iam'
1368
+ * const login = await iam.auth.login({ identifier: 'alice', password: 'ExampleOnly123!' })
1369
+ * if (login.success) {
1370
+ * const tokens: TokenPair = login.data.tokens
1371
+ * const authorization = `${tokens.tokenType} ${tokens.accessToken}` // 仅用于受保护请求。
1372
+ * }
1373
+ * ```
1374
+ */
1375
+ interface TokenPair {
1376
+ /** 访问令牌(短期,用于 API 认证) */
1377
+ accessToken: string;
1378
+ /** 刷新令牌(长期,用于换取新 accessToken) */
1379
+ refreshToken: string;
1380
+ /** accessToken 过期时间(秒) */
1381
+ expiresIn: number;
1382
+ /** 令牌类型,固定为 'Bearer' */
1383
+ tokenType: 'Bearer';
1384
+ }
1385
+ /**
1386
+ * 认证结果
1387
+ *
1388
+ * 登录/注册成功后返回,包含用户信息、令牌、角色权限等。
1389
+ * `roles` / `permissions` 来源于会话创建时写入的 RBAC 数据,
1390
+ * 调用方无需再通过 `verifyToken` 获取。
1391
+ * @example
1392
+ * ```ts
1393
+ * import { iam, type AuthResult } from '@h-ai/iam'
1394
+ * const login = await iam.auth.login({ identifier: 'alice', password: 'ExampleOnly123!' })
1395
+ * if (login.success) {
1396
+ * const authenticated: AuthResult = login.data
1397
+ * authenticated.user.displayName
1398
+ * }
1399
+ * ```
1400
+ */
1401
+ interface AuthResult {
1402
+ /** 用户信息 */
1403
+ user: User;
1404
+ /** 令牌对(替代原来的单个 accessToken) */
1405
+ tokens: TokenPair;
1406
+ /** 角色 code 列表(登录时从 RBAC 写入) */
1407
+ roles: string[];
1408
+ /** 权限 code 列表(登录时从 RBAC 写入) */
1409
+ permissions: string[];
1410
+ /** 协议展示信息(可选) */
1411
+ agreements?: AgreementDisplay;
1412
+ }
1413
+ /**
1414
+ * 会话数据
1415
+ * @example
1416
+ * ```ts
1417
+ * import { iam, type Session } from '@h-ai/iam'
1418
+ * const verified = await iam.auth.verifyToken('token-from-authorization-header')
1419
+ * if (verified.success) {
1420
+ * const session: Session = verified.data
1421
+ * session.permissions.includes('report:read')
1422
+ * }
1423
+ * ```
1424
+ */
1425
+ interface Session {
1426
+ /** 会话内容版本;显式更新产生新版本,内部滑动续期保留版本。 */
1427
+ version: string;
1428
+ /** 认证快照绑定的持久凭据代;改密后的旧会话即使缓存清理失败也拒绝。 */
1429
+ credentialVersion: string;
1430
+ /** API Key 派生会话绑定的 key ID;普通用户登录时省略。 */
1431
+ apiKeyId?: string;
1432
+ /** 当前 key scopes;get/verify/refresh 每次重新验证持久化 key 并收敛权限。 */
1433
+ apiKeyScopes?: string[];
1434
+ /** 用户 ID */
1435
+ userId: string;
1436
+ /** 用户名 */
1437
+ username?: string;
1438
+ /** 显示名称 */
1439
+ displayName?: string;
1440
+ /** 头像 URL */
1441
+ avatarUrl?: string;
1442
+ /** 角色 code 列表(登录时写入,用于会话解析) */
1443
+ roles: string[];
1444
+ /** 权限 code 列表(登录时写入,用于会话解析) */
1445
+ permissions: string[];
1446
+ /** 来源(如 pc/android/ios) */
1447
+ source?: string;
1448
+ /** 访问令牌 */
1449
+ accessToken: string;
1450
+ /** 创建时间 */
1451
+ createdAt: Date;
1452
+ /** 最后活动时间 */
1453
+ lastActiveAt: Date;
1454
+ /** 过期时间 */
1455
+ expiresAt: Date;
1456
+ /** 本会话 access 的签发/滑动有效期,单位秒;创建时固化,刷新沿用该值。 */
1457
+ maxAge: number;
1458
+ /** 扩展数据(内部保留 _tokenPair 供 logout 时吊销 refreshToken) */
1459
+ data?: SessionData;
1460
+ }
1461
+ /**
1462
+ * 会话扩展数据
1463
+ *
1464
+ * 支持开放的 Record 扩展,同时约束内部保留字段 _tokenPair。
1465
+ * @example
1466
+ * ```ts
1467
+ * import type { SessionData } from '@h-ai/iam'
1468
+ * const value: SessionData = { theme: 'dark', locale: 'zh-CN' }
1469
+ * ```
1470
+ */
1471
+ type SessionData = Record<string, unknown> & {
1472
+ /** 令牌对(内部保留字段,由 session.create 写入,logout 时读取) */
1473
+ _tokenPair?: TokenPair;
1474
+ };
1475
+ /**
1476
+ * 创建会话选项
1477
+ * @example
1478
+ * ```ts
1479
+ * import type { CreateSessionOptions } from '@h-ai/iam'
1480
+ * const value: CreateSessionOptions = { userId: 'user-1', source: 'server', maxAge: 3600 }
1481
+ * ```
1482
+ */
1483
+ interface CreateSessionOptions {
1484
+ /** 策略已验证的凭据代;创建前须与当前数据库核对,省略时仅供可信服务端按当前用户签发。 */
1485
+ expectedCredentialVersion?: string;
1486
+ /** 服务端已验证的 API Key 绑定;不得来自未验证客户端输入。 */
1487
+ apiKeyId?: string;
1488
+ apiKeyScopes?: string[];
1489
+ /** 用户 ID */
1490
+ userId: string;
1491
+ /** 用户名 */
1492
+ username?: string;
1493
+ /** 显示名称 */
1494
+ displayName?: string;
1495
+ /** 头像 URL */
1496
+ avatarUrl?: string;
1497
+ /** 角色 code 列表 */
1498
+ roles?: string[];
1499
+ /** 权限 code 列表 */
1500
+ permissions?: string[];
1501
+ /** 来源(如 pc/android/ios) */
1502
+ source?: string;
1503
+ /** 过期时间(秒) */
1504
+ maxAge?: number;
1505
+ /** 扩展数据 */
1506
+ data?: SessionData;
1507
+ }
1508
+ /**
1509
+ * 会话子功能接口
1510
+ * @example
1511
+ * ```ts
1512
+ * import { iam, type SessionOperations } from '@h-ai/iam'
1513
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化。
1514
+ * const operations: SessionOperations = iam.session
1515
+ * const result = await operations.get('token-from-authorization-header')
1516
+ * if (!result.success) {
1517
+ * result.error.code // 调用方将失败交给统一错误边界。
1518
+ * }
1519
+ * else {
1520
+ * result.data
1521
+ * }
1522
+ * ```
1523
+ */
1524
+ interface SessionOperations {
1525
+ /**
1526
+ * 创建会话
1527
+ *
1528
+ * 单设备模式在同一次原子提交内替换用户已有会话;提交失败保留旧会话。
1529
+ *
1530
+ * @param options - 会话创建选项(用户 ID、角色、来源等)
1531
+ * @returns 成功返回完整的 Session 对象(含生成的访问令牌和过期时间)
1532
+ */
1533
+ create: (options: CreateSessionOptions) => Promise<HaiResult<Session>>;
1534
+ /**
1535
+ * 获取会话
1536
+ *
1537
+ * 查询缓存中的会话数据。API Key 会话先重新校验持久化 key 与 scopes;滑动窗口模式下自动续期。
1538
+ * access 到期返回 null;记录保留到 refresh 到期或撤销,允许独立刷新。
1539
+ *
1540
+ * @param accessToken - 访问令牌
1541
+ * @returns 成功返回会话对象或 null(会话不存在/已过期)
1542
+ */
1543
+ get: (accessToken: string) => Promise<HaiResult<Session | null>>;
1544
+ /**
1545
+ * 验证访问令牌
1546
+ *
1547
+ * 等同于 get 但在会话不存在时返回错误而非 null;API Key 撤销/禁用/过期立即拒绝。
1548
+ *
1549
+ * @param accessToken - 访问令牌
1550
+ * @returns 成功返回会话;会话无效返回 SESSION_INVALID
1551
+ */
1552
+ verifyToken: (accessToken: string) => Promise<HaiResult<Session>>;
1553
+ /**
1554
+ * 更新会话
1555
+ *
1556
+ * 合并允许的资料/授权/时间字段(data 浅合并);未传 lastActiveAt 时使用提交时刻。
1557
+ * expiresAt/lastActiveAt 必须是有效日期;不允许修改主体、令牌、固有 maxAge 和版本。
1558
+ *
1559
+ * @param accessToken - 访问令牌
1560
+ * @param data - 要更新的字段(roles、username、source、data 等)
1561
+ * @param expectedVersion - 读取到的 Session.version;过期版本失败,不能覆盖较新的修改
1562
+ * @returns 成功返回 ok;不存在返回 SESSION_NOT_FOUND,版本变化返回 CONFLICT
1563
+ * @example
1564
+ * ```ts
1565
+ * import { iam } from '@h-ai/iam'
1566
+ * // 已完成身份与更新权限校验的服务端上下文。
1567
+ * const token = 'token-from-authorization-header'
1568
+ * const found = await iam.session.get(token)
1569
+ * if (found.success && found.data) {
1570
+ * const updated = await iam.session.update(token, { data: { theme: 'dark' } }, found.data.version)
1571
+ * if (!updated.success)
1572
+ * updated.error.code // 版本冲突后重新读取,不能无条件覆盖。
1573
+ * }
1574
+ * ```
1575
+ */
1576
+ update: (accessToken: string, data: Partial<Session>, expectedVersion: string) => Promise<HaiResult<void>>;
1577
+ /**
1578
+ * 删除会话
1579
+ *
1580
+ * 同时清除用户令牌映射关系。
1581
+ *
1582
+ * @param accessToken - 访问令牌
1583
+ * @returns 已撤销或令牌不存在时返回 ok;共享存储读取或提交失败时返回错误
1584
+ */
1585
+ delete: (accessToken: string) => Promise<HaiResult<void>>;
1586
+ /**
1587
+ * 删除用户所有会话
1588
+ *
1589
+ * 原子删除用户分区内所有会话与 refresh 凭据。
1590
+ *
1591
+ * @param userId - 用户 ID
1592
+ * @returns 成功返回实际删除的会话数量
1593
+ */
1594
+ deleteByUserId: (userId: string) => Promise<HaiResult<number>>;
1595
+ /**
1596
+ * 通过 refreshToken 换取新的 TokenPair
1597
+ *
1598
+ * 验证 refreshToken 有效性,签发新的 accessToken + refreshToken,
1599
+ * 旧 refreshToken 自动失效(Rotation 策略);access 过期不阻止仍有效的 refresh。
1600
+ *
1601
+ * @param refreshToken - 刷新令牌
1602
+ * @returns 成功返回新的 TokenPair;失败返回 TOKEN_REFRESH_FAILED / TOKEN_EXPIRED
1603
+ */
1604
+ refresh: (refreshToken: string) => Promise<HaiResult<TokenPair>>;
1605
+ /**
1606
+ * 吊销 refreshToken(登出时调用)
1607
+ *
1608
+ * @param refreshToken - 刷新令牌
1609
+ * @returns 成功返回 ok;令牌不存在时静默成功
1610
+ */
1611
+ revokeRefresh: (refreshToken: string) => Promise<HaiResult<void>>;
1612
+ /**
1613
+ * 批量更新用户所有活跃会话的 roles / permissions 字段
1614
+ *
1615
+ * 遍历用户缓存中的所有 session token,合并更新指定字段,
1616
+ * 同时清理已失效的会话令牌。用于角色/权限变更后的会话同步。
1617
+ *
1618
+ * @param userId - 用户 ID
1619
+ * @param updates - 要更新的字段(roles / permissions)
1620
+ * @returns 成功返回 ok
1621
+ */
1622
+ patchUserSessions: (userId: string, updates: SessionFieldUpdates) => Promise<HaiResult<void>>;
1623
+ }
1624
+ /**
1625
+ * 会话字段更新(仅限 roles / permissions)
1626
+ *
1627
+ * 用于角色/权限变更后的会话同步。
1628
+ * @example
1629
+ * ```ts
1630
+ * import type { SessionFieldUpdates } from '@h-ai/iam'
1631
+ * const value: SessionFieldUpdates = { roles: ['user'], permissions: ['report:read'] }
1632
+ * ```
1633
+ */
1634
+ interface SessionFieldUpdates {
1635
+ /** 角色 code 列表 */
1636
+ roles?: string[];
1637
+ /** 权限 code 列表 */
1638
+ permissions?: string[];
1639
+ }
1640
+
1641
+ /**
1642
+ * @h-ai/iam — 认证类型定义
1643
+ *
1644
+ * 包含: - 凭证类型(Credentials) - 认证策略接口(AuthStrategy) - 认证操作接口(AuthnOperations)
1645
+ * @module iam-authn-types
1646
+ */
1647
+
1648
+ /**
1649
+ * 用户凭证(用于密码登录)
1650
+ * @example
1651
+ * ```ts
1652
+ * import type { PasswordCredentials } from '@h-ai/iam'
1653
+ * const value: PasswordCredentials = { identifier: 'alice', password: 'ExampleOnly123!' }
1654
+ * ```
1655
+ */
1656
+ interface PasswordCredentials {
1657
+ /** 用户名/邮箱/手机号 */
1658
+ identifier: string;
1659
+ /** 密码 */
1660
+ password: string;
1661
+ }
1662
+ /**
1663
+ * OTP 凭证(用于验证码登录)
1664
+ * @example
1665
+ * ```ts
1666
+ * import type { OtpCredentials } from '@h-ai/iam'
1667
+ * const value: OtpCredentials = { identifier: 'alice@example.com', code: '123456' }
1668
+ * ```
1669
+ */
1670
+ interface OtpCredentials {
1671
+ /** 邮箱/手机号 */
1672
+ identifier: string;
1673
+ /** 验证码 */
1674
+ code: string;
1675
+ }
1676
+ /**
1677
+ * LDAP 凭证
1678
+ * @example
1679
+ * ```ts
1680
+ * import type { LdapCredentials } from '@h-ai/iam'
1681
+ * const value: LdapCredentials = { username: 'alice', password: 'ExampleOnly123!' }
1682
+ * ```
1683
+ */
1684
+ interface LdapCredentials {
1685
+ /** 用户名 */
1686
+ username: string;
1687
+ /** 密码 */
1688
+ password: string;
1689
+ }
1690
+ /**
1691
+ * API Key 凭证(用于 API Key 认证)
1692
+ * @example
1693
+ * ```ts
1694
+ * import { iam, type ApiKeyCredentials } from '@h-ai/iam'
1695
+ * const created = await iam.apiKey.createApiKey('user-1', { name: 'report-reader', scopes: ['report:read'] })
1696
+ * if (created.success) {
1697
+ * const credentials: ApiKeyCredentials = { key: created.data.rawKey }
1698
+ * const authenticated = await iam.auth.loginWithApiKey(credentials)
1699
+ * if (!authenticated.success)
1700
+ * authenticated.error.code
1701
+ * }
1702
+ * ```
1703
+ */
1704
+ interface ApiKeyCredentials {
1705
+ /** 明文 API Key */
1706
+ key: string;
1707
+ }
1708
+ /**
1709
+ * 统一凭证类型
1710
+ * @example
1711
+ * ```ts
1712
+ * import type { Credentials } from '@h-ai/iam'
1713
+ * const value: Credentials = { type: 'otp', identifier: 'alice@example.com', code: '123456' }
1714
+ * ```
1715
+ */
1716
+ type Credentials = {
1717
+ type: 'password';
1718
+ } & PasswordCredentials | {
1719
+ type: 'otp';
1720
+ } & OtpCredentials | {
1721
+ type: 'ldap';
1722
+ } & LdapCredentials | {
1723
+ type: 'apikey';
1724
+ } & ApiKeyCredentials;
1725
+ /**
1726
+ * 策略内部可信认证快照;凭据代来自实际验证的用户行,不能用会话创建时的新快照替换。
1727
+ * @internal
1728
+ * @example 模块内部上下文
1729
+ * ```ts
1730
+ * function credentialSnapshot(user: AuthenticatedUser) {
1731
+ * return { userId: user.id, expectedCredentialVersion: user.credentialVersion }
1732
+ * }
1733
+ * ```
1734
+ */
1735
+ interface AuthenticatedUser extends User {
1736
+ /** 密码最终提交时更换;仅在服务端策略和会话构造间传递。 */
1737
+ credentialVersion: string;
1738
+ }
1739
+ /**
1740
+ * 认证策略接口
1741
+ *
1742
+ * 所有认证方式(密码/OTP/LDAP)都实现此接口
1743
+ * @example
1744
+ * ```ts
1745
+ * import type { AuthStrategy, Credentials } from '@h-ai/iam'
1746
+ * async function authenticate(strategy: AuthStrategy, credentials: Credentials) {
1747
+ * const result = await strategy.authenticate(credentials)
1748
+ * if (!result.success)
1749
+ * return result
1750
+ * return { userId: result.data.id, credentialVersion: result.data.credentialVersion }
1751
+ * }
1752
+ * ```
1753
+ */
1754
+ interface AuthStrategy {
1755
+ /** 策略类型 */
1756
+ readonly type: AuthStrategyType;
1757
+ /** 策略名称 */
1758
+ readonly name: string;
1759
+ /**
1760
+ * 执行认证
1761
+ *
1762
+ * @param credentials - 统一凭证(包含 type 字段标识认证方式)
1763
+ * @returns 认证成功返回用户信息;失败返回对应错误码(INVALID_CREDENTIALS / USER_LOCKED 等)
1764
+ */
1765
+ authenticate: (credentials: Credentials) => Promise<HaiResult<AuthenticatedUser>>;
1766
+ }
1767
+ /**
1768
+ * 认证子功能接口
1769
+ * @example
1770
+ * ```ts
1771
+ * import { iam, type AuthnOperations } from '@h-ai/iam'
1772
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化。
1773
+ * const operations: AuthnOperations = iam.auth
1774
+ * const result = await operations.verifyToken('token-from-authorization-header')
1775
+ * if (!result.success) {
1776
+ * result.error.code // 调用方将失败交给统一错误边界。
1777
+ * }
1778
+ * else {
1779
+ * result.data
1780
+ * }
1781
+ * ```
1782
+ */
1783
+ interface AuthnOperations {
1784
+ /**
1785
+ * 登录(使用密码)
1786
+ *
1787
+ * 检查登录方式启用 → 密码策略认证 → 创建会话 → 返回令牌。
1788
+ *
1789
+ * @param credentials - 密码凭证(identifier + password)
1790
+ * @returns 成功返回 AuthResult(用户信息、令牌、协议展示);失败返回错误
1791
+ */
1792
+ login: (credentials: PasswordCredentials) => Promise<HaiResult<AuthResult>>;
1793
+ /**
1794
+ * 使用验证码登录
1795
+ *
1796
+ * @param credentials - OTP 凭证(identifier + code)
1797
+ * @returns 成功返回 AuthResult;验证码无效/过期返回 OTP_INVALID
1798
+ */
1799
+ loginWithOtp: (credentials: OtpCredentials) => Promise<HaiResult<AuthResult>>;
1800
+ /**
1801
+ * 使用 LDAP 登录
1802
+ *
1803
+ * @param credentials - LDAP 凭证(username + password)
1804
+ * @returns 成功返回 AuthResult(自动同步本地用户);失败返回错误
1805
+ */
1806
+ loginWithLdap: (credentials: LdapCredentials) => Promise<HaiResult<AuthResult>>;
1807
+ /**
1808
+ * 使用 API Key 登录
1809
+ *
1810
+ * 验证 API Key 有效性 → 查找关联用户 → 按 scopes 收敛授权 → 创建绑定 key 的会话。
1811
+ * 空 scopes 无操作权限;显式 * 也不超出主体权限。受限 key 通过 permission 授权,不保留角色入口。
1812
+ *
1813
+ * @param credentials - API Key 凭证
1814
+ * @returns 成功返回 AuthResult;API Key 无效/过期/禁用返回对应错误
1815
+ */
1816
+ loginWithApiKey: (credentials: ApiKeyCredentials) => Promise<HaiResult<AuthResult>>;
1817
+ /**
1818
+ * 登出
1819
+ *
1820
+ * 按完整访问令牌原子删除会话及关联 refresh,access 已到期也撤销待刷新记录。
1821
+ * 无效或不存在的令牌幂等成功;缓存读取/提交失败必须返回错误,不能宣称服务端已退出。
1822
+ *
1823
+ * @param accessToken - 访问令牌
1824
+ * @returns 撤销完成或令牌不存在返回 ok;共享存储失败返回错误,恢复后可用同一令牌重试
1825
+ */
1826
+ logout: (accessToken: string) => Promise<HaiResult<void>>;
1827
+ /**
1828
+ * 验证令牌
1829
+ *
1830
+ * 验证会话并读取当前用户状态、角色与权限;重新应用 API Key scopes,依赖失败即拒绝。
1831
+ * 会话同步仅是缓存快照,受保护请求使用此入口而非低层 session.verifyToken。
1832
+ *
1833
+ * @param accessToken - 访问令牌
1834
+ * @returns 成功返回会话信息;令牌无效/过期返回 SESSION_INVALID
1835
+ */
1836
+ verifyToken: (accessToken: string) => Promise<HaiResult<Session>>;
1837
+ /**
1838
+ * 发送验证码
1839
+ *
1840
+ * @param identifier - 用户标识(邮箱/手机号)
1841
+ * @returns 成功返回验证码过期时间;频率限制返回 OTP_RESEND_TOO_FAST
1842
+ */
1843
+ sendOtp: (identifier: string) => Promise<HaiResult<{
1844
+ expiresAt: Date;
1845
+ }>>;
1846
+ /**
1847
+ * 注册并登录(一站式)
1848
+ *
1849
+ * 先注册用户(含默认角色分配),成功后立即登录并返回令牌。
1850
+ * 注册失败则直接返回注册错误;注册成功但登录失败则返回登录错误。
1851
+ *
1852
+ * @param options - 注册选项(用户名、密码、邮箱等)
1853
+ * @returns 成功返回 AuthResult(用户信息、令牌、协议展示);失败返回对应错误码
1854
+ */
1855
+ registerAndLogin: (options: RegisterOptions) => Promise<HaiResult<AuthResult>>;
1856
+ }
1857
+
1858
+ /**
1859
+ * @h-ai/iam — LDAP 认证策略
1860
+ *
1861
+ * LDAP 目录认证方式
1862
+ * @module iam-authn-ldap-strategy
1863
+ */
1864
+
1865
+ /**
1866
+ * LDAP 客户端接口
1867
+ * @internal
1868
+ * @example 模块内部上下文
1869
+ * ```ts
1870
+ * async function lookup(client: LdapClient) {
1871
+ * const found = await client.search('ou=users,dc=example,dc=com', '(uid=alice)', ['uid', 'mail'])
1872
+ * if (!found.success)
1873
+ * return found
1874
+ * return found.data.map(entry => entry.dn)
1875
+ * }
1876
+ * ```
1877
+ */
1878
+ interface LdapClient {
1879
+ /**
1880
+ * 绑定(认证)
1881
+ */
1882
+ bind: (dn: string, password: string) => Promise<HaiResult<void>>;
1883
+ /**
1884
+ * 搜索用户
1885
+ */
1886
+ search: (base: string, filter: string, attributes: string[]) => Promise<HaiResult<LdapSearchEntry[]>>;
1887
+ /**
1888
+ * 解除绑定
1889
+ */
1890
+ unbind: () => Promise<HaiResult<void>>;
1891
+ }
1892
+ /**
1893
+ * LDAP 搜索结果条目
1894
+ * @internal
1895
+ * @example 模块内部上下文
1896
+ * ```ts
1897
+ * const entry: LdapSearchEntry = { dn: 'uid=alice,ou=users,dc=example,dc=com', attributes: { uid: 'alice', mail: ['alice@example.com'] } }
1898
+ * const username = entry.attributes.uid
1899
+ * ```
1900
+ */
1901
+ interface LdapSearchEntry {
1902
+ /** DN */
1903
+ dn: string;
1904
+ /** 属性 */
1905
+ attributes: Record<string, string | string[]>;
1906
+ }
1907
+ /**
1908
+ * LDAP 客户端工厂
1909
+ * @example
1910
+ * ```ts
1911
+ * import type { LdapClientFactory, LdapConfig } from '@h-ai/iam'
1912
+ * async function check(factory: LdapClientFactory, config: LdapConfig) {
1913
+ * const opened = await factory(config)
1914
+ * if (!opened.success)
1915
+ * return opened
1916
+ * const result = await opened.data.bind(config.bindDn, config.bindPassword)
1917
+ * const closed = await opened.data.unbind()
1918
+ * if (!closed.success)
1919
+ * return closed
1920
+ * return result
1921
+ * }
1922
+ * ```
1923
+ */
1924
+ type LdapClientFactory = (config: LdapConfig) => Promise<HaiResult<LdapClient>>;
1925
+
1926
+ /** 提供给认证页面的白名单配置;不含连接信息、密钥及安全状态。 */
1927
+
1928
+ /**
1929
+ * 认证页面可读取的白名单配置;能力开关同时考虑实际运行时依赖,不能用于服务端授权。
1930
+ * @example
1931
+ * ```ts
1932
+ * import { iam, type IamPublicConfig } from '@h-ai/iam'
1933
+ * const config: IamPublicConfig | null = iam.publicConfig
1934
+ * if (config) {
1935
+ * const canOfferEmailOtp = config.login.email
1936
+ * const passwordMinLength = config.password.minLength
1937
+ * }
1938
+ * ```
1939
+ */
1940
+ interface IamPublicConfig {
1941
+ /** 页面显示密码策略,不包含密码哈希或账户信息。 */
1942
+ password: ReturnType<typeof PasswordConfigSchema.parse>;
1943
+ /** 自助注册开关;管理端创建账户仍需要独立授权。 */
1944
+ register: {
1945
+ enabled: boolean;
1946
+ };
1947
+ /** 方式开关同时考虑配置和发送回调就绪状态,避免展示无法使用的入口。 */
1948
+ login: {
1949
+ password: boolean;
1950
+ otp: boolean;
1951
+ ldap: boolean;
1952
+ email: boolean;
1953
+ sms: boolean;
1954
+ };
1955
+ /** 重置能力同时要求配置启用和通知发送回调就绪。 */
1956
+ passwordReset: {
1957
+ enabled: boolean;
1958
+ mode: 'email' | 'phone';
1959
+ };
1960
+ /** 单位:验证码位数、重发间隔秒;安全计数与期限只由服务端执行。 */
1961
+ otp: {
1962
+ length: number;
1963
+ resendInterval: number;
1964
+ };
1965
+ /** 用户协议及隐私政策展示配置。 */
1966
+ agreements: IamConfig['agreements'];
1967
+ /** 已经由外观 Schema 校验的标题、图像 URL 和布局。 */
1968
+ ui: ReturnType<typeof AuthUiConfigSchema.parse>;
1969
+ /** 默认 access 有效时长,单位秒;真实认证期限由服务端会话状态决定。 */
1970
+ session: {
1971
+ maxAge: number;
1972
+ };
1973
+ }
1974
+
1975
+ /**
1976
+ * @h-ai/iam — 一次性票据类型
1977
+ *
1978
+ * 定义通用的短期、一次性能力票据(capability ticket):由已认证的上下文签发,
1979
+ * 绑定主体、用途与授权信息,在无法携带 Bearer Token 的通道(如 WebSocket URL)中
1980
+ * 用作一次性入场凭证。典型用途:AI 语音 WebSocket 接入。
1981
+ * @module ticket/iam-ticket-types
1982
+ */
1983
+
1984
+ /**
1985
+ * 票据授权绑定信息
1986
+ *
1987
+ * 消费时原样返回,供服务端确认本次操作、模型、会话等参数与签发时一致。
1988
+ * 除固定字段外允许应用自定义键值。
1989
+ * @example
1990
+ * ```ts
1991
+ * import type { TicketGrant } from '@h-ai/iam'
1992
+ * const value: TicketGrant = { operation: 'transcribe', model: 'speech-model', sessionId: 'conversation-1' }
1993
+ * ```
1994
+ */
1995
+ interface TicketGrant {
1996
+ /** 操作类型(如 `'transcribe'` | `'synthesize'` 或应用自定义) */
1997
+ operation?: string;
1998
+ /** 模型 ID */
1999
+ model?: string;
2000
+ /** 会话 ID */
2001
+ sessionId?: string;
2002
+ /** 应用自定义绑定字段 */
2003
+ [key: string]: unknown;
2004
+ }
2005
+ /**
2006
+ * 签发一次性票据的选项
2007
+ * @example
2008
+ * ```ts
2009
+ * import type { IssueTicketOptions } from '@h-ai/iam'
2010
+ * const value: IssueTicketOptions = { subjectId: 'user-1', purpose: 'ai-audio', ttlMs: 30000, grant: { operation: 'transcribe' } }
2011
+ * ```
2012
+ */
2013
+ interface IssueTicketOptions {
2014
+ /** 主体 ID(票据绑定的用户 / 主体,消费时原样返回) */
2015
+ subjectId: string;
2016
+ /** 票据用途(如 `'ai-audio'`),消费时校验一致 */
2017
+ purpose: string;
2018
+ /** 授权绑定信息(操作 / 模型 / 会话等,消费时原样返回) */
2019
+ grant?: TicketGrant;
2020
+ /** 有效期(毫秒,默认 30000) */
2021
+ ttlMs?: number;
2022
+ }
2023
+ /**
2024
+ * 签发结果
2025
+ * @example
2026
+ * ```ts
2027
+ * import { iam, type IssuedTicket } from '@h-ai/iam'
2028
+ * const issued = await iam.ticket.issue({ subjectId: 'user-1', purpose: 'ai-audio' })
2029
+ * if (issued.success) {
2030
+ * const value: IssuedTicket = issued.data
2031
+ * value.expiresAt // 不能延长服务端签发期限;票据只能消费一次。
2032
+ * }
2033
+ * ```
2034
+ */
2035
+ interface IssuedTicket {
2036
+ /** 一次性票据值(密码学安全随机,base64url) */
2037
+ ticket: string;
2038
+ /** 过期时间(Unix 毫秒) */
2039
+ expiresAt: number;
2040
+ }
2041
+ /**
2042
+ * 消费票据的选项
2043
+ * @example
2044
+ * ```ts
2045
+ * import type { ConsumeTicketOptions } from '@h-ai/iam'
2046
+ * const value: ConsumeTicketOptions = { purpose: 'ai-audio' }
2047
+ * ```
2048
+ */
2049
+ interface ConsumeTicketOptions {
2050
+ /** 期望用途;与签发用途不一致时返回 `TICKET_INVALID`(防止跨用途重放) */
2051
+ purpose?: string;
2052
+ }
2053
+ /**
2054
+ * 消费结果(校验通过并原子消费后返回)
2055
+ * @example
2056
+ * ```ts
2057
+ * import { iam, type ConsumedTicket } from '@h-ai/iam'
2058
+ * const consumed = await iam.ticket.consume('ticket-from-upgrade-request', { purpose: 'ai-audio' })
2059
+ * if (consumed.success) {
2060
+ * const authorization: ConsumedTicket = consumed.data
2061
+ * authorization.grant.operation // 校验与本次请求操作相同。
2062
+ * }
2063
+ * ```
2064
+ */
2065
+ interface ConsumedTicket {
2066
+ /** 票据绑定的主体 ID */
2067
+ subjectId: string;
2068
+ /** 票据用途 */
2069
+ purpose: string;
2070
+ /** 授权绑定信息 */
2071
+ grant: TicketGrant;
2072
+ }
2073
+ /**
2074
+ * 一次性票据操作接口(通过 `iam.ticket` 访问)
2075
+ *
2076
+ * 提供密码学安全、带 TTL、原子单次消费的能力票据签发与消费。
2077
+ * @example
2078
+ * ```ts
2079
+ * import { iam, type TicketOperations } from '@h-ai/iam'
2080
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化。
2081
+ * const operations: TicketOperations = iam.ticket
2082
+ * const result = await operations.issue({ subjectId: 'user-1', purpose: 'ai-audio', ttlMs: 30000 })
2083
+ * if (!result.success) {
2084
+ * result.error.code // 调用方将失败交给统一错误边界。
2085
+ * }
2086
+ * else {
2087
+ * result.data
2088
+ * }
2089
+ * ```
2090
+ */
2091
+ interface TicketOperations {
2092
+ /**
2093
+ * 签发一次性票据
2094
+ *
2095
+ * 生成密码学安全随机值,绑定主体 / 用途 / 授权信息并按 TTL 存入 cache。
2096
+ *
2097
+ * @param options - 签发选项
2098
+ * @returns 票据值与过期时间
2099
+ */
2100
+ issue: (options: IssueTicketOptions) => Promise<HaiResult<IssuedTicket>>;
2101
+ /**
2102
+ * 原子消费一次性票据
2103
+ *
2104
+ * 单次有效:并发消费同一票据时只有一个成功,其余返回 `TICKET_INVALID`。
2105
+ * 票据不存在 / 已过期 / 已消费 / 用途不匹配时返回错误。
2106
+ *
2107
+ * @param ticket - 票据值
2108
+ * @param options - 消费选项(可校验用途)
2109
+ * @returns 主体 + 用途 + 授权信息
2110
+ */
2111
+ consume: (ticket: string, options?: ConsumeTicketOptions) => Promise<HaiResult<ConsumedTicket>>;
2112
+ }
2113
+
2114
+ /**
2115
+ * IAM 错误码及 HTTP 状态定义;调用方按 code 分支,底层原因只用于脱敏诊断。
2116
+ * @example
2117
+ * ```ts
2118
+ * import { HaiIamError, iam } from '@h-ai/iam'
2119
+ * const result = await iam.auth.verifyToken('token-from-authorization-header')
2120
+ * if (!result.success && result.error.code === HaiIamError.SESSION_INVALID.code) {
2121
+ * // 由应用的认证边界转为重新登录响应,不泄露底层 cause。
2122
+ * }
2123
+ * ```
2124
+ */
2125
+ declare const HaiIamError: {
2126
+ readonly AUTH_FAILED: _h_ai_core.HaiErrorDef;
2127
+ readonly INVALID_CREDENTIALS: _h_ai_core.HaiErrorDef;
2128
+ readonly USER_NOT_FOUND: _h_ai_core.HaiErrorDef;
2129
+ readonly USER_DISABLED: _h_ai_core.HaiErrorDef;
2130
+ readonly USER_LOCKED: _h_ai_core.HaiErrorDef;
2131
+ readonly USER_ALREADY_EXISTS: _h_ai_core.HaiErrorDef;
2132
+ readonly PASSWORD_EXPIRED: _h_ai_core.HaiErrorDef;
2133
+ readonly PASSWORD_POLICY_VIOLATION: _h_ai_core.HaiErrorDef;
2134
+ readonly OTP_INVALID: _h_ai_core.HaiErrorDef;
2135
+ readonly NOT_INITIALIZED: _h_ai_core.HaiErrorDef;
2136
+ readonly OTP_RESEND_TOO_FAST: _h_ai_core.HaiErrorDef;
2137
+ readonly LOGIN_DISABLED: _h_ai_core.HaiErrorDef;
2138
+ readonly REGISTER_DISABLED: _h_ai_core.HaiErrorDef;
2139
+ readonly STRATEGY_NOT_SUPPORTED: _h_ai_core.HaiErrorDef;
2140
+ readonly APIKEY_INVALID: _h_ai_core.HaiErrorDef;
2141
+ readonly APIKEY_EXPIRED: _h_ai_core.HaiErrorDef;
2142
+ readonly APIKEY_DISABLED: _h_ai_core.HaiErrorDef;
2143
+ readonly APIKEY_NOT_FOUND: _h_ai_core.HaiErrorDef;
2144
+ readonly RESET_TOKEN_INVALID: _h_ai_core.HaiErrorDef;
2145
+ readonly RESET_TOKEN_EXPIRED: _h_ai_core.HaiErrorDef;
2146
+ readonly RESET_TOKEN_MAX_ATTEMPTS: _h_ai_core.HaiErrorDef;
2147
+ readonly OTP_EXPIRED: _h_ai_core.HaiErrorDef;
2148
+ readonly SECURITY_BUSY: _h_ai_core.HaiErrorDef;
2149
+ readonly PASSWORD_RESET_DISABLED: _h_ai_core.HaiErrorDef;
2150
+ readonly SESSION_NOT_FOUND: _h_ai_core.HaiErrorDef;
2151
+ readonly SESSION_EXPIRED: _h_ai_core.HaiErrorDef;
2152
+ readonly SESSION_INVALID: _h_ai_core.HaiErrorDef;
2153
+ readonly SESSION_CREATE_FAILED: _h_ai_core.HaiErrorDef;
2154
+ readonly TOKEN_EXPIRED: _h_ai_core.HaiErrorDef;
2155
+ readonly TOKEN_INVALID: _h_ai_core.HaiErrorDef;
2156
+ readonly TOKEN_REFRESH_FAILED: _h_ai_core.HaiErrorDef;
2157
+ readonly PERMISSION_DENIED: _h_ai_core.HaiErrorDef;
2158
+ readonly ROLE_NOT_FOUND: _h_ai_core.HaiErrorDef;
2159
+ readonly PERMISSION_NOT_FOUND: _h_ai_core.HaiErrorDef;
2160
+ readonly ROLE_ALREADY_EXISTS: _h_ai_core.HaiErrorDef;
2161
+ readonly PERMISSION_ALREADY_EXISTS: _h_ai_core.HaiErrorDef;
2162
+ readonly LDAP_CONNECTION_FAILED: _h_ai_core.HaiErrorDef;
2163
+ readonly LDAP_BIND_FAILED: _h_ai_core.HaiErrorDef;
2164
+ readonly LDAP_SEARCH_FAILED: _h_ai_core.HaiErrorDef;
2165
+ readonly TICKET_INVALID: _h_ai_core.HaiErrorDef;
2166
+ readonly TICKET_EXPIRED: _h_ai_core.HaiErrorDef;
2167
+ readonly TICKET_ISSUE_FAILED: _h_ai_core.HaiErrorDef;
2168
+ readonly REPOSITORY_ERROR: _h_ai_core.HaiErrorDef;
2169
+ readonly NOT_FOUND: _h_ai_core.HaiErrorDef;
2170
+ readonly CONFLICT: _h_ai_core.HaiErrorDef;
2171
+ readonly FORBIDDEN: _h_ai_core.HaiErrorDef;
2172
+ readonly INVALID_ARGUMENT: _h_ai_core.HaiErrorDef;
2173
+ readonly CONFIG_ERROR: _h_ai_core.HaiErrorDef;
2174
+ readonly INTERNAL_ERROR: _h_ai_core.HaiErrorDef;
2175
+ };
2176
+ /**
2177
+ * 已成功发布的认证通知上下文;发送服务必须按幂等键持久化去重。
2178
+ * 回调抛错代表送达结果未知;IAM 不自动重发,也不回滚已经发布的凭据。
2179
+ * @example
2180
+ * ```ts
2181
+ * import type { IamNotificationContext } from '@h-ai/iam'
2182
+ * async function deliver(context: IamNotificationContext, enqueue: (key: string, expiresAt: Date) => Promise<void>) {
2183
+ * // 接收端持久去重;回调失败代表送达未知,不能擅自生成新的幂等键重发。
2184
+ * await enqueue(context.idempotencyKey, context.expiresAt)
2185
+ * }
2186
+ * ```
2187
+ */
2188
+ interface IamNotificationContext {
2189
+ /** 同一次凭据发布的稳定 ID,不包含验证码或明文令牌。 */
2190
+ readonly idempotencyKey: string;
2191
+ /** 凭据过期时间;迟到通知不得延长其有效期。 */
2192
+ readonly expiresAt: Date;
2193
+ }
2194
+ /**
2195
+ * IAM 初始化配置
2196
+ *
2197
+ * 包含 Zod 校验的设置字段和运行时依赖。
2198
+ * 传入 `iam.init()` 的唯一参数。
2199
+ * @example
2200
+ * ```ts
2201
+ * import type { IamConfigInput } from '@h-ai/iam'
2202
+ * const value: IamConfigInput = { login: { password: true, otp: false }, register: { enabled: false }, seedDefaultData: false }
2203
+ * ```
2204
+ */
2205
+ interface IamConfigInput extends IamConfigSettingsInput {
2206
+ /**
2207
+ * 可选、已初始化的触达模块;由应用安装并注入,IAM 不导入或关闭该模块。
2208
+ * 自动使用 otp_email、otp_sms、password_reset、password_reset_sms 模板;显式发送回调优先。
2209
+ */
2210
+ reach?: ReachFunctions;
2211
+ /** LDAP 客户端工厂(可选);启用 LDAP 且未注入时才加载应用安装的 ldapts。 */
2212
+ ldapClientFactory?: LdapClientFactory;
2213
+ /** LDAP 用户同步开关(默认 true) */
2214
+ ldapSyncUser?: boolean;
2215
+ /**
2216
+ * 密码重置令牌回调(可选)
2217
+ *
2218
+ * 当用户请求密码重置时,框架生成令牌后通过此回调通知业务层,
2219
+ * 业务层负责将令牌通过邮件/短信等渠道发送给用户。
2220
+ * 也可传入已初始化的 reach 自动发送;两者均未配置时重置功能不可用。
2221
+ *
2222
+ * @param user - 请求重置的用户信息
2223
+ * @param token - 重置令牌(明文,需发送给用户)
2224
+ * @param context - 令牌有效期及接收端必须复用的幂等键;发送失败/超时视为结果未知。
2225
+ */
2226
+ onPasswordResetRequest?: (user: User, token: string, context: IamNotificationContext) => Promise<void>;
2227
+ /**
2228
+ * OTP 邮件验证码发送回调(可选)
2229
+ *
2230
+ * 当用户请求 OTP 验证码时,框架生成验证码后通过此回调通知业务层,
2231
+ * 业务层负责将验证码通过邮件发送给用户。
2232
+ * 显式回调覆盖 Reach 的 otp_email 模板;两者均不可用时该登录入口关闭。
2233
+ * 投递失败须拒绝 Promise,异常由 IAM 转为业务结果,不要在回调中吞掉失败。
2234
+ *
2235
+ * @param email - 目标邮箱
2236
+ * @param code - 验证码
2237
+ */
2238
+ onOtpSendEmail?: (email: string, code: string, context: IamNotificationContext) => Promise<void>;
2239
+ /**
2240
+ * OTP 短信验证码发送回调(可选)
2241
+ *
2242
+ * 当用户请求 OTP 验证码时,框架生成验证码后通过此回调通知业务层,
2243
+ * 业务层负责将验证码通过短信发送给用户。
2244
+ * 显式回调覆盖 Reach 的 otp_sms 模板;两者均不可用时该登录入口关闭。
2245
+ * 投递失败须拒绝 Promise,异常由 IAM 转为业务结果,不要在回调中吞掉失败。
2246
+ *
2247
+ * @param phone - 目标手机号
2248
+ * @param code - 验证码
2249
+ */
2250
+ onOtpSendSms?: (phone: string, code: string, context: IamNotificationContext) => Promise<void>;
2251
+ }
2252
+ /**
2253
+ * IAM 函数接口
2254
+ *
2255
+ * 统一聚合所有 IAM 功能。
2256
+ * @example
2257
+ * ```ts
2258
+ * import { iam, type IamFunctions } from '@h-ai/iam'
2259
+ * const service: IamFunctions = iam
2260
+ * // 应用先初始化 Cache、RelDB、Crypto;关闭时先停止接收请求。
2261
+ * const initialized = await service.init({ seedDefaultData: false })
2262
+ * if (initialized.success) {
2263
+ * const users = await service.user.listUsers({ page: 1, pageSize: 20 })
2264
+ * if (!users.success)
2265
+ * users.error.code
2266
+ * await service.close() // IAM 不关闭应用注入的依赖。
2267
+ * }
2268
+ * ```
2269
+ */
2270
+ interface IamFunctions {
2271
+ /**
2272
+ * 初始化 IAM 服务
2273
+ *
2274
+ * 已初始化时先关闭旧内部状态再重新初始化;并发初始化返回配置错误。
2275
+ * 内部按依赖顺序创建 session → authz → authn → user 子功能,
2276
+ * 并可选执行种子数据初始化。
2277
+ *
2278
+ * @param config - IAM 初始化配置(可选 session/password/LDAP 等策略配置)
2279
+ * @returns 成功返回 `ok(undefined)`;失败返回含错误码的 `err`
2280
+ *
2281
+ * @example
2282
+ * ```ts
2283
+ * import { iam } from '@h-ai/iam'
2284
+ * // 共享 RelDB、Cache 已由应用初始化;IAM 会确保 Crypto 可用。
2285
+ * const result = await iam.init({ session: { maxAge: 86400 } })
2286
+ * if (!result.success)
2287
+ * result.error.code // 交给应用统一错误边界,不能继续接收认证请求。
2288
+ * ```
2289
+ */
2290
+ init: (config: IamConfigInput) => Promise<HaiResult<void>>;
2291
+ /**
2292
+ * 关闭 IAM 服务
2293
+ *
2294
+ * 释放所有内部子功能引用,将模块恢复到未初始化状态。
2295
+ * 关闭后访问 `iam.auth` 等属性将返回未初始化错误。
2296
+ */
2297
+ close: () => Promise<void>;
2298
+ /** 当前脱敏后的配置快照(未初始化时为 null) */
2299
+ readonly config: IamConfig | null;
2300
+ /** 安全且反映实际可用能力的认证页面配置。 */
2301
+ readonly publicConfig: IamPublicConfig | null;
2302
+ /** 是否已初始化 */
2303
+ readonly isInitialized: boolean;
2304
+ /** 注册功能是否启用(未初始化或未配置时默认启用) */
2305
+ readonly isRegisterEnabled: boolean;
2306
+ /** 认证操作(登录、登出、令牌验证等) */
2307
+ readonly auth: AuthnOperations;
2308
+ /** 用户管理(注册、查询、更新、密码管理等) */
2309
+ readonly user: UserOperations;
2310
+ /** 授权管理(角色/权限 CRUD、用户角色分配、权限检查) */
2311
+ readonly authz: AuthzOperations;
2312
+ /** 会话管理(创建、查询、验证、删除会话) */
2313
+ readonly session: SessionOperations;
2314
+ /** API Key 管理(创建、列表、吊销、验证),未启用 apikey 登录时返回未初始化代理 */
2315
+ readonly apiKey: ApiKeyOperations;
2316
+ /** 一次性能力票据(签发 / 原子消费短期票据,用于 WebSocket 等无法携带 Bearer Token 的通道) */
2317
+ readonly ticket: TicketOperations;
2318
+ }
2319
+
2320
+ export { type AgreementConfig, AgreementConfigSchema, type AgreementDisplay, type ApiKey, type ApiKeyConfig, ApiKeyConfigSchema, type ApiKeyCredentials, type ApiKeyOperations, type ApiKeySortDirection, type ApiKeySortField, type AuthResult, type AuthStrategy, type AuthStrategyType, AuthStrategyTypeSchema, type AuthUiConfig, AuthUiConfigSchema, type AuthnOperations, type AuthzOperations, type ConsumeTicketOptions, type ConsumedTicket, type CreateApiKeyOptions, type CreateApiKeyResult, type CreateSessionOptions, type Credentials, HaiIamError, type IamConfig, type IamConfigInput, IamConfigSchema, type IamConfigSettingsInput, type IamFunctions, type IamNotificationContext, type IamPublicConfig, type IssueTicketOptions, type IssuedTicket, type LdapClientFactory, type LdapConfig, LdapConfigSchema, type LdapCredentials, type ListApiKeysOptions, type ListUsersOptions, type LoginConfig, LoginConfigSchema, type OtpConfig, OtpConfigSchema, type OtpCredentials, type PasswordConfig, PasswordConfigSchema, type PasswordCredentials, type PasswordResetConfig, PasswordResetConfigSchema, type Permission, type PermissionQueryOptions, type PermissionType, type RbacConfig, RbacConfigSchema, type RegisterConfig, RegisterConfigSchema, type RegisterOptions, type RegisterResult, type Role, type SecurityConfig, SecurityConfigSchema, type Session, type SessionConfig, SessionConfigSchema, type SessionData, type SessionFieldUpdates, type SessionOperations, type StoredUser, type TicketGrant, type TicketOperations, type TokenPair, type UpdateCurrentUserInput, type User, type UserOperations, type UserSortDirection, type UserSortField };