@floken-io/engine 0.0.1
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 +39 -0
- package/LICENSE +153 -0
- package/README.md +138 -0
- package/dist/chunk-RMCROXES.js +376 -0
- package/dist/conformance.d.ts +162 -0
- package/dist/conformance.js +711 -0
- package/dist/index.d.ts +1948 -0
- package/dist/index.js +3645 -0
- package/dist/spi-BABH0Tcs.d.ts +635 -0
- package/package.json +45 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
本包遵循 [Semantic Versioning](https://semver.org/),格式参考 [Keep a Changelog](https://keepachangelog.com/)。
|
|
4
|
+
0.x 阶段跨包依赖写 `>=x.y.z <1.0.0`(不用 `^`)。
|
|
5
|
+
|
|
6
|
+
## 0.0.1 — 2026-10-01
|
|
7
|
+
|
|
8
|
+
首发。令牌制流程内核 + 中国式审批动作,覆盖 `03` 的阶段 **E1~E9**(685 单测 / `verify` 六道门禁全绿 /
|
|
9
|
+
冷启动探针 98 项跑真 `dist/`)。
|
|
10
|
+
|
|
11
|
+
### 新增
|
|
12
|
+
|
|
13
|
+
- **内核**:10 个业务无知原语 + 令牌推进 + run-to-wait(跑到稳定点才停);状态分 Header(宿主建列)+ Body
|
|
14
|
+
(不透明 JSON)两层,`JSON.stringify` 出得来(AC-E8)。
|
|
15
|
+
- **19 项审批动作**:其中 **17 项内核原生执行**;超时与暂存 2 项在内核外(经 `Scheduler` SPI 驱动)。
|
|
16
|
+
设计期未开启的动作提交即抛错(AC-E2);`enabledActionNames()` 是「按钮该不该灰」的唯一判据。
|
|
17
|
+
- **会签 / 或签 / 票签**:计票口径为「已表态 + 仍在途」,含 `03` §5.3 的**反向提前终止三条**;
|
|
18
|
+
组结算后解散、承接令牌另造。
|
|
19
|
+
- **节点**:22 类 L3 执行语义,含子流程 / 调用活动(版本绑定,**绝不回退到别的版本**)、
|
|
20
|
+
`intermediateCatchEvent` / `receiveTask` 的等待语义、边界事件(中断 / 非中断)、
|
|
21
|
+
`Transaction` 的 `cancel`、`EventBasedGateway` 竞速。
|
|
22
|
+
- **两条集成路径**:`submit()`(门 1,save 后触发 hooks)与 `plan()`(门 2 纯函数,宿主自己包事务)——
|
|
23
|
+
两条路径的状态演化**完全一致**,由测试钉死,不靠纪律。
|
|
24
|
+
- **一致性**:快照 + `rev` CAS(`expectedRev === 0` = INSERT 信号)+ 进程内 per-instance 串行队列。
|
|
25
|
+
- **投递**:`deliverMessage`(点对点)/ `deliverSignal`(广播);未命中抛错并列出合法取值。
|
|
26
|
+
- **令牌轨迹**:`exportTrace()` 返回 `TraceResult`(含 `truncated`),是 `auditTrail` 的只读投影,不新增存储。
|
|
27
|
+
- **11 项 SPI**;`createMemoryStore()` 不传即用;`runStoreConformance` / `runProjectionConformance` /
|
|
28
|
+
`runDefinitionConformance` 三套契约测试供宿主验证自研实现。
|
|
29
|
+
|
|
30
|
+
### 刻意不做(不是欠账,是设计取向)
|
|
31
|
+
|
|
32
|
+
- **内核不定时**:`ScheduleRequest` 只交 `fromAt` + 原始 `TimeoutSpec`,**不交 `dueAt`**——
|
|
33
|
+
工作日历是业务数据,且时态库不得进 `dist`。不注入 `Scheduler` 就是真的不排程。
|
|
34
|
+
- **原语级审计已否决**(差异表 D-87):run-to-wait 的令牌推进不走 `advance` 原语,
|
|
35
|
+
按原语记账会造出一份「没有令牌移动的轨迹」,且一次提交炸几十条会扭曲 `maxAuditEntries`。
|
|
36
|
+
故审计恒定**一次动作一条**。
|
|
37
|
+
- 已知但未实现的节点类型一律**显式抛错**并指名归属需求编号,不降级成自动直通
|
|
38
|
+
(`sendTask` / `intermediateThrowEvent` / `implicitThrowEvent` / `complexGateway` /
|
|
39
|
+
`AdHocSubProcess` / 补偿处理器;捕获事件目前只认 `message` / `signal`)。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
95
|
+
Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work; and
|
|
103
|
+
|
|
104
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
105
|
+
distribution, then any Derivative Works that You distribute must
|
|
106
|
+
include a readable copy of the attribution notices contained
|
|
107
|
+
within such NOTICE file.
|
|
108
|
+
|
|
109
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
110
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
111
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
112
|
+
this License, without any additional terms or conditions.
|
|
113
|
+
|
|
114
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
115
|
+
names, trademarks, service marks, or product names of the Licensor.
|
|
116
|
+
|
|
117
|
+
7. Disclaimer of Warranty. Unless required by applicable law or agreed
|
|
118
|
+
to in writing, Licensor provides the Work (and each Contributor
|
|
119
|
+
provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES
|
|
120
|
+
OR CONDITIONS OF ANY KIND, either express or implied.
|
|
121
|
+
|
|
122
|
+
8. Limitation of Liability. In no event and under no legal theory shall
|
|
123
|
+
any Contributor be liable to You for damages, including any direct,
|
|
124
|
+
indirect, special, incidental, or consequential damages of any
|
|
125
|
+
character arising as a result of this License or out of the use or
|
|
126
|
+
inability to use the Work.
|
|
127
|
+
|
|
128
|
+
9. Accepting Warranty or Additional Liability. While redistributing the
|
|
129
|
+
Work or Derivative Works thereof, You may choose to offer, and charge
|
|
130
|
+
a fee for, acceptance of support, warranty, indemnity, or other
|
|
131
|
+
liability obligations and/or rights consistent with this License.
|
|
132
|
+
|
|
133
|
+
END OF TERMS AND CONDITIONS
|
|
134
|
+
|
|
135
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
136
|
+
|
|
137
|
+
To apply the Apache License to your work, attach the following
|
|
138
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
139
|
+
replaced with your own identifying information.
|
|
140
|
+
|
|
141
|
+
Copyright 2026 floken contributors
|
|
142
|
+
|
|
143
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
144
|
+
you may not use this file except in compliance with the License.
|
|
145
|
+
You may obtain a copy of the License at
|
|
146
|
+
|
|
147
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
148
|
+
|
|
149
|
+
Unless required by applicable law or agreed to in writing, software
|
|
150
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
151
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
152
|
+
See the License for the specific language governing permissions and
|
|
153
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# @floken-io/engine
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@floken-io/engine)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
令牌制流程内核 + 中国式审批动作(会签 / 或签 / 票签 / 加签 / 转办 / 驳回 / 撤回)。
|
|
7
|
+
|
|
8
|
+
零 DOM、零数据库、零定时——持久化与调度全部经 SPI 注入,**核心引擎零基础设施依赖**。
|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i @floken-io/engine
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`@floken-io/feel` 是默认依赖,装完即可在网关上写 `amount > 5000` 这样的条件,无需额外接线。
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
一个三段报销流程,从发起到办结:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { createEngine, createMemoryStore } from '@floken-io/engine';
|
|
24
|
+
|
|
25
|
+
// 流程定义:通常由 @floken-io/moddle 从 BPMN XML 读进来,这里直接手写
|
|
26
|
+
const def = {
|
|
27
|
+
schemaVersion: '1.0.0',
|
|
28
|
+
id: 'Definitions_1',
|
|
29
|
+
processes: [{
|
|
30
|
+
id: 'Process_1',
|
|
31
|
+
nodes: [
|
|
32
|
+
{ id: 'Start_1', type: 'startEvent' },
|
|
33
|
+
{ id: 'Task_1', type: 'userTask',
|
|
34
|
+
extension: { 'floken:approval': { approvers: [{ type: 'user', value: 'u_manager' }] } } },
|
|
35
|
+
{ id: 'Task_2', type: 'userTask',
|
|
36
|
+
extension: { 'floken:approval': { approvers: [{ type: 'user', value: 'u_finance' }] } } },
|
|
37
|
+
{ id: 'End_1', type: 'endEvent' },
|
|
38
|
+
],
|
|
39
|
+
flows: [
|
|
40
|
+
{ id: 'f1', from: 'Start_1', to: 'Task_1' },
|
|
41
|
+
{ id: 'f2', from: 'Task_1', to: 'Task_2' },
|
|
42
|
+
{ id: 'f3', from: 'Task_2', to: 'End_1' },
|
|
43
|
+
],
|
|
44
|
+
}],
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const engine = createEngine({
|
|
48
|
+
// 定义源是「图纸」:只读、按版本取。改版不影响在途实例
|
|
49
|
+
definitionSource: {
|
|
50
|
+
async getDefinition(processId, version) {
|
|
51
|
+
return processId === 'Process_1' && version === 1 ? def : null;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
store: createMemoryStore(), // 不传也是它
|
|
55
|
+
clock: () => new Date().toISOString(), // 不传用 Date.now(),但显式传可让测试完全可复现
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const id = await engine.start('Process_1', {
|
|
59
|
+
definitionVersion: 1,
|
|
60
|
+
starter: 'u_applicant',
|
|
61
|
+
variables: { amount: 8600 },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await engine.submit(id, { action: 'approve', actor: 'u_manager', comment: '同意' });
|
|
65
|
+
await engine.submit(id, { action: 'approve', actor: 'u_finance' });
|
|
66
|
+
|
|
67
|
+
const trace = await engine.exportTrace(id);
|
|
68
|
+
console.log(trace.entries.map((e) => `${e.seq} ${e.actor} ${e.action} ${e.from} → ${e.to}`));
|
|
69
|
+
// [
|
|
70
|
+
// '1 u_applicant start Start_1 → Task_1',
|
|
71
|
+
// '2 u_manager approve Task_1 → Task_2',
|
|
72
|
+
// '3 u_finance approve Task_2 → End_1'
|
|
73
|
+
// ]
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## API 面
|
|
77
|
+
|
|
78
|
+
| 方法 | 用途 |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `start(processId, opts)` | 发起实例,返回 `instanceId` |
|
|
81
|
+
| `submit(instanceId, action)` | 提交一次审批动作,返回待办差分 `TaskDelta` |
|
|
82
|
+
| `deliverMessage(instanceId, input)` | **点对点**投递消息,唤醒在等它的令牌 |
|
|
83
|
+
| `deliverSignal(instanceIds, input)` | **广播**信号,唤醒候选里所有在等的实例 |
|
|
84
|
+
| `exportTrace(instanceId)` | 导出令牌轨迹(`auditTrail` 的只读投影,不新增存储) |
|
|
85
|
+
| `plan(state, action, options?)` | ★ 纯函数入口:给宿主自己包事务用(不碰存储) |
|
|
86
|
+
|
|
87
|
+
`submit()` 只是 `plan()` + 落库的便利封装——**两条路径的状态演化完全一致**,由测试钉死。
|
|
88
|
+
|
|
89
|
+
## 19 项审批动作
|
|
90
|
+
|
|
91
|
+
`approve` / `reject` / `rejectTo` / `rollback` / `rollbackTo` / `transfer` / `delegate` /
|
|
92
|
+
`delegateBack` / `addSignBefore` / `addSignAfter` / `addSignParallel` / `reduceSign` /
|
|
93
|
+
`takeBack` / `revoke` / `urge` / `suspend` / `resume` / `terminate` / `skip`。
|
|
94
|
+
|
|
95
|
+
其中 **17 项由内核原生执行**;**超时**与**暂存** 2 项在内核外(由调度层经 `Scheduler` SPI 驱动)。
|
|
96
|
+
当前配置下哪些动作可用,用 `enabledActionNames(config)` 问——按钮该不该灰,只有这一处判据。
|
|
97
|
+
|
|
98
|
+
## 11 项 SPI
|
|
99
|
+
|
|
100
|
+
| 组 | 接口 | 默认 |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| 存储三线 | `StateStore`(真相)/ `TaskProjection`(视图)/ `DefinitionSource`(图纸) | 内存 store;后两项**必须**注入 |
|
|
103
|
+
| 业务接入 | `ApproverSource` / `ServiceHandler` / `AuthResolver` / `FormProvider` | 无(不注入 = 相关节点走不通并显式报错) |
|
|
104
|
+
| 求值 | `conditionHandler` / `decisionHandler` | **条件有**默认 FEEL 实现;决策无默认 |
|
|
105
|
+
| 出口 | `EventSink` / `Scheduler` | 无(不注入 `Scheduler` = **不排程**,不假装做了) |
|
|
106
|
+
|
|
107
|
+
## 一致性
|
|
108
|
+
|
|
109
|
+
- **快照 + `rev` CAS**:`save(next, expectedRev)`,`expectedRev === 0` 是 INSERT 信号,否则 CAS UPDATE;不匹配抛 `ENGINE_PERSIST_CONFLICT`,不静默覆盖。
|
|
110
|
+
- **并发三道防线**:进程内 per-instance 串行队列(主力)+ rev CAS(跨进程兜底);不开读从库、不加悲观锁。
|
|
111
|
+
- **引擎内不做事务**:要么走 `submit()`(门 1:save 后触发 hooks,至少一次 + 宿主幂等),要么用 `plan()`(门 2:纯函数,宿主自己包事务)。
|
|
112
|
+
|
|
113
|
+
## 能力边界(诚实清单)
|
|
114
|
+
|
|
115
|
+
已知但**未实现**的节点类型一律**显式抛错**并指名归属需求编号——引擎刻意不把它们降级成"自动直通",
|
|
116
|
+
因为那会让「这件事从来没发生过」变成一个没有报错的静默事实:
|
|
117
|
+
|
|
118
|
+
`sendTask` · `intermediateThrowEvent` · `implicitThrowEvent` · `complexGateway` · `AdHocSubProcess` ·
|
|
119
|
+
补偿处理器(`compensate`);捕获事件目前只认 `message` / `signal`(等 `timer` / `error` 仍抛)。
|
|
120
|
+
|
|
121
|
+
`endEvent` 的 `eventDefinition`(terminate / message)尚未区分。
|
|
122
|
+
|
|
123
|
+
同样**没有**的:复杂查询与报表、作业执行器与重试框架、多租户、批量操作 API、历史归档、可视化运维台、
|
|
124
|
+
时间旅行重放、分布式锁(只有 CAS 重试)。这些归宿主——`03-包需求` §9.6 写明这是设计取向,不是欠账。
|
|
125
|
+
|
|
126
|
+
## 相关包
|
|
127
|
+
|
|
128
|
+
| 包 | 用途 |
|
|
129
|
+
|---|---|
|
|
130
|
+
| [`@floken-io/feel`](https://www.npmjs.com/package/@floken-io/feel) | FEEL 表达式语言 |
|
|
131
|
+
| [`@floken-io/moddle`](https://www.npmjs.com/package/@floken-io/moddle) | BPMN 2.0 模型与 XML 转换 |
|
|
132
|
+
| [`@floken-io/dmn`](https://www.npmjs.com/package/@floken-io/dmn) | DMN 1.5 决策引擎 |
|
|
133
|
+
| `@floken-io/engine` | 流程内核与审批动作(本包) |
|
|
134
|
+
| `@floken-io/designer` | 流程画布与审批配置面板(开发中) |
|
|
135
|
+
|
|
136
|
+
## 许可证
|
|
137
|
+
|
|
138
|
+
[Apache-2.0](./LICENSE)
|