openxiangda 2.25.3 → 2.27.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/resource/useResourceFormDrafts.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.js +145 -16
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -1
- package/dist/browser/platform-client.d.ts +25 -1
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +62 -27
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/workflow-submission-recovery.d.ts +16 -0
- package/dist/browser/workflow-submission-recovery.d.ts.map +1 -0
- package/dist/browser/workflow-submission-recovery.js +56 -0
- package/dist/browser/workflow-submission-recovery.js.map +1 -0
- package/dist/core.d.ts +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/nest.d.ts +2 -2
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +1 -1
- package/dist/nest.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/documentation/backend.md +44 -13
- package/documentation/decimal-reservations.md +111 -0
- package/documentation/getting-started.md +7 -7
- package/documentation/manifest.json +11 -5
- package/documentation/testing.md +15 -0
- package/documentation/upgrading.md +12 -0
- package/package.json +28 -22
- package/releases/2.26.0.json +41 -0
- package/releases/2.27.0.json +38 -0
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +5 -4
- package/skills/openxiangda-v2/references/backend.md +44 -13
- package/skills/openxiangda-v2/references/decimal-reservations.md +111 -0
- package/skills/openxiangda-v2/references/getting-started.md +7 -7
- package/skills/openxiangda-v2/references/testing.md +15 -0
- package/skills/openxiangda-v2/references/upgrading.md +12 -0
|
@@ -41,6 +41,15 @@ SDK 继承当前环境与身份,平台沿用发起人或既有超级管理员
|
|
|
41
41
|
`items/nextCursor`,分页与多次流程的选择规则见[前端](frontend.md)。找回后使用原
|
|
42
42
|
`receipt/poll/surface`;查询不重放提交、不生成第二份命令状态。
|
|
43
43
|
|
|
44
|
+
连 commandId 都没收到时,用同一动作的 `businessProcess.resolveOriginal({ workflowCode,
|
|
45
|
+
idempotencyKey })` 查询原操作。此能力需要 `business-process.original-resolution` 1.0.0。
|
|
46
|
+
`committed` 才有可信回执;`not_observed` 可能仍在提交,不能据此生成新键或宣称回滚。
|
|
47
|
+
前端可用 `resolveBusinessProcessOriginal`(`openxiangda/react`),传原 workflowCode、
|
|
48
|
+
operationCode、idempotencyKey;SDK 绑定当前环境并核验返回关联。Named Action 如果业务无需
|
|
49
|
+
审批,没有流程回执并不代表业务没写入,应沿该动作自身回执诊断。
|
|
50
|
+
标准 PC/移动发起页在响应未知时保留原操作定位信息,刷新可继续查询;同一页面、原身份和
|
|
51
|
+
版本内可手动重试冻结的标准输入,绝不自动重发或悄悄换键。
|
|
52
|
+
|
|
44
53
|
自定义表单页若先用 `createResourceFormDraftClient` 保存认证草稿,并由 Named Action
|
|
45
54
|
提交业务记录和流程,则在同一次 `OpenXiangdaBusinessProcessService.commit` 中传入
|
|
46
55
|
`formDraft: { resourceCode, id, expectedRevision, mode, recordId?, viewCode? }`。草稿必须
|
|
@@ -101,21 +110,28 @@ data: {
|
|
|
101
110
|
|
|
102
111
|
### 幂等冲突复核 {#idempotency-recovery}
|
|
103
112
|
|
|
104
|
-
同一 `idempotencyKey`
|
|
113
|
+
同一 `idempotencyKey` 要求内容指纹一致。冻结首次请求的 operations、guards、expectedRevision、主体、环境和版本上下文;重试不能重新计算这些值。平台原回执的 `replayed` 才是重放成功证据。业务记录已经变化,本身不会导致原请求的幂等内容冲突;重新读取 revision 并改变请求才会。
|
|
114
|
+
|
|
115
|
+
`isIdempotencyConflict(error)` 只识别 409 `OPENXIANGDA_NATIVE_DATA_IDEMPOTENCY_CONFLICT`,不证明首次请求已成功。保留原操作并核对原回执;结果不明时显示“结果待确认”,不能把当前记录状态拼成伪造的成功回执,也不能换新键重试。部署 Head 改变时先恢复原上下文,不把同一键发送到另一版本当作原请求恢复。
|
|
116
|
+
|
|
117
|
+
### 使用生成类型绑定资源 {#typed-resources}
|
|
118
|
+
|
|
119
|
+
工具生成的共享契约导出 `ResourceTypes`;使用项目锁定版本的 `pnpm openxiangda check` 验证接入。三种 Nest 数据服务均保留原主体;当前用户业务优先用当前用户服务,具名业务动作使用业务服务。
|
|
105
120
|
|
|
106
121
|
```ts
|
|
107
|
-
import {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
}
|
|
122
|
+
import type { ResourceTypes } from '@app/contracts';
|
|
123
|
+
|
|
124
|
+
const resources = this.data.resources<ResourceTypes>();
|
|
125
|
+
const requests = resources('repair-requests');
|
|
126
|
+
const record = await requests.get(input.id);
|
|
127
|
+
return requests.update(record.data.id, {
|
|
128
|
+
expectedRevision: record.data.revision,
|
|
129
|
+
data: { assignedTechnician: userSnapshot(input.technicianId) },
|
|
130
|
+
});
|
|
117
131
|
```
|
|
118
132
|
|
|
133
|
+
资源名、写入字段、引用形状和 query 的字段/排序键会在 TypeScript 检查时验证;示例字段须由自己的模型声明。get/create/update/delete 保留 `data` 信封,revision 位于 `record.data.revision`。query 返回分页的 `items`。字段权限可能隐藏业务字段,所以读取类型保留这些字段可缺失的事实;应用必须按权限和必需字段做有意义的提示。该包装不会自动重试、修改 revision 或提升权限。运行时仍由平台校验所有输入。
|
|
134
|
+
|
|
119
135
|
事务守卫的 `errorCode` 必须匹配 `^OPENXIANGDA_[A-Z0-9_]{1,96}$`,例如 `OPENXIANGDA_REPAIR_REQUEST_NOT_PENDING`。
|
|
120
136
|
|
|
121
137
|
## 在同一事务中引用前序 create 生成的 id {#transaction-references}
|
|
@@ -161,8 +177,21 @@ platformAccess: { roleAssertions: { roleCodes: ['technician'] } }
|
|
|
161
177
|
```
|
|
162
178
|
|
|
163
179
|
`technician` 必须存在于本应用 `authz.roles`,最多声明 20 个角色。应用管理员身份
|
|
164
|
-
|
|
165
|
-
|
|
180
|
+
不自动代表维修角色。经办人使用请求作用域 `OpenXiangdaBusinessDirectoryService` 查询
|
|
181
|
+
本动作声明的候选,无需成员管理权:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
const page = await businessDirectory.assignmentCandidates({
|
|
185
|
+
roleCode: 'technician', keyword: input.keyword, limit: 20,
|
|
186
|
+
...(input.cursor ? { cursor: input.cursor } : {}),
|
|
187
|
+
});
|
|
188
|
+
// page.items 仅有 value/label;下一页沿用同一关键词和 page.nextCursor。
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
这项可选能力需要目标平台 `directory.assignment-candidates` 1.0.0。环境由 SDK 绑定,
|
|
192
|
+
禁止传入任意环境或账号。平台只返回生效、未过期、正常且未锁定的成员,验证账号与正式
|
|
193
|
+
账号隔离。游标绑定环境 Head、调用者、动作和角色,收到上下文变化错误后清空游标重新查询。
|
|
194
|
+
候选结果只用于选人;提交时仍使用下面的事务条件,不能凭查询结果绕过重新核验。
|
|
166
195
|
|
|
167
196
|
在 `OpenXiangdaBusinessDataApiService` 的同一次事务中表达业务状态与目标角色:
|
|
168
197
|
|
|
@@ -292,3 +321,5 @@ if (output.status === 'pending') {
|
|
|
292
321
|
```
|
|
293
322
|
|
|
294
323
|
这些方法适用于当前用户、具名业务动作和应用服务身份,沿用各自权限;业务记录绑定仍需正式数据事务。输出目前支持 OSS/MinIO,受字段上限与100MiB硬上限约束,上传凭据五分钟后过期,完成须在额外十分钟内进行。过期错误应由调用者建立新的处理意图,不能无限重试相同过期计划。下载最长五分钟,签发后到期前为短期委托,不能即时撤回。不要在日志、持久草稿或业务数据中保存签名地址、POST policy 或签名字段。
|
|
324
|
+
|
|
325
|
+
主子记录共享精确金额额度、撤回修订和审批释放,请使用[精确金额占用](decimal-reservations.md)的受管提交及终态事务。
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# 主子记录精确金额占用
|
|
2
|
+
|
|
3
|
+
需要跨多条子记录共享主记录额度时,使用平台 `data.decimal-reservations` 1.1.0,
|
|
4
|
+
金额字段声明 `number.decimal`、`precision: 18`、`scale: 2`、`exactDecimal: true`。
|
|
5
|
+
JSON 金额使用字符串。平台在父记录锁内用 PostgreSQL NUMERIC 校验占用;应用不做
|
|
6
|
+
浮点求和、不维护另一个余额字段。此能力需要匹配 SDK、平台镜像和迁移;包安装成功
|
|
7
|
+
不表示目标环境已就绪,先检查平台能力和正式部署回执。
|
|
8
|
+
|
|
9
|
+
## 声明与首次提交
|
|
10
|
+
|
|
11
|
+
提交的 Named Action 在 `platformAccess.decimalReservation` 声明 `mode: 'reserve'`、
|
|
12
|
+
资源、amount/currency/relation/parent/root/status 六个字段、主子关系取值和允许状态,
|
|
13
|
+
并用 `platformAccess.workflow.codes` 声明实际审批。当前用户仍需资源与字段读写权限。
|
|
14
|
+
首次使用会冻结环境内该资源的映射;已有未入账子记录时拒绝启用,不自动补账。
|
|
15
|
+
|
|
16
|
+
在 `OpenXiangdaBusinessProcessService.commit` 顶层增加:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const decimalReservation = {
|
|
20
|
+
parentId,
|
|
21
|
+
expectedParentRevision: parent.revision,
|
|
22
|
+
childOperationKey: 'child',
|
|
23
|
+
reservationKey: submission.reservationKey,
|
|
24
|
+
amount: '123.45',
|
|
25
|
+
currencyCode: 'CNY',
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`childOperationKey` 同 `workflow.subject.fromOperation`,选中唯一一条该资源的
|
|
30
|
+
create 或 update。平台原子完成子记录、占额、审批命令和可选本人草稿消费。
|
|
31
|
+
审批通过将 reserved 改为 committed,继续占额;驳回或撤回释放一次。
|
|
32
|
+
|
|
33
|
+
## 撤回后修订并重提
|
|
34
|
+
|
|
35
|
+
released 子记录仍不能通过普通 CRUD 或 `BusinessData.transaction` 修改金额、
|
|
36
|
+
状态、父/root/关系等保护字段。界面把修订保存到本人 FormDraft,重提时一次提交:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
await businessProcess.commit({
|
|
40
|
+
idempotencyKey: submission.idempotencyKey,
|
|
41
|
+
data: {
|
|
42
|
+
operations: [{
|
|
43
|
+
key: 'child', kind: 'update', resourceCode: 'contracts',
|
|
44
|
+
id: child.id, expectedRevision: child.revision,
|
|
45
|
+
data: {
|
|
46
|
+
title: draft.title,
|
|
47
|
+
amount: '123.45',
|
|
48
|
+
status: { value: 'approving' },
|
|
49
|
+
},
|
|
50
|
+
}],
|
|
51
|
+
},
|
|
52
|
+
formDraft: {
|
|
53
|
+
resourceCode: 'contracts', id: draft.id,
|
|
54
|
+
expectedRevision: draft.revision, mode: 'update', recordId: child.id,
|
|
55
|
+
},
|
|
56
|
+
decimalReservation,
|
|
57
|
+
workflow: { workflowCode: 'contract-approval', subject: { fromOperation: 'child' } },
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
每次新的提交意图使用新的 reservationKey 和提交键;网络结果未知时保留原键及原
|
|
62
|
+
payload查询/重试,不能用新键重做旧请求。更新保留父/root/关系,失败会整体回滚,
|
|
63
|
+
本人草稿仍可恢复,正式金额与审批命令不会半完成。普通主记录继续原来的无额度路径。
|
|
64
|
+
|
|
65
|
+
## 真实审批事件终态
|
|
66
|
+
|
|
67
|
+
在真实审批消费者的 `platformAccess` 增加以下声明;其中状态取值由应用自己的
|
|
68
|
+
资源选项决定。审批必须声明同一 subject 资源,且存在该资源的 reserve 动作映射。
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
platformAccess: {
|
|
72
|
+
decimalReservation: {
|
|
73
|
+
resourceCode: 'contracts', workflowCode: 'contract-approval',
|
|
74
|
+
outcomes: [
|
|
75
|
+
{ eventType: 'openxiangda.workflow.instance.completed.v2', mode: 'commit', eligibleChildStatuses: ['signing'] },
|
|
76
|
+
{ eventType: 'openxiangda.workflow.instance.rejected.v2', mode: 'release', eligibleChildStatuses: ['rejected'] },
|
|
77
|
+
{ eventType: 'openxiangda.workflow.instance.withdrawn.v2', mode: 'release', eligibleChildStatuses: ['draft'] },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
每个 eventType 也必须列在订阅的 eventTypes 中。不得使用自造应用事件或
|
|
84
|
+
native-data execution 订阅获得此权限。事件 handler 中用已有的
|
|
85
|
+
`OpenXiangdaApplicationDataApiService`,将终态附加到原事务:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { idempotentTransaction } from 'openxiangda/nest';
|
|
89
|
+
|
|
90
|
+
await applicationData.transaction(idempotentTransaction(
|
|
91
|
+
context.idempotencyKey,
|
|
92
|
+
[childStatusUpdate, auditCreate],
|
|
93
|
+
[],
|
|
94
|
+
{ decimalReservation: {
|
|
95
|
+
reservationKey: originalSubmission.reservationKey,
|
|
96
|
+
transitionKey: context.idempotencyKey,
|
|
97
|
+
childOperationIndex: 0,
|
|
98
|
+
} },
|
|
99
|
+
));
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
选中的 childStatusUpdate 必须是该资源唯一 update,保留正常 expectedRevision。
|
|
103
|
+
模式和金额不能放进终态请求;平台从真实 leased delivery、原始及当前不可变订阅、
|
|
104
|
+
workflow command/instance/subject revision 和台账验证,SDK自动继承已验签事件上下文。
|
|
105
|
+
普通应用凭据或自填事件头不构成授权。精确同键、同payload重放返回原完整事务结果;
|
|
106
|
+
旧轮次不能释放重提后的新占用。重放仍受当前权限、有效事件租约和父记录可读性约束。
|
|
107
|
+
|
|
108
|
+
首批只覆盖主子额度和三个真实审批结果。作废/终止释放 committed 必须另有受管
|
|
109
|
+
真实业务动作;状态枚举不代表已实现该能力,签后金额变更仍拒绝。锁等待最多2秒、
|
|
110
|
+
单条SQL最多5秒,较严格的已有约束优先;retryable 409
|
|
111
|
+
`OPENXIANGDA_NATIVE_DECIMAL_CONTENTION` 不允许换键掩盖未知结果。
|
|
@@ -68,10 +68,10 @@ MCP 服务随项目根包一起安装,AI 客户端的 stdio 连接仍需配置
|
|
|
68
68
|
以下命令的版本占位符由随包资料替换为该根包的精确版本。网站源码阅读者应先确认要使用的发行版本。
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
|
-
pnpm dlx openxiangda@2.
|
|
72
|
-
pnpm dlx openxiangda@2.
|
|
73
|
-
pnpm dlx openxiangda@2.
|
|
74
|
-
pnpm dlx openxiangda@2.
|
|
71
|
+
pnpm dlx openxiangda@2.27.0 skill install --force
|
|
72
|
+
pnpm dlx openxiangda@2.27.0 auth status --base-url <平台地址> --json
|
|
73
|
+
pnpm dlx openxiangda@2.27.0 login --cwd my-app --base-url https://platform.example.com
|
|
74
|
+
pnpm dlx openxiangda@2.27.0 create my-app --base-url https://platform.example.com
|
|
75
75
|
cd my-app
|
|
76
76
|
pnpm openxiangda context --json
|
|
77
77
|
pnpm openxiangda dev
|
|
@@ -174,9 +174,9 @@ MCP 的 `docs_read` 可以读取本说明,当前没有独立的源码操作 MC
|
|
|
174
174
|
无需本地工作区,使用本 Skill 随包精确版本或已安装的对应 CLI:
|
|
175
175
|
|
|
176
176
|
```bash
|
|
177
|
-
pnpm dlx openxiangda@2.
|
|
178
|
-
pnpm dlx openxiangda@2.
|
|
179
|
-
pnpm dlx openxiangda@2.
|
|
177
|
+
pnpm dlx openxiangda@2.27.0 auth status --base-url <平台> --json
|
|
178
|
+
pnpm dlx openxiangda@2.27.0 source resolve <仓库URL> --base-url <平台> --json
|
|
179
|
+
pnpm dlx openxiangda@2.27.0 source clone <仓库URL> <新目录> --base-url <平台> --json
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
登录缺失或站点不匹配时,先按该平台执行 login。resolve 根据平台已经登记的绑定返回
|
|
@@ -64,6 +64,21 @@ pnpm openxiangda accept --plan .openxiangda/acceptance-plan.json --json
|
|
|
64
64
|
|
|
65
65
|
记录源码/包版本、AppVersion、环境、角色、预期及实际结果、必要请求标识。区分本地检查、分发安装、部署激活与业务验收。某项未执行时说明原因,不将其写成通过。
|
|
66
66
|
|
|
67
|
+
## 复制请求诊断 {#request-diagnostics}
|
|
68
|
+
|
|
69
|
+
标准浏览器请求错误保留服务端 requestId,文件导出及权限读取重试耗尽也使用同一错误类型。自定义页面通过公开入口读取固定格式诊断:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { platformRequestDiagnostic } from 'openxiangda/react';
|
|
73
|
+
|
|
74
|
+
function supportDetails(error: unknown) {
|
|
75
|
+
const diagnostic = platformRequestDiagnostic(error);
|
|
76
|
+
return diagnostic ? JSON.stringify(diagnostic, null, 2) : null;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
将这段结果放入当前操作的错误详情,附应用版本和原 operationId/DeploymentRun;不要复制 Cookie、令牌、完整请求正文或原始响应。诊断包含错误码、请求路径(无 query)、方法、站点内应用/环境、观测时间和合法 requestId。网络未收到响应时 requestId 为 null,不能编造关联标识。该信息不等于提交结果:写入未知时查询原操作,保留原键与原输入;不要自动换键再写。Nest SDK 的平台错误已有 `request` 上下文,平台管理仍通过授权范围内的日志/支持通道检索。
|
|
81
|
+
|
|
67
82
|
## 并发执行
|
|
68
83
|
|
|
69
84
|
同一工作区的公共 check 和测试 deploy 共享本地互斥锁,前一个命令结束后才能启动下一个。出现 WORKSPACE_OPERATION_BUSY 时等待当前进程完成;异常退出时先确认锁中进程已经退出,再移除提示中的锁文件。锁只保护工具执行,不阻止编辑器修改源码;检查和部署期间应暂停其他写入。平台部署状态仍以 status/logs 为准。
|
|
@@ -20,6 +20,18 @@
|
|
|
20
20
|
|
|
21
21
|
## 更新项目 {#upgrade}
|
|
22
22
|
|
|
23
|
+
按实际启用的功能核对要求,不把浏览器文案、局部错误提示等更新当成平台升级理由:
|
|
24
|
+
|
|
25
|
+
| 变化 | 平台条件 | 应用验证 |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| ResourceTypes 和 Nest 类型绑定 | 复用现有 Data API;不新增服务端模型协议 | 运行生成与类型检查,确认隐藏字段可缺失及 revision 来源 |
|
|
28
|
+
| 浏览器安全诊断、安装错误提示 | 复用现有响应及请求头 | 模拟只读失败、导出失败、网络中断,确认没有重复写入 |
|
|
29
|
+
| 原流程提交结果恢复 | 可选 `business-process.original-resolution` 1.0.0 | 原幂等键查询、刷新恢复、授权拒绝,未知不能转换为未提交 |
|
|
30
|
+
| 业务角色候选 | 可选 `directory.assignment-candidates` 1.0.0 | 当前动作声明的角色、目标环境、过期/锁定账号、提交再校验 |
|
|
31
|
+
| 预检一次汇总 | 已协商的 configuration-compatibility 与共享 validator 摘要一致 | 同时缺能力/密钥/登录提供方时一次报告;成功结果仍按闭合协议校验 |
|
|
32
|
+
|
|
33
|
+
平台能力声明、共享校验摘要、根包精确依赖及发布说明共同构成兼容依据。版本号大小、某次 Pod Ready 或历史工单“已发布”不能替代当前目标能力读回。未启用新增可选能力的旧应用继续使用原协议;不承诺未经回归验证的任意旧版本组合。
|
|
34
|
+
|
|
23
35
|
更新项目的精确根包依赖并安装,提交相应锁文件;不要使用 latest、alpha 或范围版本代替明确版本。运行统一 check,处理实际契约变化,再在测试环境验证后晋级。
|
|
24
36
|
|
|
25
37
|
执行 `pnpm openxiangda skill install --workspace . --force`,通过新版本根包安装 Skill;已有项目使用项目安装模式时会刷新 AGENTS 的平台管理段,并保留管理段外的自定义说明。没有可识别管理段的旧 AGENTS 不会被整份替换;先审阅工具输出的候选内容,再合并需要的规则。
|