@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.
Files changed (44) hide show
  1. package/README.en.md +80 -46
  2. package/README.ja.md +72 -40
  3. package/README.md +73 -41
  4. package/dist/adapter/index.d.ts +17 -2
  5. package/dist/adapter/index.js.map +1 -1
  6. package/dist/browser.d.ts +12 -6
  7. package/dist/browser.js +6 -7
  8. package/dist/browser.js.map +1 -1
  9. package/dist/{chunk-DVW7CQ3H.js → chunk-2PWGJCWX.js} +3 -3
  10. package/dist/chunk-2PWGJCWX.js.map +1 -0
  11. package/dist/{chunk-VOTDAVCB.js → chunk-2YYRP7HH.js} +17 -33
  12. package/dist/chunk-2YYRP7HH.js.map +1 -0
  13. package/dist/{chunk-MLSP67JF.js → chunk-333FGMGQ.js} +59 -111
  14. package/dist/chunk-333FGMGQ.js.map +1 -0
  15. package/dist/chunk-OVRZIDCD.js +175 -0
  16. package/dist/chunk-OVRZIDCD.js.map +1 -0
  17. package/dist/{chunk-L7BTMAKX.js → chunk-P6XH7G4N.js} +3 -6
  18. package/dist/chunk-P6XH7G4N.js.map +1 -0
  19. package/dist/{chunk-NVYIUBU7.js → chunk-XC7I2L3G.js} +2 -2
  20. package/dist/chunk-XC7I2L3G.js.map +1 -0
  21. package/dist/client/index.d.ts +47 -1
  22. package/dist/client/index.js +3 -3
  23. package/dist/client/index.js.map +1 -1
  24. package/dist/index.d.ts +217 -347
  25. package/dist/index.js +138 -83
  26. package/dist/index.js.map +1 -1
  27. package/dist/kit-a2a-types-CwT1AFQu.d.ts +136 -0
  28. package/dist/{index-B7s-0mZl.d.ts → kit-client-auth-HnZIYUia.d.ts} +220 -101
  29. package/dist/kit-crypto-types-Dd24aJ4m.d.ts +194 -0
  30. package/dist/{kit-i18n-D9Qqk-1k.d.ts → kit-i18n-DEzmzE5T.d.ts} +142 -29
  31. package/dist/{kit-types-ByWdbCeO.d.ts → kit-types-CnzhN-AS.d.ts} +240 -162
  32. package/dist/modules/a2a/index.d.ts +13 -111
  33. package/dist/modules/a2a/index.js +2 -2
  34. package/dist/modules/crypto/index.d.ts +28 -195
  35. package/dist/modules/crypto/index.js +3 -3
  36. package/dist/modules/crypto/index.js.map +1 -1
  37. package/package.json +10 -10
  38. package/dist/chunk-DVW7CQ3H.js.map +0 -1
  39. package/dist/chunk-L7BTMAKX.js.map +0 -1
  40. package/dist/chunk-MLSP67JF.js.map +0 -1
  41. package/dist/chunk-NVYIUBU7.js.map +0 -1
  42. package/dist/chunk-QHYNL24G.js +0 -117
  43. package/dist/chunk-QHYNL24G.js.map +0 -1
  44. package/dist/chunk-VOTDAVCB.js.map +0 -1
package/README.en.md CHANGED
@@ -4,23 +4,11 @@
4
4
 
5
5
  [Framework home](../../README.en.md) · Related modules: [@h-ai/core](../core/README.en.md) · [@h-ai/crypto](../crypto/README.en.md) · [@h-ai/iam](../iam/README.en.md)
6
6
 
7
- `@h-ai/kit` integrates SvelteKit with hai-framework, providing a shared request pipeline and same-origin endpoint utilities:
8
-
9
- - `kit.createHandle()`: session parsing, route guards, middleware chains, and optional transport/cookie encryption.
10
- - `kit.handler()`: an exception boundary for API endpoints.
11
- - `kit.guard` / `kit.response` / `kit.validate` / `kit.auth` / `kit.client` / `kit.crud`
12
-
13
- > Shared cross-platform HTTP contracts belong in `@h-ai/api-contract`, are mounted by `@h-ai/serv`, and are called through the `@h-ai/api-client` typed client. `@h-ai/kit` does not define or host business API contracts.
14
-
15
- ## Installation
7
+ ## Introduction
16
8
 
17
- ```bash
18
- npm install @h-ai/kit
19
- npm install svelte @sveltejs/kit zod
20
- npm install -D @sveltejs/vite-plugin-svelte vite
21
- ```
9
+ `@h-ai/kit` integrates SvelteKit with hai-framework, providing a shared request pipeline and same-origin endpoint utilities:
22
10
 
23
- ## Capabilities
11
+ ## Core features
24
12
 
25
13
  - Handle hook composition (`createHandle` / `sequence`)
26
14
  - Authentication/role/permission guards (`guard.require` / `guard.check`)
@@ -32,14 +20,26 @@ npm install -D @sveltejs/vite-plugin-svelte vite
32
20
  - A2A integration: discovery defaults to `/.well-known/agent-card.json`. With `authenticate` configured, null/undefined returns 401; anonymous access is allowed only without authentication configured. API Key parameters come from the complete Agent Card's `securitySchemes.apiKey`. Hooks and explicit A2A routes share JSON-RPC parse-error and SSE cancellation cleanup logic.
33
21
  - Dual build mode (`createAdapter()`)
34
22
 
35
- ## Dependencies
23
+ ## Getting started
24
+
25
+ `sequence` preserves SvelteKit resolve options: page transformations run from inner to outer, while the first preload and serialized-header filter win. This preserves the i18n HTML language replacement.
26
+
27
+ ### Installation
28
+
29
+ ```bash
30
+ npm install @h-ai/kit @h-ai/core sm-crypto@0.5.7
31
+ npm install svelte @sveltejs/kit zod
32
+ npm install -D @sveltejs/vite-plugin-svelte vite
33
+ ```
34
+
35
+ ### Dependencies
36
36
 
37
37
  - `@h-ai/iam`: optional authentication/authorization for A2A; initialize before using kit's A2A features.
38
38
  - `@h-ai/crypto`: optional transport/cookie encryption; initialize before using encryption in kit.
39
39
 
40
- ## Quick start
40
+ ### Quick start
41
41
 
42
- ### Project configuration
42
+ #### Project configuration
43
43
 
44
44
  **svelte.config.js**:
45
45
 
@@ -53,7 +53,7 @@ const config = {
53
53
  kit: {
54
54
  adapter: adapter(),
55
55
  // 双构建模式:import { createAdapter } from '@h-ai/kit/adapter'
56
- // adapter: createAdapter(),
56
+ // adapter: await createAdapter(),
57
57
  },
58
58
  }
59
59
 
@@ -70,35 +70,41 @@ import { defineConfig } from 'vite'
70
70
  export default defineConfig({
71
71
  plugins: [sveltekit(), tailwindcss()],
72
72
  optimizeDeps: { exclude: ['bits-ui'] },
73
- ssr: { noExternal: [/@h-ai\//] },
73
+ ssr: { noExternal: ['@h-ai/ui', '@h-ai/kit'], external: ['@h-ai/core', 'sm-crypto'] },
74
74
  })
75
75
  ```
76
76
 
77
- ### Build the request pipeline
77
+ When using Crypto or Kit/IAM, include `sm-crypto@0.5.7` in application production dependencies. CLI projects already do this; for manual setup, run `pnpm add sm-crypto@0.5.7`. The external option alone is insufficient: adapter-node also uses direct production dependencies to preserve native package loading.
78
+
79
+ #### Build the request pipeline
78
80
 
79
81
  **src/hooks.server.ts**:
80
82
 
81
83
  ```typescript
82
84
  import type { Handle } from '@sveltejs/kit'
85
+ import { cache } from '@h-ai/cache'
83
86
  import { kit } from '@h-ai/kit'
84
87
 
85
88
  const haiHandle = kit.createHandle({
86
89
  auth: {
87
90
  verifyToken: async (token) => {
88
- return token ? { userId: 'u_1', roles: ['admin'], permissions: ['user:read'] } : null
91
+ const verified = await iam.auth.verifyToken(token)
92
+ return verified.success ? verified.data : null
89
93
  },
90
94
  loginUrl: '/auth/login',
91
95
  protectedPaths: ['/admin/*', '/api/*'],
92
96
  publicPaths: ['/api/auth/*', '/api/public/*'],
93
97
  },
94
- rateLimit: { windowMs: 60_000, maxRequests: 100 },
98
+ rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
95
99
  logging: true,
96
100
  })
97
101
 
98
102
  export const handle: Handle = haiHandle
99
103
  ```
100
104
 
101
- ### API endpoints
105
+ Rate limits use fixed windows beginning at the first successful commit; later requests preserve the TTL. A store is required. Initialize shared Redis and check its result before serving; all nodes use the same namespace/windowMs/maxRequests. Cache read/commit failure or exhausted contention returns 503, while exceeding the limit returns 429, without get+set or local fallback. createMemoryRateLimitStore is for development or explicit HAI_E2E/HAI_E2E_MOCK tests; it has no timer and can be garbage collected when released; each request scans at most 64 entries, capacity is 10000 windows, new keys receive 503 at capacity without evicting active counts, and external stores remain owned by their creators. Never enable test flags in production. Reset headers estimate node time; Redis TTL controls the actual window, so synchronize clocks. The default key uses the trusted adapter getClientAddress, normalizes equivalent IPv6/mapped IPv4 addresses and ignores raw forwarded headers; configure proxy trust in the deployment adapter.
106
+
107
+ #### API endpoints
102
108
 
103
109
  ```typescript
104
110
  import { kit } from '@h-ai/kit'
@@ -116,7 +122,7 @@ export const POST = kit.handler(async ({ request, locals }) => {
116
122
  })
117
123
  ```
118
124
 
119
- ### Browser client
125
+ #### Browser client
120
126
 
121
127
  `kit.client.create()` targets SvelteKit same-origin endpoints. Use `@h-ai/api-client` for cross-origin access to public APIs from Web, apps, or mini programs.
122
128
 
@@ -137,20 +143,24 @@ const response = await apiFetch('/api/users', { method: 'GET' })
137
143
 
138
144
  > `apiFetch` injects the CSRF header automatically; `@h-ai/kit` does not expose a separate CSRF middleware factory.
139
145
  >
140
- > Authentication: prefer httpOnly cookies for same-origin SvelteKit endpoints and verify them on the server. Browsers need not write sensitive tokens to `localStorage`. If Bearer headers are required, provide a custom `BrowserTokenStore`, or set an in-memory token with `kit.auth.setBrowserToken()` before `kit.client.create({ auth: true })`.
146
+ > Use httpOnly cookies for same-origin SvelteKit endpoints and verify them on the server. For browser Bearer headers, set an in-memory token with `kit.auth.setBrowserToken()` before `kit.client.create({ auth: true })`. Custom `BrowserTokenStore` implementations must use memory or platform secure storage; never persist sensitive credentials in Web Storage.
141
147
 
142
- ### Same-origin transport encryption
148
+ #### Same-origin transport encryption
143
149
 
144
- kit delegates transport encryption to `@h-ai/crypto`. The server creates a manager with `crypto.transport.createServer()`; the browser installs a same-origin fetch wrapper with one call to `kit.client.installBrowserTransport(kitConfig, { crypto })`. Applications only configure the top-level `crypto` handle.
150
+ kit delegates transport encryption to `@h-ai/crypto`. The server creates a manager with `crypto.transport.createServer({ serverKeyRing, keyStore })`; the browser installs a same-origin fetch wrapper with one call to `kit.client.installBrowserTransport(kitConfig, { crypto })`. Servers must also inject a managed key ring and shared registry.
145
151
 
146
152
  **src/hooks.server.ts**:
147
153
 
148
154
  ```ts
149
155
  import { cache } from '@h-ai/cache'
150
- import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
156
+ import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
151
157
  import { kit } from '@h-ai/kit'
152
158
 
153
159
  await crypto.init()
160
+ const ring = parseTransportServerKeyRing(process.env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING)
161
+ if (!ring.success)
162
+ throw new Error(ring.error.message)
163
+ const serverKeyRing = ring.data
154
164
  await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
155
165
 
156
166
  export const handle = kit.createHandle({
@@ -162,7 +172,7 @@ export const handle = kit.createHandle({
162
172
  crypto: {
163
173
  crypto,
164
174
  transport: {
165
- requireEncryption: true,
175
+ serverKeyRing,
166
176
  keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
167
177
  },
168
178
  },
@@ -197,13 +207,17 @@ export const { apiFetch } = kit.client.create()
197
207
 
198
208
  The default key exchange path is `/api/_hai/key-exchange`. If the server customizes `transport.keyExchangePath`, update the client's `transport.keyExchangeUrl` accordingly.
199
209
 
200
- For shared client public keys across nodes, inject `createRedisTransportKeyStore()` or `createReldbTransportKeyStore()` through `kit.createHandle({ crypto: { transport: { keyStore } } })` at runtime. These object dependencies **must not** go in `_kit.yml`; configuration files contain only public paths and switches.
210
+ Servers must explicitly inject the same managed `serverKeyRing` and a shared `keyStore` (Redis or a shared database). Sharing client public keys alone cannot enable cross-node decryption. There is no implicit process key or memory-registry fallback; development/tests may explicitly use `createInMemoryKeyStore(capacity)`. Reload the same ring after restart; sticky sessions are unnecessary.
201
211
 
202
212
  Transport applies by default to same-origin `/api/*` endpoints, SvelteKit `__data.json` page data, and key exchange itself. Page documents and static assets remain plaintext and do not require `X-Client-Id`. `multipart/form-data` requests such as uploads are sent unchanged; explicitly allow their paths through server `excludePaths`.
203
213
 
204
- Security defaults to fail-closed: with `requireEncryption: true`, protected paths without `X-Client-Id` return 400. An unavailable transport manager, unencryptable response, or encryption size limit returns an error rather than forwarding plaintext business data. `requireEncryption: false` is for staged migration only and is not recommended in production.
214
+ Only authenticated protocol v2 is accepted. Independent random SM4-CBC and HMAC-SM3 keys are wrapped with SM2; verify the sender signature and MAC before CBC decryption. Clients sign requests and the selected server key version signs responses. Authentication covers version, direction, serverKeyId, clientId, a random 128-bit requestId acting as the nonce, issuedAt, HTTP method, the SM3 pathHash of pathname plus the original search, and response status. Requests have a five-minute lifetime and at most 30 seconds of future clock skew. The shared registry atomically consumes (clientId, requestId), retaining it until at least issuedAt plus six minutes to cover node skew; storage failures reject requests. Synchronize node clocks and use a Redis noeviction/durable policy that preserves live nonces. Transport replay prevention does not replace business idempotency keys.
205
215
 
206
- ### Shared transport configuration with `_kit.yml`
216
+ Empty POSTs still send an authenticated envelope for empty plaintext. GET/HEAD carry it in X-Hai-Transport; bodyless responses such as 204/304/HEAD use the same header. Other requests/responses carry a JSON envelope and X-Encrypted: true. The client must match the original request context and HTTP status; missing markers, old formats and authentication failures reject. Exclude plaintext endpoints explicitly with excludePaths. CORS must allow and expose X-Hai-Transport. TLS authenticates handshake keys; this protocol does not replace IAM authorization.
217
+
218
+ Fixed budgets share `@h-ai/crypto`'s `TRANSPORT_BODY_LIMITS` with serv and the client: 16 KiB key exchange JSON, 4 KiB per public key, 1 MiB plaintext, and 2 MiB + 32 KiB encrypted JSON, counting actual UTF-8 bytes. Incremental reads consume the original stream; exceeding limits or cancellation stops/cancels it and releases its reader without cloning and fully buffering it. Oversized requests return 413, oversized responses return 500, and invalid public keys return 400. Rebuilt requests preserve signals; rebuilt requests/responses remove stale Content-Length/Content-Encoding. These budgets are not `_kit.yml` or environment settings.
219
+
220
+ #### Shared transport configuration with `_kit.yml`
207
221
 
208
222
  `@h-ai/kit` provides `KitConfigSchema` / `resolveKitConfig()` so a single `_kit.yml`
209
223
  can drive both `hooks.server.ts` and browser `kit.client.installBrowserTransport()`:
@@ -215,13 +229,10 @@ server:
215
229
 
216
230
  transport:
217
231
  keyExchangePath: /api/_hai/key-exchange
218
- requireEncryption: true
219
- encryptResponse: true
220
232
  excludePaths:
221
233
  - /api/storage
222
234
  - /api/public
223
235
  - /api/auth/profile/avatar
224
- maxClients: 10000
225
236
  ```
226
237
 
227
238
  ```ts
@@ -236,7 +247,7 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
236
247
  For server-only configuration, use `core.config.validate('kit', KitConfigSchema)` as well.
237
248
  Because the browser may read this configuration, `_kit.yml` must contain only public server/transport paths and switches, never secrets.
238
249
 
239
- ## Configuration
250
+ ### Configuration
240
251
 
241
252
  `kit.createHandle()` options:
242
253
 
@@ -253,16 +264,21 @@ Because the browser may read this configuration, `_kit.yml` must contain only pu
253
264
 
254
265
  With `crypto.encryptedCookies`, also provide `crypto.cookieEncryptionKey` or `HAI_KIT_COOKIE_KEY`. Missing keys fail immediately in `createHandle()`. Plaintext, damaged ciphertext, or decryption failures for protected cookies are treated as absent; encryption failures never fall back to writing plaintext.
255
266
 
256
- ## Export paths
267
+ Authentication cookies default to `Secure` when either `NODE_ENV` or `HAI_CORE_ENV` is `production`; `HAI_E2E` / `HAI_E2E_MOCK` do not relax cookie security. Production rate limiting recognizes both flags; only explicit test switches permit memory counters.
268
+
269
+ ### Export paths
270
+
271
+ Use runtime methods through the `kit` namespace or explicit subpaths; types are exported separately. Browser declarations do not expose server factories. Vite configuration uses `@sveltejs/kit/vite`; there is no `@h-ai/kit/vite` plugin.
257
272
 
258
273
  - `@h-ai/kit`: main entry, with the `kit` namespace and types.
259
274
  - `@h-ai/kit/client`: browser client.
260
275
  - `@h-ai/kit/adapter`: dual build adapter (`createAdapter()`).
261
- - `@h-ai/kit/vite`: Vite plugin.
262
276
  - `@h-ai/kit/a2a`: A2A integration.
263
277
  - `@h-ai/kit/crypto`: crypto integration.
264
278
 
265
- ## Configuration driven authentication
279
+ ### Configuration driven authentication
280
+
281
+ Password login submits only `identifier` and `password`; `AuthPanel` maps the `LoginForm` field `username` to `identifier`. Server settings `session.maxAge` / `session.refreshTokenMaxAge` control session lifetimes. The login form has no per-login persistent-session option.
266
282
 
267
283
  Agreements support configuration-loaded userAgreementMarkdown/privacyPolicyMarkdown and URLs. Markdown takes priority for the same agreement and is safely rendered in a modal.
268
284
 
@@ -270,22 +286,40 @@ Export standard handlers from kit.auth.createApi(iam), use kit.auth.publicPaths
270
286
 
271
287
  [完整 IAM 配置 / IAM configuration](../iam/README.en.md)
272
288
 
273
- ## Error handling
289
+ `kit.auth.logout(cookies, accessToken)` returns `Promise<HaiResult<void>>`. Without a token it only clears cookies and succeeds; with a token but no configured auth operations it fails. Local cookies are cleared for every server outcome. Callers must preserve failed results in their HTTP response or UI; local clearing does not confirm server revocation. Underlying control-flow exceptions still propagate.
290
+
291
+ ### Error handling
274
292
 
275
293
  - Wrap API endpoints with `kit.handler()`.
276
294
  - `kit.validate.body` / `kit.guard.require` throw `Response` for SvelteKit control flow.
277
295
  - `kit.handler()` converts non-control-flow exceptions into `500 INTERNAL_ERROR` responses.
278
296
 
279
- ## Tests
297
+ ### CRUD fields
298
+
299
+ Declarative CRUD fields support `colSpan: 'auto' | 1 | 2` for UI form widths. `validation.message` accepts a string or `() => string` for current-locale validation messages. Configure layout through `CrudPage.form`; validate independently on the server.
300
+
301
+ ### Runtime behavior and limits
302
+
303
+ - `kit.createHandle()`: session parsing, route guards, middleware chains, and optional transport/cookie encryption.
304
+ - `kit.handler()`: an exception boundary for API endpoints.
305
+ - `kit.guard` / `kit.response` / `kit.validate` / `kit.auth` / `kit.client` / `kit.crud`
306
+
307
+ > Shared cross-platform HTTP contracts belong in `@h-ai/api-contract`, are mounted by `@h-ai/serv`, and are called through the `@h-ai/api-client` typed client. `@h-ai/kit` does not define or host business API contracts.
308
+
309
+ ### Request locale isolation
310
+
311
+ Wrap Node requests and SSR in `core.i18n.runWithLocale(locale, () => handleRequest())`. SvelteKit can use `kit.i18n.runWithLocale(locale, () => resolve(event))`; serv creates the scope automatically from request headers. Async descendants inherit it. Explicit `MessageOptions.locale` takes precedence over the request locale and the startup default. Within a scope, `setGlobalLocale` only changes that request; outside a scope it configures the startup default and must not be called by request hooks.
312
+
313
+ Browsers keep application-level `setGlobalLocale` / `createLocaleStore`. During SSR, UI store initialization and setters only update the store; messages read the request scope. `runWithLocale` requires the Node entry; browser translations use explicit locale options or application state.
314
+
315
+ ## Development and testing
280
316
 
281
317
  ```bash
282
318
  pnpm --filter @h-ai/kit test
283
319
  ```
284
320
 
321
+ Kit has no module-wide init/close. The application initializes and closes shared cache, IAM and crypto dependencies. See the [JSDoc conventions (Chinese)](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证) for typechecked public examples. Authenticate requests with iam.auth.verifyToken; a nonempty token is not proof of identity.
322
+
285
323
  ## License
286
324
 
287
325
  Apache-2.0
288
-
289
- ## CRUD fields
290
-
291
- Declarative CRUD fields support `colSpan: 'auto' | 1 | 2` for UI form widths. `validation.message` accepts a string or `() => string` for current-locale validation messages. Configure layout through `CrudPage.form`; validate independently on the server.
package/README.ja.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  [フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/core](../core/README.ja.md) · [@h-ai/crypto](../crypto/README.ja.md) · [@h-ai/iam](../iam/README.ja.md)
6
6
 
7
+ ## 概要
8
+
7
9
  `@h-ai/kit` は hai-framework の SvelteKit 統合モジュールで、共通のリクエストパイプラインと同一オリジンの endpoint ツールを提供します:
8
10
 
9
11
  - `kit.createHandle()`:セッション解析、ルートガード、middleware チェーン、任意の通信・Cookie 暗号化。
@@ -12,14 +14,6 @@
12
14
 
13
15
  > クロスプラットフォームの公開 HTTP contract は `@h-ai/api-contract` で定義し、`@h-ai/serv` にマウント、`@h-ai/api-client` の型付きクライアントで呼び出します。`@h-ai/kit` は業務 API contract を定義・提供しません。
14
16
 
15
- ## インストール
16
-
17
- ```bash
18
- npm install @h-ai/kit
19
- npm install svelte @sveltejs/kit zod
20
- npm install -D @sveltejs/vite-plugin-svelte vite
21
- ```
22
-
23
17
  ## 主な機能
24
18
 
25
19
  - Handle Hook の合成(`createHandle` / `sequence`)
@@ -32,14 +26,26 @@ npm install -D @sveltejs/vite-plugin-svelte vite
32
26
  - A2A 統合:既定の検出パスは `/.well-known/agent-card.json`。`authenticate` 設定時は null/undefined が 401 となり、認証未設定時のみ匿名を許可します。API Key の引数は完全な Agent Card の `securitySchemes.apiKey` から取得します。Hook と明示的 A2A ルートは JSON-RPC 解析エラー・SSE キャンセル時の解放処理を共有します。
33
27
  - 2 種類のビルドモード(`createAdapter()`)
34
28
 
35
- ## 依存関係
29
+ ## 使い始める
30
+
31
+ `sequence` は SvelteKit の resolve オプションを保持します。ページ変換は内側から外側へ実行し、preload とシリアライズ対象ヘッダーのフィルターは最初の設定を優先します。
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
+ ### 依存関係
36
42
 
37
43
  - `@h-ai/iam`:A2A 用の認証・認可(任意)。A2A 機能を使う前に初期化。
38
44
  - `@h-ai/crypto`:通信・Cookie 暗号化(任意)。暗号化を使う前に初期化。
39
45
 
40
- ## クイックスタート
46
+ ### クイックスタート
41
47
 
42
- ### プロジェクト設定
48
+ #### プロジェクト設定
43
49
 
44
50
  **svelte.config.js**:
45
51
 
@@ -53,7 +59,7 @@ const config = {
53
59
  kit: {
54
60
  adapter: adapter(),
55
61
  // 双构建模式:import { createAdapter } from '@h-ai/kit/adapter'
56
- // adapter: createAdapter(),
62
+ // adapter: await createAdapter(),
57
63
  },
58
64
  }
59
65
 
@@ -70,35 +76,41 @@ import { defineConfig } from 'vite'
70
76
  export default defineConfig({
71
77
  plugins: [sveltekit(), tailwindcss()],
72
78
  optimizeDeps: { exclude: ['bits-ui'] },
73
- ssr: { noExternal: [/@h-ai\//] },
79
+ ssr: { noExternal: ['@h-ai/ui', '@h-ai/kit'], external: ['@h-ai/core', 'sm-crypto'] },
74
80
  })
75
81
  ```
76
82
 
77
- ### リクエストパイプラインの構築
83
+ Crypto または Kit/IAM を使う場合、アプリの本番依存に `sm-crypto@0.5.7` を含めます。CLI 生成済みのプロジェクトでは設定済みです。手動導入は `pnpm add sm-crypto@0.5.7` を実行してください。adapter-node は直接の本番依存も参照するため、external 指定だけでは不十分です。
84
+
85
+ #### リクエストパイプラインの構築
78
86
 
79
87
  **src/hooks.server.ts**:
80
88
 
81
89
  ```typescript
82
90
  import type { Handle } from '@sveltejs/kit'
91
+ import { cache } from '@h-ai/cache'
83
92
  import { kit } from '@h-ai/kit'
84
93
 
85
94
  const haiHandle = kit.createHandle({
86
95
  auth: {
87
96
  verifyToken: async (token) => {
88
- return token ? { userId: 'u_1', roles: ['admin'], permissions: ['user:read'] } : null
97
+ const verified = await iam.auth.verifyToken(token)
98
+ return verified.success ? verified.data : null
89
99
  },
90
100
  loginUrl: '/auth/login',
91
101
  protectedPaths: ['/admin/*', '/api/*'],
92
102
  publicPaths: ['/api/auth/*', '/api/public/*'],
93
103
  },
94
- rateLimit: { windowMs: 60_000, maxRequests: 100 },
104
+ rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
95
105
  logging: true,
96
106
  })
97
107
 
98
108
  export const handle: Handle = haiHandle
99
109
  ```
100
110
 
101
- ### API endpoint
111
+ 最初の確定時点から固定ウィンドウを開始し、後続リクエストはTTLを延長しません。storeは必須です。共有Redisの初期化成功を確認し、全ノードのnamespace/windowMs/maxRequestsを一致させます。キャッシュ障害や競合上限は503、超過は429で、get+setやローカル計数へフォールバックしません。createMemoryRateLimitStoreは開発または明示HAI_E2E/HAI_E2E_MOCKテスト用で、常駐タイマーを使わず参照解放で回収されます。1リクエスト最大64項目を遅延走査し、上限10000ウィンドウです。満杯時は有効な計数を追い出さず新キーを503にし、外部storeのライフサイクルは作成者が管理します。本番でテスト変数を設定しません。ヘッダー時刻は推定、実際の期間はRedis TTLで制御するため時計を同期します。キーは信頼済みadapterのgetClientAddressのみ使い、等価IPv6/IPv4表記を正規化します。生の転送ヘッダーを信頼せず、代理信頼はadapterで設定します。
112
+
113
+ #### API endpoint
102
114
 
103
115
  ```typescript
104
116
  import { kit } from '@h-ai/kit'
@@ -116,7 +128,7 @@ export const POST = kit.handler(async ({ request, locals }) => {
116
128
  })
117
129
  ```
118
130
 
119
- ### ブラウザークライアント
131
+ #### ブラウザークライアント
120
132
 
121
133
  `kit.client.create()` は SvelteKit の同一オリジン endpoint 向けです。Web・アプリ・ミニプログラムからクロスオリジンで公開 API を使う場合は `@h-ai/api-client` を使用してください。
122
134
 
@@ -137,20 +149,24 @@ const response = await apiFetch('/api/users', { method: 'GET' })
137
149
 
138
150
  > CSRF Header は `apiFetch` が自動付与します。`@h-ai/kit` は独立した CSRF middleware ファクトリーを提供しません。
139
151
  >
140
- > 認証:同一オリジンの SvelteKit endpoint は httpOnly Cookie を優先し、サーバーで Cookie を読んで認証します。機密 Token を `localStorage` に保存する必要はありません。Bearer Header が必要なら独自の `BrowserTokenStore`、または `kit.auth.setBrowserToken()` でページ内メモリーに保存してから `kit.client.create({ auth: true })` を使います。
152
+ > 同一オリジンの SvelteKit endpoint は httpOnly Cookie を使い、サーバーで検証します。ブラウザーの Bearer Header が必要なら `kit.auth.setBrowserToken()` でページ内メモリーに保存してから `kit.client.create({ auth: true })` を使います。独自の `BrowserTokenStore` もメモリーまたはプラットフォームの安全なストレージを使用し、機密の認証情報を Web Storage に永続化しないでください。
141
153
 
142
- ### 同一オリジンの通信暗号化
154
+ #### 同一オリジンの通信暗号化
143
155
 
144
- kit の通信暗号化は `@h-ai/crypto` に委譲します。サーバーは `crypto.transport.createServer()` で管理器を作成し、ブラウザーは `kit.client.installBrowserTransport(kitConfig, { crypto })` の 1 行で同一オリジンの fetch ラッパーを導入します。アプリ側はトップレベルの `crypto` のみを設定します。
156
+ kit の通信暗号化は `@h-ai/crypto` に委譲します。サーバーは `crypto.transport.createServer({ serverKeyRing, keyStore })` で管理器を作成し、ブラウザーは `kit.client.installBrowserTransport(kitConfig, { crypto })` の 1 行で同一オリジンの fetch ラッパーを導入します。サーバーには管理済み鍵環と共有 registry も渡します。
145
157
 
146
158
  **src/hooks.server.ts**:
147
159
 
148
160
  ```ts
149
161
  import { cache } from '@h-ai/cache'
150
- import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
162
+ import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
151
163
  import { kit } from '@h-ai/kit'
152
164
 
153
165
  await crypto.init()
166
+ const ring = parseTransportServerKeyRing(process.env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING)
167
+ if (!ring.success)
168
+ throw new Error(ring.error.message)
169
+ const serverKeyRing = ring.data
154
170
  await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
155
171
 
156
172
  export const handle = kit.createHandle({
@@ -162,7 +178,7 @@ export const handle = kit.createHandle({
162
178
  crypto: {
163
179
  crypto,
164
180
  transport: {
165
- requireEncryption: true,
181
+ serverKeyRing,
166
182
  keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
167
183
  },
168
184
  },
@@ -197,13 +213,17 @@ export const { apiFetch } = kit.client.create()
197
213
 
198
214
  既定の鍵交換パスは `/api/_hai/key-exchange` です。サーバーで `transport.keyExchangePath` を変更した場合、クライアントの `transport.keyExchangeUrl` も合わせて設定してください。
199
215
 
200
- ノード間でクライアント公開鍵を共有するには、実行時に `kit.createHandle({ crypto: { transport: { keyStore } } })` へ `createRedisTransportKeyStore()` または `createReldbTransportKeyStore()` を渡します。このようなオブジェクト依存を `_kit.yml` に**書いてはいけません**。設定ファイルは公開パスとスイッチのみを保持します。
216
+ サーバーには同じ管理済み `serverKeyRing` と共有 `keyStore`(Redis または共有 DB)を明示的に渡します。クライアント公開鍵の共有だけではノード間で復号できません。暗黙のプロセス鍵・メモリー registry はなく、開発・テストでは `createInMemoryKeyStore(capacity)` を明示します。再起動後は同じ鍵環を読み込み、sticky session は不要です。
201
217
 
202
218
  transport は既定で同一オリジンの `/api/*`、SvelteKit の `__data.json`、鍵交換 endpoint に適用します。ページ文書・静的ファイルは平文で `X-Client-Id` は不要です。アップロードなどの `multipart/form-data` はそのまま送信し、サーバーの `excludePaths` で明示的に許可してください。
203
219
 
204
- 既定の安全方針は fail-closed です。`requireEncryption: true` で保護パスに `X-Client-Id` がなければ 400 を返します。管理器の利用不可、応答の暗号化失敗、暗号化サイズ上限超過はエラーになり、平文の業務応答は渡しません。`requireEncryption: false` は段階的移行用で、本番では推奨しません。
220
+ 認証済み v2 のみを受け付けます。独立したランダム SM4-CBC 鍵と HMAC-SM3 鍵を SM2 で包み、送信者署名、MAC の順に検証してから CBC を復号します。要求はクライアント秘密鍵、応答は選択されたサーバー鍵バージョンで署名します。version、direction、serverKeyId、clientId、nonce を兼ねるランダム 128 ビット requestId、issuedAt、HTTP method、pathname と元の search の SM3 pathHash、応答 status を認証します。要求の有効期限は 5 分、未来方向の時計差は最大 30 秒です。共有 registry が (clientId, requestId) を原子的に消費し、ノード間の時計差を含め issuedAt + 6 分まで保持します。保存障害では拒否します。時計同期と Redis の noeviction/永続化により有効な nonce を保持してください。業務の再試行には別の冪等キーが必要です。
221
+
222
+ 空の POST も空平文の認証封装を送ります。GET/HEAD は X-Hai-Transport ヘッダー、204/304/HEAD など本文なし応答も同じヘッダーを使います。他の要求・応答は JSON 本文と X-Encrypted: true を使います。クライアントは元の要求コンテキストと HTTP status を照合し、マーカー欠落、旧形式、認証失敗では reject します。平文 endpoint は excludePaths で明示的に除外し、CORS では X-Hai-Transport を許可・公開してください。鍵交換の公開鍵認証は TLS に依存し、IAM の業務認可は別に必要です。
223
+
224
+ 固定上限は serv・クライアントと `@h-ai/crypto` の `TRANSPORT_BODY_LIMITS` を共有し、鍵交換 JSON は 16 KiB、公開鍵は 1 個あたり 4 KiB、平文は 1 MiB、暗号文 JSON は 2 MiB + 32 KiB です。実際の UTF-8 バイトを元のストリームから逐次読み取り、超過・キャンセル時は停止・キャンセルして reader を解放します。clone による全量読み取りは行いません。リクエスト超過は 413、応答超過は 500、不正な公開鍵は 400 です。再構築した Request は signal を維持し、リクエスト・応答の古い Content-Length/Content-Encoding を削除します。上限は `_kit.yml`・環境変数の設定ではありません。
205
225
 
206
- ### `_kit.yml` による共通 transport 設定
226
+ #### `_kit.yml` による共通 transport 設定
207
227
 
208
228
  `@h-ai/kit` は `KitConfigSchema` / `resolveKitConfig()` を提供し、同じ `_kit.yml` から
209
229
  `hooks.server.ts` とブラウザーの `kit.client.installBrowserTransport()` の両方を設定できます:
@@ -215,13 +235,10 @@ server:
215
235
 
216
236
  transport:
217
237
  keyExchangePath: /api/_hai/key-exchange
218
- requireEncryption: true
219
- encryptResponse: true
220
238
  excludePaths:
221
239
  - /api/storage
222
240
  - /api/public
223
241
  - /api/auth/profile/avatar
224
- maxClients: 10000
225
242
  ```
226
243
 
227
244
  ```ts
@@ -236,7 +253,7 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
236
253
  サーバーのみで設定を読む場合は `core.config.validate('kit', KitConfigSchema)` も利用できます。
237
254
  ブラウザーも読む可能性があるため、`_kit.yml` は公開 server/transport パスとスイッチのみを含め、秘密鍵などを書かないでください。
238
255
 
239
- ## 設定
256
+ ### 設定
240
257
 
241
258
  `kit.createHandle()` の設定項目:
242
259
 
@@ -253,16 +270,21 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
253
270
 
254
271
  `crypto.encryptedCookies` を設定する場合、`crypto.cookieEncryptionKey` または `HAI_KIT_COOKIE_KEY` が必要です。鍵がなければ `createHandle()` ですぐエラーになります。保護対象 Cookie の平文・破損暗号文・復号失敗は未存在として扱い、暗号化失敗時も平文保存に切り替えません。
255
272
 
256
- ## エクスポートパス
273
+ 認証 Cookie は `NODE_ENV` または `HAI_CORE_ENV` が `production` の場合に `Secure` を既定で有効にします。`HAI_E2E` / `HAI_E2E_MOCK` は Cookie の安全要件を緩和しません。本番のレート制限も両方の環境変数を認識し、明示的なテストフラグだけがメモリカウンターを許可します。
274
+
275
+ ### エクスポートパス
276
+
277
+ 実行時メソッドは `kit` 名前空間または明示したサブパスを使用し、型は個別に公開します。browser 宣言はサーバーファクトリを公開しません。Vite 設定には `@sveltejs/kit/vite` を使い、`@h-ai/kit/vite` プラグインはありません。
257
278
 
258
279
  - `@h-ai/kit`:主入口。`kit` 名前空間と型を提供。
259
280
  - `@h-ai/kit/client`:ブラウザークライアント。
260
281
  - `@h-ai/kit/adapter`:2 モードのビルド adapter(`createAdapter()`)。
261
- - `@h-ai/kit/vite`:Vite プラグイン。
262
282
  - `@h-ai/kit/a2a`:A2A 統合。
263
283
  - `@h-ai/kit/crypto`:暗号モジュール統合。
264
284
 
265
- ## 設定による認証画面
285
+ ### 設定による認証画面
286
+
287
+ パスワードログインの送信項目は `identifier` と `password` のみです。`AuthPanel` は `LoginForm` の `username` を `identifier` に変換します。有効期間はサーバーの `session.maxAge` / `session.refreshTokenMaxAge` で設定し、フォームにログインごとの永続セッション選択肢はありません。
266
288
 
267
289
  規約は設定の userAgreementMarkdown/privacyPolicyMarkdown または URL を使用できます。同じ規約は Markdown 本文を優先して安全な Modal で描画します。
268
290
 
@@ -270,22 +292,32 @@ kit.auth.createApi(iam) の標準 handler と kit.auth.publicPaths を使用し
270
292
 
271
293
  [完整 IAM 配置 / IAM configuration](../iam/README.ja.md)
272
294
 
273
- ## エラー処理
295
+ `kit.auth.logout(cookies, accessToken)` は `Promise<HaiResult<void>>` を返します。Token がなければ Cookie のみ消去して成功し、Token があるのに認証操作が未設定なら失敗します。サーバー結果にかかわらず Cookie は消去しますが、呼出側は失敗を HTTP 応答や UI に伝えます。ローカル消去はサーバー失効の確認ではありません。制御フロー例外は引き続き伝播します。
296
+
297
+ ### エラー処理
274
298
 
275
299
  - API endpoint は `kit.handler()` でラップすることを推奨。
276
300
  - `kit.validate.body` / `kit.guard.require` は SvelteKit の制御フローとして `Response` を throw。
277
301
  - 制御フロー以外の例外は `kit.handler()` が `500 INTERNAL_ERROR` 応答に変換。
278
302
 
279
- ## テスト
303
+ ### CRUD fields
304
+
305
+ 宣言型 CRUD 項目は UI フォームの幅を指定する `colSpan: 'auto' | 1 | 2` に対応します。`validation.message` は文字列または `() => string` を受け取り、現在の言語で表示できます。レイアウトは `CrudPage.form` で設定し、サーバーでも検証してください。
306
+
307
+ ### リクエスト言語の分離
308
+
309
+ Node リクエストと SSR は `core.i18n.runWithLocale(locale, () => handleRequest())` で囲みます。SvelteKit は `kit.i18n.runWithLocale(locale, () => resolve(event))` を使えます。serv はリクエストヘッダーから自動設定します。非同期の子処理も言語を継承し、明示的な `MessageOptions.locale`、リクエスト言語、起動時の既定値の順で優先します。コンテキスト内の `setGlobalLocale` はそのリクエストだけを変更します。コンテキスト外の設定は起動時に限定し、リクエスト hook から呼びません。
310
+
311
+ ブラウザーはアプリ全体の `setGlobalLocale` / `createLocaleStore` を使います。SSR の UI store 初期化と setter は自身の状態のみ変更し、メッセージはリクエストコンテキストを参照します。`runWithLocale` は Node 入口専用です。
312
+
313
+ ## 開発とテスト
280
314
 
281
315
  ```bash
282
316
  pnpm --filter @h-ai/kit test
283
317
  ```
284
318
 
285
- ## License
319
+ Kit に共通の init/close はありません。共有 cache・IAM・crypto はアプリが初期化と終了を管理します。型検査できる例は [JSDoc 規約(中国語)](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证) を参照してください。認証は iam.auth.verifyToken で検証し、空でない token だけでは許可しません。
286
320
 
287
- Apache-2.0
288
-
289
- ## CRUD fields
321
+ ## ライセンス
290
322
 
291
- 宣言型 CRUD 項目は UI フォームの幅を指定する `colSpan: 'auto' | 1 | 2` に対応します。`validation.message` は文字列または `() => string` を受け取り、現在の言語で表示できます。レイアウトは `CrudPage.form` で設定し、サーバーでも検証してください。
323
+ Apache-2.0