@izara_project/izara-core-generate-service-code 1.0.60 → 1.0.62
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.
- package/package.json +11 -8
- package/src/codeGenerators/app/initial_setup/InitialSetupGenerator.js +100 -150
- package/src/codeGenerators/app/initial_setup/templates/InitialSetup_LambdaRole.ejs +27 -20
- package/src/codeGenerators/app/sls_yaml/FunctionYamlGenerator.js +12 -22
- package/src/codeGenerators/app/sls_yaml/RoleNameConfigGenerator.js +13 -72
- package/src/codeGenerators/app/sls_yaml/_policy/PolicyEmitter.js +3 -2
- package/src/codeGenerators/app/sls_yaml/_policy/__tests__/PolicyEmitter.test.js +3 -3
- package/src/codeGenerators/app/sls_yaml/_policy/templates/ManagedPolicy_Yaml.ejs +2 -2
- package/src/codeGenerators/app/sls_yaml/templates/SharedResource_Yaml.ejs +1 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/EndpointsGenerator.js +3 -2
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/RbacFlowGenerator.js +4 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowRelationships/RelationshipFlowGenerator.js +2 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowEndpoint_HdrWbs.ejs +2 -2
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowEndpoint_Main.ejs +8 -4
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/endpoint/FlowMain_Wbs.ejs +4 -4
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/s3/CreatePreSignUrl_Main.ejs +1 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/s3/ProcessS3File_Main.ejs +1 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/templates/step/FlowEndpointComplete_Main.ejs +11 -12
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseDsqHandler.js +55 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseSqsHandler.js +20 -21
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/__tests__/BaseDsqHandler.test.js +93 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/dsq.js +5 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncApi.js +10 -19
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncInv.js +10 -19
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/ownTopic.js +16 -4
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/registry.js +3 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrApi.ejs +3 -3
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrDsq.ejs +137 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrInv.ejs +3 -3
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrSqs.ejs +62 -51
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/eventTypes.js +2 -2
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowEntryPointBase.js +8 -4
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js +28 -36
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowNaming.js +16 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowSelection.js +0 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepBase.js +11 -5
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepNormalizer.js +48 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowValidator.js +7 -21
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/propertyNormalizer.js +20 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/roleNameDetection.js +49 -0
- package/src/codeGenerators/app/src/generatedCode/libs/templates/Consts.ejs +10 -10
- package/src/codeGenerators/resource/sls_yaml/DynamoDBGenerator.js +1 -10
- package/src/codeGenerators/resource/sls_yaml/FlowOutGenerator.js +1 -10
- package/src/codeGenerators/resource/sls_yaml/FlowResourceYamlGenerator.js +3 -12
- package/src/core/validate.js +9 -5
- package/src/generate.js +1 -1
- package/src/generateCode.js +90 -24
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/FlowSchemaGenerator.js +0 -43
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs +3 -3
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicRbacFlowSchemaTemplate.ejs +1 -1
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/RelationshipFlowSchemaTemplate.ejs +2 -2
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/UserRbacFlowSchemaTemplate.ejs +1 -1
|
@@ -35,6 +35,10 @@ export async function generateRbacFlows(allSchemas, options) {
|
|
|
35
35
|
path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrSqs.ejs'),
|
|
36
36
|
'utf-8'
|
|
37
37
|
),
|
|
38
|
+
dsq: await fs.readFile(
|
|
39
|
+
path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrDsq.ejs'),
|
|
40
|
+
'utf-8'
|
|
41
|
+
),
|
|
38
42
|
api: await fs.readFile(
|
|
39
43
|
path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrApi.ejs'),
|
|
40
44
|
'utf-8'
|
package/src/codeGenerators/app/src/generatedCode/Flow/FlowRelationships/RelationshipFlowGenerator.js
CHANGED
|
@@ -25,6 +25,7 @@ export async function generateRelationshipFlows(allSchemas, options) {
|
|
|
25
25
|
// Read standard handler templates for reuse
|
|
26
26
|
const templates = {
|
|
27
27
|
sqs: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrSqs.ejs'), 'utf-8'),
|
|
28
|
+
dsq: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrDsq.ejs'), 'utf-8'),
|
|
28
29
|
api: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrApi.ejs'), 'utf-8'),
|
|
29
30
|
inv: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrInv.ejs'), 'utf-8')
|
|
30
31
|
};
|
|
@@ -98,7 +99,7 @@ export async function generateRelationshipFlows(allSchemas, options) {
|
|
|
98
99
|
generatedCount++;
|
|
99
100
|
} else if (event === 'dsq') {
|
|
100
101
|
handlerFunctionName = `${processFunction}_HdrDsq`;
|
|
101
|
-
handlerContent = ejs.render(templates.sqs, {
|
|
102
|
+
handlerContent = ejs.render(templates.dsq || templates.sqs, {
|
|
102
103
|
flowTag: flowTag,
|
|
103
104
|
flowStepName: '',
|
|
104
105
|
mainFileName: actionFileName,
|
|
@@ -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
|
|
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
|
|
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("
|
|
69
|
-
_izContext.logger.debug("
|
|
70
|
-
_izContext.logger.debug("
|
|
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:
|
|
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:
|
|
19
|
+
const s3 = new S3Client({ region: process.env.AWS_REGION });
|
|
20
20
|
|
|
21
21
|
//(<optionalRequired>)
|
|
22
22
|
//(</optionalRequired>)
|
|
@@ -39,7 +39,7 @@ const PREFIX = {
|
|
|
39
39
|
* @param {*} graphServiceTag
|
|
40
40
|
* @param {*} errorsFound
|
|
41
41
|
*/
|
|
42
|
-
function
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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 (
|
|
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
|
-
|
|
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 =
|
|
225
|
+
const existsNode = _buildExistsNode(returnValue);
|
|
227
226
|
|
|
228
227
|
const awaitingStepId = await asyncFlowSharedLib.createAwaitingStepId(
|
|
229
228
|
parentFlowId,
|
|
@@ -269,7 +268,7 @@ export default async function <%- functionName %>(
|
|
|
269
268
|
}
|
|
270
269
|
}))
|
|
271
270
|
|
|
272
|
-
const messageObject =
|
|
271
|
+
const messageObject = _buildMessageObject(
|
|
273
272
|
returnValue,
|
|
274
273
|
existsNode,
|
|
275
274
|
status,
|
|
@@ -279,7 +278,7 @@ export default async function <%- functionName %>(
|
|
|
279
278
|
//(<beforeSendMessage>)
|
|
280
279
|
//(</beforeSendMessage>)
|
|
281
280
|
|
|
282
|
-
await
|
|
281
|
+
await _sendSnsMessage(_izContext, passBackProperties, messageObject);
|
|
283
282
|
|
|
284
283
|
//(<afterSendMessage>)
|
|
285
284
|
//(</afterSendMessage>)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import ejs from 'ejs';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { normalizePropertyType } from '../shared/propertyNormalizer.js';
|
|
5
|
+
|
|
6
|
+
export async function generateDsqHandler(flow, stepName, suffix, flowOutputDir, mainFileName, templates) {
|
|
7
|
+
const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
8
|
+
const flowTag = flow.flowTag;
|
|
9
|
+
|
|
10
|
+
// For entry point stepName is empty
|
|
11
|
+
const handlerFileName = stepName ? `${flowTag}${stepName}_${suffix}` : `Process${upperCase(flowTag)}_${suffix}`;
|
|
12
|
+
|
|
13
|
+
// Function name: matches default export in the referenced _Main.js
|
|
14
|
+
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
15
|
+
|
|
16
|
+
// Queue name: keep the full handler suffix so handler code matches
|
|
17
|
+
const queueNameSuffix = suffix;
|
|
18
|
+
let queueName = '';
|
|
19
|
+
if (stepName) {
|
|
20
|
+
queueName = `${flowTag}${stepName}${queueNameSuffix}`;
|
|
21
|
+
} else {
|
|
22
|
+
if (flow.event && flow.event.includes('ownTopic')) {
|
|
23
|
+
queueName = `${flowTag}${queueNameSuffix}`;
|
|
24
|
+
} else {
|
|
25
|
+
queueName = `${functionName}${queueNameSuffix}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let startConfig = null;
|
|
30
|
+
if (!stepName && flow.flowSteps) {
|
|
31
|
+
const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
|
|
32
|
+
if (startStep) {
|
|
33
|
+
startConfig = { ...startStep };
|
|
34
|
+
// Map properties
|
|
35
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
36
|
+
startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
|
|
37
|
+
}
|
|
38
|
+
// Map messageAttributes
|
|
39
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
40
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const handlerContent = ejs.render(templates.dsq || templates.sqs, {
|
|
46
|
+
flowTag: flowTag,
|
|
47
|
+
flowStepName: stepName || '',
|
|
48
|
+
mainFileName: mainFileName,
|
|
49
|
+
functionName: functionName,
|
|
50
|
+
queueName: queueName,
|
|
51
|
+
startConfig: startConfig
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
55
|
+
}
|
|
@@ -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
|
|
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
|
|
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.
|
|
@@ -28,28 +37,18 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
|
|
|
28
37
|
}
|
|
29
38
|
}
|
|
30
39
|
|
|
31
|
-
let
|
|
40
|
+
let startConfig = null;
|
|
32
41
|
if (!stepName && flow.flowSteps) {
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
|
|
42
|
+
const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
|
|
43
|
+
if (startStep) {
|
|
44
|
+
startConfig = { ...startStep };
|
|
36
45
|
// Map properties
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
if (typeof p === 'string') {
|
|
40
|
-
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
41
|
-
}
|
|
42
|
-
return p;
|
|
43
|
-
});
|
|
46
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
47
|
+
startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
|
|
44
48
|
}
|
|
45
49
|
// Map messageAttributes
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
if (typeof p === 'string') {
|
|
49
|
-
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
50
|
-
}
|
|
51
|
-
return p;
|
|
52
|
-
});
|
|
50
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
51
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
|
|
53
52
|
}
|
|
54
53
|
}
|
|
55
54
|
}
|
|
@@ -60,7 +59,7 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
|
|
|
60
59
|
mainFileName: mainFileName,
|
|
61
60
|
functionName: functionName,
|
|
62
61
|
queueName: queueName,
|
|
63
|
-
|
|
62
|
+
startConfig: startConfig
|
|
64
63
|
});
|
|
65
64
|
|
|
66
65
|
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { generateDsqHandler } from '../BaseDsqHandler.js';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
describe('generateDsqHandler', () => {
|
|
12
|
+
let tmpDir;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'iz-dsq-handler-'));
|
|
15
|
+
});
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('generates a DSQ handler file containing reformatDsqMessage and setValidatorSchema', async () => {
|
|
21
|
+
// Read the template
|
|
22
|
+
const templatePath = path.join(__dirname, '..', '..', 'handlers', 'FlowHandler_HdrDsq.ejs');
|
|
23
|
+
const dsqTemplate = await fs.readFile(templatePath, 'utf-8');
|
|
24
|
+
const templates = { dsq: dsqTemplate };
|
|
25
|
+
|
|
26
|
+
const mockFlow = {
|
|
27
|
+
flowTag: 'createOrder',
|
|
28
|
+
event: ['dsq']
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
await generateDsqHandler(
|
|
32
|
+
mockFlow,
|
|
33
|
+
'', // entry point
|
|
34
|
+
'HdrDsq', // suffix
|
|
35
|
+
tmpDir, // flowOutputDir
|
|
36
|
+
'ProcessCreateOrder_Main', // mainFileName
|
|
37
|
+
templates
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const generatedFilePath = path.join(tmpDir, 'ProcessCreateOrder_HdrDsq.js');
|
|
41
|
+
const generatedContent = await fs.readFile(generatedFilePath, 'utf-8');
|
|
42
|
+
|
|
43
|
+
// Verify it contains setValidatorSchema on line 39 (approx or exactly depending on formatting, let's verify substring)
|
|
44
|
+
expect(generatedContent).toContain('middleware.setValidatorSchema(recordHandlerSharedLib.baseValidatorSchema(');
|
|
45
|
+
expect(generatedContent).toContain('type: "object"');
|
|
46
|
+
expect(generatedContent).toContain('required: [\'body\', \'messageAttributes\']');
|
|
47
|
+
|
|
48
|
+
// Verify it contains reformatDsqMessage
|
|
49
|
+
expect(generatedContent).toContain('record = recordHandlerSharedLib.reformatDsqMessage(record._izContext, record);');
|
|
50
|
+
expect(generatedContent).toContain('record._izContext.logger.debug(\'record ReceiveMsgOutHdrSqs\', record);');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('generates a DSQ handler for step containing step properties mapping', async () => {
|
|
54
|
+
const templatePath = path.join(__dirname, '..', '..', 'handlers', 'FlowHandler_HdrDsq.ejs');
|
|
55
|
+
const dsqTemplate = await fs.readFile(templatePath, 'utf-8');
|
|
56
|
+
const templates = { dsq: dsqTemplate };
|
|
57
|
+
|
|
58
|
+
const mockFlow = {
|
|
59
|
+
flowTag: 'createOrder',
|
|
60
|
+
event: ['dsq'],
|
|
61
|
+
flowSteps: [
|
|
62
|
+
{
|
|
63
|
+
stepName: 'Start',
|
|
64
|
+
properties: ['orderId'],
|
|
65
|
+
messageAttributes: ['userId']
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
stepProperties: {
|
|
69
|
+
orderId: { propertyName: 'orderId', type: 'string', required: true }
|
|
70
|
+
},
|
|
71
|
+
stepMessageAttributes: {
|
|
72
|
+
userId: { propertyName: 'userId', type: 'string', required: true }
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
await generateDsqHandler(
|
|
77
|
+
mockFlow,
|
|
78
|
+
'StepOne', // step name
|
|
79
|
+
'HdrDsq', // suffix
|
|
80
|
+
tmpDir, // flowOutputDir
|
|
81
|
+
'CreateOrderStepOne_Main', // mainFileName
|
|
82
|
+
templates
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const generatedFilePath = path.join(tmpDir, 'createOrderStepOne_HdrDsq.js');
|
|
86
|
+
const generatedContent = await fs.readFile(generatedFilePath, 'utf-8');
|
|
87
|
+
|
|
88
|
+
// Verify template rendering and function names
|
|
89
|
+
expect(generatedContent).toContain('import createOrderStepOne from \'./CreateOrderStepOne_Main.js\';');
|
|
90
|
+
expect(generatedContent).toContain('createOrderStepOne');
|
|
91
|
+
expect(generatedContent).toContain('"createOrderStepOneHdrDsq"');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -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);
|
|
@@ -13,28 +14,18 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
13
14
|
// Function name matches default export of the referenced _Main.js
|
|
14
15
|
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
15
16
|
|
|
16
|
-
let
|
|
17
|
+
let startConfig = null;
|
|
17
18
|
if (!stepName && flow.flowSteps) {
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
|
|
19
|
+
const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
|
|
20
|
+
if (startStep) {
|
|
21
|
+
startConfig = { ...startStep };
|
|
21
22
|
// Map properties
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
if (typeof p === 'string') {
|
|
25
|
-
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
26
|
-
}
|
|
27
|
-
return p;
|
|
28
|
-
});
|
|
23
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
24
|
+
startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
|
|
29
25
|
}
|
|
30
26
|
// Map messageAttributes
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
if (typeof p === 'string') {
|
|
34
|
-
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
35
|
-
}
|
|
36
|
-
return p;
|
|
37
|
-
});
|
|
27
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
28
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
|
|
38
29
|
}
|
|
39
30
|
}
|
|
40
31
|
}
|
|
@@ -45,7 +36,7 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
45
36
|
mainFileName: mainFileName,
|
|
46
37
|
functionName: functionName,
|
|
47
38
|
queueName: queueName,
|
|
48
|
-
|
|
39
|
+
startConfig: startConfig
|
|
49
40
|
});
|
|
50
41
|
|
|
51
42
|
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
@@ -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);
|
|
@@ -13,28 +14,18 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
13
14
|
// Function name matches default export of the referenced _Main.js
|
|
14
15
|
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
15
16
|
|
|
16
|
-
let
|
|
17
|
+
let startConfig = null;
|
|
17
18
|
if (!stepName && flow.flowSteps) {
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
|
|
19
|
+
const startStep = flow.flowSteps && flow.flowSteps.length > 0 ? flow.flowSteps[0] : null;
|
|
20
|
+
if (startStep) {
|
|
21
|
+
startConfig = { ...startStep };
|
|
21
22
|
// Map properties
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
if (typeof p === 'string') {
|
|
25
|
-
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
26
|
-
}
|
|
27
|
-
return p;
|
|
28
|
-
});
|
|
23
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
24
|
+
startConfig.properties = startConfig.properties.map(p => normalizePropertyType(p, flow.stepProperties));
|
|
29
25
|
}
|
|
30
26
|
// Map messageAttributes
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
if (typeof p === 'string') {
|
|
34
|
-
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
35
|
-
}
|
|
36
|
-
return p;
|
|
37
|
-
});
|
|
27
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
28
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => normalizePropertyType(p, flow.stepMessageAttributes));
|
|
38
29
|
}
|
|
39
30
|
}
|
|
40
31
|
}
|
|
@@ -45,7 +36,7 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
45
36
|
mainFileName: mainFileName,
|
|
46
37
|
functionName: functionName,
|
|
47
38
|
queueName: queueName,
|
|
48
|
-
|
|
39
|
+
startConfig: startConfig
|
|
49
40
|
});
|
|
50
41
|
|
|
51
42
|
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
@@ -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:
|
|
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
|
}
|
|
@@ -4,6 +4,7 @@ import lambdaSyncInv from './lambdaSyncInv.js';
|
|
|
4
4
|
import lambdaSyncApi from './lambdaSyncApi.js';
|
|
5
5
|
import eventBridge from './eventBridge.js';
|
|
6
6
|
import s3 from './s3.js';
|
|
7
|
+
import dsq from './dsq.js';
|
|
7
8
|
|
|
8
9
|
export const EVENT_HANDLERS = {
|
|
9
10
|
ownTopic,
|
|
@@ -11,5 +12,6 @@ export const EVENT_HANDLERS = {
|
|
|
11
12
|
lambdaSyncInv,
|
|
12
13
|
lambdaSyncApi,
|
|
13
14
|
eventBridge,
|
|
14
|
-
s3
|
|
15
|
+
s3,
|
|
16
|
+
dsq
|
|
15
17
|
};
|
package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrApi.ejs
CHANGED
|
@@ -5,14 +5,14 @@ import <%= functionName %> from './<%= mainFileName %>.js';
|
|
|
5
5
|
|
|
6
6
|
const validatorSchema = {
|
|
7
7
|
//(<validatorSchema>)
|
|
8
|
-
<% if (typeof
|
|
8
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.properties && startConfig.properties.length > 0) { -%>
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
|
11
|
-
<%
|
|
11
|
+
<% startConfig.properties.forEach(prop => { -%>
|
|
12
12
|
<%- prop.propertyName %>: { type: '<%- prop.type || 'string' %>' },
|
|
13
13
|
<% }) -%>
|
|
14
14
|
},
|
|
15
|
-
required: [ <%-
|
|
15
|
+
required: [ <%- startConfig.properties.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
16
16
|
<% } -%>
|
|
17
17
|
//(</validatorSchema>)
|
|
18
18
|
};
|