@h-ai/api-client 0.1.0-alpha.67 → 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.
- package/README.en.md +21 -3
- package/README.ja.md +21 -3
- package/README.md +21 -3
- package/dist/index.d.ts +518 -179
- package/dist/index.js +113 -47
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
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
|
-
*
|
|
14
|
+
* 客户端标准错误集合;包含稳定 code/httpStatus 与构造错误的方法,业务调用先检查 success。
|
|
15
|
+
* 传输失败在 procedure 代理中映射;服务端 HaiResult 的业务错误保持原契约。
|
|
15
16
|
*
|
|
16
17
|
* @example
|
|
17
18
|
* ```ts
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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: {
|
|
@@ -33,7 +42,17 @@ declare const HaiApiClientError: {
|
|
|
33
42
|
readonly CONFIG_ERROR: _h_ai_core.HaiErrorDef;
|
|
34
43
|
readonly UNKNOWN: _h_ai_core.HaiErrorDef;
|
|
35
44
|
};
|
|
36
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* 短期 access token、可选 refresh token 与有效期;HTTP 头使用 Bearer。
|
|
47
|
+
* Cookie 模式的 refresh token 由服务端管理,不能要求浏览器读取或持久化它。
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import type { TokenPair } from '@h-ai/api-client'
|
|
52
|
+
* const tokens: TokenPair = { accessToken: 'test-access', expiresIn: 3600, tokenType: 'Bearer' }
|
|
53
|
+
* // 示例为测试凭据;生产 Token 只能来自可信服务端认证响应。
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
37
56
|
interface TokenPair {
|
|
38
57
|
/** 短期访问凭证,请求时作为 `Authorization: Bearer ...`。 */
|
|
39
58
|
readonly accessToken: string;
|
|
@@ -45,30 +64,110 @@ interface TokenPair {
|
|
|
45
64
|
readonly tokenType: 'Bearer';
|
|
46
65
|
}
|
|
47
66
|
/**
|
|
48
|
-
*
|
|
67
|
+
* 异步安全凭据存储契约;null 仅表示无可用凭据,读写故障须拒绝 Promise。
|
|
68
|
+
* 浏览器使用内存 access token/httpOnly refresh Cookie,原生端注入平台安全存储,禁止敏感 Token 放入 localStorage。
|
|
69
|
+
* 已绑定客户端的身份切换通过 client.auth,避免绕过刷新代际与串行写入;部分写入失败须执行清理并报告清理失败。
|
|
49
70
|
*
|
|
50
71
|
* 内置实现:
|
|
51
72
|
* - `apiClient.tokenStorage.httpOnlyCookie()` — **默认**;浏览器端推荐,refresh token 由服务端管理,防 XSS。
|
|
52
73
|
* - `apiClient.tokenStorage.memory()` — Node.js 测试 / SSR(需显式传入)。
|
|
53
|
-
* - `apiClient.tokenStorage.localStorage()` — 浏览器 SPA / PWA(有 XSS 风险,生产不推荐)。
|
|
54
74
|
*
|
|
55
75
|
* Capacitor / 小程序场景请由对应模块提供(例如 `@h-ai/capacitor`)。
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { apiClient, type TokenStorage } from '@h-ai/api-client'
|
|
80
|
+
* const storage: TokenStorage = apiClient.tokenStorage.memory()
|
|
81
|
+
* await storage.setAccessToken('test-access')
|
|
82
|
+
* const accessToken = await storage.getAccessToken()
|
|
83
|
+
* await storage.clear()
|
|
84
|
+
* ```
|
|
56
85
|
*/
|
|
57
86
|
interface TokenStorage {
|
|
87
|
+
/**
|
|
88
|
+
* 读取本适配器可用 access token;无凭据返回 null,存储故障拒绝。
|
|
89
|
+
* @returns Token 或 null;不能把读取失败当成不存在。
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
94
|
+
* const storage = apiClient.tokenStorage.memory()
|
|
95
|
+
* const accessToken = await storage.getAccessToken()
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
58
98
|
readonly getAccessToken: () => Promise<string | null>;
|
|
99
|
+
/**
|
|
100
|
+
* 保存 access token;已绑定客户端应通过 auth.setTokens 维护代际。
|
|
101
|
+
* @param token - 可信服务端认证返回的 access token。
|
|
102
|
+
* @returns 写入完成;底层故障须拒绝。
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
107
|
+
* const storage = apiClient.tokenStorage.memory()
|
|
108
|
+
* await storage.setAccessToken('test-access')
|
|
109
|
+
* await storage.clear()
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
59
112
|
readonly setAccessToken: (token: string) => Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* 读取 refresh token 或 Cookie 模式内部哨兵;null 仅表示没有凭据。
|
|
115
|
+
* @returns Token、模式哨兵或 null,不是对 httpOnly Cookie 内容的脚本读取。
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
120
|
+
* const storage = apiClient.tokenStorage.memory()
|
|
121
|
+
* const refreshToken = await storage.getRefreshToken()
|
|
122
|
+
* // 内存适配器初始为空;Cookie 适配器由管理器识别模式哨兵。
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
60
125
|
readonly getRefreshToken: () => Promise<string | null>;
|
|
126
|
+
/**
|
|
127
|
+
* 保存 refresh token;Cookie 实现不通过脚本修改服务端 Cookie。
|
|
128
|
+
* @param token - 服务端返回的刷新凭据;禁止写入 Web Storage。
|
|
129
|
+
* @returns 写入完成;原生安全存储故障须拒绝。
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
134
|
+
* const storage = apiClient.tokenStorage.memory()
|
|
135
|
+
* await storage.setRefreshToken('test-refresh')
|
|
136
|
+
* await storage.clear()
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
61
139
|
readonly setRefreshToken: (token: string) => Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* 清空适配器可管理的凭据;Cookie 实现只能清内存 access token。
|
|
142
|
+
* @returns 清理完成;失败须拒绝,服务端 Cookie/会话另由退出接口撤销。
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
147
|
+
* const storage = apiClient.tokenStorage.memory()
|
|
148
|
+
* await storage.clear()
|
|
149
|
+
* const remaining = await storage.getAccessToken()
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
62
152
|
readonly clear: () => Promise<void>;
|
|
63
153
|
}
|
|
64
|
-
/**
|
|
154
|
+
/**
|
|
155
|
+
* 启用 Token 注入与自动刷新;默认 Cookie 适配器,refreshPath 相对 baseUrl。
|
|
156
|
+
* 网络/超时/5xx 为暂时失败,保留凭据;明确失效才清理并通知。回调不应抛出或记录 Token。
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* import { apiClient, type AuthConfig } from '@h-ai/api-client'
|
|
161
|
+
* const auth: AuthConfig = { storage: apiClient.tokenStorage.memory(), refreshPath: '/auth/refresh', refreshTimeoutMs: 5000, onTokenRefreshed: tokens => { const lifetime = tokens.expiresIn } }
|
|
162
|
+
* // Node/SSR 选择独立内存存储;浏览器通常直接配置 auth: {}。
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
65
165
|
interface AuthConfig {
|
|
66
166
|
/**
|
|
67
167
|
* Token 存储适配器;默认 `apiClient.tokenStorage.httpOnlyCookie()`(refresh token 由服务端管理,防 XSS)。
|
|
68
168
|
*
|
|
69
169
|
* - SSR / Node.js 测试场景请显式传入 `apiClient.tokenStorage.memory()`。
|
|
70
|
-
* -
|
|
71
|
-
* 但请先评估 XSS 风险。
|
|
170
|
+
* - 浏览器刷新后通过 httpOnly Cookie 恢复会话,不将 Token 持久化到 Web Storage。
|
|
72
171
|
* - Capacitor / 小程序请使用对应平台的安全存储适配器(如 `@h-ai/capacitor`)。
|
|
73
172
|
*/
|
|
74
173
|
readonly storage?: TokenStorage;
|
|
@@ -85,7 +184,20 @@ interface AuthConfig {
|
|
|
85
184
|
/** 刷新失败回调(如 refresh token 已失效),通常用于跳转登录页。 */
|
|
86
185
|
readonly onRefreshFailed?: () => void;
|
|
87
186
|
}
|
|
88
|
-
/**
|
|
187
|
+
/**
|
|
188
|
+
* 客户端初始化配置;baseUrl 包含 API 前缀,headers/fetch 用于平台适配。
|
|
189
|
+
* auth 缺省时不创建 TokenManager;timeout 是底层请求中断期限,不代表服务端已取消副作用。
|
|
190
|
+
* transport 需要已初始化 crypto,首次业务请求前协商会话;客户端不接收服务端私钥。
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* import { apiClient, type ApiClientConfig } from '@h-ai/api-client'
|
|
195
|
+
* 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' }) }
|
|
196
|
+
* const initialized = await apiClient.init(config)
|
|
197
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
198
|
+
* await apiClient.close()
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
89
201
|
interface ApiClientConfig {
|
|
90
202
|
/** API service 完整 baseUrl,通常含 `apiPrefix`,例如 `https://api.example.com/api/v1`。 */
|
|
91
203
|
readonly baseUrl: string;
|
|
@@ -112,16 +224,38 @@ interface ApiClientConfig {
|
|
|
112
224
|
* import { apiClient } from '@h-ai/api-client'
|
|
113
225
|
* import { crypto } from '@h-ai/crypto'
|
|
114
226
|
*
|
|
115
|
-
* await crypto.init()
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* transport: { crypto }
|
|
119
|
-
*
|
|
227
|
+
* const cryptography = await crypto.init()
|
|
228
|
+
* if (!cryptography.success) throw new Error(cryptography.error.message)
|
|
229
|
+
* try {
|
|
230
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', transport: { crypto } })
|
|
231
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
232
|
+
* await apiClient.close()
|
|
233
|
+
* }
|
|
234
|
+
* finally { await crypto.close() }
|
|
120
235
|
* ```
|
|
121
236
|
*/
|
|
122
237
|
readonly transport?: ApiClientTransportConfig;
|
|
123
238
|
}
|
|
124
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
* 可选加密会话配置;密钥协商路径相对 baseUrl,并与服务端配置匹配。
|
|
241
|
+
* crypto 必须先初始化;服务器版本公钥通过受保护的 TLS 握手取得,不配置服务端私钥。
|
|
242
|
+
* 传输防重放不能代替业务幂等性,失败后不要自动重放非幂等操作。
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```ts
|
|
246
|
+
* import { apiClient, type ApiClientTransportConfig } from '@h-ai/api-client'
|
|
247
|
+
* import { crypto } from '@h-ai/crypto'
|
|
248
|
+
* const cryptography = await crypto.init()
|
|
249
|
+
* if (!cryptography.success) throw new Error(cryptography.error.message)
|
|
250
|
+
* try {
|
|
251
|
+
* const transport: ApiClientTransportConfig = { crypto, keyExchangePath: '/_hai/key-exchange' }
|
|
252
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', transport })
|
|
253
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
254
|
+
* await apiClient.close()
|
|
255
|
+
* }
|
|
256
|
+
* finally { await crypto.close() }
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
125
259
|
interface ApiClientTransportConfig {
|
|
126
260
|
/**
|
|
127
261
|
* crypto 服务实例(通常直接传入 `@h-ai/crypto` 的 `crypto`)。
|
|
@@ -135,31 +269,141 @@ interface ApiClientTransportConfig {
|
|
|
135
269
|
*/
|
|
136
270
|
readonly keyExchangePath?: string;
|
|
137
271
|
}
|
|
138
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* 当前客户端的凭据辅助操作;仅 init 启用 auth 时建立实际管理器。
|
|
274
|
+
* setTokens/clear 撤销旧刷新代际并等待串行存储变更;故障拒绝 Promise,调用方处理失败。
|
|
275
|
+
* clear 不能撤销服务端会话或删除 httpOnly Cookie,退出仍需服务端接口成功。
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* import { apiClient, type ApiClientAuth } from '@h-ai/api-client'
|
|
280
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
281
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
282
|
+
* try {
|
|
283
|
+
* const auth: ApiClientAuth = apiClient.auth
|
|
284
|
+
* const off = auth.onTokenRefreshed(tokens => { const lifetime = tokens.expiresIn })
|
|
285
|
+
* off()
|
|
286
|
+
* await auth.clear()
|
|
287
|
+
* }
|
|
288
|
+
* finally { await apiClient.close() }
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
139
291
|
interface ApiClientAuth {
|
|
140
|
-
/**
|
|
292
|
+
/**
|
|
293
|
+
* 替换整对凭据并同步废弃旧刷新代际;缺省 refreshToken 时清除旧值。
|
|
294
|
+
* @param tokens - 服务端成功认证返回的真实 TokenPair。
|
|
295
|
+
* @returns 写入完成;安全存储失败拒绝 Promise,调用方应清理部分凭据并报告清理失败。
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* ```ts
|
|
299
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
300
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
301
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
302
|
+
* try {
|
|
303
|
+
* const form = { identifier: 'alice', password: 'test-password' }
|
|
304
|
+
* const login = await apiClient.iam.auth.login(form)
|
|
305
|
+
* if (!login.success) throw new Error(login.error.message)
|
|
306
|
+
* try { await apiClient.auth.setTokens(login.data.tokens) }
|
|
307
|
+
* catch (writeError) {
|
|
308
|
+
* try { await apiClient.auth.clear() }
|
|
309
|
+
* catch (cleanupError) { throw new AggregateError([writeError, cleanupError], 'Credential persistence and cleanup failed') }
|
|
310
|
+
* throw writeError
|
|
311
|
+
* }
|
|
312
|
+
* }
|
|
313
|
+
* finally { await apiClient.close() }
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
141
316
|
readonly setTokens: (tokens: TokenPair) => Promise<void>;
|
|
142
|
-
/**
|
|
317
|
+
/**
|
|
318
|
+
* 同步废弃旧刷新代际并等待存储清理;失败拒绝 Promise,不声称已持久删除。
|
|
319
|
+
* 服务端会话与 httpOnly Cookie 仍需服务端退出撤销;本操作不能替代退出接口。
|
|
320
|
+
* @returns 本地清理完成,不返回 HaiResult。
|
|
321
|
+
*
|
|
322
|
+
* @example
|
|
323
|
+
* ```ts
|
|
324
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
325
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
326
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
327
|
+
* try {
|
|
328
|
+
* const logout = await apiClient.iam.auth.logout({})
|
|
329
|
+
* await apiClient.auth.clear()
|
|
330
|
+
* if (!logout.success) throw new Error(logout.error.message)
|
|
331
|
+
* // 只有服务端退出和本地清理都成功,才能确认两侧均已处理。
|
|
332
|
+
* }
|
|
333
|
+
* finally { await apiClient.close() }
|
|
334
|
+
* ```
|
|
335
|
+
*/
|
|
143
336
|
readonly clear: () => Promise<void>;
|
|
144
|
-
/**
|
|
337
|
+
/**
|
|
338
|
+
* 订阅当前管理器刷新成功事件;回调在写入后同步调用,避免抛错或输出 Token。
|
|
339
|
+
* @param callback - 接收 TokenPair 的同步回调。
|
|
340
|
+
* @returns 取消订阅函数;未启用 auth 时返回空操作。
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* ```ts
|
|
344
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
345
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
346
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
347
|
+
* try {
|
|
348
|
+
* const off = apiClient.auth.onTokenRefreshed(tokens => { const expiresIn = tokens.expiresIn })
|
|
349
|
+
* off()
|
|
350
|
+
* }
|
|
351
|
+
* finally { await apiClient.close() }
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
145
354
|
readonly onTokenRefreshed: (callback: (tokens: TokenPair) => void) => () => void;
|
|
146
355
|
}
|
|
147
|
-
/**
|
|
356
|
+
/**
|
|
357
|
+
* 客户端生命周期与认证辅助能力;init 的 HaiResult 必须先检查 success。
|
|
358
|
+
* 同一实例并发 init 共享在途初始化,已初始化后再 init 返回 CONFIG_ERROR;切换配置先 close。
|
|
359
|
+
* config 为脱敏快照;close 清理运行状态/加密会话,不等于服务端退出或凭据存储清理。
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* ```ts
|
|
363
|
+
* import { apiClient, type ApiClientLifecycle } from '@h-ai/api-client'
|
|
364
|
+
* const client: ApiClientLifecycle = apiClient
|
|
365
|
+
* const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1' })
|
|
366
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
367
|
+
* const active = client.isInitialized
|
|
368
|
+
* const snapshot = client.config
|
|
369
|
+
* await client.close()
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
148
372
|
interface ApiClientLifecycle {
|
|
149
373
|
/**
|
|
150
|
-
*
|
|
374
|
+
* 构造并提交客户端运行状态;初始化失败返回 CONFIG_ERROR,未提交半初始化对象。
|
|
375
|
+
* 并发 init 共享同一初始化;已初始化再调用会失败,切换配置先 close。
|
|
376
|
+
* @param config - baseUrl、认证、fetch 与可选加密配置。
|
|
377
|
+
* @returns HaiResult;必须先判断 success,再发起 procedure。
|
|
151
378
|
*
|
|
152
379
|
* @example
|
|
153
380
|
* ```ts
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
381
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
382
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
383
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
384
|
+
* try {
|
|
385
|
+
* const result = await apiClient.iam.auth.publicConfig()
|
|
386
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
387
|
+
* }
|
|
388
|
+
* finally { await apiClient.close() }
|
|
159
389
|
* ```
|
|
160
390
|
*/
|
|
161
391
|
readonly init: (config: ApiClientConfig) => Promise<HaiResult<void>>;
|
|
162
|
-
/**
|
|
392
|
+
/**
|
|
393
|
+
* 销毁当前加密会话并清除运行状态,允许重新 init;不发送服务端退出、不清空外置存储。
|
|
394
|
+
* @returns 资源清理完成;不是 HaiResult,不应读取 success。
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```ts
|
|
398
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
399
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
400
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
401
|
+
* await apiClient.close()
|
|
402
|
+
* const reinitialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
403
|
+
* if (!reinitialized.success) throw new Error(reinitialized.error.message)
|
|
404
|
+
* await apiClient.close()
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
163
407
|
readonly close: () => Promise<void>;
|
|
164
408
|
/** 当前脱敏后的运行配置快照;未初始化时为 `null`。 */
|
|
165
409
|
readonly config: ApiClientConfig | null;
|
|
@@ -168,15 +412,66 @@ interface ApiClientLifecycle {
|
|
|
168
412
|
/** Token 辅助操作。 */
|
|
169
413
|
readonly auth: ApiClientAuth;
|
|
170
414
|
}
|
|
171
|
-
/**
|
|
415
|
+
/**
|
|
416
|
+
* 由 oRPC 契约推导的 JSON typed client,与生命周期组合;procedure 的输入/输出由契约决定。
|
|
417
|
+
* 调用先检查初始化和业务 HaiResult;自定义契约不能覆盖 init/close/config/isInitialized/auth 顶层成员。
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* import { apiClient, type ApiClient } from '@h-ai/api-client'
|
|
422
|
+
* import { apiContract } from '@h-ai/api-contract'
|
|
423
|
+
* const contract = apiContract.create({ iam: apiContract.iam })
|
|
424
|
+
* const client: ApiClient<typeof contract> = apiClient.create(contract)
|
|
425
|
+
* const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
426
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
427
|
+
* try {
|
|
428
|
+
* const result = await client.iam.auth.currentUser()
|
|
429
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
430
|
+
* const userId = result.data.id
|
|
431
|
+
* }
|
|
432
|
+
* finally { await client.close() }
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
172
435
|
type ApiClient<TContract extends AnyContractRouter> = ApiClientLifecycle & JsonifiedClient<ContractRouterClient<TContract>>;
|
|
173
436
|
|
|
174
|
-
/**
|
|
437
|
+
/**
|
|
438
|
+
* 认证表单登录输入;默认 password,ldap 使用 identifier/password,email/sms 使用 identifier/code。
|
|
439
|
+
* method/code 为客户端表单辅助字段,按所选方式映射到标准 IAM procedure。
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* ```ts
|
|
443
|
+
* import type { IamAuthLoginInput } from '@h-ai/api-client'
|
|
444
|
+
* const input: IamAuthLoginInput = { identifier: 'alice@example.com', password: '', method: 'email', code: '123456' }
|
|
445
|
+
* ```
|
|
446
|
+
*/
|
|
175
447
|
type IamAuthLoginInput = IamLoginInput & {
|
|
176
448
|
method?: 'password' | 'ldap' | 'email' | 'sms';
|
|
177
449
|
code?: string;
|
|
178
450
|
};
|
|
179
|
-
/**
|
|
451
|
+
/**
|
|
452
|
+
* 将含标准 IAM 契约的客户端绑定为认证表单动作;包用户通过 apiClient.createAuthActions 调用。
|
|
453
|
+
* 登录/注册成功后等待 client.auth.setTokens,失败 HaiResult 原样返回;存储失败拒绝 Promise,不能据服务端成功就显示已登录。
|
|
454
|
+
* 调用方必须先 init 并启用 auth;未启用 auth 时客户端 setTokens 不会建立 Token 管理器。
|
|
455
|
+
* @param client - 具有标准 IAM procedure 与 setTokens 能力的已初始化客户端。
|
|
456
|
+
* @param client.iam - 标准 IAM 契约的领域分组。
|
|
457
|
+
* @param client.iam.auth - 公开配置、登录、注册、验证码和密码重置 procedure。
|
|
458
|
+
* @param client.auth - 认证成功后的凭据写入能力(setTokens)。
|
|
459
|
+
* @returns publicConfig、按方式登录、注册、验证码和密码重置动作。
|
|
460
|
+
*
|
|
461
|
+
* @example
|
|
462
|
+
* ```ts
|
|
463
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
464
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
465
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
466
|
+
* try {
|
|
467
|
+
* const actions = apiClient.createAuthActions(apiClient)
|
|
468
|
+
* // 运行时凭据来自已验证的表单;此处只请求公开配置,不提交示例密码。
|
|
469
|
+
* const config = await actions.publicConfig()
|
|
470
|
+
* if (!config.success) throw new Error(config.error.message)
|
|
471
|
+
* }
|
|
472
|
+
* finally { await apiClient.close() }
|
|
473
|
+
* ```
|
|
474
|
+
*/
|
|
180
475
|
declare function createIamAuthActions(client: {
|
|
181
476
|
iam: {
|
|
182
477
|
auth: Pick<ApiClient<{
|
|
@@ -382,17 +677,19 @@ declare function createIamAuthActions(client: {
|
|
|
382
677
|
/**
|
|
383
678
|
* @h-ai/api-client — Token 存储与刷新管理
|
|
384
679
|
*
|
|
385
|
-
* 提供两个内置 Token 存储适配器(
|
|
680
|
+
* 提供两个内置 Token 存储适配器(httpOnly Cookie / 内存)和一个 Token 管理器
|
|
386
681
|
* (封装存储读写、自动刷新、并发去重、回调通知)。
|
|
387
682
|
*
|
|
388
683
|
* @example 浏览器 SPA
|
|
389
684
|
* ```ts
|
|
390
685
|
* import { apiClient } from '@h-ai/api-client'
|
|
391
686
|
*
|
|
392
|
-
* await apiClient.init({
|
|
687
|
+
* const initialized = await apiClient.init({
|
|
393
688
|
* baseUrl: 'https://api.example.com/api/v1',
|
|
394
|
-
* auth: { storage: apiClient.tokenStorage.
|
|
689
|
+
* auth: { storage: apiClient.tokenStorage.httpOnlyCookie() },
|
|
395
690
|
* })
|
|
691
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
692
|
+
* await apiClient.close()
|
|
396
693
|
* ```
|
|
397
694
|
*
|
|
398
695
|
* @example Node.js 测试
|
|
@@ -400,122 +697,80 @@ declare function createIamAuthActions(client: {
|
|
|
400
697
|
* import { apiClient } from '@h-ai/api-client'
|
|
401
698
|
*
|
|
402
699
|
* const storage = apiClient.tokenStorage.memory()
|
|
403
|
-
* await storage.setAccessToken('
|
|
700
|
+
* await storage.setAccessToken('test-access')
|
|
701
|
+
* await storage.clear()
|
|
404
702
|
* ```
|
|
405
703
|
*
|
|
406
704
|
* @module api-client-auth
|
|
407
705
|
*/
|
|
408
706
|
|
|
409
707
|
/**
|
|
410
|
-
*
|
|
411
|
-
*
|
|
412
|
-
*
|
|
413
|
-
*
|
|
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
|
-
* 页面刷新后丢失。
|
|
708
|
+
* 创建仅属于本适配器实例的内存凭据存储,页面刷新或进程结束后丢失。
|
|
709
|
+
* SSR 应为每个请求创建客户端和存储实例,避免不同用户共享默认单例。
|
|
710
|
+
* 通过 client.auth 更新已绑定的存储,才能撤销旧代际刷新;直接存储写入不提供这种保证。
|
|
711
|
+
* @returns 两个初始为空的 Token 槽位及清理操作。
|
|
431
712
|
*
|
|
432
713
|
* @example
|
|
433
714
|
* ```ts
|
|
715
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
434
716
|
* const storage = apiClient.tokenStorage.memory()
|
|
435
|
-
* await storage.setAccessToken('
|
|
717
|
+
* await storage.setAccessToken('test-access')
|
|
718
|
+
* const saved = await storage.getAccessToken()
|
|
719
|
+
* await storage.clear()
|
|
720
|
+
* // saved 为本实例的测试值;不把 Token 写入 Web Storage。
|
|
436
721
|
* ```
|
|
437
722
|
*/
|
|
438
723
|
declare function createMemoryTokenStorage(): TokenStorage;
|
|
439
724
|
/**
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
443
|
-
*
|
|
444
|
-
*
|
|
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'`。
|
|
725
|
+
* 创建浏览器使用的内存 access token 与服务端 httpOnly refresh Cookie 适配器。
|
|
726
|
+
* refresh getter 返回内部哨兵,setter 不修改 Cookie;clear 只清除内存 access token。
|
|
727
|
+
* 刷新请求使用 credentials: include;服务端须实际设置/撤销 Cookie,配置适当的 Secure、SameSite、Path 与跨域凭据策略。
|
|
728
|
+
* HttpOnly 限制脚本直接读取 Cookie,不能阻止已执行的恶意脚本代用户发请求;服务端仍须授权和防护 CSRF。
|
|
729
|
+
* @returns 独立内存 access token 与 Cookie 模式标记;不接触 localStorage。
|
|
468
730
|
*
|
|
469
731
|
* @example
|
|
470
732
|
* ```ts
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
733
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
734
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: { storage: apiClient.tokenStorage.httpOnlyCookie() } })
|
|
735
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
736
|
+
* try {
|
|
737
|
+
* const me = await apiClient.iam.auth.currentUser()
|
|
738
|
+
* if (!me.success) throw new Error(me.error.message)
|
|
739
|
+
* const userId = me.data.id
|
|
740
|
+
* }
|
|
741
|
+
* finally { await apiClient.close() }
|
|
475
742
|
* ```
|
|
476
743
|
*/
|
|
477
744
|
declare function createHttpOnlyCookieTokenStorage(): TokenStorage;
|
|
478
745
|
|
|
479
|
-
/** Token 存储方案集合:内存 /
|
|
746
|
+
/** Token 存储方案集合:内存 / httpOnly Cookie。 */
|
|
480
747
|
declare const tokenStorage: {
|
|
481
748
|
/** 内存存储——SSR / Node 测试或一次性会话使用。 */
|
|
482
749
|
readonly memory: typeof createMemoryTokenStorage;
|
|
483
|
-
/** 浏览器 `localStorage` 存储——单页应用便捷选项;注意 XSS 风险。 */
|
|
484
|
-
readonly localStorage: typeof createLocalStorageTokenStorage;
|
|
485
750
|
/** httpOnly Cookie 存储——浏览器场景推荐方案。 */
|
|
486
751
|
readonly httpOnlyCookie: typeof createHttpOnlyCookieTokenStorage;
|
|
487
752
|
};
|
|
488
753
|
/**
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
754
|
+
* 按真实 oRPC 契约创建独立 typed client;公开调用入口为 apiClient.create(contract)。
|
|
755
|
+
* init 返回 HaiResult,成功后才调用 procedure;已初始化实例必须先 close 再换配置。
|
|
756
|
+
* procedure 将传输异常转换为 HaiResult;auth.setTokens/clear 的安全存储失败仍会拒绝 Promise。
|
|
757
|
+
* SSR 应为每个请求创建客户端和内存存储;不共享默认单例中的用户凭据。
|
|
758
|
+
* @param contract - 已定义的嵌套 oRPC contract;顶层命名不能与生命周期成员冲突。
|
|
759
|
+
* @returns 生命周期、认证辅助操作与契约推导出的 procedure 代理。
|
|
494
760
|
*
|
|
495
|
-
* @example
|
|
761
|
+
* @example
|
|
496
762
|
* ```ts
|
|
497
763
|
* import { apiClient } from '@h-ai/api-client'
|
|
498
764
|
* import { apiContract } from '@h-ai/api-contract'
|
|
499
|
-
*
|
|
500
765
|
* const client = apiClient.create(apiContract.create({ iam: apiContract.iam }))
|
|
501
|
-
* await client.init({ baseUrl: 'https://api.example.com/api/v1' })
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
766
|
+
* const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1', auth: { storage: apiClient.tokenStorage.memory() }, timeout: 10000 })
|
|
767
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
768
|
+
* try {
|
|
769
|
+
* const result = await client.iam.auth.currentUser()
|
|
770
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
771
|
+
* const userId = result.data.id
|
|
506
772
|
* }
|
|
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
|
-
* })
|
|
773
|
+
* finally { await client.close() }
|
|
519
774
|
* ```
|
|
520
775
|
*/
|
|
521
776
|
declare function createApiClient<const TContract extends AnyContractRouter>(contract: TContract): ApiClient<TContract>;
|
|
@@ -528,12 +783,16 @@ declare function createApiClient<const TContract extends AnyContractRouter>(cont
|
|
|
528
783
|
* ```ts
|
|
529
784
|
* import { apiClient } from '@h-ai/api-client'
|
|
530
785
|
*
|
|
531
|
-
* await apiClient.init({
|
|
786
|
+
* const initialized = await apiClient.init({
|
|
532
787
|
* baseUrl: 'http://localhost:3000/api/v1',
|
|
533
788
|
* auth: { refreshPath: '/auth/refresh' },
|
|
534
789
|
* })
|
|
535
|
-
*
|
|
536
|
-
*
|
|
790
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
791
|
+
* try {
|
|
792
|
+
* const result = await apiClient.iam.auth.currentUser()
|
|
793
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
794
|
+
* }
|
|
795
|
+
* finally { await apiClient.close() }
|
|
537
796
|
* ```
|
|
538
797
|
*/
|
|
539
798
|
declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
@@ -699,7 +958,6 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
699
958
|
login: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
700
959
|
identifier: zod.ZodString;
|
|
701
960
|
password: zod.ZodString;
|
|
702
|
-
rememberMe: zod.ZodOptional<zod.ZodBoolean>;
|
|
703
961
|
}, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
704
962
|
success: zod.ZodLiteral<true>;
|
|
705
963
|
data: zod.ZodObject<{
|
|
@@ -1466,7 +1724,7 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1466
1724
|
createDownload: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
1467
1725
|
key: zod.ZodString;
|
|
1468
1726
|
expiresIn: zod.ZodOptional<zod.ZodNumber>;
|
|
1469
|
-
}, zod_v4_core.$
|
|
1727
|
+
}, zod_v4_core.$strict>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
1470
1728
|
success: zod.ZodLiteral<true>;
|
|
1471
1729
|
data: zod.ZodObject<{
|
|
1472
1730
|
url: zod.ZodString;
|
|
@@ -1489,9 +1747,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1489
1747
|
createUpload: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
1490
1748
|
key: zod.ZodString;
|
|
1491
1749
|
contentType: zod.ZodOptional<zod.ZodString>;
|
|
1492
|
-
contentLength: zod.ZodOptional<zod.ZodNumber>;
|
|
1493
1750
|
expiresIn: zod.ZodOptional<zod.ZodNumber>;
|
|
1494
|
-
}, zod_v4_core.$
|
|
1751
|
+
}, zod_v4_core.$strict>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
1495
1752
|
success: zod.ZodLiteral<true>;
|
|
1496
1753
|
data: zod.ZodObject<{
|
|
1497
1754
|
url: zod.ZodString;
|
|
@@ -1593,7 +1850,19 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1593
1850
|
keys: zod.ZodArray<zod.ZodString>;
|
|
1594
1851
|
}, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
1595
1852
|
success: zod.ZodLiteral<true>;
|
|
1596
|
-
data: zod.
|
|
1853
|
+
data: zod.ZodObject<{
|
|
1854
|
+
deletedKeys: zod.ZodArray<zod.ZodString>;
|
|
1855
|
+
failures: zod.ZodArray<zod.ZodObject<{
|
|
1856
|
+
key: zod.ZodString;
|
|
1857
|
+
code: zod.ZodString;
|
|
1858
|
+
retryable: zod.ZodBoolean;
|
|
1859
|
+
outcome: zod.ZodEnum<{
|
|
1860
|
+
unknown: "unknown";
|
|
1861
|
+
failed: "failed";
|
|
1862
|
+
notAttempted: "notAttempted";
|
|
1863
|
+
}>;
|
|
1864
|
+
}, zod_v4_core.$strip>>;
|
|
1865
|
+
}, zod_v4_core.$strip>;
|
|
1597
1866
|
}, zod_v4_core.$strip>, zod.ZodObject<{
|
|
1598
1867
|
success: zod.ZodLiteral<false>;
|
|
1599
1868
|
error: zod.ZodObject<{
|
|
@@ -1604,7 +1873,21 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1604
1873
|
module: zod.ZodOptional<zod.ZodString>;
|
|
1605
1874
|
cause: zod.ZodOptional<zod.ZodUnknown>;
|
|
1606
1875
|
suggestion: zod.ZodOptional<zod.ZodString>;
|
|
1607
|
-
ext: zod.ZodOptional<zod.
|
|
1876
|
+
ext: zod.ZodOptional<zod.ZodObject<{
|
|
1877
|
+
deleteMany: zod.ZodOptional<zod.ZodObject<{
|
|
1878
|
+
deletedKeys: zod.ZodArray<zod.ZodString>;
|
|
1879
|
+
failures: zod.ZodArray<zod.ZodObject<{
|
|
1880
|
+
key: zod.ZodString;
|
|
1881
|
+
code: zod.ZodString;
|
|
1882
|
+
retryable: zod.ZodBoolean;
|
|
1883
|
+
outcome: zod.ZodEnum<{
|
|
1884
|
+
unknown: "unknown";
|
|
1885
|
+
failed: "failed";
|
|
1886
|
+
notAttempted: "notAttempted";
|
|
1887
|
+
}>;
|
|
1888
|
+
}, zod_v4_core.$strip>>;
|
|
1889
|
+
}, zod_v4_core.$strip>>;
|
|
1890
|
+
}, zod_v4_core.$catchall<zod.ZodUnknown>>>;
|
|
1608
1891
|
}, zod_v4_core.$strip>;
|
|
1609
1892
|
}, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
|
|
1610
1893
|
};
|
|
@@ -1612,18 +1895,22 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1612
1895
|
readonly ai: {
|
|
1613
1896
|
chats: {
|
|
1614
1897
|
createCompletion: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
1898
|
+
objectId: zod.ZodOptional<zod.ZodString>;
|
|
1899
|
+
sessionId: zod.ZodOptional<zod.ZodString>;
|
|
1615
1900
|
model: zod.ZodOptional<zod.ZodString>;
|
|
1616
|
-
messages: zod.ZodArray<zod.ZodObject<{
|
|
1617
|
-
role: zod.
|
|
1618
|
-
|
|
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<{
|
|
1901
|
+
messages: zod.ZodArray<zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
1902
|
+
role: zod.ZodLiteral<"system">;
|
|
1903
|
+
content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
|
|
1624
1904
|
type: zod.ZodLiteral<"text">;
|
|
1625
1905
|
text: zod.ZodString;
|
|
1626
|
-
}, zod_v4_core.$
|
|
1906
|
+
}, zod_v4_core.$strict>>]>;
|
|
1907
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
1908
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
1909
|
+
role: zod.ZodLiteral<"user">;
|
|
1910
|
+
content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
|
|
1911
|
+
type: zod.ZodLiteral<"text">;
|
|
1912
|
+
text: zod.ZodString;
|
|
1913
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
1627
1914
|
type: zod.ZodLiteral<"image_url">;
|
|
1628
1915
|
image_url: zod.ZodObject<{
|
|
1629
1916
|
url: zod.ZodString;
|
|
@@ -1632,8 +1919,15 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1632
1919
|
low: "low";
|
|
1633
1920
|
high: "high";
|
|
1634
1921
|
}>>;
|
|
1635
|
-
}, zod_v4_core.$
|
|
1636
|
-
}, zod_v4_core.$
|
|
1922
|
+
}, zod_v4_core.$strict>;
|
|
1923
|
+
}, zod_v4_core.$strict>]>>]>;
|
|
1924
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
1925
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
1926
|
+
role: zod.ZodLiteral<"assistant">;
|
|
1927
|
+
content: zod.ZodOptional<zod.ZodNullable<zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
|
|
1928
|
+
type: zod.ZodLiteral<"text">;
|
|
1929
|
+
text: zod.ZodString;
|
|
1930
|
+
}, zod_v4_core.$strict>>]>>>;
|
|
1637
1931
|
name: zod.ZodOptional<zod.ZodString>;
|
|
1638
1932
|
tool_calls: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
|
|
1639
1933
|
id: zod.ZodString;
|
|
@@ -1641,37 +1935,35 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1641
1935
|
function: zod.ZodObject<{
|
|
1642
1936
|
name: zod.ZodString;
|
|
1643
1937
|
arguments: zod.ZodString;
|
|
1644
|
-
}, zod_v4_core.$
|
|
1645
|
-
}, zod_v4_core.$
|
|
1646
|
-
|
|
1647
|
-
|
|
1938
|
+
}, zod_v4_core.$strict>;
|
|
1939
|
+
}, zod_v4_core.$strict>>>;
|
|
1940
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
1941
|
+
role: zod.ZodLiteral<"tool">;
|
|
1942
|
+
content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
|
|
1943
|
+
type: zod.ZodLiteral<"text">;
|
|
1944
|
+
text: zod.ZodString;
|
|
1945
|
+
}, zod_v4_core.$strict>>]>;
|
|
1946
|
+
tool_call_id: zod.ZodString;
|
|
1947
|
+
}, zod_v4_core.$strict>], "role">>;
|
|
1648
1948
|
temperature: zod.ZodOptional<zod.ZodNumber>;
|
|
1649
1949
|
top_p: zod.ZodOptional<zod.ZodNumber>;
|
|
1650
1950
|
max_tokens: zod.ZodOptional<zod.ZodNumber>;
|
|
1651
|
-
stream: zod.ZodOptional<zod.ZodBoolean>;
|
|
1652
1951
|
tools: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
|
|
1653
1952
|
type: zod.ZodLiteral<"function">;
|
|
1654
1953
|
function: zod.ZodObject<{
|
|
1655
1954
|
name: zod.ZodString;
|
|
1656
1955
|
description: zod.ZodOptional<zod.ZodString>;
|
|
1657
|
-
parameters: zod.ZodOptional<zod.
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
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<{
|
|
1956
|
+
parameters: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodJSONSchema>>;
|
|
1957
|
+
strict: zod.ZodOptional<zod.ZodNullable<zod.ZodBoolean>>;
|
|
1958
|
+
}, zod_v4_core.$strict>;
|
|
1959
|
+
}, zod_v4_core.$strict>>>;
|
|
1960
|
+
tool_choice: zod.ZodOptional<zod.ZodUnion<readonly [zod.ZodLiteral<"auto">, zod.ZodLiteral<"none">, zod.ZodLiteral<"required">, zod.ZodObject<{
|
|
1669
1961
|
type: zod.ZodLiteral<"function">;
|
|
1670
1962
|
function: zod.ZodObject<{
|
|
1671
1963
|
name: zod.ZodString;
|
|
1672
|
-
}, zod_v4_core.$
|
|
1673
|
-
}, zod_v4_core.$
|
|
1674
|
-
}, zod_v4_core.$
|
|
1964
|
+
}, zod_v4_core.$strict>;
|
|
1965
|
+
}, zod_v4_core.$strict>]>>;
|
|
1966
|
+
}, zod_v4_core.$strict>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
1675
1967
|
success: zod.ZodLiteral<true>;
|
|
1676
1968
|
data: zod.ZodObject<{
|
|
1677
1969
|
id: zod.ZodString;
|
|
@@ -1689,8 +1981,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1689
1981
|
function: zod.ZodObject<{
|
|
1690
1982
|
name: zod.ZodString;
|
|
1691
1983
|
arguments: zod.ZodString;
|
|
1692
|
-
}, zod_v4_core.$
|
|
1693
|
-
}, zod_v4_core.$
|
|
1984
|
+
}, zod_v4_core.$strict>;
|
|
1985
|
+
}, zod_v4_core.$strict>>>;
|
|
1694
1986
|
}, zod_v4_core.$strip>;
|
|
1695
1987
|
finish_reason: zod.ZodEnum<{
|
|
1696
1988
|
length: "length";
|
|
@@ -1719,6 +2011,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1719
2011
|
}, zod_v4_core.$strip>;
|
|
1720
2012
|
}, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
|
|
1721
2013
|
sendMessage: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
2014
|
+
objectId: zod.ZodOptional<zod.ZodString>;
|
|
2015
|
+
sessionId: zod.ZodOptional<zod.ZodString>;
|
|
1722
2016
|
message: zod.ZodString;
|
|
1723
2017
|
systemPrompt: zod.ZodOptional<zod.ZodString>;
|
|
1724
2018
|
model: zod.ZodOptional<zod.ZodString>;
|
|
@@ -1748,7 +2042,7 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1748
2042
|
}, zod_v4_core.$strip>;
|
|
1749
2043
|
}, zod_v4_core.$strip>], "success">, Record<never, never>, Record<never, never>>;
|
|
1750
2044
|
listHistory: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
1751
|
-
objectId: zod.ZodString
|
|
2045
|
+
objectId: zod.ZodOptional<zod.ZodString>;
|
|
1752
2046
|
sessionId: zod.ZodString;
|
|
1753
2047
|
limit: zod.ZodOptional<zod.ZodNumber>;
|
|
1754
2048
|
order: zod.ZodOptional<zod.ZodEnum<{
|
|
@@ -1764,17 +2058,19 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1764
2058
|
sessionId: zod.ZodString;
|
|
1765
2059
|
request: zod.ZodObject<{
|
|
1766
2060
|
model: zod.ZodString;
|
|
1767
|
-
messages: zod.ZodArray<zod.ZodObject<{
|
|
1768
|
-
role: zod.
|
|
1769
|
-
|
|
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<{
|
|
2061
|
+
messages: zod.ZodArray<zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
2062
|
+
role: zod.ZodLiteral<"system">;
|
|
2063
|
+
content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
|
|
1775
2064
|
type: zod.ZodLiteral<"text">;
|
|
1776
2065
|
text: zod.ZodString;
|
|
1777
|
-
}, zod_v4_core.$
|
|
2066
|
+
}, zod_v4_core.$strict>>]>;
|
|
2067
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
2068
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2069
|
+
role: zod.ZodLiteral<"user">;
|
|
2070
|
+
content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
|
|
2071
|
+
type: zod.ZodLiteral<"text">;
|
|
2072
|
+
text: zod.ZodString;
|
|
2073
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
1778
2074
|
type: zod.ZodLiteral<"image_url">;
|
|
1779
2075
|
image_url: zod.ZodObject<{
|
|
1780
2076
|
url: zod.ZodString;
|
|
@@ -1783,8 +2079,15 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1783
2079
|
low: "low";
|
|
1784
2080
|
high: "high";
|
|
1785
2081
|
}>>;
|
|
1786
|
-
}, zod_v4_core.$
|
|
1787
|
-
}, zod_v4_core.$
|
|
2082
|
+
}, zod_v4_core.$strict>;
|
|
2083
|
+
}, zod_v4_core.$strict>]>>]>;
|
|
2084
|
+
name: zod.ZodOptional<zod.ZodString>;
|
|
2085
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2086
|
+
role: zod.ZodLiteral<"assistant">;
|
|
2087
|
+
content: zod.ZodOptional<zod.ZodNullable<zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
|
|
2088
|
+
type: zod.ZodLiteral<"text">;
|
|
2089
|
+
text: zod.ZodString;
|
|
2090
|
+
}, zod_v4_core.$strict>>]>>>;
|
|
1788
2091
|
name: zod.ZodOptional<zod.ZodString>;
|
|
1789
2092
|
tool_calls: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
|
|
1790
2093
|
id: zod.ZodString;
|
|
@@ -1792,10 +2095,16 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1792
2095
|
function: zod.ZodObject<{
|
|
1793
2096
|
name: zod.ZodString;
|
|
1794
2097
|
arguments: zod.ZodString;
|
|
1795
|
-
}, zod_v4_core.$
|
|
1796
|
-
}, zod_v4_core.$
|
|
1797
|
-
|
|
1798
|
-
|
|
2098
|
+
}, zod_v4_core.$strict>;
|
|
2099
|
+
}, zod_v4_core.$strict>>>;
|
|
2100
|
+
}, zod_v4_core.$strict>, zod.ZodObject<{
|
|
2101
|
+
role: zod.ZodLiteral<"tool">;
|
|
2102
|
+
content: zod.ZodUnion<readonly [zod.ZodString, zod.ZodArray<zod.ZodObject<{
|
|
2103
|
+
type: zod.ZodLiteral<"text">;
|
|
2104
|
+
text: zod.ZodString;
|
|
2105
|
+
}, zod_v4_core.$strict>>]>;
|
|
2106
|
+
tool_call_id: zod.ZodString;
|
|
2107
|
+
}, zod_v4_core.$strict>], "role">>;
|
|
1799
2108
|
}, zod_v4_core.$strip>;
|
|
1800
2109
|
response: zod.ZodObject<{
|
|
1801
2110
|
content: zod.ZodString;
|
|
@@ -1805,8 +2114,8 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1805
2114
|
function: zod.ZodObject<{
|
|
1806
2115
|
name: zod.ZodString;
|
|
1807
2116
|
arguments: zod.ZodString;
|
|
1808
|
-
}, zod_v4_core.$
|
|
1809
|
-
}, zod_v4_core.$
|
|
2117
|
+
}, zod_v4_core.$strict>;
|
|
2118
|
+
}, zod_v4_core.$strict>>>;
|
|
1810
2119
|
finishReason: zod.ZodString;
|
|
1811
2120
|
usage: zod.ZodObject<{
|
|
1812
2121
|
prompt_tokens: zod.ZodNumber;
|
|
@@ -1928,7 +2237,7 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1928
2237
|
};
|
|
1929
2238
|
sessions: {
|
|
1930
2239
|
list: _orpc_contract.ContractProcedureBuilderWithInputOutput<zod.ZodObject<{
|
|
1931
|
-
objectId: zod.ZodString
|
|
2240
|
+
objectId: zod.ZodOptional<zod.ZodString>;
|
|
1932
2241
|
}, zod_v4_core.$strip>, zod.ZodDiscriminatedUnion<[zod.ZodObject<{
|
|
1933
2242
|
success: zod.ZodLiteral<true>;
|
|
1934
2243
|
data: zod.ZodObject<{
|
|
@@ -1956,13 +2265,43 @@ declare const defaultApiContract: _h_ai_api_contract.CreatedApiContract<{
|
|
|
1956
2265
|
};
|
|
1957
2266
|
};
|
|
1958
2267
|
}>;
|
|
1959
|
-
/**
|
|
2268
|
+
/**
|
|
2269
|
+
* 默认 iam/storage/ai typed client 与 create、tokenStorage、createAuthActions 命名空间的交叉类型。
|
|
2270
|
+
* 具体项目契约使用 apiClient.create 的返回类型,不给默认单例附加未知 procedure。
|
|
2271
|
+
*
|
|
2272
|
+
* @example
|
|
2273
|
+
* ```ts
|
|
2274
|
+
* import { apiClient, type DefaultApiClient } from '@h-ai/api-client'
|
|
2275
|
+
* const client: DefaultApiClient = apiClient
|
|
2276
|
+
* const initialized = await client.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
2277
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
2278
|
+
* try { const actions = client.createAuthActions(client); const result = await actions.publicConfig(); if (!result.success) throw new Error(result.error.message) }
|
|
2279
|
+
* finally { await client.close() }
|
|
2280
|
+
* ```
|
|
2281
|
+
*/
|
|
1960
2282
|
type DefaultApiClient = ApiClient<typeof defaultApiContract> & {
|
|
1961
2283
|
readonly create: typeof createApiClient;
|
|
1962
2284
|
readonly tokenStorage: typeof tokenStorage;
|
|
1963
2285
|
readonly createAuthActions: typeof createIamAuthActions;
|
|
1964
2286
|
};
|
|
1965
|
-
/**
|
|
2287
|
+
/**
|
|
2288
|
+
* API Client 公开入口:默认 iam/storage/ai 单例,以及独立实例、安全存储和认证动作工厂。
|
|
2289
|
+
* 未启用 auth 时不注入或刷新 Token;浏览器 auth: {} 使用 httpOnly Cookie 方案。
|
|
2290
|
+
* close 释放客户端运行状态/加密会话,不能替代服务端退出或 auth.clear。
|
|
2291
|
+
*
|
|
2292
|
+
* @example
|
|
2293
|
+
* ```ts
|
|
2294
|
+
* import { apiClient } from '@h-ai/api-client'
|
|
2295
|
+
* const initialized = await apiClient.init({ baseUrl: 'https://api.example.com/api/v1', auth: {} })
|
|
2296
|
+
* if (!initialized.success) throw new Error(initialized.error.message)
|
|
2297
|
+
* try {
|
|
2298
|
+
* const result = await apiClient.iam.auth.currentUser()
|
|
2299
|
+
* if (!result.success) throw new Error(result.error.message)
|
|
2300
|
+
* const permissions = result.data.permissions
|
|
2301
|
+
* }
|
|
2302
|
+
* finally { await apiClient.close() }
|
|
2303
|
+
* ```
|
|
2304
|
+
*/
|
|
1966
2305
|
declare const apiClient: DefaultApiClient;
|
|
1967
2306
|
|
|
1968
2307
|
export { type ApiClient, type ApiClientAuth, type ApiClientConfig, type ApiClientLifecycle, type ApiClientTransportConfig, type AuthConfig, type DefaultApiClient, HaiApiClientError, type IamAuthLoginInput, type TokenPair, type TokenStorage, apiClient };
|