Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,64 @@
|
||||
# 应用
|
||||
|
||||
## API 和 CMD
|
||||
|
||||
源码:[健康检查 API](../assets/examples/http-rest/module/system/health/api/admin/status.dever)
|
||||
|
||||
```dever
|
||||
public get ready = app.status
|
||||
```
|
||||
|
||||
API 只绑定同领域 App 或声明 REST。支持 get/post/put/delete;CMD 写 `cmd name = app.function`。输入输出继承 App,每个接口绑定一个可序列化输出。
|
||||
|
||||
GET/DELETE 从 query 读标量,POST/PUT 从 JSON 对象读参数。未知、重复或缺少必填字段失败。成功为 `{"code":0,"message":"ok","data":...}`;失败的 code 对应 HTTP 状态,data 为 null。dever.api.Error 映射 400/401/403/404/409/429,内部故障返回安全的 500。
|
||||
|
||||
## 站点、身份与权限
|
||||
|
||||
`sites.admin.path = "admin"` 匹配 api/admin/**;文件主题也进入 URL,上例为 /system/health/admin/status/ready。每条 HTTP 声明恰好匹配一个站点;path 不重写 URL,也不匹配 api/admin.dever。
|
||||
|
||||
| 声明 | 校验 |
|
||||
| --- | --- |
|
||||
| 默认 HTTP | 身份与精确角色权限 |
|
||||
| public HTTP | 匿名入口 |
|
||||
| authenticated HTTP | 可信身份;App 校验对象所有权和实际业务权限 |
|
||||
|
||||
public/authenticated 不修饰 CMD 或 REST。权限键由核心生成,为 component.domain.site.action;REST 使用 read/create/replace/delete,方法不进入键。
|
||||
|
||||
Provider 的 verify App 接收 dever.auth.Claims,只返回 id: Text、user_id: UserModelId?、tenant_id: TenantModelId?。它读取 global Model 核验账号、会话、成员和租户,不返回权限列表。
|
||||
|
||||
认证后使用 dever.auth 和 dever.site 读取可信身份,Model ID 须匹配 verify。客户端数据不作为身份来源。public、CMD、Job 和普通测试不能直接读取 HTTP 身份。
|
||||
|
||||
核心管理角色、用户角色和权限,读取允许受保护及 authenticated 入口,修改仅允许普通受保护写入口。通用业务权限使用 registerCapability/removeCapability,命名空间与租户来自可信入口。方法见 [签名](signatures.md)。
|
||||
|
||||
Cookie 登录/退出使用 issueCookie/clearCookie;配置站点 origin,Cookie 写入及 Cookie 认证的写请求校验 Origin 和 Host。敏感头不读作普通 Text。
|
||||
|
||||
## Model 与业务操作
|
||||
|
||||
源码:[文章 Model](../assets/examples/http-rest/module/content/article/model.dever)
|
||||
|
||||
```dever
|
||||
type Article {
|
||||
title: Text(1, 200)
|
||||
body: Text raw
|
||||
}
|
||||
```
|
||||
|
||||
Model 自动生成只读 id 和 created_at,字段支持 default/private/unique/index。不同 Model 的 ID 不混用。
|
||||
|
||||
Model Text 写入时默认去除首尾 Unicode 空白,再校验长度;`raw` 保留原文,`lower`/`upper` 在去空白后转换大小写,三者互斥。null 不变,空串不转 null。普通 Text、查询和原生 SQL 不自动转换。正文、代码等用 raw;用户名可以用 lower,但登录查询仍由业务明确采用同一规范。唯一性使用数据库 unique,不能先查询代替约束。
|
||||
|
||||
普通 CRUD 直接写 rest model;多 Model 指定 model.topic。App 使用 model.create/get/list/update/delete 等操作,字段和查询由编译器检查,值参数绑定。
|
||||
|
||||
REST 的 create/replace/search 表达式引用 input 时转换客户端输入,否则由服务端提供并拒绝客户端同名字段。private owner 使用可信用户绑定全部读写 SQL。
|
||||
|
||||
有关联操作、状态变化或额外输入输出转换再写 App。Model 数据库操作不套 Port/repository,私有字段通过显式 View 隐藏。
|
||||
|
||||
## 事务、租户与 Job
|
||||
|
||||
普通写 HTTP、CMD、Job 建立整体事务,成功编码后提交。GET 不写库或入队。外部 I/O、Worker、密码计算和并发放事务外;需要分阶段编排时用 long 入口,写入进入显式 transaction。事务内重查写入依赖的状态;先前提交的阶段不因后续失败撤销。
|
||||
|
||||
tenant.database 选择控制连接,global type 使用平台库,其余 Model/Job 使用租户库。只支持 database 隔离;缺少租户或 schema 未就绪时报错。
|
||||
|
||||
部署侧用 dever tenant migrate、tenant owner、tenant component enable/disable 管理租户。Job 按 [示例](examples.md#持久-job)声明,由核心负责队列、重试和执行前权限重验。
|
||||
|
||||
配置只加实际用到的 database、tenant、auth、sites、http、job、runtime、log。完整配置见 [HTTP 项目](../assets/examples/http-rest/config/setting.json)和 [Job 项目](../assets/examples/jobs/config/setting.json);示例占位凭据须替换,真实秘密不提交。
|
||||
@@ -0,0 +1,57 @@
|
||||
# 开发指引
|
||||
|
||||
## 开始项目
|
||||
|
||||
```sh
|
||||
dever new my_app
|
||||
dever check my_app
|
||||
dever test my_app
|
||||
dever run my_app -- hello.greeting.greet '{"name":"Dever"}'
|
||||
```
|
||||
|
||||
目标目录须不存在,父目录须存在。模板带源码、测试、配置和说明;替换演示功能时同步替换相应用例。
|
||||
|
||||
## 项目组织
|
||||
|
||||
源码使用 `.dever`。每个领域放 README、主题 doc 和自动 link.md,结构见 [文档写法](documentation.md)。业务角色按需要创建:
|
||||
|
||||
| 角色 | 职责 |
|
||||
| --- | --- |
|
||||
| App | 公开能力和业务编排,跨领域只调用目标 App |
|
||||
| Domain | 本领域内部规则 |
|
||||
| Model | 数据结构、查询和迁移,只由本领域 App 操作 |
|
||||
| API | HTTP/CMD 绑定和自动 REST |
|
||||
| Port / Adapter | 外部操作声明及实现 |
|
||||
| Job | 绑定本领域 App 的持久任务 |
|
||||
|
||||
函数用 ASCII lowerCamelCase,字段、局部值和目录用 snake_case,类型用 UpperCamelCase。不建 common/shared/utils/helper/base/service 目录。
|
||||
|
||||
同一职责的函数放在同一文件,也可按主题写入 `app/publish.dever`。App/Domain/Port/Adapter/Job 的主文件与目录二选一;Model/API 可共存。只有 API 主题目录可递归并影响 URL。
|
||||
|
||||
## 实现
|
||||
|
||||
- 先读相关领域 README、主题、调用图和源码。可用 `dever inspect . --symbol component.domain.function --depth 2` 查询上下游,不默认读取全项目索引。
|
||||
- 普通 CRUD 使用 Model 和 REST,有额外业务规则再写 App。复用标准库和组件,不为每次调用套 helper、repository 或转发层。
|
||||
- 外部输入在入口验证;内部不重复检查已确定的类型。权限、归属和可变状态仍由所属逻辑检查。
|
||||
- 错误按声明传播,不用默认成功、空集合或测试数据掩盖失败。不为假想情况加兜底、重试或备用实现。
|
||||
- Model Text 默认去首尾空白;raw 保留原文,lower/upper 转换大小写。不要在业务代码重复清洗。
|
||||
- 环境配置放 `config/setting.json`,身份和归属取可信上下文。业务程序不从环境变量读取配置,真实凭据不提交。
|
||||
- 只实现当前需求,不写无调用方的扩展。Dever 源码不写说明注释;必要解释放主题 doc,句子要具体,不填“操作参数”等空话。
|
||||
|
||||
项目不设置 `dever.version`;编译器跟随开发环境,依赖由 `dever.lock` 锁定。
|
||||
|
||||
## 修改后检查
|
||||
|
||||
```sh
|
||||
dever fmt . --check
|
||||
dever check .
|
||||
dever test . --filter component.domain.case
|
||||
dever inspect . --links
|
||||
dever inspect . --links --check
|
||||
```
|
||||
|
||||
测试使用 assert/assertEq。用例主题转为 lowerCamelCase 入口,例如 `account_login.dever` 对应 `accountLogin() ()`。每例默认 60 秒,可用 `--timeout-ms` 调整;无匹配用例会报错。
|
||||
|
||||
Port 用每例独立 fake,Model 使用临时 SQLite,不连接部署数据库。check 也检查配置、接口基线及生产入口可达性;测试调用不能代替生产调用。重复实现和业务合理性仍需审查。
|
||||
|
||||
修改实现时同步受影响的主题说明、测试和调用图。已有 `dever.api` 不直接覆盖;接口变更先用 `dever api . --output <新文件>` 导出并审查。报告实际结果及未测范围,删除本次废弃内容,保留无关修改。
|
||||
@@ -0,0 +1,21 @@
|
||||
# 文档写法
|
||||
|
||||
每个领域使用 README.md、doc/<主题>.md 和自动生成的 link.md。源码为 `.dever` 纯代码。
|
||||
|
||||
- README 用一段话介绍领域职责,并列出主题入口。
|
||||
- doc 按功能组织。二级标题绑定完整符号名,例如 `## manage.account.login`;同一函数只写一处,多分句共用。
|
||||
- 正文解释用途和必要规则,一般一两句。参数含义不清楚时再补说明,不复制签名、调用方或行号。
|
||||
- 不写占位描述、对话、修改日志或重复的模块介绍。说明必须符合当前源码。
|
||||
|
||||
VS Code 悬浮自动组合源码签名、主题说明和调用摘要;点击可查看源码与上下游。没有说明时仍显示真实签名,不需要在源码加注释。
|
||||
|
||||
修改代码后执行:
|
||||
|
||||
```sh
|
||||
dever inspect . --links
|
||||
dever inspect . --links --check
|
||||
```
|
||||
|
||||
link 展示调用顺序、分支和任务调度,保留完整关系,不手工改写。它是静态流程,实际请求和 Adapter 选择仍取决于输入及配置。
|
||||
|
||||
修改前读相关 README、主题与调用图,改完同步说明。检查器能发现失效符号、重复绑定和过期调用图,文字含义仍需对照实现。
|
||||
@@ -0,0 +1,53 @@
|
||||
# 示例
|
||||
|
||||
最小项目用 `dever new <新目录>`。下列项目可复制到新目录后修改,均包含源码、测试和配置。
|
||||
|
||||
| 场景 | 项目 | 用例筛选 |
|
||||
| --- | --- | --- |
|
||||
| 集合、分句 | [collections](../assets/examples/collections/) | content.article |
|
||||
| HTTP、REST、身份核验 | [http-rest](../assets/examples/http-rest/) | content.article.title |
|
||||
| 持久任务 | [jobs](../assets/examples/jobs/) | report.archive.queued |
|
||||
| Python/JS/Go 与 Port fake | [external-lib](../assets/examples/external-lib/) | document.markup |
|
||||
| 普通二进制与 Port fake | [command](../assets/examples/command/) | document.tool.version |
|
||||
|
||||
```sh
|
||||
dever fmt <root> --check
|
||||
dever check <root>
|
||||
dever test <root> --filter <表中筛选> --timeout-ms 5000
|
||||
```
|
||||
|
||||
测试不会启动真实第三方程序或连接部署数据库。教程片段链接到这些项目的源码,校验脚本检查片段、签名及项目;运行验证使用当前编译器。
|
||||
|
||||
## HTTP 与 REST
|
||||
|
||||
http-rest 包含匿名健康检查和受保护 Article 资源:
|
||||
|
||||
- GET /system/health/admin/status/ready 返回成功包裹的 true。
|
||||
- /content/article/admin/entries 提供 REST;用 dever api 导出具体方法和输入输出。
|
||||
- verify 检查会话、用户、租户和成员关系;未提供注册、密码登录或签发凭据。
|
||||
|
||||
实际部署需配置密钥、身份数据、租户库和 Owner。角色由核心管理,不能把 fake 测试当作认证或部署验收。操作规则见 [应用](application.md)。
|
||||
|
||||
## 持久 Job
|
||||
|
||||
jobs 通过 report.archive.submit 入队,key 去重,Job 在事务中写入归档记录。测试用临时 SQLite、独立时钟和 drainJobs 验证队列,不启动常驻 worker。
|
||||
|
||||
真实 CMD 会写配置的数据库;无命令参数时才按 runtime.mode 启动服务:
|
||||
|
||||
```sh
|
||||
dever run <root> -- report.archive.submit '{"input":{"key":"report-2026-10","title":"Monthly report"}}'
|
||||
```
|
||||
|
||||
任务至少执行一次,外部副作用仍须业务幂等。执行身份和权限规则见 [应用](application.md)。
|
||||
|
||||
## 外部程序
|
||||
|
||||
external-lib 附三种生态的处理函数和 fake,不附真实依赖锁与运行资源,见 [接入说明](external-lib.md)。
|
||||
|
||||
command 不附 bin/tool;真实运行前需提供目标架构的 ELF 及所需库。fake 只验证 App 与 Port 的接口。
|
||||
|
||||
collections 可直接运行,无需数据库:
|
||||
|
||||
```sh
|
||||
dever run <root> -- content.article.summarize '{"articles":[{"title":" First ","published":true}]}'
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
# 外部库接入
|
||||
|
||||
[external-lib 项目](../assets/examples/external-lib/) 使用现成 Markdown 库,App 调用 Port,外部程序实现 render。示例可运行 fake 测试,真实依赖与运行资源另行准备。生成 HTML 未清洗,展示不可信输入前需处理。
|
||||
|
||||
| 生态 | external 声明 | lib 声明 | setting.json 的 lib 项 |
|
||||
| --- | --- | --- | --- |
|
||||
| Python | external pip "python/render.py" | markdown@3.8.2 | pip:markdown@3.8.2 |
|
||||
| JavaScript | external npm "javascript/render.mjs" | marked@15.0.12 | npm:marked@15.0.12 |
|
||||
| Go | external go "go/render.go" | github.com/yuin/goldmark@v1.7.8 | go:github.com/yuin/goldmark@v1.7.8 |
|
||||
|
||||
源码:[Adapter](../assets/examples/external-lib/module/document/markup/adapter.dever)
|
||||
|
||||
```dever
|
||||
external pip "python/render.py" {
|
||||
lib "markdown@3.8.2"
|
||||
}
|
||||
```
|
||||
|
||||
切换生态时同步 Adapter 和配置,Port、App 和测试的接口不变。版本是示例固定输入,各库的 Markdown 方言和换行可能不同。
|
||||
|
||||
## 处理函数
|
||||
|
||||
| 生态 | 导出签名 |
|
||||
| --- | --- |
|
||||
| Python | async def render(payload, setting) |
|
||||
| JavaScript | async function render(payload, setting, signal) |
|
||||
| Go | func Render(context.Context, any, any) (any, error) |
|
||||
|
||||
Go 声明 package main,入口由工具生成。操作名按单词转 UpperCamelCase。Worker 接口定义和运行器由编译器按 Port 生成,不手写协议、hash 或操作注册表。
|
||||
|
||||
输入为 `{"source":"# Report"}`,成功输出为 `{"html":"..."}`。单输出也须保留命名字段;没有 setting 时传 null/nil。
|
||||
|
||||
业务拒绝使用 SDK BusinessError,identity 为 document.markup.RenderResult.Rejected,payload 为 `{"message":"..."}`。其他异常为运行失败。stdout 专用于协议,日志写 stderr;处理函数须响应各生态的取消信号。
|
||||
|
||||
配置通过 Adapter setting 传入。文件、网络、进程或 GPU 用 allow 声明,实际权限由运行环境管理;Worker 不是不可信代码沙箱。
|
||||
|
||||
## 验证与运行
|
||||
|
||||
```sh
|
||||
dever check <root>
|
||||
dever test <root> --filter document.markup --timeout-ms 5000
|
||||
```
|
||||
|
||||
rendered/rejected 分别验证成功和拒绝,每例独立 fake。真实运行需可信的 dever.lock、目标运行时及 Worker 资源;当前 CLI 只提供 lib install 恢复已有锁,不提供 add/update 解析新锁。
|
||||
|
||||
准备好资源后运行 `dever run <root> -- document.markup.render '{"source":"# Report"}'`。fake 不验证第三方库的实际输出或跨架构运行。
|
||||
@@ -0,0 +1,32 @@
|
||||
# 安装与环境
|
||||
|
||||
开发 Dever 应用只需安装 Dever,底层编译环境由安装包管理。
|
||||
|
||||
| 方式 | 用途 |
|
||||
| --- | --- |
|
||||
| `bash install` | 先启用 Dever 命令,后台准备编译环境 |
|
||||
| `bash install --wait` | 等待完整环境就绪,用于 CI 或构建镜像 |
|
||||
| 完整离线包 | 首次安装就没有外网的环境 |
|
||||
|
||||
安装包支持 Linux x86_64、glibc 2.41 及以上。默认目录为 `~/.dever`,支持 `--prefix` 和 `--no-modify-path`。创建、编辑、fmt/check 可先进行,首次 run/test/build 会等待环境就绪;中断后可继续。
|
||||
|
||||
同版本重装会复用已有目录。验证重新打包的 0.0.1 时使用新的安装目录。
|
||||
|
||||
## 项目规则
|
||||
|
||||
新项目执行 `dever new <目录>`。已有项目可在根目录执行:
|
||||
|
||||
```sh
|
||||
dever skill path .
|
||||
dever skill install
|
||||
```
|
||||
|
||||
path 返回随包 Skill;install 更新项目 AGENTS 的 Dever 标记块,不替换标记外内容。它不切换编译器,也不注册 AI 客户端的原生 Skill。
|
||||
|
||||
项目不写 `dever.version`。更换开发环境后检查 `dever --version` 和 Skill 路径;依赖版本保留在 `dever.lock`。
|
||||
|
||||
## 目标与依赖
|
||||
|
||||
用 `dever package` 管理 Dever 组件,`dever lib install <root>` 恢复已锁定资源。当前 CLI 没有 Lib add/update;新锁和外部运行资源需由发行方准备,不能伪造锁或借用系统解释器。
|
||||
|
||||
`build --target linux-x86_64|linux-aarch64` 选择目标。交叉构建须预备目标库、链接器和 sysroot;run/test 在本机执行。
|
||||
@@ -0,0 +1,78 @@
|
||||
# 语法速查
|
||||
|
||||
源码用 `.dever`,说明写法见 [源码与说明](documentation.md)。完整规则见安装根 LANGUAGE.md,函数参数见 [签名索引](signatures.md)。
|
||||
|
||||
## 类型和函数
|
||||
|
||||
源码:[模板 App](../assets/template/module/hello/greeting/app.dever)
|
||||
|
||||
```dever
|
||||
greet(name: Text) (message: Text) {
|
||||
message = "Hello, " + name
|
||||
}
|
||||
```
|
||||
|
||||
函数为 `名称(输入) (命名输出)`,按位置调用;没有输入或输出仍写 `()`。单输出直接得到值,多输出按名字访问。正常结束前须给输出赋值。
|
||||
|
||||
类型用 UpperCamelCase,函数用 lowerCamelCase;字段、局部值和目录用 snake_case。record 构造一次给全字段,choice 按分支构造。App 的公开参数和输出不能暴露 Domain/Adapter 的私有类型。
|
||||
|
||||
局部值通常由表达式推断类型。解码、空集合或 null 需要上下文时,首次写 `input: CreateInput = dever.json.decode(payload)`;后续只写 `input = ...`,类型不变。不为提供类型另写包装函数。
|
||||
|
||||
常用类型有 Bool、Int、Decimal、Float、Text、Bytes、Id、Uuid、日期时间、Json、Secret;可空为 T?,集合为 List<T>、Map<K,V>。Model ID 是每个 Model 独有的类型。
|
||||
|
||||
集合成员判断用 `contains(values, target)`。条件不满足时失败用 `dever.api.require(condition, dever.api.Error.Invalid)`,不为每个条件写一对 true/false 函数。状态分支仍用分句表达。
|
||||
|
||||
| 易混规则 | 语义 |
|
||||
| --- | --- |
|
||||
| 小数字面量 | 默认 Decimal,科学计数形式为 Float |
|
||||
| 数值运算 | Int/Int 的 / 返回 Decimal;// 为整数除法 |
|
||||
| 可空值 | 用分句处理,没有隐式默认值或强制解包 |
|
||||
| Map | 保留插入顺序,相等比较也包含顺序 |
|
||||
| 普通值 | 修改副本不影响原值 |
|
||||
| 资源 | 副本共享读取位置或关闭状态 |
|
||||
|
||||
## 分句
|
||||
|
||||
条件使用同名函数分句,必须相邻、互斥且穷尽;没有顺序优先级。other 表示该参数位置未被明确模式覆盖的值。
|
||||
|
||||
源码:[分句测试](../assets/examples/collections/test/content/article/clauses.dever)
|
||||
|
||||
```dever
|
||||
grade(score: Int<60) (text: Text) {
|
||||
text = "fail"
|
||||
}
|
||||
|
||||
grade(score: Int >= 60) (text: Text) {
|
||||
text = "pass"
|
||||
}
|
||||
```
|
||||
|
||||
模式支持类型、choice 分支、null、常量及 Int/Decimal 范围,多参数检查全部组合。没有 if/else、match、return、任意循环或递归。
|
||||
|
||||
## 集合与处理函数
|
||||
|
||||
| 调用 | 结果 |
|
||||
| --- | --- |
|
||||
| each(handler, list) | handler 单输出时映射为 List,零输出时遍历 |
|
||||
| filter(handler, list) | 按 Bool 输出筛选 |
|
||||
| find(handler, list) | 第一个匹配值或 null |
|
||||
| sum(list) | 数值求和 |
|
||||
| reduce(handler, values, initial) | 按“元素、累计值”调用,空集合返回 initial |
|
||||
| reduceUntil(handler, values, initial) | handler 另输出 stop: Bool |
|
||||
| parallelEach(handler, values, limit) | 并行执行零输出 handler,返回前全部收尾 |
|
||||
|
||||
使用具名 handler,无 lambda 或运行时闭包。each/filter/find/投影 sum 可带一个末尾 context;reduce 的共享数据放累计状态。完整用法见 [集合项目](../assets/examples/collections/)。
|
||||
|
||||
## 失败和并发
|
||||
|
||||
choice 的 error 分支声明业务失败;普通调用默认传播,fail 主动失败,result(call) 捕获后交给穷尽分句。主动恢复写 recover("具体理由"),不能用读取错误消息代替处理。
|
||||
|
||||
类型化 JSON 也可直接捕获:`decoded: DecodeResult = result(dever.json.decode(payload))`。结果 Choice 用一个成功字段指定目标类型,error 分支包装 `dever.json.JsonResult`;错误身份保持不变,参数失败仍向外传播。无载荷且无 error 分支的 Choice 在 API/CMD/JSON 中使用分支名字符串,其他 Choice 留在程序内部。
|
||||
|
||||
pure 禁止 I/O、时钟和并发等效果。外部 I/O 经 Port/Adapter;密码使用 dever.crypto,Secret 不可打印、比较或转为普通 Text。
|
||||
|
||||
普通调用顺序完成,挂起自动推断。run 启动 Task,wait/stop 消费;timeout 到期先清理再执行 fallback,race 清理未选中的任务。Task/Group 不得逃逸。同步阻塞操作用 blocking,纯计算可用 parallel。
|
||||
|
||||
Stream/AsyncStream/Channel 的能力与生命周期由编译器检查;result 只改变失败表示,不改变调度或访问权限。
|
||||
|
||||
Channel 不接受可空元素;关闭且缓存读完时 receive 返回 null。需要传递空值时,使用带可空字段的消息 Choice。
|
||||
@@ -0,0 +1,40 @@
|
||||
# 标准库与依赖
|
||||
|
||||
标准库直接按包名调用,无需 import、下载或复制源码。参数和返回值查 [签名](signatures.md),完整声明在安装根 lib/。
|
||||
|
||||
| 能力 | 包 |
|
||||
| --- | --- |
|
||||
| 文本、数字 | text、int、decimal、float、math |
|
||||
| 标识、字节、时间 | uuid、dever.id、dever.bytes、dever.time |
|
||||
| 密码与摘要 | dever.crypto |
|
||||
| JSON | dever.json;普通 API/CMD 自动编解码 |
|
||||
| 文件与网络 | dever.io、dever.net、dever.http |
|
||||
| 请求与身份 | dever.api、dever.auth、dever.site |
|
||||
|
||||
## Dever Package
|
||||
|
||||
Package 为可复用 Dever 组件,在 setting.json 的 package.registry/use 声明。使用 dever package add/update/remove/list/doctor 管理,dever.lock 固定版本和摘要,不能覆盖本地同名组件。
|
||||
|
||||
资源随 module/<name>/ 发布。用 `dever package export <root> <name> <相对子目录> --output <新目录>` 导出:消费已验证锁和缓存,不联网或执行脚本;目标须不存在,父目录须存在且无符号链接。输出包含逐文件摘要,文件不保留执行位,前端构建和发布由调用方完成。
|
||||
|
||||
## 外部 Lib 与普通二进制
|
||||
|
||||
第三方生态依赖在 setting.json 根 lib 数组声明,由 Port/Adapter 使用。已有锁用 `dever lib install <root>` 恢复;当前 CLI 不提供 Lib add/update,不能伪造锁或借用系统解释器补缺失资源。
|
||||
|
||||
Port 定义输入、输出和错误;external exec/pip/npm/go 由匹配的 Worker SDK 执行。具体方法见 [外部库](external-lib.md)。allow 声明能力,实际文件、网络和设备权限由运行环境控制,只执行可信代码。
|
||||
|
||||
普通二进制使用 command:
|
||||
|
||||
源码:[Port](../assets/examples/command/module/document/tool/port.dever)
|
||||
|
||||
```dever
|
||||
execute(args: List<Text>, stdin: Bytes?) (output: dever.process.Output) fails dever.process.Error
|
||||
```
|
||||
|
||||
源码:[Adapter](../assets/examples/command/module/document/tool/adapter.dever)
|
||||
|
||||
```dever
|
||||
external command "bin/tool" {}
|
||||
```
|
||||
|
||||
bin/tool 相对所属领域,须提供匹配目标的 ELF。参数直接传 argv,不经过 shell;输出含 code/stdout/stderr,非零退出码是正常结果。启动失败、超时或超限产生错误。普通测试使用 Port fake。
|
||||
@@ -0,0 +1,122 @@
|
||||
# 标准库常用签名
|
||||
|
||||
参数按位置传入,输出名属于合同。以下签名与随包 lib/ 的公开声明由 test/skill_examples.py 核对。
|
||||
|
||||
## 文本与数字
|
||||
|
||||
```signatures
|
||||
text.trim(value: Text) (result: Text)
|
||||
text.lower(value: Text) (result: Text)
|
||||
text.upper(value: Text) (result: Text)
|
||||
text.at(value: Text, index: Int) (result: Text?)
|
||||
text.slice(value: Text, start: Int, end: Int) (result: Text?)
|
||||
text.contains(value: Text, pattern: Text) (result: Bool)
|
||||
text.startsWith(value: Text, prefix: Text) (result: Bool)
|
||||
text.endsWith(value: Text, suffix: Text) (result: Bool)
|
||||
text.split(value: Text, separator: Text) (result: List<Text>)
|
||||
text.replace(value: Text, pattern: Text, replacement: Text) (result: Text)
|
||||
text.join(values: List<Text>, separator: Text) (result: Text)
|
||||
int.parse(value: Text) (result: Int?)
|
||||
int.toText(value: Int) (result: Text)
|
||||
decimal.parse(value: Text) (result: Decimal?)
|
||||
decimal.round(value: Decimal, places: Int) (result: Decimal)
|
||||
decimal.fromInt(value: Int) (result: Decimal)
|
||||
decimal.toText(value: Decimal) (result: Text)
|
||||
float.parse(value: Text) (result: Float?)
|
||||
float.fromInt(value: Int) (result: Float)
|
||||
uuid.parse(value: Text) (result: Uuid?)
|
||||
uuid.toText(value: Uuid) (result: Text)
|
||||
dever.id.fromText(text: Text) (id: Id)
|
||||
dever.id.toText(id: Id) (text: Text)
|
||||
```
|
||||
|
||||
数值和 Uuid 的 parse 失败返回 null。Id、Uuid、Model ID 是不同类型。Text 索引按 Unicode 码点,slice 含起点、不含终点。
|
||||
|
||||
## Bytes、时间与密码
|
||||
|
||||
```signatures
|
||||
dever.bytes.fromText(text: Text) (bytes: Bytes)
|
||||
dever.bytes.toText(bytes: Bytes) (text: Text)
|
||||
dever.bytes.fromInts(values: List<Int>) (bytes: Bytes)
|
||||
dever.bytes.length(bytes: Bytes) (length: Int)
|
||||
dever.bytes.at(bytes: Bytes, index: Int) (value: Int?)
|
||||
dever.bytes.slice(bytes: Bytes, start: Int, end: Int) (result: Bytes)
|
||||
dever.bytes.concat(left: Bytes, right: Bytes) (bytes: Bytes)
|
||||
dever.time.now() (output: DateTime)
|
||||
dever.time.parseDatetime(text: Text) (output: DateTime) pure
|
||||
dever.time.formatDatetime(value: DateTime) (output: Text) pure
|
||||
dever.time.parseDate(text: Text) (output: Date) pure
|
||||
dever.time.formatDate(value: Date) (output: Text) pure
|
||||
dever.time.duration(millis: Int) (output: Duration) pure
|
||||
dever.time.add(value: DateTime, duration: Duration) (output: DateTime) pure
|
||||
dever.time.subtract(value: DateTime, duration: Duration) (output: DateTime) pure
|
||||
dever.time.difference(later: DateTime, earlier: DateTime) (output: Duration) pure
|
||||
dever.crypto.passwordHash(password: Secret) (value: Text)
|
||||
dever.crypto.passwordVerify(password: Secret, hash: Text) (value: Bool)
|
||||
dever.crypto.token(bytes: Int) (value: Secret)
|
||||
dever.crypto.sha256(bytes: Bytes) (value: Bytes) pure
|
||||
dever.crypto.hmacSha256(key: Secret, bytes: Bytes) (value: Bytes) pure
|
||||
dever.crypto.constantTimeEq(left: Bytes, right: Bytes) (equal: Bool) pure
|
||||
```
|
||||
|
||||
时间解析失败传播 DateTimeResult/DateResult,格式化失败传播 TextResult。非法 UTF-8 为 DecodeResult,字节范围错误为 BufferResult。密码与 token 分别传播 HashResult/VerifyResult/TokenResult;用 result 捕获。密码计算放事务外,在挂起调用链中使用 blocking。
|
||||
|
||||
## JSON 与 HTTP
|
||||
|
||||
```signatures
|
||||
dever.json.fromText(source: Text) (value: Json)
|
||||
dever.json.toText(value: Json) (source: Text)
|
||||
dever.json.setProperty(value: Json, name: Text, child: Json) (result: Json)
|
||||
dever.json.propertyValue(value: Json, name: Text) (result: Json?)
|
||||
dever.json.asText(value: Json) (source: Text)
|
||||
dever.json.asInteger(value: Json) (number: Int)
|
||||
dever.json.parse(source: Text) (document: dever.json.value.Document)
|
||||
dever.json.stringify(document: dever.json.value.Document) (text: Text)
|
||||
dever.json.node(document: dever.json.value.Document, id: Int) (value: dever.json.value.Value?)
|
||||
dever.json.property(document: dever.json.value.Document, id: Int, name: Text) (value: Int?)
|
||||
dever.http.defaultLimits() (result: Limits)
|
||||
dever.http.send(address: Text, port: Int, request: Request, limits: Limits) (response: Response)
|
||||
```
|
||||
|
||||
Json 是不透明值,fromText/toText 保留原始 JSON;propertyValue 返回子 Json。普通 API/CMD 自动编解码。已有 Json 转具体类型用 `dever.json.decode(value)`,由局部类型声明、命名输出、字段或参数确定类型;直接复用 Serde 解码,失败传播 JsonResult.Failed。需要捕获时直接使用 `result(dever.json.decode(value))`,结果 Choice 的成功字段提供目标类型,error 分支包装 JsonResult。不要先转 Text、Document 再手工组装已知类型。未知结构才使用 Document 的 root/nodes 节点树。
|
||||
|
||||
HTTP 的 Limits/Request/Response 属于 dever.http。Request 有 method/target: Text、headers: List<Header>、body: Bytes;Header 有 name: Text、value: Bytes,Response 有 status: Int、headers、body。send 在 Adapter 使用,失败传播 ResponseResult.Failed。
|
||||
|
||||
日志由运行时和部署配置管理,当前标准库没有 dever.log 源码接口。
|
||||
|
||||
## 请求与权限
|
||||
|
||||
```signatures
|
||||
dever.api.requestId() (value: Text)
|
||||
dever.api.header(name: Text) (value: Text?)
|
||||
dever.api.setHeader(name: Text, value: Text) ()
|
||||
dever.auth.id() (value: Text)
|
||||
dever.auth.session() (value: Text)
|
||||
dever.auth.permissions() (values: List<Permission>)
|
||||
dever.auth.currentPermissions() (values: List<Permission>)
|
||||
dever.auth.roles() (values: List<Role>)
|
||||
dever.auth.role(id: Text) (value: Role?)
|
||||
dever.auth.userRoles(user_id: Int) (values: List<Role>)
|
||||
dever.auth.isOwner(user_id: Int) (value: Bool)
|
||||
dever.auth.hasProtectedRoles(user_id: Int) (value: Bool)
|
||||
dever.auth.registerCapability(id: Uuid) (key: Text)
|
||||
dever.auth.removeCapability(id: Uuid) ()
|
||||
dever.auth.saveRole(id: Text, name: Text, all_permissions: Bool, permission_keys: List<Text>) ()
|
||||
dever.auth.grantRole(user_id: Int, role_id: Text) ()
|
||||
dever.auth.revokeRole(user_id: Int, role_id: Text) ()
|
||||
dever.auth.disableRole(role_id: Text) ()
|
||||
dever.auth.deleteRole(role_id: Text) ()
|
||||
dever.auth.issueCookie(subject: Text, session: Text, tenant: Text?) ()
|
||||
dever.auth.clearCookie() ()
|
||||
dever.site.key() (value: Text)
|
||||
```
|
||||
|
||||
`dever.api.require(condition, error)` 接受 Bool 条件和 dever.api.Error;false 时失败,true 时继续。
|
||||
|
||||
Permission 的 key/component/domain/site/action/method/kind 均为 Text;kind 为 http 或 capability,后者 method 为空、action 为 UUID。Role 有 id/site/name: Text、all_permissions/enabled/protected: Bool、permission_keys: List<Text>。
|
||||
|
||||
授权读取允许受保护或 authenticated 入口,修改仅允许普通受保护写入口。capability 还要求可信租户,返回 capability:<component>.<domain>.<site>.<uuid>。isOwner 查询当前站点,hasProtectedRoles 查询当前租户全部站点。访问边界见 [应用](application.md)。
|
||||
|
||||
dever.auth.userId()/tenantId() 可按上下文产生 verify 对应的可空名义 ID。角色操作的目标 user_id 为 Int,只标识当前租户内的对象,不替代操作者身份。
|
||||
|
||||
dever.job.enqueue(job.name[, payload], key) 返回 Id;enqueueAt 末尾加 DateTime。测试的 drainJobs(limit) 返回 Int,advanceClock(ms) 无输出。见 [Job 示例](examples.md#持久-job)。
|
||||
Reference in new issue
Block a user