@izara_project/izara-core-generate-service-code 1.0.87 → 1.0.89
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 +1 -1
- package/src/compile/flowValidator.js +25 -0
- package/src/compile/loadSchemas.js +199 -10
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
- package/src/emit/crud/crudActionPlan.js +105 -6
- package/src/emit/crud/emitCrudApplicationArtifacts.js +63 -3
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
- package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +121 -0
- package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +108 -0
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +140 -340
- package/src/emit/crud/templates/CreateLogicalLib.ejs +338 -82
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +90 -0
- package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
- package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +99 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +151 -179
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +244 -27
- package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
- package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +112 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +166 -185
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +123 -3
- package/src/emit/custom/customFlows.js +3 -1
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +8 -2
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +34 -14
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +34 -14
- package/src/emit/resource/emitResourceArtifacts.js +119 -59
- package/test/crudApplicationArtifacts.test.js +876 -0
- package/test/dynamicCrudFlowSchemas.test.js +10 -5
- package/test/dynamicRbacFlowSchemas.test.js +24 -2
- package/test/graphDrivenFlowSchema.test.js +36 -0
- package/test/resourceArtifacts.test.js +271 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izara_project/izara-core-generate-service-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.89",
|
|
4
4
|
"description": "Code for locally generating per service files",
|
|
5
5
|
"homepage": "https://bitbucket.org/izara-core-support-services/izara-core-support-services-generate-service-code#readme",
|
|
6
6
|
"repository": {
|
|
@@ -32,6 +32,31 @@ export function validateFlowSchema(flowSchema) {
|
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
let flowEvents = [];
|
|
36
|
+
if (Array.isArray(flowSchema.event)) {
|
|
37
|
+
flowEvents = flowSchema.event;
|
|
38
|
+
}
|
|
39
|
+
const syncEvents = ['lambdaSyncInv', 'lambdaSyncApi'];
|
|
40
|
+
let hasSyncEvent = false;
|
|
41
|
+
for (const eventName of flowEvents) {
|
|
42
|
+
if (syncEvents.includes(eventName)) {
|
|
43
|
+
hasSyncEvent = true;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (hasSyncEvent && steps.length > 1) {
|
|
49
|
+
let flowTag = 'unknown';
|
|
50
|
+
if (flowSchema.flowTag) {
|
|
51
|
+
flowTag = flowSchema.flowTag;
|
|
52
|
+
}
|
|
53
|
+
throw new Error(
|
|
54
|
+
`FlowSchema validation error: Flow '${flowTag}' with synchronous ` +
|
|
55
|
+
`events ('lambdaSyncInv' | 'lambdaSyncApi') must only define a ` +
|
|
56
|
+
`single entry step 'Start'`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
35
60
|
const entryStep = steps[0];
|
|
36
61
|
if (
|
|
37
62
|
!entryStep ||
|
|
@@ -22,11 +22,66 @@ const VALID_INITIATE_BY_ENUM = [
|
|
|
22
22
|
'systemNoUser'
|
|
23
23
|
];
|
|
24
24
|
|
|
25
|
+
const VALID_CODE_HOOK_TAG_ENUM = ['before', 'after'];
|
|
26
|
+
const VALID_GENERATE_CODE_TAG_ENUM = ['create', 'update', 'delete'];
|
|
27
|
+
|
|
25
28
|
if (basicValidatorSchema?.basicFlowSchema?.properties?.initiateBy) {
|
|
26
29
|
basicValidatorSchema.basicFlowSchema.properties.initiateBy.enum =
|
|
27
30
|
VALID_INITIATE_BY_ENUM;
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
if (
|
|
34
|
+
basicValidatorSchema?.basicFlowSchema?.properties?.generatedCodeConfig
|
|
35
|
+
?.properties?.codeHookTag
|
|
36
|
+
) {
|
|
37
|
+
basicValidatorSchema.basicFlowSchema.properties.generatedCodeConfig.properties.codeHookTag.enum =
|
|
38
|
+
VALID_CODE_HOOK_TAG_ENUM;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (
|
|
42
|
+
basicValidatorSchema?.basicFlowSchema?.properties?.generatedCodeConfig
|
|
43
|
+
?.properties?.generateCodeTag
|
|
44
|
+
) {
|
|
45
|
+
basicValidatorSchema.basicFlowSchema.properties.generatedCodeConfig.properties.generateCodeTag = {
|
|
46
|
+
anyOf: [
|
|
47
|
+
{
|
|
48
|
+
type: 'array',
|
|
49
|
+
items: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
enum: VALID_GENERATE_CODE_TAG_ENUM
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'string',
|
|
56
|
+
enum: VALID_GENERATE_CODE_TAG_ENUM
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
basicValidatorSchema?.basicFlowSchema?.properties?.generatedCodeConfig
|
|
64
|
+
?.properties
|
|
65
|
+
) {
|
|
66
|
+
basicValidatorSchema.basicFlowSchema.properties.generatedCodeConfig.properties.objType = {
|
|
67
|
+
anyOf: [
|
|
68
|
+
{ type: 'string' },
|
|
69
|
+
{
|
|
70
|
+
type: 'array',
|
|
71
|
+
items: { type: 'string' }
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
objectType: { type: 'string' },
|
|
77
|
+
serviceTag: { type: 'string' }
|
|
78
|
+
},
|
|
79
|
+
required: ['objectType']
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
30
85
|
const VALID_GENERATED_BY_ENUM = [
|
|
31
86
|
'user',
|
|
32
87
|
'systemWithUser',
|
|
@@ -113,9 +168,101 @@ export async function loadLocalSchemaDirectory(
|
|
|
113
168
|
if (directoryName === 'FlowSchemas') {
|
|
114
169
|
for (const schema of loadedSchemas) {
|
|
115
170
|
if (Object.prototype.hasOwnProperty.call(schema?.generatedCodeConfig ?? {}, 'codeHookTag')) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
171
|
+
const hookTag = schema.generatedCodeConfig.codeHookTag;
|
|
172
|
+
if (hookTag === 'beforeLogical') {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`Unsupported FlowHook configuration in ${entry.name}: generatedCodeConfig.codeHookTag is no longer supported`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
if (hookTag !== 'before' && hookTag !== 'after') {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Unsupported FlowHook configuration in ${entry.name}: generatedCodeConfig.codeHookTag '${hookTag}' is invalid. Must be 'before' or 'after'`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (
|
|
184
|
+
Object.prototype.hasOwnProperty.call(
|
|
185
|
+
schema?.generatedCodeConfig ?? {},
|
|
186
|
+
'generateCodeTag'
|
|
187
|
+
)
|
|
188
|
+
) {
|
|
189
|
+
const codeTag = schema.generatedCodeConfig.generateCodeTag;
|
|
190
|
+
if (Array.isArray(codeTag)) {
|
|
191
|
+
if (codeTag.length === 0) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
194
|
+
`generatedCodeConfig.generateCodeTag array must not be empty`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
for (const tag of codeTag) {
|
|
198
|
+
if (
|
|
199
|
+
typeof tag !== 'string' ||
|
|
200
|
+
!VALID_GENERATE_CODE_TAG_ENUM.includes(tag.toLowerCase())
|
|
201
|
+
) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
204
|
+
`generatedCodeConfig.generateCodeTag contains invalid ` +
|
|
205
|
+
`tag '${tag}'. Must be 'create', 'update', or 'delete'`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} else if (typeof codeTag === 'string') {
|
|
210
|
+
if (!VALID_GENERATE_CODE_TAG_ENUM.includes(codeTag.toLowerCase())) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
213
|
+
`generatedCodeConfig.generateCodeTag '${codeTag}' ` +
|
|
214
|
+
`is invalid. Must be 'create', 'update', or 'delete'`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
220
|
+
`generatedCodeConfig.generateCodeTag must be an array or string`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (
|
|
225
|
+
Object.prototype.hasOwnProperty.call(
|
|
226
|
+
schema?.generatedCodeConfig ?? {},
|
|
227
|
+
'objType'
|
|
228
|
+
)
|
|
229
|
+
) {
|
|
230
|
+
const hookObjType = schema.generatedCodeConfig.objType;
|
|
231
|
+
if (Array.isArray(hookObjType)) {
|
|
232
|
+
if (hookObjType.length === 0) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
235
|
+
`generatedCodeConfig.objType array must not be empty`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
for (const item of hookObjType) {
|
|
239
|
+
const strVal = typeof item === 'string' ? item : item?.objectType;
|
|
240
|
+
if (!strVal || typeof strVal !== 'string') {
|
|
241
|
+
throw new Error(
|
|
242
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
243
|
+
`generatedCodeConfig.objType array items must be non-empty strings or objects with objectType`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
} else if (typeof hookObjType === 'object' && hookObjType !== null) {
|
|
248
|
+
if (
|
|
249
|
+
!hookObjType.objectType ||
|
|
250
|
+
typeof hookObjType.objectType !== 'string'
|
|
251
|
+
) {
|
|
252
|
+
throw new Error(
|
|
253
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
254
|
+
`generatedCodeConfig.objType object must have string property objectType`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
} else if (
|
|
258
|
+
typeof hookObjType !== 'string' ||
|
|
259
|
+
hookObjType.trim() === ''
|
|
260
|
+
) {
|
|
261
|
+
throw new Error(
|
|
262
|
+
`Unsupported FlowHook configuration in ${entry.name}: ` +
|
|
263
|
+
`generatedCodeConfig.objType must be a non-empty string, array, or object`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
119
266
|
}
|
|
120
267
|
}
|
|
121
268
|
}
|
|
@@ -177,13 +324,55 @@ export async function loadLocalSchemaDirectory(
|
|
|
177
324
|
{ logger },
|
|
178
325
|
schema
|
|
179
326
|
);
|
|
180
|
-
if (!status && Array.isArray(errors)
|
|
181
|
-
|
|
182
|
-
(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
327
|
+
if (!status && Array.isArray(errors)) {
|
|
328
|
+
if (VALID_INITIATE_BY_ENUM.includes(schema?.initiateBy)) {
|
|
329
|
+
errors = errors.filter(
|
|
330
|
+
(err) =>
|
|
331
|
+
!err.includes('initiateBy') &&
|
|
332
|
+
!err.includes('must be equal to one of the allowed values (enum)') &&
|
|
333
|
+
!(err.includes('should be one of enum') && err.includes(schema?.initiateBy))
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
if (
|
|
337
|
+
VALID_CODE_HOOK_TAG_ENUM.includes(
|
|
338
|
+
schema?.generatedCodeConfig?.codeHookTag
|
|
339
|
+
)
|
|
340
|
+
) {
|
|
341
|
+
errors = errors.filter(
|
|
342
|
+
(err) =>
|
|
343
|
+
!err.includes('codeHookTag') &&
|
|
344
|
+
!err.includes('must be equal to one of the allowed values (enum)') &&
|
|
345
|
+
!(
|
|
346
|
+
err.includes('should be one of enum') &&
|
|
347
|
+
err.includes(schema?.generatedCodeConfig?.codeHookTag)
|
|
348
|
+
)
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
const generateCodeTag =
|
|
352
|
+
schema?.generatedCodeConfig?.generateCodeTag;
|
|
353
|
+
let isGenerateCodeTagValid = false;
|
|
354
|
+
if (Array.isArray(generateCodeTag)) {
|
|
355
|
+
isGenerateCodeTagValid =
|
|
356
|
+
generateCodeTag.length > 0 &&
|
|
357
|
+
generateCodeTag.every((t) => {
|
|
358
|
+
return (
|
|
359
|
+
typeof t === 'string' &&
|
|
360
|
+
VALID_GENERATE_CODE_TAG_ENUM.includes(t.toLowerCase())
|
|
361
|
+
);
|
|
362
|
+
});
|
|
363
|
+
} else if (typeof generateCodeTag === 'string') {
|
|
364
|
+
isGenerateCodeTagValid = VALID_GENERATE_CODE_TAG_ENUM.includes(
|
|
365
|
+
generateCodeTag.toLowerCase()
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
if (isGenerateCodeTagValid) {
|
|
369
|
+
errors = errors.filter((err) => {
|
|
370
|
+
return (
|
|
371
|
+
!err.includes('generateCodeTag') &&
|
|
372
|
+
!err.includes('must match a schema in "anyOf"')
|
|
373
|
+
);
|
|
374
|
+
});
|
|
375
|
+
}
|
|
187
376
|
if (errors.length === 0) {
|
|
188
377
|
status = true;
|
|
189
378
|
}
|
|
@@ -181,12 +181,6 @@ const tableConfigs = {
|
|
|
181
181
|
|
|
182
182
|
const currentServiceTag = (typeof serviceTag !== 'undefined' && serviceTag) ? serviceTag : ((typeof project !== 'undefined' && project?.serviceTag) ? project.serviceTag : '');
|
|
183
183
|
const rbacSubs = [];
|
|
184
|
-
if (crud && rbac) {
|
|
185
|
-
if (typeof hasQuotaReservation !== 'undefined' && hasQuotaReservation) {
|
|
186
|
-
rbacSubs.push({ serviceTag: 'Rbac', topicName: 'ConfirmUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
|
|
187
|
-
rbacSubs.push({ serviceTag: 'Rbac', topicName: 'CancelUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
184
|
|
|
191
185
|
if (typeof customRbacFlowTags !== 'undefined' && customRbacFlowTags && customRbacFlowTags.length > 0) {
|
|
192
186
|
const allRbacTags = Array.from(new Set([
|
|
@@ -309,7 +303,9 @@ function roleConfigs() {
|
|
|
309
303
|
Effect: 'Allow',
|
|
310
304
|
Action: ['lambda:InvokeFunction'],
|
|
311
305
|
Resource: [
|
|
312
|
-
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv', 'Rbac')}
|
|
306
|
+
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv', 'Rbac')}`,
|
|
307
|
+
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ConfirmUsageHdrInv', 'Rbac')}`,
|
|
308
|
+
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'CancelUsageHdrInv', 'Rbac')}`<% if (rbac) { %>,
|
|
313
309
|
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv')}`<% } %><% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
314
310
|
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv', '<%= tag %>')}`<% }); %>
|
|
315
311
|
]
|
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
export const CRUD_ACTIONS = ['Create', 'Update', 'Delete', 'Get'];
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function findHooksForAction(flows = [], action) {
|
|
4
|
+
if (!Array.isArray(flows)) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
const actionLower = action?.toLowerCase();
|
|
8
|
+
return flows.filter((flow) => {
|
|
9
|
+
const config = flow?.generatedCodeConfig;
|
|
10
|
+
if (!config) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
const tag = config.generateCodeTag || config.generatedCodeTag;
|
|
14
|
+
if (!tag) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(tag)) {
|
|
18
|
+
return tag.some((t) => {
|
|
19
|
+
return typeof t === 'string' && t.toLowerCase() === actionLower;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (typeof tag === 'string') {
|
|
23
|
+
return tag.toLowerCase() === actionLower;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function createCrudActionPlans(objects = [], flows = []) {
|
|
4
30
|
const hasGraph = hasGraphStorageResource(objects);
|
|
5
31
|
const hasRbac = objects.some(
|
|
6
32
|
(object) => isCrudObject(object) && hasRbacObject(object, objects)
|
|
@@ -12,29 +38,102 @@ export function createCrudActionPlans(objects = []) {
|
|
|
12
38
|
return Object.fromEntries(
|
|
13
39
|
CRUD_ACTIONS.map((action) => [
|
|
14
40
|
action,
|
|
15
|
-
createCrudActionPlan(action, { hasGraph, hasRbac, isBillable })
|
|
41
|
+
createCrudActionPlan(action, { hasGraph, hasRbac, isBillable, flows })
|
|
16
42
|
])
|
|
17
43
|
);
|
|
18
44
|
}
|
|
19
45
|
|
|
46
|
+
export function resolveHookTargetObjectTypes(hook) {
|
|
47
|
+
const config = hook?.generatedCodeConfig;
|
|
48
|
+
const targetObjType = config?.objType ?? config?.objectType;
|
|
49
|
+
if (targetObjType) {
|
|
50
|
+
if (typeof targetObjType === 'string') {
|
|
51
|
+
return [targetObjType];
|
|
52
|
+
}
|
|
53
|
+
if (Array.isArray(targetObjType)) {
|
|
54
|
+
const types = targetObjType
|
|
55
|
+
.map((t) => (typeof t === 'string' ? t : t?.objectType))
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
if (types.length > 0) {
|
|
58
|
+
return types;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (typeof targetObjType === 'object' && targetObjType?.objectType) {
|
|
62
|
+
return [targetObjType.objectType];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (hook?.objType?.objectType) {
|
|
66
|
+
return [hook.objType.objectType];
|
|
67
|
+
}
|
|
68
|
+
if (typeof hook?.objType === 'string') {
|
|
69
|
+
return [hook.objType];
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
20
74
|
export function createCrudActionPlan(
|
|
21
75
|
action,
|
|
22
|
-
{ hasGraph = false, hasRbac = false, isBillable = true } = {}
|
|
76
|
+
{ hasGraph = false, hasRbac = false, isBillable = true, flows = [] } = {}
|
|
23
77
|
) {
|
|
24
78
|
const actionHasRbac = action !== 'Get' && hasRbac;
|
|
25
79
|
const outputTopic = action !== 'Get';
|
|
26
80
|
const hasQuotaReservation = action === 'Create' && hasRbac && isBillable;
|
|
27
81
|
|
|
82
|
+
const actionHooks = findHooksForAction(flows, action).map((h) => ({
|
|
83
|
+
...h,
|
|
84
|
+
targetObjectTypes: resolveHookTargetObjectTypes(h)
|
|
85
|
+
}));
|
|
86
|
+
const beforeHooks = actionHooks.filter(
|
|
87
|
+
(h) => h?.generatedCodeConfig?.codeHookTag === 'before'
|
|
88
|
+
);
|
|
89
|
+
const afterHooks = actionHooks.filter(
|
|
90
|
+
(h) => h?.generatedCodeConfig?.codeHookTag === 'after'
|
|
91
|
+
);
|
|
92
|
+
const hasBeforeHookSync = beforeHooks.some(
|
|
93
|
+
(h) => h?.generatedCodeConfig?.invocationType === 'lambdaSyncInv'
|
|
94
|
+
);
|
|
95
|
+
const hasBeforeHookAsync = beforeHooks.some(
|
|
96
|
+
(h) => h?.generatedCodeConfig?.invocationType === 'ownTopic'
|
|
97
|
+
);
|
|
98
|
+
const hasBeforeHookCallback = outputTopic && hasBeforeHookAsync;
|
|
99
|
+
|
|
100
|
+
const hasAfterHookSync = afterHooks.some(
|
|
101
|
+
(h) => h?.generatedCodeConfig?.invocationType === 'lambdaSyncInv'
|
|
102
|
+
);
|
|
103
|
+
const hasAfterHookAsync = afterHooks.some(
|
|
104
|
+
(h) => h?.generatedCodeConfig?.invocationType === 'ownTopic'
|
|
105
|
+
);
|
|
106
|
+
const hasAfterHookCallback = outputTopic && hasAfterHookAsync;
|
|
107
|
+
|
|
108
|
+
const hasCreateNodeCallback =
|
|
109
|
+
outputTopic &&
|
|
110
|
+
action === 'Create' &&
|
|
111
|
+
actionHasRbac &&
|
|
112
|
+
hasGraph &&
|
|
113
|
+
hasQuotaReservation;
|
|
114
|
+
|
|
115
|
+
const hasComplete =
|
|
116
|
+
outputTopic &&
|
|
117
|
+
!hasCreateNodeCallback &&
|
|
118
|
+
(actionHasRbac || hasGraph || hasAfterHookCallback);
|
|
119
|
+
|
|
28
120
|
return {
|
|
29
121
|
action,
|
|
30
122
|
outputTopic,
|
|
31
123
|
hasGraph: outputTopic && hasGraph,
|
|
32
124
|
hasRbac: actionHasRbac,
|
|
33
125
|
hasQuotaReservation,
|
|
34
|
-
hasComplete
|
|
126
|
+
hasComplete,
|
|
35
127
|
hasRbacCallback: false,
|
|
36
|
-
hasCreateNodeCallback
|
|
37
|
-
|
|
128
|
+
hasCreateNodeCallback,
|
|
129
|
+
hasBeforeHookSync,
|
|
130
|
+
hasBeforeHookAsync,
|
|
131
|
+
hasBeforeHookCallback,
|
|
132
|
+
hasAfterHookSync,
|
|
133
|
+
hasAfterHookAsync,
|
|
134
|
+
hasAfterHookCallback,
|
|
135
|
+
beforeHooks,
|
|
136
|
+
afterHooks
|
|
38
137
|
};
|
|
39
138
|
}
|
|
40
139
|
|
|
@@ -51,7 +51,7 @@ export async function emitCrudApplicationArtifacts({
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const handlers = await Promise.all(
|
|
54
|
-
ACTIONS.map((action) => emitAction(action, objects, serviceTag))
|
|
54
|
+
ACTIONS.map((action) => emitAction(action, objects, serviceTag, flows))
|
|
55
55
|
);
|
|
56
56
|
return [
|
|
57
57
|
...handlers.flatMap((handler) => handler.artifacts),
|
|
@@ -88,6 +88,10 @@ export function crudApplicationManagedPaths() {
|
|
|
88
88
|
`${source}/${action}RbacCallback_HdrSqs.js`,
|
|
89
89
|
`${source}/${action}NodeCallback_Main.js`,
|
|
90
90
|
`${source}/${action}NodeCallback_HdrSqs.js`,
|
|
91
|
+
`${source}/${action}BeforeHookCallback_Main.js`,
|
|
92
|
+
`${source}/${action}BeforeHookCallback_HdrSqs.js`,
|
|
93
|
+
`${source}/${action}AfterHookCallback_Main.js`,
|
|
94
|
+
`${source}/${action}AfterHookCallback_HdrSqs.js`,
|
|
91
95
|
`${source}/${action}Complete_Main.js`,
|
|
92
96
|
`${source}/${action}Complete_HdrSqs.js`
|
|
93
97
|
);
|
|
@@ -98,10 +102,10 @@ export function crudApplicationManagedPaths() {
|
|
|
98
102
|
];
|
|
99
103
|
}
|
|
100
104
|
|
|
101
|
-
async function emitAction(action, objects, serviceTag) {
|
|
105
|
+
async function emitAction(action, objects, serviceTag, flows = []) {
|
|
102
106
|
const source = `app/src/generatedCode/FlowObjects/${action}/source`;
|
|
103
107
|
const handlerRoot = `src/generatedCode/FlowObjects/${action}/source`;
|
|
104
|
-
const plan = createCrudActionPlans(objects)[action];
|
|
108
|
+
const plan = createCrudActionPlans(objects, flows)[action];
|
|
105
109
|
const mainFileName = `${action}_Main`;
|
|
106
110
|
const shared = {
|
|
107
111
|
flowTag: action,
|
|
@@ -326,6 +330,62 @@ async function emitAction(action, objects, serviceTag) {
|
|
|
326
330
|
});
|
|
327
331
|
}
|
|
328
332
|
|
|
333
|
+
if (plan.hasBeforeHookCallback) {
|
|
334
|
+
const beforeHookCallbackMain = `${action}BeforeHookCallback_Main`;
|
|
335
|
+
artifacts.push(
|
|
336
|
+
{
|
|
337
|
+
path: `${source}/${beforeHookCallbackMain}.js`,
|
|
338
|
+
content: await render(`${action}BeforeHookCallback_Main.ejs`, shared)
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
path: `${source}/${action}BeforeHookCallback_HdrSqs.js`,
|
|
342
|
+
content: await renderShared('FlowHandler_HdrSqs.ejs', {
|
|
343
|
+
...shared,
|
|
344
|
+
mainFileName: beforeHookCallbackMain,
|
|
345
|
+
functionName: `${action}BeforeHookCallbackMain`,
|
|
346
|
+
queueName: `${action}BeforeHookCallbackHdrSqs`
|
|
347
|
+
})
|
|
348
|
+
}
|
|
349
|
+
);
|
|
350
|
+
functions.push({
|
|
351
|
+
type: 'sqs',
|
|
352
|
+
functionName: `${action}BeforeHookCallbackHdrSqs`,
|
|
353
|
+
handlerPath: `${handlerRoot}/${action}BeforeHookCallback_HdrSqs.main`,
|
|
354
|
+
roleName: 'FlowObjectsRole',
|
|
355
|
+
queueName: `${action}BeforeHookCallbackHdrSqs`,
|
|
356
|
+
flowTag: action,
|
|
357
|
+
flowStepName: 'BeforeHookCallback'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (plan.hasAfterHookCallback) {
|
|
362
|
+
const afterHookCallbackMain = `${action}AfterHookCallback_Main`;
|
|
363
|
+
artifacts.push(
|
|
364
|
+
{
|
|
365
|
+
path: `${source}/${afterHookCallbackMain}.js`,
|
|
366
|
+
content: await render(`${action}AfterHookCallback_Main.ejs`, shared)
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
path: `${source}/${action}AfterHookCallback_HdrSqs.js`,
|
|
370
|
+
content: await renderShared('FlowHandler_HdrSqs.ejs', {
|
|
371
|
+
...shared,
|
|
372
|
+
mainFileName: afterHookCallbackMain,
|
|
373
|
+
functionName: `${action}AfterHookCallbackMain`,
|
|
374
|
+
queueName: `${action}AfterHookCallbackHdrSqs`
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
functions.push({
|
|
379
|
+
type: 'sqs',
|
|
380
|
+
functionName: `${action}AfterHookCallbackHdrSqs`,
|
|
381
|
+
handlerPath: `${handlerRoot}/${action}AfterHookCallback_HdrSqs.main`,
|
|
382
|
+
roleName: 'FlowObjectsRole',
|
|
383
|
+
queueName: `${action}AfterHookCallbackHdrSqs`,
|
|
384
|
+
flowTag: action,
|
|
385
|
+
flowStepName: 'AfterHookCallback'
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
329
389
|
if (plan.hasComplete) {
|
|
330
390
|
const completeMain = `${action}Complete_Main`;
|
|
331
391
|
let templateName = `${action}Complete_Main.ejs`;
|
|
@@ -72,8 +72,10 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
|
|
|
72
72
|
toStepNames: ['RbacCallback']
|
|
73
73
|
}
|
|
74
74
|
);
|
|
75
|
-
} else if (plan.hasComplete) {
|
|
76
|
-
const nextStepName = plan.hasCreateNodeCallback
|
|
75
|
+
} else if (plan.hasComplete || plan.hasCreateNodeCallback) {
|
|
76
|
+
const nextStepName = plan.hasCreateNodeCallback
|
|
77
|
+
? 'CreateNodeCallback'
|
|
78
|
+
: 'Complete';
|
|
77
79
|
startNextSteps.push({
|
|
78
80
|
targetType: 'ownTopic',
|
|
79
81
|
stepName: nextStepName
|
|
@@ -106,7 +108,9 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
|
|
|
106
108
|
];
|
|
107
109
|
|
|
108
110
|
if (plan.hasRbacCallback) {
|
|
109
|
-
const nextStepName = plan.hasCreateNodeCallback
|
|
111
|
+
const nextStepName = plan.hasCreateNodeCallback
|
|
112
|
+
? 'CreateNodeCallback'
|
|
113
|
+
: 'Complete';
|
|
110
114
|
const rbacNextSteps = [
|
|
111
115
|
{
|
|
112
116
|
targetType: 'ownTopic',
|
|
@@ -162,14 +166,9 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
|
|
|
162
166
|
],
|
|
163
167
|
nextSteps: [
|
|
164
168
|
{
|
|
165
|
-
targetType: '
|
|
166
|
-
stepName: 'Complete'
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
targetType: 'extTopic',
|
|
169
|
+
targetType: 'lambdaSyncInv',
|
|
170
170
|
serviceTag: 'Rbac',
|
|
171
|
-
|
|
172
|
-
toStepNames: ['Complete']
|
|
171
|
+
functionName: 'ConfirmUsageHdrInv'
|
|
173
172
|
}
|
|
174
173
|
],
|
|
175
174
|
properties: [
|
|
@@ -184,9 +183,7 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
|
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
if (plan.hasComplete) {
|
|
187
|
-
const prevStepName = plan.
|
|
188
|
-
? 'CreateNodeCallback'
|
|
189
|
-
: (plan.hasRbacCallback ? 'RbacCallback' : 'Start');
|
|
186
|
+
const prevStepName = plan.hasRbacCallback ? 'RbacCallback' : 'Start';
|
|
190
187
|
|
|
191
188
|
const completePrevSteps = [
|
|
192
189
|
{
|
|
@@ -195,14 +192,7 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
|
|
|
195
192
|
}
|
|
196
193
|
];
|
|
197
194
|
|
|
198
|
-
if (plan.
|
|
199
|
-
completePrevSteps.push({
|
|
200
|
-
sourceType: 'extTopic',
|
|
201
|
-
serviceTag: 'Rbac',
|
|
202
|
-
topicName: 'ConfirmUsage_Out',
|
|
203
|
-
fromStepNames: ['CreateNodeCallback']
|
|
204
|
-
});
|
|
205
|
-
} else if (plan.hasGraph) {
|
|
195
|
+
if (plan.hasGraph) {
|
|
206
196
|
completePrevSteps.push({
|
|
207
197
|
sourceType: 'extTopic',
|
|
208
198
|
serviceTag: 'GraphHandler',
|
|
@@ -215,22 +205,15 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
|
|
|
215
205
|
stepName: 'Complete',
|
|
216
206
|
event: ['extTopic'],
|
|
217
207
|
previousSteps: completePrevSteps,
|
|
218
|
-
properties: plan.
|
|
208
|
+
properties: plan.hasGraph
|
|
219
209
|
? [
|
|
220
210
|
'returnValue',
|
|
221
211
|
'parentFlowId',
|
|
222
212
|
'status',
|
|
223
|
-
'errorsFound'
|
|
213
|
+
'errorsFound',
|
|
214
|
+
'graphServiceTag'
|
|
224
215
|
]
|
|
225
|
-
:
|
|
226
|
-
? [
|
|
227
|
-
'returnValue',
|
|
228
|
-
'parentFlowId',
|
|
229
|
-
'status',
|
|
230
|
-
'errorsFound',
|
|
231
|
-
'graphServiceTag'
|
|
232
|
-
]
|
|
233
|
-
: []),
|
|
216
|
+
: [],
|
|
234
217
|
messageAttributes: MESSAGE_ATTRIBUTES
|
|
235
218
|
});
|
|
236
219
|
}
|