@microi.net/cli 4.9.6 → 4.9.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.
Files changed (93) 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 -5
  7. package/package.json +1 -1
  8. package/scripts/mcp-server.js +83 -83
  9. package/scripts/microi-cli.js +55 -85
  10. package/scripts/microi-codex-broker.js +418 -0
  11. package/scripts/microi-codex-router.js +129 -65
  12. package/scripts/microi-skills.meta.json +310 -151
  13. package/skills/.microi-skills-version.json +2 -2
  14. package/skills/.progressive-disclosure-manifest.json +3566 -0
  15. package/skills/ai-platform-governance/SKILL.md +21 -166
  16. package/skills/ai-platform-governance/references/progressive-01-/345/212/237/350/203/275/345/274/200/345/205/263.md +190 -0
  17. package/skills/microi-client-frontend/SKILL.md +17 -434
  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 +144 -0
  19. package/skills/microi-client-frontend/references/progressive-02-8-/350/277/220/350/241/214/346/227/266/351/253/230/351/242/221/345/235/221/345/244/215/347/233/230.md +178 -0
  20. 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 +144 -0
  21. package/skills/microi-db-schema/SKILL.md +3 -3
  22. package/skills/microi-db-schema/references/schema-overview.md +1 -1
  23. package/skills/microi-db-schema/references/schema.md +1 -1
  24. package/skills/microi-db-schema/references/table-catalog.md +1 -1
  25. package/skills/microi-form-engine/SKILL.md +1 -1
  26. package/skills/microi-form-layout/SKILL.md +19 -225
  27. package/skills/microi-form-layout/references/progressive-01-3-/344/270/211/347/247/215/345/210/206/347/273/204/347/232/204/345/255/230/345/202/250/344/270/216/351/205/215/347/275/256.md +235 -0
  28. package/skills/microi-frontend-sdk/SKILL.md +17 -151
  29. package/skills/microi-frontend-sdk/references/progressive-01-token-/345/275/223/345/211/215/347/231/273/345/275/225/347/224/250/346/210/267/344/270/216/345/275/223/345/211/215/347/273/210/347/253/257/347/231/273/345/275/225/345/215/217/350/256/256.md +171 -0
  30. package/skills/microi-mobile-app-quality/SKILL.md +22 -288
  31. package/skills/microi-mobile-app-quality/references/progressive-01-4-/351/207/215/350/246/201/346/214/211/351/222/256/345/277/205/351/241/273/345/270/246/345/233/276/346/240/207.md +209 -0
  32. package/skills/microi-mobile-app-quality/references/progressive-02-9-/344/270/273/351/242/230/345/210/207/346/215/242/345/277/205/351/241/273/347/234/237/345/256/236/344/270/224/345/205/250/345/261/200/347/224/237/346/225/210.md +117 -0
  33. package/skills/microi-system-delivery/SKILL.md +16 -380
  34. package/skills/microi-system-delivery/references/progressive-01-/346/240/207/345/207/206/345/267/245/344/275/234/346/265/201.md +186 -0
  35. package/skills/microi-system-delivery/references/progressive-02-/350/207/252/345/212/250/345/214/226/346/265/213/350/257/225/345/277/205/351/241/273/350/246/206/347/233/226/347/232/204/345/235/221.md +210 -0
  36. package/skills/microi-ui/SKILL.md +19 -169
  37. package/skills/microi-ui/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/234/272/346/231/257/350/223/235/345/233/276.md +183 -0
  38. package/skills/microi-uniapp-frontend/SKILL.md +26 -335
  39. package/skills/microi-uniapp-frontend/references/progressive-01-/347/247/273/345/212/250/347/253/257/345/210/206/347/261/273-/345/217/214/346/240/217/345/210/227/350/241/250/347/213/254/347/253/213/346/273/232/345/212/250.md +225 -0
  40. package/skills/microi-uniapp-frontend/references/progressive-02-/345/205/263/351/224/256/344/270/232/345/212/241/350/265/204/344/272/247/344/270/215/345/276/227/351/273/230/350/256/244/351/200/211/344/270/255.md +154 -0
  41. package/skills/page-engine/SKILL.md +23 -271
  42. package/skills/page-engine/references/progressive-01-/346/211/200/346/234/211/347/273/204/344/273/266/347/261/273/345/236/213.md +234 -0
  43. package/skills/page-engine/references/progressive-02-/347/211/210/346/234/254/345/216/206/345/217/262-/345/271/266/345/217/221/344/277/235/345/255/230/344/270/216/345/233/236/346/273/232.md +60 -0
  44. package/skills/playwright-e2e/SKILL.md +24 -590
  45. package/skills/playwright-e2e/references/progressive-01-/345/205/250/350/207/252/345/212/250/347/231/273/345/275/225-/345/205/215/351/252/214/350/257/201/347/240/201-/344/275/206/344/270/215/345/205/215/345/257/206/347/240/201-/345/277/205/350/257/273.md +173 -0
  46. package/skills/playwright-e2e/references/progressive-02-/346/226/207/345/255/227/345/257/271/346/257/224/345/272/246/344/270/216/345/217/257/350/257/273/346/200/247/350/207/252/345/212/250/345/214/226/346/243/200/346/237/245-/345/277/205/345/201/232.md +183 -0
  47. package/skills/playwright-e2e/references/progressive-03-microi-helper-/346/250/241/346/235/277.md +221 -0
  48. package/skills/playwright-e2e/references/progressive-04-ci-/345/273/272/350/256/256.md +69 -0
  49. package/skills/scripts/optimize-progressive-disclosure.mjs +204 -0
  50. package/skills/scripts/refresh-progressive-disclosure.mjs +64 -0
  51. package/skills/scripts/validate-progressive-disclosure.mjs +52 -0
  52. package/skills/ui-design/SKILL.md +26 -1461
  53. package/skills/ui-design/references/progressive-01-/351/242/234/350/211/262/344/275/223/347/263/273-css-variables-/346/224/257/346/214/201/344/270/273/351/242/230/345/210/207/346/215/242.md +218 -0
  54. package/skills/ui-design/references/progressive-02-/345/255/227/344/275/223.md +155 -0
  55. package/skills/ui-design/references/progressive-03-/345/212/250/346/225/210/350/247/204/350/214/203-/344/270/260/345/257/214/344/275/206/344/270/215/345/215/241.md +235 -0
  56. package/skills/ui-design/references/progressive-04-/347/273/204/344/273/266/351/243/216/346/240/274/351/200/237/346/237/245.md +152 -0
  57. package/skills/ui-design/references/progressive-05-/347/247/273/345/212/250/347/253/257/344/270/223/347/224/250/350/247/204/350/214/203.md +238 -0
  58. package/skills/ui-design/references/progressive-06-/344/270/273/351/242/230/345/210/207/346/215/242/345/256/236/347/216/260.md +194 -0
  59. package/skills/ui-design/references/progressive-07-/351/200/237/346/237/245-/344/273/216/345/244/264/346/220/255/345/273/272/344/270/200/344/270/252/347/247/273/345/212/250/347/253/257/351/241/265/351/235/242.md +207 -0
  60. package/skills/ui-design/references/progressive-08-/350/241/250/345/215/225/345/210/206/347/273/204/350/247/204/350/214/203-tabs-vs-collapsegroup-/345/274/272/345/210/266.md +142 -0
  61. package/skills/v8-crud-api/SKILL.md +20 -245
  62. package/skills/v8-crud-api/references/progressive-01-/346/237/245/350/257/242/345/210/227/350/241/250-/345/210/206/351/241/265.md +226 -0
  63. package/skills/v8-crud-api/references/progressive-02-where-/346/235/241/344/273/266/350/257/255/346/263/225/351/200/237/346/237/245.md +49 -0
  64. package/skills/v8-export-import/SKILL.md +15 -425
  65. package/skills/v8-export-import/references/progressive-01-excellayout-/351/253/230/347/272/247/350/207/252/347/224/261/345/270/203/345/261/200.md +211 -0
  66. package/skills/v8-export-import/references/progressive-02-powerpoint-/345/257/274/345/207/272.md +202 -0
  67. package/skills/v8-export-import/references/progressive-03-/345/256/211/345/205/250-/346/200/247/350/203/275/346/263/250/346/204/217.md +42 -0
  68. package/skills/v8-file-upload/SKILL.md +16 -354
  69. 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 +227 -0
  70. package/skills/v8-file-upload/references/progressive-02-office-/346/226/207/344/273/266/345/234/250/347/272/277/347/274/226/350/276/221/347/211/210/346/234/254/345/217/267/350/247/204/345/210/231.md +149 -0
  71. package/skills/v8-frontend-events/SKILL.md +19 -205
  72. package/skills/v8-frontend-events/references/progressive-01-/345/210/227/350/241/250/344/272/213/344/273/266.md +219 -0
  73. package/skills/v8-http-integration/SKILL.md +14 -236
  74. package/skills/v8-http-integration/references/progressive-01-get-/350/257/267/346/261/202.md +220 -0
  75. package/skills/v8-http-integration/references/progressive-02-/351/224/231/350/257/257/345/244/204/347/220/206/346/250/241/345/274/217.md +44 -0
  76. package/skills/v8-menu-buttons/SKILL.md +15 -511
  77. package/skills/v8-menu-buttons/references/progressive-01-2-/346/214/211/351/222/256/345/257/271/350/261/241-schema.md +221 -0
  78. package/skills/v8-menu-buttons/references/progressive-02-8-/346/250/241/345/274/217-f-/345/220/216/345/217/260/344/273/273/345/212/241/346/214/211/351/222/256-/351/225/277/344/273/273/345/212/241.md +224 -0
  79. package/skills/v8-menu-buttons/references/progressive-03-10-/345/217/215/346/250/241/345/274/217-/351/201/277/345/205/215.md +104 -0
  80. package/skills/v8-mq-mqtt/SKILL.md +11 -175
  81. package/skills/v8-mq-mqtt/references/progressive-01-v8-mqtt-iot-/347/211/251/350/201/224/347/275/221.md +181 -0
  82. package/skills/v8-security/SKILL.md +16 -329
  83. package/skills/v8-security/references/progressive-01-2-/346/235/203/351/231/220/346/240/241/351/252/214.md +199 -0
  84. package/skills/v8-security/references/progressive-02-7-/346/227/245/345/277/227/350/256/260/345/275/225.md +158 -0
  85. package/skills/v8-table-event/SKILL.md +16 -236
  86. package/skills/v8-table-event/references/progressive-01-informv8-js-/350/241/250/345/215/225/346/211/223/345/274/200/344/272/213/344/273/266.md +216 -0
  87. 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 +46 -0
  88. package/skills/v8-workflow/SKILL.md +19 -160
  89. package/skills/v8-workflow/references/progressive-01-/350/212/202/347/202/271/345/274/200/345/247/213-v8-/344/272/213/344/273/266.md +180 -0
  90. package/skills/workspace-conventions/SKILL.md +29 -361
  91. package/skills/workspace-conventions/references/progressive-01-/347/211/210/346/234/254/346/233/264/346/226/260/346/227/245/345/277/227/344/277/235/346/212/244/350/247/204/345/210/231-/345/274/272/345/210/266.md +208 -0
  92. package/skills/workspace-conventions/references/progressive-02-microi-net-api-/346/234/254/345/234/260/345/220/257/345/212/250/347/272/246/345/256/232.md +196 -0
  93. package/skills/workspace-conventions/references/progressive-03-cli-/344/270/216-ide-/346/217/222/344/273/266/351/224/231/347/211/210/345/205/261/345/255/230/347/272/246/345/256/232.md +27 -0
@@ -11,6 +11,8 @@ description: Microi V8 与 MCP 文件上传下载指南。用于处理流式 AI
11
11
 
12
12
  公开入口覆盖 `V8.uploadFile`、多文件 `V8.uploadFiles` 与 MCP `microi_upload_file_base64`。多文件上传必须限制并发、逐文件返回结果;Base64 工具只接受明确文件名、大小和租户内目标范围,写后回读路径、大小与哈希。
13
13
 
14
+ <!-- microi-progressive:begin -->
15
+ <!-- microi-progressive:chunk id=v8-file-upload-000 sha256=b48ce09f93a43efd30e700af637db3881355e8d2baaf45165ea2bd0bdfda25cf -->
14
16
  ## 核心 API
15
17
 
16
18
  | API | 说明 |
@@ -21,6 +23,8 @@ description: Microi V8 与 MCP 文件上传下载指南。用于处理流式 AI
21
23
  | `V8.Http.GetResponse({Url}).RawBytes` | 下载远程文件为字节数组 |
22
24
  | 接口返回 `{ FileName, ContentType, FileByteBase64 }` | 接口直接响应文件 |
23
25
 
26
+ <!-- /microi-progressive:chunk -->
27
+ <!-- microi-progressive:chunk id=v8-file-upload-001 sha256=a7572bc0fd333c8f0c240d0f62db4763225ba9f69bfd45d0e0d41ae3f4b1edd0 -->
24
28
  ## 第三方数据库附件迁移
25
29
 
26
30
  当第三方表只保存附件路径时,先用 `microi_inspect_external_database` / `microi_query_external_database` 或 `V8.Dbs.<DbKey>` 查询记录。`microi_import_external_attachment` 允许后端已确认的 `Level >= 9999` 当前用户直接提供 HTTP/HTTPS URL、API 节点可读的本机绝对路径或 UNC 路径。
@@ -33,6 +37,8 @@ description: Microi V8 与 MCP 文件上传下载指南。用于处理流式 AI
33
37
 
34
38
  可信后端 V8 可用 `V8.Http.GetResponse({ Url: url }).RawBytes` 下载,再用 `System.Convert.ToBase64String` 和 `V8.Method.Upload` 上传。该路径同样必须校验域名、大小、Content-Type、后缀和最终重定向目标。
35
39
 
40
+ <!-- /microi-progressive:chunk -->
41
+ <!-- microi-progressive:chunk id=v8-file-upload-002 sha256=ab3fa9eda3090868f45651aaddfa6b5ecd390535123f4666c9b67fba6a6e34f7 -->
36
42
  ## 接收前端上传的文件
37
43
 
38
44
  前端发起文件上传时,平台自动把文件以 base64 形式注入到 `V8.FilesByteBase64`:
@@ -122,197 +128,8 @@ Token 不是无限上传授权。所有 HTTP、表单、V8 和移动端上传入
122
128
  - `OsClient` 只能保留一个规范字段,避免同时提交 `OsClient`、`osclient` 或 query/header/formData 多处互相冲突。
123
129
  - 生产 H5 不能只依赖 `uni.uploadFile`。页面从 `uni.chooseImage` 得到的 `tempFiles[0].file`、`tempFiles[0]`、`blob:` / `data:` 临时路径都要传给 `V8.uploadFile`,并设置 `preferFetch:true`;SDK 必须能用 `fetch + FormData` 兜底,否则线上可能报 `未找到 MicroiV8 上传适配器。`。
124
130
 
125
- ## 公有桶 vs 私有桶
126
-
127
- ### 应用商城 ZIP
128
-
129
- 应用商城的 AI 应用/微服务资产禁止逐文件 Base64 持久化到数据库。源码/安装包场景可以生成 ZIP;真实在线编译目录优先使用下节的 MCP 流式发布。数据库只保存路径和校验元数据。
130
-
131
- 在线商城安装的后台任务只传 `StoreId/StoreApiBase/StoreOsClient` 等定位信息,不能复制整行、`Form/Row/Btn` 或 `AppPakcet`。兼容旧 Base64 包的导入器必须按片限制真实上传数量/体积,片间靠已提交的 `AppId + FilePath + Hash` 复用;上传后统计大小优先使用包内 `Size/Sha256`,禁止再次 `FromBase64String` 构造完整字节数组。
132
-
133
- ```javascript
134
- var zipResult = V8.Method.CreateZip({
135
- Entries: [
136
- { Path: 'index.html', Content: '<html></html>' },
137
- { Path: 'assets/app.js', FileByteBase64: jsBase64 }
138
- ],
139
- MaxFileCount: 20000,
140
- MaxEntryBytes: 268435456,
141
- MaxTotalBytes: 2147483648
142
- });
143
-
144
- var extractResult = V8.Method.ExtractZip({
145
- FileByteBase64: zipBase64,
146
- MaxFileCount: 20000,
147
- MaxCompressionRatio: 200
148
- });
149
- ```
150
-
151
- `System.IO` 在 Jint 沙箱中被禁止,不能在 V8 代码里直接构造 `MemoryStream/ZipArchive`;必须使用以上受控方法。
152
-
153
- ### AI 应用编译目录流式发布(首选)
154
-
155
- 发布 Web、UniApp、MicroService 的 `dist` / H5 编译目录时,必须优先使用 `microi_publish_application_directory_stream`,不要把每个文件读成 Base64 后传给 `ai_app_build`、`microi_publish_microservice` 或普通 JSON 接口。旧工具仅为小文件兼容保留。
156
-
157
- 标准流程:
158
-
159
- 1. 先运行不带 `confirmExecution` 的预检。MCP 按流计算 SHA-256,拒绝符号链接、`.git`、`node_modules`、密钥/`.env`、路径穿越、超过 20000 个文件或超过 20 GB 的垃圾目录;默认不发布 `.map`。
160
- 2. 确认后把 `confirmExecution` 精确设为 `appIdOrKey`。每个文件通过 multipart 原始流进入 `/api/V8Engine/UploadApplicationAssetStream`,不构造整文件 `Buffer`、Base64 或 JSON 文件体。
161
- 3. 文件只写不可变版本目录。全部成功后,清单确认接口只接收 `Path/Sha256/Size`,由 HDFS Provider 的 `CopyObject` 在服务端复制到 root 与 `latest`;非入口先复制,入口最后复制。
162
- 4. 历史版本 URL 保留语义版本;分享/在线使用 URL 使用不含版本号的 root 稳定地址。重试必须复用同一版本与摘要,不能覆盖已有但缺少完整性证明的历史对象。
163
- 5. 该控制面只允许当前 Token 租户的 `Level >= 9999` 交互式管理员;访问密钥会话不得发布。单文件、HTTP/Multipart 和每日额度仍然生效,不能把“使用流”理解成无限上传。
164
-
165
- 几十 MB **不是** Jint 或 HDFS 的固定上限。旧链路失败的原因是二进制先膨胀为约 `4/3` 的 Base64,又在 JSON、Jint 字符串、.NET 字符串/字节数组之间产生多份累计分配;文件数量、并发和当前进程内存共同决定触发点。描述问题时必须明确“旧 Base64/Jint 发布链路的累计分配”,不得写成“几十 MB 就达到 Jint 硬上限”。HDFS 上传本身应走二进制流。
166
-
167
- ```json
168
- {
169
- "appIdOrKey": "flower-store",
170
- "versionNo": "v1.2.0",
171
- "directory": "D:/build/flower-store/dist",
172
- "entryPath": "index.html",
173
- "changeSummary": "修复移动端布局",
174
- "confirmExecution": "flower-store"
175
- }
176
- ```
177
-
178
- 底层断点式单文件工具是 `microi_upload_application_asset_stream`。除诊断或精确恢复单文件外,不要只调用它而遗漏最终清单确认,否则稳定入口不会切换。
179
-
180
- | 类型 | `Limit` | 访问 URL | 用途 |
181
- |------|---------|---------|------|
182
- | 公有桶 | `false` | 直接拼接 `V8.SysConfig.FileServer + Path` | 产品图、Banner、公开文档 |
183
- | 私有桶 | `true` | 必须用 `V8.Method.GetPrivateFileUrl` 获取临时 URL | 合同、身份证、敏感数据 |
184
-
185
- ### 默认 MinIO 桶名与安装验收
186
-
187
- - Microi 一键安装的默认私有桶固定为 `mci-private`,默认公有桶固定为 `mci-public`;禁止使用 `mci-publish` 等近似名称。
188
- - `MinIOEndPointInternet` / `MinIOPrivateEndPoint` 同时兼容 `host:port` 与 `http(s)://host:port`。Provider 必须先归一化为 Host、Port、UseSsl,再调用 MinIO SDK 的 host/port 重载;不得把包含协议的整串 URL 直接作为 hostname,否则会出现 `Invalid URI: The hostname could not be parsed.`。显式 URL 的协议优先于历史 SSL 开关;端点禁止携带用户名密码、桶路径、查询或片段。
189
- - 安装脚本创建 `mci-public` 后必须设置匿名下载权限,并把 `HDFS=MinIO`、内外网端点、AccessKey/SecretKey、`MinIOPrivateBucketName=mci-private`、`MinIOPublicBucketName=mci-public` 同步写入当前租户的 `sys_osclients`。
190
- - 安装脚本还必须同步当前有效 `sys_config`:`ApiBase` 使用对外可访问的 API 端口,`FileServer` 使用 `http://<访问IP>:<MinIO API端口>/mci-public`。`ApiBase` 不能误用 Web 前端端口,因为 V8 代码会直接在其后拼接 `/api/...` 或 `/apiengine/...`。
191
- - 安装验收必须使用真实登录 Token 分别执行一次 `Limit=false` 和 `Limit=true` 上传:公有文件匿名访问应返回 `200`,私有文件匿名访问应返回 `403`,私有文件通过签名 URL 访问应返回 `200`,并核对下载内容与上传内容一致。
192
-
193
- ### 复盘:签名 HEAD 被代理转换为 GET 导致上传后回读误报
194
-
195
- - 触发场景:`PutObject` 已返回成功、对象可通过 GET 下载,但公有桶和私有桶的上传后 `StatObject` 均对桶根路径返回 `AccessDenied`;常见于启用严格回读校验后,MinIO Endpoint 前的 Nginx 同时启用了缓存与默认的 `proxy_cache_convert_head on`。
196
- - 根因判断:S3 SigV4 的签名包含 HTTP 方法;代理把客户端签名的 HEAD 转为上游 GET 后会造成签名不一致。另一个可能原因是对象级凭据缺少桶级 `ListBucket` / `GetBucketLocation` 权限,因此不能只凭 `AccessDenied /bucket/` 推断对象未落盘,也不能把空 Region 当作唯一原因。
197
- - 通用规则:优先在 MinIO 代理位置设置 `proxy_cache_convert_head off`;若仍使用缓存,缓存键需区分 `$request_method`。平台不得跳过上传后回读:当 HEAD/Stat 失败时,使用同一凭据生成签名 GET,并以 `Range: bytes=0-0` 回读;禁用重定向,非空对象必须同时验证期望总长度与首字节,空对象验证长度为零,`404` 判不存在,`403`、网络错误和证据不足继续失败关闭。禁止记录或返回带签名查询参数的 URL。
198
- - 配置边界:只有实时回读证明 Endpoint、桶名、Region 或凭据确实错误时才修改 SaaS 配置;对象 GET 正常而仅 HEAD 失败时应修复代理或兼容回读路径,不能猜测内网地址、降低校验强度或轮换正常凭据。
199
- - 自动化检查:覆盖签名 GET 的单字节 Range、期望总长度、首字节实际读取、空对象、长度不符、重定向、`403` 和 `404`;真实环境同时验证公有桶与私有桶的 `Put -> Range GET -> 内容一致`,并对比相同签名在 GET 与 HEAD 方法下的响应。
200
-
201
- ### 复盘:旧空库缺少可选字段导致 MinIO 初始化后中断
202
-
203
- - 触发场景:MinIO 容器、私有桶和公有桶均已成功创建,但安装器更新 `sys_osclients` 时因旧库缺少 `NetworkIsInternet` 返回 `Unknown column`,整套安装停在 API 部署之前。
204
- - 根因:安装器在 API/Upgrade 尚未启动时依赖了并非 MinIO 必需、且存量数据库不保证存在的旧可选字段;同时只按 `OsClient` 更新且没有写后回读。
205
- - 通用规则:MinIO 安装前先校验真正必需的物理字段,并按 `OsClient + OsClientType + OsClientNetwork + IsEnable + IsDeleted` 唯一定位运行租户。内外网端点由 API 允许的启动项 `OsClientNetwork` 选择,安装器不得再写 `NetworkIsInternet`;配置更新后逐字段回读一致才继续。
206
- - 恢复规则:桶初始化成功而配置写入失败不需要删除桶或数据卷。中断的新安装应先备份现有 Compose 并记录绑定数据目录,只对对应编排执行不带 `-v` 的 `docker compose down`,保留数据恢复点后再使用最新版脚本;禁止直接删除数据库或对象存储目录。
207
- - 自动化检查:用一个不含 `NetworkIsInternet`、但包含 MinIO 必需字段的临时 MySQL 表执行 schema、唯一租户、UPDATE 和回读闭环;再插入重复三参数租户,断言安装器失败关闭且不批量覆盖。
208
-
209
- ### 复盘:MinIO 已可上传但系统设置仍指向官方地址
210
-
211
- - 触发场景:一键安装和桶初始化均成功,用户手工上传也成功,但读取系统设置时发现 `ApiBase`、`FileServer` 仍是空库模板中的官方地址。
212
- - 根因:安装流程只回写了 `sys_osclients` 的 MinIO 配置,没有同步前端和 V8 公共使用的 `sys_config` 地址字段。
213
- - 通用规则:数据库还原并创建默认桶后,必须按安装模式选择的访问 IP 和动态端口同时回写有效 `sys_config.ApiBase/FileServer`;其中 `ApiBase` 指向 API 服务,`FileServer` 指向公有桶根地址。
214
- - 自动化检查:安装完成后通过 `GetSysConfig` 回读两个字段,断言均使用本次访问 IP 和实际端口;再执行公有上传并使用 `FileServer + Path` 匿名下载,内容必须一致。
215
-
216
- 公开页面图片(首页 banner、商品主图、公开活动头像等)应返回公有 URL,例如 `V8.SysConfig.FileServer + Path`。不要把公有图片统一转成 `GetPrivateFileUrl` 的 `static-private` 签名地址;部分 H5/浏览器会因响应头或跨域策略触发 ORB/CORS 拦截,表现为 uni-app `<image>` 内层 `background-image: none`。
217
-
218
- ### `sys_user.Avatar` 固定使用私有桶
219
-
220
- - `sys_user` 是内部系统用户表,`Avatar` 可能暴露员工身份信息,因此字段配置必须保持 `ImgUpload.Limit=true`,上传端也必须显式传 `Limit:true`;自定义用户管理页不能因为绕过表单引擎而回退到公有上传。
221
- - 数据库继续只保存租户内相对路径,例如 `/tenant_demo/avatar/20240218/user.png`。历史公有头像迁移时,应把同一文件复制到私有桶的同一路径,确认私有对象可访问后再停用公有访问;不得为了迁移批量改写路径或制造重复日期目录。
222
- - PC、移动端、聊天、工作流等任何页面渲染 `sys_user.Avatar` 时,禁止 `FileServer + Avatar`、`GetServerPath(Avatar)` 或把相对路径直接交给 `<img>`。前端应调用 `DiyCommon.GetUserAvatarUrl(avatar, userId)`,接口/V8 应调用 `V8.Method.GetPrivateFileUrl({ FilePathName: avatar })`,并为临时 URL 设置短期缓存与失败占位图。
223
- - `ContactUserAvatar`、`FromUserAvatar`、`SenderAvatar` 等从 `sys_user.Avatar` 派生的快照字段同样按私有路径处理;消息数据只保存原始相对路径,不能把会过期的临时 URL 持久化到数据库。
224
-
225
- #### 复盘:字段改私有后卡片仍访问公有桶
226
-
227
- - 触发条件:把 `sys_user.Avatar` 改为 `Limit=true`,但模块卡片仍配置 `TableCardImgField=Avatar`。
228
- - 根因:通用卡片渲染器只读取了字段值,没有读取图片字段的 `Config.ImgUpload.Limit`,仍统一调用 `GetServerPath/FileServer`。
229
- - 修复规则:通用图片渲染器必须同时检查字段配置;私有字段先异步换取临时地址,`sys_user.Avatar` 还要有表名+字段名语义兜底,避免元数据缓存短暂陈旧时泄露到公有路径。
230
- - 验收断言:筛选一条有头像的系统用户,页面中 `/tenant_demo/avatar/` 的直接公有请求数必须为 0,私有代理图片 `naturalWidth > 0`,并同时验证无头像占位图不报错。
231
-
232
- 定制移动端项目的 Hero、Banner、音频、视频、字体等大资源也应优先上传到目标租户公有 HDFS,再通过 FileServer/CDN 引用;小型导航图标和离线关键素材才保留在主包。上传前可适度压缩,但必须在多尺寸截图或试听/试播中确认质量,禁止以明显失真换取包体扫描通过。完整移动端规则见 `microi-uniapp-frontend/SKILL.md`。
233
-
234
- 后台 `ImgUpload` 字段通常保存相对路径或 JSON:接口返回给移动端前先解析出 `Path`,再按公私有场景转换 URL:
235
-
236
- ```javascript
237
- function publicFileUrl(path) {
238
- if (!path) return '';
239
- if (/^https?:/i.test(path)) return path;
240
- return String(V8.SysConfig.FileServer || '').replace(/\/+$/, '') + '/' + String(path).replace(/^\/+/, '');
241
- }
242
- ```
243
-
244
- ### 私有桶临时 URL
245
-
246
- ```javascript
247
- var url = V8.Method.GetPrivateFileUrl({
248
- FilePathName: '/private/contract/2024/abc.pdf',
249
- OsClient: V8.OsClient, // 可选,默认当前
250
- Expires: 600 // 可选,过期秒数
251
- });
252
- // 后端审计代理 URL,过期不可访问;真实对象存储签名 URL 不会返回前端
253
- ```
254
-
255
- - 普通客户端调用 `/api/HDFS/GetPrivateFileUrl` 时,不能只提交 `FilePathName`,必须同时提交 `FormEngineKey`、`FormDataId`、`FieldId`、`SysMenuId`。服务端校验菜单、菜单绑定表、记录数据范围、字段归属以及字段值确实引用该路径后,才签发临时票据。
256
- - `FieldId` 必须属于目标表,且组件为 `FileUpload` 或 `ImgUpload`;`SysMenuId` 必须是当前用户真实拥有、并绑定目标表的菜单。
257
- - 普通用户禁止通过该入口直接取得私有文件 `Byte` / `Stream`。签发失败时不能回退裸路径、真实对象存储签名地址或公有 URL。
258
- - 私有文件访问必须经过后端短期票据代理:签发链接时记录当前登录用户,实际 `GET/HEAD` 打开或下载时再记录一次访问行为;支持 `Range` 流式响应,并对同一次分片请求做短时去重,不能把文件完整读入内存。
259
- - 审计代理由平台后端回源对象存储,必须使用服务端内网端点生成上游地址,不能先生成公网 MinIO 签名地址再让后端绕公网回源。否则同一对象经内网上传成功后,可能在公网端点表现为 404。
260
- - 备份包、安装包、导出包等重要大文件不能只信任 `PutObject` 成功响应;必须在写入后通过同一私有桶和内网端点执行 `ObjectExist` 回读(可行时再核对大小或 SHA-256),通过后才能把业务记录标记为完成。
261
- - 平台任务若绕过 `V8.Method.Upload` 直接使用底层 `PutObject`,必须保证写入对象键与后续 `V8.Method.GetPrivateFileUrl` 的租户前缀规则一致。像 `/database-backups/` 这种服务端保留目录只能做严格白名单规范化,禁止对普通租户文件泛化去除 `/{OsClient}/` 隔离前缀。
262
- - 下载验收至少对新签发地址执行一次 `Range: bytes=0-0`,断言返回 `200/206`、内容长度大于 0 且不是 JSON 错误;完整交付再核对下载字节数或 SHA-256。若产品要求保留当前业务页,应在新浏览上下文打开代理地址,并在浏览器拦截弹窗时给出品牌化反馈。
263
- - 用户把私有链接转发给别人后,接收者没有有效登录身份时按“匿名访问”记录,禁止根据签发人猜测实际访问人;票据仍按原有效期失效。
264
- - 代理创建或包装失败时必须失败关闭,不得退回未经审计的真实签名 URL;行为日志中也禁止保存真实签名 URL、Token、Authorization 或存储密钥。
265
- - `Limit:false` 的公有文件允许通过 CDN/公有桶直接访问,不要求记录用户行为日志,也不要为了审计强制改走私有代理。
266
-
267
- ## 接口直接响应文件(下载/导出)
268
-
269
- 接口引擎需要在配置中开启【**响应文件**】选项,然后返回特殊结构:
270
-
271
- 平台后端会统一处理响应文件:图片和 PDF 自动 `inline` 在浏览器中打开,其它类型默认下载;PDF、PNG、JPEG、GIF、WebP、AVIF、BMP、TIFF、ICO、SVG 等常见可预览类型会自动校验文件头。V8 代码不要手写复杂的文件头判断,只需要保证 `ContentType` 与真实文件内容一致。
272
-
273
- ```javascript
274
- // 模板:导出 Excel
275
- var excelResult = V8.Office.ExportExcel({...});
276
- return {
277
- Code: 1,
278
- Data: {
279
- FileName: 'export_' + DateNow('yyyyMMdd_HHmmss') + '.xls',
280
- ContentType: 'application/vnd.ms-excel',
281
- FileByteBase64: System.Convert.ToBase64String(excelResult.Data)
282
- }
283
- };
284
-
285
- // 模板:返回图片
286
- var resp = V8.Http.GetResponse({ Url: 'https://example.com/img.png' });
287
- return {
288
- Code: 1,
289
- Data: {
290
- FileName: 'img.png',
291
- ContentType: 'image/png',
292
- FileByteBase64: System.Convert.ToBase64String(resp.RawBytes)
293
- }
294
- };
295
-
296
- // 模板:返回 PDF(浏览器直接预览;后端自动校验 %PDF- 文件头)
297
- var pdfResp = V8.Http.GetResponse({ Url: 'https://example.com/report.pdf' });
298
- return {
299
- Code: 1,
300
- Data: {
301
- FileName: 'report.pdf',
302
- ContentType: 'application/pdf',
303
- FileByteBase64: System.Convert.ToBase64String(pdfResp.RawBytes)
304
- }
305
- };
306
- ```
307
-
308
- 常用 ContentType:
309
- - `application/vnd.ms-excel` / `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
310
- - `application/pdf`
311
- - `image/png` / `image/jpeg`
312
- - `application/octet-stream`(通用二进制)
313
-
314
- 注意:如果远程系统返回的是错误页、登录页、业务容器格式(例如金蝶 PLM 电子仓 `KD_C_PLM`、或其它文件头不是 `%PDF-` 的伪 PDF),不要在 V8 里伪装成 PDF。后端会返回 JSON 错误,包含 `ExpectedFirstAscii`、`ActualFirstAscii`、`ActualFirstHex`、`Length`,按这些信息排查上游下载接口。
315
-
131
+ <!-- /microi-progressive:chunk -->
132
+ <!-- microi-progressive:chunk id=v8-file-upload-003 sha256=5765949bee76ce3ccd05503174ff7601135f1d330f8c11a2bf5f268cdeb74133 -->
316
133
  ## 跨平台文件同步登录会话
317
134
 
318
135
  文件柜、文件同步等需要连接另一套 Microi API 的工具,必须把远程平台视为独立登录会话:
@@ -325,6 +142,8 @@ return {
325
142
  - 远程目标登录后必须调用文件柜能力探针(如 `mci_file_sync_capability`)检查同步协议版本。接口不存在、返回 404/非标准结果或协议版本过低时,提示目标平台更新【文件柜】应用,不得继续同步。
326
143
  - 验收至少覆盖:登录成功显示身份、退出后 Token 清空、历史连接一键重连、删除连接、密文落库、服务重启后仍可解密、目标平台缺少能力接口时的升级提示。
327
144
 
145
+ <!-- /microi-progressive:chunk -->
146
+ <!-- microi-progressive:chunk id=v8-file-upload-004 sha256=176fe6d254d2cff9d3dcb4b8620888243d3881704ca1432bbff023c9c553cb74 -->
328
147
  ## 下载远程文件并存到 HDFS
329
148
 
330
149
  ```javascript
@@ -350,168 +169,11 @@ return upResult;
350
169
 
351
170
  移动端公开图片优先使用 `.jpg` / `.png` / `.webp`。如果上传 `.svg`,必须确认对象存储返回正确 `Content-Type: image/svg+xml`,否则浏览器可能拦截或不渲染。
352
171
 
353
- ## 通过 URL 列表批量下载并入库
172
+ <!-- /microi-progressive:chunk -->
173
+ ## 详细参考路由(渐进披露)
354
174
 
355
- ```javascript
356
- var urls = V8.Param.urls; // ['https://...', 'https://...']
357
- var savedPaths = [];
358
- for (var i = 0; i < urls.length; i++) {
359
- try {
360
- var resp = V8.Http.GetResponse({ Url: urls[i], Timeout: 30 });
361
- if (resp.StatusCode !== 200) continue;
175
+ 仅在当前任务涉及对应主题时读取;下列文件合计保留了原 SKILL.md 的全部详细知识。
362
176
 
363
- var base64 = System.Convert.ToBase64String(resp.RawBytes);
364
- var fileName = V8.Method.NewGuid() + '.bin';
365
- var up = V8.Method.Upload({
366
- FilesByteBase64: { [fileName]: base64 },
367
- Limit: false,
368
- Path: '/batch-import/' + DateNow('yyyy-MM-dd'),
369
- OsClient: V8.OsClient
370
- });
371
- if (up.Code === 1) savedPaths.push(up.Data[0].Path);
372
- } catch (ex) {
373
- console.error('第' + (i + 1) + '个下载失败:' + ex.message);
374
- }
375
- }
376
- return { Code: 1, Data: savedPaths };
377
- ```
378
-
379
- ## Office 文件在线编辑版本号规则
380
-
381
- 当文件上传控件开启【Office 在线预览】、【允许在线编辑】和【开启 Office 文件版本号】时,前后端必须遵循统一版本规则:
382
-
383
- - 新上传的 Office 文件(`pdf/doc/docx/xls/xlsx/ppt/pptx`)要立即写入初始版本 `v1.0.0`,字段 JSON 的 `Path` 指向该原始文件,`Version` 为 `v1.0.0`,`Versions[0]` 保存同一份原始文件路径。
384
- - 用户进入 OnlyOffice 在线编辑页后,每次手动点击【保存文件】才生成新版本;第一次保存生成 `v1.0.1`,之后依次生成 `v1.0.2`、`v1.0.3`。
385
- - 未开启版本号时,保存文件直接覆盖当前 `Path` 对应的 HDFS/OSS 源文件。
386
- - 开启版本号时,保存文件必须生成带版本号后缀的新文件,例如 `contract_v1.0.1.docx`,字段 JSON 的 `Path` 指向最新版本,`Versions` 保留历史版本路径。
387
- - 在线 Office 路由和文件上传字段都要能读取 `Versions`,用于右上角切换历史版本预览/编辑。
388
-
389
- ### OnlyOffice 服务端取文件与匿名预览规则
390
-
391
- - OnlyOffice 文档服务器会在服务端再次下载文件。浏览器可以下载但 OnlyOffice 提示“下载失败”时,优先检查生成地址是否为 `localhost/127.0.0.1/内网域名`。
392
- - OnlyOffice 可能先对文档地址发起 `HEAD` 探测。响应文件接口除了 `GET 200`,还必须让 `HEAD` 返回相同的 `Content-Type/Content-Length/Content-Disposition`,不能返回 `405`。
393
- - 私有文件在线预览调用 `GetPrivateFileUrl` 或 `/api/HDFS/GetPrivateFileUrl` 时传 `ForOfficePreview:true`。审计代理应优先使用租户系统配置的公网 `ApiBase`,但仍把真实对象存储签名地址保存在共享 Redis ticket 中,禁止直接返回真实签名地址。
394
- - `/online-office` 可以匿名访问。公有存储模式只允许当前 `OsClient` 目录下的 `filePathName`;接口模式通过 `fileUrl` 接收当前平台正式 `ApiBase`,或由同端口本地后端读取的 loopback `/apiengine/...` 响应文件地址,并要求 URL 显式携带当前 `OsClient`。两种模式都拒绝跨租户、路径穿越和任意第三方 URL;`isPrivate=1` 必须登录。
395
- - 匿名接口引擎预览不要求 V8 代码先上传 HDFS:接口开启【响应文件】和【允许匿名】后,完整地址 URL 编码传给 `fileUrl`,同时传 `fileName/fileType`。页面通过匿名安全中转让当前后端限域读取源文件,并以确定性路径缓存到当前租户公有对象存储;OnlyOffice 只接收公网 `FileServer` 地址。loopback 仅允许同端口本地后端访问,禁止开放任意 URL 代理。
396
- - `canEdit` 只是前端请求参数,不是权限。最终编辑条件必须是“有效登录态 && canEdit=true”;匿名始终只读,不能因 URL 参数放开编辑。
397
- - 匿名预览页隐藏左侧菜单、顶部导航和页签;已登录用户保持原系统布局。
398
- - 匿名导出响应接口应配置频率限制或保证生成逻辑足够轻量,不能让单个公网 URL 无界消耗 CPU/内存;如业务仍需要落盘缓存,缓存事实必须进入共享 Redis/HDFS,不能用进程内变量。
399
-
400
- 字段 JSON 示例:
401
-
402
- ```json
403
- {
404
- "Name": "contract.docx",
405
- "Path": "/tenant_demo/file/20260622/contract_v1.0.1.docx",
406
- "Version": "v1.0.1",
407
- "Versions": [
408
- { "Version": "v1.0.0", "Name": "contract.docx", "Path": "/tenant_demo/file/20260622/contract.docx", "IsLatest": false },
409
- { "Version": "v1.0.1", "Name": "contract_v1.0.1.docx", "Path": "/tenant_demo/file/20260622/contract_v1.0.1.docx", "IsLatest": true }
410
- ]
411
- }
412
- ```
413
-
414
- ## ImgUpload / FileUpload 字段值兼容规则
415
-
416
- `ImgUpload` 不能假设只是一种值结构。PC 表单、移动端、旧数据、单图/多图、公开/私有桶会混合出现以下格式:
417
-
418
- | 场景 | 可能的值 |
419
- |------|----------|
420
- | 空值/占位 | `''`、`null`、`undefined`、`'[]'`、`'null'`、`'正在上传中...'` |
421
- | 旧单图 | `'/upload/xxx/a.png'`、`'https://cdn/a.png'` |
422
- | 新单图 | `{ Path, Name, Size, Id, State }` 或 JSON 字符串 `'{"Path":"..."}'` |
423
- | 多图 | `[{ Path, Name, Id, State }]` 或 JSON 字符串 `'[{"Path":"..."}]'` |
424
- | 其它兼容字段 | `Path`、`FilePathName`、`FullPath`、`Url`、`url`、`src` |
425
-
426
- 任何端(PC、uni-app、H5、小程序)渲染图片前都必须先做“归一化 -> 取 Path -> 转最终 URL”,不要直接 `JSON.parse` 后只处理数组,也不要直接把字段值拼到 `FileServer`。
427
-
428
- 推荐归一化:
429
-
430
- ```javascript
431
- function normalizeUploadValue(value) {
432
- if (value == null || value === '' || value === 'undefined' || value === 'null') return [];
433
- if (value === '正在上传中...' || value === '[]' || value === '[ ]') return [];
434
-
435
- var raw = value;
436
- if (typeof raw === 'string') {
437
- var s = raw.trim();
438
- if ((s.indexOf('{') === 0 || s.indexOf('[') === 0)) {
439
- try { raw = JSON.parse(s); } catch (e) { raw = s; }
440
- } else {
441
- raw = s;
442
- }
443
- }
444
-
445
- if (Array.isArray(raw)) {
446
- return raw.map(normalizeUploadItem).filter(function (it) { return !!it.Path; });
447
- }
448
-
449
- var one = normalizeUploadItem(raw);
450
- return one.Path ? [one] : [];
451
- }
452
-
453
- function normalizeUploadItem(item) {
454
- if (!item) return {};
455
- if (typeof item === 'string') {
456
- return { Path: item, Name: item.split('/').pop() || item, State: 1 };
457
- }
458
- if (typeof item === 'object') {
459
- var path = item.Path || item.FilePathName || item.FullPath || item.Url || item.url || item.src || '';
460
- return {
461
- Id: item.Id || item.id || '',
462
- Name: item.Name || item.FileName || item.name || (path ? String(path).split('/').pop() : ''),
463
- Size: item.Size || item.size || '',
464
- CreateTime: item.CreateTime || item.createTime || '',
465
- State: item.State == null ? 1 : item.State,
466
- Path: path
467
- };
468
- }
469
- return {};
470
- }
471
- ```
472
-
473
- 公开图片 URL 解析原则与 `Microi.Client/src/utils/diy.common.js` 的 `GetServerPath` 一致:
474
-
475
- ```javascript
476
- function publicUploadUrl(path) {
477
- if (!path) return '';
478
- var s = String(path).trim();
479
- if (!s || s === '正在上传中...') return '';
480
- if (s.indexOf('.') === 0) return s; // ./static/img/loading.gif 等本地静态资源
481
- if (/^(https?:|data:|blob:)/i.test(s)) return s; // 已经是最终 URL
482
- if (s.indexOf('{') === 0 || s.indexOf('[') === 0) {
483
- var list = normalizeUploadValue(s);
484
- s = list.length ? list[0].Path : '';
485
- }
486
- if (!s) return '';
487
- return String(V8.SysConfig.FileServer || '').replace(/\/+$/, '') + '/' + s.replace(/^\/+/, '');
488
- }
489
- ```
490
-
491
- 私有桶(`Limit === true`)不要拼 `FileServer`,必须把归一化后的 `Path` 传给 `V8.Method.GetPrivateFileUrl({ FilePathName: path })` 或后端签名接口换临时 URL。
492
-
493
- ## 安全注意
494
-
495
- - ❌ 不要让前端任意指定 `Path`(路径穿越风险),只允许后端固定路径
496
- - ❌ 不要不校验文件类型 / 大小:根据 ContentType + 后缀双重校验
497
- - ❌ 不要把持有 Token 当成私有文件授权;普通用户必须证明菜单、记录和字段引用关系
498
- - ❌ 不要向普通角色开放文件列表、移动、重命名、删除、覆盖等管理接口;这些接口仅限 `Level >= 9999`
499
- - ❌ 不要开启 UEditor `catchimage` 远程抓图;默认关闭,确需采集时另建带域名白名单、DNS/IP 校验、禁止跳转、超时和响应上限的受控接口
500
- - ❌ 敏感文件(合同、身份证)必须用私有桶 `Limit: true`
501
- - ✅ 公有桶 URL 可缓存到前端,私有桶临时 URL 每次重新生成
502
- - ✅ 删除数据时同步清理 HDFS 文件(避免存储泄漏)
503
- - ✅ Excel/PDF 等导出文件通过【响应文件】配置返回,不要拼接到 JSON 数据里
504
-
505
- ### 安全升级兼容
506
-
507
- - 旧页面如果只传 `FilePathName` 获取私有地址,升级后普通帐号会失败;必须补齐 `FormEngineKey`、`FormDataId`、`FieldId`、`SysMenuId`,不能改回匿名或放开管理权限。
508
- - 旧自定义上传若依赖普通用户设置 `Limit:false` 或任意多级 `Path`,应改成私有上传;公开资源改走受控发布流程。
509
- - 历史公有文件不会自动变成私有文件。迁移时先复制对象、验证私有读取,再停止旧公有访问;数据库继续保存租户内相对路径,不能持久化临时 URL。
510
- - 上线验收至少覆盖:普通角色跨菜单/跨记录/跨字段读取被拒绝、单文件/单请求/数量限制、帐号与租户配额、Redis 故障失败关闭、多节点并发、公有匿名 `200`、私有匿名 `403`、授权私有访问 `200`。
511
-
512
- ### 复盘:ZIP 发布端与安装端 SHA256 口径不一致
513
-
514
- - 触发场景:应用包已成功生成 ZIP 和摘要,但安装端下载 ZIP 后调用不存在的哈希辅助函数,或尝试通过当前 V8 环境不可用的 `.NET SHA256.Create()` 校验,导致安装中断。
515
- - 根因:发布端实际使用 `V8.EncryptHelper.Sha256Hex(FileByteBase64)`,安装端却按原始字节设计了另一套实现,函数名称、输入数据和运行时能力均未对齐。
516
- - 通用规则:文件摘要必须在包清单中记录算法和输入口径;当前应用 ZIP 统一使用 `SHA256-Base64Text`,发布端与安装端都对同一份 Base64 文本调用 `V8.EncryptHelper.Sha256Hex`。禁止仅凭函数名推测算法,也不要在未验证 V8 互操作能力时直接实例化 `.NET` 加密对象。
517
- - 自动化检查:生成同时包含源码 ZIP、编译 ZIP 的应用包,再从官方地址下载并安装;分别篡改 Base64 文本和摘要,正常包应安装成功,两个篡改包都必须在解压前被拒绝。
177
+ - [references/progressive-01-公有桶-vs-私有桶.md](references/progressive-01-公有桶-vs-私有桶.md):公有桶 vs 私有桶;接口直接响应文件(下载/导出);通过 URL 列表批量下载并入库
178
+ - [references/progressive-02-office-文件在线编辑版本号规则.md](references/progressive-02-office-文件在线编辑版本号规则.md):Office 文件在线编辑版本号规则;ImgUpload / FileUpload 字段值兼容规则;安全注意
179
+ <!-- microi-progressive:end -->