@h-ai/kit 0.1.0-alpha.66 → 0.1.0-alpha.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +80 -46
- package/README.ja.md +72 -40
- package/README.md +73 -41
- package/dist/adapter/index.d.ts +17 -2
- package/dist/adapter/index.js.map +1 -1
- package/dist/browser.d.ts +12 -6
- package/dist/browser.js +6 -7
- package/dist/browser.js.map +1 -1
- package/dist/{chunk-DVW7CQ3H.js → chunk-2PWGJCWX.js} +3 -3
- package/dist/chunk-2PWGJCWX.js.map +1 -0
- package/dist/{chunk-VOTDAVCB.js → chunk-2YYRP7HH.js} +17 -33
- package/dist/chunk-2YYRP7HH.js.map +1 -0
- package/dist/{chunk-MLSP67JF.js → chunk-333FGMGQ.js} +59 -111
- package/dist/chunk-333FGMGQ.js.map +1 -0
- package/dist/chunk-OVRZIDCD.js +175 -0
- package/dist/chunk-OVRZIDCD.js.map +1 -0
- package/dist/{chunk-L7BTMAKX.js → chunk-P6XH7G4N.js} +3 -6
- package/dist/chunk-P6XH7G4N.js.map +1 -0
- package/dist/{chunk-NVYIUBU7.js → chunk-XC7I2L3G.js} +2 -2
- package/dist/chunk-XC7I2L3G.js.map +1 -0
- package/dist/client/index.d.ts +47 -1
- package/dist/client/index.js +3 -3
- package/dist/client/index.js.map +1 -1
- package/dist/index.d.ts +217 -347
- package/dist/index.js +138 -83
- package/dist/index.js.map +1 -1
- package/dist/kit-a2a-types-CwT1AFQu.d.ts +136 -0
- package/dist/{index-B7s-0mZl.d.ts → kit-client-auth-HnZIYUia.d.ts} +220 -101
- package/dist/kit-crypto-types-Dd24aJ4m.d.ts +194 -0
- package/dist/{kit-i18n-D9Qqk-1k.d.ts → kit-i18n-DEzmzE5T.d.ts} +142 -29
- package/dist/{kit-types-ByWdbCeO.d.ts → kit-types-CnzhN-AS.d.ts} +240 -162
- package/dist/modules/a2a/index.d.ts +13 -111
- package/dist/modules/a2a/index.js +2 -2
- package/dist/modules/crypto/index.d.ts +28 -195
- package/dist/modules/crypto/index.js +3 -3
- package/dist/modules/crypto/index.js.map +1 -1
- package/package.json +10 -10
- package/dist/chunk-DVW7CQ3H.js.map +0 -1
- package/dist/chunk-L7BTMAKX.js.map +0 -1
- package/dist/chunk-MLSP67JF.js.map +0 -1
- package/dist/chunk-NVYIUBU7.js.map +0 -1
- package/dist/chunk-QHYNL24G.js +0 -117
- package/dist/chunk-QHYNL24G.js.map +0 -1
- package/dist/chunk-VOTDAVCB.js.map +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { CryptoFunctions, TransportKeyStore } from '@h-ai/crypto';
|
|
1
|
+
import { CryptoFunctions, TransportServerKeyRing, TransportKeyStore } from '@h-ai/crypto';
|
|
2
2
|
import { AuthnOperations } from '@h-ai/iam';
|
|
3
3
|
import { RequestEvent } from '@sveltejs/kit';
|
|
4
|
+
import { HaiResult } from '@h-ai/core';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @h-ai/kit — 速率限制中间件
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
+
* 以首个成功请求为起点的固定窗口限流;后续计数不延长窗口。
|
|
9
10
|
* 内置内存存储(`MemoryRateLimitStore`),并支持通过 `RateLimitStore` 接入
|
|
10
11
|
* Redis 等外部存储后端。
|
|
11
12
|
* @module kit-ratelimit
|
|
@@ -13,6 +14,13 @@ import { RequestEvent } from '@sveltejs/kit';
|
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* 速率限制存储条目
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import type { RateLimitEntry } from '@h-ai/kit'
|
|
20
|
+
*
|
|
21
|
+
* const value: RateLimitEntry = { count: 1, resetAt: Date.now() + 60_000 }
|
|
22
|
+
* void value
|
|
23
|
+
* ```
|
|
16
24
|
*/
|
|
17
25
|
interface RateLimitEntry {
|
|
18
26
|
/** 当前窗口内的请求次数 */
|
|
@@ -21,92 +29,135 @@ interface RateLimitEntry {
|
|
|
21
29
|
resetAt: number;
|
|
22
30
|
}
|
|
23
31
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* 内置 `MemoryRateLimitStore` 适合单进程开发;
|
|
27
|
-
* 多实例部署需传入基于 Redis / @h-ai/cache 的分布式实现。
|
|
28
|
-
*
|
|
32
|
+
* 原子固定窗口计数器;故障抛错由中间件转为503,禁止读改写回退。
|
|
29
33
|
* @example
|
|
30
34
|
* ```ts
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* async delete(key) { ... },
|
|
35
|
+
* import type { RateLimitStore } from '@h-ai/kit'
|
|
36
|
+
*
|
|
37
|
+
* async function count(store: RateLimitStore) {
|
|
38
|
+
* return store.increment('client_1', 60_000)
|
|
36
39
|
* }
|
|
37
|
-
* kit.middleware.rateLimit({ windowMs: 60_000, maxRequests: 100, store: redisStore })
|
|
38
40
|
* ```
|
|
39
41
|
*/
|
|
40
42
|
interface RateLimitStore {
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
/** 删除指定 key 的限流条目 */
|
|
46
|
-
delete: (key: string) => Promise<void> | void;
|
|
47
|
-
/**
|
|
48
|
-
* 原子自增并返回当前计数和重置时间
|
|
49
|
-
*
|
|
50
|
-
* 实现时必须保证 get→increment→set 操作的原子性,
|
|
51
|
-
* 防止并发请求在窗口切换时产生竞态绕过限流。
|
|
52
|
-
* 若未实现,则退回非原子 get+set 流程。
|
|
53
|
-
*
|
|
54
|
-
* @param key - 限流键
|
|
55
|
-
* @param windowMs - 窗口时长(ms)
|
|
56
|
-
* @returns 自增后的计数和窗口重置时间
|
|
57
|
-
*/
|
|
58
|
-
increment?: (key: string, windowMs: number) => Promise<RateLimitEntry> | RateLimitEntry;
|
|
43
|
+
/** shared要求共享后端;memory仅限显式开发/测试。 */
|
|
44
|
+
readonly scope: 'shared' | 'memory';
|
|
45
|
+
/** 原子计数并保留首次请求的窗口,返回提交后的计数/重置点。 */
|
|
46
|
+
increment: (key: string, windowMs: number) => Promise<RateLimitEntry> | RateLimitEntry;
|
|
59
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* 共享缓存的最小结构契约;使用其单键CAS与服务端TTL,不使用锁或客户端到期清零。
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import type { RateLimitCache } from '@h-ai/kit'
|
|
53
|
+
* import { cache } from '@h-ai/cache'
|
|
54
|
+
*
|
|
55
|
+
* const backend: RateLimitCache = cache
|
|
56
|
+
* void backend
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
interface RateLimitCache {
|
|
60
|
+
readonly config: {
|
|
61
|
+
type: string;
|
|
62
|
+
} | null;
|
|
63
|
+
readonly kv: {
|
|
64
|
+
get: <T>(key: string) => Promise<HaiResult<T | null>>;
|
|
65
|
+
compareAndSwap: (key: string, expected: RateLimitEntry | undefined, value: RateLimitEntry, options: {
|
|
66
|
+
px?: number;
|
|
67
|
+
keepTtl?: boolean;
|
|
68
|
+
}) => Promise<HaiResult<boolean>>;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 创建共享缓存固定窗口计数器;Redis/Cluster的CAS与TTL构成原子边界。
|
|
73
|
+
* 只有缓存键实际过期才新建窗口,节点时钟只影响响应头估算,不提前重置计数。
|
|
74
|
+
* @param backend - 已初始化的cache模块;每次请求重新核对provider,防止切换后回退内存
|
|
75
|
+
* @param options - 业务限流命名空间与显式开发内存选项
|
|
76
|
+
* @param options.namespace - 同一策略的稳定业务范围
|
|
77
|
+
* @param options.allowMemory - 仅开发或显式HAI_E2E测试允许内存cache
|
|
78
|
+
* @returns 无内部定时器、不接管cache生命周期的计数器;基础设施错误显式抛错
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { kit } from '@h-ai/kit'
|
|
82
|
+
*
|
|
83
|
+
* import { cache } from '@h-ai/cache'
|
|
84
|
+
*
|
|
85
|
+
* // 应用在启动时先初始化 Redis cache,关闭时由应用统一回收。
|
|
86
|
+
* const store = kit.middleware.createCacheRateLimitStore(cache, { namespace: 'api' })
|
|
87
|
+
* void store
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare function createCacheRateLimitStore(backend: RateLimitCache, options: {
|
|
91
|
+
namespace: string;
|
|
92
|
+
allowMemory?: boolean;
|
|
93
|
+
}): RateLimitStore;
|
|
94
|
+
/**
|
|
95
|
+
* 创建显式开发/测试计数器;无定时器,最多保存 10000 个窗口,生产拒绝内存模式。
|
|
96
|
+
* @returns 由调用者持有的计数器;丢弃引用即可回收,无需关闭,也不接管外部 store。
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* import { kit } from '@h-ai/kit'
|
|
100
|
+
*
|
|
101
|
+
* // 开发/测试进程;生产环境会明确拒绝内存计数。
|
|
102
|
+
* const store = kit.middleware.createMemoryRateLimitStore()
|
|
103
|
+
* const entry = await store.increment('client_1', 60_000)
|
|
104
|
+
* void entry.count
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function createMemoryRateLimitStore(): MemoryRateLimitStore;
|
|
60
108
|
/**
|
|
61
109
|
* 内存速率限制存储
|
|
62
110
|
*
|
|
63
|
-
* 基于 Map
|
|
64
|
-
*
|
|
111
|
+
* 基于 Map 实现,仅用于单进程开发/测试;每次请求最多扫描 64 项过期窗口,
|
|
112
|
+
* 不持有定时器。最多 10000 项,容量耗尽时拒绝新 key,不驱逐有效计数以免绕过限流。
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* import { kit } from '@h-ai/kit'
|
|
116
|
+
*
|
|
117
|
+
* // 仅开发/测试;丢弃引用即可回收,无内部定时器。
|
|
118
|
+
* const store = kit.middleware.createMemoryRateLimitStore()
|
|
119
|
+
* void store.increment('client_1', 60_000)
|
|
120
|
+
* ```
|
|
65
121
|
*/
|
|
66
122
|
declare class MemoryRateLimitStore implements RateLimitStore {
|
|
123
|
+
readonly scope: "memory";
|
|
67
124
|
private store;
|
|
68
|
-
private
|
|
125
|
+
private cleanupCursor;
|
|
69
126
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* @param intervalMs - 清理间隔(毫秒)
|
|
73
|
-
*/
|
|
74
|
-
startCleanup(intervalMs: number): void;
|
|
75
|
-
/**
|
|
76
|
-
* 停止定期清理并释放定时器资源
|
|
77
|
-
*
|
|
78
|
-
* 调用后可再次 startCleanup 重启。进程退出 / 热重载 / 测试拆装场景必须调用以
|
|
79
|
-
* 避免资源泄漏。
|
|
127
|
+
* 有界惰性回收;保留迭代位置,避免每次从头扫描使尾部过期项永久滞留。
|
|
128
|
+
* @param now - 当前请求时间,等于 resetAt 时窗口已经失效。
|
|
80
129
|
*/
|
|
81
|
-
|
|
82
|
-
get(key: string): RateLimitEntry | undefined;
|
|
83
|
-
set(key: string, entry: RateLimitEntry): void;
|
|
84
|
-
delete(key: string): void;
|
|
130
|
+
private prune;
|
|
85
131
|
/**
|
|
86
132
|
* 原子自增(内存实现为同步操作,天然原子)
|
|
87
133
|
*
|
|
88
134
|
* @param key - 限流键
|
|
89
135
|
* @param windowMs - 窗口时长
|
|
90
|
-
* @returns
|
|
136
|
+
* @returns 自增后的快照,修改返回对象不会改变已保存的计数。
|
|
137
|
+
* @throws 新 key 超出容量或期限非法;中间件将其转换为 503。
|
|
138
|
+
* @example store.increment('client', 60_000)
|
|
91
139
|
*/
|
|
92
140
|
increment(key: string, windowMs: number): RateLimitEntry;
|
|
93
141
|
}
|
|
94
142
|
/**
|
|
95
143
|
* 创建速率限制中间件
|
|
96
144
|
*
|
|
97
|
-
*
|
|
145
|
+
* 基于必选原子存储的固定窗口限流:
|
|
98
146
|
* - 超限时返回 429,并在响应头中告知重置时间
|
|
99
147
|
* - 正常响应附带 `X-RateLimit-*` 头
|
|
100
|
-
* -
|
|
148
|
+
* - 必须显式传入 store;生产使用共享计数器,故障返回503
|
|
101
149
|
*
|
|
102
150
|
* @param config - 限流配置
|
|
103
151
|
* @returns Middleware 实例
|
|
104
|
-
*
|
|
105
152
|
* @example
|
|
106
153
|
* ```ts
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
154
|
+
* import { kit } from '@h-ai/kit'
|
|
155
|
+
*
|
|
156
|
+
* import { cache } from '@h-ai/cache'
|
|
157
|
+
*
|
|
158
|
+
* // Redis 由应用初始化和关闭;多节点复用相同 namespace。
|
|
159
|
+
* const middleware = kit.middleware.rateLimit({ windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'api' }) })
|
|
160
|
+
* void middleware
|
|
110
161
|
* ```
|
|
111
162
|
*/
|
|
112
163
|
declare function rateLimitMiddleware(config: RateLimitConfig): Middleware;
|
|
@@ -123,9 +174,28 @@ declare function rateLimitMiddleware(config: RateLimitConfig): Middleware;
|
|
|
123
174
|
*
|
|
124
175
|
* 注入后,kit.auth.login / kit.auth.logout 等函数自动委托到 iam.auth 对应方法。
|
|
125
176
|
* 传入 `iam.auth` 即可,kit 会自动提取所需方法。
|
|
177
|
+
* @example
|
|
178
|
+
* ```ts
|
|
179
|
+
* import type { AuthOperations } from '@h-ai/kit'
|
|
180
|
+
* import { iam } from '@h-ai/iam'
|
|
181
|
+
*
|
|
182
|
+
* // 在 IAM 初始化后注入其当前操作对象。
|
|
183
|
+
* const operations: AuthOperations = iam.auth
|
|
184
|
+
* void operations
|
|
185
|
+
* ```
|
|
126
186
|
*/
|
|
127
187
|
type AuthOperations = Pick<AuthnOperations, 'login' | 'loginWithOtp' | 'loginWithLdap' | 'loginWithApiKey' | 'registerAndLogin' | 'logout'>;
|
|
128
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* 认证操作提供器:支持直接传对象或按需返回最新对象的工厂函数
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* import type { AuthOperationsProvider } from '@h-ai/kit'
|
|
193
|
+
* import { iam } from '@h-ai/iam'
|
|
194
|
+
*
|
|
195
|
+
* const operations: AuthOperationsProvider = () => iam.auth
|
|
196
|
+
* void operations
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
129
199
|
type AuthOperationsProvider = AuthOperations | (() => AuthOperations);
|
|
130
200
|
/**
|
|
131
201
|
* 会话数据最小接口
|
|
@@ -133,6 +203,13 @@ type AuthOperationsProvider = AuthOperations | (() => AuthOperations);
|
|
|
133
203
|
* 守卫和权限检查函数所需的最小会话形状。
|
|
134
204
|
* 应用层扩展的 session(如添加 displayName / avatarUrl 等字段)
|
|
135
205
|
* 只要包含此接口的字段即可直接传入守卫函数,无需类型断言。
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* import type { SessionLike } from '@h-ai/kit'
|
|
209
|
+
*
|
|
210
|
+
* const value: SessionLike = { userId: 'user_1', roles: ['editor'], permissions: ['article:read'] }
|
|
211
|
+
* void value
|
|
212
|
+
* ```
|
|
136
213
|
*/
|
|
137
214
|
interface SessionLike {
|
|
138
215
|
/** 用户 ID */
|
|
@@ -152,18 +229,12 @@ interface SessionLike {
|
|
|
152
229
|
*
|
|
153
230
|
* 应用层可通过 `& { displayName: string }` 等方式扩展,
|
|
154
231
|
* 扩展后的类型自动兼容所有守卫和权限检查函数(它们接受 `SessionLike`)。
|
|
155
|
-
*
|
|
156
232
|
* @example
|
|
157
233
|
* ```ts
|
|
158
|
-
*
|
|
159
|
-
* userId: 'u_123',
|
|
160
|
-
* username: 'alice',
|
|
161
|
-
* roles: ['admin'],
|
|
162
|
-
* permissions: ['user:read', 'user:write'],
|
|
163
|
-
* }
|
|
234
|
+
* import type { SessionData } from '@h-ai/kit'
|
|
164
235
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
236
|
+
* const value: SessionData = { userId: 'user_1', username: 'alice', roles: ['editor'], permissions: ['article:read'] }
|
|
237
|
+
* void value
|
|
167
238
|
* ```
|
|
168
239
|
*/
|
|
169
240
|
interface SessionData {
|
|
@@ -184,6 +255,14 @@ interface SessionData {
|
|
|
184
255
|
* 扩展的请求事件
|
|
185
256
|
*
|
|
186
257
|
* 在 SvelteKit 原生 `RequestEvent` 基础上注入会话和请求 ID。
|
|
258
|
+
* @example
|
|
259
|
+
* ```ts
|
|
260
|
+
* import type { HaiRequestEvent } from '@h-ai/kit'
|
|
261
|
+
*
|
|
262
|
+
* function requestLabel(event: HaiRequestEvent) {
|
|
263
|
+
* return { requestId: event.requestId, userId: event.session?.userId }
|
|
264
|
+
* }
|
|
265
|
+
* ```
|
|
187
266
|
*/
|
|
188
267
|
interface HaiRequestEvent extends RequestEvent {
|
|
189
268
|
/** 会话数据 */
|
|
@@ -196,6 +275,14 @@ interface HaiRequestEvent extends RequestEvent {
|
|
|
196
275
|
*
|
|
197
276
|
* 由 `createHandle` 构建,传递给所有中间件函数。
|
|
198
277
|
* 包含当前请求事件、已解析的会话以及请求唯一 ID。
|
|
278
|
+
* @example
|
|
279
|
+
* ```ts
|
|
280
|
+
* import type { MiddlewareContext } from '@h-ai/kit'
|
|
281
|
+
*
|
|
282
|
+
* function requestLabel(context: MiddlewareContext) {
|
|
283
|
+
* return context.event.url.pathname + ':' + context.requestId
|
|
284
|
+
* }
|
|
285
|
+
* ```
|
|
199
286
|
*/
|
|
200
287
|
interface MiddlewareContext {
|
|
201
288
|
/** 请求事件 */
|
|
@@ -209,15 +296,12 @@ interface MiddlewareContext {
|
|
|
209
296
|
* 中间件函数
|
|
210
297
|
*
|
|
211
298
|
* 遵循洋葱模型:调用 `next()` 前执行前置逻辑,调用后执行后置逻辑。
|
|
212
|
-
*
|
|
213
299
|
* @example
|
|
214
300
|
* ```ts
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* return response
|
|
220
|
-
* }
|
|
301
|
+
* import type { Middleware } from '@h-ai/kit'
|
|
302
|
+
*
|
|
303
|
+
* const value: Middleware = async (_context, next) => { const response = await next(); response.headers.set('X-Example', 'enabled'); return response }
|
|
304
|
+
* void value
|
|
221
305
|
* ```
|
|
222
306
|
*/
|
|
223
307
|
type Middleware = (context: MiddlewareContext, next: () => Promise<Response>) => Promise<Response>;
|
|
@@ -226,6 +310,13 @@ type Middleware = (context: MiddlewareContext, next: () => Promise<Response>) =>
|
|
|
226
310
|
*
|
|
227
311
|
* 守卫函数必须返回此结构。`allowed: true` 表示放行,否则根据
|
|
228
312
|
* `redirect` / `message` / `status` 决定拦截行为。
|
|
313
|
+
* @example
|
|
314
|
+
* ```ts
|
|
315
|
+
* import type { GuardResult } from '@h-ai/kit'
|
|
316
|
+
*
|
|
317
|
+
* const value: GuardResult = { allowed: false, status: 403 }
|
|
318
|
+
* void value
|
|
319
|
+
* ```
|
|
229
320
|
*/
|
|
230
321
|
interface GuardResult {
|
|
231
322
|
/** 是否允许访问 */
|
|
@@ -241,13 +332,12 @@ interface GuardResult {
|
|
|
241
332
|
* 路由守卫函数
|
|
242
333
|
*
|
|
243
334
|
* 接收请求事件与可选会话,返回 `GuardResult`(同步或异步均可)。
|
|
244
|
-
*
|
|
245
335
|
* @example
|
|
246
336
|
* ```ts
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
337
|
+
* import type { RouteGuard } from '@h-ai/kit'
|
|
338
|
+
*
|
|
339
|
+
* const value: RouteGuard = (_event, session) => ({ allowed: session?.permissions.includes('article:read') ?? false, status: 403 })
|
|
340
|
+
* void value
|
|
251
341
|
* ```
|
|
252
342
|
*/
|
|
253
343
|
type RouteGuard = (event: RequestEvent, session?: SessionData) => Promise<GuardResult> | GuardResult;
|
|
@@ -256,14 +346,12 @@ type RouteGuard = (event: RequestEvent, session?: SessionData) => Promise<GuardR
|
|
|
256
346
|
*
|
|
257
347
|
* 在 `createHandle({ guards })` 中使用。
|
|
258
348
|
* `paths` 支持 `/*` 和 `/**` 通配符,`exclude` 优先于 `paths`。
|
|
259
|
-
*
|
|
260
349
|
* @example
|
|
261
350
|
* ```ts
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
* }
|
|
351
|
+
* import type { GuardConfig } from '@h-ai/kit'
|
|
352
|
+
*
|
|
353
|
+
* const value: GuardConfig = { paths: ['/admin/**'], guard: (_event, session) => ({ allowed: Boolean(session) }) }
|
|
354
|
+
* void value
|
|
267
355
|
* ```
|
|
268
356
|
*/
|
|
269
357
|
interface GuardConfig {
|
|
@@ -284,17 +372,12 @@ interface GuardConfig {
|
|
|
284
372
|
*
|
|
285
373
|
* API 路径(以 `/api/` 开头)未认证时返回 401 JSON;
|
|
286
374
|
* 非 API 路径未认证时重定向到 `loginUrl`(若配置)或返回 401。
|
|
287
|
-
*
|
|
288
375
|
* @example
|
|
289
376
|
* ```ts
|
|
290
|
-
* kit
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* protectedPaths: ['/admin/*', '/api/*'],
|
|
295
|
-
* publicPaths: ['/api/auth/*', '/api/public/*'],
|
|
296
|
-
* },
|
|
297
|
-
* })
|
|
377
|
+
* import type { HandleAuthConfig } from '@h-ai/kit'
|
|
378
|
+
*
|
|
379
|
+
* const value: HandleAuthConfig = { verifyToken: async () => null, protectedPaths: ['/admin/**'], loginUrl: '/auth/login' }
|
|
380
|
+
* void value
|
|
298
381
|
* ```
|
|
299
382
|
*/
|
|
300
383
|
interface HandleAuthConfig {
|
|
@@ -327,19 +410,12 @@ interface HandleAuthConfig {
|
|
|
327
410
|
* 3. 执行路由守卫
|
|
328
411
|
* 4. 执行中间件链(logging / rateLimit / 自定义)
|
|
329
412
|
* 5. 调用 resolve + 附加 `X-Request-Id` 响应头
|
|
330
|
-
*
|
|
331
413
|
* @example
|
|
332
414
|
* ```ts
|
|
333
|
-
* kit
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
* protectedPaths: ['/admin/*', '/api/*'],
|
|
338
|
-
* publicPaths: ['/api/auth/*'],
|
|
339
|
-
* },
|
|
340
|
-
* rateLimit: { maxRequests: 100 },
|
|
341
|
-
* crypto: { crypto, transport: true },
|
|
342
|
-
* })
|
|
415
|
+
* import type { HandleConfig } from '@h-ai/kit'
|
|
416
|
+
*
|
|
417
|
+
* const value: HandleConfig = { logging: true, auth: { verifyToken: async () => null, protectedPaths: ['/admin/**'] } }
|
|
418
|
+
* void value
|
|
343
419
|
* ```
|
|
344
420
|
*/
|
|
345
421
|
interface HandleConfig {
|
|
@@ -356,7 +432,7 @@ interface HandleConfig {
|
|
|
356
432
|
* 提供对象启用速率限制;设为 `false` 显式禁用。
|
|
357
433
|
* 不提供则不开启速率限制。
|
|
358
434
|
*/
|
|
359
|
-
rateLimit?: {
|
|
435
|
+
rateLimit?: Omit<RateLimitConfig, 'windowMs' | 'maxRequests'> & {
|
|
360
436
|
windowMs?: number;
|
|
361
437
|
maxRequests?: number;
|
|
362
438
|
} | false;
|
|
@@ -398,6 +474,13 @@ interface HandleConfig {
|
|
|
398
474
|
* A2A 操作接口(用于 Handle 集成)
|
|
399
475
|
*
|
|
400
476
|
* 与 `ai.a2a` 结构兼容,可直接传入 `ai.a2a` 对象。
|
|
477
|
+
* @example
|
|
478
|
+
* ```ts
|
|
479
|
+
* import type { HandleA2AOperations } from '@h-ai/kit'
|
|
480
|
+
* import { ai } from '@h-ai/ai'
|
|
481
|
+
*
|
|
482
|
+
* function operationsAfterInit(): HandleA2AOperations { return ai.a2a }
|
|
483
|
+
* ```
|
|
401
484
|
*/
|
|
402
485
|
interface HandleA2AOperations {
|
|
403
486
|
/** 获取 Agent Card(返回 HaiResult 对象) */
|
|
@@ -415,16 +498,12 @@ interface HandleA2AOperations {
|
|
|
415
498
|
}
|
|
416
499
|
/**
|
|
417
500
|
* A2A Handle 配置(高级模式)
|
|
418
|
-
*
|
|
419
501
|
* @example
|
|
420
502
|
* ```ts
|
|
421
|
-
* kit
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
425
|
-
* authenticate: 'apiKey', // 自动使用 IAM API Key 验证
|
|
426
|
-
* },
|
|
427
|
-
* })
|
|
503
|
+
* import type { HandleA2AConfig } from '@h-ai/kit'
|
|
504
|
+
* import { ai } from '@h-ai/ai'
|
|
505
|
+
*
|
|
506
|
+
* function configAfterInit(): HandleA2AConfig { return { operations: ai.a2a, authenticate: async () => null } }
|
|
428
507
|
* ```
|
|
429
508
|
*/
|
|
430
509
|
interface HandleA2AConfig {
|
|
@@ -445,41 +524,36 @@ interface HandleA2AConfig {
|
|
|
445
524
|
}
|
|
446
525
|
/**
|
|
447
526
|
* 传输加密详细配置
|
|
527
|
+
* @example
|
|
528
|
+
* ```ts
|
|
529
|
+
* import type { TransportEncryptionOptions } from '@h-ai/kit'
|
|
530
|
+
* import type { TransportServerKeyRing, TransportKeyStore } from '@h-ai/crypto'
|
|
531
|
+
*
|
|
532
|
+
* function transport(serverKeyRing: TransportServerKeyRing, keyStore: TransportKeyStore): TransportEncryptionOptions {
|
|
533
|
+
* return { serverKeyRing, keyStore, excludePaths: ['/api/health'] }
|
|
534
|
+
* }
|
|
535
|
+
* ```
|
|
448
536
|
*/
|
|
449
537
|
interface TransportEncryptionOptions {
|
|
538
|
+
/** 受管服务端版本化密钥环,不进入公开 YAML/客户端配置。 */
|
|
539
|
+
serverKeyRing: TransportServerKeyRing;
|
|
450
540
|
/** 密钥交换端点路径(默认 `'/api/_hai/key-exchange'`) */
|
|
451
541
|
keyExchangePath?: string;
|
|
452
542
|
/** 排除路径(不加密),支持精确匹配和前缀匹配 */
|
|
453
543
|
excludePaths?: string[];
|
|
454
|
-
/**
|
|
455
|
-
* 是否强制要求传输加密(默认 `true`)
|
|
456
|
-
*
|
|
457
|
-
* - `true`:非排除路径上缺少 X-Client-Id 请求头时返回 400
|
|
458
|
-
* - `false`:缺少 X-Client-Id 时透传明文(仅用于渐进式迁移,不建议生产启用)
|
|
459
|
-
*/
|
|
460
|
-
requireEncryption?: boolean;
|
|
461
|
-
/** 是否加密响应体(默认 `true`) */
|
|
462
|
-
encryptResponse?: boolean;
|
|
463
|
-
/** 服务端可缓存的客户端公钥数量上限(默认 `10000`) */
|
|
464
|
-
maxClients?: number;
|
|
465
544
|
/** 共享客户端公钥存储;适用于多节点部署。 */
|
|
466
|
-
keyStore
|
|
545
|
+
keyStore: TransportKeyStore;
|
|
467
546
|
}
|
|
468
547
|
/**
|
|
469
548
|
* Handle Hook 加密配置
|
|
470
549
|
*
|
|
471
550
|
* 在 `kit.createHandle({ crypto: { ... } })` 中使用。
|
|
472
|
-
*
|
|
473
551
|
* @example
|
|
474
552
|
* ```ts
|
|
475
|
-
* kit
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
* encryptedCookies: ['hai_session'],
|
|
480
|
-
* cookieEncryptionKey: process.env.HAI_KIT_COOKIE_KEY,
|
|
481
|
-
* },
|
|
482
|
-
* })
|
|
553
|
+
* import type { HookCryptoConfig, TransportEncryptionOptions } from '@h-ai/kit'
|
|
554
|
+
* import { crypto } from '@h-ai/crypto'
|
|
555
|
+
*
|
|
556
|
+
* function config(transport: TransportEncryptionOptions): HookCryptoConfig { return { crypto, transport } }
|
|
483
557
|
* ```
|
|
484
558
|
*/
|
|
485
559
|
interface HookCryptoConfig {
|
|
@@ -487,10 +561,10 @@ interface HookCryptoConfig {
|
|
|
487
561
|
crypto: CryptoFunctions;
|
|
488
562
|
/**
|
|
489
563
|
* 启用传输加密。
|
|
490
|
-
* - `
|
|
491
|
-
* -
|
|
564
|
+
* - `false` 或省略:关闭
|
|
565
|
+
* - 对象:必填受管 serverKeyRing / keyStore,可附加公开路径配置
|
|
492
566
|
*/
|
|
493
|
-
transport?:
|
|
567
|
+
transport?: false | TransportEncryptionOptions;
|
|
494
568
|
/**
|
|
495
569
|
* 需要加密的 Cookie 名称列表
|
|
496
570
|
*
|
|
@@ -511,13 +585,12 @@ interface HookCryptoConfig {
|
|
|
511
585
|
*
|
|
512
586
|
* `kit.response.*` 系列函数统一返回此结构的 JSON 响应。
|
|
513
587
|
* 成功时 `success: true` 且 `data` 有值;失败时 `success: false` 且 `error` 有值。
|
|
514
|
-
*
|
|
515
588
|
* @example
|
|
516
589
|
* ```ts
|
|
517
|
-
*
|
|
518
|
-
*
|
|
519
|
-
*
|
|
520
|
-
*
|
|
590
|
+
* import type { ApiResponse } from '@h-ai/kit'
|
|
591
|
+
*
|
|
592
|
+
* const value: ApiResponse<{ id: string }> = { success: true, data: { id: 'article_1' } }
|
|
593
|
+
* void value
|
|
521
594
|
* ```
|
|
522
595
|
*/
|
|
523
596
|
interface ApiResponse<T = unknown> {
|
|
@@ -539,6 +612,13 @@ interface ApiResponse<T = unknown> {
|
|
|
539
612
|
*
|
|
540
613
|
* 由 `kit.validate.*` 在校验失败时返回。
|
|
541
614
|
* `field` 使用点号路径(如 `'address.city'`),`_` 表示全局错误。
|
|
615
|
+
* @example
|
|
616
|
+
* ```ts
|
|
617
|
+
* import type { FormError } from '@h-ai/kit'
|
|
618
|
+
*
|
|
619
|
+
* const value: FormError = { field: 'title', message: 'Title is required' }
|
|
620
|
+
* void value
|
|
621
|
+
* ```
|
|
542
622
|
*/
|
|
543
623
|
interface FormError {
|
|
544
624
|
/** 字段名 */
|
|
@@ -550,12 +630,12 @@ interface FormError {
|
|
|
550
630
|
* 表单验证结果
|
|
551
631
|
*
|
|
552
632
|
* @template T - Zod schema 推导出的数据类型
|
|
553
|
-
*
|
|
554
633
|
* @example
|
|
555
634
|
* ```ts
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
635
|
+
* import type { FormValidationResult } from '@h-ai/kit'
|
|
636
|
+
*
|
|
637
|
+
* const value: FormValidationResult<{ title: string }> = { valid: true, data: { title: 'Example' }, errors: [] }
|
|
638
|
+
* void value
|
|
559
639
|
* ```
|
|
560
640
|
*/
|
|
561
641
|
interface FormValidationResult<T> {
|
|
@@ -569,15 +649,16 @@ interface FormValidationResult<T> {
|
|
|
569
649
|
/**
|
|
570
650
|
* 速率限制配置
|
|
571
651
|
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
574
|
-
*
|
|
652
|
+
* 基于可插拔原子存储的固定窗口限流。超限后返回 429 状态码与 `Retry-After` 响应头。
|
|
653
|
+
* 必须显式传入 store;生产使用共享计数器,故障返回503。
|
|
575
654
|
* @example
|
|
576
655
|
* ```ts
|
|
577
|
-
* kit
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
656
|
+
* import type { RateLimitConfig } from '@h-ai/kit'
|
|
657
|
+
* import { kit } from '@h-ai/kit'
|
|
658
|
+
* import { cache } from '@h-ai/cache'
|
|
659
|
+
*
|
|
660
|
+
* const config: RateLimitConfig = { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'api' }) }
|
|
661
|
+
* void config
|
|
581
662
|
* ```
|
|
582
663
|
*/
|
|
583
664
|
interface RateLimitConfig {
|
|
@@ -592,23 +673,20 @@ interface RateLimitConfig {
|
|
|
592
673
|
/**
|
|
593
674
|
* 自定义存储实现
|
|
594
675
|
*
|
|
595
|
-
*
|
|
596
|
-
* 多实例部署时传入基于 Redis / @h-ai/cache 的分布式 Store。
|
|
676
|
+
* 必须提供原子 increment;不支持 get+set 回退。共享缓存由调用方初始化和关闭。
|
|
597
677
|
*/
|
|
598
|
-
store
|
|
678
|
+
store: RateLimitStore;
|
|
599
679
|
}
|
|
600
680
|
/**
|
|
601
681
|
* CORS 中间件配置
|
|
602
682
|
*
|
|
603
683
|
* 配置跨域资源共享策略。预检请求(OPTIONS)自动返回 204。
|
|
604
|
-
*
|
|
605
684
|
* @example
|
|
606
685
|
* ```ts
|
|
607
|
-
* kit
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
* })
|
|
686
|
+
* import type { CorsConfig } from '@h-ai/kit'
|
|
687
|
+
*
|
|
688
|
+
* const value: CorsConfig = { origin: ['https://app.example.com'], credentials: true }
|
|
689
|
+
* void value
|
|
612
690
|
* ```
|
|
613
691
|
*/
|
|
614
692
|
interface CorsConfig {
|
|
@@ -628,4 +706,4 @@ interface CorsConfig {
|
|
|
628
706
|
capacitor?: boolean;
|
|
629
707
|
}
|
|
630
708
|
|
|
631
|
-
export { type ApiResponse as A, type CorsConfig as C, type FormError as F, type GuardConfig as G, type HaiRequestEvent as H, type Middleware as M, type RateLimitConfig as R, type SessionData as S, type TransportEncryptionOptions as T, type AuthOperations as a, type AuthOperationsProvider as b, type FormValidationResult as c, type GuardResult as d, type HandleA2AConfig as e, type HandleA2AOperations as f, type HandleAuthConfig as g, type HandleConfig as h, type HookCryptoConfig as i, type MiddlewareContext as j, type RouteGuard as k, type SessionLike as l,
|
|
709
|
+
export { type ApiResponse as A, type CorsConfig as C, type FormError as F, type GuardConfig as G, type HaiRequestEvent as H, type Middleware as M, type RateLimitConfig as R, type SessionData as S, type TransportEncryptionOptions as T, type AuthOperations as a, type AuthOperationsProvider as b, type FormValidationResult as c, type GuardResult as d, type HandleA2AConfig as e, type HandleA2AOperations as f, type HandleAuthConfig as g, type HandleConfig as h, type HookCryptoConfig as i, type MiddlewareContext as j, type RouteGuard as k, type SessionLike as l, createCacheRateLimitStore as m, createMemoryRateLimitStore as n, MemoryRateLimitStore as o, type RateLimitCache as p, type RateLimitEntry as q, rateLimitMiddleware as r, type RateLimitStore as s };
|