@izara_project/izara-core-generate-service-code 1.0.66 → 1.0.67

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 (27) hide show
  1. package/docs/TriggeredCache Flow.drawio +193 -0
  2. package/docs/test.mmd +47 -0
  3. package/docs/test.png +0 -0
  4. package/package.json +2 -2
  5. package/src/compile/loadSchemas.js +23 -1
  6. package/src/emit/crud/emitCrudApplicationArtifacts.js +9 -5
  7. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +5 -5
  8. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +5 -5
  9. package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +25 -4
  10. package/src/emit/crud/templates/FlowHandler_HdrApi.ejs +18 -0
  11. package/src/emit/crud/templates/GetEndpoint_Main.ejs +2 -2
  12. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +10 -8
  13. package/src/emit/custom/customFlows.js +76 -25
  14. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +92 -75
  15. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +4 -4
  16. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_Main.ejs +1 -1
  17. package/src/emit/function/functionYamlArtifact.js +26 -12
  18. package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -7
  19. package/src/emit/relationship/emitRelationshipApplicationArtifacts.js +6 -5
  20. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +2 -2
  21. package/src/emit/resource/emitResourceArtifacts.js +400 -105
  22. package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
  23. package/src/generate.js +2 -2
  24. package/test/crudApplicationArtifacts.test.js +1 -1
  25. package/test/customFlowApplicationArtifacts.test.js +37 -34
  26. package/test/publicApi.test.js +9 -9
  27. package/test/resourceArtifacts.test.js +1 -1
@@ -1,15 +1,25 @@
1
- const SUPPORTED_EVENTS = new Set(['eventBridge', 'extTopic', 'lambdaSyncInv', 'lambdaSyncApi', 'ownTopic', 's3']);
1
+ const SUPPORTED_EVENTS = new Set([
2
+ 'eventBridge',
3
+ 'extTopic',
4
+ 'lambdaSyncInv',
5
+ 'lambdaSyncApi',
6
+ 'ownTopic',
7
+ 's3',
8
+ 'dsq'
9
+ ]);
2
10
 
3
11
  export function supportedCustomFlows(flows) {
4
12
  if (!Array.isArray(flows)) {
5
13
  throw new TypeError('flows must be an array');
6
14
  }
7
- return flows.filter(flow => (
8
- typeof flow?.flowTag === 'string' && flow.flowTag !== '' &&
9
- !flow.generatedCodeConfig &&
10
- Array.isArray(flow.event) &&
11
- flow.event.some(event => SUPPORTED_EVENTS.has(event))
12
- ));
15
+ return flows.filter(
16
+ flow =>
17
+ typeof flow?.flowTag === 'string' &&
18
+ flow.flowTag !== '' &&
19
+ !flow.generatedCodeConfig &&
20
+ Array.isArray(flow.event) &&
21
+ flow.event.some(event => SUPPORTED_EVENTS.has(event))
22
+ );
13
23
  }
14
24
 
15
25
  export function customFlowRoleName(flowTag) {
@@ -24,13 +34,49 @@ export function flowExtTopicSteps(flows) {
24
34
  if (typeof flow?.flowTag !== 'string' || flow.flowTag === '') {
25
35
  return [];
26
36
  }
27
- return (flow.flowSteps ?? []).flatMap(step => (
28
- typeof step?.stepName === 'string' && step.stepName !== '' &&
37
+ return (flow.flowSteps ?? []).flatMap(step =>
38
+ typeof step?.stepName === 'string' &&
39
+ step.stepName !== '' &&
29
40
  step.stepName.toLowerCase() !== 'start' &&
30
- Array.isArray(step.event) && step.event.includes('extTopic')
31
- ? [{ flow, step, flowTag: upperFirst(flow.flowTag), stepName: upperFirst(step.stepName) }]
41
+ Array.isArray(step.event) &&
42
+ step.event.includes('extTopic')
43
+ ? [
44
+ {
45
+ flow,
46
+ step,
47
+ flowTag: upperFirst(flow.flowTag),
48
+ stepName: upperFirst(step.stepName)
49
+ }
50
+ ]
32
51
  : []
33
- ));
52
+ );
53
+ });
54
+ }
55
+
56
+ export function flowDsqSteps(flows) {
57
+ if (!Array.isArray(flows)) {
58
+ throw new TypeError('flows must be an array');
59
+ }
60
+ return flows.flatMap(flow => {
61
+ if (typeof flow?.flowTag !== 'string' || flow.flowTag === '') {
62
+ return [];
63
+ }
64
+ return (flow.flowSteps ?? []).flatMap(step =>
65
+ typeof step?.stepName === 'string' &&
66
+ step.stepName !== '' &&
67
+ step.stepName.toLowerCase() !== 'start' &&
68
+ Array.isArray(step.event) &&
69
+ step.event.includes('dsq')
70
+ ? [
71
+ {
72
+ flow,
73
+ step,
74
+ flowTag: upperFirst(flow.flowTag),
75
+ stepName: upperFirst(step.stepName)
76
+ }
77
+ ]
78
+ : []
79
+ );
34
80
  });
35
81
  }
36
82
 
@@ -38,21 +84,30 @@ export function generatedOwnTopicFlows(flows) {
38
84
  if (!Array.isArray(flows)) {
39
85
  throw new TypeError('flows must be an array');
40
86
  }
41
- return flows.filter(flow => (
42
- typeof flow?.flowTag === 'string' && flow.flowTag !== '' &&
43
- flow.generatedCodeConfig &&
44
- Array.isArray(flow.event) && flow.event.includes('ownTopic')
45
- ));
87
+ return flows.filter(
88
+ flow =>
89
+ typeof flow?.flowTag === 'string' &&
90
+ flow.flowTag !== '' &&
91
+ flow.generatedCodeConfig &&
92
+ Array.isArray(flow.event) &&
93
+ flow.event.includes('ownTopic')
94
+ );
95
+ }
96
+
97
+ export function upperFirst(value) {
98
+ return value[0].toUpperCase() + value.slice(1);
46
99
  }
47
100
 
48
101
  export function triggerCacheFlows(flows) {
49
102
  if (!Array.isArray(flows)) {
50
103
  throw new TypeError('flows must be an array');
51
104
  }
52
- return flows.filter(flow => (
53
- typeof flow?.flowTag === 'string' && flow.flowTag !== '' &&
54
- flow.statusType === 'triggerCache'
55
- ));
105
+ return flows.filter(
106
+ flow =>
107
+ typeof flow?.flowTag === 'string' &&
108
+ flow.flowTag !== '' &&
109
+ flow.statusType === 'triggerCache'
110
+ );
56
111
  }
57
112
 
58
113
  export function triggerCacheQueueNames(flow) {
@@ -64,7 +119,3 @@ export function triggerCacheQueueNames(flow) {
64
119
  `TriggerCache${tag}CompleteHdrDsq`
65
120
  ];
66
121
  }
67
-
68
- export function upperFirst(value) {
69
- return value[0].toUpperCase() + value.slice(1);
70
- }
@@ -8,7 +8,7 @@ import {
8
8
  renderSqsFunctionYaml,
9
9
  renderWbsFunctionYaml
10
10
  } from '../function/functionYamlArtifact.js';
11
- import { customFlowRoleName, flowExtTopicSteps, generatedOwnTopicFlows, supportedCustomFlows, triggerCacheFlows, triggerCacheQueueNames, upperFirst } from './customFlows.js';
11
+ import { customFlowRoleName, flowDsqSteps, flowExtTopicSteps, generatedOwnTopicFlows, supportedCustomFlows, upperFirst } from './customFlows.js';
12
12
 
13
13
  const YAML_PATH = 'app/sls_yaml/generatedCode/source/flow-schema.yml';
14
14
  const TEMPLATE_URL = new URL('../crud/templates/', import.meta.url);
@@ -19,19 +19,19 @@ export async function emitCustomFlowApplicationArtifacts(flows, { systemFunction
19
19
  const customFlows = supportedCustomFlows(flows);
20
20
  const generatedRoots = generatedOwnTopicFlows(flows);
21
21
  const steps = flowExtTopicSteps(flows);
22
- const triggerCache = triggerCacheFlows(flows);
23
- if (customFlows.length === 0 && generatedRoots.length === 0 && steps.length === 0 && triggerCache.length === 0 && systemFunctions.length === 0) return [];
22
+ const dsqSteps = flowDsqSteps(flows);
23
+ if (customFlows.length === 0 && generatedRoots.length === 0 && steps.length === 0 && dsqSteps.length === 0 && systemFunctions.length === 0) return [];
24
24
 
25
25
  const emitted = await Promise.all(customFlows.map(flow => emitFlow(flow, objects)));
26
26
  const roots = await Promise.all(generatedRoots.map(flow => emitOwnTopicRoot(flow, objects)));
27
27
  const stepResults = await Promise.all(steps.map(emitExtTopicStep));
28
- const triggerCacheResults = await Promise.all(triggerCache.map(emitTriggerCacheFlow));
28
+ const dsqStepResults = await Promise.all(dsqSteps.map(emitDsqStep));
29
29
  return [
30
30
  ...emitted.flatMap(result => result.artifacts),
31
31
  ...roots.flatMap(result => result.artifacts),
32
32
  ...stepResults.flatMap(result => result.artifacts),
33
- ...triggerCacheResults.flatMap(result => result.artifacts),
34
- { path: YAML_PATH, content: [...systemFunctions, ...emitted.flatMap(result => result.functions), ...roots.flatMap(result => result.functions), ...stepResults.map(result => result.function), ...triggerCacheResults.flatMap(result => result.functions)].join('\n') }
33
+ ...dsqStepResults.flatMap(result => result.artifacts),
34
+ { path: YAML_PATH, content: [...systemFunctions, ...emitted.flatMap(result => result.functions), ...roots.flatMap(result => result.functions), ...stepResults.flatMap(result => result.functions), ...dsqStepResults.flatMap(result => result.functions)].join('\n') }
35
35
  ];
36
36
  }
37
37
 
@@ -43,61 +43,23 @@ export function customFlowApplicationManagedPaths(flows, { includeYaml = false }
43
43
  const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
44
44
  return [`${source}/${flowTag}${stepName}_Main.js`, `${source}/${flowTag}${stepName}_HdrSqs.js`];
45
45
  }),
46
- ...triggerCacheFlows(flows).flatMap(triggerCachePaths),
47
- ...(supportedCustomFlows(flows).length > 0 || generatedOwnTopicFlows(flows).length > 0 || flowExtTopicSteps(flows).length > 0 || triggerCacheFlows(flows).length > 0 || includeYaml ? [YAML_PATH] : [])
46
+ ...flowDsqSteps(flows).flatMap(({ flowTag, stepName, step }) => {
47
+ const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
48
+ const stepEvents = Array.isArray(step.event) ? step.event : [];
49
+ return [
50
+ ...(stepEvents.includes('extTopic') ? [] : [`${source}/${flowTag}${stepName}_Main.js`]),
51
+ `${source}/${flowTag}${stepName}_HdrDsq.js`
52
+ ];
53
+ }),
54
+ ...(supportedCustomFlows(flows).length > 0 || generatedOwnTopicFlows(flows).length > 0 || flowExtTopicSteps(flows).length > 0 || flowDsqSteps(flows).length > 0 || includeYaml ? [YAML_PATH] : [])
48
55
  ];
49
56
  }
50
57
 
51
- async function emitTriggerCacheFlow(flow) {
52
- const tag = upperFirst(flow.flowTag);
53
- const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
54
- const handlerRoot = `src/generatedCode/FlowSchemas/${tag}/source`;
55
- const roleName = customFlowRoleName(flow.flowTag);
56
- const [processQueue, checkQueue, completeSqsQueue, completeDsqQueue] = triggerCacheQueueNames(flow);
57
- const process = `TriggerCache${tag}`;
58
- const check = `CheckTriggerCache${tag}Complete`;
59
- const complete = `TriggerCache${tag}Complete`;
60
- const handler = (functionName, handlerType) => `${handlerRoot}/${functionName}_${handlerType}.main`;
61
-
62
- return {
63
- artifacts: [
64
- { path: `${source}/${process}_Main.js`, content: await renderCustom('triggerCache/TriggerCache_Main.ejs', { functionName: process }) },
65
- { path: `${source}/${process}_HdrDsq.js`, content: await renderDsq('FlowHandler_HdrDsq.ejs', { functionName: process, mainFileName: `${process}_Main`, queueName: processQueue, startConfig: null }) },
66
- { path: `${source}/${check}_Main.js`, content: await renderCustom('triggerCache/CheckTriggerCache_Main.ejs', { functionName: check, flowTag: flow.flowTag }) },
67
- { path: `${source}/${check}_HdrSqs.js`, content: await renderCustom('triggerCache/CheckTriggerCache_HdrSqs.ejs', { functionName: check, queueName: checkQueue }) },
68
- { path: `${source}/${complete}_Main.js`, content: await renderCustom('triggerCache/TriggerCacheComplete_Main.ejs', { functionName: complete, flowTag: flow.flowTag }) },
69
- { path: `${source}/${complete}_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { functionName: complete, mainFileName: `${complete}_Main`, queueName: completeSqsQueue, startConfig: null, usePassBack: false }) },
70
- { path: `${source}/${complete}_HdrDsq.js`, content: await renderDsq('FlowHandler_HdrDsq.ejs', { functionName: complete, mainFileName: `${complete}_Main`, queueName: completeDsqQueue, startConfig: null, usePassBack: false }) }
71
- ],
72
- functions: [
73
- renderSqsFunctionYaml({ functionName: `${process}HdrDsq`, handlerPath: handler(process, 'HdrDsq'), roleName, queueName: processQueue }),
74
- renderSqsFunctionYaml({ functionName: `${check}HdrSqs`, handlerPath: handler(check, 'HdrSqs'), roleName, queueName: checkQueue }),
75
- renderSqsFunctionYaml({ functionName: `${complete}HdrSqs`, handlerPath: handler(complete, 'HdrSqs'), roleName, queueName: completeSqsQueue }),
76
- renderSqsFunctionYaml({ functionName: `${complete}HdrDsq`, handlerPath: handler(complete, 'HdrDsq'), roleName, queueName: completeDsqQueue })
77
- ]
78
- };
79
- }
80
58
 
81
- function triggerCachePaths(flow) {
82
- const tag = upperFirst(flow.flowTag);
83
- const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
84
- const process = `TriggerCache${tag}`;
85
- const check = `CheckTriggerCache${tag}Complete`;
86
- const complete = `TriggerCache${tag}Complete`;
87
- return [
88
- `${source}/${process}_Main.js`,
89
- `${source}/${process}_HdrDsq.js`,
90
- `${source}/${check}_Main.js`,
91
- `${source}/${check}_HdrSqs.js`,
92
- `${source}/${complete}_Main.js`,
93
- `${source}/${complete}_HdrSqs.js`,
94
- `${source}/${complete}_HdrDsq.js`
95
- ];
96
- }
97
59
 
98
60
  async function emitFlow(flow, objects) {
99
61
  const tag = upperFirst(flow.flowTag);
100
- const process = `Process${tag}`;
62
+ const process = tag;
101
63
  const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
102
64
  const handlerRoot = `src/generatedCode/FlowSchemas/${tag}/source`;
103
65
  const shared = { flowTag: flow.flowTag, flowStepName: '', mainFileName: `${process}_Main`, functionName: process, startConfig: startConfig(flow) };
@@ -106,21 +68,25 @@ async function emitFlow(flow, objects) {
106
68
  : [];
107
69
  const functions = [];
108
70
 
109
- if (flow.event.includes('extTopic')) {
71
+ if (flow.event.includes('extTopic') && !flow.event.includes('ownTopic')) {
110
72
  artifacts.push({ path: `${source}/${process}_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { ...shared, queueName: `${process}HdrSqs` }) });
111
- functions.push(renderSqsFunctionYaml({ functionName: `${process}HdrSqs`, handlerPath: `${handlerRoot}/${process}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName: `${process}HdrSqs` }));
73
+ functions.push(renderSqsFunctionYaml({ functionName: `${process}HdrSqs`, handlerPath: `${handlerRoot}/${process}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName: `${process}HdrSqs`, flowTag: flow.flowTag, flowStepName: '' }));
74
+ }
75
+ if (flow.event.includes('dsq')) {
76
+ artifacts.push({ path: `${source}/${process}_HdrDsq.js`, content: await renderDsq('FlowHandler_HdrDsq.ejs', { ...shared, queueName: `${process}HdrDsq` }) });
77
+ functions.push(renderSqsFunctionYaml({ functionName: `${process}HdrDsq`, handlerPath: `${handlerRoot}/${process}_HdrDsq.main`, roleName: customFlowRoleName(flow.flowTag), queueName: `${process}HdrDsq`, flowTag: flow.flowTag, flowStepName: '' }));
112
78
  }
113
79
  if (flow.event.includes('lambdaSyncInv')) {
114
80
  artifacts.push({ path: `${source}/${process}_HdrInv.js`, content: await render('FlowHandler_HdrInv.ejs', shared) });
115
- functions.push(renderInvFunctionYaml({ functionName: `${process}HdrInv`, handlerPath: `${handlerRoot}/${process}_HdrInv.main`, roleName: customFlowRoleName(flow.flowTag) }));
81
+ functions.push(renderInvFunctionYaml({ functionName: `${process}HdrInv`, handlerPath: `${handlerRoot}/${process}_HdrInv.main`, roleName: customFlowRoleName(flow.flowTag), flowTag: flow.flowTag, flowStepName: '' }));
116
82
  }
117
83
  if (flow.event.includes('lambdaSyncApi')) {
118
84
  artifacts.push({ path: `${source}/${process}_HdrApi.js`, content: await render('FlowHandler_HdrApi.ejs', shared) });
119
- functions.push(renderApiFunctionYaml({ functionName: `${process}HdrApi`, handlerPath: `${handlerRoot}/${process}_HdrApi.main`, roleName: customFlowRoleName(flow.flowTag) }));
85
+ functions.push(renderApiFunctionYaml({ functionName: `${process}HdrApi`, handlerPath: `${handlerRoot}/${process}_HdrApi.main`, roleName: customFlowRoleName(flow.flowTag), flowTag: flow.flowTag, flowStepName: '' }));
120
86
  }
121
87
  if (flow.event.includes('eventBridge')) {
122
88
  artifacts.push({ path: `${source}/${process}_HdrInv.js`, content: await render('FlowHandler_HdrInv.ejs', shared) });
123
- functions.push(renderEventBridgeFunctionYaml({ functionName: `${process}HdrInv`, handlerPath: `${handlerRoot}/${process}_HdrInv.main`, roleName: customFlowRoleName(flow.flowTag), flowTag: tag, schedules: flow.schedules ?? [] }));
89
+ functions.push(renderEventBridgeFunctionYaml({ functionName: `${process}HdrInv`, handlerPath: `${handlerRoot}/${process}_HdrInv.main`, roleName: customFlowRoleName(flow.flowTag), flowTag: flow.flowTag, flowStepName: '', schedules: flow.schedules ?? [] }));
124
90
  }
125
91
  if (flow.event.includes('ownTopic')) {
126
92
  const root = await emitOwnTopicRoot(flow, objects);
@@ -137,10 +103,11 @@ async function emitFlow(flow, objects) {
137
103
 
138
104
  function flowPaths(flow) {
139
105
  const tag = upperFirst(flow.flowTag);
140
- const process = `Process${tag}`;
106
+ const process = tag;
141
107
  const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
142
108
  const paths = needsProcessMain(flow) ? [`${source}/${process}_Main.js`] : [];
143
- if (flow.event.includes('extTopic')) paths.push(`${source}/${process}_HdrSqs.js`);
109
+ if (flow.event.includes('extTopic') && !flow.event.includes('ownTopic')) paths.push(`${source}/${process}_HdrSqs.js`);
110
+ if (flow.event.includes('dsq')) paths.push(`${source}/${process}_HdrDsq.js`);
144
111
  if (flow.event.includes('lambdaSyncInv') || flow.event.includes('eventBridge')) paths.push(`${source}/${process}_HdrInv.js`);
145
112
  if (flow.event.includes('lambdaSyncApi')) paths.push(`${source}/${process}_HdrApi.js`);
146
113
  if (flow.event.includes('ownTopic')) paths.push(...ownTopicRootPaths(flow));
@@ -158,15 +125,65 @@ async function emitExtTopicStep({ flow, step, flowTag, stepName }) {
158
125
  const handlerRoot = `src/generatedCode/FlowSchemas/${flowTag}/source`;
159
126
  const functionName = `${flowTag}${stepName}`;
160
127
  const mainFileName = `${functionName}_Main`;
161
- const queueName = `${functionName}HdrSqs`;
162
128
  const startConfig = stepConfig(flow, step);
163
- return {
164
- artifacts: [
165
- { path: `${source}/${mainFileName}.js`, content: await renderStepMain(functionName) },
166
- { path: `${source}/${functionName}_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { flowTag: flow.flowTag, flowStepName: step.stepName, functionName, mainFileName, startConfig, queueName }) }
167
- ],
168
- function: renderSqsFunctionYaml({ functionName: queueName, handlerPath: `${handlerRoot}/${functionName}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName })
169
- };
129
+
130
+ if (step.checkTriggerType === 'flowType') {
131
+ const completeStep = flow.flowSteps?.find(s => s.checkTriggerType === 'complete');
132
+ const completeStepName = completeStep ? completeStep.stepName : undefined;
133
+ const queueName = `${functionName}HdrSqs`;
134
+ return {
135
+ artifacts: [
136
+ { path: `${source}/${mainFileName}.js`, content: await renderCustom('triggerCache/CheckTriggerCache_Main.ejs', { functionName, flowTag }) },
137
+ { path: `${source}/${functionName}_HdrSqs.js`, content: await renderCustom('triggerCache/CheckTriggerCache_HdrSqs.ejs', { functionName, queueName }) }
138
+ ],
139
+ functions: [renderSqsFunctionYaml({ functionName: queueName, handlerPath: `${handlerRoot}/${functionName}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName, flowTag, flowStepName: step.stepName, targetCompleteStepName: completeStepName })]
140
+ };
141
+ } else if (step.checkTriggerType === 'complete') {
142
+ const queueName = `${functionName}HdrSqs`;
143
+ return {
144
+ artifacts: [
145
+ { path: `${source}/${mainFileName}.js`, content: await renderCustom('triggerCache/TriggerCacheComplete_Main.ejs', { functionName, flowTag }) },
146
+ { path: `${source}/${functionName}_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { flowTag: flow.flowTag, flowStepName: step.stepName, functionName, mainFileName, startConfig, queueName, usePassBack: false }) }
147
+ ],
148
+ functions: [renderSqsFunctionYaml({ functionName: queueName, handlerPath: `${handlerRoot}/${functionName}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName, flowTag, flowStepName: step.stepName })]
149
+ };
150
+ }
151
+
152
+ const artifacts = [{ path: `${source}/${mainFileName}.js`, content: await renderStepMain(functionName) }];
153
+ const functions = [];
154
+
155
+ const stepEvents = Array.isArray(step.event) ? step.event : [];
156
+ const hasSqs = stepEvents.includes('extTopic') || stepEvents.includes('sqs');
157
+
158
+ if (hasSqs) {
159
+ const queueName = `${functionName}HdrSqs`;
160
+ artifacts.push({ path: `${source}/${functionName}_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { flowTag: flow.flowTag, flowStepName: step.stepName, functionName, mainFileName, startConfig, queueName }) });
161
+ functions.push(renderSqsFunctionYaml({ functionName: queueName, handlerPath: `${handlerRoot}/${functionName}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName, flowTag, flowStepName: step.stepName }));
162
+ }
163
+
164
+ return { artifacts, functions };
165
+ }
166
+
167
+ async function emitDsqStep({ flow, step, flowTag, stepName }) {
168
+ const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
169
+ const handlerRoot = `src/generatedCode/FlowSchemas/${flowTag}/source`;
170
+ const functionName = `${flowTag}${stepName}`;
171
+ const mainFileName = `${functionName}_Main`;
172
+ const startConfig = stepConfig(flow, step);
173
+
174
+ const stepEvents = Array.isArray(step.event) ? step.event : [];
175
+ const artifacts = stepEvents.includes('extTopic') ? [] : [{ path: `${source}/${mainFileName}.js`, content: await renderStepMain(functionName) }];
176
+ const functions = [];
177
+
178
+ const hasDsq = stepEvents.includes('dsq');
179
+
180
+ if (hasDsq) {
181
+ const queueName = `${functionName}HdrDsq`;
182
+ artifacts.push({ path: `${source}/${functionName}_HdrDsq.js`, content: await renderDsq('FlowHandler_HdrDsq.ejs', { flowTag: flow.flowTag, flowStepName: step.stepName, functionName, mainFileName, startConfig, queueName }) });
183
+ functions.push(renderSqsFunctionYaml({ functionName: queueName, handlerPath: `${handlerRoot}/${functionName}_HdrDsq.main`, roleName: customFlowRoleName(flow.flowTag), queueName, flowTag, flowStepName: step.stepName }));
184
+ }
185
+
186
+ return { artifacts, functions };
170
187
  }
171
188
 
172
189
  async function emitOwnTopicRoot(flow, objects) {
@@ -184,8 +201,8 @@ async function emitOwnTopicRoot(flow, objects) {
184
201
  { path: `${source}/${tag}_HdrWbs.js`, content: await render('FlowEndpoint_HdrWbs.ejs', { ...shared, functionName: tag, mainFileName: wbsMainFileName, route: tag }) }
185
202
  ],
186
203
  functions: [
187
- renderWbsFunctionYaml({ functionName: `${tag}HdrWbs`, handlerPath: `${handlerRoot}/${tag}_HdrWbs.main`, roleName: customFlowRoleName(flow.flowTag), routeName: tag }),
188
- renderSqsFunctionYaml({ functionName: `${tag}HdrSqs`, handlerPath: `${handlerRoot}/${tag}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName: `${tag}HdrSqs` })
204
+ renderWbsFunctionYaml({ functionName: `${tag}HdrWbs`, handlerPath: `${handlerRoot}/${tag}_HdrWbs.main`, roleName: customFlowRoleName(flow.flowTag), routeName: tag, flowTag: flow.flowTag, flowStepName: '' }),
205
+ renderSqsFunctionYaml({ functionName: `${tag}HdrSqs`, handlerPath: `${handlerRoot}/${tag}_HdrSqs.main`, roleName: customFlowRoleName(flow.flowTag), queueName: `${tag}HdrSqs`, flowTag: flow.flowTag, flowStepName: '' })
189
206
  ]
190
207
  };
191
208
  }
@@ -197,7 +214,7 @@ function ownTopicRootPaths(flow) {
197
214
  }
198
215
 
199
216
  function needsProcessMain(flow) {
200
- return !isS3Only(flow) && flow.event.some(event => event !== 'ownTopic' && event !== 's3');
217
+ return !isS3Only(flow) && !flow.event.includes('ownTopic') && flow.event.some(event => event !== 'ownTopic' && event !== 's3');
201
218
  }
202
219
 
203
220
  async function emitS3Flow(flow, source, handlerRoot) {
@@ -218,10 +235,10 @@ async function emitS3Flow(flow, source, handlerRoot) {
218
235
  const handlerContent = await renderCustom(`s3/${handlerTemplate}`, s3HandlerData({ action, flow, functionName, mainFileName, handler }));
219
236
  const descriptor = { functionName: `${functionName}${handler}`, handlerPath: `${handlerRoot}/${handlerFileName}.main`, roleName };
220
237
  const functionYaml = type === 'wbs'
221
- ? renderWbsFunctionYaml({ ...descriptor, routeName: tag })
238
+ ? renderWbsFunctionYaml({ ...descriptor, routeName: tag, flowTag: flow.flowTag, flowStepName: '' })
222
239
  : type === 'sqs'
223
- ? renderSqsFunctionYaml({ ...descriptor, queueName: handlerFileName })
224
- : renderInvFunctionYaml(descriptor);
240
+ ? renderSqsFunctionYaml({ ...descriptor, queueName: handlerFileName, flowTag: flow.flowTag, flowStepName: '' })
241
+ : renderInvFunctionYaml({ ...descriptor, flowTag: flow.flowTag, flowStepName: '' });
225
242
  return {
226
243
  artifacts: [
227
244
  { path: `${source}/${mainFileName}.js`, content: mainContent },
@@ -56,7 +56,7 @@ const { createFlowTypeConcat } = utils;
56
56
  * @returns {object} description of return value
57
57
  */
58
58
 
59
- export default async function <%- typeof functionName !== 'undefined' ? functionName : `Process${upperCaseFlowTag}` %>(
59
+ export default async function <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
60
60
  _izContext,
61
61
  requestParams,
62
62
  callingFlowConfig = {},
@@ -65,9 +65,9 @@ export default async function <%- typeof functionName !== 'undefined' ? function
65
65
  ) {
66
66
 
67
67
  try {
68
- _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : `Process${upperCaseFlowTag}` %> _izContext", _izContext)
69
- _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : `Process${upperCaseFlowTag}` %> requestParams", requestParams)
70
- _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : `Process${upperCaseFlowTag}` %> callingFlowConfig", callingFlowConfig)
68
+ _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> _izContext", _izContext)
69
+ _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> requestParams", requestParams)
70
+ _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> callingFlowConfig", callingFlowConfig)
71
71
 
72
72
  <% if (typeof flow !== 'undefined' && flow.statusType === 'storedCache') { %>
73
73
 
@@ -39,7 +39,7 @@ export default async function <%- functionName %>(
39
39
  _izContext,
40
40
  { serviceTag: topicName[0], flowTag: topicName[2] },
41
41
  identifiers,
42
- { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag }
42
+ { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag, targetCompleteStep: process.env.iz_targetCompleteStepName }
43
43
  );
44
44
 
45
45
  _izContext.logger.debug(
@@ -1,14 +1,14 @@
1
- export function createSqsFunctionYamlArtifact({ functionName, handlerPath, roleName, queueName, fileName }) {
1
+ export function createSqsFunctionYamlArtifact({ functionName, handlerPath, roleName, queueName, fileName, flowTag, flowStepName, targetCompleteStepName }) {
2
2
  if (![functionName, handlerPath, roleName, queueName, fileName].every(value => typeof value === 'string' && value !== '')) {
3
3
  throw new TypeError('Function descriptor must include functionName, handlerPath, roleName, queueName, and fileName');
4
4
  }
5
5
  return {
6
6
  path: `app/sls_yaml/generatedCode/source/${fileName}`,
7
- content: renderSqsFunctionYaml({ functionName, handlerPath, roleName, queueName })
7
+ content: renderSqsFunctionYaml({ functionName, handlerPath, roleName, queueName, flowTag, flowStepName })
8
8
  };
9
9
  }
10
10
 
11
- export function renderSqsFunctionYaml({ functionName, handlerPath, roleName, queueName }) {
11
+ export function renderSqsFunctionYaml({ functionName, handlerPath, roleName, queueName, flowTag, flowStepName, targetCompleteStepName }) {
12
12
  if (![functionName, handlerPath, roleName, queueName].every(value => typeof value === 'string' && value !== '')) {
13
13
  throw new TypeError('SQS function descriptor must include functionName, handlerPath, roleName, and queueName');
14
14
  }
@@ -16,7 +16,7 @@ export function renderSqsFunctionYaml({ functionName, handlerPath, roleName, que
16
16
  handler: ${handlerPath}
17
17
  name: \${self:custom.iz_resourcePrefix}${functionName}
18
18
  role: ${roleName}
19
- ${functionSetting(functionName)}
19
+ ${environmentSetting(functionName, flowTag, flowStepName, targetCompleteStepName)}${functionSetting(functionName)}
20
20
  events:
21
21
  - sqs:
22
22
  arn: arn:aws:sqs:\${self:custom.iz_region}:\${self:custom.iz_accountId}:\${self:custom.iz_resourcePrefix}${queueName}
@@ -24,7 +24,7 @@ ${functionSetting(functionName)}
24
24
  ${completionFilter(functionName)}`;
25
25
  }
26
26
 
27
- export function renderApiFunctionYaml({ functionName, handlerPath, roleName, routes = [] }) {
27
+ export function renderApiFunctionYaml({ functionName, handlerPath, roleName, routes = [], flowTag, flowStepName }) {
28
28
  if (!Array.isArray(routes)) {
29
29
  throw new TypeError('API function routes must be an array');
30
30
  }
@@ -41,12 +41,12 @@ export function renderApiFunctionYaml({ functionName, handlerPath, roleName, rou
41
41
  handler: ${handlerPath}
42
42
  name: \${self:custom.iz_resourcePrefix}${functionName}
43
43
  role: ${roleName}
44
- ${functionSetting(functionName)}
44
+ ${environmentSetting(functionName, flowTag, flowStepName)}${functionSetting(functionName)}
45
45
  events:
46
46
  ${routeEvents ? `${routeEvents}\n` : ''}`;
47
47
  }
48
48
 
49
- export function renderWbsFunctionYaml({ functionName, handlerPath, roleName, routeName }) {
49
+ export function renderWbsFunctionYaml({ functionName, handlerPath, roleName, routeName, flowTag, flowStepName }) {
50
50
  if (![functionName, handlerPath, roleName, routeName].every(value => typeof value === 'string' && value !== '')) {
51
51
  throw new TypeError('WebSocket function descriptor must include functionName, handlerPath, roleName, and routeName');
52
52
  }
@@ -54,7 +54,7 @@ export function renderWbsFunctionYaml({ functionName, handlerPath, roleName, rou
54
54
  handler: ${handlerPath}
55
55
  name: \${self:custom.iz_resourcePrefix}${functionName}
56
56
  role: ${roleName}
57
- ${functionSetting(functionName)}
57
+ ${environmentSetting(functionName, flowTag, flowStepName)}${functionSetting(functionName)}
58
58
  events:
59
59
  - websocket:
60
60
  route: ${routeName}
@@ -63,16 +63,16 @@ ${functionSetting(functionName)}
63
63
  `;
64
64
  }
65
65
 
66
- export function renderInvFunctionYaml({ functionName, handlerPath, roleName }) {
66
+ export function renderInvFunctionYaml({ functionName, handlerPath, roleName, flowTag, flowStepName }) {
67
67
  return `${functionName}:
68
68
  handler: ${handlerPath}
69
69
  name: \${self:custom.iz_resourcePrefix}${functionName}
70
70
  role: ${roleName}
71
- ${functionSetting(functionName)}
71
+ ${environmentSetting(functionName, flowTag, flowStepName)}${functionSetting(functionName)}
72
72
  `;
73
73
  }
74
74
 
75
- export function renderEventBridgeFunctionYaml({ functionName, handlerPath, roleName, flowTag, schedules = [] }) {
75
+ export function renderEventBridgeFunctionYaml({ functionName, handlerPath, roleName, flowTag, flowStepName, schedules = [] }) {
76
76
  if (![functionName, handlerPath, roleName, flowTag].every(value => typeof value === 'string' && value !== '') || !Array.isArray(schedules)) {
77
77
  throw new TypeError('EventBridge function descriptor must include functionName, handlerPath, roleName, flowTag, and schedules');
78
78
  }
@@ -85,11 +85,25 @@ export function renderEventBridgeFunctionYaml({ functionName, handlerPath, roleN
85
85
  return `\${self:custom.iz_resourcePrefix}${functionName}:
86
86
  handler: ${handlerPath}
87
87
  role: ${roleName}
88
- ${functionSetting(functionName)}
88
+ ${environmentSetting(functionName, flowTag, flowStepName)}${functionSetting(functionName)}
89
89
  description: ${flowTag} (EventBridge Schedule)
90
90
  ${schedules.length === 0 ? '' : ` events:\n${schedules.map(schedule => ` - schedule:\n name: \${self:custom.iz_resourcePrefix}${schedule.name}\n description: '${schedule.description ?? ''}'\n rate: ${schedule.rate?.[0]}\n enabled: true`).join('\n')}\n`}`;
91
91
  }
92
92
 
93
+ function environmentSetting(functionName, flowTag, flowStepName, targetCompleteStepName) {
94
+ if (flowTag === undefined && flowStepName === undefined && targetCompleteStepName === undefined) return '';
95
+ let envs = [];
96
+ if (flowTag !== undefined) envs.push(` iz_flowTag: ${flowTag === '' ? "''" : flowTag}`);
97
+ if (flowStepName !== undefined) envs.push(` iz_flowStepName: ${flowStepName === '' ? "''" : flowStepName}`);
98
+ if (targetCompleteStepName !== undefined) envs.push(` iz_targetCompleteStepName: ${flowTag}${targetCompleteStepName}`);
99
+
100
+ if (envs.length === 0) return '';
101
+ return ` environment:
102
+ ${envs.join('\n')}
103
+ #<#${functionName}Environment#>
104
+ #<#/${functionName}Environment#>\n`;
105
+ }
106
+
93
107
  function functionSetting(functionName) {
94
108
  return ` #<#${functionName}FunctionSetting#>\n #<#/${functionName}FunctionSetting#>`;
95
109
  }
@@ -115,7 +115,9 @@ async function createTargetRoleHandler() {
115
115
  functionName: 'ProcessCreateTargetRoleHdrSqs',
116
116
  handlerPath: 'src/generatedCode/FlowRbac/CreateTargetRole/source/ProcessCreateTargetRole_HdrSqs.main',
117
117
  roleName: 'FlowRbacRole',
118
- queueName: 'ProcessCreateTargetRoleHdrSqs'
118
+ queueName: 'ProcessCreateTargetRoleHdrSqs',
119
+ flowTag: 'CreateTargetRole',
120
+ flowStepName: ''
119
121
  },
120
122
  ...webSocket.functions
121
123
  ]
@@ -137,13 +139,17 @@ async function createListHandler(definition) {
137
139
  functionName: `Process${definition.flowTag}HdrSqs`,
138
140
  handlerPath: `${handlerPath}/Process${definition.flowTag}_HdrSqs.main`,
139
141
  roleName: 'FlowRbacRole',
140
- queueName: `Process${definition.flowTag}HdrSqs`
142
+ queueName: `Process${definition.flowTag}HdrSqs`,
143
+ flowTag: definition.flowTag,
144
+ flowStepName: ''
141
145
  },
142
146
  {
143
147
  type: 'api',
144
148
  functionName: `Process${definition.flowTag}HdrApi`,
145
149
  handlerPath: `${handlerPath}/Process${definition.flowTag}_HdrApi.main`,
146
- roleName: 'FlowRbacRole'
150
+ roleName: 'FlowRbacRole',
151
+ flowTag: definition.flowTag,
152
+ flowStepName: ''
147
153
  }
148
154
  ]
149
155
  };
@@ -165,7 +171,9 @@ async function createMutationHandler(definition) {
165
171
  functionName: `Process${definition.flowTag}HdrSqs`,
166
172
  handlerPath: `${handlerPath}/Process${definition.flowTag}_HdrSqs.main`,
167
173
  roleName: 'FlowRbacRole',
168
- queueName: `Process${definition.flowTag}HdrSqs`
174
+ queueName: `Process${definition.flowTag}HdrSqs`,
175
+ flowTag: definition.flowTag,
176
+ flowStepName: ''
169
177
  },
170
178
  ...webSocket.functions
171
179
  ]
@@ -188,7 +196,9 @@ async function createUserRoleMutationHandler(definition) {
188
196
  functionName: `Process${definition.flowTag}HdrSqs`,
189
197
  handlerPath: `${handlerPath}/Process${definition.flowTag}_HdrSqs.main`,
190
198
  roleName: 'FlowRbacRole',
191
- queueName: `Process${definition.flowTag}HdrSqs`
199
+ queueName: `Process${definition.flowTag}HdrSqs`,
200
+ flowTag: definition.flowTag,
201
+ flowStepName: ''
192
202
  },
193
203
  ...webSocket.functions
194
204
  ]
@@ -208,7 +218,9 @@ async function createUserRbacFlowHandler(object) {
208
218
  type: 'inv',
209
219
  functionName: `Process${flowTag}HdrInv`,
210
220
  handlerPath: `${handlerPath}/Process${flowTag}_HdrInv.main`,
211
- roleName: 'FlowRbacRole'
221
+ roleName: 'FlowRbacRole',
222
+ flowTag: flowTag,
223
+ flowStepName: ''
212
224
  }]
213
225
  };
214
226
  }
@@ -238,7 +250,9 @@ async function createWebSocketEntry(flowTag, sourcePath, handlerPath) {
238
250
  functionName: `${flowTag}HdrWbs`,
239
251
  handlerPath: `${handlerPath}/${flowTag}_HdrWbs.main`,
240
252
  roleName: 'FlowRbacRole',
241
- routeName: flowTag
253
+ routeName: flowTag,
254
+ flowTag: flowTag,
255
+ flowStepName: ''
242
256
  }]
243
257
  };
244
258
  }