openxiangda-skill-kit 2.3.36 → 2.3.37
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda-skill-kit",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.37",
|
|
4
4
|
"description": "OpenXiangda 2.0 中文 AI 技能的校验、分发与安装。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"openxiangda-devkit-core": "2.
|
|
20
|
+
"openxiangda-devkit-core": "2.35.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"tsx": "4.23.12",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 并发能力的前端接入
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
适用于活动报名、限量申领、抢票和预约。permit API 从 `openxiangda@2.31.0` 引入;目标平台必须支持 `data.managed-concurrency@1.0.0`。先按[缓存、排队与整数配额](managed-concurrency.md)声明读取、命令、配额和权限,再选择页面接入形式。
|
|
4
4
|
|
|
5
5
|
推荐体验是正常浏览内容,在用户明确提交时按需等待,并持续核对同一次申请的结果。低负载时可以很快完成,不需要人为添加等待页。
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
| 形式 | 适用场景 | 用户流程 | 当前接入方式 |
|
|
10
10
|
| --- | --- | --- | --- |
|
|
11
|
+
| 持久受理后可离开 | 后台自动完成、跨设备恢复 | 填写 → 明确提交 → 持久受理 → 查询结果 | `useDurableCommand`,需 durable 独立能力 |
|
|
11
12
|
| 热点内容直接浏览 | 详情、场次、活动说明 | 浏览 → 按需刷新 | `client.read`,应用处理读取状态 |
|
|
12
13
|
| 按钮发起、原地等待 | 一键报名、限量申领 | 点击 → 排队 → 处理 → 结果 | `useManagedCommand` + `ManagedCommandStatus` |
|
|
13
14
|
| 先填写、再排队提交 | 有选项的预约和申请 | 填写校验 → 确认内容 → 排队提交 | 有界参数组合现有 hook;复杂资料需要额外冻结契约 |
|
|
@@ -167,17 +168,17 @@ export function ClaimAction({ offerId }: { offerId: string }) {
|
|
|
167
168
|
|
|
168
169
|
默认恢复信息保存在 `sessionStorage`,按应用、环境、主体、命令和 `storageKey` 隔离。同标签页刷新可以恢复;`storageKey` 必须稳定,不能在每次渲染时随机生成。存储不可用时明确停止或处理,不能悄悄改用易丢失的内存继续提交。
|
|
169
170
|
|
|
170
|
-
已知 `operationId` 或原 `requestKey` 时,可以用 `client.result`
|
|
171
|
+
已知 `operationId` 或原 `requestKey` 时,可以用 `client.result` 查询原结果。已成功业务记录可通过本人权限下的普通数据查询展示。durable 命令另有 client.mine 和 useDurableCommand 用于本人跨设备恢复,见下文;原 permit 等待票据仍依赖本地保存,不能把浏览器存储当作全平台事实。
|
|
171
172
|
|
|
172
173
|
不要把超时解释为提交失败,也不要在结果未知时 `clear()`。重试、恢复与返回入口都应该指向原意图。配额永久去重与界面请求键是不同边界:清除一个已终结的界面状态不代表可以再次获得同一池名额。
|
|
173
174
|
|
|
174
175
|
## 当前组件与后续封装边界 {#available-components}
|
|
175
176
|
|
|
176
|
-
当前可用:`createManagedConcurrencyClient`、`useManagedCommand`、`ManagedCommandStatus`、`ManagedCommandGate`,以及客户端的读取、结果、取消和分配状态方法。
|
|
177
|
+
当前可用:`createManagedConcurrencyClient`、`useManagedCommand`、`useDurableCommand`、`ManagedCommandStatus`、`ManagedCommandGate`,以及客户端的读取、结果、取消和分配状态方法。
|
|
177
178
|
|
|
178
179
|
`useManagedRead`、`ManagedCommandButton`、`ManagedCommandPanel`、`useManagedFormSubmission`、`useManagedAllocation`、`AllocationStatus` 是建议的后续封装名称,当前不是公开导出。不要照这些名称编写 import。应用现在可以使用已有 hook 与平台普通 UI 组件组合界面,后续标准封装仍应复用同一状态机和传输。
|
|
179
180
|
|
|
180
|
-
|
|
181
|
+
复杂资料冻结、跨所有命令的全局索引、独立页面准入及精确倒计时需要相应的平台契约,不能仅通过前端外观补齐。SDK 版本、平台部署和实际业务容量需要分别确认。
|
|
181
182
|
|
|
182
183
|
## 接入验收 {#acceptance}
|
|
183
184
|
|
|
@@ -194,3 +195,21 @@ export function ClaimAction({ offerId }: { offerId: string }) {
|
|
|
194
195
|
| 键盘、屏幕阅读器、窄屏 | 状态可读,焦点可控,关闭与取消语义清楚 |
|
|
195
196
|
|
|
196
197
|
这些检查与目标环境的吞吐、P95/P99、授权查询成本和故障恢复验证一起完成;页面演示和 SDK 单元测试不能代替真实业务验收。
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
## 持久受理与跨设备恢复 {#durable}
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
const client = useMemo(() => createManagedConcurrencyClient(), []);
|
|
204
|
+
const command = useDurableCommand({client,command:'registration-enroll',resourceKey:activityId});
|
|
205
|
+
// 仅真实点击提交;不是 useEffect 或页面 mount 回调。
|
|
206
|
+
const submit = () => command.submit({activity:activityId,channel:channelId,agreed:true,phone});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
hook 从 `openxiangda/react` 和 `openxiangda/mobile` 导出。state、initialized、isObserving、requestKey、receipt、errorCode 用于统一状态区;submit(input)、resume()、refresh()、stop() 分别为明确提交、用冻结 input 重试原请求、恢复查询和停止观察。挂载只查本地原 key 或服务端 mine,不自动 enqueue。未知应答保留原 key 与 input;用户恢复后先查原结果,不能换 key 重试。浏览器存储失败在提交前明确失败。未知应答后的恢复按钮调用 resume(),不传当前可能已经修改的表单。snapshot.input 可恢复本地冻结表单;跨设备只有回执时不展示推测的原输入。一次明确 submit/resume 期间,429、暂时5xx或网络错误会按原 key/input 自动退避恢复,先查原结果再重试 enqueue,最多6次、最长120秒,遵守更长的 Retry-After;尚无 receipt 时只能提示“正在确认受理”,不能承诺可关闭页面。用完预算保留原意图,明确点击 resume() 继续。如果刷新时原请求尚未被平台受理,挂载只查询,明确点击 resume() 才重新启动有界受理重试。
|
|
210
|
+
|
|
211
|
+
默认每次至少间隔 5 秒,遵守更长的服务端 retryAfterMs,再加随机抖动;暂时失败指数退避,终态停止。一个业务区域只挂载一个观察者。离开或关闭页面不撤销已受理请求,平台自动继续;新设备通过 mine 找到本人的原请求。position 为空时显示「已受理,稍后可查看」,不要显示虚假的精确人数或预计秒数。
|
|
212
|
+
|
|
213
|
+
refresh 会优先恢复 mine 返回的新进行中周期,避免本地历史 succeeded 遮蔽另一个设备的新申请。不要在 mount 发现历史 succeeded 时自动跳成功页或永久禁用提交。它可能已经被管理员取消,需结合当前业务记录展示。只有用户明确再次点击 submit,且原请求已有终态,SDK 才创建新的 requestKey;活跃请求或未知应答始终恢复原 key。平台明确返回未受理的参数错误(400 + CONCURRENCY_INPUT_INVALID 等约定错误)时,SDK 才清除被拒输入,允许修正后再提交;未知 400、409、429、5xx 和网络错误仍保留原意图。成功提示以 receipt.state==='succeeded' 和 receipt.result 为准,accepted/executing 只显示「已登记,处理中」。
|
|
214
|
+
|
|
215
|
+
permit 的 ManagedCommandGate 仍只用于 admitted 短确认,不用于 durable。durable 不能套任意前端 onSubmit 冒充后台事务,真正业务必须由已声明的 backend-plan handler 返回受管计划。
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| `commands` | 当前用户的能力、按资源分队列、最长等待、处理截止、Native 守卫和原子写入 |
|
|
16
16
|
| `quotas` | 容量来源、业务记录上的分配 ID、可选的预占到期时间 |
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
默认 permit 模式的参数限于 UUID、有限字符串枚举和有限整数范围;绑定只接受 `input`、可信 `actor`、字面量和平台生成的 `allocation`。permit 命令最多 8 个操作、8 个记录守卫。permit 模式不执行应用任意 JS/SQL,也不在锁内调用外部系统。通知和外部副作用接已有事务后事件。
|
|
19
19
|
|
|
20
20
|
配额来源模型的容量字段必须是整数;分配记录模型的引用字段必须是必填 UUID,模型设置 `mutationOwner: 'queued-command'`。角色仍须具备来源读取、分配模型创建和命令能力。普通 CRUD、导入、应用凭据均不能绕过命令所有权。用户身份由 `actor` 绑定,不能使用用户填写的人员编号决定名额归属。
|
|
21
21
|
|
|
@@ -75,7 +75,7 @@ export function Claim({ offerId }: { offerId: string }) {
|
|
|
75
75
|
|
|
76
76
|
立即分配用 `quota.action: 'allocate', mode: 'committed'`;需要预占时声明 `reservationSeconds` 并用 `mode: 'reserved'`。另声明 `confirm`、`release` 命令,绑定原 `allocation`,该命令的 `operations` 为空。只有原主体可确认/释放;到期与确认竞争使用数据库时间及固定锁顺序。
|
|
77
77
|
|
|
78
|
-
原命令回执不可变。预占之后到期或释放,应调用 `client.allocation(allocationId)`
|
|
78
|
+
原命令回执不可变。预占之后到期或释放,应调用 `client.allocation(allocationId)` 获取当前分配状态,不能用旧成功回执证明仍持有名额。内置 quota 模式同一池/主体保留永久去重事实,释放后不会自动重新报名;应用若需要新一轮,应使用新的权威资源/配额池,不能删除历史分配。
|
|
79
79
|
|
|
80
80
|
容量减少不能低于已预占加已确认数量。存在配额历史时,禁止删除来源、改写分配引用或发布移除配额映射的版本。应用激活先排空所有非终态命令;不会让旧任务在新 Head 上执行。连接开发消费已激活测试版本的并发声明,未激活的本地模型覆盖层不能作为持久命令契约。
|
|
81
81
|
|
|
@@ -98,3 +98,54 @@ RabbitMQ 的消息只是唤醒提示;队列丢失或发布失败由数据库
|
|
|
98
98
|
暂停/恢复按同一个环境锁串行传播;Redis 不可用时控制接口明确报错。控制值是绝对值,可以使用相同 `paused` 重试并核对状态。数据库提交确认丢失时不猜测控制结果;受理始终复查数据库的暂停状态。
|
|
99
99
|
|
|
100
100
|
验证应包括内容 SQL 与授权 SQL 占比、每秒完成数、P95/P99、最老等待、连接数、锁等待和恢复时间。仓库故障测试证明协议边界,不代表任何客户环境的生产吞吐。部署者仍需使用目标硬件、真实权限和活动规模做容量验收。
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
## 持久排队的应用业务计划(durable)
|
|
104
|
+
|
|
105
|
+
需要「受理后关闭浏览器仍继续」或取消后再次申请的业务,声明 `mode: 'durable'` 和 `execution.kind: 'backend-plan'`,额外要求 `data.managed-concurrency.durable@1.0.0`。默认省略 mode 仍走原 permit 协议,不能混用 wait/accept 和 enqueue。持久受理先提交数据库;MQ 只唤醒,Redis 只保存可重建的预算和位置投影。受理成功不是报名成功。
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
{
|
|
109
|
+
code: 'registration-enroll', mode: 'durable', capability: 'app:arts:registration:submit',
|
|
110
|
+
parameters: { activity: {type:'uuid'}, channel: {type:'uuid'},
|
|
111
|
+
agreed: {type:'boolean'}, phone: {type:'string',maxLength:32} },
|
|
112
|
+
resourceKey: {from:'input',key:'activity'}, deadlineSeconds:3600,
|
|
113
|
+
intake: {perSecond:100,burst:100,maxInFlight:50},
|
|
114
|
+
admission: {perSecond:2,burst:2,maxInFlight:2,maxQueue:5000,maxWaitSeconds:3600},
|
|
115
|
+
execution: {kind:'backend-plan',handlerCode:'registration-enroll',timeoutMs:10000,
|
|
116
|
+
resources:[{resourceCode:'registrations',readFields:['id','activityId','person'],
|
|
117
|
+
writeOperations:['create'],writeFields:['activityId','person']}],
|
|
118
|
+
directory:{mode:'current-initiator',fields:['displayName','employeeNumber','primaryDepartment','departments']}}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
这是声明片段,资源/字段、角色能力和应用总 admission 必须与实际模型一致。示例预算不是吞吐量承诺。durable 参数最多 8 个、编码最多 8 KiB;自由字符串 maxLength 最大 256,boolean 只允许 durable。intake 的 perSecond/burst/maxInFlight 各为 1..1000,独立限制新受理;admission 三项限制执行,不能超过应用共享预算。maxQueue 最大 10000,maxWaitSeconds 最大 3600,deadlineSeconds 为 10..3600,处理期限从最初数据库 acceptedAt 起算,重试不延长。
|
|
123
|
+
|
|
124
|
+
resources 最多 32 个,每项 readFields/writeFields 各最多 64 字段,writeOperations 仅 create/update/increment;不声明即不可访问。directory 仅允许当前发起人及四种现有字段,不接受 userId。不得同时声明静态 operations/guards/quota。普通业务模型不必改为 queued-command 所有权;管理员取消等正常业务动作仍使用原权限。已有内置 quota 的独占分配模型不允许通过 backend-plan 改写。
|
|
125
|
+
|
|
126
|
+
### 后端只读计划
|
|
127
|
+
|
|
128
|
+
从应用 generated 导入 `managedCommandHandlerManifest`,传给 `OpenXiangdaModule.forApplication({managedCommandHandlerManifest})`。使用 `OpenXiangdaManagedCommandHandler({commandCode,handlerCode})` 注册实现 `plan(input, context)` 的 Nest provider。声明会启用后端;显式禁用 backend 会编译失败。SDK 生成固定 `POST /__platform/managed-commands/:handlerCode/plan`,不可自定义 URL。
|
|
129
|
+
|
|
130
|
+
context 提供 commandId/commandCode/generation、actor.userId、acceptedAt/deadlineAt、data.get/query 和 directory.currentInitiator()。get 无记录抛 404;query 返回标准 DataPage。handler 强制 request scope,构造函数和依赖只在网关签名与在线执行证明核实之后解析。执行证明保存在 SDK 私有 ALS,普通 SDK 事务、写入、通知和 OAuth 调用在该上下文内拒绝。应用只返回:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
return {
|
|
134
|
+
schemaVersion:'openxiangda.managed-command-plan/v1',
|
|
135
|
+
guards:[{kind:'record-match',resourceCode:'channels',id:channel.id,
|
|
136
|
+
lockKey:`channel:${channel.id}`,errorCode:'OPENXIANGDA_REGISTRATION_CLOSED',
|
|
137
|
+
assertions:[{kind:'command-accepted-at',field:'closesAt',operator:'gte'}]}],
|
|
138
|
+
operations:[{operation:'create',resourceCode:'registrations',data:{activityId,person:context.actor.userId}}],
|
|
139
|
+
result:{registrationId:{operationIndex:0,field:'id'}}
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
对应读取和写入字段必须列入 declaration。guard 比较方向为「字段 operator acceptedAt」,不使用客户端时间,也不改变普通 database-now 含义。最多 99 操作、20 守卫、64 KiB 完整响应;仅 create/update/increment。result 中的 `{operationIndex,field:'id'}` 必须指向本计划的 create,由平台提交后替换真实 ID。禁止事务 key、任意副作用或调用回调。应用仍需实时容量、活动开关与活动周期去重守卫,不能把受理时间当作名额保证。
|
|
144
|
+
|
|
145
|
+
平台在短事务中复核 generation/租约/head/期限/当前命令资格,执行 Native 计划并原子落终态。冲突重新运行只读 handler;网络重试不会重复业务效果。通知以业务事务中的待发送事实或已有事务事件触发,不能在 plan 中直接发送。
|
|
146
|
+
|
|
147
|
+
### 本人结果与恢复
|
|
148
|
+
|
|
149
|
+
`client.enqueue(code,input,requestKey)` 返回持久回执;`client.mine(code,{resourceKey,cursor?,limit})` 只查询当前主体,最多 20 条;`client.result` 延续原 ID/原 key。回执包含 resourceKey、updatedAt,可选 queue `{position:number|null,observedAt}`,位置是近似投影,缺失不代表请求丢失。结果终态只说明那次业务事务;管理员取消后仍应读当前业务记录,用户明确操作才发起新周期。
|
|
150
|
+
|
|
151
|
+
浏览器使用 `useDurableCommand`,详见[前端接入](managed-concurrency-frontend.md#durable)。部署先发布新 SDK/编译器并确认平台能力;回退前暂停新受理、排空或核对所有原命令,不让旧镜像消费未知执行模式。不能用 SDK 单测替代真实多用户并发、关闭浏览器、跨设备结果和原子事务验收。
|