@h-ai/api-client 0.1.0-alpha.67 → 0.1.0-alpha.69

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/index.d.ts CHANGED
@@ -11,13 +11,22 @@ import * as zod_v4_core from 'zod/v4/core';
11
11
  import * as zod from 'zod';
12
12
 
13
13
  /**
14
- * API client 标准错误集合(遵循 `@h-ai/core` 错误码规范)。
14
+ * 客户端标准错误集合;包含稳定 code/httpStatus 与构造错误的方法,业务调用先检查 success。
15
+ * 传输失败在 procedure 代理中映射;服务端 HaiResult 的业务错误保持原契约。
15
16
  *
16
17
  * @example
17
18
  * ```ts
18
- * if (!result.success && result.error.code === HaiApiClientError.UNAUTHORIZED.code) {
19
- * redirectToLogin()
19
+ * import { apiClient, HaiApiClientError } from '@h-ai/api-client'
20
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1' })
21
+ * if (!initialized.success) throw new Error(initialized.error.message)
22
+ * try {
23
+ * const result = await apiClient.iam.auth.currentUser()
24
+ * if (!result.success && result.error.code === HaiApiClientError.UNAUTHORIZED.code) {
25
+ * // 由应用切换到登录页面;不输出 Token。
26
+ * const message = result.error.message
27
+ * }
20
28
  * }
29
+ * finally { await apiClient.close() }
21
30
  * ```
22
31
  */
23
32
  declare const HaiApiClientError: {
@@ -29,11 +38,22 @@ declare const HaiApiClientError: {
29
38
  readonly NOT_FOUND: _h_ai_core.HaiErrorDef;
30
39
  readonly VALIDATION_FAILED: _h_ai_core.HaiErrorDef;
31
40
  readonly TOKEN_REFRESH_FAILED: _h_ai_core.HaiErrorDef;
41
+ readonly PAYLOAD_TOO_LARGE: _h_ai_core.HaiErrorDef;
32
42
  readonly NOT_INITIALIZED: _h_ai_core.HaiErrorDef;
33
43
  readonly CONFIG_ERROR: _h_ai_core.HaiErrorDef;
34
44
  readonly UNKNOWN: _h_ai_core.HaiErrorDef;
35
45
  };
36
- /** Token 对(与 `@h-ai/iam` 的 TokenPair 对齐)。 */
46
+ /**
47
+ * 短期 access token、可选 refresh token 与有效期;HTTP 头使用 Bearer。
48
+ * Cookie 模式的 refresh token 由服务端管理,不能要求浏览器读取或持久化它。
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import type { TokenPair } from '@h-ai/api-client'
53
+ * const tokens: TokenPair = { accessToken: 'test-access', expiresIn: 3600, tokenType: 'Bearer' }
54
+ * // 示例为测试凭据;生产 Token 只能来自可信服务端认证响应。
55
+ * ```
56
+ */
37
57
  interface TokenPair {
38
58
  /** 短期访问凭证,请求时作为 `Authorization: Bearer ...`。 */
39
59
  readonly accessToken: string;
@@ -45,30 +65,110 @@ interface TokenPair {
45
65
  readonly tokenType: 'Bearer';
46
66
  }
47
67
  /**
48
- * Token 存储适配器。
68
+ * 异步安全凭据存储契约;null 仅表示无可用凭据,读写故障须拒绝 Promise。
69
+ * 浏览器使用内存 access token/httpOnly refresh Cookie,原生端注入平台安全存储,禁止敏感 Token 放入 localStorage。
70
+ * 已绑定客户端的身份切换通过 client.auth,避免绕过刷新代际与串行写入;部分写入失败须执行清理并报告清理失败。
49
71
  *
50
72
  * 内置实现:
51
73
  * - `apiClient.tokenStorage.httpOnlyCookie()` — **默认**;浏览器端推荐,refresh token 由服务端管理,防 XSS。
52
74
  * - `apiClient.tokenStorage.memory()` — Node.js 测试 / SSR(需显式传入)。
53
- * - `apiClient.tokenStorage.localStorage()` — 浏览器 SPA / PWA(有 XSS 风险,生产不推荐)。
54
75
  *
55
76
  * Capacitor / 小程序场景请由对应模块提供(例如 `@h-ai/capacitor`)。
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * import { apiClient, type TokenStorage } from '@h-ai/api-client'
81
+ * const storage: TokenStorage = apiClient.tokenStorage.memory()
82
+ * await storage.setAccessToken('test-access')
83
+ * const accessToken = await storage.getAccessToken()
84
+ * await storage.clear()
85
+ * ```
56
86
  */
57
87
  interface TokenStorage {
88
+ /**
89
+ * 读取本适配器可用 access token;无凭据返回 null,存储故障拒绝。
90
+ * @returns Token 或 null;不能把读取失败当成不存在。
91
+ *
92
+ * @example
93
+ * ```ts
94
+ * import { apiClient } from '@h-ai/api-client'
95
+ * const storage = apiClient.tokenStorage.memory()
96
+ * const accessToken = await storage.getAccessToken()
97
+ * ```
98
+ */
58
99
  readonly getAccessToken: () => Promise<string | null>;
100
+ /**
101
+ * 保存 access token;已绑定客户端应通过 auth.setTokens 维护代际。
102
+ * @param token - 可信服务端认证返回的 access token。
103
+ * @returns 写入完成;底层故障须拒绝。
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * import { apiClient } from '@h-ai/api-client'
108
+ * const storage = apiClient.tokenStorage.memory()
109
+ * await storage.setAccessToken('test-access')
110
+ * await storage.clear()
111
+ * ```
112
+ */
59
113
  readonly setAccessToken: (token: string) => Promise<void>;
114
+ /**
115
+ * 读取 refresh token 或 Cookie 模式内部哨兵;null 仅表示没有凭据。
116
+ * @returns Token、模式哨兵或 null,不是对 httpOnly Cookie 内容的脚本读取。
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { apiClient } from '@h-ai/api-client'
121
+ * const storage = apiClient.tokenStorage.memory()
122
+ * const refreshToken = await storage.getRefreshToken()
123
+ * // 内存适配器初始为空;Cookie 适配器由管理器识别模式哨兵。
124
+ * ```
125
+ */
60
126
  readonly getRefreshToken: () => Promise<string | null>;
127
+ /**
128
+ * 保存 refresh token;Cookie 实现不通过脚本修改服务端 Cookie。
129
+ * @param token - 服务端返回的刷新凭据;禁止写入 Web Storage。
130
+ * @returns 写入完成;原生安全存储故障须拒绝。
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * import { apiClient } from '@h-ai/api-client'
135
+ * const storage = apiClient.tokenStorage.memory()
136
+ * await storage.setRefreshToken('test-refresh')
137
+ * await storage.clear()
138
+ * ```
139
+ */
61
140
  readonly setRefreshToken: (token: string) => Promise<void>;
141
+ /**
142
+ * 清空适配器可管理的凭据;Cookie 实现只能清内存 access token。
143
+ * @returns 清理完成;失败须拒绝,服务端 Cookie/会话另由退出接口撤销。
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * import { apiClient } from '@h-ai/api-client'
148
+ * const storage = apiClient.tokenStorage.memory()
149
+ * await storage.clear()
150
+ * const remaining = await storage.getAccessToken()
151
+ * ```
152
+ */
62
153
  readonly clear: () => Promise<void>;
63
154
  }
64
- /** Token 自动刷新配置。 */
155
+ /**
156
+ * 启用 Token 注入与自动刷新;默认 Cookie 适配器,refreshPath 相对 baseUrl。
157
+ * 网络/超时/5xx 为暂时失败,保留凭据;明确失效才清理并通知。回调不应抛出或记录 Token。
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * import { apiClient, type AuthConfig } from '@h-ai/api-client'
162
+ * const auth: AuthConfig = { storage: apiClient.tokenStorage.memory(), refreshPath: '/auth/refresh', refreshTimeoutMs: 5000, onTokenRefreshed: tokens => { const lifetime = tokens.expiresIn } }
163
+ * // Node/SSR 选择独立内存存储;浏览器通常直接配置 auth: {}。
164
+ * ```
165
+ */
65
166
  interface AuthConfig {
66
167
  /**
67
168
  * Token 存储适配器;默认 `apiClient.tokenStorage.httpOnlyCookie()`(refresh token 由服务端管理,防 XSS)。
68
169
  *
69
170
  * - SSR / Node.js 测试场景请显式传入 `apiClient.tokenStorage.memory()`。
70
- * - 浏览器 SPA 如确需持久化,可显式传 `apiClient.tokenStorage.localStorage()`,
71
- * 但请先评估 XSS 风险。
171
+ * - 浏览器刷新后通过 httpOnly Cookie 恢复会话,不将 Token 持久化到 Web Storage。
72
172
  * - Capacitor / 小程序请使用对应平台的安全存储适配器(如 `@h-ai/capacitor`)。
73
173
  */
74
174
  readonly storage?: TokenStorage;
@@ -85,7 +185,20 @@ interface AuthConfig {
85
185
  /** 刷新失败回调(如 refresh token 已失效),通常用于跳转登录页。 */
86
186
  readonly onRefreshFailed?: () => void;
87
187
  }
88
- /** API client 初始化配置。 */
188
+ /**
189
+ * 客户端初始化配置;baseUrl 包含 API 前缀,headers/fetch 用于平台适配。
190
+ * auth 缺省时不创建 TokenManager;timeout 是底层请求中断期限,不代表服务端已取消副作用。
191
+ * transport 需要已初始化 crypto,首次业务请求前协商会话;客户端不接收服务端私钥。
192
+ *
193
+ * @example
194
+ * ```ts
195
+ * import { apiClient, type ApiClientConfig } from '@h-ai/api-client'
196
+ * const config: ApiClientConfig = { baseUrl: 'https://api.example.com/api/v1', auth: { storage: apiClient.tokenStorage.memory() }, timeout: 15000, clientName: 'orders-web', headers: () => ({ 'x-app-channel': 'web' }) }
197
+ * const initialized = await apiClient.init(config)
198
+ * if (!initialized.success) throw new Error(initialized.error.message)
199
+ * await apiClient.close()
200
+ * ```
201
+ */
89
202
  interface ApiClientConfig {
90
203
  /** API service 完整 baseUrl,通常含 `apiPrefix`,例如 `https://api.example.com/api/v1`。 */
91
204
  readonly baseUrl: string;
@@ -112,17 +225,41 @@ interface ApiClientConfig {
112
225
  * import { apiClient } from '@h-ai/api-client'
113
226
  * import { crypto } from '@h-ai/crypto'
114
227
  *
115
- * await crypto.init()
116
- * await apiClient.init({
117
- * baseUrl: 'https://api.example.com/api/v1',
118
- * transport: { crypto },
119
- * })
228
+ * const cryptography = await crypto.init()
229
+ * if (!cryptography.success) throw new Error(cryptography.error.message)
230
+ * try {
231
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', transport: { crypto } })
232
+ * if (!initialized.success) throw new Error(initialized.error.message)
233
+ * await apiClient.close()
234
+ * }
235
+ * finally { await crypto.close() }
120
236
  * ```
121
237
  */
122
238
  readonly transport?: ApiClientTransportConfig;
123
239
  }
124
- /** {@link ApiClientConfig.transport} 的配置项。 */
240
+ /**
241
+ * 可选加密会话配置;密钥协商路径相对 baseUrl,并与服务端配置匹配。
242
+ * crypto 必须先初始化;服务器版本公钥通过受保护的 TLS 握手取得,不配置服务端私钥。
243
+ * 传输防重放不能代替业务幂等性,失败后不要自动重放非幂等操作。
244
+ *
245
+ * @example
246
+ * ```ts
247
+ * import { apiClient, type ApiClientTransportConfig } from '@h-ai/api-client'
248
+ * import { crypto } from '@h-ai/crypto'
249
+ * const cryptography = await crypto.init()
250
+ * if (!cryptography.success) throw new Error(cryptography.error.message)
251
+ * try {
252
+ * const transport: ApiClientTransportConfig = { crypto, keyExchangePath: '/_hai/key-exchange' }
253
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', transport })
254
+ * if (!initialized.success) throw new Error(initialized.error.message)
255
+ * await apiClient.close()
256
+ * }
257
+ * finally { await crypto.close() }
258
+ * ```
259
+ */
125
260
  interface ApiClientTransportConfig {
261
+ /** 可选本地明文 UTF-8 字节上限;缺省自动跟随服务端,指定时取较小值。 */
262
+ readonly maxPlaintextBytes?: number;
126
263
  /**
127
264
  * crypto 服务实例(通常直接传入 `@h-ai/crypto` 的 `crypto`)。
128
265
  * api-client 通过 `crypto.transport.createClient(...)` 创建会话。
@@ -135,31 +272,152 @@ interface ApiClientTransportConfig {
135
272
  */
136
273
  readonly keyExchangePath?: string;
137
274
  }
138
- /** Token 辅助操作。 */
275
+ /**
276
+ * 当前客户端的凭据辅助操作;仅 init 启用 auth 时建立实际管理器。
277
+ * setTokens/clear 撤销旧刷新代际并等待串行存储变更;故障拒绝 Promise,调用方处理失败。
278
+ * clear 不能撤销服务端会话或删除 httpOnly Cookie,退出仍需服务端接口成功。
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * import { apiClient, type ApiClientAuth } from '@h-ai/api-client'
283
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
284
+ * if (!initialized.success) throw new Error(initialized.error.message)
285
+ * try {
286
+ * const auth: ApiClientAuth = apiClient.auth
287
+ * const off = auth.onTokenRefreshed(tokens => { const lifetime = tokens.expiresIn })
288
+ * off()
289
+ * await auth.clear()
290
+ * }
291
+ * finally { await apiClient.close() }
292
+ * ```
293
+ */
139
294
  interface ApiClientAuth {
140
- /** 手动写入 Token(例如登录成功后)。 */
295
+ /**
296
+ * 替换整对凭据并同步废弃旧刷新代际;缺省 refreshToken 时清除旧值。
297
+ * @param tokens - 服务端成功认证返回的真实 TokenPair。
298
+ * @returns 写入完成;安全存储失败拒绝 Promise,调用方应清理部分凭据并报告清理失败。
299
+ *
300
+ * @example
301
+ * ```ts
302
+ * import { apiClient } from '@h-ai/api-client'
303
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
304
+ * if (!initialized.success) throw new Error(initialized.error.message)
305
+ * try {
306
+ * const form = { identifier: 'alice', password: 'test-password' }
307
+ * const login = await apiClient.iam.auth.login(form)
308
+ * if (!login.success) throw new Error(login.error.message)
309
+ * try { await apiClient.auth.setTokens(login.data.tokens) }
310
+ * catch (writeError) {
311
+ * try { await apiClient.auth.clear() }
312
+ * catch (cleanupError) { throw new AggregateError([writeError, cleanupError], 'Credential persistence and cleanup failed') }
313
+ * throw writeError
314
+ * }
315
+ * }
316
+ * finally { await apiClient.close() }
317
+ * ```
318
+ */
141
319
  readonly setTokens: (tokens: TokenPair) => Promise<void>;
142
- /** 清空存储的 Token(登出)。 */
320
+ /**
321
+ * 同步废弃旧刷新代际并等待存储清理;失败拒绝 Promise,不声称已持久删除。
322
+ * 服务端会话与 httpOnly Cookie 仍需服务端退出撤销;本操作不能替代退出接口。
323
+ * @returns 本地清理完成,不返回 HaiResult。
324
+ *
325
+ * @example
326
+ * ```ts
327
+ * import { apiClient } from '@h-ai/api-client'
328
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
329
+ * if (!initialized.success) throw new Error(initialized.error.message)
330
+ * try {
331
+ * const logout = await apiClient.iam.auth.logout({})
332
+ * await apiClient.auth.clear()
333
+ * if (!logout.success) throw new Error(logout.error.message)
334
+ * // 只有服务端退出和本地清理都成功,才能确认两侧均已处理。
335
+ * }
336
+ * finally { await apiClient.close() }
337
+ * ```
338
+ */
143
339
  readonly clear: () => Promise<void>;
144
- /** 订阅 Token 刷新成功事件,返回取消订阅函数。 */
340
+ /**
341
+ * 订阅当前管理器刷新成功事件;回调在写入后同步调用,避免抛错或输出 Token。
342
+ * @param callback - 接收 TokenPair 的同步回调。
343
+ * @returns 取消订阅函数;未启用 auth 时返回空操作。
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * import { apiClient } from '@h-ai/api-client'
348
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
349
+ * if (!initialized.success) throw new Error(initialized.error.message)
350
+ * try {
351
+ * const off = apiClient.auth.onTokenRefreshed(tokens => { const expiresIn = tokens.expiresIn })
352
+ * off()
353
+ * }
354
+ * finally { await apiClient.close() }
355
+ * ```
356
+ */
145
357
  readonly onTokenRefreshed: (callback: (tokens: TokenPair) => void) => () => void;
146
358
  }
147
- /** API client 生命周期能力。 */
359
+ /**
360
+ * 客户端生命周期与认证辅助能力;init 的 HaiResult 必须先检查 success。
361
+ * 同一实例并发 init 共享在途初始化,已初始化后再 init 返回 CONFIG_ERROR;切换配置先 close。
362
+ * config 为脱敏快照;close 清理运行状态/加密会话,不等于服务端退出或凭据存储清理。
363
+ *
364
+ * @example
365
+ * ```ts
366
+ * import { apiClient, type ApiClientLifecycle } from '@h-ai/api-client'
367
+ * const client: ApiClientLifecycle = apiClient
368
+ * const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1' })
369
+ * if (!initialized.success) throw new Error(initialized.error.message)
370
+ * const active = client.isInitialized
371
+ * const snapshot = client.config
372
+ * await client.close()
373
+ * ```
374
+ */
148
375
  interface ApiClientLifecycle {
149
376
  /**
150
- * 初始化 client;必须在调用任何 procedure 前完成。
377
+ * 观察一次逻辑调用的最终结果;刷新重试保留关联 ID,不包含请求正文或凭据。
378
+ * close 清理订阅;回调异常不影响请求,返回函数可提前取消。
379
+ * @example
380
+ * ```ts
381
+ * import { apiClient } from '@h-ai/api-client'
382
+ * const unsubscribe = apiClient.observeRequests(record => { const requestId = record.requestId })
383
+ * unsubscribe()
384
+ * ```
385
+ */
386
+ readonly observeRequests: (observer: ApiRequestObserver) => () => void;
387
+ /**
388
+ * 构造并提交客户端运行状态;初始化失败返回 CONFIG_ERROR,未提交半初始化对象。
389
+ * 并发 init 共享同一初始化;已初始化再调用会失败,切换配置先 close。
390
+ * @param config - baseUrl、认证、fetch 与可选加密配置。
391
+ * @returns HaiResult;必须先判断 success,再发起 procedure。
151
392
  *
152
393
  * @example
153
394
  * ```ts
154
- * await client.init({
155
- * baseUrl: 'https://api.example.com/api/v1',
156
- * auth: { refreshPath: '/auth/refresh' },
157
- * timeout: 15_000,
158
- * })
395
+ * import { apiClient } from '@h-ai/api-client'
396
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
397
+ * if (!initialized.success) throw new Error(initialized.error.message)
398
+ * try {
399
+ * const result = await apiClient.iam.auth.publicConfig()
400
+ * if (!result.success) throw new Error(result.error.message)
401
+ * }
402
+ * finally { await apiClient.close() }
159
403
  * ```
160
404
  */
161
405
  readonly init: (config: ApiClientConfig) => Promise<HaiResult<void>>;
162
- /** 释放资源并允许重新 `init`。 */
406
+ /**
407
+ * 销毁当前加密会话并清除运行状态,允许重新 init;不发送服务端退出、不清空外置存储。
408
+ * @returns 资源清理完成;不是 HaiResult,不应读取 success。
409
+ *
410
+ * @example
411
+ * ```ts
412
+ * import { apiClient } from '@h-ai/api-client'
413
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
414
+ * if (!initialized.success) throw new Error(initialized.error.message)
415
+ * await apiClient.close()
416
+ * const reinitialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
417
+ * if (!reinitialized.success) throw new Error(reinitialized.error.message)
418
+ * await apiClient.close()
419
+ * ```
420
+ */
163
421
  readonly close: () => Promise<void>;
164
422
  /** 当前脱敏后的运行配置快照;未初始化时为 `null`。 */
165
423
  readonly config: ApiClientConfig | null;
@@ -168,15 +426,97 @@ interface ApiClientLifecycle {
168
426
  /** Token 辅助操作。 */
169
427
  readonly auth: ApiClientAuth;
170
428
  }
171
- /** 根据 oRPC contract 推导出的 typed API client(生命周期 + procedure 调用)。 */
429
+ /**
430
+ * 逻辑请求诊断摘要。HTTP 200 的失败 HaiResult 同样 success=false。
431
+ * @example
432
+ * ```ts
433
+ * import type { ApiRequestRecord } from '@h-ai/api-client'
434
+ * const record: ApiRequestRecord = { requestId: 'request-1', procedure: 'orders.get', timestamp: 1, duration: 10, success: false, attempts: 1, errorCode: 'orders:missing' }
435
+ * ```
436
+ */
437
+ interface ApiRequestRecord {
438
+ readonly requestId: string;
439
+ readonly procedure: string;
440
+ readonly timestamp: number;
441
+ readonly duration: number;
442
+ readonly success: boolean;
443
+ readonly attempts: number;
444
+ readonly errorCode?: string;
445
+ readonly method?: string;
446
+ readonly url?: string;
447
+ readonly status?: number;
448
+ }
449
+ /**
450
+ * 同步观察者,只做有界收集。
451
+ * @example
452
+ * ```ts
453
+ * import { apiClient, type ApiRequestObserver } from '@h-ai/api-client'
454
+ * const observer: ApiRequestObserver = record => { const failed = !record.success }
455
+ * const unsubscribe = apiClient.observeRequests(observer)
456
+ * unsubscribe()
457
+ * ```
458
+ */
459
+ type ApiRequestObserver = (record: ApiRequestRecord) => void;
460
+ /**
461
+ * 由 oRPC 契约推导的 JSON typed client,与生命周期组合;procedure 的输入/输出由契约决定。
462
+ * 调用先检查初始化和业务 HaiResult;自定义契约不能覆盖 init/close/config/isInitialized/auth 顶层成员。
463
+ *
464
+ * @example
465
+ * ```ts
466
+ * import { apiClient, type ApiClient } from '@h-ai/api-client'
467
+ * import { apiContract } from '@h-ai/api-contract'
468
+ * const contract = apiContract.create({ iam: apiContract.iam })
469
+ * const client: ApiClient<typeof contract> = apiClient.create(contract)
470
+ * const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
471
+ * if (!initialized.success) throw new Error(initialized.error.message)
472
+ * try {
473
+ * const result = await client.iam.auth.currentUser()
474
+ * if (!result.success) throw new Error(result.error.message)
475
+ * const userId = result.data.id
476
+ * }
477
+ * finally { await client.close() }
478
+ * ```
479
+ */
172
480
  type ApiClient<TContract extends AnyContractRouter> = ApiClientLifecycle & JsonifiedClient<ContractRouterClient<TContract>>;
173
481
 
174
- /** 与认证场景表单对齐的登录输入。 */
482
+ /**
483
+ * 认证表单登录输入;默认 password,ldap 使用 identifier/password,email/sms 使用 identifier/code。
484
+ * method/code 为客户端表单辅助字段,按所选方式映射到标准 IAM procedure。
485
+ *
486
+ * @example
487
+ * ```ts
488
+ * import type { IamAuthLoginInput } from '@h-ai/api-client'
489
+ * const input: IamAuthLoginInput = { identifier: 'alice@example.com', password: '', method: 'email', code: '123456' }
490
+ * ```
491
+ */
175
492
  type IamAuthLoginInput = IamLoginInput & {
176
493
  method?: 'password' | 'ldap' | 'email' | 'sms';
177
494
  code?: string;
178
495
  };
179
- /** 绑定任意包含标准 iam contract 的客户端;成功时自动保存 Token。 */
496
+ /**
497
+ * 将含标准 IAM 契约的客户端绑定为认证表单动作;包用户通过 apiClient.createAuthActions 调用。
498
+ * 登录/注册成功后等待 client.auth.setTokens,失败 HaiResult 原样返回;存储失败拒绝 Promise,不能据服务端成功就显示已登录。
499
+ * 调用方必须先 init 并启用 auth;未启用 auth 时客户端 setTokens 不会建立 Token 管理器。
500
+ * @param client - 具有标准 IAM procedure 与 setTokens 能力的已初始化客户端。
501
+ * @param client.iam - 标准 IAM 契约的领域分组。
502
+ * @param client.iam.auth - 公开配置、登录、注册、验证码和密码重置 procedure。
503
+ * @param client.auth - 认证成功后的凭据写入能力(setTokens)。
504
+ * @returns publicConfig、按方式登录、注册、验证码和密码重置动作。
505
+ *
506
+ * @example
507
+ * ```ts
508
+ * import { apiClient } from '@h-ai/api-client'
509
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
510
+ * if (!initialized.success) throw new Error(initialized.error.message)
511
+ * try {
512
+ * const actions = apiClient.createAuthActions(apiClient)
513
+ * // 运行时凭据来自已验证的表单;此处只请求公开配置,不提交示例密码。
514
+ * const config = await actions.publicConfig()
515
+ * if (!config.success) throw new Error(config.error.message)
516
+ * }
517
+ * finally { await apiClient.close() }
518
+ * ```
519
+ */
180
520
  declare function createIamAuthActions(client: {
181
521
  iam: {
182
522
  auth: Pick<ApiClient<{
@@ -382,17 +722,19 @@ declare function createIamAuthActions(client: {
382
722
  /**
383
723
  * @h-ai/api-client — Token 存储与刷新管理
384
724
  *
385
- * 提供两个内置 Token 存储适配器(localStorage / 内存)和一个 Token 管理器
725
+ * 提供两个内置 Token 存储适配器(httpOnly Cookie / 内存)和一个 Token 管理器
386
726
  * (封装存储读写、自动刷新、并发去重、回调通知)。
387
727
  *
388
728
  * @example 浏览器 SPA
389
729
  * ```ts
390
730
  * import { apiClient } from '@h-ai/api-client'
391
731
  *
392
- * await apiClient.init({
732
+ * const initialized = await apiClient.init({
393
733
  * baseUrl: 'https://api.example.com/api/v1',
394
- * auth: { storage: apiClient.tokenStorage.localStorage() },
734
+ * auth: { storage: apiClient.tokenStorage.httpOnlyCookie() },
395
735
  * })
736
+ * if (!initialized.success) throw new Error(initialized.error.message)
737
+ * await apiClient.close()
396
738
  * ```
397
739
  *
398
740
  * @example Node.js 测试
@@ -400,122 +742,80 @@ declare function createIamAuthActions(client: {
400
742
  * import { apiClient } from '@h-ai/api-client'
401
743
  *
402
744
  * const storage = apiClient.tokenStorage.memory()
403
- * await storage.setAccessToken('abc')
745
+ * await storage.setAccessToken('test-access')
746
+ * await storage.clear()
404
747
  * ```
405
748
  *
406
749
  * @module api-client-auth
407
750
  */
408
751
 
409
752
  /**
410
- * 创建基于 `localStorage` 的 Token 存储(浏览器 SPA / PWA)。
411
- *
412
- * ⚠️ 安全提示(XSS 风险):
413
- * - `localStorage` 对同源脚本可读,任意 XSS 漏洞都可以偷取 Token。
414
- * - 生产环境应优先使用 httpOnly cookie + SameSite 或 BFF 主机代理。
415
- * - 本适配器仅适用于内部工具、Demo、或者已接受 XSS 风险的浏览器场景,
416
- * 并且在调用方明确选择使用。`apiClient.create` 默认不会使用本适配器,
417
- * 需调用方显式传入 `auth.storage = apiClient.tokenStorage.localStorage()`。
418
- *
419
- * @example
420
- * ```ts
421
- * await apiClient.init({
422
- * baseUrl: 'https://api.example.com/api/v1',
423
- * auth: { storage: apiClient.tokenStorage.localStorage() },
424
- * })
425
- * ```
426
- */
427
- declare function createLocalStorageTokenStorage(): TokenStorage;
428
- /**
429
- * 创建内存 Token 存储(Node.js 测试 / SSR / 短生命周期场景)。
430
- * 页面刷新后丢失。
753
+ * 创建仅属于本适配器实例的内存凭据存储,页面刷新或进程结束后丢失。
754
+ * SSR 应为每个请求创建客户端和存储实例,避免不同用户共享默认单例。
755
+ * 通过 client.auth 更新已绑定的存储,才能撤销旧代际刷新;直接存储写入不提供这种保证。
756
+ * @returns 两个初始为空的 Token 槽位及清理操作。
431
757
  *
432
758
  * @example
433
759
  * ```ts
760
+ * import { apiClient } from '@h-ai/api-client'
434
761
  * const storage = apiClient.tokenStorage.memory()
435
- * await storage.setAccessToken('abc')
762
+ * await storage.setAccessToken('test-access')
763
+ * const saved = await storage.getAccessToken()
764
+ * await storage.clear()
765
+ * // saved 为本实例的测试值;不把 Token 写入 Web Storage。
436
766
  * ```
437
767
  */
438
768
  declare function createMemoryTokenStorage(): TokenStorage;
439
769
  /**
440
- * 创建基于 httpOnly cookie 的 Token 存储(生产环境推荐方案)。
441
- *
442
- * **安全模型:**
443
- * - `accessToken` 保存在**内存**中:JS 可读写,用于注入 `Authorization: Bearer`;
444
- * 页面刷新后丢失,由 refresh 流程自动补充。
445
- * - `refreshToken` 保存在服务端设置的 **httpOnly cookie** 中:
446
- * - JS 不可读写,XSS 脚本无法直接盗取。
447
- * - 结合 `SameSite=Strict` 可阻止 CSRF 攻击。
448
- * - 浏览器在每次请求时自动携带,无需客户端显式传递。
449
- *
450
- * **服务端配套要求:**
451
- * 1. 登录端点在响应中设置:
452
- * ```
453
- * Set-Cookie: refresh_token=<token>; HttpOnly; SameSite=Strict; Secure;
454
- * Path=/api/v1/auth/refresh; Max-Age=<seconds>
455
- * ```
456
- * `Path` 限定为 refresh 端点,减少 Cookie 暴露面。
457
- * 2. Refresh 端点从 Cookie 读取 refresh token(忽略请求体中的 `refreshToken` 字段)。
458
- * 3. Logout 端点清除 Cookie:
459
- * ```
460
- * Set-Cookie: refresh_token=; HttpOnly; SameSite=Strict; Secure;
461
- * Path=/api/v1/auth/refresh; Max-Age=0
462
- * ```
463
- *
464
- * **跨域注意事项:**
465
- * 若 API 与前端不同源,服务端还需设置:
466
- * `Access-Control-Allow-Origin: <前端域名>` 和 `Access-Control-Allow-Credentials: true`。
467
- * 调用方不需要做额外配置,`apiClient.create` 会自动识别并设置 `credentials: 'include'`。
770
+ * 创建浏览器使用的内存 access token 与服务端 httpOnly refresh Cookie 适配器。
771
+ * refresh getter 返回内部哨兵,setter 不修改 Cookie;clear 只清除内存 access token。
772
+ * 刷新请求使用 credentials: include;服务端须实际设置/撤销 Cookie,配置适当的 Secure、SameSite、Path 与跨域凭据策略。
773
+ * HttpOnly 限制脚本直接读取 Cookie,不能阻止已执行的恶意脚本代用户发请求;服务端仍须授权和防护 CSRF。
774
+ * @returns 独立内存 access token 与 Cookie 模式标记;不接触 localStorage。
468
775
  *
469
776
  * @example
470
777
  * ```ts
471
- * await apiClient.init({
472
- * baseUrl: 'https://api.example.com/api/v1',
473
- * auth: { storage: apiClient.tokenStorage.httpOnlyCookie() },
474
- * })
778
+ * import { apiClient } from '@h-ai/api-client'
779
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: { storage: apiClient.tokenStorage.httpOnlyCookie() } })
780
+ * if (!initialized.success) throw new Error(initialized.error.message)
781
+ * try {
782
+ * const me = await apiClient.iam.auth.currentUser()
783
+ * if (!me.success) throw new Error(me.error.message)
784
+ * const userId = me.data.id
785
+ * }
786
+ * finally { await apiClient.close() }
475
787
  * ```
476
788
  */
477
789
  declare function createHttpOnlyCookieTokenStorage(): TokenStorage;
478
790
 
479
- /** Token 存储方案集合:内存 / 浏览器 localStorage / httpOnly Cookie。 */
791
+ /** Token 存储方案集合:内存 / httpOnly Cookie。 */
480
792
  declare const tokenStorage: {
481
793
  /** 内存存储——SSR / Node 测试或一次性会话使用。 */
482
794
  readonly memory: typeof createMemoryTokenStorage;
483
- /** 浏览器 `localStorage` 存储——单页应用便捷选项;注意 XSS 风险。 */
484
- readonly localStorage: typeof createLocalStorageTokenStorage;
485
795
  /** httpOnly Cookie 存储——浏览器场景推荐方案。 */
486
796
  readonly httpOnlyCookie: typeof createHttpOnlyCookieTokenStorage;
487
797
  };
488
798
  /**
489
- * 根据 oRPC contract 创建 typed API client。
799
+ * 按真实 oRPC 契约创建独立 typed client;公开调用入口为 apiClient.create(contract)。
800
+ * init 返回 HaiResult,成功后才调用 procedure;已初始化实例必须先 close 再换配置。
801
+ * procedure 将传输异常转换为 HaiResult;auth.setTokens/clear 的安全存储失败仍会拒绝 Promise。
802
+ * SSR 应为每个请求创建客户端和内存存储;不共享默认单例中的用户凭据。
803
+ * @param contract - 已定义的嵌套 oRPC contract;顶层命名不能与生命周期成员冲突。
804
+ * @returns 生命周期、认证辅助操作与契约推导出的 procedure 代理。
490
805
  *
491
- * 返回对象同时具备:
492
- * - **生命周期能力**:`init` / `close` / `config` / `isInitialized` / `auth`
493
- * - **contract procedure**:按 contract 嵌套结构调用,例如 `client.iam.auth.login(input)`
494
- *
495
- * @example 基础用法
806
+ * @example
496
807
  * ```ts
497
808
  * import { apiClient } from '@h-ai/api-client'
498
809
  * import { apiContract } from '@h-ai/api-contract'
499
- *
500
810
  * const client = apiClient.create(apiContract.create({ iam: apiContract.iam }))
501
- * await client.init({ baseUrl: 'https://api.example.com/api/v1' })
502
- *
503
- * const result = await client.iam.auth.login({ identifier: 'alice', password: 'secret' })
504
- * if (result.success) {
505
- * await client.auth.setTokens(result.data.tokens)
811
+ * const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1', auth: { storage: apiClient.tokenStorage.memory() }, timeout: 10000 })
812
+ * if (!initialized.success) throw new Error(initialized.error.message)
813
+ * try {
814
+ * const result = await client.iam.auth.currentUser()
815
+ * if (!result.success) throw new Error(result.error.message)
816
+ * const userId = result.data.id
506
817
  * }
507
- *
508
- * await client.close()
509
- * ```
510
- *
511
- * @example 自定义 fetch / 超时
512
- * ```ts
513
- * const client = apiClient.create(contract)
514
- * await client.init({
515
- * baseUrl: 'https://api.example.com/api/v1',
516
- * fetch: customFetch,
517
- * timeout: 10_000,
518
- * })
818
+ * finally { await client.close() }
519
819
  * ```
520
820
  */
521
821
  declare function createApiClient<const TContract extends AnyContractRouter>(contract: TContract): ApiClient<TContract>;
@@ -528,12 +828,16 @@ declare function createApiClient<const TContract extends AnyContractRouter>(cont
528
828
  * ```ts
529
829
  * import { apiClient } from '@h-ai/api-client'
530
830
  *
531
- * await apiClient.init({
831
+ * const initialized = await apiClient.init({
532
832
  * baseUrl: 'http://localhost:3000/api/v1',
533
833
  * auth: { refreshPath: '/auth/refresh' },
534
834
  * })
535
- * const result = await apiClient.iam.auth.login({ identifier: 'alice', password: 'secret' })
536
- * await apiClient.close()
835
+ * if (!initialized.success) throw new Error(initialized.error.message)
836
+ * try {
837
+ * const result = await apiClient.iam.auth.currentUser()
838
+ * if (!result.success) throw new Error(result.error.message)
839
+ * }
840
+ * finally { await apiClient.close() }
537
841
  * ```
538
842
  */
539
843
  declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
@@ -699,7 +1003,6 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
699
1003
  login: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
700
1004
  identifier: zod.ZodString;
701
1005
  password: zod.ZodString;
702
- rememberMe: zod.ZodOptional<zod.ZodBoolean>;
703
1006
  }, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
704
1007
  success: zod.ZodLiteral<true>;
705
1008
  data: zod.ZodObject<{
@@ -1466,7 +1769,7 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1466
1769
  createDownload: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
1467
1770
  key: zod.ZodString;
1468
1771
  expiresIn: zod.ZodOptional<zod.ZodNumber>;
1469
- }, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1772
+ }, zod_v4_core.$strict>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1470
1773
  success: zod.ZodLiteral<true>;
1471
1774
  data: zod.ZodObject<{
1472
1775
  url: zod.ZodString;
@@ -1489,9 +1792,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1489
1792
  createUpload: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
1490
1793
  key: zod.ZodString;
1491
1794
  contentType: zod.ZodOptional<zod.ZodString>;
1492
- contentLength: zod.ZodOptional<zod.ZodNumber>;
1493
1795
  expiresIn: zod.ZodOptional<zod.ZodNumber>;
1494
- }, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1796
+ }, zod_v4_core.$strict>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1495
1797
  success: zod.ZodLiteral<true>;
1496
1798
  data: zod.ZodObject<{
1497
1799
  url: zod.ZodString;
@@ -1593,7 +1895,19 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1593
1895
  keys: zod.ZodArray<zod.ZodString>;
1594
1896
  }, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1595
1897
  success: zod.ZodLiteral<true>;
1596
- data: zod.ZodVoid;
1898
+ data: zod.ZodObject<{
1899
+ deletedKeys: zod.ZodArray<zod.ZodString>;
1900
+ failures: zod.ZodArray<zod.ZodObject<{
1901
+ key: zod.ZodString;
1902
+ code: zod.ZodString;
1903
+ retryable: zod.ZodBoolean;
1904
+ outcome: zod.ZodEnum<{
1905
+ unknown: "unknown";
1906
+ failed: "failed";
1907
+ notAttempted: "notAttempted";
1908
+ }>;
1909
+ }, zod_v4_core.$strip>>;
1910
+ }, zod_v4_core.$strip>;
1597
1911
  }, zod_v4_core.$strip>, zod.ZodObject<{
1598
1912
  success: zod.ZodLiteral<false>;
1599
1913
  error: zod.ZodObject<{
@@ -1604,7 +1918,21 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1604
1918
  module: zod.ZodOptional<zod.ZodString>;
1605
1919
  cause: zod.ZodOptional<zod.ZodUnknown>;
1606
1920
  suggestion: zod.ZodOptional<zod.ZodString>;
1607
- ext: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>>;
1921
+ ext: zod.ZodOptional<zod.ZodObject<{
1922
+ deleteMany: zod.ZodOptional<zod.ZodObject<{
1923
+ deletedKeys: zod.ZodArray<zod.ZodString>;
1924
+ failures: zod.ZodArray<zod.ZodObject<{
1925
+ key: zod.ZodString;
1926
+ code: zod.ZodString;
1927
+ retryable: zod.ZodBoolean;
1928
+ outcome: zod.ZodEnum<{
1929
+ unknown: "unknown";
1930
+ failed: "failed";
1931
+ notAttempted: "notAttempted";
1932
+ }>;
1933
+ }, zod_v4_core.$strip>>;
1934
+ }, zod_v4_core.$strip>>;
1935
+ }, zod_v4_core.$catchall<zod.ZodUnknown>>>;
1608
1936
  }, zod_v4_core.$strip>;
1609
1937
  }, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
1610
1938
  };
@@ -1612,18 +1940,22 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1612
1940
  readonly ai: {
1613
1941
  chats: {
1614
1942
  createCompletion: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
1943
+ objectId: zod.ZodOptional<zod.ZodString>;
1944
+ sessionId: zod.ZodOptional<zod.ZodString>;
1615
1945
  model: zod.ZodOptional<zod.ZodString>;
1616
- messages: zod.ZodArray<zod.ZodObject<{
1617
- role: zod.ZodEnum<{
1618
- system: "system";
1619
- user: "user";
1620
- assistant: "assistant";
1621
- tool: "tool";
1622
- }>;
1623
- content: zod.ZodOptional<zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
1946
+ messages: zod.ZodArray<zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1947
+ role: zod.ZodLiteral<"system">;
1948
+ content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
1949
+ type: zod.ZodLiteral<"text">;
1950
+ text: zod.ZodString;
1951
+ }, zod_v4_core.$strict>>]>;
1952
+ name: zod.ZodOptional<zod.ZodString>;
1953
+ }, zod_v4_core.$strict>, zod.ZodObject<{
1954
+ role: zod.ZodLiteral<"user">;
1955
+ content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
1624
1956
  type: zod.ZodLiteral<"text">;
1625
1957
  text: zod.ZodString;
1626
- }, zod_v4_core.$strip>, zod.ZodObject<{
1958
+ }, zod_v4_core.$strict>, zod.ZodObject<{
1627
1959
  type: zod.ZodLiteral<"image_url">;
1628
1960
  image_url: zod.ZodObject<{
1629
1961
  url: zod.ZodString;
@@ -1632,8 +1964,15 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1632
1964
  low: "low";
1633
1965
  high: "high";
1634
1966
  }>>;
1635
- }, zod_v4_core.$strip>;
1636
- }, zod_v4_core.$strip>]>>]>>;
1967
+ }, zod_v4_core.$strict>;
1968
+ }, zod_v4_core.$strict>]>>]>;
1969
+ name: zod.ZodOptional<zod.ZodString>;
1970
+ }, zod_v4_core.$strict>, zod.ZodObject<{
1971
+ role: zod.ZodLiteral<"assistant">;
1972
+ content: zod.ZodOptional<zod.ZodNullable<zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
1973
+ type: zod.ZodLiteral<"text">;
1974
+ text: zod.ZodString;
1975
+ }, zod_v4_core.$strict>>]>>>;
1637
1976
  name: zod.ZodOptional<zod.ZodString>;
1638
1977
  tool_calls: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
1639
1978
  id: zod.ZodString;
@@ -1641,37 +1980,35 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1641
1980
  function: zod.ZodObject<{
1642
1981
  name: zod.ZodString;
1643
1982
  arguments: zod.ZodString;
1644
- }, zod_v4_core.$strip>;
1645
- }, zod_v4_core.$strip>>>;
1646
- tool_call_id: zod.ZodOptional<zod.ZodString>;
1647
- }, zod_v4_core.$strip>>;
1983
+ }, zod_v4_core.$strict>;
1984
+ }, zod_v4_core.$strict>>>;
1985
+ }, zod_v4_core.$strict>, zod.ZodObject<{
1986
+ role: zod.ZodLiteral<"tool">;
1987
+ content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
1988
+ type: zod.ZodLiteral<"text">;
1989
+ text: zod.ZodString;
1990
+ }, zod_v4_core.$strict>>]>;
1991
+ tool_call_id: zod.ZodString;
1992
+ }, zod_v4_core.$strict>], "role">>;
1648
1993
  temperature: zod.ZodOptional<zod.ZodNumber>;
1649
1994
  top_p: zod.ZodOptional<zod.ZodNumber>;
1650
1995
  max_tokens: zod.ZodOptional<zod.ZodNumber>;
1651
- stream: zod.ZodOptional<zod.ZodBoolean>;
1652
1996
  tools: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
1653
1997
  type: zod.ZodLiteral<"function">;
1654
1998
  function: zod.ZodObject<{
1655
1999
  name: zod.ZodString;
1656
2000
  description: zod.ZodOptional<zod.ZodString>;
1657
- parameters: zod.ZodOptional<zod.ZodObject<{
1658
- type: zod.ZodLiteral<"object">;
1659
- properties: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodObject<{
1660
- type: zod.ZodString;
1661
- description: zod.ZodOptional<zod.ZodString>;
1662
- enum: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
1663
- }, zod_v4_core.$strip>>>;
1664
- required: zod.ZodOptional<zod.ZodArray<zod.ZodString>>;
1665
- }, zod_v4_core.$strip>>;
1666
- }, zod_v4_core.$strip>;
1667
- }, zod_v4_core.$strip>>>;
1668
- tool_choice: zod.ZodOptional<zod.ZodUnion<readonly [zod.ZodLiteral<"auto">, zod.ZodLiteral<"none">, zod.ZodObject<{
2001
+ parameters: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodJSONSchema>>;
2002
+ strict: zod.ZodOptional<zod.ZodNullable<zod.ZodBoolean>>;
2003
+ }, zod_v4_core.$strict>;
2004
+ }, zod_v4_core.$strict>>>;
2005
+ tool_choice: zod.ZodOptional<zod.ZodUnion<readonly [zod.ZodLiteral<"auto">, zod.ZodLiteral<"none">, zod.ZodLiteral<"required">, zod.ZodObject<{
1669
2006
  type: zod.ZodLiteral<"function">;
1670
2007
  function: zod.ZodObject<{
1671
2008
  name: zod.ZodString;
1672
- }, zod_v4_core.$strip>;
1673
- }, zod_v4_core.$strip>]>>;
1674
- }, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
2009
+ }, zod_v4_core.$strict>;
2010
+ }, zod_v4_core.$strict>]>>;
2011
+ }, zod_v4_core.$strict>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1675
2012
  success: zod.ZodLiteral<true>;
1676
2013
  data: zod.ZodObject<{
1677
2014
  id: zod.ZodString;
@@ -1689,8 +2026,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1689
2026
  function: zod.ZodObject<{
1690
2027
  name: zod.ZodString;
1691
2028
  arguments: zod.ZodString;
1692
- }, zod_v4_core.$strip>;
1693
- }, zod_v4_core.$strip>>>;
2029
+ }, zod_v4_core.$strict>;
2030
+ }, zod_v4_core.$strict>>>;
1694
2031
  }, zod_v4_core.$strip>;
1695
2032
  finish_reason: zod.ZodEnum<{
1696
2033
  length: "length";
@@ -1719,6 +2056,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1719
2056
  }, zod_v4_core.$strip>;
1720
2057
  }, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
1721
2058
  sendMessage: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
2059
+ objectId: zod.ZodOptional<zod.ZodString>;
2060
+ sessionId: zod.ZodOptional<zod.ZodString>;
1722
2061
  message: zod.ZodString;
1723
2062
  systemPrompt: zod.ZodOptional<zod.ZodString>;
1724
2063
  model: zod.ZodOptional<zod.ZodString>;
@@ -1748,7 +2087,7 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1748
2087
  }, zod_v4_core.$strip>;
1749
2088
  }, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
1750
2089
  listHistory: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
1751
- objectId: zod.ZodString;
2090
+ objectId: zod.ZodOptional<zod.ZodString>;
1752
2091
  sessionId: zod.ZodString;
1753
2092
  limit: zod.ZodOptional<zod.ZodNumber>;
1754
2093
  order: zod.ZodOptional<zod.ZodEnum<{
@@ -1764,17 +2103,19 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1764
2103
  sessionId: zod.ZodString;
1765
2104
  request: zod.ZodObject<{
1766
2105
  model: zod.ZodString;
1767
- messages: zod.ZodArray<zod.ZodObject<{
1768
- role: zod.ZodEnum<{
1769
- system: "system";
1770
- user: "user";
1771
- assistant: "assistant";
1772
- tool: "tool";
1773
- }>;
1774
- content: zod.ZodOptional<zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
2106
+ messages: zod.ZodArray<zod.ZodDiscriminatedUnion<[zod.ZodObject<{
2107
+ role: zod.ZodLiteral<"system">;
2108
+ content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
2109
+ type: zod.ZodLiteral<"text">;
2110
+ text: zod.ZodString;
2111
+ }, zod_v4_core.$strict>>]>;
2112
+ name: zod.ZodOptional<zod.ZodString>;
2113
+ }, zod_v4_core.$strict>, zod.ZodObject<{
2114
+ role: zod.ZodLiteral<"user">;
2115
+ content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
1775
2116
  type: zod.ZodLiteral<"text">;
1776
2117
  text: zod.ZodString;
1777
- }, zod_v4_core.$strip>, zod.ZodObject<{
2118
+ }, zod_v4_core.$strict>, zod.ZodObject<{
1778
2119
  type: zod.ZodLiteral<"image_url">;
1779
2120
  image_url: zod.ZodObject<{
1780
2121
  url: zod.ZodString;
@@ -1783,8 +2124,15 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1783
2124
  low: "low";
1784
2125
  high: "high";
1785
2126
  }>>;
1786
- }, zod_v4_core.$strip>;
1787
- }, zod_v4_core.$strip>]>>]>>;
2127
+ }, zod_v4_core.$strict>;
2128
+ }, zod_v4_core.$strict>]>>]>;
2129
+ name: zod.ZodOptional<zod.ZodString>;
2130
+ }, zod_v4_core.$strict>, zod.ZodObject<{
2131
+ role: zod.ZodLiteral<"assistant">;
2132
+ content: zod.ZodOptional<zod.ZodNullable<zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
2133
+ type: zod.ZodLiteral<"text">;
2134
+ text: zod.ZodString;
2135
+ }, zod_v4_core.$strict>>]>>>;
1788
2136
  name: zod.ZodOptional<zod.ZodString>;
1789
2137
  tool_calls: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
1790
2138
  id: zod.ZodString;
@@ -1792,10 +2140,16 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1792
2140
  function: zod.ZodObject<{
1793
2141
  name: zod.ZodString;
1794
2142
  arguments: zod.ZodString;
1795
- }, zod_v4_core.$strip>;
1796
- }, zod_v4_core.$strip>>>;
1797
- tool_call_id: zod.ZodOptional<zod.ZodString>;
1798
- }, zod_v4_core.$strip>>;
2143
+ }, zod_v4_core.$strict>;
2144
+ }, zod_v4_core.$strict>>>;
2145
+ }, zod_v4_core.$strict>, zod.ZodObject<{
2146
+ role: zod.ZodLiteral<"tool">;
2147
+ content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
2148
+ type: zod.ZodLiteral<"text">;
2149
+ text: zod.ZodString;
2150
+ }, zod_v4_core.$strict>>]>;
2151
+ tool_call_id: zod.ZodString;
2152
+ }, zod_v4_core.$strict>], "role">>;
1799
2153
  }, zod_v4_core.$strip>;
1800
2154
  response: zod.ZodObject<{
1801
2155
  content: zod.ZodString;
@@ -1805,8 +2159,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1805
2159
  function: zod.ZodObject<{
1806
2160
  name: zod.ZodString;
1807
2161
  arguments: zod.ZodString;
1808
- }, zod_v4_core.$strip>;
1809
- }, zod_v4_core.$strip>>>;
2162
+ }, zod_v4_core.$strict>;
2163
+ }, zod_v4_core.$strict>>>;
1810
2164
  finishReason: zod.ZodString;
1811
2165
  usage: zod.ZodObject<{
1812
2166
  prompt_tokens: zod.ZodNumber;
@@ -1928,7 +2282,7 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1928
2282
  };
1929
2283
  sessions: {
1930
2284
  list: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
1931
- objectId: zod.ZodString;
2285
+ objectId: zod.ZodOptional<zod.ZodString>;
1932
2286
  }, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
1933
2287
  success: zod.ZodLiteral<true>;
1934
2288
  data: zod.ZodObject<{
@@ -1956,13 +2310,43 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
1956
2310
  };
1957
2311
  };
1958
2312
  }>;
1959
- /** `apiClient` 默认单例 + 工厂命名空间的统一对外类型。 */
2313
+ /**
2314
+ * 默认 iam/storage/ai typed client 与 create、tokenStorage、createAuthActions 命名空间的交叉类型。
2315
+ * 具体项目契约使用 apiClient.create 的返回类型,不给默认单例附加未知 procedure。
2316
+ *
2317
+ * @example
2318
+ * ```ts
2319
+ * import { apiClient, type DefaultApiClient } from '@h-ai/api-client'
2320
+ * const client: DefaultApiClient = apiClient
2321
+ * const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
2322
+ * if (!initialized.success) throw new Error(initialized.error.message)
2323
+ * try { const actions = client.createAuthActions(client); const result = await actions.publicConfig(); if (!result.success) throw new Error(result.error.message) }
2324
+ * finally { await client.close() }
2325
+ * ```
2326
+ */
1960
2327
  type DefaultApiClient = ApiClient<typeof defaultApiContract> & {
1961
2328
  readonly create: typeof createApiClient;
1962
2329
  readonly tokenStorage: typeof tokenStorage;
1963
2330
  readonly createAuthActions: typeof createIamAuthActions;
1964
2331
  };
1965
- /** hai-framework API client 统一入口(默认单例 + `create` + `tokenStorage`)。 */
2332
+ /**
2333
+ * API Client 公开入口:默认 iam/storage/ai 单例,以及独立实例、安全存储和认证动作工厂。
2334
+ * 未启用 auth 时不注入或刷新 Token;浏览器 auth: {} 使用 httpOnly Cookie 方案。
2335
+ * close 释放客户端运行状态/加密会话,不能替代服务端退出或 auth.clear。
2336
+ *
2337
+ * @example
2338
+ * ```ts
2339
+ * import { apiClient } from '@h-ai/api-client'
2340
+ * const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
2341
+ * if (!initialized.success) throw new Error(initialized.error.message)
2342
+ * try {
2343
+ * const result = await apiClient.iam.auth.currentUser()
2344
+ * if (!result.success) throw new Error(result.error.message)
2345
+ * const permissions = result.data.permissions
2346
+ * }
2347
+ * finally { await apiClient.close() }
2348
+ * ```
2349
+ */
1966
2350
  declare const apiClient: DefaultApiClient;
1967
2351
 
1968
- export { type ApiClient, type ApiClientAuth, type ApiClientConfig, type ApiClientLifecycle, type ApiClientTransportConfig, type AuthConfig, type DefaultApiClient, HaiApiClientError, type IamAuthLoginInput, type TokenPair, type TokenStorage, apiClient };
2352
+ export { type ApiClient, type ApiClientAuth, type ApiClientConfig, type ApiClientLifecycle, type ApiClientTransportConfig, type ApiRequestObserver, type ApiRequestRecord, type AuthConfig, type DefaultApiClient, HaiApiClientError, type IamAuthLoginInput, type TokenPair, type TokenStorage, apiClient };