@h-ai/kit 1.0.0-beta.2 → 1.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.en.md +190 -110
  2. package/README.ja.md +192 -112
  3. package/README.md +195 -114
  4. package/dist/adapter/index.d.ts +8 -7
  5. package/dist/adapter/index.js.map +1 -1
  6. package/dist/browser.d.ts +9 -26
  7. package/dist/browser.js +4 -4
  8. package/dist/browser.js.map +1 -1
  9. package/dist/{chunk-JRQPMPQC.js → chunk-BCEBXG4X.js} +2 -2
  10. package/dist/chunk-BCEBXG4X.js.map +1 -0
  11. package/dist/{chunk-7EH47MTW.js → chunk-BVGXHIXR.js} +30 -9
  12. package/dist/chunk-BVGXHIXR.js.map +1 -0
  13. package/dist/{chunk-5VWPH7DO.js → chunk-GQZCU6PC.js} +14 -6
  14. package/dist/chunk-GQZCU6PC.js.map +1 -0
  15. package/dist/{chunk-YKJRQCWR.js → chunk-JL2C5ZGQ.js} +54 -20
  16. package/dist/chunk-JL2C5ZGQ.js.map +1 -0
  17. package/dist/{chunk-3OHUSKHI.js → chunk-WYGIKXHE.js} +23 -8
  18. package/dist/chunk-WYGIKXHE.js.map +1 -0
  19. package/dist/client/index.d.ts +6 -5
  20. package/dist/client/index.js +5 -5
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/index.d.ts +18 -711
  23. package/dist/index.js +266 -149
  24. package/dist/index.js.map +1 -1
  25. package/dist/{kit-a2a-types-4dapztu2.d.ts → kit-a2a-types-sw7sI-ZT.d.ts} +3 -2
  26. package/dist/kit-config-BQKQnu8Y.d.ts +182 -0
  27. package/dist/kit-crypto-types-CqFENBqm.d.ts +47 -0
  28. package/dist/kit-types-Cr1cnB3M.d.ts +2051 -0
  29. package/dist/modules/a2a/index.d.ts +9 -5
  30. package/dist/modules/a2a/index.js +1 -1
  31. package/dist/modules/crypto/index.d.ts +8 -105
  32. package/dist/modules/crypto/index.js +3 -149
  33. package/dist/modules/crypto/index.js.map +1 -1
  34. package/package.json +22 -22
  35. package/dist/chunk-3OHUSKHI.js.map +0 -1
  36. package/dist/chunk-5VWPH7DO.js.map +0 -1
  37. package/dist/chunk-7EH47MTW.js.map +0 -1
  38. package/dist/chunk-JRQPMPQC.js.map +0 -1
  39. package/dist/chunk-YKJRQCWR.js.map +0 -1
  40. package/dist/kit-client-auth-BnhrkzZF.d.ts +0 -422
  41. package/dist/kit-crypto-types-CXr888wf.d.ts +0 -200
  42. package/dist/kit-i18n-EBzZKYN-.d.ts +0 -502
  43. package/dist/kit-types-BkNdyKj8.d.ts +0 -822
@@ -1,10 +1,14 @@
1
- import { K as KitA2AHandlerConfig } from '../../kit-a2a-types-4dapztu2.js';
2
- export { A as A2AApiKeyAuthConfig, R as ResolvedA2AConfig, c as createA2AApiKeyAuthenticator, h as handleA2ARequest, r as resolveA2AConfig } from '../../kit-a2a-types-4dapztu2.js';
1
+ import { K as KitA2AHandlerConfig } from '../../kit-a2a-types-sw7sI-ZT.js';
2
+ export { A as A2AApiKeyAuthConfig, R as ResolvedA2AConfig, c as createA2AApiKeyAuthenticator, h as handleA2ARequest, r as resolveA2AConfig } from '../../kit-a2a-types-sw7sI-ZT.js';
3
3
  import { RequestHandler } from '@sveltejs/kit';
4
- import '../../kit-types-BkNdyKj8.js';
4
+ import '../../kit-types-Cr1cnB3M.js';
5
5
  import '@h-ai/core';
6
6
  import '@h-ai/crypto';
7
7
  import '@h-ai/iam';
8
+ import '@h-ai/api-contract';
9
+ import '@sveltejs/kit/hooks';
10
+ import '@h-ai/feedback';
11
+ import 'zod';
8
12
 
9
13
  /**
10
14
  * @h-ai/kit — A2A 路由处理器
@@ -18,11 +22,11 @@ import '@h-ai/iam';
18
22
  *
19
23
  * 返回当前 Agent 的 Agent Card(JSON),通常挂载在 `/.well-known/agent-card.json`。
20
24
  *
21
- * @param getAgentCard - 获取 Agent Card 的回调(通常调用 `ai.a2a.getAgentCard()`)
25
+ * @param getAgentCard - 返回标准 ProtoJSON Agent Card 文档的回调(成功时取 `ai.a2a.getAgentCard().data`)
22
26
  * @returns SvelteKit GET 处理器
23
27
  * @example 模块内部上下文
24
28
  * ```ts
25
- * const handler = createAgentCardHandler(() => ({ name: 'Example agent', url: 'https://agent.example.com/a2a' }))
29
+ * const handler = createAgentCardHandler(() => ({ name: 'Example agent', supportedInterfaces: [{ url: 'https://agent.example.com/a2a', protocolBinding: 'JSONRPC', protocolVersion: '1.0' }] }))
26
30
  * void handler
27
31
  * ```
28
32
  */
@@ -1,4 +1,4 @@
1
- export { createA2AApiKeyAuthenticator, createA2AHandler, createAgentCardHandler, handleA2ARequest, resolveA2AConfig } from '../../chunk-7EH47MTW.js';
1
+ export { createA2AApiKeyAuthenticator, createA2AHandler, createAgentCardHandler, handleA2ARequest, resolveA2AConfig } from '../../chunk-BVGXHIXR.js';
2
2
  import '../../chunk-USFJN7IO.js';
3
3
  //# sourceMappingURL=index.js.map
4
4
  //# sourceMappingURL=index.js.map
@@ -1,110 +1,13 @@
1
- import { Cookies, RequestEvent } from '@sveltejs/kit';
2
- import { C as CryptoCsrfConfig, E as EncryptedCookieConfig, a as CryptoServiceLike, W as WebhookVerifyConfig, T as TransportEncryptionConfig } from '../../kit-crypto-types-CXr888wf.js';
1
+ import { T as TransportEncryptionConfig } from '../../kit-crypto-types-CqFENBqm.js';
3
2
  import { RequestAccessCheck } from '@h-ai/core';
4
- import { M as Middleware } from '../../kit-types-BkNdyKj8.js';
3
+ import { Middleware } from '../../browser.js';
5
4
  export { EncryptedPayload, TransportEncryptionManager, TransportKeyPair } from '@h-ai/crypto';
6
5
  import '@h-ai/iam';
7
-
8
- /**
9
- * @h-ai/kit — Crypto Helpers
10
- *
11
- * 集成 @h-ai/crypto 的 SvelteKit 工具
12
- * @module kit-crypto-helpers
13
- */
14
-
15
- /**
16
- * 验证 Webhook 签名
17
- *
18
- * 从请求头取出签名,用 HMAC 对原始 Body 进行比较验证。
19
- *
20
- * @param config - 签名验证配置
21
- * @returns 签名是否合法
22
- * @example 模块内部上下文
23
- * ```ts
24
- * async function authorized(config: WebhookVerifyConfig) {
25
- * return verifyWebhookSignature(config) // 使用原始 body;读取后不可再次消费同一流。
26
- * }
27
- * ```
28
- */
29
- declare function verifyWebhookSignature(config: WebhookVerifyConfig): Promise<boolean>;
30
- /**
31
- * 生成请求 HMAC 签名(用于调用外部服务)
32
- *
33
- * @param crypto - @h-ai/crypto 服务实例
34
- * @param body - 请求体字符串
35
- * @param secretKey - 共享密钥
36
- * @param algorithm - 哈希算法(默认 `'sha256'`)
37
- * @returns 签名字符串
38
- * @throws 签名失败时抛出 Error
39
- * @example 模块内部上下文
40
- * ```ts
41
- * async function sign(crypto: CryptoServiceLike, secretKey: string) {
42
- * return signRequest(crypto, JSON.stringify({ id: 'article_1' }), secretKey)
43
- * }
44
- * ```
45
- */
46
- declare function signRequest(crypto: CryptoServiceLike, body: string, secretKey: string, algorithm?: string): Promise<string>;
47
- /**
48
- * 创建 CSRF Token 管理器
49
- *
50
- * 基于 `@h-ai/crypto` 随机字节 + 时间安全比较,
51
- * 提供 token 生成、验证和 SvelteKit handle 中间件。
52
- *
53
- * @param config - CSRF 配置(crypto 实例、Cookie 名、Header 名等)
54
- * @returns `{ generate, verify, createHandle }`
55
- * @example 模块内部上下文
56
- * ```ts
57
- * function csrf(config: CryptoCsrfConfig) {
58
- * const manager = createCsrfManager(config)
59
- * return manager
60
- * }
61
- * ```
62
- */
63
- declare function createCsrfManager(config: CryptoCsrfConfig): {
64
- /**
65
- * 生成新的 CSRF Token 并设置 Cookie
66
- */
67
- generate(cookies: Cookies): Promise<string>;
68
- /**
69
- * 验证 CSRF Token
70
- */
71
- verify(event: RequestEvent): Promise<boolean>;
72
- /**
73
- * 创建 CSRF 验证中间件
74
- */
75
- createHandle(): ({ event, resolve }: {
76
- event: RequestEvent;
77
- resolve: (event: RequestEvent) => Promise<Response>;
78
- }) => Promise<Response>;
79
- };
80
- /**
81
- * 创建加密 Cookie 管理器
82
- *
83
- * 使用 AES 对 Cookie 值进行加解密,防止客户端篡改。
84
- *
85
- * @param config - 加密 Cookie 配置(含加密密钥)
86
- * @returns `{ set, get, delete }`
87
- * @example 模块内部上下文
88
- * ```ts
89
- * function cookies(config: EncryptedCookieConfig) {
90
- * return createEncryptedCookie(config)
91
- * }
92
- * ```
93
- */
94
- declare function createEncryptedCookie(config: EncryptedCookieConfig): {
95
- /**
96
- * 设置加密 Cookie
97
- */
98
- set(cookies: Cookies, name: string, value: unknown): Promise<void>;
99
- /**
100
- * 获取并解密 Cookie
101
- */
102
- get<T = unknown>(cookies: Cookies, name: string): Promise<T | null>;
103
- /**
104
- * 删除 Cookie
105
- */
106
- delete(cookies: Cookies, name: string): void;
107
- };
6
+ import '@sveltejs/kit';
7
+ import '@h-ai/api-contract';
8
+ import '@sveltejs/kit/hooks';
9
+ import '@h-ai/feedback';
10
+ import 'zod';
108
11
 
109
12
  /**
110
13
  * @h-ai/kit — 传输加密中间件
@@ -129,4 +32,4 @@ declare function createEncryptedCookie(config: EncryptedCookieConfig): {
129
32
  */
130
33
  declare function transportEncryptionMiddleware(config: TransportEncryptionConfig, encryption?: RequestAccessCheck['encryption']): Middleware;
131
34
 
132
- export { CryptoCsrfConfig, CryptoServiceLike, EncryptedCookieConfig, TransportEncryptionConfig, WebhookVerifyConfig, createCsrfManager, createEncryptedCookie, signRequest, transportEncryptionMiddleware, verifyWebhookSignature };
35
+ export { TransportEncryptionConfig, transportEncryptionMiddleware };
@@ -1,151 +1,5 @@
1
- export { transportEncryptionMiddleware } from '../../chunk-3OHUSKHI.js';
2
- import '../../chunk-JRQPMPQC.js';
3
- import { kitM } from '../../chunk-USFJN7IO.js';
4
-
5
- // src/modules/crypto/kit-crypto-helpers.ts
6
- async function verifyWebhookSignature(config) {
7
- const {
8
- crypto,
9
- event,
10
- secretKey,
11
- signatureHeader = "X-Signature",
12
- algorithm = "sha256"
13
- } = config;
14
- const signature = event.request.headers.get(signatureHeader);
15
- if (!signature) {
16
- return false;
17
- }
18
- const body = await event.request.text();
19
- try {
20
- const result = await crypto.hmac.verify(body, secretKey, signature, algorithm);
21
- return result.success && result.data === true;
22
- } catch {
23
- return false;
24
- }
25
- }
26
- async function signRequest(crypto, body, secretKey, algorithm = "sha256") {
27
- const result = await crypto.hmac.sign(body, secretKey, algorithm);
28
- if (!result.success) {
29
- throw new Error(result.error?.message || kitM("kit_signFailed"));
30
- }
31
- return result.data;
32
- }
33
- function createCsrfManager(config) {
34
- const {
35
- crypto,
36
- cookieName = "csrf_token",
37
- headerName = "X-CSRF-Token",
38
- formFieldName = "_csrf",
39
- tokenLength = 32,
40
- cookieOptions = {}
41
- } = config;
42
- return {
43
- /**
44
- * 生成新的 CSRF Token 并设置 Cookie
45
- */
46
- async generate(cookies) {
47
- const result = await crypto.random.bytes(tokenLength);
48
- if (!result.success) {
49
- throw new Error(kitM("kit_csrfTokenFailed"));
50
- }
51
- const token = Array.from(result.data).map((b) => b.toString(16).padStart(2, "0")).join("");
52
- cookies.set(cookieName, token, {
53
- path: "/",
54
- httpOnly: true,
55
- secure: true,
56
- sameSite: "strict",
57
- ...cookieOptions
58
- });
59
- return token;
60
- },
61
- /**
62
- * 验证 CSRF Token
63
- */
64
- async verify(event) {
65
- const cookieToken = event.cookies.get(cookieName);
66
- if (!cookieToken) {
67
- return false;
68
- }
69
- let requestToken = event.request.headers.get(headerName);
70
- if (!requestToken && event.request.method === "POST") {
71
- try {
72
- const formData = await event.request.clone().formData();
73
- const fieldValue = formData.get(formFieldName);
74
- requestToken = typeof fieldValue === "string" ? fieldValue : null;
75
- } catch {
76
- }
77
- }
78
- if (!requestToken) {
79
- return false;
80
- }
81
- const result = await crypto.hash.timingSafeEqual(cookieToken, requestToken);
82
- return result.success && result.data === true;
83
- },
84
- /**
85
- * 创建 CSRF 验证中间件
86
- */
87
- createHandle() {
88
- return async ({ event, resolve }) => {
89
- const safeMethods = ["GET", "HEAD", "OPTIONS"];
90
- if (safeMethods.includes(event.request.method)) {
91
- return resolve(event);
92
- }
93
- const isValid = await this.verify(event);
94
- if (!isValid) {
95
- return new Response(kitM("kit_csrfVerifyFailed"), { status: 403 });
96
- }
97
- return resolve(event);
98
- };
99
- }
100
- };
101
- }
102
- function createEncryptedCookie(config) {
103
- const { crypto, encryptionKey, cookieOptions = {} } = config;
104
- return {
105
- /**
106
- * 设置加密 Cookie
107
- */
108
- async set(cookies, name, value) {
109
- const json = JSON.stringify(value);
110
- const result = await crypto.aes.encrypt(json, encryptionKey);
111
- if (!result.success) {
112
- throw new Error(kitM("kit_encryptFailed"));
113
- }
114
- cookies.set(name, result.data, {
115
- path: "/",
116
- httpOnly: true,
117
- secure: true,
118
- sameSite: "lax",
119
- ...cookieOptions
120
- });
121
- },
122
- /**
123
- * 获取并解密 Cookie
124
- */
125
- async get(cookies, name) {
126
- const encrypted = cookies.get(name);
127
- if (!encrypted) {
128
- return null;
129
- }
130
- try {
131
- const result = await crypto.aes.decrypt(encrypted, encryptionKey);
132
- if (!result.success) {
133
- return null;
134
- }
135
- return JSON.parse(result.data);
136
- } catch {
137
- return null;
138
- }
139
- },
140
- /**
141
- * 删除 Cookie
142
- */
143
- delete(cookies, name) {
144
- cookies.delete(name, { path: "/" });
145
- }
146
- };
147
- }
148
-
149
- export { createCsrfManager, createEncryptedCookie, signRequest, verifyWebhookSignature };
1
+ export { transportEncryptionMiddleware } from '../../chunk-WYGIKXHE.js';
2
+ import '../../chunk-BCEBXG4X.js';
3
+ import '../../chunk-USFJN7IO.js';
150
4
  //# sourceMappingURL=index.js.map
151
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/modules/crypto/kit-crypto-helpers.ts"],"names":[],"mappings":";;;;;AA8BA,eAAsB,uBAAuB,MAAA,EAA+C;AAC1F,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA;AAAA,IACA,eAAA,GAAkB,aAAA;AAAA,IAClB,SAAA,GAAY;AAAA,GACd,GAAI,MAAA;AAEJ,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,eAAe,CAAA;AAC3D,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,KAAA,CAAM,OAAA,CAAQ,IAAA,EAAK;AAEtC,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,CAAK,OAAO,IAAA,EAAM,SAAA,EAAW,WAAW,SAAS,CAAA;AAC7E,IAAA,OAAO,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,IAAA,KAAS,IAAA;AAAA,EAC3C,CAAA,CAAA,MACM;AACJ,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAkBA,eAAsB,WAAA,CACpB,MAAA,EACA,IAAA,EACA,SAAA,EACA,YAAY,QAAA,EACK;AACjB,EAAA,MAAM,SAAS,MAAM,MAAA,CAAO,KAAK,IAAA,CAAK,IAAA,EAAM,WAAW,SAAS,CAAA;AAChE,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,IAAI,KAAA,CAAM,MAAA,CAAO,OAAO,OAAA,IAAW,IAAA,CAAK,gBAAgB,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,MAAA,CAAO,IAAA;AAChB;AAkBO,SAAS,kBAAkB,MAAA,EAA0B;AAC1D,EAAA,MAAM;AAAA,IACJ,MAAA;AAAA,IACA,UAAA,GAAa,YAAA;AAAA,IACb,UAAA,GAAa,cAAA;AAAA,IACb,aAAA,GAAgB,OAAA;AAAA,IAChB,WAAA,GAAc,EAAA;AAAA,IACd,gBAAgB;AAAC,GACnB,GAAI,MAAA;AAEJ,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,MAAM,SAAS,OAAA,EAAmC;AAChD,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,MAAA,CAAO,MAAM,WAAW,CAAA;AACpD,MAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,qBAAqB,CAAC,CAAA;AAAA,MAC7C;AAEA,MAAA,MAAM,QAAQ,KAAA,CAAM,IAAA,CAAK,OAAO,IAAK,CAAA,CAClC,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CACxC,KAAK,EAAE,CAAA;AAEV,MAAA,OAAA,CAAQ,GAAA,CAAI,YAAY,KAAA,EAAO;AAAA,QAC7B,IAAA,EAAM,GAAA;AAAA,QACN,QAAA,EAAU,IAAA;AAAA,QACV,MAAA,EAAQ,IAAA;AAAA,QACR,QAAA,EAAU,QAAA;AAAA,QACV,GAAG;AAAA,OACJ,CAAA;AAED,MAAA,OAAO,KAAA;AAAA,IACT,CAAA;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,OAAO,KAAA,EAAuC;AAClD,MAAA,MAAM,WAAA,GAAc,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA;AAChD,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,OAAO,KAAA;AAAA,MACT;AAGA,MAAA,IAAI,YAAA,GAAe,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,UAAU,CAAA;AAEvD,MAAA,IAAI,CAAC,YAAA,IAAgB,KAAA,CAAM,OAAA,CAAQ,WAAW,MAAA,EAAQ;AACpD,QAAA,IAAI;AACF,UAAA,MAAM,WAAW,MAAM,KAAA,CAAM,OAAA,CAAQ,KAAA,GAAQ,QAAA,EAAS;AACtD,UAAA,MAAM,UAAA,GAAa,QAAA,CAAS,GAAA,CAAI,aAAa,CAAA;AAC7C,UAAA,YAAA,GAAe,OAAO,UAAA,KAAe,QAAA,GAAW,UAAA,GAAa,IAAA;AAAA,QAC/D,CAAA,CAAA,MACM;AAAA,QAEN;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,OAAO,KAAA;AAAA,MACT;AAGA,MAAA,MAAM,SAAS,MAAM,MAAA,CAAO,IAAA,CAAK,eAAA,CAAgB,aAAa,YAAY,CAAA;AAC1E,MAAA,OAAO,MAAA,CAAO,OAAA,IAAW,MAAA,CAAO,IAAA,KAAS,IAAA;AAAA,IAC3C,CAAA;AAAA;AAAA;AAAA;AAAA,IAKA,YAAA,GAAe;AACb,MAAA,OAAO,OAAO,EAAE,KAAA,EAAO,OAAA,EAAQ,KAAoF;AAEjH,QAAA,MAAM,WAAA,GAAc,CAAC,KAAA,EAAO,MAAA,EAAQ,SAAS,CAAA;AAC7C,QAAA,IAAI,WAAA,CAAY,QAAA,CAAS,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC9C,UAAA,OAAO,QAAQ,KAAK,CAAA;AAAA,QACtB;AAEA,QAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA;AACvC,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,OAAO,IAAI,SAAS,IAAA,CAAK,sBAAsB,GAAG,EAAE,MAAA,EAAQ,KAAK,CAAA;AAAA,QACnE;AAEA,QAAA,OAAO,QAAQ,KAAK,CAAA;AAAA,MACtB,CAAA;AAAA,IACF;AAAA,GACF;AACF;AAgBO,SAAS,sBAAsB,MAAA,EAA+B;AACnE,EAAA,MAAM,EAAE,MAAA,EAAQ,aAAA,EAAe,aAAA,GAAgB,IAAG,GAAI,MAAA;AAEtD,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,MAAM,GAAA,CAAI,OAAA,EAAkB,IAAA,EAAc,KAAA,EAA+B;AACvE,MAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AACjC,MAAA,MAAM,SAAS,MAAM,MAAA,CAAO,GAAA,CAAI,OAAA,CAAQ,MAAM,aAAa,CAAA;AAE3D,MAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,QAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,mBAAmB,CAAC,CAAA;AAAA,MAC3C;AAEA,MAAA,OAAA,CAAQ,GAAA,CAAI,IAAA,EAAM,MAAA,CAAO,IAAA,EAAO;AAAA,QAC9B,IAAA,EAAM,GAAA;AAAA,QACN,QAAA,EAAU,IAAA;AAAA,QACV,MAAA,EAAQ,IAAA;AAAA,QACR,QAAA,EAAU,KAAA;AAAA,QACV,GAAG;AAAA,OACJ,CAAA;AAAA,IACH,CAAA;AAAA;AAAA;AAAA;AAAA,IAKA,MAAM,GAAA,CAAiB,OAAA,EAAkB,IAAA,EAAiC;AACxE,MAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AAClC,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,MAAM,MAAA,CAAO,GAAA,CAAI,OAAA,CAAQ,WAAW,aAAa,CAAA;AAChE,QAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,OAAO,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,IAAK,CAAA;AAAA,MAChC,CAAA,CAAA,MACM;AACJ,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA;AAAA;AAAA;AAAA,IAKA,MAAA,CAAO,SAAkB,IAAA,EAAoB;AAC3C,MAAA,OAAA,CAAQ,MAAA,CAAO,IAAA,EAAM,EAAE,IAAA,EAAM,KAAK,CAAA;AAAA,IACpC;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * @h-ai/kit — Crypto Helpers\n *\n * 集成 @h-ai/crypto 的 SvelteKit 工具\n * @module kit-crypto-helpers\n */\n\nimport type { Cookies, RequestEvent } from '@sveltejs/kit'\nimport type {\n CryptoCsrfConfig,\n CryptoServiceLike,\n EncryptedCookieConfig,\n WebhookVerifyConfig,\n} from './kit-crypto-types.js'\nimport { kitM } from '../../kit-i18n.js'\n\n/**\n * 验证 Webhook 签名\n *\n * 从请求头取出签名,用 HMAC 对原始 Body 进行比较验证。\n *\n * @param config - 签名验证配置\n * @returns 签名是否合法\n * @example 模块内部上下文\n * ```ts\n * async function authorized(config: WebhookVerifyConfig) {\n * return verifyWebhookSignature(config) // 使用原始 body;读取后不可再次消费同一流。\n * }\n * ```\n */\nexport async function verifyWebhookSignature(config: WebhookVerifyConfig): Promise<boolean> {\n const {\n crypto,\n event,\n secretKey,\n signatureHeader = 'X-Signature',\n algorithm = 'sha256',\n } = config\n\n const signature = event.request.headers.get(signatureHeader)\n if (!signature) {\n return false\n }\n\n const body = await event.request.text()\n\n try {\n const result = await crypto.hmac.verify(body, secretKey, signature, algorithm)\n return result.success && result.data === true\n }\n catch {\n return false\n }\n}\n\n/**\n * 生成请求 HMAC 签名(用于调用外部服务)\n *\n * @param crypto - @h-ai/crypto 服务实例\n * @param body - 请求体字符串\n * @param secretKey - 共享密钥\n * @param algorithm - 哈希算法(默认 `'sha256'`)\n * @returns 签名字符串\n * @throws 签名失败时抛出 Error\n * @example 模块内部上下文\n * ```ts\n * async function sign(crypto: CryptoServiceLike, secretKey: string) {\n * return signRequest(crypto, JSON.stringify({ id: 'article_1' }), secretKey)\n * }\n * ```\n */\nexport async function signRequest(\n crypto: CryptoServiceLike,\n body: string,\n secretKey: string,\n algorithm = 'sha256',\n): Promise<string> {\n const result = await crypto.hmac.sign(body, secretKey, algorithm)\n if (!result.success) {\n throw new Error(result.error?.message || kitM('kit_signFailed'))\n }\n return result.data!\n}\n\n/**\n * 创建 CSRF Token 管理器\n *\n * 基于 `@h-ai/crypto` 随机字节 + 时间安全比较,\n * 提供 token 生成、验证和 SvelteKit handle 中间件。\n *\n * @param config - CSRF 配置(crypto 实例、Cookie 名、Header 名等)\n * @returns `{ generate, verify, createHandle }`\n * @example 模块内部上下文\n * ```ts\n * function csrf(config: CryptoCsrfConfig) {\n * const manager = createCsrfManager(config)\n * return manager\n * }\n * ```\n */\nexport function createCsrfManager(config: CryptoCsrfConfig) {\n const {\n crypto,\n cookieName = 'csrf_token',\n headerName = 'X-CSRF-Token',\n formFieldName = '_csrf',\n tokenLength = 32,\n cookieOptions = {},\n } = config\n\n return {\n /**\n * 生成新的 CSRF Token 并设置 Cookie\n */\n async generate(cookies: Cookies): Promise<string> {\n const result = await crypto.random.bytes(tokenLength)\n if (!result.success) {\n throw new Error(kitM('kit_csrfTokenFailed'))\n }\n\n const token = Array.from(result.data!)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n\n cookies.set(cookieName, token, {\n path: '/',\n httpOnly: true,\n secure: true,\n sameSite: 'strict',\n ...cookieOptions,\n })\n\n return token\n },\n\n /**\n * 验证 CSRF Token\n */\n async verify(event: RequestEvent): Promise<boolean> {\n const cookieToken = event.cookies.get(cookieName)\n if (!cookieToken) {\n return false\n }\n\n // 从 header 或 form data 获取 token\n let requestToken = event.request.headers.get(headerName)\n\n if (!requestToken && event.request.method === 'POST') {\n try {\n const formData = await event.request.clone().formData()\n const fieldValue = formData.get(formFieldName)\n requestToken = typeof fieldValue === 'string' ? fieldValue : null\n }\n catch {\n // 不是 form data\n }\n }\n\n if (!requestToken) {\n return false\n }\n\n // 时间安全的比较\n const result = await crypto.hash.timingSafeEqual(cookieToken, requestToken)\n return result.success && result.data === true\n },\n\n /**\n * 创建 CSRF 验证中间件\n */\n createHandle() {\n return async ({ event, resolve }: { event: RequestEvent, resolve: (event: RequestEvent) => Promise<Response> }) => {\n // 跳过安全方法\n const safeMethods = ['GET', 'HEAD', 'OPTIONS']\n if (safeMethods.includes(event.request.method)) {\n return resolve(event)\n }\n\n const isValid = await this.verify(event)\n if (!isValid) {\n return new Response(kitM('kit_csrfVerifyFailed'), { status: 403 })\n }\n\n return resolve(event)\n }\n },\n }\n}\n\n/**\n * 创建加密 Cookie 管理器\n *\n * 使用 AES 对 Cookie 值进行加解密,防止客户端篡改。\n *\n * @param config - 加密 Cookie 配置(含加密密钥)\n * @returns `{ set, get, delete }`\n * @example 模块内部上下文\n * ```ts\n * function cookies(config: EncryptedCookieConfig) {\n * return createEncryptedCookie(config)\n * }\n * ```\n */\nexport function createEncryptedCookie(config: EncryptedCookieConfig) {\n const { crypto, encryptionKey, cookieOptions = {} } = config\n\n return {\n /**\n * 设置加密 Cookie\n */\n async set(cookies: Cookies, name: string, value: unknown): Promise<void> {\n const json = JSON.stringify(value)\n const result = await crypto.aes.encrypt(json, encryptionKey)\n\n if (!result.success) {\n throw new Error(kitM('kit_encryptFailed'))\n }\n\n cookies.set(name, result.data!, {\n path: '/',\n httpOnly: true,\n secure: true,\n sameSite: 'lax',\n ...cookieOptions,\n })\n },\n\n /**\n * 获取并解密 Cookie\n */\n async get<T = unknown>(cookies: Cookies, name: string): Promise<T | null> {\n const encrypted = cookies.get(name)\n if (!encrypted) {\n return null\n }\n\n try {\n const result = await crypto.aes.decrypt(encrypted, encryptionKey)\n if (!result.success) {\n return null\n }\n\n return JSON.parse(result.data!) as T\n }\n catch {\n return null\n }\n },\n\n /**\n * 删除 Cookie\n */\n delete(cookies: Cookies, name: string): void {\n cookies.delete(name, { path: '/' })\n },\n }\n}\n"]}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/kit",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.2",
4
+ "version": "1.0.0-beta.21",
5
5
  "description": "Hai Framework SvelteKit integration module.",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -43,11 +43,11 @@
43
43
  "node": "^22.23.4 || ^24.22.1 || ^26.12.1"
44
44
  },
45
45
  "peerDependencies": {
46
- "@h-ai/feedback": "1.0.0-beta.2",
47
- "@sveltejs/adapter-node": "^5.5.7",
48
- "@sveltejs/adapter-static": "^3.0.10",
49
- "@sveltejs/kit": "^2.70.3",
50
- "svelte": "^5.57.2"
46
+ "@h-ai/feedback": "1.0.0-beta.21",
47
+ "@sveltejs/adapter-node": "^6.0.1",
48
+ "@sveltejs/adapter-static": "^4.0.1",
49
+ "@sveltejs/kit": "^3.1.1",
50
+ "svelte": "^5.57.3"
51
51
  },
52
52
  "peerDependenciesMeta": {
53
53
  "@h-ai/feedback": {
@@ -61,25 +61,25 @@
61
61
  }
62
62
  },
63
63
  "dependencies": {
64
- "@h-ai/api-contract": "1.0.0-beta.2",
65
- "@h-ai/audit": "1.0.0-beta.2",
66
- "@h-ai/core": "1.0.0-beta.2",
67
- "@h-ai/crypto": "1.0.0-beta.2",
68
- "@h-ai/iam": "1.0.0-beta.2",
69
- "zod": "^4.6.5"
64
+ "@h-ai/api-contract": "1.0.0-beta.21",
65
+ "@h-ai/audit": "1.0.0-beta.21",
66
+ "@h-ai/core": "1.0.0-beta.21",
67
+ "@h-ai/crypto": "1.0.0-beta.21",
68
+ "@h-ai/iam": "1.0.0-beta.21",
69
+ "zod": "^4.6.7"
70
70
  },
71
71
  "devDependencies": {
72
- "@h-ai/cache": "1.0.0-beta.2",
73
- "@h-ai/feedback": "1.0.0-beta.2",
74
- "@h-ai/reldb": "1.0.0-beta.2",
75
- "@sveltejs/kit": "^2.70.3",
76
- "@types/node": "^26.6.5",
77
- "rimraf": "^6.1.3",
78
- "svelte": "^5.57.2",
79
- "testcontainers": "^12.2.0",
80
- "tsup": "^8.5.1",
72
+ "@h-ai/cache": "1.0.0-beta.21",
73
+ "@h-ai/feedback": "1.0.0-beta.21",
74
+ "@h-ai/reldb": "1.0.0-beta.21",
75
+ "@sveltejs/kit": "^3.1.1",
76
+ "@types/node": "^26.6.6",
77
+ "rimraf": "^6.1.4",
78
+ "svelte": "^5.57.3",
79
+ "testcontainers": "^12.2.1",
80
+ "tsup": "^9.0.0",
81
81
  "typescript": "^6.0.3",
82
- "vitest": "^4.1.11"
82
+ "vitest": "^5.1.0"
83
83
  },
84
84
  "scripts": {
85
85
  "build": "tsup",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/modules/crypto/kit-transport-middleware.ts"],"names":[],"mappings":"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","file":"chunk-3OHUSKHI.js","sourcesContent":["/**\n * @h-ai/kit — 传输加密中间件\n *\n * SvelteKit 中间件,自动对请求/响应进行传输加密解密。\n * @module kit-transport-middleware\n */\n\nimport type { RequestAccessCheck } from '@h-ai/core'\nimport type { TransportEncryptionManager, TransportMessageContext } from '@h-ai/crypto'\nimport type { Middleware } from '../../kit-types.js'\nimport type { TransportEncryptionConfig } from './kit-crypto-types.js'\nimport { core, err, HaiCommonError } from '@h-ai/core'\nimport { authenticateTransportRequest, createTransportBodyPolicy, createTransportErrorResponse, isValidSM2PublicKey, readTransportBody, TRANSPORT_BODY_LIMITS, TRANSPORT_PROTOCOL, TransportBodyTooLargeError, TransportTimeError } from '@h-ai/crypto'\nimport { kitM } from '../../kit-i18n.js'\nimport { DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH, normalizeTransportBasePath, shouldExcludeTransportPath, shouldHandleTransportPath } from './kit-transport-paths.js'\n\nconst ENCRYPTABLE_RESPONSE_CONTENT_TYPES = ['application/json', 'text/sveltekit-data']\n\n/**\n * 创建传输加密中间件\n *\n * @param config - 传输加密配置\n * @param encryption - 已编译的路径/方法选择器;省略时沿用宿主默认范围。\n * @returns SvelteKit 中间件\n * @throws 显式启用但管理器初始化失败时抛出配置错误,调用方须停止宿主装配。\n * @example 模块内部上下文\n * ```ts\n * function install(config: TransportEncryptionConfig) {\n * return transportEncryptionMiddleware(config) // 受管密钥环、共享 keyStore 与 crypto 生命周期由应用管理。\n * }\n * ```\n */\nexport function transportEncryptionMiddleware(config: TransportEncryptionConfig, encryption?: RequestAccessCheck['encryption']): Middleware {\n // 未启用时直接透传\n if (!config.enabled) {\n return async (_context, next) => next()\n }\n\n const keyExchangePath = config.keyExchangePath ?? DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH\n const basePath = normalizeTransportBasePath(config.basePath)\n const excludePaths = config.excludePaths ?? []\n\n const policy = createTransportBodyPolicy(config.maxPlaintextBytes, config.routePlaintextBytes)\n\n // 初始化传输加密管理器\n const result = config.crypto.transport.createServer({\n serverKeyRing: config.serverKeyRing,\n keyStore: config.keyStore,\n maxPlaintextBytes: policy.maximum.plaintextBytes,\n })\n if (!result.success) {\n // 与 Serv 一致:静态配置或必需依赖失败即拒绝装配,不能让健康页面掩盖不可用的业务加密。\n throw core.error.buildHaiErrorInst(HaiCommonError.INTERNAL_ERROR, kitM('kit_transportKeyGenerationFailed'), result.error)\n }\n const manager = result.data\n\n return async (context, next) => {\n const { event } = context\n const pathname = getRequestPathname(event.request)\n\n // CORS 预检没有业务密文,仍交由请求访问策略判断。\n if (event.request.method === 'OPTIONS')\n return next()\n\n // 密钥交换端点:委托给 keyExchangeHandler\n if (pathname === keyExchangePath && event.request.method === 'POST') {\n return handleKeyExchange(manager, event.request)\n }\n\n const mode = encryption?.(pathname, event.request.method)\n if (mode === 'disabled') {\n if (event.request.headers.has(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER) || event.request.headers.has(TRANSPORT_PROTOCOL.ENVELOPE_HEADER))\n return Response.json(err({ ...HaiCommonError.VALIDATION_ERROR, message: kitM('kit_transportPlaintextRequired'), traceId: context.requestId }), { status: 400 })\n return next()\n }\n // 仅对同源 API endpoint 与 SvelteKit __data 请求启用 transport;\n // 显式 required 也可保护自定义 JSON 端点;不能拿它包裹 HTML 页面。\n if (mode !== 'required' && !shouldHandleTransportPath(pathname, keyExchangePath, basePath)) {\n return next()\n }\n\n // 排除路径不做加解密\n if (mode !== 'required' && shouldExcludeTransportPath(pathname, excludePaths, keyExchangePath)) {\n return next()\n }\n\n // 请求头中无 X-Client-Id 时的处理\n const clientId = event.request.headers.get(TRANSPORT_PROTOCOL.CLIENT_ID_HEADER)\n if (!clientId)\n return jsonError(kitM('kit_transportClientIdRequired'), 400)\n\n const lease = policy.acquire(pathname)\n if (!lease)\n return jsonError(kitM('kit_transportBusy'), 503)\n try {\n // ── 解密请求 ──\n // 不依赖可伪造/省略的 Content-Length/Type 判空,非 null 流必须进入实际内容检查。\n let requestContext: TransportMessageContext\n try {\n const verified = await authenticateTransportRequest(manager, event.request, lease.limits)\n if (!verified.success) {\n if (verified.error.cause instanceof TransportTimeError && verified.error.cause.context)\n return createTransportErrorResponse(verified.error.cause, { manager, context: verified.error.cause.context })\n return jsonError(kitM('kit_transportDecryptFailed'), 400)\n }\n requestContext = verified.data.context\n if (event.request.method !== 'GET' && event.request.method !== 'HEAD')\n replaceRequestBody(event, verified.data.plaintext)\n }\n catch (error) {\n if (error instanceof TransportBodyTooLargeError)\n return createTransportErrorResponse(error)\n return jsonError(kitM('kit_transportInvalidPayload'), error instanceof RangeError ? 413 : 400)\n }\n\n // ── 执行后续中间件/端点 ──\n const response = await next()\n\n // ── 加密响应 ──\n\n // 只允许可安全加密的响应体离开受保护路由;无法加密时 fail-closed,禁止明文泄露。\n const bodyless = event.request.method === 'HEAD' || isEmptyResponse(response)\n if (bodyless)\n void response.body?.cancel().catch(() => {})\n\n const contentType = response.headers.get('Content-Type') ?? ''\n if (!bodyless && !canEncryptResponseContentType(contentType)) {\n void response.body?.cancel().catch(() => {})\n return jsonError(kitM('kit_transportEncryptFailed'), 500)\n }\n try {\n const responseBody = bodyless\n ? ''\n : await readTransportBody(response.body, {\n maxBytes: lease.limits.plaintextBytes,\n direction: 'response',\n signal: event.request.signal,\n })\n const headers = new Headers(response.headers)\n headers.delete(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER)\n headers.delete(TRANSPORT_PROTOCOL.ENVELOPE_HEADER)\n headers.delete('Content-Length')\n headers.delete('Content-Encoding')\n\n const encryptedPayload = await manager.encryptResponse(requestContext, responseBody, response.status)\n if (!encryptedPayload.success) {\n return jsonError(kitM('kit_transportEncryptFailed'), 500)\n }\n headers.set(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER, TRANSPORT_PROTOCOL.ENCRYPTED_HEADER_VALUE)\n if (bodyless)\n headers.set(TRANSPORT_PROTOCOL.ENVELOPE_HEADER, JSON.stringify(encryptedPayload.data))\n return new Response(bodyless ? null : JSON.stringify(encryptedPayload.data), {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n }\n catch (error) {\n if (error instanceof TransportBodyTooLargeError)\n return createTransportErrorResponse(error, { manager, context: requestContext })\n return jsonError(kitM('kit_transportEncryptFailed'), 500)\n }\n }\n finally { lease.release() }\n }\n}\n\nfunction canEncryptResponseContentType(contentType: string): boolean {\n return ENCRYPTABLE_RESPONSE_CONTENT_TYPES.some(type => contentType.includes(type))\n}\n\nfunction isEmptyResponse(response: Response): boolean {\n if ([204, 304].includes(response.status))\n return true\n // Content-Length 不能证明响应流为空,避免明文伪装零长度后绕过加密。\n return response.body === null\n}\n\nfunction getRequestPathname(request: Request): string {\n return new URL(request.url).pathname\n}\n\nfunction jsonError(message: string, status: number): Response {\n return new Response(JSON.stringify({ error: message }), {\n status,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\n/**\n * 处理密钥交换 POST 请求\n *\n * 接收客户端公钥,注册并返回服务端公钥与 clientId。\n *\n * @param manager - 传输加密管理器\n * @param request - 原始 Request\n * @returns JSON Response\n */\nasync function handleKeyExchange(\n manager: TransportEncryptionManager,\n request: Request,\n): Promise<Response> {\n let body: unknown\n try {\n body = JSON.parse(await readTransportBody(request.body, {\n maxBytes: TRANSPORT_BODY_LIMITS.keyExchangeBytes,\n signal: request.signal,\n }))\n }\n catch (error) {\n return jsonError(kitM('kit_transportInvalidPayload'), error instanceof RangeError ? 413 : 400)\n }\n if (!body || typeof body !== 'object' || !('clientPublicKey' in body)\n || !isValidSM2PublicKey(body.clientPublicKey)\n || new TextEncoder().encode(body.clientPublicKey).byteLength > TRANSPORT_BODY_LIMITS.publicKeyBytes) {\n return jsonError(kitM('kit_transportInvalidPayload'), 400)\n }\n\n try {\n const serverPublicKey = manager.getServerPublicKey()\n if (new TextEncoder().encode(serverPublicKey).byteLength > TRANSPORT_BODY_LIMITS.publicKeyBytes)\n return jsonError(kitM('kit_transportKeyExchangeFailed'), 500)\n const clientId = await manager.registerClientKey(body.clientPublicKey)\n\n return new Response(\n JSON.stringify({ serverKeyId: manager.getServerKeyId(), serverPublicKey, clientId, maxPlaintextBytes: manager.bodyLimits.plaintextBytes }),\n { status: 200, headers: { 'Content-Type': 'application/json' } },\n )\n }\n catch {\n return jsonError(kitM('kit_transportKeyExchangeFailed'), 500)\n }\n}\n\n/**\n * 用于替换已验证请求正文的最小可写容器。\n * @example 模块内部上下文\n * ```ts\n * const holder: RequestHolder = { request: new Request('https://app.example.com/api/articles', { method: 'POST', body: '{}' }) }\n * replaceRequestBody(holder, JSON.stringify({ title: 'Example' }))\n * ```\n */\ninterface RequestHolder {\n request: Request\n}\n\n/**\n * 重建 SvelteKit 事件中的 Request。\n *\n * 有界认证会消费密文 body;只将成功认证的明文恢复给后续端点。\n *\n * @param event SvelteKit 请求事件\n * @param body 新请求体\n */\nfunction replaceRequestBody(event: RequestHolder, body: string): void {\n const headers = new Headers(event.request.headers)\n headers.delete(TRANSPORT_PROTOCOL.ENCRYPTED_HEADER)\n headers.delete('Content-Length')\n headers.delete('Content-Encoding')\n headers.set('Content-Type', 'application/json; charset=utf-8')\n const newRequest = new Request(event.request.url, {\n method: event.request.method,\n headers,\n body,\n signal: event.request.signal,\n })\n Object.defineProperty(event, 'request', {\n value: newRequest,\n writable: true,\n configurable: true,\n })\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/crud/kit-crud.ts","../src/kit-config.ts"],"names":[],"mappings":"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","file":"chunk-5VWPH7DO.js","sourcesContent":["/**\n * @h-ai/kit — CRUD 操作定义\n *\n * 声明式 CRUD 资源定义工厂函数。\n * @module kit-crud\n */\n\nimport type {\n CrudFieldDef,\n CrudFieldOptions,\n CrudOperations,\n CrudResourceDef,\n CrudTableColumn,\n CrudText,\n} from './kit-crud-types.js'\n\n/**\n * 解析 CrudText 为字符串\n */\nfunction resolveText(text: CrudText): string {\n return typeof text === 'function' ? text() : text\n}\n\n/**\n * 按 order 排序字段\n */\nfunction sortFields(fields: CrudFieldDef[]): CrudFieldDef[] {\n return [...fields].sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n}\n\n/**\n * 解析选项列表\n */\nfunction resolveOptions(options: CrudFieldOptions | undefined): Array<{ label: string, value: string | number | boolean }> {\n if (!options)\n return []\n return typeof options === 'function' ? options() : options\n}\n\n/**\n * 定义 CRUD 资源\n *\n * 返回 CrudOperations 对象,包含字段过滤、列构建和 API 代理等能力。\n * 与 @h-ai/ui 的 CrudPage 组件配合使用。\n *\n * @param resource - 资源定义\n * @returns CRUD 操作对象\n * @example\n * ```ts\n * import { kit } from '@h-ai/kit'\n *\n * import type { CrudApiDef } from '@h-ai/kit'\n *\n * function articleResource(api: CrudApiDef<{ id: string, title: string }>) {\n * return kit.crud.define({ name: 'article', label: 'Articles', fields: [{ id: 'title', label: 'Title', type: 'string' }], api })\n * }\n * ```\n */\nexport function defineCrud<T = Record<string, unknown>>(\n resource: CrudResourceDef<T>,\n): CrudOperations<T> {\n const fields = resource.fields\n\n function getListFields(): CrudFieldDef[] {\n return sortFields(fields.filter(f => f.inList !== false))\n }\n\n function getFilterFields(): CrudFieldDef[] {\n return sortFields(fields.filter(f => f.filterable === true))\n }\n\n function getCreateFields(): CrudFieldDef[] {\n return sortFields(fields.filter(f => f.inCreate !== false))\n }\n\n function getEditFields(): CrudFieldDef[] {\n return sortFields(fields.filter(f => f.inEdit !== false))\n }\n\n function getDetailFields(): CrudFieldDef[] {\n return sortFields(fields.filter(f => f.inDetail !== false))\n }\n\n function toTableColumns(): CrudTableColumn[] {\n return getListFields().map(f => ({\n key: f.id,\n label: resolveText(f.label),\n width: f.width,\n align: f.align,\n render: f.render\n ? (item: Record<string, unknown>) => f.render!(item[f.id], item)\n : undefined,\n }))\n }\n\n function getDefaultValues(): Record<string, unknown> {\n const defaults: Record<string, unknown> = {}\n for (const f of fields) {\n if (f.defaultValue !== undefined) {\n defaults[f.id] = f.defaultValue\n }\n else if (f.type === 'boolean' || f.type === 'checkbox') {\n defaults[f.id] = false\n }\n else if (f.type === 'multi-select') {\n defaults[f.id] = []\n }\n else if (f.type === 'number') {\n defaults[f.id] = undefined\n }\n else {\n defaults[f.id] = ''\n }\n }\n return defaults\n }\n\n return {\n resource,\n getListFields,\n getFilterFields,\n getCreateFields,\n getEditFields,\n getDetailFields,\n toTableColumns,\n getDefaultValues,\n api: resource.api,\n }\n}\n\n// re-export 解析工具,供 UI 层使用\nexport { resolveOptions, resolveText }\n","/**\n * @h-ai/kit — 宿主配置\n *\n * 为 `config/_kit.yml` 提供监听、传输与请求策略的默认值和校验。\n * 服务端消费完整配置;浏览器仅接收显式投影的 transport 公共字段。\n * @module kit-config\n */\n\nimport type { KitConfig, KitConfigInput, KitServerConfig, KitServerConfigInput, KitTransportConfig, KitTransportConfigInput } from './kit-types.js'\nimport { RequestAccessConfigSchema, TrustedProxiesSchema } from '@h-ai/core'\nimport { TRANSPORT_PLAINTEXT_RANGE } from '@h-ai/crypto'\nimport { z } from 'zod'\n\nconst AbsolutePathSchema = z.custom<`/${string}`>(\n value => typeof value === 'string' && value.startsWith('/'),\n 'path must start with /',\n)\n\nconst KitTransportConfigInputSchema = z.union([\n z.literal(false),\n z.object({\n maxPlaintextBytes: z.union([z.number().int().min(TRANSPORT_PLAINTEXT_RANGE.min).max(TRANSPORT_PLAINTEXT_RANGE.max), z.literal('auto')]).transform(value => value === 'auto' ? undefined : value).optional().describe('普通业务双向明文上限;auto 为 1 MiB;大材料使用 routePlaintextBytes 单独声明').meta({ default: 'auto' }),\n routePlaintextBytes: z.record(AbsolutePathSchema, z.number().int().min(TRANSPORT_PLAINTEXT_RANGE.min).max(TRANSPORT_PLAINTEXT_RANGE.max)).optional().describe('完整路径段到双向明文字节上限的映射;星号匹配单段,供附件和归档独立容量'),\n keyExchangePath: AbsolutePathSchema.default('/api/_hai/key-exchange'),\n excludePaths: z.array(AbsolutePathSchema).default([]),\n }),\n])\n\nconst ServerConfigInputSchema = z.object({\n host: z.string().min(1).default('127.0.0.1'),\n port: z.number().int().min(1).max(65535).default(3000),\n})\n\n/**\n * `config/_kit.yml` 对应的配置 Schema。\n * @example\n * ```ts\n * import { KitConfigSchema } from '@h-ai/kit'\n *\n * const config = KitConfigSchema.parse({ server: { port: 3000 }, transport: false })\n * void config\n * ```\n */\nexport const KitConfigSchema = z.object({\n server: ServerConfigInputSchema.optional(),\n transport: KitTransportConfigInputSchema.optional(),\n trustedProxies: TrustedProxiesSchema.default('auto'),\n access: RequestAccessConfigSchema.default(false),\n}).transform(({ server, transport, trustedProxies, access }) => ({\n server: resolveKitServerConfig(server ?? {}),\n transport: resolveKitTransportConfig(transport ?? false),\n trustedProxies,\n access,\n}))\n\n/**\n * 读取 `HOST` / `PORT` 环境变量覆盖(环境变量高于配置文件)。\n *\n * 浏览器端 `process` 不存在时安全回退为空;`PORT` 仅采纳 1-65535 的整数。\n */\nfunction readServerEnvOverride(): KitServerConfigInput {\n // eslint-disable-next-line node/prefer-global/process\n const env = typeof process !== 'undefined' ? process.env : undefined\n const override: { host?: string, port?: number } = {}\n const host = env?.HOST\n if (host)\n override.host = host\n const rawPort = env?.PORT\n if (rawPort) {\n const port = Number(rawPort)\n if (Number.isInteger(port) && port >= 1 && port <= 65535)\n override.port = port\n }\n return override\n}\n\n/**\n * 解析服务器监听配置并补齐默认值。\n *\n * 优先级:`HOST` / `PORT` 环境变量 > `config/_kit.yml` 的 `server` > 默认 `127.0.0.1:3000`。\n *\n * @param input - `config/_kit.yml` 中的 server 配置\n * @returns 完整 server 配置\n * @example 模块内部上下文\n * ```ts\n * const config = resolveKitServerConfig({ port: 4000 })\n * // HOST / PORT 环境变量优先于输入。\n * void config.port\n * ```\n */\nexport function resolveKitServerConfig(input: KitServerConfigInput = {}): KitServerConfig {\n return { ...ServerConfigInputSchema.parse(input), ...readServerEnvOverride() }\n}\n\n/**\n * 解析 transport 配置并补齐默认值。\n *\n * @param input - `config/_kit.yml` 中的 transport 配置\n * @returns 完整 transport 配置;`false` 表示关闭\n * @example\n * ```ts\n * import { resolveKitTransportConfig } from '@h-ai/kit'\n *\n * const transport = resolveKitTransportConfig({ excludePaths: ['/api/health'] })\n * if (transport) void transport.keyExchangePath\n * ```\n */\nexport function resolveKitTransportConfig(\n input: false | KitTransportConfigInput = false,\n): false | KitTransportConfig {\n return KitTransportConfigInputSchema.parse(input)\n}\n\n/**\n * 解析 `config/_kit.yml` 顶层配置并补齐默认值。\n *\n * 适合同一份配置同时供 SvelteKit 服务端 hook 与浏览器端 client 读取。\n * @param input - Kit 监听和公开 transport 输入;省略字段按 Schema 补默认值。\n * @returns 已补齐默认值的配置;不合法输入抛出 ZodError。\n * @example\n * ```ts\n * import { resolveKitConfig } from '@h-ai/kit'\n *\n * const config = resolveKitConfig({ transport: false })\n * void config.server.port\n * ```\n */\nexport function resolveKitConfig(input: KitConfigInput = {}): KitConfig {\n return KitConfigSchema.parse(input)\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/modules/a2a/kit-a2a-auth.ts","../src/modules/a2a/kit-a2a-helpers.ts","../src/modules/a2a/kit-a2a-handle.ts"],"names":[],"mappings":"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","file":"chunk-7EH47MTW.js","sourcesContent":["/**\n * @h-ai/kit — A2A API Key 认证器\n *\n * 从请求头或 query 参数中提取 API Key,调用 IAM apiKey.verifyApiKey 验证。\n * @module kit-a2a-auth\n */\n\nimport type { RequestEvent } from '@sveltejs/kit'\nimport { iam } from '@h-ai/iam'\n\n/**\n * A2A API Key 认证器配置\n * @example\n * ```ts\n * import type { A2AApiKeyAuthConfig } from '@h-ai/kit'\n *\n * const value: A2AApiKeyAuthConfig = { in: 'header', name: 'X-Agent-Key' }\n * void value\n * ```\n */\nexport interface A2AApiKeyAuthConfig {\n /** API Key 的传递位置 */\n in: 'header' | 'query'\n /** 参数名 */\n name: string\n}\n\n/**\n * 创建 A2A API Key 认证函数\n *\n * 根据配置从请求头或 query 参数中提取 API Key,\n * 通过 `iam.apiKey.verifyApiKey()` 验证后返回调用方上下文。\n *\n * - 无 API Key → 返回 `null`(由调用方拒绝请求)\n * - 验证失败 → 返回 `null`(拒绝)\n * - 验证成功 → 返回 `{ agentId, apiKeyId, scopes }`\n *\n * @param config - API Key 提取配置\n * @returns authenticate 函数,可直接赋给 HandleA2AConfig.authenticate\n * @example 模块内部上下文\n * ```ts\n * const authenticate = createA2AApiKeyAuthenticator({ in: 'header', name: 'X-Agent-Key' })\n * // 应用先初始化 IAM;拒绝返回 null,交给路由转为 401。\n * void authenticate\n * ```\n */\nexport function createA2AApiKeyAuthenticator(\n config: A2AApiKeyAuthConfig,\n): (event: RequestEvent) => Promise<Record<string, unknown> | null> {\n return async (event: RequestEvent) => {\n const rawKey = config.in === 'header'\n ? event.request.headers.get(config.name)\n : event.url.searchParams.get(config.name)\n\n if (!rawKey)\n return null\n\n const result = await iam.apiKey.verifyApiKey(rawKey)\n if (!result.success)\n return null\n\n return {\n agentId: result.data.userId,\n apiKeyId: result.data.id,\n scopes: result.data.scopes,\n }\n }\n}\n","/**\n * @h-ai/kit — A2A 路由处理器\n *\n * 提供 SvelteKit 路由工厂:Agent Card 端点和 JSON-RPC 处理端点。\n * @module kit-a2a-helpers\n */\n\nimport type { RequestEvent, RequestHandler } from '@sveltejs/kit'\n\nimport type { KitA2AHandlerConfig } from './kit-a2a-types.js'\nimport { kitM } from '../../kit-i18n.js'\nimport { createA2AApiKeyAuthenticator } from './kit-a2a-auth.js'\n\n/**\n * 创建 Agent Card GET 处理器\n *\n * 返回当前 Agent 的 Agent Card(JSON),通常挂载在 `/.well-known/agent-card.json`。\n *\n * @param getAgentCard - 获取 Agent Card 的回调(通常调用 `ai.a2a.getAgentCard()`)\n * @returns SvelteKit GET 处理器\n * @example 模块内部上下文\n * ```ts\n * const handler = createAgentCardHandler(() => ({ name: 'Example agent', url: 'https://agent.example.com/a2a' }))\n * void handler\n * ```\n */\nexport function createAgentCardHandler(\n getAgentCard: () => object,\n): RequestHandler {\n return async () => {\n const card = getAgentCard()\n return new Response(JSON.stringify(card), {\n headers: { 'Content-Type': 'application/json' },\n })\n }\n}\n\n/**\n * 创建 A2A JSON-RPC POST 处理器\n *\n * 将 SvelteKit Request 转换为 JSON-RPC body,委托给 `handleRequest` 回调处理。\n * 支持单条响应和流式(SSE)响应。\n *\n * @param handleRequest - JSON-RPC 请求处理回调(通常调用 `ai.a2a.handleRequest()`)\n * @param config - 可选配置(认证等)\n * @returns SvelteKit POST 处理器\n * @example 模块内部上下文\n * ```ts\n * function build(operations: Parameters<typeof createA2AHandler>[0]) {\n * return createA2AHandler(operations, { authenticate: async () => null })\n * }\n * ```\n */\nexport function createA2AHandler(\n handleRequest: (body: unknown, context?: Record<string, unknown>) => Promise<{\n streaming: boolean\n body?: unknown\n stream?: AsyncGenerator<unknown, void, undefined>\n }>,\n config?: KitA2AHandlerConfig,\n): RequestHandler {\n return async (event: RequestEvent) => {\n // 可选认证\n let context: Record<string, unknown> | undefined\n if (config?.authenticate) {\n const authFn = typeof config.authenticate === 'function'\n ? config.authenticate\n : createA2AApiKeyAuthenticator({ in: 'header', name: 'x-api-key' })\n const authResult = await authFn(event)\n if (!authResult)\n return Response.json({ error: { code: 'A2A_AUTH_FAILED', message: kitM('kit_a2aAuthFailed') } }, { status: 401 })\n context = authResult\n }\n\n // 解析 JSON-RPC 请求体\n let requestBody: unknown\n try {\n requestBody = await event.request.json()\n }\n catch {\n return Response.json({ jsonrpc: '2.0', id: null, error: { code: -32700, message: kitM('kit_a2aParseError') } }, { status: 400 })\n }\n const result = await handleRequest(requestBody, context)\n\n if (result.streaming && result.stream) {\n // 流式响应:SSE 格式\n const stream = result.stream\n const readableStream = new ReadableStream({\n // 按下游拉取推进迭代,避免 start 中无界预读;断开时释放生成器。\n async pull(controller) {\n try {\n const chunk = await stream.next()\n if (chunk.done)\n controller.close()\n else\n controller.enqueue(new TextEncoder().encode(`data: ${JSON.stringify(chunk.value)}\\n\\n`))\n }\n catch (error) {\n controller.error(error)\n }\n },\n async cancel() {\n await stream.return()\n },\n })\n\n return new Response(readableStream, {\n headers: {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n },\n })\n }\n\n // 单条响应\n return new Response(JSON.stringify(result.body), {\n headers: { 'Content-Type': 'application/json' },\n })\n }\n}\n","/**\n * @h-ai/kit — A2A Handle 拦截器\n *\n * 在 SvelteKit Handle Hook 中拦截 A2A 端点(Agent Card 发现 + JSON-RPC 处理),\n * 自动处理请求并返回 Response,不匹配时返回 null 由 Handle 继续后续流程。\n * @module kit-a2a-handle\n */\n\nimport type { RequestEvent } from '@sveltejs/kit'\nimport type { HandleA2AConfig, HandleA2AOperations, HandleConfig } from '../../kit-types.js'\nimport { kitM } from '../../kit-i18n.js'\nimport { createA2AApiKeyAuthenticator } from './kit-a2a-auth.js'\nimport { createA2AHandler } from './kit-a2a-helpers.js'\n\n// ─── 解析后的 A2A 内部配置 ───\n\n/**\n * A2A 解析后的内部配置\n * @example\n * ```ts\n * import type { ResolvedA2AConfig } from '@h-ai/kit'\n *\n * function paths(config: ResolvedA2AConfig) { return [config.cardPath, config.rpcPath] }\n * ```\n */\nexport interface ResolvedA2AConfig {\n operations: HandleA2AOperations\n cardPath: string\n rpcPath: string\n authenticate?: (event: RequestEvent) => Promise<Record<string, unknown> | null | undefined>\n}\n\n// ─── A2A 配置解析 ───\n\n/**\n * 解析 A2A 配置(简单模式 / 配置模式)\n *\n * - 简单模式:直接传入 `ai.a2a` 操作对象,使用默认路径\n * - 配置模式:传入 `{ operations, rpcPath?, cardPath?, authenticate? }`\n *\n * @param input - HandleConfig.a2a 配置\n * @returns 解析后的配置,或 `null` 表示未配置\n * @example 模块内部上下文\n * ```ts\n * function resolve(operations: HandleA2AOperations) {\n * return resolveA2AConfig({ operations, rpcPath: '/a2a', authenticate: async () => null })\n * }\n * ```\n */\nexport function resolveA2AConfig(\n input: HandleConfig['a2a'],\n): ResolvedA2AConfig | null {\n if (!input)\n return null\n\n // 简单模式:直接传入操作对象\n if ('getAgentCard' in input && 'handleRequest' in input) {\n return {\n operations: input as HandleA2AOperations,\n cardPath: '/.well-known/agent-card.json',\n rpcPath: '/a2a',\n }\n }\n\n // 配置模式:带 operations 字段\n const cfg = input as HandleA2AConfig\n return {\n operations: cfg.operations,\n cardPath: cfg.cardPath ?? '/.well-known/agent-card.json',\n rpcPath: cfg.rpcPath ?? '/a2a',\n authenticate: resolveAuthenticate(cfg.authenticate, cfg.operations),\n }\n}\n\n/**\n * 解析 authenticate 配置\n *\n * - `undefined` → 无认证\n * - `'apiKey'` → 从 Agent Card security 配置创建 API Key 认证器\n * - 函数 → 直接使用\n */\nfunction resolveAuthenticate(\n authenticate: HandleA2AConfig['authenticate'],\n operations: HandleA2AOperations,\n): ResolvedA2AConfig['authenticate'] {\n if (!authenticate)\n return undefined\n\n if (typeof authenticate === 'function')\n return authenticate\n\n // 'apiKey' 快捷方式:从 Agent Card 获取 security 配置\n const cardResult = operations.getAgentCard()\n const securitySchemes = cardResult.success && cardResult.data\n ? (cardResult.data as { securitySchemes?: Record<string, { type: string, in?: string, name?: string }> }).securitySchemes\n : undefined\n const apiKeyCfg = securitySchemes?.apiKey\n\n return createA2AApiKeyAuthenticator({\n in: apiKeyCfg?.in === 'query' ? 'query' : 'header',\n name: apiKeyCfg?.name ?? 'x-api-key',\n })\n}\n\n// ─── A2A 请求处理 ───\n\n/**\n * 处理 A2A 端点请求\n *\n * 匹配 Agent Card GET 和 JSON-RPC POST 端点,返回 Response。\n * 不匹配时返回 `null`,由 Handle 继续后续流程。\n *\n * @param event - SvelteKit RequestEvent\n * @param requestId - 当前请求 ID(用于响应头)\n * @param config - 解析后的 A2A 配置\n * @returns 匹配时返回 Response,不匹配返回 null\n * @example 模块内部上下文\n * ```ts\n * async function handle(event: RequestEvent, config: ResolvedA2AConfig) {\n * return handleA2ARequest(event, 'req_1', config) // null 表示路径未匹配,交给后续 handle。\n * }\n * ```\n */\nexport async function handleA2ARequest(\n event: RequestEvent,\n requestId: string,\n config: ResolvedA2AConfig,\n): Promise<Response | null> {\n const { pathname } = event.url\n\n // Agent Card 发现端点\n if (pathname === config.cardPath && event.request.method === 'GET') {\n const result = config.operations.getAgentCard()\n if (result.success) {\n return new Response(JSON.stringify(result.data), {\n headers: { 'Content-Type': 'application/json', 'X-Request-Id': requestId },\n })\n }\n return new Response(\n JSON.stringify({ error: { code: 'A2A_NOT_CONFIGURED', message: kitM('kit_a2aCardUnavailable') } }),\n { status: 503, headers: { 'Content-Type': 'application/json', 'X-Request-Id': requestId } },\n )\n }\n\n // A2A JSON-RPC 端点\n if (pathname === config.rpcPath && event.request.method === 'POST') {\n // Hook 与显式路由共享认证、JSON-RPC 错误和流式生命周期逻辑。\n const handler = createA2AHandler(\n (body, context) => config.operations.handleRequest(body, context),\n { authenticate: config.authenticate },\n )\n const response = await handler(event)\n response.headers.set('X-Request-Id', requestId)\n return response\n }\n\n return null\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/modules/crypto/kit-transport-paths.ts"],"names":[],"mappings":"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","file":"chunk-JRQPMPQC.js","sourcesContent":["/**\n * @h-ai/kit — 传输加密路径匹配工具\n *\n * 统一定义哪些同源请求应纳入 transport 保护范围,供服务端 middleware\n * 与浏览器端 fetch 包装共同复用,避免两端判断漂移。\n * @module kit-transport-paths\n */\n\nimport { TRANSPORT_PROTOCOL } from '@h-ai/crypto'\n\n/**\n * 客户端与服务端共用的默认公开密钥交换路径。\n * @example 模块内部上下文\n * ```ts\n * const endpoint = new URL(DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH, 'https://app.example.com')\n * void endpoint.pathname\n * ```\n */\nexport const DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH = `/api${TRANSPORT_PROTOCOL.DEFAULT_KEY_EXCHANGE_PATH}`\n\nconst API_PREFIX = '/api/'\nconst ROOT_DATA_PATH = '/__data.json'\nconst DATA_SUFFIX = '/__data.json'\n\nfunction normalizePath(pathname: string): string {\n return pathname.startsWith('/') ? pathname : `/${pathname}`\n}\n\n/**\n * 初始化时校验宿主挂载目录,统一为无末尾斜杠的 URL pathname;请求阶段不重复解析。\n * @param value - 可信宿主的构建目录,域名根目录为空字符串。\n * @returns 已规范化的挂载目录。\n * @throws TypeError 目录包含转义分隔符、点段、查询、片段或控制字符。\n * @internal\n * @example 模块内部上下文\n * ```ts\n * const basePath = normalizeTransportBasePath('/console/')\n * const endpoint = `${basePath}/api/articles`\n * ```\n */\nexport function normalizeTransportBasePath(value = ''): string {\n const invalid = () => new TypeError('Transport basePath must be an absolute mount path without dot segments, query or fragment')\n if (value.includes('//') || /[\\\\?#\\p{Cc} ]/u.test(value) || /%(?:2f|5c|25)/i.test(value))\n throw invalid()\n const basePath = value.replace(/\\/$/, '')\n if (!basePath)\n return ''\n if (!basePath.startsWith('/'))\n throw invalid()\n try {\n const decoded = decodeURIComponent(basePath)\n if (/[\\\\?#\\p{Cc} ]/u.test(decoded) || decoded.split('/').some(segment => segment === '.' || segment === '..'))\n throw invalid()\n return new URL(basePath, 'http://kit.invalid').pathname\n }\n catch {\n throw invalid()\n }\n}\n\n/**\n * 判断路径是否为 SvelteKit 的页面数据端点。\n * @param pathname - URL pathname,不含 query 或 fragment。\n * @returns 是否是页面 __data.json 端点。\n * @example 模块内部上下文\n * ```ts\n * const isData = isSvelteKitDataPath('/articles/__data.json')\n * void isData\n * ```\n */\nexport function isSvelteKitDataPath(pathname: string): boolean {\n return pathname === ROOT_DATA_PATH || pathname.endsWith(DATA_SUFFIX)\n}\n\n/**\n * 判断路径是否属于 transport 保护范围。\n * @param pathname - 待判断的 URL pathname。\n * @param keyExchangePath - 公开密钥交换路径。\n * @param basePath - 已校验的宿主挂载目录;默认空字符串。\n * @returns 是否属于 API、密钥交换或 SvelteKit 数据端点。\n * @example 模块内部上下文\n * ```ts\n * const protectedPath = shouldHandleTransportPath('/api/articles')\n * void protectedPath\n * ```\n */\nexport function shouldHandleTransportPath(\n pathname: string,\n keyExchangePath: string = DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH,\n basePath = '',\n): boolean {\n if (pathname === keyExchangePath)\n return true\n if (basePath && pathname !== basePath && !pathname.startsWith(`${basePath}/`))\n return false\n return pathname.startsWith(`${basePath}${API_PREFIX}`) || isSvelteKitDataPath(pathname)\n}\n\n/**\n * 判断路径是否应排除 transport。\n * @param pathname - 待判断的 URL pathname。\n * @param excludePaths - 按精确路径或子路径前缀排除的列表。\n * @param keyExchangePath - 始终排除加密载荷处理的密钥交换路径。\n * @returns 是否匹配交换端点、排除路径或其子路径。\n * @example 模块内部上下文\n * ```ts\n * const excluded = shouldExcludeTransportPath('/api/health', ['/api/health'], DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH)\n * void excluded\n * ```\n */\nexport function shouldExcludeTransportPath(\n pathname: string,\n excludePaths: readonly string[],\n keyExchangePath: string,\n): boolean {\n if (pathname === keyExchangePath)\n return true\n\n return excludePaths.some((excludePath) => {\n const normalizedPath = normalizePath(excludePath)\n return pathname === normalizedPath || pathname.startsWith(`${normalizedPath}/`)\n })\n}\n\n/**\n * 从相对/绝对 URL 中提取 pathname。\n * @param urlOrPath - 绝对 URL 或相对路径。\n * @param origin - 解析相对路径的基准 origin。\n * @returns 解析后的 pathname;无效 URL 抛出 TypeError。\n * @example 模块内部上下文\n * ```ts\n * const path = resolveTransportPath('https://app.example.com/api/articles?page=1')\n * void path\n * ```\n */\nexport function resolveTransportPath(urlOrPath: string, origin = 'http://localhost'): string {\n return new URL(urlOrPath, origin).pathname\n}\n\n/**\n * 判断浏览器侧请求是否应走 transport。\n *\n * - 仅处理同源请求\n * - 仅保护宿主 basePath 下的 `/api/*` 与 SvelteKit `__data.json`\n * - 命中 `excludePaths` 时透传明文\n * @param url - 待判断的绝对或相对 URL。\n * @param options - 同源基准、密钥交换路径及排除列表。\n * @param options.origin - 当前应用 origin;跨域请求不进入包装。\n * @param options.keyExchangePath - 公开密钥交换路径。\n * @param options.excludePaths - 明文排除路径列表。\n * @param options.basePath - 已校验的宿主挂载目录;默认空字符串。\n * @returns 是否同源、属于保护范围且未被排除。\n * @example 模块内部上下文\n * ```ts\n * const protectedUrl = shouldUseTransportForUrl('/api/articles', { origin: 'https://app.example.com', excludePaths: ['/api/health'] })\n * void protectedUrl\n * ```\n */\nexport function shouldUseTransportForUrl(\n url: string | URL,\n options: {\n origin?: string\n keyExchangePath?: string\n excludePaths?: readonly string[]\n basePath?: string\n } = {},\n): boolean {\n const baseOrigin = options.origin ?? 'http://localhost'\n const requestUrl = url instanceof URL ? url : new URL(url, baseOrigin)\n\n if (options.origin && requestUrl.origin !== options.origin)\n return false\n\n const keyExchangePath = options.keyExchangePath ?? DEFAULT_TRANSPORT_KEY_EXCHANGE_PATH\n if (!shouldHandleTransportPath(requestUrl.pathname, keyExchangePath, options.basePath))\n return false\n\n return !shouldExcludeTransportPath(requestUrl.pathname, options.excludePaths ?? [], keyExchangePath)\n}\n"]}