@rytass/bpm-core-shared 0.5.0 → 0.6.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 (50) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/package.json +3 -2
  3. package/src/index.js +13 -0
  4. package/src/index.js.map +1 -0
  5. package/src/lib/condition.d.ts +43 -0
  6. package/src/lib/condition.js +3 -0
  7. package/src/lib/condition.js.map +1 -0
  8. package/src/lib/form.d.ts +48 -0
  9. package/src/lib/form.js +3 -0
  10. package/src/lib/form.js.map +1 -0
  11. package/src/lib/identity.d.ts +24 -0
  12. package/src/lib/identity.js +3 -0
  13. package/src/lib/identity.js.map +1 -0
  14. package/src/lib/organization.d.ts +47 -0
  15. package/src/lib/organization.js +3 -0
  16. package/src/lib/organization.js.map +1 -0
  17. package/src/lib/status.d.ts +7 -0
  18. package/src/lib/status.js +3 -0
  19. package/src/lib/status.js.map +1 -0
  20. package/src/lib/workflow-command.d.ts +156 -0
  21. package/src/lib/workflow-command.js +292 -0
  22. package/src/lib/workflow-command.js.map +1 -0
  23. package/src/lib/workflow-graph.d.ts +96 -0
  24. package/src/lib/workflow-graph.js +605 -0
  25. package/src/lib/workflow-graph.js.map +1 -0
  26. package/src/lib/workflow-toolset.d.ts +105 -0
  27. package/src/lib/workflow-toolset.js +707 -0
  28. package/src/lib/workflow-toolset.js.map +1 -0
  29. package/src/lib/workflow.d.ts +162 -0
  30. package/src/lib/workflow.js +3 -0
  31. package/src/lib/workflow.js.map +1 -0
  32. package/eslint.config.mjs +0 -19
  33. package/jest.config.cts +0 -10
  34. package/project.json +0 -49
  35. package/src/lib/condition.ts +0 -55
  36. package/src/lib/form.ts +0 -77
  37. package/src/lib/identity.ts +0 -25
  38. package/src/lib/organization.ts +0 -52
  39. package/src/lib/shared.spec.ts +0 -13
  40. package/src/lib/status.ts +0 -29
  41. package/src/lib/workflow-command.spec.ts +0 -278
  42. package/src/lib/workflow-command.ts +0 -848
  43. package/src/lib/workflow-graph.ts +0 -974
  44. package/src/lib/workflow-toolset.spec.ts +0 -230
  45. package/src/lib/workflow-toolset.ts +0 -1083
  46. package/src/lib/workflow.ts +0 -216
  47. package/tsconfig.json +0 -23
  48. package/tsconfig.lib.json +0 -16
  49. package/tsconfig.spec.json +0 -16
  50. /package/src/{index.ts → index.d.ts} +0 -0
@@ -1,230 +0,0 @@
1
- import { readFallbackWorkflowDefinition } from './workflow-graph';
2
- import { WorkflowDesignerState } from './workflow-command';
3
- import {
4
- WORKFLOW_TOOLSET,
5
- WorkflowDirectory,
6
- WorkflowSnapshot,
7
- executeWorkflowTool,
8
- readWorkflowSnapshot,
9
- } from './workflow-toolset';
10
-
11
- function initialState(): WorkflowDesignerState {
12
- return {
13
- definition: readFallbackWorkflowDefinition(),
14
- editingEdgeId: null,
15
- formDefinitionVersionId: null,
16
- formSchema: null,
17
- initiatorPolicyCel: null,
18
- selectedEdgeIds: [],
19
- selectedNodeId: 'start',
20
- };
21
- }
22
-
23
- const deterministicIds = {
24
- createEdgeId: ((): ((source: string, target: string) => string) => {
25
- let counter = 0;
26
-
27
- return (source: string, target: string): string =>
28
- `edge_${source}_${target}_${(counter += 1)}`;
29
- })(),
30
- };
31
-
32
- describe('WORKFLOW_TOOLSET', () => {
33
- it('every tool has a unique name and an object input schema', () => {
34
- const names = WORKFLOW_TOOLSET.map((tool) => tool.name);
35
-
36
- expect(new Set(names).size).toBe(names.length);
37
-
38
- WORKFLOW_TOOLSET.forEach((tool) => {
39
- expect(tool.inputSchema['type']).toBe('object');
40
- expect(['mutation', 'macro', 'query']).toContain(tool.kind);
41
- });
42
- });
43
- });
44
-
45
- describe('executeWorkflowTool', () => {
46
- it('returns an error for an unknown tool', async () => {
47
- const result = await executeWorkflowTool(
48
- initialState(),
49
- 'no_such_tool',
50
- {},
51
- );
52
-
53
- expect(result.ok).toBe(false);
54
-
55
- if (!result.ok) {
56
- expect(result.error).toContain('未知的工具');
57
- }
58
- });
59
-
60
- it('runs a mutation tool and returns a fresh snapshot', async () => {
61
- const result = await executeWorkflowTool(
62
- initialState(),
63
- 'add_node',
64
- { nodeType: 'userTask' },
65
- deterministicIds,
66
- );
67
-
68
- expect(result.ok).toBe(true);
69
-
70
- if (result.ok && result.kind === 'mutation') {
71
- expect(
72
- result.snapshot.nodes.some((node) => node.type === 'userTask'),
73
- ).toBe(true);
74
- }
75
- });
76
-
77
- it('runs a macro tool (insert_approval_step)', async () => {
78
- const result = await executeWorkflowTool(
79
- initialState(),
80
- 'insert_approval_step',
81
- {
82
- approverResolver: { memberIds: ['m-1'], type: 'DIRECT' },
83
- label: '主管簽核',
84
- },
85
- deterministicIds,
86
- );
87
-
88
- expect(result.ok).toBe(true);
89
-
90
- if (result.ok && result.kind === 'macro') {
91
- const userTask = result.snapshot.nodes.find(
92
- (node) => node.type === 'userTask',
93
- );
94
-
95
- expect(userTask?.label).toBe('主管簽核');
96
- }
97
- });
98
-
99
- it('coerces a malformed approver resolver to the manager default instead of failing', async () => {
100
- const added = await executeWorkflowTool(
101
- initialState(),
102
- 'add_node',
103
- { nodeType: 'userTask' },
104
- deterministicIds,
105
- );
106
-
107
- expect(added.ok).toBe(true);
108
-
109
- if (!(added.ok && added.kind === 'mutation')) {
110
- return;
111
- }
112
-
113
- const nodeId =
114
- added.snapshot.nodes.find((node) => node.type === 'userTask')?.id ?? '';
115
- const result = await executeWorkflowTool(
116
- added.result.state,
117
- 'set_user_task_approver',
118
- { approverResolver: { type: 'DIRECT' }, nodeId },
119
- deterministicIds,
120
- );
121
-
122
- expect(result.ok).toBe(true);
123
-
124
- if (result.ok && result.kind === 'mutation') {
125
- const userTask = result.snapshot.nodes.find((node) => node.id === nodeId);
126
-
127
- expect(userTask?.summary).toContain('簽核人=ORG_MANAGER');
128
- }
129
- });
130
-
131
- it('draws a draft approval step with no approver supplied (manager default)', async () => {
132
- const result = await executeWorkflowTool(
133
- initialState(),
134
- 'insert_approval_step',
135
- { label: '主管簽核' },
136
- deterministicIds,
137
- );
138
-
139
- expect(result.ok).toBe(true);
140
-
141
- if (result.ok && result.kind === 'macro') {
142
- const userTask = result.snapshot.nodes.find(
143
- (node) => node.type === 'userTask',
144
- );
145
-
146
- expect(userTask?.label).toBe('主管簽核');
147
- expect(result.snapshot.issue).toBeNull();
148
- }
149
- });
150
-
151
- it('answers the get_workflow_snapshot query without mutating', async () => {
152
- const result = await executeWorkflowTool(
153
- initialState(),
154
- 'get_workflow_snapshot',
155
- {},
156
- );
157
-
158
- expect(result.ok).toBe(true);
159
-
160
- if (result.ok && result.kind === 'query') {
161
- const snapshot = result.data as WorkflowSnapshot;
162
-
163
- expect(snapshot.nodes.map((node) => node.type)).toEqual([
164
- 'startEvent',
165
- 'endEvent',
166
- ]);
167
- }
168
- });
169
-
170
- it('reports validation issues via validate_workflow', async () => {
171
- const result = await executeWorkflowTool(
172
- initialState(),
173
- 'validate_workflow',
174
- {},
175
- );
176
-
177
- expect(result.ok).toBe(true);
178
-
179
- if (result.ok && result.kind === 'query') {
180
- expect(result.data).toEqual({ issue: null });
181
- }
182
- });
183
-
184
- it('search_members reports unavailable without an injected directory', async () => {
185
- const result = await executeWorkflowTool(initialState(), 'search_members', {
186
- query: '財務',
187
- });
188
-
189
- expect(result.ok).toBe(true);
190
-
191
- if (result.ok && result.kind === 'query') {
192
- expect(result.data).toEqual({ available: false, items: [] });
193
- }
194
- });
195
-
196
- it('search_members returns members from the injected directory', async () => {
197
- const directory: WorkflowDirectory = {
198
- listOrgUnits: async () => [],
199
- listPositions: async () => [],
200
- searchMembers: async (query) => [
201
- { email: 'amy@example.com', id: 'm-1', name: `${query}-王小明` },
202
- ],
203
- };
204
- const result = await executeWorkflowTool(
205
- initialState(),
206
- 'search_members',
207
- { query: '財務' },
208
- { directory },
209
- );
210
-
211
- expect(result.ok).toBe(true);
212
-
213
- if (result.ok && result.kind === 'query') {
214
- expect(result.data).toEqual({
215
- available: true,
216
- items: [{ email: 'amy@example.com', id: 'm-1', name: '財務-王小明' }],
217
- });
218
- }
219
- });
220
- });
221
-
222
- describe('readWorkflowSnapshot', () => {
223
- it('summarises nodes and selection', () => {
224
- const snapshot = readWorkflowSnapshot(initialState());
225
-
226
- expect(snapshot.selectedNodeId).toBe('start');
227
- expect(snapshot.issue).toBeNull();
228
- expect(snapshot.nodes).toHaveLength(2);
229
- });
230
- });