Files
core/LANGUAGE.md
T
2026-11-03 03:32:07 +00:00

449 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dever 语言规范
Dever 使用静态类型、命名输出和互斥分句。应用由 API、CMD、Job 声明入口,编译为原生程序。
- 开始项目:[开发约定](skills/references/development.md)
- 源码格式:[源码与说明](DOCUMENTATION.md)
- AI 开发:[随包 Skill](skills/SKILL.md)
- 安装:[安装指引](skills/references/install.md)
本文代码块是语法片段,放入对应角色的 `.dever` 文件。完整项目见 [示例](skills/references/examples.md)。
## 项目与命名
```text
config/setting.json
module/<组件>/<领域>/<角色>.dever
test/<组件>/<领域>/<主题>.dever
data/
```
配置来自 `config/setting.json`。run 读取项目配置,独立程序读取可执行文件旁的 `config/setting.json`。
| 名称 | 格式 |
| --- | --- |
| 组件、领域、主题、字段、局部值 | ASCII lower_snake_case |
| 函数、SQL 方法、标准库方法 | ASCII lowerCamelCase |
| 类型、choice 分支 | UpperCamelCase |
源码使用 UTF-8 和 `.dever` 后缀,不写分号。说明放领域 README 和 doc,Markdown 不参与编译。词法支持 `#` 行注释,项目源码不写说明注释;`//` 表示整数除法,不支持块注释。
| 角色 | 职责与可见性 |
| --- | --- |
| app | 公开领域能力;可调用本领域 Domain、Model、Port 和其他领域 App |
| domain | 本领域业务规则;不能调用其他领域或执行外部 I/O |
| model | 字段、查询和迁移,只由本领域 App 操作 |
| api | 绑定本领域 App,或声明自动 REST |
| port | 外部操作的输入、输出和错误 |
| adapter | 实现 Port,可调用本文件函数和标准能力 |
| job | 绑定本领域 App 的持久任务 |
应用不声明 package、import、exposes、internal 或 main。App 函数按 `组件.领域.函数` 调用;同组件可省略组件,同领域使用 `app.函数`。跨领域只访问 App,公开参数和输出不能暴露私有类型。领域之间不得循环依赖。
角色可使用 `app/publish.dever` 等主题文件,主题名不进入调用名,目录允许一个文件。App/Domain/Port/Adapter/Job 的主文件与目录二选一;Model/API 主文件可与目录共存。只有 API 目录可递归,其路径参与 URL。目录不能命名为 `common/shared/utils/helper/base/service`。
## 类型与值
| 类型 | 语义 |
| --- | --- |
| Bool | true / false |
| Int | 有符号 64 位整数,检查溢出 |
| Decimal | decimal128,最多 34 位有效数字,银行家舍入 |
| Float | IEEE 754 binary64 |
| Text / Bytes | UTF-8 文本 / 字节序列 |
| Id / Uuid | 不透明标识 / UUID |
| DateTime / Date / Time / Duration | UTC 时间点、日期、日内时间、时长;毫秒精度 |
| Json | 不透明 JSON 值,保留数字文本 |
| Secret | 仅在规定的输入、密码和摘要操作中使用的敏感值 |
| T? | T 或 null |
| List<T> / Map<K,V> | 同类型列表 / 保留插入顺序的映射 |
整数字面量默认 Int,小数字面量默认 Decimal;明确 Float 上下文可接收小数。科学计数形式为 Float。Decimal 与 Float 不隐式混合。Text 支持反斜杠、引号、换行、回车、Tab 和 `\u{HEX}` 转义。
字段型 type:
```dever
type User {
name: Text
phone: Text?
}
rename(user: User, name: Text) (result: User) {
result = user
result.name = name
}
```
构造使用 `User { name = "Lin" phone = null }`,必须一次给全字段。字段型、choice、List、Map 使用值语义,修改局部副本不改变原值。
选择型 type:
```dever
type State {
Draft
Published
Rejected(reason: Text)
}
```
构造为 `State.Published` 或 `State.Rejected("原因")`,载荷按位置传入。
List 写为 `[1, 2]`,Map 写为 `{"name" = "Lin"}`。空集合需由上下文确定类型。Map 键允许 Text、Int、Bool、Id 和无载荷 choice。Map 相等比较包含插入顺序;List 按位置比较。Float 的 NaN 与自身不相等。
## 函数与分句
```dever
greet(name: Text) (message: Text) {
message = "Hello, " + name
}
```
函数格式为 `名称(输入) (命名输出)`,空输入或输出仍写 `()`。调用按位置传参;单输出直接得到值,多输出按名称访问。输出必须在正常结束前赋值。
`=` 可初始化或修改当前函数的参数、局部值和输出;变量类型保持不变,读取前须初始化。字段只能在完整值上读取或修改。
局部值首次声明可写 `input: CreateInput = dever.json.decode(payload)`,为解码、空集合或 null 提供具体类型;类型省略时仍由表达式推断。后续赋值只写 `input = ...`,不重复声明类型,也不改变原类型。
同名、同参数数量的分句须相邻,输出类型和错误声明一致。分句互不重叠并覆盖全部输入,没有先后优先级:
```dever
label(state: State.Published) (text: Text) {
text = "published"
}
label(state: State.Rejected(reason)) (text: Text) {
text = reason
}
label(state: other) (text: Text) {
text = "draft"
}
```
模式支持类型、choice 分支、null、常量、Int/Decimal 范围和 other。other 是该参数位置未被明确模式覆盖的补集;多个参数按全部组合检查。choice 载荷按位置绑定,不使用的载荷可写 `_`。
可空值用 `value: Text` 与 `value: null` 两个分句处理。范围可写 `score: Int >= 60 and < 90`。没有 if/else、switch/match、return、条件表达式、用户递归、lambda、运行时闭包或用户泛型。
## 运算与范围
| 运算 | 规则 |
| --- | --- |
| + - * | 同类数值;Int 可提升为 Decimal;Text 支持 + |
| / | Int/Int 和 Decimal 运算返回 Decimal;Float/Float 返回 Float |
| // % | 仅 Int,整数除法向零截断 |
| == != | 同类型且可比较的值 |
| < <= > >= | Int、Decimal、Float |
| and or not | Bool;and/or 短路 |
优先级依次为调用/字段、一元运算、乘除取余、加减、比较、and、or。同级从左到右。
字段、choice 载荷、函数及 handler 参数都可声明 Int、Decimal 范围:
```dever
type Port {
value: Int >= 1 and <= 65535
}
```
构造、赋值和返回都须满足范围。未知 Int 先经范围分句确认;不支持任意用户谓词。静态可知的数值故障在检查时拒绝,运行时故障报告源码位置并终止当前执行。
## 集合与 handler
使用具名函数处理集合,不提供 for/while、break/continue。
| 操作 | 行为 |
| --- | --- |
| each(handler, values[, context]) | 零输出时遍历;单输出时生成 List |
| filter(handler, values[, context]) | Bool handler 筛选 List |
| find(handler, values[, context]) | 返回 List 的首个匹配项或 null |
| sum(values) / sum(handler, values[, context]) | 数值 List 求和 |
| reduce(handler, values, initial) | handler 输入为元素、当前状态,返回下一状态 |
| reduceUntil(handler, values, initial) | 另输出 stop: Bool,处理当前项后停止 |
| parallelEach(handler, values, limit[, context]) | 并行执行零输出 handler,返回前收尾全部工作 |
| contains(values, target) | 判断 List 中是否存在相等项,直接返回 Bool |
List/Bytes 支持 each、reduce、reduceUntil;Bytes 元素是 0–255 的 Int。Stream/AsyncStream 的 each 只接受零输出 handler。filter/find/sum 只处理 List。除 parallelEach 外按顺序处理,空集合求和为零,reduce 返回初始状态。
context 最多一个,需要多项数据时用 record;reduce 的共享数据放 State。parallelEach 的非挂起并发数为 1–256,挂起任务容量为 1–65536,并受运行时容量限制。同步 Stream 不接受挂起 handler。
handler 是签名匹配的具名函数或 handler 参数,不是可存储、比较或返回的运行时值:
```dever
transformAll(
transform: handler(value: Int) (result: Text),
values: List<Int>
) (results: List<Text>) {
results = each(transform, values)
}
```
`append`、`put`、`remove` 返回新集合;`get`、`first`、`find` 返回可空值。entries 返回有序 MapEntry 列表。length 接受 List、Map、Text、Bytes,Text 按 Unicode 码点计数。
## 失败、纯函数与敏感值
choice 的错误分支显式标记 error:
```dever
type DeliveryError {
error Unavailable(message: Text)
}
```
普通调用返回成功值,失败自动向调用方传播。`fail(DeliveryError.Unavailable("原因"))` 主动失败;`result(call)` 捕获后交给覆盖所有结果的分句处理。
捕获按错误类型及变体身份匹配,不按消息或载荷形状猜测。结果 Choice 的 error 分支可包装原错误 Choice,实际构造的仍是原失败变体;原错误 Choice 含有成功分支不妨碍捕获。参数求值的失败继续向外传播。
错误必须传播、返回或明确恢复。读取消息、记录日志、覆盖变量不算处理;恢复函数写 `recover("具体原因")`,全部分句理由一致。失败义务跟随 record、choice 和集合,局部查找不能代表处理了其余错误。程序故障不属于可捕获业务失败。
`pure` 写在输出声明后,禁止 I/O、时钟、随机源、并发等效果;检查沿调用链和 handler 传播。pure 函数仍可能有数值故障。
private 字段只能由所属源码边界访问,含私有字段的值不能直接用于公开 wire 输出。Model 私有字段仅供同领域 App 操作,跨边界返回显式 View。
Secret 不可比较、打印、拼接、转为普通文本、作为 Model 列或输出。密码使用 dever.crypto;哈希和验证属于阻塞操作。测试源可用 `secret(Text)` 构造固定输入,生产源码没有此能力。
## 并发与资源
挂起由调用图推断,不写 async/await。普通调用等待完成,显式 run 才启动子任务。
| 操作 | 合同 |
| --- | --- |
| run(call) | 启动 Task |
| wait(task) | 等待并消费 Task |
| stop(task) | 请求取消并等待退出;仅接受零输出 Task |
| timeout(task, ms, fallback) | 到期先清理任务,再调用输出签名相同的零输入 fallback |
| race(task, task, ...) | 取首个完成结果,清理其余任务;输出签名须相同 |
| group(limit) / run(group, call) | 有界零输出任务组,满时等待;最终 wait/stop |
| parallel(pure_call) | 在线程池执行非挂起纯计算 |
| blocking(call) | 在线程池执行明确的非挂起阻塞调用 |
| channel(T, capacity) | 有界通道;send/receive 挂起,close 唤醒等待者 |
Task/Group 不能复制、嵌套、传参或逃逸,必须消费一次。异常路径也会收尾子任务;取消不撤销已经发生的外部副作用。程序故障不会变成 timeout 的正常 fallback。
Group、Channel 容量为 1–65536。Channel 关闭后仍可读完缓存,之后 receive 返回 null。Channel 元素不能为可空类型;需要传递空值时,用含可空字段的消息 Choice 区分消息与关闭。
跨线程或挂起点存活的普通值须可传递。挂起调用链中的同步文件、睡眠、密码计算等操作用 blocking;网络等待和 dever.task.sleep 自动挂起。
File、Socket、Listener、Stream、AsyncStream 等资源的副本共享状态。普通数据的值语义不适用于这些句柄。
- Stream 按需单次消费,别名共享读取位置;reduceUntil 停止后可继续读取同步 Stream。
- AsyncStream 的消费结束、提前停止、故障或取消会关闭流;别名不能继续消费。
- `stream(channel/list/bytes)` 创建 AsyncStream;`dever.task.ticks(ms)` 创建周期流。
- 关闭流释放其持有的资源别名,不关闭调用者另外持有的 File、Socket 或 Channel。
## API、身份与权限
API 文件只声明绑定:
```dever
get profile = app.profile
public post login = app.login
authenticated get current = app.current
long post generate = app.generate
cmd export = app.export
rest model
```
HTTP 支持 get/post/put/delete。URL 为组件、领域、API 主题路径和 action;CMD 为 `组件.领域.命令`。API 绑定本领域 App 的一个可序列化输出。
GET/DELETE 从 query 读取标量;POST/PUT 从 JSON 对象读取;CMD 接受单个 JSON 对象。未知、重复和缺少必填字段失败。成功包裹为 `{"code":0,"message":"ok","data":...}`,失败的 data 为 null。dever.api.Error 映射 400/401/403/404/409/429,其他内部失败返回安全的 500。
| 声明 | 访问要求 |
| --- | --- |
| 默认 HTTP | 可信身份与精确角色权限 |
| public HTTP | 匿名入口 |
| authenticated HTTP | 可信身份;对象所有权与业务权限由 App 检查 |
public/authenticated 不用于 CMD 或 REST。权限键为 `component.domain.site.action`,REST 的 action 为 read/create/replace/delete。HTTP 方法不进入权限键。
`sites.<key>.path` 匹配 API 父目录,每条接口须恰好匹配一个站点。例如 admin 匹配 api/admin/**,不匹配 api/admin.dever,也不改写 URL。
认证 Provider 绑定项目的 verify App。它接收 dever.auth.Claims,返回仅含 `id: Text`、`user_id: UserModelId?`、`tenant_id: TenantModelId?` 的身份 record。verify 校验账号、会话、租户和成员关系,只读 global Model,不返回权限列表。
身份读取使用 dever.auth 和 dever.site,ID 类型须匹配 verify。客户端参数不能建立身份。public、CMD、Job 和普通测试不能直接读取 HTTP 身份。
角色与权限由核心管理。授权读取允许受保护或 authenticated 入口;修改只允许普通受保护写入口。Owner 为受保护角色,不按特定用户 ID 判断。业务 capability 在可信租户和入口命名空间内注册,撤销同时清理 grants,重新注册不恢复授权。
HTTP 元数据用 dever.api 读取和设置。敏感头不能读作普通 Text;Cookie 登录/退出用 issueCookie/clearCookie。Cookie 写入及 Cookie 认证的写请求要求 Origin、Host 精确匹配站点 origin。响应元数据仅在处理与编码成功后发布。
Upload 仅用于 POST 的顶层 multipart 参数,不能复制、嵌套、输出或进入 CMD。显式关闭,或一次性传给本领域 Port,由 Adapter 使用 storage;失败和取消清理临时文件。
完整配置与调用边界见 [应用指引](skills/references/application.md)和 [签名索引](skills/references/signatures.md)。
## Model 与查询
主文件的记录名对应领域,主题文件对应主题名:
```dever
type Article {
title: Text(1, 200)
body: Text
published: Bool default false index
}
```
自动生成只读 id 和 created_at。每个 Model 的 id 是不同的名义类型,不能用 Int 或其他 Model 的 ID 替代。
字段支持存储标量、无载荷 choice、Model ID 及可空形式。Text/Bytes 可指定长度,Decimal(P,S) 指定精度;generated 用于非空 Uuid。default 为静态值,index/unique 可用于单字段或顶层复合索引。外键自动建立索引,不自动加载关联。结构化数据显式使用 Json。
Model 的 `Text` 字段写入时默认去除首尾 Unicode 空白,再检查长度;不处理内部空白。`raw` 保留原文,`lower`/`upper` 在去除首尾空白后转换大小写,三者互斥。可空字段的 null 保持不变,空串不转为 null。普通函数中的 Text、查询条件、读取结果和原生 SQL 不自动转换。
```dever
type Category {
name: Text(1, 80)
code: Text(1, 40) lower unique
description: Text?
content: Text raw
active: Bool default true
}
```
create、update、条件更新、createMany、upsert 和 REST 使用同一写入规则。default、Seed 在编译期按该规则处理。富文本、代码、签名原文等需要逐字保留的字段使用 raw;不会依据字段名称猜测策略。去除空白不负责 HTML 安全过滤。
同领域 App 使用 model.create/createMany/get/first/list/cursor/count/exists/stream/update/delete/upsert。多 Model 使用 model.topic.operation。查询块只出现在调用位置,不是可保存的动态 Map:
```dever
page = model.list({
where = published == true
order = [created_at.desc, id.desc]
page = 1
size = 20
})
```
where 支持布尔组合、比较、null、in、between、contains、startsWith、endsWith;结构静态确定,值参数绑定。list 返回 items/page/size/total/pages;cursor 返回 items/next/has_more,不做 count。max_page_size 限制结果规模。
update(id, values) 返回记录,不存在时失败;条件 update/delete 返回影响行数,必须明确 where。delete(id) 返回影响行数。关系用 with 显式加载,返回 Related 的 Unloaded/Loaded 状态;仅 first/list/cursor 支持一层关系。
### REST 字段
create/replace/search 表达式写在 Model 字段上:引用 input 时转换客户端值,否则由服务端提供并拒绝客户端同名输入。表达式只允许纯计算及指定的只读请求能力。search 最多一个,不能叫 page/size。
`private owner user_id: ... = dever.auth.userId()` 创建时绑定可信用户,全部读写 SQL 均包含 owner 条件。private 字段不出现在 REST 输出;没有 replace 来源时 PUT 保留其原值。
普通 CRUD 直接使用 rest model;关联编排、状态转换或不同输出合同由 App 实现。
### 事务
```dever
transaction publish(id: model.id) (article: model.Article) {
article = model.update(id, { published = true })
}
```
普通写 HTTP、CMD、Job 建立整体事务,成功编码后提交。嵌套 transaction 复用同一连接的事务;失败或取消回滚后传播原错误。GET 不写库或入队。
long 入口不建立整体事务,写库和入队必须进入显式 transaction。外部 I/O、Worker、等待、并发和密码计算放在事务外,写入依赖的状态在事务内重新确认。long 已提交阶段不会因后续失败撤销。
事务不能跨物理数据库或混用 global/tenant 存储,不暴露 begin/commit/rollback。数据库失败保留 dever.database.Error。
### 数据库、迁移与租户
Model 优先使用组件同名连接,否则 database.default;显式 `database report` 绑定固定连接,缺失时报错。SQLite/PostgreSQL 配置在 setting.json;PostgreSQL 明确选择 TLS system/disabled。
当前 Model 是目标 schema。空库建最终表;安全变更自动应用,收紧约束先检查数据。字段重命名用 `from old_name`;破坏性变化用命名 migrate。已执行迁移的内容与顺序不可修改。
migrate 可含 before/after SQL,每块提供 sqlite、postgres 和参数列表,只允许单条参数化 INSERT/UPDATE/DELETE。全新数据库不执行历史数据变换。seed 按唯一键补缺失记录,不覆盖既有数据;迁移原子性限于所属 Model。
复杂查询在 Model 声明 `sql name(inputs) (output)`,两种方言均为静态字符串;结果是具体 Model、私有 SQL record 或本领域 App View。只有可证明只读的 SQL 能用于 GET。
启用 tenant 后,global type 使用控制库,其余 Model/Job 使用租户库。只支持 database 隔离。租户库须先显式迁移;缺失、未就绪或 schema 过期时报错,不回退控制库。
运维入口为 `dever tenant migrate`、`dever tenant owner`、`dever tenant component enable|disable`。数据库权限和真实数据操作由部署侧管理。
## Job
```dever
database default
job store(input: app.Request) () retry(3) timeout(30000) {
app.store(input)
}
```
Job 输入为零个或一个本领域 App record,无输出,只绑定本领域 App。retry 为 1–100 次,包含首次执行;timeout 为 1–3600000 毫秒。定时声明为 `schedule name = "0 * * * *"`,使用 UTC。
App 使用 dever.job.enqueue/enqueueAt,传入任务、可选 payload 和幂等 key。key 为 1–1024 字节;同租户、任务身份和 key 的活跃任务复用 Id。入队与业务写入可共享事务。
任务至少执行一次,外部副作用须业务幂等。受保护 HTTP 入队保存可信身份与精确入口权限键,执行时重验;public/authenticated 不能入队角色权限绑定的任务。CMD、schedule、测试使用 System 身份。身份失效、坏 payload 或不兼容 schema 进入 blocked。
runtime.mode 为 api/worker/all。任务配置包括 workers、poll_ms、lease_ms 和重试间隔;SQLite 的 lease 必须长于 Job timeout,worker 连接池需留出监管连接。停止时先停止接收和 claim,再按 shutdown_ms 排空。
测试使用临时数据库和用例独立时钟,可用 dever.test.advanceClock、drainJobs 验证队列。
## Port、Adapter 与依赖
Port 声明输入、命名输出和明确失败集合:
```dever
send(message: Text) () fails app.DeliveryError
```
Adapter 用 `port.send(...) (...) { ... }` 实现。每个文件完整实现一个 Port;单实现自动绑定,多实现由 setting.json 的 adapter 配置选择。实现只能抛出 Port 声明的错误。Port 不接受 handler 或数值范围参数。
Adapter 可声明 setting,选中的实现从配置读取同类型字段。外部程序用 external command/exec/pip/npm/go;代码可信性、网络、文件和设备权限由运行环境负责,allow 声明不是 OS 沙箱。
| 方式 | 用途 |
| --- | --- |
| external command | 普通 ELF;argv/stdin 输入,code/stdout/stderr 输出,无 shell |
| external exec | 遵循 Port Worker 协议的程序 |
| external pip/npm/go | 由相应生态实现 Port,使用锁定资源 |
外部调用和 fake 用法见 [依赖](skills/references/libraries.md)、[外部库示例](skills/references/external-lib.md)。协议与运行资源见 [SDK](sdk/README.md)。
Dever Package 是 module 下的可复用组件,使用 `dever package add/update/remove/list/doctor/export` 管理。dever.lock 固定版本、来源和摘要,不能覆盖本地同名组件。已有锁通过 `dever lib install` 恢复资源;run/build 消费锁定资产。当前 CLI 不提供 Lib add/update 或 target add。
## 标准库与数据格式
标准库按包名直接调用,无需 import。功能目录见 [标准库](lib/README.md),参数和输出见 [签名索引](skills/references/signatures.md)。
### JSON 数据
API/CMD 根据参数和输出类型编解码。Decimal/Id/Uuid 使用字符串,ModelId 为整数,日期时间使用规范字符串,Duration 为整数毫秒。支持 List、可空、可公开传输的 record 和无载荷、无 error 分支的 Choice。此类 Choice 按声明的分支名编码为 JSON 字符串,也可作 query 或 multipart 标量;未知分支报错。带载荷或 error 分支的 Choice、Map、资源不用于普通 wire。缺少可空字段得到 null,未知、重复和缺少必填字段失败。
已有 Json 需要转换成具体类型时,使用 `dever.json.decode(value)`;目标类型由局部声明、命名输出、字段或参数类型确定。直接从已有原文解码,不转为 Text 或 Document。解码失败传播 `dever.json.JsonResult.Failed`。Text 不在此处清洗。
需要处理解码失败时,直接写 `decoded: DecodeResult = result(dever.json.decode(payload))`。DecodeResult 必须有一个含单个目标类型字段的成功分支,以及包装 dever.json.JsonResult 的 error 分支,例如 `Parsed(value: CreateInput)` 和 `error Invalid(cause: dever.json.JsonResult)`。不需要另写解码函数;无类型上下文时不会猜测目标类型。
单个布尔条件失败使用 `dever.api.require(condition, dever.api.Error.Invalid)`;false 传播指定错误,true 继续。该函数不代替业务状态分支和执行时的权限校验。
日期时间使用 RFC3339,输出 UTC,最多毫秒精度;Date 为 YYYY-MM-DD,Time 为 HH:MM:SS[.sss]。无效日期、非有限 Float、越界整数失败。
Json 提供 fromText/toText、object/array、propertyValue/setProperty 等操作;encode 按实参具体类型输出 Json。原始数字不经过 Float。Json 限制为 16 MiB、64 层、65536 个值。
需要遍历节点时使用 parse/stringify 和 Document:root 为根 ID,nodes 为连续节点列表,子 ID 小于父 ID。Number 保留原文,Object 保留键顺序。node/property/element 缺失返回 null;JSON null 是实际节点。Document 的解析深度上限为 256,stringify 检查手工节点引用。
### 文件、HTTP 与流
文件 create 只建新文件,read 可能短读。I/O 错误通过声明失败传播;流的终止错误最多产生一次,之后结束。TCP 支持同时读写,每个方向串行;部分写入后失败关闭连接,不重发整条消息。
HTTP 支持 HTTP/1、HTTP/2、TLS、连接池、流式响应、SSE 与 HTTP/1 WebSocket。普通应用使用 API 声明,底层服务和客户端放 Adapter。
- Limits 控制头、正文、期限和连接数;HTTP/2 另限制流数与接收窗口。
- serve/send 缓冲完整正文;serveLive/open/openStream 按块处理。
- 池和会话归创建它们的任务作用域,响应须消费或关闭后释放名额。
- TLS 校验证书和名称,不自动降级;HTTP/2 使用 ALPN 或明文 prior knowledge。
- HTTP 协议头和正文定界由引擎管理;应用不写 Content-Length/Transfer-Encoding/Upgrade。
- 关闭 Listener 停止接收并排空;stop 取消服务并等待清理。
- 不支持 CONNECT、非空 trailer、服务器推送、WebSocket-over-HTTP/2、WebSocket 子协议或压缩扩展。
## 检查、测试与构建
```sh
dever new my_app
dever fmt my_app --check
dever check my_app
dever test my_app --filter hello.greeting
dever run my_app -- hello.greeting.greet '{"name":"Dever"}'
dever build my_app --output my_app/program
```
check 检查源码、配置、类型规则和生产入口可达性,不启动应用。重复实现和业务合理性仍需代码审查。
测试入口把文件主题转成 lowerCamelCase,例如 account_login.dever 对应 accountLogin() (),可调用本领域 App/Domain。外部 Port 使用用例独立 fake;Model 使用临时 SQLite。筛选不跳过源码检查,每例独立进程,默认 60 秒;任一失败返回非零。
`dever api <root> --output <新文件>` 导出接口快照。已有 dever.api 时,check/run/build 检查基线;变更需审查新快照,工具不自动覆盖。
构建输出须是新文件。生成的程序可脱离开发包运行,仍需配套配置和系统运行库。
安装环境与交叉编译见 [安装说明](build/README.md)和 [编译器开发](rust/README.md)。