@h-ai/cli 0.1.0-alpha.66 → 0.1.0-alpha.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.en.md +86 -241
  2. package/README.ja.md +86 -241
  3. package/README.md +86 -241
  4. package/dist/{src-RDQ2EIBT.js → chunk-FI56GONY.js} +32 -2669
  5. package/dist/chunk-FI56GONY.js.map +1 -0
  6. package/dist/chunk-MBPB37FR.js +1348 -0
  7. package/dist/chunk-MBPB37FR.js.map +1 -0
  8. package/dist/{chunk-QYX6V7H2.js → chunk-ZFNBUF77.js} +347 -276
  9. package/dist/chunk-ZFNBUF77.js.map +1 -0
  10. package/dist/cli-config-templates-W2LLPMB6.js +5 -0
  11. package/dist/{cli-config-templates-3XSFIXBP.js.map → cli-config-templates-W2LLPMB6.js.map} +1 -1
  12. package/dist/{cli-skill-templates-TSYEQTCY.js → cli-skill-templates-US5CCAJ4.js} +3 -3
  13. package/dist/{cli-skill-templates-TSYEQTCY.js.map → cli-skill-templates-US5CCAJ4.js.map} +1 -1
  14. package/dist/index.js +1304 -532
  15. package/dist/index.js.map +1 -1
  16. package/dist/metafile-esm.json +1 -0
  17. package/dist/src-DSJJXM2F.js +3849 -0
  18. package/dist/src-DSJJXM2F.js.map +1 -0
  19. package/package.json +9 -8
  20. package/templates/README.md +48 -145
  21. package/templates/apps/admin/messages/ja-JP.json +38 -0
  22. package/templates/apps/admin/src/routes/+layout.svelte.hbs +16 -6
  23. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +3 -3
  24. package/templates/apps/api/.dockerignore.hbs +14 -7
  25. package/templates/apps/api/.gitignore.hbs +7 -0
  26. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +23 -2
  27. package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +2 -0
  28. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +4 -1
  29. package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +33 -8
  30. package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +0 -10
  31. package/templates/apps/api/apps/{{projectName}}-service/config/_serv.yml.hbs +2 -1
  32. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -2
  33. package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +24 -11
  34. package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +8 -1
  35. package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +68 -11
  36. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/index.ts.hbs +10 -2
  37. package/templates/apps/api/e2e/api-service.spec.ts.hbs +2 -2
  38. package/templates/apps/api/hai.build.json.hbs +1 -1
  39. package/templates/apps/api/images/app.Dockerfile.hbs +35 -0
  40. package/templates/apps/api/package.json.hbs +6 -1
  41. package/templates/apps/api/playwright.config.ts.hbs +15 -7
  42. package/templates/apps/fullstack/.dockerignore.hbs +14 -9
  43. package/templates/apps/fullstack/.gitignore.hbs +7 -0
  44. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +24 -6
  45. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +1 -0
  46. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/ja-JP.json.hbs +7 -0
  47. package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
  48. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +7 -1
  49. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +2 -2
  50. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +23 -5
  51. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/ja-JP.json.hbs +7 -0
  52. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +1 -1
  53. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +16 -6
  54. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/ja-JP.json.hbs +12 -0
  55. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +24 -6
  56. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/ja-JP.json.hbs +7 -0
  57. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +2 -2
  58. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +30 -9
  59. package/templates/apps/fullstack/hai.build.json.hbs +2 -2
  60. package/templates/apps/fullstack/images/app.Dockerfile.hbs +36 -0
  61. package/templates/apps/fullstack/images/web.Dockerfile.hbs +34 -0
  62. package/templates/apps/fullstack/package.json.hbs +3 -1
  63. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +23 -2
  64. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +1 -1
  65. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +2 -0
  66. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +3 -0
  67. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +32 -8
  68. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +0 -6
  69. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +8 -0
  70. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +2 -1
  71. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +6 -0
  72. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +9 -5
  73. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +3 -2
  74. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +16 -1
  75. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +7 -3
  76. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +3 -0
  77. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +58 -7
  78. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +13 -3
  79. package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +7 -0
  80. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +40 -14
  81. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +105 -0
  82. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +3 -3
  83. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +6 -6
  84. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +7 -7
  85. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +4 -4
  86. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +8 -8
  87. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +13 -14
  88. package/templates/apps/fullstack/playwright.config.ts.hbs +15 -6
  89. package/templates/apps/h5/messages/ja-JP.json +40 -0
  90. package/templates/apps/h5/src/routes/+layout.svelte.hbs +16 -5
  91. package/templates/apps/mobile-app/messages/ja-JP.json +36 -0
  92. package/templates/apps/mobile-app/src/App.svelte.hbs +15 -5
  93. package/templates/apps/mobile-app/src/lib/api.ts.hbs +173 -14
  94. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +2 -2
  95. package/templates/apps/website/messages/ja-JP.json +32 -0
  96. package/templates/apps/website/src/routes/+layout.svelte.hbs +13 -5
  97. package/templates/apps/website/src/routes/services/+page.svelte.hbs +1 -1
  98. package/templates/base/.dockerignore.hbs +14 -8
  99. package/templates/base/.gitignore.hbs +7 -0
  100. package/templates/base/e2e/app.spec.ts.hbs +23 -8
  101. package/templates/base/hai.build.json.hbs +1 -1
  102. package/templates/base/{Dockerfile.hbs → images/app.Dockerfile.hbs} +19 -17
  103. package/templates/base/package.json.hbs +11 -3
  104. package/templates/base/playwright.config.ts +15 -4
  105. package/templates/base/src/hooks.server.ts.hbs +15 -6
  106. package/templates/base/src/lib/server/init.ts.hbs +139 -30
  107. package/templates/base/vite.config.ts.hbs +5 -3
  108. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +11 -6
  109. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +18 -25
  110. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +4 -0
  111. package/templates/i18n/project.inlang/settings.json +1 -1
  112. package/templates/shared/.gitattributes +6 -0
  113. package/templates/shared/e2e-env.ts +98 -0
  114. package/templates/shared/run-e2e.mjs +51 -12
  115. package/templates/skills/AGENTS.md +7 -3
  116. package/templates/skills/bridges/admin/AGENTS.md +6 -2
  117. package/templates/skills/bridges/api/AGENTS.md +3 -1
  118. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +5 -1
  119. package/templates/skills/bridges/h5/AGENTS.md +6 -2
  120. package/templates/skills/bridges/mobile-app/AGENTS.md +6 -2
  121. package/templates/skills/bridges/website/AGENTS.md +6 -2
  122. package/templates/skills/hai-ai/SKILL.md +8 -2
  123. package/templates/skills/hai-ai/guide.md +134 -60
  124. package/templates/skills/hai-ai/reference.md +51 -11
  125. package/templates/skills/hai-api-client/SKILL.md +15 -160
  126. package/templates/skills/hai-api-client/reference.md +178 -0
  127. package/templates/skills/hai-api-contract/SKILL.md +16 -273
  128. package/templates/skills/hai-api-contract/reference.md +280 -0
  129. package/templates/skills/hai-app-create/SKILL.md +6 -2
  130. package/templates/skills/hai-app-create/development.md +24 -8
  131. package/templates/skills/hai-app-create/reference.md +7 -5
  132. package/templates/skills/hai-app-review/SKILL.md +7 -3
  133. package/templates/skills/hai-app-review/differential.md +34 -0
  134. package/templates/skills/hai-app-tests/SKILL.md +6 -3
  135. package/templates/skills/hai-app-tests/reference.md +5 -5
  136. package/templates/skills/hai-app-tests/validation.md +38 -0
  137. package/templates/skills/hai-audit/SKILL.md +24 -147
  138. package/templates/skills/hai-audit/reference.md +148 -0
  139. package/templates/skills/hai-build/SKILL.md +14 -8
  140. package/templates/skills/hai-build/reference.md +16 -13
  141. package/templates/skills/hai-cache/SKILL.md +20 -181
  142. package/templates/skills/hai-cache/reference.md +229 -0
  143. package/templates/skills/hai-capacitor/SKILL.md +7 -4
  144. package/templates/skills/hai-capacitor/reference.md +15 -9
  145. package/templates/skills/hai-ci/SKILL.md +2 -0
  146. package/templates/skills/hai-core/SKILL.md +7 -3
  147. package/templates/skills/hai-core/reference.md +25 -5
  148. package/templates/skills/hai-crypto/SKILL.md +22 -250
  149. package/templates/skills/hai-crypto/reference.md +310 -0
  150. package/templates/skills/hai-datapipe/SKILL.md +16 -195
  151. package/templates/skills/hai-datapipe/reference.md +204 -0
  152. package/templates/skills/hai-deploy/SKILL.md +24 -54
  153. package/templates/skills/hai-deploy/middleware.md +51 -43
  154. package/templates/skills/hai-framework-sync/SKILL.md +2 -2
  155. package/templates/skills/hai-framework-sync/sync.md +1 -1
  156. package/templates/skills/hai-iam/SKILL.md +25 -11
  157. package/templates/skills/hai-iam/reference.md +181 -154
  158. package/templates/skills/hai-kit/SKILL.md +35 -174
  159. package/templates/skills/hai-kit/reference.md +190 -0
  160. package/templates/skills/hai-payment/SKILL.md +33 -263
  161. package/templates/skills/hai-payment/reference.md +295 -0
  162. package/templates/skills/hai-pr-review/SKILL.md +21 -88
  163. package/templates/skills/hai-reach/SKILL.md +6 -3
  164. package/templates/skills/hai-reach/reference.md +83 -22
  165. package/templates/skills/hai-reldb/SKILL.md +6 -3
  166. package/templates/skills/hai-reldb/reference.md +68 -25
  167. package/templates/skills/hai-scheduler/SKILL.md +18 -195
  168. package/templates/skills/hai-scheduler/reference.md +216 -0
  169. package/templates/skills/hai-serv/SKILL.md +25 -10
  170. package/templates/skills/hai-serv/reference.md +123 -87
  171. package/templates/skills/hai-spec-implement/SKILL.md +5 -1
  172. package/templates/skills/hai-spec-implement/evaluation.md +18 -0
  173. package/templates/skills/hai-spec-implement/handoff.md +47 -0
  174. package/templates/skills/hai-spec-implement/templates.md +5 -0
  175. package/templates/skills/hai-spec-implement/workflow.md +5 -3
  176. package/templates/skills/hai-spec-review/SKILL.md +4 -0
  177. package/templates/skills/hai-storage/SKILL.md +23 -238
  178. package/templates/skills/hai-storage/reference.md +282 -0
  179. package/templates/skills/hai-ui/SKILL.md +17 -3
  180. package/templates/skills/hai-ui/guide.md +3 -3
  181. package/templates/skills/hai-ui/reference.md +26 -11
  182. package/templates/skills/hai-ui-design/SKILL.md +31 -0
  183. package/templates/skills/hai-ui-design/patterns.md +26 -0
  184. package/templates/skills/hai-ui-review/SKILL.md +30 -0
  185. package/templates/skills/hai-ui-review/checklist.md +22 -0
  186. package/templates/skills/hai-vecdb/SKILL.md +14 -10
  187. package/templates/skills/hai-vecdb/reference.md +33 -3
  188. package/dist/chunk-FWN5B54L.js +0 -468
  189. package/dist/chunk-FWN5B54L.js.map +0 -1
  190. package/dist/chunk-QYX6V7H2.js.map +0 -1
  191. package/dist/cli-config-templates-3XSFIXBP.js +0 -5
  192. package/dist/src-RDQ2EIBT.js.map +0 -1
  193. package/templates/apps/api/Dockerfile.hbs +0 -35
  194. package/templates/apps/fullstack/Dockerfile.hbs +0 -57
  195. /package/templates/apps/fullstack/{docker → images/web}/19-runtime-config.envsh.hbs +0 -0
  196. /package/templates/apps/fullstack/{docker → images/web}/nginx.conf.hbs +0 -0
  197. /package/templates/apps/fullstack/{docker → images/web}/runtime-config.js.template.hbs +0 -0
  198. /package/templates/base/{docker → images/web}/nginx.conf.hbs +0 -0
@@ -1,187 +1,48 @@
1
1
  ---
2
2
  name: hai-kit
3
- description: "使用 @h-ai/kit 集成 SvelteKit hooks、守卫、校验、响应及同源客户端传输。"
3
+ description: "在 SvelteKit 中接入 hooks、认证守卫、输入校验、响应和同源加密客户端;不用于独立 serv 服务。"
4
4
  ---
5
5
 
6
6
  # hai-kit
7
7
 
8
+ 限流采用首次成功提交为起点的固定窗口,后续请求不延长 TTL。必须显式传 store;应用先检查共享 Redis 初始化结果,所有节点使用相同 namespace/windowMs/maxRequests。缓存读取/条件提交失败或冲突耗尽返回503,超限429;不会回退 get+set 或本地计数。createMemoryRateLimitStore 仅开发或显式 HAI_E2E/HAI_E2E_MOCK 测试使用,无常驻定时器,丢弃引用即可回收;每次请求最多惰性扫描 64 项,最多保存 10000 个窗口,容量满时对新 key 返回503且不驱逐有效计数,外部 store 生命周期由创建者管理;生产不得设置测试开关。响应重置时间为节点时钟估算,实际窗口由 Redis TTL 决定,须同步时钟。默认键只读取可信 adapter 的 getClientAddress、规范化等价IPv6和IPv4映射地址,不采信原始转发头;代理信任通过部署adapter配置。
9
+
10
+ transport 仅支持 v2:SM2 发送方签名、独立密钥的 Encrypt-then-HMAC、HTTP 上下文/响应状态绑定及共享原子防重放。GET/HEAD、空 POST 与空响应也认证;无降级开关。TLS 信任边界、5 分钟窗口、nonce 持久化与实现示例见 [参考](reference.md)。
11
+
8
12
  ## 能力契约
9
13
 
10
- | 项目 | 契约 |
11
- | --- | --- |
12
- | 能力 | 使用 @h-ai/kit 集成 SvelteKit hooks、守卫、校验、响应及同源客户端传输 |
13
- | 适用场景 | SvelteKit hooks、load 和同源端点集成 |
14
- | 输入 | SvelteKit handle/RequestEvent、schema、guard、transport |
15
- | 输出 | handle、Response、校验值和客户端请求结果 |
16
- | 限制 | 无 init/close;保留 SvelteKit 控制流异常。跨端共享 HTTP contract 用 api-contract + serv,勿复制到 kit。 |
17
-
18
- > `@h-ai/kit` 只负责 SvelteKit 集成:`handle` hook、guard、response、validate、client、auth、crud、A2A。公共跨端 HTTP API 契约统一使用 `@h-ai/api-contract` + `@h-ai/serv`,不要在 kit 中定义业务 API contract。
19
-
20
- ## 使用步骤
21
-
22
- ### 1. 请求管道
14
+ | 项目 | 契约 |
15
+ | -------- | ------------------------------------------------------------------------------------------------------- |
16
+ | 能力 | 使用 @h-ai/kit 集成 SvelteKit hooks、守卫、校验、响应及同源客户端传输 |
17
+ | 适用场景 | SvelteKit hooks、load 和同源端点集成 |
18
+ | 输入 | SvelteKit handle/RequestEvent、schema、guard、transport |
19
+ | 输出 | handle、Response、校验值和客户端请求结果 |
20
+ | 限制 | 无 init/close;保留 SvelteKit 控制流异常。跨端共享 HTTP contract 用 api-contract + serv,勿复制到 kit。 |
21
+
22
+ ## 使用路径
23
+
24
+ 1. 仅在 SvelteKit 集成;先查现有 hooks、配置、守卫与路由,不将其套用于独立 serv 应用。
25
+ 2. 用 createHandle 编排已初始化模块;认证 API 与公开路径复用 kit.auth,客户端复用框架动作。
26
+ 3. 区分返回 HaiResult 的业务操作与抛 Response/redirect/error 的框架控制流,不吞掉控制流。
27
+ 4. 对齐 Cookie/CSRF/transport 与服务端配置,验证匿名、登录、权限拒绝和表单失败。
28
+
29
+ 服务端 transport 使用含受管 serverKeyRing、共享 keyStore 的对象,不再接受单独 true。公开 _kit.yml 只保留路径/开关,不放私钥;浏览器无 ring。请求携带协商 serverKeyId,各节点同 ring + registry,不依赖粘性路由;轮换见 hai-crypto。
30
+
31
+ 传输加密按实际请求/响应 body 判断空正文,不信任 Content-Type/Length;非空明文不能借缺头、chunked 或伪造零长度旁路,实际空流保留无 input POST 行为。
32
+
33
+ transport 与 serv/客户端共享固定 UTF-8 字节预算:握手 JSON 16 KiB、公钥 4 KiB、明文 1 MiB、密文 JSON 2 MiB + 32 KiB。直接有界读取原流,超限/取消停止读取、取消流并释放 reader;请求超限 413、响应超限 500。重建 Request 保留 signal,重建正文移除旧长度/编码头;预算不属于 `_kit.yml` 或环境变量。
34
+
35
+ ## 按需参考
23
36
 
24
- ```ts
25
- import type { Handle } from '@sveltejs/kit'
26
- import { kit } from '@h-ai/kit'
37
+ 按本次操作读取对应小节;以已安装版本的公开类型核验签名,示例中的业务变量由应用提供。
27
38
 
28
- const haiHandle = kit.createHandle({
29
- auth: {
30
- verifyToken: async token => token ? { userId: 'u_1', roles: ['admin'], permissions: ['user:read'] } : null,
31
- loginUrl: '/auth/login',
32
- protectedPaths: ['/admin/*'],
33
- },
34
- rateLimit: { windowMs: 60_000, maxRequests: 100 },
35
- logging: true,
36
- })
39
+ - [使用步骤](reference.md#使用步骤)
40
+ - [核心 API](reference.md#核心-api)
41
+ - [常见模式](reference.md#常见模式)
42
+ - [声明式 CRUD 表单字段](reference.md#声明式-crud-表单字段)
37
43
 
38
- export const handle: Handle = haiHandle
39
- ```
44
+ Node 请求/SSR 必须用 `core.i18n.runWithLocale(locale, callback)`(kit 同名方法)包裹实际异步 resolve;serv 自动建立请求语言上下文。浏览器 setGlobalLocale/createLocaleStore 继续管理应用语言,SSR 的 UI setter/store 不写全局值。显式 MessageOptions.locale 优先;进程默认语言仅在启动时设置。
40
45
 
41
- ### 2. SvelteKit API endpoint
46
+ 认证 Cookie 在 NODE_ENV 或 HAI_CORE_ENV 为 production 时默认启用 Secure,HAI_E2E/HAI_E2E_MOCK 不降低 Cookie 安全;限流生产判断也识别这两个环境标志,测试开关仅放宽共享状态要求。
42
47
 
43
- ```ts
44
- import { kit } from '@h-ai/kit'
45
- import { z } from 'zod'
46
-
47
- const CreateUserSchema = z.object({ name: z.string().min(1) })
48
-
49
- export const POST = kit.handler(async ({ request, locals }) => {
50
- kit.guard.require(locals.session, 'user:create')
51
- const payload = await kit.validate.body(request, CreateUserSchema)
52
- return kit.response.created(payload)
53
- })
54
- ```
55
-
56
- ### 3. 浏览器同源请求
57
-
58
- ```ts
59
- import { kit } from '@h-ai/kit'
60
-
61
- const client = kit.client.create()
62
- export const { apiFetch } = client
63
- ```
64
-
65
- > 同源 endpoint 优先使用 httpOnly Cookie;`auth: true` 只读取 `kit.auth.setBrowserToken()` 写入的页面内存 Token,不会默认读写 localStorage。确需 Bearer Header 时,显式传入 `BrowserTokenStore`,禁止把敏感 Token 存入 localStorage。
66
-
67
- ### 4. 同源传输加密
68
-
69
- kit 不再维护本地传输加密实现;服务端和客户端都统一委托 `@h-ai/crypto` 的 `crypto.transport`。
70
-
71
- ```ts
72
- // hooks.server.ts
73
- import { cache } from '@h-ai/cache'
74
- import { createRedisTransportKeyStore, crypto } from '@h-ai/crypto'
75
- import { kit } from '@h-ai/kit'
76
-
77
- await crypto.init()
78
- await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
79
-
80
- export const handle = kit.createHandle({
81
- auth: {
82
- verifyToken,
83
- protectedPaths: ['/api/*'],
84
- publicPaths: ['/api/_hai/*'],
85
- },
86
- crypto: {
87
- crypto,
88
- transport: {
89
- requireEncryption: true,
90
- keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
91
- },
92
- },
93
- })
94
- ```
95
-
96
- 需要保护会话 Cookie 时配置 `crypto.encryptedCookies`,并通过 `crypto.cookieEncryptionKey` 或 `HAI_KIT_COOKIE_KEY` 提供密钥。缺少密钥会在 `createHandle()` 时失败;加解密错误不会回退到明文 Cookie。
97
-
98
- ```ts
99
- // routes/+layout.svelte
100
- <script lang='ts'>
101
- import { browser } from '$app/environment'
102
- import { crypto } from '@h-ai/crypto'
103
- import { kit } from '@h-ai/kit'
104
- import { appKitConfig } from '$lib/config/kit-config'
105
-
106
- // 一次性安装:内部按 appKitConfig.transport 是否启用决定行为,并预热 crypto
107
- if (browser) {
108
- kit.client.installBrowserTransport(appKitConfig, { crypto })
109
- }
110
- </script>
111
- ```
112
-
113
- ```ts
114
- // lib/utils/api.ts —— 业务层只看到 apiFetch
115
- import { kit } from '@h-ai/kit'
116
-
117
- export const { apiFetch } = kit.client.create()
118
- ```
119
-
120
- 默认协商端点:`/api/_hai/key-exchange`。如 `keyExchangePath` 自定义,浏览器端同步设置 `keyExchangeUrl`。
121
-
122
- 多节点部署时,可在 `kit.createHandle({ crypto: { transport } })` 的运行时对象里直接传 `keyStore`;推荐使用 `@h-ai/crypto` 根入口导出的 `createRedisTransportKeyStore()` / `createReldbTransportKeyStore()`。这类对象依赖不要写进 `_kit.yml`。
123
-
124
- transport 默认保护同源 `/api/*` endpoint 与 SvelteKit `__data.json` 页面数据请求;页面文档、静态资源与 `multipart/form-data` 上传请求保持明文透传。
125
-
126
- 安全策略默认 fail-closed:`requireEncryption: true` 时,受保护路径缺少 `X-Client-Id` 必须返回 400;服务端 transport 管理器不可用、响应体无法加密或超过单次加密上限时返回错误,禁止明文业务响应回退。`requireEncryption: false` 只适合迁移期灰度。
127
-
128
- ### 5. 使用 `_kit.yml` 统一 transport 配置
129
-
130
- `@h-ai/kit` 现在提供 `KitConfigSchema` / `resolveKitConfig()`,适合同一份 `_kit.yml`
131
- 同时驱动 `hooks.server.ts` 与浏览器端 `kit.client.installBrowserTransport()`:
132
-
133
- ```yml
134
- server:
135
- host: 127.0.0.1
136
- port: 3000
137
-
138
- transport:
139
- keyExchangePath: /api/_hai/key-exchange
140
- requireEncryption: true
141
- encryptResponse: true
142
- excludePaths:
143
- - /api/storage
144
- - /api/public
145
- - /api/auth/profile/avatar
146
- maxClients: 10000
147
- ```
148
-
149
- ```ts
150
- import { resolveKitConfig } from '@h-ai/kit'
151
- import { parse } from 'yaml'
152
- import rawKitConfig from '../config/_kit.yml?raw'
153
-
154
- export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
155
- ```
156
-
157
- `resolveKitConfig()` 同时解析 `server`(host/port)与 `transport`;host/port 优先级为 `HOST` / `PORT` 环境变量 > `_kit.yml` 的 `server` > 默认 `127.0.0.1:3000`(与 `@h-ai/serv` 同构)。
158
- `_kit.yml` 只放公开的 server/transport 路径/开关,不放密钥;如自定义 `keyExchangePath`,浏览器端必须同步映射为 `keyExchangeUrl`。
159
-
160
- ## 核心 API
161
-
162
- | API | 用途 |
163
- | --- | --- |
164
- | `kit.createHandle()` | 创建 SvelteKit Handle |
165
- | `kit.sequence()` | 组合多个 Handle |
166
- | `kit.handler()` | API endpoint 错误边界 |
167
- | `kit.guard.require()` | 权限守卫 |
168
- | `kit.response.*` | 统一响应工厂 |
169
- | `kit.validate.*` | Zod 请求校验 |
170
- | `kit.auth.*` | Cookie / Token 辅助 |
171
- | `kit.client.create()` | 浏览器端同源 apiFetch |
172
- | `kit.client.installBrowserTransport(config, { crypto })` | 推荐入口:按解析后的 `_kit.yml` 一键安装浏览器端传输加密 |
173
- | `kit.client.installBrowserTransportFetch()` | 底层入口:直接传 transport 配置安装浏览器全局 fetch 包装 |
174
- | `kit.crud.define()` | 声明式 CRUD 资源 |
175
-
176
- ## 常见模式
177
-
178
- - SvelteKit 应用内同源请求用 `kit.client.create().apiFetch`。
179
- - SvelteKit 应用启用 transport 时,在 `+layout.svelte` 的 `if (browser)` 分支调用一次 `kit.client.installBrowserTransport(appKitConfig, { crypto })`,无需重复连线 `keyExchangeUrl` / `excludePaths`。
180
- - Web/App/小程序跨域访问公共 API 用 `@h-ai/api-client` typed client。
181
- - 传输加密只通过 `crypto.transport` 间接装配,不在 kit 中新增本地加密工厂或鸭子类型。
182
- - 服务端业务模块直接调用模块 API,不通过 HTTP 自环。
183
- - API endpoint 必须用 Zod 校验用户输入,并设置认证/权限边界。
184
-
185
- ## 声明式 CRUD 表单字段
186
-
187
- `kit.crud.define` 的字段支持 `colSpan: 'auto' | 1 | 2`,以及 `validation.message: string | (() => string)`。布局通过 UI 的 `CrudPage.form` 配置;客户端校验用于交互提示,服务端仍使用 Zod 验证和现有权限守卫。UI 公共契约见相邻 [hai-ui skill](../hai-ui/SKILL.md)。
48
+ `kit.auth.logout(cookies, accessToken)` 返回 `Promise<HaiResult<void>>`。无令牌时仅清除 Cookie 并成功;有令牌但未配置认证操作时返回失败。无论服务端结果如何都清除本地 Cookie,调用方仍必须把失败转换为错误响应或提示;仅成功结果代表服务端撤销已经确认。底层控制流异常继续传播。
@@ -0,0 +1,190 @@
1
+ # hai-kit 参考
2
+
3
+ > `@h-ai/kit` 只负责 SvelteKit 集成:`handle` hook、guard、response、validate、client、auth、crud、A2A。公共跨端 HTTP API 契约统一使用 `@h-ai/api-contract` + `@h-ai/serv`,不要在 kit 中定义业务 API contract。
4
+
5
+ 认证协议仅支持 v2:独立随机 SM4-CBC 密钥和 HMAC-SM3 密钥由 SM2 封装,先验签、再验证 MAC,最后解密 CBC。请求由客户端私钥签名,响应由所选服务端版本签名。认证字段包括 version、direction、serverKeyId、clientId、128 位随机 requestId(兼 nonce)、issuedAt、HTTP method、pathname + 原始 search 的 SM3 pathHash,以及响应 status。请求有效期 5 分钟,未来时钟偏差最多 30 秒;共享 registry 原子消费 (clientId, requestId),nonce 至少保留到 issuedAt + 6 分钟以覆盖节点偏差,存储故障拒绝请求。Redis 必须保留有效 nonce,使用 noeviction/可靠持久化策略;各节点时钟须同步。此能力防止同一传输消息重放,业务重试仍需自己的幂等键。
6
+
7
+ 空 POST 也发送空明文的认证封装;GET/HEAD 将封装放在 X-Hai-Transport 头,204/304/HEAD 等无正文响应也使用同名头承载认证封装。其它请求/响应在 JSON 正文承载封装并带 X-Encrypted: true。客户端必须关联原请求上下文和 HTTP status,缺标记、旧格式或认证失败一律 reject;明文接口只能经 excludePaths 显式排除。CORS 须允许并暴露 X-Hai-Transport。握手公钥的真实性依赖 TLS,不替代 IAM 业务授权。
8
+
9
+ ## 使用步骤
10
+
11
+ ### 1. 请求管道
12
+
13
+ ```ts
14
+ import type { Handle } from '@sveltejs/kit'
15
+ import { cache } from '@h-ai/cache'
16
+ import { kit } from '@h-ai/kit'
17
+
18
+ const haiHandle = kit.createHandle({
19
+ auth: {
20
+ verifyToken: async token => token ? { userId: 'u_1', roles: ['admin'], permissions: ['user:read'] } : null,
21
+ loginUrl: '/auth/login',
22
+ protectedPaths: ['/admin/*'],
23
+ },
24
+ rateLimit: { windowMs: 60_000, maxRequests: 100, store: kit.middleware.createCacheRateLimitStore(cache, { namespace: 'app' }) },
25
+ logging: true,
26
+ })
27
+
28
+ export const handle: Handle = haiHandle
29
+ ```
30
+
31
+ 限流采用首次成功提交为起点的固定窗口,后续请求不延长 TTL。必须显式传 store;应用先检查共享 Redis 初始化结果,所有节点使用相同 namespace/windowMs/maxRequests。缓存读取/条件提交失败或冲突耗尽返回503,超限429;不会回退 get+set 或本地计数。createMemoryRateLimitStore 仅开发或显式 HAI_E2E/HAI_E2E_MOCK 测试使用,无常驻定时器,丢弃引用即可回收;每次请求最多惰性扫描 64 项,最多保存 10000 个窗口,容量满时对新 key 返回503且不驱逐有效计数,外部 store 生命周期由创建者管理;生产不得设置测试开关。响应重置时间为节点时钟估算,实际窗口由 Redis TTL 决定,须同步时钟。默认键只读取可信 adapter 的 getClientAddress、规范化等价IPv6和IPv4映射地址,不采信原始转发头;代理信任通过部署adapter配置。
32
+
33
+ ### 2. SvelteKit API endpoint
34
+
35
+ ```ts
36
+ import { kit } from '@h-ai/kit'
37
+ import { z } from 'zod'
38
+
39
+ const CreateUserSchema = z.object({ name: z.string().min(1) })
40
+
41
+ export const POST = kit.handler(async ({ request, locals }) => {
42
+ kit.guard.require(locals.session, 'user:create')
43
+ const payload = await kit.validate.body(request, CreateUserSchema)
44
+ return kit.response.created(payload)
45
+ })
46
+ ```
47
+
48
+ ### 3. 浏览器同源请求
49
+
50
+ ```ts
51
+ import { kit } from '@h-ai/kit'
52
+
53
+ const client = kit.client.create()
54
+ export const { apiFetch } = client
55
+ ```
56
+
57
+ > 同源 endpoint 使用 httpOnly Cookie;`auth: true` 只读取 `kit.auth.setBrowserToken()` 写入的页面内存 Token。自定义 `BrowserTokenStore` 也须使用内存或平台安全存储,禁止把敏感凭据持久化到 Web Storage。
58
+
59
+ ### 4. 同源传输加密
60
+
61
+ kit 不再维护本地传输加密实现;服务端和客户端都统一委托 `@h-ai/crypto` 的 `crypto.transport`。
62
+
63
+ ```ts
64
+ // hooks.server.ts
65
+ import { cache } from '@h-ai/cache'
66
+ import { createRedisTransportKeyStore, crypto, parseTransportServerKeyRing } from '@h-ai/crypto'
67
+ import { kit } from '@h-ai/kit'
68
+
69
+ await crypto.init()
70
+ const ring = parseTransportServerKeyRing(process.env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING)
71
+ if (!ring.success)
72
+ throw new Error(ring.error.message)
73
+ const serverKeyRing = ring.data
74
+ await cache.init({ type: 'redis', host: '127.0.0.1', port: 6379 })
75
+
76
+ export const handle = kit.createHandle({
77
+ auth: {
78
+ verifyToken,
79
+ protectedPaths: ['/api/*'],
80
+ publicPaths: ['/api/_hai/*'],
81
+ },
82
+ crypto: {
83
+ crypto,
84
+ transport: {
85
+ serverKeyRing,
86
+ keyStore: createRedisTransportKeyStore({ cache, ttlSeconds: 3600 }),
87
+ },
88
+ },
89
+ })
90
+ ```
91
+
92
+ 需要保护会话 Cookie 时配置 `crypto.encryptedCookies`,并通过 `crypto.cookieEncryptionKey` 或 `HAI_KIT_COOKIE_KEY` 提供密钥。缺少密钥会在 `createHandle()` 时失败;加解密错误不会回退到明文 Cookie。
93
+
94
+ ```svelte
95
+ <!-- src/routes/+layout.svelte -->
96
+ <script lang='ts'>
97
+ import { browser } from '$app/environment'
98
+ import { appKitConfig } from '$lib/config/kit-config'
99
+ import { crypto } from '@h-ai/crypto'
100
+ import { kit } from '@h-ai/kit'
101
+
102
+ // 一次性安装:内部按 appKitConfig.transport 是否启用决定行为,并预热 crypto
103
+ if (browser) {
104
+ kit.client.installBrowserTransport(appKitConfig, { crypto })
105
+ }
106
+ </script>
107
+ ```
108
+
109
+ ```ts
110
+ // lib/utils/api.ts —— 业务层只看到 apiFetch
111
+ import { kit } from '@h-ai/kit'
112
+
113
+ export const { apiFetch } = kit.client.create()
114
+ ```
115
+
116
+ 默认协商端点:`/api/_hai/key-exchange`。如 `keyExchangePath` 自定义,浏览器端同步设置 `keyExchangeUrl`。
117
+
118
+ 启用 transport 使用 `{ serverKeyRing, keyStore, ...公开路径配置 }`,两项必填,不再接受单独的 true。serverKeyRing 通过服务端 Secret/私有 `HAI_CRYPTO_TRANSPORT_SERVERKEYRING` 安全解析,不放 `_kit.yml`、PUBLIC_/VITE_ 或日志;浏览器仅需公开 transport 配置和 crypto。各节点使用同一版本化 ring 与共享 Redis/数据库 registry;仅共享客户端公钥不够。请求带协商 serverKeyId,无需 sticky session;轮换先分发新旧 ring,再切 activeKeyId 重建 manager,删除旧 ID 后客户端 destroy 并重协商。开发/测试须显式选择内存 registry;原公开 maxClients 已删除。完整轮换步骤见 hai-crypto。
119
+
120
+ transport 默认保护同源 `/api/*` endpoint 与 SvelteKit `__data.json` 页面数据请求;页面文档、静态资源与 `multipart/form-data` 上传请求保持明文透传。
121
+
122
+ 受保护路径不允许协议降级;缺少认证、管理器不可用、响应加密失败均拒绝。明文接口仅通过 excludePaths 显式排除。
123
+
124
+ 空 POST 也发送空明文的认证封装;GET/HEAD 将封装放在 X-Hai-Transport 头,204/304/HEAD 等无正文响应也使用同名头承载认证封装。其它请求/响应在 JSON 正文承载封装并带 X-Encrypted: true。客户端必须关联原请求上下文和 HTTP status,缺标记、旧格式或认证失败一律 reject;明文接口只能经 excludePaths 显式排除。CORS 须允许并暴露 X-Hai-Transport。握手公钥的真实性依赖 TLS,不替代 IAM 业务授权。
125
+
126
+ 与 serv/客户端共享 `@h-ai/crypto` 根入口的 `TRANSPORT_BODY_LIMITS` / `readTransportBody`:握手 JSON 16 KiB、公钥 4 KiB、明文 1 MiB、密文 JSON 2 MiB + 32 KiB,按 UTF-8 字节计数。原始流逐块检查,超限/取消停止并取消流、释放 reader,不 clone/tee 后完整缓冲。请求超限返回 413,响应超限返回 500,无效公钥返回 400;重建 Request 保留 signal,重建正文清除旧 Content-Length/Content-Encoding。固定协议预算不写入 `_kit.yml` 或环境变量。
127
+
128
+ ### 5. 使用 `_kit.yml` 统一 transport 配置
129
+
130
+ `@h-ai/kit` 现在提供 `KitConfigSchema` / `resolveKitConfig()`,适合同一份 `_kit.yml`
131
+ 同时驱动 `hooks.server.ts` 与浏览器端 `kit.client.installBrowserTransport()`:
132
+
133
+ ```yml
134
+ server:
135
+ host: 127.0.0.1
136
+ port: 3000
137
+
138
+ transport:
139
+ keyExchangePath: /api/_hai/key-exchange
140
+ excludePaths:
141
+ - /api/storage
142
+ - /api/public
143
+ - /api/auth/profile/avatar
144
+ ```
145
+
146
+ ```ts
147
+ import { resolveKitConfig } from '@h-ai/kit'
148
+ import { parse } from 'yaml'
149
+ import rawKitConfig from '../config/_kit.yml?raw'
150
+
151
+ export const appKitConfig = resolveKitConfig(parse(rawKitConfig) ?? {})
152
+ ```
153
+
154
+ `resolveKitConfig()` 同时解析 `server`(host/port)与 `transport`;host/port 优先级为 `HOST` / `PORT` 环境变量 > `_kit.yml` 的 `server` > 默认 `127.0.0.1:3000`(与 `@h-ai/serv` 同构)。
155
+ `_kit.yml` 只放公开的 server/transport 路径/开关,不放密钥;如自定义 `keyExchangePath`,浏览器端必须同步映射为 `keyExchangeUrl`。
156
+
157
+ ## 核心 API
158
+
159
+ | API | 用途 |
160
+ | -------------------------------------------------------- | -------------------------------------------------------- |
161
+ | `kit.createHandle()` | 创建 SvelteKit Handle |
162
+ | `kit.sequence()` | 组合多个 Handle |
163
+ | `kit.handler()` | API endpoint 错误边界 |
164
+ | `kit.guard.require()` | 权限守卫 |
165
+ | `kit.response.*` | 统一响应工厂 |
166
+ | `kit.validate.*` | Zod 请求校验 |
167
+ | `kit.auth.*` | Cookie / Token 辅助 |
168
+ | `kit.client.create()` | 浏览器端同源 apiFetch |
169
+ | `kit.client.installBrowserTransport(config, { crypto })` | 推荐入口:按解析后的 `_kit.yml` 一键安装浏览器端传输加密 |
170
+ | `kit.client.installBrowserTransportFetch()` | 底层入口:直接传 transport 配置安装浏览器全局 fetch 包装 |
171
+ | `kit.crud.define()` | 声明式 CRUD 资源 |
172
+
173
+ ## 常见模式
174
+
175
+ - SvelteKit 应用内同源请求用 `kit.client.create().apiFetch`。
176
+ - SvelteKit 应用启用 transport 时,在 `+layout.svelte` 的 `if (browser)` 分支调用一次 `kit.client.installBrowserTransport(appKitConfig, { crypto })`,无需重复连线 `keyExchangeUrl` / `excludePaths`。
177
+ - Web/App/小程序跨域访问公共 API 用 `@h-ai/api-client` typed client。
178
+ - 传输加密只通过 `crypto.transport` 间接装配,不在 kit 中新增本地加密工厂或鸭子类型。
179
+ - 服务端业务模块直接调用模块 API,不通过 HTTP 自环。
180
+ - API endpoint 必须用 Zod 校验用户输入,并设置认证/权限边界。
181
+
182
+ ## 声明式 CRUD 表单字段
183
+
184
+ `kit.crud.define` 的字段支持 `colSpan: 'auto' | 1 | 2`,以及 `validation.message: string | (() => string)`。布局通过 UI 的 `CrudPage.form` 配置;客户端校验用于交互提示,服务端仍使用 Zod 验证和现有权限守卫。UI 公共契约见相邻 [hai-ui skill](../hai-ui/SKILL.md)。
185
+
186
+ Node 请求/SSR 必须用 `core.i18n.runWithLocale(locale, callback)`(kit 同名方法)包裹实际异步 resolve;serv 自动建立请求语言上下文。浏览器 setGlobalLocale/createLocaleStore 继续管理应用语言,SSR 的 UI setter/store 不写全局值。显式 MessageOptions.locale 优先;进程默认语言仅在启动时设置。
187
+
188
+ 认证 Cookie 在 NODE_ENV 或 HAI_CORE_ENV 为 production 时默认启用 Secure,HAI_E2E/HAI_E2E_MOCK 不降低 Cookie 安全;限流生产判断也识别这两个环境标志,测试开关仅放宽共享状态要求。
189
+
190
+ `kit.auth.logout(cookies, accessToken)` 返回 `Promise<HaiResult<void>>`。无令牌时仅清除 Cookie 并成功;有令牌但未配置认证操作时返回失败。无论服务端结果如何都清除本地 Cookie,调用方仍必须把失败转换为错误响应或提示;仅成功结果代表服务端撤销已经确认。底层控制流异常继续传播。