@h-ai/cli 0.1.0-alpha.65 → 0.1.0-alpha.67

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 (141) hide show
  1. package/README.en.md +66 -251
  2. package/README.ja.md +67 -252
  3. package/README.md +66 -251
  4. package/dist/{chunk-47V5OT22.js → chunk-7DSURTJ4.js} +32 -115
  5. package/dist/chunk-7DSURTJ4.js.map +1 -0
  6. package/dist/{chunk-IPG3QNYK.js → chunk-AOQ4N657.js} +212 -8
  7. package/dist/chunk-AOQ4N657.js.map +1 -0
  8. package/dist/cli-config-templates-6AHNUGBN.js +5 -0
  9. package/dist/{cli-config-templates-SJ2MBIR7.js.map → cli-config-templates-6AHNUGBN.js.map} +1 -1
  10. package/dist/{cli-skill-templates-A5VIR5J6.js → cli-skill-templates-FC3QRKDO.js} +3 -3
  11. package/dist/{cli-skill-templates-A5VIR5J6.js.map → cli-skill-templates-FC3QRKDO.js.map} +1 -1
  12. package/dist/index.js +644 -391
  13. package/dist/index.js.map +1 -1
  14. package/dist/{src-6PPBKQ6Q.js → src-2V6VP4I5.js} +972 -520
  15. package/dist/src-2V6VP4I5.js.map +1 -0
  16. package/package.json +8 -8
  17. package/templates/README.md +48 -145
  18. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +1 -1
  19. package/templates/apps/api/.dockerignore.hbs +18 -12
  20. package/templates/apps/api/.gitignore.hbs +9 -1
  21. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +23 -2
  22. package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +28 -7
  23. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -3
  24. package/templates/apps/api/hai.build.json.hbs +1 -0
  25. package/templates/apps/api/images/app.Dockerfile.hbs +35 -0
  26. package/templates/apps/api/package.json.hbs +10 -8
  27. package/templates/apps/fullstack/.dockerignore.hbs +18 -14
  28. package/templates/apps/fullstack/.gitignore.hbs +9 -1
  29. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +23 -8
  30. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +1 -0
  31. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +0 -2
  32. package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
  33. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +3 -3
  34. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +25 -10
  35. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +2 -3
  36. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +73 -2
  37. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +2 -2
  38. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +2 -2
  39. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +16 -6
  40. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +24 -10
  41. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +0 -2
  42. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +3 -3
  43. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +12 -1
  44. package/templates/apps/fullstack/hai.build.json.hbs +7 -0
  45. package/templates/apps/fullstack/images/app.Dockerfile.hbs +36 -0
  46. package/templates/apps/fullstack/images/web.Dockerfile.hbs +34 -0
  47. package/templates/apps/fullstack/package.json.hbs +7 -12
  48. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +23 -2
  49. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +28 -7
  50. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +0 -1
  51. package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +7 -0
  52. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +33 -12
  53. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +2 -2
  54. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +3 -3
  55. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +2 -2
  56. package/templates/apps/h5/src/routes/+layout.svelte.hbs +2 -2
  57. package/templates/apps/mobile-app/index.html.hbs +1 -0
  58. package/templates/apps/mobile-app/public/runtime-config.js +1 -0
  59. package/templates/apps/mobile-app/src/App.svelte.hbs +2 -2
  60. package/templates/apps/mobile-app/src/lib/api.ts.hbs +2 -1
  61. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +3 -2
  62. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +2 -2
  63. package/templates/apps/website/src/routes/+layout.svelte.hbs +3 -3
  64. package/templates/apps/website/src/routes/services/+page.svelte.hbs +1 -1
  65. package/templates/base/.dockerignore.hbs +18 -13
  66. package/templates/base/.gitignore.hbs +9 -1
  67. package/templates/base/e2e/app.spec.ts.hbs +10 -0
  68. package/templates/base/hai.build.json.hbs +1 -0
  69. package/templates/base/images/app.Dockerfile.hbs +64 -0
  70. package/templates/base/{docker → images/web}/nginx.conf.hbs +6 -0
  71. package/templates/base/package.json.hbs +20 -19
  72. package/templates/base/svelte.config.js.hbs +2 -0
  73. package/templates/base/vite.config.ts.hbs +9 -3
  74. package/templates/shared/.gitattributes +11 -0
  75. package/templates/shared/container-runtime-config.sh +30 -0
  76. package/templates/shared/run-e2e.mjs +65 -0
  77. package/templates/shared/vite-runtime-config.ts +54 -0
  78. package/templates/skills/AGENTS.md +3 -3
  79. package/templates/skills/bridges/admin/AGENTS.md +1 -1
  80. package/templates/skills/bridges/api/AGENTS.md +1 -1
  81. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +1 -1
  82. package/templates/skills/bridges/h5/AGENTS.md +1 -1
  83. package/templates/skills/bridges/mobile-app/AGENTS.md +1 -1
  84. package/templates/skills/bridges/website/AGENTS.md +1 -1
  85. package/templates/skills/hai-api-client/SKILL.md +14 -161
  86. package/templates/skills/hai-api-client/reference.md +166 -0
  87. package/templates/skills/hai-api-contract/SKILL.md +15 -273
  88. package/templates/skills/hai-api-contract/reference.md +278 -0
  89. package/templates/skills/hai-app-create/SKILL.md +2 -2
  90. package/templates/skills/hai-app-create/development.md +6 -4
  91. package/templates/skills/hai-app-create/reference.md +5 -4
  92. package/templates/skills/hai-app-review/SKILL.md +1 -1
  93. package/templates/skills/hai-app-tests/SKILL.md +4 -3
  94. package/templates/skills/hai-app-tests/reference.md +2 -2
  95. package/templates/skills/hai-app-tests/validation.md +31 -0
  96. package/templates/skills/hai-audit/SKILL.md +17 -142
  97. package/templates/skills/hai-audit/reference.md +145 -0
  98. package/templates/skills/hai-build/SKILL.md +24 -3
  99. package/templates/skills/hai-build/reference.md +10 -9
  100. package/templates/skills/hai-cache/SKILL.md +15 -182
  101. package/templates/skills/hai-cache/reference.md +187 -0
  102. package/templates/skills/hai-capacitor/SKILL.md +4 -3
  103. package/templates/skills/hai-capacitor/reference.md +6 -4
  104. package/templates/skills/hai-ci/SKILL.md +2 -0
  105. package/templates/skills/hai-core/SKILL.md +3 -3
  106. package/templates/skills/hai-crypto/SKILL.md +16 -252
  107. package/templates/skills/hai-crypto/reference.md +256 -0
  108. package/templates/skills/hai-datapipe/SKILL.md +15 -196
  109. package/templates/skills/hai-datapipe/reference.md +202 -0
  110. package/templates/skills/hai-deploy/SKILL.md +28 -271
  111. package/templates/skills/hai-deploy/middleware.md +6 -18
  112. package/templates/skills/hai-framework-sync/SKILL.md +2 -2
  113. package/templates/skills/hai-framework-sync/sync.md +1 -1
  114. package/templates/skills/hai-iam/SKILL.md +1 -3
  115. package/templates/skills/hai-kit/SKILL.md +12 -167
  116. package/templates/skills/hai-kit/reference.md +172 -0
  117. package/templates/skills/hai-payment/SKILL.md +19 -251
  118. package/templates/skills/hai-payment/reference.md +256 -0
  119. package/templates/skills/hai-pr-review/SKILL.md +4 -4
  120. package/templates/skills/hai-reach/SKILL.md +2 -2
  121. package/templates/skills/hai-reldb/SKILL.md +1 -1
  122. package/templates/skills/hai-scheduler/SKILL.md +15 -195
  123. package/templates/skills/hai-scheduler/reference.md +202 -0
  124. package/templates/skills/hai-serv/SKILL.md +2 -2
  125. package/templates/skills/hai-spec-implement/SKILL.md +1 -1
  126. package/templates/skills/hai-spec-implement/workflow.md +3 -3
  127. package/templates/skills/hai-storage/SKILL.md +17 -238
  128. package/templates/skills/hai-storage/reference.md +243 -0
  129. package/templates/skills/hai-ui/SKILL.md +1 -1
  130. package/templates/skills/hai-ui/reference.md +11 -5
  131. package/templates/skills/hai-vecdb/SKILL.md +2 -2
  132. package/dist/chunk-47V5OT22.js.map +0 -1
  133. package/dist/chunk-IPG3QNYK.js.map +0 -1
  134. package/dist/cli-config-templates-SJ2MBIR7.js +0 -5
  135. package/dist/src-6PPBKQ6Q.js.map +0 -1
  136. package/templates/apps/api/Dockerfile.hbs +0 -48
  137. package/templates/apps/fullstack/Dockerfile.hbs +0 -69
  138. package/templates/base/Dockerfile.hbs +0 -79
  139. /package/templates/apps/fullstack/{docker → images/web}/19-runtime-config.envsh.hbs +0 -0
  140. /package/templates/apps/fullstack/{docker → images/web}/nginx.conf.hbs +0 -0
  141. /package/templates/apps/fullstack/{docker → images/web}/runtime-config.js.template.hbs +0 -0
@@ -1,292 +1,49 @@
1
1
  ---
2
2
  name: hai-deploy
3
- description: "使用 @h-ai/deploy 部署应用:Vercel 云平台或 docker-ssh 容器化部署到任意 Linux 主机,并按需开通/生成基础设施。"
3
+ description: "构建并发布或交付已有镜像:完整离线包、按服务更新、SSH 与跨平台手工部署、失败恢复;也支持 Vercel prebuilt。"
4
4
  ---
5
5
 
6
6
  # hai-deploy
7
7
 
8
8
  ## 能力契约
9
9
 
10
- `hai deploy` 在模块/配置缺失或凭证、扫描、初始化、部署、关闭失败时返回非零退出码。自动化流程必须以退出码判断成功,不要只判断命令是否完成或是否输出日志。
11
-
12
10
  | 项目 | 契约 |
13
11
  | --- | --- |
14
- | 能力 | 使用 @h-ai/deploy 部署应用:Vercel 云平台或 docker-ssh 容器化部署到任意 Linux 主机 |
15
- | 适用场景 | 部署目标配置、云资源开通、SSH 主机容器部署或部署故障排查 |
16
- | 输入 | 项目构建产物、部署目标(vercel / docker-ssh)、环境配置与凭据引用 |
17
- | 输出 | 部署/资源操作结果和可验证的目标状态(含访问 URL 与健康检查) |
18
- | 限制 | 核对实际 provider 与应用运行时;开通收费资源、发布或删除必须在用户授权范围内,凭据不写入仓库。 |
19
-
20
- > `@h-ai/deploy` 提供两种部署方式:
21
- > 1. **vercel** — 将 SvelteKit(adapter-vercel)应用部署到 Vercel,并自动开通 Neon/Upstash/R2/Resend/阿里云等云基础设施;
22
- > 2. **docker-ssh** — 将原生 fullstack API 或 SvelteKit(adapter-node)应用容器化后经 SSH 部署到任意具备 docker/podman + compose 的 Linux 主机,按所选功能自动生成 compose sidecar。
23
-
24
- ## 运行环境
25
-
26
- > ⚠️ **Node.js CLI / 服务端模块。** 通过 `hai deploy` CLI 命令或在 Node.js 脚本中使用。
27
- > docker-ssh 方式要求本地安装 docker 或 podman(`auto` 优先 podman)。
28
-
29
- 当前 Node 要求 `^22.22.2 || ^24.15.0 || >=26.0.0`,生成工程固定 pnpm 12.11.2;Node 20 / pnpm 9.5.0 不受支持。Windows 必须有已启动、能构建目标 Linux 架构的容器引擎,不能把仅安装客户端或远程有 Docker 当作本地可构建。
30
-
31
- ## 适用场景
32
-
33
- - 一键部署 SvelteKit 应用到 Vercel
34
- - 容器化后经 SSH 部署到自有服务器 / 云主机 / 内网虚拟机(docker-ssh)
35
- - 自动开通 PostgreSQL、Redis、S3 等云服务,或按功能生成自建 sidecar
36
- - 管理部署凭证(~/.hai/credentials.yml)
37
- - 扫描应用依赖,自动检测所需服务
38
- - CLI 部署流程(`hai deploy`)
39
-
40
- ## 使用步骤
12
+ | 能力 | 配置环境与中间件,交付完整离线包或发布选中服务 |
13
+ | 适用场景 | 一体化构建发布、独立打包、隔离网络手工部署、增量更新与故障排查 |
14
+ | 输入 | package.json、hai.build.json、运行依赖锁文件、目标环境、已有制品或明确构建要求 |
15
+ | 输出 | 带校验和的 tar、跨平台部署入口与分步结果,或经过 HTTP 检查的部署结果 |
16
+ | 限制 | SDK 只消费产物;CLI --build 显式先构建。首次安装必须完整交付,packaged 不代表服务器 ready。云资源需要外网。 |
41
17
 
42
- 部署前按 [环境与中间件向导](middleware.md) 先选择环境并检查对应文件,再逐项选择默认配置、自定义连接或保持不变。用户确认配置已完备时,可选择直接部署或传 `--skip-middleware` 跳过全部中间件处理。SSH 地址、端口、密钥路径及平台 Token 首次填写后仅保存 `.env.local`,后续自动复用。该文档列出模块依赖、后端、连接字段、云开通边界和启动验证要求。
18
+ ## 操作流程
43
19
 
44
- ### 1. 配置
20
+ 1. 读取项目 scripts、images/ 中的 Dockerfile、hai.build.json 与服务目录配置。创建默认带开发期部署工具;用户明确 --no-deploy 时不生成部署入口。构建细节见 [hai-build](../hai-build/SKILL.md)。
21
+ 2. 选择环境,验证 .env.<mode> 存在,再处理 SSH 与必要中间件。使用人类可读字段说明,复用有效配置;私有参数写 .env.local,私钥仅引用路径。环境规则见 [middleware.md](middleware.md)。
22
+ 3. 先校验所选制品、版本、服务和 SHA-256。--build 只构建所选应用镜像;不带它时缺产物明确失败,不隐式补构建。格式版本 3 记录 appVersion、buildId、partial、hasWeb、镜像归档及显式配置的 appContainerPort/webContainerPort;部分构建也保留未选镜像端口,缺省使用部署默认值。同一应用版本可重建,镜像引用区分实际内容;禁止 latest 与无版本镜像。
23
+ 4. 完整包自动导出实际自建中间件镜像并去重;只更新 Web 不重新打包 API/中间件。打包机需容器引擎导出中间件,服务器仅 load,禁止 pull/build。外部连接及云开通不能伪称为离线自包含服务。
24
+ 5. --services 使用目标服务器最后成功状态为基线,检查端口/拓扑及未选依赖,保留未选配置、凭据、网络和卷。脚本先按项目/服务标签仅删除选中旧容器(保留卷),再 up -d --no-deps --no-build --pull never --no-recreate 创建新容器并保留其他容器,避免 Compose Provider 连带重建反向依赖,禁止整个项目 down。storage-init 是一次性创建 S3 桶,涉及存储初始化才运行。仅更新 storage 也需含 app 镜像的制品运行初始化;最近为 web-only 时,用 --artifact-dir 选择原完整制品,或先 pnpm build --target docker --images app,不会更新运行中的 app 服务。
25
+ 6. --bundle-only 不连接 SSH,同时输出 tar 和 -deploy/ 操作目录。Windows deploy.ps1、Linux/macOS deploy.sh 上传并执行包内 apply.sh;完全隔离时搬运 tar,独立目录解包执行 sh apply.sh,可传部署根目录。脚本不依赖源码、Node 或 pnpm。
26
+ 7. 工具预检、基线、上传、校验、镜像导入、服务更新和 HTTP 检查分别报告。失败返回非零退出码,结果文件保留失败阶段;只有检查成功才更新服务器 current。已有部署失败尝试恢复所选服务的旧容器和配置;数据卷保留,已写业务数据不回退,恢复后仍需验证健康。禁止把本地打包记录当服务器成功状态。
45
27
 
46
- ```yaml
47
- # config/_deploy.yml
48
- provider:
49
- type: vercel
50
- token: ${HAI_DEPLOY_PROVIDER_TOKEN}
28
+ ## CLI
51
29
 
52
- services:
53
- db:
54
- provisioner: neon
55
- apiKey: ${HAI_DEPLOY_SERVICES_DB_APIKEY}
56
- cache:
57
- provisioner: upstash
58
- email: ${HAI_DEPLOY_SERVICES_CACHE_EMAIL}
59
- apiKey: ${HAI_DEPLOY_SERVICES_CACHE_APIKEY}
60
- storage:
61
- provisioner: cloudflare-r2
62
- accountId: ${HAI_DEPLOY_SERVICES_STORAGE_ACCOUNTID}
63
- apiToken: ${HAI_DEPLOY_SERVICES_STORAGE_APITOKEN}
64
- accessKeyId: ${HAI_DEPLOY_SERVICES_STORAGE_ACCESSKEYID}
65
- secretAccessKey: ${HAI_DEPLOY_SERVICES_STORAGE_SECRETACCESSKEY}
66
- email:
67
- provisioner: resend
68
- apiKey: ${HAI_DEPLOY_SERVICES_EMAIL_APIKEY}
69
- from: ${HAI_DEPLOY_SERVICES_EMAIL_FROM}
70
- sms:
71
- provisioner: aliyun
72
- accessKeyId: ${HAI_DEPLOY_SERVICES_SMS_ACCESSKEYID}
73
- accessKeySecret: ${HAI_DEPLOY_SERVICES_SMS_ACCESSKEYSECRET}
74
- signName: ${HAI_DEPLOY_SERVICES_SMS_SIGNNAME}
30
+ ```sh
31
+ pnpm run deploy --env prod --build
32
+ pnpm build --target docker
33
+ pnpm run deploy --env prod --artifact-dir .hai/build/docker/<buildId>
34
+ pnpm run deploy --env prod --bundle-only --output release-prod.tar
35
+ pnpm build --target docker --images web
36
+ pnpm run deploy --env prod --services web
75
37
  ```
76
38
 
77
- 这些凭证名由 `deploy.credentials` 管理,属于显式特殊映射;若同时设置
78
- `HAI_DEPLOY_PROVIDER_TOKEN` 等约定变量,约定变量仍拥有最高优先级。
79
-
80
- #### docker-ssh 配置
81
-
82
- 将上面的 `provider` 替换为 docker-ssh(远程主机需 SSH + docker/podman + compose):
83
-
84
- ```yaml
85
- # config/_deploy.yml
86
- provider:
87
- type: docker-ssh
88
- ssh:
89
- host: ${HAI_DEPLOY_PROVIDER_SSH_HOST}
90
- port: 22
91
- username: deploy
92
- identityFile: ${HAI_DEPLOY_PROVIDER_SSH_IDENTITYFILE} # 私钥文件路径,省略则用 ssh-agent
93
- remote:
94
- baseDir: /opt/hai/apps
95
- runtime: auto # auto 优先 podman,其次 docker
96
- expose:
97
- type: port
98
- containerPort: 3000
99
- hostPort: 18080 # 访问地址 http://<host>:18080
100
-
101
- container:
102
- runtime: auto # 本地构建运行时,可选
103
-
104
- services:
105
- # 启用的服务会被加入远程 compose sidecar(postgres/redis/rustfs 或 minio)
106
- # 若配置了云 Provisioner(如 neon),则优先用云资源,不再自建 sidecar
107
- db:
108
- provisioner: neon
109
- apiKey: ${HAI_DEPLOY_SERVICES_DB_APIKEY}
110
- ```
111
-
112
- docker-ssh 要点:
113
-
114
- - 应用镜像优先使用工程自带的 Dockerfile;SvelteKit 需要 adapter-node,原生 fullstack 服务自动生成以 `dist/index.js` 启动的镜像。
115
- - compose 按 `deploy.scan()` 识别的服务**及其后端类型**生成匹配 sidecar 并注入 `HAI_*` 覆盖变量:
116
- - `db`:`postgresql`→postgres、`mysql`→mysql、`sqlite`→数据卷(无 sidecar)→ `HAI_DB`
117
- - `cache`:`redis`→redis → `HAI_CACHE`;`storage`:`s3`→RustFS/MinIO(container.s3Engine) → `HAI_STORAGE`
118
- - `vecdb`:`qdrant`/`pgvector`/`chroma`→对应 sidecar、`lancedb`→数据卷 → `HAI_VECDB`
119
- - 若同一服务已配置云 Provisioner(如 neon 提供 `HAI_DB`),优先用云资源,不再自建 sidecar
120
- - sidecar 密码写被忽略的本机私有配置及远程 `.env.runtime`(权限 600),不入公共环境文件或 `compose.yml`
121
- - `identityFile` 是私钥**路径**(非私钥内容);禁止把私钥内容写进 `_deploy.yml`
122
-
123
- ### 2. 初始化与关闭
124
-
125
- ```typescript
126
- import { deploy } from '@h-ai/deploy'
127
-
128
- deploy.credentials.load()
129
-
130
- await deploy.init({
131
- provider: { type: 'vercel', token: 'vel_xxx' },
132
- services: {
133
- db: { provisioner: 'neon', apiKey: 'neon_xxx' },
134
- },
135
- })
136
-
137
- // 使用后关闭
138
- await deploy.close()
139
- ```
140
-
141
- ### 3. 扫描应用
142
-
143
- ```typescript
144
- const scanResult = await deploy.scan('./apps/my-app', { environment: 'test' })
145
- if (scanResult.success) {
146
- const { appName, isSvelteKit, requiredServices } = scanResult.data
147
- }
148
- ```
149
-
150
- ### 4. 开通基础设施
151
-
152
- ```typescript
153
- const provResults = await deploy.provisionAll('my-project')
154
- if (provResults.success) {
155
- for (const prov of provResults.data) {
156
- // prov.envVars 包含需要注入的环境变量
157
- }
158
- }
159
- ```
160
-
161
- ### 5. 完整部署
162
-
163
- ```typescript
164
- const result = await deploy.deployApp('./apps/my-app', {
165
- projectName: 'my-project',
166
- skipProvision: false,
167
- skipBuild: false,
168
- })
169
- if (result.success) {
170
- // result.data.url — 部署地址
171
- // result.data.deploymentId — 部署 ID
172
- // result.data.envVarsSet — 已设置的环境变量列表
173
- }
174
- ```
39
+ 使用 pnpm run deploy,避免与 pnpm 自带 deploy 混淆。fullstack 指向 packages/<项目>-serv,API workspace 指向 apps/<项目>-service;这是扫描入口,不是镜像选择。--services 负责选择;--skip-middleware 只跳过配置及开通。--yes 复用有效配置,缺值时不盲目继续。
175
40
 
176
- ## 核心 API
41
+ ## SDK
177
42
 
178
- | 方法 | 签名 | 说明 |
179
- | ---------------------- | -------------------------------------------------------------------------- | ------------ |
180
- | `deploy.credentials.load` | `() => HaiResult<string[]>` | 加载凭证到 `process.env` |
181
- | `deploy.credentials.save` | `(key: string, value: string) => HaiResult<void>` | 保存单个凭证 |
182
- | `deploy.credentials.saveAll` | `(entries: Record<string, string>) => HaiResult<void>` | 批量保存凭证 |
183
- | `deploy.credentials.getPath` | `() => string` | 获取凭证文件路径 |
184
- | `deploy.init` | `(config: DeployConfigInput) => Promise<HaiResult<void>>` | 初始化模块 |
185
- | `deploy.close` | `() => Promise<void>` | 关闭模块 |
186
- | `deploy.scan` | `(appDir: string, options?: DeployScanOptions) => Promise<HaiResult<ScanResult>>` | 按环境扫描(不依赖 init) |
187
- | `deploy.provisionAll` | `(projectName: string, services?: ServiceType[]) => Promise<HaiResult<ProvisionResult[]>>` | 开通指定或全部已配置服务 |
188
- | `deploy.deployApp` | `(appDir: string, options?) => Promise<HaiResult<DeployResult>>` | 完整部署 |
189
- | `deploy.config` | `DeployConfig \| null` | 当前配置 |
190
- | `deploy.isInitialized` | `boolean` | 初始化状态 |
43
+ deploy.init 后检查 HaiResult.success,deploy.deployApp 接收 artifactDir、bundleOnly、selectedServices、runtime 与 onProgress;finally 中 deploy.close。deploy.scan 和 deploy.credentials.* 不依赖 init。Vercel 只消费已有 .vercel/output,不执行源码构建,也不支持 Compose 离线/部分更新。
191
44
 
192
- ## 凭证管理
193
-
194
- 所有凭证操作都通过 `deploy.credentials.*` 访问,模块入口不再单独导出自由函数。
195
-
196
- > `deploy.credentials.*()` 与 `deploy.scan()` 都不依赖 `deploy.init()`,可用于 CLI 在读取 `_deploy.yml` 之前准备环境。
197
-
198
- ## 配置消费与失败恢复
199
-
200
- 云资源配置消费:Neon 输出 HAI_DB(PostgreSQL JSON),Upstash 输出 HAI_CACHE(Redis rediss URL JSON),R2 输出 HAI_STORAGE(扁平 S3 JSON)。邮件/短信输出 HAI_REACH_PROVIDERS 数组,deployApp 合并两个渠道并保留 YAML 中的消息模板;此覆盖替换原 providers 数组。Core 支持整体对象/数组覆盖,父节点优先于叶子变量,仍执行 Schema 校验;构建子进程与目标运行环境使用相同开通结果。R2 必须提供已有 S3 accessKeyId/secretAccessKey;Resend 必须提供已验证域名的 from;阿里云必须提供已审核 signName/模板。应用须已有相应 _db/_cache/_storage/_reach.yml 并在启动时加载,网络客户端需要 Node 运行时。
201
-
202
- 部署失败恢复:`ProvisionResult.resourceStatus` 标记 created/reused;`getDeployRecovery(result.error)` 读取 projectName、stage、platformProjectId 和资源清单,unknown 表示请求结果不确定,必须先在服务商控制台核对。失败资源已返回 ID 时保留该 ID。恢复结果不含 envVars、原始异常或连接凭证,CLI 会展示清单和建议。同名重试复用现有资源;不自动删除复用资源,新建资源仅在人工确认未被使用后清理。
203
-
204
- ## 错误码 — `HaiDeployError`
205
-
206
- | 错误码 | code | 说明 |
207
- | --------------------------------------- | ------------------ | ------------------------ |
208
- | `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | 部署失败(通用) |
209
- | `HaiDeployError.PROJECT_CREATE_FAILED` | `hai:deploy:002` | 平台项目创建失败 |
210
- | `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | 应用构建失败 |
211
- | `HaiDeployError.UPLOAD_FAILED` | `hai:deploy:004` | 构建产物上传失败 |
212
- | `HaiDeployError.AUTH_REQUIRED` | `hai:deploy:005` | 未认证 |
213
- | `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | 认证失败 |
214
- | `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | 基础设施开通失败 |
215
- | `HaiDeployError.ADAPTER_MISSING` | `hai:deploy:008` | SvelteKit adapter 未安装 |
216
- | `HaiDeployError.SCAN_FAILED` | `hai:deploy:009` | 应用扫描失败 |
217
- | `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:010` | 模块未初始化 |
218
- | `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:011` | 环境变量设置失败 |
219
- | `HaiDeployError.UNSUPPORTED_TYPE` | `hai:deploy:012` | 不支持的类型 |
220
- | `HaiDeployError.CONFIG_ERROR` | `hai:deploy:013` | 配置错误 |
221
- | `HaiDeployError.CREDENTIAL_ERROR` | `hai:deploy:014` | 凭证读写失败 |
222
- | `HaiDeployError.CONTAINER_RUNTIME_NOT_FOUND` | `hai:deploy:015` | 未找到容器运行时 |
223
- | `HaiDeployError.CONTAINER_BUILD_FAILED` | `hai:deploy:016` | 镜像构建失败 |
224
- | `HaiDeployError.REMOTE_CONNECT_FAILED` | `hai:deploy:017` | 远程连接失败 |
225
- | `HaiDeployError.REMOTE_COMMAND_FAILED` | `hai:deploy:018` | 远程命令失败 |
226
- | `HaiDeployError.IMAGE_TRANSFER_FAILED` | `hai:deploy:019` | 镜像传输失败 |
227
- | `HaiDeployError.HEALTH_CHECK_FAILED` | `hai:deploy:020` | 健康检查未通过 |
228
-
229
- ## CLI 命令
230
-
231
- 通过 CLI 部署前,先按 [CLI 安装与命令](../hai-app-create/development.md#cli-安装与命令) 全局安装 `@h-ai/cli`,确认 `hai --version` 可运行后再执行下列命令。在 Node.js 脚本中直接使用 `@h-ai/deploy` API 时无需安装 CLI。
232
-
233
- ```bash
234
- # 部署当前目录
235
- hai deploy
236
-
237
- # 部署指定应用
238
- hai deploy ./apps/admin-console --env test
239
-
240
- # 跳过基础设施开通
241
- hai deploy --env prod --skip-provision
242
-
243
- # 仅 Vercel:跳过应用构建;docker-ssh 仍会构建镜像
244
- hai deploy --env prod --skip-build
245
-
246
- # 自定义项目名
247
- hai deploy --project-name my-custom-name
248
- ```
249
-
250
- > 部署方式由 `config/_deploy.yml` 的 `provider.type` 决定(vercel / docker-ssh),
251
- > CLI 命令相同。docker-ssh 成功后输出的访问地址为 `http://<host>:<hostPort>`。
252
-
253
- fullstack 需明确部署服务包;`hai deploy packages/my-app-serv --env prod` 不会发布 Web。根 Dockerfile 的 `runtime` / `web` target 分别构建 API / Web;Web 单独转移、运行,设置浏览器可访问的 `PUBLIC_API_BASE` 和 API 的 CORS。模板 `pnpm run deploy` 是打包脚本,不等于 CLI 发布。
254
-
255
- 离线部署先按 [离线准备与验收](middleware.md#离线准备与验收) 检查材料。docker-ssh 在本地构建并导出镜像 tar,再分别上传镜像、Compose、运行环境和启动脚本,不在远程构建源码。当前无直接指定预构建镜像的参数;不得声称 `--skip-build` 能离线发布容器,也不得将联网部署测试作为断网证明。
256
-
257
- ## 常见模式
258
-
259
- ### 仅部署(跳过基础设施)
260
-
261
- ```typescript
262
- await deploy.deployApp('./apps/my-app', { skipProvision: true })
263
- ```
264
-
265
- ### 仅开通基础设施
266
-
267
- ```typescript
268
- await deploy.init(config)
269
- const result = await deploy.provisionAll('my-project')
270
- // 手动使用 result.data 中的环境变量
271
- await deploy.close()
272
- ```
273
-
274
- ### 自定义部署流程
275
-
276
- ```typescript
277
- import { deploy } from '@h-ai/deploy'
278
-
279
- // Provider 通过 init 配置自动创建,不需要手动导入
280
- await deploy.init({
281
- provider: { type: 'vercel', token: 'vel_xxx' },
282
- })
283
-
284
- // 使用 deploy API 部署
285
- const result = await deploy.deployApp('./apps/my-app')
286
- ```
45
+ ## 离线交付与验证
287
46
 
288
- ## 相关 Skills
47
+ Linux 预备 Docker/Podman、支持 --pull never 的 Compose(Docker Compose v2 或 podman-compose 1.6.0 及以上)、sh、tar、sha256sum、awk、curl 及目录/容器权限。完整 tar 包含全部自建中间件归档;目标架构须匹配。包中有私有配置,安全搬运,不提交 Git。离线构建额外准备基础镜像、Linux 依赖缓存、工具链与原生预编译包;Windows node_modules 不能替代。
289
48
 
290
- - **hai-core** — 配置加载、日志、HaiResult 类型
291
- - **hai-reldb** — 数据库(Neon PostgreSQL)
292
- - **hai-cache** — 缓存(Upstash Redis)
49
+ 按 [分轮验证与集中修复](../hai-app-tests/validation.md) 收集适用的 typecheck、lint、build、test、scaffold gates 和 test:deploy-gates,汇总后集中修复、再验证。实际验证无 registry 网络的首次部署、登录刷新、同版本重发、只更新 Web/API、损坏归档、缺基线、健康失败与恢复。Windows/Linux/macOS 上传入口分别执行验收;原生安装包在对应 OS 验证。测试临时工程、容器、镜像、数据和进程在 finally/teardown 清理,只清理测试拥有的资源;日志、截图和报告保留到分析和交付结束再清理。
@@ -29,7 +29,7 @@
29
29
  2. **使用自定义配置**:逐项输入所选后端的连接字段,展示变量名、字段用途与约束,校验必填项、端口、布尔和 URL;凭据用密码输入。保存配置后跳过该服务的开通与 sidecar。
30
30
  3. **保持不变**:仅在目标 `.env.<mode>` 显式声明当前后端及完整连接配置时出现;私有凭据可来自 `.env.local`/进程。选择后不修改该项、不认证其 Provisioner、不创建或移除已有中间件容器,继续下一项。只有 `.env` 或其他环境有配置不满足此条件。
31
31
 
32
- 逐项配置前提供“环境配置已完备,直接部署”。选择后跳过全部中间件提示、变量改写、云资源与 sidecar 创建,保留已有服务;仍执行应用构建、部署及健康检查。命令行可用 `--skip-middleware`(或 `--skip-provision`)明确选择。不要因为缺少某项中间件的目标文件声明而阻止用户主动跳过。
32
+ 逐项配置前提供“环境配置已完备,直接部署”。选择后跳过全部中间件提示、变量改写、云资源与 sidecar 创建,保留已有服务;仍校验已有构建产物并执行部署及健康检查。命令行使用唯一的 `--skip-middleware`,SDK 使用 `skipMiddleware`。不要因为缺少某项中间件的目标文件声明而阻止用户主动跳过。
33
33
 
34
34
  `--yes` 用于已授权的自动化:目标环境已有完整配置时保持不变,否则使用当前后端默认配置;不支持的云后端或缺少必需凭据直接失败。自动化直接部署用 `hai deploy packages/my-app-serv --env prod --yes --skip-middleware`。跳过不作为配置完整性或连接成功的证明。
35
35
 
@@ -71,24 +71,12 @@ S3 是协议,不是某个容器产品。默认配置时另选 RustFS/MinIO,
71
71
 
72
72
  ## 离线准备与验收
73
73
 
74
- 先核对 Node、pnpm 与目标 Linux 架构。当前要求 Node `^22.22.2 || ^24.15.0 || >=26.0.0`,生成工程固定 pnpm 12.11.2。Windows 本地需已初始化的 Linux 容器引擎、OpenSSH、完整项目及已安装的 CLI/SDK 依赖;Linux 需容器引擎和 Compose、SSH 授权与权限。无互联网仍需 Windows 到 Linux 的 SSH 和应用端口可达。
74
+ 构建与部署可分开,也可通过 pnpm run deploy --build 明确串联。构建保持环境无关;部署选择环境并只消费所选镜像。完整包自动包含 Compose 自建中间件镜像,因此导出阶段需要本地 Podman/Docker,缺镜像在打包阶段准备,不能留给隔离服务器下载。
75
75
 
76
- 有 PostgreSQL/Redis/RustFS 镜像不代表有可用服务。默认配置要求 Compose 中镜像名称、tag、架构准确匹配,SDK 不传输中间件镜像;自定义连接要求服务已启动、地址从应用容器可达并提供数据库/账号、密码、S3 密钥/桶。不要用容器内 localhost 指代宿主机服务。
76
+ --bundle-only 生成带版本 tar 与 -deploy/ 目录。操作目录含 Windows deploy.ps1、Linux/macOS deploy.sh 和目标配置。隔离服务器搬运并解包后执行 sh apply.sh。每步失败返回非零,结果写 result-<部署ID>.json;只有 HTTP 检查通过才更新服务器 current。
77
77
 
78
- 默认 Dockerfile 会下载 Node 基础镜像、pnpm、依赖和 SQLite 预编译包,不能直接称为离线可用。源码离线构建要准备 Linux 构建环境的完整缓存和构建 frontend,调整下载步骤并断开外网演练;Windows node_modules/pnpm store 不代表 Linux 的原生依赖可用。云 Provider/Provisioner 需要外网,不用于完全离线部署。
78
+ 部分更新通过 --services 指定,使用服务器成功基线保留未选服务和中间件凭据。首次安装不能使用部分包。storage-init 复用应用镜像及 S3 SDK 检查/创建桶,不清空数据;只有涉及存储初始化时执行,并检查退出码。仅更新 storage 仍需含 app 镜像的制品;最近为 web-only 时,用 --artifact-dir 选择原完整制品,或先 pnpm build --target docker --images app。app 镜像仅用于初始化,不会更新 app 服务。失败恢复尝试还原容器和配置,保留数据卷,不回退已写业务数据。
79
79
 
80
- docker-ssh 始终执行本地镜像构建,`--skip-build` 仅对 Vercel 生效。预构建离线交付可在准备环境导出 API/Web 镜像,在 Windows 引擎加载 API 镜像后,为目标服务包提供仅含 `FROM <已加载的API镜像>` 的 Dockerfile 和内容 `*` 的 `.dockerignore`,让 SDK 复用成品并上传。业务代码变更后必须重制成品镜像;无匹配本地镜像时不能继续假定构建无网络。
80
+ 服务器需要 Linux、Docker/Podman、Compose、sh、tar、sha256sum、awk、curl、持久化磁盘和容器/目录权限。完整交付包含自建服务镜像;自定义外部连接仍需准备服务、账号和网络可达性。云 Provider/Provisioner 需要外网,不能用于完全离线。
81
81
 
82
- fullstack 的 Web 不在服务包 `hai deploy` 中发布,需单独加载/运行 Web 镜像并设置 PUBLIC_API_BASE、API CORS。生产禁止通配 CORS,refresh Cookie 启用 Secure;须准备 HTTPS 入口、内网证书/信任与 DNS/hosts,SDK 不自动配置 TLS/反向代理。离线验收须包含断外网构建/上传/启动、API 健康、真实 Web 登录、页面与会话刷新、重启和持久化;分别报告 API 部署、Web 发布和断网证据,不能互相替代。
83
-
84
- ## 启动与验证
85
-
86
- fullstack 创建时可通过 `--features deploy` 安装对应版本的本地部署工具。SQLite 在模板及兜底 Dockerfile 中先按驱动版本、Node ABI、架构和 libc 下载官方预编译包,最多尝试三次,加载验证后由生产依赖安装复用缓存;不预装 Python/make/C++,无匹配包或下载失败时停止构建。受限网络可预置 prebuild-install 缓存,或配置 container.sqlitePrebuildMirror(HAI_DEPLOY_CONTAINER_SQLITEPREBUILDMIRROR;自带 Dockerfile 使用 SQLITE_PREBUILD_MIRROR build arg)。镜像根地址后附 /v<驱动版本>/<匹配 ABI 的包名>,不得包含认证信息。不能把更换下载命令当成解决网络不可达,也不能用 CUDA 开关掩盖无关 AI 依赖。
87
-
88
- Podman 构建默认继承运行时代理。代理地址在容器内不可达时,在 `_deploy.yml` 配置 `container.httpProxy: false`(已声明该节点时也可使用 `HAI_DEPLOY_CONTAINER_HTTPPROXY=false`),不要修改用户的系统代理。`loadDeploymentEnvironment`、`loadDeploymentConfig`、`saveDeploymentEnvironment` 可用于脚本显式读取、解析和保存同一份部署配置,均返回 HaiResult。
89
-
90
- 构建上下文必须排除 `.env.local`、`.env.*.local`、`.env.runtime` 和 `.hai/deploy`(含镜像归档与凭据);公共环境文件仍可进入上下文。兜底 Dockerfile 使用伴随忽略文件,Podman 通过 `--ignorefile` 显式指定,避免使用 workspace 根规则后把上次部署的归档或运行配置重新打进构建层。
91
-
92
- 容器运行期设置 `NODE_ENV=production`,`HAI_DEPLOY_ENVIRONMENT` 保存文件模式,`HAI_CORE_ENV` 映射为 development/test/production/staging。显式环境部署的资源名追加环境后缀,避免 test/prod 复用同一数据卷。启动脚本位于服务包 `.hai/deploy/<mode>/start-<mode>.sh`,显式导出环境并执行 compose;私有 `.env.runtime` 权限为 600。自带 Dockerfile 可读取同名 build args;不得把私有环境文件或运行凭据复制进镜像。
93
-
94
- 修改此流程后执行 deploy/CLI 的 typecheck、lint、build、test,以及 `pnpm --filter @h-ai/cli test:deploy-gates`(当前源码 tarball → fullstack → Podman/SSH → 健康检查、环境标识、登录和重复部署)。模板变动另执行受影响的 scaffold gates。日志、截图、验收报告保存在 Git 忽略的临时目录,不提交仓库;付费云资源、原生客户端与远程生产部署须单独验证并说明边界。
82
+ 完全离线构建另需基础镜像、Linux 依赖缓存、pnpm 和匹配驱动/Node ABI/架构/libc 的原生预编译包。构建可用 --sqlite-prebuild-mirror,Podman 代理不可达可用 --no-http-proxy;不要改系统代理或让 deploy 下载编译环境。生产 HTTPS、CORS、证书、DNS 另行准备。实际断网验收登录、刷新、重启和数据持久化。
@@ -75,7 +75,7 @@ npm view @h-ai/cli dist-tags --json
75
75
  | --- | --- |
76
76
  | 自动处理 | 目标明确、可保持现有行为的依赖更新、兼容性修正、无冲突的 skills 合并和验证,直接执行 |
77
77
  | 用户选择 | 存在多个有意义的方案且影响产品行为、架构、成本、Provider 或运维方式,展示证据、选项、推荐与取舍,等待回答 |
78
- | 阻塞 | 无法取得必要产物、依赖不兼容、无法无损合并、必要工具/服务/授权缺失或关键验证失败,先诊断并修复可自行解决的原因;仍无法推进时说明具体处理步骤 |
78
+ | 阻塞 | 无法取得必要产物、依赖不兼容、无法无损合并、必要工具/服务/授权缺失等导致后续无法执行,先处理可自行解决的原因;仍无法推进时说明具体步骤。普通门禁失败先记录,继续独立检查,本轮汇总后集中修复;必要门禁未通过仍不能交付完成 |
79
79
  | 不适用 | 当前应用未使用且不影响其依赖/运行的变化,记录依据;不要求用户逐项确认 |
80
80
 
81
81
  - 尽量合并相互独立的选择,明确每个回答控制哪项改动;已给出的目标、授权和选择持续有效,不重复询问。
@@ -95,7 +95,7 @@ npm view @h-ai/cli dist-tags --json
95
95
 
96
96
  ### 6. 验证与交付
97
97
 
98
- 按应用实际 scripts 和 [hai-ci](../hai-ci/SKILL.md) 执行 `typecheck → lint → build → test`,优先受影响 workspace;跨包契约验证所有消费者。按 [hai-app-tests](../hai-app-tests/SKILL.md) 选择受影响的集成/E2E,覆盖启动/关闭、变更 API、认证、持久化等实际路径。
98
+ 按应用实际 scripts 和 [分轮验证与集中修复](../hai-app-tests/validation.md) 先收集一轮适用门禁,汇总根因后集中修复、再验证;优先受影响 workspace,跨包契约验证所有消费者。按 [hai-app-tests](../hai-app-tests/SKILL.md) 选择集成/E2E,覆盖启动/关闭、变更 API、认证、持久化等实际路径;CI/发布按 [hai-ci](../hai-ci/SKILL.md) 保留失败阻断。
99
99
 
100
100
  - 依赖升级后另核对 lockfile 与安装版本、公开入口、配置加载和关键业务流程;build 通过不能替代 typecheck 或运行验收。
101
101
  - 检查同步后的全部相邻资源、相对引用和各工具入口;目标存在 `check:skills` 时运行,不假定应用具有框架仓库私有脚本。
@@ -45,5 +45,5 @@ PowerShell 使用 `pnpm.cmd`;占位包名替换后执行。本地来源先验
45
45
 
46
46
  - 仅 skills/入口变更:检查 diff、完整目录、目标实际存在的入口及相邻资源、相对引用;排除框架仓库私有绝对路径/命令。
47
47
  - 框架模板维护:运行已有 `check:skills` 和 CLI `test:scaffold-gates`,确认资源与路由在生成项目中可达。
48
- - 同步应用依赖或运行时:按入口升级流程和 [hai-ci](../hai-ci/SKILL.md) 选择应用门禁,不以模板已同步代替运行验收。
48
+ - 同步应用依赖或运行时:按入口升级流程和 [分轮验证与集中修复](../hai-app-tests/validation.md) 收集适用门禁、集中修复并复测;CI/发布遵守 [hai-ci](../hai-ci/SKILL.md),不以模板已同步代替运行验收。
49
49
  - 双仓改动时说明来源版本/提交、改动顺序、应用私有覆盖和双方验证;涉及 PR 时按 [hai-pr-review](../hai-pr-review/SKILL.md) 关联同步说明。仅授权一个仓库时记录另一方待同步,不擅自修改。
@@ -28,14 +28,12 @@ description: "使用 @h-ai/iam 实现登录、注册、会话、OTP/LDAP/API Key
28
28
  - LDAP/Reach 均可选:基础认证无需安装;默认 LDAP 关闭,选用默认客户端才安装 ldapts 并设置 login.ldap + ldap。OTP 邮件/短信由 otp.email/sms 控制,选择 Reach 标准模板或自定义发送回调;具体签名与失败处理见参考中的“可选 LDAP 与通知”。
29
29
  - 多节点共享 DB + Redis,Memory 只用于单进程。重置的策略失败计入 maxAttempts;OTP 消费不解除 resendInterval。管理员 createUser 不受自助注册开关限制。
30
30
 
31
- - 协议支持配置中的 userAgreementMarkdown/privacyPolicyMarkdown 正文及 URL;同主题优先 Markdown,由安全渲染器在弹窗显示。
32
-
33
31
  - 受保护请求使用 `iam.auth.verifyToken`:当前用户状态 + 角色 JOIN + 批量权限读取,失败即拒绝;`iam.session.verifyToken` 仅验证会话快照。serv 内置 IAM 注入默认使用当前授权入口,无需手动补查。
34
32
  - 用户批量读取用 `iam.user.getUsers(ids, { include: ['roles'] })`(最多 1000,去重保留输入顺序,缺失省略);角色筛选用 `listUsers({ roleCode })`,在分页前执行,避免 N+1 和分页后过滤。
35
33
 
36
34
  ## 按需参考
37
35
 
38
- 详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
36
+ 按任务读取 [reference.md](reference.md) 的对应小节;签名以当前源码或安装版本的公开类型为准,不默认加载全部资料。示例中的业务变量由应用提供。
39
37
 
40
38
  - 运行环境
41
39
  - 依赖
@@ -1,6 +1,6 @@
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
@@ -15,173 +15,18 @@ description: "使用 @h-ai/kit 集成 SvelteKit hooks、守卫、校验、响应
15
15
  | 输出 | handle、Response、校验值和客户端请求结果 |
16
16
  | 限制 | 无 init/close;保留 SvelteKit 控制流异常。跨端共享 HTTP contract 用 api-contract + serv,勿复制到 kit。 |
17
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。
18
+ ## 使用路径
19
19
 
20
- ## 使用步骤
20
+ 1. 仅在 SvelteKit 集成;先查现有 hooks、配置、守卫与路由,不将其套用于独立 serv 应用。
21
+ 2. 用 createHandle 编排已初始化模块;认证 API 与公开路径复用 kit.auth,客户端复用框架动作。
22
+ 3. 区分返回 HaiResult 的业务操作与抛 Response/redirect/error 的框架控制流,不吞掉控制流。
23
+ 4. 对齐 Cookie/CSRF/transport 与服务端配置,验证匿名、登录、权限拒绝和表单失败。
21
24
 
22
- ### 1. 请求管道
25
+ ## 按需参考
23
26
 
24
- ```ts
25
- import type { Handle } from '@sveltejs/kit'
26
- import { kit } from '@h-ai/kit'
27
+ 按本次操作读取对应小节;以已安装版本的公开类型核验签名,示例中的业务变量由应用提供。
27
28
 
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
- })
37
-
38
- export const handle: Handle = haiHandle
39
- ```
40
-
41
- ### 2. SvelteKit API endpoint
42
-
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)。
29
+ - [使用步骤](reference.md#使用步骤)
30
+ - [核心 API](reference.md#核心-api)
31
+ - [常见模式](reference.md#常见模式)
32
+ - [声明式 CRUD 表单字段](reference.md#声明式-crud-表单字段)