eventmodeler 0.4.0 → 0.4.2

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 (64) hide show
  1. package/dist/cloud/slices/index.d.ts +269 -0
  2. package/dist/cloud/slices/index.js +348 -0
  3. package/dist/index.js +1017 -45
  4. package/dist/lib/auth.d.ts +24 -0
  5. package/dist/lib/auth.js +331 -0
  6. package/dist/lib/backend.d.ts +43 -0
  7. package/dist/lib/backend.js +73 -0
  8. package/dist/lib/cloud-client.d.ts +69 -0
  9. package/dist/lib/cloud-client.js +297 -0
  10. package/dist/lib/config.d.ts +27 -0
  11. package/dist/lib/config.js +80 -11
  12. package/dist/lib/diff/three-way-merge.js +4 -4
  13. package/dist/lib/file-loader.js +43 -12
  14. package/dist/lib/project-config.d.ts +30 -0
  15. package/dist/lib/project-config.js +90 -0
  16. package/dist/lib/slice-utils.d.ts +49 -0
  17. package/dist/lib/slice-utils.js +141 -0
  18. package/dist/local/slices/index.d.ts +11 -0
  19. package/dist/local/slices/index.js +13 -0
  20. package/dist/projection.js +372 -371
  21. package/dist/slices/add-field/index.js +25 -15
  22. package/dist/slices/add-scenario/index.d.ts +27 -0
  23. package/dist/slices/add-scenario/index.js +317 -155
  24. package/dist/slices/codegen-chapter-events/index.d.ts +2 -0
  25. package/dist/slices/codegen-chapter-events/index.js +145 -0
  26. package/dist/slices/create-automation-slice/index.js +93 -65
  27. package/dist/slices/create-flow/index.js +24 -18
  28. package/dist/slices/create-state-change-slice/index.js +77 -53
  29. package/dist/slices/create-state-view-slice/index.js +25 -17
  30. package/dist/slices/import/index.d.ts +8 -0
  31. package/dist/slices/import/index.js +63 -0
  32. package/dist/slices/init/index.d.ts +4 -0
  33. package/dist/slices/init/index.js +133 -0
  34. package/dist/slices/list-processors/index.d.ts +3 -0
  35. package/dist/slices/list-processors/index.js +20 -0
  36. package/dist/slices/list-readmodels/index.d.ts +3 -0
  37. package/dist/slices/list-readmodels/index.js +21 -0
  38. package/dist/slices/list-scenarios/index.d.ts +3 -0
  39. package/dist/slices/list-scenarios/index.js +35 -0
  40. package/dist/slices/list-screens/index.d.ts +3 -0
  41. package/dist/slices/list-screens/index.js +47 -0
  42. package/dist/slices/login/index.d.ts +1 -0
  43. package/dist/slices/login/index.js +20 -0
  44. package/dist/slices/logout/index.d.ts +1 -0
  45. package/dist/slices/logout/index.js +14 -0
  46. package/dist/slices/map-fields/index.js +5 -3
  47. package/dist/slices/mark-slice-status/index.js +4 -2
  48. package/dist/slices/remove-field/index.js +25 -15
  49. package/dist/slices/remove-scenario/index.js +8 -4
  50. package/dist/slices/show-aggregate/index.d.ts +3 -0
  51. package/dist/slices/show-aggregate/index.js +108 -0
  52. package/dist/slices/show-processor/index.d.ts +3 -0
  53. package/dist/slices/show-processor/index.js +111 -0
  54. package/dist/slices/show-readmodel/index.d.ts +3 -0
  55. package/dist/slices/show-readmodel/index.js +158 -0
  56. package/dist/slices/show-scenario/index.d.ts +3 -0
  57. package/dist/slices/show-scenario/index.js +196 -0
  58. package/dist/slices/show-screen/index.d.ts +3 -0
  59. package/dist/slices/show-screen/index.js +139 -0
  60. package/dist/slices/update-field/index.js +30 -20
  61. package/dist/slices/whoami/index.d.ts +2 -0
  62. package/dist/slices/whoami/index.js +35 -0
  63. package/dist/types.d.ts +1 -2
  64. package/package.json +1 -1
@@ -0,0 +1,139 @@
1
+ import { escapeXml, outputJson } from '../../lib/format.js';
2
+ import { findElementOrExit } from '../../lib/element-lookup.js';
3
+ function formatFieldXml(field, indent) {
4
+ const attrs = [
5
+ `name="${escapeXml(field.name)}"`,
6
+ `type="${field.fieldType}"`,
7
+ ];
8
+ if (field.isList)
9
+ attrs.push('list="true"');
10
+ if (field.isGenerated)
11
+ attrs.push('generated="true"');
12
+ if (field.isOptional)
13
+ attrs.push('optional="true"');
14
+ if (field.isUserInput)
15
+ attrs.push('user-input="true"');
16
+ if (field.subfields && field.subfields.length > 0) {
17
+ let xml = `${indent}<field ${attrs.join(' ')}>\n`;
18
+ for (const subfield of field.subfields) {
19
+ xml += formatFieldXml(subfield, indent + ' ');
20
+ }
21
+ xml += `${indent}</field>\n`;
22
+ return xml;
23
+ }
24
+ return `${indent}<field ${attrs.join(' ')}/>\n`;
25
+ }
26
+ function fieldToJson(field) {
27
+ const result = {
28
+ name: field.name,
29
+ type: field.fieldType
30
+ };
31
+ if (field.isList)
32
+ result.list = true;
33
+ if (field.isGenerated)
34
+ result.generated = true;
35
+ if (field.isOptional)
36
+ result.optional = true;
37
+ if (field.isUserInput)
38
+ result.userInput = true;
39
+ if (field.subfields && field.subfields.length > 0) {
40
+ result.subfields = field.subfields.map(fieldToJson);
41
+ }
42
+ return result;
43
+ }
44
+ // Find which slice contains a screen
45
+ function findSliceForScreen(model, screen) {
46
+ for (const slice of model.slices.values()) {
47
+ const centerX = screen.position.x + screen.width / 2;
48
+ const centerY = screen.position.y + screen.height / 2;
49
+ if (centerX >= slice.position.x &&
50
+ centerX <= slice.position.x + slice.size.width &&
51
+ centerY >= slice.position.y &&
52
+ centerY <= slice.position.y + slice.size.height) {
53
+ return slice.name;
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ // Find which actor contains a screen
59
+ function findActorForScreen(model, screen) {
60
+ const centerX = screen.position.x + screen.width / 2;
61
+ const centerY = screen.position.y + screen.height / 2;
62
+ for (const actor of model.actors.values()) {
63
+ const bounds = {
64
+ left: actor.position.x,
65
+ right: actor.position.x + actor.size.width,
66
+ top: actor.position.y,
67
+ bottom: actor.position.y + actor.size.height,
68
+ };
69
+ if (centerX >= bounds.left && centerX <= bounds.right &&
70
+ centerY >= bounds.top && centerY <= bounds.bottom) {
71
+ return actor;
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+ export function showScreen(model, name, format) {
77
+ // Filter out linked copies
78
+ const originalScreens = new Map([...model.screens.entries()].filter(([_, s]) => !s.originalNodeId));
79
+ const screen = findElementOrExit(originalScreens, name, 'screen');
80
+ const slice = findSliceForScreen(model, screen);
81
+ const actor = findActorForScreen(model, screen);
82
+ // Find incoming flows (ReadModel → Screen)
83
+ const incomingFlows = [...model.flows.values()].filter(f => f.flowType === 'ReadModelToScreen' && f.targetId === screen.id);
84
+ // Find outgoing flows (Screen → Command)
85
+ const outgoingFlows = [...model.flows.values()].filter(f => f.flowType === 'ScreenToCommand' && f.sourceId === screen.id);
86
+ if (format === 'json') {
87
+ const result = {
88
+ id: screen.id,
89
+ name: screen.name,
90
+ fields: screen.fields.map(fieldToJson)
91
+ };
92
+ if (slice)
93
+ result.slice = slice;
94
+ if (actor)
95
+ result.actor = actor.name;
96
+ if (incomingFlows.length > 0) {
97
+ result.displaysFrom = incomingFlows.map(flow => {
98
+ const rm = model.readModels.get(flow.sourceId);
99
+ return rm?.name ?? flow.sourceId;
100
+ });
101
+ }
102
+ if (outgoingFlows.length > 0) {
103
+ result.triggersCommands = outgoingFlows.map(flow => {
104
+ const cmd = model.commands.get(flow.targetId);
105
+ return cmd?.name ?? flow.targetId;
106
+ });
107
+ }
108
+ outputJson(result);
109
+ return;
110
+ }
111
+ // XML output
112
+ const sliceAttr = slice ? ` slice="${escapeXml(slice)}"` : '';
113
+ const actorAttr = actor ? ` actor="${escapeXml(actor.name)}"` : '';
114
+ console.log(`<screen id="${screen.id}" name="${escapeXml(screen.name)}"${sliceAttr}${actorAttr}>`);
115
+ if (screen.fields.length > 0) {
116
+ console.log(' <fields>');
117
+ for (const field of screen.fields) {
118
+ process.stdout.write(formatFieldXml(field, ' '));
119
+ }
120
+ console.log(' </fields>');
121
+ }
122
+ if (incomingFlows.length > 0) {
123
+ console.log(' <displays-from>');
124
+ for (const flow of incomingFlows) {
125
+ const rm = model.readModels.get(flow.sourceId);
126
+ console.log(` <read-model name="${escapeXml(rm?.name ?? flow.sourceId)}"/>`);
127
+ }
128
+ console.log(' </displays-from>');
129
+ }
130
+ if (outgoingFlows.length > 0) {
131
+ console.log(' <triggers-commands>');
132
+ for (const flow of outgoingFlows) {
133
+ const cmd = model.commands.get(flow.targetId);
134
+ console.log(` <command name="${escapeXml(cmd?.name ?? flow.targetId)}"/>`);
135
+ }
136
+ console.log(' </triggers-commands>');
137
+ }
138
+ console.log('</screen>');
139
+ }
@@ -75,10 +75,12 @@ function updateCommandField(model, filePath, commandName, fieldName, updates) {
75
75
  const updatedField = createUpdatedField(field, updates);
76
76
  appendEvent(filePath, {
77
77
  type: 'CommandFieldAdjusted',
78
- commandStickyId: command.id,
79
- fieldId: field.id,
80
- field: updatedField,
81
- timestamp: Date.now(),
78
+ data: {
79
+ commandStickyId: command.id,
80
+ fieldId: field.id,
81
+ field: updatedField,
82
+ timestamp: Date.now(),
83
+ },
82
84
  });
83
85
  console.log(`Updated field "${field.name}" on command "${command.name}"`);
84
86
  logUpdates(updates);
@@ -100,10 +102,12 @@ function updateEventField(model, filePath, eventName, fieldName, updates) {
100
102
  const updatedField = createUpdatedField(field, updates);
101
103
  appendEvent(filePath, {
102
104
  type: 'EventFieldAdjusted',
103
- eventStickyId: event.id,
104
- fieldId: field.id,
105
- field: updatedField,
106
- timestamp: Date.now(),
105
+ data: {
106
+ eventStickyId: event.id,
107
+ fieldId: field.id,
108
+ field: updatedField,
109
+ timestamp: Date.now(),
110
+ },
107
111
  });
108
112
  console.log(`Updated field "${field.name}" on event "${event.name}"`);
109
113
  logUpdates(updates);
@@ -125,10 +129,12 @@ function updateReadModelField(model, filePath, readModelName, fieldName, updates
125
129
  const updatedField = createUpdatedField(field, updates);
126
130
  appendEvent(filePath, {
127
131
  type: 'ReadModelFieldAdjusted',
128
- readModelStickyId: readModel.id,
129
- fieldId: field.id,
130
- field: updatedField,
131
- timestamp: Date.now(),
132
+ data: {
133
+ readModelStickyId: readModel.id,
134
+ fieldId: field.id,
135
+ field: updatedField,
136
+ timestamp: Date.now(),
137
+ },
132
138
  });
133
139
  console.log(`Updated field "${field.name}" on read model "${readModel.name}"`);
134
140
  logUpdates(updates);
@@ -150,10 +156,12 @@ function updateScreenField(model, filePath, screenName, fieldName, updates) {
150
156
  const updatedField = createUpdatedField(field, updates);
151
157
  appendEvent(filePath, {
152
158
  type: 'ScreenFieldAdjusted',
153
- screenId: screen.id,
154
- fieldId: field.id,
155
- field: updatedField,
156
- timestamp: Date.now(),
159
+ data: {
160
+ screenId: screen.id,
161
+ fieldId: field.id,
162
+ field: updatedField,
163
+ timestamp: Date.now(),
164
+ },
157
165
  });
158
166
  console.log(`Updated field "${field.name}" on screen "${screen.name}"`);
159
167
  logUpdates(updates);
@@ -174,10 +182,12 @@ function updateProcessorField(model, filePath, processorName, fieldName, updates
174
182
  const updatedField = createUpdatedField(field, updates);
175
183
  appendEvent(filePath, {
176
184
  type: 'ProcessorFieldAdjusted',
177
- processorId: processor.id,
178
- fieldId: field.id,
179
- field: updatedField,
180
- timestamp: Date.now(),
185
+ data: {
186
+ processorId: processor.id,
187
+ fieldId: field.id,
188
+ field: updatedField,
189
+ timestamp: Date.now(),
190
+ },
181
191
  });
182
192
  console.log(`Updated field "${field.name}" on processor "${processor.name}"`);
183
193
  logUpdates(updates);
@@ -0,0 +1,2 @@
1
+ import type { OutputFormat } from '../../lib/format.js';
2
+ export declare function whoami(format: OutputFormat): void;
@@ -0,0 +1,35 @@
1
+ import { isAuthenticated, getAuthTokens, getBackendUrl, getKeycloakUrl } from '../../lib/config.js';
2
+ import { outputJson, escapeXml } from '../../lib/format.js';
3
+ export function whoami(format) {
4
+ const tokens = getAuthTokens();
5
+ const backendUrl = getBackendUrl();
6
+ const keycloakUrl = getKeycloakUrl();
7
+ if (!tokens) {
8
+ if (format === 'json') {
9
+ outputJson({ authenticated: false, backendUrl, keycloakUrl });
10
+ }
11
+ else {
12
+ console.log(`<auth authenticated="false" backendUrl="${escapeXml(backendUrl)}" keycloakUrl="${escapeXml(keycloakUrl)}"/>`);
13
+ }
14
+ return;
15
+ }
16
+ const isValid = isAuthenticated();
17
+ if (format === 'json') {
18
+ outputJson({
19
+ authenticated: isValid,
20
+ email: tokens.email,
21
+ userId: tokens.userId,
22
+ backendUrl,
23
+ keycloakUrl,
24
+ expiresAt: new Date(tokens.expiresAt).toISOString(),
25
+ });
26
+ }
27
+ else {
28
+ if (isValid) {
29
+ console.log(`<auth authenticated="true" email="${escapeXml(tokens.email)}" backendUrl="${escapeXml(backendUrl)}"/>`);
30
+ }
31
+ else {
32
+ console.log(`<auth authenticated="false" email="${escapeXml(tokens.email)}" backendUrl="${escapeXml(backendUrl)}" reason="token_expired"/>`);
33
+ }
34
+ }
35
+ }
package/dist/types.d.ts CHANGED
@@ -191,6 +191,5 @@ export interface EventModel {
191
191
  }
192
192
  export interface RawEvent {
193
193
  type: string;
194
- timestamp: number;
195
- [key: string]: unknown;
194
+ data: Record<string, unknown>;
196
195
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eventmodeler",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "CLI tool for interacting with Event Model files - query, update, and export event models from the terminal",
5
5
  "type": "module",
6
6
  "bin": {