@logicflow/engine 0.0.9 → 0.0.10-beta.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.
Files changed (190) hide show
  1. package/README.md +5 -2
  2. package/dist/index.js +2 -0
  3. package/dist/index.js.map +1 -0
  4. package/es/EventEmitter.d.ts +34 -4
  5. package/es/EventEmitter.js +70 -48
  6. package/es/EventEmitter.js.map +1 -0
  7. package/es/FlowModel.d.ts +75 -73
  8. package/es/FlowModel.js +130 -173
  9. package/es/FlowModel.js.map +1 -0
  10. package/es/Scheduler.d.ts +50 -34
  11. package/es/Scheduler.js +134 -209
  12. package/es/Scheduler.js.map +1 -0
  13. package/es/constant/{constant.js → index.js} +8 -7
  14. package/es/constant/index.js.map +1 -0
  15. package/es/constant/logCode.js +29 -0
  16. package/es/constant/logCode.js.map +1 -0
  17. package/es/expression/brewserVm.d.ts +2 -0
  18. package/es/expression/brewserVm.js +30 -0
  19. package/es/expression/brewserVm.js.map +1 -0
  20. package/es/expression/index.d.ts +1 -1
  21. package/es/expression/index.js +16 -59
  22. package/es/expression/index.js.map +1 -0
  23. package/es/expression/nodeVm.d.ts +4 -2
  24. package/es/expression/nodeVm.js +10 -50
  25. package/es/expression/nodeVm.js.map +1 -0
  26. package/es/index.d.ts +135 -38
  27. package/es/index.js +92 -144
  28. package/es/index.js.map +1 -0
  29. package/es/nodes/base.d.ts +108 -0
  30. package/es/nodes/base.js +149 -0
  31. package/es/nodes/base.js.map +1 -0
  32. package/es/nodes/index.d.ts +3 -0
  33. package/es/nodes/index.js +4 -0
  34. package/es/nodes/index.js.map +1 -0
  35. package/es/nodes/{StartNode.d.ts → start.d.ts} +3 -2
  36. package/es/nodes/start.js +11 -0
  37. package/es/nodes/start.js.map +1 -0
  38. package/es/nodes/{TaskNode.d.ts → task.d.ts} +3 -2
  39. package/es/nodes/task.js +11 -0
  40. package/es/nodes/task.js.map +1 -0
  41. package/es/platform/browser/browserVm.d.ts +4 -0
  42. package/es/platform/browser/browserVm.js +44 -0
  43. package/es/platform/browser/browserVm.js.map +1 -0
  44. package/es/platform/browser/index.d.ts +4 -0
  45. package/es/platform/browser/index.js +23 -0
  46. package/es/platform/browser/index.js.map +1 -0
  47. package/es/platform/index.d.ts +1 -0
  48. package/es/platform/index.js +2 -0
  49. package/es/platform/index.js.map +1 -0
  50. package/es/platform/node/index.d.ts +4 -0
  51. package/es/platform/node/index.js +23 -0
  52. package/es/platform/node/index.js.map +1 -0
  53. package/es/platform/node/nodeVm.d.ts +1 -0
  54. package/es/platform/node/nodeVm.js +9 -0
  55. package/es/platform/node/nodeVm.js.map +1 -0
  56. package/es/recorder/index.d.ts +36 -10
  57. package/es/recorder/index.js +82 -135
  58. package/es/recorder/index.js.map +1 -0
  59. package/es/utils/global.d.ts +5 -0
  60. package/es/utils/global.js +27 -0
  61. package/es/utils/global.js.map +1 -0
  62. package/es/utils/id.js +14 -0
  63. package/es/utils/id.js.map +1 -0
  64. package/es/utils/index.d.ts +4 -0
  65. package/es/utils/index.js +5 -0
  66. package/es/utils/index.js.map +1 -0
  67. package/es/{util → utils}/storage.js +17 -16
  68. package/es/utils/storage.js.map +1 -0
  69. package/lib/EventEmitter.d.ts +37 -0
  70. package/lib/EventEmitter.js +94 -0
  71. package/lib/EventEmitter.js.map +1 -0
  72. package/lib/FlowModel.d.ts +146 -0
  73. package/lib/FlowModel.js +236 -0
  74. package/lib/FlowModel.js.map +1 -0
  75. package/lib/Scheduler.d.ts +78 -0
  76. package/lib/Scheduler.js +179 -0
  77. package/lib/Scheduler.js.map +1 -0
  78. package/lib/constant/index.d.ts +16 -0
  79. package/{cjs/constant/constant.js → lib/constant/index.js} +4 -3
  80. package/lib/constant/index.js.map +1 -0
  81. package/lib/constant/logCode.d.ts +12 -0
  82. package/{cjs/constant/LogCode.js → lib/constant/logCode.js} +16 -13
  83. package/lib/constant/logCode.js.map +1 -0
  84. package/lib/expression/brewserVm.d.ts +2 -0
  85. package/lib/expression/brewserVm.js +33 -0
  86. package/lib/expression/brewserVm.js.map +1 -0
  87. package/lib/expression/index.d.ts +2 -0
  88. package/lib/expression/index.js +20 -0
  89. package/lib/expression/index.js.map +1 -0
  90. package/lib/expression/nodeVm.d.ts +4 -0
  91. package/lib/expression/nodeVm.js +13 -0
  92. package/lib/expression/nodeVm.js.map +1 -0
  93. package/lib/index.d.ts +157 -0
  94. package/lib/index.js +159 -0
  95. package/lib/index.js.map +1 -0
  96. package/lib/nodes/base.d.ts +108 -0
  97. package/lib/nodes/base.js +152 -0
  98. package/lib/nodes/base.js.map +1 -0
  99. package/lib/nodes/index.d.ts +3 -0
  100. package/lib/nodes/index.js +7 -0
  101. package/lib/nodes/index.js.map +1 -0
  102. package/lib/nodes/start.d.ts +6 -0
  103. package/lib/nodes/start.js +15 -0
  104. package/lib/nodes/start.js.map +1 -0
  105. package/lib/nodes/task.d.ts +6 -0
  106. package/lib/nodes/task.js +15 -0
  107. package/lib/nodes/task.js.map +1 -0
  108. package/lib/platform/browser/browserVm.d.ts +4 -0
  109. package/lib/platform/browser/browserVm.js +49 -0
  110. package/lib/platform/browser/browserVm.js.map +1 -0
  111. package/lib/platform/browser/index.d.ts +4 -0
  112. package/lib/platform/browser/index.js +28 -0
  113. package/lib/platform/browser/index.js.map +1 -0
  114. package/lib/platform/index.d.ts +1 -0
  115. package/lib/platform/index.js +5 -0
  116. package/lib/platform/index.js.map +1 -0
  117. package/lib/platform/node/index.d.ts +4 -0
  118. package/lib/platform/node/index.js +28 -0
  119. package/lib/platform/node/index.js.map +1 -0
  120. package/lib/platform/node/nodeVm.d.ts +1 -0
  121. package/lib/platform/node/nodeVm.js +13 -0
  122. package/lib/platform/node/nodeVm.js.map +1 -0
  123. package/lib/recorder/index.d.ts +46 -0
  124. package/lib/recorder/index.js +117 -0
  125. package/lib/recorder/index.js.map +1 -0
  126. package/lib/utils/global.d.ts +5 -0
  127. package/lib/utils/global.js +31 -0
  128. package/lib/utils/global.js.map +1 -0
  129. package/lib/utils/id.d.ts +3 -0
  130. package/lib/utils/id.js +20 -0
  131. package/lib/utils/id.js.map +1 -0
  132. package/lib/utils/index.d.ts +4 -0
  133. package/lib/utils/index.js +9 -0
  134. package/lib/utils/index.js.map +1 -0
  135. package/lib/utils/storage.d.ts +7 -0
  136. package/{cjs/util → lib/utils}/storage.js +18 -17
  137. package/lib/utils/storage.js.map +1 -0
  138. package/package.json +30 -71
  139. package/src/EventEmitter.ts +103 -0
  140. package/src/FlowModel.ts +325 -0
  141. package/src/Scheduler.ts +244 -0
  142. package/src/constant/index.ts +23 -0
  143. package/src/constant/logCode.ts +34 -0
  144. package/src/expression/brewserVm.ts +36 -0
  145. package/src/expression/index.ts +17 -0
  146. package/src/expression/nodeVm.ts +14 -0
  147. package/src/index.ts +300 -0
  148. package/src/nodes/base.ts +234 -0
  149. package/src/nodes/index.ts +3 -0
  150. package/src/nodes/start.ts +8 -0
  151. package/src/nodes/task.ts +8 -0
  152. package/src/platform/browser/browserVm.ts +52 -0
  153. package/src/platform/browser/index.ts +28 -0
  154. package/src/platform/index.ts +1 -0
  155. package/src/platform/node/index.ts +28 -0
  156. package/src/platform/node/nodeVm.ts +12 -0
  157. package/src/recorder/index.ts +137 -0
  158. package/src/typings.d.ts +0 -0
  159. package/src/utils/global.ts +41 -0
  160. package/src/utils/id.ts +16 -0
  161. package/src/utils/index.ts +5 -0
  162. package/src/utils/storage.ts +55 -0
  163. package/cjs/EventEmitter.js +0 -70
  164. package/cjs/FlowModel.js +0 -277
  165. package/cjs/Scheduler.js +0 -252
  166. package/cjs/expression/browserVm.js +0 -81
  167. package/cjs/expression/index.js +0 -63
  168. package/cjs/expression/nodeVm.js +0 -53
  169. package/cjs/index.js +0 -210
  170. package/cjs/nodes/BaseNode.js +0 -252
  171. package/cjs/nodes/StartNode.js +0 -27
  172. package/cjs/nodes/TaskNode.js +0 -27
  173. package/cjs/recorder/index.js +0 -168
  174. package/cjs/util/ID.js +0 -16
  175. package/cjs/util/global.js +0 -32
  176. package/es/constant/LogCode.js +0 -28
  177. package/es/expression/browserVm.d.ts +0 -4
  178. package/es/expression/browserVm.js +0 -76
  179. package/es/nodes/BaseNode.d.ts +0 -110
  180. package/es/nodes/BaseNode.js +0 -250
  181. package/es/nodes/StartNode.js +0 -25
  182. package/es/nodes/TaskNode.js +0 -25
  183. package/es/util/ID.js +0 -13
  184. package/es/util/global.d.ts +0 -5
  185. package/es/util/global.js +0 -26
  186. package/lib/main.js +0 -1
  187. /package/es/constant/{constant.d.ts → index.d.ts} +0 -0
  188. /package/es/constant/{LogCode.d.ts → logCode.d.ts} +0 -0
  189. /package/es/{util/ID.d.ts → utils/id.d.ts} +0 -0
  190. /package/es/{util → utils}/storage.d.ts +0 -0
@@ -0,0 +1,234 @@
1
+ import { Engine } from '..'
2
+ import { ActionStatus } from '../constant'
3
+ import { getExpressionResult } from '../platform'
4
+
5
+ export interface IBaseNodeProps {
6
+ nodeConfig: BaseNode.NodeConfig
7
+ context: Record<string, any>
8
+ globalData: Record<string, unknown>
9
+ }
10
+
11
+ export class BaseNode implements BaseNode.Base {
12
+ readonly baseType: string
13
+ static nodeTypeName = 'BaseNode'
14
+
15
+ /**
16
+ * 节点的入边
17
+ */
18
+ incoming: BaseNode.IncomingConfig[]
19
+ /**
20
+ * 节点的出边
21
+ */
22
+ outgoing: BaseNode.OutgoingConfig[]
23
+ /**
24
+ * 节点的属性
25
+ */
26
+ properties?: Record<string, unknown>
27
+ nodeId: Engine.Key
28
+ type: string
29
+ /**
30
+ * 节点的上下文,是调用流程时传入的上下文
31
+ */
32
+ context: Record<string, any>
33
+ /**
34
+ * 节点的全局数据,是调用流程时传入的全局数据
35
+ * 在计算表达式时,即基于全局数据进行计算
36
+ */
37
+ globalData: Record<string, unknown>
38
+
39
+ constructor({ nodeConfig, context, globalData }: IBaseNodeProps) {
40
+ const { outgoing, incoming, id, type, properties } = nodeConfig
41
+ this.baseType = 'base'
42
+ this.outgoing = outgoing
43
+ this.incoming = incoming
44
+ this.nodeId = id
45
+ this.type = type
46
+ this.properties = properties
47
+
48
+ this.context = context
49
+ this.globalData = globalData
50
+ }
51
+
52
+ /**
53
+ * 节点的执行逻辑
54
+ * @overridable 可以自定义节点重写此方法
55
+ * @param param.executionId 流程执行记录 ID
56
+ * @param param.actionId 此节点执行记录 ID
57
+ * @param param.nodeId 节点 ID
58
+ * @return 返回下一步的执行参数
59
+ * 当不返回时,表示此节点执行成功,流程会继续执行下一步。
60
+ * 当返回时,返回格式为
61
+ */
62
+ public async action(
63
+ param?: Engine.ActionParam,
64
+ ): Promise<BaseNode.ActionResult | undefined> {
65
+ console.log('action param --->>>', param)
66
+ return undefined
67
+ }
68
+
69
+ /**
70
+ * 节点重新恢复执行的逻辑
71
+ * @overridable 可以自定义节点重写此方法
72
+ * @param params.executionId 流程执行记录 ID
73
+ * @param params.actionId 此节点执行记录 ID
74
+ * @param params.nodeId 节点 ID
75
+ */
76
+ public async onResume(params: Engine.ResumeParam): Promise<void> {
77
+ console.log('onResume params --->>>', params)
78
+ return undefined
79
+ }
80
+
81
+ /**
82
+ * 判断该节点是否满足条件
83
+ */
84
+ private async isPass(properties?: Record<string, unknown>): Promise<boolean> {
85
+ if (!properties) return true
86
+
87
+ const { conditionExpression } = properties
88
+ if (!conditionExpression) return true
89
+
90
+ try {
91
+ // bug:uuid 创建的 NodeId 为 xxxx-xxxx-xxxx-zzzz 格式,eval 执行时会将 - 识别为数学减号,导致执行报错
92
+ // 解决方案: 赋值变量直接命名为 isPassResult, 因为每次执行 getExpressionResult 时,都会重新射程一个 context
93
+ const result = await getExpressionResult(
94
+ `isPassResult = (${conditionExpression})`,
95
+ {
96
+ ...this.globalData,
97
+ },
98
+ )
99
+ return result.isPassResult
100
+ } catch (error) {
101
+ return false
102
+ }
103
+ }
104
+
105
+ /**
106
+ * 获取当前节点执行的下一个节点
107
+ */
108
+ private async getOutgoing(): Promise<BaseNode.OutgoingConfig[]> {
109
+ const outgoing: BaseNode.OutgoingConfig[] = []
110
+ const expressions: any = []
111
+ for (const item of this.outgoing) {
112
+ const { properties } = item
113
+ expressions.push(this.isPass(properties))
114
+ }
115
+
116
+ const result = await Promise.all(expressions)
117
+ result.forEach((item, index) => {
118
+ const out = this.outgoing[index]
119
+ out.result = item
120
+ outgoing.push(out)
121
+ })
122
+ return outgoing
123
+ }
124
+
125
+ /**
126
+ * 节点的每一次执行都会生成一个唯一的 actionId
127
+ */
128
+ public async execute(
129
+ params: Engine.ExecParam,
130
+ ): Promise<Engine.NextActionParam> {
131
+ const { executionId, actionId } = params
132
+ const res = await this.action({
133
+ nodeId: this.nodeId,
134
+ executionId,
135
+ actionId,
136
+ })
137
+ const status = res ? res.status : 'success'
138
+
139
+ if (status === ActionStatus.SUCCESS) {
140
+ const outgoing = await this.getOutgoing()
141
+ const detail = res ? res.detail : {}
142
+ params.next({
143
+ status: ActionStatus.SUCCESS,
144
+ detail,
145
+ nodeId: this.nodeId,
146
+ nodeType: this.type,
147
+ properties: this.properties,
148
+ executionId,
149
+ actionId,
150
+ outgoing,
151
+ })
152
+ }
153
+
154
+ return {
155
+ status,
156
+ detail: res?.detail,
157
+ executionId,
158
+ actionId,
159
+ nodeId: this.nodeId,
160
+ nodeType: this.type,
161
+ properties: this.properties,
162
+ outgoing: [],
163
+ }
164
+ }
165
+
166
+ public async resume(params: Engine.ExecResumeParam): Promise<undefined> {
167
+ const outgoing = await this.getOutgoing()
168
+ await this.onResume({
169
+ executionId: params.executionId,
170
+ actionId: params.actionId,
171
+ nodeId: params.nodeId,
172
+ data: params.data,
173
+ })
174
+
175
+ params.next({
176
+ executionId: params.executionId,
177
+ actionId: params.actionId,
178
+ nodeId: this.nodeId,
179
+ nodeType: this.type,
180
+ properties: this.properties,
181
+ outgoing,
182
+ status: ActionStatus.SUCCESS,
183
+ })
184
+ return undefined
185
+ }
186
+ }
187
+
188
+ export namespace BaseNode {
189
+ export interface Base {
190
+ incoming: IncomingConfig[]
191
+ outgoing: OutgoingConfig[]
192
+ properties?: Record<string, unknown>
193
+ nodeId: Engine.Key
194
+ type: string
195
+ readonly baseType: string
196
+ execute(actionParam: Engine.ActionParam): Promise<Engine.NextActionParam>
197
+ }
198
+
199
+ export type IncomingConfig = {
200
+ id: Engine.Key
201
+ source: string
202
+ properties?: Record<string, unknown>
203
+ }
204
+
205
+ export type OutgoingConfig = {
206
+ id: Engine.Key
207
+ target: string
208
+ properties?: Record<string, unknown>
209
+ result?: string | boolean
210
+ }
211
+
212
+ export type NodeConfig = {
213
+ id: Engine.Key
214
+ type: string
215
+ properties?: Record<string, unknown>
216
+ incoming: IncomingConfig[]
217
+ outgoing: OutgoingConfig[]
218
+ }
219
+
220
+ export type NodeConstructor = {
221
+ new (config: {
222
+ nodeConfig: NodeConfig
223
+ context: Record<string, any>
224
+ globalData: Record<string, unknown>
225
+ }): BaseNode
226
+ }
227
+
228
+ export type ActionResult = {
229
+ status: ActionStatus
230
+ detail?: Record<string, unknown>
231
+ }
232
+ }
233
+
234
+ export default BaseNode
@@ -0,0 +1,3 @@
1
+ export * from './base'
2
+ export * from './start'
3
+ export * from './task'
@@ -0,0 +1,8 @@
1
+ import BaseNode from './base'
2
+
3
+ export default class StartNode extends BaseNode {
4
+ readonly baseType = 'start'
5
+ static nodeTypeName = 'StartNode'
6
+ }
7
+
8
+ export { StartNode }
@@ -0,0 +1,8 @@
1
+ import BaseNode from './base'
2
+
3
+ export default class TaskNode extends BaseNode {
4
+ readonly baseType = 'task'
5
+ static nodeTypeName = 'TaskNode'
6
+ }
7
+
8
+ export { TaskNode }
@@ -0,0 +1,52 @@
1
+ import {
2
+ ErrorCode,
3
+ getErrorMsg,
4
+ getWarningMsg,
5
+ WarningCode,
6
+ } from '../../constant/logCode'
7
+
8
+ const createContext = (globalData: Record<string, unknown>) => {
9
+ const iframe = document.createElement('iframe')
10
+ iframe.style.display = 'none'
11
+ if (!document || !document.body) {
12
+ console.error(getErrorMsg(ErrorCode.NO_DOCUMENT_BODY))
13
+ }
14
+ document.body.appendChild(iframe)
15
+ const iframeWindow = iframe.contentWindow
16
+ if (iframeWindow) {
17
+ // TODO: 确认是否需要该代码,parent 置为空是为了解决什么问题
18
+ // @ts-ignore
19
+ ;(iframeWindow!.parent as any) = null
20
+ Object.keys(globalData).forEach((key) => {
21
+ iframeWindow[key] = globalData[key]
22
+ })
23
+ }
24
+ return iframeWindow
25
+ }
26
+
27
+ const runInContext = (code: string, context) => {
28
+ try {
29
+ const iframeEval = context.eval
30
+ iframeEval.call(context, code)
31
+ if (context.iframeElement) {
32
+ document.body.removeChild(context.iframeElement)
33
+ }
34
+ } catch (e) {
35
+ console.warn(getWarningMsg(WarningCode.EXPRESSION_EXEC_ERROR), {
36
+ code,
37
+ context,
38
+ e,
39
+ })
40
+ }
41
+ }
42
+
43
+ const runInBrowserContext = async (
44
+ code: string,
45
+ globalData = {},
46
+ ): Promise<any> => {
47
+ const context = createContext(globalData)
48
+ runInContext(code, context)
49
+ return context
50
+ }
51
+
52
+ export { createContext, runInContext, runInBrowserContext }
@@ -0,0 +1,28 @@
1
+ import { runInBrowserContext } from './browserVm'
2
+
3
+ const isInBrowser = typeof window === 'object' && window.window === window
4
+
5
+ const globalScope: any = (() => {
6
+ if (isInBrowser) {
7
+ return window
8
+ }
9
+
10
+ if (typeof self === 'object' && self.self === self) {
11
+ return self
12
+ }
13
+
14
+ if (typeof globalThis === 'object') {
15
+ return globalThis
16
+ }
17
+
18
+ return {
19
+ eval: () => undefined,
20
+ } as Record<string, unknown>
21
+ })()
22
+
23
+ const getExpressionResult = async (code: string, context: any) => {
24
+ const r = await runInBrowserContext(code, context)
25
+ return r
26
+ }
27
+
28
+ export { isInBrowser, globalScope, getExpressionResult }
@@ -0,0 +1 @@
1
+ export * from './node'
@@ -0,0 +1,28 @@
1
+ import { runInNodeContext } from './nodeVm'
2
+
3
+ const isInNodeJS = typeof global === 'object' && global.global === global
4
+
5
+ const globalScope: any = (() => {
6
+ if (typeof self === 'object' && self.self === self) {
7
+ return self
8
+ }
9
+
10
+ if (isInNodeJS) {
11
+ return global
12
+ }
13
+
14
+ if (typeof globalThis === 'object') {
15
+ return globalThis
16
+ }
17
+
18
+ return {
19
+ eval: () => undefined,
20
+ } as Record<string, unknown>
21
+ })()
22
+
23
+ const getExpressionResult = async (code: string, context: any) => {
24
+ const r = await runInNodeContext(code, context)
25
+ return r
26
+ }
27
+
28
+ export { isInNodeJS, globalScope, getExpressionResult }
@@ -0,0 +1,12 @@
1
+ import vm from 'node:vm'
2
+ // const vm = require('node:vm');
3
+
4
+ export const runInNodeContext = async (
5
+ code: string,
6
+ globalData: Record<string, unknown> = {},
7
+ ): Promise<any> => {
8
+ const context = vm.createContext(globalData)
9
+ vm.runInContext(code, context)
10
+
11
+ return context
12
+ }
@@ -0,0 +1,137 @@
1
+ import { Engine } from '..'
2
+ import { storage } from '../utils'
3
+
4
+ export const MAX_RECORDER = 100
5
+ export const MAX_INSTANCE = 100
6
+ export const LOGICFLOW_ENGINE_INSTANCES = 'LOGICFLOW_ENGINE_INSTANCES'
7
+
8
+ export class Recorder implements Recorder.Base {
9
+ instanceId: Engine.Key
10
+ maxRecorder: number
11
+
12
+ constructor({ instanceId }) {
13
+ this.instanceId = instanceId
14
+ this.maxRecorder = MAX_RECORDER
15
+
16
+ const instances = this.getItem(LOGICFLOW_ENGINE_INSTANCES) || []
17
+ if (instances.indexOf(instanceId) === -1) {
18
+ instances.push(instanceId)
19
+ }
20
+ if (instances.length > MAX_INSTANCE) {
21
+ const clearInstance = instances.shift()
22
+ this.clearInstance(clearInstance)
23
+ }
24
+ this.setItem(LOGICFLOW_ENGINE_INSTANCES, instances)
25
+ }
26
+
27
+ setMaxRecorderNumber(max: number) {
28
+ this.maxRecorder = max
29
+ }
30
+
31
+ // 将存储 storage 的方法收敛到此处,并在此处做异常处理 - setItem
32
+ setItem(key: string | number, value: unknown) {
33
+ try {
34
+ storage.setItem(key, value)
35
+ } catch (error) {
36
+ console.error('Ops, something wrong with storage.setItem !!!')
37
+ storage.clear()
38
+ storage.setItem(key, value)
39
+ }
40
+ }
41
+
42
+ // getItem 方法
43
+ getItem(key: string | number) {
44
+ return storage.getItem(key)
45
+ }
46
+
47
+ async getExecutionActions(executionId: Engine.Key) {
48
+ return this.getItem(executionId)
49
+ }
50
+
51
+ async getExecutionList() {
52
+ return this.getItem(this.instanceId) || []
53
+ }
54
+
55
+ private addExecution(executionId: Engine.Key) {
56
+ const instanceExecutions = this.getItem(this.instanceId) || []
57
+ if (instanceExecutions.length >= this.maxRecorder) {
58
+ const toBeRemovedItem = instanceExecutions.shift()
59
+ this.popExecution(toBeRemovedItem)
60
+ }
61
+ instanceExecutions.push(executionId)
62
+ this.setItem(this.instanceId, instanceExecutions)
63
+ }
64
+
65
+ private popExecution(executionId: Engine.Key) {
66
+ const instanceData = this.getItem(executionId) || []
67
+ instanceData.forEach((actionId) => {
68
+ storage.removeItem(actionId)
69
+ })
70
+ storage.removeItem(executionId)
71
+ }
72
+
73
+ private pushActionToExecution(executionId: Engine.Key, actionId: Engine.Key) {
74
+ const actions = this.getItem(executionId) || []
75
+ actions.push(actionId)
76
+ this.setItem(executionId, actions)
77
+ }
78
+
79
+ /**
80
+ * @param {Object} action
81
+ * {
82
+ * actionId: '',
83
+ * nodeId: '',
84
+ * executionId: '',
85
+ * nodeType: '',
86
+ * timestamp: '',
87
+ * properties: {},
88
+ * }
89
+ */
90
+ async addActionRecord(action: Recorder.Info) {
91
+ const { executionId, actionId } = action
92
+ const instanceData = await this.getExecutionActions(executionId)
93
+
94
+ if (!instanceData) {
95
+ this.addExecution(executionId)
96
+ }
97
+ this.pushActionToExecution(executionId, actionId)
98
+ this.setItem(actionId, action)
99
+ }
100
+
101
+ async getActionRecord(actionId: Engine.Key): Promise<Recorder.Info> {
102
+ return this.getItem(actionId)
103
+ }
104
+
105
+ clear() {
106
+ this.clearInstance(this.instanceId)
107
+ }
108
+
109
+ clearInstance(instanceId: Engine.Key) {
110
+ const instanceExecutions = this.getItem(instanceId) || []
111
+ // TODO: 完善类型定义
112
+ instanceExecutions.forEach((executionId) => {
113
+ storage.removeItem(executionId)
114
+ const instanceData = this.getItem(executionId) || []
115
+ instanceData.forEach((actionId) => {
116
+ storage.removeItem(actionId)
117
+ })
118
+ })
119
+
120
+ storage.removeItem(instanceId)
121
+ }
122
+ }
123
+
124
+ export namespace Recorder {
125
+ export interface Base {
126
+ addActionRecord: (action: Info) => Promise<void>
127
+ getActionRecord: (actionId: Engine.Key) => Promise<Info>
128
+ getExecutionActions: (executionId: Engine.Key) => Promise<string[]>
129
+ clear: () => void
130
+ }
131
+
132
+ export type Info = {
133
+ timestamp: number
134
+ } & Engine.NextActionParam
135
+ }
136
+
137
+ export default Recorder
File without changes
@@ -0,0 +1,41 @@
1
+ // 判断当前环境是否为服务端
2
+ // const isServer = typeof window === undefined;
3
+
4
+ // const isServer = process.env.BROWSER === true;
5
+
6
+ const isInBrowser = typeof window === 'object' && window.window === window
7
+
8
+ const isInNodeJS = typeof global === 'object' && global.global === global
9
+
10
+ const isInWebWorker =
11
+ !isInBrowser && typeof self === 'object' && self.constructor
12
+
13
+ const globalScope: any = (() => {
14
+ if (isInBrowser) {
15
+ return window
16
+ }
17
+
18
+ if (typeof self === 'object' && self.self === self) {
19
+ return self
20
+ }
21
+
22
+ if (isInNodeJS) {
23
+ return global
24
+ }
25
+
26
+ if (typeof globalThis === 'object') {
27
+ return globalThis
28
+ }
29
+
30
+ return {
31
+ eval: () => undefined,
32
+ } as Record<string, unknown>
33
+ })()
34
+
35
+ export {
36
+ // 环境相关方法
37
+ globalScope,
38
+ isInWebWorker,
39
+ isInBrowser,
40
+ isInNodeJS,
41
+ }
@@ -0,0 +1,16 @@
1
+ import { v4 as uuidV4 } from 'uuid'
2
+
3
+ export const createExecId = (): string => {
4
+ const uuid = uuidV4()
5
+ return `exec-${uuid}`
6
+ }
7
+
8
+ export const createActionId = (): string => {
9
+ const uuid = uuidV4()
10
+ return `action-${uuid}`
11
+ }
12
+
13
+ export const createEngineId = (): string => {
14
+ const uuid = uuidV4()
15
+ return `engine-${uuid}`
16
+ }
@@ -0,0 +1,5 @@
1
+ import storage from './storage'
2
+
3
+ export * from './global'
4
+ export * from './id'
5
+ export { storage }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 存储执行记录
3
+ */
4
+ import { globalScope } from './global'
5
+
6
+ if (!globalScope.sessionStorage) {
7
+ const storage = {
8
+ data: {} as Record<string, unknown>,
9
+
10
+ setItem(key, value) {
11
+ storage.data[key] = value
12
+ },
13
+
14
+ getItem(key) {
15
+ return storage.data[key]
16
+ },
17
+
18
+ removeItem(key) {
19
+ delete storage.data[key]
20
+ },
21
+
22
+ clear() {
23
+ storage.data = {}
24
+ },
25
+ }
26
+
27
+ globalScope.sessionStorage = storage
28
+ }
29
+
30
+ export default {
31
+ setItem(key, value) {
32
+ if (typeof value === 'object') {
33
+ value = JSON.stringify(value)
34
+ }
35
+
36
+ globalScope.sessionStorage.setItem(key, value)
37
+ },
38
+
39
+ getItem(key) {
40
+ const value = globalScope.sessionStorage.getItem(key)
41
+ try {
42
+ return JSON.parse(value)
43
+ } catch (error) {
44
+ return value
45
+ }
46
+ },
47
+
48
+ removeItem(key) {
49
+ globalScope.sessionStorage.removeItem(key)
50
+ },
51
+
52
+ clear() {
53
+ globalScope.sessionStorage.clear()
54
+ },
55
+ }