@h-ai/cli 1.0.0-beta.6 → 1.0.0-beta.8
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 +9 -9
- package/README.ja.md +9 -9
- package/README.md +9 -9
- package/dist/{chunk-4XVCGFBA.js → chunk-MEEFB4BI.js} +552 -11
- package/dist/chunk-MEEFB4BI.js.map +1 -0
- package/dist/{chunk-STWZQ3IP.js → chunk-SGWSVWZ5.js} +588 -11
- package/dist/chunk-SGWSVWZ5.js.map +1 -0
- package/dist/cli-config-templates-SVV3633D.js +5 -0
- package/dist/{cli-config-templates-YGPVNRX5.js.map → cli-config-templates-SVV3633D.js.map} +1 -1
- package/dist/index.js +97 -78
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/{src-NXCCU6GO.js → src-IW4CY2IN.js} +3 -3
- package/dist/src-IW4CY2IN.js.map +1 -0
- package/package.json +16 -12
- package/templates/apps/api/apps/{{projectName}}-serv/config/_serv.yml.hbs +1 -1
- package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +6 -2
- package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +29 -3
- package/templates/apps/fullstack/.gitignore.hbs +7 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +2 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +2 -2
- package/templates/apps/mobile-app/messages/en-US.json +1 -1
- package/templates/apps/mobile-app/messages/ja-JP.json +1 -1
- package/templates/apps/mobile-app/messages/zh-CN.json +1 -1
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +8 -5
- package/templates/base/.gitignore.hbs +7 -2
- package/templates/base/e2e/app.spec.ts.hbs +9 -4
- package/templates/base/package.json.hbs +7 -2
- package/templates/skills/hai-ai/SKILL.md +6 -2
- package/templates/skills/hai-ai/acp.md +145 -0
- package/templates/skills/hai-ai/guide.md +1 -1
- package/templates/skills/hai-ai/reference.md +1 -1
- package/templates/skills/hai-ai/resources.md +69 -0
- package/templates/skills/hai-api-client/reference.md +2 -0
- package/templates/skills/hai-app-create/development.md +1 -1
- package/templates/skills/hai-app-create/reference.md +1 -1
- package/templates/skills/hai-build/SKILL.md +1 -1
- package/templates/skills/hai-build/reference.md +1 -1
- package/templates/skills/hai-cache/reference.md +6 -2
- package/templates/skills/hai-ci/SKILL.md +2 -0
- package/templates/skills/hai-core/SKILL.md +1 -1
- package/templates/skills/hai-crypto/reference.md +2 -0
- package/templates/skills/hai-payment/reference.md +39 -17
- package/templates/skills/hai-reach/reference.md +15 -7
- package/templates/skills/hai-reldb/reference.md +5 -2
- package/templates/skills/hai-scheduler/reference.md +1 -1
- package/templates/skills/hai-storage/reference.md +8 -2
- package/templates/skills/hai-vecdb/reference.md +7 -2
- package/dist/chunk-4XVCGFBA.js.map +0 -1
- package/dist/chunk-STWZQ3IP.js.map +0 -1
- package/dist/cli-config-templates-YGPVNRX5.js +0 -5
- package/dist/src-NXCCU6GO.js.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# 配置与数据库资源清单
|
|
2
|
+
|
|
3
|
+
AI 的可维护资源统一使用两份来源:初始化配置(通常来自 config/ai.yml)和 AIStoreProvider 数据库。按 ID 合并,同 ID 配置优先;配置条目只读,不复制到数据库。移除配置后,原来被遮蔽的数据库条目重新可见。数据库变更不会修改配置文件。
|
|
4
|
+
|
|
5
|
+
| 清单入口 | 配置数组 | 使用方 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| `ai.llm.models` | `llm.models` | LLM、embedding、rerank、ACP 原生模型配置 |
|
|
8
|
+
| `ai.audio.models` | `audio.models` | ASR/TTS |
|
|
9
|
+
| `ai.image.models` | `image.models` | 图像生成 |
|
|
10
|
+
| `ai.mcp.servers` | `mcp.servers` | ACP `mcpServerIds`,外部 MCP 连接资料 |
|
|
11
|
+
| `ai.retrieval.sources` | `retrieval.sources` | 检索源及旧 addSource/removeSource/listSources 接口 |
|
|
12
|
+
| `ai.acp.agents` | `acp.agents` | 智能体接入、初始化和会话 |
|
|
13
|
+
| `ai.acp.workspaces` | `acp.workspaces` | 工程准备、会话目录及 Git 操作 |
|
|
14
|
+
|
|
15
|
+
这些清单支持 `list/get/register/update/remove`。`list/get` 返回 `HaiResult`,条目为 `{ value, source, version? }`;`source` 是 config 或 database,数据库 `get` 带版本。`update` 接受完整定义,不是部分 patch。编辑前 get,再把 version 传给 update/remove,过期写入返回冲突。已有运行中的 ACP 会话保留原模型绑定;新会话读取最新清单,恢复会话会校验模型与智能体定义是否仍兼容。
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { ai } from '@h-ai/ai'
|
|
19
|
+
|
|
20
|
+
// 已按应用生命周期成功初始化 reldb、vecdb 和 ai。
|
|
21
|
+
async function changeModel() {
|
|
22
|
+
const current = await ai.llm.models.get('coding')
|
|
23
|
+
if (!current.success) return current
|
|
24
|
+
if (current.data.source === 'config') return current
|
|
25
|
+
return ai.llm.models.update({ ...current.data.value, temperature: 0.2 }, current.data.version)
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
配置示例(模型名、地址与路径由部署提供):
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
llm:
|
|
33
|
+
models:
|
|
34
|
+
- id: coding
|
|
35
|
+
model: your-model
|
|
36
|
+
protocol: responses
|
|
37
|
+
acp:
|
|
38
|
+
agents:
|
|
39
|
+
- id: coder
|
|
40
|
+
name: Codex
|
|
41
|
+
mode: embedded
|
|
42
|
+
adapter: codex
|
|
43
|
+
modelIds: [coding]
|
|
44
|
+
workspaces:
|
|
45
|
+
- id: project
|
|
46
|
+
storage:
|
|
47
|
+
type: directory
|
|
48
|
+
path: /srv/projects/project
|
|
49
|
+
repositories:
|
|
50
|
+
- id: api
|
|
51
|
+
url: https://git.example.com/team/api.git
|
|
52
|
+
mainBranch: trunk
|
|
53
|
+
mcp:
|
|
54
|
+
servers:
|
|
55
|
+
- id: docs
|
|
56
|
+
name: Docs
|
|
57
|
+
transport: stdio
|
|
58
|
+
command: docs-mcp
|
|
59
|
+
environmentRefs:
|
|
60
|
+
API_TOKEN: DOCS_API_TOKEN
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
创建会话时传 `mcpServerIds: ['docs']`;配置和数据库 MCP 条目都可选择。环境变量在实际启动时解析,不将引用替换为密钥后保存到 MCP 定义。HTTP/SSE 的 headers 使用 `headerEnv`,stdio 的环境变量使用 `environmentRefs`。这份清单只维护外部服务器;`ai.mcp.registerTool/registerResource/registerPrompt` 仍是宿主进程的函数注册,不将可执行函数存进数据库。
|
|
64
|
+
|
|
65
|
+
框架的异步模型调用每次读取最新清单;mem0 外部运行时在初始化时读取合并快照,其内置模型配置修改后需要重新初始化 AI。音频 `getCapabilities()` 保留原同步契约,使用本进程最近一次目录读写或异步音频调用刷新的快照;跨节点修改后先 await `ai.audio.models.get/list` 再同步查询能力。清单不是业务会话历史:session、聊天记录、persona 等继续使用各自已有的持久化 API,不从配置导入运行历史。
|
|
66
|
+
|
|
67
|
+
配置项改写返回 `hai:ai:090`,缺失为 091,版本/重复冲突为 092,无效定义为 093,存储失败为 094。工作区路径重叠、仍被会话引用等使用 ACP 错误。数据库工作区更新/删除前需关闭并移除引用它的会话记录;移除记录不删除磁盘目录、worktree 或 volume。
|
|
68
|
+
|
|
69
|
+
清单 API 是可信服务端管理接口,模型原始定义可能包含 apiKey。应用必须鉴权并自行选择可返回浏览器的字段,不直接透传整个 value。生产继续沿用 AI 模块已有共享数据库及向量库前置要求。
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
## 使用步骤
|
|
11
11
|
|
|
12
|
+
`client.close()` 使旧刷新失效并等待已开始的凭据写入,但不清除宿主 TokenStorage。关闭完成后可复用同一存储重新 init;迟到刷新不能覆盖新身份。请求 timeout 覆盖响应头与完整 JSON 正文;自定义流按需读取,以调用方 signal 取消正文。内置 Cookie 适配器的登录和刷新包含跨域凭据,服务端须配置明确 Origin;内存/原生存储保留原请求凭据策略。
|
|
13
|
+
|
|
12
14
|
### 1. 初始化
|
|
13
15
|
|
|
14
16
|
浏览器默认使用 httpOnly cookie 存储(推荐):
|
|
@@ -22,7 +22,7 @@ README 编辑先读章节,把功能说明与示例合并到对应章节;新
|
|
|
22
22
|
|
|
23
23
|
### 页面与布局
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
每个模板只安装实际使用的模块:admin/h5 包含认证、验证码及找回密码通知,以及数据库、缓存、加密依赖;website 只包含 Core/Kit/UI;API 包含认证、通知、上传和反馈;fullstack 保留管理后台的认证、审计、存储、通知、调度和反馈;mobile-app 只使用客户端能力。AI、payment、vecdb、datapipe 不默认安装。所有项目保留完整模块 YAML 和 `.env.example`,未启用项以注释提供,只有已启用项进入公共环境默认值。后续添加对应依赖、取消所需配置注释,再接入初始化、关闭及业务路由;添加依赖不会自动启用功能。`--template`、`--features`、`--examples/--no-examples` 已删除,`create --yes/-y` 改为 `--defaults`,旧参数明确报错;`deploy --yes` 保持原义。已有工程不会自动裁剪依赖。
|
|
26
26
|
|
|
27
27
|
website默认SSR;静态发布须先移除服务端业务依赖、初始化及API/actions。静态构建与实际路径验证按[hai-build](../hai-build/SKILL.md)。
|
|
28
28
|
|
|
@@ -315,7 +315,7 @@ interface CreateArticleInput {
|
|
|
315
315
|
|
|
316
316
|
## 初始化顺序
|
|
317
317
|
|
|
318
|
-
CLI 项目统一忽略 `**/data/`,含根目录、workspace 子目录及 `.gitkeep`;数据库/上传文件不入 Git
|
|
318
|
+
CLI 项目统一忽略 `**/data/`,含根目录、workspace 子目录及 `.gitkeep`;数据库/上传文件不入 Git。每个模板只安装实际使用的模块,同时在应用 config 保留 core、serv、kit、db、cache、iam、storage、audit、reach、ai、vecdb、payment、scheduler、feedback 共 14 份 YAML;纯客户端的服务端配置仅作参考。构建部署配置统一位于项目根 hai.json,未启用模块整份注释,可选字段及替代 Provider 按块注释,`.env.example` 保留全部模块变量,未启用项不进入公共环境默认值。新增功能时添加对应依赖、启用所需配置,并接入初始化、反序关闭和业务路由;添加依赖不会自动接入模块。LDAP 只有在 login.ldap 为 true 时才参与部署扫描。
|
|
319
319
|
|
|
320
320
|
H5 所有页面继承根布局的 header/footer;认证页隐藏底部导航,业务页面使用 `@h-ai/ui` 的 `BottomNav` 与移动端壳样式,导航启用 centered/maxWidth/safeArea,与页面同宽。
|
|
321
321
|
|
|
@@ -27,7 +27,7 @@ description: "构建或排查 hai 应用的源码、静态网站、容器镜像
|
|
|
27
27
|
|
|
28
28
|
## 构建与部署
|
|
29
29
|
|
|
30
|
-
- 新建website
|
|
30
|
+
- 新建website只安装Core/Kit/UI,默认Node SSR,可直接切换静态发布;注释配置与环境变量参考不启用模块。后续增加的服务端业务依赖、初始化及API/actions须先移除。compile静态预渲染使用`HAI_BUILD_STATIC=1 PUBLIC_BASE_PATH=/docs-site`,docs-site替换为实际仓库名,各路径段仅ASCII字母、数字、_、.、-,无末尾/;省略/0保持SSR,根站路径留空。HAI_BUILD_STATIC仅用于compile,PUBLIC_BASE_PATH也支持image网站构建。静态拒绝服务端业务模块、自定义API/actions与未预渲染页面,不放宽生产守卫、不用SPA fallback;默认健康端点不发布。构建不读根.env,static为公开目录,拒绝.env/.env.*与符号链接。上传build使用include-hidden-files:true保留.nojekyll,验首页/深链/刷新/资产与敏感哨兵。
|
|
31
31
|
|
|
32
32
|
- 创建默认包含开发期部署工具,可用 --no-deploy 关闭。每个镜像使用 images/ 中独立 Dockerfile,Web 配置位于 images/web/,不使用镜像阶段 target 配置。
|
|
33
33
|
- 构建器生成 images/dependencies/ 安装输入;fetch、安装和生产依赖整理共用 pnpm store,安装与生产依赖整理共用 SQLite 驱动缓存,并复用依赖层;依赖安装在源码COPY前,前后端仅复制各自需要的源码。运行镜像去掉应用自身声明、source map和README。file: 归档、补丁、workspace 元数据必须进入下载上下文;原生依赖缓存按系统/架构/ABI 区分。基础镜像、中间件及工具指定版本,禁止 latest。
|
|
@@ -60,7 +60,7 @@ Dockerfile 在 FROM 前声明 HAI_NODE_IMAGE / 适用的 HAI_NGINX_IMAGE,构
|
|
|
60
60
|
|
|
61
61
|
### SvelteKit Adapter 模式
|
|
62
62
|
|
|
63
|
-
CLI website模板默认Node SSR
|
|
63
|
+
CLI website模板默认Node SSR,只安装Core/Kit/UI;注释配置和环境变量参考不启用模块。后续增加的服务端业务依赖、初始化和API/actions须在静态发布前移除;在compile时使用`HAI_BUILD_STATIC=1`与可选`PUBLIC_BASE_PATH`切换完整静态预渲染,边界见本skill的静态网站说明;该模板没有使用下方VITE_ADAPTER工厂。静态产物用preview本机检查,上传build到Pages/CDN;生成的start/Docker配置属于普通SSR模式,不能用于运行静态HTML。切回SSR只需清除静态开关并重建,PUBLIC_BASE_PATH仍可按实际网站目录用于SSR或Docker;SvelteKit/Vite差异、制品格式和健康检查见[网站挂载目录](paths.md)。
|
|
64
64
|
|
|
65
65
|
仅在项目实际使用 SvelteKit 和 `@h-ai/kit/adapter` 时使用;Vite SPA 不配置 SvelteKit adapter,fullstack 各前端按自身 scripts 构建。
|
|
66
66
|
|
|
@@ -38,9 +38,13 @@ type: memory # memory | redis
|
|
|
38
38
|
### 2. 初始化与关闭
|
|
39
39
|
|
|
40
40
|
```typescript
|
|
41
|
-
import {
|
|
41
|
+
import { core } from '@h-ai/core'
|
|
42
|
+
import { cache, CacheConfigSchema } from '@h-ai/cache'
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
const config = core.config.validate('cache', CacheConfigSchema)
|
|
45
|
+
if (!config.success) throw new Error(config.error.message)
|
|
46
|
+
const initialized = await cache.init(config.data)
|
|
47
|
+
if (!initialized.success) throw new Error(initialized.error.message)
|
|
44
48
|
// 使用后关闭
|
|
45
49
|
const closed = await cache.close()
|
|
46
50
|
if (!closed.success) throw new Error(closed.error.message)
|
|
@@ -61,6 +61,8 @@ lint/typecheck 只能执行已配置的规则。新增开发规范时区分可
|
|
|
61
61
|
- 若 E2E 稳定且耗时可控,可作为 required check。
|
|
62
62
|
- 若 E2E 依赖浏览器、服务、密钥或容易 flaky,先放到 `workflow_dispatch` / `schedule` / 独立 job。
|
|
63
63
|
- 应用级 E2E 使用:`pnpm --filter <app> test:e2e`。
|
|
64
|
+
- 依赖镜像或环境开关的关键 E2E,在 CI 中必须明确准备前置并启用;准备失败应阻断,不能让缺少配置导致的 skip 冒充验收。使用 Turbo 严格环境时,将影响测试执行范围的变量放入 `env`,同时传递变量并参与缓存身份,避免命中跳过用例时的缓存。
|
|
65
|
+
- 真实付费服务验收限用户已授权的可信分支和事件。可复用 workflow 的 secret 仅在调用方按事件显式传入,并只向定向验收步骤注入;安装、构建和普通根测试剥离该凭据。PR 继续使用夹具。成功和失败均可保留脱敏 JSON/HTML/截图证据,不能将密钥或认证头写入制品。
|
|
64
66
|
|
|
65
67
|
### hai-framework 依赖策略
|
|
66
68
|
|
|
@@ -21,7 +21,7 @@ description: "配置 hai 应用启动、YAML/环境变量、日志、i18n 与 Ha
|
|
|
21
21
|
- 自动加载和监听配置目录内所有 YAML;项目根 `hai.json` 的 `build` / `deploy` 由 CLI 读取,不进入运行时配置。单项 load 返回失败时记日志并继续,必需配置须 validate 并检查 success;目录扫描、日志设置等异常仍可能传播。
|
|
22
22
|
- 应用名称、版本、环境、默认语言和日志设置统一从 `_core.yml` 经 core.config 获取,日志使用 core.logger;UI 不另维护硬编码副本。SvelteKit layout / fullstack app.info 仅下发公开字段白名单;独立 Vite mobile-app 在 Node 构建时解析并注入公开默认值,修改这些编译默认值需要重新构建。静态 Web 的公开 API 地址等通过 `runtime-config.js` 覆盖时无需重建镜像,原生包在复制静态资源前准备配置入口。浏览器不加载 YAML,不接收完整模块配置、密钥或日志脱敏上下文。
|
|
23
23
|
- `HAI_<配置名>_<路径>` 支持父 JSON 基础与细项覆盖,同源先父后子,高来源整段替换清除低来源细项。camelCase 不拆词,约定变量优先于显式插值;宿主显式提供 `configSchemas` 识别 YAML 缺少的可选路径,模块执行业务校验。
|
|
24
|
-
-
|
|
24
|
+
- 环境文件约定:`.env.example` 完整列出字段用途、默认值、枚举和范围;`.env` 为公共基础;`.env.dev`、`.env.test`、`.env.prod` 为公共环境覆盖,公共文件提交 Git。`.env.local` 为共享私有配置,`.env.<mode>.local` 为模式私有配置,均不提交 Git。优先级为进程环境 > `.env.<mode>.local` > `.env.local` > `.env.<mode>` > `.env` > YAML;Vite 在 Node 配置阶段调用 `core.config.loadEnvFiles({ mode, envDir })` 并检查 success 后注入进程,Node 入口复用 `run-node.mjs` 的结构合并,避免原生多 `--env-file` 遗留低来源细项。`core.init` 不自行读取 dotenv。
|
|
25
25
|
- 配置 getter 与 ID/logger 方法不是 HaiResult;validate/load 等须检查 success。
|
|
26
26
|
- 日志可用 `{ error }` 记录原生 Error;两端先规范化诊断再字段/URL 脱敏,配置 redact 路径仍生效。默认包含 passwordHash、passwd、secretKey 等实际凭据字段;异常文本清理显式凭据标签和 URL,不保证识别无标签秘密。原异常不变,错误子图循环/深度用固定标记;业务隐私仍由调用方清理或遮蔽整条路径。
|
|
27
27
|
- 初始化前创建的默认、模块与嵌套 child Logger 在后续输出中应用当前全局 logging;configure/setLevel 也作用于已有实例。create 的显式 level/format/context 优先,未指定项动态继承。浏览器 json/pretty 与附加 redact 路径实际生效,消息文本仍由调用方脱敏。
|
|
@@ -244,30 +244,52 @@ import { apiContract } from '@h-ai/api-contract'
|
|
|
244
244
|
|
|
245
245
|
### 服务端路由(SvelteKit)
|
|
246
246
|
|
|
247
|
+
应用实现 `readOrder`:从共享数据库读取订单,返回持久化的金额、币种、所有者与支付状态。通知地址取服务端配置;在宿主权限配置中登记并授予 `payment:create`。以下工厂在路由模块中注入这两个可信依赖,`kit.handler` 仅提供错误边界,认证和资源授权仍在示例中显式执行。
|
|
248
|
+
|
|
247
249
|
```typescript
|
|
250
|
+
import type { HaiResult } from '@h-ai/core'
|
|
248
251
|
import { kit } from '@h-ai/kit'
|
|
249
|
-
// src/routes/api/v1/payment/create/+server.ts
|
|
250
252
|
import { payment } from '@h-ai/payment'
|
|
253
|
+
import { z } from 'zod'
|
|
254
|
+
|
|
255
|
+
interface PayableOrder {
|
|
256
|
+
orderNo: string
|
|
257
|
+
ownerId: string
|
|
258
|
+
amount: number
|
|
259
|
+
currency: string
|
|
260
|
+
description: string
|
|
261
|
+
status: 'pending' | 'paid' | 'closed'
|
|
262
|
+
}
|
|
251
263
|
|
|
252
|
-
export
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
264
|
+
export function createPaymentHandler(
|
|
265
|
+
readOrder: (id: string) => Promise<HaiResult<PayableOrder | null>>,
|
|
266
|
+
notifyUrl: string,
|
|
267
|
+
) {
|
|
268
|
+
return kit.handler(async ({ request, locals }) => {
|
|
269
|
+
const session = locals.session
|
|
270
|
+
if (!session) return kit.response.unauthorized()
|
|
271
|
+
kit.guard.require(session, 'payment:create')
|
|
272
|
+
const input = await kit.validate.body(request, z.object({ orderId: z.string().min(1) }).strict())
|
|
273
|
+
const order = await readOrder(input.orderId)
|
|
274
|
+
if (!order.success) return kit.response.fromError(order.error)
|
|
275
|
+
if (!order.data || order.data.ownerId !== session.userId || order.data.status !== 'pending')
|
|
276
|
+
return kit.response.forbidden()
|
|
277
|
+
const result = await payment.createOrder('stripe', {
|
|
278
|
+
orderNo: order.data.orderNo,
|
|
279
|
+
amount: order.data.amount,
|
|
280
|
+
currency: order.data.currency,
|
|
281
|
+
description: order.data.description,
|
|
282
|
+
tradeType: 'h5',
|
|
283
|
+
notifyUrl,
|
|
284
|
+
})
|
|
285
|
+
if (!result.success) return kit.response.fromError(result.error, locals.requestId)
|
|
286
|
+
return kit.response.ok(result.data, locals.requestId)
|
|
261
287
|
})
|
|
262
|
-
|
|
263
|
-
if (!result.success) {
|
|
264
|
-
return kit.response.internalError(result.error.message)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
return kit.response.ok(result.data, locals.requestId)
|
|
268
|
-
})
|
|
288
|
+
}
|
|
269
289
|
```
|
|
270
290
|
|
|
291
|
+
在 `+server.ts` 中将可信业务读取函数和通知地址传给工厂,再导出返回值为 `POST`。
|
|
292
|
+
|
|
271
293
|
### 完整支付流程
|
|
272
294
|
|
|
273
295
|
```
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
## 运行环境
|
|
8
8
|
|
|
9
|
+
Provider 名称必须唯一,重名在连接前返回 CONFIG_ERROR。close 等待在途初始化并释放其 Provider,返回后不再迟到发布模块或定时器。
|
|
10
|
+
|
|
9
11
|
> ⚠️ **服务端模块(Node.js only)。** 浏览器端不直接发送邮件/短信,而是通过 API 端点触发服务端 `reach.send()`。
|
|
10
12
|
|
|
11
13
|
## 依赖
|
|
@@ -76,21 +78,27 @@ API Provider 只接受 HTTP(S) URL。回调地址若来自不可信输入,业
|
|
|
76
78
|
### 2. 初始化与关闭
|
|
77
79
|
|
|
78
80
|
```typescript
|
|
79
|
-
import { cache } from '@h-ai/cache'
|
|
81
|
+
import { cache, CacheConfigSchema } from '@h-ai/cache'
|
|
80
82
|
import { core } from '@h-ai/core'
|
|
81
|
-
import { reach } from '@h-ai/reach'
|
|
82
|
-
import { reldb } from '@h-ai/reldb'
|
|
83
|
+
import { reach, ReachConfigSchema } from '@h-ai/reach'
|
|
84
|
+
import { reldb, ReldbConfigSchema } from '@h-ai/reldb'
|
|
83
85
|
|
|
84
86
|
// 当前配置启用了 delay:数据库和队列表为必需依赖。
|
|
85
|
-
const
|
|
87
|
+
const databaseConfig = core.config.validate('db', ReldbConfigSchema)
|
|
88
|
+
if (!databaseConfig.success) throw new Error(databaseConfig.error.message)
|
|
89
|
+
const database = await reldb.init(databaseConfig.data)
|
|
86
90
|
if (!database.success)
|
|
87
91
|
throw new Error(database.error.message)
|
|
88
|
-
const
|
|
92
|
+
const cacheConfig = core.config.validate('cache', CacheConfigSchema)
|
|
93
|
+
if (!cacheConfig.success) throw new Error(cacheConfig.error.message)
|
|
94
|
+
const cached = await cache.init(cacheConfig.data) // 可选,启用 flush 分布式锁
|
|
89
95
|
if (!cached.success)
|
|
90
96
|
throw new Error(cached.error.message)
|
|
91
97
|
|
|
92
98
|
// 再初始化触达模块(自动检测已初始化的 reldb/cache 单例)
|
|
93
|
-
const
|
|
99
|
+
const reachConfig = core.config.validate('reach', ReachConfigSchema)
|
|
100
|
+
if (!reachConfig.success) throw new Error(reachConfig.error.message)
|
|
101
|
+
const initialized = await reach.init(reachConfig.data)
|
|
94
102
|
if (!initialized.success)
|
|
95
103
|
throw new Error(initialized.error.message)
|
|
96
104
|
// ... 使用触达服务
|
|
@@ -234,7 +242,7 @@ interface ReachConfigInput {
|
|
|
234
242
|
|
|
235
243
|
验证码和密码重置等有时效的通知应明确选择 DND 策略;可靠入队成功不代表用户已收到验证码。
|
|
236
244
|
|
|
237
|
-
队列 `created_at` / `updated_at` / `locked_until` / `next_attempt_at` 均为 Unix 毫秒 `BIGINT`(SQLite 为 64 位 INTEGER);仓库把 driver 的字符串/数字归一化为安全整数 number,并拒绝负数、小数和不安全整数。模板仓库的 TIMESTAMP 时间返回 Date
|
|
245
|
+
队列 `created_at` / `updated_at` / `locked_until` / `next_attempt_at` 均为 Unix 毫秒 `BIGINT`(SQLite 为 64 位 INTEGER);仓库把 driver 的字符串/数字归一化为安全整数 number,并拒绝负数、小数和不安全整数。模板仓库的 TIMESTAMP 时间返回 Date。初始化自动执行版本化迁移,包含次数、退避策略和失败分类;升级前先 dry-run、备份并停止旧写入。旧通知载荷退役会清空正文/变量并将旧待发项标记 discarded,回退镜像不能恢复这些数据;跨库验收必须运行 PostgreSQL/MySQL 用例,SQLite 无法证明 32 位溢出已经消除。
|
|
238
246
|
|
|
239
247
|
### 租约、接收端幂等与未知结果
|
|
240
248
|
|
|
@@ -62,9 +62,12 @@ PostgreSQL 空闲连接错误已监听,由池移除并在下一次查询替换
|
|
|
62
62
|
|
|
63
63
|
```typescript
|
|
64
64
|
import { core } from '@h-ai/core'
|
|
65
|
-
import { reldb } from '@h-ai/reldb'
|
|
65
|
+
import { reldb, ReldbConfigSchema } from '@h-ai/reldb'
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
const config = core.config.validate('db', ReldbConfigSchema)
|
|
68
|
+
if (!config.success) throw new Error(config.error.message)
|
|
69
|
+
const initialized = await reldb.init(config.data)
|
|
70
|
+
if (!initialized.success) throw new Error(initialized.error.message)
|
|
68
71
|
// ... 使用数据库
|
|
69
72
|
const closed = await reldb.close()
|
|
70
73
|
if (!closed.success) throw new Error(closed.error.message)
|
|
@@ -175,7 +175,7 @@ await scheduler.init({
|
|
|
175
175
|
|
|
176
176
|
可信服务端用 `execution.listLogFailures({ limit, offset })` 监控 pending(范围与 listUnknown 相同),用 `execution.repairLog(occurrenceId)` 从共享 journal 幂等补写;可跨节点、重启及并发调用。写入已提交但回执丢失时通过固定主键和完整内容核对去重。补写返回 `LOG_PERSIST_FAILED`(032)时继续保留 pending,并输出安全告警;全部数据库不可用且终态未提交时仍按 unknown 核对外部效果,不能假定存在可恢复结果。补写与日志保留均不调用业务 Hook。保留策略失败仅告警,不撤销已保存日志。`onTaskFinish` 是本地业务完成通知,其 unconfirmed 状态不是持久化确认;以 trigger 返回值及 execution.get 的 logPersistence 为准。
|
|
177
177
|
|
|
178
|
-
领取前竞争/跳过的 interrupted 仅为观测日志,没有可补写的终态;其写入未确认时返回 unconfirmed。JSON 大载荷保存完整结果和全部重试记录,避免 MySQL 的 255
|
|
178
|
+
领取前竞争/跳过的 interrupted 仅为观测日志,没有可补写的终态;其写入未确认时返回 unconfirmed。JSON 大载荷保存完整结果和全部重试记录,避免 MySQL 的 255 字符截断;初始化会自动执行版本化迁移,归档并复制旧日志;升级前先 dry-run、备份并停止旧写入,按模块 README 核对迁移影响。关闭会等待在途补写,先关闭 scheduler 再关闭数据库。
|
|
179
179
|
|
|
180
180
|
```ts
|
|
181
181
|
const result = await scheduler.trigger('cleanup', { idempotencyKey: 'cleanup-2026-10-23' })
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
## 运行环境
|
|
6
6
|
|
|
7
|
+
Local 的 key 路径拒绝文件符号链接和目录 junction,`.meta.json` / `.upload.tmp` 保留后缀不区分大小写。覆盖 put 清除旧元数据,copy 默认继承源元数据。浏览器根入口仅导出 Schema、类型和客户端辅助能力。
|
|
8
|
+
|
|
7
9
|
> ⚠️ **服务端模块**。`storage.file` / `storage.dir` / `storage.presign` 均在 Node.js 端使用。浏览器端通过预签名 URL 或 API 端点间接访问存储(见下方「浏览器端文件上传」)。
|
|
8
10
|
|
|
9
11
|
## 适用场景
|
|
@@ -53,9 +55,13 @@ MinIO、RustFS 使用同一个 S3 Provider:配置 `type: s3`、S3 API `endpoin
|
|
|
53
55
|
### 2. 初始化与关闭
|
|
54
56
|
|
|
55
57
|
```typescript
|
|
56
|
-
import {
|
|
58
|
+
import { core } from '@h-ai/core'
|
|
59
|
+
import { storage, StorageConfigSchema } from '@h-ai/storage'
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
const config = core.config.validate('storage', StorageConfigSchema)
|
|
62
|
+
if (!config.success) throw new Error(config.error.message)
|
|
63
|
+
const initialized = await storage.init(config.data)
|
|
64
|
+
if (!initialized.success) throw new Error(initialized.error.message)
|
|
59
65
|
// 使用后关闭
|
|
60
66
|
const closeResult = await storage.close()
|
|
61
67
|
if (!closeResult.success) {
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
## 运行环境
|
|
8
8
|
|
|
9
|
+
pgvector 将集合 metric 持久保存在 vector 列注释,索引、info、search 使用同一值;重连后修改默认 metric 不改变已有集合。旧集合从实际索引恢复;缺少索引与有效注释时先恢复定义,不按当前默认值猜测。
|
|
10
|
+
|
|
9
11
|
> ⚠️ **服务端模块(Node.js only)。** 浏览器端不直接操作向量数据库,通过 `@h-ai/ai` 的 API 端点间接使用(如 RAG 检索、知识库查询)。
|
|
10
12
|
|
|
11
13
|
## 适用场景
|
|
@@ -62,9 +64,12 @@ operationLog:
|
|
|
62
64
|
|
|
63
65
|
```typescript
|
|
64
66
|
import { core } from '@h-ai/core'
|
|
65
|
-
import { vecdb } from '@h-ai/vecdb'
|
|
67
|
+
import { vecdb, VecdbConfigSchema } from '@h-ai/vecdb'
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
const config = core.config.validate('vecdb', VecdbConfigSchema)
|
|
70
|
+
if (!config.success) throw new Error(config.error.message)
|
|
71
|
+
const initialized = await vecdb.init(config.data)
|
|
72
|
+
if (!initialized.success) throw new Error(initialized.error.message)
|
|
68
73
|
// ... 使用向量数据库
|
|
69
74
|
const closeResult = await vecdb.close()
|
|
70
75
|
if (!closeResult.success) {
|