@h-ai/kit 0.1.0-alpha.59 → 0.1.0-alpha.60

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 CHANGED
@@ -262,6 +262,14 @@ With `crypto.encryptedCookies`, also provide `crypto.cookieEncryptionKey` or `HA
262
262
  - `@h-ai/kit/a2a`: A2A integration.
263
263
  - `@h-ai/kit/crypto`: crypto integration.
264
264
 
265
+ ## Configuration driven authentication
266
+
267
+ Agreements support configuration-loaded userAgreementMarkdown/privacyPolicyMarkdown and URLs. Markdown takes priority for the same agreement and is safely rendered in a modal.
268
+
269
+ 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
+
271
+ [完整 IAM 配置 / IAM configuration](../iam/README.en.md)
272
+
265
273
  ## Error handling
266
274
 
267
275
  - Wrap API endpoints with `kit.handler()`.
package/README.ja.md CHANGED
@@ -262,6 +262,14 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
262
262
  - `@h-ai/kit/a2a`:A2A 統合。
263
263
  - `@h-ai/kit/crypto`:暗号モジュール統合。
264
264
 
265
+ ## 設定による認証画面
266
+
267
+ 規約は設定の userAgreementMarkdown/privacyPolicyMarkdown または URL を使用できます。同じ規約は Markdown 本文を優先して安全な Modal で描画します。
268
+
269
+ kit.auth.createApi(iam) の標準 handler と kit.auth.publicPaths を使用し、AuthPanel には kit.client.createAuthActions({ apiFetch }) を接続します。検証、Cookie、HaiResult 変換を共通化し、ユーザー情報と改密の保護を維持します。
270
+
271
+ [完整 IAM 配置 / IAM configuration](../iam/README.ja.md)
272
+
265
273
  ## エラー処理
266
274
 
267
275
  - API endpoint は `kit.handler()` でラップすることを推奨。
package/README.md CHANGED
@@ -262,6 +262,14 @@ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
262
262
  - `@h-ai/kit/a2a`:A2A 协议集成。
263
263
  - `@h-ai/kit/crypto`:加密模块集成。
264
264
 
265
+ ## 配置驱动认证页面
266
+
267
+ 协议支持配置中的 userAgreementMarkdown/privacyPolicyMarkdown 正文及 URL;同主题优先 Markdown,由安全渲染器在弹窗显示。
268
+
269
+ 路由直接导出 `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。
270
+
271
+ [完整 IAM 配置 / IAM configuration](../iam/README.md)
272
+
265
273
  ## 错误处理
266
274
 
267
275
  - 推荐使用 `kit.handler()` 包装 API 端点。
package/dist/browser.d.ts CHANGED
@@ -1,9 +1,10 @@
1
- import { c as createKitClient, i as installBrowserTransport, a as installBrowserTransportFetch, s as setBrowserToken, b as clearBrowserToken, d as createTokenStore } from './index-CglzrPiE.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, n as createSvelteKitNavAdapter, r as resolveKitConfig, o as resolveKitTransportConfig } from './index-CglzrPiE.js';
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
3
  import { d as defineCrud, s as setAllModulesLocale } from './kit-i18n-CjFHORw5.js';
4
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';
5
- import '@h-ai/crypto';
5
+ import '@h-ai/api-contract';
6
6
  import '@h-ai/core';
7
+ import '@h-ai/crypto';
7
8
  import '@h-ai/iam';
8
9
  import 'zod';
9
10
  import '@sveltejs/kit';
@@ -21,6 +22,7 @@ import '@sveltejs/kit';
21
22
  declare const kit: {
22
23
  client: {
23
24
  create: typeof createKitClient;
25
+ createAuthActions: typeof createKitAuthActions;
24
26
  installBrowserTransport: typeof installBrowserTransport;
25
27
  installBrowserTransportFetch: typeof installBrowserTransportFetch;
26
28
  };
@@ -37,4 +39,4 @@ declare const kit: {
37
39
  };
38
40
  };
39
41
 
40
- export { createKitClient, installBrowserTransport, installBrowserTransportFetch, kit };
42
+ export { createKitAuthActions, createKitClient, installBrowserTransport, installBrowserTransportFetch, kit };
package/dist/browser.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { defineCrud } from './chunk-L7BTMAKX.js';
2
2
  export { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig } from './chunk-L7BTMAKX.js';
3
- import { createTokenStore, clearBrowserToken, setBrowserToken, installBrowserTransportFetch, installBrowserTransport, createKitClient } from './chunk-CTIN5EQP.js';
3
+ import { createTokenStore, clearBrowserToken, setBrowserToken, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient } from './chunk-VOTDAVCB.js';
4
4
  import './chunk-NVYIUBU7.js';
5
5
  import { setAllModulesLocale } from './chunk-QHYNL24G.js';
6
6
 
@@ -8,6 +8,7 @@ import { setAllModulesLocale } from './chunk-QHYNL24G.js';
8
8
  var kit = {
9
9
  client: {
10
10
  create: createKitClient,
11
+ createAuthActions: createKitAuthActions,
11
12
  installBrowserTransport,
12
13
  installBrowserTransportFetch
13
14
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/browser.ts"],"names":[],"mappings":";;;;;;;AAgBO,IAAM,GAAA,GAAM;AAAA,EACjB,MAAA,EAAQ;AAAA,IACN,MAAA,EAAQ,eAAA;AAAA,IACR,uBAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,eAAA;AAAA,IACA,iBAAA;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 { createKitClient, installBrowserTransport, installBrowserTransportFetch } from './client/kit-client.js'\nimport { defineCrud } from './crud/kit-crud.js'\nimport { clearBrowserToken, createTokenStore, 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 */\nexport const kit = {\n client: {\n create: createKitClient,\n installBrowserTransport,\n installBrowserTransportFetch,\n },\n crud: {\n define: defineCrud,\n },\n auth: {\n setBrowserToken,\n clearBrowserToken,\n createTokenStore,\n },\n i18n: {\n setLocale: setAllModulesLocale,\n },\n}\n\nexport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig }\n\nexport type * from './client/index.js'\nexport type * from './kit-types.js'\n"]}
1
+ {"version":3,"sources":["../src/browser.ts"],"names":[],"mappings":";;;;;;;AAiBO,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,iBAAA;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, createTokenStore, 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 */\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 createTokenStore,\n },\n i18n: {\n setLocale: setAllModulesLocale,\n },\n}\n\nexport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig }\n\nexport type * from './client/index.js'\nexport type * from './kit-types.js'\n"]}
@@ -1,8 +1,10 @@
1
1
  import { resolveTransportPath, DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH, shouldUseTransportForUrl } from './chunk-NVYIUBU7.js';
2
2
  import { kitM } from './chunk-QHYNL24G.js';
3
3
  import process from 'process';
4
- import { err } from '@h-ai/core';
4
+ import { ok, err } from '@h-ai/core';
5
5
  import { TRANSPORT_PROTOCOL } from '@h-ai/crypto';
6
+ import { apiContract, IamPublicConfigSchema } from '@h-ai/api-contract';
7
+ import { z } from 'zod';
6
8
 
7
9
  var DEFAULT_TOKEN_COOKIE_NAME = "hai_access_token";
8
10
  var authState = {
@@ -266,7 +268,33 @@ function createKitClient(config = {}) {
266
268
  }
267
269
  };
268
270
  }
271
+ function createKitAuthActions(options = {}) {
272
+ const apiFetch = options.apiFetch ?? createKitClient().apiFetch;
273
+ const base = options.basePath ?? "/api/auth";
274
+ async function post(path, input) {
275
+ const response = await apiFetch(`${base}/${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(input) });
276
+ const result = apiContract.haiResultSchema(z.unknown().optional()).parse(await response.json());
277
+ return result.success ? ok(result.data) : result;
278
+ }
279
+ return {
280
+ async publicConfig() {
281
+ const response = await apiFetch(`${base}/config`);
282
+ return apiContract.haiResultSchema(IamPublicConfigSchema.nullable()).parse(await response.json());
283
+ },
284
+ login(input) {
285
+ if (input.method === "ldap")
286
+ return post("login/ldap", { username: input.identifier, password: input.password });
287
+ if (input.method === "email" || input.method === "sms")
288
+ return post("login/otp", { identifier: input.identifier, code: input.code });
289
+ return post("login", { identifier: input.identifier, password: input.password, rememberMe: input.rememberMe });
290
+ },
291
+ register: (input) => post("register", { ...input, confirmPassword: input.password }),
292
+ sendOtp: (identifier) => post("otp/send", { identifier }),
293
+ requestPasswordReset: (identifier) => post("password-reset/request", { identifier }),
294
+ confirmPasswordReset: (token, newPassword) => post("password-reset/confirm", { token, newPassword })
295
+ };
296
+ }
269
297
 
270
- export { clearBrowserToken, configureAuth, createKitClient, createTokenStore, getAccessToken, installBrowserTransport, installBrowserTransportFetch, login, loginWithApiKey, loginWithLdap, loginWithOtp, logout, registerAndLogin, setBrowserToken };
271
- //# sourceMappingURL=chunk-CTIN5EQP.js.map
272
- //# sourceMappingURL=chunk-CTIN5EQP.js.map
298
+ export { clearBrowserToken, configureAuth, createKitAuthActions, createKitClient, createTokenStore, getAccessToken, installBrowserTransport, installBrowserTransportFetch, login, loginWithApiKey, loginWithLdap, loginWithOtp, logout, registerAndLogin, setBrowserToken };
299
+ //# sourceMappingURL=chunk-VOTDAVCB.js.map
300
+ //# sourceMappingURL=chunk-VOTDAVCB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/kit-auth.ts","../src/client/kit-client.ts","../src/client/kit-client-auth.ts"],"names":[],"mappings":"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","file":"chunk-VOTDAVCB.js","sourcesContent":["/**\n * @h-ai/kit — Bearer 认证工具\n *\n * 提供服务端认证 Cookie 管理(login / logout)与浏览器端 Token 存储工具。\n * @module kit-auth\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ApiKeyCredentials, AuthResult, LdapCredentials, OtpCredentials, PasswordCredentials, RegisterOptions } from '@h-ai/iam'\nimport type { AuthOperations, AuthOperationsProvider } from './kit-types.js'\nimport process from 'node:process'\nimport { err } from '@h-ai/core'\nimport { kitM } from './kit-i18n.js'\n\n/** 默认 Token Cookie 名 */\nconst DEFAULT_TOKEN_COOKIE_NAME = 'hai_access_token'\n\n/**\n * 应用级认证配置(由 createHandle 一次性初始化,生命周期同进程)\n *\n * 此状态非请求级:仅在 createHandle() 时写入一次,后续所有请求只读访问。\n */\nconst authState = {\n cookieName: DEFAULT_TOKEN_COOKIE_NAME,\n operations: null as AuthOperationsProvider | null,\n}\n\n/**\n * 配置认证参数\n *\n * 通常由 `createHandle` 在初始化时自动调用,无需手动调用。\n */\nexport function configureAuth(config: { cookieName?: string, operations?: AuthOperationsProvider }): void {\n if (config.cookieName)\n authState.cookieName = config.cookieName\n if (config.operations)\n authState.operations = config.operations\n}\n\ninterface CookieReader {\n get: (name: string) => string | undefined\n}\n\ninterface CookieWriter {\n set: (name: string, value: string, options: {\n path: string\n httpOnly: boolean\n sameSite: 'lax' | 'strict' | 'none'\n secure: boolean\n maxAge?: number\n }) => void\n delete: (name: string, options: { path: string }) => void\n}\n\n/** 浏览器 Token 存储器 */\nexport interface BrowserTokenStore {\n get: () => string | null\n set: (token: string) => void\n clear: () => void\n}\n\nfunction createMemoryTokenStore(): BrowserTokenStore {\n let token: string | null = null\n return {\n get: () => token,\n set: (value: string) => { token = value },\n clear: () => { token = null },\n }\n}\n\n// 默认浏览器 Token 只保存在当前页面内存中,避免 auth: true 隐式落到 localStorage。\nconst defaultBrowserTokenStore = createMemoryTokenStore()\n\n/** 获取默认浏览器 Token 存储(页面内存,不持久化)。 */\nexport function getDefaultBrowserTokenStore(): BrowserTokenStore {\n return defaultBrowserTokenStore\n}\n\n// ─── 内部工具(仅 kit 包内使用) ───\n\n/**\n * 从请求 Authorization 头提取 Bearer Token。\n */\nfunction getBearerTokenFromRequest(request: Request): string | null {\n const authorization = request.headers.get('authorization')\n if (!authorization)\n return null\n\n const [scheme, token] = authorization.split(' ')\n if (!scheme || !token)\n return null\n\n if (scheme.toLowerCase() !== 'bearer')\n return null\n\n const trimmed = token.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\n/**\n * 从请求中统一提取 Access Token(Bearer 优先,其次配置的 Cookie 名)。\n */\nexport function getAccessToken(request: Request, cookies?: CookieReader): string | null {\n return getBearerTokenFromRequest(request) ?? cookies?.get(authState.cookieName) ?? null\n}\n\n// ─── 服务端认证 Cookie 管理 ───\n\n/**\n * 写入 Access Token Cookie(内部使用,由 login 自动调用)。\n */\nfunction setToken(cookies: CookieWriter, token: string, maxAge?: number): void {\n cookies.set(authState.cookieName, token, {\n path: '/',\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge,\n })\n}\n\n/**\n * 清除 Access Token Cookie(内部使用,由 logout 自动调用)。\n */\nfunction clearToken(cookies: CookieWriter): void {\n cookies.delete(authState.cookieName, { path: '/' })\n}\n\n// ─── 服务端高级认证 API(通过 kit.auth 暴露) ───\n\n/**\n * 获取已注入的认证操作;未配置时返回 null。\n *\n * 公共 API 不应 throw,因此此处用 null 信号配合上层短路返回 HaiResult。\n */\nfunction getAuthOperations(): AuthOperations | null {\n if (!authState.operations)\n return null\n return typeof authState.operations === 'function'\n ? authState.operations()\n : authState.operations\n}\n\n/**\n * 构造 \"auth 未配置\" 的标准 HaiResult 错误。\n *\n * 用于公共认证 API 在 `authState.operations` 未注入时返回,\n * 避免向调用方抛出未捕获异常。\n */\nfunction authNotConfiguredError(): HaiResult<never> {\n return err({\n code: 'KIT_AUTH_NOT_CONFIGURED',\n message: kitM('kit_authNotConfigured'),\n })\n}\n\n/**\n * 执行已配置的认证登录操作,并在成功时写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - 认证凭证\n * @param run - 具体 IAM 认证操作\n */\nasync function runAuthLogin<TCredentials>(\n cookies: CookieWriter,\n credentials: TCredentials,\n run: (ops: AuthOperations, credentials: TCredentials) => Promise<HaiResult<AuthResult>>,\n): Promise<HaiResult<AuthResult>> {\n const ops = getAuthOperations()\n if (!ops)\n return authNotConfiguredError()\n\n const result = await run(ops, credentials)\n if (result.success) {\n setToken(cookies, result.data.tokens.accessToken, result.data.tokens.expiresIn)\n }\n return result\n}\n\n/**\n * 服务端登录(密码):内部调用 iam.auth.login,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - 密码凭证(identifier + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.login(cookies, { identifier, password })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * const { user, roles, permissions } = result.data\n * ```\n */\nexport async function login(\n cookies: CookieWriter,\n credentials: PasswordCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.login(input))\n}\n\n/**\n * 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - OTP 凭证(identifier + code)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithOtp(cookies, { identifier, code })\n * ```\n */\nexport async function loginWithOtp(\n cookies: CookieWriter,\n credentials: OtpCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.loginWithOtp(input))\n}\n\n/**\n * 服务端登录(LDAP):内部调用 iam.auth.loginWithLdap,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - LDAP 凭证(username + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithLdap(cookies, { username, password })\n * ```\n */\nexport async function loginWithLdap(\n cookies: CookieWriter,\n credentials: LdapCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.loginWithLdap(input))\n}\n\n/**\n * 服务端登录(API Key):内部调用 iam.auth.loginWithApiKey,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - API Key 凭证(key)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithApiKey(cookies, { key: apiKey })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * ```\n */\nexport async function loginWithApiKey(\n cookies: CookieWriter,\n credentials: ApiKeyCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.loginWithApiKey(input))\n}\n\n/**\n * 服务端注册并登录:内部调用 iam.auth.registerAndLogin,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param options - 注册选项(username、password、email 等)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.registerAndLogin(cookies, { username, email, password })\n * ```\n */\nexport async function registerAndLogin(\n cookies: CookieWriter,\n options: RegisterOptions,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, options, (ops, input) => ops.registerAndLogin(input))\n}\n\n/**\n * 服务端登出:内部调用 iam.auth.logout 使会话失效,并清除 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param accessToken - 访问令牌(为 null/undefined 时仅清除 Cookie)\n *\n * @example\n * ```ts\n * await kit.auth.logout(cookies, locals.accessToken)\n * return kit.response.ok(null)\n * ```\n */\nexport async function logout(\n cookies: CookieWriter,\n accessToken?: string | null,\n): Promise<void> {\n // 即使 auth 未配置也需要清除 Cookie,保证登出语义幂等\n const ops = getAuthOperations()\n if (accessToken && ops) {\n await ops.logout(accessToken)\n }\n clearToken(cookies)\n}\n\n// ─── 浏览器端 Token 存储(通过 kit.auth 暴露) ───\n\n/**\n * 创建浏览器端 Token 存储器(localStorage)。\n *\n * ⚠️ 安全提示:localStorage 对同源脚本可读,任意 XSS 都可能窃取 Token。\n * 本函数仅供调用方显式接受风险时使用;`kit.client.create({ auth: true })`\n * 不会默认调用它。\n *\n * @param key - localStorage 键名,默认 `'hai_access_token'`\n */\nexport function createTokenStore(key = DEFAULT_TOKEN_COOKIE_NAME): BrowserTokenStore {\n return {\n get(): string | null {\n if (typeof window === 'undefined') {\n return null\n }\n return window.localStorage.getItem(key)\n },\n set(token: string): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.setItem(key, token)\n },\n clear(): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.removeItem(key)\n },\n }\n}\n\n/**\n * 写入默认浏览器端 Access Token(仅页面内存,不持久化到 localStorage)。\n */\nexport function setBrowserToken(token: string): void {\n defaultBrowserTokenStore.set(token)\n}\n\n/**\n * 清除默认浏览器端 Access Token(仅页面内存)。\n */\nexport function clearBrowserToken(): void {\n defaultBrowserTokenStore.clear()\n}\n","/**\n * @h-ai/kit — 统一客户端\n *\n * 将 CSRF Token 附加与可选传输加密封装为统一 `apiFetch`。\n * 应用层只需调用一次 `createKitClient()`,后续 API 调用即可复用同一套安全能力。\n * @module kit-client\n */\n\nimport type { CryptoFunctions, TransportClient } from '@h-ai/crypto'\nimport type { BrowserTokenStore } from '../kit-auth.js'\nimport type { KitConfig } from '../kit-config.js'\nimport { TRANSPORT_PROTOCOL } from '@h-ai/crypto'\nimport { getDefaultBrowserTokenStore } from '../kit-auth.js'\nimport { DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH, resolveTransportPath, shouldUseTransportForUrl } from '../modules/crypto/kit-transport-paths.js'\n\nconst DEFAULT_KEY_EXCHANGE_URL = `/api${TRANSPORT_PROTOCOL.DEFAULT_KEY_EXCHANGE_PATH}`\n\n// ─── 类型 ───\n\n/**\n * 传输加密客户端配置\n */\nexport interface ClientTransportConfig {\n /** @h-ai/crypto 服务实例 */\n crypto: CryptoFunctions\n /** 密钥交换端点 URL(默认 `'/api/_hai/key-exchange'`) */\n keyExchangeUrl?: string\n /** 排除路径(命中后强制走明文),需与服务端 transport.excludePaths 保持一致 */\n excludePaths?: string[]\n}\n\n/**\n * Kit 客户端配置\n */\nexport interface KitClientConfig {\n /**\n * 传输加密配置。\n * - 不提供 / undefined:不启用传输加密,仅 CSRF\n * - 提供对象:启用传输加密\n */\n transport?: ClientTransportConfig\n /** CSRF Cookie 名称(默认 `'hai_csrf'`) */\n csrfCookieName?: string\n /** CSRF Header 名称(默认 `'X-CSRF-Token'`) */\n csrfHeaderName?: string\n /**\n * 认证配置:自动从浏览器存储读取 Access Token 并注入请求头。\n * - `true`:使用默认页面内存存储(由 `kit.auth.setBrowserToken()` 写入,不读写 localStorage)\n * - `BrowserTokenStore`:使用自定义存储\n * - 不提供 / `false`:不自动注入\n */\n auth?: boolean | BrowserTokenStore\n}\n\n/**\n * Kit 客户端实例\n */\nexport interface KitClient {\n /** 统一 API fetch(写请求自动附加 CSRF,启用 transport 时自动加解密) */\n apiFetch: (url: string, init?: RequestInit) => Promise<Response>\n /** 传输加密是否就绪(未启用传输加密时始终为 true) */\n readonly ready: boolean\n /**\n * 手动触发密钥交换(transport 启用时)。\n *\n * 注意:本方法是 Client 形态的合规例外,密钥协商失败时 `throw`(与 `@h-ai/api-client` 一致),\n * 调用方需自行 `try/catch`,不返回 `HaiResult`。\n */\n init: () => Promise<void>\n /** 销毁密钥状态 */\n destroy: () => void\n}\n\n// ─── 工具函数 ───\n\n/**\n * 从 document.cookie 中读取指定名称的 Cookie 值\n *\n * @param name - Cookie 名称\n * @returns Cookie 值;不存在或运行在服务端时返回 undefined\n */\nfunction getCookie(name: string): string | undefined {\n if (typeof document === 'undefined')\n return undefined\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n return match?.[1]\n}\n\n/**\n * 判断当前请求体是否可以作为文本载荷进行传输加密。\n *\n * 传输加密中间件会把解密后的明文重新注入 `Request`,当前仅能可靠保留\n * JSON 字符串请求体。`FormData` / `Blob` / `ArrayBuffer` 等二进制或浏览器\n * 自动生成边界的请求体必须保持原样发送,否则文件上传会被序列化成 `{}`。\n *\n * @param body fetch 请求体\n * @returns 是否支持客户端传输加密\n */\nfunction canEncryptRequestBody(body: BodyInit | null | undefined): boolean {\n return body === undefined || body === null || typeof body === 'string'\n}\n\n/**\n * 判断全局 fetch 包装路径下,某个 `Request` 是否可走传输加密。\n *\n * 与上方 {@link canEncryptRequestBody} 区别:本谓词服务于 {@link installBrowserTransportFetch}\n * 的全局包装路径,输入是完整 `Request`,故可基于 method(GET/HEAD 无 body 安全放行)与\n * `Content-Type`(仅 JSON 可重注入明文)综合判定;而 `canEncryptRequestBody` 服务于\n * `createKitClient` 的 `apiFetch` 路径,仅拿到 `BodyInit`,只能按 body 类型粗判。\n * 两者判定维度不同是有意为之,请勿合并。\n */\nfunction canUseTransportForRequest(request: Request): boolean {\n const method = request.method.toUpperCase()\n if (method === 'GET' || method === 'HEAD') {\n return true\n }\n\n const headers = new Headers(request.headers)\n const contentType = headers.get('Content-Type') ?? ''\n if (contentType.includes('application/json')) {\n return true\n }\n\n return request.body === null\n}\n\nfunction getCurrentOrigin(): string {\n if (typeof window !== 'undefined' && window.location?.origin) {\n return window.location.origin\n }\n\n return 'http://localhost'\n}\n\nfunction toRequest(input: RequestInfo | URL, init?: RequestInit): Request {\n if (input instanceof Request)\n return init ? new Request(input, init) : input\n\n return new Request(input, init)\n}\n\ntype BrowserTransportFetchState = typeof globalThis & {\n __haiKitOriginalFetch?: typeof fetch\n __haiKitTransportFetchInstalled?: boolean\n}\n\n/**\n * 在浏览器启动时安装同源 transport fetch 包装。\n *\n * 该包装作用于同源 `/api/*` 与 SvelteKit `__data.json` 请求,页面文档、\n * 静态资源以及 multipart/form-data 等上传请求保持原样。应用只需安装一次,\n * 后续 `fetch` / SvelteKit 内部 data fetch / `kit.client.create()` 明文发送路径\n * 都会共用这层传输加密能力。\n */\nexport function installBrowserTransportFetch(transportConfig?: ClientTransportConfig): void {\n if (typeof window === 'undefined' || !transportConfig)\n return\n\n const fetchState = globalThis as BrowserTransportFetchState\n if (fetchState.__haiKitTransportFetchInstalled)\n return\n\n const originalFetch = fetchState.__haiKitOriginalFetch ?? globalThis.fetch.bind(globalThis)\n fetchState.__haiKitOriginalFetch = originalFetch\n\n const origin = getCurrentOrigin()\n const keyExchangeUrl = new URL(transportConfig.keyExchangeUrl ?? DEFAULT_KEY_EXCHANGE_URL, origin).toString()\n const keyExchangePath = resolveTransportPath(keyExchangeUrl, origin)\n const transportClient = transportConfig.crypto.transport.createClient({\n keyExchangeUrl,\n fetch: originalFetch,\n })\n\n const wrappedFetch: typeof fetch = async (input, init) => {\n const request = toRequest(input, init)\n const requestUrl = new URL(request.url, origin)\n const headers = new Headers(request.headers)\n\n if (!shouldUseTransportForUrl(requestUrl, {\n origin,\n keyExchangePath,\n excludePaths: transportConfig.excludePaths,\n })) {\n return originalFetch(input, init)\n }\n\n if (headers.has(TRANSPORT_PROTOCOL.CLIENT_ID_HEADER))\n return originalFetch(input, init)\n\n if (!canUseTransportForRequest(request))\n return originalFetch(input, init)\n\n return transportClient.encryptedFetch(request)\n }\n\n globalThis.fetch = wrappedFetch\n window.fetch = wrappedFetch\n fetchState.__haiKitTransportFetchInstalled = true\n}\n\n/**\n * 用 `config/_kit.yml` 解析后的 {@link KitConfig} 一次性安装浏览器端传输加密。\n *\n * 行为:\n * - `config.transport === false` 时直接返回(不启用传输加密);\n * - 否则启动 {@link installBrowserTransportFetch},并预热 {@link CryptoFunctions} 模块。\n *\n * 应用层(SvelteKit `+layout.svelte` 或浏览器入口)只需调用此函数一次,\n * 之后所有同源 `/api/*` 与 `__data.json` 请求都会自动走传输加密。\n *\n * @param config 已解析的 kit 顶层配置\n * @param deps 外部依赖\n * @param deps.crypto `@h-ai/crypto` 模块实例\n *\n * @example\n * ```ts\n * import { browser } from '$app/environment'\n * import { crypto } from '@h-ai/crypto'\n * import { kit } from '@h-ai/kit'\n * import { adminConsoleKitConfig } from '$lib/config/kit-config.js'\n *\n * if (browser) {\n * kit.client.installBrowserTransport(adminConsoleKitConfig, { crypto })\n * }\n * ```\n */\nexport function installBrowserTransport(\n config: KitConfig,\n deps: { crypto: CryptoFunctions },\n): void {\n if (typeof window === 'undefined' || config.transport === false)\n return\n\n // crypto.init() 当前为同步副作用(signature 是 async 仅为接口一致性),\n // 此处不 await,以便 `+layout.svelte` 顶层模块加载阶段就完成初始化。\n void deps.crypto.init()\n\n installBrowserTransportFetch({\n crypto: deps.crypto,\n keyExchangeUrl: config.transport.keyExchangePath,\n excludePaths: [...config.transport.excludePaths],\n })\n}\n\n// ─── 主函数 ───\n\n/**\n * 创建 Kit 客户端\n *\n * 返回统一的 `apiFetch`,内部自动完成:\n * 1. CSRF Token 附加(写方法自动读取 Cookie + 设置 Header)\n * 2. 密钥交换(首次写请求时 lazy init,transport 启用时)\n * 3. 请求体加密(transport 启用时)\n * 4. 响应体解密(transport 启用时)\n *\n * @param config - 客户端配置\n * @returns KitClient 实例\n *\n * @example\n * ```ts\n * const client = createKitClient({ transport: { crypto } })\n * const res = await client.apiFetch('/api/users', { method: 'POST', body: '{}' })\n * ```\n */\nexport function createKitClient(config: KitClientConfig = {}): KitClient {\n const {\n transport: transportConfig,\n csrfCookieName = 'hai_csrf',\n csrfHeaderName = 'X-CSRF-Token',\n auth: authConfig,\n } = config\n\n // ── Auth token store ──\n // 安全默认:auth:true 只读取页面内存 token,避免隐式 localStorage 持久化敏感凭证。\n const authStore: BrowserTokenStore | null = authConfig\n ? (authConfig === true ? getDefaultBrowserTokenStore() : authConfig)\n : null\n\n // ── 传输加密状态 ──\n const transportOrigin = getCurrentOrigin()\n const transportKeyExchangeUrl = transportConfig?.keyExchangeUrl ?? DEFAULT_KEY_EXCHANGE_URL\n const transportKeyExchangePath = transportConfig\n ? resolveTransportPath(transportKeyExchangeUrl, transportOrigin)\n : DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH\n const transportClient: TransportClient | null = transportConfig\n ? transportConfig.crypto.transport.createClient({\n keyExchangeUrl: transportKeyExchangeUrl,\n fetch,\n })\n : null\n\n /**\n * 统一 API fetch\n */\n async function apiFetch(url: string, init: RequestInit = {}): Promise<Response> {\n const method = (init.method ?? 'GET').toUpperCase()\n const isWriteMethod = !['GET', 'HEAD', 'OPTIONS'].includes(method)\n const canUseTransport = canEncryptRequestBody(init.body)\n\n const headers = new Headers(init.headers)\n\n // ── Auth ──\n if (authStore) {\n const token = authStore.get()\n if (token) {\n headers.set('Authorization', `Bearer ${token}`)\n }\n }\n\n // ── CSRF ──\n if (isWriteMethod) {\n const csrfToken = getCookie(csrfCookieName)\n if (csrfToken) {\n headers.set(csrfHeaderName, csrfToken)\n }\n }\n\n // ── 传输加密 ──\n if (\n transportClient\n && canUseTransport\n && shouldUseTransportForUrl(url, {\n origin: transportOrigin,\n keyExchangePath: transportKeyExchangePath,\n excludePaths: transportConfig?.excludePaths,\n })\n ) {\n return transportClient.encryptedFetch(url, { ...init, headers })\n }\n\n // ── 发送(FormData/Blob/Stream 等保持原样,不破坏浏览器边界) ──\n return fetch(url, { ...init, headers })\n }\n\n return {\n apiFetch,\n get ready() { return !transportClient || transportClient.ready() },\n async init() {\n if (!transportClient)\n return\n const result = await transportClient.init()\n if (!result.success)\n throw new Error(result.error.message)\n },\n destroy() {\n transportClient?.destroy()\n },\n }\n}\n","/** 与标准 Kit 认证端点配套的表单动作;复用已有 CSRF/transport fetch。 */\nimport type { IamLoginInput, IamPublicConfig, IamRegisterInput } from '@h-ai/api-contract'\nimport type { HaiResult } from '@h-ai/core'\nimport type { KitClient } from './kit-client.js'\nimport { apiContract, IamPublicConfigSchema } from '@h-ai/api-contract'\nimport { ok } from '@h-ai/core'\nimport { z } from 'zod'\nimport { createKitClient } from './kit-client.js'\n\nexport function createKitAuthActions(options: { apiFetch?: KitClient['apiFetch'], basePath?: string } = {}) {\n const apiFetch = options.apiFetch ?? createKitClient().apiFetch\n const base = options.basePath ?? '/api/auth'\n async function post(path: string, input: object): Promise<HaiResult<unknown>> {\n const response = await apiFetch(`${base}/${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(input) })\n // void 成功响应在 JSON 中省略 data,统一还原为 HaiResult 的 data: undefined。\n const result = apiContract.haiResultSchema(z.unknown().optional()).parse(await response.json())\n return result.success ? ok(result.data) : result\n }\n return {\n async publicConfig(): Promise<HaiResult<IamPublicConfig | null>> {\n const response = await apiFetch(`${base}/config`)\n return apiContract.haiResultSchema(IamPublicConfigSchema.nullable()).parse(await response.json())\n },\n login(input: IamLoginInput & { method?: 'password' | 'ldap' | 'email' | 'sms', code?: string }) {\n if (input.method === 'ldap')\n return post('login/ldap', { username: input.identifier, password: input.password })\n if (input.method === 'email' || input.method === 'sms')\n return post('login/otp', { identifier: input.identifier, code: input.code })\n return post('login', { identifier: input.identifier, password: input.password, rememberMe: input.rememberMe })\n },\n register: (input: IamRegisterInput) => post('register', { ...input, confirmPassword: input.password }),\n sendOtp: (identifier: string) => post('otp/send', { identifier }),\n requestPasswordReset: (identifier: string) => post('password-reset/request', { identifier }),\n confirmPasswordReset: (token: string, newPassword: string) => post('password-reset/confirm', { token, newPassword }),\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
- export { C as ClientTransportConfig, K as KitClient, e as KitClientConfig, c as createKitClient, n as createSvelteKitNavAdapter, i as installBrowserTransport, a as installBrowserTransportFetch } from '../index-CglzrPiE.js';
2
- import '@h-ai/crypto';
1
+ export { C as ClientTransportConfig, K as KitClient, f as KitClientConfig, a as createKitAuthActions, c as createKitClient, o as createSvelteKitNavAdapter, i as installBrowserTransport, b as installBrowserTransportFetch } from '../index-B7s-0mZl.js';
2
+ import '@h-ai/api-contract';
3
3
  import '@h-ai/core';
4
+ import '@h-ai/crypto';
4
5
  import '@h-ai/iam';
5
6
  import 'zod';
@@ -1,4 +1,4 @@
1
- export { createKitClient, installBrowserTransport, installBrowserTransportFetch } from '../chunk-CTIN5EQP.js';
1
+ export { createKitAuthActions, createKitClient, installBrowserTransport, installBrowserTransportFetch } from '../chunk-VOTDAVCB.js';
2
2
  import '../chunk-NVYIUBU7.js';
3
3
  import '../chunk-QHYNL24G.js';
4
4
  import { invalidateAll, goto } from '$app/navigation';
@@ -1,5 +1,6 @@
1
- import { CryptoFunctions } from '@h-ai/crypto';
1
+ import { IamPublicConfig, IamLoginInput, IamRegisterInput } from '@h-ai/api-contract';
2
2
  import { HaiResult } from '@h-ai/core';
3
+ import { CryptoFunctions } from '@h-ai/crypto';
3
4
  import { PasswordCredentials, AuthResult, OtpCredentials, LdapCredentials, ApiKeyCredentials, RegisterOptions } from '@h-ai/iam';
4
5
  import { z } from 'zod';
5
6
 
@@ -329,6 +330,23 @@ declare function installBrowserTransport(config: KitConfig, deps: {
329
330
  */
330
331
  declare function createKitClient(config?: KitClientConfig): KitClient;
331
332
 
333
+ /** 与标准 Kit 认证端点配套的表单动作;复用已有 CSRF/transport fetch。 */
334
+
335
+ declare function createKitAuthActions(options?: {
336
+ apiFetch?: KitClient['apiFetch'];
337
+ basePath?: string;
338
+ }): {
339
+ publicConfig(): Promise<HaiResult<IamPublicConfig | null>>;
340
+ login(input: IamLoginInput & {
341
+ method?: "password" | "ldap" | "email" | "sms";
342
+ code?: string;
343
+ }): Promise<HaiResult<unknown>>;
344
+ register: (input: IamRegisterInput) => Promise<HaiResult<unknown>>;
345
+ sendOtp: (identifier: string) => Promise<HaiResult<unknown>>;
346
+ requestPasswordReset: (identifier: string) => Promise<HaiResult<unknown>>;
347
+ confirmPasswordReset: (token: string, newPassword: string) => Promise<HaiResult<unknown>>;
348
+ };
349
+
332
350
  /**
333
351
  * @h-ai/kit — SvelteKit 路由适配器
334
352
  *
@@ -366,4 +384,4 @@ declare function createSvelteKitNavAdapter(): {
366
384
  readonly refresh: () => Promise<void>;
367
385
  };
368
386
 
369
- export { type ClientTransportConfig as C, type KitClient as K, installBrowserTransportFetch as a, clearBrowserToken as b, createKitClient as c, createTokenStore as d, type KitClientConfig as e, type KitConfig as f, type KitConfigInput as g, KitConfigSchema as h, installBrowserTransport as i, type KitServerConfig as j, type KitServerConfigInput as k, type KitTransportConfig as l, type KitTransportConfigInput as m, createSvelteKitNavAdapter as n, resolveKitTransportConfig as o, login as p, loginWithOtp as q, resolveKitConfig as r, setBrowserToken as s, loginWithLdap as t, loginWithApiKey as u, registerAndLogin as v, logout as w };
387
+ export { type ClientTransportConfig as C, type KitClient as K, createKitAuthActions as a, installBrowserTransportFetch as b, createKitClient as c, clearBrowserToken as d, createTokenStore as e, type KitClientConfig as f, type KitConfig as g, type KitConfigInput as h, installBrowserTransport as i, KitConfigSchema as j, type KitServerConfig as k, type KitServerConfigInput as l, type KitTransportConfig as m, type KitTransportConfigInput as n, createSvelteKitNavAdapter as o, resolveKitTransportConfig as p, login as q, resolveKitConfig as r, setBrowserToken as s, loginWithOtp as t, loginWithLdap as u, loginWithApiKey as v, registerAndLogin as w, logout as x };
package/dist/index.d.ts CHANGED
@@ -1,19 +1,21 @@
1
- import { c as createKitClient, i as installBrowserTransport, a as installBrowserTransportFetch, p as login, q as loginWithOtp, t as loginWithLdap, u as loginWithApiKey, v as registerAndLogin, w as logout, s as setBrowserToken, b as clearBrowserToken, d as createTokenStore } from './index-CglzrPiE.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, n as createSvelteKitNavAdapter, r as resolveKitConfig, o as resolveKitTransportConfig } from './index-CglzrPiE.js';
1
+ import { c as createKitClient, a as createKitAuthActions, i as installBrowserTransport, b as installBrowserTransportFetch, q as login, t as loginWithOtp, u as loginWithLdap, v as loginWithApiKey, w as registerAndLogin, x as logout, 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
3
  import { d as defineCrud, s as setAllModulesLocale } from './kit-i18n-CjFHORw5.js';
4
4
  export { C as CrudApiDef, a as CrudFieldDef, b as CrudFieldOption, c as CrudFieldOptions, e as CrudFieldType, f as CrudFieldValidation, g as CrudFilterParams, h as CrudOperations, i as CrudPaginatedResult, j as CrudPaginationParams, k as CrudResourceDef, l as CrudTableColumn, m as CrudText, r as resolveOptions, n as resolveText } from './kit-i18n-CjFHORw5.js';
5
5
  import { S as SessionData, k as RouteGuard, l as SessionLike, h as HandleConfig, C as CorsConfig, M as Middleware } from './kit-types-ByWdbCeO.js';
6
6
  export { A as ApiResponse, a as AuthOperations, b as AuthOperationsProvider, F as FormError, c as FormValidationResult, G as GuardConfig, d as GuardResult, H as HaiRequestEvent, e as HandleA2AConfig, f as HandleA2AOperations, g as HandleAuthConfig, i as HookCryptoConfig, m as MemoryRateLimitStore, j as MiddlewareContext, R as RateLimitConfig, n as RateLimitEntry, o as RateLimitStore, T as TransportEncryptionOptions, r as rateLimitMiddleware } from './kit-types-ByWdbCeO.js';
7
+ import * as _sveltejs_kit from '@sveltejs/kit';
7
8
  import { RequestEvent, Cookies, Handle, RequestHandler } from '@sveltejs/kit';
8
9
  import { CryptoFunctions } from '@h-ai/crypto';
9
10
  export { EncryptedPayload, TransportEncryptionManager, TransportKeyPair } from '@h-ai/crypto';
10
11
  import * as zod_v4_core from 'zod/v4/core';
11
12
  import * as zod from 'zod';
12
13
  import { z } from 'zod';
14
+ import { IamFunctions } from '@h-ai/iam';
13
15
  import { HaiError } from '@h-ai/core';
14
16
  export { A2AApiKeyAuthConfig, KitA2AHandlerConfig, ResolvedA2AConfig, createA2AApiKeyAuthenticator, createA2AHandler, createAgentCardHandler, handleA2ARequest, resolveA2AConfig } from './modules/a2a/index.js';
15
17
  export { CryptoCsrfConfig, CryptoServiceLike, EncryptedCookieConfig, TransportEncryptionConfig, WebhookVerifyConfig, createCsrfManager, createEncryptedCookie, signRequest, transportEncryptionMiddleware, verifyWebhookSignature } from './modules/crypto/index.js';
16
- import '@h-ai/iam';
18
+ import '@h-ai/api-contract';
17
19
 
18
20
  /**
19
21
  * @h-ai/kit — 认证守卫
@@ -423,6 +425,18 @@ declare function createHandle(config?: HandleConfig): Handle;
423
425
  */
424
426
  declare function sequence(...handles: Handle[]): Handle;
425
427
 
428
+ /** 应用路由直接导出对应 handler;认证 ops 仍由 createHandle 注入。 */
429
+ declare function createAuthApi(iam: IamFunctions): {
430
+ publicConfig: _sveltejs_kit.RequestHandler;
431
+ login: _sveltejs_kit.RequestHandler;
432
+ loginWithLdap: _sveltejs_kit.RequestHandler;
433
+ loginWithOtp: _sveltejs_kit.RequestHandler;
434
+ register: _sveltejs_kit.RequestHandler;
435
+ sendOtp: _sveltejs_kit.RequestHandler;
436
+ requestPasswordReset: _sveltejs_kit.RequestHandler;
437
+ confirmPasswordReset: _sveltejs_kit.RequestHandler;
438
+ };
439
+
426
440
  /**
427
441
  * @h-ai/kit — API Handler 包装器
428
442
  *
@@ -792,6 +806,8 @@ declare const kit: {
792
806
  client: {
793
807
  /** 创建统一客户端(CSRF + 传输加密透明合并) */
794
808
  create: typeof createKitClient;
809
+ /** 标准认证表单动作(Cookie 模式)。 */
810
+ createAuthActions: typeof createKitAuthActions;
795
811
  /**
796
812
  * 用解析后的 {@link KitConfig} 一键安装浏览器端传输加密
797
813
  * (应用层推荐入口;内部预热 crypto 并调用 installBrowserTransportFetch)
@@ -801,6 +817,10 @@ declare const kit: {
801
817
  installBrowserTransportFetch: typeof installBrowserTransportFetch;
802
818
  };
803
819
  auth: {
820
+ /** 标准匿名认证端点白名单。 */
821
+ publicPaths: string[];
822
+ /** 标准配置/登录/注册/验证码/重置 handler 集合。 */
823
+ createApi: typeof createAuthApi;
804
824
  /** 服务端登录(密码):内部调用 iam.auth.login + 自动写入 Token Cookie */
805
825
  login: typeof login;
806
826
  /** 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp + 自动写入 Token Cookie */
@@ -899,4 +919,4 @@ interface LoggingMiddlewareConfig {
899
919
  */
900
920
  declare function loggingMiddleware(config?: LoggingMiddlewareConfig): Middleware;
901
921
 
902
- export { type AuthGuardConfig, type CookieProxyConfig, CorsConfig, HandleConfig, IdParamSchema, type LoggingMiddlewareConfig, Middleware, PaginationQuerySchema, type PermissionGuardConfig, type RoleGuardConfig, RouteGuard, SessionData, type SessionGuardConfig, SessionLike, allGuards, anyGuard, assertPermission, authGuard, conditionalGuard, corsMiddleware, createEncryptedCookieProxy, createHandle, createKitClient, defineCrud, hasPermission, installBrowserTransport, installBrowserTransportFetch, kit, loggingMiddleware, matchPermission, notGuard, permissionGuard, requirePermission, roleGuard, sequence, sessionGuard, withPermission };
922
+ export { type AuthGuardConfig, type CookieProxyConfig, CorsConfig, HandleConfig, IdParamSchema, type LoggingMiddlewareConfig, Middleware, PaginationQuerySchema, type PermissionGuardConfig, type RoleGuardConfig, RouteGuard, SessionData, type SessionGuardConfig, SessionLike, allGuards, anyGuard, assertPermission, authGuard, conditionalGuard, corsMiddleware, createEncryptedCookieProxy, createHandle, createKitAuthActions, createKitClient, defineCrud, hasPermission, installBrowserTransport, installBrowserTransportFetch, kit, loggingMiddleware, matchPermission, notGuard, permissionGuard, requirePermission, roleGuard, sequence, sessionGuard, withPermission };
package/dist/index.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { defineCrud } from './chunk-L7BTMAKX.js';
2
2
  export { KitConfigSchema, defineCrud, resolveKitConfig, resolveKitTransportConfig, resolveOptions, resolveText } from './chunk-L7BTMAKX.js';
3
- import { createTokenStore, clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitClient, configureAuth, getAccessToken } from './chunk-CTIN5EQP.js';
3
+ import { createTokenStore, clearBrowserToken, setBrowserToken, logout, registerAndLogin, loginWithApiKey, loginWithLdap, loginWithOtp, login, installBrowserTransportFetch, installBrowserTransport, createKitAuthActions, createKitClient, configureAuth, getAccessToken } from './chunk-VOTDAVCB.js';
4
4
  import { resolveA2AConfig, handleA2ARequest } from './chunk-DVW7CQ3H.js';
5
5
  import { transportEncryptionMiddleware } from './chunk-MLSP67JF.js';
6
6
  import './chunk-NVYIUBU7.js';
7
7
  import { kitM, setAllModulesLocale } from './chunk-QHYNL24G.js';
8
8
  import { core } from '@h-ai/core';
9
+ import { IamConfirmPasswordResetInputSchema, IamRequestPasswordResetInputSchema, IamSendOtpInputSchema, IamRegisterInputSchema, IamOtpLoginInputSchema, IamLdapLoginInputSchema, IamLoginInputSchema } from '@h-ai/api-contract';
9
10
  import { z } from 'zod';
10
11
 
11
12
  // src/guards/kit-permission.ts
@@ -724,6 +725,49 @@ var PaginationQuerySchema = z.object({
724
725
  search: z.string().optional()
725
726
  });
726
727
 
728
+ // src/kit-auth-api.ts
729
+ var authApiPublicPaths = ["/api/auth/config", "/api/auth/login", "/api/auth/login/ldap", "/api/auth/login/otp", "/api/auth/register", "/api/auth/otp/send", "/api/auth/password-reset/request", "/api/auth/password-reset/confirm"];
730
+ function createAuthApi(iam) {
731
+ function response(result) {
732
+ return result.success ? ok(result.data) : fromError(result.error);
733
+ }
734
+ return {
735
+ publicConfig: handler(() => ok(iam.publicConfig)),
736
+ login: handler(async ({ request, cookies }) => {
737
+ const input = await validateFormOrFail(request, IamLoginInputSchema);
738
+ const result = await login(cookies, input);
739
+ return result.success ? ok({ user: result.data.user }) : fromError(result.error);
740
+ }),
741
+ loginWithLdap: handler(async ({ request, cookies }) => {
742
+ const input = await validateFormOrFail(request, IamLdapLoginInputSchema);
743
+ const result = await loginWithLdap(cookies, input);
744
+ return result.success ? ok({ user: result.data.user }) : fromError(result.error);
745
+ }),
746
+ loginWithOtp: handler(async ({ request, cookies }) => {
747
+ const input = await validateFormOrFail(request, IamOtpLoginInputSchema);
748
+ const result = await loginWithOtp(cookies, input);
749
+ return result.success ? ok({ user: result.data.user }) : fromError(result.error);
750
+ }),
751
+ register: handler(async ({ request, cookies }) => {
752
+ const input = await validateFormOrFail(request, IamRegisterInputSchema);
753
+ const result = await registerAndLogin(cookies, input);
754
+ return result.success ? ok({ user: result.data.user }) : fromError(result.error);
755
+ }),
756
+ sendOtp: handler(async ({ request }) => {
757
+ const input = await validateFormOrFail(request, IamSendOtpInputSchema);
758
+ return response(await iam.auth.sendOtp(input.identifier));
759
+ }),
760
+ requestPasswordReset: handler(async ({ request }) => {
761
+ const input = await validateFormOrFail(request, IamRequestPasswordResetInputSchema);
762
+ return response(await iam.user.requestPasswordReset(input.identifier));
763
+ }),
764
+ confirmPasswordReset: handler(async ({ request }) => {
765
+ const input = await validateFormOrFail(request, IamConfirmPasswordResetInputSchema);
766
+ return response(await iam.user.confirmPasswordReset(input.token, input.newPassword));
767
+ })
768
+ };
769
+ }
770
+
727
771
  // src/kit-main.ts
728
772
  var kit = {
729
773
  // ─── Handle Hook ───
@@ -788,6 +832,8 @@ var kit = {
788
832
  client: {
789
833
  /** 创建统一客户端(CSRF + 传输加密透明合并) */
790
834
  create: createKitClient,
835
+ /** 标准认证表单动作(Cookie 模式)。 */
836
+ createAuthActions: createKitAuthActions,
791
837
  /**
792
838
  * 用解析后的 {@link KitConfig} 一键安装浏览器端传输加密
793
839
  * (应用层推荐入口;内部预热 crypto 并调用 installBrowserTransportFetch)
@@ -798,6 +844,10 @@ var kit = {
798
844
  },
799
845
  // ─── 认证工具 ───
800
846
  auth: {
847
+ /** 标准匿名认证端点白名单。 */
848
+ publicPaths: authApiPublicPaths,
849
+ /** 标准配置/登录/注册/验证码/重置 handler 集合。 */
850
+ createApi: createAuthApi,
801
851
  /** 服务端登录(密码):内部调用 iam.auth.login + 自动写入 Token Cookie */
802
852
  login,
803
853
  /** 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp + 自动写入 Token Cookie */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/guards/kit-permission.ts","../src/kit-utils.ts","../src/middleware/kit-logging.ts","../src/middleware/kit-ratelimit.ts","../src/hooks/kit-cookie-proxy.ts","../src/hooks/kit-handle.ts","../src/kit-response.ts","../src/kit-handler.ts","../src/kit-validation.ts","../src/kit-main.ts"],"names":["core","response","error","event","zod"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/kit — 权限守卫\n *\n * 验证用户是否具有指定权限。\n * @module kit-permission\n */\n\nimport type { GuardResult, RouteGuard, SessionLike } from '../kit-types.js'\nimport { kitM } from '../kit-i18n.js'\n\n/**\n * 权限守卫配置\n */\nexport interface PermissionGuardConfig {\n /** 需要的权限列表(默认 OR 逻辑,满足任一即通过) */\n permissions: string[]\n /** 为 `true` 时要求用户拥有 **全部** 权限(AND 逻辑) */\n requireAll?: boolean\n /** 无权限时重定向 URL(默认 `'/403'`) */\n forbiddenUrl?: string\n /** 为 `true` 时返回 JSON 403 而非重定向 */\n apiMode?: boolean\n}\n\n/**\n * 创建权限守卫\n *\n * 检查用户 `session.permissions` 是否满足配置中的权限要求。\n * 支持通配符匹配:`admin:*` 可匹配 `admin:read`、`admin:write` 等。\n * 未认证时返回 401;权限不匹配时根据 `apiMode` 返回 JSON 403 或重定向。\n *\n * @param config - 权限守卫配置\n * @returns RouteGuard 实例\n *\n * @example\n * ```ts\n * guards: [\n * { guard: kit.guard.permission({ permissions: ['user:read', 'user:write'], requireAll: true }), paths: ['/api/users/*'] },\n * ]\n * ```\n */\nexport function permissionGuard(config: PermissionGuardConfig): RouteGuard {\n const { permissions, requireAll = false, forbiddenUrl = '/403', apiMode = false } = config\n\n return (_event, session): GuardResult => {\n if (!session) {\n return {\n allowed: false,\n message: kitM('kit_authRequired'),\n status: 401,\n }\n }\n\n const userPermissions = session.permissions ?? []\n\n // 支持通配符权限,如 admin:* 匹配 admin:read, admin:write 等\n const hasPermission = requireAll\n ? permissions.every(perm => matchPermission(perm, userPermissions))\n : permissions.some(perm => matchPermission(perm, userPermissions))\n\n if (!hasPermission) {\n if (apiMode) {\n return {\n allowed: false,\n message: kitM('kit_requiredPermissions', { params: { permissions: permissions.join(', ') } }),\n status: 403,\n }\n }\n\n return {\n allowed: false,\n redirect: forbiddenUrl,\n }\n }\n\n return { allowed: true }\n }\n}\n\n/**\n * 匹配权限\n *\n * 支持通配符:\n * - `admin:*` 匹配 `admin:read`、`admin:write` 等\n * - `*` 匹配所有权限\n *\n * @param required - 需要的权限码\n * @param userPermissions - 用户已有的权限列表\n * @returns 是否匹配\n */\nexport function matchPermission(required: string, userPermissions: string[]): boolean {\n for (const userPerm of userPermissions) {\n // 完全匹配\n if (userPerm === required) {\n return true\n }\n\n // 用户有超级权限\n if (userPerm === '*') {\n return true\n }\n\n // 通配符匹配\n if (userPerm.endsWith(':*')) {\n const prefix = userPerm.slice(0, -1) // 移除 *\n if (required.startsWith(prefix)) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * 检查会话是否具有指定权限(布尔判断)\n *\n * 适用于条件分支场景(如菜单过滤、按钮显示等)。\n *\n * @param session - 当前会话数据,null/undefined 视为无权限\n * @param permission - 需要的权限码,如 `user:read`\n * @returns 是否拥有权限\n *\n * @example\n * ```ts\n * if (kit.guard.check(locals.session, 'user:read')) {\n * // 有权限\n * }\n * ```\n */\nexport function hasPermission(\n session: SessionLike | null | undefined,\n permission: string,\n): boolean {\n if (!session)\n return false\n return matchPermission(permission, session.permissions ?? [])\n}\n\n/**\n * 断言会话具有指定权限,不满足时返回 403 Response\n *\n * 适用于 SvelteKit API Handler 内部,不满足权限时直接返回 JSON 错误响应。\n * 调用者需检查返回值:若有返回值则表示权限不足,应直接 return。\n *\n * @param session - 当前会话数据,null/undefined 视为未认证\n * @param permission - 需要的权限码,如 `user:create`\n * @returns 权限不足时返回 Response;有权限时返回 undefined\n *\n * @example\n * ```ts\n * export const POST: RequestHandler = async ({ locals }) => {\n * const denied = kit.guard.assertPermission(locals.session, 'user:create')\n * if (denied) return denied\n * // ... 正常逻辑\n * }\n * ```\n */\nexport function assertPermission(\n session: SessionLike | null | undefined,\n permission: string,\n): Response | undefined {\n if (!session) {\n return new Response(\n JSON.stringify({ success: false, error: kitM('kit_unauthorized') }),\n { status: 401, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n if (!matchPermission(permission, session.permissions ?? [])) {\n return new Response(\n JSON.stringify({ success: false, error: kitM('kit_forbidden', { params: { permission } }) }),\n { status: 403, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n return undefined\n}\n\n/**\n * 要求会话具有指定权限,不满足时 throw Response\n *\n * 利用 SvelteKit 控制流机制:throw 的 Response 对象会被框架捕获并直接作为响应返回。\n * 搭配 `kit.handler()` 使用时,无需手动检查返回值。\n *\n * @param session - 当前会话数据,null/undefined 视为未认证\n * @param permission - 需要的权限码,如 `user:create`\n * @throws Response - 未认证 401 / 无权限 403\n *\n * @example\n * ```ts\n * export const GET = kit.handler(async ({ locals }) => {\n * kit.guard.require(locals.session, 'user:read')\n * // 执行到这里说明权限已通过\n * return kit.response.ok(data)\n * })\n * ```\n */\nexport function requirePermission(\n session: SessionLike | null | undefined,\n permission: string,\n): void {\n const denied = assertPermission(session, permission)\n if (denied) {\n throw denied\n }\n}\n\n/**\n * 权限守卫高阶函数包装器\n *\n * 将权限检查从业务逻辑中提取到装饰层,handler 内部无需关心权限。\n * 未认证返回 401、无权限返回 403(均通过 SvelteKit throw 控制流抛出)。\n *\n * 适用于 page load、API handler 等所有 SvelteKit server 函数。\n *\n * @param permission - 需要的权限码,如 `'user:read'`\n * @param handler - 原始处理函数\n * @returns 包装后的处理函数(签名不变)\n *\n * @example\n * ```ts\n * // +page.server.ts\n * export const load = kit.guard.withPermission('user:read', async ({ locals }) => {\n * const result = await iam.user.listUsers()\n * return { users: result.success ? result.data.items : [] }\n * })\n *\n * // +server.ts (API handler)\n * export const GET = kit.handler(kit.guard.withPermission('user:list', async ({ locals }) => {\n * const result = await iam.user.listUsers()\n * return kit.response.ok(result.data)\n * }))\n * ```\n */\nexport function withPermission<TEvent extends { locals: Record<string, unknown> }, TReturn>(\n permission: string,\n handler: (event: TEvent) => Promise<TReturn>,\n): (event: TEvent) => Promise<TReturn> {\n return async (event: TEvent) => {\n requirePermission(event.locals.session as SessionLike | undefined, permission)\n return handler(event)\n }\n}\n","/**\n * @h-ai/kit — 内部工具函数\n *\n * 提取 Handler 与 Handle 共享的 SvelteKit 控制流检测逻辑。\n * @module kit-utils\n */\n\n/**\n * 检测是否为 Response 对象(兼容跨模块 instanceof 失效场景)\n *\n * 在 Vite 开发环境下,不同模块可能引用不同的 `Response` 构造器,\n * 导致 `instanceof Response` 返回 false。通过特征检测兜底辨识。\n *\n * @param value - 待检测值\n * @returns 是否为 Response(或 Response-like 对象)\n */\nexport function isResponseLike(value: unknown): value is Response {\n if (value instanceof Response)\n return true\n if (\n typeof value === 'object'\n && value !== null\n && 'status' in value\n && 'headers' in value\n && typeof (value as Response).text === 'function'\n && typeof (value as Response).json === 'function'\n ) {\n return true\n }\n return false\n}\n\n/**\n * 检测是否为 SvelteKit 控制流对象(redirect / error)\n *\n * SvelteKit 的 `redirect()` 和 `error()` 会抛出带 `status` 属性的特殊对象,\n * 框架在上层捕获后做控制流处理。此类对象必须继续抛出,不可吞掉。\n *\n * redirect 特征:`{ status, location }` 且 status 为 number\n * error 特征:`{ status, body }` 且 status 为 number\n *\n * @param value - 被捕获的异常\n * @returns 是否为 SvelteKit 控制流\n */\nexport function isSvelteKitControlFlow(value: unknown): boolean {\n // Response 对象不是控制流\n if (isResponseLike(value))\n return false\n if (typeof value === 'object' && value !== null && 'status' in value) {\n const status = (value as { status: unknown }).status\n return typeof status === 'number'\n }\n return false\n}\n","/**\n * @h-ai/kit — 日志中间件\n *\n * HTTP 请求日志中间件,记录请求/响应摘要(方法、路径、状态码、耗时),\n * 并自动脱敏敏感字段(password / token / secret 等)。\n * @module kit-logging\n */\n\nimport type { Middleware } from '../kit-types.js'\nimport { core } from '@h-ai/core'\n\n/**\n * 日志中间件配置\n */\nexport interface LoggingMiddlewareConfig {\n /** 为 `true` 时记录非 GET 请求体(自动脱敏) */\n logBody?: boolean\n /** 为 `true` 时记录响应头 */\n logResponse?: boolean\n /** 指定需要脱敏的字段名(默认 `['password', 'token', 'secret']`) */\n redactFields?: string[]\n}\n\n/**\n * 创建日志中间件\n *\n * 以 `core.logger.trace` 级别记录请求进出信息,包含:\n * - 请求:method / path / query / userAgent / ip\n * - 响应:status / duration\n *\n * 敏感字段会被自动替换为 `[REDACTED]`。\n *\n * @param config - 日志配置\n * @returns Middleware 实例\n *\n * @example\n * ```ts\n * middleware: [\n * kit.middleware.logging({ logBody: true, redactFields: ['password', 'creditCard'] }),\n * ]\n * ```\n */\nexport function loggingMiddleware(config: LoggingMiddlewareConfig = {}): Middleware {\n const { logBody = false, logResponse = false, redactFields = ['password', 'token', 'secret', 'authorization', 'apikey', 'api_key', 'creditcard', 'credit_card'] } = config\n\n return async (context, next) => {\n const { event, requestId } = context\n const startTime = Date.now()\n\n // 安全获取客户端 IP,处理开发环境下可能的错误\n let clientIp = 'unknown'\n try {\n clientIp = event.getClientAddress?.() ?? 'unknown'\n }\n catch {\n // 开发环境下 getClientAddress 可能抛出错误\n }\n\n const logData: Record<string, unknown> = {\n requestId,\n method: event.request.method,\n path: event.url.pathname,\n query: Object.fromEntries(event.url.searchParams),\n userAgent: event.request.headers.get('user-agent'),\n ip: clientIp,\n }\n\n if (logBody && event.request.method !== 'GET') {\n try {\n const clonedRequest = event.request.clone()\n const body = await clonedRequest.json()\n logData.body = redactObject(body, redactFields)\n }\n catch {\n // 忽略非 JSON 请求体\n }\n }\n\n core.logger.trace('Incoming request', { ...logData })\n\n const response = await next()\n\n const duration = Date.now() - startTime\n\n const responseLogData: Record<string, unknown> = {\n requestId,\n status: response.status,\n duration,\n }\n\n if (logResponse) {\n responseLogData.headers = Object.fromEntries(response.headers)\n }\n\n core.logger.trace('Request completed', { ...responseLogData })\n\n return response\n }\n}\n\n/**\n * 递归屏蔽对象中的敏感字段\n *\n * 匹配规则:字段名转小写后与 `fields` 列表比较。\n *\n * @param obj - 待处理对象\n * @param fields - 需要屏蔽的字段名列表(全小写)\n * @returns 屏蔽后的副本\n */\nfunction redactObject(obj: unknown, fields: string[]): unknown {\n return core.sanitize.sanitizeSensitiveFields(obj, { matcher: fields })\n}\n","/**\n * @h-ai/kit — 速率限制中间件\n *\n * 基于滑动窗口的请求速率限制中间件。\n * 内置内存存储(`MemoryRateLimitStore`),并支持通过 `RateLimitStore` 接入\n * Redis 等外部存储后端。\n * @module kit-ratelimit\n */\n\nimport type { Middleware, RateLimitConfig } from '../kit-types.js'\nimport { core } from '@h-ai/core'\nimport { kitM } from '../kit-i18n.js'\n\n/**\n * 速率限制存储条目\n */\nexport interface RateLimitEntry {\n /** 当前窗口内的请求次数 */\n count: number\n /** 窗口重置时间戳(ms) */\n resetAt: number\n}\n\n/**\n * 速率限制存储接口\n *\n * 内置 `MemoryRateLimitStore` 适合单进程开发;\n * 多实例部署需传入基于 Redis / @h-ai/cache 的分布式实现。\n *\n * @example\n * ```ts\n * // 自定义 Redis 存储\n * const redisStore: RateLimitStore = {\n * async get(key) { ... },\n * async set(key, entry) { ... },\n * async delete(key) { ... },\n * }\n * kit.middleware.rateLimit({ windowMs: 60_000, maxRequests: 100, store: redisStore })\n * ```\n */\nexport interface RateLimitStore {\n /** 获取指定 key 的限流条目 */\n get: (key: string) => Promise<RateLimitEntry | undefined> | RateLimitEntry | undefined\n /** 设置限流条目 */\n set: (key: string, entry: RateLimitEntry) => Promise<void> | void\n /** 删除指定 key 的限流条目 */\n delete: (key: string) => Promise<void> | void\n /**\n * 原子自增并返回当前计数和重置时间\n *\n * 实现时必须保证 get→increment→set 操作的原子性,\n * 防止并发请求在窗口切换时产生竞态绕过限流。\n * 若未实现,则退回非原子 get+set 流程。\n *\n * @param key - 限流键\n * @param windowMs - 窗口时长(ms)\n * @returns 自增后的计数和窗口重置时间\n */\n increment?: (key: string, windowMs: number) => Promise<RateLimitEntry> | RateLimitEntry\n}\n\n/**\n * 内存速率限制存储\n *\n * 基于 Map 实现,适合单进程/开发环境。\n * 多实例部署时限流上限会乘以实例数,建议使用分布式 Store。\n */\nexport class MemoryRateLimitStore implements RateLimitStore {\n private store = new Map<string, RateLimitEntry>()\n private cleanupTimer: ReturnType<typeof setInterval> | null = null\n\n /**\n * 启动定期清理过期条目\n *\n * @param intervalMs - 清理间隔(毫秒)\n */\n startCleanup(intervalMs: number): void {\n if (this.cleanupTimer)\n return\n this.cleanupTimer = setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of this.store) {\n if (entry.resetAt < now) {\n this.store.delete(key)\n }\n }\n }, intervalMs)\n // 允许进程正常退出\n if (this.cleanupTimer && typeof this.cleanupTimer === 'object' && 'unref' in this.cleanupTimer) {\n this.cleanupTimer.unref()\n }\n }\n\n /**\n * 停止定期清理并释放定时器资源\n *\n * 调用后可再次 startCleanup 重启。进程退出 / 热重载 / 测试拆装场景必须调用以\n * 避免资源泄漏。\n */\n stopCleanup(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer)\n this.cleanupTimer = null\n }\n }\n\n get(key: string): RateLimitEntry | undefined {\n return this.store.get(key)\n }\n\n set(key: string, entry: RateLimitEntry): void {\n this.store.set(key, entry)\n }\n\n delete(key: string): void {\n this.store.delete(key)\n }\n\n /**\n * 原子自增(内存实现为同步操作,天然原子)\n *\n * @param key - 限流键\n * @param windowMs - 窗口时长\n * @returns 自增后的条目\n */\n increment(key: string, windowMs: number): RateLimitEntry {\n const now = Date.now()\n let entry = this.store.get(key)\n if (!entry || entry.resetAt < now) {\n entry = { count: 1, resetAt: now + windowMs }\n }\n else {\n entry.count++\n }\n this.store.set(key, entry)\n return entry\n }\n}\n\n/**\n * 创建速率限制中间件\n *\n * 基于可插拔存储的滑动窗口限流:\n * - 超限时返回 429,并在响应头中告知重置时间\n * - 正常响应附带 `X-RateLimit-*` 头\n * - 默认使用内存存储(单进程),可传入 `store` 实现分布式限流\n *\n * @param config - 限流配置\n * @returns Middleware 实例\n *\n * @example\n * ```ts\n * middleware: [\n * kit.middleware.rateLimit({ windowMs: 60_000, maxRequests: 100 }),\n * ]\n * ```\n */\nexport function rateLimitMiddleware(config: RateLimitConfig): Middleware {\n const {\n windowMs,\n maxRequests,\n keyGenerator = (event) => {\n try {\n return event.getClientAddress?.() ?? 'unknown'\n }\n catch {\n // 开发环境下 getClientAddress 可能抛出错误\n return 'unknown'\n }\n },\n onLimitReached,\n } = config\n\n // 构建存储:支持外部注入,默认内存\n const store: RateLimitStore = config.store ?? (() => {\n const memStore = new MemoryRateLimitStore()\n memStore.startCleanup(windowMs)\n return memStore\n })()\n\n return async (context, next) => {\n const { event, requestId } = context\n const key = keyGenerator(event)\n const now = Date.now()\n\n // 优先使用原子 increment,防止并发竞态\n let entry: RateLimitEntry\n if (store.increment) {\n entry = await store.increment(key, windowMs)\n }\n else {\n // 退回非原子流程(仅用于未实现 increment 的存储后端)\n const existing = await store.get(key)\n if (!existing || existing.resetAt < now) {\n entry = { count: 1, resetAt: now + windowMs }\n }\n else {\n entry = { ...existing, count: existing.count + 1 }\n }\n await store.set(key, entry)\n }\n\n // 设置速率限制头\n const remaining = Math.max(0, maxRequests - entry.count)\n const resetTime = Math.ceil(entry.resetAt / 1000)\n\n if (entry.count > maxRequests) {\n core.logger.warn('Rate limit exceeded', { key, requestId })\n\n if (onLimitReached) {\n return onLimitReached(event)\n }\n\n return new Response(\n JSON.stringify({\n success: false,\n error: {\n code: 'RATE_LIMIT_EXCEEDED',\n message: kitM('kit_rateLimitExceeded'),\n },\n requestId,\n }),\n {\n status: 429,\n headers: {\n 'Content-Type': 'application/json',\n 'X-RateLimit-Limit': String(maxRequests),\n 'X-RateLimit-Remaining': '0',\n 'X-RateLimit-Reset': String(resetTime),\n 'Retry-After': String(Math.ceil((entry.resetAt - now) / 1000)),\n },\n },\n )\n }\n\n const response = await next()\n\n // 添加速率限制头到响应\n response.headers.set('X-RateLimit-Limit', String(maxRequests))\n response.headers.set('X-RateLimit-Remaining', String(remaining))\n response.headers.set('X-RateLimit-Reset', String(resetTime))\n\n return response\n }\n}\n","/**\n * @h-ai/kit — Cookie 加密代理\n *\n * 通过 Proxy 拦截 SvelteKit Cookies 对象的 get/set 方法, 对指定名称的 Cookie 自动进行 SM4-CBC 加解密。\n * @module kit-cookie-proxy\n */\n\nimport type { CryptoFunctions } from '@h-ai/crypto'\nimport type { Cookies } from '@sveltejs/kit'\nimport { core } from '@h-ai/core'\n\n/**\n * Cookie 加密代理配置\n */\nexport interface CookieProxyConfig {\n /** 需要加密的 Cookie 名称集合 */\n names: Set<string>\n /** 对称加密服务(SM4) */\n symmetric: CryptoFunctions['symmetric']\n /** 加密密钥(32 字符十六进制) */\n encryptionKey: string\n}\n\n/**\n * 加密 Cookie 值的前缀标记\n *\n * 用于区分已加密和未加密的 Cookie 值,\n * 避免对明文值做解密导致乱码。\n */\nconst ENCRYPTED_PREFIX = 'enc:'\n\n/**\n * 创建加密 Cookie 代理\n *\n * 返回一个 Proxy 包装的 Cookies 对象:\n * - `get(name)` —— 若 name 在加密列表中,自动解密后返回明文;格式或解密失败时返回 `undefined`\n * - `set(name, value, opts)` —— 若 name 在加密列表中,自动加密后存储;加密失败时拒绝写入\n * - `delete(name, opts)` —— 透传,无需解密\n * - 其他方法原样透传\n *\n * @param cookies - SvelteKit 原始 Cookies 对象\n * @param config - 加密配置\n * @returns 代理后的 Cookies 对象(类型不变)\n */\nexport function createEncryptedCookieProxy(\n cookies: Cookies,\n config: CookieProxyConfig,\n): Cookies {\n const { names, symmetric, encryptionKey } = config\n const logger = core.logger.child({ module: 'kit', scope: 'cookie-proxy' })\n\n return new Proxy(cookies, {\n get(target, prop, receiver) {\n // 拦截 get 方法:对加密 Cookie 自动解密\n if (prop === 'get') {\n return (name: string, opts?: Parameters<Cookies['get']>[1]) => {\n const raw = target.get(name, opts)\n if (!raw || !names.has(name))\n return raw\n\n // 受保护 Cookie 不接受明文,避免攻击者绕过加密边界注入伪造值。\n if (!raw.startsWith(ENCRYPTED_PREFIX)) {\n logger.warn('Encrypted cookie has invalid format', { name })\n return undefined\n }\n\n try {\n const ciphertext = raw.slice(ENCRYPTED_PREFIX.length)\n // 格式: iv:ciphertext\n const separatorIndex = ciphertext.indexOf(':')\n if (separatorIndex === -1) {\n logger.warn('Encrypted cookie has invalid format', { name })\n return undefined\n }\n\n const iv = ciphertext.slice(0, separatorIndex)\n const encrypted = ciphertext.slice(separatorIndex + 1)\n\n const result = symmetric.decryptWithIV(encrypted, encryptionKey, iv)\n if (!result.success || typeof result.data !== 'string') {\n logger.warn('Cookie decryption failed', { name })\n return undefined\n }\n\n return result.data\n }\n catch {\n logger.warn('Cookie decryption error', { name })\n return undefined\n }\n }\n }\n\n // 拦截 set 方法:对加密 Cookie 自动加密\n if (prop === 'set') {\n return (name: string, value: string, opts: Parameters<Cookies['set']>[2]) => {\n if (names.has(name)) {\n const result = symmetric.encryptWithIV(value, encryptionKey)\n if (!result.success || !result.data) {\n logger.error('Cookie encryption failed', { name })\n throw new Error('Cookie encryption failed')\n }\n // 格式: enc:iv:ciphertext\n value = `${ENCRYPTED_PREFIX}${result.data.iv}:${result.data.ciphertext}`\n }\n\n return target.set(name, value, opts)\n }\n }\n\n // 其他方法(getAll / delete / serialize)原样透传\n return Reflect.get(target, prop, receiver)\n },\n })\n}\n","/**\n * @h-ai/kit — SvelteKit Handle Hook\n *\n * 创建 SvelteKit Handle Hook,集成请求 ID 生成、会话验证、Cookie 加密代理、\n * 路由守卫、中间件链与可选传输加密;同时提供 `sequence()` 组合多个 Handle。\n * @module kit-handle\n */\n\nimport type { Handle, RequestEvent } from '@sveltejs/kit'\nimport type { GuardConfig, GuardResult, HandleConfig, Middleware, MiddlewareContext, SessionData } from '../kit-types.js'\nimport type { CookieProxyConfig } from './kit-cookie-proxy.js'\nimport { core } from '@h-ai/core'\nimport { configureAuth, getAccessToken } from '../kit-auth.js'\nimport { kitM } from '../kit-i18n.js'\nimport { isSvelteKitControlFlow } from '../kit-utils.js'\nimport { loggingMiddleware as loggingMiddlewareFn } from '../middleware/kit-logging.js'\nimport { rateLimitMiddleware as rateLimitMiddlewareFn } from '../middleware/kit-ratelimit.js'\nimport { handleA2ARequest, resolveA2AConfig } from '../modules/a2a/kit-a2a-handle.js'\nimport { transportEncryptionMiddleware } from '../modules/crypto/kit-transport-middleware.js'\nimport { createEncryptedCookieProxy } from './kit-cookie-proxy.js'\n\n/**\n * 生成唯一请求级 ID\n *\n * 由时间戳(base36)+ 6 位随机串拼接,用于日志追踪与响应头 `X-Request-Id`。\n */\nfunction generateId(prefix: string): string {\n const timestamp = Date.now().toString(36)\n const random = crypto.randomUUID().replace(/-/g, '').substring(0, 8)\n return `${prefix}_${timestamp}${random}`\n}\n\n/**\n * 为 SvelteKit 响应补充默认安全头。\n *\n * 仅设置不会破坏页面渲染的基础头;CSP 需要应用结合 nonce / 静态资源策略单独配置。\n */\nfunction applyDefaultSecurityHeaders(response: Response): void {\n response.headers.set('X-Content-Type-Options', 'nosniff')\n response.headers.set('X-Frame-Options', 'DENY')\n response.headers.set('Referrer-Policy', 'no-referrer')\n}\n\n/**\n * 创建 hai handle hook\n *\n * 整合会话解析、路由守卫、中间件链与统一错误处理的 SvelteKit Handle 工厂。\n *\n * 执行顺序:\n * 1. 生成 `requestId` 并写入 `event.locals`\n * 2. 根据 `auth` 配置从 Bearer / Cookie 解析会话\n * 3. 根据 `auth.protectedPaths` 自动执行路由守卫 + 额外自定义守卫\n * 4. 构建中间件链(内置 logging / rateLimit + 自定义)并执行\n * 5. 调用 `resolve(event)` 获取业务响应\n * 6. 附加 `X-Request-Id` 响应头\n *\n * @param config - Handle 配置(均有合理默认值,可零配置使用)\n * @returns SvelteKit Handle 函数\n *\n * @example\n * ```ts\n * export const handle = kit.createHandle({\n * auth: {\n * verifyToken: validateSession,\n * loginUrl: '/auth/login',\n * protectedPaths: ['/admin/*', '/api/*'],\n * publicPaths: ['/api/auth/*', '/api/public/*'],\n * },\n * rateLimit: { maxRequests: 100 },\n * crypto: { crypto, transport: true },\n * })\n * ```\n */\nexport function createHandle(config: HandleConfig = {}): Handle {\n const {\n auth: authConfig,\n rateLimit: rateLimitConfig,\n logging: loggingConfig = true,\n crypto: cryptoConfig,\n onError,\n guards: customGuards = [],\n middleware: customMiddleware = [],\n a2a: a2aInput,\n } = config\n\n // ── A2A 配置解析 ──\n const a2aResolved = resolveA2AConfig(a2aInput)\n\n // ── 配置 Cookie 名 + 认证操作 ──\n if (authConfig?.cookieName || authConfig?.operations) {\n configureAuth({ cookieName: authConfig.cookieName, operations: authConfig.operations })\n }\n\n // ── 构建守卫列表(auth 自动守卫 + 自定义守卫) ──\n const guards: GuardConfig[] = []\n if (authConfig?.protectedPaths?.length) {\n guards.push({\n guard: buildAuthGuard(authConfig.verifyToken, authConfig.loginUrl),\n paths: authConfig.protectedPaths,\n exclude: authConfig.publicPaths,\n })\n }\n guards.push(...customGuards)\n\n // ── 构建中间件链 ──\n const builtinMiddleware: Middleware[] = []\n if (loggingConfig) {\n const logOpts = typeof loggingConfig === 'object' ? loggingConfig : { logBody: false }\n builtinMiddleware.push(loggingMiddlewareFn(logOpts))\n }\n if (rateLimitConfig) {\n builtinMiddleware.push(rateLimitMiddlewareFn({\n windowMs: rateLimitConfig.windowMs ?? 60000,\n maxRequests: rateLimitConfig.maxRequests ?? 100,\n }))\n }\n const allMiddleware = [...builtinMiddleware, ...customMiddleware]\n\n // ── 传输加密中间件单独包裹整个 handle 流程 ──\n const transportMiddleware = buildTransportMiddleware(cryptoConfig)\n\n // ── Cookie 加密配置预处理 ──\n const cookieProxyConfig = buildCookieProxyConfig(cryptoConfig)\n\n return async ({ event, resolve }) => {\n const requestId = generateId('req')\n const context: MiddlewareContext = {\n event,\n requestId,\n }\n\n // 注入 requestId 到 event.locals\n // Workaround:SvelteKit App.Locals 是项目侧声明的 interface,库代码无法靠模块增强检查动态 key。\n const locals = event.locals as unknown as Record<string, unknown>\n locals.requestId = requestId\n\n // ── Cookie 加密代理(透明) ──\n if (cookieProxyConfig) {\n const proxiedCookies = createEncryptedCookieProxy(event.cookies, cookieProxyConfig)\n Object.defineProperty(event, 'cookies', {\n value: proxiedCookies,\n writable: true,\n configurable: true,\n })\n }\n\n const runRequest = async (): Promise<Response> => {\n try {\n // ── A2A 端点拦截(在认证/守卫之前,A2A 有专用认证) ──\n if (a2aResolved) {\n const a2aResponse = await handleA2ARequest(event, requestId, a2aResolved)\n if (a2aResponse)\n return a2aResponse\n }\n\n // ── 会话解析 ──\n let session: SessionData | undefined\n\n if (authConfig) {\n const token = getAccessToken(event.request, event.cookies)\n if (token) {\n session = await authConfig.verifyToken(token) ?? undefined\n locals.session = session\n if (session) {\n locals.accessToken = token\n }\n }\n }\n context.session = session\n\n // ── 执行守卫 ──\n for (const guardConfig of guards) {\n const guardResult = await executeGuard(guardConfig, event, session)\n\n if (!guardResult.allowed) {\n if (guardResult.redirect) {\n return new Response(null, {\n status: 302,\n headers: { Location: guardResult.redirect },\n })\n }\n\n return new Response(\n JSON.stringify({\n success: false,\n error: {\n code: 'FORBIDDEN',\n message: guardResult.message ?? kitM('kit_accessDenied'),\n },\n requestId,\n }),\n {\n status: guardResult.status ?? 403,\n headers: { 'Content-Type': 'application/json' },\n },\n )\n }\n }\n\n // ── 中间件链 ──\n const response = await executeMiddlewareChain(\n allMiddleware,\n context,\n () => resolve(event),\n )\n\n return response\n }\n catch (error) {\n // SvelteKit 控制流异常(redirect / error)必须继续抛出\n if (isSvelteKitControlFlow(error)) {\n throw error\n }\n\n core.logger.error('Request failed', { requestId, error: error instanceof Error ? error.message : error })\n\n if (onError) {\n return onError(error, event)\n }\n\n // 默认错误响应\n return new Response(\n JSON.stringify({\n success: false,\n error: {\n code: 'INTERNAL_ERROR',\n message: kitM('kit_internalError'),\n },\n requestId,\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n },\n )\n }\n }\n\n const response = transportMiddleware\n ? await transportMiddleware(context, runRequest)\n : await runRequest()\n\n applyDefaultSecurityHeaders(response)\n response.headers.set('X-Request-Id', requestId)\n return response\n }\n}\n\n// ─── 内部:构建 auth 守卫 ───\n\n/**\n * 根据 auth 配置构建路由守卫\n *\n * - API 路径(以 `/api/` 开头):未认证返回 401 JSON\n * - 非 API 路径:未认证时重定向到 loginUrl(若配置),否则返回 401\n */\nfunction buildAuthGuard(\n verifyToken: (token: string) => Promise<SessionData | null>,\n loginUrl?: string,\n): (event: RequestEvent, session?: SessionData) => GuardResult {\n // verifyToken 参数仅用于类型签名对齐,实际会话已在上层解析\n void verifyToken\n\n return (event, session) => {\n if (session) {\n return { allowed: true }\n }\n\n const isApiRoute = event.url.pathname.startsWith('/api/')\n\n if (isApiRoute) {\n return {\n allowed: false,\n message: kitM('kit_authRequired'),\n status: 401,\n }\n }\n\n if (loginUrl) {\n const returnUrl = encodeURIComponent(event.url.pathname + event.url.search)\n return {\n allowed: false,\n redirect: `${loginUrl}?returnUrl=${returnUrl}`,\n }\n }\n\n return {\n allowed: false,\n message: kitM('kit_authRequired'),\n status: 401,\n }\n }\n}\n\n// ─── 内部:守卫执行 ───\n\n/**\n * 执行单个守卫(含路径过滤逻辑)\n */\nasync function executeGuard(\n config: GuardConfig,\n event: RequestEvent,\n session?: SessionData,\n): Promise<GuardResult> {\n const { guard, paths, exclude } = config\n const pathname = event.url.pathname\n\n if (exclude?.some(pattern => matchPath(pathname, pattern))) {\n return { allowed: true }\n }\n\n if (paths && !paths.some(pattern => matchPath(pathname, pattern))) {\n return { allowed: true }\n }\n\n return guard(event, session)\n}\n\n// ─── 内部:中间件执行 ───\n\n/**\n * 递归执行中间件链(洋葱模型)\n */\nasync function executeMiddlewareChain(\n middleware: Middleware[],\n context: MiddlewareContext,\n final: () => Response | Promise<Response>,\n): Promise<Response> {\n if (middleware.length === 0) {\n return final()\n }\n\n const [current, ...rest] = middleware\n\n return current(context, () => executeMiddlewareChain(rest, context, final))\n}\n\n// ─── 内部:路径匹配 ───\n\n/**\n * 路径通配符匹配(`/*` `/**` 精确匹配)\n */\nfunction matchPath(pathname: string, pattern: string): boolean {\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2)\n return pathname === base || pathname.startsWith(`${base}/`)\n }\n\n if (pattern.endsWith('/**')) {\n const base = pattern.slice(0, -3)\n return pathname === base || pathname.startsWith(`${base}/`)\n }\n\n return pathname === pattern\n}\n\n// ─── 内部:Crypto 配置构建 ───\n\n/**\n * 构建最终中间件链:将传输加密中间件自动插入到最外层\n */\nfunction buildTransportMiddleware(\n cryptoConfig: HandleConfig['crypto'],\n): Middleware | null {\n if (!cryptoConfig?.transport)\n return null\n\n const transportOpts = typeof cryptoConfig.transport === 'object' ? cryptoConfig.transport : {}\n\n return transportEncryptionMiddleware({\n enabled: true,\n crypto: cryptoConfig.crypto,\n keyExchangePath: transportOpts.keyExchangePath,\n excludePaths: transportOpts.excludePaths,\n encryptResponse: transportOpts.encryptResponse,\n keyStore: transportOpts.keyStore,\n maxClients: transportOpts.maxClients,\n requireEncryption: transportOpts.requireEncryption,\n })\n}\n\n/**\n * 构建 Cookie 加密代理配置\n */\nfunction buildCookieProxyConfig(\n cryptoConfig: HandleConfig['crypto'],\n): CookieProxyConfig | null {\n if (!cryptoConfig?.encryptedCookies?.length)\n return null\n\n // eslint-disable-next-line node/prefer-global/process\n const key = cryptoConfig.cookieEncryptionKey ?? (typeof process !== 'undefined' ? process.env?.HAI_KIT_COOKIE_KEY : undefined)\n if (!key) {\n throw new Error('Cookie encryption requires crypto.cookieEncryptionKey or HAI_KIT_COOKIE_KEY')\n }\n\n return {\n names: new Set(cryptoConfig.encryptedCookies),\n symmetric: cryptoConfig.crypto.symmetric,\n encryptionKey: key,\n }\n}\n\n/**\n * 组合多个 SvelteKit handle 为单一 handle\n *\n * 洋葱模型:`sequence(a, b, c)` 执行顺序为 a → b → c → resolve → c → b → a。\n *\n * @param handles - 待组合的 handle 函数列表\n * @returns 组合后的单一 Handle 函数\n *\n * @example\n * ```ts\n * const haiHandle = kit.createHandle({ ... })\n * export const handle = kit.sequence(i18nHandle, haiHandle)\n * ```\n */\nexport function sequence(...handles: Handle[]): Handle {\n const filtered = handles.filter(Boolean)\n if (filtered.length === 0) {\n return ({ event, resolve }) => resolve(event)\n }\n if (filtered.length === 1) {\n return filtered[0]\n }\n return async ({ event, resolve }) => {\n return filtered.reduceRight(\n (next, handle) => (event: RequestEvent) => handle({ event, resolve: next }),\n resolve,\n )(event)\n }\n}\n","/**\n * @h-ai/kit — API 响应工具\n *\n * 标准化 API 响应工具集,统一 `{ success, data?, error?, requestId? }` 结构。\n * 提供成功响应(ok / created / noContent)、错误响应\n * (badRequest / unauthorized / forbidden / notFound / conflict / validationError / internalError)\n * 以及重定向响应。\n * @module kit-response\n */\n\nimport type { HaiError } from '@h-ai/core'\nimport type { ApiResponse } from './kit-types.js'\nimport { kitM } from './kit-i18n.js'\n\n/**\n * 创建 200 成功响应\n *\n * @param data - 响应数据,序列化为 JSON\n * @param requestId - 可选请求 ID,用于链路追踪\n * @returns `{ success: true, data, requestId }` 格式的 JSON Response\n *\n * @example\n * ```ts\n * return kit.response.ok({ id: '1', name: 'Alice' })\n * ```\n */\nexport function ok<T>(data: T, requestId?: string): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n requestId,\n }\n\n return new Response(JSON.stringify(response), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 创建 201 资源创建成功响应\n *\n * @param data - 新创建的资源数据\n * @param requestId - 可选请求 ID\n * @returns `{ success: true, data }` 格式的 JSON Response(status 201)\n *\n * @example\n * ```ts\n * return kit.response.created({ id: 'new_1' })\n * ```\n */\nexport function created<T>(data: T, requestId?: string): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n requestId,\n }\n\n return new Response(JSON.stringify(response), {\n status: 201,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 创建 204 无内容响应\n *\n * 通常用于 DELETE 成功或无返回值的更新操作。\n *\n * @returns 空 body、status 204 的 Response\n */\nexport function noContent(): Response {\n return new Response(null, { status: 204 })\n}\n\n/**\n * 创建自定义错误响应\n *\n * @param code - 错误码(如 `'CUSTOM_ERROR'`)\n * @param message - 人可读错误消息\n * @param status - HTTP 状态码,默认 400\n * @param requestId - 可选请求 ID\n * @param details - 可选额外详情\n * @returns `{ success: false, error: { code, message, details } }` 格式的 JSON Response\n *\n * @example\n * ```ts\n * return kit.response.error('QUOTA_EXCEEDED', '配额已用尽', 429)\n * ```\n */\nexport function error(\n code: string,\n message: string,\n status = 400,\n requestId?: string,\n details?: unknown,\n): Response {\n const response: ApiResponse = {\n success: false,\n error: {\n code,\n message,\n details,\n },\n requestId,\n }\n\n return new Response(JSON.stringify(response), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 创建 400 Bad Request 响应\n *\n * @param message - 错误消息\n * @param requestId - 可选请求 ID\n * @param details - 可选额外详情\n * @returns error code 为 `'BAD_REQUEST'` 的 JSON Response\n */\nexport function badRequest(message: string, requestId?: string, details?: unknown): Response {\n return error('BAD_REQUEST', message, 400, requestId, details)\n}\n\n/**\n * 创建 401 Unauthorized 响应\n *\n * @param message - 错误消息,默认 `'Authentication required'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'UNAUTHORIZED'` 的 JSON Response\n */\nexport function unauthorized(message?: string, requestId?: string): Response {\n return error('UNAUTHORIZED', message ?? kitM('kit_authRequired'), 401, requestId)\n}\n\n/**\n * 创建 403 Forbidden 响应\n *\n * @param message - 错误消息,默认 `'Access denied'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'FORBIDDEN'` 的 JSON Response\n */\nexport function forbidden(message?: string, requestId?: string): Response {\n return error('FORBIDDEN', message ?? kitM('kit_accessDenied'), 403, requestId)\n}\n\n/**\n * 创建 404 Not Found 响应\n *\n * @param message - 错误消息,默认 `'Resource not found'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'NOT_FOUND'` 的 JSON Response\n */\nexport function notFound(message?: string, requestId?: string): Response {\n return error('NOT_FOUND', message ?? kitM('kit_resourceNotFound'), 404, requestId)\n}\n\n/**\n * 创建 409 Conflict 响应\n *\n * @param message - 冲突描述(如重复创建等)\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'CONFLICT'` 的 JSON Response\n */\nexport function conflict(message: string, requestId?: string): Response {\n return error('CONFLICT', message, 409, requestId)\n}\n\n/**\n * 创建 422 Unprocessable Entity 响应(验证错误)\n *\n * @param errors - 字段级别的验证错误列表\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'VALIDATION_ERROR'`,details 包含 `errors` 数组\n *\n * @example\n * ```ts\n * return kit.response.validationError([\n * { field: 'email', message: '格式无效' },\n * ])\n * ```\n */\nexport function validationError(\n errors: Array<{ field: string, message: string }>,\n requestId?: string,\n): Response {\n return error('VALIDATION_ERROR', kitM('kit_validationFailed'), 422, requestId, { errors })\n}\n\n/**\n * 创建 500 Internal Server Error 响应\n *\n * @param message - 错误消息,默认 `'Internal server error'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'INTERNAL_ERROR'` 的 JSON Response\n */\nexport function internalError(message?: string, requestId?: string): Response {\n return error('INTERNAL_ERROR', message ?? kitM('kit_internalError'), 500, requestId)\n}\n\n/**\n * 创建重定向响应\n *\n * @param url - 目标 URL\n * @param status - HTTP 状态码,默认 302;常用 303(POST 后重定向)\n * @returns 带 `Location` 头的空 body Response\n *\n * @example\n * ```ts\n * return kit.response.redirect('/dashboard', 303)\n * ```\n */\nexport function redirect(url: string, status: 301 | 302 | 303 | 307 | 308 = 302): Response {\n return new Response(null, {\n status,\n headers: { Location: url },\n })\n}\n\n// ─── HaiResult → Response 转换 ───\n\n/**\n * 将 HaiResult<T> 转换为标准 API Response\n *\n * 成功时返回 200 ok(data),失败时从 error 对象中提取 code、message,\n * 并根据 httpStatusMap 映射 HTTP 状态码(未命中时默认 400)。\n *\n * @param result - core HaiResult 对象({ success, data } 或 { success: false, error })\n * @param httpStatusMap - 模块导出的错误码 → HTTP 状态码映射表(如 IamErrorHttpStatus)\n * @param requestId - 可选请求 ID,用于链路追踪\n * @returns 标准化 JSON Response\n *\n * @example\n * ```ts\n * // 无映射(默认 400)\n * return kit.response.fromResult(result)\n *\n * // 带模块错误码映射\n * return kit.response.fromResult(result, IamErrorHttpStatus)\n * ```\n */\nexport function fromResult<T>(\n result: { success: true, data: T } | { success: false, error: { code: number | string, message: string, [key: string]: unknown } },\n httpStatusMap?: Record<number | string, number>,\n requestId?: string,\n): Response {\n if (result.success) {\n return ok(result.data, requestId)\n }\n\n const { code, message } = result.error\n const status = httpStatusMap?.[code] ?? 400\n return error(String(code), message, status, requestId)\n}\n\nexport function fromError(\n haiError: HaiError,\n requestId?: string,\n): Response {\n return error(String(haiError.code), haiError.message, haiError.httpStatus ?? 400, requestId)\n}\n","/**\n * @h-ai/kit — API Handler 包装器\n *\n * 统一封装 SvelteKit API Handler 的错误处理逻辑。\n * @module kit-handler\n */\n\nimport type { RequestEvent, RequestHandler } from '@sveltejs/kit'\nimport { core } from '@h-ai/core'\nimport { internalError } from './kit-response.js'\nimport { isResponseLike, isSvelteKitControlFlow } from './kit-utils.js'\n\n/**\n * 创建 API Handler 包装器\n *\n * 将业务逻辑包裹在统一的异常边界中:\n * 1. 正常执行 `fn(event)` 返回 Response\n * 2. 若 `fn` throw 了 `Response`(如 `kit.guard.require` / `kit.validate.body`),直接返回该 Response\n * 3. 若 `fn` throw 了 SvelteKit 控制流(`redirect()` / `error()`),继续抛出\n * 4. 其他异常:记录日志 → 返回 `kit.response.internalError()`\n *\n * @param fn - 业务处理函数\n * @returns SvelteKit RequestHandler\n *\n * @example\n * ```ts\n * export const GET = kit.handler(async ({ locals }) => {\n * kit.guard.require(locals.session, 'user:read')\n * return kit.response.ok(await getUsers())\n * })\n * ```\n */\nexport function handler(fn: (event: RequestEvent) => Promise<Response> | Response): RequestHandler {\n return async (event) => {\n try {\n return await fn(event)\n }\n catch (error) {\n // validate.body / guard.require 等场景会 throw Response,直接返回即可\n // 使用 isResponseLike 兼容 Vite 开发环境下跨模块 instanceof 失效\n if (isResponseLike(error)) {\n return error\n }\n\n // redirect/error 等 SvelteKit 控制流必须继续抛出\n if (isSvelteKitControlFlow(error)) {\n throw error\n }\n\n const normalizedError = error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n cause: error.cause,\n }\n : error\n\n core.logger.error('Request handler error', {\n error: normalizedError,\n path: event.url.pathname,\n method: event.request.method,\n })\n\n return internalError()\n }\n }\n}\n","/**\n * @h-ai/kit — 请求数据验证\n *\n * 基于 Zod 的请求数据验证工具,支持表单/JSON Body、URL 查询参数与路由参数。\n * Zod 默认错误消息的本地化规则委托给 `core.zodValidation`,避免 kit / serv\n * 等模块重复维护同一套 issue 解析与消息映射逻辑;模块前缀映射也统一交给\n * `core.zodValidation.createPrefixedZodMessageGetter()` 处理。\n * 每种数据源都提供两类 API:\n * - 安全返回:`FormValidationResult`\n * - 失败抛出:`OrFail`(抛出 `Response` 以走 SvelteKit 控制流)\n * @module kit-validation\n */\n\nimport type { z } from 'zod'\nimport type { FormValidationResult } from './kit-types.js'\nimport { core } from '@h-ai/core'\nimport { z as zod } from 'zod'\nimport { kitM } from './kit-i18n.js'\nimport { badRequest } from './kit-response.js'\n\n// ─── 内部工具 ───\n\n/**\n * 构造与 kit 消息表对齐的 `ZodMessageGetter`。\n *\n * 统一复用 `core.zodValidation` 的 Zod issue 解析与默认消息识别逻辑,\n * kit 仅提供自己的消息获取器。\n */\nconst getKitZodMessage = core.zodValidation.createPrefixedZodMessageGetter<Parameters<typeof kitM>[0]>(\n 'kit',\n (messageKey, params) => kitM(messageKey, { params }),\n)\n\nfunction validateParsedData<T extends z.ZodType>(\n data: unknown,\n schema: T,\n): FormValidationResult<z.infer<T>> {\n const result = schema.safeParse(data)\n if (result.success)\n return { valid: true, data: result.data, errors: [] }\n return {\n valid: false,\n errors: core.zodValidation.mapZodErrorToFormErrors(result.error, getKitZodMessage),\n }\n}\n\nfunction unwrapValidationResultOrThrow<T>(result: FormValidationResult<T>): T {\n if (result.valid && result.data !== undefined)\n return result.data\n\n throw badRequest(\n result.errors[0]?.message ?? kitM('kit_validationFailed'),\n undefined,\n { errors: result.errors },\n )\n}\n\n// ─── 公共验证函数 ───\n\n/**\n * 从 Request 解析并验证表单数据\n *\n * 支持 `application/json` 和 `multipart/form-data` / `application/x-www-form-urlencoded`。\n * 其他 Content-Type 返回全局错误 `{ field: '_', message: 'Unsupported content type' }`。\n *\n * @param request - SvelteKit 请求对象\n * @param schema - Zod Schema\n * @returns 验证结果;成功时 `valid: true` 且 `data` 类型安全\n *\n * @example\n * ```ts\n * const { valid, data, errors } = await kit.validate.form(event.request, CreateUserSchema)\n * if (!valid) return kit.response.validationError(errors)\n * ```\n */\nexport async function validateForm<T extends z.ZodType>(\n request: Request,\n schema: T,\n): Promise<FormValidationResult<z.infer<T>>> {\n try {\n const contentType = request.headers.get('content-type') ?? ''\n\n let data: unknown\n\n if (contentType.includes('application/json')) {\n data = await request.json()\n }\n else if (contentType.includes('application/x-www-form-urlencoded') || contentType.includes('multipart/form-data')) {\n const formData = await request.formData()\n data = Object.fromEntries(formData)\n }\n else {\n return {\n valid: false,\n errors: [{ field: '_', message: kitM('kit_unsupportedContentType') }],\n }\n }\n\n return validateParsedData(data, schema)\n }\n catch {\n return {\n valid: false,\n errors: [{ field: '_', message: kitM('kit_parseBodyFailed') }],\n }\n }\n}\n\n/**\n * 从 URL 查询参数验证\n *\n * 将 `url.searchParams` 转为普通对象后交给 Zod 校验。\n * 适用于 GET 请求的分页、搜索等场景。\n *\n * @param url - 请求 URL 对象\n * @param schema - Zod Schema\n * @returns 验证结果\n *\n * @example\n * ```ts\n * const { valid, data } = kit.validate.query(event.url, PaginationSchema)\n * ```\n */\nexport function validateQuery<T extends z.ZodType>(\n url: URL,\n schema: T,\n): FormValidationResult<z.infer<T>> {\n const data = Object.fromEntries(url.searchParams)\n return validateParsedData(data, schema)\n}\n\n/**\n * 验证路径参数\n *\n * 将 SvelteKit 路由 `params` 交给 Zod 校验,适用于动态路由段的类型安全校验。\n *\n * @param params - SvelteKit 路由参数(`event.params`)\n * @param schema - Zod Schema\n * @returns 验证结果\n *\n * @example\n * ```ts\n * const { valid, data } = kit.validate.params(event.params, z.object({ id: z.string().uuid() }))\n * ```\n */\nexport function validateParams<T extends z.ZodType>(\n params: Record<string, string>,\n schema: T,\n): FormValidationResult<z.infer<T>> {\n return validateParsedData(params, schema)\n}\n\n// ─── OrFail 变体 — 校验失败时抛出 Response(SvelteKit 控制流) ───\n\n/**\n * 从 Request 解析并验证表单数据,失败时 throw Response\n *\n * 与 `validateForm` 功能相同,但校验失败时 throw 400 Response(SvelteKit 控制流),\n * 搭配 `kit.handler()` 使用可精简 handler 代码。\n *\n * @param request - SvelteKit 请求对象\n * @param schema - Zod Schema\n * @returns 校验通过的数据(类型安全)\n * @throws Response - 400 BadRequest(含首条错误消息)\n *\n * @example\n * ```ts\n * export const POST = kit.handler(async ({ request }) => {\n * const data = await kit.validate.body(request, CreateUserSchema)\n * // data 类型安全,校验已通过\n * })\n * ```\n */\nexport async function validateFormOrFail<T extends z.ZodType>(\n request: Request,\n schema: T,\n): Promise<z.infer<T>> {\n return unwrapValidationResultOrThrow(await validateForm(request, schema))\n}\n\n/**\n * 从 URL 查询参数验证,失败时 throw Response\n *\n * @param url - 请求 URL 对象\n * @param schema - Zod Schema\n * @returns 校验通过的数据\n * @throws Response - 400 BadRequest\n *\n * @example\n * ```ts\n * const query = kit.validate.query(event.url, PaginationSchema)\n * ```\n */\nexport function validateQueryOrFail<T extends z.ZodType>(\n url: URL,\n schema: T,\n): z.infer<T> {\n return unwrapValidationResultOrThrow(validateQuery(url, schema))\n}\n\n/**\n * 验证路径参数,失败时 throw Response\n *\n * @param params - SvelteKit 路由参数\n * @param schema - Zod Schema\n * @returns 校验通过的数据\n * @throws Response - 400 BadRequest\n *\n * @example\n * ```ts\n * const { id } = kit.validate.params(event.params, IdParamSchema)\n * ```\n */\nexport function validateParamsOrFail<T extends z.ZodType>(\n params: Record<string, string>,\n schema: T,\n): z.infer<T> {\n return unwrapValidationResultOrThrow(validateParams(params, schema))\n}\n\n// ─── 通用 Schema ───\n\n/**\n * 路径参数 id 校验 Schema\n *\n * 验证 `event.params.id` 为非空字符串。\n *\n * @example\n * ```ts\n * const { id } = kit.validate.params(event.params, IdParamSchema)\n * ```\n */\nexport const IdParamSchema = zod.object({\n id: zod.string().min(1, kitM('kit_idRequired')),\n})\n\n/** 分页 pageSize 上限 */\nconst MAX_PAGE_SIZE = 100\n\n/**\n * 通用分页查询参数 Schema\n *\n * 包含 page(默认 1)、pageSize(默认 20,上限 100)、search(可选)。\n * 可通过 `.extend()` 扩展业务字段。\n *\n * @example\n * ```ts\n * // 直接使用\n * const { page, pageSize, search } = kit.validate.query(url, PaginationQuerySchema)\n *\n * // 扩展业务字段\n * const ListUsersSchema = PaginationQuerySchema.extend({\n * enabled: z.enum(['true', 'false']).transform(v => v === 'true').optional(),\n * })\n * ```\n */\nexport const PaginationQuerySchema = zod.object({\n page: zod.coerce.number().int().min(1).default(1),\n pageSize: zod.coerce.number().int().min(1).max(MAX_PAGE_SIZE).default(20),\n search: zod.string().optional(),\n})\n","/**\n * @h-ai/kit — 服务对象主入口\n *\n * SvelteKit 集成模块的统一命名空间出口。 所有功能通过 kit 对象访问:\n * @module kit-main\n */\n\nimport { createKitClient, installBrowserTransport, installBrowserTransportFetch } from './client/kit-client.js'\nimport { defineCrud } from './crud/kit-crud.js'\nimport { hasPermission, requirePermission } from './guards/kit-permission.js'\nimport { createHandle, sequence } from './hooks/kit-handle.js'\nimport {\n clearBrowserToken,\n createTokenStore,\n login,\n loginWithApiKey,\n loginWithLdap,\n loginWithOtp,\n logout,\n registerAndLogin,\n setBrowserToken,\n} from './kit-auth.js'\nimport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig } from './kit-config.js'\nimport { handler } from './kit-handler.js'\nimport { setAllModulesLocale } from './kit-i18n.js'\nimport { badRequest, conflict, created, error, forbidden, fromError, fromResult, internalError, noContent, notFound, ok, redirect, unauthorized, validationError } from './kit-response.js'\nimport { IdParamSchema, PaginationQuerySchema, validateFormOrFail, validateParamsOrFail, validateQueryOrFail } from './kit-validation.js'\n\nexport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig }\n\n/**\n * Kit 模块统一出口。\n *\n * 作为纯工具模块,kit 不需要 init/close 生命周期,\n * 所有功能均为无状态工厂函数或工具函数。\n */\nexport const kit = {\n // ─── Handle Hook ───\n\n /** 创建 SvelteKit Handle Hook(含 auth / logging / rateLimit 内置配置) */\n createHandle,\n /** 组合多个 Handle */\n sequence,\n /** API Handler 包装器(自动错误边界) */\n handler,\n\n // ─── 路由守卫 ───\n\n guard: {\n /** 要求权限,不满足时 throw Response(SvelteKit 控制流) */\n require: requirePermission,\n /** 检查会话是否具有指定权限(布尔) */\n check: hasPermission,\n },\n\n // ─── API 响应 ───\n\n response: {\n /** 200 成功 */\n ok,\n /** 201 创建成功 */\n created,\n /** 204 无内容 */\n noContent,\n /** 自定义错误响应 */\n error,\n /** 400 BadRequest */\n badRequest,\n /** 401 Unauthorized */\n unauthorized,\n /** 403 Forbidden */\n forbidden,\n /** 404 NotFound */\n notFound,\n /** 409 Conflict */\n conflict,\n /** 422 验证错误 */\n validationError,\n /** 500 InternalError */\n internalError,\n /** 重定向 */\n redirect,\n /** 将 HaiResult<T> 转为标准 API Response(支持 httpStatusMap) */\n fromResult,\n /** 将模块错误码映射为标准 HTTP Response */\n fromError,\n },\n\n // ─── 验证 ───\n\n validate: {\n /** 验证请求体(JSON/表单),失败 throw Response */\n body: validateFormOrFail,\n /** 验证查询参数,失败 throw Response */\n query: validateQueryOrFail,\n /** 验证路径参数,失败 throw Response */\n params: validateParamsOrFail,\n /** 路径参数 id Schema({id: string}) */\n IdParamSchema,\n /** 通用分页查询 Schema(page / pageSize / search) */\n PaginationQuerySchema,\n },\n\n // ─── 客户端工具 ───\n\n client: {\n /** 创建统一客户端(CSRF + 传输加密透明合并) */\n create: createKitClient,\n /**\n * 用解析后的 {@link KitConfig} 一键安装浏览器端传输加密\n * (应用层推荐入口;内部预热 crypto 并调用 installBrowserTransportFetch)\n */\n installBrowserTransport,\n /** 底层入口:直接传 transport 配置安装浏览器全局 fetch 包装 */\n installBrowserTransportFetch,\n },\n\n // ─── 认证工具 ───\n\n auth: {\n /** 服务端登录(密码):内部调用 iam.auth.login + 自动写入 Token Cookie */\n login,\n /** 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp + 自动写入 Token Cookie */\n loginWithOtp,\n /** 服务端登录(LDAP):内部调用 iam.auth.loginWithLdap + 自动写入 Token Cookie */\n loginWithLdap,\n /** 服务端登录(API Key):内部调用 iam.auth.loginWithApiKey + 自动写入 Token Cookie */\n loginWithApiKey,\n /** 服务端注册并登录:内部调用 iam.auth.registerAndLogin + 自动写入 Token Cookie */\n registerAndLogin,\n /** 服务端登出:内部调用 iam.auth.logout + 清除 Token Cookie */\n logout,\n /** 写入浏览器端 Access Token(客户端 login/register 用) */\n setBrowserToken,\n /** 清除浏览器端 Access Token(客户端 logout 用) */\n clearBrowserToken,\n /** 创建浏览器端 Token 存储器(自定义 key 时使用) */\n createTokenStore,\n },\n\n // ─── CRUD ───\n\n crud: {\n /** 定义 CRUD 资源(声明式配置 → 操作对象) */\n define: defineCrud,\n },\n\n // ─── i18n ───\n\n i18n: {\n /** 统一设置所有 hai 模块的默认语言 */\n setLocale: setAllModulesLocale,\n },\n}\n"]}
1
+ {"version":3,"sources":["../src/guards/kit-permission.ts","../src/kit-utils.ts","../src/middleware/kit-logging.ts","../src/middleware/kit-ratelimit.ts","../src/hooks/kit-cookie-proxy.ts","../src/hooks/kit-handle.ts","../src/kit-response.ts","../src/kit-handler.ts","../src/kit-validation.ts","../src/kit-auth-api.ts","../src/kit-main.ts"],"names":["core","response","error","event","zod"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @h-ai/kit — 权限守卫\n *\n * 验证用户是否具有指定权限。\n * @module kit-permission\n */\n\nimport type { GuardResult, RouteGuard, SessionLike } from '../kit-types.js'\nimport { kitM } from '../kit-i18n.js'\n\n/**\n * 权限守卫配置\n */\nexport interface PermissionGuardConfig {\n /** 需要的权限列表(默认 OR 逻辑,满足任一即通过) */\n permissions: string[]\n /** 为 `true` 时要求用户拥有 **全部** 权限(AND 逻辑) */\n requireAll?: boolean\n /** 无权限时重定向 URL(默认 `'/403'`) */\n forbiddenUrl?: string\n /** 为 `true` 时返回 JSON 403 而非重定向 */\n apiMode?: boolean\n}\n\n/**\n * 创建权限守卫\n *\n * 检查用户 `session.permissions` 是否满足配置中的权限要求。\n * 支持通配符匹配:`admin:*` 可匹配 `admin:read`、`admin:write` 等。\n * 未认证时返回 401;权限不匹配时根据 `apiMode` 返回 JSON 403 或重定向。\n *\n * @param config - 权限守卫配置\n * @returns RouteGuard 实例\n *\n * @example\n * ```ts\n * guards: [\n * { guard: kit.guard.permission({ permissions: ['user:read', 'user:write'], requireAll: true }), paths: ['/api/users/*'] },\n * ]\n * ```\n */\nexport function permissionGuard(config: PermissionGuardConfig): RouteGuard {\n const { permissions, requireAll = false, forbiddenUrl = '/403', apiMode = false } = config\n\n return (_event, session): GuardResult => {\n if (!session) {\n return {\n allowed: false,\n message: kitM('kit_authRequired'),\n status: 401,\n }\n }\n\n const userPermissions = session.permissions ?? []\n\n // 支持通配符权限,如 admin:* 匹配 admin:read, admin:write 等\n const hasPermission = requireAll\n ? permissions.every(perm => matchPermission(perm, userPermissions))\n : permissions.some(perm => matchPermission(perm, userPermissions))\n\n if (!hasPermission) {\n if (apiMode) {\n return {\n allowed: false,\n message: kitM('kit_requiredPermissions', { params: { permissions: permissions.join(', ') } }),\n status: 403,\n }\n }\n\n return {\n allowed: false,\n redirect: forbiddenUrl,\n }\n }\n\n return { allowed: true }\n }\n}\n\n/**\n * 匹配权限\n *\n * 支持通配符:\n * - `admin:*` 匹配 `admin:read`、`admin:write` 等\n * - `*` 匹配所有权限\n *\n * @param required - 需要的权限码\n * @param userPermissions - 用户已有的权限列表\n * @returns 是否匹配\n */\nexport function matchPermission(required: string, userPermissions: string[]): boolean {\n for (const userPerm of userPermissions) {\n // 完全匹配\n if (userPerm === required) {\n return true\n }\n\n // 用户有超级权限\n if (userPerm === '*') {\n return true\n }\n\n // 通配符匹配\n if (userPerm.endsWith(':*')) {\n const prefix = userPerm.slice(0, -1) // 移除 *\n if (required.startsWith(prefix)) {\n return true\n }\n }\n }\n\n return false\n}\n\n/**\n * 检查会话是否具有指定权限(布尔判断)\n *\n * 适用于条件分支场景(如菜单过滤、按钮显示等)。\n *\n * @param session - 当前会话数据,null/undefined 视为无权限\n * @param permission - 需要的权限码,如 `user:read`\n * @returns 是否拥有权限\n *\n * @example\n * ```ts\n * if (kit.guard.check(locals.session, 'user:read')) {\n * // 有权限\n * }\n * ```\n */\nexport function hasPermission(\n session: SessionLike | null | undefined,\n permission: string,\n): boolean {\n if (!session)\n return false\n return matchPermission(permission, session.permissions ?? [])\n}\n\n/**\n * 断言会话具有指定权限,不满足时返回 403 Response\n *\n * 适用于 SvelteKit API Handler 内部,不满足权限时直接返回 JSON 错误响应。\n * 调用者需检查返回值:若有返回值则表示权限不足,应直接 return。\n *\n * @param session - 当前会话数据,null/undefined 视为未认证\n * @param permission - 需要的权限码,如 `user:create`\n * @returns 权限不足时返回 Response;有权限时返回 undefined\n *\n * @example\n * ```ts\n * export const POST: RequestHandler = async ({ locals }) => {\n * const denied = kit.guard.assertPermission(locals.session, 'user:create')\n * if (denied) return denied\n * // ... 正常逻辑\n * }\n * ```\n */\nexport function assertPermission(\n session: SessionLike | null | undefined,\n permission: string,\n): Response | undefined {\n if (!session) {\n return new Response(\n JSON.stringify({ success: false, error: kitM('kit_unauthorized') }),\n { status: 401, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n if (!matchPermission(permission, session.permissions ?? [])) {\n return new Response(\n JSON.stringify({ success: false, error: kitM('kit_forbidden', { params: { permission } }) }),\n { status: 403, headers: { 'Content-Type': 'application/json' } },\n )\n }\n\n return undefined\n}\n\n/**\n * 要求会话具有指定权限,不满足时 throw Response\n *\n * 利用 SvelteKit 控制流机制:throw 的 Response 对象会被框架捕获并直接作为响应返回。\n * 搭配 `kit.handler()` 使用时,无需手动检查返回值。\n *\n * @param session - 当前会话数据,null/undefined 视为未认证\n * @param permission - 需要的权限码,如 `user:create`\n * @throws Response - 未认证 401 / 无权限 403\n *\n * @example\n * ```ts\n * export const GET = kit.handler(async ({ locals }) => {\n * kit.guard.require(locals.session, 'user:read')\n * // 执行到这里说明权限已通过\n * return kit.response.ok(data)\n * })\n * ```\n */\nexport function requirePermission(\n session: SessionLike | null | undefined,\n permission: string,\n): void {\n const denied = assertPermission(session, permission)\n if (denied) {\n throw denied\n }\n}\n\n/**\n * 权限守卫高阶函数包装器\n *\n * 将权限检查从业务逻辑中提取到装饰层,handler 内部无需关心权限。\n * 未认证返回 401、无权限返回 403(均通过 SvelteKit throw 控制流抛出)。\n *\n * 适用于 page load、API handler 等所有 SvelteKit server 函数。\n *\n * @param permission - 需要的权限码,如 `'user:read'`\n * @param handler - 原始处理函数\n * @returns 包装后的处理函数(签名不变)\n *\n * @example\n * ```ts\n * // +page.server.ts\n * export const load = kit.guard.withPermission('user:read', async ({ locals }) => {\n * const result = await iam.user.listUsers()\n * return { users: result.success ? result.data.items : [] }\n * })\n *\n * // +server.ts (API handler)\n * export const GET = kit.handler(kit.guard.withPermission('user:list', async ({ locals }) => {\n * const result = await iam.user.listUsers()\n * return kit.response.ok(result.data)\n * }))\n * ```\n */\nexport function withPermission<TEvent extends { locals: Record<string, unknown> }, TReturn>(\n permission: string,\n handler: (event: TEvent) => Promise<TReturn>,\n): (event: TEvent) => Promise<TReturn> {\n return async (event: TEvent) => {\n requirePermission(event.locals.session as SessionLike | undefined, permission)\n return handler(event)\n }\n}\n","/**\n * @h-ai/kit — 内部工具函数\n *\n * 提取 Handler 与 Handle 共享的 SvelteKit 控制流检测逻辑。\n * @module kit-utils\n */\n\n/**\n * 检测是否为 Response 对象(兼容跨模块 instanceof 失效场景)\n *\n * 在 Vite 开发环境下,不同模块可能引用不同的 `Response` 构造器,\n * 导致 `instanceof Response` 返回 false。通过特征检测兜底辨识。\n *\n * @param value - 待检测值\n * @returns 是否为 Response(或 Response-like 对象)\n */\nexport function isResponseLike(value: unknown): value is Response {\n if (value instanceof Response)\n return true\n if (\n typeof value === 'object'\n && value !== null\n && 'status' in value\n && 'headers' in value\n && typeof (value as Response).text === 'function'\n && typeof (value as Response).json === 'function'\n ) {\n return true\n }\n return false\n}\n\n/**\n * 检测是否为 SvelteKit 控制流对象(redirect / error)\n *\n * SvelteKit 的 `redirect()` 和 `error()` 会抛出带 `status` 属性的特殊对象,\n * 框架在上层捕获后做控制流处理。此类对象必须继续抛出,不可吞掉。\n *\n * redirect 特征:`{ status, location }` 且 status 为 number\n * error 特征:`{ status, body }` 且 status 为 number\n *\n * @param value - 被捕获的异常\n * @returns 是否为 SvelteKit 控制流\n */\nexport function isSvelteKitControlFlow(value: unknown): boolean {\n // Response 对象不是控制流\n if (isResponseLike(value))\n return false\n if (typeof value === 'object' && value !== null && 'status' in value) {\n const status = (value as { status: unknown }).status\n return typeof status === 'number'\n }\n return false\n}\n","/**\n * @h-ai/kit — 日志中间件\n *\n * HTTP 请求日志中间件,记录请求/响应摘要(方法、路径、状态码、耗时),\n * 并自动脱敏敏感字段(password / token / secret 等)。\n * @module kit-logging\n */\n\nimport type { Middleware } from '../kit-types.js'\nimport { core } from '@h-ai/core'\n\n/**\n * 日志中间件配置\n */\nexport interface LoggingMiddlewareConfig {\n /** 为 `true` 时记录非 GET 请求体(自动脱敏) */\n logBody?: boolean\n /** 为 `true` 时记录响应头 */\n logResponse?: boolean\n /** 指定需要脱敏的字段名(默认 `['password', 'token', 'secret']`) */\n redactFields?: string[]\n}\n\n/**\n * 创建日志中间件\n *\n * 以 `core.logger.trace` 级别记录请求进出信息,包含:\n * - 请求:method / path / query / userAgent / ip\n * - 响应:status / duration\n *\n * 敏感字段会被自动替换为 `[REDACTED]`。\n *\n * @param config - 日志配置\n * @returns Middleware 实例\n *\n * @example\n * ```ts\n * middleware: [\n * kit.middleware.logging({ logBody: true, redactFields: ['password', 'creditCard'] }),\n * ]\n * ```\n */\nexport function loggingMiddleware(config: LoggingMiddlewareConfig = {}): Middleware {\n const { logBody = false, logResponse = false, redactFields = ['password', 'token', 'secret', 'authorization', 'apikey', 'api_key', 'creditcard', 'credit_card'] } = config\n\n return async (context, next) => {\n const { event, requestId } = context\n const startTime = Date.now()\n\n // 安全获取客户端 IP,处理开发环境下可能的错误\n let clientIp = 'unknown'\n try {\n clientIp = event.getClientAddress?.() ?? 'unknown'\n }\n catch {\n // 开发环境下 getClientAddress 可能抛出错误\n }\n\n const logData: Record<string, unknown> = {\n requestId,\n method: event.request.method,\n path: event.url.pathname,\n query: Object.fromEntries(event.url.searchParams),\n userAgent: event.request.headers.get('user-agent'),\n ip: clientIp,\n }\n\n if (logBody && event.request.method !== 'GET') {\n try {\n const clonedRequest = event.request.clone()\n const body = await clonedRequest.json()\n logData.body = redactObject(body, redactFields)\n }\n catch {\n // 忽略非 JSON 请求体\n }\n }\n\n core.logger.trace('Incoming request', { ...logData })\n\n const response = await next()\n\n const duration = Date.now() - startTime\n\n const responseLogData: Record<string, unknown> = {\n requestId,\n status: response.status,\n duration,\n }\n\n if (logResponse) {\n responseLogData.headers = Object.fromEntries(response.headers)\n }\n\n core.logger.trace('Request completed', { ...responseLogData })\n\n return response\n }\n}\n\n/**\n * 递归屏蔽对象中的敏感字段\n *\n * 匹配规则:字段名转小写后与 `fields` 列表比较。\n *\n * @param obj - 待处理对象\n * @param fields - 需要屏蔽的字段名列表(全小写)\n * @returns 屏蔽后的副本\n */\nfunction redactObject(obj: unknown, fields: string[]): unknown {\n return core.sanitize.sanitizeSensitiveFields(obj, { matcher: fields })\n}\n","/**\n * @h-ai/kit — 速率限制中间件\n *\n * 基于滑动窗口的请求速率限制中间件。\n * 内置内存存储(`MemoryRateLimitStore`),并支持通过 `RateLimitStore` 接入\n * Redis 等外部存储后端。\n * @module kit-ratelimit\n */\n\nimport type { Middleware, RateLimitConfig } from '../kit-types.js'\nimport { core } from '@h-ai/core'\nimport { kitM } from '../kit-i18n.js'\n\n/**\n * 速率限制存储条目\n */\nexport interface RateLimitEntry {\n /** 当前窗口内的请求次数 */\n count: number\n /** 窗口重置时间戳(ms) */\n resetAt: number\n}\n\n/**\n * 速率限制存储接口\n *\n * 内置 `MemoryRateLimitStore` 适合单进程开发;\n * 多实例部署需传入基于 Redis / @h-ai/cache 的分布式实现。\n *\n * @example\n * ```ts\n * // 自定义 Redis 存储\n * const redisStore: RateLimitStore = {\n * async get(key) { ... },\n * async set(key, entry) { ... },\n * async delete(key) { ... },\n * }\n * kit.middleware.rateLimit({ windowMs: 60_000, maxRequests: 100, store: redisStore })\n * ```\n */\nexport interface RateLimitStore {\n /** 获取指定 key 的限流条目 */\n get: (key: string) => Promise<RateLimitEntry | undefined> | RateLimitEntry | undefined\n /** 设置限流条目 */\n set: (key: string, entry: RateLimitEntry) => Promise<void> | void\n /** 删除指定 key 的限流条目 */\n delete: (key: string) => Promise<void> | void\n /**\n * 原子自增并返回当前计数和重置时间\n *\n * 实现时必须保证 get→increment→set 操作的原子性,\n * 防止并发请求在窗口切换时产生竞态绕过限流。\n * 若未实现,则退回非原子 get+set 流程。\n *\n * @param key - 限流键\n * @param windowMs - 窗口时长(ms)\n * @returns 自增后的计数和窗口重置时间\n */\n increment?: (key: string, windowMs: number) => Promise<RateLimitEntry> | RateLimitEntry\n}\n\n/**\n * 内存速率限制存储\n *\n * 基于 Map 实现,适合单进程/开发环境。\n * 多实例部署时限流上限会乘以实例数,建议使用分布式 Store。\n */\nexport class MemoryRateLimitStore implements RateLimitStore {\n private store = new Map<string, RateLimitEntry>()\n private cleanupTimer: ReturnType<typeof setInterval> | null = null\n\n /**\n * 启动定期清理过期条目\n *\n * @param intervalMs - 清理间隔(毫秒)\n */\n startCleanup(intervalMs: number): void {\n if (this.cleanupTimer)\n return\n this.cleanupTimer = setInterval(() => {\n const now = Date.now()\n for (const [key, entry] of this.store) {\n if (entry.resetAt < now) {\n this.store.delete(key)\n }\n }\n }, intervalMs)\n // 允许进程正常退出\n if (this.cleanupTimer && typeof this.cleanupTimer === 'object' && 'unref' in this.cleanupTimer) {\n this.cleanupTimer.unref()\n }\n }\n\n /**\n * 停止定期清理并释放定时器资源\n *\n * 调用后可再次 startCleanup 重启。进程退出 / 热重载 / 测试拆装场景必须调用以\n * 避免资源泄漏。\n */\n stopCleanup(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer)\n this.cleanupTimer = null\n }\n }\n\n get(key: string): RateLimitEntry | undefined {\n return this.store.get(key)\n }\n\n set(key: string, entry: RateLimitEntry): void {\n this.store.set(key, entry)\n }\n\n delete(key: string): void {\n this.store.delete(key)\n }\n\n /**\n * 原子自增(内存实现为同步操作,天然原子)\n *\n * @param key - 限流键\n * @param windowMs - 窗口时长\n * @returns 自增后的条目\n */\n increment(key: string, windowMs: number): RateLimitEntry {\n const now = Date.now()\n let entry = this.store.get(key)\n if (!entry || entry.resetAt < now) {\n entry = { count: 1, resetAt: now + windowMs }\n }\n else {\n entry.count++\n }\n this.store.set(key, entry)\n return entry\n }\n}\n\n/**\n * 创建速率限制中间件\n *\n * 基于可插拔存储的滑动窗口限流:\n * - 超限时返回 429,并在响应头中告知重置时间\n * - 正常响应附带 `X-RateLimit-*` 头\n * - 默认使用内存存储(单进程),可传入 `store` 实现分布式限流\n *\n * @param config - 限流配置\n * @returns Middleware 实例\n *\n * @example\n * ```ts\n * middleware: [\n * kit.middleware.rateLimit({ windowMs: 60_000, maxRequests: 100 }),\n * ]\n * ```\n */\nexport function rateLimitMiddleware(config: RateLimitConfig): Middleware {\n const {\n windowMs,\n maxRequests,\n keyGenerator = (event) => {\n try {\n return event.getClientAddress?.() ?? 'unknown'\n }\n catch {\n // 开发环境下 getClientAddress 可能抛出错误\n return 'unknown'\n }\n },\n onLimitReached,\n } = config\n\n // 构建存储:支持外部注入,默认内存\n const store: RateLimitStore = config.store ?? (() => {\n const memStore = new MemoryRateLimitStore()\n memStore.startCleanup(windowMs)\n return memStore\n })()\n\n return async (context, next) => {\n const { event, requestId } = context\n const key = keyGenerator(event)\n const now = Date.now()\n\n // 优先使用原子 increment,防止并发竞态\n let entry: RateLimitEntry\n if (store.increment) {\n entry = await store.increment(key, windowMs)\n }\n else {\n // 退回非原子流程(仅用于未实现 increment 的存储后端)\n const existing = await store.get(key)\n if (!existing || existing.resetAt < now) {\n entry = { count: 1, resetAt: now + windowMs }\n }\n else {\n entry = { ...existing, count: existing.count + 1 }\n }\n await store.set(key, entry)\n }\n\n // 设置速率限制头\n const remaining = Math.max(0, maxRequests - entry.count)\n const resetTime = Math.ceil(entry.resetAt / 1000)\n\n if (entry.count > maxRequests) {\n core.logger.warn('Rate limit exceeded', { key, requestId })\n\n if (onLimitReached) {\n return onLimitReached(event)\n }\n\n return new Response(\n JSON.stringify({\n success: false,\n error: {\n code: 'RATE_LIMIT_EXCEEDED',\n message: kitM('kit_rateLimitExceeded'),\n },\n requestId,\n }),\n {\n status: 429,\n headers: {\n 'Content-Type': 'application/json',\n 'X-RateLimit-Limit': String(maxRequests),\n 'X-RateLimit-Remaining': '0',\n 'X-RateLimit-Reset': String(resetTime),\n 'Retry-After': String(Math.ceil((entry.resetAt - now) / 1000)),\n },\n },\n )\n }\n\n const response = await next()\n\n // 添加速率限制头到响应\n response.headers.set('X-RateLimit-Limit', String(maxRequests))\n response.headers.set('X-RateLimit-Remaining', String(remaining))\n response.headers.set('X-RateLimit-Reset', String(resetTime))\n\n return response\n }\n}\n","/**\n * @h-ai/kit — Cookie 加密代理\n *\n * 通过 Proxy 拦截 SvelteKit Cookies 对象的 get/set 方法, 对指定名称的 Cookie 自动进行 SM4-CBC 加解密。\n * @module kit-cookie-proxy\n */\n\nimport type { CryptoFunctions } from '@h-ai/crypto'\nimport type { Cookies } from '@sveltejs/kit'\nimport { core } from '@h-ai/core'\n\n/**\n * Cookie 加密代理配置\n */\nexport interface CookieProxyConfig {\n /** 需要加密的 Cookie 名称集合 */\n names: Set<string>\n /** 对称加密服务(SM4) */\n symmetric: CryptoFunctions['symmetric']\n /** 加密密钥(32 字符十六进制) */\n encryptionKey: string\n}\n\n/**\n * 加密 Cookie 值的前缀标记\n *\n * 用于区分已加密和未加密的 Cookie 值,\n * 避免对明文值做解密导致乱码。\n */\nconst ENCRYPTED_PREFIX = 'enc:'\n\n/**\n * 创建加密 Cookie 代理\n *\n * 返回一个 Proxy 包装的 Cookies 对象:\n * - `get(name)` —— 若 name 在加密列表中,自动解密后返回明文;格式或解密失败时返回 `undefined`\n * - `set(name, value, opts)` —— 若 name 在加密列表中,自动加密后存储;加密失败时拒绝写入\n * - `delete(name, opts)` —— 透传,无需解密\n * - 其他方法原样透传\n *\n * @param cookies - SvelteKit 原始 Cookies 对象\n * @param config - 加密配置\n * @returns 代理后的 Cookies 对象(类型不变)\n */\nexport function createEncryptedCookieProxy(\n cookies: Cookies,\n config: CookieProxyConfig,\n): Cookies {\n const { names, symmetric, encryptionKey } = config\n const logger = core.logger.child({ module: 'kit', scope: 'cookie-proxy' })\n\n return new Proxy(cookies, {\n get(target, prop, receiver) {\n // 拦截 get 方法:对加密 Cookie 自动解密\n if (prop === 'get') {\n return (name: string, opts?: Parameters<Cookies['get']>[1]) => {\n const raw = target.get(name, opts)\n if (!raw || !names.has(name))\n return raw\n\n // 受保护 Cookie 不接受明文,避免攻击者绕过加密边界注入伪造值。\n if (!raw.startsWith(ENCRYPTED_PREFIX)) {\n logger.warn('Encrypted cookie has invalid format', { name })\n return undefined\n }\n\n try {\n const ciphertext = raw.slice(ENCRYPTED_PREFIX.length)\n // 格式: iv:ciphertext\n const separatorIndex = ciphertext.indexOf(':')\n if (separatorIndex === -1) {\n logger.warn('Encrypted cookie has invalid format', { name })\n return undefined\n }\n\n const iv = ciphertext.slice(0, separatorIndex)\n const encrypted = ciphertext.slice(separatorIndex + 1)\n\n const result = symmetric.decryptWithIV(encrypted, encryptionKey, iv)\n if (!result.success || typeof result.data !== 'string') {\n logger.warn('Cookie decryption failed', { name })\n return undefined\n }\n\n return result.data\n }\n catch {\n logger.warn('Cookie decryption error', { name })\n return undefined\n }\n }\n }\n\n // 拦截 set 方法:对加密 Cookie 自动加密\n if (prop === 'set') {\n return (name: string, value: string, opts: Parameters<Cookies['set']>[2]) => {\n if (names.has(name)) {\n const result = symmetric.encryptWithIV(value, encryptionKey)\n if (!result.success || !result.data) {\n logger.error('Cookie encryption failed', { name })\n throw new Error('Cookie encryption failed')\n }\n // 格式: enc:iv:ciphertext\n value = `${ENCRYPTED_PREFIX}${result.data.iv}:${result.data.ciphertext}`\n }\n\n return target.set(name, value, opts)\n }\n }\n\n // 其他方法(getAll / delete / serialize)原样透传\n return Reflect.get(target, prop, receiver)\n },\n })\n}\n","/**\n * @h-ai/kit — SvelteKit Handle Hook\n *\n * 创建 SvelteKit Handle Hook,集成请求 ID 生成、会话验证、Cookie 加密代理、\n * 路由守卫、中间件链与可选传输加密;同时提供 `sequence()` 组合多个 Handle。\n * @module kit-handle\n */\n\nimport type { Handle, RequestEvent } from '@sveltejs/kit'\nimport type { GuardConfig, GuardResult, HandleConfig, Middleware, MiddlewareContext, SessionData } from '../kit-types.js'\nimport type { CookieProxyConfig } from './kit-cookie-proxy.js'\nimport { core } from '@h-ai/core'\nimport { configureAuth, getAccessToken } from '../kit-auth.js'\nimport { kitM } from '../kit-i18n.js'\nimport { isSvelteKitControlFlow } from '../kit-utils.js'\nimport { loggingMiddleware as loggingMiddlewareFn } from '../middleware/kit-logging.js'\nimport { rateLimitMiddleware as rateLimitMiddlewareFn } from '../middleware/kit-ratelimit.js'\nimport { handleA2ARequest, resolveA2AConfig } from '../modules/a2a/kit-a2a-handle.js'\nimport { transportEncryptionMiddleware } from '../modules/crypto/kit-transport-middleware.js'\nimport { createEncryptedCookieProxy } from './kit-cookie-proxy.js'\n\n/**\n * 生成唯一请求级 ID\n *\n * 由时间戳(base36)+ 6 位随机串拼接,用于日志追踪与响应头 `X-Request-Id`。\n */\nfunction generateId(prefix: string): string {\n const timestamp = Date.now().toString(36)\n const random = crypto.randomUUID().replace(/-/g, '').substring(0, 8)\n return `${prefix}_${timestamp}${random}`\n}\n\n/**\n * 为 SvelteKit 响应补充默认安全头。\n *\n * 仅设置不会破坏页面渲染的基础头;CSP 需要应用结合 nonce / 静态资源策略单独配置。\n */\nfunction applyDefaultSecurityHeaders(response: Response): void {\n response.headers.set('X-Content-Type-Options', 'nosniff')\n response.headers.set('X-Frame-Options', 'DENY')\n response.headers.set('Referrer-Policy', 'no-referrer')\n}\n\n/**\n * 创建 hai handle hook\n *\n * 整合会话解析、路由守卫、中间件链与统一错误处理的 SvelteKit Handle 工厂。\n *\n * 执行顺序:\n * 1. 生成 `requestId` 并写入 `event.locals`\n * 2. 根据 `auth` 配置从 Bearer / Cookie 解析会话\n * 3. 根据 `auth.protectedPaths` 自动执行路由守卫 + 额外自定义守卫\n * 4. 构建中间件链(内置 logging / rateLimit + 自定义)并执行\n * 5. 调用 `resolve(event)` 获取业务响应\n * 6. 附加 `X-Request-Id` 响应头\n *\n * @param config - Handle 配置(均有合理默认值,可零配置使用)\n * @returns SvelteKit Handle 函数\n *\n * @example\n * ```ts\n * export const handle = kit.createHandle({\n * auth: {\n * verifyToken: validateSession,\n * loginUrl: '/auth/login',\n * protectedPaths: ['/admin/*', '/api/*'],\n * publicPaths: ['/api/auth/*', '/api/public/*'],\n * },\n * rateLimit: { maxRequests: 100 },\n * crypto: { crypto, transport: true },\n * })\n * ```\n */\nexport function createHandle(config: HandleConfig = {}): Handle {\n const {\n auth: authConfig,\n rateLimit: rateLimitConfig,\n logging: loggingConfig = true,\n crypto: cryptoConfig,\n onError,\n guards: customGuards = [],\n middleware: customMiddleware = [],\n a2a: a2aInput,\n } = config\n\n // ── A2A 配置解析 ──\n const a2aResolved = resolveA2AConfig(a2aInput)\n\n // ── 配置 Cookie 名 + 认证操作 ──\n if (authConfig?.cookieName || authConfig?.operations) {\n configureAuth({ cookieName: authConfig.cookieName, operations: authConfig.operations })\n }\n\n // ── 构建守卫列表(auth 自动守卫 + 自定义守卫) ──\n const guards: GuardConfig[] = []\n if (authConfig?.protectedPaths?.length) {\n guards.push({\n guard: buildAuthGuard(authConfig.verifyToken, authConfig.loginUrl),\n paths: authConfig.protectedPaths,\n exclude: authConfig.publicPaths,\n })\n }\n guards.push(...customGuards)\n\n // ── 构建中间件链 ──\n const builtinMiddleware: Middleware[] = []\n if (loggingConfig) {\n const logOpts = typeof loggingConfig === 'object' ? loggingConfig : { logBody: false }\n builtinMiddleware.push(loggingMiddlewareFn(logOpts))\n }\n if (rateLimitConfig) {\n builtinMiddleware.push(rateLimitMiddlewareFn({\n windowMs: rateLimitConfig.windowMs ?? 60000,\n maxRequests: rateLimitConfig.maxRequests ?? 100,\n }))\n }\n const allMiddleware = [...builtinMiddleware, ...customMiddleware]\n\n // ── 传输加密中间件单独包裹整个 handle 流程 ──\n const transportMiddleware = buildTransportMiddleware(cryptoConfig)\n\n // ── Cookie 加密配置预处理 ──\n const cookieProxyConfig = buildCookieProxyConfig(cryptoConfig)\n\n return async ({ event, resolve }) => {\n const requestId = generateId('req')\n const context: MiddlewareContext = {\n event,\n requestId,\n }\n\n // 注入 requestId 到 event.locals\n // Workaround:SvelteKit App.Locals 是项目侧声明的 interface,库代码无法靠模块增强检查动态 key。\n const locals = event.locals as unknown as Record<string, unknown>\n locals.requestId = requestId\n\n // ── Cookie 加密代理(透明) ──\n if (cookieProxyConfig) {\n const proxiedCookies = createEncryptedCookieProxy(event.cookies, cookieProxyConfig)\n Object.defineProperty(event, 'cookies', {\n value: proxiedCookies,\n writable: true,\n configurable: true,\n })\n }\n\n const runRequest = async (): Promise<Response> => {\n try {\n // ── A2A 端点拦截(在认证/守卫之前,A2A 有专用认证) ──\n if (a2aResolved) {\n const a2aResponse = await handleA2ARequest(event, requestId, a2aResolved)\n if (a2aResponse)\n return a2aResponse\n }\n\n // ── 会话解析 ──\n let session: SessionData | undefined\n\n if (authConfig) {\n const token = getAccessToken(event.request, event.cookies)\n if (token) {\n session = await authConfig.verifyToken(token) ?? undefined\n locals.session = session\n if (session) {\n locals.accessToken = token\n }\n }\n }\n context.session = session\n\n // ── 执行守卫 ──\n for (const guardConfig of guards) {\n const guardResult = await executeGuard(guardConfig, event, session)\n\n if (!guardResult.allowed) {\n if (guardResult.redirect) {\n return new Response(null, {\n status: 302,\n headers: { Location: guardResult.redirect },\n })\n }\n\n return new Response(\n JSON.stringify({\n success: false,\n error: {\n code: 'FORBIDDEN',\n message: guardResult.message ?? kitM('kit_accessDenied'),\n },\n requestId,\n }),\n {\n status: guardResult.status ?? 403,\n headers: { 'Content-Type': 'application/json' },\n },\n )\n }\n }\n\n // ── 中间件链 ──\n const response = await executeMiddlewareChain(\n allMiddleware,\n context,\n () => resolve(event),\n )\n\n return response\n }\n catch (error) {\n // SvelteKit 控制流异常(redirect / error)必须继续抛出\n if (isSvelteKitControlFlow(error)) {\n throw error\n }\n\n core.logger.error('Request failed', { requestId, error: error instanceof Error ? error.message : error })\n\n if (onError) {\n return onError(error, event)\n }\n\n // 默认错误响应\n return new Response(\n JSON.stringify({\n success: false,\n error: {\n code: 'INTERNAL_ERROR',\n message: kitM('kit_internalError'),\n },\n requestId,\n }),\n {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n },\n )\n }\n }\n\n const response = transportMiddleware\n ? await transportMiddleware(context, runRequest)\n : await runRequest()\n\n applyDefaultSecurityHeaders(response)\n response.headers.set('X-Request-Id', requestId)\n return response\n }\n}\n\n// ─── 内部:构建 auth 守卫 ───\n\n/**\n * 根据 auth 配置构建路由守卫\n *\n * - API 路径(以 `/api/` 开头):未认证返回 401 JSON\n * - 非 API 路径:未认证时重定向到 loginUrl(若配置),否则返回 401\n */\nfunction buildAuthGuard(\n verifyToken: (token: string) => Promise<SessionData | null>,\n loginUrl?: string,\n): (event: RequestEvent, session?: SessionData) => GuardResult {\n // verifyToken 参数仅用于类型签名对齐,实际会话已在上层解析\n void verifyToken\n\n return (event, session) => {\n if (session) {\n return { allowed: true }\n }\n\n const isApiRoute = event.url.pathname.startsWith('/api/')\n\n if (isApiRoute) {\n return {\n allowed: false,\n message: kitM('kit_authRequired'),\n status: 401,\n }\n }\n\n if (loginUrl) {\n const returnUrl = encodeURIComponent(event.url.pathname + event.url.search)\n return {\n allowed: false,\n redirect: `${loginUrl}?returnUrl=${returnUrl}`,\n }\n }\n\n return {\n allowed: false,\n message: kitM('kit_authRequired'),\n status: 401,\n }\n }\n}\n\n// ─── 内部:守卫执行 ───\n\n/**\n * 执行单个守卫(含路径过滤逻辑)\n */\nasync function executeGuard(\n config: GuardConfig,\n event: RequestEvent,\n session?: SessionData,\n): Promise<GuardResult> {\n const { guard, paths, exclude } = config\n const pathname = event.url.pathname\n\n if (exclude?.some(pattern => matchPath(pathname, pattern))) {\n return { allowed: true }\n }\n\n if (paths && !paths.some(pattern => matchPath(pathname, pattern))) {\n return { allowed: true }\n }\n\n return guard(event, session)\n}\n\n// ─── 内部:中间件执行 ───\n\n/**\n * 递归执行中间件链(洋葱模型)\n */\nasync function executeMiddlewareChain(\n middleware: Middleware[],\n context: MiddlewareContext,\n final: () => Response | Promise<Response>,\n): Promise<Response> {\n if (middleware.length === 0) {\n return final()\n }\n\n const [current, ...rest] = middleware\n\n return current(context, () => executeMiddlewareChain(rest, context, final))\n}\n\n// ─── 内部:路径匹配 ───\n\n/**\n * 路径通配符匹配(`/*` `/**` 精确匹配)\n */\nfunction matchPath(pathname: string, pattern: string): boolean {\n if (pattern.endsWith('/*')) {\n const base = pattern.slice(0, -2)\n return pathname === base || pathname.startsWith(`${base}/`)\n }\n\n if (pattern.endsWith('/**')) {\n const base = pattern.slice(0, -3)\n return pathname === base || pathname.startsWith(`${base}/`)\n }\n\n return pathname === pattern\n}\n\n// ─── 内部:Crypto 配置构建 ───\n\n/**\n * 构建最终中间件链:将传输加密中间件自动插入到最外层\n */\nfunction buildTransportMiddleware(\n cryptoConfig: HandleConfig['crypto'],\n): Middleware | null {\n if (!cryptoConfig?.transport)\n return null\n\n const transportOpts = typeof cryptoConfig.transport === 'object' ? cryptoConfig.transport : {}\n\n return transportEncryptionMiddleware({\n enabled: true,\n crypto: cryptoConfig.crypto,\n keyExchangePath: transportOpts.keyExchangePath,\n excludePaths: transportOpts.excludePaths,\n encryptResponse: transportOpts.encryptResponse,\n keyStore: transportOpts.keyStore,\n maxClients: transportOpts.maxClients,\n requireEncryption: transportOpts.requireEncryption,\n })\n}\n\n/**\n * 构建 Cookie 加密代理配置\n */\nfunction buildCookieProxyConfig(\n cryptoConfig: HandleConfig['crypto'],\n): CookieProxyConfig | null {\n if (!cryptoConfig?.encryptedCookies?.length)\n return null\n\n // eslint-disable-next-line node/prefer-global/process\n const key = cryptoConfig.cookieEncryptionKey ?? (typeof process !== 'undefined' ? process.env?.HAI_KIT_COOKIE_KEY : undefined)\n if (!key) {\n throw new Error('Cookie encryption requires crypto.cookieEncryptionKey or HAI_KIT_COOKIE_KEY')\n }\n\n return {\n names: new Set(cryptoConfig.encryptedCookies),\n symmetric: cryptoConfig.crypto.symmetric,\n encryptionKey: key,\n }\n}\n\n/**\n * 组合多个 SvelteKit handle 为单一 handle\n *\n * 洋葱模型:`sequence(a, b, c)` 执行顺序为 a → b → c → resolve → c → b → a。\n *\n * @param handles - 待组合的 handle 函数列表\n * @returns 组合后的单一 Handle 函数\n *\n * @example\n * ```ts\n * const haiHandle = kit.createHandle({ ... })\n * export const handle = kit.sequence(i18nHandle, haiHandle)\n * ```\n */\nexport function sequence(...handles: Handle[]): Handle {\n const filtered = handles.filter(Boolean)\n if (filtered.length === 0) {\n return ({ event, resolve }) => resolve(event)\n }\n if (filtered.length === 1) {\n return filtered[0]\n }\n return async ({ event, resolve }) => {\n return filtered.reduceRight(\n (next, handle) => (event: RequestEvent) => handle({ event, resolve: next }),\n resolve,\n )(event)\n }\n}\n","/**\n * @h-ai/kit — API 响应工具\n *\n * 标准化 API 响应工具集,统一 `{ success, data?, error?, requestId? }` 结构。\n * 提供成功响应(ok / created / noContent)、错误响应\n * (badRequest / unauthorized / forbidden / notFound / conflict / validationError / internalError)\n * 以及重定向响应。\n * @module kit-response\n */\n\nimport type { HaiError } from '@h-ai/core'\nimport type { ApiResponse } from './kit-types.js'\nimport { kitM } from './kit-i18n.js'\n\n/**\n * 创建 200 成功响应\n *\n * @param data - 响应数据,序列化为 JSON\n * @param requestId - 可选请求 ID,用于链路追踪\n * @returns `{ success: true, data, requestId }` 格式的 JSON Response\n *\n * @example\n * ```ts\n * return kit.response.ok({ id: '1', name: 'Alice' })\n * ```\n */\nexport function ok<T>(data: T, requestId?: string): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n requestId,\n }\n\n return new Response(JSON.stringify(response), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 创建 201 资源创建成功响应\n *\n * @param data - 新创建的资源数据\n * @param requestId - 可选请求 ID\n * @returns `{ success: true, data }` 格式的 JSON Response(status 201)\n *\n * @example\n * ```ts\n * return kit.response.created({ id: 'new_1' })\n * ```\n */\nexport function created<T>(data: T, requestId?: string): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n requestId,\n }\n\n return new Response(JSON.stringify(response), {\n status: 201,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 创建 204 无内容响应\n *\n * 通常用于 DELETE 成功或无返回值的更新操作。\n *\n * @returns 空 body、status 204 的 Response\n */\nexport function noContent(): Response {\n return new Response(null, { status: 204 })\n}\n\n/**\n * 创建自定义错误响应\n *\n * @param code - 错误码(如 `'CUSTOM_ERROR'`)\n * @param message - 人可读错误消息\n * @param status - HTTP 状态码,默认 400\n * @param requestId - 可选请求 ID\n * @param details - 可选额外详情\n * @returns `{ success: false, error: { code, message, details } }` 格式的 JSON Response\n *\n * @example\n * ```ts\n * return kit.response.error('QUOTA_EXCEEDED', '配额已用尽', 429)\n * ```\n */\nexport function error(\n code: string,\n message: string,\n status = 400,\n requestId?: string,\n details?: unknown,\n): Response {\n const response: ApiResponse = {\n success: false,\n error: {\n code,\n message,\n details,\n },\n requestId,\n }\n\n return new Response(JSON.stringify(response), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 创建 400 Bad Request 响应\n *\n * @param message - 错误消息\n * @param requestId - 可选请求 ID\n * @param details - 可选额外详情\n * @returns error code 为 `'BAD_REQUEST'` 的 JSON Response\n */\nexport function badRequest(message: string, requestId?: string, details?: unknown): Response {\n return error('BAD_REQUEST', message, 400, requestId, details)\n}\n\n/**\n * 创建 401 Unauthorized 响应\n *\n * @param message - 错误消息,默认 `'Authentication required'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'UNAUTHORIZED'` 的 JSON Response\n */\nexport function unauthorized(message?: string, requestId?: string): Response {\n return error('UNAUTHORIZED', message ?? kitM('kit_authRequired'), 401, requestId)\n}\n\n/**\n * 创建 403 Forbidden 响应\n *\n * @param message - 错误消息,默认 `'Access denied'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'FORBIDDEN'` 的 JSON Response\n */\nexport function forbidden(message?: string, requestId?: string): Response {\n return error('FORBIDDEN', message ?? kitM('kit_accessDenied'), 403, requestId)\n}\n\n/**\n * 创建 404 Not Found 响应\n *\n * @param message - 错误消息,默认 `'Resource not found'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'NOT_FOUND'` 的 JSON Response\n */\nexport function notFound(message?: string, requestId?: string): Response {\n return error('NOT_FOUND', message ?? kitM('kit_resourceNotFound'), 404, requestId)\n}\n\n/**\n * 创建 409 Conflict 响应\n *\n * @param message - 冲突描述(如重复创建等)\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'CONFLICT'` 的 JSON Response\n */\nexport function conflict(message: string, requestId?: string): Response {\n return error('CONFLICT', message, 409, requestId)\n}\n\n/**\n * 创建 422 Unprocessable Entity 响应(验证错误)\n *\n * @param errors - 字段级别的验证错误列表\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'VALIDATION_ERROR'`,details 包含 `errors` 数组\n *\n * @example\n * ```ts\n * return kit.response.validationError([\n * { field: 'email', message: '格式无效' },\n * ])\n * ```\n */\nexport function validationError(\n errors: Array<{ field: string, message: string }>,\n requestId?: string,\n): Response {\n return error('VALIDATION_ERROR', kitM('kit_validationFailed'), 422, requestId, { errors })\n}\n\n/**\n * 创建 500 Internal Server Error 响应\n *\n * @param message - 错误消息,默认 `'Internal server error'`\n * @param requestId - 可选请求 ID\n * @returns error code 为 `'INTERNAL_ERROR'` 的 JSON Response\n */\nexport function internalError(message?: string, requestId?: string): Response {\n return error('INTERNAL_ERROR', message ?? kitM('kit_internalError'), 500, requestId)\n}\n\n/**\n * 创建重定向响应\n *\n * @param url - 目标 URL\n * @param status - HTTP 状态码,默认 302;常用 303(POST 后重定向)\n * @returns 带 `Location` 头的空 body Response\n *\n * @example\n * ```ts\n * return kit.response.redirect('/dashboard', 303)\n * ```\n */\nexport function redirect(url: string, status: 301 | 302 | 303 | 307 | 308 = 302): Response {\n return new Response(null, {\n status,\n headers: { Location: url },\n })\n}\n\n// ─── HaiResult → Response 转换 ───\n\n/**\n * 将 HaiResult<T> 转换为标准 API Response\n *\n * 成功时返回 200 ok(data),失败时从 error 对象中提取 code、message,\n * 并根据 httpStatusMap 映射 HTTP 状态码(未命中时默认 400)。\n *\n * @param result - core HaiResult 对象({ success, data } 或 { success: false, error })\n * @param httpStatusMap - 模块导出的错误码 → HTTP 状态码映射表(如 IamErrorHttpStatus)\n * @param requestId - 可选请求 ID,用于链路追踪\n * @returns 标准化 JSON Response\n *\n * @example\n * ```ts\n * // 无映射(默认 400)\n * return kit.response.fromResult(result)\n *\n * // 带模块错误码映射\n * return kit.response.fromResult(result, IamErrorHttpStatus)\n * ```\n */\nexport function fromResult<T>(\n result: { success: true, data: T } | { success: false, error: { code: number | string, message: string, [key: string]: unknown } },\n httpStatusMap?: Record<number | string, number>,\n requestId?: string,\n): Response {\n if (result.success) {\n return ok(result.data, requestId)\n }\n\n const { code, message } = result.error\n const status = httpStatusMap?.[code] ?? 400\n return error(String(code), message, status, requestId)\n}\n\nexport function fromError(\n haiError: HaiError,\n requestId?: string,\n): Response {\n return error(String(haiError.code), haiError.message, haiError.httpStatus ?? 400, requestId)\n}\n","/**\n * @h-ai/kit — API Handler 包装器\n *\n * 统一封装 SvelteKit API Handler 的错误处理逻辑。\n * @module kit-handler\n */\n\nimport type { RequestEvent, RequestHandler } from '@sveltejs/kit'\nimport { core } from '@h-ai/core'\nimport { internalError } from './kit-response.js'\nimport { isResponseLike, isSvelteKitControlFlow } from './kit-utils.js'\n\n/**\n * 创建 API Handler 包装器\n *\n * 将业务逻辑包裹在统一的异常边界中:\n * 1. 正常执行 `fn(event)` 返回 Response\n * 2. 若 `fn` throw 了 `Response`(如 `kit.guard.require` / `kit.validate.body`),直接返回该 Response\n * 3. 若 `fn` throw 了 SvelteKit 控制流(`redirect()` / `error()`),继续抛出\n * 4. 其他异常:记录日志 → 返回 `kit.response.internalError()`\n *\n * @param fn - 业务处理函数\n * @returns SvelteKit RequestHandler\n *\n * @example\n * ```ts\n * export const GET = kit.handler(async ({ locals }) => {\n * kit.guard.require(locals.session, 'user:read')\n * return kit.response.ok(await getUsers())\n * })\n * ```\n */\nexport function handler(fn: (event: RequestEvent) => Promise<Response> | Response): RequestHandler {\n return async (event) => {\n try {\n return await fn(event)\n }\n catch (error) {\n // validate.body / guard.require 等场景会 throw Response,直接返回即可\n // 使用 isResponseLike 兼容 Vite 开发环境下跨模块 instanceof 失效\n if (isResponseLike(error)) {\n return error\n }\n\n // redirect/error 等 SvelteKit 控制流必须继续抛出\n if (isSvelteKitControlFlow(error)) {\n throw error\n }\n\n const normalizedError = error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n cause: error.cause,\n }\n : error\n\n core.logger.error('Request handler error', {\n error: normalizedError,\n path: event.url.pathname,\n method: event.request.method,\n })\n\n return internalError()\n }\n }\n}\n","/**\n * @h-ai/kit — 请求数据验证\n *\n * 基于 Zod 的请求数据验证工具,支持表单/JSON Body、URL 查询参数与路由参数。\n * Zod 默认错误消息的本地化规则委托给 `core.zodValidation`,避免 kit / serv\n * 等模块重复维护同一套 issue 解析与消息映射逻辑;模块前缀映射也统一交给\n * `core.zodValidation.createPrefixedZodMessageGetter()` 处理。\n * 每种数据源都提供两类 API:\n * - 安全返回:`FormValidationResult`\n * - 失败抛出:`OrFail`(抛出 `Response` 以走 SvelteKit 控制流)\n * @module kit-validation\n */\n\nimport type { z } from 'zod'\nimport type { FormValidationResult } from './kit-types.js'\nimport { core } from '@h-ai/core'\nimport { z as zod } from 'zod'\nimport { kitM } from './kit-i18n.js'\nimport { badRequest } from './kit-response.js'\n\n// ─── 内部工具 ───\n\n/**\n * 构造与 kit 消息表对齐的 `ZodMessageGetter`。\n *\n * 统一复用 `core.zodValidation` 的 Zod issue 解析与默认消息识别逻辑,\n * kit 仅提供自己的消息获取器。\n */\nconst getKitZodMessage = core.zodValidation.createPrefixedZodMessageGetter<Parameters<typeof kitM>[0]>(\n 'kit',\n (messageKey, params) => kitM(messageKey, { params }),\n)\n\nfunction validateParsedData<T extends z.ZodType>(\n data: unknown,\n schema: T,\n): FormValidationResult<z.infer<T>> {\n const result = schema.safeParse(data)\n if (result.success)\n return { valid: true, data: result.data, errors: [] }\n return {\n valid: false,\n errors: core.zodValidation.mapZodErrorToFormErrors(result.error, getKitZodMessage),\n }\n}\n\nfunction unwrapValidationResultOrThrow<T>(result: FormValidationResult<T>): T {\n if (result.valid && result.data !== undefined)\n return result.data\n\n throw badRequest(\n result.errors[0]?.message ?? kitM('kit_validationFailed'),\n undefined,\n { errors: result.errors },\n )\n}\n\n// ─── 公共验证函数 ───\n\n/**\n * 从 Request 解析并验证表单数据\n *\n * 支持 `application/json` 和 `multipart/form-data` / `application/x-www-form-urlencoded`。\n * 其他 Content-Type 返回全局错误 `{ field: '_', message: 'Unsupported content type' }`。\n *\n * @param request - SvelteKit 请求对象\n * @param schema - Zod Schema\n * @returns 验证结果;成功时 `valid: true` 且 `data` 类型安全\n *\n * @example\n * ```ts\n * const { valid, data, errors } = await kit.validate.form(event.request, CreateUserSchema)\n * if (!valid) return kit.response.validationError(errors)\n * ```\n */\nexport async function validateForm<T extends z.ZodType>(\n request: Request,\n schema: T,\n): Promise<FormValidationResult<z.infer<T>>> {\n try {\n const contentType = request.headers.get('content-type') ?? ''\n\n let data: unknown\n\n if (contentType.includes('application/json')) {\n data = await request.json()\n }\n else if (contentType.includes('application/x-www-form-urlencoded') || contentType.includes('multipart/form-data')) {\n const formData = await request.formData()\n data = Object.fromEntries(formData)\n }\n else {\n return {\n valid: false,\n errors: [{ field: '_', message: kitM('kit_unsupportedContentType') }],\n }\n }\n\n return validateParsedData(data, schema)\n }\n catch {\n return {\n valid: false,\n errors: [{ field: '_', message: kitM('kit_parseBodyFailed') }],\n }\n }\n}\n\n/**\n * 从 URL 查询参数验证\n *\n * 将 `url.searchParams` 转为普通对象后交给 Zod 校验。\n * 适用于 GET 请求的分页、搜索等场景。\n *\n * @param url - 请求 URL 对象\n * @param schema - Zod Schema\n * @returns 验证结果\n *\n * @example\n * ```ts\n * const { valid, data } = kit.validate.query(event.url, PaginationSchema)\n * ```\n */\nexport function validateQuery<T extends z.ZodType>(\n url: URL,\n schema: T,\n): FormValidationResult<z.infer<T>> {\n const data = Object.fromEntries(url.searchParams)\n return validateParsedData(data, schema)\n}\n\n/**\n * 验证路径参数\n *\n * 将 SvelteKit 路由 `params` 交给 Zod 校验,适用于动态路由段的类型安全校验。\n *\n * @param params - SvelteKit 路由参数(`event.params`)\n * @param schema - Zod Schema\n * @returns 验证结果\n *\n * @example\n * ```ts\n * const { valid, data } = kit.validate.params(event.params, z.object({ id: z.string().uuid() }))\n * ```\n */\nexport function validateParams<T extends z.ZodType>(\n params: Record<string, string>,\n schema: T,\n): FormValidationResult<z.infer<T>> {\n return validateParsedData(params, schema)\n}\n\n// ─── OrFail 变体 — 校验失败时抛出 Response(SvelteKit 控制流) ───\n\n/**\n * 从 Request 解析并验证表单数据,失败时 throw Response\n *\n * 与 `validateForm` 功能相同,但校验失败时 throw 400 Response(SvelteKit 控制流),\n * 搭配 `kit.handler()` 使用可精简 handler 代码。\n *\n * @param request - SvelteKit 请求对象\n * @param schema - Zod Schema\n * @returns 校验通过的数据(类型安全)\n * @throws Response - 400 BadRequest(含首条错误消息)\n *\n * @example\n * ```ts\n * export const POST = kit.handler(async ({ request }) => {\n * const data = await kit.validate.body(request, CreateUserSchema)\n * // data 类型安全,校验已通过\n * })\n * ```\n */\nexport async function validateFormOrFail<T extends z.ZodType>(\n request: Request,\n schema: T,\n): Promise<z.infer<T>> {\n return unwrapValidationResultOrThrow(await validateForm(request, schema))\n}\n\n/**\n * 从 URL 查询参数验证,失败时 throw Response\n *\n * @param url - 请求 URL 对象\n * @param schema - Zod Schema\n * @returns 校验通过的数据\n * @throws Response - 400 BadRequest\n *\n * @example\n * ```ts\n * const query = kit.validate.query(event.url, PaginationSchema)\n * ```\n */\nexport function validateQueryOrFail<T extends z.ZodType>(\n url: URL,\n schema: T,\n): z.infer<T> {\n return unwrapValidationResultOrThrow(validateQuery(url, schema))\n}\n\n/**\n * 验证路径参数,失败时 throw Response\n *\n * @param params - SvelteKit 路由参数\n * @param schema - Zod Schema\n * @returns 校验通过的数据\n * @throws Response - 400 BadRequest\n *\n * @example\n * ```ts\n * const { id } = kit.validate.params(event.params, IdParamSchema)\n * ```\n */\nexport function validateParamsOrFail<T extends z.ZodType>(\n params: Record<string, string>,\n schema: T,\n): z.infer<T> {\n return unwrapValidationResultOrThrow(validateParams(params, schema))\n}\n\n// ─── 通用 Schema ───\n\n/**\n * 路径参数 id 校验 Schema\n *\n * 验证 `event.params.id` 为非空字符串。\n *\n * @example\n * ```ts\n * const { id } = kit.validate.params(event.params, IdParamSchema)\n * ```\n */\nexport const IdParamSchema = zod.object({\n id: zod.string().min(1, kitM('kit_idRequired')),\n})\n\n/** 分页 pageSize 上限 */\nconst MAX_PAGE_SIZE = 100\n\n/**\n * 通用分页查询参数 Schema\n *\n * 包含 page(默认 1)、pageSize(默认 20,上限 100)、search(可选)。\n * 可通过 `.extend()` 扩展业务字段。\n *\n * @example\n * ```ts\n * // 直接使用\n * const { page, pageSize, search } = kit.validate.query(url, PaginationQuerySchema)\n *\n * // 扩展业务字段\n * const ListUsersSchema = PaginationQuerySchema.extend({\n * enabled: z.enum(['true', 'false']).transform(v => v === 'true').optional(),\n * })\n * ```\n */\nexport const PaginationQuerySchema = zod.object({\n page: zod.coerce.number().int().min(1).default(1),\n pageSize: zod.coerce.number().int().min(1).max(MAX_PAGE_SIZE).default(20),\n search: zod.string().optional(),\n})\n","import type { HaiResult } from '@h-ai/core'\n/** SvelteKit 标准认证端点,统一验证、Cookie 和 HaiResult 处理。 */\nimport type { IamFunctions } from '@h-ai/iam'\nimport {\n IamConfirmPasswordResetInputSchema,\n IamLdapLoginInputSchema,\n IamLoginInputSchema,\n IamOtpLoginInputSchema,\n IamRegisterInputSchema,\n IamRequestPasswordResetInputSchema,\n IamSendOtpInputSchema,\n} from '@h-ai/api-contract'\nimport { login, loginWithLdap, loginWithOtp, registerAndLogin } from './kit-auth.js'\nimport { handler } from './kit-handler.js'\nimport { fromError, ok } from './kit-response.js'\nimport { validateFormOrFail } from './kit-validation.js'\n\n/** 标准匿名认证端点;不会放开 /me、改密等账户端点。 */\nexport const authApiPublicPaths = ['/api/auth/config', '/api/auth/login', '/api/auth/login/ldap', '/api/auth/login/otp', '/api/auth/register', '/api/auth/otp/send', '/api/auth/password-reset/request', '/api/auth/password-reset/confirm']\n\n/** 应用路由直接导出对应 handler;认证 ops 仍由 createHandle 注入。 */\nexport function createAuthApi(iam: IamFunctions) {\n function response<T>(result: HaiResult<T>) {\n return result.success ? ok(result.data) : fromError(result.error)\n }\n return {\n publicConfig: handler(() => ok(iam.publicConfig)),\n login: handler(async ({ request, cookies }) => {\n const input = await validateFormOrFail(request, IamLoginInputSchema)\n const result = await login(cookies, input)\n return result.success ? ok({ user: result.data.user }) : fromError(result.error)\n }),\n loginWithLdap: handler(async ({ request, cookies }) => {\n const input = await validateFormOrFail(request, IamLdapLoginInputSchema)\n const result = await loginWithLdap(cookies, input)\n return result.success ? ok({ user: result.data.user }) : fromError(result.error)\n }),\n loginWithOtp: handler(async ({ request, cookies }) => {\n const input = await validateFormOrFail(request, IamOtpLoginInputSchema)\n const result = await loginWithOtp(cookies, input)\n return result.success ? ok({ user: result.data.user }) : fromError(result.error)\n }),\n register: handler(async ({ request, cookies }) => {\n const input = await validateFormOrFail(request, IamRegisterInputSchema)\n const result = await registerAndLogin(cookies, input)\n return result.success ? ok({ user: result.data.user }) : fromError(result.error)\n }),\n sendOtp: handler(async ({ request }) => {\n const input = await validateFormOrFail(request, IamSendOtpInputSchema)\n return response(await iam.auth.sendOtp(input.identifier))\n }),\n requestPasswordReset: handler(async ({ request }) => {\n const input = await validateFormOrFail(request, IamRequestPasswordResetInputSchema)\n return response(await iam.user.requestPasswordReset(input.identifier))\n }),\n confirmPasswordReset: handler(async ({ request }) => {\n const input = await validateFormOrFail(request, IamConfirmPasswordResetInputSchema)\n return response(await iam.user.confirmPasswordReset(input.token, input.newPassword))\n }),\n }\n}\n","/**\n * @h-ai/kit — 服务对象主入口\n *\n * SvelteKit 集成模块的统一命名空间出口。 所有功能通过 kit 对象访问:\n * @module kit-main\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 { hasPermission, requirePermission } from './guards/kit-permission.js'\nimport { createHandle, sequence } from './hooks/kit-handle.js'\nimport { authApiPublicPaths, createAuthApi } from './kit-auth-api.js'\nimport {\n clearBrowserToken,\n createTokenStore,\n login,\n loginWithApiKey,\n loginWithLdap,\n loginWithOtp,\n logout,\n registerAndLogin,\n setBrowserToken,\n} from './kit-auth.js'\nimport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig } from './kit-config.js'\nimport { handler } from './kit-handler.js'\nimport { setAllModulesLocale } from './kit-i18n.js'\nimport { badRequest, conflict, created, error, forbidden, fromError, fromResult, internalError, noContent, notFound, ok, redirect, unauthorized, validationError } from './kit-response.js'\nimport { IdParamSchema, PaginationQuerySchema, validateFormOrFail, validateParamsOrFail, validateQueryOrFail } from './kit-validation.js'\n\nexport { KitConfigSchema, resolveKitConfig, resolveKitTransportConfig }\n\n/**\n * Kit 模块统一出口。\n *\n * 作为纯工具模块,kit 不需要 init/close 生命周期,\n * 所有功能均为无状态工厂函数或工具函数。\n */\nexport const kit = {\n // ─── Handle Hook ───\n\n /** 创建 SvelteKit Handle Hook(含 auth / logging / rateLimit 内置配置) */\n createHandle,\n /** 组合多个 Handle */\n sequence,\n /** API Handler 包装器(自动错误边界) */\n handler,\n\n // ─── 路由守卫 ───\n\n guard: {\n /** 要求权限,不满足时 throw Response(SvelteKit 控制流) */\n require: requirePermission,\n /** 检查会话是否具有指定权限(布尔) */\n check: hasPermission,\n },\n\n // ─── API 响应 ───\n\n response: {\n /** 200 成功 */\n ok,\n /** 201 创建成功 */\n created,\n /** 204 无内容 */\n noContent,\n /** 自定义错误响应 */\n error,\n /** 400 BadRequest */\n badRequest,\n /** 401 Unauthorized */\n unauthorized,\n /** 403 Forbidden */\n forbidden,\n /** 404 NotFound */\n notFound,\n /** 409 Conflict */\n conflict,\n /** 422 验证错误 */\n validationError,\n /** 500 InternalError */\n internalError,\n /** 重定向 */\n redirect,\n /** 将 HaiResult<T> 转为标准 API Response(支持 httpStatusMap) */\n fromResult,\n /** 将模块错误码映射为标准 HTTP Response */\n fromError,\n },\n\n // ─── 验证 ───\n\n validate: {\n /** 验证请求体(JSON/表单),失败 throw Response */\n body: validateFormOrFail,\n /** 验证查询参数,失败 throw Response */\n query: validateQueryOrFail,\n /** 验证路径参数,失败 throw Response */\n params: validateParamsOrFail,\n /** 路径参数 id Schema({id: string}) */\n IdParamSchema,\n /** 通用分页查询 Schema(page / pageSize / search) */\n PaginationQuerySchema,\n },\n\n // ─── 客户端工具 ───\n\n client: {\n /** 创建统一客户端(CSRF + 传输加密透明合并) */\n create: createKitClient,\n /** 标准认证表单动作(Cookie 模式)。 */\n createAuthActions: createKitAuthActions,\n /**\n * 用解析后的 {@link KitConfig} 一键安装浏览器端传输加密\n * (应用层推荐入口;内部预热 crypto 并调用 installBrowserTransportFetch)\n */\n installBrowserTransport,\n /** 底层入口:直接传 transport 配置安装浏览器全局 fetch 包装 */\n installBrowserTransportFetch,\n },\n\n // ─── 认证工具 ───\n\n auth: {\n /** 标准匿名认证端点白名单。 */\n publicPaths: authApiPublicPaths,\n /** 标准配置/登录/注册/验证码/重置 handler 集合。 */\n createApi: createAuthApi,\n /** 服务端登录(密码):内部调用 iam.auth.login + 自动写入 Token Cookie */\n login,\n /** 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp + 自动写入 Token Cookie */\n loginWithOtp,\n /** 服务端登录(LDAP):内部调用 iam.auth.loginWithLdap + 自动写入 Token Cookie */\n loginWithLdap,\n /** 服务端登录(API Key):内部调用 iam.auth.loginWithApiKey + 自动写入 Token Cookie */\n loginWithApiKey,\n /** 服务端注册并登录:内部调用 iam.auth.registerAndLogin + 自动写入 Token Cookie */\n registerAndLogin,\n /** 服务端登出:内部调用 iam.auth.logout + 清除 Token Cookie */\n logout,\n /** 写入浏览器端 Access Token(客户端 login/register 用) */\n setBrowserToken,\n /** 清除浏览器端 Access Token(客户端 logout 用) */\n clearBrowserToken,\n /** 创建浏览器端 Token 存储器(自定义 key 时使用) */\n createTokenStore,\n },\n\n // ─── CRUD ───\n\n crud: {\n /** 定义 CRUD 资源(声明式配置 → 操作对象) */\n define: defineCrud,\n },\n\n // ─── i18n ───\n\n i18n: {\n /** 统一设置所有 hai 模块的默认语言 */\n setLocale: setAllModulesLocale,\n },\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/kit",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.59",
4
+ "version": "0.1.0-alpha.60",
5
5
  "description": "Hai Framework SvelteKit integration module.",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -58,9 +58,10 @@
58
58
  }
59
59
  },
60
60
  "dependencies": {
61
- "@h-ai/core": "0.1.0-alpha.59",
62
- "@h-ai/crypto": "0.1.0-alpha.59",
63
- "@h-ai/iam": "0.1.0-alpha.59",
61
+ "@h-ai/api-contract": "0.1.0-alpha.60",
62
+ "@h-ai/core": "0.1.0-alpha.60",
63
+ "@h-ai/crypto": "0.1.0-alpha.60",
64
+ "@h-ai/iam": "0.1.0-alpha.60",
64
65
  "zod": "^4.6.5"
65
66
  },
66
67
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/kit-auth.ts","../src/client/kit-client.ts"],"names":[],"mappings":"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","file":"chunk-CTIN5EQP.js","sourcesContent":["/**\n * @h-ai/kit — Bearer 认证工具\n *\n * 提供服务端认证 Cookie 管理(login / logout)与浏览器端 Token 存储工具。\n * @module kit-auth\n */\n\nimport type { HaiResult } from '@h-ai/core'\nimport type { ApiKeyCredentials, AuthResult, LdapCredentials, OtpCredentials, PasswordCredentials, RegisterOptions } from '@h-ai/iam'\nimport type { AuthOperations, AuthOperationsProvider } from './kit-types.js'\nimport process from 'node:process'\nimport { err } from '@h-ai/core'\nimport { kitM } from './kit-i18n.js'\n\n/** 默认 Token Cookie 名 */\nconst DEFAULT_TOKEN_COOKIE_NAME = 'hai_access_token'\n\n/**\n * 应用级认证配置(由 createHandle 一次性初始化,生命周期同进程)\n *\n * 此状态非请求级:仅在 createHandle() 时写入一次,后续所有请求只读访问。\n */\nconst authState = {\n cookieName: DEFAULT_TOKEN_COOKIE_NAME,\n operations: null as AuthOperationsProvider | null,\n}\n\n/**\n * 配置认证参数\n *\n * 通常由 `createHandle` 在初始化时自动调用,无需手动调用。\n */\nexport function configureAuth(config: { cookieName?: string, operations?: AuthOperationsProvider }): void {\n if (config.cookieName)\n authState.cookieName = config.cookieName\n if (config.operations)\n authState.operations = config.operations\n}\n\ninterface CookieReader {\n get: (name: string) => string | undefined\n}\n\ninterface CookieWriter {\n set: (name: string, value: string, options: {\n path: string\n httpOnly: boolean\n sameSite: 'lax' | 'strict' | 'none'\n secure: boolean\n maxAge?: number\n }) => void\n delete: (name: string, options: { path: string }) => void\n}\n\n/** 浏览器 Token 存储器 */\nexport interface BrowserTokenStore {\n get: () => string | null\n set: (token: string) => void\n clear: () => void\n}\n\nfunction createMemoryTokenStore(): BrowserTokenStore {\n let token: string | null = null\n return {\n get: () => token,\n set: (value: string) => { token = value },\n clear: () => { token = null },\n }\n}\n\n// 默认浏览器 Token 只保存在当前页面内存中,避免 auth: true 隐式落到 localStorage。\nconst defaultBrowserTokenStore = createMemoryTokenStore()\n\n/** 获取默认浏览器 Token 存储(页面内存,不持久化)。 */\nexport function getDefaultBrowserTokenStore(): BrowserTokenStore {\n return defaultBrowserTokenStore\n}\n\n// ─── 内部工具(仅 kit 包内使用) ───\n\n/**\n * 从请求 Authorization 头提取 Bearer Token。\n */\nfunction getBearerTokenFromRequest(request: Request): string | null {\n const authorization = request.headers.get('authorization')\n if (!authorization)\n return null\n\n const [scheme, token] = authorization.split(' ')\n if (!scheme || !token)\n return null\n\n if (scheme.toLowerCase() !== 'bearer')\n return null\n\n const trimmed = token.trim()\n return trimmed.length > 0 ? trimmed : null\n}\n\n/**\n * 从请求中统一提取 Access Token(Bearer 优先,其次配置的 Cookie 名)。\n */\nexport function getAccessToken(request: Request, cookies?: CookieReader): string | null {\n return getBearerTokenFromRequest(request) ?? cookies?.get(authState.cookieName) ?? null\n}\n\n// ─── 服务端认证 Cookie 管理 ───\n\n/**\n * 写入 Access Token Cookie(内部使用,由 login 自动调用)。\n */\nfunction setToken(cookies: CookieWriter, token: string, maxAge?: number): void {\n cookies.set(authState.cookieName, token, {\n path: '/',\n httpOnly: true,\n sameSite: 'lax',\n secure: process.env.NODE_ENV === 'production',\n maxAge,\n })\n}\n\n/**\n * 清除 Access Token Cookie(内部使用,由 logout 自动调用)。\n */\nfunction clearToken(cookies: CookieWriter): void {\n cookies.delete(authState.cookieName, { path: '/' })\n}\n\n// ─── 服务端高级认证 API(通过 kit.auth 暴露) ───\n\n/**\n * 获取已注入的认证操作;未配置时返回 null。\n *\n * 公共 API 不应 throw,因此此处用 null 信号配合上层短路返回 HaiResult。\n */\nfunction getAuthOperations(): AuthOperations | null {\n if (!authState.operations)\n return null\n return typeof authState.operations === 'function'\n ? authState.operations()\n : authState.operations\n}\n\n/**\n * 构造 \"auth 未配置\" 的标准 HaiResult 错误。\n *\n * 用于公共认证 API 在 `authState.operations` 未注入时返回,\n * 避免向调用方抛出未捕获异常。\n */\nfunction authNotConfiguredError(): HaiResult<never> {\n return err({\n code: 'KIT_AUTH_NOT_CONFIGURED',\n message: kitM('kit_authNotConfigured'),\n })\n}\n\n/**\n * 执行已配置的认证登录操作,并在成功时写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - 认证凭证\n * @param run - 具体 IAM 认证操作\n */\nasync function runAuthLogin<TCredentials>(\n cookies: CookieWriter,\n credentials: TCredentials,\n run: (ops: AuthOperations, credentials: TCredentials) => Promise<HaiResult<AuthResult>>,\n): Promise<HaiResult<AuthResult>> {\n const ops = getAuthOperations()\n if (!ops)\n return authNotConfiguredError()\n\n const result = await run(ops, credentials)\n if (result.success) {\n setToken(cookies, result.data.tokens.accessToken, result.data.tokens.expiresIn)\n }\n return result\n}\n\n/**\n * 服务端登录(密码):内部调用 iam.auth.login,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - 密码凭证(identifier + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.login(cookies, { identifier, password })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * const { user, roles, permissions } = result.data\n * ```\n */\nexport async function login(\n cookies: CookieWriter,\n credentials: PasswordCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.login(input))\n}\n\n/**\n * 服务端登录(OTP 验证码):内部调用 iam.auth.loginWithOtp,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - OTP 凭证(identifier + code)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithOtp(cookies, { identifier, code })\n * ```\n */\nexport async function loginWithOtp(\n cookies: CookieWriter,\n credentials: OtpCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.loginWithOtp(input))\n}\n\n/**\n * 服务端登录(LDAP):内部调用 iam.auth.loginWithLdap,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - LDAP 凭证(username + password)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithLdap(cookies, { username, password })\n * ```\n */\nexport async function loginWithLdap(\n cookies: CookieWriter,\n credentials: LdapCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.loginWithLdap(input))\n}\n\n/**\n * 服务端登录(API Key):内部调用 iam.auth.loginWithApiKey,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param credentials - API Key 凭证(key)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.loginWithApiKey(cookies, { key: apiKey })\n * if (!result.success) return kit.response.fromError(result.error, IamErrorHttpStatus)\n * ```\n */\nexport async function loginWithApiKey(\n cookies: CookieWriter,\n credentials: ApiKeyCredentials,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, credentials, (ops, input) => ops.loginWithApiKey(input))\n}\n\n/**\n * 服务端注册并登录:内部调用 iam.auth.registerAndLogin,成功时自动写入 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param options - 注册选项(username、password、email 等)\n * @returns 认证结果(成功时 Cookie 已自动写入)\n *\n * @example\n * ```ts\n * const result = await kit.auth.registerAndLogin(cookies, { username, email, password })\n * ```\n */\nexport async function registerAndLogin(\n cookies: CookieWriter,\n options: RegisterOptions,\n): Promise<HaiResult<AuthResult>> {\n return runAuthLogin(cookies, options, (ops, input) => ops.registerAndLogin(input))\n}\n\n/**\n * 服务端登出:内部调用 iam.auth.logout 使会话失效,并清除 Token Cookie。\n *\n * @param cookies - SvelteKit cookies 对象\n * @param accessToken - 访问令牌(为 null/undefined 时仅清除 Cookie)\n *\n * @example\n * ```ts\n * await kit.auth.logout(cookies, locals.accessToken)\n * return kit.response.ok(null)\n * ```\n */\nexport async function logout(\n cookies: CookieWriter,\n accessToken?: string | null,\n): Promise<void> {\n // 即使 auth 未配置也需要清除 Cookie,保证登出语义幂等\n const ops = getAuthOperations()\n if (accessToken && ops) {\n await ops.logout(accessToken)\n }\n clearToken(cookies)\n}\n\n// ─── 浏览器端 Token 存储(通过 kit.auth 暴露) ───\n\n/**\n * 创建浏览器端 Token 存储器(localStorage)。\n *\n * ⚠️ 安全提示:localStorage 对同源脚本可读,任意 XSS 都可能窃取 Token。\n * 本函数仅供调用方显式接受风险时使用;`kit.client.create({ auth: true })`\n * 不会默认调用它。\n *\n * @param key - localStorage 键名,默认 `'hai_access_token'`\n */\nexport function createTokenStore(key = DEFAULT_TOKEN_COOKIE_NAME): BrowserTokenStore {\n return {\n get(): string | null {\n if (typeof window === 'undefined') {\n return null\n }\n return window.localStorage.getItem(key)\n },\n set(token: string): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.setItem(key, token)\n },\n clear(): void {\n if (typeof window === 'undefined') {\n return\n }\n window.localStorage.removeItem(key)\n },\n }\n}\n\n/**\n * 写入默认浏览器端 Access Token(仅页面内存,不持久化到 localStorage)。\n */\nexport function setBrowserToken(token: string): void {\n defaultBrowserTokenStore.set(token)\n}\n\n/**\n * 清除默认浏览器端 Access Token(仅页面内存)。\n */\nexport function clearBrowserToken(): void {\n defaultBrowserTokenStore.clear()\n}\n","/**\n * @h-ai/kit — 统一客户端\n *\n * 将 CSRF Token 附加与可选传输加密封装为统一 `apiFetch`。\n * 应用层只需调用一次 `createKitClient()`,后续 API 调用即可复用同一套安全能力。\n * @module kit-client\n */\n\nimport type { CryptoFunctions, TransportClient } from '@h-ai/crypto'\nimport type { BrowserTokenStore } from '../kit-auth.js'\nimport type { KitConfig } from '../kit-config.js'\nimport { TRANSPORT_PROTOCOL } from '@h-ai/crypto'\nimport { getDefaultBrowserTokenStore } from '../kit-auth.js'\nimport { DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH, resolveTransportPath, shouldUseTransportForUrl } from '../modules/crypto/kit-transport-paths.js'\n\nconst DEFAULT_KEY_EXCHANGE_URL = `/api${TRANSPORT_PROTOCOL.DEFAULT_KEY_EXCHANGE_PATH}`\n\n// ─── 类型 ───\n\n/**\n * 传输加密客户端配置\n */\nexport interface ClientTransportConfig {\n /** @h-ai/crypto 服务实例 */\n crypto: CryptoFunctions\n /** 密钥交换端点 URL(默认 `'/api/_hai/key-exchange'`) */\n keyExchangeUrl?: string\n /** 排除路径(命中后强制走明文),需与服务端 transport.excludePaths 保持一致 */\n excludePaths?: string[]\n}\n\n/**\n * Kit 客户端配置\n */\nexport interface KitClientConfig {\n /**\n * 传输加密配置。\n * - 不提供 / undefined:不启用传输加密,仅 CSRF\n * - 提供对象:启用传输加密\n */\n transport?: ClientTransportConfig\n /** CSRF Cookie 名称(默认 `'hai_csrf'`) */\n csrfCookieName?: string\n /** CSRF Header 名称(默认 `'X-CSRF-Token'`) */\n csrfHeaderName?: string\n /**\n * 认证配置:自动从浏览器存储读取 Access Token 并注入请求头。\n * - `true`:使用默认页面内存存储(由 `kit.auth.setBrowserToken()` 写入,不读写 localStorage)\n * - `BrowserTokenStore`:使用自定义存储\n * - 不提供 / `false`:不自动注入\n */\n auth?: boolean | BrowserTokenStore\n}\n\n/**\n * Kit 客户端实例\n */\nexport interface KitClient {\n /** 统一 API fetch(写请求自动附加 CSRF,启用 transport 时自动加解密) */\n apiFetch: (url: string, init?: RequestInit) => Promise<Response>\n /** 传输加密是否就绪(未启用传输加密时始终为 true) */\n readonly ready: boolean\n /**\n * 手动触发密钥交换(transport 启用时)。\n *\n * 注意:本方法是 Client 形态的合规例外,密钥协商失败时 `throw`(与 `@h-ai/api-client` 一致),\n * 调用方需自行 `try/catch`,不返回 `HaiResult`。\n */\n init: () => Promise<void>\n /** 销毁密钥状态 */\n destroy: () => void\n}\n\n// ─── 工具函数 ───\n\n/**\n * 从 document.cookie 中读取指定名称的 Cookie 值\n *\n * @param name - Cookie 名称\n * @returns Cookie 值;不存在或运行在服务端时返回 undefined\n */\nfunction getCookie(name: string): string | undefined {\n if (typeof document === 'undefined')\n return undefined\n const match = document.cookie.match(new RegExp(`(?:^|;\\\\s*)${name}=([^;]*)`))\n return match?.[1]\n}\n\n/**\n * 判断当前请求体是否可以作为文本载荷进行传输加密。\n *\n * 传输加密中间件会把解密后的明文重新注入 `Request`,当前仅能可靠保留\n * JSON 字符串请求体。`FormData` / `Blob` / `ArrayBuffer` 等二进制或浏览器\n * 自动生成边界的请求体必须保持原样发送,否则文件上传会被序列化成 `{}`。\n *\n * @param body fetch 请求体\n * @returns 是否支持客户端传输加密\n */\nfunction canEncryptRequestBody(body: BodyInit | null | undefined): boolean {\n return body === undefined || body === null || typeof body === 'string'\n}\n\n/**\n * 判断全局 fetch 包装路径下,某个 `Request` 是否可走传输加密。\n *\n * 与上方 {@link canEncryptRequestBody} 区别:本谓词服务于 {@link installBrowserTransportFetch}\n * 的全局包装路径,输入是完整 `Request`,故可基于 method(GET/HEAD 无 body 安全放行)与\n * `Content-Type`(仅 JSON 可重注入明文)综合判定;而 `canEncryptRequestBody` 服务于\n * `createKitClient` 的 `apiFetch` 路径,仅拿到 `BodyInit`,只能按 body 类型粗判。\n * 两者判定维度不同是有意为之,请勿合并。\n */\nfunction canUseTransportForRequest(request: Request): boolean {\n const method = request.method.toUpperCase()\n if (method === 'GET' || method === 'HEAD') {\n return true\n }\n\n const headers = new Headers(request.headers)\n const contentType = headers.get('Content-Type') ?? ''\n if (contentType.includes('application/json')) {\n return true\n }\n\n return request.body === null\n}\n\nfunction getCurrentOrigin(): string {\n if (typeof window !== 'undefined' && window.location?.origin) {\n return window.location.origin\n }\n\n return 'http://localhost'\n}\n\nfunction toRequest(input: RequestInfo | URL, init?: RequestInit): Request {\n if (input instanceof Request)\n return init ? new Request(input, init) : input\n\n return new Request(input, init)\n}\n\ntype BrowserTransportFetchState = typeof globalThis & {\n __haiKitOriginalFetch?: typeof fetch\n __haiKitTransportFetchInstalled?: boolean\n}\n\n/**\n * 在浏览器启动时安装同源 transport fetch 包装。\n *\n * 该包装作用于同源 `/api/*` 与 SvelteKit `__data.json` 请求,页面文档、\n * 静态资源以及 multipart/form-data 等上传请求保持原样。应用只需安装一次,\n * 后续 `fetch` / SvelteKit 内部 data fetch / `kit.client.create()` 明文发送路径\n * 都会共用这层传输加密能力。\n */\nexport function installBrowserTransportFetch(transportConfig?: ClientTransportConfig): void {\n if (typeof window === 'undefined' || !transportConfig)\n return\n\n const fetchState = globalThis as BrowserTransportFetchState\n if (fetchState.__haiKitTransportFetchInstalled)\n return\n\n const originalFetch = fetchState.__haiKitOriginalFetch ?? globalThis.fetch.bind(globalThis)\n fetchState.__haiKitOriginalFetch = originalFetch\n\n const origin = getCurrentOrigin()\n const keyExchangeUrl = new URL(transportConfig.keyExchangeUrl ?? DEFAULT_KEY_EXCHANGE_URL, origin).toString()\n const keyExchangePath = resolveTransportPath(keyExchangeUrl, origin)\n const transportClient = transportConfig.crypto.transport.createClient({\n keyExchangeUrl,\n fetch: originalFetch,\n })\n\n const wrappedFetch: typeof fetch = async (input, init) => {\n const request = toRequest(input, init)\n const requestUrl = new URL(request.url, origin)\n const headers = new Headers(request.headers)\n\n if (!shouldUseTransportForUrl(requestUrl, {\n origin,\n keyExchangePath,\n excludePaths: transportConfig.excludePaths,\n })) {\n return originalFetch(input, init)\n }\n\n if (headers.has(TRANSPORT_PROTOCOL.CLIENT_ID_HEADER))\n return originalFetch(input, init)\n\n if (!canUseTransportForRequest(request))\n return originalFetch(input, init)\n\n return transportClient.encryptedFetch(request)\n }\n\n globalThis.fetch = wrappedFetch\n window.fetch = wrappedFetch\n fetchState.__haiKitTransportFetchInstalled = true\n}\n\n/**\n * 用 `config/_kit.yml` 解析后的 {@link KitConfig} 一次性安装浏览器端传输加密。\n *\n * 行为:\n * - `config.transport === false` 时直接返回(不启用传输加密);\n * - 否则启动 {@link installBrowserTransportFetch},并预热 {@link CryptoFunctions} 模块。\n *\n * 应用层(SvelteKit `+layout.svelte` 或浏览器入口)只需调用此函数一次,\n * 之后所有同源 `/api/*` 与 `__data.json` 请求都会自动走传输加密。\n *\n * @param config 已解析的 kit 顶层配置\n * @param deps 外部依赖\n * @param deps.crypto `@h-ai/crypto` 模块实例\n *\n * @example\n * ```ts\n * import { browser } from '$app/environment'\n * import { crypto } from '@h-ai/crypto'\n * import { kit } from '@h-ai/kit'\n * import { adminConsoleKitConfig } from '$lib/config/kit-config.js'\n *\n * if (browser) {\n * kit.client.installBrowserTransport(adminConsoleKitConfig, { crypto })\n * }\n * ```\n */\nexport function installBrowserTransport(\n config: KitConfig,\n deps: { crypto: CryptoFunctions },\n): void {\n if (typeof window === 'undefined' || config.transport === false)\n return\n\n // crypto.init() 当前为同步副作用(signature 是 async 仅为接口一致性),\n // 此处不 await,以便 `+layout.svelte` 顶层模块加载阶段就完成初始化。\n void deps.crypto.init()\n\n installBrowserTransportFetch({\n crypto: deps.crypto,\n keyExchangeUrl: config.transport.keyExchangePath,\n excludePaths: [...config.transport.excludePaths],\n })\n}\n\n// ─── 主函数 ───\n\n/**\n * 创建 Kit 客户端\n *\n * 返回统一的 `apiFetch`,内部自动完成:\n * 1. CSRF Token 附加(写方法自动读取 Cookie + 设置 Header)\n * 2. 密钥交换(首次写请求时 lazy init,transport 启用时)\n * 3. 请求体加密(transport 启用时)\n * 4. 响应体解密(transport 启用时)\n *\n * @param config - 客户端配置\n * @returns KitClient 实例\n *\n * @example\n * ```ts\n * const client = createKitClient({ transport: { crypto } })\n * const res = await client.apiFetch('/api/users', { method: 'POST', body: '{}' })\n * ```\n */\nexport function createKitClient(config: KitClientConfig = {}): KitClient {\n const {\n transport: transportConfig,\n csrfCookieName = 'hai_csrf',\n csrfHeaderName = 'X-CSRF-Token',\n auth: authConfig,\n } = config\n\n // ── Auth token store ──\n // 安全默认:auth:true 只读取页面内存 token,避免隐式 localStorage 持久化敏感凭证。\n const authStore: BrowserTokenStore | null = authConfig\n ? (authConfig === true ? getDefaultBrowserTokenStore() : authConfig)\n : null\n\n // ── 传输加密状态 ──\n const transportOrigin = getCurrentOrigin()\n const transportKeyExchangeUrl = transportConfig?.keyExchangeUrl ?? DEFAULT_KEY_EXCHANGE_URL\n const transportKeyExchangePath = transportConfig\n ? resolveTransportPath(transportKeyExchangeUrl, transportOrigin)\n : DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH\n const transportClient: TransportClient | null = transportConfig\n ? transportConfig.crypto.transport.createClient({\n keyExchangeUrl: transportKeyExchangeUrl,\n fetch,\n })\n : null\n\n /**\n * 统一 API fetch\n */\n async function apiFetch(url: string, init: RequestInit = {}): Promise<Response> {\n const method = (init.method ?? 'GET').toUpperCase()\n const isWriteMethod = !['GET', 'HEAD', 'OPTIONS'].includes(method)\n const canUseTransport = canEncryptRequestBody(init.body)\n\n const headers = new Headers(init.headers)\n\n // ── Auth ──\n if (authStore) {\n const token = authStore.get()\n if (token) {\n headers.set('Authorization', `Bearer ${token}`)\n }\n }\n\n // ── CSRF ──\n if (isWriteMethod) {\n const csrfToken = getCookie(csrfCookieName)\n if (csrfToken) {\n headers.set(csrfHeaderName, csrfToken)\n }\n }\n\n // ── 传输加密 ──\n if (\n transportClient\n && canUseTransport\n && shouldUseTransportForUrl(url, {\n origin: transportOrigin,\n keyExchangePath: transportKeyExchangePath,\n excludePaths: transportConfig?.excludePaths,\n })\n ) {\n return transportClient.encryptedFetch(url, { ...init, headers })\n }\n\n // ── 发送(FormData/Blob/Stream 等保持原样,不破坏浏览器边界) ──\n return fetch(url, { ...init, headers })\n }\n\n return {\n apiFetch,\n get ready() { return !transportClient || transportClient.ready() },\n async init() {\n if (!transportClient)\n return\n const result = await transportClient.init()\n if (!result.success)\n throw new Error(result.error.message)\n },\n destroy() {\n transportClient?.destroy()\n },\n }\n}\n"]}