@izara_project/izara-core-generate-service-code 1.0.88 → 1.0.90
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 +154 -0
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
- package/src/emit/crud/crudActionPlan.js +67 -9
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
- package/src/emit/crud/templates/CreateComplete_Main.ejs +135 -10
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +33 -27
- package/src/emit/crud/templates/CreateLogicalLib.ejs +282 -95
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +38 -21
- package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +26 -16
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +113 -4
- package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +34 -22
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +121 -4
- 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/rbac/templates/UserRbacFlow_Main.ejs +20 -13
- package/src/emit/resource/emitResourceArtifacts.js +55 -14
- package/test/createTargetRoleHandler.test.js +11 -8
- package/test/crudApplicationArtifacts.test.js +440 -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 +113 -0
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.90",
|
|
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 ||
|
|
@@ -23,6 +23,7 @@ const VALID_INITIATE_BY_ENUM = [
|
|
|
23
23
|
];
|
|
24
24
|
|
|
25
25
|
const VALID_CODE_HOOK_TAG_ENUM = ['before', 'after'];
|
|
26
|
+
const VALID_GENERATE_CODE_TAG_ENUM = ['create', 'update', 'delete'];
|
|
26
27
|
|
|
27
28
|
if (basicValidatorSchema?.basicFlowSchema?.properties?.initiateBy) {
|
|
28
29
|
basicValidatorSchema.basicFlowSchema.properties.initiateBy.enum =
|
|
@@ -37,6 +38,50 @@ if (
|
|
|
37
38
|
VALID_CODE_HOOK_TAG_ENUM;
|
|
38
39
|
}
|
|
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
|
+
|
|
40
85
|
const VALID_GENERATED_BY_ENUM = [
|
|
41
86
|
'user',
|
|
42
87
|
'systemWithUser',
|
|
@@ -135,6 +180,90 @@ export async function loadLocalSchemaDirectory(
|
|
|
135
180
|
);
|
|
136
181
|
}
|
|
137
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
|
+
}
|
|
266
|
+
}
|
|
138
267
|
}
|
|
139
268
|
}
|
|
140
269
|
|
|
@@ -219,6 +348,31 @@ export async function loadLocalSchemaDirectory(
|
|
|
219
348
|
)
|
|
220
349
|
);
|
|
221
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
|
+
}
|
|
222
376
|
if (errors.length === 0) {
|
|
223
377
|
status = true;
|
|
224
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,12 +1,28 @@
|
|
|
1
1
|
export const CRUD_ACTIONS = ['Create', 'Update', 'Delete', 'Get'];
|
|
2
2
|
|
|
3
3
|
export function findHooksForAction(flows = [], action) {
|
|
4
|
-
if (!Array.isArray(flows))
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
+
}
|
|
8
13
|
const tag = config.generateCodeTag || config.generatedCodeTag;
|
|
9
|
-
|
|
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;
|
|
10
26
|
});
|
|
11
27
|
}
|
|
12
28
|
|
|
@@ -27,6 +43,34 @@ export function createCrudActionPlans(objects = [], flows = []) {
|
|
|
27
43
|
);
|
|
28
44
|
}
|
|
29
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
|
+
|
|
30
74
|
export function createCrudActionPlan(
|
|
31
75
|
action,
|
|
32
76
|
{ hasGraph = false, hasRbac = false, isBillable = true, flows = [] } = {}
|
|
@@ -35,7 +79,10 @@ export function createCrudActionPlan(
|
|
|
35
79
|
const outputTopic = action !== 'Get';
|
|
36
80
|
const hasQuotaReservation = action === 'Create' && hasRbac && isBillable;
|
|
37
81
|
|
|
38
|
-
const actionHooks = findHooksForAction(flows, action)
|
|
82
|
+
const actionHooks = findHooksForAction(flows, action).map((h) => ({
|
|
83
|
+
...h,
|
|
84
|
+
targetObjectTypes: resolveHookTargetObjectTypes(h)
|
|
85
|
+
}));
|
|
39
86
|
const beforeHooks = actionHooks.filter(
|
|
40
87
|
(h) => h?.generatedCodeConfig?.codeHookTag === 'before'
|
|
41
88
|
);
|
|
@@ -58,16 +105,27 @@ export function createCrudActionPlan(
|
|
|
58
105
|
);
|
|
59
106
|
const hasAfterHookCallback = outputTopic && hasAfterHookAsync;
|
|
60
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
|
+
|
|
61
120
|
return {
|
|
62
121
|
action,
|
|
63
122
|
outputTopic,
|
|
64
123
|
hasGraph: outputTopic && hasGraph,
|
|
65
124
|
hasRbac: actionHasRbac,
|
|
66
125
|
hasQuotaReservation,
|
|
67
|
-
hasComplete
|
|
126
|
+
hasComplete,
|
|
68
127
|
hasRbacCallback: false,
|
|
69
|
-
hasCreateNodeCallback
|
|
70
|
-
outputTopic && action === 'Create' && actionHasRbac && hasGraph && hasQuotaReservation,
|
|
128
|
+
hasCreateNodeCallback,
|
|
71
129
|
hasBeforeHookSync,
|
|
72
130
|
hasBeforeHookAsync,
|
|
73
131
|
hasBeforeHookCallback,
|
|
@@ -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
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import asyncFlowSharedLib from '@izara_project/izara-core-library-asynchronous-flow';
|
|
2
2
|
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
3
3
|
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
4
|
+
import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
|
|
4
5
|
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
sns,
|
|
8
|
+
lambda
|
|
9
|
+
} from '@izara_project/izara-core-library-external-request';
|
|
6
10
|
import { consts } from '@izara_project/izara-core-library-service-schemas';
|
|
7
11
|
import { NoRetryError } from '@izara_project/izara-core-library-core';
|
|
8
12
|
|
|
@@ -142,18 +146,138 @@ export default async function CreateComplete(
|
|
|
142
146
|
const callingFlowConfig =
|
|
143
147
|
result?.additionalAttributes?.callingFlowConfig ||
|
|
144
148
|
passBackProperties;
|
|
149
|
+
const actionData = {
|
|
150
|
+
objType: returnValue.requestParams.objType,
|
|
151
|
+
objInstanceFull: node.objInstanceFull,
|
|
152
|
+
relationships: node.relationships,
|
|
153
|
+
parentFlowId: parentFlowId || returnValue?.parentFlowId,
|
|
154
|
+
existsNode,
|
|
155
|
+
status,
|
|
156
|
+
errorsFound
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
<%_ if (plan?.hasAfterHookSync) { _%>
|
|
160
|
+
// ── Synchronous After Hooks ──
|
|
161
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'lambdaSyncInv').forEach(hook => { _%>
|
|
162
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length === 1) { _%>
|
|
163
|
+
if (returnValue.requestParams?.objType?.objectType === '<%= hook.targetObjectTypes[0] %>') {
|
|
164
|
+
<%_ } else if (hook.targetObjectTypes && hook.targetObjectTypes.length > 1) { _%>
|
|
165
|
+
if (<%- JSON.stringify(hook.targetObjectTypes) %>.includes(returnValue.requestParams?.objType?.objectType)) {
|
|
166
|
+
<%_ } _%>
|
|
167
|
+
try {
|
|
168
|
+
let hookPayload_<%= hook.flowTag %> = {
|
|
169
|
+
objType: returnValue.requestParams.objType,
|
|
170
|
+
objInstanceFull: node.objInstanceFull,
|
|
171
|
+
relationships: node.relationships || [],
|
|
172
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
173
|
+
submittedByUserId: returnValue?.requestParams?.submittedByUserId || requestParams?.submittedByUserId
|
|
174
|
+
};
|
|
175
|
+
//(<beforeSendHook_<%= hook.flowTag %>>)
|
|
176
|
+
//(</beforeSendHook_<%= hook.flowTag %>>)
|
|
177
|
+
const hookResult = await lambda.invokeSync(
|
|
178
|
+
_izContext,
|
|
179
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
180
|
+
_izContext,
|
|
181
|
+
'<%= hook.flowTag %>'
|
|
182
|
+
),
|
|
183
|
+
{
|
|
184
|
+
requestParams: hookPayload_<%= hook.flowTag %>,
|
|
185
|
+
callingFlowConfig
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
if (hookResult?.errorsFound?.length > 0 || hookResult?.status === 'error') {
|
|
189
|
+
errorsFound.push(...(hookResult.errorsFound || ['Hook <%= hook.flowTag %> failed']));
|
|
190
|
+
}
|
|
191
|
+
} catch (hookErr) {
|
|
192
|
+
_izContext.logger.error('[CreateComplete] Sync hook <%= hook.flowTag %> error:', hookErr);
|
|
193
|
+
errorsFound.push(hookErr.message || 'Hook <%= hook.flowTag %> failed');
|
|
194
|
+
}
|
|
195
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length > 0) { _%>
|
|
196
|
+
}
|
|
197
|
+
<%_ } _%>
|
|
198
|
+
<%_ }) _%>
|
|
199
|
+
<%_ } _%>
|
|
200
|
+
|
|
201
|
+
<%_ if (plan?.hasAfterHookAsync) { _%>
|
|
202
|
+
// ── Asynchronous After Hooks ──
|
|
203
|
+
let afterHookDispatched = false;
|
|
204
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'ownTopic').forEach(hook => { _%>
|
|
205
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length === 1) { _%>
|
|
206
|
+
if (returnValue.requestParams?.objType?.objectType === '<%= hook.targetObjectTypes[0] %>') {
|
|
207
|
+
<%_ } else if (hook.targetObjectTypes && hook.targetObjectTypes.length > 1) { _%>
|
|
208
|
+
if (<%- JSON.stringify(hook.targetObjectTypes) %>.includes(returnValue.requestParams?.objType?.objectType)) {
|
|
209
|
+
<%_ } _%>
|
|
210
|
+
afterHookDispatched = true;
|
|
211
|
+
let hookPayload_<%= hook.flowTag %> = {
|
|
212
|
+
objType: returnValue.requestParams.objType,
|
|
213
|
+
objInstanceFull: node.objInstanceFull,
|
|
214
|
+
relationships: node.relationships || [],
|
|
215
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
216
|
+
submittedByUserId: returnValue?.requestParams?.submittedByUserId || requestParams?.submittedByUserId
|
|
217
|
+
};
|
|
218
|
+
//(<beforeSendHook_<%= hook.flowTag %>>)
|
|
219
|
+
//(</beforeSendHook_<%= hook.flowTag %>>)
|
|
220
|
+
const hookMsg_<%= hook.flowTag %> = callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
221
|
+
hookPayload_<%= hook.flowTag %>,
|
|
222
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
223
|
+
callingFlowConfig,
|
|
224
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
225
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
226
|
+
_izContext,
|
|
227
|
+
'CreateAfterHookCallbackHdrSqs'
|
|
228
|
+
),
|
|
229
|
+
{
|
|
230
|
+
actionData
|
|
231
|
+
}
|
|
232
|
+
)
|
|
233
|
+
)
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
await sns.publishAsync(_izContext, {
|
|
237
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
238
|
+
_izContext,
|
|
239
|
+
'<%= hook.flowTag %>_In'
|
|
240
|
+
),
|
|
241
|
+
Message: JSON.stringify(hookMsg_<%= hook.flowTag %>),
|
|
242
|
+
MessageAttributes: sns.createStringMessageAttributes(_izContext, {})
|
|
243
|
+
});
|
|
244
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length > 0) { _%>
|
|
245
|
+
}
|
|
246
|
+
<%_ } _%>
|
|
247
|
+
<%_ }) _%>
|
|
248
|
+
if (!afterHookDispatched) {
|
|
249
|
+
const message =
|
|
250
|
+
callingFlowSharedLib.addParentPassBackPropertiesToSnsResponseMessageObject(
|
|
251
|
+
callingFlowConfig,
|
|
252
|
+
actionData
|
|
253
|
+
);
|
|
254
|
+
const messageAttributes =
|
|
255
|
+
callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(
|
|
256
|
+
callingFlowConfig,
|
|
257
|
+
{}
|
|
258
|
+
);
|
|
259
|
+
const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
|
|
260
|
+
_izContext,
|
|
261
|
+
TOPIC_NAME_GENERATE_CODE.outCreateNodeComplete
|
|
262
|
+
);
|
|
263
|
+
_izContext.logger.debug('[CreateComplete] publishing to SNS', {
|
|
264
|
+
TopicArn: topicArn,
|
|
265
|
+
message
|
|
266
|
+
});
|
|
267
|
+
await sns.publishAsync(_izContext, {
|
|
268
|
+
Message: JSON.stringify(message),
|
|
269
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
270
|
+
_izContext,
|
|
271
|
+
messageAttributes
|
|
272
|
+
),
|
|
273
|
+
TopicArn: topicArn
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
<%_ } else { _%>
|
|
145
277
|
const message =
|
|
146
278
|
callingFlowSharedLib.addParentPassBackPropertiesToSnsResponseMessageObject(
|
|
147
279
|
callingFlowConfig,
|
|
148
|
-
|
|
149
|
-
objType: returnValue.requestParams.objType,
|
|
150
|
-
objInstanceFull: node.objInstanceFull,
|
|
151
|
-
relationships: node.relationships,
|
|
152
|
-
parentFlowId: parentFlowId || returnValue?.parentFlowId,
|
|
153
|
-
existsNode,
|
|
154
|
-
status,
|
|
155
|
-
errorsFound
|
|
156
|
-
}
|
|
280
|
+
actionData
|
|
157
281
|
);
|
|
158
282
|
const messageAttributes =
|
|
159
283
|
callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(
|
|
@@ -176,6 +300,7 @@ export default async function CreateComplete(
|
|
|
176
300
|
),
|
|
177
301
|
TopicArn: topicArn
|
|
178
302
|
});
|
|
303
|
+
<%_ } _%>
|
|
179
304
|
//(<afterSendMessage>)
|
|
180
305
|
//(</afterSendMessage>)
|
|
181
306
|
}
|