# 模块事件与发布机制

区分事件声明、发布和订阅，并通过当前 Runtime 安全发布模块事件。

模块事件是安装到 Runtime 的类型化业务能力。事件名和载荷由 Module 版本声明；发布方调用当前 Runtime
物化出的事件方法；订阅、触发和投递由独立资源管理。三者不是同一个动作：

```text
module.json events 声明
  -> 创建不可变 Module 版本并随 Bundle 发布
  -> 安装到目标 Runtime，物化事件方法和发布能力
  -> 工作流或模块后端发布事件
  -> 已安装的 Event Trigger / 订阅消费事件
```

事件声明、事件发布和事件订阅是三份独立合同。因此，新增 `events` 不会自动发送事件，也不会自动创建
工作流、Webhook 或 Event Trigger。事件生产方必须
显式发布；需要自动触发后续动作时，还要把相应触发资源纳入 Bundle。

## 地址从哪里来

事件发布地址不写死，也不由 Bundle 作者填写。Runtime 会根据目标环境和当前安装实例生成可调用的事件方法，
并同时生成作用于该 Runtime 的授权。应用代码和工作流都不能保存或推断内部主机、端口、服务地址、Runtime
`businessId` 或事件平台凭据。

对调用方而言，事件方法与普通 Runtime 方法使用同一调用入口和授权边界；不存在需要开发者选择的“事件
专用网关”或额外协议。地址在环境迁移、重新安装或授权轮换后可以变化，所以必须使用当前 Runtime 物化并
交付的值。

## 从工作流发布

工作流使用 `emit_event` 节点。`service` 必须是 Bundle Manifest 中 Module 资源的完整 Bundle Resource Locator，
`eventName` 必须是该 Module 当前版本声明的事件名，`payload` 必须符合其 `paramDefinitions`：

```json
{
  "type": "emit_event",
  "id": "emit_order_status_changed",
  "name": "发布订单状态变更",
  "service": "baijimu/example-orders/MODULE/orders",
  "eventName": "orderStatusChanged",
  "payload": {
    "orderId": "{{input.orderId}}",
    "status": "{{context.order.status}}",
    "occurredAt": "{{context.order.occurredAt}}"
  },
  "idempotencyKey": "order-status:{{input.orderId}}:{{context.order.status}}",
  "timeoutSecs": 30
}
```

安装物化时，平台会用目标 Runtime 中已经验证的 Bundle 安装资源解析 Locator 并生成执行授权。Workflow
定义中不得出现 Runtime `businessId`、原始 URL 或 Authorization。通用 `http` 节点不能替代
`emit_event`：它不提供 Module Locator 解析、事件合同校验和 Runtime 作用域授权。

完整节点字段见[工作流](/features/workflows/)与
[Workflow Definition JSON Schema 4.1.0](/contracts/workflow-definition/4.1.0/schema.json)。

## 从独立模块后端发布

模块方法调用 Hosted Service 或其他独立后端，并由后端在业务事务成功后发布事件时，应让 Runtime 把发布
目标作为一对只读能力交付给后端：

- `<eventName>_event_url`：当前 Runtime 生成的事件方法 URL。
- `<eventName>_event_authorization`：只允许调用该 Runtime 能力的完整 Authorization 值。

如果 `methodBody` 需要引用这两个值，先在 `module.json` 的 `propertyDefinition` 中声明同名属性。URL 必须
只读；Authorization 必须同时只读且敏感：

```json
{
  "propertyDefinition": [
    {
      "name": "orderStatusChanged_event_url",
      "type": {
        "@type": "DataType",
        "type": "string",
        "nullable": true
      },
      "description": "由当前 Runtime 生成的 orderStatusChanged 发布地址。",
      "isSensitive": false,
      "readOnly": true,
      "required": false
    },
    {
      "name": "orderStatusChanged_event_authorization",
      "type": {
        "@type": "DataType",
        "type": "string",
        "nullable": true
      },
      "description": "由当前 Runtime 生成的 orderStatusChanged 发布授权。",
      "isSensitive": true,
      "readOnly": true,
      "required": false
    }
  ]
}
```

再在调用后端的 HTTP 方法中用 `position: "property"` 映射。下列 Header 名是模块与自身后端约定的示例，
不是平台保留 Header：

```json
{
  "header": {
    "X-Module-Event-Url": {
      "required": true,
      "position": "property",
      "key": "orderStatusChanged_event_url"
    },
    "X-Module-Event-Authorization": {
      "required": true,
      "position": "property",
      "key": "orderStatusChanged_event_authorization"
    }
  }
}
```

后端从受信任的模块调用中读取这对值，向 URL 发送符合事件 `paramDefinitions` 的 JSON，并把 Authorization
值原样放入请求头。URL 已经是完整事件方法地址；不要追加内部路径，也不要把 Authorization 改造成另一种
token。

```http
POST <orderStatusChanged_event_url>
Authorization: <orderStatusChanged_event_authorization>
Content-Type: application/json

{
  "orderId": "order-123",
  "status": "approved",
  "occurredAt": 1788537600000
}
```

## 安全与生命周期规则

- URL 与 Authorization 是当前 Runtime 颁发的一对能力，必须成对使用、成对更新；不得跨工作区或跨
  Runtime 复用。
- 不允许终端用户提交任意事件 URL 或 Authorization。浏览器、表单、工作流输入和普通业务 API 都不应包含
  这两个字段。
- Authorization 不进入日志、响应、事件载荷、任务参数或普通数据库字段。异步后端确需跨请求保存时，应写入
  该 Runtime 安装实例的敏感配置存储，并在 Runtime 属性交付更新时替换。
- 后端不得按工作区 ID、项目 ID、域名规则或环境名称拼接发布地址，也不得直接调用内部事件服务。
- 发布成功只证明事件已被接受；后续动作还取决于目标 Runtime 中是否安装并启用了匹配的 Event Trigger 或
  订阅，以及其投递与重试状态。

## 发布前验证

1. 从精确 ModuleVersion 回读事件名和 `paramDefinitions`，确认来自预期 Git commit。
2. 检查 Bundle Manifest 精确引用该 ModuleVersion，并包含需要的 Event Trigger 资源。
3. 安装或升级 Bundle 后，从目标 Runtime 回读事件方法；不要只检查项目工作区文件。
4. 分别验证工作流 `emit_event` 和后端回调所需的入口；不使用生产凭据做本地硬编码测试。
5. 发送一条带稳定业务幂等键的测试事件，再检查订阅触发、Webhook/动作结果和失败重试。

事件声明的 JSON 结构与版本演进规则见[模块定义开发](/development/bundle-development/module-development/module-definition/)。
