@h-ai/cli 0.1.0-alpha.19 → 0.1.0-alpha.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 (219) hide show
  1. package/README.md +10 -7
  2. package/dist/{chunk-GSMXGUYF.js → chunk-5IGMJVV5.js} +56 -38
  3. package/dist/chunk-5IGMJVV5.js.map +1 -0
  4. package/dist/{chunk-BPO34NRL.js → chunk-CFCXOKGV.js} +27 -5
  5. package/dist/chunk-CFCXOKGV.js.map +1 -0
  6. package/dist/cli-config-templates-5J5VKWWD.js +5 -0
  7. package/dist/{cli-config-templates-JCS7T3NU.js.map → cli-config-templates-5J5VKWWD.js.map} +1 -1
  8. package/dist/cli-skill-templates-JMSV2SVW.js +5 -0
  9. package/dist/{cli-skill-templates-IMYZPQRG.js.map → cli-skill-templates-JMSV2SVW.js.map} +1 -1
  10. package/dist/index.js +627 -107
  11. package/dist/index.js.map +1 -1
  12. package/dist/{src-N4NPS7AG.js → src-QNEJJ3BV.js} +261 -103
  13. package/dist/src-QNEJJ3BV.js.map +1 -0
  14. package/package.json +3 -2
  15. package/templates/README.md +40 -29
  16. package/templates/apps/admin/messages/en-US.json +5 -0
  17. package/templates/apps/admin/messages/zh-CN.json +5 -0
  18. package/templates/apps/admin/src/routes/+layout.svelte.hbs +5 -5
  19. package/templates/apps/admin/src/routes/+page.svelte.hbs +32 -12
  20. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +37 -20
  21. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
  22. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
  23. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +16 -0
  24. package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +38 -0
  25. package/templates/apps/api/apps/{{projectName}}-contract/src/app-contract.ts.hbs +27 -0
  26. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +33 -0
  27. package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +3 -0
  28. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +12 -0
  29. package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +18 -0
  30. package/templates/apps/api/apps/{{projectName}}-contract/tsconfig.json.hbs +12 -0
  31. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +11 -0
  32. package/templates/apps/api/apps/{{projectName}}-contract/vitest.config.ts.hbs +9 -0
  33. package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +17 -0
  34. package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +19 -0
  35. package/templates/apps/api/apps/{{projectName}}-service/config/_serv.yml.hbs +26 -0
  36. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +55 -0
  37. package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +98 -0
  38. package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +21 -0
  39. package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +184 -0
  40. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/app-procedures.ts.hbs +49 -0
  41. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/index.ts.hbs +18 -0
  42. package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +168 -0
  43. package/templates/apps/api/apps/{{projectName}}-service/tsconfig.json.hbs +16 -0
  44. package/templates/apps/api/apps/{{projectName}}-service/tsup.config.ts.hbs +11 -0
  45. package/templates/apps/api/apps/{{projectName}}-service/vitest.config.ts.hbs +9 -0
  46. package/templates/apps/api/e2e/api-service.spec.ts.hbs +18 -0
  47. package/templates/apps/api/eslint.config.js +32 -0
  48. package/templates/apps/api/package.json.hbs +29 -0
  49. package/templates/apps/api/playwright.config.ts.hbs +58 -0
  50. package/templates/apps/api/pnpm-workspace.yaml.hbs +14 -0
  51. package/templates/apps/api/tsconfig.base.json +15 -0
  52. package/templates/apps/fullstack/apps/{{projectName}}-app/.env.example.hbs +10 -0
  53. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +24 -7
  54. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +18 -0
  55. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +1 -1
  56. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +16 -0
  57. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +6 -0
  58. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +6 -0
  59. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +51 -29
  60. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +186 -0
  61. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +2 -0
  62. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +0 -1
  63. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +18 -0
  64. package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +14 -0
  65. package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +1 -5
  66. package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +10 -4
  67. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +4 -3
  68. package/templates/apps/fullstack/apps/{{projectName}}-desktop/.env.example.hbs +6 -0
  69. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +20 -6
  70. package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +1 -1
  71. package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +15 -0
  72. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +33 -30
  73. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +152 -0
  74. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +1 -2
  75. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/main.ts.hbs +13 -0
  76. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +22 -0
  77. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/build.rs.hbs +6 -0
  78. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/capabilities/default.json.hbs +12 -0
  79. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128.png +0 -0
  80. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128@2x.png +0 -0
  81. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/32x32.png +0 -0
  82. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.icns +0 -0
  83. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.ico +0 -0
  84. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +16 -0
  85. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/main.rs.hbs +8 -0
  86. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +41 -0
  87. package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +2 -8
  88. package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +9 -4
  89. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +44 -21
  90. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +15 -6
  91. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +1 -1
  92. package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +15 -0
  93. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +25 -27
  94. package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +153 -0
  95. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +0 -1
  96. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +14 -0
  97. package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +1 -5
  98. package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +10 -4
  99. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +3 -2
  100. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +2 -1
  101. package/templates/apps/fullstack/eslint.config.js +0 -1
  102. package/templates/apps/fullstack/package.json.hbs +18 -17
  103. package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +3 -3
  104. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +5 -2
  105. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +14 -0
  106. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +13 -0
  107. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +2 -2
  108. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/{server-app.ts.hbs → app-server.ts.hbs} +23 -3
  109. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +4 -1
  110. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/{server-app.test.ts.hbs → app-server.test.ts.hbs} +1 -1
  111. package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +9 -8
  112. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +1 -1
  113. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +5 -1
  114. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +1 -1
  115. package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +1 -1
  116. package/templates/apps/fullstack/playwright.config.ts.hbs +41 -4
  117. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +15 -0
  118. package/templates/apps/h5/messages/en-US.json +3 -0
  119. package/templates/apps/h5/messages/zh-CN.json +3 -0
  120. package/templates/apps/h5/src/routes/+layout.svelte.hbs +30 -29
  121. package/templates/apps/h5/src/routes/+page.svelte.hbs +17 -6
  122. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
  123. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
  124. package/templates/apps/mobile-app/.env.hbs +3 -0
  125. package/templates/apps/{android-app → mobile-app}/capacitor.config.ts.hbs +2 -2
  126. package/templates/apps/mobile-app/index.html.hbs +13 -0
  127. package/templates/apps/mobile-app/messages/en-US.json +36 -0
  128. package/templates/apps/mobile-app/messages/zh-CN.json +36 -0
  129. package/templates/apps/mobile-app/src/App.svelte.hbs +162 -0
  130. package/templates/apps/mobile-app/src/lib/api.ts.hbs +54 -0
  131. package/templates/apps/{android-app → mobile-app}/src/lib/capacitor.ts +6 -7
  132. package/templates/apps/mobile-app/src/main.ts.hbs +11 -0
  133. package/templates/apps/website/src/routes/+layout.svelte.hbs +35 -26
  134. package/templates/apps/website/src/routes/+page.svelte.hbs +28 -10
  135. package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
  136. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +37 -34
  137. package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
  138. package/templates/base/.gitignore.hbs +16 -0
  139. package/templates/base/{eslint.config.js → eslint.config.js.hbs} +4 -1
  140. package/templates/base/package.json.hbs +55 -31
  141. package/templates/base/playwright.config.ts +30 -3
  142. package/templates/base/pnpm-workspace.yaml.hbs +14 -0
  143. package/templates/base/src/app.d.ts.hbs +3 -0
  144. package/templates/base/src/app.html.hbs +7 -0
  145. package/templates/base/src/hooks.server.ts.hbs +17 -7
  146. package/templates/base/src/lib/server/init.ts.hbs +20 -12
  147. package/templates/base/static/favicon.png +0 -0
  148. package/templates/base/svelte.config.js.hbs +43 -3
  149. package/templates/base/tests/scaffold.test.ts.hbs +16 -1
  150. package/templates/base/tsconfig.json.hbs +50 -0
  151. package/templates/base/vite.config.ts.hbs +13 -3
  152. package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +5 -5
  153. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +34 -32
  154. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +46 -48
  155. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +35 -31
  156. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +41 -38
  157. package/templates/skills/AGENTS.md +60 -17
  158. package/templates/skills/CLAUDE.md +18 -6
  159. package/templates/skills/bridges/admin/AGENTS.md +66 -0
  160. package/templates/skills/bridges/admin/CLAUDE.md +19 -0
  161. package/templates/skills/bridges/admin/copilot-instructions.md +46 -0
  162. package/templates/skills/bridges/api/AGENTS.md +65 -0
  163. package/templates/skills/bridges/api/CLAUDE.md +19 -0
  164. package/templates/skills/bridges/api/copilot-instructions.md +46 -0
  165. package/templates/skills/bridges/fullstack/AGENTS.md +84 -0
  166. package/templates/skills/bridges/fullstack/CLAUDE.md +19 -0
  167. package/templates/skills/bridges/fullstack/copilot-instructions.md +54 -0
  168. package/templates/skills/bridges/h5/AGENTS.md +65 -0
  169. package/templates/skills/bridges/h5/CLAUDE.md +19 -0
  170. package/templates/skills/bridges/h5/copilot-instructions.md +44 -0
  171. package/templates/skills/bridges/mobile-app/AGENTS.md +77 -0
  172. package/templates/skills/bridges/mobile-app/CLAUDE.md +19 -0
  173. package/templates/skills/bridges/mobile-app/copilot-instructions.md +45 -0
  174. package/templates/skills/bridges/website/AGENTS.md +65 -0
  175. package/templates/skills/bridges/website/CLAUDE.md +19 -0
  176. package/templates/skills/bridges/website/copilot-instructions.md +44 -0
  177. package/templates/skills/copilot-instructions.md +29 -50
  178. package/templates/skills/hai-ai/SKILL.md +115 -648
  179. package/templates/skills/hai-ai/reference.md +197 -0
  180. package/templates/skills/hai-api-client/SKILL.md +3 -1
  181. package/templates/skills/hai-app-create/SKILL.md +2 -1
  182. package/templates/skills/hai-app-review/SKILL.md +2 -2
  183. package/templates/skills/hai-app-tests/SKILL.md +28 -3
  184. package/templates/skills/hai-capacitor/SKILL.md +14 -22
  185. package/templates/skills/hai-deploy/SKILL.md +12 -9
  186. package/templates/skills/hai-kit/SKILL.md +5 -3
  187. package/templates/skills/hai-serv/SKILL.md +2 -0
  188. package/templates/skills/hai-ui/SKILL.md +25 -11
  189. package/templates/skills/opencode.json +1 -6
  190. package/dist/chunk-BPO34NRL.js.map +0 -1
  191. package/dist/chunk-GSMXGUYF.js.map +0 -1
  192. package/dist/cli-config-templates-JCS7T3NU.js +0 -5
  193. package/dist/cli-skill-templates-IMYZPQRG.js +0 -5
  194. package/dist/src-N4NPS7AG.js.map +0 -1
  195. package/templates/apps/android-app/.env.hbs +0 -3
  196. package/templates/apps/android-app/messages/en-US.json +0 -24
  197. package/templates/apps/android-app/messages/zh-CN.json +0 -24
  198. package/templates/apps/android-app/src/lib/api.ts.hbs +0 -31
  199. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +0 -42
  200. package/templates/apps/android-app/src/routes/+layout.ts +0 -7
  201. package/templates/apps/android-app/src/routes/+page.svelte.hbs +0 -27
  202. package/templates/apps/api/src/routes/+layout.svelte +0 -14
  203. package/templates/apps/api/src/routes/+page.svelte +0 -11
  204. package/templates/apps/api/src/routes/api/v1/health/+server.ts +0 -14
  205. package/templates/apps/api/src/routes/api/v1/items/+server.ts +0 -37
  206. package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +0 -30
  207. package/templates/apps/api/tests/health.test.ts.hbs +0 -26
  208. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.html.hbs +0 -14
  209. package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+layout.svelte.hbs +0 -18
  210. package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+page.svelte.hbs +0 -162
  211. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.html.hbs +0 -14
  212. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+layout.svelte.hbs +0 -18
  213. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+page.svelte.hbs +0 -162
  214. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.html.hbs +0 -14
  215. package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+layout.svelte.hbs +0 -18
  216. package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+page.svelte.hbs +0 -162
  217. package/templates/apps/fullstack/pnpm-workspace.yaml +0 -7
  218. package/templates/base/tsconfig.json +0 -20
  219. /package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/{theme.svelte.ts.hbs → theme-store.svelte.ts.hbs} +0 -0
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {},
4
+ "include": [
5
+ "src/**/*"
6
+ ],
7
+ "exclude": [
8
+ "node_modules",
9
+ "dist",
10
+ "tests"
11
+ ]
12
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: { index: 'src/index.ts' },
5
+ format: ['esm'],
6
+ target: 'node22',
7
+ sourcemap: true,
8
+ clean: true,
9
+ dts: true,
10
+ external: ['@h-ai/api-contract', 'zod'],
11
+ })
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['tests/**/*.test.ts'],
8
+ },
9
+ })
@@ -0,0 +1,17 @@
1
+ # {{api.servicePackageName}}
2
+
3
+ {{projectName}} API service 包,负责模块初始化、procedure 装配与 HTTP 入口。
4
+
5
+ ## 常用命令
6
+
7
+ ```bash
8
+ pnpm --filter {{api.servicePackageName}} dev
9
+ pnpm --filter {{api.servicePackageName}} test
10
+ ```
11
+
12
+ ## 关键目录
13
+
14
+ - `config/`:service 配置
15
+ - `src/app.ts`:HTTP App 装配
16
+ - `src/lib/server/init.ts`:模块初始化与关闭
17
+ - `src/server/procedures/`:应用级 procedures
@@ -0,0 +1,19 @@
1
+ # =============================================================================
2
+ # {{projectName}} API Service - 应用配置
3
+ # =============================================================================
4
+
5
+ name: {{projectName}} API Service
6
+ version: 0.1.0
7
+ env: ${HAI_ENV:development}
8
+ debug: false
9
+
10
+ defaultLocale: {{defaultLocale}}
11
+ supportedLocales:
12
+ {{#if_eq defaultLocale 'en-US'}} - en-US
13
+ - zh-CN
14
+ {{else}} - zh-CN
15
+ - en-US
16
+ {{/if_eq}}
17
+
18
+ features:
19
+ apiAccess: true
@@ -0,0 +1,26 @@
1
+ # =============================================================================
2
+ # {{projectName}} API Service - Serv / HTTP 入口配置
3
+ # =============================================================================
4
+
5
+ http:
6
+ apiPrefix: /api/v1
7
+ openapi:
8
+ path: /openapi.json
9
+ docs:
10
+ path: /docs
11
+ health:
12
+ path: /health
13
+ readyPath: /ready
14
+ rpc: false
15
+
16
+ {{#if features.crypto}}transport:
17
+ keyExchangePath: /_hai/key-exchange
18
+ excludePaths:
19
+ - /health
20
+ - /ready
21
+ - /openapi.json
22
+ - /docs
23
+ - /_hai/scalar.js
24
+ maxClients: 10000
25
+ {{else}}transport: false
26
+ {{/if}}
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "{{api.servicePackageName}}",
3
+ "type": "module",
4
+ "version": "0.1.0",
5
+ "private": true,
6
+ "license": "MIT",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "typecheck": "tsc --noEmit",
22
+ "lint": "eslint .",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "clean": "rimraf dist .turbo",
26
+ "dev": "pnpm build && node dist/index.js",
27
+ "start": "node dist/index.js"
28
+ },
29
+ "dependencies": {
30
+ "@h-ai/core": "{{haiPackageSpecifier}}",
31
+ "@h-ai/serv": "{{haiPackageSpecifier}}",
32
+ "{{api.contractPackageName}}": "workspace:*"{{#if features.ai}},
33
+ "@h-ai/ai": "{{haiPackageSpecifier}}"{{/if}}{{#if features.audit}},
34
+ "@h-ai/audit": "{{haiPackageSpecifier}}"{{/if}}{{#if features.cache}},
35
+ "@h-ai/cache": "{{haiPackageSpecifier}}"{{/if}}{{#if features.crypto}},
36
+ "@h-ai/crypto": "{{haiPackageSpecifier}}"{{/if}}{{#if features.datapipe}},
37
+ "@h-ai/datapipe": "{{haiPackageSpecifier}}"{{/if}}{{#if features.deploy}},
38
+ "@h-ai/deploy": "{{haiPackageSpecifier}}"{{/if}}{{#if features.iam}},
39
+ "@h-ai/iam": "{{haiPackageSpecifier}}"{{/if}}{{#if features.payment}},
40
+ "@h-ai/payment": "{{haiPackageSpecifier}}"{{/if}}{{#if features.reach}},
41
+ "@h-ai/reach": "{{haiPackageSpecifier}}"{{/if}}{{#if features.db}},
42
+ "@h-ai/reldb": "{{haiPackageSpecifier}}"{{/if}}{{#if features.scheduler}},
43
+ "@h-ai/scheduler": "{{haiPackageSpecifier}}"{{/if}}{{#if features.storage}},
44
+ "@h-ai/storage": "{{haiPackageSpecifier}}"{{/if}}{{#if features.vecdb}},
45
+ "@h-ai/vecdb": "{{haiPackageSpecifier}}"{{/if}}
46
+ },
47
+ "devDependencies": {
48
+ "@h-ai/api-client": "{{haiPackageSpecifier}}",
49
+ "@types/node": "{{api.packageSpecifiers.nodeTypes}}",
50
+ "rimraf": "{{api.packageSpecifiers.rimraf}}",
51
+ "tsup": "{{api.packageSpecifiers.tsup}}",
52
+ "typescript": "{{api.packageSpecifiers.typescript}}",
53
+ "vitest": "{{api.packageSpecifiers.vitest}}"
54
+ }
55
+ }
@@ -0,0 +1,98 @@
1
+ import type { ServConfig } from '@h-ai/serv'
2
+ import { core } from '@h-ai/core'
3
+ {{#if features.crypto}}import { crypto, TRANSPORT_PROTOCOL } from '@h-ai/crypto'
4
+ {{/if}}{{#if features.iam}}import { iam } from '@h-ai/iam'
5
+ {{/if}}import { serv } from '@h-ai/serv'
6
+ import { {{api.contractExportName}} } from '{{api.contractPackageName}}'
7
+ import pkg from '../package.json' with { type: 'json' }
8
+ import { {{api.serviceProceduresFactoryName}} } from './server/procedures/index.js'
9
+
10
+ const startedAt = Date.now()
11
+
12
+ interface CreateApiServiceAppOptions {
13
+ transport?: 'config' | 'disabled'
14
+ refreshCookie?: 'enabled' | 'disabled'
15
+ }
16
+
17
+ const LOOPBACK_ORIGIN_RE = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/
18
+ const WEBVIEW_ORIGINS = new Set([
19
+ 'capacitor://localhost',
20
+ 'http://localhost',
21
+ 'https://tauri.localhost',
22
+ 'tauri://localhost',
23
+ ])
24
+ const DEFAULT_CORS_ALLOWED_HEADERS = [
25
+ 'Authorization',
26
+ 'Content-Type',
27
+ {{#if features.crypto}} TRANSPORT_PROTOCOL.CLIENT_ID_HEADER,
28
+ TRANSPORT_PROTOCOL.ENCRYPTED_HEADER,
29
+ {{/if}} 'X-Hai-Locale',
30
+ 'X-Request-Id',
31
+ 'X-Requested-With',
32
+ ]
33
+
34
+ /** 创建 API Service HTTP 应用。 */
35
+ export function {{api.serviceAppFactoryName}}(_options: CreateApiServiceAppOptions = {}) {
36
+ const servConfig = core.config.getOrThrow<ServConfig>('serv')
37
+ {{#if features.crypto}} const transportMode = _options.transport ?? 'config'
38
+ const transport = transportMode === 'disabled' || servConfig.transport === false
39
+ ? undefined
40
+ : {
41
+ crypto,
42
+ keyExchangePath: servConfig.transport.keyExchangePath,
43
+ excludePaths: [...servConfig.transport.excludePaths],
44
+ maxClients: servConfig.transport.maxClients,
45
+ }
46
+ {{else}} const transport = undefined
47
+ {{/if}}
48
+ {{#if features.iam}}
49
+ const refreshCookie = _options.refreshCookie === 'disabled' ? undefined : {}
50
+ {{/if}}
51
+
52
+ const appOptions: Parameters<typeof serv.createApp>[0] = {
53
+ contract: {{api.contractExportName}},
54
+ procedures: {{api.serviceProceduresFactoryName}}({
55
+ app: {
56
+ info: {
57
+ name: pkg.name,
58
+ version: pkg.version,
59
+ transportEnabled: transport !== undefined,
60
+ },
61
+ startedAt,
62
+ },
63
+ }),
64
+ http: servConfig.http,
65
+ {{#if features.iam}}
66
+ iam,
67
+ {{/if}}
68
+ middlewares: [
69
+ {
70
+ middleware: serv.cors({
71
+ origin: origin => resolveCorsOrigin(origin) !== null,
72
+ {{#if features.iam}} credentials: true,
73
+ {{/if}} allowedHeaders: DEFAULT_CORS_ALLOWED_HEADERS,{{#if features.crypto}}
74
+ exposedHeaders: [TRANSPORT_PROTOCOL.ENCRYPTED_HEADER, 'X-Request-Id'],{{/if}}
75
+ }),
76
+ },
77
+ ],
78
+ }
79
+ {{#if features.iam}}
80
+
81
+ appOptions.refreshCookie = refreshCookie
82
+ {{/if}}{{#if features.crypto}}
83
+ if (transport)
84
+ appOptions.transport = transport
85
+ {{/if}}
86
+
87
+ return serv.createApp(appOptions)
88
+ }
89
+
90
+ function resolveCorsOrigin(origin: string | undefined): string | null {
91
+ if (!origin)
92
+ return null
93
+ if (WEBVIEW_ORIGINS.has(origin))
94
+ return origin
95
+ if (LOOPBACK_ORIGIN_RE.test(origin))
96
+ return origin
97
+ return null
98
+ }
@@ -0,0 +1,21 @@
1
+ import process from 'node:process'
2
+ import { core } from '@h-ai/core'
3
+ import { serv } from '@h-ai/serv'
4
+ import { {{api.serviceAppFactoryName}} } from './app.js'
5
+ import { closeApp, initApp } from './lib/server/init.js'
6
+
7
+ const logger = core.logger.child({ app: '{{api.servicePackageName}}', scope: 'entrypoint' })
8
+
9
+ async function main(): Promise<void> {
10
+ await initApp()
11
+
12
+ serv.listen({{api.serviceAppFactoryName}}(), {
13
+ onListening: info => logger.info('API service listening', { address: info.address, port: info.port }),
14
+ onClose: closeApp,
15
+ })
16
+ }
17
+
18
+ main().catch((error: unknown) => {
19
+ logger.error('API service failed to start', { error })
20
+ process.exitCode = 1
21
+ })
@@ -0,0 +1,184 @@
1
+ {{#if features.ai}}import type { AIConfigInput } from '@h-ai/ai'
2
+ {{/if}}{{#if features.cache}}import type { CacheConfigInput } from '@h-ai/cache'
3
+ {{/if}}{{#if features.iam}}import type { IamConfigInput } from '@h-ai/iam'
4
+ {{/if}}{{#if features.crypto}}import type { ServConfig } from '@h-ai/serv'
5
+ {{/if}}{{#if features.storage}}import type { StorageConfigInput } from '@h-ai/storage'
6
+ {{/if}}{{#if features.ai}}import { ai, AIConfigSchema } from '@h-ai/ai'
7
+ {{/if}}{{#if features.cache}}import { cache, CacheConfigSchema } from '@h-ai/cache'
8
+ {{/if}}import { core } from '@h-ai/core'
9
+ {{#if features.crypto}}import { crypto } from '@h-ai/crypto'
10
+ {{/if}}{{#if features.iam}}import { iam, IamConfigSchema } from '@h-ai/iam'
11
+ {{/if}}{{#if features.db}}import { reldb, ReldbConfigSchema } from '@h-ai/reldb'
12
+ {{/if}}import { ServConfigSchema } from '@h-ai/serv'
13
+ {{#if features.storage}}import { storage, StorageConfigSchema } from '@h-ai/storage'
14
+ {{/if}}{{#if features.vecdb}}import { vecdb, VecdbConfigSchema } from '@h-ai/vecdb'
15
+ {{/if}}
16
+
17
+ {{#if features.db}}type DbConfigInput = Parameters<typeof reldb.init>[0]
18
+ {{/if}}{{#if features.vecdb}}type VecdbConfigInput = Parameters<typeof vecdb.init>[0]
19
+ {{/if}}
20
+
21
+ let initialized = false
22
+ let initPromise: Promise<void> | null = null
23
+ {{#if features.crypto}}let cryptoInitialized = false
24
+ {{/if}}
25
+
26
+ export async function initApp(): Promise<void> {
27
+ if (initialized)
28
+ return
29
+ if (initPromise)
30
+ return initPromise
31
+
32
+ initPromise = doInit()
33
+ try {
34
+ await initPromise
35
+ initialized = true
36
+ }
37
+ finally {
38
+ initPromise = null
39
+ }
40
+ }
41
+
42
+ async function doInit(): Promise<void> {
43
+ core.init({
44
+ configDir: './config',
45
+ logging: { level: 'info' },
46
+ })
47
+
48
+ const servValidation = core.config.validate('serv', ServConfigSchema)
49
+ if (!servValidation.success) {
50
+ throw new Error(`Serv config invalid: ${servValidation.error.message}`)
51
+ }
52
+ {{#if features.crypto}}
53
+ const servConfig = core.config.getOrThrow<ServConfig>('serv')
54
+ if (servConfig.transport !== false) {
55
+ const cryptoResult = await crypto.init()
56
+ if (!cryptoResult.success) {
57
+ throw new Error(`Crypto initialization failed: ${cryptoResult.error.message}`)
58
+ }
59
+ cryptoInitialized = true
60
+ }
61
+ {{/if}}{{#if features.db}}
62
+
63
+ const dbValidation = core.config.validate('db', ReldbConfigSchema)
64
+ if (!dbValidation.success) {
65
+ throw new Error(`DB config invalid: ${dbValidation.error.message}`)
66
+ }
67
+ {{/if}}{{#if features.cache}}
68
+
69
+ const cacheValidation = core.config.validate('cache', CacheConfigSchema)
70
+ if (!cacheValidation.success) {
71
+ throw new Error(`Cache config invalid: ${cacheValidation.error.message}`)
72
+ }
73
+ {{/if}}{{#if features.vecdb}}
74
+
75
+ const vecdbValidation = core.config.validate('vecdb', VecdbConfigSchema)
76
+ if (!vecdbValidation.success) {
77
+ throw new Error(`VecDB config invalid: ${vecdbValidation.error.message}`)
78
+ }
79
+ {{/if}}{{#if features.iam}}
80
+
81
+ const iamValidation = core.config.validate('iam', IamConfigSchema)
82
+ if (!iamValidation.success) {
83
+ throw new Error(`IAM config invalid: ${iamValidation.error.message}`)
84
+ }
85
+ {{/if}}{{#if features.storage}}
86
+
87
+ const storageValidation = core.config.validate('storage', StorageConfigSchema)
88
+ if (!storageValidation.success) {
89
+ throw new Error(`Storage config invalid: ${storageValidation.error.message}`)
90
+ }
91
+ {{/if}}{{#if features.ai}}
92
+
93
+ const aiValidation = core.config.validate('ai', AIConfigSchema)
94
+ if (!aiValidation.success) {
95
+ throw new Error(`AI config invalid: ${aiValidation.error.message}`)
96
+ }
97
+ {{/if}}{{#if features.db}}
98
+
99
+ const dbConfig = core.config.getOrThrow<DbConfigInput>('db')
100
+ {{/if}}{{#if features.cache}} const cacheConfig = core.config.getOrThrow<CacheConfigInput>('cache')
101
+ {{/if}}{{#if features.vecdb}} const vecdbConfig = core.config.getOrThrow<VecdbConfigInput>('vecdb')
102
+ {{/if}}{{#if features.iam}} const iamConfig = core.config.getOrThrow<IamConfigInput>('iam')
103
+ {{/if}}{{#if features.storage}} const storageConfig = core.config.getOrThrow<StorageConfigInput>('storage')
104
+ {{/if}}{{#if features.ai}} const aiConfig = core.config.getOrThrow<AIConfigInput>('ai')
105
+ {{/if}}{{#if features.db}}
106
+
107
+ if (dbConfig.type === 'sqlite') {
108
+ const fs = await import('node:fs')
109
+ const path = await import('node:path')
110
+ const dbDir = path.dirname(dbConfig.database)
111
+ if (!fs.existsSync(dbDir)) {
112
+ fs.mkdirSync(dbDir, { recursive: true })
113
+ }
114
+ }
115
+
116
+ const dbResult = await reldb.init(dbConfig)
117
+ if (!dbResult.success) {
118
+ throw new Error(`Database initialization failed: ${dbResult.error.message}`)
119
+ }
120
+ {{/if}}{{#if features.cache}}
121
+
122
+ const cacheResult = await cache.init(cacheConfig)
123
+ if (!cacheResult.success) {
124
+ throw new Error(`Cache initialization failed: ${cacheResult.error.message}`)
125
+ }
126
+ {{/if}}{{#if features.vecdb}}
127
+
128
+ const vecdbResult = await vecdb.init(vecdbConfig)
129
+ if (!vecdbResult.success) {
130
+ throw new Error(`VecDB initialization failed: ${vecdbResult.error.message}`)
131
+ }
132
+ {{/if}}{{#if features.iam}}
133
+
134
+ const iamResult = await iam.init(iamConfig)
135
+ if (!iamResult.success) {
136
+ throw new Error(`IAM initialization failed: ${iamResult.error.message}`)
137
+ }
138
+ {{/if}}{{#if features.storage}}
139
+
140
+ const storageResult = await storage.init(storageConfig)
141
+ if (!storageResult.success) {
142
+ throw new Error(`Storage initialization failed: ${storageResult.error.message}`)
143
+ }
144
+ {{/if}}{{#if features.ai}}
145
+
146
+ const aiResult = await ai.init(aiConfig)
147
+ if (!aiResult.success) {
148
+ throw new Error(`AI initialization failed: ${aiResult.error.message}`)
149
+ }
150
+ {{/if}}
151
+
152
+ core.logger.info('API service initialized')
153
+ }
154
+
155
+ export async function closeApp(): Promise<void> {
156
+ if (!initialized && !initPromise)
157
+ return
158
+
159
+ const closers: Array<readonly [string, () => unknown]> = [
160
+ {{#if features.ai}} ['ai', () => ai.close()],
161
+ {{/if}}{{#if features.storage}} ['storage', () => storage.close()],
162
+ {{/if}}{{#if features.iam}} ['iam', () => iam.close()],
163
+ {{/if}}{{#if features.vecdb}} ['vecdb', () => vecdb.close()],
164
+ {{/if}}{{#if features.cache}} ['cache', () => cache.close()],
165
+ {{/if}}{{#if features.db}} ['reldb', () => reldb.close()],
166
+ {{/if}} ]
167
+ {{#if features.crypto}} if (cryptoInitialized) {
168
+ closers.push(['crypto', () => crypto.close()])
169
+ }
170
+ {{/if}}
171
+
172
+ for (const [name, close] of closers) {
173
+ try {
174
+ await close()
175
+ }
176
+ catch (error) {
177
+ core.logger.warn(`Module close failed: ${name}`, { error })
178
+ }
179
+ }
180
+
181
+ initialized = false
182
+ {{#if features.crypto}} cryptoInitialized = false
183
+ {{/if}} core.logger.info('API service closed')
184
+ }
@@ -0,0 +1,49 @@
1
+ import type { ServContext } from '@h-ai/serv'
2
+ {{#if features.iam}}import type { AppEchoInput, AppEchoOutputData, AppInfoOutputData } from '{{api.contractPackageName}}'
3
+ {{else}}import type { AppEchoOutputData, AppInfoOutputData } from '{{api.contractPackageName}}'
4
+ {{/if}}
5
+ import { ok } from '@h-ai/core'
6
+ import { serv } from '@h-ai/serv'
7
+ import { appContract } from '{{api.contractPackageName}}'
8
+
9
+ export interface AppProcedureDeps {
10
+ readonly info: {
11
+ readonly name: string
12
+ readonly version: string
13
+ readonly transportEnabled: boolean
14
+ }
15
+ readonly startedAt: number
16
+ }
17
+
18
+ const p = serv.implement(appContract).$context<ServContext>()
19
+
20
+ /** 创建应用自有 procedures。 */
21
+ export function createAppProcedures(deps: AppProcedureDeps) {
22
+ return p.router({
23
+ info: p.info.handler(() => {
24
+ const data: AppInfoOutputData = {
25
+ name: deps.info.name,
26
+ version: deps.info.version,
27
+ transportEnabled: deps.info.transportEnabled,
28
+ uptimeMs: Math.max(0, Date.now() - deps.startedAt),
29
+ }
30
+ return ok(data)
31
+ }),
32
+ echo: {{#if features.iam}}p.echo.handler(serv.requireAuth<AppEchoInput, AppEchoOutputData>(({ input, context }) => {
33
+ const data: AppEchoOutputData = {
34
+ message: input.message,
35
+ userId: context.session!.userId,
36
+ requestId: context.requestId,
37
+ timestamp: new Date().toISOString(),
38
+ }
39
+ return Promise.resolve(ok(data))
40
+ })){{else}}p.echo.handler(({ input, context }) => {
41
+ const data: AppEchoOutputData = {
42
+ message: input.message,
43
+ requestId: context.requestId,
44
+ timestamp: new Date().toISOString(),
45
+ }
46
+ return ok(data)
47
+ }){{/if}},
48
+ })
49
+ }
@@ -0,0 +1,18 @@
1
+ import type { AppProcedureDeps } from './app-procedures.js'
2
+ {{#if features.ai}}import { ai } from '@h-ai/ai'
3
+ {{/if}}{{#if features.iam}}import { iam } from '@h-ai/iam'
4
+ {{/if}}{{#if features.ai}}import { createAiProcedures } from '@h-ai/serv/features/ai'
5
+ {{/if}}{{#if features.iam}}import { createIamProcedures } from '@h-ai/serv/features/iam'
6
+ {{/if}}{{#if features.storage}}import { createStorageProcedures } from '@h-ai/serv/features/storage'
7
+ import { storage } from '@h-ai/storage'
8
+ {{/if}}import { createAppProcedures } from './app-procedures.js'
9
+
10
+ /** 创建应用级 procedures 聚合。 */
11
+ export function {{api.serviceProceduresFactoryName}}(deps: { app: AppProcedureDeps }) {
12
+ return {
13
+ {{#if features.iam}} iam: createIamProcedures({ iam }),
14
+ {{/if}}{{#if features.storage}} storage: createStorageProcedures({ storage }),
15
+ {{/if}}{{#if features.ai}} ai: createAiProcedures({ ai }),
16
+ {{/if}} app: createAppProcedures(deps.app),
17
+ }
18
+ }