@h-ai/kit 0.1.0-alpha8 → 1.0.0-beta.1
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 +430 -0
- package/README.ja.md +430 -0
- package/README.md +351 -40
- package/dist/adapter/index.d.ts +17 -2
- package/dist/adapter/index.js.map +1 -1
- package/dist/browser.d.ts +19 -8
- package/dist/browser.js +10 -7
- package/dist/browser.js.map +1 -1
- package/dist/chunk-3OHUSKHI.js +175 -0
- package/dist/chunk-3OHUSKHI.js.map +1 -0
- package/dist/chunk-5VWPH7DO.js +126 -0
- package/dist/chunk-5VWPH7DO.js.map +1 -0
- package/dist/chunk-7EH47MTW.js +141 -0
- package/dist/chunk-7EH47MTW.js.map +1 -0
- package/dist/chunk-JRQPMPQC.js +63 -0
- package/dist/chunk-JRQPMPQC.js.map +1 -0
- package/dist/chunk-USFJN7IO.js +187 -0
- package/dist/chunk-USFJN7IO.js.map +1 -0
- package/dist/chunk-YKJRQCWR.js +363 -0
- package/dist/chunk-YKJRQCWR.js.map +1 -0
- package/dist/client/index.d.ts +51 -2
- package/dist/client/index.js +21 -2
- package/dist/client/index.js.map +1 -1
- package/dist/index.d.ts +303 -409
- package/dist/index.js +598 -310
- package/dist/index.js.map +1 -1
- package/dist/kit-a2a-types-4dapztu2.d.ts +136 -0
- package/dist/kit-client-auth-BnhrkzZF.d.ts +422 -0
- package/dist/kit-crypto-types-CXr888wf.d.ts +200 -0
- package/dist/kit-i18n-EBzZKYN-.d.ts +502 -0
- package/dist/kit-types-BkNdyKj8.d.ts +822 -0
- package/dist/modules/a2a/index.d.ts +15 -113
- package/dist/modules/a2a/index.js +2 -55
- package/dist/modules/a2a/index.js.map +1 -1
- package/dist/modules/crypto/index.d.ts +31 -79
- package/dist/modules/crypto/index.js +3 -3
- package/dist/modules/crypto/index.js.map +1 -1
- package/package.json +36 -22
- package/dist/chunk-475WECWK.js +0 -110
- package/dist/chunk-475WECWK.js.map +0 -1
- package/dist/chunk-6TMSXG7J.js +0 -169
- package/dist/chunk-6TMSXG7J.js.map +0 -1
- package/dist/chunk-AD6S473Y.js +0 -137
- package/dist/chunk-AD6S473Y.js.map +0 -1
- package/dist/chunk-FRYJMRTP.js +0 -71
- package/dist/chunk-FRYJMRTP.js.map +0 -1
- package/dist/chunk-PHS7ZD5L.js +0 -274
- package/dist/chunk-PHS7ZD5L.js.map +0 -1
- package/dist/index-BotXLTck.d.ts +0 -203
- package/dist/kit-crypto-types-C-gEvx04.d.ts +0 -253
- package/dist/kit-i18n-CgpNTh9G.d.ts +0 -206
- package/dist/kit-types-BHlDNNpd.d.ts +0 -618
package/README.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# @h-ai/kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
|
|
4
|
+
|
|
5
|
+
[框架首页](../../README.md) · 相关模块:[@h-ai/core](../core/README.md) · [@h-ai/crypto](../crypto/README.md) · [@h-ai/iam](../iam/README.md)
|
|
6
|
+
|
|
7
|
+
## 简介
|
|
8
|
+
|
|
9
|
+
`@h-ai/kit` 是 hai-framework 的 SvelteKit 集成模块,提供统一的请求管道与同源 endpoint 工具:
|
|
4
10
|
|
|
5
11
|
- `kit.createHandle()`:会话解析、路由守卫、中间件链、可选传输加密与 Cookie 加密
|
|
6
12
|
- `kit.handler()`:API 端点异常边界
|
|
7
13
|
- `kit.guard` / `kit.response` / `kit.validate` / `kit.auth` / `kit.client` / `kit.crud`
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
> 公共跨端 HTTP API contract 统一放在 `@h-ai/api-contract`,由 `@h-ai/serv` 挂载,客户端通过 `@h-ai/api-client` typed client 调用;`@h-ai/kit` 不定义也不承载业务 API contract。
|
|
16
|
+
|
|
17
|
+
## 核心功能清单
|
|
10
18
|
|
|
11
19
|
- Handle Hook 组合(`createHandle` / `sequence`)
|
|
12
20
|
- 认证/角色/权限守卫(`guard.require` / `guard.check`)
|
|
@@ -14,39 +22,100 @@
|
|
|
14
22
|
- 统一 API 响应与请求验证(Zod)
|
|
15
23
|
- Bearer Token 工具(服务端 login/logout + 浏览器端 Token 存储)
|
|
16
24
|
- 浏览器端统一客户端(自动 CSRF,支持传输加密)
|
|
17
|
-
- 基于 EndpointDef 的契约模式(`fromContract`)
|
|
18
25
|
- 声明式 CRUD 资源定义(`crud.define`)
|
|
19
|
-
- A2A
|
|
26
|
+
- A2A 协议集成:默认发现路径 `/.well-known/agent-card.json`;配置 `authenticate` 后 null/undefined 返回 401,仅未配置认证时允许匿名。API Key 参数从完整 Agent Card 的 `securitySchemes.apiKey` 读取。Hook 与显式 A2A 路由共享 JSON-RPC 解析错误和 SSE 取消清理逻辑。
|
|
20
27
|
- 双构建模式(`createAdapter()`)
|
|
21
28
|
|
|
22
|
-
##
|
|
29
|
+
## 使用入门
|
|
30
|
+
|
|
31
|
+
`sequence` 保留并组合 SvelteKit 的 `resolve` 选项:页面转换由内向外执行,`preload` 与序列化响应头过滤使用首个配置,确保 i18n 的 HTML 语言标记正确替换。
|
|
32
|
+
|
|
33
|
+
### 安装
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @h-ai/kit @h-ai/core sm-crypto@0.5.7
|
|
37
|
+
npm install svelte @sveltejs/kit zod
|
|
38
|
+
npm install -D @sveltejs/vite-plugin-svelte vite
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 依赖
|
|
23
42
|
|
|
24
43
|
- `@h-ai/iam` — 身份认证与授权(A2A 认证),可选;使用 A2A 功能时需在 kit 使用前初始化
|
|
25
44
|
- `@h-ai/crypto` — 加密(传输加密 / Cookie 加密),可选;启用加密时需在 kit 使用前初始化
|
|
26
45
|
|
|
27
|
-
|
|
46
|
+
### 快速开始
|
|
47
|
+
|
|
48
|
+
#### 项目配置
|
|
49
|
+
|
|
50
|
+
**svelte.config.js**:
|
|
28
51
|
|
|
29
|
-
|
|
52
|
+
```js
|
|
53
|
+
import adapter from '@sveltejs/adapter-node'
|
|
54
|
+
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
|
|
55
|
+
|
|
56
|
+
const config = {
|
|
57
|
+
preprocess: [vitePreprocess()],
|
|
58
|
+
compilerOptions: { runes: true },
|
|
59
|
+
kit: {
|
|
60
|
+
adapter: adapter(),
|
|
61
|
+
// 双构建模式:import { createAdapter } from '@h-ai/kit/adapter'
|
|
62
|
+
// adapter: await createAdapter(),
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default config
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**vite.config.ts**:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { sveltekit } from '@sveltejs/kit/vite'
|
|
73
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
74
|
+
import { defineConfig } from 'vite'
|
|
75
|
+
|
|
76
|
+
export default defineConfig({
|
|
77
|
+
plugins: [sveltekit(), tailwindcss()],
|
|
78
|
+
optimizeDeps: { exclude: ['bits-ui'] },
|
|
79
|
+
ssr: { noExternal: ['@h-ai/ui', '@h-ai/kit'], external: ['@h-ai/core', 'sm-crypto'] },
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
使用 Crypto 或依赖它的 Kit/IAM 时,应用生产依赖需包含 `sm-crypto@0.5.7`。CLI 已配好这一项;手工接入时运行 `pnpm add sm-crypto@0.5.7`。仅设置 external 不够,adapter-node 还需要这项直接依赖声明才能保留原包加载。
|
|
84
|
+
|
|
85
|
+
#### 搭建请求管道
|
|
86
|
+
|
|
87
|
+
应用部署在 `/yyy/` 等子目录时,SvelteKit 的 `kit.paths.base` 与守卫使用的实际 URL 应保持一致:将 `$app/paths` 的 `base` 加到 `protectedPaths`、`publicPaths` 和 `loginUrl`,例如 `${base}/api/*`。认证页面使用 ``kit.client.createAuthActions({ basePath: `${base}/api/auth` })``。Kit 根据应用路由识别 `/api/*`,包括路由分组和挂载前缀;未认证的 API 返回 401,页面按配置跳转登录。生成模板已处理这些路径。
|
|
88
|
+
|
|
89
|
+
以下 Hook 片段假设应用已完成数据库、共享缓存和 IAM 初始化,并检查每项初始化结果。关闭资源由应用统一负责;不在每个请求中初始化模块。
|
|
90
|
+
|
|
91
|
+
**src/hooks.server.ts**:
|
|
30
92
|
|
|
31
93
|
```typescript
|
|
94
|
+
import type { Handle } from '@sveltejs/kit'
|
|
95
|
+
import { cache } from '@h-ai/cache'
|
|
96
|
+
import { iam } from '@h-ai/iam'
|
|
32
97
|
import { kit } from '@h-ai/kit'
|
|
33
98
|
|
|
34
|
-
|
|
99
|
+
const haiHandle = kit.createHandle({
|
|
35
100
|
auth: {
|
|
36
101
|
verifyToken: async (token) => {
|
|
37
|
-
|
|
38
|
-
return
|
|
102
|
+
const verified = await iam.auth.verifyToken(token)
|
|
103
|
+
return verified.success ? verified.data : null
|
|
39
104
|
},
|
|
40
105
|
loginUrl: '/auth/login',
|
|
41
106
|
protectedPaths: ['/admin/*', '/api/*'],
|
|
42
107
|
publicPaths: ['/api/auth/*', '/api/public/*'],
|
|
43
108
|
},
|
|
44
|
-
rateLimit: { windowMs: 60_000, maxRequests: 100 },
|
|
109
|
+
rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
|
|
45
110
|
logging: true,
|
|
46
111
|
})
|
|
112
|
+
|
|
113
|
+
export const handle: Handle = haiHandle
|
|
47
114
|
```
|
|
48
115
|
|
|
49
|
-
|
|
116
|
+
限流采用首次成功提交为起点的固定窗口,后续请求不延长 TTL。必须显式传 store;应用先检查共享 Redis 初始化结果,所有节点使用相同 namespace/windowMs/maxRequests。缓存读取/条件提交失败或冲突耗尽返回503,超限429;不会回退 get+set 或本地计数。createMemoryRateLimitStore 仅开发或显式 HAI_E2E/HAI_E2E_MOCK 测试使用,无常驻定时器,丢弃引用即可回收;每次请求最多惰性扫描 64 项,最多保存 10000 个窗口,容量满时对新 key 返回503且不驱逐有效计数,外部 store 生命周期由创建者管理;生产不得设置测试开关。响应重置时间为节点时钟估算,实际窗口由 Redis TTL 决定,须同步时钟。默认键只读取可信 adapter 的 getClientAddress、规范化等价IPv6和IPv4映射地址,不采信原始转发头;代理信任通过部署adapter配置。
|
|
117
|
+
|
|
118
|
+
#### API 端点
|
|
50
119
|
|
|
51
120
|
```typescript
|
|
52
121
|
import { kit } from '@h-ai/kit'
|
|
@@ -64,58 +133,300 @@ export const POST = kit.handler(async ({ request, locals }) => {
|
|
|
64
133
|
})
|
|
65
134
|
```
|
|
66
135
|
|
|
67
|
-
|
|
136
|
+
#### 浏览器客户端
|
|
137
|
+
|
|
138
|
+
`kit.client.create()` 面向 SvelteKit 同源 endpoint;Web / App / 小程序跨域访问公共 API 时,请使用 `@h-ai/api-client`。
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// src/lib/utils/api.ts — 全应用共享
|
|
142
|
+
import { kit } from '@h-ai/kit'
|
|
143
|
+
|
|
144
|
+
const client = kit.client.create()
|
|
145
|
+
export const { apiFetch } = client
|
|
146
|
+
```
|
|
68
147
|
|
|
69
148
|
```typescript
|
|
70
|
-
|
|
149
|
+
// 使用
|
|
150
|
+
import { apiFetch } from '$lib/utils/api'
|
|
151
|
+
|
|
152
|
+
const response = await apiFetch('/api/users', { method: 'GET' })
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
> CSRF Header 注入由 `apiFetch` 自动处理;`@h-ai/kit` 不提供独立的 CSRF 中间件工厂。
|
|
156
|
+
> `apiFetch` 接受字符串、URL 或 Request;Request 自带的方法、请求头与正文会保留,写方法同样附加 CSRF。启用 transport 时仅加密可支持的正文,multipart 上传保持原始边界。
|
|
157
|
+
>
|
|
158
|
+
> 同源 SvelteKit endpoint 使用 httpOnly Cookie,由服务端读取 Cookie 完成鉴权。浏览器 Bearer Token 使用 `kit.auth.setBrowserToken()` 写入页面内存,再通过 `kit.client.create({ auth: true })` 注入。自定义 `BrowserTokenStore` 也必须使用内存或平台安全存储,禁止将敏感凭据写入 Web Storage。
|
|
159
|
+
|
|
160
|
+
#### 同源传输加密
|
|
161
|
+
|
|
162
|
+
kit 的传输加密也统一委托 `@h-ai/crypto`:服务端通过 `crypto.transport.createServer({ serverKeyRing, keyStore })` 创建管理器,浏览器端通过 `kit.client.installBrowserTransport(kitConfig, { crypto })` 一行安装同源 fetch 包装。服务端还须注入受管密钥环和共享 registry。
|
|
163
|
+
|
|
164
|
+
部署到子目录时,从 `$app/paths` 读取 `base`:服务端 `crypto.transport` 传入 `basePath: base`,浏览器调用 `installBrowserTransport(kitConfig, { crypto, basePath: base })`;独立 `kit.client.create` 的 `transport.basePath` 采用同一值。默认空字符串表示域名根目录。这个运行时参数来自宿主的构建目录,不在 YAML 另设一份,也不从转发头推断。`keyExchangePath`、`excludePaths` 和路由容量仍使用完整请求路径。CLI 的 SSR 模板已同步装配。
|
|
165
|
+
|
|
166
|
+
**src/hooks.server.ts**:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { base } from '$app/paths'
|
|
170
|
+
import { appKitConfig } from '$lib/server/kit-config'
|
|
171
|
+
import { cache } from '@h-ai/cache'
|
|
172
|
+
import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
|
|
173
|
+
import { iam } from '@h-ai/iam'
|
|
71
174
|
import { kit } from '@h-ai/kit'
|
|
72
175
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
176
|
+
const cryptoReady = await crypto.init()
|
|
177
|
+
if (!cryptoReady.success)
|
|
178
|
+
throw new Error(cryptoReady.error.message)
|
|
179
|
+
const ring = parseTransportServerKeyRing(process.env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING)
|
|
180
|
+
if (!ring.success)
|
|
181
|
+
throw new Error(ring.error.message)
|
|
182
|
+
const serverKeyRing = ring.data
|
|
183
|
+
// Redis/IAM 由应用启动流程初始化并检查;此处复用同一实例。
|
|
184
|
+
|
|
185
|
+
export const handle = kit.createHandle({
|
|
186
|
+
auth: {
|
|
187
|
+
verifyToken: async (token) => {
|
|
188
|
+
const verified = await iam.auth.verifyToken(token)
|
|
189
|
+
return verified.success ? verified.data : null
|
|
190
|
+
},
|
|
191
|
+
protectedPaths: [`${base}/api/*`],
|
|
192
|
+
publicPaths: [`${base}/api/_hai/*`], // 默认密钥协商端点
|
|
193
|
+
},
|
|
194
|
+
crypto: {
|
|
195
|
+
crypto,
|
|
196
|
+
transport: appKitConfig.transport === false
|
|
197
|
+
? false
|
|
198
|
+
: {
|
|
199
|
+
...appKitConfig.transport,
|
|
200
|
+
basePath: base,
|
|
201
|
+
serverKeyRing,
|
|
202
|
+
keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
|
|
203
|
+
},
|
|
204
|
+
},
|
|
78
205
|
})
|
|
79
206
|
```
|
|
80
207
|
|
|
81
|
-
|
|
208
|
+
**src/routes/+layout.svelte**(推荐入口:浏览器端只需一行):
|
|
82
209
|
|
|
83
|
-
```
|
|
84
|
-
|
|
210
|
+
```svelte
|
|
211
|
+
<script lang='ts'>
|
|
212
|
+
import { browser } from '$app/environment'
|
|
213
|
+
import { base } from '$app/paths'
|
|
214
|
+
import { page } from '$app/state'
|
|
215
|
+
import { crypto } from '@h-ai/crypto'
|
|
216
|
+
import { kit } from '@h-ai/kit'
|
|
217
|
+
import { untrack } from 'svelte'
|
|
218
|
+
|
|
219
|
+
// 一次性安装:内部按 _kit.yml 决定是否启用 transport,并预热 crypto
|
|
220
|
+
if (browser) {
|
|
221
|
+
kit.client.installBrowserTransport(untrack(() => page.data.kitConfig), { crypto, basePath: base })
|
|
222
|
+
}
|
|
223
|
+
</script>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**src/lib/utils/api.ts**(业务层只看到 `apiFetch`):
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
import { kit } from '@h-ai/kit'
|
|
230
|
+
|
|
231
|
+
export const { apiFetch } = kit.client.create()
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
> 不再需要 `src/hooks.client.ts`:默认 `handleFetch` 行为已经够用,SvelteKit 内部 `__data.json` 请求会自动走上面安装的全局 fetch 包装。若确需同源 Authorization Header,使用显式 `BrowserTokenStore` 或 `kit.auth.setBrowserToken()` + `kit.client.create({ auth: true })`;不要把敏感 Token 存入 `localStorage`。
|
|
235
|
+
|
|
236
|
+
默认密钥协商路径为 `/api/_hai/key-exchange`。如服务端自定义 `transport.keyExchangePath`,客户端需同步配置 `transport.keyExchangeUrl`。
|
|
237
|
+
|
|
238
|
+
服务端必须显式注入相同的受管 `serverKeyRing` 和共享 `keyStore`(Redis 或共享数据库)。仅共享客户端公钥不足以跨节点解密。没有隐式进程私钥或内存 registry 回退;开发/测试显式用 `createInMemoryKeyStore(capacity)`。服务端重启后重新加载同一密钥环即可,无需 sticky session。
|
|
239
|
+
|
|
240
|
+
transport 默认作用于同源 `/api/*` endpoint 与 SvelteKit `__data.json` 页面数据请求(以及密钥协商端点本身);页面文档与静态资源仍保持明文,不要求携带 `X-Client-Id`。文件上传等 `multipart/form-data` 请求会保持原样发送,需在服务端 `excludePaths` 中显式放行对应上传路径。
|
|
85
241
|
|
|
86
|
-
|
|
87
|
-
|
|
242
|
+
认证协议仅支持 v2:独立随机 SM4-CBC 密钥和 HMAC-SM3 密钥由 SM2 封装,先验签、再验证 MAC,最后解密 CBC。请求由客户端私钥签名,响应由所选服务端版本签名。认证字段包括 version、direction、serverKeyId、clientId、128 位随机 requestId(兼 nonce)、issuedAt、HTTP method、pathname + 原始 search 的 SM3 pathHash,以及响应 status。请求有效期 5 分钟,未来时钟偏差最多 30 秒;共享 registry 原子消费 (clientId, requestId),nonce 至少保留到 issuedAt + 6 分钟以覆盖节点偏差,存储故障拒绝请求。Redis 必须保留有效 nonce,使用 noeviction/可靠持久化策略;各节点时钟须同步。此能力防止同一传输消息重放,业务重试仍需自己的幂等键。
|
|
243
|
+
|
|
244
|
+
空 POST 也发送空明文的认证封装;GET/HEAD 将封装放在 X-Hai-Transport 头,204/304/HEAD 等无正文响应也使用同名头承载认证封装。其它请求/响应在 JSON 正文承载封装并带 X-Encrypted: true。客户端必须关联原请求上下文和 HTTP status,缺标记、旧格式或认证失败一律 reject;明文接口由 Serv/Kit 路径规则 `encryption: disabled` 或宿主 `excludePaths` 显式允许;调用方同步选择普通请求,API Client/Kit 包装器使用自己的 `excludePaths`。CORS 须允许并暴露 X-Hai-Transport。握手公钥的真实性依赖 TLS,不替代 IAM 业务授权。
|
|
245
|
+
|
|
246
|
+
业务容量通过 `transport.maxPlaintextBytes` 统一配置:默认 1 MiB,整数范围 1 KiB~64 MiB,请求和响应共用 UTF-8 明文字节预算。客户端从握手自动获取上限,密文与部署代理预算由 `resolveTransportBodyLimits()` 推导(两倍明文 + 32 KiB)。握手、公钥、认证头和防重放约束独立;超限取消原流并释放 reader,请求 413、响应为加密的 500 容量错误,客户端识别 `TransportBodyTooLargeError` / `hai:crypto:070`。 [Transport capacity and upgrade](../crypto/TRANSPORT-CAPACITY.md)。
|
|
247
|
+
|
|
248
|
+
普通业务仍使用 `transport.maxPlaintextBytes`(auto/省略为 1 MiB);Feedback 的报告受理、证据、附件及 ZIP 下载路由通过 `routePlaintextBytes` 单独声明 `feedback.budget.maxTransportBytes`。路径中的 `*` 仅匹配一个完整路径段;宿主显式路由值优先。握手、adapter-node 与代理使用各路由最大容量,普通业务不会随材料预算扩大。HTTP 适配器为单独声明且大于 1 MiB 的材料路由保留最多 2 个槽,普通业务另有 16 个槽,完整响应/失败后释放;忙碌返回 503 / `hai:crypto:072`,不自动重放业务写入。
|
|
249
|
+
|
|
250
|
+
serv/kit 对通过请求绑定、签名和 MAC 校验但超出时间窗口的报文返回加密的 HTTP 400 时间错误;客户端抛 `TransportTimeError`(`hai:crypto:071`),提示同步设备和服务器时间后刷新重试。`api-client` 映射为 `VALIDATION_FAILED`,在 `cause.transportCode` 保留该原因。不会自动重放请求或放宽防重放窗口;篡改或未认证报文仍返回通用认证失败。
|
|
251
|
+
|
|
252
|
+
#### 使用 `_kit.yml` 统一 transport 配置
|
|
253
|
+
|
|
254
|
+
`@h-ai/kit` 提供 `KitConfigSchema` / `resolveKitConfig()`,方便应用用同一份 `_kit.yml`
|
|
255
|
+
同时驱动 `hooks.server.ts` 与浏览器端 `kit.client.installBrowserTransport()`:
|
|
256
|
+
|
|
257
|
+
```yml
|
|
258
|
+
server:
|
|
259
|
+
host: 127.0.0.1
|
|
260
|
+
port: 3000
|
|
261
|
+
|
|
262
|
+
transport:
|
|
263
|
+
keyExchangePath: /api/_hai/key-exchange
|
|
264
|
+
excludePaths:
|
|
265
|
+
- /api/storage
|
|
266
|
+
- /api/public
|
|
267
|
+
- /api/auth/profile/avatar
|
|
88
268
|
```
|
|
89
269
|
|
|
90
|
-
|
|
270
|
+
```ts
|
|
271
|
+
import { core } from '@h-ai/core'
|
|
272
|
+
import { KitConfigSchema } from '@h-ai/kit'
|
|
91
273
|
|
|
92
|
-
|
|
274
|
+
// 仅放在 src/lib/server 中;浏览器通过 layout data 接收公共投影。
|
|
275
|
+
const loaded = core.config.load('kit', './config/_kit.yml', KitConfigSchema)
|
|
276
|
+
if (!loaded.success)
|
|
277
|
+
throw new Error(loaded.error.message)
|
|
278
|
+
export const appKitConfig = loaded.data
|
|
279
|
+
export const publicKitConfig = { transport: appKitConfig.transport }
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
在 `src/routes/+layout.server.ts` 将公共投影交给上述浏览器布局,不导入服务端配置文件:
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
import { publicKitConfig } from '$lib/server/kit-config'
|
|
286
|
+
|
|
287
|
+
export function load() {
|
|
288
|
+
return { kitConfig: publicKitConfig }
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
`resolveKitConfig()` 同时解析 `server` (host/port)与 `transport`;host/port 优先级为 `HOST` / `PORT` 环境变量 > `_kit.yml` 的 `server` > 默认 `127.0.0.1:3000`,供 SvelteKit 服务器入口统一消费(与 `@h-ai/serv` 同构)。
|
|
293
|
+
如只在服务端读取配置,也可配合 `core.config.validate('kit', KitConfigSchema)` 使用。
|
|
294
|
+
完整 `_kit.yml` 由服务端读取,可包含内部代理网段和访问策略文件路径。`+layout.server.ts` 只返回 `{ kitConfig: publicKitConfig }` 等明确公共投影,浏览器消费其中的 transport;禁止用 `?raw` 把完整配置或策略文件打入客户端,也不要在其中写入密钥。
|
|
295
|
+
|
|
296
|
+
### 配置
|
|
93
297
|
|
|
94
298
|
`kit.createHandle()` 配置项:
|
|
95
299
|
|
|
96
|
-
| 字段
|
|
97
|
-
|
|
|
98
|
-
| `auth`
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
300
|
+
| 字段 | 类型 | 说明 |
|
|
301
|
+
| ---------------- | ---------------------------------------- | ------------------------------------------------------------------ |
|
|
302
|
+
| `auth` | `HandleAuthConfig` | 认证配置(verifyToken / protectedPaths / publicPaths / loginUrl) |
|
|
303
|
+
| `trustedProxies` | `TrustedProxies` | 默认 `auto`;普通宿主忽略转发头,受管私有 Compose 代理采用容器网段 |
|
|
304
|
+
| `access` | `RequestAccessConfigInput` | 默认 `false`;按路径、IP 和时间检查每次请求,可引用独立 YAML |
|
|
305
|
+
| `rateLimit` | `object \| false` | 速率限制(windowMs / maxRequests) |
|
|
306
|
+
| `logging` | `boolean \| object` | 请求日志(默认 `true`,`{ logBody: true }` 记录请求体) |
|
|
307
|
+
| `crypto` | `HookCryptoConfig` | 传输加密 + Cookie 加密 |
|
|
308
|
+
| `guards` | `GuardConfig[]` | 自定义守卫(在 auth 自动守卫之后执行) |
|
|
309
|
+
| `middleware` | `Middleware[]` | 自定义中间件(在内置中间件之后执行) |
|
|
310
|
+
| `a2a` | `HandleA2AOperations \| HandleA2AConfig` | A2A 协议集成(Agent Card + JSON-RPC) |
|
|
311
|
+
| `onError` | `function` | 自定义错误处理 |
|
|
312
|
+
|
|
313
|
+
请求/响应摘要使用 `trace` 日志级别;`logging` 默认开启,`logBody` 默认关闭。日志查询从原始 `request.url` 读取,路径保留 SvelteKit 当前路由的 `event.url.pathname`,不会读取预渲染受限的 `event.url.search/searchParams`;静态页无需为构建关闭日志。查询和启用后的 JSON 正文在日志入口对 password/token/secret、授权/API Key 等字段脱敏,正文使用请求副本读取,不影响业务处理。
|
|
106
314
|
|
|
107
|
-
|
|
315
|
+
请求自动审计仅在 `audit.isInitialized` 时执行,纯静态站点或未选 Audit 的应用无需为 handle 初始化它。该状态在每个请求中判断,因此 handle 可先创建、模块随后初始化。选择了 Audit 的应用仍必须检查 `audit.init()` 结果并在失败时停止启动;业务显式 `audit.log/capture` 的未初始化错误不变,已初始化模块的真实写入失败仍记录 `Request audit failed`。需要强制审计的业务应检查显式审计结果,并按业务事务约束提交。
|
|
316
|
+
|
|
317
|
+
配置 `crypto.encryptedCookies` 时必须同时提供 `crypto.cookieEncryptionKey`,或设置 `HAI_KIT_COOKIE_KEY`。缺少密钥会在 `createHandle()` 时立即报错;受保护 Cookie 的明文、损坏密文或解密失败都按不存在处理,加密失败也不会回退写入明文。
|
|
318
|
+
|
|
319
|
+
认证 Cookie 的 `Secure` 默认值在 `NODE_ENV` 或 `HAI_CORE_ENV` 为 `production` 时开启,`HAI_E2E` / `HAI_E2E_MOCK` 不降低 Cookie 安全要求。生产限流同样识别这两个环境标志;仅显式测试开关可放宽内存计数器限制。
|
|
320
|
+
|
|
321
|
+
### 导出路径
|
|
322
|
+
|
|
323
|
+
子模块运行时方法通过 `kit` 命名空间或明确子路径使用,类型单独导出;浏览器声明不暴露服务端工厂。Vite 配置使用 `@sveltejs/kit/vite`,不存在 `@h-ai/kit/vite` 插件。
|
|
324
|
+
|
|
325
|
+
- `@h-ai/kit`:主入口,提供 `kit` 命名空间与类型。
|
|
326
|
+
- `@h-ai/kit/client`:浏览器端客户端。
|
|
327
|
+
- `@h-ai/kit/adapter`:双构建 adapter(`createAdapter()`)。
|
|
328
|
+
- `@h-ai/kit/a2a`:A2A 协议集成。
|
|
329
|
+
- `@h-ai/kit/crypto`:加密模块集成。
|
|
330
|
+
|
|
331
|
+
### 配置驱动认证页面
|
|
332
|
+
|
|
333
|
+
密码登录只提交 `identifier` 和 `password`;`AuthPanel` 将 `LoginForm` 的 `username` 映射为 `identifier`。会话有效期由服务端 `session.maxAge` / `session.refreshTokenMaxAge` 配置决定,登录表单不提供按次登录的持久会话选项。
|
|
334
|
+
|
|
335
|
+
协议支持配置中的 userAgreementMarkdown/privacyPolicyMarkdown 正文及 URL;同主题优先 Markdown,由安全渲染器在弹窗显示。
|
|
336
|
+
|
|
337
|
+
路由直接导出 `kit.auth.createApi(iam)` 的 login、loginWithOtp、loginWithLdap、register、publicConfig、sendOtp、requestPasswordReset、confirmPasswordReset handler;自动执行 schema 验证、Cookie 设置和 HaiResult 映射。匿名白名单使用 `kit.auth.publicPaths`,不会放开 /me 和改密端点。浏览器用 `kit.client.createAuthActions({ apiFetch })` 直接连接 AuthPanel,复用 CSRF/transport。
|
|
338
|
+
|
|
339
|
+
[完整 IAM 配置 / IAM configuration](../iam/README.md)
|
|
340
|
+
|
|
341
|
+
`kit.auth.logout(cookies, accessToken)` 返回 `Promise<HaiResult<void>>`。无令牌时仅清除 Cookie 并成功;有令牌但未配置认证操作时返回失败。无论服务端结果如何都清除本地 Cookie,调用方仍必须把失败转换为错误响应或提示;仅成功结果代表服务端撤销已经确认。底层控制流异常继续传播。
|
|
342
|
+
|
|
343
|
+
### 错误处理
|
|
108
344
|
|
|
109
345
|
- 推荐使用 `kit.handler()` 包装 API 端点。
|
|
110
|
-
- `kit.validate.body` / `kit.guard.require`
|
|
346
|
+
- `kit.validate.body` / `kit.guard.require` 抛出 `Response`,由 `kit.handler` 处理 API 控制流。页面 `load` 使用 `kit.guard.check` 和 SvelteKit `error`;校验查询参数用 `schema.safeParse` 后返回原生页面错误,不能直接抛 API Response。
|
|
111
347
|
- 非控制流异常会由 `kit.handler()` 统一转换为 `500 INTERNAL_ERROR` 响应。
|
|
112
348
|
|
|
113
|
-
|
|
349
|
+
### CRUD fields
|
|
350
|
+
|
|
351
|
+
声明式 CRUD 字段支持 `colSpan: 'auto' | 1 | 2`,供 UI 双列表单决定字段宽度;`validation.message` 支持字符串或 `() => string`,便于随当前语言显示校验错误。UI 布局在 `CrudPage.form` 上配置,服务端仍须独立校验。
|
|
352
|
+
|
|
353
|
+
### 请求语言隔离
|
|
354
|
+
|
|
355
|
+
Node 请求与 SSR 使用 `core.i18n.runWithLocale(locale, () => handleRequest())`;SvelteKit 可使用 `kit.i18n.runWithLocale(locale, () => resolve(event))`,serv 自动按请求头建立上下文。异步子任务继承请求语言,优先级为显式 `MessageOptions.locale`、请求语言、进程启动默认语言。`setGlobalLocale` 在请求上下文中只更新当前请求;上下文外仅用于启动默认值,不能在请求 hook 中调用它修改默认值。
|
|
356
|
+
|
|
357
|
+
浏览器继续使用应用级 `setGlobalLocale` / `createLocaleStore`。SSR 的 UI store 初始化和 setter 只修改自身状态,不写全局语言;UI 消息从请求上下文读取。`runWithLocale` 仅支持 Node 入口,浏览器通过显式 locale 或应用状态翻译。
|
|
358
|
+
|
|
359
|
+
## 反馈接口与普通请求关联
|
|
360
|
+
|
|
361
|
+
`kit.createFeedbackHandler` 可作为 `/api/feedback/[...path]/+server.ts` 的 GET/POST/PATCH handler,复用 api-contract schema,与 serv 使用同一数据契约;输入流受大小上限约束,客户端身份/租户字段被拒绝。宿主通过 resolveContext 从已经验证的 locals.session 映射范围和权限,null 拒绝访问,并保留现有 createHandle 的 CSRF、认证与传输加密。
|
|
362
|
+
|
|
363
|
+
createHandle 保留有效且有界的入站 X-Request-Id,补写响应头,并为异步业务传递请求 ID 和已验证用户。需要收集普通业务后端日志时,在宿主 middleware 中以 `core.context.run({ scopeId: 'configured-product' }, next)` 包住实际业务;该可信范围应与反馈接口一致,不能从客户端头推导。
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
import type { SessionData } from '@h-ai/kit'
|
|
367
|
+
import { feedback } from '@h-ai/feedback'
|
|
368
|
+
import { kit } from '@h-ai/kit'
|
|
369
|
+
|
|
370
|
+
const handler = kit.createFeedbackHandler({
|
|
371
|
+
feedback,
|
|
372
|
+
resolveContext: (event) => {
|
|
373
|
+
const session = (event.locals as { session?: SessionData }).session
|
|
374
|
+
return session
|
|
375
|
+
? { scopeId: 'configured-product', userId: session.userId, permissions: session.permissions }
|
|
376
|
+
: null
|
|
377
|
+
},
|
|
378
|
+
})
|
|
379
|
+
export const GET = handler
|
|
380
|
+
export const POST = handler
|
|
381
|
+
export const PATCH = handler
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## 错误提示与关联日志
|
|
385
|
+
|
|
386
|
+
HTTP 错误返回本地化安全文案及追踪编号;ToastContainer 默认隐藏编号,由排查信息图标展开和复制。响应同时包含 `error.traceId` 和 `X-Trace-Id`。框架复用本次 requestId 作为 traceId,前后端日志自动关联。底层异常、堆栈和操作上下文经凭据脱敏后写入日志,不通过 cause/ext 向用户公开。字段校验只返回本地化的字段名和错误。
|
|
387
|
+
|
|
388
|
+
`core.error.toPublic(error, traceId?)` 用于接口/UI 边界;`core.error.formatMessage(error)` 用于重新翻译后的提示,重复调用不会重复追加标识。日志传入完整 Error 对象,不能只记录通用标题或提前 String(error) 丢失上下文。数据库失败记录驱动错误码、消息、堆栈及表/列;SQL 原文、绑定值和连接凭据不进入日志。
|
|
389
|
+
|
|
390
|
+
audit 已初始化时,createHandle 为业务 audit.log 绑定已验证会话的身份/角色快照、平台 getClientAddress 地址和请求编号。自动入口事件 request.execute 包含路由模板、方法、状态和成功/失败/拒绝,包含守卫跳转及 SvelteKit HTTP 控制流;不复制请求体或错误详情。capture.enabled 可关闭自动采集,capture.includeReads 可开启成功读取;默认保留失败读取、跳过成功读取。业务含义仍在应用完成/失败边界显式记录,关闭自动采集不影响业务 log。
|
|
391
|
+
|
|
392
|
+
## 可选交互挑战
|
|
393
|
+
|
|
394
|
+
将 kit.auth.createApi(iam).createCaptcha 导出为 POST /api/auth/captcha;kit.auth.publicPaths 已包含它。kit.client.createAuthActions() 保留标准交互请求的 captcha 字段,并提供 createCaptcha;AuthPanel 提交时自动求解。匿名首次/过期改密仍须导出 /api/auth/password/renew。服务端 IAM 检查证明,开启策略不会只依赖界面。
|
|
395
|
+
|
|
396
|
+
策略、默认值和恢复边界见 [IAM](../iam/README.md)。
|
|
397
|
+
|
|
398
|
+
## 原地恢复过期会话
|
|
399
|
+
|
|
400
|
+
配置 `kit.client.create({ recoverSession })` 回调可在服务端明确拒绝会话时原地重新登录并保留页面输入。使用 `@h-ai/ui` 的 `createSessionRecovery` / `SessionRecoveryDialog`:根布局绑定公开配置与原用户,回调设为 `recovery.recover`,弹窗使用标准认证 actions,销毁时 `cancel()`。登录的 `expectedUserId` 由 IAM 限定原主体;常规验证码、锁定、改密和登录限制照常执行。只对明确未认证拒绝的原请求续接一次;取消、5xx、超时和结果不明的网络写入不重放。敏感操作证明绑定旧会话时可能需要再次确认,不复用到新会话。标准认证动作显式禁用自身的恢复重试,避免错误密码递归打开弹窗。自定义认证请求应传第三个参数 `{ recoverSession: false }`。终端分组通过 terminalType(web/app/desktop/api,默认 web)传入;它不是硬件身份认证。
|
|
401
|
+
|
|
402
|
+
## 页面离开会话策略
|
|
403
|
+
|
|
404
|
+
`session.endOnPageHide` 默认 `false`。启用后宿主调用 `actions.bindPageExit({ enabled: config.session.endOnPageHide })` 并在卸载时调用返回的清理函数;标准 admin/H5/fullstack 模板已经接入。非 BFCache 的 `pagehide`(也包括刷新、整页导航)通过 POST `/auth/session/close` 尽力撤销当前 access 及关联 refresh,沿用 CSRF/传输加密,使用 `keepalive` 且不自动刷新会话。该响应不清 Cookie/本地凭据,避免旧响应覆盖下一次登录。显式退出仍使用正常 logout,可靠撤销并清理当前凭据。浏览器可能不发送页面离开请求,因此必须按业务配合服务端 `idleTimeout`/`absoluteTimeout`;不能据此保证关闭即撤销。
|
|
405
|
+
|
|
406
|
+
## 传输容量与模块预算
|
|
407
|
+
|
|
408
|
+
配置 `transport.maxPlaintextBytes` 支持 1 KiB~64 MiB 的显式整数或 `auto`。auto/省略在解析后为 undefined:无模块需求时仍为 1 MiB,反馈宿主使用 crypto.resolveTransportBodyLimits 的 requiredPlaintextBytes 统一推导。显式上限不足时启动/打包失败,不能被反馈覆盖;代理、adapter-node、握手与运行时使用一致预算。业务附件、解压和数据行数上限继续独立校验。
|
|
409
|
+
|
|
410
|
+
敏感调用通过本次 `reauthorize: () => sensitiveActions.authorize(operation)` 重新确认用途:Kit 放 apiFetch 第三参数,typed client 放 options.context。会话刷新/恢复或明确的再认证拒绝后仅续发一次;取消不写入,未提供回调不重放旧证明。
|
|
411
|
+
|
|
412
|
+
## 每次请求的访问控制
|
|
413
|
+
|
|
414
|
+
路径规则的 `encryption` 可选 required / disabled,省略沿用宿主。disabled 不解密请求或加密响应,仍执行访问和身份检查;不接受框架传输信封。required 可保护自定义 JSON 端点并优先于 `excludePaths`,没有 Crypto、密钥环和 registry 时不能启用。模式冲突在创建 Handle 时拒绝。CLI 的 crypto 模板同步装配服务端和浏览器,生产选择 db 和共享数据库;策略及代理配置不下发浏览器,明文调用方按公开传输排除路径选择协议。
|
|
415
|
+
|
|
416
|
+
将服务端 `_kit.yml` 的 `trustedProxies` 和 `access` 显式传给 `kit.createHandle`。示例和生成模板在应用初始化后只创建一次 Handle。`access` 默认为 `false`;内联 `{ rules: [{ id: 'external', paths: ['/api/v1/external/**'], allowIps: ['192.0.2.0/24'] }] }` 只限制匹配接口,`global` 则限制宿主处理的全部请求。实际路径包含部署前缀;静态服务器直接返回的资源不经过 Handle。
|
|
417
|
+
|
|
418
|
+
独立文件使用 `access: { file: './config/security/request-access.yml' }`,按工作目录解析,启动读取一次,最大 1 MiB,修改后重建 Handle。全局与所有匹配规则取交集,空列表不限对应维度,时区默认 UTC。时间窗口结束后,已有会话的后续请求同样被拒绝。预检和密钥交换也执行策略;普通 transport 请求的 HTTP 403 / `hai:common:104` 保留响应加密。
|
|
419
|
+
|
|
420
|
+
`trustedProxies: auto` 在普通宿主不信任转发头;受管 Compose 只有后端私有且存在入口代理时才采用容器网段。自管入口显式指定代理 IP/CIDR,`[]` 可关闭。解析后的 `event.getClientAddress()` 与策略、IAM、审计使用相同地址。外层代理、不可恢复的源地址丢失、环境变量与部署回滚见[请求访问控制手册](../../docs/usage/configuration/request-access.md)。
|
|
421
|
+
|
|
422
|
+
## 开发测试
|
|
114
423
|
|
|
115
424
|
```bash
|
|
116
425
|
pnpm --filter @h-ai/kit test
|
|
117
426
|
```
|
|
118
427
|
|
|
119
|
-
|
|
428
|
+
模块无统一 init/close;共享缓存、IAM 与 crypto 由应用启动时初始化并统一关闭。示例使用真实公开入口并作类型检查,见[模块 JSDoc 约定](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证)。请求认证必须调用 iam.auth.verifyToken,不能把非空 token 视为有效身份。
|
|
429
|
+
|
|
430
|
+
## 许可证
|
|
120
431
|
|
|
121
432
|
Apache-2.0
|
package/dist/adapter/index.d.ts
CHANGED
|
@@ -13,14 +13,22 @@ import * as _sveltejs_kit from '@sveltejs/kit';
|
|
|
13
13
|
*
|
|
14
14
|
* export default {
|
|
15
15
|
* kit: {
|
|
16
|
-
* adapter: createAdapter(),
|
|
16
|
+
* adapter: await createAdapter(),
|
|
17
17
|
* },
|
|
18
18
|
* }
|
|
19
19
|
* ```
|
|
20
20
|
*
|
|
21
21
|
* @module kit-adapter
|
|
22
22
|
*/
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* 双构建适配器配置
|
|
25
|
+
* @example 模块内部上下文
|
|
26
|
+
* ```ts
|
|
27
|
+
* const options: AdapterOptions = {}
|
|
28
|
+
* const adapter = await createAdapter(options)
|
|
29
|
+
* void adapter
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
24
32
|
interface AdapterOptions {
|
|
25
33
|
/** adapter-node 输出目录,默认 `'build'` */
|
|
26
34
|
nodeBuildDir?: string;
|
|
@@ -38,6 +46,13 @@ interface AdapterOptions {
|
|
|
38
46
|
*
|
|
39
47
|
* **注意**:adapter-node / adapter-static 仍然需要在应用的 devDependencies 中声明。
|
|
40
48
|
* 本函数只做动态 import + 统一配置。
|
|
49
|
+
* @param options - Node/static 输出目录和 SPA fallback;应用仍需安装对应适配器。
|
|
50
|
+
* @returns 按 VITE_ADAPTER 选择的 SvelteKit adapter;缺失依赖时拒绝 Promise。
|
|
51
|
+
* @example 模块内部上下文
|
|
52
|
+
* ```ts
|
|
53
|
+
* const adapter = await createAdapter({})
|
|
54
|
+
* void adapter
|
|
55
|
+
* ```
|
|
41
56
|
*/
|
|
42
57
|
declare function createAdapter(options?: AdapterOptions): Promise<_sveltejs_kit.Adapter>;
|
|
43
58
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/kit-adapter.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../../src/kit-adapter.ts"],"names":[],"mappings":";;;AA0DA,eAAsB,cAAc,OAAA,EAA0B;AAC5D,EAAA,MAAM;AAAA,IACJ,YAAA,GAAe,OAAA;AAAA,IACf,cAAA,GAAiB,cAAA;AAAA,IACjB,cAAA,GAAiB;AAAA,GACnB,GAAI,WAAW,EAAC;AAEhB,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,GAAA,CAAI,YAAA,IAAgB,MAAA;AAEzC,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,MAAM,EAAE,OAAA,EAAS,aAAA,EAAc,GAAI,MAAM,OAAO,0BAA0B,CAAA;AAC1E,IAAA,OAAO,aAAA,CAAc;AAAA,MACnB,KAAA,EAAO,cAAA;AAAA,MACP,MAAA,EAAQ,cAAA;AAAA,MACR,QAAA,EAAU,cAAA;AAAA,MACV,WAAA,EAAa;AAAA,KACd,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,EAAE,OAAA,EAAS,WAAA,EAAY,GAAI,MAAM,OAAO,wBAAwB,CAAA;AACtE,EAAA,OAAO,WAAA,CAAY;AAAA,IACjB,GAAA,EAAK;AAAA,GACN,CAAA;AACH","file":"index.js","sourcesContent":["/**\n * SvelteKit 双构建模式 — 适配器工厂\n *\n * 根据 `VITE_ADAPTER` 环境变量自动选择 adapter-node 或 adapter-static,\n * 使同一个 SvelteKit 应用能同时产出 SSR(Web + API)和 SPA(H5/App)两种构建产物。\n *\n * @example\n * ```js\n * // svelte.config.js\n * import { createAdapter } from '@h-ai/kit/adapter'\n *\n * export default {\n * kit: {\n * adapter: await createAdapter(),\n * },\n * }\n * ```\n *\n * @module kit-adapter\n */\n\nimport process from 'node:process'\n\n/**\n * 双构建适配器配置\n * @example 模块内部上下文\n * ```ts\n * const options: AdapterOptions = {}\n * const adapter = await createAdapter(options)\n * void adapter\n * ```\n */\nexport interface AdapterOptions {\n /** adapter-node 输出目录,默认 `'build'` */\n nodeBuildDir?: string\n /** adapter-static 输出目录,默认 `'build-static'` */\n staticBuildDir?: string\n /** adapter-static 的 SPA fallback 页面,默认 `'index.html'` */\n staticFallback?: string\n}\n\n/**\n * 根据环境变量 `VITE_ADAPTER` 选择 SvelteKit adapter\n *\n * - `VITE_ADAPTER=node` → `@sveltejs/adapter-node`(SSR + API)\n * - `VITE_ADAPTER=static` → `@sveltejs/adapter-static`(SPA,可被 Capacitor 包装)\n * - 未设置时默认使用 `node`\n *\n * **注意**:adapter-node / adapter-static 仍然需要在应用的 devDependencies 中声明。\n * 本函数只做动态 import + 统一配置。\n * @param options - Node/static 输出目录和 SPA fallback;应用仍需安装对应适配器。\n * @returns 按 VITE_ADAPTER 选择的 SvelteKit adapter;缺失依赖时拒绝 Promise。\n * @example 模块内部上下文\n * ```ts\n * const adapter = await createAdapter({})\n * void adapter\n * ```\n */\nexport async function createAdapter(options?: AdapterOptions) {\n const {\n nodeBuildDir = 'build',\n staticBuildDir = 'build-static',\n staticFallback = 'index.html',\n } = options ?? {}\n\n const mode = process.env.VITE_ADAPTER ?? 'node'\n\n if (mode === 'static') {\n const { default: adapterStatic } = await import('@sveltejs/adapter-static')\n return adapterStatic({\n pages: staticBuildDir,\n assets: staticBuildDir,\n fallback: staticFallback,\n precompress: false,\n })\n }\n\n // 默认 node\n const { default: adapterNode } = await import('@sveltejs/adapter-node')\n return adapterNode({\n out: nodeBuildDir,\n })\n}\n"]}
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { c as createKitClient,
|
|
2
|
-
export { C as ClientTransportConfig, K as KitClient, e as KitClientConfig } from './
|
|
3
|
-
import { d as defineCrud, s as setAllModulesLocale } from './kit-i18n-
|
|
4
|
-
export {
|
|
1
|
+
import { c as createKitClient, a as createKitAuthActions, i as installBrowserTransport, b as installBrowserTransportFetch, s as setBrowserToken, d as clearBrowserToken } from './kit-client-auth-BnhrkzZF.js';
|
|
2
|
+
export { C as ClientTransportConfig, K as KitClient, e as KitClientConfig } from './kit-client-auth-BnhrkzZF.js';
|
|
3
|
+
import { d as defineCrud, s as setAllModulesLocale } from './kit-i18n-EBzZKYN-.js';
|
|
4
|
+
export { K as KitConfigSchema, r as resolveKitConfig, a as resolveKitTransportConfig } from './kit-i18n-EBzZKYN-.js';
|
|
5
|
+
export { A as ApiResponse, a as AuthOperations, b as AuthOperationsProvider, C as CorsConfig, F as FormError, c as FormValidationResult, G as GuardConfig, d as GuardResult, H as HaiRequestEvent, e as HandleA2AConfig, f as HandleA2AOperations, g as HandleAuthConfig, h as HandleConfig, i as HookCryptoConfig, K as KitConfig, j as KitConfigInput, k as KitPublicConfig, l as KitServerConfig, m as KitServerConfigInput, n as KitTransportConfig, o as KitTransportConfigInput, M as Middleware, p as MiddlewareContext, R as RateLimitConfig, q as RouteGuard, S as SessionData, r as SessionLike, T as TransportEncryptionOptions } from './kit-types-BkNdyKj8.js';
|
|
6
|
+
import '@h-ai/api-contract';
|
|
5
7
|
import '@h-ai/core';
|
|
8
|
+
import '@h-ai/crypto';
|
|
6
9
|
import '@h-ai/iam';
|
|
10
|
+
import 'zod';
|
|
7
11
|
import '@sveltejs/kit';
|
|
8
|
-
import './kit-crypto-types-C-gEvx04.js';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* @h-ai/kit — 浏览器入口
|
|
@@ -16,10 +19,20 @@ import './kit-crypto-types-C-gEvx04.js';
|
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* 浏览器端 kit 对象(仅暴露 client-safe 能力)
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { kit } from '@h-ai/kit'
|
|
25
|
+
*
|
|
26
|
+
* const client = kit.client.create({ auth: true })
|
|
27
|
+
* client.destroy()
|
|
28
|
+
* ```
|
|
19
29
|
*/
|
|
20
30
|
declare const kit: {
|
|
21
31
|
client: {
|
|
22
32
|
create: typeof createKitClient;
|
|
33
|
+
createAuthActions: typeof createKitAuthActions;
|
|
34
|
+
installBrowserTransport: typeof installBrowserTransport;
|
|
35
|
+
installBrowserTransportFetch: typeof installBrowserTransportFetch;
|
|
23
36
|
};
|
|
24
37
|
crud: {
|
|
25
38
|
define: typeof defineCrud;
|
|
@@ -27,12 +40,10 @@ declare const kit: {
|
|
|
27
40
|
auth: {
|
|
28
41
|
setBrowserToken: typeof setBrowserToken;
|
|
29
42
|
clearBrowserToken: typeof clearBrowserToken;
|
|
30
|
-
createTokenStore: typeof createTokenStore;
|
|
31
|
-
createHandleFetch: typeof createHandleFetch;
|
|
32
43
|
};
|
|
33
44
|
i18n: {
|
|
34
45
|
setLocale: typeof setAllModulesLocale;
|
|
35
46
|
};
|
|
36
47
|
};
|
|
37
48
|
|
|
38
|
-
export {
|
|
49
|
+
export { kit };
|
package/dist/browser.js
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
import { defineCrud } from './chunk-
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import { defineCrud } from './chunk-5VWPH7DO.js';
|
|
2
|
+
export { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig } from './chunk-5VWPH7DO.js';
|
|
3
|
+
import { clearBrowserToken, setBrowserToken, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient } from './chunk-YKJRQCWR.js';
|
|
4
|
+
import './chunk-JRQPMPQC.js';
|
|
5
|
+
import { setAllModulesLocale } from './chunk-USFJN7IO.js';
|
|
4
6
|
|
|
5
7
|
// src/browser.ts
|
|
6
8
|
var kit = {
|
|
7
9
|
client: {
|
|
8
|
-
create: createKitClient
|
|
10
|
+
create: createKitClient,
|
|
11
|
+
createAuthActions: createKitAuthActions,
|
|
12
|
+
installBrowserTransport,
|
|
13
|
+
installBrowserTransportFetch
|
|
9
14
|
},
|
|
10
15
|
crud: {
|
|
11
16
|
define: defineCrud
|
|
12
17
|
},
|
|
13
18
|
auth: {
|
|
14
19
|
setBrowserToken,
|
|
15
|
-
clearBrowserToken
|
|
16
|
-
createTokenStore,
|
|
17
|
-
createHandleFetch
|
|
20
|
+
clearBrowserToken
|
|
18
21
|
},
|
|
19
22
|
i18n: {
|
|
20
23
|
setLocale: setAllModulesLocale
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/browser.ts"],"names":[],"mappings":";;;;;;;AAwBO,IAAM,GAAA,GAAM;AAAA,EACjB,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ,eAAA;AAAA,IACR,iBAAA,EAAmB,oBAAA;AAAA,IACnB,uBAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,eAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,SAAA,EAAW;AAAA;AAEf","file":"browser.js","sourcesContent":["/**\n * @h-ai/kit — 浏览器入口\n *\n * 为客户端提供精简且安全的运行时导出,避免将服务端 Hook/A2A/IAM 运行时代码打入浏览器包。\n * @module browser\n */\n\nimport { createKitAuthActions } from './client/kit-client-auth.js'\nimport { createKitClient, installBrowserTransport, installBrowserTransportFetch } from './client/kit-client.js'\nimport { defineCrud } from './crud/kit-crud.js'\nimport { clearBrowserToken, setBrowserToken } from './kit-auth.js'\nimport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig } from './kit-config.js'\nimport { setAllModulesLocale } from './kit-i18n.js'\n\n/**\n * 浏览器端 kit 对象(仅暴露 client-safe 能力)\n * @example\n * ```ts\n * import { kit } from '@h-ai/kit'\n *\n * const client = kit.client.create({ auth: true })\n * client.destroy()\n * ```\n */\nexport const kit = {\n client: {\n create: createKitClient,\n createAuthActions: createKitAuthActions,\n installBrowserTransport,\n installBrowserTransportFetch,\n },\n crud: {\n define: defineCrud,\n },\n auth: {\n setBrowserToken,\n clearBrowserToken,\n },\n i18n: {\n setLocale: setAllModulesLocale,\n },\n}\n\nexport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig }\n\nexport type {\n ClientTransportConfig,\n KitClient,\n KitClientConfig,\n} from './client/index.js'\nexport type {\n ApiResponse,\n AuthOperations,\n AuthOperationsProvider,\n CorsConfig,\n FormError,\n FormValidationResult,\n GuardConfig,\n GuardResult,\n HaiRequestEvent,\n HandleA2AConfig,\n HandleA2AOperations,\n HandleAuthConfig,\n HandleConfig,\n HookCryptoConfig,\n KitConfig,\n KitConfigInput,\n KitPublicConfig,\n KitServerConfig,\n KitServerConfigInput,\n KitTransportConfig,\n KitTransportConfigInput,\n Middleware,\n MiddlewareContext,\n RateLimitConfig,\n RouteGuard,\n SessionData,\n SessionLike,\n TransportEncryptionOptions,\n} from './kit-types.js'\n"]}
|