@h-ai/kit 0.1.0-alpha.67 → 0.1.0-alpha.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.en.md +39 -13
  2. package/README.ja.md +39 -13
  3. package/README.md +39 -13
  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
@@ -22,6 +22,8 @@
22
22
 
23
23
  ## Getting started
24
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
+
25
27
  ### Installation
26
28
 
27
29
  ```bash
@@ -51,7 +53,7 @@ const config = {
51
53
  kit: {
52
54
  adapter: adapter(),
53
55
  // 双构建模式:import { createAdapter } from '@h-ai/kit/adapter'
54
- // adapter: createAdapter(),
56
+ // adapter: await createAdapter(),
55
57
  },
56
58
  }
57
59
 
@@ -80,24 +82,28 @@ When using Crypto or Kit/IAM, include `sm-crypto@0.5.7` in application productio
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
 
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
+
101
107
  #### API endpoints
102
108
 
103
109
  ```typescript
@@ -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
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,11 +207,15 @@ 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.
215
+
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.
205
219
 
206
220
  #### Shared transport configuration with `_kit.yml`
207
221
 
@@ -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
@@ -253,23 +264,30 @@ 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
 
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
+
256
269
  ### Export paths
257
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.
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
279
  ### Configuration driven authentication
266
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.
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
 
269
285
  Export standard handlers from kit.auth.createApi(iam), use kit.auth.publicPaths for anonymous endpoints, and connect AuthPanel with kit.client.createAuthActions({ apiFetch }). Validation, Cookie writes and HaiResult mapping are built in; current-user and password-change endpoints remain guarded.
270
286
 
271
287
  [完整 IAM 配置 / IAM configuration](../iam/README.en.md)
272
288
 
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
+
273
291
  ### Error handling
274
292
 
275
293
  - Wrap API endpoints with `kit.handler()`.
@@ -288,12 +306,20 @@ Declarative CRUD fields support `colSpan: 'auto' | 1 | 2` for UI form widths. `v
288
306
 
289
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.
290
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
+
291
315
  ## Development and testing
292
316
 
293
317
  ```bash
294
318
  pnpm --filter @h-ai/kit test
295
319
  ```
296
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
+
297
323
  ## License
298
324
 
299
325
  Apache-2.0
package/README.ja.md CHANGED
@@ -28,6 +28,8 @@
28
28
 
29
29
  ## 使い始める
30
30
 
31
+ `sequence` は SvelteKit の resolve オプションを保持します。ページ変換は内側から外側へ実行し、preload とシリアライズ対象ヘッダーのフィルターは最初の設定を優先します。
32
+
31
33
  ### インストール
32
34
 
33
35
  ```bash
@@ -57,7 +59,7 @@ const config = {
57
59
  kit: {
58
60
  adapter: adapter(),
59
61
  // 双构建模式:import { createAdapter } from '@h-ai/kit/adapter'
60
- // adapter: createAdapter(),
62
+ // adapter: await createAdapter(),
61
63
  },
62
64
  }
63
65
 
@@ -86,24 +88,28 @@ Crypto または Kit/IAM を使う場合、アプリの本番依存に `sm-crypt
86
88
 
87
89
  ```typescript
88
90
  import type { Handle } from '@sveltejs/kit'
91
+ import { cache } from '@h-ai/cache'
89
92
  import { kit } from '@h-ai/kit'
90
93
 
91
94
  const haiHandle = kit.createHandle({
92
95
  auth: {
93
96
  verifyToken: async (token) => {
94
- 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
95
99
  },
96
100
  loginUrl: '/auth/login',
97
101
  protectedPaths: ['/admin/*', '/api/*'],
98
102
  publicPaths: ['/api/auth/*', '/api/public/*'],
99
103
  },
100
- rateLimit: { windowMs: 60_000, maxRequests: 100 },
104
+ rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
101
105
  logging: true,
102
106
  })
103
107
 
104
108
  export const handle: Handle = haiHandle
105
109
  ```
106
110
 
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
+
107
113
  #### API endpoint
108
114
 
109
115
  ```typescript
@@ -143,20 +149,24 @@ const response = await apiFetch('/api/users', { method: 'GET' })
143
149
 
144
150
  > CSRF Header は `apiFetch` が自動付与します。`@h-ai/kit` は独立した CSRF middleware ファクトリーを提供しません。
145
151
  >
146
- > 認証:同一オリジンの 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 に永続化しないでください。
147
153
 
148
154
  #### 同一オリジンの通信暗号化
149
155
 
150
- 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 も渡します。
151
157
 
152
158
  **src/hooks.server.ts**:
153
159
 
154
160
  ```ts
155
161
  import { cache } from '@h-ai/cache'
156
- import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
162
+ import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
157
163
  import { kit } from '@h-ai/kit'
158
164
 
159
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
160
170
  await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
161
171
 
162
172
  export const handle = kit.createHandle({
@@ -168,7 +178,7 @@ export const handle = kit.createHandle({
168
178
  crypto: {
169
179
  crypto,
170
180
  transport: {
171
- requireEncryption: true,
181
+ serverKeyRing,
172
182
  keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
173
183
  },
174
184
  },
@@ -203,11 +213,15 @@ export const { apiFetch } = kit.client.create()
203
213
 
204
214
  既定の鍵交換パスは `/api/_hai/key-exchange` です。サーバーで `transport.keyExchangePath` を変更した場合、クライアントの `transport.keyExchangeUrl` も合わせて設定してください。
205
215
 
206
- ノード間でクライアント公開鍵を共有するには、実行時に `kit.createHandle({ crypto: { transport: { keyStore } } })` へ `createRedisTransportKeyStore()` または `createReldbTransportKeyStore()` を渡します。このようなオブジェクト依存を `_kit.yml` に**書いてはいけません**。設定ファイルは公開パスとスイッチのみを保持します。
216
+ サーバーには同じ管理済み `serverKeyRing` と共有 `keyStore`(Redis または共有 DB)を明示的に渡します。クライアント公開鍵の共有だけではノード間で復号できません。暗黙のプロセス鍵・メモリー registry はなく、開発・テストでは `createInMemoryKeyStore(capacity)` を明示します。再起動後は同じ鍵環を読み込み、sticky session は不要です。
207
217
 
208
218
  transport は既定で同一オリジンの `/api/*`、SvelteKit の `__data.json`、鍵交換 endpoint に適用します。ページ文書・静的ファイルは平文で `X-Client-Id` は不要です。アップロードなどの `multipart/form-data` はそのまま送信し、サーバーの `excludePaths` で明示的に許可してください。
209
219
 
210
- 既定の安全方針は 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`・環境変数の設定ではありません。
211
225
 
212
226
  #### `_kit.yml` による共通 transport 設定
213
227
 
@@ -221,13 +235,10 @@ server:
221
235
 
222
236
  transport:
223
237
  keyExchangePath: /api/_hai/key-exchange
224
- requireEncryption: true
225
- encryptResponse: true
226
238
  excludePaths:
227
239
  - /api/storage
228
240
  - /api/public
229
241
  - /api/auth/profile/avatar
230
- maxClients: 10000
231
242
  ```
232
243
 
233
244
  ```ts
@@ -259,23 +270,30 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
259
270
 
260
271
  `crypto.encryptedCookies` を設定する場合、`crypto.cookieEncryptionKey` または `HAI_KIT_COOKIE_KEY` が必要です。鍵がなければ `createHandle()` ですぐエラーになります。保護対象 Cookie の平文・破損暗号文・復号失敗は未存在として扱い、暗号化失敗時も平文保存に切り替えません。
261
272
 
273
+ 認証 Cookie は `NODE_ENV` または `HAI_CORE_ENV` が `production` の場合に `Secure` を既定で有効にします。`HAI_E2E` / `HAI_E2E_MOCK` は Cookie の安全要件を緩和しません。本番のレート制限も両方の環境変数を認識し、明示的なテストフラグだけがメモリカウンターを許可します。
274
+
262
275
  ### エクスポートパス
263
276
 
277
+ 実行時メソッドは `kit` 名前空間または明示したサブパスを使用し、型は個別に公開します。browser 宣言はサーバーファクトリを公開しません。Vite 設定には `@sveltejs/kit/vite` を使い、`@h-ai/kit/vite` プラグインはありません。
278
+
264
279
  - `@h-ai/kit`:主入口。`kit` 名前空間と型を提供。
265
280
  - `@h-ai/kit/client`:ブラウザークライアント。
266
281
  - `@h-ai/kit/adapter`:2 モードのビルド adapter(`createAdapter()`)。
267
- - `@h-ai/kit/vite`:Vite プラグイン。
268
282
  - `@h-ai/kit/a2a`:A2A 統合。
269
283
  - `@h-ai/kit/crypto`:暗号モジュール統合。
270
284
 
271
285
  ### 設定による認証画面
272
286
 
287
+ パスワードログインの送信項目は `identifier` と `password` のみです。`AuthPanel` は `LoginForm` の `username` を `identifier` に変換します。有効期間はサーバーの `session.maxAge` / `session.refreshTokenMaxAge` で設定し、フォームにログインごとの永続セッション選択肢はありません。
288
+
273
289
  規約は設定の userAgreementMarkdown/privacyPolicyMarkdown または URL を使用できます。同じ規約は Markdown 本文を優先して安全な Modal で描画します。
274
290
 
275
291
  kit.auth.createApi(iam) の標準 handler と kit.auth.publicPaths を使用し、AuthPanel には kit.client.createAuthActions({ apiFetch }) を接続します。検証、Cookie、HaiResult 変換を共通化し、ユーザー情報と改密の保護を維持します。
276
292
 
277
293
  [完整 IAM 配置 / IAM configuration](../iam/README.ja.md)
278
294
 
295
+ `kit.auth.logout(cookies, accessToken)` は `Promise<HaiResult<void>>` を返します。Token がなければ Cookie のみ消去して成功し、Token があるのに認証操作が未設定なら失敗します。サーバー結果にかかわらず Cookie は消去しますが、呼出側は失敗を HTTP 応答や UI に伝えます。ローカル消去はサーバー失効の確認ではありません。制御フロー例外は引き続き伝播します。
296
+
279
297
  ### エラー処理
280
298
 
281
299
  - API endpoint は `kit.handler()` でラップすることを推奨。
@@ -286,12 +304,20 @@ kit.auth.createApi(iam) の標準 handler と kit.auth.publicPaths を使用し
286
304
 
287
305
  宣言型 CRUD 項目は UI フォームの幅を指定する `colSpan: 'auto' | 1 | 2` に対応します。`validation.message` は文字列または `() => string` を受け取り、現在の言語で表示できます。レイアウトは `CrudPage.form` で設定し、サーバーでも検証してください。
288
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
+
289
313
  ## 開発とテスト
290
314
 
291
315
  ```bash
292
316
  pnpm --filter @h-ai/kit test
293
317
  ```
294
318
 
319
+ Kit に共通の init/close はありません。共有 cache・IAM・crypto はアプリが初期化と終了を管理します。型検査できる例は [JSDoc 規約(中国語)](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证) を参照してください。認証は iam.auth.verifyToken で検証し、空でない token だけでは許可しません。
320
+
295
321
  ## ライセンス
296
322
 
297
323
  Apache-2.0
package/README.md CHANGED
@@ -28,6 +28,8 @@
28
28
 
29
29
  ## 使用入门
30
30
 
31
+ `sequence` 保留并组合 SvelteKit 的 `resolve` 选项:页面转换由内向外执行,`preload` 与序列化响应头过滤使用首个配置,确保 i18n 的 HTML 语言标记正确替换。
32
+
31
33
  ### 安装
32
34
 
33
35
  ```bash
@@ -57,7 +59,7 @@ const config = {
57
59
  kit: {
58
60
  adapter: adapter(),
59
61
  // 双构建模式:import { createAdapter } from '@h-ai/kit/adapter'
60
- // adapter: createAdapter(),
62
+ // adapter: await createAdapter(),
61
63
  },
62
64
  }
63
65
 
@@ -86,24 +88,28 @@ export default defineConfig({
86
88
 
87
89
  ```typescript
88
90
  import type { Handle } from '@sveltejs/kit'
91
+ import { cache } from '@h-ai/cache'
89
92
  import { kit } from '@h-ai/kit'
90
93
 
91
94
  const haiHandle = kit.createHandle({
92
95
  auth: {
93
96
  verifyToken: async (token) => {
94
- 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
95
99
  },
96
100
  loginUrl: '/auth/login',
97
101
  protectedPaths: ['/admin/*', '/api/*'],
98
102
  publicPaths: ['/api/auth/*', '/api/public/*'],
99
103
  },
100
- rateLimit: { windowMs: 60_000, maxRequests: 100 },
104
+ rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
101
105
  logging: true,
102
106
  })
103
107
 
104
108
  export const handle: Handle = haiHandle
105
109
  ```
106
110
 
111
+ 限流采用首次成功提交为起点的固定窗口,后续请求不延长 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配置。
112
+
107
113
  #### API 端点
108
114
 
109
115
  ```typescript
@@ -143,20 +149,24 @@ const response = await apiFetch('/api/users', { method: 'GET' })
143
149
 
144
150
  > CSRF Header 注入由 `apiFetch` 自动处理;`@h-ai/kit` 不提供独立的 CSRF 中间件工厂。
145
151
  >
146
- > 认证建议:同源 SvelteKit endpoint 优先使用 httpOnly Cookie,由服务端读取 Cookie 完成鉴权,浏览器端不需要把敏感 Token 写入 `localStorage`。如确需注入 Bearer Header,请传入自定义 `BrowserTokenStore`,或先用 `kit.auth.setBrowserToken()` 写入页面内存后再使用 `kit.client.create({ auth: true })`。
152
+ > 同源 SvelteKit endpoint 使用 httpOnly Cookie,由服务端读取 Cookie 完成鉴权。浏览器 Bearer Token 使用 `kit.auth.setBrowserToken()` 写入页面内存,再通过 `kit.client.create({ auth: true })` 注入。自定义 `BrowserTokenStore` 也必须使用内存或平台安全存储,禁止将敏感凭据写入 Web Storage。
147
153
 
148
154
  #### 同源传输加密
149
155
 
150
- kit 的传输加密也统一委托 `@h-ai/crypto`:服务端通过 `crypto.transport.createServer()` 创建管理器,浏览器端通过 `kit.client.installBrowserTransport(kitConfig, { crypto })` 一行安装同源 fetch 包装。应用层只配置顶层 `crypto` 句柄。
156
+ kit 的传输加密也统一委托 `@h-ai/crypto`:服务端通过 `crypto.transport.createServer({ serverKeyRing, keyStore })` 创建管理器,浏览器端通过 `kit.client.installBrowserTransport(kitConfig, { crypto })` 一行安装同源 fetch 包装。服务端还须注入受管密钥环和共享 registry。
151
157
 
152
158
  **src/hooks.server.ts**:
153
159
 
154
160
  ```ts
155
161
  import { cache } from '@h-ai/cache'
156
- import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
162
+ import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
157
163
  import { kit } from '@h-ai/kit'
158
164
 
159
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
160
170
  await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
161
171
 
162
172
  export const handle = kit.createHandle({
@@ -168,7 +178,7 @@ export const handle = kit.createHandle({
168
178
  crypto: {
169
179
  crypto,
170
180
  transport: {
171
- requireEncryption: true,
181
+ serverKeyRing,
172
182
  keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
173
183
  },
174
184
  },
@@ -203,11 +213,15 @@ export const { apiFetch } = kit.client.create()
203
213
 
204
214
  默认密钥协商路径为 `/api/_hai/key-exchange`。如服务端自定义 `transport.keyExchangePath`,客户端需同步配置 `transport.keyExchangeUrl`。
205
215
 
206
- 如需多节点共享客户端公钥,可在运行时为 `kit.createHandle({ crypto: { transport: { keyStore } } })` 注入 `createRedisTransportKeyStore()` 或 `createReldbTransportKeyStore()`;这类对象型依赖**不应**写入 `_kit.yml`,配置文件仍只保存公开路径与开关。
216
+ 服务端必须显式注入相同的受管 `serverKeyRing` 和共享 `keyStore`(Redis 或共享数据库)。仅共享客户端公钥不足以跨节点解密。没有隐式进程私钥或内存 registry 回退;开发/测试显式用 `createInMemoryKeyStore(capacity)`。服务端重启后重新加载同一密钥环即可,无需 sticky session。
207
217
 
208
218
  transport 默认作用于同源 `/api/*` endpoint 与 SvelteKit `__data.json` 页面数据请求(以及密钥协商端点本身);页面文档与静态资源仍保持明文,不要求携带 `X-Client-Id`。文件上传等 `multipart/form-data` 请求会保持原样发送,需在服务端 `excludePaths` 中显式放行对应上传路径。
209
219
 
210
- 安全策略默认 fail-closed:`requireEncryption: true` 时,受保护路径缺少 `X-Client-Id` 会直接返回 400;服务端 transport 管理器不可用、响应体无法加密或超过单次加密上限时返回错误,不会把业务明文响应透传给客户端。`requireEncryption: false` 仅用于迁移期灰度,不建议在生产启用。
220
+ 认证协议仅支持 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/可靠持久化策略;各节点时钟须同步。此能力防止同一传输消息重放,业务重试仍需自己的幂等键。
221
+
222
+ 空 POST 也发送空明文的认证封装;GET/HEAD 将封装放在 X-Hai-Transport 头,204/304/HEAD 等无正文响应也使用同名头承载认证封装。其它请求/响应在 JSON 正文承载封装并带 X-Encrypted: true。客户端必须关联原请求上下文和 HTTP status,缺标记、旧格式或认证失败一律 reject;明文接口只能经 excludePaths 显式排除。CORS 须允许并暴露 X-Hai-Transport。握手公钥的真实性依赖 TLS,不替代 IAM 业务授权。
223
+
224
+ 固定预算与 serv/客户端共享 `@h-ai/crypto` 的 `TRANSPORT_BODY_LIMITS`:握手 JSON 16 KiB,单个公钥 4 KiB,明文 1 MiB,密文 JSON 2 MiB + 32 KiB,均按实际 UTF-8 字节计数。逐块读取原始流,超限/取消立即停止、取消流并释放 reader,不克隆后完整缓冲。请求正文超限返回 413,响应超限返回 500,无效公钥返回 400。重建 Request 时保留 signal,重建请求/响应时移除旧 Content-Length/Content-Encoding。预算不属于 `_kit.yml` 或环境变量配置。
211
225
 
212
226
  #### 使用 `_kit.yml` 统一 transport 配置
213
227
 
@@ -221,13 +235,10 @@ server:
221
235
 
222
236
  transport:
223
237
  keyExchangePath: /api/_hai/key-exchange
224
- requireEncryption: true
225
- encryptResponse: true
226
238
  excludePaths:
227
239
  - /api/storage
228
240
  - /api/public
229
241
  - /api/auth/profile/avatar
230
- maxClients: 10000
231
242
  ```
232
243
 
233
244
  ```ts
@@ -259,23 +270,30 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
259
270
 
260
271
  配置 `crypto.encryptedCookies` 时必须同时提供 `crypto.cookieEncryptionKey`,或设置 `HAI_KIT_COOKIE_KEY`。缺少密钥会在 `createHandle()` 时立即报错;受保护 Cookie 的明文、损坏密文或解密失败都按不存在处理,加密失败也不会回退写入明文。
261
272
 
273
+ 认证 Cookie 的 `Secure` 默认值在 `NODE_ENV` 或 `HAI_CORE_ENV` 为 `production` 时开启,`HAI_E2E` / `HAI_E2E_MOCK` 不降低 Cookie 安全要求。生产限流同样识别这两个环境标志;仅显式测试开关可放宽内存计数器限制。
274
+
262
275
  ### 导出路径
263
276
 
277
+ 子模块运行时方法通过 `kit` 命名空间或明确子路径使用,类型单独导出;浏览器声明不暴露服务端工厂。Vite 配置使用 `@sveltejs/kit/vite`,不存在 `@h-ai/kit/vite` 插件。
278
+
264
279
  - `@h-ai/kit`:主入口,提供 `kit` 命名空间与类型。
265
280
  - `@h-ai/kit/client`:浏览器端客户端。
266
281
  - `@h-ai/kit/adapter`:双构建 adapter(`createAdapter()`)。
267
- - `@h-ai/kit/vite`:Vite 插件。
268
282
  - `@h-ai/kit/a2a`:A2A 协议集成。
269
283
  - `@h-ai/kit/crypto`:加密模块集成。
270
284
 
271
285
  ### 配置驱动认证页面
272
286
 
287
+ 密码登录只提交 `identifier` 和 `password`;`AuthPanel` 将 `LoginForm` 的 `username` 映射为 `identifier`。会话有效期由服务端 `session.maxAge` / `session.refreshTokenMaxAge` 配置决定,登录表单不提供按次登录的持久会话选项。
288
+
273
289
  协议支持配置中的 userAgreementMarkdown/privacyPolicyMarkdown 正文及 URL;同主题优先 Markdown,由安全渲染器在弹窗显示。
274
290
 
275
291
  路由直接导出 `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。
276
292
 
277
293
  [完整 IAM 配置 / IAM configuration](../iam/README.md)
278
294
 
295
+ `kit.auth.logout(cookies, accessToken)` 返回 `Promise<HaiResult<void>>`。无令牌时仅清除 Cookie 并成功;有令牌但未配置认证操作时返回失败。无论服务端结果如何都清除本地 Cookie,调用方仍必须把失败转换为错误响应或提示;仅成功结果代表服务端撤销已经确认。底层控制流异常继续传播。
296
+
279
297
  ### 错误处理
280
298
 
281
299
  - 推荐使用 `kit.handler()` 包装 API 端点。
@@ -286,12 +304,20 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
286
304
 
287
305
  声明式 CRUD 字段支持 `colSpan: 'auto' | 1 | 2`,供 UI 双列表单决定字段宽度;`validation.message` 支持字符串或 `() => string`,便于随当前语言显示校验错误。UI 布局在 `CrudPage.form` 上配置,服务端仍须独立校验。
288
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 只修改自身状态,不写全局语言;UI 消息从请求上下文读取。`runWithLocale` 仅支持 Node 入口,浏览器通过显式 locale 或应用状态翻译。
312
+
289
313
  ## 开发测试
290
314
 
291
315
  ```bash
292
316
  pnpm --filter @h-ai/kit test
293
317
  ```
294
318
 
319
+ 模块无统一 init/close;共享缓存、IAM 与 crypto 由应用启动时初始化并统一关闭。示例使用真实公开入口并作类型检查,见[模块 JSDoc 约定](../../.agents/instructions/module-conventions.md#jsdoc-与示例验证)。请求认证必须调用 iam.auth.verifyToken,不能把非空 token 视为有效身份。
320
+
295
321
  ## 许可证
296
322
 
297
323
  Apache-2.0
@@ -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":";;;AA2CA,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: createAdapter(),\n * },\n * }\n * ```\n *\n * @module kit-adapter\n */\n\nimport process from 'node:process'\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 */\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"]}
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,7 +1,7 @@
1
- import { c as createKitClient, a as createKitAuthActions, i as installBrowserTransport, b as installBrowserTransportFetch, s as setBrowserToken, d as clearBrowserToken, e as createTokenStore } from './index-B7s-0mZl.js';
2
- export { C as ClientTransportConfig, K as KitClient, f as KitClientConfig, g as KitConfig, h as KitConfigInput, j as KitConfigSchema, k as KitServerConfig, l as KitServerConfigInput, m as KitTransportConfig, n as KitTransportConfigInput, o as createSvelteKitNavAdapter, r as resolveKitConfig, p as resolveKitTransportConfig } from './index-B7s-0mZl.js';
3
- import { d as defineCrud, s as setAllModulesLocale } from './kit-i18n-D9Qqk-1k.js';
4
- 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, M as Middleware, j as MiddlewareContext, R as RateLimitConfig, k as RouteGuard, S as SessionData, l as SessionLike, T as TransportEncryptionOptions } from './kit-types-ByWdbCeO.js';
1
+ import { c as createKitClient, a as createKitAuthActions, i as installBrowserTransport, b as installBrowserTransportFetch, s as setBrowserToken, d as clearBrowserToken } from './kit-client-auth-HnZIYUia.js';
2
+ export { C as ClientTransportConfig, K as KitClient, e as KitClientConfig, f as KitConfig, g as KitConfigInput, h as KitConfigSchema, j as KitServerConfig, k as KitServerConfigInput, l as KitTransportConfig, m as KitTransportConfigInput, r as resolveKitConfig, n as resolveKitTransportConfig } from './kit-client-auth-HnZIYUia.js';
3
+ import { d as defineCrud, s as setAllModulesLocale } from './kit-i18n-DEzmzE5T.js';
4
+ 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, M as Middleware, j as MiddlewareContext, R as RateLimitConfig, k as RouteGuard, S as SessionData, l as SessionLike, T as TransportEncryptionOptions } from './kit-types-CnzhN-AS.js';
5
5
  import '@h-ai/api-contract';
6
6
  import '@h-ai/core';
7
7
  import '@h-ai/crypto';
@@ -18,6 +18,13 @@ import '@sveltejs/kit';
18
18
 
19
19
  /**
20
20
  * 浏览器端 kit 对象(仅暴露 client-safe 能力)
21
+ * @example
22
+ * ```ts
23
+ * import { kit } from '@h-ai/kit'
24
+ *
25
+ * const client = kit.client.create({ auth: true })
26
+ * client.destroy()
27
+ * ```
21
28
  */
22
29
  declare const kit: {
23
30
  client: {
@@ -32,11 +39,10 @@ declare const kit: {
32
39
  auth: {
33
40
  setBrowserToken: typeof setBrowserToken;
34
41
  clearBrowserToken: typeof clearBrowserToken;
35
- createTokenStore: typeof createTokenStore;
36
42
  };
37
43
  i18n: {
38
44
  setLocale: typeof setAllModulesLocale;
39
45
  };
40
46
  };
41
47
 
42
- export { createKitAuthActions, createKitClient, installBrowserTransport, installBrowserTransportFetch, kit };
48
+ export { kit };