@lark-base-open/base-database-cli 1.1.0 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +86 -0
- package/LICENSE +6 -0
- package/README.md +55 -31
- package/dist/ai-functions.d.ts +42 -0
- package/dist/ai-functions.d.ts.map +1 -0
- package/dist/ai-functions.js +327 -0
- package/dist/ai-functions.js.map +1 -0
- package/dist/archive.d.ts +21 -0
- package/dist/archive.d.ts.map +1 -1
- package/dist/archive.js +65 -10
- package/dist/archive.js.map +1 -1
- package/dist/auth.d.ts +8 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +60 -6
- package/dist/auth.js.map +1 -1
- package/dist/check.d.ts +74 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +283 -0
- package/dist/check.js.map +1 -0
- package/dist/dependency-policy.d.ts +10 -0
- package/dist/dependency-policy.d.ts.map +1 -0
- package/dist/dependency-policy.js +162 -0
- package/dist/dependency-policy.js.map +1 -0
- package/dist/deploy.d.ts +1 -0
- package/dist/deploy.d.ts.map +1 -1
- package/dist/deploy.js +122 -175
- package/dist/deploy.js.map +1 -1
- package/dist/environment-variables.d.ts +52 -0
- package/dist/environment-variables.d.ts.map +1 -0
- package/dist/environment-variables.js +563 -0
- package/dist/environment-variables.js.map +1 -0
- package/dist/environment.d.ts +1 -1
- package/dist/environment.js +1 -1
- package/dist/environment.js.map +1 -1
- package/dist/function-input-types.d.ts +10 -0
- package/dist/function-input-types.d.ts.map +1 -0
- package/dist/function-input-types.js +160 -0
- package/dist/function-input-types.js.map +1 -0
- package/dist/function-schema.d.ts.map +1 -1
- package/dist/function-schema.js +89 -36
- package/dist/function-schema.js.map +1 -1
- package/dist/init-field-retry.d.ts +17 -0
- package/dist/init-field-retry.d.ts.map +1 -0
- package/dist/init-field-retry.js +127 -0
- package/dist/init-field-retry.js.map +1 -0
- package/dist/init-journal.d.ts +98 -0
- package/dist/init-journal.d.ts.map +1 -0
- package/dist/init-journal.js +492 -0
- package/dist/init-journal.js.map +1 -0
- package/dist/init-schema.d.ts +8 -0
- package/dist/init-schema.d.ts.map +1 -0
- package/dist/init-schema.js +423 -0
- package/dist/init-schema.js.map +1 -0
- package/dist/init.d.ts +14 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +886 -243
- package/dist/init.js.map +1 -1
- package/dist/lark-cli-error.d.ts +46 -0
- package/dist/lark-cli-error.d.ts.map +1 -0
- package/dist/lark-cli-error.js +171 -0
- package/dist/lark-cli-error.js.map +1 -0
- package/dist/lark-cli.d.ts +2 -1
- package/dist/lark-cli.d.ts.map +1 -1
- package/dist/lark-cli.js +292 -29
- package/dist/lark-cli.js.map +1 -1
- package/dist/mutation-schema.d.ts +146 -0
- package/dist/mutation-schema.d.ts.map +1 -0
- package/dist/mutation-schema.js +153 -0
- package/dist/mutation-schema.js.map +1 -0
- package/dist/mutation.d.ts +10 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +131 -0
- package/dist/mutation.js.map +1 -0
- package/dist/npm.d.ts +1 -0
- package/dist/npm.d.ts.map +1 -1
- package/dist/npm.js +2 -2
- package/dist/npm.js.map +1 -1
- package/dist/preview-receipt.d.ts.map +1 -1
- package/dist/preview-receipt.js +15 -5
- package/dist/preview-receipt.js.map +1 -1
- package/dist/process.d.ts +3 -1
- package/dist/process.d.ts.map +1 -1
- package/dist/process.js +16 -4
- package/dist/process.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +241 -42
- package/dist/program.js.map +1 -1
- package/dist/project-build.d.ts +25 -0
- package/dist/project-build.d.ts.map +1 -0
- package/dist/project-build.js +229 -0
- package/dist/project-build.js.map +1 -0
- package/dist/project-context.d.ts +344 -0
- package/dist/project-context.d.ts.map +1 -0
- package/dist/project-context.js +485 -0
- package/dist/project-context.js.map +1 -0
- package/dist/project-layout.d.ts +5 -0
- package/dist/project-layout.d.ts.map +1 -0
- package/dist/project-layout.js +24 -0
- package/dist/project-layout.js.map +1 -0
- package/dist/public-sql-error.d.ts +25 -0
- package/dist/public-sql-error.d.ts.map +1 -0
- package/dist/public-sql-error.js +81 -0
- package/dist/public-sql-error.js.map +1 -0
- package/dist/pull.d.ts.map +1 -1
- package/dist/pull.js +54 -15
- package/dist/pull.js.map +1 -1
- package/dist/site-readme.d.ts +3 -0
- package/dist/site-readme.d.ts.map +1 -0
- package/dist/site-readme.js +83 -0
- package/dist/site-readme.js.map +1 -0
- package/dist/workspace-fingerprint.d.ts +21 -1
- package/dist/workspace-fingerprint.d.ts.map +1 -1
- package/dist/workspace-fingerprint.js +81 -2
- package/dist/workspace-fingerprint.js.map +1 -1
- package/package.json +2 -1
- package/skills/lark-base-database/SKILL.md +70 -53
- package/skills/lark-base-database/references/ai-function.md +471 -0
- package/skills/lark-base-database/references/base-capability-routing.md +3 -3
- package/skills/lark-base-database/references/database-function-limitations.md +46 -0
- package/skills/lark-base-database/references/database-function.md +349 -0
- package/skills/lark-base-database/references/design/components/actions-fields.md +16 -0
- package/skills/lark-base-database/references/design/components/code/controls.css +122 -0
- package/skills/lark-base-database/references/design/components/code/controls.tsx +73 -0
- package/skills/lark-base-database/references/design/components/code/date-picker.tsx +42 -0
- package/skills/lark-base-database/references/design/components/code/floating.tsx +41 -0
- package/skills/lark-base-database/references/design/components/code/overlays.tsx +19 -0
- package/skills/lark-base-database/references/design/components/code/select.tsx +34 -0
- package/skills/lark-base-database/references/design/components/code/styles.d.ts +1 -0
- package/skills/lark-base-database/references/design/components/code/theme.css +49 -0
- package/skills/lark-base-database/references/design/components/code/usage.tsx +38 -0
- package/skills/lark-base-database/references/design/components/date-time-number.md +9 -0
- package/skills/lark-base-database/references/design/components/feedback-navigation.md +9 -0
- package/skills/lark-base-database/references/design/components/index.md +18 -0
- package/skills/lark-base-database/references/design/components/overlays.md +9 -0
- package/skills/lark-base-database/references/design/components/patterns/flat-business.md +7 -0
- package/skills/lark-base-database/references/design/components/selection.md +24 -0
- package/skills/lark-base-database/references/design/components.md +91 -0
- package/skills/lark-base-database/references/design/composition.md +90 -0
- package/skills/lark-base-database/references/design/control-recipes.md +107 -0
- package/skills/lark-base-database/references/design/examples.md +172 -0
- package/skills/lark-base-database/references/design/foundations.md +126 -0
- package/skills/lark-base-database/references/design/review.md +82 -0
- package/skills/lark-base-database/references/design/scenes/analysis-report.md +66 -0
- package/skills/lark-base-database/references/design/scenes/brand-showcase.md +70 -0
- package/skills/lark-base-database/references/design/scenes/business-operations.md +85 -0
- package/skills/lark-base-database/references/design/scenes/campaign-report.md +66 -0
- package/skills/lark-base-database/references/design/scenes/dashboard.md +77 -0
- package/skills/lark-base-database/references/design/scenes/festive-campaign.md +69 -0
- package/skills/lark-base-database/references/design/theme.md +27 -0
- package/skills/lark-base-database/references/design/typography.md +56 -0
- package/skills/lark-base-database/references/development.md +165 -32
- package/skills/lark-base-database/references/environment-variables.md +55 -0
- package/skills/lark-base-database/references/faas.md +41 -48
- package/skills/lark-base-database/references/file-transfer.md +25 -25
- package/skills/lark-base-database/references/frontend-design-guide.md +33 -77
- package/skills/lark-base-database/references/mutations.md +295 -0
- package/skills/lark-base-database/references/permission-design.md +24 -24
- package/skills/lark-base-database/references/release.md +54 -27
- package/skills/lark-base-database/references/style-guide.md +10 -67
- package/skills/lark-base-database/references/verification.md +17 -13
- package/skills/lark-base-database/references/workspace.md +71 -22
- package/templates/database-starter/README.md +34 -4
- package/templates/database-starter/database-functions/README.md +8 -0
- package/templates/database-starter/mutations/README.md +19 -0
- package/templates/database-starter/page/README.md +25 -19
- package/templates/database-starter/page/package-lock.json +8 -16
- package/templates/database-starter/page/package.json +2 -3
- package/templates/database-starter/page/src/App.tsx +23 -3
- package/templates/database-starter/page/src/components/UserSelectorEditor/index.tsx +32 -4
- package/templates/database-starter/page/src/components/UserSelectorPanel/index.tsx +104 -34
- package/templates/database-starter/page/src/components/UserSelectorPanel/user-search.test.ts +55 -11
- package/templates/database-starter/page/src/components/UserSelectorPanel/user-search.ts +68 -25
- package/templates/database-starter/page/src/components/database-runtime-ready.tsx +1 -1
- package/templates/database-starter/page/src/components/database-user-menu/index.tsx +4 -7
- package/templates/database-starter/page/src/components/feedback/page-state.tsx +40 -5
- package/templates/database-starter/page/src/components/floating-button/assets/edit-active.svg +3 -0
- package/templates/database-starter/page/src/components/floating-button/assets/edit-default.svg +3 -0
- package/templates/database-starter/page/src/components/floating-button/index.tsx +75 -112
- package/templates/database-starter/page/src/components/floating-button/utils/project-meta.test.ts +107 -37
- package/templates/database-starter/page/src/components/floating-button/utils/project-meta.ts +13 -50
- package/templates/database-starter/page/src/components/ui-language.test.tsx +101 -0
- package/templates/database-starter/page/src/examples/ai-function/ImageTaskOperation.tsx +202 -0
- package/templates/database-starter/page/src/examples/ai-function/README.md +14 -0
- package/templates/database-starter/page/src/examples/ai-function/TextStreamOperation.tsx +184 -0
- package/templates/database-starter/page/src/examples/ai-function/ai-copy.ts +173 -0
- package/templates/database-starter/page/src/examples/ai-function/ai-delta.test.ts +30 -0
- package/templates/database-starter/page/src/examples/ai-function/ai-delta.ts +26 -0
- package/templates/database-starter/page/src/examples/ai-function/ai-language.test.tsx +86 -0
- package/templates/database-starter/page/src/examples/ai-function/ai-media-panel.test.ts +201 -0
- package/templates/database-starter/page/src/examples/ai-function/ai-media-panel.tsx +382 -0
- package/templates/database-starter/page/src/lib/attachment-image.tsx +144 -0
- package/templates/database-starter/page/src/lib/database-function-inputs.generated.ts +4 -0
- package/templates/database-starter/page/src/lib/database-runtime-attachment.test.ts +180 -76
- package/templates/database-starter/page/src/lib/database-runtime.test.ts +130 -10
- package/templates/database-starter/page/src/lib/database-runtime.ts +484 -51
- package/templates/database-starter/page/src/lib/date-time.ts +61 -0
- package/templates/database-starter/page/src/lib/ui-language.ts +86 -0
- package/templates/database-starter/page/src/main.tsx +1 -1
- package/templates/database-starter/page/tsconfig.json +2 -2
- package/templates/database-starter/page/vite.config.ts +1 -2
- package/templates/database-starter/prettierignore +1 -1
- package/templates/database-starter/server-functions/README.md +2 -2
- package/templates/database-starter/server-functions/package-lock.json +4 -4
- package/templates/database-starter/server-functions/package.json +1 -1
- package/dist/agent-guide.d.ts +0 -19
- package/dist/agent-guide.d.ts.map +0 -1
- package/dist/agent-guide.js +0 -31
- package/dist/agent-guide.js.map +0 -1
- package/dist/database-skill.d.ts +0 -24
- package/dist/database-skill.d.ts.map +0 -1
- package/dist/database-skill.js +0 -151
- package/dist/database-skill.js.map +0 -1
- package/skills/lark-base-database/references/base-sql-unsupported.md +0 -42
- package/skills/lark-base-database/references/database-capability-skill.md +0 -40
- package/skills/lark-base-database/references/sql-function.md +0 -289
- package/templates/database-capability/SKILL.md.tmpl +0 -58
- package/templates/database-starter/page/src/components/floating-button/chatbot-entry.test.ts +0 -23
- package/templates/database-starter/page/src/components/floating-button/chatbot-entry.tsx +0 -873
- package/templates/database-starter/page/src/components/floating-button/local-chat-panel.test.ts +0 -25
- package/templates/database-starter/page/src/components/floating-button/local-chat-panel.tsx +0 -197
- package/templates/database-starter/page/src/components/floating-button/utils/env.ts +0 -18
- package/templates/database-starter/sql/README.md +0 -8
|
@@ -1,51 +1,94 @@
|
|
|
1
1
|
# Page 开发与 Function 调用
|
|
2
2
|
|
|
3
|
-
实现或修改 Page 的运行时接入时读取。FaaS 新增或修改时,还须在 meta.json 显式声明 inputSchema,见[FaaS 开发](faas.md#faas-开发)
|
|
3
|
+
实现或修改 Page 的运行时接入时读取。FaaS 新增或修改时,还须在 meta.json 显式声明 inputSchema,见[FaaS 开发](faas.md#faas-开发)。基础单表写入与批量调用见[Mutation Function](mutations.md)。查询语法见[Database Function](database-function.md),服务端 handler 与记录写入见[FaaS 协议](faas.md),设计原则见[工程质量](style-guide.md)。
|
|
4
4
|
|
|
5
5
|
## 工程结构
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
8
|
project/
|
|
9
9
|
├── page/
|
|
10
|
-
├──
|
|
10
|
+
├── database-functions/<functionId>/{main.sql,meta.json}
|
|
11
|
+
├── mutations/<functionId>/{spec.json,meta.json}
|
|
11
12
|
└── server-functions/functions/<functionId>/{index.ts,meta.json}
|
|
12
13
|
```
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
Database Function、Mutation 与 FaaS 的 `functionId` 在应用内全局唯一,匹配 `/^[A-Za-z0-9_-]+$/`;Database Function ID 长度为 1~64。`functionId` 会作为 URL 路径段参与运行态调用,除该字符集外不接受其它字符。不同 FaaS Function 目录独立构建,不跨目录 import。Page 和 `server-functions/` 分别维护自己的 npm 工程与 `package-lock.json`。
|
|
16
|
+
|
|
17
|
+
## 第三方依赖策略
|
|
18
|
+
|
|
19
|
+
为 Page 或 FaaS 新增、升级第三方 npm 依赖前,先查询当前应用的服务端策略。路径参数 `<app-token>` 是当前应用的 appToken,从工程的 `base-database.jsonc` 读取(不是 Base token):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
base-database-cli lark-cli -- api GET /open-apis/base/v3/sites/<app-token>/get --params '{"withDependencyPolicy":true}' --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
响应中的 `data.dependencyPolicy` 是唯一策略事实源,字段形如:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"restrictedProtocols": ["file", "git"],
|
|
30
|
+
"rejectLocalPaths": true,
|
|
31
|
+
"rejectScpGitSyntax": true,
|
|
32
|
+
"rejectHostedGitShorthand": true,
|
|
33
|
+
"allowedValues": ["https://registry[.]example[.]com/.*[.]tgz"]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
普通 npm registry 版本、semver、`npm:` alias 和服务端未限制的协议默认可用。四个限制字段分别控制:`restrictedProtocols` 列出禁用的 URL 协议,如 `file:../pkg`、`git+https://example.com/pkg.git`;`rejectLocalPaths` 拒绝本地路径,如 `../pkg`、`/tmp/pkg`;`rejectScpGitSyntax` 拒绝 SCP 风格 Git 地址,如 `git@example.com:team/pkg.git`;`rejectHostedGitShorthand` 拒绝 hosted-git shorthand,如 `github:team/pkg`、`team/pkg`。
|
|
38
|
+
|
|
39
|
+
`allowedValues` 的每一项都是 RE2 语法的正则表达式;受限来源只有在原始 dependency value(未 trim、未改大小写)被其中某项**完整匹配**时才可用。不能按包名、域名、前缀或子串推断放行,也不能把 `allowedValues` 解释成 npm 包名白名单。固定字符串里的 `.`、`+`、`?` 等正则元字符必须写成 `[.]`、`\+`、`[?]` 等转义形式。
|
|
40
|
+
|
|
41
|
+
策略查询失败、字段缺失或类型错误,或 `allowedValues` 含非法正则时,停止添加依赖,保留错误信息与 LogID 并通过支持渠道反馈;不用内置列表或历史策略继续。`deploy` 会在安装依赖前再次查询策略,递归校验最终制品范围内的全部 `package.json`;本地预检通过不替代上传接口的最终校验。
|
|
15
42
|
|
|
16
43
|
## Function 调用契约
|
|
17
44
|
|
|
18
|
-
|
|
45
|
+
Page 与 Function 之间使用固定的调用契约。Page 侧三类 Function 都通过 `invokeDatabaseFunction(functionId, params)` 调用,但 `params` 类型不同:
|
|
19
46
|
|
|
20
47
|
`functionId` 使用源码目录名,是工程常量。应用 token 由 `page/src/lib/database-runtime.ts` 从产物托管路径解析,不由业务代码传入;FaaS 内部的 `context.invokeFunction` 仍使用 `{projectId,functionId,params}`,两者不要混用。
|
|
21
48
|
|
|
22
|
-
| Function
|
|
23
|
-
|
|
24
|
-
|
|
|
25
|
-
|
|
|
49
|
+
| Function | `params` | 实现 | 结果 |
|
|
50
|
+
| ---------------------- | ------------------------------------------ | ------------------------ | ------------------------------------------------------------------------------------ |
|
|
51
|
+
| Database Function | 按 `$1`、`$2` 排列的数组 | `main.sql` + `meta.json` | 一层 `{data:{rows},code,msg}` |
|
|
52
|
+
| Mutation | 声明顺序的位置数组;多组参数用批量 helper | `spec.json` + `meta.json` | 一层 `{data:{record_ids,records?,record_not_found?,ignored_fields?},code,msg}` |
|
|
53
|
+
| FaaS | 业务对象 | `index.ts` + `meta.json` | 一层 `{data,code,msg}`,`data` 是 handler 业务数据 |
|
|
26
54
|
|
|
27
|
-
|
|
55
|
+
Database Function 查询示例:
|
|
28
56
|
|
|
29
57
|
```ts
|
|
30
|
-
await invokeDatabaseFunction<{ rows: unknown[] }>('listTasks', ['待处理'])
|
|
58
|
+
await invokeDatabaseFunction<{ rows: unknown[] }>('listTasks', ['待处理']);
|
|
31
59
|
```
|
|
32
60
|
|
|
61
|
+
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#调用与结果)。
|
|
62
|
+
|
|
33
63
|
FaaS 创建操作示例:
|
|
34
64
|
|
|
35
65
|
```ts
|
|
36
66
|
await invokeDatabaseFunction<{ created: boolean | null }>('createTask', {
|
|
37
67
|
title: '准备评审',
|
|
38
68
|
status: '待处理',
|
|
39
|
-
})
|
|
69
|
+
});
|
|
40
70
|
```
|
|
41
71
|
|
|
72
|
+
`base-database-cli check --json` 与 Preview `deploy` 会先校验本地 Function metadata,再把 Database Function 的
|
|
73
|
+
`meta.params` 和 FaaS `inputSchema` 生成到
|
|
74
|
+
`page/src/lib/database-function-inputs.generated.ts`,随后才编译 Page。不要手改该文件;新增或修改
|
|
75
|
+
Function 后运行 `check`,让 `functionId`、查询参数顺序以及 FaaS 必填字段和枚举值在 Page
|
|
76
|
+
编译时保持一致。动态字符串不能作为 `functionId` 绕过这份本地契约。
|
|
77
|
+
|
|
78
|
+
metadata 只声明输入,因此生成文件只约束调用参数。调用结果仍由 Page 按 operation 定义
|
|
79
|
+
`invokeDatabaseFunction<TData>` 的 `TData`,并在运行时校验真实响应;CLI 不根据 handler
|
|
80
|
+
实现或查询投影猜测返回类型。生成类型覆盖标量类型、对象属性、必填项、枚举、数组元素和
|
|
81
|
+
`prefixItems` 位置,以及 Database Function 的固定参数 tuple;`minimum`、`maximum`、`minLength`、
|
|
82
|
+
`maxLength`、非固定数组的 `minItems` / `maxItems` 和对象精确性仍由 Function 运行时校验;
|
|
83
|
+
数组的元素类型和 `prefixItems` 位置仍保留在生成类型中。TypeScript 类型不能替代输入解析。
|
|
84
|
+
|
|
42
85
|
`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}`,页面使用当前登录用户身份,不保存也不传递任何凭证。
|
|
43
86
|
|
|
44
87
|
## Page 调用
|
|
45
88
|
|
|
46
89
|
默认 Page 的 `page/index.html` 需要把 `<title>` 设置为本次生成的 应用 名称,不留空。
|
|
47
90
|
|
|
48
|
-
默认 Page 必须引用并渲染 `page/src/components/floating-button/index.tsx` 中的 `FloatingButton`
|
|
91
|
+
默认 Page 必须引用并渲染 `page/src/components/floating-button/index.tsx` 中的 `FloatingButton` 组件。该组件自行解析应用 token,不接受 `projectId`。悬浮控件仅在正式环境向服务端判定有管理权限的访问者提供「编辑应用」入口。
|
|
49
92
|
|
|
50
93
|
当前账号信息(头像、姓名、组织、退出登录)由**应用自己的导航**承载,用 `page/src/components/database-user-menu/index.tsx` 的 `DatabaseUserMenu`。账号菜单位于应用导航区域,例如顶栏右上角或侧边栏底部:
|
|
51
94
|
|
|
@@ -54,13 +97,13 @@ await invokeDatabaseFunction<{ created: boolean | null }>('createTask', {
|
|
|
54
97
|
<header className="flex items-center justify-between ...">
|
|
55
98
|
<h1>设备台账</h1>
|
|
56
99
|
{/* 判据:员工 / 部门 / 领用归还属于组织内多角色协作 */}
|
|
57
|
-
<DatabaseUserMenu
|
|
100
|
+
<DatabaseUserMenu audience="enterprise" />
|
|
58
101
|
</header>
|
|
59
102
|
|
|
60
103
|
// 侧边栏左下角
|
|
61
104
|
<aside className="flex flex-col ...">
|
|
62
105
|
<nav className="flex-1">…</nav>
|
|
63
|
-
<DatabaseUserMenu
|
|
106
|
+
<DatabaseUserMenu audience="enterprise" align="left" side="up" />
|
|
64
107
|
</aside>
|
|
65
108
|
```
|
|
66
109
|
|
|
@@ -71,36 +114,126 @@ await invokeDatabaseFunction<{ created: boolean | null }>('createTask', {
|
|
|
71
114
|
`page/src/main.tsx` 已在首屏挂载后通过 `DatabaseRuntimeReady` 上报 `siteRuntime.ready()`,并在启动失败时上报 `reportLoadFailed`。宿主从握手完成起 10 秒内等不到 ready 会展示加载失败态,因此不要把 ready 上报移到数据加载完成之后,也不要删除该组件。
|
|
72
115
|
|
|
73
116
|
涉及人员搜索或人员选择的页面,优先引用 `page/src/components/UserSelectorEditor` 和 `page/src/components/UserSelectorPanel` 等 `page/src/components/` 下的人员组件;只有现有组件无法满足交互契约时才做局部扩展。
|
|
74
|
-
|
|
117
|
+
这些一方组件以及 `DatabaseUserMenu`、`FloatingButton`、`PageState`、`AttachmentImage` 内置中文、英文、日文固定文案,不依赖 Starling。组件统一按宿主 Runtime Context 的 locale → 浏览器语言 → 英语选择文案,无需 Page 传入或写死语言;宿主切换语言后,组件随重新加载的页面重新解析。Page 自己编写的业务文案仍由应用负责。
|
|
118
|
+
选人组件返回的 `User.user_id` 是 Base 人员单元格使用的内部用户 ID。Mutation 的 `USER_ID` 参数传该 ID 字符串,`list:true` 时传 ID 数组;FaaS 下游人员单元格传 `[{"id": user.user_id}]`。`User.open_id` 只是可选的开放平台标识,不得填入应用记录写入 payload。
|
|
75
119
|
|
|
76
120
|
业务请求集中在 operation/runtime client,不散落在组件中:
|
|
77
121
|
|
|
78
122
|
```ts
|
|
79
|
-
import { invokeDatabaseFunction } from '../lib/database-runtime'
|
|
123
|
+
import { invokeDatabaseFunction } from '../lib/database-runtime';
|
|
80
124
|
|
|
81
|
-
interface
|
|
82
|
-
rows: TRow[]
|
|
83
|
-
columns?: unknown[]
|
|
84
|
-
row_count?: number
|
|
85
|
-
log_id?: string
|
|
125
|
+
interface DatabaseRows<TRow> {
|
|
126
|
+
rows: TRow[];
|
|
127
|
+
columns?: unknown[];
|
|
128
|
+
row_count?: number;
|
|
129
|
+
log_id?: string;
|
|
86
130
|
}
|
|
87
131
|
```
|
|
88
132
|
|
|
89
|
-
浏览器 SDK 对
|
|
133
|
+
浏览器 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` 二次解包。否则后端已经写入成功时,页面仍可能误报失败。
|
|
90
134
|
|
|
91
135
|
运行时业务数据在边界处校验,不能只依赖 TypeScript 泛型。`functionId` 和所有路由是工程常量;用户输入只进入已声明的业务参数。
|
|
92
136
|
|
|
93
|
-
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
|
|
137
|
+
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。
|
|
138
|
+
|
|
139
|
+
## 日期与时区
|
|
140
|
+
|
|
141
|
+
Database Function 返回类型与 FaaS 写入格式分别以 [查询类型](database-function.md#查询类型与结果值) 和 [CellValue 协议](faas.md#base-读写协议)为准;Mutation 日期参数见 [Mutation 声明与参数](mutations.md#声明与参数)。转换时先区分字段语义:
|
|
142
|
+
|
|
143
|
+
| 业务语义 | 应用内表示 | 转换边界 |
|
|
144
|
+
| ------------------------------ | ---------------------- | ---------------------------------------------------------------------------- |
|
|
145
|
+
| 入库日、生日、到期日等日历日期 | `YYYY-MM-DD` 字符串 | 从 Base TIMESTAMP 回填时按该字段约定的业务时区取日期;表单编辑期间保持字符串 |
|
|
146
|
+
| 下单、上传等事件时刻 | Unix epoch 毫秒 number | 显示时按目标时区格式化;写入无偏移文本时按写入端解析时区格式化 |
|
|
147
|
+
|
|
148
|
+
已有 Base 先通过 `lark-cli base +base-get --base-token <base-token>` 核对 `time_zone`;新建使用本次明确设置的 Base 时区。记录业务日期时区、写入解析时区及显示时区是否一致。`init` 的默认值、浏览器时区和 FaaS 进程时区都不能代替已有 Base 的真实配置;不要给所有应用固定加八小时。多 Base 应用分别确认。
|
|
149
|
+
|
|
150
|
+
`toISOString()` 输出 UTC。`toISOString().slice(0, 10)` 只适用于明确要求 UTC 日期的场景,不能用于其他业务时区的日期回填;同样,截掉 `Z` 再将 UTC 文本作为本地时间写入,会改变事件时刻。不要对已正确的 epoch 再加偏移后交给带 `timeZone` 的格式化器,否则会重复转换。
|
|
151
|
+
|
|
152
|
+
### 转换与编辑示例
|
|
153
|
+
|
|
154
|
+
工程 `page/src/lib/date-time.ts` 提供不依赖浏览器或 SDK 的纯函数:
|
|
155
|
+
|
|
156
|
+
- `formatDateInput(epochMs, timeZone)`:时间戳到该业务时区的 `YYYY-MM-DD`。
|
|
157
|
+
- `formatBaseDateTime(epochMs, timeZone)`:时间戳到该时区的 `YYYY-MM-DD HH:mm:ss`。
|
|
158
|
+
- `dateInputToBaseDateTime(value)`:校验日历日期并补 `00:00:00`,不先转成 UTC。
|
|
159
|
+
|
|
160
|
+
旧工程没有 helper 时,从当前 CLI 的 starter 复制此文件并保持原工程其余接入。FaaS 需要使用时,将该无依赖文件复制到目标 `server-functions/functions/<functionId>/`,在同一 Function 内导入;不要跨 Function 或从 Page 目录运行时导入。
|
|
161
|
+
|
|
162
|
+
以下 `BASE_TIME_ZONE` 是应用根据 Base 信息确定的常量,示例值不是默认值。不要让任意请求参数改变写入解释时区。
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
// Page:时间戳只在回填边界转换,用户输入仍保持日历日期。
|
|
166
|
+
import { formatDateInput } from './lib/date-time';
|
|
167
|
+
|
|
168
|
+
const BASE_TIME_ZONE = 'Asia/Shanghai'; // 示例:已核对该 Base 的 time_zone
|
|
169
|
+
|
|
170
|
+
export function initialDate(stored: number | null): string {
|
|
171
|
+
return stored === null ? '' : formatDateInput(stored, BASE_TIME_ZONE);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function editPayload(
|
|
175
|
+
publisher: string,
|
|
176
|
+
dateValue: string,
|
|
177
|
+
originalDate: string,
|
|
178
|
+
) {
|
|
179
|
+
return {
|
|
180
|
+
publisher,
|
|
181
|
+
...(dateValue !== originalDate ? { addedAt: dateValue } : {}),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
// FaaS:同一 Function 目录内使用 helper,产生符合现有 CellValue 的文本。
|
|
188
|
+
import { dateInputToBaseDateTime, formatBaseDateTime } from './date-time';
|
|
189
|
+
|
|
190
|
+
const BASE_TIME_ZONE = 'Asia/Shanghai'; // 示例:已核对无偏移写入按此时区解释
|
|
191
|
+
|
|
192
|
+
export function updateFields(input: { publisher: string; addedAt?: string }) {
|
|
193
|
+
return {
|
|
194
|
+
出版社: input.publisher,
|
|
195
|
+
...(input.addedAt !== undefined
|
|
196
|
+
? { 入库日期: dateInputToBaseDateTime(input.addedAt) }
|
|
197
|
+
: {}),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function eventFields(now: number) {
|
|
202
|
+
return { 上传时间: formatBaseDateTime(now, BASE_TIME_ZONE) };
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
示例采用日期字段的增量更新,因此更新 Schema 中 `addedAt` 为可选项,创建 Schema 可继续要求必填。handler 按 [FaaS 输入契约](faas.md#faas-开发)校验并处理 helper 抛出的无效日期错误。清空日期需明确提交清空操作,不把空字符串解释成清空或今天。
|
|
207
|
+
|
|
208
|
+
无偏移文本不能唯一表示夏令时回拨时的重复小时。业务需要这类精确时刻往返时,先确认写入端支持的无歧义表示,不靠固定偏移或 helper 宣称已保证。显示时区与写入时区不同可以成立,但界面必须清楚表达,不能将显示文本直接回写。
|
|
209
|
+
|
|
210
|
+
### 日期与时间验证
|
|
211
|
+
|
|
212
|
+
- 纯日期:午夜前后、月末/年末、闰日;在不同浏览器/进程时区下回填相同业务日期。
|
|
213
|
+
- 编辑:只修改其他字段,写入 payload 不包含日期,底表原日期不变;主动修改日期后回读与选择一致;空值和 epoch `0` 分别处理。
|
|
214
|
+
- 事件:用已知 epoch 验证写入文本与目标时区,Database Function 回读后对应同一时刻(按接口精度比较),再分别验证页面和底表显示。覆盖实际使用时区的偏移和夏令时边界。
|
|
215
|
+
|
|
216
|
+
历史数据偏移先核对原始值、字段语义与时区配置,再判断是否需要修复;不要因发现一处转换错误而批量平移历史时间。
|
|
217
|
+
|
|
218
|
+
## AI 对话与调用
|
|
219
|
+
|
|
220
|
+
AI 调用使用 AI Function,不创建 FaaS 模型代理,也不直连模型域名。
|
|
221
|
+
Preview 使用草稿版本;Prod 使用正式发布的版本。Function 配置为 `disabled: true` 时不得调用。
|
|
222
|
+
能力归属按运行场景判断:面向当前页面业务流程的生成、分类、总结和推荐使用 AI Function;Base 查询与写入仍分别使用 Database Function 和 FaaS。
|
|
223
|
+
|
|
224
|
+
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 生成内容保留原文。
|
|
225
|
+
|
|
226
|
+
AI 与 Base 数据组合时保持既有边界:先用 Database Function 读取,再由 Page 裁剪必要数据并拼入 `messages` 或 `variables`;需要把结果写回 Base 时另行调用 FaaS。AI 调用本身不经过 FaaS。
|
|
94
227
|
|
|
95
228
|
## 开发期与运行态输出
|
|
96
229
|
|
|
97
|
-
| 调用层
|
|
98
|
-
|
|
|
99
|
-
| lark-cli 默认 JSON 输出
|
|
100
|
-
| Page `invokeDatabaseFunction` | 检查一次顶层 `code`,再校验 operation 的 `data`
|
|
101
|
-
|
|
|
102
|
-
| FaaS handler
|
|
103
|
-
| FaaS 下游记录写入
|
|
230
|
+
| 调用层 | 判定方式 |
|
|
231
|
+
| ----------------------------- | --------------------------------------------------------------------------------- |
|
|
232
|
+
| lark-cli 默认 JSON 输出 | 先检查进程退出与外层 `ok`,再按该命令的 `data` 契约取值;错误诊断见 `error` |
|
|
233
|
+
| Page `invokeDatabaseFunction` | 检查一次顶层 `code`,再校验 operation 的 `data` |
|
|
234
|
+
| Database Function | `data` 为 ResultJSON,包含 rows 等查询信息 |
|
|
235
|
+
| FaaS handler | 返回 `{data,code,msg}`,data 为业务结果,不再由 Page 二次解包 |
|
|
236
|
+
| FaaS 下游记录写入 | 检查下游 envelope 和各 batch 的结果语义,见[FaaS 协议](faas.md#应用记录-写入协议) |
|
|
104
237
|
|
|
105
238
|
不要把 SDK 的 `code===0` 套在 CLI 外层,也不要将 CLI 外层的 data 当作 handler 业务数据。raw API 的命令封装与业务响应按当前 lark-cli reference 分别解析。
|
|
106
239
|
|
|
@@ -108,8 +241,8 @@ Page 的所有业务 HTTP 都经父页面代理,使用 `page/src/lib/database-
|
|
|
108
241
|
|
|
109
242
|
实现前确定 operation 固定输入输出,按[工程质量](style-guide.md)检查远程调用依赖。新建示例数据在[发布阶段](release.md#从零建站示例数据验收)通过 CLI 写入真实 Base;不创建仅用于播种的 FaaS,也不在 Page 加载时自动写入。
|
|
110
243
|
|
|
111
|
-
|
|
244
|
+
Page 的读取与写入分别通过 Database Function 与 Mutation/FaaS,自动化使用[原生能力](base-capability-routing.md),不从页面模拟后台定时任务。附件上传使用 `siteRuntime.uploadAttachment()`,缩略图与下载复用 starter 的 `fetchAttachmentCover`、`fetchAttachmentDownloadUrl`;附件的写入选型、上传、展示与重试边界见[文件传输](file-transfer.md)。不能以 mock、未约定网关或旧列表整格覆盖代替。
|
|
112
245
|
|
|
113
|
-
|
|
246
|
+
修改或恢复旧应用时,按[旧工程与 CSRF 排查](verification.md#旧工程与-csrf-排查)迁移页面通信和构建配置。业务请求的身份与 CSRF 处理由宿主负责;Page 不注入 CSRF 脚本或手写 CSRF Header。
|
|
114
247
|
|
|
115
248
|
实现完成后按[发布与交付](release.md)继续;用户明确要求运行态检查时按[诊断与验收](verification.md)执行。
|
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
# FaaS 与记录协议
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
实现、维护或排查 FaaS 时读取;新写入的选型见[写入方式选择](mutations.md#写入方式选择)。Page 调用方式见[Page 开发](development.md),查询类型与参数见[Database Function](database-function.md),权限判定见[权限设计](permission-design.md)。
|
|
4
4
|
|
|
5
5
|
## 阅读路径
|
|
6
6
|
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
## FaaS 开发
|
|
15
15
|
|
|
16
|
-
|
|
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`
|
|
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
|
-
|
|
45
|
+
Database Function 的 `inputSchema` 不手写,由 CLI 根据 `meta.params` 的顺序和 `kind` 确定性生成固定长度数组 Schema;参数类型见 [查询参数协议](database-function.md#function-文件与参数)。
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
FaaS 在 `meta.json` 中声明 `inputSchema`,在 `index.ts` 中实现 handler。部署时,CLI 自动校验并上传 Schema 和应用源码。
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
handler 第一个参数 `rawParams` 是调用方的 `params` 业务对象;第二个参数是 runtime context:
|
|
48
50
|
|
|
49
51
|
```ts
|
|
50
52
|
interface FunctionContext {
|
|
@@ -90,27 +92,15 @@ function parseCreateTask(value: unknown): CreateTaskInput {
|
|
|
90
92
|
|
|
91
93
|
### 远程调用与写入链路设计
|
|
92
94
|
|
|
93
|
-
|
|
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
|
-
-
|
|
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
|
|
|
@@ -183,8 +173,7 @@ 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
178
|
路径首个参数是 **Base token,不是 应用 appToken**:取 `catalog.json` 中该表的
|
|
190
179
|
`tables[].baseToken`,与 table ID 一起作为 Function 内的工程常量。应用 appToken 只用于
|
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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` 非空是
|
|
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,
|
|
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 时调用固定
|
|
479
|
+
需要读 Base 时调用固定 Database Function:
|
|
488
480
|
|
|
489
481
|
```ts
|
|
490
482
|
const result: unknown = await context.invokeFunction({
|
|
@@ -494,28 +486,29 @@ const result: unknown = await context.invokeFunction({
|
|
|
494
486
|
})
|
|
495
487
|
```
|
|
496
488
|
|
|
497
|
-
确需写前查重、权限范围、状态检查或写后查询时复用固定
|
|
489
|
+
确需写前查重、权限范围、状态检查或写后查询时复用固定 Database Function;可以在一次查询中完成的检查不拆成多个串行调用。前一次查询返回的关联 ID 仅用于定位后一次查询的记录时,优先把关联查询下推为一个 Database Function。
|
|
498
490
|
|
|
499
491
|
## Base 读写协议
|
|
500
492
|
|
|
501
|
-
同一个字段在创建 schema、
|
|
493
|
+
同一个字段在创建 schema、Database Function 读取和 FaaS 应用记录 写入时使用三套不同但相关的数据结构。下表只适用于 FaaS 固定 batch 与附件增量路由;开发期 lark-cli 示例数据使用[发布手册中的独立输入契约](release.md#从零建站示例数据验收)。
|
|
502
494
|
|
|
503
|
-
| Field JSON |
|
|
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`
|
|
508
|
-
| 多选 `select` | `
|
|
509
|
-
| `datetime` | `TIMESTAMP`
|
|
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` / `
|
|
512
|
-
| 单/多 `group_chat` | `
|
|
513
|
-
| `link` | `
|
|
514
|
-
| `attachment` | `
|
|
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
|
|
|
@@ -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
|
|
552
|
+
batch 路由单批最多 200 条。多选、多人员和多值关联这些集合字段是**整格覆盖**:追加或移除必须先读现有值、合并出完整列表再整格写回,直接写会丢掉单元格里已有的项。单值关联同样用对象数组写入,但最多一个元素,替换时提交新的单元素数组,清空时提交 `null`。**附件字段是唯一的例外**:追加/移除走上面的附件增量路由,禁止用读-合并-整格写回实现——服务端不会补齐省略的宽高,而 Database Function 读不回旧图宽高,基于 Database Function 返回列表的重写无法重建宽高;并发时整格写回还会互相覆盖。见[文件传输](file-transfer.md)的「写单元格」。
|
|
560
553
|
|
|
561
|
-
**整格覆盖的合并基准必须是可信的完整列表。**
|
|
554
|
+
**整格覆盖的合并基准必须是可信的完整列表。** Database Function 回读走从库,刚写完就回读可能拿到写入前的旧值;拿缺项的列表做基准整格写回,会静默删掉其它项,而写入仍返回成功。读取失败、从未读到过、或回读缺少本次刚写入的项时,禁掉入口让用户稍后重试,不要写。
|
|
562
555
|
|
|
563
556
|
页面内可串行处理同一记录字段的更新,但不能因此承诺跨访问者原子性。文件字节的上传与展示是另外的路,见[文件传输](file-transfer.md)。
|