@h-ai/api-client 0.1.0-alpha.56 → 0.1.0-alpha.57
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 +134 -0
- package/README.ja.md +134 -0
- package/README.md +6 -0
- package/package.json +4 -4
package/README.en.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @h-ai/api-client
|
|
2
|
+
|
|
3
|
+
[简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
[Framework home](../../README.en.md) · Related modules: [@h-ai/api-contract](../api-contract/README.en.md) · [@h-ai/core](../core/README.en.md) · [@h-ai/crypto](../crypto/README.en.md)
|
|
6
|
+
|
|
7
|
+
> A cross-platform oRPC/OpenAPI typed client for hai-framework, with consistent API calls and token management across Web, apps, and mini programs.
|
|
8
|
+
|
|
9
|
+
## Capabilities
|
|
10
|
+
|
|
11
|
+
- `apiClient`: the default typed client for the iam/storage/ai domains.
|
|
12
|
+
- `apiClient.create(contract)`: create a typed client for a custom contract.
|
|
13
|
+
- `apiClient.tokenStorage.{memory,localStorage,httpOnlyCookie}()`: token storage factories.
|
|
14
|
+
- Custom `fetch` support for browsers, Node, Capacitor, and mini-program bridges.
|
|
15
|
+
- Automatic Bearer token injection, with token refresh and one retry after a 401.
|
|
16
|
+
- Network failures are converted to `HaiResult` errors.
|
|
17
|
+
- Optional transport encryption: `apiClient.init({ transport: { crypto } })` automatically uses `crypto.transport.createClient()`.
|
|
18
|
+
- Transport encryption and automatic refresh can run together: `/auth/refresh` after a 401 still uses encrypted fetch without falling back to plaintext.
|
|
19
|
+
|
|
20
|
+
## Quick start
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { apiClient } from '@h-ai/api-client'
|
|
24
|
+
|
|
25
|
+
await apiClient.init({
|
|
26
|
+
baseUrl: 'https://api.example.com/api/v1',
|
|
27
|
+
auth: {}, // 默认使用 httpOnly cookie 存储(推荐);SSR 测试请显式传入 apiClient.tokenStorage.memory()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const login = await apiClient.iam.auth.login({
|
|
31
|
+
identifier: 'alice',
|
|
32
|
+
password: 'secret',
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
if (login.success) {
|
|
36
|
+
// httpOnly cookie 模式下 refresh token 由服务端 Set-Cookie 管理,
|
|
37
|
+
// api-client 默认存储只需要把 access token 写入内存。
|
|
38
|
+
await apiClient.auth.setTokens(login.data.tokens)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const me = await apiClient.iam.auth.currentUser()
|
|
42
|
+
if (me.success) {
|
|
43
|
+
// 身份资料与服务端重新校验后的访问范围一次返回,客户端无需持久化权限快照。
|
|
44
|
+
const { roles, permissions, ...user } = me.data
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await apiClient.close()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Enable transport encryption
|
|
51
|
+
|
|
52
|
+
First enable `serv.createApp({ transport: { crypto } })` on the server. The client only needs the same `@h-ai/crypto` service instance; no manual key exchange code is required.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { apiClient } from '@h-ai/api-client'
|
|
56
|
+
import { crypto } from '@h-ai/crypto'
|
|
57
|
+
|
|
58
|
+
await crypto.init()
|
|
59
|
+
|
|
60
|
+
await apiClient.init({
|
|
61
|
+
baseUrl: 'https://api.example.com/api/v1',
|
|
62
|
+
auth: {},
|
|
63
|
+
transport: { crypto }, // 默认协商路径:/api/v1/_hai/key-exchange
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
await apiClient.close()
|
|
67
|
+
await crypto.close()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API contracts
|
|
71
|
+
|
|
72
|
+
Custom applications can bind their own oRPC contract:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { apiClient } from '@h-ai/api-client'
|
|
76
|
+
import { apiContract } from '@h-ai/api-contract'
|
|
77
|
+
|
|
78
|
+
const contract = apiContract.create({ iam: apiContract.iam })
|
|
79
|
+
const client = apiClient.create(contract)
|
|
80
|
+
|
|
81
|
+
await client.init({ baseUrl: 'https://api.example.com/api/v1' })
|
|
82
|
+
const result = await client.iam.auth.login({ identifier: 'alice', password: 'secret' })
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API overview
|
|
86
|
+
|
|
87
|
+
- `apiClient.init(config)`: initialize the default client.
|
|
88
|
+
- `apiClient.close()`: clear client state.
|
|
89
|
+
- `apiClient.auth.setTokens(tokens)`: store the access token; storage other than httpOnly also stores the refresh token.
|
|
90
|
+
- `apiClient.auth.clear()`: clear tokens.
|
|
91
|
+
- `apiClient.create(contract)`: create a custom typed client.
|
|
92
|
+
|
|
93
|
+
Calling `init()` on an initialized client returns `CONFIG_ERROR` and leaves the existing client intact. To change `baseUrl` / `fetch` / `transport`, call `await apiClient.close()` before initializing again.
|
|
94
|
+
|
|
95
|
+
## Configuration
|
|
96
|
+
|
|
97
|
+
- `baseUrl`: API base URL, usually including `/api/v1`.
|
|
98
|
+
- `auth.storage`: token storage adapter; defaults to `apiClient.tokenStorage.httpOnlyCookie()` (recommended for browsers). Explicitly use `apiClient.tokenStorage.memory()` for SSR / tests.
|
|
99
|
+
- `auth.refreshPath`: token refresh path; defaults to `/auth/refresh`.
|
|
100
|
+
- `timeout`: request timeout; defaults to 30000 ms.
|
|
101
|
+
- `headers`: static or dynamic shared request headers.
|
|
102
|
+
- `fetch`: custom fetch implementation.
|
|
103
|
+
- `transport.crypto`: transparent request/response encryption and decryption; requires an initialized `@h-ai/crypto` instance.
|
|
104
|
+
- `transport.keyExchangePath`: key exchange subpath; defaults to `/_hai/key-exchange` and is appended to `baseUrl` automatically.
|
|
105
|
+
- `apiClient.config`: a **redacted snapshot of runtime configuration**; credentials embedded in `baseUrl`, `headers.authorization`, and other sensitive values are hidden automatically.
|
|
106
|
+
|
|
107
|
+
## Error handling
|
|
108
|
+
|
|
109
|
+
Business APIs return `HaiResult<T>`:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const result = await apiClient.iam.auth.currentUser()
|
|
113
|
+
if (!result.success) {
|
|
114
|
+
// result.error.code / result.error.message
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// result.data = User & { roles: string[], permissions: string[] }
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Client-side failures such as missing initialization, network errors, timeouts, and 401/403/404 responses are also converted to failed `HaiResult` values.
|
|
122
|
+
|
|
123
|
+
Automatic refresh is triggered only by an actual HTTP 401 (`Response.status`). Ordinary serv procedures return failed HaiResult values over HTTP 200 by default. `error.httpStatus=401` inside that envelope does not trigger refresh; callers must still check `success` and `error.code` and handle expired authentication.
|
|
124
|
+
|
|
125
|
+
## Tests
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pnpm --filter @h-ai/api-client test
|
|
129
|
+
pnpm --filter @h-ai/api-client typecheck
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
Apache-2.0
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @h-ai/api-client
|
|
2
|
+
|
|
3
|
+
[简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
[フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/api-contract](../api-contract/README.ja.md) · [@h-ai/core](../core/README.ja.md) · [@h-ai/crypto](../crypto/README.ja.md)
|
|
6
|
+
|
|
7
|
+
> hai-framework のクロスプラットフォーム oRPC/OpenAPI 型付きクライアント。Web、アプリ、ミニプログラムに共通の API 呼び出しと Token 管理を提供します。
|
|
8
|
+
|
|
9
|
+
## 機能概要
|
|
10
|
+
|
|
11
|
+
- `apiClient`:iam/storage/ai ドメインに対応する既定の型付きクライアント。
|
|
12
|
+
- `apiClient.create(contract)`:独自の contract に対応する型付きクライアントを作成。
|
|
13
|
+
- `apiClient.tokenStorage.{memory,localStorage,httpOnlyCookie}()`:Token ストレージのファクトリー。
|
|
14
|
+
- ブラウザー、Node、Capacitor、ミニプログラムのブリッジに対応する独自 `fetch` を指定可能。
|
|
15
|
+
- Bearer Token の自動付与と、401 応答後の更新および 1 回の再試行。
|
|
16
|
+
- ネットワークエラーを `HaiResult` のエラーに変換。
|
|
17
|
+
- 任意の通信暗号化:`apiClient.init({ transport: { crypto } })` が `crypto.transport.createClient()` を自動使用。
|
|
18
|
+
- 通信暗号化と自動更新を併用可能。401 後の `/auth/refresh` も暗号化された fetch を使用し、平文には切り替わりません。
|
|
19
|
+
|
|
20
|
+
## クイックスタート
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { apiClient } from '@h-ai/api-client'
|
|
24
|
+
|
|
25
|
+
await apiClient.init({
|
|
26
|
+
baseUrl: 'https://api.example.com/api/v1',
|
|
27
|
+
auth: {}, // 默认使用 httpOnly cookie 存储(推荐);SSR 测试请显式传入 apiClient.tokenStorage.memory()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const login = await apiClient.iam.auth.login({
|
|
31
|
+
identifier: 'alice',
|
|
32
|
+
password: 'secret',
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
if (login.success) {
|
|
36
|
+
// httpOnly cookie 模式下 refresh token 由服务端 Set-Cookie 管理,
|
|
37
|
+
// api-client 默认存储只需要把 access token 写入内存。
|
|
38
|
+
await apiClient.auth.setTokens(login.data.tokens)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const me = await apiClient.iam.auth.currentUser()
|
|
42
|
+
if (me.success) {
|
|
43
|
+
// 身份资料与服务端重新校验后的访问范围一次返回,客户端无需持久化权限快照。
|
|
44
|
+
const { roles, permissions, ...user } = me.data
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await apiClient.close()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 通信暗号化の有効化
|
|
51
|
+
|
|
52
|
+
サーバーで先に `serv.createApp({ transport: { crypto } })` を有効にします。クライアントには同じ `@h-ai/crypto` サービスのインスタンスを渡すだけで、鍵交換コードの実装は不要です。
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { apiClient } from '@h-ai/api-client'
|
|
56
|
+
import { crypto } from '@h-ai/crypto'
|
|
57
|
+
|
|
58
|
+
await crypto.init()
|
|
59
|
+
|
|
60
|
+
await apiClient.init({
|
|
61
|
+
baseUrl: 'https://api.example.com/api/v1',
|
|
62
|
+
auth: {},
|
|
63
|
+
transport: { crypto }, // 默认协商路径:/api/v1/_hai/key-exchange
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
await apiClient.close()
|
|
67
|
+
await crypto.close()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## API 契約
|
|
71
|
+
|
|
72
|
+
独自のアプリケーションでは、専用の oRPC contract を指定できます:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { apiClient } from '@h-ai/api-client'
|
|
76
|
+
import { apiContract } from '@h-ai/api-contract'
|
|
77
|
+
|
|
78
|
+
const contract = apiContract.create({ iam: apiContract.iam })
|
|
79
|
+
const client = apiClient.create(contract)
|
|
80
|
+
|
|
81
|
+
await client.init({ baseUrl: 'https://api.example.com/api/v1' })
|
|
82
|
+
const result = await client.iam.auth.login({ identifier: 'alice', password: 'secret' })
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## API 一覧
|
|
86
|
+
|
|
87
|
+
- `apiClient.init(config)`:既定のクライアントを初期化。
|
|
88
|
+
- `apiClient.close()`:クライアントの状態を解放。
|
|
89
|
+
- `apiClient.auth.setTokens(tokens)`:access token を保存。httpOnly 以外のストレージでは refresh token も保存します。
|
|
90
|
+
- `apiClient.auth.clear()`:Token を削除。
|
|
91
|
+
- `apiClient.create(contract)`:独自の型付きクライアントを作成。
|
|
92
|
+
|
|
93
|
+
初期化済みのクライアントで `init()` を再度呼ぶと `CONFIG_ERROR` が返り、既存のクライアントは維持されます。`baseUrl` / `fetch` / `transport` を変更する場合は、先に `await apiClient.close()` を呼んでから再初期化してください。
|
|
94
|
+
|
|
95
|
+
## 設定
|
|
96
|
+
|
|
97
|
+
- `baseUrl`:API のベース URL。通常は `/api/v1` を含みます。
|
|
98
|
+
- `auth.storage`:Token ストレージアダプター。既定は `apiClient.tokenStorage.httpOnlyCookie()`(ブラウザー推奨)。SSR / テストでは `apiClient.tokenStorage.memory()` を明示してください。
|
|
99
|
+
- `auth.refreshPath`:Token 更新パス。既定は `/auth/refresh`。
|
|
100
|
+
- `timeout`:リクエストのタイムアウト。既定は 30000 ms。
|
|
101
|
+
- `headers`:静的または動的な共通リクエストヘッダー。
|
|
102
|
+
- `fetch`:独自の fetch 実装。
|
|
103
|
+
- `transport.crypto`:透過的なリクエスト/レスポンス暗号化・復号。初期化済みの `@h-ai/crypto` インスタンスが必要です。
|
|
104
|
+
- `transport.keyExchangePath`:鍵交換のサブパス。既定は `/_hai/key-exchange` で、`baseUrl` に自動的に連結されます。
|
|
105
|
+
- `apiClient.config`:**機密情報をマスクした実行時設定のスナップショット**。`baseUrl` 内の認証情報や `headers.authorization` などの機密値は自動的に非表示になります。
|
|
106
|
+
|
|
107
|
+
## エラー処理
|
|
108
|
+
|
|
109
|
+
業務 API は `HaiResult<T>` を返します:
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const result = await apiClient.iam.auth.currentUser()
|
|
113
|
+
if (!result.success) {
|
|
114
|
+
// result.error.code / result.error.message
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// result.data = User & { roles: string[], permissions: string[] }
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
未初期化、ネットワークエラー、タイムアウト、401/403/404 などのクライアント側の問題も、失敗の `HaiResult` に変換されます。
|
|
122
|
+
|
|
123
|
+
自動更新は実際の HTTP 401(`Response.status`)でのみ動作します。serv の通常の procedure は既定で失敗の HaiResult を HTTP 200 で返し、その包絡中の `error.httpStatus=401` は更新を起動しません。呼び出し側は `success` と `error.code` を確認し、認証の失効を処理してください。
|
|
124
|
+
|
|
125
|
+
## テスト
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pnpm --filter @h-ai/api-client test
|
|
129
|
+
pnpm --filter @h-ai/api-client typecheck
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
Apache-2.0
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @h-ai/api-client
|
|
2
2
|
|
|
3
|
+
[简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
[框架首页](../../README.md) · 相关模块:[@h-ai/api-contract](../api-contract/README.md) · [@h-ai/core](../core/README.md) · [@h-ai/crypto](../crypto/README.md)
|
|
6
|
+
|
|
3
7
|
> hai-framework 的跨端 oRPC/OpenAPI typed client,面向 Web、App、小程序等运行时提供统一 API 调用与 Token 管理。
|
|
4
8
|
|
|
5
9
|
## 能力概览
|
|
@@ -116,6 +120,8 @@ else {
|
|
|
116
120
|
|
|
117
121
|
未初始化、网络错误、超时、401/403/404 等客户端侧问题也会转换为失败的 `HaiResult`。
|
|
118
122
|
|
|
123
|
+
自动刷新仅由真实 HTTP 401(`Response.status`)触发。serv 普通 procedure 默认通过 HTTP 200 返回失败 HaiResult,包络中的 `error.httpStatus=401` 不会触发刷新;调用方仍须检查 `success` 与 `error.code` 并处理登录失效。
|
|
124
|
+
|
|
119
125
|
## 测试
|
|
120
126
|
|
|
121
127
|
```bash
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/api-client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.57",
|
|
5
5
|
"description": "Hai Framework universal HTTP client with Bearer token and API contract support.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"exports": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"@orpc/contract": "^1.14.3",
|
|
28
28
|
"@orpc/openapi-client": "^1.14.3",
|
|
29
29
|
"zod": "^4.4.3",
|
|
30
|
-
"@h-ai/
|
|
31
|
-
"@h-ai/
|
|
32
|
-
"@h-ai/
|
|
30
|
+
"@h-ai/core": "0.1.0-alpha.57",
|
|
31
|
+
"@h-ai/crypto": "0.1.0-alpha.57",
|
|
32
|
+
"@h-ai/api-contract": "0.1.0-alpha.57"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^25.9.1",
|