@lark-base-open/base-database-cli 1.1.1 → 1.3.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 (199) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/LICENSE +6 -0
  3. package/README.md +47 -27
  4. package/dist/ai-functions.d.ts +53 -0
  5. package/dist/ai-functions.d.ts.map +1 -0
  6. package/dist/ai-functions.js +436 -0
  7. package/dist/ai-functions.js.map +1 -0
  8. package/dist/archive.d.ts +21 -0
  9. package/dist/archive.d.ts.map +1 -1
  10. package/dist/archive.js +69 -10
  11. package/dist/archive.js.map +1 -1
  12. package/dist/auth.d.ts +5 -0
  13. package/dist/auth.d.ts.map +1 -1
  14. package/dist/auth.js +26 -3
  15. package/dist/auth.js.map +1 -1
  16. package/dist/check.d.ts +74 -0
  17. package/dist/check.d.ts.map +1 -0
  18. package/dist/check.js +283 -0
  19. package/dist/check.js.map +1 -0
  20. package/dist/dependency-policy.d.ts +10 -0
  21. package/dist/dependency-policy.d.ts.map +1 -0
  22. package/dist/dependency-policy.js +162 -0
  23. package/dist/dependency-policy.js.map +1 -0
  24. package/dist/deploy.d.ts +5 -0
  25. package/dist/deploy.d.ts.map +1 -1
  26. package/dist/deploy.js +141 -176
  27. package/dist/deploy.js.map +1 -1
  28. package/dist/environment-variables.d.ts +52 -0
  29. package/dist/environment-variables.d.ts.map +1 -0
  30. package/dist/environment-variables.js +563 -0
  31. package/dist/environment-variables.js.map +1 -0
  32. package/dist/environment.d.ts +1 -1
  33. package/dist/environment.js +1 -1
  34. package/dist/environment.js.map +1 -1
  35. package/dist/function-input-types.d.ts +10 -0
  36. package/dist/function-input-types.d.ts.map +1 -0
  37. package/dist/function-input-types.js +160 -0
  38. package/dist/function-input-types.js.map +1 -0
  39. package/dist/function-schema.d.ts.map +1 -1
  40. package/dist/function-schema.js +89 -36
  41. package/dist/function-schema.js.map +1 -1
  42. package/dist/init-field-retry.d.ts +17 -0
  43. package/dist/init-field-retry.d.ts.map +1 -0
  44. package/dist/init-field-retry.js +127 -0
  45. package/dist/init-field-retry.js.map +1 -0
  46. package/dist/init-journal.d.ts +98 -0
  47. package/dist/init-journal.d.ts.map +1 -0
  48. package/dist/init-journal.js +492 -0
  49. package/dist/init-journal.js.map +1 -0
  50. package/dist/init-schema.d.ts +8 -0
  51. package/dist/init-schema.d.ts.map +1 -0
  52. package/dist/init-schema.js +423 -0
  53. package/dist/init-schema.js.map +1 -0
  54. package/dist/init.d.ts +15 -1
  55. package/dist/init.d.ts.map +1 -1
  56. package/dist/init.js +884 -261
  57. package/dist/init.js.map +1 -1
  58. package/dist/lark-cli-error.d.ts +47 -0
  59. package/dist/lark-cli-error.d.ts.map +1 -0
  60. package/dist/lark-cli-error.js +201 -0
  61. package/dist/lark-cli-error.js.map +1 -0
  62. package/dist/lark-cli.d.ts +1 -1
  63. package/dist/lark-cli.d.ts.map +1 -1
  64. package/dist/lark-cli.js +78 -18
  65. package/dist/lark-cli.js.map +1 -1
  66. package/dist/mutation-schema.d.ts +146 -0
  67. package/dist/mutation-schema.d.ts.map +1 -0
  68. package/dist/mutation-schema.js +153 -0
  69. package/dist/mutation-schema.js.map +1 -0
  70. package/dist/mutation.d.ts +10 -0
  71. package/dist/mutation.d.ts.map +1 -0
  72. package/dist/mutation.js +131 -0
  73. package/dist/mutation.js.map +1 -0
  74. package/dist/npm.d.ts +1 -0
  75. package/dist/npm.d.ts.map +1 -1
  76. package/dist/npm.js +2 -2
  77. package/dist/npm.js.map +1 -1
  78. package/dist/preview-receipt.d.ts.map +1 -1
  79. package/dist/preview-receipt.js +15 -5
  80. package/dist/preview-receipt.js.map +1 -1
  81. package/dist/process.d.ts +3 -1
  82. package/dist/process.d.ts.map +1 -1
  83. package/dist/process.js +16 -4
  84. package/dist/process.js.map +1 -1
  85. package/dist/program.d.ts.map +1 -1
  86. package/dist/program.js +246 -42
  87. package/dist/program.js.map +1 -1
  88. package/dist/project-build.d.ts +25 -0
  89. package/dist/project-build.d.ts.map +1 -0
  90. package/dist/project-build.js +229 -0
  91. package/dist/project-build.js.map +1 -0
  92. package/dist/project-context.d.ts +344 -0
  93. package/dist/project-context.d.ts.map +1 -0
  94. package/dist/project-context.js +485 -0
  95. package/dist/project-context.js.map +1 -0
  96. package/dist/project-layout.d.ts +5 -0
  97. package/dist/project-layout.d.ts.map +1 -0
  98. package/dist/project-layout.js +24 -0
  99. package/dist/project-layout.js.map +1 -0
  100. package/dist/public-sql-error.d.ts +25 -0
  101. package/dist/public-sql-error.d.ts.map +1 -0
  102. package/dist/public-sql-error.js +65 -0
  103. package/dist/public-sql-error.js.map +1 -0
  104. package/dist/pull.d.ts +1 -0
  105. package/dist/pull.d.ts.map +1 -1
  106. package/dist/pull.js +67 -15
  107. package/dist/pull.js.map +1 -1
  108. package/dist/site-readme.d.ts +3 -0
  109. package/dist/site-readme.d.ts.map +1 -0
  110. package/dist/site-readme.js +83 -0
  111. package/dist/site-readme.js.map +1 -0
  112. package/dist/workspace-fingerprint.d.ts +21 -1
  113. package/dist/workspace-fingerprint.d.ts.map +1 -1
  114. package/dist/workspace-fingerprint.js +81 -2
  115. package/dist/workspace-fingerprint.js.map +1 -1
  116. package/package.json +2 -1
  117. package/skills/lark-base-database/SKILL.md +86 -52
  118. package/skills/lark-base-database/references/ai-function.md +479 -0
  119. package/skills/lark-base-database/references/base-capability-routing.md +7 -7
  120. package/skills/lark-base-database/references/base-sql-errors.generated.md +403 -0
  121. package/skills/lark-base-database/references/database-function-limitations.md +29 -0
  122. package/skills/lark-base-database/references/database-function.md +323 -0
  123. package/skills/lark-base-database/references/development.md +166 -33
  124. package/skills/lark-base-database/references/environment-variables.md +55 -0
  125. package/skills/lark-base-database/references/faas.md +46 -53
  126. package/skills/lark-base-database/references/file-transfer.md +25 -25
  127. package/skills/lark-base-database/references/frontend-design-guide.md +151 -65
  128. package/skills/lark-base-database/references/mutations.md +295 -0
  129. package/skills/lark-base-database/references/notifications.md +9 -9
  130. package/skills/lark-base-database/references/permission-design.md +24 -24
  131. package/skills/lark-base-database/references/release.md +57 -30
  132. package/skills/lark-base-database/references/style-guide.md +10 -67
  133. package/skills/lark-base-database/references/verification.md +19 -13
  134. package/skills/lark-base-database/references/workspace.md +57 -17
  135. package/templates/database-starter/README.md +34 -4
  136. package/templates/database-starter/database-functions/README.md +8 -0
  137. package/templates/database-starter/gitignore +7 -0
  138. package/templates/database-starter/mutations/README.md +19 -0
  139. package/templates/database-starter/page/README.md +25 -19
  140. package/templates/database-starter/page/package-lock.json +8 -16
  141. package/templates/database-starter/page/package.json +2 -3
  142. package/templates/database-starter/page/src/App.tsx +23 -3
  143. package/templates/database-starter/page/src/components/UserSelectorEditor/index.tsx +32 -4
  144. package/templates/database-starter/page/src/components/UserSelectorPanel/index.tsx +104 -34
  145. package/templates/database-starter/page/src/components/UserSelectorPanel/user-search.test.ts +55 -11
  146. package/templates/database-starter/page/src/components/UserSelectorPanel/user-search.ts +68 -25
  147. package/templates/database-starter/page/src/components/database-runtime-ready.tsx +1 -1
  148. package/templates/database-starter/page/src/components/database-user-menu/index.tsx +4 -7
  149. package/templates/database-starter/page/src/components/feedback/page-state.tsx +40 -5
  150. package/templates/database-starter/page/src/components/floating-button/assets/edit-active.svg +3 -0
  151. package/templates/database-starter/page/src/components/floating-button/assets/edit-default.svg +3 -0
  152. package/templates/database-starter/page/src/components/floating-button/assets/toast-close.svg +3 -0
  153. package/templates/database-starter/page/src/components/floating-button/assets/toast-info.svg +5 -0
  154. package/templates/database-starter/page/src/components/floating-button/assets/tooltip-caret.svg +3 -0
  155. package/templates/database-starter/page/src/components/floating-button/index.tsx +193 -113
  156. package/templates/database-starter/page/src/components/floating-button/utils/project-meta.test.ts +107 -37
  157. package/templates/database-starter/page/src/components/floating-button/utils/project-meta.ts +13 -50
  158. package/templates/database-starter/page/src/components/ui-language.test.tsx +101 -0
  159. package/templates/database-starter/page/src/examples/ai-function/ImageTaskOperation.tsx +202 -0
  160. package/templates/database-starter/page/src/examples/ai-function/README.md +14 -0
  161. package/templates/database-starter/page/src/examples/ai-function/TextStreamOperation.tsx +184 -0
  162. package/templates/database-starter/page/src/examples/ai-function/ai-copy.ts +173 -0
  163. package/templates/database-starter/page/src/examples/ai-function/ai-delta.test.ts +30 -0
  164. package/templates/database-starter/page/src/examples/ai-function/ai-delta.ts +26 -0
  165. package/templates/database-starter/page/src/examples/ai-function/ai-language.test.tsx +86 -0
  166. package/templates/database-starter/page/src/examples/ai-function/ai-media-panel.test.ts +201 -0
  167. package/templates/database-starter/page/src/examples/ai-function/ai-media-panel.tsx +382 -0
  168. package/templates/database-starter/page/src/lib/attachment-image.tsx +144 -0
  169. package/templates/database-starter/page/src/lib/database-function-inputs.generated.ts +4 -0
  170. package/templates/database-starter/page/src/lib/database-runtime-attachment.test.ts +180 -76
  171. package/templates/database-starter/page/src/lib/database-runtime.test.ts +130 -10
  172. package/templates/database-starter/page/src/lib/database-runtime.ts +484 -51
  173. package/templates/database-starter/page/src/lib/date-time.ts +61 -0
  174. package/templates/database-starter/page/src/lib/ui-language.ts +86 -0
  175. package/templates/database-starter/page/src/main.tsx +1 -1
  176. package/templates/database-starter/page/tsconfig.json +2 -2
  177. package/templates/database-starter/page/vite.config.ts +1 -2
  178. package/templates/database-starter/prettierignore +1 -1
  179. package/templates/database-starter/server-functions/README.md +2 -2
  180. package/templates/database-starter/server-functions/package-lock.json +4 -4
  181. package/templates/database-starter/server-functions/package.json +1 -1
  182. package/dist/agent-guide.d.ts +0 -19
  183. package/dist/agent-guide.d.ts.map +0 -1
  184. package/dist/agent-guide.js +0 -31
  185. package/dist/agent-guide.js.map +0 -1
  186. package/dist/database-skill.d.ts +0 -24
  187. package/dist/database-skill.d.ts.map +0 -1
  188. package/dist/database-skill.js +0 -148
  189. package/dist/database-skill.js.map +0 -1
  190. package/skills/lark-base-database/references/base-sql-unsupported.md +0 -42
  191. package/skills/lark-base-database/references/database-capability-skill.md +0 -40
  192. package/skills/lark-base-database/references/sql-function.md +0 -289
  193. package/templates/database-capability/SKILL.md.tmpl +0 -58
  194. package/templates/database-starter/page/src/components/floating-button/chatbot-entry.test.ts +0 -23
  195. package/templates/database-starter/page/src/components/floating-button/chatbot-entry.tsx +0 -873
  196. package/templates/database-starter/page/src/components/floating-button/local-chat-panel.test.ts +0 -25
  197. package/templates/database-starter/page/src/components/floating-button/local-chat-panel.tsx +0 -197
  198. package/templates/database-starter/page/src/components/floating-button/utils/env.ts +0 -18
  199. package/templates/database-starter/sql/README.md +0 -8
@@ -0,0 +1,55 @@
1
+ # 第三方 Agent 环境变量
2
+
3
+ 本协议仅适用于外部 Agent 通过公开 CLI 配置 FaaS 环境变量。满足下述进入条件后,按[工程与环境](workspace.md)确认 CLI 入口和同一账号的 profile,再通过 `environment-variables --help` 核对子命令能力。旧版本缺少能力时报告版本限制,不调用底层 API 绕过。
4
+
5
+ ## 进入条件
6
+
7
+ 先检查 FaaS 源码与用户需求。仅在存在自定义环境变量引用,或用户明确要求查询、配置环境变量时进入本协议。两者都没有时,跳过环境变量命令与配置询问,按[发布与交付](release.md)继续;不要先调用 `list` 来判断是否需要环境变量。宿主、构建工具的环境变量和注释、字符串中的示例不构成 FaaS 配置需求。
8
+
9
+ 存在引用时,即使使用了代码回退值,也仍按本协议核对;接口 404 或查询失败不能当作“没有变量”而跳过。
10
+
11
+ ## 运行配置与边界
12
+
13
+ 环境变量是 Base Database FaaS 的运行配置,不是应用的业务数据或页面功能。值只注入发布后的 FaaS runtime,不注入 Agent 进程、Page 或构建阶段的环境。FaaS 仅用静态 `process.env.NAME` 或 `process.env['NAME']` 读取;CLI 按语法扫描 `server-functions/functions/`,忽略注释和字符串示例,动态下标、解构或无法静态确定名称的访问会阻止发布。
14
+
15
+ - `config`:非敏感配置,查询时明文返回。
16
+ - `secret`:API Key、Token 等敏感值,保存后只返回脱敏值。
17
+
18
+ 定义由 Preview 和 Prod 共享,两套环境的值独立配置。保存不发布;发布冻结目标环境的值并注入 runtime,旧运行版本保留原快照。不得将值写入源码、`base-database.jsonc`、`.env`、日志或其他工程文件,也不得用于 Page build。
19
+
20
+ Page 不得实现环境变量管理页、配置清单、变量调试页,或展示变量名、类型、Config 原值、Secret 原文或脱敏值。配置交互由第三方 Agent 的普通聊天和 CLI 承载。业务需要反馈第三方服务是否可用时,仅展示业务语义的派生状态;FaaS 只返回业务结果或最小派生状态,不返回任何 Secret 值。
21
+
22
+ ## 收集、配置与首次 Preview
23
+
24
+ 环境变量的 Value 属于用户配置,不属于 Agent 可生成的工程内容。只有用户在当前或此前聊天消息中明确给出的具体值,才允许保存;变量名、描述、页面期望文案、示例值和占位符不代表真实 Value。禁止生成、推断或代填任何测试值、默认值、随机值或看似可用的 API Key。
25
+
26
+ 满足上述进入条件的首次 Preview 使用以下流程;等待期间保留当前工程与会话,收到回复后从配置步骤继续,不重新 init 或 pull:
27
+
28
+ 1. 首次执行 `deploy` 前,一次性收集 FaaS 静态引用和用户明确要求的全部定义,确定名称、类型、客观描述及必填性。不得把 `deploy` 作为环境变量发现机制;尚不明确的信息只询问缺失项。
29
+ 2. 执行一次 `environment-variables list --target preview`,同名同类型时复用现有定义,保留当前描述和必填性,只声明缺失定义;不因 Agent 新生成的描述而覆盖已有元数据,不自动删除未引用变量。
30
+ 3. 保存用户已明确提供、且变量名与 Preview 目标对应关系明确的值。仍有缺失时一次性询问全部缺失必填变量的名称、类型、描述与对应值,并结束当前 Turn;不执行 `deploy`,不声称已经配置。
31
+ 4. 收到回复后保存明确对应的值,并执行一次 Preview list 核对。仍缺少值时只询问剩余项;全部必填值完整时自动继续首次 Preview 发布,不再要求用户回复“配置完成”或“继续”。
32
+ 5. 环境变量校验已通过但部署失败时,报告脱敏错误与可用 LogID,不重复询问值,不绕过 CLI 调用 `source_code`、`artifact` 或 `publish`。已取得 publish ID 的部署按[发布任务查询](verification.md#发布任务查询)恢复观察,不重复发起发布。
33
+ 6. Preview 成功后按[发布与交付](release.md)完成示例数据和通知收尾,再交付顶层 `baseAppUrl`、配置状态与业务摘要。普通交付不展示环境变量命令或内部排障过程。
34
+
35
+ ## CLI 写入与核对
36
+
37
+ 沿用已核实的本机 `base-database-cli`,无可用入口时按[工程与环境](workspace.md#公开-cli-版本预检)使用全限定包名回退;仅替换命令前缀,实际业务参数保持一致:
38
+
39
+ ```bash
40
+ base-database-cli environment-variables declare MAP_API_KEY \
41
+ --target preview \
42
+ --type secret \
43
+ --description '地图服务 API Key' \
44
+ --required
45
+
46
+ base-database-cli environment-variables set MAP_API_KEY \
47
+ --target preview \
48
+ --value-stdin
49
+ ```
50
+
51
+ 调用 `declare` 显式指定 `--target`、`--type`、`--description`,并在 `--required` 与 `--optional` 中选择一个;`set`、`clear` 显式指定目标环境。用户可以在普通聊天中提供 Config 或 Secret,必须通过 `--value-stdin` 的标准输入传入;使用执行工具的独立 stdin 输入通道,不把值嵌入命令文本、进程参数、临时文件或 shell 历史。CLI 在内存中通过 `lark-cli api --data -` 发送 JSON。当前执行工具没有独立 stdin 通道时说明限制,等待可用的安全输入通道,不用含值的 here-document 或 `echo` 命令替代。不得在回复、命令结果或后续消息中复述完整 Secret。
52
+
53
+ `declare` 只管理共享定义。同名元数据不同默认拒绝覆盖;只有用户明确要求修改已有描述或必填性时才更新,并先确认授权覆盖 Preview 与 Prod 的共同影响,再使用 `--force`。删除、重命名或类型变更前,说明对两套环境的定义与值的影响,并取得明确确认;类型变化会清空两套值,删除定义也会删除两套值,重命名不得擅自删除旧定义或代填新值。当前 CLI 不提供删除或重命名命令,缺少可用入口时报告限制。`set` 只更新目标环境已有定义的值;`clear` 清空该值但保留定义,两者都不触发发布。保存后用同一入口的 `environment-variables list --target <preview|prod>` 核对,Config 返回明文、Secret 返回脱敏值。
54
+
55
+ 普通更新保存后说明需要重新发布,按用户已有 Preview 发布授权执行;未授权时等待。Prod 值独立配置,Prod 仍发布本次已验证 Preview 制品,要求用户体验并明确授权,见[主流程授权约定](../SKILL.md#外部操作与授权)。不删除引用、硬编码值或将 Secret 改为 Config 绕过校验。
@@ -1,19 +1,21 @@
1
1
  # FaaS 与记录协议
2
2
 
3
- 实现服务端业务写入或诊断下游调用时读取。Page 调用方式见[Page 开发](development.md),查询类型与参数见[SQL Function](sql-function.md),权限判定见[权限设计](permission-design.md)。
3
+ 实现、维护或排查 FaaS 时读取;新写入的选型见[写入方式选择](mutations.md#写入方式选择)。Page 调用方式见[Page 开发](development.md),查询类型与参数见[Database Function](database-function.md),权限判定见[权限设计](permission-design.md)。
4
4
 
5
5
  ## 阅读路径
6
6
 
7
7
  - [FaaS 开发](#faas-开发):目录、handler 与 context
8
8
  - [远程调用与写入链路设计](#远程调用与写入链路设计):依赖、一致性与重试
9
9
  - [下游错误归一化](#下游错误归一化):业务结果与诊断
10
- - [应用记录 写入协议](#应用记录-写入协议):请求、响应与部分成功
10
+ - [应用记录写入协议](#应用记录写入协议):请求、响应与部分成功
11
11
  - [创建实现示例](#创建实现示例):固定操作示例
12
12
  - [Base 读写协议](#base-读写协议):字段格式与集合更新
13
13
 
14
14
  ## FaaS 开发
15
15
 
16
- 每个由 Page 主动发起的写入 operation 的目录:
16
+ 第三方 Agent 配置 FaaS 的凭证或环境相关配置时,先读取[环境变量协议](environment-variables.md)。值仅由 FaaS 静态 `process.env.NAME` 或 `process.env['NAME']` 读取,不进入 Page、源码、配置、日志或函数返回值。动态 `process.env[key]`、解构和其他无法静态确定变量名的访问会阻止部署。
17
+
18
+ 每个 FaaS 业务动作的目录:
17
19
 
18
20
  ```text
19
21
  server-functions/functions/<functionId>/
@@ -38,13 +40,13 @@ server-functions/functions/<functionId>/
38
40
  }
39
41
  ```
40
42
 
41
- `inputSchema` 是 Agent 调用该 Function 时 `params` 业务值的结构,不包含外层 `{"params": ...}`;FaaS Function 必须显式声明。CLI 会校验并上传该 Schema,发布后的能力发现接口据此返回可调用参数。只使用 JSON Schema 2020-12 的受限子集:`type`、`description`、`properties`、`required`、`additionalProperties`、`items`、`prefixItems`、`minItems`、`maxItems`、`enum`、`minimum`、`maximum`、`minLength`、`maxLength`;不使用 `$ref`、组合关键字、`pattern`、`format` 或未知关键字。Schema 最大 32 KiB、嵌套不超过 16 层、节点不超过 256 个。
43
+ `inputSchema` 是调用该 Function 时 `params` 业务值的结构,不包含外层 `{"params": ...}`;FaaS Function 必须显式声明。CLI 会校验并上传该 Schema。只使用 JSON Schema 2020-12 的受限子集:`type`、`description`、`properties`、`required`、`additionalProperties`、`items`、`prefixItems`、`minItems`、`maxItems`、`enum`、`minimum`、`maximum`、`minLength`、`maxLength`;不使用 `$ref`、组合关键字、`pattern`、`format` 或未知关键字。Schema 最大 32 KiB、嵌套不超过 16 层、节点不超过 256 个。
42
44
 
43
- SQL Function 的 `inputSchema` 不手写,由 CLI 根据 `meta.params` 的顺序和 `kind` 确定性生成固定长度数组 Schema;`TIMESTAMP` 与 `DURATION` 均明确为毫秒整数。
45
+ Database Function 的 `inputSchema` 不手写,由 CLI 根据 `meta.params` 的顺序和 `kind` 确定性生成固定长度数组 Schema;参数类型见 [查询参数协议](database-function.md#function-文件与参数)。
44
46
 
45
- 上传时 CLI 把 Schema 对象放入 `sourceCode` JSON 字符串:SQL 为 `{sql,meta,inputSchema}`,FaaS 为 `{inputSchema}`,不发送独立的 Function `inputSchema` 字段。FaaS 的可执行代码仍在源码包,`meta.json` 的写法不变;发现接口仍独立返回 `inputSchema` JSON 字符串。
47
+ FaaS 在 `meta.json` 中声明 `inputSchema`,在 `index.ts` 中实现 handler。部署时,CLI 自动校验并上传 Schema 和应用源码。
46
48
 
47
- loader 读取 HTTP `req.body.params`,把这个业务对象作为 handler 第一个参数 `rawParams`;第二个参数是 runtime context:
49
+ handler 第一个参数 `rawParams` 是调用方的 `params` 业务对象;第二个参数是 runtime context:
48
50
 
49
51
  ```ts
50
52
  interface FunctionContext {
@@ -90,33 +92,21 @@ function parseCreateTask(value: unknown): CreateTaskInput {
90
92
 
91
93
  ### 远程调用与写入链路设计
92
94
 
93
- 实现前先按设计结果确认一致性、部分成功、重试语义和远程调用依赖。以一次 Page/FaaS operation 为边界列出 SQL Function、`context.fetch` 和写入 OpenAPI;标记哪些输入在 operation 开始时已经确定、哪些必须等待前一步响应。默认使用满足业务语义的最少远程等待阶段:
95
+ 每个写入 operation 先确认成功条件、一致性要求、是否允许部分成功和重试边界,再选择调用方式:
94
96
 
97
+ - 需要事务、唯一约束、条件更新或原子 compare-and-set 才能保证正确性的 operation,在当前 Base 能力下标记为不支持,不使用多次远程请求模拟。只有用户明确同意改变后端架构时才采用其他存储;交付按[完成条件](../SKILL.md#完成条件)报告。
98
+ - 在满足权限、业务条件及一致性要求后,并发执行输入已确定且互不依赖的调用;后一步依赖前一步响应时串行。
95
99
  - 同表多条创建、更新或删除合并到一个 batch 请求,单批不超过 200 条。
96
- - 同一 operation 调用多个 SQL Function 或 FaaS Function 时,输入已确定、互不依赖,且并发不改变一致性或部分成功语义的调用尽量并发;只有真实响应依赖才串行。
97
- - 多个无副作用读取或请求的参数已经确定且互不依赖时,先启动全部 Promise,再在共同消费结果处等待;存在真实响应依赖时才串行。
98
100
  - 原始 Promise 仍可能 reject 且需要知道每一路结果时使用 `Promise.allSettled`;helper 已把异常归一化为结构化结果时可以使用 `Promise.all`。
99
- - 写前 SQL 只用于服务端必须确认的权限、关键状态或其他可信数据;写后 SQL 回读用于验收或明确要求的业务校验,不作为每次生产写入的默认步骤。
100
- - 页面状态仅可用于允许弱一致性的非安全敏感计算。用户身份、权限、租户隔离、支付、库存、额度等约束不得信任页面传值。
101
- - 多路写入返回值区分全部成功、部分成功和全部失败,并携带已取得的 record ID 与安全错误信息。非幂等创建结果未知时不自动整体重试。
102
- - 需要事务、唯一约束、条件更新或原子 compare-and-set 才能保证正确性的 operation,在当前 Base 能力下标记为不支持,不使用多次远程请求模拟。
103
-
104
- 无依赖的多路写入可以采用:
105
-
106
- ```ts
107
- const writes = await Promise.allSettled([
108
- updatePrimaryRecord(context, input),
109
- createAuditRecord(context, input),
110
- ])
111
-
112
- return summarizeWrites(writes)
113
- ```
101
+ - 写前调用 Database Function 只用于服务端必须确认的权限、关键状态或其他可信数据;写后 Database Function 回读用于验收或明确要求的业务校验,不作为每次生产写入的默认步骤。
102
+ - 用户身份、权限、租户隔离、支付、库存、额度等关键约束必须由服务端可信数据确认,不得信任页面传值。
103
+ - 多路写入返回值区分全部成功、部分成功和全部失败,并携带已取得的 record ID 与安全错误信息。非幂等创建结果未知时不自动整体重试;只有底层存在可靠幂等原语时才承诺严格幂等。
114
104
 
115
105
  性能敏感的 operation 记录总耗时和各远程调用耗时;只使用成功业务请求评价写入性能,鉴权失败、参数失败和平台凭证缺失只用于诊断。日志和返回值不得包含 token、cookie 或请求凭证。
116
106
 
117
107
  ### 下游错误归一化
118
108
 
119
- FaaS 调用 Base OpenAPI 或其他 应用 Function 时,把当前 operation 的业务结果与下游诊断分开:
109
+ FaaS 调用 Base OpenAPI 或其他应用 Function 时,把当前 operation 的业务结果与下游诊断分开:
120
110
 
121
111
  - 顶层 `code` 和 `msg` 表达稳定、面向调用方的业务语义,不直接使用上游错误码,也不把技术细节拼进 `msg`。
122
112
  - 成功或部分成功的业务结果保留在 `data`;仅在失败或部分成功时,把失败步骤放入 `data.errors`。
@@ -169,7 +159,7 @@ FaaS 使用 `context.fetch` 调用固定的批量写入路由;只使用线上
169
159
  |---|---|
170
160
  | Online | `https://open.feishu.cn` |
171
161
 
172
- #### 应用记录 写入协议
162
+ #### 应用记录写入协议
173
163
 
174
164
  FaaS 只使用以下五个固定路由,均为 `POST`,请求头为
175
165
  `Content-Type: application/json; charset=utf-8`:
@@ -183,10 +173,9 @@ POST /open-apis/bitable/v1/apps/:base_token/tables/:table_id/remove_attachments
183
173
  ```
184
174
 
185
175
  后两条是附件字段专用的增量路由(注意不在 `records/` 段下):请求只提交本次增删的
186
- `file_token`,服务端读取、合并后整格提交,保留读到的其它附件及宽高;不保证原子性或去重。目标环境必须已部署对应 FaaS runtime 和服务端能力,不能仅凭 Skill 存在就判定可用。什么时候必须用它们、什么时候仍可整格写,
187
- 见[文件传输](file-transfer.md)的「写单元格」。
176
+ `file_token`,服务端读取、合并后整格提交,保留读到的其它附件及宽高;不保证原子性或去重。目标环境必须已部署对应 FaaS runtime 和服务端能力,不能仅凭 Skill 存在就判定可用。何时使用增量路由或整格写入,见[文件传输](file-transfer.md#写单元格)。Mutation 的声明、参数和返回结构见[附件写入](mutations.md#附件写入);这里的原始路由响应不能直接套用于 Page 调用 Mutation。
188
177
 
189
- 路径首个参数是 **Base token,不是 应用 appToken**:取 `catalog.json` 中该表的
178
+ 路径首个参数是 **Base token,不是应用 appToken**:取 `catalog.json` 中该表的
190
179
  `tables[].baseToken`,与 table ID 一起作为 Function 内的工程常量。应用 appToken 只用于
191
180
  `context.invokeFunction` 的 `projectId`,两者不要混用。
192
181
 
@@ -202,8 +191,9 @@ POST /open-apis/bitable/v1/apps/:base_token/tables/:table_id/remove_attachments
202
191
 
203
192
  五个请求体都是 strict JSON Schema:不接受表格中未列出的额外顶层字段。「每批 1~200 条
204
193
  记录」只适用于前三条 batch 路由;附件增量路由的限制是**一次操作的 `file_token` 总数不超过
205
- 50**;附件映射及每个 record-field 数组没有非空 Schema 约束。record ID 必须匹配
206
- `^rec[A-Za-z0-9]{1,11}$`;删除列表不允许重复,
194
+ 50**;附件映射及每个 record-field 数组没有非空 Schema 约束。record ID 必须以 `rec` 开头、
195
+ 后续为大小写字母和数字,用 `^rec[A-Za-z0-9]{1,32}$` 校验即可(实际返回如
196
+ `reczz2893mUCkwnr` 长度会超过旧的 `{1,11}` 上限,不要在业务层依赖固定短长度);删除列表不允许重复,
207
197
  更新映射的 key 自然唯一。`batch_update` 使用 `update_records` 为不同记录分别提交
208
198
  patch;不要混用 MCP 工具层 `patch_records_batch` 的 `record_id_list + patch` 请求结构。
209
199
 
@@ -225,7 +215,7 @@ patch;不要混用 MCP 工具层 `patch_records_batch` 的 `record_id_list + p
225
215
  }
226
216
  ```
227
217
 
228
- Node MCP 直接响应中的 `meta` 不会经过当前 FaaS Entry 的合成响应返回,FaaS 不得依赖该字段。
218
+ 这些路由的响应不包含 `meta` 字段,FaaS 不得依赖它。
229
219
 
230
220
  `batch_create` 和 `batch_update` 的 `data` 还可能包含被忽略的只读或不支持字段;未忽略任何字段时
231
221
  `ignored_fields` 不存在:
@@ -243,13 +233,15 @@ Node MCP 直接响应中的 `meta` 不会经过当前 FaaS Entry 的合成响应
243
233
  }
244
234
  ```
245
235
 
246
- 附件增量路由的成功响应没有 `record_id_list`:`data.attachments` 按记录、字段回显
236
+ 附件增量路由的成功响应没有 `record_id_list`:`data.attachments` 按记录 ID、字段 ID 回显
247
237
  **本次操作合并出的附件列表**(`file_token` / `name` / `size`),页面用它更新本地状态;
248
- 它不是包含全部并发写入的最终快照,不要立即用 SQL 回读替换它(从库可能尚未同步)。超时或结果未知时保留已上传 token,按[文件传输](file-transfer.md#超时与结果未知)有界核对;append 不幂等,不能自动重提或重新上传。字段设置了「仅限手机拍摄」时,
238
+ 即使请求使用字段名,响应也用字段 ID,固定按 `data.attachments[recordId][fieldId]` 读取,
239
+ 其中 `fieldId` 来自 Catalog。不要按请求中的字段名取值,否则写入成功后可能被误判为结果未知。
240
+ 它不是包含全部并发写入的最终快照,不要立即用 Database Function 回读替换它(查询结果可能尚未同步)。超时或结果未知时保留已上传 token,按[文件传输](file-transfer.md#超时与结果未知)有界核对;append 不幂等,不能自动重提或重新上传。字段设置了「仅限手机拍摄」时,
249
241
  `append_attachments` 对该字段的追加被忽略并进入 `ignored_fields`;`remove_attachments`
250
242
  不受该限制,仍可移除。校验纪律同 batch:只认约定字段,不递归找。
251
243
 
252
- runtime 识别后返回的是合成响应,因此这条链路上:
244
+ 这些路由的响应规则:
253
245
 
254
246
  - HTTP 状态恒为 `200`,业务成败只看 body 的 `code`,不能只判 `response.ok`;
255
247
  - 响应头没有 `x-tt-logid`,`DownstreamError.logId` 必然为空。排查改用 invoke 响应
@@ -265,7 +257,7 @@ runtime 识别后返回的是合成响应,因此这条链路上:
265
257
  - `batch_update`:`record_id_list` 是实际存在的记录,允许为空;它与 `record_not_found` 必须是请求 key 的不重叠、无遗漏分组。
266
258
  - `batch_delete`:`record_id_list` 必须与请求列表一致,`record_not_found` 必须是其子集;实际删除的 ID 是两者的差集。
267
259
 
268
- `code === 0` 且 `record_not_found` 非空是 Node MCP batch 的合法部分成功,不是 `invalid_response`。FaaS handler 必须在
260
+ `code === 0` 且 `record_not_found` 非空是 批量写入的合法部分成功,不是 `invalid_response`。FaaS handler 必须在
269
261
  业务结果中保留已完成和未找到的 ID;需要向 Page 表达部分成功时,使用当前 operation 的稳定业务码,
270
262
  但不得伪装成下游失败或整体重试。只有响应缺失、类型不符或不满足上述 operation 约束时才按
271
263
  `invalid_response` 处理;非幂等创建不得自动重试。
@@ -301,7 +293,7 @@ function parseSiteRecordsWriteData(
301
293
  return undefined
302
294
  }
303
295
  const data = envelope.data as Record<string, unknown>
304
- const recordIdPattern = /^rec[A-Za-z0-9]{1,11}$/
296
+ const recordIdPattern = /^rec[A-Za-z0-9]{1,32}$/
305
297
  const parseRecordIDs = (input: unknown): string[] | undefined => {
306
298
  if (
307
299
  !Array.isArray(input) ||
@@ -484,7 +476,7 @@ FaaS 写入 Base 时,必须调用目标环境的
484
476
  `.../append_attachments`、`.../remove_attachments`(附件增量)路由;
485
477
  `:base_token` 取 `catalog.json` 的 `tables[].baseToken`,并检查 HTTP 状态和业务码。
486
478
 
487
- 需要读 Base 时调用固定 SQL Function:
479
+ 需要读 Base 时调用固定 Database Function:
488
480
 
489
481
  ```ts
490
482
  const result: unknown = await context.invokeFunction({
@@ -494,30 +486,31 @@ const result: unknown = await context.invokeFunction({
494
486
  })
495
487
  ```
496
488
 
497
- 确需写前查重、权限范围、状态检查或写后查询时复用固定 SQL Function;可以在一次查询中完成的检查不拆成多个串行调用。前一个 SQL 返回的关联 ID 仅用于定位后一个 SQL 的记录时,优先把关联查询下推为一个 SQL Function。
489
+ 确需写前查重、权限范围、状态检查或写后查询时复用固定 Database Function;可以在一次查询中完成的检查不拆成多个串行调用。前一次查询返回的关联 ID 仅用于定位后一次查询的记录时,优先把关联查询下推为一个 Database Function。
498
490
 
499
491
  ## Base 读写协议
500
492
 
501
- 同一个字段在创建 schema、SQL 读取和 FaaS 应用记录 写入时使用三套不同但相关的数据结构。下表只适用于 FaaS 固定 batch 与附件增量路由;开发期 lark-cli 示例数据使用[发布手册中的独立输入契约](release.md#从零建站示例数据验收)。
493
+ 同一个字段在创建 schema、Database Function 读取和 FaaS 应用记录写入时使用三套不同但相关的数据结构。下表只适用于 FaaS 固定 batch 与附件增量路由;开发期 lark-cli 示例数据使用[发布手册中的独立输入契约](release.md#从零建站示例数据验收)。
502
494
 
503
- | Field JSON | SQL 读取 | FaaS 应用记录 CellValue |
495
+ | Field JSON | Database Function 读取 | FaaS 应用记录 CellValue |
504
496
  |---|---|---|
505
497
  | `text` | `TEXT` string | string |
506
498
  | `number` | `DOUBLE` number | finite number |
507
- | 单选 `select` | `OPTION` string | 合法选项名 string |
508
- | 多选 `select` | `COLLECTION<OPTION>` | 合法选项名 string[] |
509
- | `datetime` | `TIMESTAMP` 毫秒 number | `YYYY-MM-DD HH:mm:ss` |
499
+ | 单选 `select` | `OPTION` `{id,name}` | 合法选项名 string |
500
+ | 多选 `select` | `ARRAY<OPTION>`,元素为 `{id,name}` | 合法选项名 string[] |
501
+ | `datetime` | `TIMESTAMP` 字符串 `YYYY-MM-DD HH:mm:ss.SSS` | `YYYY-MM-DD HH:mm:ss` 或带毫秒格式 |
510
502
  | `checkbox` | `BOOL` boolean | boolean |
511
- | 单/多 `user` | `USER` / `COLLECTION<USER>` | `[{"id":"6882577547121393684"}]`;`id` 是内部 `user_id` |
512
- | 单/多 `group_chat` | `GROUP` / `COLLECTION<GROUP>` | `[{"id":"oc_xxx"}]` |
513
- | `link` | `COLLECTION<RECORD_ID>` | `[{"id":"rec_xxx"}]` |
514
- | `attachment` | `COLLECTION<FILE>` | `[{"file_token":"...","image_width":number,"image_height":number}]`;追加/移除走附件增量路由,`batch_update` 写该字段是整格覆盖、会丢已有图片宽高,仅用于置空或明确重设。见[文件传输](file-transfer.md) |
503
+ | 单/多 `user` | `USER` / `ARRAY<USER>` | `[{"id":"<User.user_id>"}]`;从 starter 人员选择器取得 `User.user_id` |
504
+ | 单/多 `group_chat` | `CHAT` / `ARRAY<CHAT>` | `[{"id":"oc_xxx"}]` |
505
+ | 单/多 `link` | `TEXT` / `ARRAY<TEXT>`,以 Catalog `sqlType` 为准 | 都使用 record 对象数组:单值最多一个元素,多值可多个,例如 `[{"id":"rec_xxx"}]` |
506
+ | `attachment` | `ARRAY<FILE>` | `[{"file_token":"...","image_width":number,"image_height":number}]`;追加/移除走附件增量路由,`batch_update` 写该字段是整格覆盖、会丢已有图片宽高,仅用于置空或明确重设。见[文件传输](file-transfer.md) |
515
507
  | `location` | `UNSUPPORTED` | `{"lng":number,"lat":number}` |
508
+ | `auto_number` | `AUTONUMBER` `{sequence,number}` | 只读 |
516
509
  | 公式、lookup、系统字段 | 推导类型或 `UNSUPPORTED` | 只读 |
517
510
 
518
- 写入时 `null` 清空字段,`[]` 表示空集合,省略字段表示不修改。选项名、用户/群 ID 和关联 record ID 必须来自真实数据。
511
+ 写入时 `null` 清空字段,`[]` 表示空集合,省略字段表示不修改。选项名、用户/群 ID 和关联 record ID 必须来自真实数据。日期与时间的转换见[日期与时区](development.md#日期与时区)。
519
512
 
520
- 应用 行写入只使用 [应用记录 写入协议](#应用记录-写入协议)中的固定路由。
513
+ 应用行写入只使用 [应用记录写入协议](#应用记录写入协议)中的固定路由。
521
514
 
522
515
  创建一行或多行时,`create_records` 中每一项是字段到 cell value 的映射,不同记录可以填写不同字段:
523
516
 
@@ -556,8 +549,8 @@ const result: unknown = await context.invokeFunction({
556
549
  `data.record_id_list`,附件增量路由校验 `data.attachments`;需要后续写入、关联或回读时,
557
550
  只使用约定字段中的记录 ID。
558
551
 
559
- batch 路由单批最多 200 条。多选、多人员、关联这些集合字段是**整格覆盖**:追加或移除必须先读现有值、合并出完整列表再整格写回,直接写会丢掉单元格里已有的项。**附件字段是唯一的例外**:追加/移除走上面的附件增量路由,禁止用读-合并-整格写回实现——服务端不会补齐省略的宽高,而 SQL 读不回旧图宽高,基于 SQL 列表的重写无法重建宽高;并发时整格写回还会互相覆盖。见[文件传输](file-transfer.md)的「写单元格」。
552
+ batch 路由单批最多 200 条。多选、多人员和多值关联这些集合字段是**整格覆盖**:追加或移除必须先读现有值、合并出完整列表再整格写回,直接写会丢掉单元格里已有的项。单值关联同样用对象数组写入,但最多一个元素,替换时提交新的单元素数组,清空时提交 `null`。**附件字段是唯一的例外**:追加/移除走上面的附件增量路由,禁止用读-合并-整格写回实现——服务端不会补齐省略的宽高,而 Database Function 读不回旧图宽高,基于 Database Function 返回列表的重写无法重建宽高;并发时整格写回还会互相覆盖。见[文件传输](file-transfer.md)的「写单元格」。
560
553
 
561
- **整格覆盖的合并基准必须是可信的完整列表。** SQL 回读走从库,刚写完就回读可能拿到写入前的旧值;拿缺项的列表做基准整格写回,会静默删掉其它项,而写入仍返回成功。读取失败、从未读到过、或回读缺少本次刚写入的项时,禁掉入口让用户稍后重试,不要写。
554
+ **整格覆盖的合并基准必须是可信的完整列表。** Database Function 回读走从库,刚写完就回读可能拿到写入前的旧值;拿缺项的列表做基准整格写回,会静默删掉其它项,而写入仍返回成功。读取失败、从未读到过、或回读缺少本次刚写入的项时,禁掉入口让用户稍后重试,不要写。
562
555
 
563
556
  页面内可串行处理同一记录字段的更新,但不能因此承诺跨访问者原子性。文件字节的上传与展示是另外的路,见[文件传输](file-transfer.md)。
@@ -1,22 +1,22 @@
1
1
  # 文件传输
2
2
 
3
- 实现附件能力时,先读取操作路由和公共约束,再读取当前操作章节。本文说明 Page 如何编排附件流程;请求体、响应结构和限制的唯一协议说明见[FaaS 与记录协议](faas.md#应用记录-写入协议),SQL 类型见[SQL Function](sql-function.md#sql-类型与结果值)。不因仅需展示附件而实现上传或写入功能。
3
+ 实现附件能力时,先读取操作路由和公共约束,再读取当前操作章节。本文说明 Page 如何编排附件流程;基础挂载/移除见[Mutation 附件写入](mutations.md#附件写入),需业务校验或编排时见[FaaS 与记录协议](faas.md#应用记录写入协议),查询类型见[Database Function](database-function.md#查询类型与结果值)。不因仅需展示附件而实现上传或写入功能。
4
4
 
5
5
  ## 操作路由
6
6
 
7
7
  | 目标 | 入口 | 必读章节 |
8
8
  | --- | --- | --- |
9
9
  | 上传文件字节 | `siteRuntime.uploadAttachment()` | [上传](#上传) |
10
- | 展示缩略图或大图 | `buildAttachmentCoverUrl(context, ref)` | [展示与下载](#展示与下载) |
10
+ | 展示缩略图或大图 | `fetchAttachmentCover(ref, size)` | [展示与下载](#展示与下载) |
11
11
  | 下载原文件 | `fetchAttachmentDownloadUrl(context, ref)` | [展示与下载](#展示与下载) |
12
- | 将新文件挂载到单元格或移除引用 | Page 调 FaaS,使用附件增量路由 | [写单元格](#写单元格)和 FaaS 协议 |
13
- | 写入超时、结果不明 | 保留 token,通过固定 SQL 有界核对 | [超时与结果未知](#超时与结果未知) |
12
+ | 将新文件挂载到单元格或移除引用 | 基础写入用 Mutation;业务校验与编排用 FaaS | [写单元格](#写单元格)和 [Mutation 附件写入](mutations.md#附件写入) |
13
+ | 写入超时、结果不明 | 保留 token,通过固定 Database Function 有界核对 | [超时与结果未知](#超时与结果未知) |
14
14
 
15
15
  ## 公共约束
16
16
 
17
17
  - `file_token` 是附件资源标识,不是可直接访问的 URL,也不是登录凭证。临时下载链接携带授权信息,不持久化、不记录到日志或作为长期公开链接。
18
- - 表、字段 ID 来自 Catalog;已有附件的记录 ID、FILE.id(即 file_token)来自 SQL。上传成功返回的新 fileToken 供后续挂载使用。不能通过伪造位置声明获取其他附件。
19
- - 上传依赖父页面 `attachment.upload`;挂载还依赖目标环境的 FaaS runtime 和服务端增量路由。更新 starter 不证明平台已开通。能力不具备时报告具体限制,按用户决定调整需求,不猜网关或回退为旧列表整格覆盖。
18
+ - 表、字段 ID 来自 Catalog;已有附件的记录 ID、FILE.token 来自 Database Function 查询结果。上传成功返回的新 fileToken 供后续挂载使用。不能通过伪造位置声明获取其他附件。
19
+ - 上传依赖父页面 `attachment.upload`;Mutation 挂载依赖目标环境的附件操作和服务端增量路由,FaaS 挂载依赖对应 runtime 和服务端增量路由。更新 starter 不证明平台已开通。能力不具备时报告具体限制,按用户决定调整需求,不猜网关或回退为旧列表整格覆盖。
20
20
  - 上传校验应用权限与绑定关系。不要要求访客取得底层 Base 权限来绕过应用链路问题。
21
21
  - 上传成功只证明文件字节已提交,不证明附件已挂载;移除只删除单元格引用,不删除云盘文件,也不承诺释放 Base 附件计数。
22
22
 
@@ -33,7 +33,7 @@ baseToken/tableId 取自 Catalog;file 必须是 File。不传 fieldId,目标
33
33
 
34
34
  ### 图片宽高
35
35
 
36
- 图片上传前从本地 File 解码读取原始宽高,不依赖上传结果中的可选 width/height,也不使用预览元素的 CSS 尺寸。服务端不会补齐省略的宽高,SQL 也不返回旧图片宽高。
36
+ 图片上传前从本地 File 解码读取原始宽高,不依赖上传结果中的可选 width/height,也不使用预览元素的 CSS 尺寸。服务端不会补齐省略的宽高,Database Function 也不返回旧图片宽高。
37
37
 
38
38
  ```ts
39
39
  async function readImageDimensions(file: File) {
@@ -56,7 +56,7 @@ async function readImageDimensions(file: File) {
56
56
  const dimensions = await readImageDimensions(file)
57
57
  const uploaded = await siteRuntime.uploadAttachment({ baseToken, tableId, file, onProgress })
58
58
  const newAttachment = { file_token: uploaded.fileToken, ...dimensions }
59
- // 经业务 FaaS 挂载 newAttachment,不合并页面旧附件列表。
59
+ // 基础写入:新建记录时随 create Mutation 提交,已有记录通过 append_attachments 追加。
60
60
  ```
61
61
 
62
62
  非图片省略宽高;类型未知时先识别或提示用户,不能把可能的图片直接当非图片。图片解码失败或尺寸无效时停止上传和挂载,不伪造尺寸。
@@ -78,22 +78,22 @@ const context = await resolveDatabaseContext()
78
78
  const ref = { tableId, fieldId, recordId, fileToken }
79
79
  ```
80
80
 
81
- helper 负责生成 extra,其中 baseAppToken 将鉴权对象指向应用。业务代码不手工拼接 extra,也不移除该字段来尝试底表鉴权。不存在、错位或无权限的附件可能返回错误或无可展示内容。
81
+ 封面和下载 helper 负责生成 extra,其中 siteToken 和 siteEnv 指定应用及 Preview/正式环境,宿主校验其与当前页面一致。业务代码不手工拼接 extra,也不移除该字段来尝试底表鉴权。不存在、错位或无权限的附件可能返回错误或无可展示内容。
82
82
 
83
83
  | 操作 | helper 与结果 | 前置条件 |
84
84
  | --- | --- | --- |
85
- | 封面/大图 | `buildAttachmentCoverUrl(context, ref, 360)` 返回绝对 URL,交给 img | 需要有效应用、附件坐标和 gatewayOrigin;无法构造时返回空字符串 |
85
+ | 封面/大图 | `await fetchAttachmentCover(ref, 360)` 返回 Blob | 需要支持 HTTP 二进制响应的宿主和完整附件坐标;不需要 iframe 推断 gatewayOrigin |
86
86
  | 原文件下载 | `await fetchAttachmentDownloadUrl(context, ref)` 返回临时链接 | 通过父页面代理取链接,不依赖封面 helper 的 gatewayOrigin |
87
87
 
88
- 不能因为封面 URL 为空就禁用下载。下载失败应显示 helper 返回的错误;任何动作入口都不能静默无响应。
88
+ 不能因为封面加载失败就禁用下载。下载失败应显示 helper 返回的错误;任何动作入口都不能静默无响应。
89
89
 
90
- ### 封面与重试
90
+ ### 缩略图和点击大图
91
91
 
92
- 封面尺寸取服务端档位 120/360/720/1280,默认 360;列表可用 360,大图用 1280。除用户明确要求原文件画质外,展示不调用下载端点获取大体积原文件。
92
+ 基础取图入口是 starter `src/lib/database-runtime.ts` 的 `fetchAttachmentCover(ref, size, { signal })`,返回 Blob。图片由宿主以当前访问者身份请求,经通用 HTTP bridge 返回。调用方用 `URL.createObjectURL(blob)` 展示,替换或卸载时取消请求并 revoke。`size` 控制封面请求尺寸,默认 360、最大 1280,可按展示需求调整;页面显示尺寸由样式决定,大图仍是封面。
93
93
 
94
- 封面异步生成;202/90002006 或 img 的 onError 不足以判定文件类型不支持。采用占位图或文件名,并按[工程质量](style-guide.md)设置有限重试:限定次数或总时长,仅在组件可见且仍挂载时调度,替换附件或卸载时取消;超过预算保留手动重试入口。具体预算由体验需求决定,不把某次样本耗时写成平台保证。
94
+ React 页面可选用 `src/lib/attachment-image.tsx` 的 `AttachmentImage`。它内部调用同一取图函数,封装可见时加载、取消请求、手动重试和 Blob URL 释放;例如预览使用 `<AttachmentImage attachment={ref} alt={name} size={1280} />`。需要自定义展示时直接使用取图函数即可。
95
95
 
96
- 重试封面可更新 cache-bust 参数,不重新上传文件。网关 origin 来自 runtime 的 ancestorOrigins/referrer 解析,无法取得时不猜域名。支持格式、生成耗时和有效期以目标环境表现为准。
96
+ 封面异步生成,保留占位和失败状态;自动重试按[工程质量](style-guide.md)设置有限预算,替换或卸载时取消。遇到 `HTTP_RESPONSE_TYPE_UNSUPPORTED` 或 `INVALID_HTTP_URL` 时,先核对是否使用当前 starter 的 helper、完整附件坐标和匹配的依赖版本。修正本地接入后重新构建并发布;接入正确但仍报错时,保留错误码与请求标识,报告平台能力限制并向平台支持反馈,不自行猜测域名或绕过代理。
97
97
 
98
98
  ### 原文件下载
99
99
 
@@ -103,21 +103,21 @@ helper 负责生成 extra,其中 baseAppToken 将鉴权对象指向应用。
103
103
 
104
104
  ## 写单元格
105
105
 
106
- 普通追加/移除通过业务 FaaS 调用 append_attachments/remove_attachments,路径、JSON 和响应见[FaaS 协议](faas.md#应用记录-写入协议)。保持以下操作语义:
106
+ 按[写入方式选择](mutations.md#写入方式选择)确定是否需要 FaaS;基础追加/移除通过 `invokeDatabaseFunction` 调用 `append_attachments` / `remove_attachments` Mutation。声明、Page 参数和完整响应见[Mutation 附件写入](mutations.md#附件写入)。保持以下操作语义:
107
107
 
108
- - 追加只提交本次新增项;图片附带本地读取的宽高。正常追加不要求先查询旧列表,不依赖 SQL 重建旧图宽高。
109
- - 移除只提交目标 file_token,按 token 删除全部同名引用;SQL 的 id 须映射为 file_token。不要直接提交 SQL 返回对象。
110
- - 请求前过滤空字段数组和空记录映射,全空则本地短路。不能假定 append 空数组无副作用。
111
- - 成功后使用 data.attachments 更新本次操作的本地状态,不用立即 SQL 回读覆盖它;从库可能尚未同步。业务结果仍需处理 ignored_fields。
112
- - batch_update 仅用于明确的整格置空或重设;重设旧图无法从 SQL 补回宽高,不用于普通追加/移除。
108
+ - 追加只提交本次新增项;图片附带本地读取的宽高。正常追加不要求先查询旧列表,不依赖 Database Function 重建旧图宽高。
109
+ - 移除只提交目标 file_token,按 token 删除全部同名引用;Database Function 返回附件对象中的 `token`,调用 Mutation 时将该值填入 `file_token`。不要直接提交查询返回对象。
110
+ - 没有新增或移除项时本地短路,批量只提交有改动的参数组。Mutation 拒绝空附件列表;FaaS 直调仍需过滤空字段数组和空记录映射,不能假定 append 空数组无副作用。
111
+ - Mutation 成功后用 `data.records` 中对应记录/字段的完整附件列表更新本地状态,不立即调用 Database Function 回读覆盖它;查询结果可能尚未同步。FaaS 直调使用 `data.attachments`,并处理 `ignored_fields`;不要混用两种返回结构。
112
+ - 新记录可通过 create Mutation 随记录提交附件;update 的整格写入只用于明确的替换或 clear 清空。重设旧图无法从 Database Function 补回宽高,不用于普通追加/移除。
113
113
 
114
- 服务端仍是读取、合并、写回,不保证原子性、去重或并发不丢项。页面按单元格串行可减少本页交错,但不能保护多个访问者同时写入;不同记录或字段不应共用全局上传锁。严格并发一致性的需求须说明当前能力限制,不通过固定等待时间承诺安全。
114
+ 附件增量写入不保证原子性、去重或并发不丢项。页面按单元格串行可减少本页交错,但不能保护多个访问者同时写入;不同记录或字段不应共用全局上传锁。严格并发一致性的需求须说明当前能力限制,不通过固定等待时间承诺安全。
115
115
 
116
116
  ### 超时与结果未知
117
117
 
118
118
  页面区分上传中、已上传待挂载、挂载结果待确认,保留已有 fileToken 和图片宽高。append 与上传都不幂等,结果未知时不自动重提或重新上传。
119
119
 
120
- 1. 使用固定 SQL Function 按记录核对目标 token。未立即读到不证明上一请求失败;读到也不保证不会被并发写入覆盖。
120
+ 1. 使用固定 Database Function 按记录核对目标 token。未立即读到不证明上一请求失败;读到也不保证不会被并发写入覆盖。
121
121
  2. 延迟后进行有限次数或有限时长的只读核对。仍不能确认时保留待确认状态并提示用户,不拿旧列表整格覆盖。
122
122
  3. 后续明确需要补挂时复用已有 token 与宽高,只处理已核对的目标,并说明可能重复引用和并发覆盖。没有可靠去重原语时不承诺只执行一次。
123
123
 
@@ -126,9 +126,9 @@ helper 负责生成 extra,其中 baseAppToken 将鉴权对象指向应用。
126
126
  | 条件/错误 | 处理 |
127
127
  | --- | --- |
128
128
  | INVALID_ATTACHMENT_TARGET | 区分文件类型/大小与应用绑定配置;修正对应输入,不重复发送同一错误请求 |
129
- | ATTACHMENT_UNAVAILABLE | 父页面不支持上传,报告环境能力限制 |
129
+ | ATTACHMENT_UNAVAILABLE | 父页面不支持当前附件接口,报告环境能力限制 |
130
130
  | ATTACHMENT_UPLOAD_FAILED / STALLED | 显示进度或网络问题;检查是否已上传,不自动重传 |
131
- | 位置不匹配、403 或没有封面 | 核对坐标与应用鉴权;封面未就绪按有限重试处理 |
131
+ | 位置不匹配或没有封面 | 核对坐标与应用鉴权;封面未就绪按有限重试处理 |
132
132
  | 下载操作无响应 | 核对代理错误及 iframe 下载设置;不因缺 gatewayOrigin 直接禁用下载 |
133
133
  | 单元格已满或出现 ignored_fields | 不报告全部成功;指出未写入项及原因 |
134
134
  | property.capture 字段 | 上传挂载可能被忽略;读取和移除按对应协议处理 |