@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.
- package/CHANGELOG.md +75 -0
- package/README.md +119 -15
- package/THIRD_PARTY_LICENSES.json +1662 -0
- package/config-schema.json +64 -3
- package/data/template-hmr-scripts.json +9 -0
- package/data/template-index-html/17e698eef687ece8f1628e3e2c4801da5e7233faa87076b3424acde8df57b825.html +24 -0
- package/dist/agent-tools-guide.d.ts +29 -0
- package/dist/agent-tools-guide.d.ts.map +1 -0
- package/dist/agent-tools-guide.js +169 -0
- package/dist/agent-tools-guide.js.map +1 -0
- package/dist/agent-tools-skill.d.ts +16 -0
- package/dist/agent-tools-skill.d.ts.map +1 -0
- package/dist/agent-tools-skill.js +183 -0
- package/dist/agent-tools-skill.js.map +1 -0
- package/dist/agent-tools.d.ts +20 -0
- package/dist/agent-tools.d.ts.map +1 -0
- package/dist/agent-tools.js +137 -0
- package/dist/agent-tools.js.map +1 -0
- package/dist/ai-functions.d.ts +10 -0
- package/dist/ai-functions.d.ts.map +1 -1
- package/dist/ai-functions.js +264 -212
- package/dist/ai-functions.js.map +1 -1
- package/dist/app-builder/core.d.mts +37 -0
- package/dist/app-builder/core.d.mts.map +1 -0
- package/dist/app-builder/core.mjs +673 -0
- package/dist/app-builder/core.mjs.map +1 -0
- package/dist/app-builder/package.json +1 -0
- package/dist/app-builder/schema.d.ts +4 -0
- package/dist/app-builder/schema.d.ts.map +1 -0
- package/dist/app-builder/schema.js +72 -0
- package/dist/app-builder/schema.js.map +1 -0
- package/dist/archive.d.ts +22 -2
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +311 -74
- package/dist/archive.js.map +1 -1
- package/dist/auth.d.ts +2 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +13 -8
- package/dist/auth.js.map +1 -1
- package/dist/build-server.d.ts +25 -0
- package/dist/build-server.d.ts.map +1 -0
- package/dist/build-server.js +32 -0
- package/dist/build-server.js.map +1 -0
- package/dist/business-update-notice.d.ts +37 -0
- package/dist/business-update-notice.d.ts.map +1 -0
- package/dist/business-update-notice.js +24 -0
- package/dist/business-update-notice.js.map +1 -0
- package/dist/check.d.ts +11 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +85 -15
- package/dist/check.js.map +1 -1
- package/dist/cloud-build-diagnostic.d.ts +9 -0
- package/dist/cloud-build-diagnostic.d.ts.map +1 -0
- package/dist/cloud-build-diagnostic.js +65 -0
- package/dist/cloud-build-diagnostic.js.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +41 -11
- package/dist/config.js.map +1 -1
- package/dist/contract-extractor.d.ts +21 -0
- package/dist/contract-extractor.d.ts.map +1 -0
- package/dist/contract-extractor.js +260 -0
- package/dist/contract-extractor.js.map +1 -0
- package/dist/contract-worker.d.ts +12 -0
- package/dist/contract-worker.d.ts.map +1 -0
- package/dist/contract-worker.js +90 -0
- package/dist/contract-worker.js.map +1 -0
- package/dist/dependency-policy.d.ts.map +1 -1
- package/dist/dependency-policy.js +6 -1
- package/dist/dependency-policy.js.map +1 -1
- package/dist/deploy.d.ts +20 -1
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +181 -52
- package/dist/deploy.js.map +1 -1
- package/dist/dev-bootstrap.d.ts +5 -0
- package/dist/dev-bootstrap.d.ts.map +1 -0
- package/dist/dev-bootstrap.js +185 -0
- package/dist/dev-bootstrap.js.map +1 -0
- package/dist/dev-events.d.ts +24 -0
- package/dist/dev-events.d.ts.map +1 -0
- package/dist/dev-events.js +67 -0
- package/dist/dev-events.js.map +1 -0
- package/dist/dev-pairing.d.ts +4 -0
- package/dist/dev-pairing.d.ts.map +1 -0
- package/dist/dev-pairing.js +54 -0
- package/dist/dev-pairing.js.map +1 -0
- package/dist/dev-url.d.ts +4 -0
- package/dist/dev-url.d.ts.map +1 -0
- package/dist/dev-url.js +29 -0
- package/dist/dev-url.js.map +1 -0
- package/dist/dev-vite.d.ts +9 -0
- package/dist/dev-vite.d.ts.map +1 -0
- package/dist/dev-vite.js +237 -0
- package/dist/dev-vite.js.map +1 -0
- package/dist/dev-watch.d.ts +33 -0
- package/dist/dev-watch.d.ts.map +1 -0
- package/dist/dev-watch.js +246 -0
- package/dist/dev-watch.js.map +1 -0
- package/dist/dev.d.ts +24 -0
- package/dist/dev.d.ts.map +1 -0
- package/dist/dev.js +244 -0
- package/dist/dev.js.map +1 -0
- package/dist/development-pairing.generated.d.ts +12 -0
- package/dist/development-pairing.generated.d.ts.map +1 -0
- package/dist/development-pairing.generated.js +13 -0
- package/dist/development-pairing.generated.js.map +1 -0
- package/dist/diagnostic-platforms.d.ts +3 -0
- package/dist/diagnostic-platforms.d.ts.map +1 -0
- package/dist/diagnostic-platforms.js +3 -0
- package/dist/diagnostic-platforms.js.map +1 -0
- package/dist/diagnostic-schema.d.ts +151 -0
- package/dist/diagnostic-schema.d.ts.map +1 -0
- package/dist/diagnostic-schema.js +129 -0
- package/dist/diagnostic-schema.js.map +1 -0
- package/dist/diagnostics.d.ts +78 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +333 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/distribution-commands.d.ts.map +1 -1
- package/dist/distribution-commands.js +6 -2
- package/dist/distribution-commands.js.map +1 -1
- package/dist/distribution-npm.d.ts +2 -2
- package/dist/distribution-npm.d.ts.map +1 -1
- package/dist/distribution-npm.js +14 -1
- package/dist/distribution-npm.js.map +1 -1
- package/dist/environment-variables.d.ts.map +1 -1
- package/dist/environment-variables.js +2 -1
- package/dist/environment-variables.js.map +1 -1
- package/dist/function-contracts.d.ts +40 -0
- package/dist/function-contracts.d.ts.map +1 -0
- package/dist/function-contracts.js +357 -0
- package/dist/function-contracts.js.map +1 -0
- package/dist/function-description.d.ts +11 -4
- package/dist/function-description.d.ts.map +1 -1
- package/dist/function-description.js +22 -12
- package/dist/function-description.js.map +1 -1
- package/dist/function-input-types.d.ts +6 -4
- package/dist/function-input-types.d.ts.map +1 -1
- package/dist/function-input-types.js +97 -135
- package/dist/function-input-types.js.map +1 -1
- package/dist/function-params.d.ts +53 -0
- package/dist/function-params.d.ts.map +1 -0
- package/dist/function-params.js +184 -0
- package/dist/function-params.js.map +1 -0
- package/dist/function-schema.d.ts +14 -0
- package/dist/function-schema.d.ts.map +1 -1
- package/dist/function-schema.js +99 -9
- package/dist/function-schema.js.map +1 -1
- package/dist/init-journal.d.ts +1 -0
- package/dist/init-journal.d.ts.map +1 -1
- package/dist/init-journal.js +21 -7
- package/dist/init-journal.js.map +1 -1
- package/dist/init.d.ts +1 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +55 -5
- package/dist/init.js.map +1 -1
- package/dist/lark-cli-error.d.ts +13 -2
- package/dist/lark-cli-error.d.ts.map +1 -1
- package/dist/lark-cli-error.js +54 -13
- package/dist/lark-cli-error.js.map +1 -1
- package/dist/lark-cli-passthrough.d.ts +9 -0
- package/dist/lark-cli-passthrough.d.ts.map +1 -0
- package/dist/lark-cli-passthrough.js +101 -0
- package/dist/lark-cli-passthrough.js.map +1 -0
- package/dist/lark-cli.d.ts +5 -2
- package/dist/lark-cli.d.ts.map +1 -1
- package/dist/lark-cli.js +96 -29
- package/dist/lark-cli.js.map +1 -1
- package/dist/legacy-function-input-renderer.d.ts +6 -0
- package/dist/legacy-function-input-renderer.d.ts.map +1 -0
- package/dist/legacy-function-input-renderer.js +175 -0
- package/dist/legacy-function-input-renderer.js.map +1 -0
- package/dist/link-guard-check.d.ts +12 -0
- package/dist/link-guard-check.d.ts.map +1 -0
- package/dist/link-guard-check.js +138 -0
- package/dist/link-guard-check.js.map +1 -0
- package/dist/managed-agent-docs.d.ts +14 -0
- package/dist/managed-agent-docs.d.ts.map +1 -0
- package/dist/managed-agent-docs.js +172 -0
- package/dist/managed-agent-docs.js.map +1 -0
- package/dist/mutation-schema.d.ts +6 -0
- package/dist/mutation-schema.d.ts.map +1 -1
- package/dist/mutation-schema.js +6 -0
- package/dist/mutation-schema.js.map +1 -1
- package/dist/mutation.d.ts +4 -1
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +17 -2
- package/dist/mutation.js.map +1 -1
- package/dist/npm.d.ts +1 -0
- package/dist/npm.d.ts.map +1 -1
- package/dist/npm.js +28 -0
- package/dist/npm.js.map +1 -1
- package/dist/preview-receipt.d.ts +0 -2
- package/dist/preview-receipt.d.ts.map +1 -1
- package/dist/preview-receipt.js +0 -28
- package/dist/preview-receipt.js.map +1 -1
- package/dist/process.d.ts +1 -0
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js +25 -0
- package/dist/process.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +239 -26
- package/dist/program.js.map +1 -1
- package/dist/project-build.d.ts +2 -1
- package/dist/project-build.d.ts.map +1 -1
- package/dist/project-build.js +53 -16
- package/dist/project-build.js.map +1 -1
- package/dist/project-capabilities.d.ts +8 -0
- package/dist/project-capabilities.d.ts.map +1 -0
- package/dist/project-capabilities.js +47 -0
- package/dist/project-capabilities.js.map +1 -0
- package/dist/project-context.d.ts +66 -0
- package/dist/project-context.d.ts.map +1 -1
- package/dist/project-context.js +68 -6
- package/dist/project-context.js.map +1 -1
- package/dist/project-layout.d.ts +11 -0
- package/dist/project-layout.d.ts.map +1 -1
- package/dist/project-layout.js +63 -1
- package/dist/project-layout.js.map +1 -1
- package/dist/public-exports.d.ts +5 -0
- package/dist/public-exports.d.ts.map +1 -0
- package/dist/public-exports.js +76 -0
- package/dist/public-exports.js.map +1 -0
- package/dist/public-sql-error.d.ts +3 -1
- package/dist/public-sql-error.d.ts.map +1 -1
- package/dist/public-sql-error.js +5 -2
- package/dist/public-sql-error.js.map +1 -1
- package/dist/pull.d.ts +1 -0
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +103 -20
- package/dist/pull.js.map +1 -1
- package/dist/sdk-codegen.d.ts +16 -0
- package/dist/sdk-codegen.d.ts.map +1 -0
- package/dist/sdk-codegen.js +181 -0
- package/dist/sdk-codegen.js.map +1 -0
- package/dist/sdk-install.d.ts +4 -0
- package/dist/sdk-install.d.ts.map +1 -0
- package/dist/sdk-install.js +33 -0
- package/dist/sdk-install.js.map +1 -0
- package/dist/skill-frontmatter.d.ts +5 -0
- package/dist/skill-frontmatter.d.ts.map +1 -0
- package/dist/skill-frontmatter.js +28 -0
- package/dist/skill-frontmatter.js.map +1 -0
- package/dist/skill.d.ts +2 -1
- package/dist/skill.d.ts.map +1 -1
- package/dist/skill.js +18 -12
- package/dist/skill.js.map +1 -1
- package/dist/source-format.d.ts +10 -0
- package/dist/source-format.d.ts.map +1 -0
- package/dist/source-format.js +49 -0
- package/dist/source-format.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/unified-functions.d.ts +22 -0
- package/dist/unified-functions.d.ts.map +1 -0
- package/dist/unified-functions.js +114 -0
- package/dist/unified-functions.js.map +1 -0
- package/dist/updates.d.ts +13 -1
- package/dist/updates.d.ts.map +1 -1
- package/dist/updates.js +65 -29
- package/dist/updates.js.map +1 -1
- package/dist/workspace-fingerprint.d.ts.map +1 -1
- package/dist/workspace-fingerprint.js +5 -0
- package/dist/workspace-fingerprint.js.map +1 -1
- package/package.json +17 -5
- package/skills/lark-base-database/SKILL.md +21 -55
- package/skills/lark-base-database/references/agent-tool-design.md +181 -0
- package/skills/lark-base-database/references/agent-tools.md +101 -0
- package/skills/lark-base-database/references/ai-function.md +80 -186
- package/skills/lark-base-database/references/database-function-limitations.md +12 -4
- package/skills/lark-base-database/references/database-function.md +49 -21
- package/skills/lark-base-database/references/development.md +81 -109
- package/skills/lark-base-database/references/environment-variables.md +2 -2
- package/skills/lark-base-database/references/faas.md +43 -16
- package/skills/lark-base-database/references/file-transfer.md +10 -33
- package/skills/lark-base-database/references/frontend-design-guide.md +1 -1
- package/skills/lark-base-database/references/legacy-ai-function.md +120 -0
- package/skills/lark-base-database/references/legacy-development.md +156 -0
- package/skills/lark-base-database/references/legacy-file-transfer.md +68 -0
- package/skills/lark-base-database/references/mutations.md +38 -29
- package/skills/lark-base-database/references/notifications.md +1 -1
- package/skills/lark-base-database/references/permission-design.md +11 -5
- package/skills/lark-base-database/references/release.md +22 -7
- package/skills/lark-base-database/references/verification.md +55 -16
- package/skills/lark-base-database/references/workspace-migration.md +86 -0
- package/skills/lark-base-database/references/workspace.md +55 -44
- package/templates/database-starter/README.md +2 -0
- package/templates/database-starter/database-functions/README.md +2 -2
- package/templates/database-starter/mutations/README.md +2 -2
- package/templates/database-starter/page/README.md +5 -4
- package/templates/database-starter/page/src/examples/ai-function/TextStreamOperation.tsx +6 -6
- package/templates/database-starter/page/src/lib/attachment-image.tsx +19 -5
- package/templates/database-starter/page/src/lib/database-runtime-attachment.test.ts +124 -5
- package/templates/database-starter/page/src/lib/database-runtime.test.ts +2 -2
- package/templates/database-starter/page/src/lib/database-runtime.ts +77 -13
- package/templates/database-starter/server-functions/scripts/run-tsc.mjs +3 -2
- package/templates/database-starter-v2/README.md +25 -0
- package/templates/database-starter-v2/base-app.config.ts +10 -0
- package/templates/database-starter-v2/database-functions/README.md +1 -0
- package/templates/database-starter-v2/gitignore +6 -0
- package/templates/database-starter-v2/mutations/README.md +1 -0
- package/templates/database-starter-v2/package-lock.json +2239 -0
- package/templates/database-starter-v2/package.json +18 -0
- package/templates/database-starter-v2/page/index.html +2 -0
- package/templates/database-starter-v2/page/package.json +25 -0
- package/templates/database-starter-v2/page/src/App.tsx +12 -0
- package/templates/database-starter-v2/page/src/generated/README.md +1 -0
- package/templates/database-starter-v2/page/src/index.css +1 -0
- package/templates/database-starter-v2/page/src/lib/date-time.ts +61 -0
- package/templates/database-starter-v2/page/src/main.tsx +6 -0
- package/templates/database-starter-v2/page/tsconfig.json +19 -0
- package/templates/database-starter-v2/page/vite.config.ts +3 -0
- package/templates/database-starter-v2/prettierignore +3 -0
- package/templates/database-starter-v2/server/functions/README.md +1 -0
- package/templates/database-starter-v2/server/functions/hello/contract.ts +5 -0
- package/templates/database-starter-v2/server/functions/hello/index.ts +7 -0
- package/templates/database-starter-v2/server/functions/hello/meta.json +1 -0
- package/templates/database-starter-v2/server/generated/runtime-profile.ts +5 -0
- package/templates/database-starter-v2/server/package.json +17 -0
- package/templates/database-starter-v2/server/tsconfig.json +14 -0
|
@@ -7,42 +7,61 @@
|
|
|
7
7
|
项目命令按 `--profile` → `larkProfile` → `LARKSUITE_CLI_PROFILE` → lark-cli 默认值选择。
|
|
8
8
|
直接调用原生 `lark-cli base +...` 时也必须传入同一个 `--profile <name>`,不能改用默认账号。
|
|
9
9
|
profile 决定账号与品牌,`--env` 决定运行环境。profile 缺失、未授权或与注入凭证冲突时停止,
|
|
10
|
-
|
|
10
|
+
不创建新账号、不回退。
|
|
11
11
|
|
|
12
12
|
新建、恢复或修改工程前读取。只读设计与评审不执行本文件中的资源变更。
|
|
13
13
|
|
|
14
|
+
## 环境与依赖
|
|
15
|
+
|
|
16
|
+
CLI/存量 classic 使用 Node.js 20.19+;新建 workspace 与契约生成使用 Node.js 22+。init 在建 Base/应用前检查版本,不满足时返回 `INIT_NODE22_REQUIRED`,升级 Node.js 后再运行 init。
|
|
17
|
+
|
|
18
|
+
`skill install` 安装用于搭建、修改和发布应用的开发者 Skill;外部 Agent 使用已发布业务功能时,按[站点 Skill 安装](agent-tools.md#安装到本地-agent)运行 `agent-tools skill install`。
|
|
19
|
+
|
|
20
|
+
公开 CLI 只使用 `online` 环境;`init`、`pull` 等支持环境参数的命令显式传 `--env online`,`deploy` 不接受该参数。CLI、OpenAPI、Accounts、应用和 Page runtime 必须处于同一环境;原生资源操作始终使用 `--as user`。
|
|
21
|
+
|
|
22
|
+
首次使用 `lark-cli` 时读取当前入口的 `--help`,本会话复用已确认的命令能力;不只按版本号判断。
|
|
23
|
+
|
|
24
|
+
| 能力 | 使用方式与缺失时处理 |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `lark-cli` 可执行文件 | 公开环境缺失时执行 `npx @larksuite/cli@latest install`,其他安装方式见 [github.com/larksuite/cli](https://github.com/larksuite/cli) |
|
|
27
|
+
| `api`、本任务需要的 `base` 命令 | 业务所需能力;按当前帮助和协议执行,真实认证、权限或接口错误按失败阶段处理 |
|
|
28
|
+
| `config` / `auth` | 本地账号管理能力,沿用当前任务选定的 profile;认证错误按[认证与重新授权](#认证与重新授权)处理 |
|
|
29
|
+
| `skills read` | 可选的文档入口。存在时读取 `lark-base` 并沿路由找 reference;不存在时直接读取环境提供的 lark-base 文件与相应命令帮助,后续不反复尝试该入口 |
|
|
30
|
+
| `doctor` | 排障入口,不是每次业务操作的必经步骤。真实认证、权限或接口错误按失败阶段处理 |
|
|
31
|
+
|
|
32
|
+
自动选择失败时,仅使用当前环境已确认的可执行文件绝对路径设置 `BASE_DATABASE_LARK_CLI_PATH`;不全盘搜索、循环重装或替换宿主认证。只有发生真实认证、身份或 scope 错误时才读取 lark-shared 并恢复原身份,不主动重登或切换 bot。
|
|
33
|
+
Windows 官方 npm 安装的 `lark-cli.cmd` 由 Base Database CLI 解析到同一安装目录下的原生 `lark-cli.exe`;手动指定路径时优先使用该 `.exe`。原生程序由官方安装脚本下载,不随 npm tarball 打包;若缺失,先在终端运行该安装入口的 `lark-cli --version` 完成初始化。该步骤只解决命令调用,不代表用户授权已完成。
|
|
34
|
+
|
|
35
|
+
优先使用本机已安装的 `base-database-cli`。已知全局安装存在但 PATH 异常时,使用确认过的可执行路径;不自动修改 shell 配置。没有可用本地入口时,回退 `npx @lark-base-open/base-database-cli`;需要固定版本时使用 `npx @lark-base-open/base-database-cli@<已确认的精确版本>`。不猜 npm scope,不全盘搜索或反复安装。
|
|
36
|
+
|
|
37
|
+
首次使用先确认 `lark-cli` 与 `base-database-cli` 可执行;缺失时按上述安装命令及回退入口处理。执行 `base-database-cli doctor`;认证缺失时按[认证与重新授权](#认证与重新授权)处理,用户完成授权后重新执行 doctor,`ok: true` 后再 init。`init`、`pull` 不会自动触发登录。
|
|
38
|
+
|
|
14
39
|
### 公开 CLI 版本预检
|
|
15
40
|
|
|
16
41
|
本节的全局安装特指 `npm root -g` 对应的 CLI 包目录;不能仅凭 PATH 中存在同名命令就认定满足更新条件。
|
|
17
42
|
|
|
18
43
|
仅本地公开 CLI:每个会话首次业务操作前,优先确认本机 `base-database-cli` 入口及其 `--help`。已有全局安装时用已核实的全局入口执行 `check-update --json --skill-dir "<当前读取的 lark-base-database 目录>"`;仅通过 npx 使用时沿用已选版本的完整包名入口。使用实际 Skill 加载路径,不猜测默认 Agent 目录。业务命令复用本次确认的入口。
|
|
19
44
|
|
|
20
|
-
|
|
45
|
+
CI 跳过更新检查;其他环境正常检查。检查失败不阻塞任务。业务命令输出含更新提示时,也按下述 `status=available` 流程询问用户;同一会话已拒绝时不重复询问。
|
|
21
46
|
|
|
22
|
-
- `status=current|
|
|
47
|
+
- `status=current|skipped`:不向用户播报更新检查,继续任务。
|
|
48
|
+
- `status=unavailable`:静默继续任务,不为更新检查申请额外权限。
|
|
23
49
|
- `status=available`:先确认上述全局入口可用;不可用时按下文说明更新限制并继续任务。可用时说明当前版本和可更新版本,以及会同步已安装的用户级 Lark Base Database Skill,再询问是否升级。拒绝后继续已安装版,本会话不再询问;不要自动执行 npm 或更新命令。
|
|
24
50
|
- 确认全局安装入口且用户同意后,执行 `base-database-cli update --version <返回的 latest 精确版本> --skill-dir "<当前 Skill 目录>" --yes`,成功后重新读取该目录的 SKILL.md 和所需 references。升级会现场查找 Codex、Claude、通用 Agent 用户目录中已安装的本 Skill,并同步这些副本及显式传入的当前目录;不扫描项目或历史自定义目录,不补装已删除的副本。
|
|
25
51
|
- `update` 只允许从全局安装的 CLI 执行,不从 npx 临时副本或项目副本执行,也不移除来源检查。全局命令的 PATH 异常时,通过 `npm root -g` 确认 `@lark-base-open/base-database-cli/dist/cli.js` 的实际位置,用 Node 执行该入口并核对版本。没有全局安装时说明更新限制,继续 npx 业务调用;只有用户明确要求全局安装时才进入安装流程,不将更新确认自动扩展为新建全局安装。
|
|
26
52
|
- `skill.status=mismatch`:简短提示当前 Skill 与 CLI 来自不同版本,可通过本次执行预检的同一 CLI 入口运行 `skill install --dir "<当前 Skill 的父目录>" --force` 同步后重读;不因版本号不同中断业务或自动覆盖。`unknown` 表示未找到有效记录,不推断一致,也不阻塞。
|
|
27
53
|
- 更新失败时按实际结果反馈。`skill-update-failed` 表示 CLI 已更新,但部分 Skill 未同步;说明 `installed` 中的成功目录和 `failed` 中的失败目录,按每项 `repair` 参数数组修复后重读,不宣称整体升级成功,不自动降级或反复重试。
|
|
28
54
|
- 首次使用先确认当前调用入口支持 `check-update`(读取其 `--help`);旧 CLI 没有该子命令时跳过预检,继续业务,不为预检自动升级。
|
|
29
|
-
- 非托管环境优先使用本机已安装的 `base-database-cli`。已知全局安装存在但 PATH 异常时,使用确认过的可执行路径;不自动修改 shell 配置。没有可用本地入口时,回退 `npx @lark-base-open/base-database-cli`;需要固定版本时使用 `npx @lark-base-open/base-database-cli@<已确认的精确版本>`。不猜 npm scope,不全盘搜索或反复安装。托管环境始终使用宿主入口,不走公开包回退。
|
|
30
55
|
|
|
31
|
-
##
|
|
56
|
+
## 认证与重新授权
|
|
32
57
|
|
|
33
|
-
|
|
58
|
+
沿用本任务已选定的 CLI 入口、环境和同一 profile。`not_configured`(原文 `not configured`)、`token_missing`(用户身份原文 `no access token available for user`,或 `need_user_authorization (user: …)`)来自 lark-cli;`need_user_authorization` 是后者的消息标记,`…` 代表实际用户标识。`missing_scopes` 由本 CLI 检查用户 scope 后返回,原文包含 `missing_scopes:` 和 `Run auth login with the same CLI, environment and profile to authorize these user scopes.`:说明缺少用户授权,执行 `base-database-cli auth login`,用户完成授权后只重试原命令一次;仍失败时停止并保留原错误,不循环授权。
|
|
34
59
|
|
|
35
|
-
|
|
60
|
+
`app_scope_not_applied` 来自 lark-cli(原文 `access denied: app has not applied for the required scope(s)`,`app` 后可能附应用 ID),表示应用侧尚未申请所需 scope;不执行 auth login,报告应用权限未开通的阻塞并保留原错误,按错误提示处理。
|
|
36
61
|
|
|
37
|
-
|
|
38
|
-
| --- | --- |
|
|
39
|
-
| `lark-cli` 可执行文件 | 公开环境缺失时执行 `npx @larksuite/cli@latest install`,其他安装方式见 [github.com/larksuite/cli](https://github.com/larksuite/cli);托管环境缺失时报告环境阻塞,不自行安装 |
|
|
40
|
-
| `api`、本任务需要的 `base` 命令 | 业务所需能力;按当前帮助和协议执行,真实认证、权限或接口错误按失败阶段处理 |
|
|
41
|
-
| `config` / `auth` | 本地账号管理能力。宿主提供认证时不补建 `default` profile;宿主缺少管理命令但通过 `LARKSUITE_CLI_PROFILE` 选择托管凭证时保留该环境变量,不传宿主禁止的 `--profile` 参数,由真实业务请求校验 profile,不回退账号 |
|
|
42
|
-
| `skills read` | 可选的文档入口。存在时读取 `lark-base` 并沿路由找 reference;不存在时直接读取环境提供的 lark-base 文件与相应命令帮助,后续不反复尝试该入口 |
|
|
43
|
-
| `doctor` | 排障入口,不是每次业务操作的必经步骤。先区分管理命令缺失与实际接口失败;旧版 CLI 因缺少管理命令无法继续时报告兼容性阻塞,不伪造配置、认证回执或修改已安装 CLI 来绕过 |
|
|
62
|
+
非 doctor 命令可能只透出错误文字而没有 subtype;按上述原文特征判定,不因缺少码名就把应用权限未开通误判为用户未授权,无法匹配时保留原错误继续定位。
|
|
44
63
|
|
|
45
|
-
|
|
64
|
+
AI Function 管理命令或 deploy 返回 `800004011`(`ai function feature is not enabled`)不是 scope 问题,auth login 无效;按[未开通 AI Function](ai-function.md#未开通-ai-function-时)降级处理。其他错误按其原因处理。
|
|
46
65
|
|
|
47
66
|
## 先选择工程来源
|
|
48
67
|
|
|
@@ -54,18 +73,7 @@ base-database-cli context . --summary --json
|
|
|
54
73
|
|
|
55
74
|
它只汇总本地配置、Catalog、Function metadata、init/Preview 回执和部署输入 fingerprint;不认证、不访问远端、不构建或发布。摘要保留决策所需的状态、资源数量、readiness 和 next action,不输出本地路径、fingerprint 值或逐项资源。需要排障时去掉 `--summary` 查看完整快照。`project.status=uninitialized` 表示当前目录缺少 `base-database.jsonc`,按下述工程来源选择 init 或 pull,不能仅凭空目录自行推断远端来源。不要从快照推断运行态、权限或发布成功。
|
|
56
75
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
| 来源 | 第一项工程操作 | 约束 |
|
|
60
|
-
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
61
|
-
| `snapshot` | 读取现有配置、Catalog、源码和本地修改 | 不执行 init/pull |
|
|
62
|
-
| `artifact` | `base-database-cli pull . --app-token "$BASE_SITE_BUILDER_SITE_TOKEN"` | pull 失败停止恢复,不退回 init |
|
|
63
|
-
| `binding` | `base-database-cli init . --app-token "$BASE_SITE_BUILDER_SITE_TOKEN" --base-token "$BASE_SITE_BUILDER_BASE_TOKEN" --name '<应用名称>' --description '<应用描述>'` | 已有一个 Base 绑定但无可恢复源码;只初始化一次,复用现有应用与 Base,不新建资源 |
|
|
64
|
-
| `empty` | 执行带 `--app-token "$BASE_SITE_BUILDER_SITE_TOKEN"` 的 init | 复用宿主应用,不创建另一应用 |
|
|
65
|
-
|
|
66
|
-
上述四种来源与宿主工程恢复协议一致。`binding` 还必须有非空 `BASE_SITE_BUILDER_BASE_TOKEN`,应用名称与描述从当前需求确定。宿主变量存在但取值不在表中、必需 token 缺失或工程与宿主状态矛盾时,报告恢复条件不满足,不创建新资源掩盖问题。会话历史未恢复但工程有效时,先读取现有工程继续;没有工程的合法 binding 模式仍执行表中的恢复路径。
|
|
67
|
-
|
|
68
|
-
非托管环境:已有工程直接增量修改;只有远端应用时,在空目录执行 `base-database-cli pull . --app-token <app-token> --env online`;确认为新建时才 init。保留用户未提交内容,不能以恢复工程为由覆盖非空目录。
|
|
76
|
+
已有工程直接增量修改;只有远端应用时,在空目录执行 `base-database-cli pull . --app-token <app-token> --env online`;确认为新建时才 init。保留用户未提交内容,不能以恢复工程为由覆盖非空目录。
|
|
69
77
|
|
|
70
78
|
## 需求与 Base 定位
|
|
71
79
|
|
|
@@ -79,8 +87,6 @@ base-database-cli context . --summary --json
|
|
|
79
87
|
|
|
80
88
|
## 初始化
|
|
81
89
|
|
|
82
|
-
初始化前检查 `BASE_SITE_BUILDER_SITE_TOKEN`。变量非空表示宿主已经创建目标应用:使用 环境已安装的 `base-database-cli` 可执行文件,并在本节的 `init` 命令中追加 `--app-token "$BASE_SITE_BUILDER_SITE_TOKEN"`。该模式仍按需求创建或复用 Base,会更新已有应用的名称和描述,再调用 `bind_base` 和 `catalog`,不会调用应用 create。不要手写 `base-database.jsonc`、不要绕过 CLI 拼装低层 `lark-cli` 请求,也不要用新应用掩盖绑定失败。
|
|
83
|
-
|
|
84
90
|
### 从零创建 Base
|
|
85
91
|
|
|
86
92
|
编写 schema 前,按已确认的文档入口读取字段规范:支持 `skills read` 时先执行 `lark-cli skills read lark-base` 查看文件列表,再读取其中的字段定义 reference(当前为 `references/lark-base-field-json.md`,以列表实际名称为准);否则直接读取环境中 lark-base 的对应 reference,并用 `lark-cli base +table-create --help` 核对当前命令契约,不再尝试已知缺失的入口。不要猜测属性。`tables[].fields` 使用与 `lark-cli base +base-create/+table-create --fields` 相同的字段定义;init 会先创建每张表的主字段,取得全部真实表 ID 后再按原顺序创建其余字段。
|
|
@@ -133,16 +139,6 @@ base-database-cli init . \
|
|
|
133
139
|
--schema ./base-schema.json
|
|
134
140
|
```
|
|
135
141
|
|
|
136
|
-
托管环境 已有应用场景执行:
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
base-database-cli init . \
|
|
140
|
-
--name 'Todo 管理' \
|
|
141
|
-
--description '供个人集中创建、跟踪和完成日常任务' \
|
|
142
|
-
--schema ./base-schema.json \
|
|
143
|
-
--app-token "$BASE_SITE_BUILDER_SITE_TOKEN"
|
|
144
|
-
```
|
|
145
|
-
|
|
146
142
|
### 使用已有 Base
|
|
147
143
|
|
|
148
144
|
取得已有 Base 的 `bas...` token 后执行:
|
|
@@ -155,11 +151,9 @@ base-database-cli init . \
|
|
|
155
151
|
--base-token basxxxxxxxx
|
|
156
152
|
```
|
|
157
153
|
|
|
158
|
-
托管环境 复用已有 Base 与已有应用时,同样改用 `base-database-cli init` 并追加 `--app-token "$BASE_SITE_BUILDER_SITE_TOKEN"`。
|
|
159
|
-
|
|
160
154
|
该命令调用只读 Base 接口获取 Base 信息并分页列出全部表。未指定 `--app-token` 时,通过应用创建接口的 `baseBindings` 绑定这些表;指定时,通过目标应用的 `bind_base` 绑定这些表。最后从目标应用获取 Catalog。它不会创建或修改 Base、表、字段和记录。
|
|
161
155
|
|
|
162
|
-
两种路径必须且只能传入 `--schema` 或 `--base-token` 之一,并始终传入非空 `--description`。公开 CLI 的 `--env` 默认且只支持 `online
|
|
156
|
+
两种路径必须且只能传入 `--schema` 或 `--base-token` 之一,并始终传入非空 `--description`。公开 CLI 的 `--env` 默认且只支持 `online`。建表顺序与等待由 CLI 管理。
|
|
163
157
|
|
|
164
158
|
成功结果的 `baseSource` 和 `databaseSource` 分别为 `created` 或 `existing`;新建资源位于 `created`,复用资源位于 `reused`,同时列出表、应用、binding 和工程文件。开始开发前确认以下产物:
|
|
165
159
|
|
|
@@ -170,11 +164,13 @@ catalog.json # 已绑定数据表的真实 schema
|
|
|
170
164
|
page/ # React 页面
|
|
171
165
|
database-functions/ # Database Functions
|
|
172
166
|
mutations/ # 基础写入声明
|
|
173
|
-
server
|
|
167
|
+
server/ # workspace 服务端 FaaS Functions
|
|
168
|
+
package.json # page + server npm workspaces
|
|
169
|
+
package-lock.json # 唯一根依赖锁
|
|
174
170
|
.base-database-cli/ # 被 Git 忽略的 CLI 本地状态与临时制品
|
|
175
171
|
```
|
|
176
172
|
|
|
177
|
-
|
|
173
|
+
新建仅支持 workspace(`init`);classic 的 `server-functions/` 和独立 page/server-functions 依赖锁仅供存量兼容。
|
|
178
174
|
|
|
179
175
|
只从 `catalog.json` 读取表名、字段名、ID、选项和查询类型,不根据建表输入猜测 Catalog 结果。
|
|
180
176
|
|
|
@@ -208,3 +204,18 @@ base-database-cli lark-cli -- api GET /open-apis/base/v3/sites/<app-token>/catal
|
|
|
208
204
|
普通 `api` 请求(默认 JSON、`--json` 或 `--format json`)会将宿主自动落盘的 JSON 响应恢复为 stdout JSON,并清理本次临时文件,上传请求同样适用。真实文件下载显式使用 `--output`;该模式以及 `--jq`、`--page-all`、非 JSON 格式、标准输入请求、帮助和 dry-run 保留宿主原始行为。
|
|
209
205
|
|
|
210
206
|
初始化成功后进入[开发阶段路由](../SKILL.md#开发阶段路由),实现完成后按[发布与交付](release.md)处理。
|
|
207
|
+
|
|
208
|
+
升级 CLI 后若 check 报缺声明,按报错列出的全部函数、字段与补写示例一次补全,再 check/deploy;交付告知见[交付结果](release.md#交付结果)。
|
|
209
|
+
|
|
210
|
+
## 工程目录与构建模式
|
|
211
|
+
|
|
212
|
+
新建工程只有 workspace;恢复工程先读 base-database.jsonc,不凭安装了 Page SDK 判断布局。
|
|
213
|
+
|
|
214
|
+
| 内容 | workspace(template.version 2) | 存量 classic(version 1 或合法旧配置省略 template) |
|
|
215
|
+
| --- | --- | --- |
|
|
216
|
+
| Page | page/ | page/ |
|
|
217
|
+
| FaaS 源码与契约清单 | server/functions/、server/contracts.generated.json | server-functions/functions/、server-functions/contracts.generated.json |
|
|
218
|
+
| SQL / Mutation | database-functions/、mutations/ | database-functions/、mutations/ |
|
|
219
|
+
| npm 锁 | 根 package-lock.json,Page/server 不建嵌套 lock | page/ 与 server-functions/ 各自的 lock |
|
|
220
|
+
|
|
221
|
+
workspace 使用平台构建器。classic 在服务端声明 SDK(dependencies 或 devDependencies)或服务端能解析 SDK 时使用平台构建器,否则执行服务端工程自身 build。仅 Page 装 SDK 可启用 Page/契约 codegen,不自动把服务端变为 SDK 工程;两项能力由各自消费位置决定。平台构建器按同一函数清单构建并核对 meta.json/index.ts,生成 CJS 与 manifest;传统 handler 保留调用约定,SDK defineFunction 注入运行时绑定。
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# {{Site name}}
|
|
2
2
|
|
|
3
|
+
> classic 存量工程参考。新建请使用 `base-database-cli init`;classic 继续支持 check、deploy、pull、dev。
|
|
4
|
+
|
|
3
5
|
> {{One sentence describing who this site helps and what they can do}}
|
|
4
6
|
|
|
5
7
|
<!-- Template note: Write this README in the language of the user's original site-building request when it is Chinese, Japanese, or English; otherwise use English. Translate the headings and prose using the supported section names in the lark-base-database Skill. Replace every {{...}} placeholder before publishing. Remove this comment and any lines that do not apply. Describe only features that were implemented and verified. -->
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
Place each Database Function in `database-functions/<functionId>/`:
|
|
4
4
|
|
|
5
5
|
- `main.sql`: Write a query using the supported Database Function syntax. Refer to parameters as `$1`, `$2`, and so on.
|
|
6
|
-
- `meta.json`: Declare `name`, `description`, and
|
|
6
|
+
- `meta.json`: Declare `name`, `description`, and `meta.params` in `$1`, `$2` order. Each parameter needs `name`, `kind` and `description`, plus an optional `enum` for fixed options. Page calls use `{parameterName: value}`, matching the frozen declaration. Omit `meta` or `meta.params` when the query has no parameters.
|
|
7
7
|
|
|
8
|
-
Database Functions read Base data. Use `server-functions/functions/` for
|
|
8
|
+
Database Functions read Base data. Use `mutations/` for fixed single-table writes and `server-functions/functions/` for business validation or orchestration; see the Skill reference `mutations.md#写入方式选择`. See the `lark-base-database` Skill's `database-function.md` for parameter, response, Catalog, and SQL dialect contracts.
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
`spec.json` 示例(替换真实 table / field ID):
|
|
12
12
|
|
|
13
13
|
```json
|
|
14
|
-
{"table":{"table_id":"tblTasks"},"operation":"update","params":[{"kind":"RECORD_ID"},{"kind":"TEXT","max_length":100}],"precondition":{"conjunction":"and","conditions":[{"field_id":"rec_id","operator":"is","param":1}]},"set":{"fldTitle":{"param":2}},"returning":["rec_id","fldTitle"]}
|
|
14
|
+
{"table":{"table_id":"tblTasks"},"operation":"update","params":[{"name":"taskId","kind":"RECORD_ID","description":"要改名的任务记录 ID;先调用任务列表函数取 record_id"},{"name":"title","kind":"TEXT","max_length":100,"description":"新的任务标题,最多 100 字"}],"precondition":{"conjunction":"and","conditions":[{"field_id":"rec_id","operator":"is","param":1}]},"set":{"fldTitle":{"param":2}},"returning":["rec_id","fldTitle"]}
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
单条调用 `invokeDatabaseFunction('updateTitle',
|
|
17
|
+
单条调用 `invokeDatabaseFunction('updateTitle', { taskId: 'recA', title: '新标题' })`;批量调用 `invokeDatabaseMutationBatch('updateTitle', [{ taskId: 'recA', title: '标题 A' }, { taskId: 'recB', title: '标题 B' }])`。编号从 1 开始;一批最多 200 条。`spec.params` 每项必须写 `name` 和 `description`,固定选项可写 `enum`;外部 Agent 按 `name` 传对象。CLI deploy 自动校验、打包并更新 Function,pull 保留声明。
|
|
18
18
|
|
|
19
19
|
Mutation 负责基础单表写入;create 不带 precondition,其他操作通过 precondition 指定记录 ID。需要服务端业务校验、计算或编排时使用 FaaS。字段、附件、权限边界和完整协议见已安装的 lark-base-database Skill 的 `references/mutations.md`。
|
|
@@ -17,18 +17,19 @@ Optional AI Function example components use the same language selection for thei
|
|
|
17
17
|
The application runs in a BaseApp iframe. It does not hold login credentials or call business domains directly. `src/lib/database-runtime.ts` is the single entry point for communication with the host, using `@lark-base-open/base-site-channel/runtime`:
|
|
18
18
|
|
|
19
19
|
- `fetch` / `invokeHttp`: The parent page proxies business HTTP requests from its own origin. Business paths must start with a single `/`.
|
|
20
|
-
-
|
|
20
|
+
- This bundled classic reference helper uses named inputs. Classic projects reusing it must explicitly set `"functionInputs": "named"` in `base-database.jsonc`; omission keeps the positional default. The input declaration rules are maintained in the installed building Skill’s `references/workspace-migration.md#classic-输入声明`.
|
|
21
|
+
- `invokeDatabaseFunction(functionId, params)`: Calls `POST /space/api/bitable/site/v1/:token/functions/:function_id/invoke` through the unified gateway with a `{"params": {...}}` body. SQL and Mutation use named objects (zero parameters: `{}`); batches use `{"batch":[{"params":{...}}]}`.
|
|
21
22
|
- `src/lib/database-function-inputs.generated.ts`: The CLI generates Page input types from Database Function and FaaS metadata during `check` and Preview `deploy`. Do not edit this file. Page compilation checks Function IDs, query parameter order, and required FaaS fields and enum values. Callers still declare response types and validate them at runtime.
|
|
22
23
|
- `resolveDatabaseContext()`: Resolves the app token and `prod` or `preview` environment. Host-provided context takes precedence; otherwise it infers values from the artifact path through `getDatabaseContext()`. Use this asynchronous function in business code.
|
|
23
24
|
- `getDatabaseContext()`: Synchronous artifact-path inference for fallback use only.
|
|
24
|
-
- `callSiteAIFunction({ functionKey, capability,
|
|
25
|
-
- `invokeSiteAIFunctionStream({ functionKey, messages,
|
|
25
|
+
- `callSiteAIFunction({ functionKey, capability, params?, messages?, input? })`: Calls the configured AI Function and returns a discriminated result with `type: 'text' | 'image_task' | 'video_task'`. Poll media tasks by task ID and render by `result.type`.
|
|
26
|
+
- `invokeSiteAIFunctionStream({ functionKey, messages, params? })`: Streams text or image understanding results. It provides subscribable updates and a `destroy()` method. Consume both `delta.reasoningContent` and `delta.content` and render them separately. See `src/examples/ai-function/TextStreamOperation.tsx`.
|
|
26
27
|
- `createSiteAIFunctionTask(params)` / `getSiteAIFunctionTask(functionKey, taskId)`: Submit and poll image or video generation tasks.
|
|
27
28
|
- `siteRuntime`: Reports lifecycle events through `ready()` and `reportLoadFailed()`.
|
|
28
29
|
|
|
29
30
|
Do not call `postMessage`, use the raw Channel Client, or fetch a business domain directly from business code.
|
|
30
31
|
|
|
31
|
-
Declare the model, System Prompt, reasoning depth, image size, video duration, and related settings in `ai/<functionKey>/meta.json` at the project root. Validate with `base-database-cli ai-functions validate <functionKey>` and sync through `deploy`. The page sends call-specific `
|
|
32
|
+
Declare the model, System Prompt, reasoning depth, image size, video duration, and related settings in `ai/<functionKey>/meta.json` at the project root. Validate with `base-database-cli ai-functions validate <functionKey>` and sync through `deploy`. The page sends call-specific `params` and `messages` or `input` for the selected `functionKey`. Preview uses the draft configuration; Prod uses it only after production publication. Before calling a Function, confirm that its `functionKey` has been synced and that `disabled` is not `true`.
|
|
32
33
|
|
|
33
34
|
## Request identity and CSRF
|
|
34
35
|
|
|
@@ -21,8 +21,8 @@ import { splitAIStreamDelta } from './ai-delta'
|
|
|
21
21
|
export interface TextStreamOperationProps {
|
|
22
22
|
// functionKey 指向后台配置好的 text/vision AI Function。
|
|
23
23
|
functionKey: string
|
|
24
|
-
//
|
|
25
|
-
|
|
24
|
+
// params 渲染 AI Function System Prompt 里的 {{var}} 占位符(可选)。
|
|
25
|
+
params?: Record<string, unknown>
|
|
26
26
|
title?: string
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -50,7 +50,7 @@ export function parseAnswerItems(answer: string): string[] {
|
|
|
50
50
|
|
|
51
51
|
function useTextStream(
|
|
52
52
|
functionKey: string,
|
|
53
|
-
|
|
53
|
+
params: Record<string, unknown> | undefined,
|
|
54
54
|
unavailableMessage: string,
|
|
55
55
|
) {
|
|
56
56
|
const streamRef = useRef<SiteAIFunctionStreamHandle | null>(null)
|
|
@@ -79,7 +79,7 @@ function useTextStream(
|
|
|
79
79
|
const stream = invokeSiteAIFunctionStream({
|
|
80
80
|
functionKey,
|
|
81
81
|
messages,
|
|
82
|
-
...(
|
|
82
|
+
...(params ? { params } : {}),
|
|
83
83
|
})
|
|
84
84
|
stream.onMessage((delta) => {
|
|
85
85
|
const { answer, reasoning } = splitAIStreamDelta(delta)
|
|
@@ -110,13 +110,13 @@ function useTextStream(
|
|
|
110
110
|
/** 文本流式业务操作示例组件。 */
|
|
111
111
|
export function TextStreamOperation({
|
|
112
112
|
functionKey,
|
|
113
|
-
|
|
113
|
+
params,
|
|
114
114
|
title,
|
|
115
115
|
}: TextStreamOperationProps) {
|
|
116
116
|
const i18n = AI_FUNCTION_COPY[useUiLanguage()].text
|
|
117
117
|
const { ask, state, stop } = useTextStream(
|
|
118
118
|
functionKey,
|
|
119
|
-
|
|
119
|
+
params,
|
|
120
120
|
i18n.unavailable,
|
|
121
121
|
)
|
|
122
122
|
const [draft, setDraft] = useState('')
|
|
@@ -57,12 +57,14 @@ export function AttachmentImage({
|
|
|
57
57
|
error: string
|
|
58
58
|
localError?: 'loadFailed' | 'decodeFailed'
|
|
59
59
|
}>({ key: '', url: '', error: '' })
|
|
60
|
-
const { tableId, fieldId, recordId, fileToken } = attachment
|
|
60
|
+
const { tableId, fieldId, recordId, fileToken, name, mimeType } = attachment
|
|
61
61
|
const key = JSON.stringify([
|
|
62
62
|
tableId,
|
|
63
63
|
fieldId,
|
|
64
64
|
recordId,
|
|
65
65
|
fileToken,
|
|
66
|
+
name,
|
|
67
|
+
mimeType,
|
|
66
68
|
size,
|
|
67
69
|
attempt,
|
|
68
70
|
])
|
|
@@ -89,9 +91,11 @@ export function AttachmentImage({
|
|
|
89
91
|
if (!visible) return
|
|
90
92
|
const controller = new AbortController()
|
|
91
93
|
let url = ''
|
|
92
|
-
fetchAttachmentCover(
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
fetchAttachmentCover(
|
|
95
|
+
{ tableId, fieldId, recordId, fileToken, name, mimeType },
|
|
96
|
+
size,
|
|
97
|
+
{ signal: controller.signal },
|
|
98
|
+
)
|
|
95
99
|
.then((blob) => {
|
|
96
100
|
if (controller.signal.aborted) return
|
|
97
101
|
url = URL.createObjectURL(blob)
|
|
@@ -111,7 +115,17 @@ export function AttachmentImage({
|
|
|
111
115
|
controller.abort()
|
|
112
116
|
if (url) URL.revokeObjectURL(url)
|
|
113
117
|
}
|
|
114
|
-
}, [
|
|
118
|
+
}, [
|
|
119
|
+
visible,
|
|
120
|
+
key,
|
|
121
|
+
tableId,
|
|
122
|
+
fieldId,
|
|
123
|
+
recordId,
|
|
124
|
+
fileToken,
|
|
125
|
+
name,
|
|
126
|
+
mimeType,
|
|
127
|
+
size,
|
|
128
|
+
])
|
|
115
129
|
|
|
116
130
|
const current = image.key === key ? image : undefined
|
|
117
131
|
return (
|
|
@@ -3,10 +3,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
3
3
|
const getRuntimeContext = vi.fn()
|
|
4
4
|
const siteRuntimeFetch = vi.fn()
|
|
5
5
|
const invokeHttp = vi.fn()
|
|
6
|
+
const openLink = vi.fn()
|
|
6
7
|
|
|
7
8
|
vi.mock('@lark-base-open/base-site-channel/runtime', () => ({
|
|
8
9
|
fetch: siteRuntimeFetch,
|
|
9
10
|
invokeHttp,
|
|
11
|
+
openLink,
|
|
10
12
|
siteRuntime: { getRuntimeContext },
|
|
11
13
|
}))
|
|
12
14
|
|
|
@@ -27,6 +29,7 @@ beforeEach(() => {
|
|
|
27
29
|
getRuntimeContext.mockReset()
|
|
28
30
|
siteRuntimeFetch.mockReset()
|
|
29
31
|
invokeHttp.mockReset()
|
|
32
|
+
openLink.mockReset()
|
|
30
33
|
vi.stubGlobal('location', {
|
|
31
34
|
ancestorOrigins: ['https://ancestor.example'],
|
|
32
35
|
pathname: '/app/pathToken/',
|
|
@@ -50,9 +53,11 @@ describe('fetchAttachmentCover', () => {
|
|
|
50
53
|
)
|
|
51
54
|
const controller = new AbortController()
|
|
52
55
|
const { fetchAttachmentCover } = await loadDatabaseRuntime()
|
|
53
|
-
const blob = await fetchAttachmentCover(
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
const blob = await fetchAttachmentCover(
|
|
57
|
+
{ ...attachmentRef, name: 'historical.svg', mimeType: 'image/svg+xml' },
|
|
58
|
+
480,
|
|
59
|
+
{ signal: controller.signal },
|
|
60
|
+
)
|
|
56
61
|
expect(new Uint8Array(await blob.arrayBuffer())).toEqual(
|
|
57
62
|
new Uint8Array([0, 128, 255]),
|
|
58
63
|
)
|
|
@@ -87,12 +92,77 @@ describe('fetchAttachmentCover', () => {
|
|
|
87
92
|
}),
|
|
88
93
|
)
|
|
89
94
|
const { fetchAttachmentCover } = await loadDatabaseRuntime()
|
|
90
|
-
await expect(
|
|
91
|
-
|
|
95
|
+
await expect(
|
|
96
|
+
fetchAttachmentCover({ ...attachmentRef, name: 'drawing.svg' }),
|
|
97
|
+
).rejects.toThrow(`HTTP ${status}, LogID test-log`)
|
|
98
|
+
expect(invokeHttp).toHaveBeenCalledTimes(1)
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
it.each([
|
|
102
|
+
{ code: 90002006, name: 'drawing.svg', expectedCode: '90002005' },
|
|
103
|
+
{ code: '90002006', name: 'DRAWING.SVG', expectedCode: '90002005' },
|
|
104
|
+
{
|
|
105
|
+
code: 90002006,
|
|
106
|
+
mimeType: 'IMAGE/SVG+XML; charset=utf-8',
|
|
107
|
+
expectedCode: '90002005',
|
|
108
|
+
},
|
|
109
|
+
])(
|
|
110
|
+
'classifies a cover error using only available file metadata: %j',
|
|
111
|
+
async ({ code, name, mimeType, expectedCode }) => {
|
|
112
|
+
const body = { code, message: 'Cover service error', data: null }
|
|
113
|
+
invokeHttp.mockResolvedValue(
|
|
114
|
+
new Response(JSON.stringify(body), {
|
|
115
|
+
status: 202,
|
|
116
|
+
headers: {
|
|
117
|
+
'content-type': 'application/json',
|
|
118
|
+
'x-tt-logid': 'cover-log',
|
|
119
|
+
},
|
|
120
|
+
}),
|
|
92
121
|
)
|
|
122
|
+
const { fetchAttachmentCover } = await loadDatabaseRuntime()
|
|
123
|
+
await expect(
|
|
124
|
+
fetchAttachmentCover({ ...attachmentRef, name, mimeType }),
|
|
125
|
+
).rejects.toMatchObject({
|
|
126
|
+
code: expectedCode,
|
|
127
|
+
originalCode: String(code),
|
|
128
|
+
cause: body,
|
|
129
|
+
logId: 'cover-log',
|
|
130
|
+
message: expect.stringContaining(
|
|
131
|
+
`code ${expectedCode}, LogID cover-log`,
|
|
132
|
+
),
|
|
133
|
+
})
|
|
93
134
|
expect(invokeHttp).toHaveBeenCalledTimes(1)
|
|
94
135
|
},
|
|
95
136
|
)
|
|
137
|
+
it('preserves business errors from unsuccessful HTTP responses', async () => {
|
|
138
|
+
const body = { code: 800008201, message: 'Forbidden', data: null }
|
|
139
|
+
invokeHttp.mockResolvedValue(
|
|
140
|
+
new Response(JSON.stringify(body), {
|
|
141
|
+
status: 403,
|
|
142
|
+
headers: { 'content-type': 'application/json' },
|
|
143
|
+
}),
|
|
144
|
+
)
|
|
145
|
+
const { fetchAttachmentCover } = await loadDatabaseRuntime()
|
|
146
|
+
await expect(
|
|
147
|
+
fetchAttachmentCover({ ...attachmentRef, name: 'drawing.svg' }),
|
|
148
|
+
).rejects.toThrow('HTTP 403')
|
|
149
|
+
})
|
|
150
|
+
it.each([
|
|
151
|
+
{ name: 'animation.gif', code: 90002006 },
|
|
152
|
+
{ name: undefined, code: 90002006 },
|
|
153
|
+
{ name: 'drawing.svg', code: 90002005 },
|
|
154
|
+
])('keeps other cover failures unchanged: %j', async ({ name, code }) => {
|
|
155
|
+
invokeHttp.mockResolvedValue(
|
|
156
|
+
new Response(JSON.stringify({ code, message: 'Cover service error' }), {
|
|
157
|
+
status: 202,
|
|
158
|
+
headers: { 'content-type': 'application/json' },
|
|
159
|
+
}),
|
|
160
|
+
)
|
|
161
|
+
const { fetchAttachmentCover } = await loadDatabaseRuntime()
|
|
162
|
+
await expect(
|
|
163
|
+
fetchAttachmentCover({ ...attachmentRef, name }),
|
|
164
|
+
).rejects.toThrow('The host did not return a valid image')
|
|
165
|
+
})
|
|
96
166
|
it('rejects non-image and empty responses', async () => {
|
|
97
167
|
const { fetchAttachmentCover } = await loadDatabaseRuntime()
|
|
98
168
|
for (const response of [
|
|
@@ -273,3 +343,52 @@ describe('fetchAttachmentDownloadUrl', () => {
|
|
|
273
343
|
})
|
|
274
344
|
})
|
|
275
345
|
})
|
|
346
|
+
|
|
347
|
+
describe('openAttachmentDownload', () => {
|
|
348
|
+
const context = {
|
|
349
|
+
env: 'prod',
|
|
350
|
+
gatewayOrigin: '',
|
|
351
|
+
token: 'siteToken',
|
|
352
|
+
} as const
|
|
353
|
+
const signedUrl = 'https://download.example/authcode/?code=signed'
|
|
354
|
+
|
|
355
|
+
it('opens a fresh signed URL through the host instead of navigating the iframe', async () => {
|
|
356
|
+
siteRuntimeFetch.mockResolvedValue(
|
|
357
|
+
new Response(JSON.stringify({ code: 0, data: { url: signedUrl } })),
|
|
358
|
+
)
|
|
359
|
+
openLink.mockResolvedValue({ opened: true })
|
|
360
|
+
const { openAttachmentDownload } = await loadDatabaseRuntime()
|
|
361
|
+
|
|
362
|
+
await expect(
|
|
363
|
+
openAttachmentDownload(context, attachmentRef),
|
|
364
|
+
).resolves.toBeUndefined()
|
|
365
|
+
expect(siteRuntimeFetch).toHaveBeenCalledTimes(1)
|
|
366
|
+
expect(openLink).toHaveBeenCalledOnce()
|
|
367
|
+
expect(openLink).toHaveBeenCalledWith(signedUrl)
|
|
368
|
+
})
|
|
369
|
+
|
|
370
|
+
it('does not report success when the host refuses to open the link', async () => {
|
|
371
|
+
siteRuntimeFetch.mockResolvedValue(
|
|
372
|
+
new Response(JSON.stringify({ code: 0, data: { url: signedUrl } })),
|
|
373
|
+
)
|
|
374
|
+
openLink.mockResolvedValue({ opened: false })
|
|
375
|
+
const { openAttachmentDownload } = await loadDatabaseRuntime()
|
|
376
|
+
|
|
377
|
+
await expect(
|
|
378
|
+
openAttachmentDownload(context, attachmentRef),
|
|
379
|
+
).rejects.toThrow('The host did not open the attachment download link')
|
|
380
|
+
expect(openLink).toHaveBeenCalledWith(signedUrl)
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
it('does not open a link when the attachment service fails', async () => {
|
|
384
|
+
siteRuntimeFetch.mockResolvedValue(
|
|
385
|
+
new Response(JSON.stringify({ code: 800008201 }), { status: 403 }),
|
|
386
|
+
)
|
|
387
|
+
const { openAttachmentDownload } = await loadDatabaseRuntime()
|
|
388
|
+
|
|
389
|
+
await expect(
|
|
390
|
+
openAttachmentDownload(context, attachmentRef),
|
|
391
|
+
).rejects.toThrow('Attachment service could not provide a download URL')
|
|
392
|
+
expect(openLink).not.toHaveBeenCalled()
|
|
393
|
+
})
|
|
394
|
+
})
|
|
@@ -75,7 +75,7 @@ describe('buildDatabaseInvokeFunctionPath', () => {
|
|
|
75
75
|
{ env: 'prod', gatewayOrigin: '', token: 'bascnDemo' },
|
|
76
76
|
'list_tasks',
|
|
77
77
|
),
|
|
78
|
-
).toBe('/space/api/bitable/site/v1/bascnDemo/
|
|
78
|
+
).toBe('/space/api/bitable/site/v1/bascnDemo/functions/list_tasks/invoke')
|
|
79
79
|
})
|
|
80
80
|
|
|
81
81
|
it('adds the preview env query for draft artifacts', () => {
|
|
@@ -85,7 +85,7 @@ describe('buildDatabaseInvokeFunctionPath', () => {
|
|
|
85
85
|
'list-tasks',
|
|
86
86
|
),
|
|
87
87
|
).toBe(
|
|
88
|
-
'/space/api/bitable/site/v1/bascnDemo/
|
|
88
|
+
'/space/api/bitable/site/v1/bascnDemo/functions/list-tasks/invoke?env=preview',
|
|
89
89
|
)
|
|
90
90
|
})
|
|
91
91
|
|