@microi.net/cli 5.2.5 → 5.2.7

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.
Files changed (51) hide show
  1. package/.codebuddy-plugin/marketplace.json +2 -2
  2. package/.codebuddy-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/.workbuddy-plugin/marketplace.json +2 -2
  5. package/.workbuddy-plugin/plugin.json +1 -1
  6. package/assets/build-meta.json +6 -6
  7. package/cordis.patch.yml +1 -1
  8. package/package.json +1 -1
  9. package/scripts/mcp-server.js +88 -88
  10. package/scripts/microi-cli.js +15 -0
  11. package/scripts/microi-skills.meta.json +225 -222
  12. package/skills/.microi-skills-version.json +2 -2
  13. package/skills/.progressive-disclosure-manifest.json +93 -93
  14. package/skills/README.md +2 -1
  15. package/skills/ai-engine/SKILL.md +1 -1
  16. package/skills/app-store/SKILL.md +13 -9
  17. package/skills/microi-client-frontend/SKILL.md +1 -1
  18. package/skills/microi-client-frontend/references/progressive-01-3-/345/212/250/346/200/201/346/214/211/351/222/256/347/263/273/347/273/237.md +1 -1
  19. package/skills/microi-client-frontend/references/progressive-03-vue3-/345/211/215/347/253/257/345/276/256/346/234/215/345/212/241/345/256/277/344/270/273/350/247/204/345/210/231.md +2 -2
  20. package/skills/microi-docs-coverage/references/capability-map.md +3 -1
  21. package/skills/microi-form-layout/SKILL.md +6 -6
  22. package/skills/microi-frontend-sdk/SKILL.md +6 -6
  23. package/skills/microi-microservice/SKILL.md +2 -1
  24. package/skills/microi-sso/SKILL.md +3 -1
  25. package/skills/microi-sso/references/acceptance.md +1 -1
  26. package/skills/microi-sso/references/configuration-and-security.md +1 -1
  27. package/skills/microi-system-delivery/SKILL.md +2 -2
  28. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +1 -1
  29. package/skills/microi.v8.js +1 -1
  30. package/skills/performance-testing/SKILL.md +12 -0
  31. package/skills/system-observability/SKILL.md +139 -0
  32. package/skills/translate-engine/SKILL.md +3 -0
  33. package/skills/ui-design/SKILL.md +6 -3
  34. package/skills/v8-api-config/SKILL.md +31 -9
  35. package/skills/v8-cache-pattern/SKILL.md +304 -289
  36. package/skills/v8-debugging/SKILL.md +1 -1
  37. package/skills/v8-file-upload/SKILL.md +3 -3
  38. package/skills/v8-file-upload/references/progressive-01-/345/205/254/346/234/211/346/241/266-vs-/347/247/201/346/234/211/346/241/266.md +1 -1
  39. package/skills/v8-menu-buttons/SKILL.md +1 -1
  40. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +1 -1
  41. package/skills/v8-mq-mqtt/SKILL.md +130 -109
  42. package/skills/v8-mq-mqtt/references/mqtt-production.md +3 -2
  43. package/skills/v8-mq-mqtt/scripts/check-mqtt-skill-coverage.mjs +14 -16
  44. package/skills/v8-security/SKILL.md +7 -5
  45. package/skills/v8-table-event/SKILL.md +1 -1
  46. package/skills/v8-table-event/references/progressive-02-/345/211/215/347/253/257/344/272/213/344/273/266/345/220/215-v8-eventname-/345/217/257/350/203/275/347/232/204/345/200/274.md +1 -1
  47. package/skills/v8-utilities/SKILL.md +1 -1
  48. package/skills/v8-utilities/references/platform-http-routes.md +4 -2
  49. package/skills/v8-utilities/references/server-api-index.md +6 -3
  50. package/skills/v8-workflow/SKILL.md +1 -1
  51. package/skills/workspace-conventions/SKILL.md +1 -1
@@ -63,7 +63,7 @@ description: Microi V8 与 MCP 文件上传下载指南。用于处理流式 AI
63
63
  可信后端 V8 可用 `V8.Http.GetResponse({ Url: url }).RawBytes` 下载,再用 `System.Convert.ToBase64String` 和 `V8.Method.Upload` 上传。该路径同样必须校验域名、大小、Content-Type、后缀和最终重定向目标。
64
64
 
65
65
  <!-- /microi-progressive:chunk -->
66
- <!-- microi-progressive:chunk id=v8-file-upload-002 sha256=01111b2fe994a2a5e424f45d405821f0b4f5c29235bc93757352d4c7e10d8d84 -->
66
+ <!-- microi-progressive:chunk id=v8-file-upload-002 sha256=dc69d3bcadb1b40d98e1346a8d9d0a3599cae7f7dd6b850dd95ad054c747b2dd -->
67
67
  ## 接收前端上传的文件
68
68
 
69
69
  前端发起文件上传时,平台自动把文件以 base64 形式注入到 `V8.FilesByteBase64`:
@@ -165,7 +165,7 @@ Unity `Data`、WASM、Windows 安装包、视频模型等发布资产不得进
165
165
  - 生产 H5 不能只依赖 `uni.uploadFile`。页面从 `uni.chooseImage` 得到的 `tempFiles[0].file`、`tempFiles[0]`、`blob:` / `data:` 临时路径都要传给 `V8.uploadFile`,并设置 `preferFetch:true`;SDK 必须能用 `fetch + FormData` 兜底,否则线上可能报 `未找到 MicroiV8 上传适配器。`。
166
166
 
167
167
  <!-- /microi-progressive:chunk -->
168
- <!-- microi-progressive:chunk id=v8-file-upload-003 sha256=5765949bee76ce3ccd05503174ff7601135f1d330f8c11a2bf5f268cdeb74133 -->
168
+ <!-- microi-progressive:chunk id=v8-file-upload-003 sha256=a31f0170454bb9e44007e24ed280873e99ae4ca4f4ecc7307ecc3e738eb51df9 -->
169
169
  ## 跨平台文件同步登录会话
170
170
 
171
171
  文件柜、文件同步等需要连接另一套 Microi API 的工具,必须把远程平台视为独立登录会话:
@@ -173,7 +173,7 @@ Unity `Data`、WASM、Windows 安装包、视频模型等发布资产不得进
173
173
  - 用户必须先完成远程登录,登录成功后显示远程用户名称、帐号、ApiBase、OsClient 和登录状态,并提供明确的退出登录操作。
174
174
  - 历史远程连接通过 `mci_` 前缀表保存,并按 `V8.CurrentUser.Id` 做行级隔离;不得把帐号、密码或 Token 放入 `localStorage`。
175
175
  - 密码和 Token 只能由受保护的接口引擎写入、读取和清理。数据库必须保存可校验的加密密文,普通 FormEngine 列表不得返回密文字段。
176
- - 加密密钥优先使用租户专用 `FileCabinetSecret`,可使用仅后端可见的持久化租户密钥兜底;禁止使用进程级临时密钥,否则服务重启后无法解密历史连接。
176
+ - 密码和 Token 使用 `V8.Method.ProtectApiEngineSecret/UnprotectApiEngineSecret`,由宿主把密文绑定当前 `OsClient + ApiEngineKey`;不得从已脱敏的 `V8.OsClientModel` 读取 `AuthSecret/DbConn`,也不得使用进程级临时密钥。接口引擎 Key 必须稳定,确保服务重启和应用升级后仍能解密历史连接。
177
177
  - 历史连接列表只返回脱敏元数据;一键重连时再按记录 Id 和当前用户读取凭据。删除连接必须同时清除保存的密码和 Token。
178
178
  - 远程目标登录后必须调用文件柜能力探针(如 `mci_file_sync_capability`)检查同步协议版本。接口不存在、返回 404/非标准结果或协议版本过低时,提示目标平台更新【文件柜】应用,不得继续同步。
179
179
  - 验收至少覆盖:登录成功显示身份、退出后 Token 清空、历史连接一键重连、删除连接、密文落库、服务重启后仍可解密、目标平台缺少能力接口时的升级提示。
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
4
 
5
- <!-- microi-progressive:chunk id=v8-file-upload-005 sha256=431aed9f824e7a604e8e1e02e03404cc4940814f352e6afd3f7639a106d1f332 -->
5
+ <!-- microi-progressive:chunk id=v8-file-upload-005 sha256=6136a38af209aad174ca1cacd61fcfc66e3428e1e8bf75be8a2490bcb094b71e -->
6
6
  ## 公有桶 vs 私有桶
7
7
 
8
8
  ### 应用商城 ZIP
@@ -76,7 +76,7 @@ V8.ConfirmTips('确认领取该任务?', function () {
76
76
  ```
77
77
 
78
78
  <!-- /microi-progressive:chunk -->
79
- <!-- microi-progressive:chunk id=v8-menu-buttons-003 sha256=ae7e519897a8c331be2f657549997a91cd24a053fe00558e2b51d5c2477fc290 -->
79
+ <!-- microi-progressive:chunk id=v8-menu-buttons-003 sha256=d04e7a71ffe8baa47c2430077d0fd0bb44dffc62c7e7ce2bca9d02b220ae24f5 -->
80
80
  ## 4.1 模式 B2:在线微服务定制页(OpenAppDialog)
81
81
 
82
82
  当弹窗包含复杂布局、多步骤交互、实时校验或后续需要 AI 在线维护时,优先把页面实现为在线微服务,按钮 V8 代码只负责打开页面、传入上下文和接收结果。不要把长篇 HTML/CSS 写进 `V8Code`。
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 按需读取;本文件由 SKILL.md 的原章节无损拆分。
4
4
 
5
- <!-- microi-progressive:chunk id=v8-menu-buttons-004 sha256=f18f04c54a81c7aaf5c79867eda0f7ec716a5e9b05c723dae9b77cde127326f3 -->
5
+ <!-- microi-progressive:chunk id=v8-menu-buttons-004 sha256=9550f2e3a75583bb6f2ab940d423931511f39b6ad8a11fc982c6b24bca6416d1 -->
6
6
  ## 2. 按钮对象 Schema
7
7
 
8
8
  ```jsonc
@@ -1,24 +1,24 @@
1
- ---
2
- name: v8-mq-mqtt
1
+ ---
2
+ name: v8-mq-mqtt
3
3
  description: Microi V8 消息队列与 MQTT 生产指南。用于 V8.MQ.SendMsg、RabbitMQ 消费与幂等,以及内嵌 MQTT Broker、SaaS 租户认证、Topic ACL、TLS、QoS/Retain、七类 V8.MQTT 事件、设备级接口引擎、服务端下行、IoT 数据分层和多节点部署验收。
4
- ---
5
-
6
- > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
-
8
- # Microi V8 消息队列与 MQTT
9
-
10
- 你正在开发 Microi 吾码平台的 V8 引擎代码,需要使用 RabbitMQ 消息队列或 MQTT 物联网协议。
11
-
12
- <!-- microi-progressive:begin -->
13
- <!-- microi-progressive:chunk id=v8-mq-mqtt-000 sha256=a883bb502b306ada654b8f45bd6f955c84049f3a032568e5ef8e25e24aa1c2c6 -->
14
- ## V8.MQ — RabbitMQ 消息队列
15
-
16
- ### 生产消息(后端)
17
-
4
+ ---
5
+
6
+ > **Codex 非阻塞自动更新:** 当前宿主为 Codex 时,吾码 CLI、Codex 插件与工作区 AI/MCP 由后台自动更新;需要诊断时读取 `../microi-codex-installer/SKILL.md`。更新失败、等待空闲或尚未重载均不得阻断当前、正在进行或新建任务。非 Codex 宿主跳过此项。
7
+
8
+ # Microi V8 消息队列与 MQTT
9
+
10
+ 你正在开发 Microi 吾码平台的 V8 引擎代码,需要使用 RabbitMQ 消息队列或 MQTT 物联网协议。
11
+
12
+ <!-- microi-progressive:begin -->
13
+ <!-- microi-progressive:chunk id=v8-mq-mqtt-000 sha256=4a6559aed1af036591a04002c6e3311d9f0957fbbabbcafdc4a6bad95dabd843 -->
14
+ ## V8.MQ — RabbitMQ 消息队列
15
+
16
+ ### 生产消息(后端)
17
+
18
18
  ```javascript
19
- // async 接口引擎或 V8 事件中发送消息。
19
+ // 当前 V8EngineMQ 是同步包装,调用完成后直接返回 DosResult。
20
20
  // 业务重试必须复用同一个 EventId,供消费者幂等去重。
21
- var result = await V8.MQ.SendMsg({
21
+ var result = V8.MQ.SendMsg({
22
22
  QueueName: 'order_process',
23
23
  EventId: V8.Param.eventId || V8.Method.NewUlid(),
24
24
  Message: {
@@ -31,45 +31,52 @@ if (result.Code !== 1) return result;
31
31
  ```
32
32
 
33
33
  逻辑队列名由服务端规范为 `microi.{lowerOsClient}.{queueName}`。V8 上下文、登录 Token 与后台显式 `OsClient` 是权威租户,body 不能切换到其它租户队列。
34
-
35
- ### 生产消息(前端)
36
-
37
- ```javascript
38
- V8.Post('/api/mq/sendmsg', {
34
+
35
+ ### 生产消息(前端)
36
+
37
+ ```javascript
38
+ V8.ApiEngine.Run('platform-mq', {
39
+ Action: 'Send',
39
40
  QueueName: 'queue_name',
40
41
  EventId: stableEventId,
41
42
  Message: { ProductId: '123', Count: 2 }
42
- }, function(result) {
43
- if (result.Code === 1) V8.Tips('消息已发送', true);
44
- }, null, {}, 'json');
45
- ```
46
-
47
- ### 消费消息
48
-
49
- 消费者是一个接口引擎,在 `diy_queue_receive` 表中配置队列名和接口引擎 Key 后,消息到达时自动调用。
50
-
51
- ```javascript
52
- // 消费者接口引擎
53
- var message = V8.Param.Message; // object 类型
43
+ }).then(function(result) {
44
+ if (result.Code === 1) V8.Tips('消息已发送', true);
45
+ });
46
+ ```
47
+
48
+ `platform-mq` 是应用商城交付的 Managed 管理接口,只允许当前租户超级管理员,
49
+ 并在可信 V8 原子层固定租户、队列名和 1 MB 消息上限。普通业务前端应调用
50
+ 自己的受权接口引擎,再由业务接口引擎执行 `V8.MQ.SendMsg`。
51
+
52
+ ### 消费消息
53
+
54
+ 消费者是一个接口引擎,在 `diy_queue_receive` 表中配置队列名和接口引擎 Key 后,消息到达时自动调用。
55
+
56
+ ```javascript
57
+ // 消费者接口引擎
58
+ var message = V8.Param.Message; // object 类型
54
59
  // message.EventId — 稳定业务幂等 Id
55
60
  // message.Id — EventId 的兼容别名
56
61
  // message.OsClient — 消息所属租户
57
62
  // message.Message — 消息内容
58
63
  // message.CurrentUserId — 生产消息的用户 Id
59
-
60
- // 处理业务逻辑
61
- var data = message.Message;
62
- V8.FormEngine.UptFormData('Product', {
63
- Id: data.ProductId,
64
- Stock: data.Count
65
- });
66
- ```
67
-
68
- ### 实战模式:异步处理耗时操作
69
-
70
- ```javascript
71
- // 接口引擎:接收请求后发送到队列,快速返回
72
- await V8.MQ.SendMsg({
64
+
65
+ // 处理业务逻辑
66
+ var data = message.Message;
67
+ V8.FormEngine.UptFormData('Product', {
68
+ Id: data.ProductId,
69
+ Stock: data.Count
70
+ });
71
+
72
+ return { Code: 1, Data: { EventId: message.EventId } };
73
+ ```
74
+
75
+ ### 实战模式:异步处理耗时操作
76
+
77
+ ```javascript
78
+ // 接口引擎:接收请求后发送到队列,快速返回
79
+ var sendResult = V8.MQ.SendMsg({
73
80
  QueueName: 'order_process',
74
81
  EventId: V8.Param.eventId,
75
82
  Message: {
@@ -78,63 +85,75 @@ await V8.MQ.SendMsg({
78
85
  userId: V8.CurrentUser.Id
79
86
  }
80
87
  });
81
-
82
- return { Code: 1, Msg: '订单处理中,请稍候查看结果' };
83
- ```
84
-
85
- ```javascript
86
- // 消费者接口引擎:异步处理订单
87
- var msg = V8.Param.Message;
88
- var data = msg.Message;
89
-
90
- try {
91
- // 耗时操作:调用第三方 ERP 接口
92
- var erpResult = V8.Http.Post({
93
- Url: 'https://erp.company.com/api/order',
94
- PostParamString: JSON.stringify({ orderId: data.orderId }),
95
- ParamType: 'json',
96
- Timeout: 30
97
- });
98
-
99
- V8.FormEngine.UptFormData('Order', {
100
- Id: data.orderId,
101
- SyncStatus: 'success',
102
- SyncTime: DateNow('yyyy-MM-dd HH:mm:ss')
103
- });
104
- } catch (ex) {
105
- V8.FormEngine.UptFormData('Order', {
106
- Id: data.orderId,
107
- SyncStatus: 'failed',
108
- SyncError: ex.message
109
- });
110
- console.error('订单同步失败: ' + ex.message);
111
- }
112
- ```
113
-
114
- ### MQ 配置
115
-
116
- 主租户提供共享 Broker 地址 `MQHost/MQPort`。每个子租户必须在 RabbitMQ 中真实创建独立的 `MQUserName/MQPassword/MQVitrualHost`,并把权限限制在自己的 vhost 与 `microi.{osClient}.*` 队列;缺少凭据或与其它租户共用 user/password/vhost 时失败关闭,不回退主租户管理员账号。
117
-
118
- `diy_queue_receive` 表新增记录后,平台启动时自动订阅:
119
-
120
- | 字段 | 含义 |
121
- |------|------|
122
- | `Type` | `接口引擎`(固定) |
88
+
89
+ if (!sendResult || sendResult.Code !== 1) return sendResult;
90
+
91
+ return { Code: 1, Msg: '订单处理中,请稍候查看结果' };
92
+ ```
93
+
94
+ ```javascript
95
+ // 消费者接口引擎:异步处理订单
96
+ var msg = V8.Param.Message;
97
+ var data = msg.Message;
98
+
99
+ try {
100
+ // 耗时操作:调用第三方 ERP 接口
101
+ var erpResult = V8.Http.Post({
102
+ Url: 'https://erp.company.com/api/order',
103
+ PostParamString: JSON.stringify({ orderId: data.orderId }),
104
+ ParamType: 'json',
105
+ Timeout: 30
106
+ });
107
+
108
+ V8.FormEngine.UptFormData('Order', {
109
+ Id: data.orderId,
110
+ SyncStatus: 'success',
111
+ SyncTime: DateNow('yyyy-MM-dd HH:mm:ss')
112
+ });
113
+ return { Code: 1, Data: { EventId: msg.EventId } };
114
+ } catch (ex) {
115
+ V8.FormEngine.UptFormData('Order', {
116
+ Id: data.orderId,
117
+ SyncStatus: 'failed',
118
+ SyncError: ex.message
119
+ });
120
+ console.error('订单同步失败: ' + ex.message);
121
+ return { Code: 0, Msg: '订单同步失败' };
122
+ }
123
+ ```
124
+
125
+ ### MQ 配置
126
+
127
+ 每个租户都必须配置 `MQHost/MQPort/MQUserName/MQPassword/MQVitrualHost`,并在 RabbitMQ 中真实创建独立 user/vhost,把权限限制在自己的 vhost 与 `microi.{lowerOsClient}.*` 队列。缺少配置或与其它已加载租户共用 user/password/vhost 时失败关闭,不回退主租户管理员账号。可选 `MQUseTls/MQTlsServerName`;`MQHost` 可用逗号分隔多个端点。当前 `AddMicroiMQ()` 默认注册 `MicroiRabbitMQSingleConnection`,不会按 `MQType` 自动切换实现。
128
+
129
+ `diy_queue_receive` 表新增记录后,后台同步会创建或更新消费者:
130
+
131
+ | 字段 | 含义 |
132
+ |------|------|
133
+ | `Type` | `1`=接口引擎;`2`=仅默认主租户受控 DLL |
123
134
  | `QueueName` | 逻辑队列名(与生产端 `SendMsg({ QueueName, ... })` 一致) |
124
- | `ApiEngineKey` | 消费者接口引擎 Key |
125
- | `IsEnable` | 是否启用 |
126
- | `OsClient` | 所属租户(多租户隔离) |
127
-
128
- > ⚠️ 修改 `diy_queue_receive` 后需重启平台才会生效订阅。
135
+ | `ApiEngineKey` | 消费者接口引擎 Key |
136
+ | `FailToReject` | 值为“是”时失败后允许有限重入队 |
137
+ | `Count` | 最大重入队次数;`0` 表示首次失败后直接删除 |
138
+
139
+ 新增、修改或删除队列处理配置会在下一同步周期生效。同步间隔默认最多 180 秒,
140
+ 正数 `MQListenerTime` 可缩短但最低 15 秒;Host、端口、凭据、vhost 或 TLS 变更
141
+ 不会重建已缓存连接,需要滚动重启对应节点。
129
142
 
130
143
  多节点会对同一租户队列使用 RabbitMQ competing consumer,但“只有一个节点收到”不等于业务只执行一次。消息 envelope 的 `EventId` 是稳定幂等键,消费者必须配合数据库唯一约束、inbox/条件更新保证副作用仅一次;连接凭据轮换后当前版本需要重启节点重建连接。
131
-
132
- ---
133
-
134
- <!-- /microi-progressive:chunk -->
135
- <!-- microi-progressive:chunk id=v8-mq-mqtt-001 sha256=1f51deb2673c77cdd3a096ca658dfe0f025531760f1aee04987f3bb2723131cf -->
144
+
145
+ 消费者使用 `prefetch=1`、手动 Ack。接口引擎返回可解析的 `DosResult Code=1` 才
146
+ 明确成功;为兼容旧处理器,`null` 或非 `DosResult` 返回也会 Ack,因此新代码必须
147
+ 显式返回 `{Code:1}` 或 `{Code:0}`。失败且 `FailToReject=是` 时,Redis 以 EventId
148
+ 记录 7 天重试次数并在未达到 `Count` 前立即 requeue;当前源码没有退避和自动 DLQ,
149
+ 达到上限或未启用重入队时会 Reject 且不 requeue。
150
+
151
+ ---
152
+
153
+ <!-- /microi-progressive:chunk -->
154
+ <!-- microi-progressive:chunk id=v8-mq-mqtt-001 sha256=f65fe365f1adca83c0eabe95f73a658d6d79f33b3d9a8d34c5b35ede841e7d73 -->
136
155
  ## 注意事项
137
-
156
+
138
157
  - MQ 消费者接口引擎通过 `V8.Param.Message` 获取消息,包含 `EventId`、兼容 `Id`、`OsClient`、`Message`、`CurrentUserId`
139
158
  - MQ 适合异步解耦、削峰填谷、耗时操作异步化
140
159
  - MQTT 七类事件在同一个接口引擎中处理,通过 `V8.EventName` 区分
@@ -144,10 +163,12 @@ try {
144
163
  - `ConnectedClients` 只代表当前 MQTT 节点的诊断快照,不是集群全局在线事实
145
164
  - 内嵌 MQTT Broker 不具备跨节点共享会话/订阅/retained 的集群一致性;多 API 节点生产部署应使用支持集群的外部 Broker,或把内嵌 Broker 固定到独立节点并由负载入口路由,不能让每个 API 节点各自充当一套独立 Broker
146
165
  - MQTT 生产配置、安全语义、事件字段可用性和上线清单以 [MQTT 生产参考](references/mqtt-production.md) 为准
147
- <!-- /microi-progressive:chunk -->
148
- ## 详细参考路由(渐进披露)
149
-
150
- 仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
151
-
152
- - [references/progressive-01-v8-mqtt-iot-物联网.md](references/progressive-01-v8-mqtt-iot-物联网.md):V8.MQTT — IoT 物联网
153
- <!-- microi-progressive:end -->
166
+ <!-- /microi-progressive:chunk -->
167
+ ## 详细参考路由(渐进披露)
168
+
169
+ 仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
170
+
171
+ - [references/progressive-01-v8-mqtt-iot-物联网.md](references/progressive-01-v8-mqtt-iot-物联网.md):V8.MQTT — IoT 物联网
172
+ <!-- microi-progressive:end -->
173
+
174
+ 平台级 MQTT 状态与下行发布统一调用 Managed 接口引擎 `platform-mqtt`;该入口只允许当前租户超级管理员,并由 `V8.Method.ManageMqtt` 固定租户边界。普通设备业务仍应创建自己的授权接口引擎。
@@ -32,8 +32,9 @@
32
32
  配置、租户凭据、Topic 规范化和敏感字段边界。
33
33
  4. `Microi.Server/Microi.Core/Interface/IMicroiMQTT.cs`:
34
34
  `IMicroiMQTT.PublishAsync(osClient, ...)` 可信后端发布和节点状态接口。
35
- 5. `Microi.Server/Microi.net.Api/Controllers/MqttController.cs`:平台管理员、当前节点
36
- 状态与示例下行入口的权限边界。
35
+ 5. `Microi.Server/Microi.Core/V8Engine/Runtime/V8Method.PlatformPluginRuntimes.cs`
36
+ 与 `Microi.Server/Microi.Upgrade/Resource/platform-mqtt.js`:平台管理员、当前节点
37
+ 状态、租户 Topic 边界与接口引擎交付入口。
37
38
  6. `microi.doc/docs/doc/system-engine/mqtt-engine.md`:面向用户的完整能力说明。
38
39
 
39
40
  目标服务器可能落后于当前源码。编写事件代码前回读其 `sys_osclients` 字段和运行
@@ -14,7 +14,8 @@ const files = {
14
14
  model: 'Microi.Server/Microi.Core/Model/MqttParam.cs',
15
15
  mqttInterface: 'Microi.Server/Microi.Core/Interface/IMicroiMQTT.cs',
16
16
  tenantSecurity: 'Microi.Server/Microi.Core/SaaSEngine/TenantConfigurationSecurity.cs',
17
- controller: 'Microi.Server/Microi.net.Api/Controllers/MqttController.cs'
17
+ platformRuntime: 'Microi.Server/Microi.Core/V8Engine/Runtime/V8Method.PlatformPluginRuntimes.cs',
18
+ platformApiEngine: 'Microi.Server/Microi.Upgrade/Resource/platform-mqtt.js'
18
19
  };
19
20
 
20
21
  const content = {};
@@ -98,7 +99,7 @@ for (const propertyName of expectedProperties) {
98
99
 
99
100
  const sourceEvents = [...runtimeEvents].sort();
100
101
  const sourceProperties = [...mqttProperties].sort();
101
- for (const targetName of ['skill', 'reference', 'mqttDoc', 'v8Doc']) {
102
+ for (const targetName of ['reference', 'mqttDoc', 'v8Doc']) {
102
103
  requireTokens(targetName, sourceEvents);
103
104
  requireTokens(targetName, sourceProperties);
104
105
  }
@@ -139,22 +140,20 @@ const operationsTokens = [
139
140
  '独立 MQTT 节点'
140
141
  ];
141
142
 
142
- requireTokens('skill', [
143
- 'MqttEnable',
144
- 'MqttPort',
145
- 'MqttWsPort',
146
- 'MqttAccount',
147
- 'MqttPwd',
148
- 'MqttApiEngine',
149
- 'MqttAllowAnonymous',
150
- 'MqttTopicIsolation'
143
+ requireTokens('platformRuntime', [
144
+ 'ManageMqtt',
145
+ 'RequireCurrentTenantSuperAdmin',
146
+ 'IMicroiMQTT',
147
+ 'GetConnectedClients',
148
+ 'PublishAsync'
151
149
  ]);
150
+ requireTokens('platformApiEngine', ['V8.Method.ManageMqtt']);
151
+
152
+ requireTokens('skill', ['references/mqtt-production.md', 'platform-mqtt']);
152
153
  requireTokens('reference', configurationTokens);
153
154
 
154
- for (const targetName of ['skill', 'reference']) {
155
- requireTokens(targetName, securityTokens);
156
- requireTokens(targetName, operationsTokens);
157
- }
155
+ requireTokens('reference', securityTokens);
156
+ requireTokens('reference', operationsTokens);
158
157
 
159
158
  requireTokens(
160
159
  'mqttDoc',
@@ -190,7 +189,6 @@ requireTokens('runtime', [
190
189
  ]);
191
190
  requireTokens('mqttInterface', ['PublishAsync(string osClient', 'GetConnectedClients(string osClient)']);
192
191
  requireTokens('tenantSecurity', ['NormalizeMqttTopic', 'HasTenantServiceCredentialCollision']);
193
- requireTokens('controller', ['[PlatformAdminOnly]', 'StatusScope = "CurrentNode"']);
194
192
 
195
193
  if (failures.length > 0) {
196
194
  console.error('MQTT Skill 覆盖检查失败:');
@@ -12,7 +12,7 @@ description: Microi V8 安全指南。用于审查 DiyToken 与权限、可逆
12
12
  访问密钥由 `microi_list_my_access_keys`、`microi_create_my_access_key`、`microi_revoke_my_access_key` 管理,只允许当前用户、限期、最小 scope,明文仅创建时返回一次。外部身份回调固定为 `/api/ExternalLogin/Callback`,服务端校验租户、Provider、state、redirect 和回调域名,验证成功后仍签发 DiyToken。
13
13
 
14
14
  <!-- microi-progressive:begin -->
15
- <!-- microi-progressive:chunk id=v8-security-000 sha256=0346bd9ca3fe98dd2b589d1777aa1e55cd24cf7dedc69ee65d4ca91461db7dee -->
15
+ <!-- microi-progressive:chunk id=v8-security-000 sha256=d03ee34e72925db55f9022de26dfc251c0d3d69fac52ae6a910d42ddfc142ae7 -->
16
16
  ## 0. 租户动态系统设置与密钥边界
17
17
 
18
18
  第三方密钥(微信、支付宝、OpenAI、阿里云、ERP、SMTP)**禁止**硬编码在 V8 代码或前端。公开的租户配置必须建成当前租户 `sys_config` 的实体字段;敏感或仅供后端使用的租户业务配置保存到 `mci_system_setting`。数据库、Redis、MongoDB、MinIO、MQ 等部署控制面仍由主库 `sys_osclients` 托管,子租户不能修改。
@@ -33,7 +33,9 @@ var clientSecret = privateSettings['Login.Gitee.ClientSecret'];
33
33
  var openaiKey = 'sk-xxxxxxxxxx';
34
34
  ```
35
35
 
36
- `V8.OsClientModel` 与兼容别名 `V8.ClientModel` 均为独立脱敏副本:数据库连接、AuthSecret、Redis、对象存储、MQ、MQTT、Search 的地址与凭据不会注入脚本。存量租户业务字段只作兼容,新增 Secret 不得继续依赖 `V8.OsClientModel`。
36
+ `V8.OsClientModel` 与兼容别名 `V8.ClientModel` 均为独立脱敏副本:数据库连接、AuthSecret、Redis、对象存储、MQ、MQTT、Search 的地址与凭据不会注入脚本。存量租户业务字段只作兼容,新增 Secret 不得继续依赖 `V8.OsClientModel`。
37
+
38
+ 接口引擎需要保存可逆的接口私有密码或 Token 时,使用 `V8.Method.ProtectApiEngineSecret(value)` 写入密文,读取时使用 `V8.Method.UnprotectApiEngineSecret(cipher)`。宿主固定绑定当前 `OsClient + ApiEngineKey`,V8 不能指定租户、Purpose 或密钥;同租户其它接口引擎也不能解密。禁止继续用 `V8.OsClientModel.AuthSecret/DbConn` 自行派生 AES 密钥。列表仍只返回脱敏元数据,解密前仍要校验当前用户、行归属和业务权限,原文不得进入日志、审计或匿名响应。
37
39
 
38
40
  `V8.SysConfig` 按运行端采用不同权限投影,且任何运行端都不存在 `PublicSettings` 属性。浏览器/前端 V8 只得到匿名 `GetSysConfig` 的独立脱敏 `sys_config` 投影;`mci_system_setting` 的任何记录都不会进入浏览器。后端接口引擎和后端 V8 事件得到当前租户完整、独立的 `sys_config`,全部启用的 `mci_system_setting` 则放在 `V8.SysConfig.ServerPrivateSettings`,Secret 由可信后端按租户解密。独立节点避免动态 Key 覆盖 `sys_config` 实体字段,也让前后端边界可审计。子租户调用 `V8.FormEngine.GetSysConfig(...)` 时仍强制使用当前 `OsClient`,不能借缓存命中读取其它租户配置。
39
41
 
@@ -61,7 +63,7 @@ Secret 只通过租户管理员专用端点写入租户绑定的认证密文。
61
63
  - 多节点保存连接使用按 `OsClient + DbKey` 隔离的分布式锁,并由数据库唯一索引兜底;同步数据和附件仍必须使用业务幂等键,锁不能替代唯一约束、状态机或 inbox/outbox。
62
64
 
63
65
  <!-- /microi-progressive:chunk -->
64
- <!-- microi-progressive:chunk id=v8-security-001 sha256=c5868fd8a159b72f1038658873dfee83a9eca68661eebd837ecadab13dea5c22 -->
66
+ <!-- microi-progressive:chunk id=v8-security-001 sha256=9e477268919238bb6a2525116de3c8386aa439d8e93c5d66f3893cb07740b374 -->
65
67
  ## 0.5 接口引擎配置安全
66
68
 
67
69
  代码以外,接口本身的配置项也是安全防线(详见 `v8-api-config/SKILL.md`):
@@ -75,7 +77,7 @@ Secret 只通过租户管理员专用端点写入租户绑定的认证密文。
75
77
  | `LogParam = true` | 支付/审计类接口记录请求 |
76
78
 
77
79
  <!-- /microi-progressive:chunk -->
78
- <!-- microi-progressive:chunk id=v8-security-002 sha256=ed6c3fabf36da5a359778a0e7d085aa9b0d8a2f55337c0c9a1d39da4d72bac95 -->
80
+ <!-- microi-progressive:chunk id=v8-security-002 sha256=7229e5f8d200c0dfbab08752405f5e88d7edc80e9e92b6802880c022b09ca893 -->
79
81
  ## 1. 防 SQL 注入
80
82
 
81
83
  ### 必须:参数化查询
@@ -147,7 +149,7 @@ if (isNaN(amount) || amount <= 0 || amount > 999999.99) {
147
149
  ```
148
150
 
149
151
  <!-- /microi-progressive:chunk -->
150
- <!-- microi-progressive:chunk id=v8-security-004 sha256=e811dff8614c24c751291dda271b1574debccf741c0e166790f5324a3d3594ad -->
152
+ <!-- microi-progressive:chunk id=v8-security-004 sha256=1703ea824e4807b24d30225d41e16fb36b0fecc21c63a4ab0296106185460a27 -->
151
153
  ## 4. 防 XSS
152
154
 
153
155
  四个字符替换不是通用 XSS 防护。必须按输出上下文处理:
@@ -51,7 +51,7 @@ AI 本地开发表单 V8 事件时,优先修改 `microi-v8-engine/<租户>/<
51
51
  | `DataFilterV8.js` | **后端** | `DataFilter` | 获取列表/表单数据后 | 每行数据加工、脱敏、补充字段 |
52
52
 
53
53
  <!-- /microi-progressive:chunk -->
54
- <!-- microi-progressive:chunk id=v8-table-event-002 sha256=1956a46955c57434582c8dd5a41ffe9d445a74f42b26706c7d2033dfb822ffc0 -->
54
+ <!-- microi-progressive:chunk id=v8-table-event-002 sha256=86c13bfd4dbc035e5498fe072ed176780ed31975b64eda09c1a378de986ab73d -->
55
55
  ## 事件触发规则
56
56
 
57
57
  - 后端 V8 事件 / 接口引擎中调用 `V8.FormEngine` 增删改 → **不触发**表单 V8 事件
@@ -25,7 +25,7 @@
25
25
  | `WFNodeEnd` | 流程节点结束 V8 事件 |
26
26
 
27
27
  <!-- /microi-progressive:chunk -->
28
- <!-- microi-progressive:chunk id=v8-table-event-012 sha256=380fc790dcf02a27f8b47d9a894b98cb90ebc7ea6b57a5b30075d3d9d32a0262 -->
28
+ <!-- microi-progressive:chunk id=v8-table-event-012 sha256=db5bf410bc6babf14d3d91cc61b9875c81bc1be24b2c1b7c62334bc6819e4e55 -->
29
29
  ## 注意事项
30
30
 
31
31
  - 前端事件可使用 `window` 对象和 `async/await`,后端事件不可以
@@ -71,7 +71,7 @@ var clientDecoded = V8.Base64.decode(clientEncoded);
71
71
  | Excel/Word/PPT/邮件 | `v8-export-import` |
72
72
  | 前端事件/打印/扫码 | `v8-frontend-events` |
73
73
  | 后端表单事件 | `v8-table-event` |
74
- | 接口配置/异步/后台任务 | `v8-api-config` |
74
+ | 接口配置/流式响应/异步/后台任务 | `v8-api-config` |
75
75
 
76
76
  ## 不可越过的边界
77
77
 
@@ -9,10 +9,12 @@
9
9
  | 路由 | 用途 |
10
10
  |---|---|
11
11
  | `POST /apiengine/{ApiEngineKey}` | 推荐的稳定接口引擎入口 |
12
- | `POST /api/ApiEngine/Run` | 兼容入口,Body 传 `ApiEngineKey` |
12
+ | `POST /api/ApiEngine/Run` | 仅旧客户端兼容,Body 传 `ApiEngineKey`;新增固定业务禁止使用 |
13
13
  | `/apiengine/{ApiEngineKey}--OsClient--{OsClient}--` | 仅用于确实无法设置 Header/Form/Query 的 GET/HEAD 场景 |
14
14
 
15
15
  普通请求优先在唯一 `osclient` Header 传租户,也可在 Query/Form/JSON 中冗余;
16
+ 固定业务必须使用真实引擎动态地址或唯一 `ApiAddress`,使日志、流量、审计和限流
17
+ 直接按引擎归因;旧通用入口只能由显式 `RunLegacy` 调用。
16
18
  不要无脑把特殊租户后缀加到每条 URL。官网中的
17
19
  `/apiengine/test1`、`/apiengine/get-product-list`、打印、支付和 Excel demo
18
20
  都是业务 `ApiEngineKey` 示例,不是固定平台接口。
@@ -49,7 +51,7 @@
49
51
  | `POST /api/HDFS/GetPrivateFileUrl` | 获取当前租户短期私有文件地址 |
50
52
  | `GET /api/HDFS/OpenPrivateFile` | 受权打开私有文件/Office 代理 |
51
53
  | `POST /api/DiyChat/SendSystemMessage` | 发送站内消息;前端优先 `V8.SendSystemMessage` |
52
- | `POST /api/mq/sendmsg` | MQ HTTP 兼容入口;业务端优先受控 V8/MQ |
54
+ | `POST /apiengine/platform-mq` | MQ 管理入口;Body 使用 `Action=Send`,仅当前租户超级管理员 |
53
55
  | `GET /api/Diagnostics/health` | 聚合健康状态 |
54
56
  | `GET /api/Diagnostics/liveness` | 进程存活检查,不代表已就绪接流量 |
55
57
 
@@ -18,15 +18,18 @@
18
18
  | `V8.RowIndex`、`V8.CacheData`、`V8.NotSaveField` | DataFilter 等事件上下文 |
19
19
  | `V8.LineValue`、`V8.NextNodeId`、`V8.WF` | 工作流路线与节点上下文 |
20
20
  | `V8.FilesByteBase64` | 上传文件 Base64 字典 |
21
- | `V8.Limits` | 当前 Jint 资源预算与调用深度 |
21
+ | `V8.Limits` | 当前 Jint 资源预算与调用深度 |
22
+ | `V8.Stream` | 仅 `ResponseType=Stream` 的接口引擎可用;SSE/NDJSON 暂态分片写入器 |
22
23
  | `V8.Action` | 服务器全局 V8 自定义方法 |
23
24
 
24
25
  ## 调用、数据与异步
25
26
 
26
27
  | API | 说明 |
27
28
  |---|---|
28
- | `V8.ApiEngine.Run(...)` | 同步调用接口引擎 |
29
- | `await V8.ApiEngine.RunAsync(...)` | 请求内异步调用接口引擎 |
29
+ | `V8.ApiEngine.Run(...)` | 同步调用接口引擎 |
30
+ | `await V8.ApiEngine.RunAsync(...)` | 请求内异步调用接口引擎 |
31
+ | `V8.Stream.Write(data,eventName?,id?)` | 同步写一个受大小限制的暂态流式分片 |
32
+ | `await V8.Stream.WriteAsync(data,eventName?,id?)` | 等待网络背压后写暂态分片;每次检查返回 `Code` |
30
33
  | `V8.FormEngine.*` | 表单 CRUD,见 `v8-crud-api` |
31
34
  | `await V8.FormEngine.GetTableDataAsync(...)` | 请求内异步查列表 |
32
35
  | `V8.Db`、`V8.DbRead`、`V8.DbTrans` | 主库、只读库、共享事务 |
@@ -152,7 +152,7 @@ if (V8.Form.Money <= 100) {
152
152
  ```
153
153
 
154
154
  <!-- /microi-progressive:chunk -->
155
- <!-- microi-progressive:chunk id=v8-workflow-006 sha256=e67b72bf060a38ed5f94a57f3978026d151bb971fcf47a0b30a434dba819c264 -->
155
+ <!-- microi-progressive:chunk id=v8-workflow-006 sha256=8e2a82330c7f49c3a03920123531d310ea329fd310179918d835e3c05d49771a -->
156
156
  ## 前端发起流程
157
157
 
158
158
  ```javascript
@@ -104,7 +104,7 @@ AI 在工作区任意任务中生成的**一次性临时脚本、诊断文件、
104
104
  **2026-06 强制补充**:AI 不得在任何子项目目录下放置一次性日志、自动化截图、接口回收文件或调试脚本。像 `Microi.Server/Microi.net.Api/.tmp-*.log`、`Microi.Client/*.png` 这类文件一律视为规范失败,必须移到 `<workspace-root>/.tmp/` 或 `<workspace-root>/.tmp/screenshots/`。正式 Playwright 工程由 Microi.VSCode 插件生成时可以继续使用 `.microi-e2e/`,但 AI 为某个任务手写的一次性 Playwright 脚本、报告和截图仍然必须放在 `.tmp/`。
105
105
 
106
106
  <!-- /microi-progressive:chunk -->
107
- <!-- microi-progressive:chunk id=workspace-conventions-005 sha256=fff5f355bea04077c15039b668f0a02b1ed018f5e76aaee47113b6be777fef4a -->
107
+ <!-- microi-progressive:chunk id=workspace-conventions-005 sha256=52273704562fac1245fa364ca811949ccb2685dce8375f99bdc4029a314dd758 -->
108
108
  ## Microi 源码路径速查(工作区根相对路径)
109
109
 
110
110
  当用户提到“吾码后端源码”“吾码前端源码”“表单引擎源码”“官网源码”等简称时,默认按下列路径定位;如果当前工作区缺少对应目录,再用 `rg --files` 或目录搜索确认实际位置。