@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 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
+ [![npm](https://img.shields.io/npm/v/@floken-io/engine)](https://www.npmjs.com/package/@floken-io/engine)
4
+ [![license](https://img.shields.io/npm/l/@floken-io/engine)](./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)