@lark-base-open/base-database-cli 1.3.9 → 1.4.3

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 (320) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/README.md +119 -15
  3. package/THIRD_PARTY_LICENSES.json +1662 -0
  4. package/config-schema.json +64 -3
  5. package/data/template-hmr-scripts.json +9 -0
  6. package/data/template-index-html/17e698eef687ece8f1628e3e2c4801da5e7233faa87076b3424acde8df57b825.html +24 -0
  7. package/dist/agent-tools-guide.d.ts +29 -0
  8. package/dist/agent-tools-guide.d.ts.map +1 -0
  9. package/dist/agent-tools-guide.js +169 -0
  10. package/dist/agent-tools-guide.js.map +1 -0
  11. package/dist/agent-tools-skill.d.ts +16 -0
  12. package/dist/agent-tools-skill.d.ts.map +1 -0
  13. package/dist/agent-tools-skill.js +183 -0
  14. package/dist/agent-tools-skill.js.map +1 -0
  15. package/dist/agent-tools.d.ts +20 -0
  16. package/dist/agent-tools.d.ts.map +1 -0
  17. package/dist/agent-tools.js +137 -0
  18. package/dist/agent-tools.js.map +1 -0
  19. package/dist/ai-functions.d.ts +10 -0
  20. package/dist/ai-functions.d.ts.map +1 -1
  21. package/dist/ai-functions.js +264 -212
  22. package/dist/ai-functions.js.map +1 -1
  23. package/dist/app-builder/core.d.mts +37 -0
  24. package/dist/app-builder/core.d.mts.map +1 -0
  25. package/dist/app-builder/core.mjs +673 -0
  26. package/dist/app-builder/core.mjs.map +1 -0
  27. package/dist/app-builder/package.json +1 -0
  28. package/dist/app-builder/schema.d.ts +4 -0
  29. package/dist/app-builder/schema.d.ts.map +1 -0
  30. package/dist/app-builder/schema.js +72 -0
  31. package/dist/app-builder/schema.js.map +1 -0
  32. package/dist/archive.d.ts +22 -2
  33. package/dist/archive.d.ts.map +1 -1
  34. package/dist/archive.js +311 -74
  35. package/dist/archive.js.map +1 -1
  36. package/dist/auth.d.ts +2 -2
  37. package/dist/auth.d.ts.map +1 -1
  38. package/dist/auth.js +13 -8
  39. package/dist/auth.js.map +1 -1
  40. package/dist/build-server.d.ts +25 -0
  41. package/dist/build-server.d.ts.map +1 -0
  42. package/dist/build-server.js +32 -0
  43. package/dist/build-server.js.map +1 -0
  44. package/dist/business-update-notice.d.ts +37 -0
  45. package/dist/business-update-notice.d.ts.map +1 -0
  46. package/dist/business-update-notice.js +24 -0
  47. package/dist/business-update-notice.js.map +1 -0
  48. package/dist/check.d.ts +11 -0
  49. package/dist/check.d.ts.map +1 -1
  50. package/dist/check.js +85 -15
  51. package/dist/check.js.map +1 -1
  52. package/dist/cloud-build-diagnostic.d.ts +9 -0
  53. package/dist/cloud-build-diagnostic.d.ts.map +1 -0
  54. package/dist/cloud-build-diagnostic.js +65 -0
  55. package/dist/cloud-build-diagnostic.js.map +1 -0
  56. package/dist/config.d.ts +6 -0
  57. package/dist/config.d.ts.map +1 -1
  58. package/dist/config.js +41 -11
  59. package/dist/config.js.map +1 -1
  60. package/dist/contract-extractor.d.ts +21 -0
  61. package/dist/contract-extractor.d.ts.map +1 -0
  62. package/dist/contract-extractor.js +260 -0
  63. package/dist/contract-extractor.js.map +1 -0
  64. package/dist/contract-worker.d.ts +12 -0
  65. package/dist/contract-worker.d.ts.map +1 -0
  66. package/dist/contract-worker.js +90 -0
  67. package/dist/contract-worker.js.map +1 -0
  68. package/dist/dependency-policy.d.ts.map +1 -1
  69. package/dist/dependency-policy.js +6 -1
  70. package/dist/dependency-policy.js.map +1 -1
  71. package/dist/deploy.d.ts +20 -1
  72. package/dist/deploy.d.ts.map +1 -1
  73. package/dist/deploy.js +181 -52
  74. package/dist/deploy.js.map +1 -1
  75. package/dist/dev-bootstrap.d.ts +5 -0
  76. package/dist/dev-bootstrap.d.ts.map +1 -0
  77. package/dist/dev-bootstrap.js +185 -0
  78. package/dist/dev-bootstrap.js.map +1 -0
  79. package/dist/dev-events.d.ts +24 -0
  80. package/dist/dev-events.d.ts.map +1 -0
  81. package/dist/dev-events.js +67 -0
  82. package/dist/dev-events.js.map +1 -0
  83. package/dist/dev-pairing.d.ts +4 -0
  84. package/dist/dev-pairing.d.ts.map +1 -0
  85. package/dist/dev-pairing.js +54 -0
  86. package/dist/dev-pairing.js.map +1 -0
  87. package/dist/dev-url.d.ts +4 -0
  88. package/dist/dev-url.d.ts.map +1 -0
  89. package/dist/dev-url.js +29 -0
  90. package/dist/dev-url.js.map +1 -0
  91. package/dist/dev-vite.d.ts +9 -0
  92. package/dist/dev-vite.d.ts.map +1 -0
  93. package/dist/dev-vite.js +237 -0
  94. package/dist/dev-vite.js.map +1 -0
  95. package/dist/dev-watch.d.ts +33 -0
  96. package/dist/dev-watch.d.ts.map +1 -0
  97. package/dist/dev-watch.js +246 -0
  98. package/dist/dev-watch.js.map +1 -0
  99. package/dist/dev.d.ts +24 -0
  100. package/dist/dev.d.ts.map +1 -0
  101. package/dist/dev.js +244 -0
  102. package/dist/dev.js.map +1 -0
  103. package/dist/development-pairing.generated.d.ts +12 -0
  104. package/dist/development-pairing.generated.d.ts.map +1 -0
  105. package/dist/development-pairing.generated.js +13 -0
  106. package/dist/development-pairing.generated.js.map +1 -0
  107. package/dist/diagnostic-platforms.d.ts +3 -0
  108. package/dist/diagnostic-platforms.d.ts.map +1 -0
  109. package/dist/diagnostic-platforms.js +3 -0
  110. package/dist/diagnostic-platforms.js.map +1 -0
  111. package/dist/diagnostic-schema.d.ts +151 -0
  112. package/dist/diagnostic-schema.d.ts.map +1 -0
  113. package/dist/diagnostic-schema.js +129 -0
  114. package/dist/diagnostic-schema.js.map +1 -0
  115. package/dist/diagnostics.d.ts +78 -0
  116. package/dist/diagnostics.d.ts.map +1 -0
  117. package/dist/diagnostics.js +333 -0
  118. package/dist/diagnostics.js.map +1 -0
  119. package/dist/distribution-commands.d.ts.map +1 -1
  120. package/dist/distribution-commands.js +6 -2
  121. package/dist/distribution-commands.js.map +1 -1
  122. package/dist/distribution-npm.d.ts +2 -2
  123. package/dist/distribution-npm.d.ts.map +1 -1
  124. package/dist/distribution-npm.js +14 -1
  125. package/dist/distribution-npm.js.map +1 -1
  126. package/dist/environment-variables.d.ts.map +1 -1
  127. package/dist/environment-variables.js +2 -1
  128. package/dist/environment-variables.js.map +1 -1
  129. package/dist/function-contracts.d.ts +40 -0
  130. package/dist/function-contracts.d.ts.map +1 -0
  131. package/dist/function-contracts.js +357 -0
  132. package/dist/function-contracts.js.map +1 -0
  133. package/dist/function-description.d.ts +11 -4
  134. package/dist/function-description.d.ts.map +1 -1
  135. package/dist/function-description.js +22 -12
  136. package/dist/function-description.js.map +1 -1
  137. package/dist/function-input-types.d.ts +6 -4
  138. package/dist/function-input-types.d.ts.map +1 -1
  139. package/dist/function-input-types.js +97 -135
  140. package/dist/function-input-types.js.map +1 -1
  141. package/dist/function-params.d.ts +53 -0
  142. package/dist/function-params.d.ts.map +1 -0
  143. package/dist/function-params.js +184 -0
  144. package/dist/function-params.js.map +1 -0
  145. package/dist/function-schema.d.ts +14 -0
  146. package/dist/function-schema.d.ts.map +1 -1
  147. package/dist/function-schema.js +99 -9
  148. package/dist/function-schema.js.map +1 -1
  149. package/dist/init-journal.d.ts +1 -0
  150. package/dist/init-journal.d.ts.map +1 -1
  151. package/dist/init-journal.js +21 -7
  152. package/dist/init-journal.js.map +1 -1
  153. package/dist/init.d.ts +1 -0
  154. package/dist/init.d.ts.map +1 -1
  155. package/dist/init.js +55 -5
  156. package/dist/init.js.map +1 -1
  157. package/dist/lark-cli-error.d.ts +13 -2
  158. package/dist/lark-cli-error.d.ts.map +1 -1
  159. package/dist/lark-cli-error.js +54 -13
  160. package/dist/lark-cli-error.js.map +1 -1
  161. package/dist/lark-cli-passthrough.d.ts +9 -0
  162. package/dist/lark-cli-passthrough.d.ts.map +1 -0
  163. package/dist/lark-cli-passthrough.js +101 -0
  164. package/dist/lark-cli-passthrough.js.map +1 -0
  165. package/dist/lark-cli.d.ts +5 -2
  166. package/dist/lark-cli.d.ts.map +1 -1
  167. package/dist/lark-cli.js +96 -29
  168. package/dist/lark-cli.js.map +1 -1
  169. package/dist/legacy-function-input-renderer.d.ts +6 -0
  170. package/dist/legacy-function-input-renderer.d.ts.map +1 -0
  171. package/dist/legacy-function-input-renderer.js +175 -0
  172. package/dist/legacy-function-input-renderer.js.map +1 -0
  173. package/dist/link-guard-check.d.ts +12 -0
  174. package/dist/link-guard-check.d.ts.map +1 -0
  175. package/dist/link-guard-check.js +138 -0
  176. package/dist/link-guard-check.js.map +1 -0
  177. package/dist/managed-agent-docs.d.ts +14 -0
  178. package/dist/managed-agent-docs.d.ts.map +1 -0
  179. package/dist/managed-agent-docs.js +172 -0
  180. package/dist/managed-agent-docs.js.map +1 -0
  181. package/dist/mutation-schema.d.ts +6 -0
  182. package/dist/mutation-schema.d.ts.map +1 -1
  183. package/dist/mutation-schema.js +6 -0
  184. package/dist/mutation-schema.js.map +1 -1
  185. package/dist/mutation.d.ts +4 -1
  186. package/dist/mutation.d.ts.map +1 -1
  187. package/dist/mutation.js +17 -2
  188. package/dist/mutation.js.map +1 -1
  189. package/dist/npm.d.ts +1 -0
  190. package/dist/npm.d.ts.map +1 -1
  191. package/dist/npm.js +28 -0
  192. package/dist/npm.js.map +1 -1
  193. package/dist/preview-receipt.d.ts +0 -2
  194. package/dist/preview-receipt.d.ts.map +1 -1
  195. package/dist/preview-receipt.js +0 -28
  196. package/dist/preview-receipt.js.map +1 -1
  197. package/dist/process.d.ts +1 -0
  198. package/dist/process.d.ts.map +1 -1
  199. package/dist/process.js +25 -0
  200. package/dist/process.js.map +1 -1
  201. package/dist/program.d.ts.map +1 -1
  202. package/dist/program.js +239 -26
  203. package/dist/program.js.map +1 -1
  204. package/dist/project-build.d.ts +2 -1
  205. package/dist/project-build.d.ts.map +1 -1
  206. package/dist/project-build.js +53 -16
  207. package/dist/project-build.js.map +1 -1
  208. package/dist/project-capabilities.d.ts +8 -0
  209. package/dist/project-capabilities.d.ts.map +1 -0
  210. package/dist/project-capabilities.js +47 -0
  211. package/dist/project-capabilities.js.map +1 -0
  212. package/dist/project-context.d.ts +66 -0
  213. package/dist/project-context.d.ts.map +1 -1
  214. package/dist/project-context.js +68 -6
  215. package/dist/project-context.js.map +1 -1
  216. package/dist/project-layout.d.ts +11 -0
  217. package/dist/project-layout.d.ts.map +1 -1
  218. package/dist/project-layout.js +63 -1
  219. package/dist/project-layout.js.map +1 -1
  220. package/dist/public-exports.d.ts +5 -0
  221. package/dist/public-exports.d.ts.map +1 -0
  222. package/dist/public-exports.js +76 -0
  223. package/dist/public-exports.js.map +1 -0
  224. package/dist/public-sql-error.d.ts +3 -1
  225. package/dist/public-sql-error.d.ts.map +1 -1
  226. package/dist/public-sql-error.js +5 -2
  227. package/dist/public-sql-error.js.map +1 -1
  228. package/dist/pull.d.ts +1 -0
  229. package/dist/pull.d.ts.map +1 -1
  230. package/dist/pull.js +103 -20
  231. package/dist/pull.js.map +1 -1
  232. package/dist/sdk-codegen.d.ts +16 -0
  233. package/dist/sdk-codegen.d.ts.map +1 -0
  234. package/dist/sdk-codegen.js +181 -0
  235. package/dist/sdk-codegen.js.map +1 -0
  236. package/dist/sdk-install.d.ts +4 -0
  237. package/dist/sdk-install.d.ts.map +1 -0
  238. package/dist/sdk-install.js +33 -0
  239. package/dist/sdk-install.js.map +1 -0
  240. package/dist/skill-frontmatter.d.ts +5 -0
  241. package/dist/skill-frontmatter.d.ts.map +1 -0
  242. package/dist/skill-frontmatter.js +28 -0
  243. package/dist/skill-frontmatter.js.map +1 -0
  244. package/dist/skill.d.ts +2 -1
  245. package/dist/skill.d.ts.map +1 -1
  246. package/dist/skill.js +18 -12
  247. package/dist/skill.js.map +1 -1
  248. package/dist/source-format.d.ts +10 -0
  249. package/dist/source-format.d.ts.map +1 -0
  250. package/dist/source-format.js +49 -0
  251. package/dist/source-format.js.map +1 -0
  252. package/dist/types.d.ts +6 -0
  253. package/dist/types.d.ts.map +1 -1
  254. package/dist/unified-functions.d.ts +22 -0
  255. package/dist/unified-functions.d.ts.map +1 -0
  256. package/dist/unified-functions.js +114 -0
  257. package/dist/unified-functions.js.map +1 -0
  258. package/dist/updates.d.ts +13 -1
  259. package/dist/updates.d.ts.map +1 -1
  260. package/dist/updates.js +65 -29
  261. package/dist/updates.js.map +1 -1
  262. package/dist/workspace-fingerprint.d.ts.map +1 -1
  263. package/dist/workspace-fingerprint.js +5 -0
  264. package/dist/workspace-fingerprint.js.map +1 -1
  265. package/package.json +17 -5
  266. package/skills/lark-base-database/SKILL.md +21 -55
  267. package/skills/lark-base-database/references/agent-tool-design.md +181 -0
  268. package/skills/lark-base-database/references/agent-tools.md +101 -0
  269. package/skills/lark-base-database/references/ai-function.md +80 -186
  270. package/skills/lark-base-database/references/database-function-limitations.md +12 -4
  271. package/skills/lark-base-database/references/database-function.md +49 -21
  272. package/skills/lark-base-database/references/development.md +81 -109
  273. package/skills/lark-base-database/references/environment-variables.md +2 -2
  274. package/skills/lark-base-database/references/faas.md +43 -16
  275. package/skills/lark-base-database/references/file-transfer.md +10 -33
  276. package/skills/lark-base-database/references/frontend-design-guide.md +1 -1
  277. package/skills/lark-base-database/references/legacy-ai-function.md +120 -0
  278. package/skills/lark-base-database/references/legacy-development.md +156 -0
  279. package/skills/lark-base-database/references/legacy-file-transfer.md +68 -0
  280. package/skills/lark-base-database/references/mutations.md +38 -29
  281. package/skills/lark-base-database/references/notifications.md +1 -1
  282. package/skills/lark-base-database/references/permission-design.md +11 -5
  283. package/skills/lark-base-database/references/release.md +22 -7
  284. package/skills/lark-base-database/references/verification.md +55 -16
  285. package/skills/lark-base-database/references/workspace-migration.md +86 -0
  286. package/skills/lark-base-database/references/workspace.md +55 -44
  287. package/templates/database-starter/README.md +2 -0
  288. package/templates/database-starter/database-functions/README.md +2 -2
  289. package/templates/database-starter/mutations/README.md +2 -2
  290. package/templates/database-starter/page/README.md +5 -4
  291. package/templates/database-starter/page/src/examples/ai-function/TextStreamOperation.tsx +6 -6
  292. package/templates/database-starter/page/src/lib/attachment-image.tsx +19 -5
  293. package/templates/database-starter/page/src/lib/database-runtime-attachment.test.ts +124 -5
  294. package/templates/database-starter/page/src/lib/database-runtime.test.ts +2 -2
  295. package/templates/database-starter/page/src/lib/database-runtime.ts +77 -13
  296. package/templates/database-starter/server-functions/scripts/run-tsc.mjs +3 -2
  297. package/templates/database-starter-v2/README.md +25 -0
  298. package/templates/database-starter-v2/base-app.config.ts +10 -0
  299. package/templates/database-starter-v2/database-functions/README.md +1 -0
  300. package/templates/database-starter-v2/gitignore +6 -0
  301. package/templates/database-starter-v2/mutations/README.md +1 -0
  302. package/templates/database-starter-v2/package-lock.json +2239 -0
  303. package/templates/database-starter-v2/package.json +18 -0
  304. package/templates/database-starter-v2/page/index.html +2 -0
  305. package/templates/database-starter-v2/page/package.json +25 -0
  306. package/templates/database-starter-v2/page/src/App.tsx +12 -0
  307. package/templates/database-starter-v2/page/src/generated/README.md +1 -0
  308. package/templates/database-starter-v2/page/src/index.css +1 -0
  309. package/templates/database-starter-v2/page/src/lib/date-time.ts +61 -0
  310. package/templates/database-starter-v2/page/src/main.tsx +6 -0
  311. package/templates/database-starter-v2/page/tsconfig.json +19 -0
  312. package/templates/database-starter-v2/page/vite.config.ts +3 -0
  313. package/templates/database-starter-v2/prettierignore +3 -0
  314. package/templates/database-starter-v2/server/functions/README.md +1 -0
  315. package/templates/database-starter-v2/server/functions/hello/contract.ts +5 -0
  316. package/templates/database-starter-v2/server/functions/hello/index.ts +7 -0
  317. package/templates/database-starter-v2/server/functions/hello/meta.json +1 -0
  318. package/templates/database-starter-v2/server/generated/runtime-profile.ts +5 -0
  319. package/templates/database-starter-v2/server/package.json +17 -0
  320. package/templates/database-starter-v2/server/tsconfig.json +14 -0
@@ -1,5 +1,7 @@
1
1
  # 文件传输
2
2
 
3
+ 只有工程已安装 SDK 时才按工程内 `node_modules/@lark-base-open/base-database-app-sdk/docs/README.md` 选择 Page API;未安装 SDK 的 classic 按[工程内 helper 参考](legacy-file-transfer.md)接入,不新增 SDK 依赖。
4
+
3
5
  实现附件能力时,先读取操作路由和公共约束,再读取当前操作章节。本文说明 Page 如何编排附件流程;基础挂载/移除见[Mutation 附件写入](mutations.md#附件写入),需业务校验或编排时见[FaaS 与记录协议](faas.md#应用记录写入协议),查询类型见[Database Function](database-function.md#查询类型与结果值)。不因仅需展示附件而实现上传或写入功能。
4
6
 
5
7
  ## 操作路由
@@ -8,7 +10,8 @@
8
10
  | --- | --- | --- |
9
11
  | 上传文件字节 | `siteRuntime.uploadAttachment()` | [上传](#上传) |
10
12
  | 展示缩略图或大图 | `fetchAttachmentCover(ref, size)` | [展示与下载](#展示与下载) |
11
- | 下载原文件 | `fetchAttachmentDownloadUrl(context, ref)` | [展示与下载](#展示与下载) |
13
+ | 用户下载原文件 | `openAttachmentDownload(context, ref)` | [展示与下载](#展示与下载) |
14
+ | 页面中确需原文件临时 URL 的其他逻辑 | `fetchAttachmentDownloadUrl(context, ref)` | [展示与下载](#展示与下载) |
12
15
  | 将新文件挂载到单元格或移除引用 | 基础写入用 Mutation;业务校验与编排用 FaaS | [写单元格](#写单元格)和 [Mutation 附件写入](mutations.md#附件写入) |
13
16
  | 写入超时、结果不明 | 保留 token,通过固定 Database Function 有界核对 | [超时与结果未知](#超时与结果未知) |
14
17
 
@@ -65,41 +68,23 @@ const newAttachment = { file_token: uploaded.fileToken, ...dimensions }
65
68
 
66
69
  onProgress 返回 loaded/total,用于进度反馈;进度可能分片跳变,也可能不回调。分母取回调的 total,不自行假定 file.size。100% 仍可能处于服务端收尾,只有 Promise resolve 才代表上传完成。
67
70
 
68
- 当前停滞检测从首条进度事件之后开始:连续 120 秒无新进度可能返回 ATTACHMENT_UPLOAD_STALLED。首条事件前仍可能等待至调用超时;页面应有自己的等待提示与最大等待策略,不自动重传。调用超时不证明父页面已取消上传。
71
+ SDK 的具体超时与错误按已安装版本文档处理;classic 停滞检测与恢复见[存量上传进度](legacy-file-transfer.md#进度与即时展示)。结果未知时按[只读核对](#超时与结果未知)处理。
69
72
 
70
73
  刚上传的图片可使用本地 `URL.createObjectURL(file)` 展示,替换或卸载时 revoke。附件位置同步和封面生成都是异步过程,下次打开或刷新也不保证就绪;重新进入页面仍需处理远程封面未就绪状态。
71
74
 
72
75
  ## 展示与下载
73
76
 
74
- 从 starter runtime 导入 helper,并准备真实位置:
75
-
76
- ```ts
77
- const context = await resolveDatabaseContext()
78
- const ref = { tableId, fieldId, recordId, fileToken }
79
- ```
80
-
81
- 封面和下载 helper 负责生成 extra,其中 siteToken 和 siteEnv 指定应用及 Preview/正式环境,宿主校验其与当前页面一致。业务代码不手工拼接 extra,也不移除该字段来尝试底表鉴权。不存在、错位或无权限的附件可能返回错误或无可展示内容。
82
-
83
- | 操作 | helper 与结果 | 前置条件 |
84
- | --- | --- | --- |
85
- | 封面/大图 | `await fetchAttachmentCover(ref, 360)` 返回 Blob | 需要支持 HTTP 二进制响应的宿主和完整附件坐标;不需要 iframe 推断 gatewayOrigin |
86
- | 原文件下载 | `await fetchAttachmentDownloadUrl(context, ref)` 返回临时链接 | 通过父页面代理取链接,不依赖封面 helper 的 gatewayOrigin |
87
-
88
- 不能因为封面加载失败就禁用下载。下载失败应显示 helper 返回的错误;任何动作入口都不能静默无响应。
77
+ SDK 工程读取已安装 SDK 的 docs/README.md,按该版本的附件 API/组件文档接入;classic 的 helper 导入、完整附件坐标、extra、Blob 及组件调用细节统一见[存量附件参考](legacy-file-transfer.md#展示与下载)。不假定 workspace 存在 classic 的 helper 或组件文件。
89
78
 
90
79
  ### 缩略图和点击大图
91
80
 
92
- 基础取图入口是 starter `src/lib/database-runtime.ts` 的 `fetchAttachmentCover(ref, size, { signal })`,返回 Blob。图片由宿主以当前访问者身份请求,经通用 HTTP bridge 返回。调用方用 `URL.createObjectURL(blob)` 展示,替换或卸载时取消请求并 revoke。`size` 控制封面请求尺寸,默认 360、最大 1280,可按展示需求调整;页面显示尺寸由样式决定,大图仍是封面。
93
-
94
- React 页面可选用 `src/lib/attachment-image.tsx` 的 `AttachmentImage`。它内部调用同一取图函数,封装可见时加载、取消请求、手动重试和 Blob URL 释放;例如预览使用 `<AttachmentImage attachment={ref} alt={name} size={1280} />`。需要自定义展示时直接使用取图函数即可。
95
-
96
- 封面异步生成,保留占位和失败状态;自动重试按[工程质量](style-guide.md)设置有限预算,替换或卸载时取消。遇到 `HTTP_RESPONSE_TYPE_UNSUPPORTED` 或 `INVALID_HTTP_URL` 时,先核对是否使用当前 starter 的 helper、完整附件坐标和匹配的依赖版本。修正本地接入后重新构建并发布;接入正确但仍报错时,保留错误码与请求标识,报告平台能力限制并向平台支持反馈,不自行猜测域名或绕过代理。
81
+ 封面是异步生成的预览图,大图仍不是原文件。保留加载占位和失败状态,重试有有限预算,替换资源或卸载时取消请求并释放本地 URL。封面失败不能禁用独立的原文件下载;需要修复 classic 接入时按[封面 helper 排障](legacy-file-transfer.md#缩略图和点击大图)处理。
97
82
 
98
83
  ### 原文件下载
99
84
 
100
- 临时链接交给浏览器原生下载,文件字节不经 Page JavaScript。文件名由服务端 Content-Disposition 决定,跨源 download 属性不能保证自定义文件名。父页面 iframe 需允许下载;缺少 allow-downloads 时浏览器可能拦截,需区分配置限制与链接获取失败。
85
+ 每次用户下载重新取得短时效链接,不写入 Base 或长期缓存;原文件下载不使用 width/height 请求缩略图。通过当前 SDK 或 classic helper 请求宿主打开,不在 iframe 内设置跨源 a[download]、模拟点击或修改 window.location 来绕过宿主。文件名以服务端 Content-Disposition 为准。
101
86
 
102
- 每次用户下载时获取链接,不将其写入 Base 或长期缓存;链接过期时重新获取。下载端点提供原文件,width/height 不能用来请求缩略图。
87
+ 宿主受理打开请求不证明浏览器已完成落盘,只能提示已请求打开。点击过程中管理加载状态并显示必要错误,不静默失败;classic 的调用方式见[原文件下载](legacy-file-transfer.md#原文件下载)。
103
88
 
104
89
  ## 写单元格
105
90
 
@@ -123,15 +108,7 @@ React 页面可选用 `src/lib/attachment-image.tsx` 的 `AttachmentImage`。它
123
108
 
124
109
  ## 限制与错误处理
125
110
 
126
- | 条件/错误 | 处理 |
127
- | --- | --- |
128
- | INVALID_ATTACHMENT_TARGET | 区分文件类型/大小与应用绑定配置;修正对应输入,不重复发送同一错误请求 |
129
- | ATTACHMENT_UNAVAILABLE | 父页面不支持当前附件接口,报告环境能力限制 |
130
- | ATTACHMENT_UPLOAD_FAILED / STALLED | 显示进度或网络问题;检查是否已上传,不自动重传 |
131
- | 位置不匹配或没有封面 | 核对坐标与应用鉴权;封面未就绪按有限重试处理 |
132
- | 下载操作无响应 | 核对代理错误及 iframe 下载设置;不因缺 gatewayOrigin 直接禁用下载 |
133
- | 单元格已满或出现 ignored_fields | 不报告全部成功;指出未写入项及原因 |
134
- | property.capture 字段 | 上传挂载可能被忽略;读取和移除按对应协议处理 |
111
+ SDK 按已安装版本的错误契约处理;classic 的错误码分流与 helper 恢复步骤见[存量错误处理](legacy-file-transfer.md#限制与错误处理)。能力缺失时报告平台限制,非法输入先修正,单元格已满或出现 ignored_fields 不报告全部成功。上传或挂载结果未知仍按[只读核对](#超时与结果未知)执行,不重复写入。
135
112
 
136
113
  当前约束包括单文件 2 GB、单元格 100 个附件、Base 附件计数上限 2,000,000;单文件检查属于父页面实现,不代表平台所有接口的统一上限,也不提供累计体积限制。业务需要累计限额时另行控制。附件不能跨 Base 复用;移除引用不释放云盘文件或累计计数。限制变化时以目标环境契约核实,不反复试探上限。
137
114
 
@@ -122,7 +122,7 @@
122
122
 
123
123
  下拉、日期、时间与菜单须同时处理触发器和展开面板,面板、选项及选中/禁用/焦点状态继承当前主题,Portal 也不能丢失配色。
124
124
 
125
- **本地、mock、不发布和省开发时间都不能成为使用未经设计的系统弹层的理由。** 除用户明确要求或平台硬约束外,不用浏览器原生 `select`、日期/时间弹层作为可见选择界面。先复用现有可主题化组件;缺失时按工程依赖规则采用成熟实现,不为统一外观重写完整日历、定位或焦点管理内核。补充组件时优先选择与现有 React、Tailwind、CVA 兼容的无头原语或轻量实现(如 Popover、Listbox、日历类组件),不引入第二套完整组件库或另一套 CSS 体系;只加当前用到的组件。默认组件栈与 starter 一致:Radix 无头原语(`@radix-ui/react-popover`、`@radix-ui/react-select`)负责弹层、定位与焦点,`react-day-picker` 负责日历;把工程主题变量映射到这些组件的 className,不为它们另写一套颜色。
125
+ **本地、mock、不发布和省开发时间都不能成为使用未经设计的系统弹层的理由。** 除用户明确要求或平台硬约束外,不用浏览器原生 `select`、日期/时间弹层作为可见选择界面。先复用现有可主题化组件;缺失时按工程依赖规则采用成熟实现,不为统一外观重写完整日历、定位或焦点管理内核。补充组件时优先选择与现有 React、Tailwind、CVA 兼容的无头原语或轻量实现(如 Popover、Listbox、日历类组件),不引入第二套完整组件库或另一套 CSS 体系;只加当前用到的组件。缺少弹层或日历组件时,默认采用 Radix 无头原语(`@radix-ui/react-popover`、`@radix-ui/react-select`)负责弹层、定位与焦点,`react-day-picker` 负责日历;starter 未预装,用到时按[第三方依赖策略](development.md#第三方依赖策略)添加。把工程主题变量映射到这些组件的 className,不为它们另写一套颜色。
126
126
 
127
127
  | 组件 | 当前用到时保留 |
128
128
  | --- | --- |
@@ -0,0 +1,120 @@
1
+ # 老模板 AI 调用参考
2
+
3
+ 适用于使用当前工程 helper 的 classic;先核对实际导出和参数类型。新 SDK 工程读取工程 node_modules/@lark-base-open/base-database-app-sdk/docs/README.md,当前业务协议与交付流程见[开发指引](development.md)。
4
+
5
+ ## Page 调用方式
6
+
7
+ 本节针对存量 classic helper,实现 AI Function 不需要安装、替换或选择 SDK;新建 workspace 按已安装 SDK 文档使用。修改已有工程时,除非用户明确要求升级页面依赖,否则保留已有 `package.json` 与 lockfile,不因新增 AI Function 自行改依赖。
8
+
9
+ starter 的 `page/src/lib/database-runtime.ts` 导出 key 化调用入口。调用 `callSiteAIFunction` 时显式提供与配置一致的 `capability`:text/vision 走流式聚合,image/video 走任务提交。页面统一使用这些 helper,由 SDK 处理流式和媒体任务通信。Page 不得自行调用全局 `fetch` 绕过 SDK,也不得在代理失败时降级直连。
10
+
11
+ | 能力 | Page 本次输入 | 推荐入口 | 完成条件 |
12
+ | ------ | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | -------------------------------- |
13
+ | text | `messages` + 可选 `params` | `invokeSiteAIFunctionStream` 需要逐帧 UI;`callSiteAIFunction` 需额外传 `capability:'text'` 取得聚合文本 | `onDone` 或 `{type:'text'}` |
14
+ | vision | 多模态 `messages` + 可选 `params` | 与 text 相同;统一入口传 `capability:'vision'`,输入类型必须属于模型 Profile 的 `input_modalities` | `onDone` 或 `{type:'text'}` |
15
+ | image | `capability:'image'` + `input` + 可选 `params` | `createSiteAIFunctionTask`,也可用统一入口创建任务 | `succeeded` 且读取 `imageAssets` |
16
+ | video | `capability:'video'` + `input` + 可选 `params` | `createSiteAIFunctionTask`,也可用统一入口创建任务 | `succeeded` 且读取 `videoAsset` |
17
+
18
+ ```ts
19
+ import {
20
+ callSiteAIFunction,
21
+ invokeSiteAIFunctionStream,
22
+ createSiteAIFunctionTask,
23
+ } from './lib/database-runtime';
24
+
25
+ // 本例调用 text,因此只处理 text 结果。
26
+ const result = await callSiteAIFunction({
27
+ functionKey: 'recommend_dishes',
28
+ capability: 'text',
29
+ params: { menu: '...' },
30
+ messages: [
31
+ {
32
+ role: 'user',
33
+ content: [{ type: 'text', text: '按预算 100 元推荐两道菜' }],
34
+ },
35
+ ],
36
+ });
37
+ if (result.type === 'text') {
38
+ showAnswer(result.content); // 替换为实际的页面状态更新
39
+ }
40
+
41
+ // 显式流式(text/vision):逐帧增量
42
+ const stream = invokeSiteAIFunctionStream({
43
+ functionKey: 'recommend_dishes',
44
+ messages: [
45
+ { role: 'user', content: [{ type: 'text', text: '概括今天的缺货风险' }] },
46
+ ],
47
+ params: { menu: '...' },
48
+ });
49
+ // reasoning 模型会先持续下发 delta.reasoningContent,再下发 delta.content。
50
+ // 只消费 content 会让「思考过程」区域一直为空,看起来像没有流式输出,必须两者都消费。
51
+ stream.onMessage((delta) => {
52
+ if (delta.reasoningContent) appendReasoning(delta.reasoningContent);
53
+ if (delta.content) appendAnswer(delta.content);
54
+ });
55
+ stream.onError((error) => showError(error.message));
56
+ stream.onDone(() => markAnswerComplete());
57
+ // 只在用户取消、组件卸载或新请求替代旧请求时调用;不要在注册回调后立即销毁。
58
+ const cancel = () => stream.destroy();
59
+ // appendReasoning、appendAnswer、showError、markAnswerComplete 都是页面自己的状态更新函数。
60
+
61
+ // 多模态理解仍使用 capability:'vision'。content part 统一为 text、image、video、audio、file;
62
+ // 实际可用组合以 model_profiles 返回的 input_modalities 为准。
63
+ const multimodal = invokeSiteAIFunctionStream({
64
+ functionKey: 'understand_assets',
65
+ messages: [
66
+ {
67
+ role: 'user',
68
+ content: [
69
+ { type: 'text', text: '总结这些素材' },
70
+ { type: 'image', url: imageUrl, detail: 'high' },
71
+ { type: 'video', url: videoUrl, fps: 2 },
72
+ { type: 'audio', url: audioUrl },
73
+ { type: 'file', url: pdfUrl, filename: 'report.pdf' },
74
+ ],
75
+ },
76
+ ],
77
+ });
78
+
79
+ // 图片生成 / 文生视频:提交后必须轮询。
80
+ // image 完整可复用实现见 starter 的 `ImageTaskOperation.tsx`;video 参考 `ai-media-panel.tsx` 中的 `AIVideoPanel`。
81
+ const task = await createSiteAIFunctionTask({
82
+ functionKey: 'make_promo',
83
+ capability: 'image',
84
+ input: {
85
+ prompt: '保持角色一致,生成一组新品海报',
86
+ image: ['https://example.com/ref-1.png', 'https://example.com/ref-2.png'],
87
+ },
88
+ });
89
+ ```
90
+
91
+ 公开协议不暴露供应商字段,五类 part 固定为 `{type:'text', text}`、`{type:'image', url, detail?}`、`{type:'video', url, fps?}`、`{type:'audio', url}`、`{type:'file', url, filename?}`。四类非文本输入统一使用 `url`,不支持 `file_id`;本地文件先编码成 data URL。后端 Ark adapter 会把 image/video 转成 `image_url`/`video_url` 对象,把音频 URL 转成 `input_audio.url + format`(format 按链接后缀推断),把音频 data URL 拆成 `input_audio.data + format`,把文件映射为 `file.file_url` 或 `file.file_data`。
92
+
93
+ 文件理解当前只支持 PDF,单文件不得超过 50 MB。公网 URL 必须是 HTTP(S),路径以 `.pdf` 结尾;若签名 URL 的路径没有后缀,必须补 `filename:'*.pdf'`。本地 PDF 使用 `data:application/pdf;base64,...`,并且必须带 `filename:'*.pdf'`。`filename` 只用于校验和 data URL 场景的 Ark 请求;URL 场景不会把它透传给供应商。Chat 文件理解返回仍是文本流,不新增文件输出类型。
94
+
95
+ `reasoningContent` 是模型思考过程增量,`content` 是最终回答增量:两者分区渲染,思考过程放较小的过程区域,最终回答进正式结果区。**要从结果里解析结构化列表时,基于最终 answer(`content` 累积值)解析,不要基于 reasoning 内容解析。** 业务页面只处理 SDK 返回的 `{ content?, reasoningContent?, raw }`,无需自行解析原始流式传输格式。
96
+
97
+ `SiteAIFunctionResult` 是可判别联合(用 `switch(result.type)` 判别,避免字符串解析媒体结果):`{ type:'text', content }` / `{ type:'image_task', taskId, status }` / `{ type:'video_task', taskId, status }`。Ark Chat 的 `choices.message.content` / `choices.delta.content` 是文本,因此 vision 表示多模态输入理解、文本输出;它不会在 Chat 响应中生成图片、视频或音频。需要媒体输出时必须显式调用 image/video AI Function 的任务接口,任务完成判定统一见[任务受理与完成](ai-function.md#任务受理与完成),classic 结果字段分别为 imageAssets / videoAsset。所有响应携带 `requestId`,用于监控与排查。
98
+
99
+ 媒体任务只允许运行时覆盖有限字段:image 使用 `input.prompt` / `input.size` / `input.image`,video 使用 `input.prompt` / `input.image_url` / `input.duration`;model、张数、比例、水印等保持在 AI Function 配置中。`input.image` 接受单个字符串或字符串数组,数量上限按[模型能力](ai-function.md#可用模型-profile)核对;`input.duration` 必须是正数,并会按模型 Profile 上限收紧。图片生成参考 starter 的 `page/src/examples/ai-function/ImageTaskOperation.tsx`(只渲染 `imageAssets`),文生视频参考同目录 `ai-media-panel.tsx` 中的 `AIVideoPanel`(渲染 `videoAsset`)。两个示例按[任务受理与完成](ai-function.md#任务受理与完成)轮询,在新请求时通过 `requestSeq` 忽略旧任务结果,且带总轮询时限(`pollDeadlineMs`,默认 5 分钟)以避免死轮询;组件卸载时也停止 timer。不要用没有总时限或取消处理的 `while` 轮询。
100
+
101
+ `messages[].content` 必须是非空 content part 数组,不接受字符串。业务调用只允许 `user` / `assistant`:`user` 可传 `text`、`image`、`video`、`audio`、`file`,`assistant` 只允许 `text`;System Prompt 只能由 AI Function 配置管理,调用方不得发送 `system`。每个 message 与 part 都采用严格字段白名单,多余字段会被拒绝。
102
+
103
+ 图片 `detail` 仅允许 `low` / `high` / `xhigh`,视频 `fps` 仅允许 `[0.2, 5]`。媒体与文件 `url` 必须是非空 HTTP(S) URL 或合法 data URL;音频 data URL 的 MIME 必须对应 `mp3` / `wav` / `aac` / `m4a` / `pcm` / `ac3` / `alac`。音频 HTTP(S) URL 的路径后缀必须是这些格式之一(Ark 要求显式 format,服务端按后缀推断,签名参数不受影响),没有可识别后缀的链接请改传音频 data URL。文件只接受 PDF,并遵循上一段的 filename 和大小约束。每个 part 还必须命中所选 Profile 的 `input_modalities`。不要用 `any` 或自行 `fetch` 绕过公开类型与服务端校验。
104
+
105
+ ### 页面如何处理运行态错误
106
+
107
+ 页面只能可靠地按错误性质处理。收到 AI credit、并发限制或服务错误时,保留 `error.code`、`error.message` 和本次 `requestId`,结束 loading,并按错误是否可重试给出提示;不要在页面里自动重试,更不要绕过 AI Function 直连模型。
108
+
109
+ AI credit 耗尽会作为不可重试的错误返回,消息为 `AI credit is exhausted`。应提示应用 owner 检查可用 credit 或联系平台支持,不能把它当作网络故障反复重试。
110
+
111
+ ## 页面实现检查
112
+
113
+ 1. 页面按 `functionKey` 调用;`callSiteAIFunction` 显式传与配置相同的 `capability`。System Prompt / model / 参数由 AI Function 配置声明,`messages/input` 与 `params` 是本次运行输入。
114
+ 2. 指定模型或参数前先查 `/open-apis/base/v3/sites/:token/ai/model_profiles`;`:token` 取当前应用配置的 `appToken`,能力标记必须与 `capability_type` 匹配。
115
+ 3. 用 `switch(result.type)` 判别渲染,不直接渲染 `delta.raw`;流式每个面板只有一个活动 handle,取消与卸载均调用 `destroy()`。
116
+ 4. text/vision 流式同时消费 `delta.reasoningContent` 与 `delta.content`(或用 `readSiteAITextDelta` 取 `{ answer, reasoning }`),分区渲染;结构化解析只基于最终 answer。
117
+ 5. `onError` 与 `onDone` 都结束 loading;image/video 用 `getSiteAIFunctionTask` 轮询到 `succeeded`/`failed`/`cancelled` 收尾。
118
+ 6. vision 不绕过公开 `SiteAIMessage` 类型猜测媒体 content;只提交所选 Profile 的 `input_modalities` 已声明的 image / video / audio / file,未暴露对应输入契约时明确报告阻塞。
119
+ 7. AI 调用走 AI Function,页面不保存模型凭证。
120
+ 8. 与 Base 数据组合时,查询仍走 Database Function;写入按[Mutation 与 FaaS 分工](mutations.md#写入方式选择)选择。
@@ -0,0 +1,156 @@
1
+ # 老模板页面参考
2
+
3
+ 用于保留工程内 helper 的 classic。先按[统一调用契约判据](development.md#function-调用契约)分流;本文件分别给出命名对象和位置数组示例,有无 SDK 不是参数形态判据。已使用 SDK 的 API 以安装包文档为准。
4
+
5
+ ## 老模板参考
6
+
7
+ 本文件的工程内 helper 与 channel 接入说明供老模板工程使用,配套附件说明见[文件传输](file-transfer.md)。未接入外链保护的旧工程,先核对入口与已安装 channel 版本;经用户同意后升级到 `@lark-base-open/base-site-channel` >= 0.1.5,在 `page/src/main.tsx` 应用挂载前从 `@lark-base-open/base-site-channel/runtime` 导入并调用一次 `installLinkGuard()`。已有该调用的工程保持即可,不重复安装,也不迁移工程结构。新 SDK 工程的能力与升级方式以包内 docs 为准。
8
+
9
+ ## Function 调用契约
10
+
11
+ 示例适用条件只由[统一判据](development.md#function-调用契约)定义;不要强制安装 SDK 或覆盖现有 helper。
12
+
13
+ ### 命名对象 helper
14
+
15
+ <!-- example: classic-named -->
16
+ ```ts
17
+ import { invokeDatabaseFunction } from './lib/database-runtime';
18
+ export const listTasks = () =>
19
+ invokeDatabaseFunction<{ rows: unknown[] }>('listTasks', { status: '待处理' });
20
+ ```
21
+
22
+ ### 位置参数 helper
23
+
24
+ Page 与 Function 之间使用固定的调用契约。Page 侧三类 Function 都通过 `invokeDatabaseFunction(functionId, params)` 调用,但 `params` 类型不同:
25
+
26
+ `functionId` 使用源码目录名,是工程常量。应用 token 由 `page/src/lib/database-runtime.ts` 从产物托管路径解析,不由业务代码传入;FaaS 内部的 `context.invokeFunction` 仍使用 `{projectId,functionId,params}`,两者不要混用。
27
+
28
+ | Function | `params` | 实现 | 结果 |
29
+ | ---------------------- | ------------------------------------------ | ------------------------ | ------------------------------------------------------------------------------------ |
30
+ | Database Function | 按 `$1`、`$2` 排列的数组 | `main.sql` + `meta.json` | 一层 `{data:{rows},code,msg}` |
31
+ | Mutation | 声明顺序的位置数组;多组参数用批量 helper | `spec.json` + `meta.json` | 一层 `{data:{record_ids,records?,record_not_found?,ignored_fields?},code,msg}` |
32
+ | FaaS | 业务对象 | `index.ts` + `meta.json` | 一层 `{data,code,msg}`,`data` 是 handler 业务数据 |
33
+
34
+ Database Function 查询示例:
35
+
36
+ <!-- example: classic-positional -->
37
+ ```ts
38
+ import { invokeDatabaseFunction } from './lib/database-runtime';
39
+ export const listTasks = () =>
40
+ invokeDatabaseFunction<{ rows: unknown[] }>('listTasks', ['待处理']);
41
+ ```
42
+
43
+ Mutation 一组参数使用 `invokeDatabaseFunction(functionId, params)`,每组操作一条记录;多组参数使用 `invokeDatabaseMutationBatch(functionId, parameterGroups)`,包装成 `{batch:[{params:[...]}]}`,不能与顶层 params 混用。两个 helper 均从 `page/src/lib/database-runtime.ts` 导出。`code=0` 仍须检查 `data.record_not_found/ignored_fields`,见[调用与结果](mutations.md#调用与结果)。
44
+
45
+ FaaS 创建操作示例:
46
+
47
+ ```ts
48
+ await invokeDatabaseFunction<{ created: boolean | null }>('createTask', {
49
+ title: '准备评审',
50
+ status: '待处理',
51
+ });
52
+ ```
53
+
54
+ 契约生成与 check 的职责、依赖准备顺序见[本地检查与契约生成](development.md#本地检查与契约生成)。classic 的自动生成文件是 `page/src/lib/database-function-inputs.generated.ts`,不手改;具体参数形态按上方已选择的分支使用。
55
+
56
+ metadata 只声明输入,因此生成文件只约束调用参数。调用结果仍由 Page 按 operation 定义
57
+ `invokeDatabaseFunction<TData>` 的 `TData`,并在运行时校验真实响应;CLI 不根据 handler
58
+ 实现或查询投影猜测返回类型。生成类型覆盖标量类型、对象属性、必填项、枚举、数组元素和
59
+ `prefixItems` 位置,以及 Database Function 的固定参数 tuple;`minimum`、`maximum`、`minLength`、
60
+ `maxLength`、非固定数组的 `minItems` / `maxItems` 和对象精确性仍由 Function 运行时校验;
61
+ 数组的元素类型和 `prefixItems` 位置仍保留在生成类型中。TypeScript 类型不能替代输入解析。
62
+
63
+ `invokeDatabaseFunction` 调用统一网关的 `POST /space/api/bitable/site/v1/:token/invoke_function/:function_id`,由 BaseApp 父页面以同源身份代发;应用 token 与环境由 `src/lib/database-runtime.ts` 统一解析,`env` 走 query,请求体固定为 `{"params": <上述 params>}`。返回统一包裹结构 `{code,msg,data}`,页面使用当前登录用户身份,不保存也不传递任何凭证。
64
+
65
+ ## Page 调用
66
+
67
+ 外链由页面 Runtime 统一接管,并经宿主安全检查后打开。默认直接使用 a 标签,程序化打开使用 `@lark-base-open/base-site-channel/runtime` 的 `openLink(url)`;保留 starter 启动时的 `installLinkGuard()` 接入。页面导航留在 iframe 内,不使用 location 跳出 iframe,也不依赖宿主放开 sandbox。
68
+
69
+ 默认 Page 的 `page/index.html` 需要把 `<title>` 设置为本次生成的应用名称,不留空。
70
+
71
+ 默认 Page 必须引用并渲染 `page/src/components/floating-button/index.tsx` 中的 `FloatingButton` 组件。该组件自行解析应用 token,不接受 `projectId`。悬浮控件仅在正式环境向服务端判定有管理权限的访问者提供「编辑应用」入口。
72
+
73
+ 当前账号信息(头像、姓名、组织、退出登录)由**应用自己的导航**承载,用 `page/src/components/database-user-menu/index.tsx` 的 `DatabaseUserMenu`。账号菜单位于应用导航区域,例如顶栏右上角或侧边栏底部:
74
+
75
+ ```tsx
76
+ // 顶栏右上角
77
+ <header className="flex items-center justify-between ...">
78
+ <h1>设备台账</h1>
79
+ {/* 判据:员工 / 部门 / 领用归还属于组织内多角色协作 */}
80
+ <DatabaseUserMenu audience="enterprise" />
81
+ </header>
82
+
83
+ // 侧边栏左下角
84
+ <aside className="flex flex-col ...">
85
+ <nav className="flex-1">…</nav>
86
+ <DatabaseUserMenu audience="enterprise" align="left" side="up" />
87
+ </aside>
88
+ ```
89
+
90
+ `align` 控制弹层贴左还是贴右,`side` 控制向上还是向下展开,`showName={false}` 用于窄侧栏只留头像。
91
+
92
+ `audience` 控制是否展示账号信息:多人协作或对外共享的系统使用 `enterprise`;仅本人使用的系统可用 `personal`(不渲染菜单)。根据实际使用者与协作方式判断,不因出现“客户”“供应商”等实体名就认定为多人系统。无法确定时默认 enterprise,保留账号与退出入口;仅受众存在实质歧义时才询问。修改已有页面沿用原策略,除非本次需求改变受众。
93
+
94
+ `page/src/main.tsx` 已在首屏挂载后通过 `DatabaseRuntimeReady` 上报 `siteRuntime.ready()`,并在启动失败时上报 `reportLoadFailed`。宿主从握手完成起 10 秒内等不到 ready 会展示加载失败态,因此不要把 ready 上报移到数据加载完成之后,也不要删除该组件。
95
+
96
+ 涉及人员搜索或人员选择的页面,优先引用 `page/src/components/UserSelectorEditor` 和 `page/src/components/UserSelectorPanel` 等 `page/src/components/` 下的人员组件;只有现有组件无法满足交互契约时才做局部扩展。
97
+ 这些一方组件以及 `DatabaseUserMenu`、`FloatingButton`、`PageState`、`AttachmentImage` 内置中文、英文、日文固定文案,不依赖 Starling。组件统一按宿主 Runtime Context 的 locale → 浏览器语言 → 英语选择文案,无需 Page 传入或写死语言;宿主切换语言后,组件随重新加载的页面重新解析。Page 自己编写的业务文案仍由应用负责。
98
+ 选人组件返回的 `User.user_id` 是 Base 人员单元格使用的内部用户 ID。Mutation 的 `USER_ID` 参数传该 ID 字符串,`list:true` 时传 ID 数组;FaaS 下游人员单元格传 `[{"id": user.user_id}]`。`User.open_id` 只是可选的开放平台标识,不得填入应用记录写入 payload。
99
+
100
+ 业务请求集中在 operation/runtime client,不散落在组件中:
101
+
102
+ ```ts
103
+ import { invokeDatabaseFunction } from '../lib/database-runtime';
104
+
105
+ interface DatabaseRows<TRow> {
106
+ rows: TRow[];
107
+ columns?: unknown[];
108
+ row_count?: number;
109
+ log_id?: string;
110
+ }
111
+ ```
112
+
113
+ 浏览器 SDK 对 Database Function、Mutation 和 FaaS 都只返回一层 `{data,code,msg}`。`invokeDatabaseFunction<TData>` 的 `TData` 只描述当前 operation 约定的顶层 `data`:Database Function 通常是 ResultJSON,FaaS 则以各 handler 的业务结果为准,不能统一假设存在 `recordId`。页面只检查一次顶层 `code`,再按 operation 契约校验 `data`;不得写成 `invokeDatabaseFunction<FaasHandlerResult<TData>>`,也不得对 `result.data` 二次解包。否则后端已经写入成功时,页面仍可能误报失败。
114
+
115
+ 运行时业务数据在边界处校验,不能只依赖 TypeScript 泛型。`functionId` 和所有路由是工程常量;用户输入只进入已声明的业务参数。
116
+
117
+ Page 的所有业务 HTTP 都经父页面代理,使用 `page/src/lib/database-runtime.ts` 导出的 `fetch` 或 `invokeHttp`,URL 必须是以单个 `/` 开头的同源相对路径;绝对 URL、跨域 URL、路径穿越以及 Cookie、Authorization、Host、Origin 等受限 Header 都会被父页面拒绝。请求体只支持字符串,4xx/5xx 会正常返回 `Response`,业务必须自行判断 `response.ok`。禁止直连业务域名,也不得把直连作为代理失败时的兜底。Page 发起的 Base 业务读取和写入分别走 Database Function 与 Mutation/FaaS。
118
+
119
+ ## AI 对话与调用
120
+
121
+ AI 调用使用 AI Function,不创建 FaaS 模型代理,也不直连模型域名。
122
+ Preview 使用草稿版本;Prod 使用正式发布的版本。Function 配置为 `disabled: true` 时不得调用。
123
+ 能力归属按运行场景判断:面向当前页面业务流程的生成、分类、总结和推荐使用 AI Function;Base 查询使用 Database Function,写入按[写入方式选择](mutations.md#写入方式选择)处理。
124
+
125
+ Page 需要 AI 对话、生成、分类、总结、文生图或文生视频时,默认按 `functionKey` 使用 `page/src/lib/database-runtime.ts` 导出的 `callSiteAIFunction` / `invokeSiteAIFunctionStream`,不创建 FaaS 模型代理,也不直连模型域名。AI 能力被收口成一类版本化托管的 AI Function 配置;四类能力配置契约、CLI 建模/调试、计费与单流约束见 [AI Function](ai-function.md)。starter 的 `page/src/examples/ai-function/TextStreamOperation.tsx` 提供最小组件示例。搭建时可复用这些示例的界面及 `ai-copy.ts`,保留 `useUiLanguage()` 接入;内置标题、提示、按钮、任务状态和本地兜底错误自动跟随宿主 locale → 浏览器语言 → 英语。Page 显式传入的 `title` 由 Page 自行处理,服务端错误与 AI 生成内容保留原文。
126
+
127
+ AI 与 Base 数据组合时保持既有边界:先用 Database Function 读取,再由 Page 裁剪必要数据并拼入 `messages` 或 `params`;需要把结果写回 Base 时按[写入方式选择](mutations.md#写入方式选择)另行调用 Mutation 或 FaaS。AI 调用本身不经过 FaaS。
128
+
129
+
130
+ ## classic AI 示例
131
+
132
+ classic 已有 `page/src/examples/ai-function/TextStreamOperation.tsx` 与 `ai-copy.ts` 时可复用,保留 `useUiLanguage()`,内置文案随宿主 locale → 浏览器语言 → 英语选择语言。workspace 不依赖这两个工程文件,使用已安装 SDK 文档。
133
+
134
+ ## Mutation 调用
135
+
136
+ 仍按[Function 调用契约](development.md#function-调用契约)核对实际 helper。以下位置参数按 mutations.md 中 renameTasks/title,taskId 和 createTask/title 的声明顺序;命名 helper 改用对象,结果检查复用[调用与结果](mutations.md#调用与结果)。
137
+
138
+ <!-- example: classic-positional-mutation -->
139
+ ```ts
140
+ import { invokeDatabaseFunction, invokeDatabaseMutationBatch } from './lib/database-runtime'
141
+ export async function writeTasks() {
142
+ const renamed = await invokeDatabaseFunction('renameTasks', ['统一标题', 'recA'])
143
+ const created = await invokeDatabaseMutationBatch('createTask', [['准备评审'], ['补充文档']])
144
+ return [renamed, created]
145
+ }
146
+ ```
147
+
148
+ <!-- example: classic-named-mutation -->
149
+ ```ts
150
+ import { invokeDatabaseFunction, invokeDatabaseMutationBatch } from './lib/database-runtime'
151
+ export async function writeTasks() {
152
+ const renamed = await invokeDatabaseFunction('renameTasks', {title:'统一标题', taskId:'recA'})
153
+ const created = await invokeDatabaseMutationBatch('createTask', [{title:'准备评审'}, {title:'补充文档'}])
154
+ return [renamed, created]
155
+ }
156
+ ```
@@ -0,0 +1,68 @@
1
+ # 老模板附件参考
2
+
3
+ 仅供保留工程内附件 helper 的 classic。公共资源标识、权限、图片尺寸、写入结果与未知状态处理以[文件传输](file-transfer.md)为唯一事实源;SDK 工程读取已安装包文档。
4
+
5
+ ## 上传
6
+
7
+ 上传调用、输入来源和上传成功的含义统一见[公共上传协议](file-transfer.md#上传);本文件只补充 classic 特有的实现与恢复。
8
+
9
+ ### 图片宽高
10
+
11
+ 上传前的图片宽高读取与代码只维护在[公共上传协议](file-transfer.md#图片宽高)。将其返回尺寸与上传 fileToken 一起交给后续挂载,不在这里复制另一份实现。
12
+
13
+ ### 进度与即时展示
14
+
15
+ 公共进度、成功判定和本地预览语义见[上传进度](file-transfer.md#进度与即时展示)。
16
+
17
+ 当前停滞检测从首条进度事件之后开始:连续 120 秒无新进度可能返回 ATTACHMENT_UPLOAD_STALLED。首条事件前仍可能等待至调用超时;页面应有自己的等待提示与最大等待策略,不自动重传。调用超时不证明父页面已取消上传。
18
+
19
+ ## 展示与下载
20
+
21
+ 从 starter runtime 导入 helper,并准备真实位置:
22
+
23
+ ```ts
24
+ const context = await resolveDatabaseContext()
25
+ const ref = { tableId, fieldId, recordId, fileToken }
26
+ ```
27
+
28
+ 封面和下载 helper 负责生成 extra,其中 siteToken 和 siteEnv 指定应用及 Preview/正式环境,宿主校验其与当前页面一致。业务代码不手工拼接 extra,也不移除该字段来尝试底表鉴权。不存在、错位或无权限的附件可能返回错误或无可展示内容。
29
+
30
+ | 操作 | helper 与结果 | 前置条件 |
31
+ | --- | --- | --- |
32
+ | 封面/大图 | `await fetchAttachmentCover(ref, 360)` 返回 Blob | 需要支持 HTTP 二进制响应的宿主和完整附件坐标;不需要 iframe 推断 gatewayOrigin |
33
+ | 用户下载原文件 | `await openAttachmentDownload(context, ref)` 请求宿主打开下载链接 | 每次经父页面获取临时链接,再经宿主 `openLink` 打开 |
34
+ | 临时 URL | `await fetchAttachmentDownloadUrl(context, ref)` 返回短时效链接 | 仅供需要 URL 本身的其他能力,不作为下载按钮入口 |
35
+
36
+ ### 缩略图和点击大图
37
+
38
+ 基础取图入口是 starter `src/lib/database-runtime.ts` 的 `fetchAttachmentCover(ref, size, { signal })`,返回 Blob。图片由宿主以当前访问者身份请求,经通用 HTTP bridge 返回。调用方用 `URL.createObjectURL(blob)` 展示,替换或卸载时取消请求并 revoke。`size` 控制封面请求尺寸,默认 360、最大 1280,可按展示需求调整;页面显示尺寸由样式决定,大图仍是封面。
39
+
40
+ React 页面可选用 `src/lib/attachment-image.tsx` 的 `AttachmentImage`。它内部调用同一取图函数,封装可见时加载、取消请求、手动重试和 Blob URL 释放;例如预览使用 `<AttachmentImage attachment={ref} alt={name} size={1280} />`。需要自定义展示时直接使用取图函数即可。
41
+
42
+ 封面异步生成,保留占位和失败状态;自动重试按[工程质量](style-guide.md)设置有限预算,替换或卸载时取消。遇到 `HTTP_RESPONSE_TYPE_UNSUPPORTED` 或 `INVALID_HTTP_URL` 时,先核对是否使用当前 starter 的 helper、完整附件坐标和匹配的依赖版本。修正本地接入后重新构建并发布;接入正确但仍报错时,保留错误码与请求标识,报告平台能力限制并向平台支持反馈,不自行猜测域名或绕过代理。
43
+
44
+ ### 原文件下载
45
+
46
+ 下载按钮从 starter `src/lib/database-runtime.ts` 导入并调用 `openAttachmentDownload(context, ref)`;当前附件位置 `ref` 按上文准备:
47
+
48
+ ```ts
49
+ const context = await resolveDatabaseContext()
50
+ await openAttachmentDownload(context, ref)
51
+ ```
52
+
53
+ helper 经父页面取得临时 URL,再通过 Channel openLink 请求宿主打开;调用方捕获错误并结束加载。下载成功如何表述、链接生命周期及浏览器限制统一见[公共下载语义](file-transfer.md#原文件下载)。
54
+
55
+ ## 限制与错误处理
56
+
57
+ | 条件/错误 | 处理 |
58
+ | --- | --- |
59
+ | INVALID_ATTACHMENT_TARGET | 区分文件类型/大小与应用绑定配置;修正对应输入,不重复发送同一错误请求 |
60
+ | ATTACHMENT_UNAVAILABLE | 父页面不支持当前附件接口,报告环境能力限制 |
61
+ | ATTACHMENT_UPLOAD_FAILED / STALLED | 显示进度或网络问题;检查是否已上传,不自动重传 |
62
+ | 位置不匹配或没有封面 | 核对坐标与应用鉴权;封面未就绪按有限重试处理 |
63
+ | 下载操作无响应 | 核对取临时 URL 和宿主 `openLink` 的错误,再检查浏览器下载结果;不因缺 gatewayOrigin 直接禁用下载 |
64
+ | 单元格已满或出现 ignored_fields | 不报告全部成功;指出未写入项及原因 |
65
+ | property.capture 字段 | 上传挂载可能被忽略;读取和移除按对应协议处理 |
66
+
67
+
68
+ 保留错误码与请求标识;位置、权限和写入未知的恢复边界以[公共协议](file-transfer.md#超时与结果未知)为准。