openxiangda 2.13.0 → 2.14.0
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/dist/browser/components/platform-fields/rich-text-value.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/rich-text-value.js +7 -2
- package/dist/browser/components/platform-fields/rich-text-value.js.map +1 -1
- package/dist/browser/components/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/platform-client.d.ts +11 -1
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +24 -2
- package/dist/browser/platform-client.js.map +1 -1
- package/documentation/AGENTS.md +2 -1
- package/documentation/data-authz.md +15 -1
- package/documentation/design-workflow.md +7 -5
- package/documentation/frontend.md +8 -0
- package/documentation/getting-started.md +7 -7
- package/documentation/manifest.json +7 -7
- package/documentation/product-design.md +1 -1
- package/documentation/public-access.md +81 -2
- package/package.json +30 -30
- package/releases/2.13.1.json +33 -0
- package/releases/2.13.2.json +31 -0
- package/releases/2.14.0.json +41 -0
- package/skills/manifest.json +2 -2
- package/skills/openxiangda-v2/SKILL.md +27 -7
- package/skills/openxiangda-v2/references/data-authz.md +15 -1
- package/skills/openxiangda-v2/references/design-workflow.md +7 -5
- package/skills/openxiangda-v2/references/frontend.md +8 -0
- package/skills/openxiangda-v2/references/getting-started.md +7 -7
- package/skills/openxiangda-v2/references/product-design.md +1 -1
- package/skills/openxiangda-v2/references/public-access.md +81 -2
|
@@ -141,4 +141,4 @@ context 的 `readyForImplementation` 为真时才制定具体实现任务,把
|
|
|
141
141
|
- [Design OS,固定提交](https://github.com/buildermethods/design-os/tree/529dedb43bfec24b2cbb128f26dd8cbc6143f754)(MIT)。
|
|
142
142
|
- [Spec Kit,固定提交](https://github.com/github/spec-kit/tree/4a7341a93d944d6efe153b71da4a1adb9c2b578c)(MIT)。
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
有界面影响的工作默认由 AI 通过 design cli / 原版 MCP 使用 OpenDesign,完成可运行原型、浏览器修正及实现交接,见[设计工作流](design-workflow.md)。客户端仅用于用户主动预览;原版运行时拥有完整设计资源和工作流,随包方法与 Craft 仅作离线参考。
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
OpenXiangda 2.0 支持没有平台账号的外部访客打开一个明确公开的用户页面,保存并续填草稿、
|
|
4
4
|
上传平台托管附件、执行具名重复校验、正式提交,并在同一浏览器中查看自己已提交的列表和详情。
|
|
5
|
+
应用也可以显式发布某个资源的部分记录字段,让外部浏览器分页查询公开记录或读取一条公开记录。
|
|
5
6
|
|
|
6
7
|
该能力识别的是“持有同一个平台 HttpOnly 浏览器凭证的访问者”,不是经过实名验证的自然人。
|
|
7
8
|
清除 Cookie、无痕模式、另一浏览器或另一设备都会成为新的匿名访问者,不能找回原草稿和记录。
|
|
@@ -21,7 +22,7 @@ User-Agent 或浏览器指纹猜测同一个人。
|
|
|
21
22
|
## 应用声明
|
|
22
23
|
|
|
23
24
|
资源仍然按普通 Native Resource 声明。公开能力只在一个静态 `surface: 'user'` 路由上增加一个
|
|
24
|
-
严格有界的 `frontend.publicAccess`
|
|
25
|
+
严格有界的 `frontend.publicAccess` 策略;同一路由可以按设备或资源声明多条策略,调用方必须带策略码:
|
|
25
26
|
|
|
26
27
|
```ts
|
|
27
28
|
export default defineOpenXiangdaApp({
|
|
@@ -104,9 +105,83 @@ export default defineOpenXiangdaApp({
|
|
|
104
105
|
| `create` | 以幂等键正式提交当前草稿 |
|
|
105
106
|
| `own.list` | 分页查看同一浏览器正式提交的记录 |
|
|
106
107
|
| `own.read` | 查看同一浏览器的一条正式提交详情 |
|
|
108
|
+
| `public.list` | 分页查看当前策略明确发布的资源记录 |
|
|
109
|
+
| `public.read` | 读取当前策略明确发布的一条资源记录 |
|
|
107
110
|
|
|
108
111
|
`own.list` 和 `own.read` 不是一般查询权限。服务端固定注入匿名主体、当前公开策略和已提交草稿
|
|
109
|
-
回执条件,不接受调用方的 where
|
|
112
|
+
回执条件,不接受调用方的 where、排序、投影或统计表达式。`public.list` 和 `public.read` 同样不是
|
|
113
|
+
一般查询权限:它们只读取策略绑定资源在当前租户、应用和环境下的记录,服务端固定按创建时间和 id
|
|
114
|
+
倒序分页,只返回 `publicRecordFields` 中显式列出的字段和记录 `id`。附件、图片和清洗后的富文本
|
|
115
|
+
通过平台托管文件路由公开,不返回对象存储地址。子表字段必须在 `publicSubtableFields` 中再次显式
|
|
116
|
+
列出子资源字段,服务端按声明顺序和行数上限返回一层子表数据。签名字段仍不公开。当前不支持调用方
|
|
117
|
+
筛选、排序、聚合或导出。
|
|
118
|
+
|
|
119
|
+
## `draft` 与公共读取
|
|
120
|
+
|
|
121
|
+
`draft` 是匿名提交的服务端事务载体,不是“外部访问”本身,也不是公共读取的前置条件。提交表单时,
|
|
122
|
+
平台需要先把不完整的输入保存到当前匿名浏览器的草稿,并用 `revision` 做并发控制;附件元数据绑定
|
|
123
|
+
到草稿;最终 `create` 会在同一数据库事务中锁定草稿、重新执行必填和重复校验、创建业务记录、标记
|
|
124
|
+
草稿已提交,并用幂等键保证不重复创建。因此声明 `create` 必须同时声明 `draft: { enabled: true }`,
|
|
125
|
+
而且同一策略的 `draft.read` 与 `draft.update` 必须成对出现。
|
|
126
|
+
|
|
127
|
+
公共只读场景不需要草稿。只声明 `public.list`/`public.read` 和 `publicRecordFields` 的策略可以直接
|
|
128
|
+
调用公共查询;它不会获得 `create`、`draft`、`own.*` 或普通 Native Data API 权限。不要为了查询已发布
|
|
129
|
+
数据创建一个“空草稿”,也不要把 `draft id` 传给浏览器。
|
|
130
|
+
|
|
131
|
+
例如,目录页面可以只发布明确选定的字段:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
{
|
|
135
|
+
code: 'catalog-public',
|
|
136
|
+
routeCode: 'catalog',
|
|
137
|
+
mode: 'anonymous',
|
|
138
|
+
resourceCode: 'catalog-items',
|
|
139
|
+
operations: ['public.list', 'public.read'],
|
|
140
|
+
fields: ['name', 'category', 'available', 'internalNote'],
|
|
141
|
+
publicRecordFields: ['name', 'category', 'available', 'items'],
|
|
142
|
+
publicSubtableFields: { items: ['sku', 'quantity'] },
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`publicRecordFields` 必须是 `fields` 和资源字段的子集;附件、图片和 `text.rich` 可公开,签名仍被
|
|
147
|
+
拒绝。公开子表字段必须配置 `publicSubtableFields`,其键是父资源的子表字段,值是子资源字段列表;
|
|
148
|
+
编译器会拒绝未声明字段、嵌套子表和缺少子字段投影。公共读取沿用明确公开的 `frontend.publicAccess`
|
|
149
|
+
路由和匿名浏览器凭证,不创建 guest 角色或虚拟内部用户。
|
|
150
|
+
|
|
151
|
+
需要隐藏停用、归档或租户标记记录时,使用固定 `publicFilters`,由服务端对每次 `public.list`/
|
|
152
|
+
`public.read` 强制追加。当前只支持最多 16 个不同字段的 `eq` 等值条件,字段必须属于策略的
|
|
153
|
+
`fields` 且仅允许布尔、文本、数值、日期和时间标量;调用方不能覆盖、追加或删除这些条件:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
publicFilters: [{ field: 'enabled', operator: 'eq', value: true }]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
匿名创建需要平台生成的不可预测字段时,使用 `serverGeneratedFields`。这些字段不属于
|
|
160
|
+
`fields`,调用方不能在草稿中写入;提交事务会由平台生成随机值并在提交回执的 `generated`
|
|
161
|
+
对象中返回。`random-token` 只适用于不承载身份信息的核验令牌等用途:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
serverGeneratedFields: [{ field: 'qrToken', kind: 'random-token' }]
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
需要跨资源复核预约窗口等业务不变量时,可声明 `schedule`,绑定两个只读公开策略和资源字段。
|
|
168
|
+
平台会在最终创建事务中重新读取启用校区与规则,校验星期、日期范围、提前小时数和离散时段;页面端
|
|
169
|
+
校验只能改善体验,不能替代这次服务端复核。
|
|
170
|
+
|
|
171
|
+
子表中的文件引用会自动带上受控的 `resourceCode` 与父字段绑定;应用如需为附件生成下载地址,使用
|
|
172
|
+
`fileContentUrl(fileId, disposition, variant, resourceCode, parentFieldCode)`,不要自行拼接文件路径。
|
|
173
|
+
|
|
174
|
+
## 为什么不开放普通 Native Data API
|
|
175
|
+
|
|
176
|
+
普通 Native Data API 是内部或应用后端的可信数据边界,允许调用方提交
|
|
177
|
+
`select`、`where`、`order`、批量查询、聚合和导出,并按当前登录用户角色执行行列权限。匿名
|
|
178
|
+
公开发布的语义不同:它必须只绑定一个资源和不可变字段白名单,不接受调用方筛选、排序、聚合、
|
|
179
|
+
导出或自带角色,也必须把文件绑定到公开记录和公开字段后再读取。
|
|
180
|
+
|
|
181
|
+
直接把普通 Native Data API 暴露给浏览器会允许枚举内部资源和字段、通过筛选和计数推断未公开数据,
|
|
182
|
+
放大查询资源消耗,并增加文件 ID 猜测、审计字段泄露和权限合同混用的风险。因此公共端点继续是
|
|
183
|
+
专用的 `public.list`/`public.read`;底层可以复用 Native 的 RLS 和文件所有权校验,但不把 Native
|
|
184
|
+
Data API 的输入面开放给匿名调用方。
|
|
110
185
|
|
|
111
186
|
## 页面客户端
|
|
112
187
|
|
|
@@ -133,6 +208,10 @@ const receipt = await client.submit(withPhoto.revision, crypto.randomUUID());
|
|
|
133
208
|
|
|
134
209
|
const page = await client.listOwn({ pageSize: 20 });
|
|
135
210
|
const detail = await client.getOwn(receipt.recordId);
|
|
211
|
+
|
|
212
|
+
// 只读公开目录不需要先读取或保存 draft。
|
|
213
|
+
const publicPage = await client.listPublic({ pageSize: 20 });
|
|
214
|
+
const publicDetail = await client.getPublic(publicPage.items[0].data.id as string);
|
|
136
215
|
```
|
|
137
216
|
|
|
138
217
|
必须先 `bootstrap()`。草稿更新始终使用最近返回的 revision,冲突时重新读取,不能覆盖写。
|