@h-ai/iam 0.1.0-alpha.72 → 0.1.0-alpha.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.d.ts CHANGED
@@ -2,6 +2,7 @@ import { z } from 'zod';
2
2
  import * as _h_ai_core from '@h-ai/core';
3
3
  import { HaiResult, PaginationOptionsInput, PaginatedResult } from '@h-ai/core';
4
4
  import { ReachFunctions } from '@h-ai/reach';
5
+ import { Challenge } from 'altcha/lib';
5
6
  import { DmlWithTxOperations } from '@h-ai/reldb';
6
7
 
7
8
  /**
@@ -61,7 +62,10 @@ declare const PasswordConfigSchema: z.ZodObject<{
61
62
  requireLowercase: z.ZodDefault<z.ZodBoolean>;
62
63
  requireNumber: z.ZodDefault<z.ZodBoolean>;
63
64
  requireSpecialChar: z.ZodDefault<z.ZodBoolean>;
65
+ minCharacterClasses: z.ZodDefault<z.ZodNumber>;
64
66
  expirationDays: z.ZodDefault<z.ZodNumber>;
67
+ preventSamePassword: z.ZodDefault<z.ZodBoolean>;
68
+ requireInitialChange: z.ZodDefault<z.ZodBoolean>;
65
69
  }, z.core.$strip>;
66
70
  /**
67
71
  * 密码配置类型
@@ -255,9 +259,25 @@ type RegisterConfig = z.infer<typeof RegisterConfigSchema>;
255
259
  * ```
256
260
  */
257
261
  declare const SecurityConfigSchema: z.ZodObject<{
262
+ lockoutEnabled: z.ZodDefault<z.ZodBoolean>;
263
+ failureWindow: z.ZodDefault<z.ZodNumber>;
258
264
  maxLoginAttempts: z.ZodDefault<z.ZodNumber>;
259
265
  lockoutDuration: z.ZodDefault<z.ZodNumber>;
260
266
  }, z.core.$strip>;
267
+ /**
268
+ * 自托管 ALTCHA 计算挑战;默认关闭,强度与有效期由应用设置。
269
+ * @example
270
+ * ```ts
271
+ * import { CaptchaConfigSchema } from '@h-ai/iam'
272
+ * const config = CaptchaConfigSchema.parse({ enabled: true, ttlSeconds: 120 })
273
+ * ```
274
+ */
275
+ declare const CaptchaConfigSchema: z.ZodObject<{
276
+ enabled: z.ZodDefault<z.ZodBoolean>;
277
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
278
+ cost: z.ZodDefault<z.ZodNumber>;
279
+ maxCounter: z.ZodDefault<z.ZodNumber>;
280
+ }, z.core.$strip>;
261
281
  /**
262
282
  * 服务端账户失败计数与锁定策略。
263
283
  * @example
@@ -267,6 +287,25 @@ declare const SecurityConfigSchema: z.ZodObject<{
267
287
  * ```
268
288
  */
269
289
  type SecurityConfig = z.infer<typeof SecurityConfigSchema>;
290
+ /**
291
+ * 登录时段与地址策略;空地址/时段列表不限制对应维度。周一为1,周日为7。
292
+ * @example
293
+ * ```ts
294
+ * import { LoginAccessConfigSchema } from '@h-ai/iam'
295
+ * const policy = LoginAccessConfigSchema.parse({ enabled: true, allowIps: ['192.0.2.0/24'], timezone: 'Asia/Shanghai' })
296
+ * ```
297
+ */
298
+ declare const LoginAccessConfigSchema: z.ZodObject<{
299
+ enabled: z.ZodDefault<z.ZodBoolean>;
300
+ allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
301
+ denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
302
+ timezone: z.ZodDefault<z.ZodString>;
303
+ windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
304
+ days: z.ZodArray<z.ZodNumber>;
305
+ start: z.ZodString;
306
+ end: z.ZodString;
307
+ }, z.core.$strip>>>;
308
+ }, z.core.$strip>;
270
309
  /**
271
310
  * 协议展示配置
272
311
  * @example
@@ -340,8 +379,16 @@ type AuthUiConfig = z.infer<typeof AuthUiConfigSchema>;
340
379
  */
341
380
  declare const SessionConfigSchema: z.ZodObject<{
342
381
  maxAge: z.ZodDefault<z.ZodNumber>;
382
+ endOnPageHide: z.ZodDefault<z.ZodBoolean>;
343
383
  sliding: z.ZodDefault<z.ZodBoolean>;
344
384
  singleDevice: z.ZodDefault<z.ZodBoolean>;
385
+ singleDeviceMode: z.ZodDefault<z.ZodEnum<{
386
+ replace: "replace";
387
+ reject: "reject";
388
+ }>>;
389
+ maxSessions: z.ZodDefault<z.ZodNumber>;
390
+ idleTimeout: z.ZodDefault<z.ZodNumber>;
391
+ absoluteTimeout: z.ZodDefault<z.ZodNumber>;
345
392
  refreshTokenMaxAge: z.ZodDefault<z.ZodNumber>;
346
393
  }, z.core.$strip>;
347
394
  /**
@@ -378,6 +425,18 @@ declare const RbacConfigSchema: z.ZodObject<{
378
425
  * ```
379
426
  */
380
427
  type RbacConfig = z.infer<typeof RbacConfigSchema>;
428
+ /**
429
+ * 可选账号闲置扫描;0天关闭自动休眠,不影响明确设置的账号状态与到期时间。
430
+ * @example
431
+ * ```ts
432
+ * import { AccountConfigSchema } from '@h-ai/iam'
433
+ * const config = AccountConfigSchema.parse({ dormantAfterDays: 90, scanIntervalSeconds: 3600 })
434
+ * ```
435
+ */
436
+ declare const AccountConfigSchema: z.ZodObject<{
437
+ dormantAfterDays: z.ZodDefault<z.ZodNumber>;
438
+ scanIntervalSeconds: z.ZodDefault<z.ZodNumber>;
439
+ }, z.core.$strip>;
381
440
  /**
382
441
  * IAM 统一配置 Schema
383
442
  * @example
@@ -390,6 +449,29 @@ type RbacConfig = z.infer<typeof RbacConfigSchema>;
390
449
  * ```
391
450
  */
392
451
  declare const IamConfigSchema: z.ZodObject<{
452
+ initialCredentials: z.ZodOptional<z.ZodObject<{
453
+ enabled: z.ZodDefault<z.ZodBoolean>;
454
+ }, z.core.$strip>>;
455
+ reauthentication: z.ZodOptional<z.ZodObject<{
456
+ enabled: z.ZodDefault<z.ZodBoolean>;
457
+ operations: z.ZodDefault<z.ZodArray<z.ZodString>>;
458
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
459
+ }, z.core.$strip>>;
460
+ loginAccess: z.ZodOptional<z.ZodObject<{
461
+ enabled: z.ZodDefault<z.ZodBoolean>;
462
+ allowIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
463
+ denyIps: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodIPv4, z.ZodIPv6, z.ZodCIDRv4, z.ZodCIDRv6]>>>;
464
+ timezone: z.ZodDefault<z.ZodString>;
465
+ windows: z.ZodDefault<z.ZodArray<z.ZodObject<{
466
+ days: z.ZodArray<z.ZodNumber>;
467
+ start: z.ZodString;
468
+ end: z.ZodString;
469
+ }, z.core.$strip>>>;
470
+ }, z.core.$strip>>;
471
+ accounts: z.ZodOptional<z.ZodObject<{
472
+ dormantAfterDays: z.ZodDefault<z.ZodNumber>;
473
+ scanIntervalSeconds: z.ZodDefault<z.ZodNumber>;
474
+ }, z.core.$strip>>;
393
475
  ui: z.ZodOptional<z.ZodObject<{
394
476
  variant: z.ZodDefault<z.ZodEnum<{
395
477
  card: "card";
@@ -409,7 +491,10 @@ declare const IamConfigSchema: z.ZodObject<{
409
491
  requireLowercase: z.ZodDefault<z.ZodBoolean>;
410
492
  requireNumber: z.ZodDefault<z.ZodBoolean>;
411
493
  requireSpecialChar: z.ZodDefault<z.ZodBoolean>;
494
+ minCharacterClasses: z.ZodDefault<z.ZodNumber>;
412
495
  expirationDays: z.ZodDefault<z.ZodNumber>;
496
+ preventSamePassword: z.ZodDefault<z.ZodBoolean>;
497
+ requireInitialChange: z.ZodDefault<z.ZodBoolean>;
413
498
  }, z.core.$strip>>;
414
499
  otp: z.ZodOptional<z.ZodObject<{
415
500
  email: z.ZodDefault<z.ZodBoolean>;
@@ -464,14 +549,30 @@ declare const IamConfigSchema: z.ZodObject<{
464
549
  showOnRegister: z.ZodDefault<z.ZodBoolean>;
465
550
  showOnLogin: z.ZodDefault<z.ZodBoolean>;
466
551
  }, z.core.$strip>>;
552
+ captcha: z.ZodDefault<z.ZodObject<{
553
+ enabled: z.ZodDefault<z.ZodBoolean>;
554
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
555
+ cost: z.ZodDefault<z.ZodNumber>;
556
+ maxCounter: z.ZodDefault<z.ZodNumber>;
557
+ }, z.core.$strip>>;
467
558
  security: z.ZodDefault<z.ZodObject<{
559
+ lockoutEnabled: z.ZodDefault<z.ZodBoolean>;
560
+ failureWindow: z.ZodDefault<z.ZodNumber>;
468
561
  maxLoginAttempts: z.ZodDefault<z.ZodNumber>;
469
562
  lockoutDuration: z.ZodDefault<z.ZodNumber>;
470
563
  }, z.core.$strip>>;
471
564
  session: z.ZodOptional<z.ZodObject<{
472
565
  maxAge: z.ZodDefault<z.ZodNumber>;
566
+ endOnPageHide: z.ZodDefault<z.ZodBoolean>;
473
567
  sliding: z.ZodDefault<z.ZodBoolean>;
474
568
  singleDevice: z.ZodDefault<z.ZodBoolean>;
569
+ singleDeviceMode: z.ZodDefault<z.ZodEnum<{
570
+ replace: "replace";
571
+ reject: "reject";
572
+ }>>;
573
+ maxSessions: z.ZodDefault<z.ZodNumber>;
574
+ idleTimeout: z.ZodDefault<z.ZodNumber>;
575
+ absoluteTimeout: z.ZodDefault<z.ZodNumber>;
475
576
  refreshTokenMaxAge: z.ZodDefault<z.ZodNumber>;
476
577
  }, z.core.$strip>>;
477
578
  rbac: z.ZodDefault<z.ZodObject<{
@@ -1050,6 +1151,16 @@ interface User {
1050
1151
  avatarUrl?: string;
1051
1152
  /** 是否启用 */
1052
1153
  enabled: boolean;
1154
+ /** 账号类型;未设置时为长期账号。 */
1155
+ accountType?: 'permanent' | 'temporary';
1156
+ /** 账号生命周期;与管理员 enabled 开关共同决定可用性。 */
1157
+ accountStatus?: 'active' | 'dormant' | 'closed';
1158
+ /** 临时账号到期时间;长期账号可为 null,临时账号必须设置。 */
1159
+ accountExpiresAt?: Date | null;
1160
+ /** 最近成功登录时间,失败尝试不更新。 */
1161
+ lastLoginAt?: Date | null;
1162
+ /** 初始凭据尚未更换;此时不能签发或使用普通业务会话。 */
1163
+ mustChangePassword?: boolean;
1053
1164
  /** 是否邮箱验证 */
1054
1165
  emailVerified?: boolean;
1055
1166
  /** 是否手机验证 */
@@ -1113,6 +1224,8 @@ interface StoredUser extends User {
1113
1224
  passwordUpdatedAt?: Date;
1114
1225
  /** 登录失败次数 */
1115
1226
  loginFailedCount?: number;
1227
+ /** 当前固定失败计数窗口的起点。 */
1228
+ firstLoginFailedAt?: Date;
1116
1229
  /** 最后登录失败时间 */
1117
1230
  lastLoginFailedAt?: Date;
1118
1231
  /** 锁定截止时间 */
@@ -1127,6 +1240,14 @@ interface StoredUser extends User {
1127
1240
  * ```
1128
1241
  */
1129
1242
  interface RegisterOptions {
1243
+ /** 可选交互挑战证明;管理端 createUser/inviteUser 不使用。 */
1244
+ captcha?: string;
1245
+ /** 服务端管理入口可指定临时账号;公开注册接口不应允许修改生命周期字段。 */
1246
+ accountType?: 'permanent' | 'temporary';
1247
+ /** 管理入口指定初始状态;公开注册 Schema 不接受此字段。 */
1248
+ accountStatus?: 'active' | 'dormant' | 'closed';
1249
+ /** 临时账号的到期时间。 */
1250
+ accountExpiresAt?: Date;
1130
1251
  /** 用户名 */
1131
1252
  username: string;
1132
1253
  /** 邮箱 */
@@ -1199,6 +1320,14 @@ interface UpdateCurrentUserInput {
1199
1320
  * ```
1200
1321
  */
1201
1322
  interface UserOperations {
1323
+ /**
1324
+ * 创建独立随机初始凭据并发送短期单次邀请;不返回或通知原始初始密码。
1325
+ * initialCredentials.enabled、passwordReset 与通知通道必须就绪;接收人使用现有重置页面设密。
1326
+ * 投递未知时保留已创建账号并返回失败;核对后可通过重置通知流程恢复。
1327
+ * @param options - 可信管理端输入,必须包含通知通道对应的邮箱/手机号。
1328
+ * @returns 创建结果或失败;不能把通知结果未知当作未创建账号。
1329
+ */
1330
+ inviteUser: (options: Omit<RegisterOptions, 'password'>) => Promise<HaiResult<RegisterResult>>;
1202
1331
  /** 批量查询最多 1000 个用户 ID,去重并保持输入顺序,忽略不存在的 ID;可批量包含角色。 */
1203
1332
  getUsers: (userIds: readonly string[], options?: {
1204
1333
  include?: ('roles')[];
@@ -1253,6 +1382,17 @@ interface UserOperations {
1253
1382
  * @returns 成功返回分页用户列表
1254
1383
  */
1255
1384
  listUsers: (options?: ListUsersOptions) => Promise<HaiResult<PaginatedResult<User>>>;
1385
+ /**
1386
+ * 依据 accounts.dormantAfterDays 原子休眠长期未登录的账号,返回数量;0天时不执行。
1387
+ * IAM 开启自动扫描时定时调用;外露管理接口须自行验证管理员权限。
1388
+ * @example
1389
+ * ```ts
1390
+ * import { iam } from '@h-ai/iam'
1391
+ * const scanned = await iam.user.scanInactiveAccounts()
1392
+ * if (!scanned.success) throw new Error(scanned.error.message)
1393
+ * ```
1394
+ */
1395
+ scanInactiveAccounts: () => Promise<HaiResult<number>>;
1256
1396
  /**
1257
1397
  * 更新用户信息
1258
1398
  *
@@ -1282,6 +1422,22 @@ interface UserOperations {
1282
1422
  * @returns 成功返回 ok;用户不存在返回 USER_NOT_FOUND,密码不合规返回 PASSWORD_POLICY_VIOLATION
1283
1423
  */
1284
1424
  adminResetPassword: (userId: string, newPassword: string) => Promise<HaiResult<void>>;
1425
+ /**
1426
+ * 使用原凭据完成首次或过期改密,不需要先获得普通会话。
1427
+ * 仍执行账号状态、旧密码校验、失败锁定及新密码策略;成功后需重新登录。
1428
+ * @example
1429
+ * ```ts
1430
+ * import { iam } from '@h-ai/iam'
1431
+ * const changed = await iam.user.renewPassword({ identifier: 'alice', password: 'Temporary123!', newPassword: 'ChosenPassword456!' })
1432
+ * if (!changed.success) throw new Error(changed.error.message)
1433
+ * ```
1434
+ */
1435
+ renewPassword: (input: {
1436
+ identifier: string;
1437
+ password: string;
1438
+ newPassword: string;
1439
+ captcha?: string;
1440
+ }) => Promise<HaiResult<void>>;
1285
1441
  /**
1286
1442
  * 修改密码
1287
1443
  *
@@ -1320,7 +1476,9 @@ interface UserOperations {
1320
1476
  * requested.error.code // 投递未知不能当作成功或由调用端擅自重发通知。
1321
1477
  * ```
1322
1478
  */
1323
- requestPasswordReset: (identifier: string) => Promise<HaiResult<void>>;
1479
+ requestPasswordReset: (identifier: string, options?: {
1480
+ captcha?: string;
1481
+ }) => Promise<HaiResult<void>>;
1324
1482
  /**
1325
1483
  * 确认密码重置
1326
1484
  *
@@ -1449,7 +1607,9 @@ interface Session {
1449
1607
  accessToken: string;
1450
1608
  /** 创建时间 */
1451
1609
  createdAt: Date;
1452
- /** 最后活动时间 */
1610
+ /** 首次签发时间;刷新保留,用于绝对期限。旧记录未设置时以 createdAt 为准。 */
1611
+ startedAt?: Date;
1612
+ /** 最后活动时间;启用闲置策略时,自动 refresh 不延长此值。 */
1453
1613
  lastActiveAt: Date;
1454
1614
  /** 过期时间 */
1455
1615
  expiresAt: Date;
@@ -1638,6 +1798,145 @@ interface SessionFieldUpdates {
1638
1798
  permissions?: string[];
1639
1799
  }
1640
1800
 
1801
+ /**
1802
+ * @h-ai/iam — 一次性票据类型
1803
+ *
1804
+ * 定义通用的短期、一次性能力票据(capability ticket):由已认证的上下文签发,
1805
+ * 绑定主体、用途与授权信息,在无法携带 Bearer Token 的通道(如 WebSocket URL)中
1806
+ * 用作一次性入场凭证。典型用途:AI 语音 WebSocket 接入。
1807
+ * @module ticket/iam-ticket-types
1808
+ */
1809
+
1810
+ /**
1811
+ * 票据授权绑定信息
1812
+ *
1813
+ * 消费时原样返回,供服务端确认本次操作、模型、会话等参数与签发时一致。
1814
+ * 除固定字段外允许应用自定义键值。
1815
+ * @example
1816
+ * ```ts
1817
+ * import type { TicketGrant } from '@h-ai/iam'
1818
+ * const value: TicketGrant = { operation: 'transcribe', model: 'speech-model', sessionId: 'conversation-1' }
1819
+ * ```
1820
+ */
1821
+ interface TicketGrant {
1822
+ /** 操作类型(如 `'transcribe'` | `'synthesize'` 或应用自定义) */
1823
+ operation?: string;
1824
+ /** 模型 ID */
1825
+ model?: string;
1826
+ /** 会话 ID */
1827
+ sessionId?: string;
1828
+ /** 应用自定义绑定字段 */
1829
+ [key: string]: unknown;
1830
+ }
1831
+ /**
1832
+ * 签发一次性票据的选项
1833
+ * @example
1834
+ * ```ts
1835
+ * import type { IssueTicketOptions } from '@h-ai/iam'
1836
+ * const value: IssueTicketOptions = { subjectId: 'user-1', purpose: 'ai-audio', ttlMs: 30000, grant: { operation: 'transcribe' } }
1837
+ * ```
1838
+ */
1839
+ interface IssueTicketOptions {
1840
+ /** 主体 ID(票据绑定的用户 / 主体,消费时原样返回) */
1841
+ subjectId: string;
1842
+ /** 票据用途(如 `'ai-audio'`),消费时校验一致 */
1843
+ purpose: string;
1844
+ /** 授权绑定信息(操作 / 模型 / 会话等,消费时原样返回) */
1845
+ grant?: TicketGrant;
1846
+ /** 有效期(毫秒,默认 30000) */
1847
+ ttlMs?: number;
1848
+ }
1849
+ /**
1850
+ * 签发结果
1851
+ * @example
1852
+ * ```ts
1853
+ * import { iam, type IssuedTicket } from '@h-ai/iam'
1854
+ * const issued = await iam.ticket.issue({ subjectId: 'user-1', purpose: 'ai-audio' })
1855
+ * if (issued.success) {
1856
+ * const value: IssuedTicket = issued.data
1857
+ * value.expiresAt // 不能延长服务端签发期限;票据只能消费一次。
1858
+ * }
1859
+ * ```
1860
+ */
1861
+ interface IssuedTicket {
1862
+ /** 一次性票据值(密码学安全随机,base64url) */
1863
+ ticket: string;
1864
+ /** 过期时间(Unix 毫秒) */
1865
+ expiresAt: number;
1866
+ }
1867
+ /**
1868
+ * 消费票据的选项
1869
+ * @example
1870
+ * ```ts
1871
+ * import type { ConsumeTicketOptions } from '@h-ai/iam'
1872
+ * const value: ConsumeTicketOptions = { purpose: 'ai-audio' }
1873
+ * ```
1874
+ */
1875
+ interface ConsumeTicketOptions {
1876
+ /** 期望用途;与签发用途不一致时返回 `TICKET_INVALID`(防止跨用途重放) */
1877
+ purpose?: string;
1878
+ }
1879
+ /**
1880
+ * 消费结果(校验通过并原子消费后返回)
1881
+ * @example
1882
+ * ```ts
1883
+ * import { iam, type ConsumedTicket } from '@h-ai/iam'
1884
+ * const consumed = await iam.ticket.consume('ticket-from-upgrade-request', { purpose: 'ai-audio' })
1885
+ * if (consumed.success) {
1886
+ * const authorization: ConsumedTicket = consumed.data
1887
+ * authorization.grant.operation // 校验与本次请求操作相同。
1888
+ * }
1889
+ * ```
1890
+ */
1891
+ interface ConsumedTicket {
1892
+ /** 票据绑定的主体 ID */
1893
+ subjectId: string;
1894
+ /** 票据用途 */
1895
+ purpose: string;
1896
+ /** 授权绑定信息 */
1897
+ grant: TicketGrant;
1898
+ }
1899
+ /**
1900
+ * 一次性票据操作接口(通过 `iam.ticket` 访问)
1901
+ *
1902
+ * 提供密码学安全、带 TTL、原子单次消费的能力票据签发与消费。
1903
+ * @example
1904
+ * ```ts
1905
+ * import { iam, type TicketOperations } from '@h-ai/iam'
1906
+ * // 应用已完成 RelDB、Cache、Crypto 和 IAM 初始化。
1907
+ * const operations: TicketOperations = iam.ticket
1908
+ * const result = await operations.issue({ subjectId: 'user-1', purpose: 'ai-audio', ttlMs: 30000 })
1909
+ * if (!result.success) {
1910
+ * result.error.code // 调用方将失败交给统一错误边界。
1911
+ * }
1912
+ * else {
1913
+ * result.data
1914
+ * }
1915
+ * ```
1916
+ */
1917
+ interface TicketOperations {
1918
+ /**
1919
+ * 签发一次性票据
1920
+ *
1921
+ * 生成密码学安全随机值,绑定主体 / 用途 / 授权信息并按 TTL 存入 cache。
1922
+ *
1923
+ * @param options - 签发选项
1924
+ * @returns 票据值与过期时间
1925
+ */
1926
+ issue: (options: IssueTicketOptions) => Promise<HaiResult<IssuedTicket>>;
1927
+ /**
1928
+ * 原子消费一次性票据
1929
+ *
1930
+ * 单次有效:并发消费同一票据时只有一个成功,其余返回 `TICKET_INVALID`。
1931
+ * 票据不存在 / 已过期 / 已消费 / 用途不匹配时返回错误。
1932
+ *
1933
+ * @param ticket - 票据值
1934
+ * @param options - 消费选项(可校验用途)
1935
+ * @returns 主体 + 用途 + 授权信息
1936
+ */
1937
+ consume: (ticket: string, options?: ConsumeTicketOptions) => Promise<HaiResult<ConsumedTicket>>;
1938
+ }
1939
+
1641
1940
  /**
1642
1941
  * @h-ai/iam — 认证类型定义
1643
1942
  *
@@ -1645,6 +1944,42 @@ interface SessionFieldUpdates {
1645
1944
  * @module iam-authn-types
1646
1945
  */
1647
1946
 
1947
+ /**
1948
+ * 交互鉴别用途;同一挑战不能用于另一入口,API Key 机器鉴别不使用它。
1949
+ * @example
1950
+ * ```ts
1951
+ * import type { CaptchaOperation } from '@h-ai/iam'
1952
+ * const operation: CaptchaOperation = 'login'
1953
+ * ```
1954
+ */
1955
+ type CaptchaOperation = 'login' | 'register' | 'sendOtp' | 'passwordReset' | 'renewPassword';
1956
+ /**
1957
+ * 可公开的 ALTCHA 挑战;签名秘密仅存共享缓存,不包含在返回值中。
1958
+ * @example
1959
+ * ```ts
1960
+ * import { iam, type IamCaptchaChallenge } from '@h-ai/iam'
1961
+ * const result = await iam.auth.createCaptcha({ operation: 'login' })
1962
+ * if (result.success) { const challenge: IamCaptchaChallenge = result.data; void challenge.id }
1963
+ * ```
1964
+ */
1965
+ interface IamCaptchaChallenge {
1966
+ id: string;
1967
+ challenge: Challenge;
1968
+ }
1969
+ /**
1970
+ * 由可信 HTTP 宿主提供的登录元数据,独立于客户端凭据输入。
1971
+ * @example
1972
+ * ```ts
1973
+ * import type { AuthRequestContext } from '@h-ai/iam'
1974
+ * const context: AuthRequestContext = { ip: '192.0.2.10', requestId: 'request-1' }
1975
+ * ```
1976
+ */
1977
+ interface AuthRequestContext {
1978
+ /** socket/平台或受信代理解析后的地址;不能直接复制 X-Forwarded-For。 */
1979
+ ip?: string;
1980
+ userAgent?: string;
1981
+ requestId?: string;
1982
+ }
1648
1983
  /**
1649
1984
  * 用户凭证(用于密码登录)
1650
1985
  * @example
@@ -1654,6 +1989,7 @@ interface SessionFieldUpdates {
1654
1989
  * ```
1655
1990
  */
1656
1991
  interface PasswordCredentials {
1992
+ captcha?: string;
1657
1993
  /** 用户名/邮箱/手机号 */
1658
1994
  identifier: string;
1659
1995
  /** 密码 */
@@ -1668,6 +2004,7 @@ interface PasswordCredentials {
1668
2004
  * ```
1669
2005
  */
1670
2006
  interface OtpCredentials {
2007
+ captcha?: string;
1671
2008
  /** 邮箱/手机号 */
1672
2009
  identifier: string;
1673
2010
  /** 验证码 */
@@ -1682,6 +2019,7 @@ interface OtpCredentials {
1682
2019
  * ```
1683
2020
  */
1684
2021
  interface LdapCredentials {
2022
+ captcha?: string;
1685
2023
  /** 用户名 */
1686
2024
  username: string;
1687
2025
  /** 密码 */
@@ -1781,29 +2119,54 @@ interface AuthStrategy {
1781
2119
  * ```
1782
2120
  */
1783
2121
  interface AuthnOperations {
2122
+ /** 生成短期单用、自托管挑战;启用后各交互入口在服务端校验解答。 */
2123
+ createCaptcha: (input: {
2124
+ operation: CaptchaOperation;
2125
+ }) => Promise<HaiResult<IamCaptchaChallenge>>;
2126
+ /**
2127
+ * 验证当前会话和原密码,为已配置的敏感操作签发短期单次证明。
2128
+ * 不创建新会话,不替代操作本身的权限/资源检查。
2129
+ * @param accessToken - 当前会话令牌。
2130
+ * @param password - 原密码;失败计数与登录共用。
2131
+ * @param operation - 配置中选定的操作 ID。
2132
+ * @returns 绑定用户、会话与操作的单次票据,或鉴别失败。
2133
+ */
2134
+ reauthenticate: (accessToken: string, password: string, operation: string) => Promise<HaiResult<IssuedTicket>>;
2135
+ /**
2136
+ * 操作入口完成权限检查后调用;关闭策略/未选操作仅验证当前会话。
2137
+ * 选定操作原子消费证明;不能跨会话、跨操作或重复使用。
2138
+ * @param accessToken - 当前会话令牌。
2139
+ * @param operation - 服务端确定的操作 ID,不能由客户端选择要执行的守卫。
2140
+ * @param ticket - reauthenticate 签发的短期证明。
2141
+ * @returns 允许继续时成功;拒绝或基础设施失败时返回错误。
2142
+ */
2143
+ checkSensitiveOperation: (accessToken: string, operation: string, ticket?: string) => Promise<HaiResult<void>>;
1784
2144
  /**
1785
2145
  * 登录(使用密码)
1786
2146
  *
1787
2147
  * 检查登录方式启用 → 密码策略认证 → 创建会话 → 返回令牌。
1788
2148
  *
1789
2149
  * @param credentials - 密码凭证(identifier + password)
2150
+ * @param context - 宿主提供的可信登录元数据,不从凭据输入复制 IP。
1790
2151
  * @returns 成功返回 AuthResult(用户信息、令牌、协议展示);失败返回错误
1791
2152
  */
1792
- login: (credentials: PasswordCredentials) => Promise<HaiResult<AuthResult>>;
2153
+ login: (credentials: PasswordCredentials, context?: AuthRequestContext) => Promise<HaiResult<AuthResult>>;
1793
2154
  /**
1794
2155
  * 使用验证码登录
1795
2156
  *
1796
2157
  * @param credentials - OTP 凭证(identifier + code)
2158
+ * @param context - 宿主提供的可信登录元数据,不从凭据输入复制 IP。
1797
2159
  * @returns 成功返回 AuthResult;验证码无效/过期返回 OTP_INVALID
1798
2160
  */
1799
- loginWithOtp: (credentials: OtpCredentials) => Promise<HaiResult<AuthResult>>;
2161
+ loginWithOtp: (credentials: OtpCredentials, context?: AuthRequestContext) => Promise<HaiResult<AuthResult>>;
1800
2162
  /**
1801
2163
  * 使用 LDAP 登录
1802
2164
  *
1803
2165
  * @param credentials - LDAP 凭证(username + password)
2166
+ * @param context - 宿主提供的可信登录元数据,不从凭据输入复制 IP。
1804
2167
  * @returns 成功返回 AuthResult(自动同步本地用户);失败返回错误
1805
2168
  */
1806
- loginWithLdap: (credentials: LdapCredentials) => Promise<HaiResult<AuthResult>>;
2169
+ loginWithLdap: (credentials: LdapCredentials, context?: AuthRequestContext) => Promise<HaiResult<AuthResult>>;
1807
2170
  /**
1808
2171
  * 使用 API Key 登录
1809
2172
  *
@@ -1811,9 +2174,10 @@ interface AuthnOperations {
1811
2174
  * 空 scopes 无操作权限;显式 * 也不超出主体权限。受限 key 通过 permission 授权,不保留角色入口。
1812
2175
  *
1813
2176
  * @param credentials - API Key 凭证
2177
+ * @param context - 宿主提供的可信登录元数据,不从凭据输入复制 IP。
1814
2178
  * @returns 成功返回 AuthResult;API Key 无效/过期/禁用返回对应错误
1815
2179
  */
1816
- loginWithApiKey: (credentials: ApiKeyCredentials) => Promise<HaiResult<AuthResult>>;
2180
+ loginWithApiKey: (credentials: ApiKeyCredentials, context?: AuthRequestContext) => Promise<HaiResult<AuthResult>>;
1817
2181
  /**
1818
2182
  * 登出
1819
2183
  *
@@ -1840,7 +2204,9 @@ interface AuthnOperations {
1840
2204
  * @param identifier - 用户标识(邮箱/手机号)
1841
2205
  * @returns 成功返回验证码过期时间;频率限制返回 OTP_RESEND_TOO_FAST
1842
2206
  */
1843
- sendOtp: (identifier: string) => Promise<HaiResult<{
2207
+ sendOtp: (identifier: string, options?: {
2208
+ captcha?: string;
2209
+ }) => Promise<HaiResult<{
1844
2210
  expiresAt: Date;
1845
2211
  }>>;
1846
2212
  /**
@@ -1852,7 +2218,7 @@ interface AuthnOperations {
1852
2218
  * @param options - 注册选项(用户名、密码、邮箱等)
1853
2219
  * @returns 成功返回 AuthResult(用户信息、令牌、协议展示);失败返回对应错误码
1854
2220
  */
1855
- registerAndLogin: (options: RegisterOptions) => Promise<HaiResult<AuthResult>>;
2221
+ registerAndLogin: (options: RegisterOptions, context?: AuthRequestContext) => Promise<HaiResult<AuthResult>>;
1856
2222
  }
1857
2223
 
1858
2224
  /**
@@ -1938,6 +2304,10 @@ type LdapClientFactory = (config: LdapConfig) => Promise<HaiResult<LdapClient>>;
1938
2304
  * ```
1939
2305
  */
1940
2306
  interface IamPublicConfig {
2307
+ /** 只公开是否需要交互挑战,不公开秘密或缓存状态。 */
2308
+ captcha: {
2309
+ enabled: boolean;
2310
+ };
1941
2311
  /** 页面显示密码策略,不包含密码哈希或账户信息。 */
1942
2312
  password: ReturnType<typeof PasswordConfigSchema.parse>;
1943
2313
  /** 自助注册开关;管理端创建账户仍需要独立授权。 */
@@ -1969,146 +2339,17 @@ interface IamPublicConfig {
1969
2339
  /** 默认 access 有效时长,单位秒;真实认证期限由服务端会话状态决定。 */
1970
2340
  session: {
1971
2341
  maxAge: number;
2342
+ endOnPageHide: boolean;
2343
+ };
2344
+ /** 仅公开操作清单,便于界面在选定操作前请求再鉴别。 */
2345
+ reauthentication: {
2346
+ enabled: boolean;
2347
+ operations: string[];
2348
+ };
2349
+ /** 邀请入口同时要求开关、密码重置与通知通道就绪。 */
2350
+ initialCredentials: {
2351
+ enabled: boolean;
1972
2352
  };
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
2353
  }
2113
2354
 
2114
2355
  /**
@@ -2147,6 +2388,15 @@ declare const HaiIamError: {
2147
2388
  readonly OTP_EXPIRED: _h_ai_core.HaiErrorDef;
2148
2389
  readonly SECURITY_BUSY: _h_ai_core.HaiErrorDef;
2149
2390
  readonly PASSWORD_RESET_DISABLED: _h_ai_core.HaiErrorDef;
2391
+ readonly PASSWORD_CHANGE_REQUIRED: _h_ai_core.HaiErrorDef;
2392
+ readonly LOGIN_ACCESS_DENIED: _h_ai_core.HaiErrorDef;
2393
+ readonly REAUTHENTICATION_REQUIRED: _h_ai_core.HaiErrorDef;
2394
+ readonly INVITATION_DELIVERY_UNKNOWN: _h_ai_core.HaiErrorDef;
2395
+ readonly INVITATION_DISABLED: _h_ai_core.HaiErrorDef;
2396
+ readonly CAPTCHA_REQUIRED: _h_ai_core.HaiErrorDef;
2397
+ readonly CAPTCHA_INVALID: _h_ai_core.HaiErrorDef;
2398
+ readonly CAPTCHA_DISABLED: _h_ai_core.HaiErrorDef;
2399
+ readonly CAPTCHA_UNAVAILABLE: _h_ai_core.HaiErrorDef;
2150
2400
  readonly SESSION_NOT_FOUND: _h_ai_core.HaiErrorDef;
2151
2401
  readonly SESSION_EXPIRED: _h_ai_core.HaiErrorDef;
2152
2402
  readonly SESSION_INVALID: _h_ai_core.HaiErrorDef;
@@ -2154,6 +2404,7 @@ declare const HaiIamError: {
2154
2404
  readonly TOKEN_EXPIRED: _h_ai_core.HaiErrorDef;
2155
2405
  readonly TOKEN_INVALID: _h_ai_core.HaiErrorDef;
2156
2406
  readonly TOKEN_REFRESH_FAILED: _h_ai_core.HaiErrorDef;
2407
+ readonly SESSION_LIMIT_EXCEEDED: _h_ai_core.HaiErrorDef;
2157
2408
  readonly PERMISSION_DENIED: _h_ai_core.HaiErrorDef;
2158
2409
  readonly ROLE_NOT_FOUND: _h_ai_core.HaiErrorDef;
2159
2410
  readonly PERMISSION_NOT_FOUND: _h_ai_core.HaiErrorDef;
@@ -2317,4 +2568,4 @@ interface IamFunctions {
2317
2568
  readonly ticket: TicketOperations;
2318
2569
  }
2319
2570
 
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 };
2571
+ export { AccountConfigSchema, type AgreementConfig, AgreementConfigSchema, type AgreementDisplay, type ApiKey, type ApiKeyConfig, ApiKeyConfigSchema, type ApiKeyCredentials, type ApiKeyOperations, type ApiKeySortDirection, type ApiKeySortField, type AuthRequestContext, type AuthResult, type AuthStrategy, type AuthStrategyType, AuthStrategyTypeSchema, type AuthUiConfig, AuthUiConfigSchema, type AuthnOperations, type AuthzOperations, CaptchaConfigSchema, type CaptchaOperation, type ConsumeTicketOptions, type ConsumedTicket, type CreateApiKeyOptions, type CreateApiKeyResult, type CreateSessionOptions, type Credentials, HaiIamError, type IamCaptchaChallenge, 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, LoginAccessConfigSchema, 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 };