@izara_project/izara-core-generate-service-code 1.0.61 → 1.0.63

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 (44) hide show
  1. package/package.json +5 -6
  2. package/src/codeGenerators/app/initial_setup/InitialSetupGenerator.js +100 -150
  3. package/src/codeGenerators/app/initial_setup/templates/InitialSetup_LambdaRole.ejs +27 -20
  4. package/src/codeGenerators/app/sls_yaml/FunctionYamlGenerator.js +8 -17
  5. package/src/codeGenerators/app/sls_yaml/RoleNameConfigGenerator.js +13 -72
  6. package/src/codeGenerators/app/sls_yaml/_policy/PolicyEmitter.js +3 -2
  7. package/src/codeGenerators/app/sls_yaml/_policy/__tests__/PolicyEmitter.test.js +3 -3
  8. package/src/codeGenerators/app/sls_yaml/_policy/templates/ManagedPolicy_Yaml.ejs +2 -2
  9. package/src/codeGenerators/app/sls_yaml/templates/SharedResource_Yaml.ejs +1 -1
  10. package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/EndpointsGenerator.js +1 -1
  11. package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/crud/CreateEndpoint_Main.ejs +6 -6
  12. package/src/codeGenerators/app/src/generatedCode/Flow/{FlowSchemas → FlowObjects}/templates/step/FlowEndpointComplete_Main.ejs +78 -69
  13. package/src/codeGenerators/app/src/generatedCode/Flow/FlowRelationships/templates/relationship/ProcessChangeRelationship_Main.ejs +2 -2
  14. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowEndpoint_HdrWbs.ejs +2 -2
  15. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowEndpoint_Main.ejs +8 -4
  16. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowMain_Wbs.ejs +4 -4
  17. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/s3/CreatePreSignUrl_Main.ejs +1 -1
  18. package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/s3/ProcessS3File_Main.ejs +1 -1
  19. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseDsqHandler.js +4 -13
  20. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseSqsHandler.js +14 -15
  21. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncApi.js +4 -13
  22. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncInv.js +4 -13
  23. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/ownTopic.js +16 -4
  24. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrDsq.ejs +79 -63
  25. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrSqs.ejs +62 -50
  26. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowEntryPointBase.js +7 -4
  27. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js +23 -33
  28. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowNaming.js +16 -0
  29. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepBase.js +10 -5
  30. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepNormalizer.js +21 -20
  31. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowValidator.js +1 -13
  32. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/propertyNormalizer.js +20 -0
  33. package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/roleNameDetection.js +49 -0
  34. package/src/codeGenerators/resource/sls_yaml/DynamoDBGenerator.js +1 -10
  35. package/src/codeGenerators/resource/sls_yaml/FlowOutGenerator.js +2 -10
  36. package/src/codeGenerators/resource/sls_yaml/FlowResourceYamlGenerator.js +2 -11
  37. package/src/core/validate.js +9 -5
  38. package/src/generate.js +2 -2
  39. package/src/generateCode.js +21 -0
  40. package/src/schemaGenerators/app/src/schemas/FlowSchemas/FlowSchemaGenerator.js +0 -43
  41. package/test_schema.js +2 -0
  42. package/test_generate.js +0 -7
  43. package/test_normalize.js +0 -17
  44. /package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/templates/{FlowEndpointBeforeLogical_Main.ejs → step/FlowEndpointBeforeLogical_Main.ejs} +0 -0
@@ -39,7 +39,7 @@ const PREFIX = {
39
39
  * @param {*} graphServiceTag
40
40
  * @param {*} errorsFound
41
41
  */
42
- function validateInput(returnValue, status, graphServiceTag, errorsFound) {
42
+ function _validateInput(returnValue, status, graphServiceTag, errorsFound) {
43
43
  if (!Object.prototype.hasOwnProperty.call(returnValue, 'queryResult')) {
44
44
  errorsFound.push(
45
45
  'message is not have property queryResult, should be not happen',
@@ -83,7 +83,7 @@ function validateInput(returnValue, status, graphServiceTag, errorsFound) {
83
83
  /**
84
84
  * @param {*} value
85
85
  */
86
- function isEmpty(value) {
86
+ function _isEmpty(value) {
87
87
  if (value == null) return true;
88
88
 
89
89
  if (
@@ -108,7 +108,7 @@ function isEmpty(value) {
108
108
  * @param {*} returnValue
109
109
  * @returns {object|null}
110
110
  */
111
- function buildExistsNode(returnValue) {
111
+ function _buildExistsNode(returnValue) {
112
112
  const { existsNode } = returnValue.queryResult.return<%- upperCaseFlowTag %>Node;
113
113
  if (!existsNode || !Object.keys(existsNode).length) return null;
114
114
 
@@ -129,7 +129,7 @@ function buildExistsNode(returnValue) {
129
129
  * @param {*} errorsFound
130
130
  * @returns {object}
131
131
  */
132
- function buildMessageObject(returnValue, existsNode, status, errorsFound) {
132
+ function _buildMessageObject(returnValue, existsNode, status, errorsFound) {
133
133
  const { objType } = returnValue.requestParams;
134
134
  const { return<%- upperCaseFlowTag %>Node } = returnValue.queryResult;
135
135
 
@@ -152,15 +152,14 @@ function buildMessageObject(returnValue, existsNode, status, errorsFound) {
152
152
  * @param {*} passBackProperties
153
153
  * @param {*} messageObject
154
154
  */
155
- async function sendSnsMessage(_izContext, passBackProperties, messageObject) {
155
+ async function _sendSnsMessage(_izContext, passBackProperties, messageObject) {
156
156
  const enrichedMessage =
157
157
  callingFlowSharedLib.addParentPassBackPropertiesToSnsResponseMessageObject(
158
158
  passBackProperties,
159
159
  messageObject,
160
160
  );
161
161
  const messageAttributes =
162
- callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttribu
163
- tes(
162
+ callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(
164
163
  passBackProperties,
165
164
  {},
166
165
  );
@@ -211,19 +210,19 @@ export default async function <%- functionName %>(
211
210
  passBackProperties,
212
211
  });
213
212
 
214
- if (isEmpty(returnValue.requestParams)) {
213
+ if (_isEmpty(returnValue.requestParams)) {
215
214
  _izContext.logger.debug('message callingFlowProperties is empty');
216
215
  throw new NoRetryError('message not an object');
217
216
  }
218
217
 
219
- validateInput(returnValue, status, graphServiceTag, errorsFound);
218
+ _validateInput(returnValue, status, graphServiceTag, errorsFound);
220
219
 
221
220
  if (errorsFound.length > 0) {
222
221
  _izContext.logger.debug('Have error form graphServerTag:', errorsFound);
223
222
  errorsFound.push(errorsFound.join(','));
224
223
  }
225
224
 
226
- const existsNode = buildExistsNode(returnValue);
225
+ const existsNode = _buildExistsNode(returnValue);
227
226
 
228
227
  const awaitingStepId = await asyncFlowSharedLib.createAwaitingStepId(
229
228
  parentFlowId,
@@ -231,67 +230,77 @@ export default async function <%- functionName %>(
231
230
  );
232
231
  _izContext.logger.debug('awaitingStepId:', awaitingStepId);
233
232
 
234
- const recordAwaitingSteps = await dynamodbSharedLib.query(
233
+ const recordAwaitingStep = await asyncFlowSharedLib.findPendingStepAwaitingMultipleSteps(
235
234
  _izContext,
236
- await dynamodbSharedLib.tableName(_izContext, 'AwaitingMultipleSteps'),
237
- { awaitingStepId },
235
+ awaitingStepId
238
236
  );
239
- _izContext.logger.debug('record awaitingSteps::', recordAwaitingSteps);
240
-
241
- await Promise.all(
242
- recordAwaitingSteps.Items.map(async (recordAwaitingStep) => {
243
- if (
244
- await asyncFlowSharedLib.checkAllAwaitingStepsFinished(
245
- _izContext,
246
- recordAwaitingStep.pendingStepId,
247
- awaitingStepId,
248
- errorsFound,
249
- )
250
- ) {
251
- _izContext.logger.debug('finish all awaitingStep');
252
-
253
- await Promise.all(
254
- recordAwaitingStep.listOfRecords.map(async (listOfRecords) => {
255
- if (status === 'complete') {
256
- Object.entries(listOfRecords).map(async ([_, record]) => {
257
- await dynamodbSharedLib.putItem(
258
- _izContext,
259
- dynamodbSharedLib.tableName(_izContext,
260
- record.tableName,
261
- record.serviceTag
262
- ),
263
- {
264
- ...record.objInstanceFull.identifiers,
265
- ...record.objInstanceFull.fields
266
- }
267
- );
268
- })
269
- }
270
- }))
271
-
272
- const messageObject = buildMessageObject(
273
- returnValue,
274
- existsNode,
275
- status,
276
- errorsFound,
277
- );
278
-
279
- //(<beforeSendMessage>)
280
- //(</beforeSendMessage>)
281
-
282
- await sendSnsMessage(_izContext, passBackProperties, messageObject);
283
-
284
- //(<afterSendMessage>)
285
- //(</afterSendMessage>)
286
- }
287
-
288
- await asyncFlowSharedLib.removeAwaitingMultipleStep(
289
- _izContext,
290
- awaitingStepId,
291
- recordAwaitingStep.pendingStepId,
292
- errorsFound,
293
- );
294
- }),
237
+ _izContext.logger.debug('recordAwaitingStep:', recordAwaitingStep);
238
+
239
+ const {
240
+ isComplete,
241
+ collectedAttributes,
242
+ collectedErrors,
243
+ returnValues: _rvs,
244
+ additionalAttributes
245
+ } = await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
246
+ _izContext,
247
+ recordAwaitingStep.pendingStepId,
248
+ awaitingStepId,
249
+ errorsFound,
250
+ );
251
+
252
+ _izContext.logger.debug('checkAllAwaitingStepsFinishedWithReturnParams:', {
253
+ isComplete,
254
+ collectedAttributes,
255
+ collectedErrors,
256
+ returnValues: _rvs,
257
+ additionalAttributes
258
+ });
259
+
260
+ if (isComplete) {
261
+ _izContext.logger.debug('finish all awaitingStep');
262
+
263
+ await Promise.all(
264
+ (recordAwaitingStep.listOfRecords ?? []).map(async (listOfRecords) => {
265
+ if (status === 'complete') {
266
+ Object.entries(listOfRecords).map(async ([_, record]) => {
267
+ await dynamodbSharedLib.putItem(
268
+ _izContext,
269
+ dynamodbSharedLib.tableName(_izContext,
270
+ record.tableName,
271
+ record.serviceTag
272
+ ),
273
+ {
274
+ ...record.objInstanceFull.identifiers,
275
+ ...record.objInstanceFull.fields
276
+ }
277
+ );
278
+ });
279
+ }
280
+ })
281
+ );
282
+
283
+ const messageObject = _buildMessageObject(
284
+ returnValue,
285
+ existsNode,
286
+ status,
287
+ errorsFound,
288
+ );
289
+
290
+ //(<beforeSendMessage>)
291
+ //(</beforeSendMessage>)
292
+
293
+ await _sendSnsMessage(_izContext, passBackProperties, messageObject);
294
+
295
+ //(<afterSendMessage>)
296
+ //(</afterSendMessage>)
297
+ }
298
+
299
+ await asyncFlowSharedLib.removeAwaitingMultipleStep(
300
+ _izContext,
301
+ awaitingStepId,
302
+ recordAwaitingStep.pendingStepId,
303
+ errorsFound,
295
304
  );
296
305
 
297
306
  //(<beforeReturn>)
@@ -171,8 +171,8 @@ export default async function <%- functionName %> (
171
171
  const matchToFrom = fromServiceTag === secondServiceTag && fromObjectType === secondObjectType &&
172
172
  toServiceTag === firstServiceTag && toObjType === firstObjectType;
173
173
 
174
- if ((newRelationshipSchema.relationshipDirection === "from" && matchFromTo) ||
175
- (newRelationshipSchema.relationshipDirection === "to" && matchToFrom)) {
174
+ if ((oldRelTypeAndDirection.relationshipDirection === "from" && matchFromTo) ||
175
+ (oldRelTypeAndDirection.relationshipDirection === "to" && matchToFrom)) {
176
176
  checkCorrectLink = true
177
177
  break;
178
178
  }
@@ -27,7 +27,7 @@ const { createFlowTypeConcat } = utils;
27
27
  import { webSocket } from '@izara_project/izara-core-library-external-request';
28
28
  const { postToConnection } = webSocket;
29
29
 
30
- import <%- upperCaseFlowTag %> from './<%- upperCaseFlowTag %>_Main.js';
30
+ import <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> from './<%- typeof mainFileName !== 'undefined' ? mainFileName : `${upperCaseFlowTag}_Main` %>.js';
31
31
 
32
32
  export const main = middleware.wrap(async (event, context) => {
33
33
 
@@ -82,7 +82,7 @@ export const main = middleware.wrap(async (event, context) => {
82
82
  }
83
83
 
84
84
  let callingFlow = eventParams?.callingFlow ? eventParams.callingFlow : {};
85
- await <%- upperCaseFlowTag %>(
85
+ await <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
86
86
  event._izContext,
87
87
  eventParams,
88
88
  //(<additionalParams>)
@@ -56,7 +56,7 @@ const { createFlowTypeConcat } = utils;
56
56
  * @returns {object} description of return value
57
57
  */
58
58
 
59
- export default async function Process<%- upperCaseFlowTag %>(
59
+ export default async function <%- typeof functionName !== 'undefined' ? functionName : `Process${upperCaseFlowTag}` %>(
60
60
  _izContext,
61
61
  requestParams,
62
62
  callingFlowConfig = {},
@@ -65,11 +65,15 @@ export default async function Process<%- upperCaseFlowTag %>(
65
65
  ) {
66
66
 
67
67
  try {
68
- _izContext.logger.debug("Process<%- upperCaseFlowTag %> _izContext", _izContext)
69
- _izContext.logger.debug("Process<%- upperCaseFlowTag %> requestParams", requestParams)
70
- _izContext.logger.debug("Process<%- upperCaseFlowTag %> callingFlowConfig", callingFlowConfig)
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)
71
71
 
72
72
  <% if (typeof flow !== 'undefined' && flow.statusType === 'storedCache') { %>
73
+
74
+ //(<beforeCheckCache>)
75
+ //(</beforeCheckCache>)
76
+
73
77
  let [ cacheMainStatus, cacheMain, cacheExist ] = await storedCacheSharedLib.checkStoredCacheStatus(
74
78
  _izContext,
75
79
  "<%= tableName %>",
@@ -48,7 +48,7 @@ const { postToConnection } = webSocket;
48
48
  * @returns {object} description of return value
49
49
  */
50
50
 
51
- export default async function <%- upperCaseFlowTag %>(
51
+ export default async function <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
52
52
  _izContext,
53
53
  requestParams,
54
54
  //(<additionalParams>)
@@ -57,9 +57,9 @@ export default async function <%- upperCaseFlowTag %>(
57
57
  ) {
58
58
 
59
59
  try {
60
- _izContext.logger.debug("<%- upperCaseFlowTag %> _izContext", _izContext)
61
- _izContext.logger.debug("<%- upperCaseFlowTag %> requestParams", requestParams)
62
- _izContext.logger.debug("<%- upperCaseFlowTag %> callingFlowConfig", callingFlowConfig)
60
+ _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> _izContext", _izContext)
61
+ _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> requestParams", requestParams)
62
+ _izContext.logger.debug("<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> callingFlowConfig", callingFlowConfig)
63
63
 
64
64
  let flowSchema = await getObjectSchema.getFlowSchemaS3WithCache(_izContext, {
65
65
  flowTag: "<%- flowTag %>",
@@ -26,7 +26,7 @@ import { lambda, sns } from '@izara_project/izara-core-library-external-request'
26
26
 
27
27
  import { S3Client } from '@aws-sdk/client-s3';
28
28
  import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
29
- const client = new S3Client({ region: 'us-east-2' });
29
+ const client = new S3Client({ region: process.env.AWS_REGION });
30
30
  import { consts } from '@izara_project/izara-middleware';
31
31
 
32
32
  import { postToConnection, getNestObject } from '../../../../libs/source/GenerateCodeLibs.js'
@@ -16,7 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  */
17
17
 
18
18
  import { S3Client, GetObjectCommand, DeleteObjectCommand, PutObjectCommand, CopyObjectCommand } from '@aws-sdk/client-s3';
19
- const s3 = new S3Client({ region: 'us-east-2' });
19
+ const s3 = new S3Client({ region: process.env.AWS_REGION });
20
20
 
21
21
  //(<optionalRequired>)
22
22
  //(</optionalRequired>)
@@ -1,6 +1,7 @@
1
1
  import ejs from 'ejs';
2
2
  import fs from 'fs/promises';
3
3
  import path from 'path';
4
+ import { normalizePropertyType } from '../shared/propertyNormalizer.js';
4
5
 
5
6
  export async function generateDsqHandler(flow, stepName, suffix, flowOutputDir, mainFileName, templates) {
6
7
  const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
@@ -27,26 +28,16 @@ export async function generateDsqHandler(flow, stepName, suffix, flowOutputDir,
27
28
 
28
29
  let startConfig = null;
29
30
  if (!stepName && flow.flowSteps) {
30
- const startStep = flow.flowSteps.find(s => s.stepName === 'start');
31
+ const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
31
32
  if (startStep) {
32
33
  startConfig = { ...startStep };
33
34
  // Map properties
34
35
  if (startConfig.properties && Array.isArray(startConfig.properties)) {
35
- startConfig.properties = startConfig.properties.map(p => {
36
- if (typeof p === 'string') {
37
- return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
38
- }
39
- return p;
40
- });
36
+ startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
41
37
  }
42
38
  // Map messageAttributes
43
39
  if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
44
- startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
45
- if (typeof p === 'string') {
46
- return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
47
- }
48
- return p;
49
- });
40
+ startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
50
41
  }
51
42
  }
52
43
  }
@@ -1,18 +1,27 @@
1
+ import { isCrudFlow, isRbacFlow, isRelationshipFlow } from '../shared/flowClassifier.js';
2
+ import { ownTopicFunctionName, processFunctionName } from '../shared/flowNaming.js';
1
3
  import ejs from 'ejs';
2
4
  import fs from 'fs/promises';
3
5
  import path from 'path';
6
+ import { normalizePropertyType } from '../shared/propertyNormalizer.js';
4
7
 
5
8
  export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir, mainFileName, templates) {
6
9
  const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
7
10
  const flowTag = flow.flowTag;
8
11
 
12
+ const isOwnTopic = !stepName && !isCrudFlow(flowTag) && !isRbacFlow(flowTag) && !isRelationshipFlow(flowTag) && flow.event && flow.event.includes('ownTopic');
13
+
9
14
  // For entry point stepName is empty
10
- const handlerFileName = stepName ? `${flowTag}${stepName}_${suffix}` : `Process${upperCase(flowTag)}_${suffix}`;
15
+ const handlerFileName = stepName
16
+ ? `${flowTag}${stepName}_${suffix}`
17
+ : (isOwnTopic ? `${upperCase(flowTag)}_${suffix}` : `Process${upperCase(flowTag)}_${suffix}`);
11
18
 
12
19
  // Function name: matches default export in the referenced _Main.js
13
20
  // For entry point: Process${upperCase(flowTag)} (e.g. ProcessOwnTopicFlow)
14
21
  // For steps: ${flowTag}${flowStepName} (e.g. OwnTopicFlowProcess)
15
- const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
22
+ const functionName = stepName
23
+ ? `${flowTag}${stepName}`
24
+ : (isOwnTopic ? ownTopicFunctionName(flowTag) : processFunctionName(flowTag));
16
25
 
17
26
  // Queue name: keep the full handler suffix so handler code matches
18
27
  // the generated queue/resource names.
@@ -30,26 +39,16 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
30
39
 
31
40
  let startConfig = null;
32
41
  if (!stepName && flow.flowSteps) {
33
- const startStep = flow.flowSteps.find(s => s.stepName === 'start');
42
+ const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
34
43
  if (startStep) {
35
44
  startConfig = { ...startStep };
36
45
  // Map properties
37
46
  if (startConfig.properties && Array.isArray(startConfig.properties)) {
38
- startConfig.properties = startConfig.properties.map(p => {
39
- if (typeof p === 'string') {
40
- return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
41
- }
42
- return p;
43
- });
47
+ startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
44
48
  }
45
49
  // Map messageAttributes
46
50
  if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
47
- startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
48
- if (typeof p === 'string') {
49
- return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
50
- }
51
- return p;
52
- });
51
+ startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
53
52
  }
54
53
  }
55
54
  }
@@ -1,6 +1,7 @@
1
1
  import ejs from 'ejs';
2
2
  import fs from 'fs/promises';
3
3
  import path from 'path';
4
+ import { normalizePropertyType } from '../shared/propertyNormalizer.js';
4
5
 
5
6
  export default async function generate(flow, stepName, flowOutputDir, mainFileName, templates) {
6
7
  const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
@@ -15,26 +16,16 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
15
16
 
16
17
  let startConfig = null;
17
18
  if (!stepName && flow.flowSteps) {
18
- const startStep = flow.flowSteps.find(s => s.stepName === 'start');
19
+ const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
19
20
  if (startStep) {
20
21
  startConfig = { ...startStep };
21
22
  // Map properties
22
23
  if (startConfig.properties && Array.isArray(startConfig.properties)) {
23
- startConfig.properties = startConfig.properties.map(p => {
24
- if (typeof p === 'string') {
25
- return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
26
- }
27
- return p;
28
- });
24
+ startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
29
25
  }
30
26
  // Map messageAttributes
31
27
  if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
32
- startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
33
- if (typeof p === 'string') {
34
- return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
35
- }
36
- return p;
37
- });
28
+ startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
38
29
  }
39
30
  }
40
31
  }
@@ -1,6 +1,7 @@
1
1
  import ejs from 'ejs';
2
2
  import fs from 'fs/promises';
3
3
  import path from 'path';
4
+ import { normalizePropertyType } from '../shared/propertyNormalizer.js';
4
5
 
5
6
  export default async function generate(flow, stepName, flowOutputDir, mainFileName, templates) {
6
7
  const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
@@ -15,26 +16,16 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
15
16
 
16
17
  let startConfig = null;
17
18
  if (!stepName && flow.flowSteps) {
18
- const startStep = flow.flowSteps.find(s => s.stepName === 'start');
19
+ const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
19
20
  if (startStep) {
20
21
  startConfig = { ...startStep };
21
22
  // Map properties
22
23
  if (startConfig.properties && Array.isArray(startConfig.properties)) {
23
- startConfig.properties = startConfig.properties.map(p => {
24
- if (typeof p === 'string') {
25
- return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
26
- }
27
- return p;
28
- });
24
+ startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
29
25
  }
30
26
  // Map messageAttributes
31
27
  if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
32
- startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
33
- if (typeof p === 'string') {
34
- return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
35
- }
36
- return p;
37
- });
28
+ startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
38
29
  }
39
30
  }
40
31
  }
@@ -1,4 +1,6 @@
1
1
  import { generateSqsHandler } from './BaseSqsHandler.js';
2
+ import { isCrudFlow, isRbacFlow, isRelationshipFlow } from '../shared/flowClassifier.js';
3
+ import { ownTopicWebSocketMainFileName, ownTopicWebSocketFunctionName } from '../shared/flowNaming.js';
2
4
  import ejs from 'ejs';
3
5
  import fs from 'fs/promises';
4
6
  import path from 'path';
@@ -15,9 +17,18 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
15
17
  // ownTopic flows ALWAYS generate the WebSocket entry + SNS-publish main file,
16
18
  // regardless of initiateBy (legacy behavior: WebSocket is the universal entry point).
17
19
  if (!stepName) {
20
+ const isOwnTopicConvention = !isCrudFlow(flow.flowTag) && !isRbacFlow(flow.flowTag) && !isRelationshipFlow(flow.flowTag);
21
+ let entryPointFileName;
22
+ let wbsFunctionName;
23
+
24
+ if (isOwnTopicConvention) {
25
+ entryPointFileName = ownTopicWebSocketMainFileName(flow.flowTag);
26
+ wbsFunctionName = ownTopicWebSocketFunctionName(flow.flowTag);
27
+ } else {
28
+ entryPointFileName = `${upperCase(flow.flowTag)}_Main`;
29
+ wbsFunctionName = upperCase(flow.flowTag);
30
+ }
18
31
  const handlerFileName = `${upperCase(flow.flowTag)}_HdrWbs`;
19
- const functionName = `${flow.flowTag}Main`;
20
- const entryPointFileName = `${upperCase(flow.flowTag)}_Main`;
21
32
 
22
33
  // 1. Render HdrWbs.js
23
34
  const handlerContent = ejs.render(templates.endpointHdrWbs, {
@@ -25,7 +36,7 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
25
36
  upperCaseFlowTag: upperCase(flow.flowTag),
26
37
  flowStepName: '',
27
38
  mainFileName: entryPointFileName,
28
- functionName: functionName,
39
+ functionName: wbsFunctionName,
29
40
  route: flow.flowTag
30
41
  });
31
42
  await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
@@ -35,7 +46,8 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
35
46
  flowTag: flow.flowTag,
36
47
  upperCaseFlowTag: upperCase(flow.flowTag),
37
48
  topicArn: `${upperCase(flow.flowTag)}_In`,
38
- generateCode: generateCode
49
+ generateCode: generateCode,
50
+ functionName: wbsFunctionName
39
51
  });
40
52
  await fs.writeFile(path.join(flowOutputDir, `${entryPointFileName}.js`), mainContent, 'utf-8');
41
53
  }