@h-ai/cli 0.1.0-alpha.56 → 0.1.0-alpha.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +239 -0
- package/README.ja.md +239 -0
- package/README.md +51 -1
- package/dist/chunk-2H7UOFLK.js +0 -0
- package/dist/chunk-F4IBPVZ5.js +355 -0
- package/dist/chunk-F4IBPVZ5.js.map +1 -0
- package/dist/{chunk-O3ANVICQ.js → chunk-WUSFJFW5.js} +13 -7
- package/dist/chunk-WUSFJFW5.js.map +1 -0
- package/dist/cli-config-templates-6XA7V6CC.js +5 -0
- package/dist/{cli-config-templates-OWBEGBZQ.js.map → cli-config-templates-6XA7V6CC.js.map} +1 -1
- package/dist/{cli-skill-templates-ZIWYMS4Y.js → cli-skill-templates-45CK4RQ2.js} +3 -3
- package/dist/{cli-skill-templates-ZIWYMS4Y.js.map → cli-skill-templates-45CK4RQ2.js.map} +1 -1
- package/dist/index.js +134 -125
- package/dist/index.js.map +1 -1
- package/dist/{src-TBIET7YU.js → src-DUGLX4YB.js} +7270 -2119
- package/dist/src-DUGLX4YB.js.map +1 -0
- package/package.json +17 -17
- package/templates/README.md +4 -4
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +7 -0
- package/templates/apps/admin/src/routes/+page.svelte.hbs +5 -4
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +2 -2
- package/templates/apps/api/.gitignore.hbs +13 -0
- package/templates/apps/api/.npmrc.hbs +1 -0
- package/templates/apps/api/Dockerfile.hbs +6 -5
- package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +1 -1
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +2 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +1 -1
- package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +8 -0
- package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -1
- package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +7 -8
- package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +4 -3
- package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +0 -1
- package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/app-procedures.ts.hbs +4 -0
- package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +3 -1
- package/templates/apps/api/e2e/api-service.spec.ts.hbs +4 -2
- package/templates/apps/api/{eslint.config.js → eslint.config.js.hbs} +6 -8
- package/templates/apps/api/package.json.hbs +3 -3
- package/templates/apps/api/pnpm-workspace.yaml.hbs +26 -0
- package/templates/apps/api/tsconfig.base.json +0 -1
- package/templates/apps/fullstack/.dockerignore.hbs +3 -0
- package/templates/apps/fullstack/.gitignore.hbs +16 -0
- package/templates/apps/fullstack/.npmrc.hbs +1 -0
- package/templates/apps/fullstack/Dockerfile.hbs +6 -5
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +5 -8
- package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +7 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +1 -34
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +1 -34
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +30 -170
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +6 -5
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +48 -22
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +3 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +5 -8
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +6 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +1 -28
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +1 -28
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +5 -4
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +10 -141
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +5 -5
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +3 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +21 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +5 -8
- package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +6 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +1 -28
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +1 -28
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +5 -143
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +48 -22
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +207 -17
- package/templates/apps/fullstack/{eslint.config.js → eslint.config.js.hbs} +6 -8
- package/templates/apps/fullstack/package.json.hbs +3 -3
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +2 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +66 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +96 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +3 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +5 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +13 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_audit.yml.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_cache.yml.hbs +2 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +10 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_db.yml.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +21 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +10 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_storage.yml.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +10 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +63 -28
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +26 -11
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +276 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +29 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +94 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +6 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +5 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +98 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +446 -33
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +48 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +19 -26
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +78 -15
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +78 -15
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +4 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +3 -4
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +53 -27
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +73 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +55 -45
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AuditManagement.svelte.hbs +61 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ProfileSettings.svelte.hbs +57 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/RoleManagement.svelte.hbs +49 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/UserManagement.svelte.hbs +174 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +399 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +7 -39
- package/templates/apps/fullstack/packages/{{projectName}}-shared/svelte.config.js.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +151 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +101 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -0
- package/templates/apps/fullstack/playwright.config.ts.hbs +6 -0
- package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +24 -0
- package/templates/apps/fullstack/tsconfig.base.json +0 -1
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +4 -0
- package/templates/apps/h5/src/routes/+page.svelte.hbs +3 -2
- package/templates/apps/mobile-app/index.html.hbs +2 -2
- package/templates/apps/mobile-app/src/App.svelte.hbs +6 -2
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +13 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +8 -2
- package/templates/apps/website/src/routes/+page.svelte.hbs +4 -3
- package/templates/base/.npmrc.hbs +1 -0
- package/templates/base/Dockerfile.hbs +9 -8
- package/templates/base/e2e/app.spec.ts.hbs +1 -0
- package/templates/base/eslint-rules.js +45 -0
- package/templates/base/eslint.config.js.hbs +6 -8
- package/templates/base/package.json.hbs +39 -42
- package/templates/base/pnpm-workspace.yaml.hbs +26 -0
- package/templates/base/src/app.d.ts.hbs +4 -0
- package/templates/base/src/hooks.server.ts.hbs +0 -8
- package/templates/base/src/lib/server/init.ts.hbs +26 -5
- package/templates/base/src/routes/+layout.server.ts.hbs +18 -0
- package/templates/base/tests/scaffold.test.ts.hbs +21 -1
- package/templates/base/vite.config.ts.hbs +21 -0
- package/templates/features/ai/routes/api/chat/+server.ts +6 -7
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +1 -1
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +1 -1
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +14 -10
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +6 -4
- package/templates/features/storage/routes/api/upload/+server.ts +10 -8
- package/templates/skills/AGENTS.md +9 -8
- package/templates/skills/CLAUDE.md +0 -10
- package/templates/skills/bridges/admin/AGENTS.md +8 -0
- package/templates/skills/bridges/admin/copilot-instructions.md +2 -0
- package/templates/skills/bridges/api/AGENTS.md +8 -1
- package/templates/skills/bridges/api/copilot-instructions.md +2 -0
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +21 -4
- package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +5 -0
- package/templates/skills/bridges/h5/AGENTS.md +8 -0
- package/templates/skills/bridges/h5/copilot-instructions.md +2 -0
- package/templates/skills/bridges/mobile-app/AGENTS.md +8 -0
- package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -0
- package/templates/skills/bridges/website/AGENTS.md +8 -0
- package/templates/skills/bridges/website/copilot-instructions.md +2 -0
- package/templates/skills/copilot-instructions.md +2 -0
- package/templates/skills/hai-api-client/SKILL.md +2 -0
- package/templates/skills/hai-app-create/SKILL.md +9 -7
- package/templates/skills/hai-app-create/development.md +72 -0
- package/templates/skills/hai-app-create/reference.md +44 -32
- package/templates/skills/hai-app-review/SKILL.md +50 -144
- package/templates/skills/hai-app-tests/SKILL.md +3 -1
- package/templates/skills/hai-app-tests/reference.md +47 -27
- package/templates/skills/hai-build/SKILL.md +5 -4
- package/templates/skills/hai-build/reference.md +56 -34
- package/templates/skills/hai-ci/SKILL.md +8 -15
- package/templates/skills/hai-core/SKILL.md +2 -0
- package/templates/skills/hai-core/reference.md +6 -4
- package/templates/skills/hai-framework-sync/SKILL.md +8 -2
- package/templates/skills/hai-pr-review/SKILL.md +5 -4
- package/templates/skills/hai-reldb/SKILL.md +1 -0
- package/templates/skills/hai-reldb/reference.md +3 -0
- package/templates/skills/hai-scheduler/SKILL.md +3 -0
- package/templates/skills/hai-serv/SKILL.md +2 -0
- package/templates/skills/hai-serv/reference.md +18 -2
- package/templates/skills/hai-storage/SKILL.md +3 -1
- package/templates/skills/hai-ui/SKILL.md +6 -0
- package/templates/skills/hai-ui/reference.md +7 -4
- package/templates/skills/hai-vecdb/reference.md +53 -49
- package/dist/chunk-O3ANVICQ.js.map +0 -1
- package/dist/chunk-WUYLYCW2.js +0 -237
- package/dist/chunk-WUYLYCW2.js.map +0 -1
- package/dist/cli-config-templates-OWBEGBZQ.js +0 -5
- package/dist/src-TBIET7YU.js.map +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/tests/api.test.ts.hbs +0 -28
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/tests/api.test.ts.hbs +0 -28
- package/templates/apps/fullstack/apps/{{projectName}}-web/tests/api.test.ts.hbs +0 -55
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/LanguageSwitcher.svelte.hbs +0 -27
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +0 -18
- package/templates/skills/bridges/admin/CLAUDE.md +0 -11
- package/templates/skills/bridges/api/CLAUDE.md +0 -11
- package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +0 -5
- package/templates/skills/bridges/h5/CLAUDE.md +0 -11
- package/templates/skills/bridges/mobile-app/CLAUDE.md +0 -11
- package/templates/skills/bridges/website/CLAUDE.md +0 -11
|
@@ -173,6 +173,8 @@ const page = await reldb.sql.queryPage<User>({
|
|
|
173
173
|
|
|
174
174
|
通过配置创建单表 CRUD 仓库,免写 SQL:
|
|
175
175
|
|
|
176
|
+
`CrudConfig.dbType` 必填,必须与实际初始化的数据库后端一致(含环境变量覆盖后的类型)。以下为 SQLite 示例;切换到 PostgreSQL/MySQL 时同步修改。`BaseReldbCrudRepository` 会从已初始化的 `reldb.config.type` 获取类型,无需手动传入。
|
|
177
|
+
|
|
176
178
|
```typescript
|
|
177
179
|
const userCrud = reldb.crud.table<{ id: number, name: string, email: string }>({
|
|
178
180
|
table: 'users',
|
|
@@ -180,6 +182,7 @@ const userCrud = reldb.crud.table<{ id: number, name: string, email: string }>({
|
|
|
180
182
|
select: ['id', 'name', 'email'], // 查询列,默认 '*'
|
|
181
183
|
createColumns: ['name', 'email'], // 允许插入的列
|
|
182
184
|
updateColumns: ['name', 'email'], // 允许更新的列
|
|
185
|
+
dbType: 'sqlite', // 必填,与本例初始化后端一致
|
|
183
186
|
})
|
|
184
187
|
```
|
|
185
188
|
|
|
@@ -9,6 +9,8 @@ description: "使用 @h-ai/scheduler 注册 cron/API/JS/Hook 任务、手工触
|
|
|
9
9
|
|
|
10
10
|
持久化动态任务每个 `tickInterval`(默认 1000ms)在运行节点刷新;API 操作及获锁后的每次尝试重读定义,读取失败或任务已禁用/删除/改期时中断执行。`tasks` 仅表示最近成功刷新快照,已开始的外部副作用不会回滚。跨节点任务使用 `register()` 与共享数据库、Redis;`init({ tasks })` 是节点本地配置,memory cache 不支持跨进程防重。
|
|
11
11
|
|
|
12
|
+
`refreshTasks()` 主动刷新而不执行,同一快照的并发读取合并;保存、更新和删除落库成功后才发布内存投影。清空可选策略使用 `retry: null` / `handler: null`。Hook 业务异常为 `failed` 并重试,缺处理器、取消或 `SchedulerTaskSkippedError` 为 `interrupted`;一次性任务只在成功后删除。`event.context.occurrenceId` 在一次发生的重试期间不变,宿主用其绑定持久幂等回执;跨周期长任务使用宿主持久租约。配置被替换时旧发生停止重试,成功清理前再次核对定义。
|
|
13
|
+
|
|
12
14
|
关闭必须 `await scheduler.close()` 后再关闭数据库和缓存:关闭会拒绝新任务、取消 HTTP/Worker/重试并等待执行链退出。生命周期回调通过事件 `signal` 协作取消,必须自行停止外部副作用,禁止在 Hook 阻塞主线程。旧任务取消后不重试、不删除新实例同 ID 的任务。
|
|
13
15
|
|
|
14
16
|
JS 任务每次调用独立 Worker,默认 30000 毫秒期限包含线程启动;超时后等待线程终止才返回失败或重试,同步死循环不会占用主事件循环。上下文和结果须支持结构化克隆。Worker/vm 不构成安全沙箱,仍只接受受信任的服务端代码。
|
|
@@ -140,6 +142,7 @@ const logs = await scheduler.getLogs({
|
|
|
140
142
|
| `init` | `(config?) => Promise<HaiResult<void>>` | 初始化调度器 |
|
|
141
143
|
| `register` | `(task) => Promise<HaiResult<void>>` | 注册统一任务模型 |
|
|
142
144
|
| `updateTask` | `(taskId, updates) => Promise<HaiResult<void>>` | 更新 cron / params / handler |
|
|
145
|
+
| `refreshTasks` | `() => Promise<HaiResult<void>>` | 主动刷新共享定义,不执行任务 |
|
|
143
146
|
| `register` 扩展字段 | `description / deleteAfterRun / retry` | 支持任务描述、一次性任务、失败重试策略 |
|
|
144
147
|
| `trigger` | `(taskId, { source? }) => Promise<HaiResult<TaskExecutionLog>>` | 手工触发并记录来源 |
|
|
145
148
|
| `getLogs` | `(options?) => Promise<HaiResult<PaginatedResult<TaskExecutionLog>>>` | 支持按 trigger + startedAfter/startedBefore 过滤日志 |
|
|
@@ -19,7 +19,9 @@ description: "使用 @h-ai/serv 装配 contract/procedures、认证守卫、Open
|
|
|
19
19
|
|
|
20
20
|
- 先确定 Node listen 还是 Fetch adapter,再从共享 contract 装配 procedures;不要直接暴露 Hono。
|
|
21
21
|
- 认证绑定 route 的 auth/permission/role;启动配置错误与正常请求领域错误分别处理。
|
|
22
|
+
- 普通 procedure 的失败 HaiResult 默认通过 HTTP 200 返回,必须检查 success 与 error.code;error.httpStatus 是领域错误元数据。contract 输入校验失败为 HTTP 400,HTTP middleware、刷新 cookie 等响应另按自身契约处理,不能混为同一种状态映射。
|
|
22
23
|
- 浏览器 Cookie、CORS、apiPrefix、transport 须与 api-client 同步;语音 ticket 单独核验。
|
|
24
|
+
- 缺失路由返回本地化 HaiResult JSON 404;加密传输保留该状态。默认 feature 可按需选用,contract 与挂载的 procedures 保持一致。
|
|
23
25
|
|
|
24
26
|
## 按需参考
|
|
25
27
|
|
|
@@ -374,7 +374,7 @@ await apiClient.init({
|
|
|
374
374
|
3. `iam.session.verifyToken`(推荐:传入 `iam` 后自动启用)
|
|
375
375
|
4. 默认 `parseRequestContext`:仅解析请求元数据,`session` 为 `undefined`
|
|
376
376
|
|
|
377
|
-
> ⚠️ `verifyToken` 会在每次请求调用(不缓存);verifyToken 失败或抛错统一收敛为 `session=undefined`,由 route 的 `.auth()` / `.permission()` / `.role()`
|
|
377
|
+
> ⚠️ `verifyToken` 会在每次请求调用(不缓存);verifyToken 失败或抛错统一收敛为 `session=undefined`,由 route 的 `.auth()` / `.permission()` / `.role()` 返回失败 HaiResult,`error.httpStatus=401`;普通 procedure 的 HTTP 响应默认仍为 200。
|
|
378
378
|
|
|
379
379
|
### 链式 procedure guard
|
|
380
380
|
|
|
@@ -403,7 +403,7 @@ const procedures = serv
|
|
|
403
403
|
.build()
|
|
404
404
|
```
|
|
405
405
|
|
|
406
|
-
- `.permission()` / `.role()` 隐含 `.auth()`;未登录返回 401
|
|
406
|
+
- `.permission()` / `.role()` 隐含 `.auth()`;未登录返回 `error.httpStatus=401` 的失败 HaiResult,授权不足为 403。普通 procedure 的 HTTP 响应默认仍为 200,必须检查 `success` 与 `error.code`。
|
|
407
407
|
- 同一路由声明多个 permission/role 时必须全部满足。
|
|
408
408
|
- handler 的未处理异常由 router 统一转换成 INTERNAL_ERROR HaiResult。
|
|
409
409
|
- 重复/未知路径会被拒绝;遗漏 contract procedure 时 `.build()` 在类型上不可用,运行时也会校验。
|
|
@@ -522,6 +522,20 @@ HTTP 审计、限流、CORS、租户头校验等跨 route 能力继续放在
|
|
|
522
522
|
|
|
523
523
|
### 正常业务请求中的错误与 i18n
|
|
524
524
|
|
|
525
|
+
先区分 HTTP 状态与 HaiResult 中的 `error.httpStatus`;普通 procedure 返回的领域错误元数据不会自动改写 HTTP 状态,当前默认装配如下(显式自定义响应状态或 middleware 按实际入口契约验证):
|
|
526
|
+
|
|
527
|
+
| 失败来源 | HTTP 响应 | 结果判定 |
|
|
528
|
+
| --- | --- | --- |
|
|
529
|
+
| procedure `.auth()` / `.permission()` / `.role()` | 200 | `success=false`;`error.httpStatus` 为 401 / 403 |
|
|
530
|
+
| handler 返回 `err(...)` 或下游模块失败 HaiResult | 200 | 检查 `success`、`error.code`,例如数据库查询错误的 `error.httpStatus=500` |
|
|
531
|
+
| handler 未处理异常被 route 实现器捕获 | 200 | INTERNAL_ERROR 失败 HaiResult,`error.httpStatus=500` |
|
|
532
|
+
| oRPC contract 输入 schema 校验失败(handler 之前) | 400 | 本地化失败体,`error.httpStatus=400` 与字段错误 |
|
|
533
|
+
| handler 内 `serv.validateInputOrFail(...)` 失败 | 200 | 失败 HaiResult,`error.httpStatus=400` 与字段错误 |
|
|
534
|
+
|
|
535
|
+
HTTP middleware、自定义 Response、refresh-cookie、OpenAPI/RPC 入口权限和 transport 协议错误分别按自身响应契约处理,可返回真实 HTTP 4xx/5xx。`@h-ai/api-client` 在真实 HTTP 401 或 HTTP 200 的有效失败 HaiResult(`success=false`、字符串 `error.code/message`、`error.httpStatus=401`)后自动刷新,成功后只重试一次;内置登录、注册和配置的刷新路径除外,403/500 不刷新。启用 transport 时刷新和重试复用加密链路,不能手写明文刷新请求。
|
|
536
|
+
|
|
537
|
+
SvelteKit 的 `kit.response.fromError` 根据 `error.httpStatus` 生成 HTTP Response;`kit.response.fromResult` 使用显式错误码映射,未命中默认 400。这些响应转换规则不能套用到 serv 普通 procedure。
|
|
538
|
+
|
|
525
539
|
按三层处理:
|
|
526
540
|
|
|
527
541
|
1. **oRPC contract 输入校验**:进入 handler 前自动发生;`serv.createApp()` 会把默认英文 Zod 错误改写为本地化 `errors[]`。
|
|
@@ -598,6 +612,8 @@ http: {
|
|
|
598
612
|
|
|
599
613
|
## Feature Procedures(默认实现)
|
|
600
614
|
|
|
615
|
+
`serv.implement(...).context().route(...).build()` 同步返回普通 router,可直接按嵌套属性选取 `@h-ai/serv/features/iam` 等默认 procedures。挂载 contract 只包含实际选用的路由;不要为复用当前用户或刷新功能而同时开放注册、OTP 或通用管理入口。
|
|
616
|
+
|
|
601
617
|
`@h-ai/serv` 内置了三个 feature 模块,开箱即用:
|
|
602
618
|
|
|
603
619
|
| 导入路径 | 工厂函数 | 所需依赖 |
|
|
@@ -25,7 +25,7 @@ description: "使用 @h-ai/storage 访问本地/S3 文件、目录和预签名
|
|
|
25
25
|
|
|
26
26
|
- 文件上传与下载
|
|
27
27
|
- 预签名 URL 生成(客户端直传)
|
|
28
|
-
- S3 兼容存储对接(AWS S3、MinIO、阿里云 OSS 等)
|
|
28
|
+
- S3 兼容存储对接(AWS S3、MinIO、RustFS、阿里云 OSS 等)
|
|
29
29
|
- 本地开发文件存储
|
|
30
30
|
- 目录前缀清理与批量文件删除
|
|
31
31
|
|
|
@@ -57,6 +57,8 @@ operationLog:
|
|
|
57
57
|
约定环境变量优先于 YAML,例如 `HAI_STORAGE_ROOT`、
|
|
58
58
|
`HAI_STORAGE_ACCESSKEYID`、`HAI_STORAGE_SECRETACCESSKEY`。
|
|
59
59
|
|
|
60
|
+
MinIO、RustFS 使用同一个 S3 Provider:配置 `type: s3`、S3 API `endpoint`(通常为 9000 端口)和 `forcePathStyle: true`,并预先创建 `bucket`;不要新增 `type: minio` 或 `type: rustfs`。
|
|
61
|
+
|
|
60
62
|
`operationLog` 在 Local/S3 Provider 的真实 file/dir/presign 操作处输出日志,不要在 `storage-main.ts` 或调用方重复包装。文件内容不会写入日志,上传数据只记录字节长度;`maxLength` 用于截断序列化后的参数,`level` 默认 `debug`。
|
|
61
63
|
|
|
62
64
|
### 2. 初始化与关闭
|
|
@@ -7,6 +7,8 @@ description: "使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、移动
|
|
|
7
7
|
|
|
8
8
|
## 能力契约
|
|
9
9
|
|
|
10
|
+
主题 DOM 与安全缓存复用 `@h-ai/ui/theme` 的 `applyTheme` / `getSavedTheme(fallbackTheme?)`;默认主题取应用配置,选择范围与已编译 CSS 主题一致。
|
|
11
|
+
|
|
10
12
|
| 项目 | 契约 |
|
|
11
13
|
| --- | --- |
|
|
12
14
|
| 能力 | 使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、移动界面、主题与 AI 内容展示 |
|
|
@@ -18,7 +20,11 @@ description: "使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、移动
|
|
|
18
20
|
## 使用路径
|
|
19
21
|
|
|
20
22
|
- 先检查组件导入、Tailwind @source 和主题 CSS,再选场景 → 组合 → 原子组件,缺能力才自定义。
|
|
23
|
+
- 按安装版本的 exports 选择公开 components 目录入口;主题工具使用 `@h-ai/ui/theme`,避免仅为主题加载根入口的 AI/图表组件。禁止导入内部 src/dist;例如原子组件使用 `@h-ai/ui/components/primitives/index`。
|
|
24
|
+
- 自动导入识别无分号、跨行及别名的运行时 import;已绑定的本地组件名称不会重复注入。
|
|
21
25
|
- 应用只提供页面级文案;组件内部中英文由 @h-ai/ui 维护。
|
|
26
|
+
- `UserProfile` 用 `avatarAccept` / `avatarHint` 对齐业务的头像格式与大小限制;文件最终校验和上传由业务回调完成。
|
|
27
|
+
- `BareInput type="file"` 通过 `onchange` 的 `currentTarget.files` 读取文件,不绑定文件路径 `value`;其他输入类型可 `bind:value`。
|
|
22
28
|
- AI 文本视为不可信;Markdown/Mermaid 预览与允许执行 HTML/JS 的预览有不同边界。
|
|
23
29
|
|
|
24
30
|
## 按需参考
|
|
@@ -257,7 +257,7 @@ const p = usePlatform()
|
|
|
257
257
|
| ------------ | ------------------------------------------------------------------ | ------------- |
|
|
258
258
|
| `Form` | `loading`, `disabled`, `onsubmit` | 表单容器 |
|
|
259
259
|
| `FormField` | `label`, `name`, `error`, `hint`, `required` | 表单字段 |
|
|
260
|
-
| `Modal` | `open`, `title`, `size`, `closeOnBackdrop` |
|
|
260
|
+
| `Modal` | `open`, `title`, `size`, `closeOnBackdrop` | 模态框,内置对话框语义、焦点约束和关闭后焦点恢复 |
|
|
261
261
|
| `Drawer` | `open`, `position`, `size`, `width`, `resizable`, `widthStorageKey` | 可选拖动并记忆宽度的抽屉 |
|
|
262
262
|
| `DataTable` | `data`, `columns`, `keyField`, `sortKey`, `sortDir`, `onsort`, snippet slots | 数据表格(列定义 `sortable` 可排序) |
|
|
263
263
|
| `Combobox` | `options`, `value`, `multiple`, `placeholder`, `error`, `onchange` | 可搜索选择 |
|
|
@@ -351,7 +351,7 @@ const p = usePlatform()
|
|
|
351
351
|
| `AuthShell` | `variant`('card'/'split'), `title`, `brandTitle`, `brandText`, `illustration`, `description`, `highlights` | 认证页布局(包裹登录/注册表单) |
|
|
352
352
|
| `LoginForm` | `showRememberMe`, `showRegisterLink`, `errors` | 登录表单 |
|
|
353
353
|
| `RegisterForm` | `fields`, `minPasswordLength`, `errors` | 注册表单 |
|
|
354
|
-
| `UserProfile` | `user`, `editable`, `fields`, `
|
|
354
|
+
| `UserProfile` | `user`, `editable`, `fields`, `avatarAccept`, `avatarHint` | 用户资料,选择器和提示对齐业务校验;最终验证和上传仍由回调负责 |
|
|
355
355
|
|
|
356
356
|
#### 错误页 / 设置场景组件
|
|
357
357
|
|
|
@@ -532,10 +532,11 @@ form={{ variant: 'drawer', drawerWidth: '40rem' }}
|
|
|
532
532
|
支持 15 个精选 DaisyUI 主题。
|
|
533
533
|
|
|
534
534
|
```typescript
|
|
535
|
-
import { applyTheme, getCurrentTheme, isDarkTheme, THEMES, THEME_GROUPS } from '@h-ai/ui'
|
|
535
|
+
import { applyTheme, getCurrentTheme, getSavedTheme, isDarkTheme, THEMES, THEME_GROUPS } from '@h-ai/ui/theme'
|
|
536
536
|
|
|
537
537
|
applyTheme('dark') // 应用主题(自动持久化 localStorage)
|
|
538
538
|
getCurrentTheme() // 获取当前主题名
|
|
539
|
+
getSavedTheme('corporate') // 存储为空或不可用时使用应用默认主题
|
|
539
540
|
isDarkTheme('dracula') // 检查是否暗色主题
|
|
540
541
|
```
|
|
541
542
|
|
|
@@ -583,8 +584,10 @@ typescript, javascript, python, java, go, rust, c, cpp, csharp, ruby, php, swift
|
|
|
583
584
|
| 路径 | 用途 |
|
|
584
585
|
| --------------------------- | -------------------------------------- |
|
|
585
586
|
| `@h-ai/ui` | 主入口:所有组件、工具函数、类型 |
|
|
587
|
+
| `@h-ai/ui/theme` | 轻量主题元数据与工具,不经过组件根入口 |
|
|
586
588
|
| `@h-ai/ui/auto-import` | Svelte 预处理器:组件自动导入 |
|
|
587
|
-
| `@h-ai/ui/components/*` |
|
|
589
|
+
| `@h-ai/ui/components/*` | 公开组件目录的 JS 入口,按实际 exports/产物选择 |
|
|
590
|
+
| `@h-ai/ui/components/primitives/index` | 公开原子组件目录入口,如 Button/Input |
|
|
588
591
|
| `@h-ai/ui/styles/global.css` | 全局基础样式(重置/滚动条/焦点) |
|
|
589
592
|
| `@h-ai/ui/styles/theme.css` | Tailwind v4 `@theme` Token |
|
|
590
593
|
| `@h-ai/ui/styles/design-tokens.css`| CSS 自定义属性(间距/圆角/z-index) |
|
|
@@ -32,7 +32,7 @@ path: ./data/vecdb
|
|
|
32
32
|
# indexType: hnsw
|
|
33
33
|
# tablePrefix: vec_
|
|
34
34
|
|
|
35
|
-
# Qdrant
|
|
35
|
+
# Qdrant(服务端 1.10.0+,使用 Query API)
|
|
36
36
|
# type: qdrant
|
|
37
37
|
# url: http://localhost:6333
|
|
38
38
|
# apiKey: ''
|
|
@@ -76,22 +76,22 @@ if (!closeResult.success) {
|
|
|
76
76
|
|
|
77
77
|
### 3. 选择操作接口
|
|
78
78
|
|
|
79
|
-
| 接口 | 用途
|
|
80
|
-
| ---------- |
|
|
81
|
-
| collection | 集合创建/删除/查询/判断存在
|
|
79
|
+
| 接口 | 用途 | 入口 |
|
|
80
|
+
| ---------- | ---------------------------- | ------------------ |
|
|
81
|
+
| collection | 集合创建/删除/查询/判断存在 | `vecdb.collection` |
|
|
82
82
|
| vector | 向量插入/更新/删除/搜索/计数 | `vecdb.vector` |
|
|
83
83
|
|
|
84
84
|
## 核心 API
|
|
85
85
|
|
|
86
86
|
### 集合操作 — `vecdb.collection`
|
|
87
87
|
|
|
88
|
-
| 方法 | 签名
|
|
89
|
-
| -------- |
|
|
90
|
-
| `create` | `(name, options) => HaiResult<void>`
|
|
91
|
-
| `drop` | `(name) => HaiResult<void>`
|
|
92
|
-
| `exists` | `(name) => HaiResult<boolean>`
|
|
93
|
-
| `info` | `(name) => HaiResult<CollectionInfo>`
|
|
94
|
-
| `list` | `() => HaiResult<string[]>`
|
|
88
|
+
| 方法 | 签名 | 说明 |
|
|
89
|
+
| -------- | ------------------------------------- | ---------------- |
|
|
90
|
+
| `create` | `(name, options) => HaiResult<void>` | 创建集合 |
|
|
91
|
+
| `drop` | `(name) => HaiResult<void>` | 删除集合 |
|
|
92
|
+
| `exists` | `(name) => HaiResult<boolean>` | 判断集合是否存在 |
|
|
93
|
+
| `info` | `(name) => HaiResult<CollectionInfo>` | 获取集合信息 |
|
|
94
|
+
| `list` | `() => HaiResult<string[]>` | 列出所有集合 |
|
|
95
95
|
|
|
96
96
|
> 所有方法均返回 `Promise<HaiResult<T>>`,上表省略异步与错误类型。
|
|
97
97
|
|
|
@@ -113,20 +113,20 @@ const list = await vecdb.collection.list()
|
|
|
113
113
|
|
|
114
114
|
```typescript
|
|
115
115
|
interface CollectionCreateOptions {
|
|
116
|
-
dimension: number
|
|
117
|
-
metric?: 'cosine' | 'euclidean' | 'dot'
|
|
116
|
+
dimension: number // 向量维度(必填)
|
|
117
|
+
metric?: 'cosine' | 'euclidean' | 'dot' // 距离度量(默认 cosine)
|
|
118
118
|
}
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
### 向量操作 — `vecdb.vector`
|
|
122
122
|
|
|
123
|
-
| 方法 | 签名
|
|
124
|
-
| -------- |
|
|
125
|
-
| `insert` | `(collection, documents) => HaiResult<void>`
|
|
126
|
-
| `upsert` | `(collection, documents) => HaiResult<void>`
|
|
127
|
-
| `delete` | `(collection, ids) => HaiResult<void>`
|
|
128
|
-
| `search` | `(collection, vector, options?) => HaiResult<SearchResult[]>` | 向量搜索
|
|
129
|
-
| `count` | `(collection) => HaiResult<number>`
|
|
123
|
+
| 方法 | 签名 | 说明 |
|
|
124
|
+
| -------- | ------------------------------------------------------------- | ------------- |
|
|
125
|
+
| `insert` | `(collection, documents) => HaiResult<void>` | 批量插入 |
|
|
126
|
+
| `upsert` | `(collection, documents) => HaiResult<void>` | 批量更新/插入 |
|
|
127
|
+
| `delete` | `(collection, ids) => HaiResult<void>` | 按 ID 删除 |
|
|
128
|
+
| `search` | `(collection, vector, options?) => HaiResult<SearchResult[]>` | 向量搜索 |
|
|
129
|
+
| `count` | `(collection) => HaiResult<number>` | 文档计数 |
|
|
130
130
|
|
|
131
131
|
> 所有方法均返回 `Promise<HaiResult<T>>`,上表省略异步与错误类型。
|
|
132
132
|
|
|
@@ -166,10 +166,10 @@ await vecdb.vector.delete('docs', ['doc-1', 'doc-2'])
|
|
|
166
166
|
|
|
167
167
|
```typescript
|
|
168
168
|
interface VectorDocument {
|
|
169
|
-
id: string
|
|
170
|
-
vector: number[]
|
|
171
|
-
content?: string
|
|
172
|
-
metadata?: Record<string, unknown>
|
|
169
|
+
id: string // 文档唯一标识
|
|
170
|
+
vector: number[] // 向量数据
|
|
171
|
+
content?: string // 文本内容(可选)
|
|
172
|
+
metadata?: Record<string, unknown> // 元数据(可选)
|
|
173
173
|
}
|
|
174
174
|
```
|
|
175
175
|
|
|
@@ -177,30 +177,30 @@ interface VectorDocument {
|
|
|
177
177
|
|
|
178
178
|
```typescript
|
|
179
179
|
interface VectorSearchOptions {
|
|
180
|
-
topK?: number
|
|
181
|
-
filter?: Record<string, unknown>
|
|
182
|
-
minScore?: number
|
|
180
|
+
topK?: number // 返回数量(默认 10)
|
|
181
|
+
filter?: Record<string, unknown> // 元数据过滤(键值精确匹配)
|
|
182
|
+
minScore?: number // 最低相似度阈值(0-1)
|
|
183
183
|
}
|
|
184
184
|
```
|
|
185
185
|
|
|
186
186
|
## 错误码 — `HaiVecdbError`
|
|
187
187
|
|
|
188
|
-
| 错误码 | code
|
|
189
|
-
| ----------------------------------------- |
|
|
190
|
-
| `HaiVecdbError.CONNECTION_FAILED` | `hai:vecdb:001`
|
|
191
|
-
| `HaiVecdbError.QUERY_FAILED`
|
|
192
|
-
| `HaiVecdbError.COLLECTION_NOT_FOUND`
|
|
193
|
-
| `HaiVecdbError.COLLECTION_ALREADY_EXISTS
|
|
194
|
-
| `HaiVecdbError.DIMENSION_MISMATCH`
|
|
195
|
-
| `HaiVecdbError.INSERT_FAILED`
|
|
196
|
-
| `HaiVecdbError.DELETE_FAILED`
|
|
197
|
-
| `HaiVecdbError.UPDATE_FAILED`
|
|
198
|
-
| `HaiVecdbError.INDEX_BUILD_FAILED`
|
|
199
|
-
| `HaiVecdbError.NOT_INITIALIZED`
|
|
200
|
-
| `HaiVecdbError.CONFIG_ERROR`
|
|
201
|
-
| `HaiVecdbError.UNSUPPORTED_TYPE`
|
|
202
|
-
| `HaiVecdbError.DRIVER_NOT_FOUND`
|
|
203
|
-
| `HaiVecdbError.SERIALIZATION_FAILED`
|
|
188
|
+
| 错误码 | code | 说明 |
|
|
189
|
+
| ----------------------------------------- | --------------- | ------------------ |
|
|
190
|
+
| `HaiVecdbError.CONNECTION_FAILED` | `hai:vecdb:001` | 连接失败 |
|
|
191
|
+
| `HaiVecdbError.QUERY_FAILED` | `hai:vecdb:002` | 查询失败 |
|
|
192
|
+
| `HaiVecdbError.COLLECTION_NOT_FOUND` | `hai:vecdb:003` | 集合不存在 |
|
|
193
|
+
| `HaiVecdbError.COLLECTION_ALREADY_EXISTS` | `hai:vecdb:004` | 集合已存在 |
|
|
194
|
+
| `HaiVecdbError.DIMENSION_MISMATCH` | `hai:vecdb:005` | 向量维度不匹配 |
|
|
195
|
+
| `HaiVecdbError.INSERT_FAILED` | `hai:vecdb:006` | 插入失败 |
|
|
196
|
+
| `HaiVecdbError.DELETE_FAILED` | `hai:vecdb:007` | 删除失败 |
|
|
197
|
+
| `HaiVecdbError.UPDATE_FAILED` | `hai:vecdb:008` | 更新失败 |
|
|
198
|
+
| `HaiVecdbError.INDEX_BUILD_FAILED` | `hai:vecdb:009` | 索引构建失败 |
|
|
199
|
+
| `HaiVecdbError.NOT_INITIALIZED` | `hai:vecdb:010` | 未初始化 |
|
|
200
|
+
| `HaiVecdbError.CONFIG_ERROR` | `hai:vecdb:011` | 配置错误 |
|
|
201
|
+
| `HaiVecdbError.UNSUPPORTED_TYPE` | `hai:vecdb:012` | 不支持的数据库类型 |
|
|
202
|
+
| `HaiVecdbError.DRIVER_NOT_FOUND` | `hai:vecdb:013` | 驱动未安装 |
|
|
203
|
+
| `HaiVecdbError.SERIALIZATION_FAILED` | `hai:vecdb:014` | 序列化失败 |
|
|
204
204
|
|
|
205
205
|
## 常见模式
|
|
206
206
|
|
|
@@ -212,14 +212,16 @@ import { vecdb } from '@h-ai/vecdb'
|
|
|
212
212
|
|
|
213
213
|
// 将查询文本转为向量
|
|
214
214
|
const embedResult = await ai.embedding.embedText(query)
|
|
215
|
-
if (!embedResult.success)
|
|
215
|
+
if (!embedResult.success)
|
|
216
|
+
return embedResult
|
|
216
217
|
|
|
217
218
|
// 检索最相似的文档
|
|
218
219
|
const searchResult = await vecdb.vector.search('knowledge', embedResult.data, {
|
|
219
220
|
topK: 5,
|
|
220
221
|
minScore: 0.7,
|
|
221
222
|
})
|
|
222
|
-
if (!searchResult.success)
|
|
223
|
+
if (!searchResult.success)
|
|
224
|
+
return searchResult
|
|
223
225
|
|
|
224
226
|
// 拼接上下文,送入 LLM
|
|
225
227
|
const context = searchResult.data.map(r => r.content).join('\n\n')
|
|
@@ -234,8 +236,8 @@ const chatResult = await ai.llm.chat({
|
|
|
234
236
|
### 文档入库
|
|
235
237
|
|
|
236
238
|
```typescript
|
|
237
|
-
import { datapipe } from '@h-ai/datapipe'
|
|
238
239
|
import { ai } from '@h-ai/ai'
|
|
240
|
+
import { datapipe } from '@h-ai/datapipe'
|
|
239
241
|
import { vecdb } from '@h-ai/vecdb'
|
|
240
242
|
|
|
241
243
|
// 清洗 + 分块
|
|
@@ -244,13 +246,15 @@ const pipeline = await datapipe.pipeline()
|
|
|
244
246
|
.chunk({ mode: 'markdown', maxSize: 1000, overlap: 100 })
|
|
245
247
|
.run(rawText)
|
|
246
248
|
|
|
247
|
-
if (!pipeline.success)
|
|
249
|
+
if (!pipeline.success)
|
|
250
|
+
return pipeline
|
|
248
251
|
|
|
249
252
|
// 批量生成嵌入
|
|
250
253
|
const embeddings = await ai.embedding.embedBatch(
|
|
251
254
|
pipeline.data.chunks.map(c => c.content),
|
|
252
255
|
)
|
|
253
|
-
if (!embeddings.success)
|
|
256
|
+
if (!embeddings.success)
|
|
257
|
+
return embeddings
|
|
254
258
|
|
|
255
259
|
// 批量入库
|
|
256
260
|
const docs = pipeline.data.chunks.map((chunk, i) => ({
|
|
@@ -265,7 +269,7 @@ await vecdb.vector.insert('knowledge', docs)
|
|
|
265
269
|
### 错误分支处理
|
|
266
270
|
|
|
267
271
|
```typescript
|
|
268
|
-
import {
|
|
272
|
+
import { HaiVecdbError, vecdb } from '@h-ai/vecdb'
|
|
269
273
|
|
|
270
274
|
const result = await vecdb.collection.create('docs', { dimension: 1536 })
|
|
271
275
|
if (!result.success) {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/cli-config-templates.ts"],"names":[],"mappings":"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","file":"chunk-O3ANVICQ.js","sourcesContent":["/**\n * @h-ai/cli — 配置文件模板\n *\n * 为各模块生成默认配置文件内容。\n * @module cli-config-templates\n */\n\nimport type { AiModuleConfig, CacheModuleConfig, CoreModuleConfig, DbModuleConfig, FeatureId, IamModuleConfig, ModuleConfigs, StorageModuleConfig } from '../cli-types.js'\n\n/**\n * 生成模块配置文件内容\n *\n * @param moduleKey - 模块标识(core/serv/db/cache/iam/storage/ai)\n * @param configs - 用户自定义配置值\n * @returns YAML 格式的配置内容\n */\nexport function generateConfigFile(moduleKey: string, configs?: ModuleConfigs): string {\n switch (moduleKey) {\n case 'core':\n return generateCoreConfig(configs?.core)\n case 'serv':\n return generateServConfig()\n case 'db':\n return generateDbConfig(configs?.db)\n case 'cache':\n return generateCacheConfig(configs?.cache)\n case 'iam':\n return generateIamConfig(configs?.iam)\n case 'storage':\n return generateStorageConfig(configs?.storage)\n case 'ai':\n return generateAiConfig(configs?.ai)\n case 'deploy':\n return generateDeployConfig()\n case 'vecdb':\n return generateVecdbConfig()\n case 'reach':\n return generateReachConfig()\n case 'scheduler':\n return generateSchedulerConfig()\n case 'audit':\n return generateAuditConfig()\n case 'payment':\n return generatePaymentConfig()\n default:\n return `# ${moduleKey} 配置\\n`\n }\n}\n\nfunction generateCoreConfig(cfg?: CoreModuleConfig): string {\n const name = cfg?.name ?? 'my-app'\n const locale = cfg?.defaultLocale ?? 'zh-CN'\n const supportedLocales = locale === 'en-US'\n ? ` - en-US\\n - zh-CN`\n : ` - zh-CN\\n - en-US`\n\n return `# =============================================================================\n# 应用配置\n# =============================================================================\n\nname: ${name}\nversion: 0.1.0\nenv: development\ndebug: false\n\ndefaultLocale: ${locale}\nsupportedLocales:\n${supportedLocales}\n`\n}\n\nfunction generateServConfig(): string {\n return `# =============================================================================\n# Service / HTTP 入口配置\n# =============================================================================\n\nhttp:\n apiPrefix: /api/v1\n openapi:\n path: /openapi.json\n docs:\n path: /docs\n health:\n path: /health\n readyPath: /ready\n rpc: false\n\n# 开发期默认关闭 transport;启用 @h-ai/crypto 后可按需改为对象配置\ntransport: false\n`\n}\n\nfunction generateDbConfig(cfg?: DbModuleConfig): string {\n const dbType = cfg?.type ?? 'sqlite'\n const database = cfg?.database ?? (dbType === 'sqlite' ? './data/app.db' : 'hai')\n const host = cfg?.host ?? 'localhost'\n const port = cfg?.port ?? (dbType === 'postgresql' ? 5432 : 3306)\n\n if (dbType === 'sqlite') {\n return `# =============================================================================\n# 数据库配置\n# =============================================================================\n\n# 数据库类型: sqlite | postgresql | mysql\ntype: sqlite\n\n# SQLite 数据库路径\ndatabase: ${database}\n\n# PostgreSQL/MySQL 配置(可选)\n# host: localhost\n# port: 5432\n# user: postgres\n# password: ''\n`\n }\n\n const user = dbType === 'postgresql' ? 'postgres' : 'root'\n\n return `# =============================================================================\n# 数据库配置\n# =============================================================================\n\n# 数据库类型: sqlite | postgresql | mysql\ntype: ${dbType}\n\n# 数据库名称\ndatabase: ${database}\n\n# 连接配置\nhost: ${host}\nport: ${port}\nuser: ${user}\npassword: ''\n`\n}\n\nfunction generateCacheConfig(cfg?: CacheModuleConfig): string {\n const cacheType = cfg?.type ?? 'memory'\n\n if (cacheType === 'memory') {\n return `# =============================================================================\n# 缓存配置\n# =============================================================================\n\n# 缓存类型: memory | redis\ntype: memory\n\n# Redis 配置(当 type 为 redis 时使用)\n# url: redis://localhost:6379/0\n# host: localhost\n# port: 6379\n# password: ''\n# keyPrefix: 'hai:'\n`\n }\n\n const host = cfg?.host ?? 'localhost'\n const port = cfg?.port ?? 6379\n\n return `# =============================================================================\n# 缓存配置\n# =============================================================================\n\n# 缓存类型: memory | redis\ntype: redis\n\n# Redis 配置\nhost: ${host}\nport: ${port}\npassword: ''\nkeyPrefix: 'hai:'\n`\n}\n\nfunction generateIamConfig(cfg?: IamModuleConfig): string {\n const loginPassword = cfg?.loginPassword ?? true\n const loginOtp = cfg?.loginOtp ?? false\n\n return `# =============================================================================\n# IAM 配置\n# =============================================================================\n\n# 登录配置\nlogin:\n password: ${loginPassword}\n otp: ${loginOtp}\n ldap: false\n\n# 密码策略\npassword:\n minLength: 8\n maxLength: 128\n requireUppercase: false\n requireLowercase: false\n requireNumber: false\n requireSpecialChar: false\n\n# 会话配置\nsession:\n maxAge: 86400 # 会话超时(秒),默认 24 小时\n sliding: true # 滑动窗口(每次请求刷新过期时间)\n singleDevice: false # 单设备登录\n refreshTokenMaxAge: 604800 # refreshToken 过期(秒),默认 7 天\n\n# RBAC 配置\nrbac:\n defaultRole: user\n\n# 是否自动创建默认数据\nseedDefaultData: true\n`\n}\n\nfunction generateStorageConfig(cfg?: StorageModuleConfig): string {\n if ((cfg?.type ?? 'local') === 'local') {\n return `# 存储配置;HAI_STORAGE 可整体替换为 S3 配置。\ntype: local\nroot: ${cfg?.localPath ?? './data/uploads'}\n`\n }\n return `# S3 存储配置\ntype: s3\nbucket: ''\nregion: us-east-1\naccessKeyId: ''\nsecretAccessKey: ''\nendpoint: https://s3.amazonaws.com\nforcePathStyle: false\n`\n}\n\nfunction generateAiConfig(cfg?: AiModuleConfig): string {\n const model = cfg?.model ?? 'gpt-4o-mini'\n\n // AIConfigSchema 结构:llm(必填)+ 可选子模块\n // LLMConfigSchema 支持顶层 apiKey/model,以及多模型 models 数组\n return `# =============================================================================\n# AI 配置\n# =============================================================================\n\n# LLM 配置(必填)\nllm:\n # API Key(约定环境变量 HAI_AI_LLM_APIKEY 优先)\n apiKey: ''\n # Base URL(约定环境变量 HAI_AI_LLM_BASEURL 优先)\n # baseUrl: https://api.openai.com/v1\n # 默认模型\n model: ${model}\n # 全局最大 Token 数(默认 4096)\n # maxTokens: 4096\n # 采样温度(0-2,默认 0.7)\n # temperature: 0.7\n # 请求超时(毫秒,默认 60000)\n # timeout: 60000\n\n # 多模型配置(可选,用于场景路由)\n # models:\n # - id: fast\n # model: gpt-4o-mini\n # - id: smart\n # model: gpt-4o\n # apiKey: ''\n\n # 场景模型映射(可选)\n # scenarios:\n # default: fast\n # analysis: smart\n`\n}\n\n/**\n * 根据选中的功能模块生成 .env.example 内容\n *\n * @param features - 选中的功能模块列表\n * @param configs - 用户自定义配置值\n * @returns .env.example 文件内容\n */\nexport function generateEnvExample(features: FeatureId[], configs?: ModuleConfigs): string {\n const sections: string[] = []\n\n // 文件头\n sections.push(`# =============================================================================\n# Environment Variables\n# =============================================================================\n#\n# Copy this file to .env and fill in actual values.\n# Config files use literal defaults; matching HAI variables override YAML leaves.\n#\n# Naming convention: HAI_<config name>_<YAML path>\n# =============================================================================`)\n\n // 应用基础(始终生成)\n sections.push(`\n# =============================================================================\n# Application\n# =============================================================================\n# Environment: development | production | test\nHAI_CORE_ENV=development\n# Enable debug mode\nHAI_CORE_DEBUG=false`)\n\n // 数据库\n if (features.includes('db')) {\n const dbType = configs?.db?.type ?? 'sqlite'\n const dbDatabase = configs?.db?.database ?? (dbType === 'sqlite' ? './data/app.db' : 'hai')\n const isSqlite = dbType === 'sqlite'\n sections.push(`\n# =============================================================================\n# Database (@h-ai/reldb)\n# =============================================================================\n# Database type: sqlite | postgresql | mysql\nHAI_DB_TYPE=${dbType}\n# SQLite: file path; PostgreSQL/MySQL: database name\nHAI_DB_DATABASE=${dbDatabase}${isSqlite\n ? `\n# PostgreSQL/MySQL connection (uncomment when not using sqlite)\n# HAI_DB_HOST=localhost\n# HAI_DB_PORT=5432\n# HAI_DB_USER=postgres\n# HAI_DB_PASSWORD=`\n : `\n# Connection\nHAI_DB_HOST=${configs?.db?.host ?? 'localhost'}\nHAI_DB_PORT=${configs?.db?.port ?? (dbType === 'postgresql' ? 5432 : 3306)}\nHAI_DB_USER=${dbType === 'postgresql' ? 'postgres' : 'root'}\nHAI_DB_PASSWORD=`}`)\n }\n\n // IAM / Session\n if (features.includes('iam')) {\n sections.push(`\n# =============================================================================\n# IAM (@h-ai/iam)\n# =============================================================================\n# HAI_IAM_PASSWORD_MINLENGTH=8\n# HAI_IAM_SESSION_MAXAGE=86400\n# HAI_IAM_SESSION_REFRESHTOKENMAXAGE=604800\n# HAI_KIT_COOKIE_KEY= # 32-char hex for SM4-CBC cookie encryption\n`)\n }\n\n // 缓存\n if (features.includes('cache')) {\n const cacheType = configs?.cache?.type ?? 'memory'\n if (cacheType === 'redis') {\n sections.push(`\n# =============================================================================\n# Cache (@h-ai/cache)\n# =============================================================================\n# Cache type: memory | redis\nHAI_CACHE_TYPE=redis\n# Redis connection\nHAI_CACHE_HOST=${configs?.cache?.host ?? 'localhost'}\nHAI_CACHE_PORT=${configs?.cache?.port ?? 6379}\nHAI_CACHE_PASSWORD=\n# HAI_CACHE_URL=redis://localhost:6379/0\n# HAI_CACHE_DB=0\n# HAI_CACHE_CONNECT_TIMEOUT=10000\n# HAI_CACHE_COMMAND_TIMEOUT=5000\n# HAI_CACHE_KEY_PREFIX=hai:`)\n }\n else {\n sections.push(`\n# =============================================================================\n# Cache (@h-ai/cache)\n# =============================================================================\n# Cache type: memory | redis\nHAI_CACHE_TYPE=memory\n# Redis connection (uncomment when type=redis)\n# HAI_CACHE_URL=redis://localhost:6379/0\n# HAI_CACHE_HOST=localhost\n# HAI_CACHE_PORT=6379\n# HAI_CACHE_PASSWORD=\n# HAI_CACHE_DB=0\n# HAI_CACHE_CONNECT_TIMEOUT=10000\n# HAI_CACHE_COMMAND_TIMEOUT=5000\n# HAI_CACHE_KEY_PREFIX=hai:`)\n }\n }\n\n // 存储\n if (features.includes('storage')) {\n const storageType = configs?.storage?.type ?? 'local'\n if (storageType === 's3') {\n sections.push(`\n# =============================================================================\n# Storage (@h-ai/storage)\n# =============================================================================\n# Default storage provider: local | s3\nHAI_STORAGE_TYPE=s3\n# S3 / S3-compatible\nHAI_STORAGE_BUCKET=\nHAI_STORAGE_REGION=us-east-1\nHAI_STORAGE_ACCESSKEYID=\nHAI_STORAGE_SECRETACCESSKEY=\n# HAI_STORAGE_ENDPOINT= # Custom endpoint for MinIO / Aliyun OSS etc.\n# HAI_STORAGE_FORCEPATHSTYLE=false\n# Local storage (uncomment when type=local)\n# HAI_STORAGE_ROOT=./data/uploads`)\n }\n else {\n sections.push(`\n# =============================================================================\n# Storage (@h-ai/storage)\n# =============================================================================\n# Default storage provider: local | s3\nHAI_STORAGE_TYPE=local\n# Local storage root path\nHAI_STORAGE_ROOT=${configs?.storage?.localPath ?? './data/uploads'}\n# S3 / S3-compatible (uncomment when type=s3)\n# HAI_STORAGE_BUCKET=\n# HAI_STORAGE_REGION=us-east-1\n# HAI_STORAGE_ACCESSKEYID=\n# HAI_STORAGE_SECRETACCESSKEY=\n# HAI_STORAGE_ENDPOINT= # Custom endpoint for MinIO / Aliyun OSS etc.\n# HAI_STORAGE_FORCEPATHSTYLE=false`)\n }\n }\n\n // AI\n if (features.includes('ai')) {\n const provider = configs?.ai?.defaultProvider ?? 'openai'\n if (provider === 'anthropic') {\n sections.push(`\n# =============================================================================\n# AI (@h-ai/ai)\n# =============================================================================\n# OpenAI-compatible API Key (Anthropic models via OpenAI-compatible proxy)\nHAI_AI_LLM_APIKEY=\n# HAI_AI_LLM_BASEURL= # Custom base URL\n# Optional compatibility fallback\n# OPENAI_API_KEY=`)\n }\n else if (provider === 'openai') {\n sections.push(`\n# =============================================================================\n# AI (@h-ai/ai)\n# =============================================================================\n# OpenAI / OpenAI-compatible\nHAI_AI_LLM_APIKEY=\n# HAI_AI_LLM_BASEURL= # Custom base URL (e.g. local proxy, Azure)\n# Optional compatibility fallback\n# OPENAI_API_KEY=`)\n }\n else {\n sections.push(`\n# =============================================================================\n# AI (@h-ai/ai)\n# =============================================================================\n# OpenAI-compatible provider\nHAI_AI_LLM_APIKEY=\n# HAI_AI_LLM_BASEURL= # Custom base URL\n# Optional compatibility fallback\n# OPENAI_API_KEY=`)\n }\n }\n\n // VecDB\n if (features.includes('vecdb')) {\n sections.push(`\n# =============================================================================\n# Vector Database (@h-ai/vecdb)\n# =============================================================================\n# Backend type: lancedb | pgvector | qdrant\nHAI_VECDB_TYPE=lancedb\n# LanceDB data path\nHAI_VECDB_PATH=./data/vecdb\n# Qdrant (uncomment when type=qdrant)\n# HAI_VECDB_URL=http://localhost:6333\n# HAI_VECDB_APIKEY=\n`)\n }\n\n // Reach\n if (features.includes('reach')) {\n sections.push(`\n# =============================================================================\n# Reach (@h-ai/reach)\n# =============================================================================\n# SMTP (uncomment when enabling email provider)\n# HAI_REACH_SMTP_HOST=smtp.example.com\n# HAI_REACH_SMTP_PORT=465\n# HAI_REACH_SMTP_USER=\n# HAI_REACH_SMTP_PASS=\n# HAI_REACH_SMTP_FROM=noreply@example.com\n`)\n }\n\n // Payment\n if (features.includes('payment')) {\n sections.push(`\n# =============================================================================\n# Payment (@h-ai/payment)\n# =============================================================================\n# WeChat Pay\n# HAI_PAYMENT_WECHAT_MCHID=\n# HAI_PAYMENT_WECHAT_APIV3KEY=\n# HAI_PAYMENT_WECHAT_SERIALNO=\n# HAI_PAYMENT_WECHAT_PRIVATEKEY=\n# HAI_PAYMENT_WECHAT_APPID=\n# Alipay\n# HAI_PAYMENT_ALIPAY_APPID=\n# HAI_PAYMENT_ALIPAY_PRIVATEKEY=\n# HAI_PAYMENT_ALIPAY_ALIPAYPUBLICKEY=\n# Stripe\n# HAI_PAYMENT_STRIPE_SECRETKEY=\n# HAI_PAYMENT_STRIPE_WEBHOOKSECRET=\n`)\n }\n\n // 测试(始终生成)\n sections.push(`\n# =============================================================================\n# Testing\n# =============================================================================\n# E2E test mode (relaxes rate limiting etc.)\n# HAI_E2E=1\n`)\n\n return sections.join('\\n')\n}\n\nfunction generateDeployConfig(): string {\n return `# =============================================================================\n# 部署配置 (@h-ai/deploy)\n# =============================================================================\n# 部署平台凭证通过 ~/.hai/credentials.yml 管理\n# 环境变量引用格式: \\${VAR_NAME:default_value}\n\n# 部署平台\nprovider:\n type: vercel\n token: \\${HAI_DEPLOY_VERCEL_TOKEN}\n\n# ---------------------------------------------------------------------------\n# 方式二:docker-ssh — 将应用容器化后通过 SSH 部署到任意 Linux 主机\n# 远程主机只需具备 SSH + docker/podman + compose,本地需 docker 或 podman\n# 切换时用下方 provider 替换上面的 vercel provider\n# ---------------------------------------------------------------------------\n# provider:\n# type: docker-ssh\n# ssh:\n# host: \\${HAI_DEPLOY_SSH_HOST}\n# port: 22\n# username: deploy\n# identityFile: \\${HAI_DEPLOY_SSH_KEY} # 私钥文件路径(省略则用 ssh-agent)\n# remote:\n# baseDir: /opt/hai/apps\n# runtime: auto # auto 优先 podman,其次 docker\n# expose:\n# type: port\n# containerPort: 3000\n# hostPort: 18080 # 访问地址 http://<host>:18080\n\n# 本地构建运行时(docker-ssh 使用;auto 优先 podman)\n# container:\n# runtime: auto\n\n# 基础设施服务(按需开启)\nservices:\n # PostgreSQL 数据库 (Neon)\n # db:\n # provisioner: neon\n # apiKey: \\${HAI_DEPLOY_NEON_API_KEY}\n\n # Redis 缓存 (Upstash)\n # cache:\n # provisioner: upstash\n # email: \\${HAI_DEPLOY_UPSTASH_EMAIL}\n # apiKey: \\${HAI_DEPLOY_UPSTASH_API_KEY}\n\n # S3 存储 (Cloudflare R2)\n # storage:\n # provisioner: cloudflare-r2\n # accountId: \\${HAI_DEPLOY_CF_ACCOUNT_ID}\n # apiToken: \\${HAI_DEPLOY_CF_API_TOKEN}\n # accessKeyId: \\${HAI_DEPLOY_R2_ACCESS_KEY_ID}\n # secretAccessKey: \\${HAI_DEPLOY_R2_SECRET_ACCESS_KEY}\n\n # 邮件 (Resend)\n # email:\n # provisioner: resend\n # apiKey: \\${HAI_DEPLOY_RESEND_API_KEY}\n # from: \\${HAI_DEPLOY_RESEND_FROM}\n\n # 短信 (阿里云)\n # sms:\n # provisioner: aliyun\n # accessKeyId: \\${HAI_DEPLOY_ALIYUN_ACCESS_KEY_ID}\n # accessKeySecret: \\${HAI_DEPLOY_ALIYUN_ACCESS_KEY_SECRET}\n # signName: \\${HAI_DEPLOY_ALIYUN_SIGN_NAME}\n\n# docker-ssh 说明:\n# - 应用镜像使用工程自带的 Dockerfile(adapter-node),本地构建后经 SSH 传输并 load\n# - compose 会按上方启用的 db/cache/storage 自动追加 postgres/redis/minio sidecar\n# - 若同时配置了对应云 Provisioner,则优先使用云资源,不再自建 sidecar\n`\n}\n\nfunction generateVecdbConfig(): string {\n return `# =============================================================================\n# 向量数据库配置 (@h-ai/vecdb)\n# =============================================================================\n\n# 数据库类型: lancedb | pgvector | qdrant\ntype: lancedb\n\n# LanceDB 数据目录\npath: ./data/vecdb\n\n# 距离度量: cosine | euclidean | dot\n# metric: cosine\n\n# pgvector 配置(当 type 为 pgvector 时使用)\n# type: pgvector\n# host: localhost\n# port: 5432\n# database: hai\n# user: postgres\n# password: ''\n# indexType: hnsw\n# tablePrefix: vec_\n\n# Qdrant 配置(当 type 为 qdrant 时使用)\n# type: qdrant\n# url: http://localhost:6333\n# apiKey: ''\n`\n}\n\nfunction generateReachConfig(): string {\n return `# =============================================================================\n# 消息推送配置 (@h-ai/reach)\n# =============================================================================\n\nproviders:\n # 控制台输出(开发/测试用)\n - name: console_dev\n type: console\n\n # SMTP 邮件(按需开启)\n # - name: email\n # type: smtp\n # host: \\${HAI_REACH_SMTP_HOST:smtp.example.com}\n # port: \\${HAI_REACH_SMTP_PORT:465}\n # secure: true\n # user: \\${HAI_REACH_SMTP_USER:}\n # pass: \\${HAI_REACH_SMTP_PASS:}\n # from: \\${HAI_REACH_SMTP_FROM:noreply@example.com}\n\n # 阿里云短信(按需开启)\n # - name: sms\n # type: aliyun-sms\n # accessKeyId: \\${HAI_REACH_SMS_ACCESS_KEY}\n # accessKeySecret: \\${HAI_REACH_SMS_SECRET_KEY}\n # signName: MyApp\n\n# 模板(可选)\n# templates:\n# - name: verification_code\n# provider: email\n# subject: \"验证码: {code}\"\n# body: \"您的验证码是 {code},有效期 {minutes} 分钟。\"\n\n# 免打扰(可选)\n# dnd:\n# enabled: true\n# strategy: delay\n# start: \"22:00\"\n# end: \"08:00\"\n`\n}\n\nfunction generateSchedulerConfig(): string {\n return `# =============================================================================\n# 任务调度配置 (@h-ai/scheduler)\n# =============================================================================\n\n# 是否启用数据库日志(需要 @h-ai/reldb)\nenableDb: true\n\n# 执行日志表名\ntableName: hai_scheduler_logs\n\n# 任务定义表名\ntaskTableName: hai_scheduler_tasks\n\n# 分布式锁表名\nlockTableName: hai_scheduler_locks\n\n# 检查间隔(毫秒)\ntickInterval: 1000\n\n# 锁过期时间(毫秒)\nlockExpireMs: 300000\n`\n}\n\nfunction generateAuditConfig(): string {\n return `# =============================================================================\n# 审计日志配置 (@h-ai/audit)\n# =============================================================================\n\n# 审计日志表名\ntableName: hai_audit_logs\n\n# 用户表名(用于 JOIN 查询)\nuserTable: hai_iam_users\n\n# 用户表主键列名\nuserIdColumn: id\n\n# 用户名列名\nuserNameColumn: username\n`\n}\n\nfunction generatePaymentConfig(): string {\n return `# =============================================================================\n# 支付配置 (@h-ai/payment)\n# =============================================================================\n\n# 微信支付(按需开启)\n# wechat:\n# mchId: ''\n# apiV3Key: ''\n# serialNo: ''\n# privateKey: ''\n# appId: ''\n\n# 支付宝(按需开启)\n# alipay:\n# appId: ''\n# privateKey: ''\n# alipayPublicKey: ''\n# signType: RSA2\n# sandbox: false\n\n# Stripe(按需开启)\n# stripe:\n# secretKey: ''\n# webhookSecret: ''\n`\n}\n"]}
|