@contractspec/example.workflow-system 1.57.0 → 1.59.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 (209) hide show
  1. package/dist/approval/approval.enum.d.ts +2 -7
  2. package/dist/approval/approval.enum.d.ts.map +1 -1
  3. package/dist/approval/approval.enum.js +20 -26
  4. package/dist/approval/approval.event.d.ts +108 -114
  5. package/dist/approval/approval.event.d.ts.map +1 -1
  6. package/dist/approval/approval.event.js +103 -210
  7. package/dist/approval/approval.handler.d.ts +17 -18
  8. package/dist/approval/approval.handler.d.ts.map +1 -1
  9. package/dist/approval/approval.operations.d.ts +429 -435
  10. package/dist/approval/approval.operations.d.ts.map +1 -1
  11. package/dist/approval/approval.operations.js +364 -339
  12. package/dist/approval/approval.schema.d.ts +86 -91
  13. package/dist/approval/approval.schema.d.ts.map +1 -1
  14. package/dist/approval/approval.schema.js +71 -107
  15. package/dist/approval/index.d.ts +8 -5
  16. package/dist/approval/index.d.ts.map +1 -0
  17. package/dist/approval/index.js +484 -5
  18. package/dist/browser/approval/approval.enum.js +22 -0
  19. package/dist/browser/approval/approval.event.js +112 -0
  20. package/dist/browser/approval/approval.operations.js +369 -0
  21. package/dist/browser/approval/approval.schema.js +73 -0
  22. package/dist/browser/approval/index.js +484 -0
  23. package/dist/browser/docs/index.js +103 -0
  24. package/dist/browser/docs/workflow-system.docblock.js +103 -0
  25. package/dist/browser/entities/approval.js +119 -0
  26. package/dist/browser/entities/index.js +508 -0
  27. package/dist/browser/entities/instance.js +161 -0
  28. package/dist/browser/entities/step.js +124 -0
  29. package/dist/browser/entities/workflow.js +82 -0
  30. package/dist/browser/example.js +42 -0
  31. package/dist/browser/handlers/index.js +253 -0
  32. package/dist/browser/handlers/workflow.handlers.js +253 -0
  33. package/dist/browser/index.js +3120 -0
  34. package/dist/browser/instance/index.js +677 -0
  35. package/dist/browser/instance/instance.enum.js +15 -0
  36. package/dist/browser/instance/instance.event.js +164 -0
  37. package/dist/browser/instance/instance.handler.js +356 -0
  38. package/dist/browser/instance/instance.operations.js +9 -0
  39. package/dist/browser/instance/instance.schema.js +101 -0
  40. package/dist/browser/presentations/index.js +109 -0
  41. package/dist/browser/seeders/index.js +3 -0
  42. package/dist/browser/shared/index.js +3 -0
  43. package/dist/browser/shared/mock-data.js +11 -0
  44. package/dist/browser/shared/types.js +0 -0
  45. package/dist/browser/state-machine/index.js +6 -0
  46. package/dist/browser/tests/operations.test-spec.js +6 -0
  47. package/dist/browser/ui/WorkflowDashboard.js +3 -0
  48. package/dist/browser/ui/hooks/index.js +50 -0
  49. package/dist/browser/ui/hooks/useWorkflowList.js +50 -0
  50. package/dist/browser/ui/index.js +54 -0
  51. package/dist/browser/ui/renderers/index.js +227 -0
  52. package/dist/browser/ui/renderers/workflow.markdown.js +227 -0
  53. package/dist/browser/workflow/index.js +21 -0
  54. package/dist/browser/workflow/workflow.enum.js +36 -0
  55. package/dist/browser/workflow/workflow.event.js +6 -0
  56. package/dist/browser/workflow/workflow.handler.js +5 -0
  57. package/dist/browser/workflow/workflow.operations.js +8 -0
  58. package/dist/browser/workflow/workflow.schema.js +151 -0
  59. package/dist/browser/workflow-system.capability.js +5 -0
  60. package/dist/browser/workflow-system.feature.js +3 -0
  61. package/dist/docs/index.d.ts +2 -1
  62. package/dist/docs/index.d.ts.map +1 -0
  63. package/dist/docs/index.js +104 -1
  64. package/dist/docs/workflow-system.docblock.d.ts +2 -1
  65. package/dist/docs/workflow-system.docblock.d.ts.map +1 -0
  66. package/dist/docs/workflow-system.docblock.js +45 -56
  67. package/dist/entities/approval.d.ts +35 -40
  68. package/dist/entities/approval.d.ts.map +1 -1
  69. package/dist/entities/approval.js +116 -124
  70. package/dist/entities/index.d.ts +132 -137
  71. package/dist/entities/index.d.ts.map +1 -1
  72. package/dist/entities/index.js +506 -29
  73. package/dist/entities/instance.d.ts +46 -51
  74. package/dist/entities/instance.d.ts.map +1 -1
  75. package/dist/entities/instance.js +158 -164
  76. package/dist/entities/step.d.ts +31 -36
  77. package/dist/entities/step.d.ts.map +1 -1
  78. package/dist/entities/step.js +122 -132
  79. package/dist/entities/workflow.d.ts +22 -27
  80. package/dist/entities/workflow.d.ts.map +1 -1
  81. package/dist/entities/workflow.js +80 -99
  82. package/dist/example.d.ts +2 -6
  83. package/dist/example.d.ts.map +1 -1
  84. package/dist/example.js +41 -55
  85. package/dist/handlers/index.d.ts +2 -2
  86. package/dist/handlers/index.d.ts.map +1 -0
  87. package/dist/handlers/index.js +254 -3
  88. package/dist/handlers/workflow.handlers.d.ts +107 -106
  89. package/dist/handlers/workflow.handlers.d.ts.map +1 -1
  90. package/dist/handlers/workflow.handlers.js +237 -246
  91. package/dist/index.d.ts +15 -26
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +3121 -26
  94. package/dist/instance/index.d.ts +8 -5
  95. package/dist/instance/index.d.ts.map +1 -0
  96. package/dist/instance/index.js +677 -5
  97. package/dist/instance/instance.enum.d.ts +1 -6
  98. package/dist/instance/instance.enum.d.ts.map +1 -1
  99. package/dist/instance/instance.enum.js +14 -18
  100. package/dist/instance/instance.event.d.ts +313 -319
  101. package/dist/instance/instance.event.d.ts.map +1 -1
  102. package/dist/instance/instance.event.js +151 -279
  103. package/dist/instance/instance.handler.d.ts +21 -22
  104. package/dist/instance/instance.handler.d.ts.map +1 -1
  105. package/dist/instance/instance.handler.js +352 -89
  106. package/dist/instance/instance.operations.d.ts +819 -825
  107. package/dist/instance/instance.operations.d.ts.map +1 -1
  108. package/dist/instance/instance.operations.js +10 -464
  109. package/dist/instance/instance.schema.d.ts +196 -201
  110. package/dist/instance/instance.schema.d.ts.map +1 -1
  111. package/dist/instance/instance.schema.js +97 -167
  112. package/dist/presentations/index.d.ts +23 -28
  113. package/dist/presentations/index.d.ts.map +1 -1
  114. package/dist/presentations/index.js +104 -334
  115. package/dist/seeders/index.d.ts +4 -8
  116. package/dist/seeders/index.d.ts.map +1 -1
  117. package/dist/seeders/index.js +4 -19
  118. package/dist/shared/index.d.ts +6 -3
  119. package/dist/shared/index.d.ts.map +1 -0
  120. package/dist/shared/index.js +4 -3
  121. package/dist/shared/mock-data.d.ts +16 -16
  122. package/dist/shared/mock-data.d.ts.map +1 -1
  123. package/dist/shared/mock-data.js +11 -11
  124. package/dist/shared/types.d.ts +69 -72
  125. package/dist/shared/types.d.ts.map +1 -1
  126. package/dist/shared/types.js +1 -0
  127. package/dist/state-machine/index.d.ts +92 -95
  128. package/dist/state-machine/index.d.ts.map +1 -1
  129. package/dist/state-machine/index.js +6 -157
  130. package/dist/tests/operations.test-spec.d.ts +4 -9
  131. package/dist/tests/operations.test-spec.d.ts.map +1 -1
  132. package/dist/tests/operations.test-spec.js +7 -123
  133. package/dist/ui/WorkflowDashboard.d.ts +1 -6
  134. package/dist/ui/WorkflowDashboard.d.ts.map +1 -1
  135. package/dist/ui/WorkflowDashboard.js +3 -222
  136. package/dist/ui/hooks/index.d.ts +2 -2
  137. package/dist/ui/hooks/index.d.ts.map +1 -0
  138. package/dist/ui/hooks/index.js +51 -5
  139. package/dist/ui/hooks/useWorkflowList.d.ts +15 -19
  140. package/dist/ui/hooks/useWorkflowList.d.ts.map +1 -1
  141. package/dist/ui/hooks/useWorkflowList.js +47 -51
  142. package/dist/ui/index.d.ts +7 -6
  143. package/dist/ui/index.d.ts.map +1 -0
  144. package/dist/ui/index.js +55 -6
  145. package/dist/ui/renderers/index.d.ts +2 -2
  146. package/dist/ui/renderers/index.d.ts.map +1 -0
  147. package/dist/ui/renderers/index.js +227 -2
  148. package/dist/ui/renderers/workflow.markdown.d.ts +13 -14
  149. package/dist/ui/renderers/workflow.markdown.d.ts.map +1 -1
  150. package/dist/ui/renderers/workflow.markdown.js +223 -229
  151. package/dist/workflow/index.d.ts +8 -5
  152. package/dist/workflow/index.d.ts.map +1 -0
  153. package/dist/workflow/index.js +22 -6
  154. package/dist/workflow/workflow.enum.d.ts +4 -9
  155. package/dist/workflow/workflow.enum.d.ts.map +1 -1
  156. package/dist/workflow/workflow.enum.js +32 -42
  157. package/dist/workflow/workflow.event.d.ts +112 -118
  158. package/dist/workflow/workflow.event.d.ts.map +1 -1
  159. package/dist/workflow/workflow.event.js +7 -150
  160. package/dist/workflow/workflow.handler.d.ts +23 -24
  161. package/dist/workflow/workflow.handler.d.ts.map +1 -1
  162. package/dist/workflow/workflow.handler.js +6 -66
  163. package/dist/workflow/workflow.operations.d.ts +847 -853
  164. package/dist/workflow/workflow.operations.d.ts.map +1 -1
  165. package/dist/workflow/workflow.operations.js +9 -345
  166. package/dist/workflow/workflow.schema.d.ts +229 -234
  167. package/dist/workflow/workflow.schema.d.ts.map +1 -1
  168. package/dist/workflow/workflow.schema.js +146 -243
  169. package/dist/workflow-system.capability.d.ts +3 -8
  170. package/dist/workflow-system.capability.d.ts.map +1 -1
  171. package/dist/workflow-system.capability.js +6 -34
  172. package/dist/workflow-system.feature.d.ts +1 -6
  173. package/dist/workflow-system.feature.d.ts.map +1 -1
  174. package/dist/workflow-system.feature.js +4 -346
  175. package/package.json +415 -93
  176. package/dist/approval/approval.enum.js.map +0 -1
  177. package/dist/approval/approval.event.js.map +0 -1
  178. package/dist/approval/approval.handler.js +0 -72
  179. package/dist/approval/approval.handler.js.map +0 -1
  180. package/dist/approval/approval.operations.js.map +0 -1
  181. package/dist/approval/approval.schema.js.map +0 -1
  182. package/dist/docs/workflow-system.docblock.js.map +0 -1
  183. package/dist/entities/approval.js.map +0 -1
  184. package/dist/entities/index.js.map +0 -1
  185. package/dist/entities/instance.js.map +0 -1
  186. package/dist/entities/step.js.map +0 -1
  187. package/dist/entities/workflow.js.map +0 -1
  188. package/dist/example.js.map +0 -1
  189. package/dist/handlers/workflow.handlers.js.map +0 -1
  190. package/dist/instance/instance.enum.js.map +0 -1
  191. package/dist/instance/instance.event.js.map +0 -1
  192. package/dist/instance/instance.handler.js.map +0 -1
  193. package/dist/instance/instance.operations.js.map +0 -1
  194. package/dist/instance/instance.schema.js.map +0 -1
  195. package/dist/presentations/index.js.map +0 -1
  196. package/dist/seeders/index.js.map +0 -1
  197. package/dist/shared/mock-data.js.map +0 -1
  198. package/dist/state-machine/index.js.map +0 -1
  199. package/dist/tests/operations.test-spec.js.map +0 -1
  200. package/dist/ui/WorkflowDashboard.js.map +0 -1
  201. package/dist/ui/hooks/useWorkflowList.js.map +0 -1
  202. package/dist/ui/renderers/workflow.markdown.js.map +0 -1
  203. package/dist/workflow/workflow.enum.js.map +0 -1
  204. package/dist/workflow/workflow.event.js.map +0 -1
  205. package/dist/workflow/workflow.handler.js.map +0 -1
  206. package/dist/workflow/workflow.operations.js.map +0 -1
  207. package/dist/workflow/workflow.schema.js.map +0 -1
  208. package/dist/workflow-system.capability.js.map +0 -1
  209. package/dist/workflow-system.feature.js.map +0 -1
@@ -0,0 +1,164 @@
1
+ // src/instance/instance.event.ts
2
+ import { defineEvent, defineSchemaModel } from "@contractspec/lib.contracts";
3
+ import { ScalarTypeEnum } from "@contractspec/lib.schema";
4
+ var InstanceEventPayload = defineSchemaModel({
5
+ name: "InstanceEventPayload",
6
+ description: "Base payload for instance events",
7
+ fields: {
8
+ instanceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
9
+ workflowId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
10
+ workflowKey: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
11
+ status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
12
+ referenceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
13
+ referenceType: {
14
+ type: ScalarTypeEnum.String_unsecure(),
15
+ isOptional: true
16
+ },
17
+ triggeredBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
18
+ organizationId: {
19
+ type: ScalarTypeEnum.String_unsecure(),
20
+ isOptional: false
21
+ },
22
+ timestamp: { type: ScalarTypeEnum.DateTime(), isOptional: false }
23
+ }
24
+ });
25
+ var StepTransitionPayload = defineSchemaModel({
26
+ name: "StepTransitionEventPayload",
27
+ description: "Payload for step transition events",
28
+ fields: {
29
+ instanceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
30
+ workflowId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
31
+ fromStepKey: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
32
+ toStepKey: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
33
+ action: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
34
+ executedBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
35
+ timestamp: { type: ScalarTypeEnum.DateTime(), isOptional: false }
36
+ }
37
+ });
38
+ var InstanceCompletedPayload = defineSchemaModel({
39
+ name: "InstanceCompletedEventPayload",
40
+ description: "Payload when instance completes",
41
+ fields: {
42
+ instanceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
43
+ workflowId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
44
+ workflowKey: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
45
+ outcome: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
46
+ referenceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
47
+ referenceType: {
48
+ type: ScalarTypeEnum.String_unsecure(),
49
+ isOptional: true
50
+ },
51
+ duration: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
52
+ timestamp: { type: ScalarTypeEnum.DateTime(), isOptional: false }
53
+ }
54
+ });
55
+ var InstanceStartedEvent = defineEvent({
56
+ meta: {
57
+ key: "workflow.instance.started",
58
+ version: "1.0.0",
59
+ description: "A new workflow instance has been started.",
60
+ stability: "stable",
61
+ owners: ["@workflow-team"],
62
+ tags: ["workflow", "instance", "started"]
63
+ },
64
+ payload: InstanceEventPayload
65
+ });
66
+ var StepEnteredEvent = defineEvent({
67
+ meta: {
68
+ key: "workflow.step.entered",
69
+ version: "1.0.0",
70
+ description: "A workflow instance has entered a new step.",
71
+ stability: "stable",
72
+ owners: ["@workflow-team"],
73
+ tags: ["workflow", "step", "entered"]
74
+ },
75
+ payload: StepTransitionPayload
76
+ });
77
+ var StepExitedEvent = defineEvent({
78
+ meta: {
79
+ key: "workflow.step.exited",
80
+ version: "1.0.0",
81
+ description: "A workflow instance has exited a step.",
82
+ stability: "stable",
83
+ owners: ["@workflow-team"],
84
+ tags: ["workflow", "step", "exited"]
85
+ },
86
+ payload: StepTransitionPayload
87
+ });
88
+ var InstanceCompletedEvent = defineEvent({
89
+ meta: {
90
+ key: "workflow.instance.completed",
91
+ version: "1.0.0",
92
+ description: "A workflow instance has completed.",
93
+ stability: "stable",
94
+ owners: ["@workflow-team"],
95
+ tags: ["workflow", "instance", "completed"]
96
+ },
97
+ payload: InstanceCompletedPayload
98
+ });
99
+ var InstanceCancelledEvent = defineEvent({
100
+ meta: {
101
+ key: "workflow.instance.cancelled",
102
+ version: "1.0.0",
103
+ description: "A workflow instance has been cancelled.",
104
+ stability: "stable",
105
+ owners: ["@workflow-team"],
106
+ tags: ["workflow", "instance", "cancelled"]
107
+ },
108
+ payload: InstanceEventPayload
109
+ });
110
+ var InstancePausedEvent = defineEvent({
111
+ meta: {
112
+ key: "workflow.instance.paused",
113
+ version: "1.0.0",
114
+ description: "A workflow instance has been paused.",
115
+ stability: "stable",
116
+ owners: ["@workflow-team"],
117
+ tags: ["workflow", "instance", "paused"]
118
+ },
119
+ payload: InstanceEventPayload
120
+ });
121
+ var InstanceResumedEvent = defineEvent({
122
+ meta: {
123
+ key: "workflow.instance.resumed",
124
+ version: "1.0.0",
125
+ description: "A workflow instance has been resumed.",
126
+ stability: "stable",
127
+ owners: ["@workflow-team"],
128
+ tags: ["workflow", "instance", "resumed"]
129
+ },
130
+ payload: InstanceEventPayload
131
+ });
132
+ var InstanceFailedEvent = defineEvent({
133
+ meta: {
134
+ key: "workflow.instance.failed",
135
+ version: "1.0.0",
136
+ description: "A workflow instance has failed.",
137
+ stability: "stable",
138
+ owners: ["@workflow-team"],
139
+ tags: ["workflow", "instance", "failed"]
140
+ },
141
+ payload: InstanceEventPayload
142
+ });
143
+ var InstanceTimedOutEvent = defineEvent({
144
+ meta: {
145
+ key: "workflow.instance.timedOut",
146
+ version: "1.0.0",
147
+ description: "A workflow instance has timed out.",
148
+ stability: "stable",
149
+ owners: ["@workflow-team"],
150
+ tags: ["workflow", "instance", "timeout"]
151
+ },
152
+ payload: InstanceEventPayload
153
+ });
154
+ export {
155
+ StepExitedEvent,
156
+ StepEnteredEvent,
157
+ InstanceTimedOutEvent,
158
+ InstanceStartedEvent,
159
+ InstanceResumedEvent,
160
+ InstancePausedEvent,
161
+ InstanceFailedEvent,
162
+ InstanceCompletedEvent,
163
+ InstanceCancelledEvent
164
+ };
@@ -0,0 +1,356 @@
1
+ // src/shared/mock-data.ts
2
+ var mockDataStore = {
3
+ workflows: new Map,
4
+ steps: new Map,
5
+ instances: new Map,
6
+ approvals: new Map,
7
+ stepExecutions: new Map
8
+ };
9
+
10
+ // src/state-machine/index.ts
11
+ class BasicStateMachineEngine {
12
+ canTransition(definition, state, action, context) {
13
+ if (state.status !== "RUNNING" && state.status !== "WAITING") {
14
+ return {
15
+ allowed: false,
16
+ reason: `Workflow is ${state.status}, cannot transition`
17
+ };
18
+ }
19
+ const currentStep = definition.steps[state.currentStepKey];
20
+ if (!currentStep) {
21
+ return {
22
+ allowed: false,
23
+ reason: `Step ${state.currentStepKey} not found`
24
+ };
25
+ }
26
+ const transition = currentStep.transitions[action];
27
+ if (!transition) {
28
+ return {
29
+ allowed: false,
30
+ reason: `Action ${action} not available in step ${state.currentStepKey}`
31
+ };
32
+ }
33
+ if (currentStep.allowedRoles && currentStep.allowedRoles.length > 0) {
34
+ const hasRole = currentStep.allowedRoles.some((role) => context.userRoles.includes(role));
35
+ if (!hasRole) {
36
+ return {
37
+ allowed: false,
38
+ reason: `User lacks required role for this action`
39
+ };
40
+ }
41
+ }
42
+ if (typeof transition === "object" && transition.allowedRoles && transition.allowedRoles.length > 0) {
43
+ const hasRole = transition.allowedRoles.some((role) => context.userRoles.includes(role));
44
+ if (!hasRole) {
45
+ return {
46
+ allowed: false,
47
+ reason: `User lacks required role for action ${action}`
48
+ };
49
+ }
50
+ }
51
+ return { allowed: true };
52
+ }
53
+ getAvailableActions(definition, state, context) {
54
+ if (state.status !== "RUNNING" && state.status !== "WAITING") {
55
+ return [];
56
+ }
57
+ const currentStep = definition.steps[state.currentStepKey];
58
+ if (!currentStep) {
59
+ return [];
60
+ }
61
+ return Object.keys(currentStep.transitions).filter((action) => {
62
+ const result = this.canTransition(definition, state, action, context);
63
+ return result.allowed;
64
+ });
65
+ }
66
+ transition(definition, state, action, context) {
67
+ const validation = this.canTransition(definition, state, action, context);
68
+ if (!validation.allowed) {
69
+ return {
70
+ success: false,
71
+ previousStepKey: state.currentStepKey,
72
+ currentStepKey: state.currentStepKey,
73
+ status: state.status,
74
+ error: validation.reason
75
+ };
76
+ }
77
+ const currentStep = definition.steps[state.currentStepKey];
78
+ if (!currentStep) {
79
+ return {
80
+ success: false,
81
+ previousStepKey: state.currentStepKey,
82
+ currentStepKey: state.currentStepKey,
83
+ status: state.status,
84
+ error: `Current step ${state.currentStepKey} not found`
85
+ };
86
+ }
87
+ const transition = currentStep.transitions[action];
88
+ if (!transition) {
89
+ return {
90
+ success: false,
91
+ previousStepKey: state.currentStepKey,
92
+ currentStepKey: state.currentStepKey,
93
+ status: state.status,
94
+ error: `Transition for action ${action} not found`
95
+ };
96
+ }
97
+ const targetStepKey = typeof transition === "string" ? transition : transition.targetStepKey;
98
+ const targetStep = definition.steps[targetStepKey];
99
+ if (!targetStep) {
100
+ return {
101
+ success: false,
102
+ previousStepKey: state.currentStepKey,
103
+ currentStepKey: state.currentStepKey,
104
+ status: state.status,
105
+ error: `Target step ${targetStepKey} not found`
106
+ };
107
+ }
108
+ let newStatus = "RUNNING";
109
+ if (targetStep.type === "END") {
110
+ newStatus = "COMPLETED";
111
+ } else if (targetStep.type === "APPROVAL" || targetStep.type === "WAIT") {
112
+ newStatus = "WAITING";
113
+ }
114
+ return {
115
+ success: true,
116
+ previousStepKey: state.currentStepKey,
117
+ currentStepKey: targetStepKey,
118
+ status: newStatus
119
+ };
120
+ }
121
+ evaluateCondition(expression, contextData) {
122
+ try {
123
+ const match = expression.match(/^(\w+)\s*(>=|<=|>|<|===|!==|==|!=)\s*(.+)$/);
124
+ if (match) {
125
+ const [, prop, operator, value] = match;
126
+ if (!prop || !operator || value === undefined) {
127
+ return false;
128
+ }
129
+ const propValue = contextData[prop];
130
+ const compareValue = JSON.parse(value);
131
+ switch (operator) {
132
+ case ">":
133
+ return Number(propValue) > Number(compareValue);
134
+ case "<":
135
+ return Number(propValue) < Number(compareValue);
136
+ case ">=":
137
+ return Number(propValue) >= Number(compareValue);
138
+ case "<=":
139
+ return Number(propValue) <= Number(compareValue);
140
+ case "===":
141
+ case "==":
142
+ return propValue === compareValue;
143
+ case "!==":
144
+ case "!=":
145
+ return propValue !== compareValue;
146
+ }
147
+ }
148
+ if (expression in contextData) {
149
+ return Boolean(contextData[expression]);
150
+ }
151
+ return false;
152
+ } catch {
153
+ return false;
154
+ }
155
+ }
156
+ }
157
+ function createStateMachineEngine() {
158
+ return new BasicStateMachineEngine;
159
+ }
160
+ function buildStateMachineDefinition(workflow, steps) {
161
+ const stepMap = {};
162
+ for (const step of steps) {
163
+ stepMap[step.key] = {
164
+ key: step.key,
165
+ name: step.name,
166
+ type: step.type,
167
+ transitions: step.transitions,
168
+ approvalMode: step.approvalMode,
169
+ allowedRoles: step.approverRoles,
170
+ timeoutSeconds: step.timeoutSeconds,
171
+ conditionExpression: step.conditionExpression
172
+ };
173
+ }
174
+ const startStep = steps.find((s) => s.type === "START");
175
+ const initialStepKey = startStep?.key ?? steps[0]?.key ?? "";
176
+ return {
177
+ key: workflow.key,
178
+ name: workflow.name,
179
+ version: workflow.version,
180
+ initialStepKey,
181
+ steps: stepMap
182
+ };
183
+ }
184
+ function createInitialState(definition, contextData = {}) {
185
+ return {
186
+ currentStepKey: definition.initialStepKey,
187
+ status: "RUNNING",
188
+ contextData,
189
+ history: []
190
+ };
191
+ }
192
+
193
+ // src/approval/approval.handler.ts
194
+ async function createApprovalRequests(instance, step, _context) {
195
+ const now = new Date;
196
+ for (let i = 0;i < step.approverRoles.length; i++) {
197
+ const role = step.approverRoles[i];
198
+ const id = `approval_${Date.now()}_${i}`;
199
+ const request = {
200
+ id,
201
+ workflowInstanceId: instance.id,
202
+ stepExecutionId: `exec_${instance.id}_${step.id}`,
203
+ approverId: `user_${role}`,
204
+ approverRole: role,
205
+ title: `Approval required for ${step.name}`,
206
+ description: step.description,
207
+ status: "PENDING",
208
+ contextSnapshot: instance.contextData,
209
+ sequenceOrder: i,
210
+ createdAt: now,
211
+ updatedAt: now
212
+ };
213
+ mockDataStore.approvals.set(id, request);
214
+ }
215
+ }
216
+ async function handleSubmitDecision(input, context) {
217
+ const request = mockDataStore.approvals.get(input.requestId);
218
+ if (!request) {
219
+ throw new Error(`Approval request ${input.requestId} not found`);
220
+ }
221
+ if (request.approverId !== context.userId && !context.userRoles.includes(request.approverRole ?? "")) {
222
+ throw new Error("User is not authorized to make this decision");
223
+ }
224
+ const now = new Date;
225
+ request.decision = input.decision;
226
+ request.decisionComment = input.comment;
227
+ request.decidedAt = now;
228
+ request.updatedAt = now;
229
+ if (input.decision === "APPROVE") {
230
+ request.status = "APPROVED";
231
+ await handleTransitionWorkflow({
232
+ instanceId: request.workflowInstanceId,
233
+ action: "approve",
234
+ data: input.data,
235
+ comment: input.comment
236
+ }, context);
237
+ } else if (input.decision === "REJECT") {
238
+ request.status = "REJECTED";
239
+ await handleTransitionWorkflow({
240
+ instanceId: request.workflowInstanceId,
241
+ action: "reject",
242
+ data: input.data,
243
+ comment: input.comment
244
+ }, context);
245
+ }
246
+ return request;
247
+ }
248
+ async function handleListMyApprovals(input, context) {
249
+ let requests = Array.from(mockDataStore.approvals.values()).filter((r) => r.approverId === context.userId || context.userRoles.includes(r.approverRole ?? ""));
250
+ const pendingCount = requests.filter((r) => r.status === "PENDING").length;
251
+ if (input.status) {
252
+ requests = requests.filter((r) => r.status === input.status);
253
+ }
254
+ const total = requests.length;
255
+ const offset = input.offset ?? 0;
256
+ const limit = input.limit ?? 20;
257
+ requests = requests.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()).slice(offset, offset + limit);
258
+ return { requests, total, pendingCount };
259
+ }
260
+
261
+ // src/instance/instance.handler.ts
262
+ async function handleStartWorkflow(input, context) {
263
+ const workflow = Array.from(mockDataStore.workflows.values()).find((w) => w.key === input.workflowKey && w.status === "ACTIVE" && w.organizationId === context.organizationId);
264
+ if (!workflow) {
265
+ throw new Error(`Active workflow ${input.workflowKey} not found`);
266
+ }
267
+ const id = `inst_${Date.now()}`;
268
+ const now = new Date;
269
+ const instance = {
270
+ id,
271
+ workflowDefinitionId: workflow.id,
272
+ referenceId: input.referenceId,
273
+ referenceType: input.referenceType,
274
+ status: "RUNNING",
275
+ currentStepId: workflow.initialStepId,
276
+ contextData: input.contextData ?? {},
277
+ triggeredBy: context.userId,
278
+ organizationId: context.organizationId,
279
+ priority: input.priority ?? 0,
280
+ dueAt: input.dueAt,
281
+ createdAt: now,
282
+ updatedAt: now,
283
+ startedAt: now
284
+ };
285
+ mockDataStore.instances.set(id, instance);
286
+ if (workflow.initialStepId) {
287
+ const firstStep = mockDataStore.steps.get(workflow.initialStepId);
288
+ if (firstStep?.type === "APPROVAL") {
289
+ instance.status = "WAITING";
290
+ await createApprovalRequests(instance, firstStep, context);
291
+ }
292
+ }
293
+ return instance;
294
+ }
295
+ async function handleTransitionWorkflow(input, context) {
296
+ const instance = mockDataStore.instances.get(input.instanceId);
297
+ if (!instance) {
298
+ throw new Error(`Instance ${input.instanceId} not found`);
299
+ }
300
+ const workflow = mockDataStore.workflows.get(instance.workflowDefinitionId);
301
+ if (!workflow) {
302
+ throw new Error(`Workflow ${instance.workflowDefinitionId} not found`);
303
+ }
304
+ const steps = Array.from(mockDataStore.steps.values()).filter((s) => s.workflowDefinitionId === workflow.id);
305
+ const definition = buildStateMachineDefinition({
306
+ key: workflow.key,
307
+ name: workflow.name,
308
+ version: workflow.version,
309
+ initialStepId: workflow.initialStepId ?? null
310
+ }, steps);
311
+ const currentStep = steps.find((s) => s.id === instance.currentStepId);
312
+ const state = {
313
+ currentStepKey: currentStep?.key ?? "",
314
+ status: instance.status,
315
+ contextData: instance.contextData,
316
+ history: []
317
+ };
318
+ const transitionContext = {
319
+ userId: context.userId,
320
+ userRoles: context.userRoles,
321
+ data: input.data
322
+ };
323
+ const engine = createStateMachineEngine();
324
+ const result = engine.transition(definition, state, input.action, transitionContext);
325
+ if (!result.success) {
326
+ return {
327
+ success: false,
328
+ instance,
329
+ message: result.error
330
+ };
331
+ }
332
+ const previousStepKey = currentStep?.key;
333
+ const newStep = steps.find((s) => s.key === result.currentStepKey);
334
+ instance.currentStepId = newStep?.id;
335
+ instance.status = result.status;
336
+ instance.contextData = { ...instance.contextData, ...input.data };
337
+ instance.updatedAt = new Date;
338
+ if (result.status === "COMPLETED") {
339
+ instance.completedAt = new Date;
340
+ instance.outcome = input.action;
341
+ }
342
+ if (newStep?.type === "APPROVAL") {
343
+ instance.status = "WAITING";
344
+ await createApprovalRequests(instance, newStep, context);
345
+ }
346
+ return {
347
+ success: true,
348
+ instance,
349
+ previousStepKey,
350
+ currentStepKey: result.currentStepKey ?? undefined
351
+ };
352
+ }
353
+ export {
354
+ handleTransitionWorkflow,
355
+ handleStartWorkflow
356
+ };
@@ -0,0 +1,9 @@
1
+ export {
2
+ TransitionWorkflowContract,
3
+ StartWorkflowContract,
4
+ ResumeWorkflowContract,
5
+ PauseWorkflowContract,
6
+ ListInstancesContract,
7
+ GetInstanceContract,
8
+ CancelWorkflowContract
9
+ };
@@ -0,0 +1,101 @@
1
+ // src/instance/instance.enum.ts
2
+ import { defineEnum } from "@contractspec/lib.schema";
3
+ var InstanceStatusEnum = defineEnum("InstanceStatus", [
4
+ "PENDING",
5
+ "RUNNING",
6
+ "WAITING",
7
+ "PAUSED",
8
+ "COMPLETED",
9
+ "CANCELLED",
10
+ "FAILED",
11
+ "TIMEOUT"
12
+ ]);
13
+
14
+ // src/instance/instance.schema.ts
15
+ import { defineSchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";
16
+ var WorkflowInstanceModel = defineSchemaModel({
17
+ name: "WorkflowInstanceModel",
18
+ description: "A running workflow instance",
19
+ fields: {
20
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
21
+ workflowDefinitionId: {
22
+ type: ScalarTypeEnum.String_unsecure(),
23
+ isOptional: false
24
+ },
25
+ referenceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
26
+ referenceType: {
27
+ type: ScalarTypeEnum.String_unsecure(),
28
+ isOptional: true
29
+ },
30
+ status: { type: InstanceStatusEnum, isOptional: false },
31
+ currentStepId: {
32
+ type: ScalarTypeEnum.String_unsecure(),
33
+ isOptional: true
34
+ },
35
+ contextData: { type: ScalarTypeEnum.JSON(), isOptional: true },
36
+ triggeredBy: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
37
+ organizationId: {
38
+ type: ScalarTypeEnum.String_unsecure(),
39
+ isOptional: false
40
+ },
41
+ priority: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
42
+ dueAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
43
+ outcome: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
44
+ resultData: { type: ScalarTypeEnum.JSON(), isOptional: true },
45
+ errorMessage: {
46
+ type: ScalarTypeEnum.String_unsecure(),
47
+ isOptional: true
48
+ },
49
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
50
+ startedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
51
+ completedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true }
52
+ }
53
+ });
54
+ var StartWorkflowInputModel = defineSchemaModel({
55
+ name: "StartWorkflowInput",
56
+ description: "Input for starting a workflow",
57
+ fields: {
58
+ workflowKey: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
59
+ contextData: { type: ScalarTypeEnum.JSON(), isOptional: true },
60
+ referenceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
61
+ referenceType: {
62
+ type: ScalarTypeEnum.String_unsecure(),
63
+ isOptional: true
64
+ },
65
+ priority: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
66
+ dueAt: { type: ScalarTypeEnum.DateTime(), isOptional: true }
67
+ }
68
+ });
69
+ var TransitionInputModel = defineSchemaModel({
70
+ name: "TransitionInput",
71
+ description: "Input for transitioning a workflow",
72
+ fields: {
73
+ instanceId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
74
+ action: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
75
+ data: { type: ScalarTypeEnum.JSON(), isOptional: true },
76
+ comment: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
77
+ }
78
+ });
79
+ var TransitionResultModel = defineSchemaModel({
80
+ name: "TransitionResult",
81
+ description: "Result of a workflow transition",
82
+ fields: {
83
+ success: { type: ScalarTypeEnum.Boolean(), isOptional: false },
84
+ instance: { type: WorkflowInstanceModel, isOptional: false },
85
+ previousStepKey: {
86
+ type: ScalarTypeEnum.String_unsecure(),
87
+ isOptional: true
88
+ },
89
+ currentStepKey: {
90
+ type: ScalarTypeEnum.String_unsecure(),
91
+ isOptional: true
92
+ },
93
+ message: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
94
+ }
95
+ });
96
+ export {
97
+ WorkflowInstanceModel,
98
+ TransitionResultModel,
99
+ TransitionInputModel,
100
+ StartWorkflowInputModel
101
+ };