@izara_project/izara-core-generate-service-code 1.0.83 → 1.0.85

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 (63) hide show
  1. package/package.json +4 -4
  2. package/src/compile/flowValidator.js +13 -2
  3. package/src/compile/loadSchemas.js +116 -7
  4. package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
  5. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +34 -1
  6. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +29 -7
  7. package/src/emit/crud/crudActionPlan.js +41 -6
  8. package/src/emit/crud/emitCrudApplicationArtifacts.js +56 -8
  9. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +153 -27
  10. package/src/emit/crud/generateCrudApplicationArtifacts.js +3 -2
  11. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +3 -2
  12. package/src/emit/crud/loadLocalSchemaArrays.js +3 -3
  13. package/src/emit/crud/templates/CreateComplete_Main.ejs +1 -1
  14. package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
  15. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +252 -154
  16. package/src/emit/crud/templates/CreateLogicalLib.ejs +1163 -236
  17. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
  18. package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
  19. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +33 -8
  20. package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
  21. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
  22. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +79 -10
  23. package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
  24. package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
  25. package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
  26. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +52 -3
  27. package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
  28. package/src/emit/custom/customFlows.js +47 -0
  29. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
  30. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
  31. package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
  32. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
  33. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  34. package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
  35. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
  36. package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
  37. package/src/emit/rbac/templates/CancelUsage_Main.ejs +163 -0
  38. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +187 -0
  39. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +68 -6
  40. package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
  41. package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
  42. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +166 -0
  43. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +84 -23
  44. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +11 -8
  45. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
  46. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +4 -4
  47. package/src/emit/resource/emitResourceArtifacts.js +351 -108
  48. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +3 -1
  49. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +55 -2
  50. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
  51. package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -5
  52. package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
  53. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +6 -0
  54. package/src/emit/systemText/emitSystemTextSchemas.js +1 -1
  55. package/src/generate.js +41 -10
  56. package/test/attributeTreeSchemas.test.js +219 -0
  57. package/test/createTargetRoleHandler.test.js +59 -4
  58. package/test/crudApplicationArtifacts.test.js +20 -3
  59. package/test/customFlowApplicationArtifacts.test.js +5 -5
  60. package/test/dynamicCrudFlowSchemas.test.js +107 -6
  61. package/test/dynamicRbacFlowSchemas.test.js +15 -2
  62. package/test/publicApi.test.js +6 -6
  63. package/test/resourceArtifacts.test.js +89 -27
@@ -70,6 +70,10 @@ const externalServices = {
70
70
  dynamoTableNames.add('RolePermissions');
71
71
  dynamoTableNames.add('RoleUsers');
72
72
  dynamoTableNames.add('UserRoles');
73
+ dynamoTableNames.add('RbacPermissionCaches');
74
+ dynamoTableNames.add('RoleLimit');
75
+ dynamoTableNames.add('RunningTotalUsage');
76
+ dynamoTableNames.add('RunningTotalReservedUsage');
73
77
  }
74
78
  if (typeof s3Flows !== 'undefined' && (s3Flows || []).length > 0) {
75
79
  dynamoTableNames.add('ReservedDataMain');
@@ -127,7 +131,10 @@ const tableConfigs = {
127
131
  const nodeSubs = [];
128
132
  (objectGraphServiceTags || []).forEach(function(tag) {
129
133
  nodeSubs.push({ serviceTag: tag, topicName: 'UpdateNode_Out', sqsEndpoint: 'UpdateCompleteHdrSqs' });
130
- nodeSubs.push({ serviceTag: tag, topicName: 'CreateNode_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
134
+ const createNodeEndpoint = (typeof hasQuotaReservation !== 'undefined' && hasQuotaReservation)
135
+ ? 'CreateNodeCallbackHdrSqs'
136
+ : 'CreateCompleteHdrSqs';
137
+ nodeSubs.push({ serviceTag: tag, topicName: 'CreateNode_Out', sqsEndpoint: createNodeEndpoint });
131
138
  });
132
139
 
133
140
  const customSubs = [];
@@ -173,18 +180,31 @@ const tableConfigs = {
173
180
  });
174
181
 
175
182
  const rbacSubs = [];
176
- if (crud && typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0) {
177
- const allRbacTags = Array.from(new Set(['Rbac', ...rbacValidatorServiceTags]));
183
+ if (crud && rbac) {
184
+ const allRbacTags = Array.from(new Set(['Rbac', ...(typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags ? rbacValidatorServiceTags : [])]));
178
185
  const hasGraph = typeof objectGraphServiceTags !== 'undefined' && objectGraphServiceTags && objectGraphServiceTags.length > 0;
186
+ const createEndpoint = hasGraph ? 'CreateRbacCallbackHdrSqs' : 'CreateCompleteHdrSqs';
179
187
  const updateEndpoint = hasGraph ? 'UpdateRbacCallbackHdrSqs' : 'UpdateCompleteHdrSqs';
180
188
  const deleteEndpoint = hasGraph ? 'DeleteRbacCallbackHdrSqs' : 'DeleteCompleteHdrSqs';
181
189
  allRbacTags.forEach(function(tag) {
182
- if (!hasGraph) {
183
- rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
184
- }
190
+ rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: createEndpoint });
185
191
  rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: updateEndpoint });
186
192
  rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: deleteEndpoint });
187
193
  });
194
+ if (typeof hasQuotaReservation !== 'undefined' && hasQuotaReservation) {
195
+ rbacSubs.push({ serviceTag: 'Rbac', topicName: 'ConfirmUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
196
+ rbacSubs.push({ serviceTag: 'Rbac', topicName: 'CancelUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
197
+ }
198
+ }
199
+
200
+ if (typeof customRbacFlowTags !== 'undefined' && customRbacFlowTags && customRbacFlowTags.length > 0) {
201
+ const allRbacTags = Array.from(new Set(['Rbac', ...(typeof rbacValidatorServiceTags !== 'undefined' ? rbacValidatorServiceTags : [])]));
202
+ customRbacFlowTags.forEach(function(flowTag) {
203
+ const tagUpper = flowTag[0].toUpperCase() + flowTag.slice(1);
204
+ allRbacTags.forEach(function(tag) {
205
+ rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: `${tagUpper}RbacCallbackHdrSqs` });
206
+ });
207
+ });
188
208
  }
189
209
  -%>
190
210
  const snsTopicSubscriptions = [
@@ -294,7 +314,9 @@ function roleConfigs() {
294
314
  Effect: 'Allow',
295
315
  Action: ['sns:Publish'],
296
316
  Resource: [
297
- `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
317
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
318
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', 'Rbac')}`,
319
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
298
320
  `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
299
321
  ]
300
322
  },
@@ -5,36 +5,43 @@ export function createCrudActionPlans(objects = []) {
5
5
  const hasRbac = objects.some(
6
6
  (object) => isCrudObject(object) && hasRbacObject(object, objects)
7
7
  );
8
+ const isBillable = objects.some(
9
+ (object) => isCrudObject(object) && isBillableObject(object, objects)
10
+ );
8
11
 
9
12
  return Object.fromEntries(
10
13
  CRUD_ACTIONS.map((action) => [
11
14
  action,
12
- createCrudActionPlan(action, { hasGraph, hasRbac })
15
+ createCrudActionPlan(action, { hasGraph, hasRbac, isBillable })
13
16
  ])
14
17
  );
15
18
  }
16
19
 
17
20
  export function createCrudActionPlan(
18
21
  action,
19
- { hasGraph = false, hasRbac = false } = {}
22
+ { hasGraph = false, hasRbac = false, isBillable = true } = {}
20
23
  ) {
21
- const actionHasRbac = action !== 'Create' && action !== 'Get' && hasRbac;
24
+ const actionHasRbac = action !== 'Get' && hasRbac;
22
25
  const outputTopic = action !== 'Get';
26
+ const hasQuotaReservation = action === 'Create' && hasRbac && isBillable;
23
27
 
24
28
  return {
25
29
  action,
26
30
  outputTopic,
27
31
  hasGraph: outputTopic && hasGraph,
28
32
  hasRbac: actionHasRbac,
33
+ hasQuotaReservation,
29
34
  hasComplete: outputTopic && (actionHasRbac || hasGraph),
30
- hasRbacCallback: outputTopic && actionHasRbac && hasGraph
35
+ hasRbacCallback: outputTopic && actionHasRbac && hasGraph,
36
+ hasCreateNodeCallback:
37
+ outputTopic && action === 'Create' && actionHasRbac && hasGraph && hasQuotaReservation
31
38
  };
32
39
  }
33
40
 
34
- const VALID_CRUD_GENERATED_BY = new Set([
41
+ export const VALID_CRUD_GENERATED_BY = new Set([
35
42
  'user',
36
43
  'systemWithUser',
37
- 'systemWithNoUser'
44
+ 'systemNoUser'
38
45
  ]);
39
46
 
40
47
  export function isCrudObject(object) {
@@ -83,3 +90,31 @@ function normalizeBelongTo(object) {
83
90
  if (!object?.belongTo) return [];
84
91
  return Array.isArray(object.belongTo) ? object.belongTo : [object.belongTo];
85
92
  }
93
+
94
+ export function isBillableObject(object, objects = []) {
95
+ if (!isCrudObject(object)) return false;
96
+
97
+ const targets = normalizeBelongTo(object);
98
+ if (targets.length > 0) {
99
+ for (const target of targets) {
100
+ if (typeof target?.billable === 'boolean') {
101
+ return target.billable;
102
+ }
103
+ }
104
+ }
105
+
106
+ if (Array.isArray(object?.addOnDataStructure)) {
107
+ const rbacAddOn = object.addOnDataStructure.find(
108
+ (addOn) => addOn?.type === 'rbac'
109
+ );
110
+ if (typeof rbacAddOn?.billable === 'boolean') {
111
+ return rbacAddOn.billable;
112
+ }
113
+ }
114
+
115
+ if (typeof object?.billable === 'boolean') {
116
+ return object.billable;
117
+ }
118
+
119
+ return true;
120
+ }
@@ -11,7 +11,8 @@ import {
11
11
  import {
12
12
  CRUD_ACTIONS,
13
13
  createCrudActionPlans,
14
- isCrudObject
14
+ isCrudObject,
15
+ VALID_CRUD_GENERATED_BY
15
16
  } from './crudActionPlan.js';
16
17
 
17
18
  const ACTIONS = CRUD_ACTIONS;
@@ -22,12 +23,26 @@ const SHARED_TEMPLATE_URL = new URL('../shared/templates/', import.meta.url);
22
23
  export async function emitCrudApplicationArtifacts({
23
24
  objects,
24
25
  flows = [],
25
- serviceTag
26
+ serviceTag,
27
+ logger
26
28
  }) {
27
29
  if (!Array.isArray(objects) || !Array.isArray(flows)) {
28
30
  throw new TypeError('objects and flows must be arrays');
29
31
  }
30
- if (!objects.some(isCrudObject)) return [];
32
+ if (!objects.some(isCrudObject)) {
33
+ if (objects.length > 0) {
34
+ const summary = objects.map((obj) => ({
35
+ objectType: obj?.objectType ?? '(undefined)',
36
+ generatedBy: obj?.generatedBy ?? '(missing)'
37
+ }));
38
+ logger?.warn?.(
39
+ `[WARN] [CRUD Application] Skipped FlowObjects application artifacts generation: No valid CRUD ObjectSchema found. ` +
40
+ `Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
41
+ `Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
42
+ );
43
+ }
44
+ return [];
45
+ }
31
46
 
32
47
  const handlers = await Promise.all(
33
48
  ACTIONS.map((action) => emitAction(action, objects, serviceTag))
@@ -65,6 +80,8 @@ export function crudApplicationManagedPaths() {
65
80
  `${source}/${action}_HdrWbs.js`,
66
81
  `${source}/${action}RbacCallback_Main.js`,
67
82
  `${source}/${action}RbacCallback_HdrSqs.js`,
83
+ `${source}/${action}NodeCallback_Main.js`,
84
+ `${source}/${action}NodeCallback_HdrSqs.js`,
68
85
  `${source}/${action}Complete_Main.js`,
69
86
  `${source}/${action}Complete_HdrSqs.js`
70
87
  );
@@ -87,7 +104,7 @@ async function emitAction(action, objects, serviceTag) {
87
104
  flow: null,
88
105
  flowStepName: '',
89
106
  startConfig: null,
90
- objects: action === 'Create' ? [] : objects,
107
+ objects: objects,
91
108
  isCrudObject,
92
109
  hasRbacAddOn: (object) => hasRbacAddOn(object, objects),
93
110
  plan
@@ -275,12 +292,43 @@ async function emitAction(action, objects, serviceTag) {
275
292
  });
276
293
  }
277
294
 
295
+ if (plan.hasCreateNodeCallback) {
296
+ const nodeCallbackMain = `${action}NodeCallback_Main`;
297
+ artifacts.push(
298
+ {
299
+ path: `${source}/${nodeCallbackMain}.js`,
300
+ content: await render(`${action}NodeCallback_Main.ejs`, shared)
301
+ },
302
+ {
303
+ path: `${source}/${nodeCallbackMain.replace('_Main', '_HdrSqs')}.js`,
304
+ content: await renderShared('FlowHandler_HdrSqs.ejs', {
305
+ ...shared,
306
+ mainFileName: nodeCallbackMain,
307
+ functionName: `${action}NodeCallbackMain`,
308
+ queueName: `${action}NodeCallbackHdrSqs`
309
+ })
310
+ }
311
+ );
312
+ functions.push({
313
+ type: 'sqs',
314
+ functionName: `${action}NodeCallbackHdrSqs`,
315
+ handlerPath: `${handlerRoot}/${action}NodeCallback_HdrSqs.main`,
316
+ roleName: 'FlowObjectsRole',
317
+ queueName: `${action}NodeCallbackHdrSqs`,
318
+ flowTag: action,
319
+ flowStepName: 'CreateNodeCallback'
320
+ });
321
+ }
322
+
278
323
  if (plan.hasComplete) {
279
324
  const completeMain = `${action}Complete_Main`;
280
- const templateName =
281
- plan.hasRbac && !plan.hasGraph
282
- ? 'FlowEndpointRbacCallback_Main.ejs'
283
- : `${action}Complete_Main.ejs`;
325
+ let templateName = `${action}Complete_Main.ejs`;
326
+ if (plan.hasRbac && !plan.hasGraph) {
327
+ templateName = 'FlowEndpointRbacCallback_Main.ejs';
328
+ } else if (plan.hasCreateNodeCallback) {
329
+ templateName = 'CreateConfirmComplete_Main.ejs';
330
+ }
331
+
284
332
  const templateContext =
285
333
  plan.hasRbac && !plan.hasGraph
286
334
  ? shared
@@ -3,7 +3,8 @@ import {
3
3
  CRUD_ACTIONS,
4
4
  createCrudActionPlans,
5
5
  hasGraphStorageResource,
6
- isCrudObject
6
+ isCrudObject,
7
+ VALID_CRUD_GENERATED_BY
7
8
  } from './crudActionPlan.js';
8
9
 
9
10
  const MESSAGE_ATTRIBUTES = ['userId', 'correlationId'];
@@ -13,37 +14,77 @@ export const dynamicCrudFlowSchemaPaths = CRUD_ACTIONS.map(
13
14
  `app/src/schemas/FlowSchemas/generateCode/FlowObjects/${action}.js`
14
15
  );
15
16
 
16
- export function emitDynamicCrudFlowSchemas({ objects, flows = [], serviceTag }) {
17
+ export function emitDynamicCrudFlowSchemas({
18
+ objects,
19
+ flows = [],
20
+ serviceTag,
21
+ logger
22
+ }) {
17
23
  if (!Array.isArray(objects) || !Array.isArray(flows)) {
18
24
  throw new TypeError('objects and flows must be arrays');
19
25
  }
20
- if (!objects.some(isCrudObject)) return [];
26
+ if (!objects.some(isCrudObject)) {
27
+ if (objects.length > 0) {
28
+ const summary = objects.map((obj) => ({
29
+ objectType: obj?.objectType ?? '(undefined)',
30
+ generatedBy: obj?.generatedBy ?? '(missing)'
31
+ }));
32
+ logger?.warn?.(
33
+ `[WARN] [CRUD FlowSchemas] Skipped FlowObjects FlowSchemas generation: No valid CRUD ObjectSchema found. ` +
34
+ `Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
35
+ `Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
36
+ );
37
+ }
38
+ return [];
39
+ }
21
40
 
22
41
  const plans = createCrudActionPlans(objects);
42
+ const primaryObject = objects.find(isCrudObject);
43
+ const initiateBy = primaryObject?.generatedBy || 'user';
23
44
 
24
45
  return CRUD_ACTIONS.map((action, index) => ({
25
46
  path: dynamicCrudFlowSchemaPaths[index],
26
47
  content: renderDynamicCrudFlowSchema(
27
48
  action,
28
- _createDynamicFlow(action, plans[action], serviceTag)
49
+ _createDynamicFlow(action, plans[action], serviceTag, initiateBy)
29
50
  )
30
51
  }));
31
52
  }
32
53
 
33
- function _createDynamicFlow(action, plan, serviceTag = '') {
54
+ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user') {
55
+ const startNextSteps = [];
56
+ if (plan.hasRbacCallback) {
57
+ startNextSteps.push(
58
+ {
59
+ targetType: 'ownTopic',
60
+ stepName: 'RbacCallback'
61
+ },
62
+ {
63
+ targetType: 'extTopic',
64
+ serviceTag: 'Rbac',
65
+ topicName: 'ValidatorRbac_In',
66
+ toStepNames: ['RbacCallback']
67
+ }
68
+ );
69
+ } else if (plan.hasComplete) {
70
+ startNextSteps.push({
71
+ targetType: 'ownTopic',
72
+ stepName: 'Complete'
73
+ });
74
+ if (plan.hasGraph) {
75
+ startNextSteps.push({
76
+ targetType: 'extTopic',
77
+ serviceTag: 'GraphHandler',
78
+ topicName: `${action}Node_In`,
79
+ toStepNames: ['Complete']
80
+ });
81
+ }
82
+ }
83
+
34
84
  const flowSteps = [
35
85
  {
36
86
  stepName: 'Start',
37
- ...(plan.hasRbacCallback || plan.hasComplete
38
- ? {
39
- nextSteps: [
40
- {
41
- targetType: 'ownTopic',
42
- stepName: plan.hasRbacCallback ? 'RbacCallback' : 'Complete'
43
- }
44
- ]
45
- }
46
- : {}),
87
+ ...(startNextSteps.length > 0 ? { nextSteps: startNextSteps } : {}),
47
88
  properties: [],
48
89
  messageAttributes: MESSAGE_ATTRIBUTES,
49
90
  ...(plan.outputTopic
@@ -58,6 +99,22 @@ function _createDynamicFlow(action, plan, serviceTag = '') {
58
99
  ];
59
100
 
60
101
  if (plan.hasRbacCallback) {
102
+ const nextStepName = plan.hasCreateNodeCallback ? 'CreateNodeCallback' : 'Complete';
103
+ const rbacNextSteps = [
104
+ {
105
+ targetType: 'ownTopic',
106
+ stepName: nextStepName
107
+ }
108
+ ];
109
+ if (plan.hasGraph) {
110
+ rbacNextSteps.push({
111
+ targetType: 'extTopic',
112
+ serviceTag: 'GraphHandler',
113
+ topicName: `${action}Node_In`,
114
+ toStepNames: [nextStepName]
115
+ });
116
+ }
117
+
61
118
  flowSteps.push({
62
119
  stepName: 'RbacCallback',
63
120
  event: ['extTopic'],
@@ -65,45 +122,114 @@ function _createDynamicFlow(action, plan, serviceTag = '') {
65
122
  {
66
123
  sourceType: 'ownTopic',
67
124
  stepName: 'Start'
125
+ },
126
+ {
127
+ sourceType: 'extTopic',
128
+ serviceTag: 'Rbac',
129
+ topicName: 'ValidatorRbac_Out',
130
+ fromStepNames: ['Start']
131
+ }
132
+ ],
133
+ nextSteps: rbacNextSteps,
134
+ properties: [],
135
+ messageAttributes: MESSAGE_ATTRIBUTES
136
+ });
137
+ }
138
+
139
+ if (plan.hasCreateNodeCallback) {
140
+ flowSteps.push({
141
+ stepName: 'CreateNodeCallback',
142
+ event: ['extTopic'],
143
+ previousSteps: [
144
+ {
145
+ sourceType: 'ownTopic',
146
+ stepName: 'RbacCallback'
147
+ },
148
+ {
149
+ sourceType: 'extTopic',
150
+ serviceTag: 'GraphHandler',
151
+ topicName: 'CreateNode_Out',
152
+ fromStepNames: ['RbacCallback']
68
153
  }
69
154
  ],
70
155
  nextSteps: [
71
156
  {
72
157
  targetType: 'ownTopic',
73
158
  stepName: 'Complete'
159
+ },
160
+ {
161
+ targetType: 'extTopic',
162
+ serviceTag: 'Rbac',
163
+ topicName: 'ConfirmUsage_In',
164
+ toStepNames: ['Complete']
74
165
  }
75
166
  ],
76
- properties: [],
167
+ properties: [
168
+ 'returnValue',
169
+ 'parentFlowId',
170
+ 'status',
171
+ 'errorsFound',
172
+ 'graphServiceTag'
173
+ ],
77
174
  messageAttributes: MESSAGE_ATTRIBUTES
78
175
  });
79
176
  }
80
177
 
81
178
  if (plan.hasComplete) {
179
+ const prevStepName = plan.hasCreateNodeCallback
180
+ ? 'CreateNodeCallback'
181
+ : (plan.hasRbacCallback ? 'RbacCallback' : 'Start');
182
+
183
+ const completePrevSteps = [
184
+ {
185
+ sourceType: 'ownTopic',
186
+ stepName: prevStepName
187
+ }
188
+ ];
189
+
190
+ if (plan.hasCreateNodeCallback) {
191
+ completePrevSteps.push({
192
+ sourceType: 'extTopic',
193
+ serviceTag: 'Rbac',
194
+ topicName: 'ConfirmUsage_Out',
195
+ fromStepNames: ['CreateNodeCallback']
196
+ });
197
+ } else if (plan.hasGraph) {
198
+ completePrevSteps.push({
199
+ sourceType: 'extTopic',
200
+ serviceTag: 'GraphHandler',
201
+ topicName: `${action}Node_Out`,
202
+ fromStepNames: [prevStepName]
203
+ });
204
+ }
205
+
82
206
  flowSteps.push({
83
207
  stepName: 'Complete',
84
208
  event: ['extTopic'],
85
- previousSteps: [
86
- {
87
- sourceType: 'ownTopic',
88
- stepName: plan.hasRbacCallback ? 'RbacCallback' : 'Start'
89
- }
90
- ],
91
- properties: plan.hasGraph
209
+ previousSteps: completePrevSteps,
210
+ properties: plan.hasCreateNodeCallback
92
211
  ? [
93
212
  'returnValue',
94
213
  'parentFlowId',
95
214
  'status',
96
- 'errorsFound',
97
- 'graphServiceTag'
215
+ 'errorsFound'
98
216
  ]
99
- : [],
217
+ : (plan.hasGraph
218
+ ? [
219
+ 'returnValue',
220
+ 'parentFlowId',
221
+ 'status',
222
+ 'errorsFound',
223
+ 'graphServiceTag'
224
+ ]
225
+ : []),
100
226
  messageAttributes: MESSAGE_ATTRIBUTES
101
227
  });
102
228
  }
103
229
 
104
230
  return {
105
231
  flowTag: action,
106
- initiateBy: 'systemWithNoUser',
232
+ initiateBy,
107
233
  handleObj: 'one',
108
234
  statusType: 'none',
109
235
  event: plan.outputTopic ? ['ownTopic'] : ['lambdaSyncInv', 'lambdaSyncApi'],
@@ -9,10 +9,11 @@ import {
9
9
 
10
10
  export async function generateCrudApplicationArtifacts(rootPath, options = {}) {
11
11
  const project = compileProject({ ...options, rootPath });
12
- const schemas = await loadLocalSchemaArrays(project);
12
+ const schemas = await loadLocalSchemaArrays(project, options);
13
13
  const artifacts = await emitCrudApplicationArtifacts({
14
14
  ...schemas,
15
- serviceTag: project.serviceTag
15
+ serviceTag: project.serviceTag,
16
+ logger: options.logger
16
17
  });
17
18
  const files = await commitArtifacts(
18
19
  buildGenerationPlan(project, artifacts, {
@@ -9,12 +9,13 @@ import { loadLocalSchemaArrays } from './loadLocalSchemaArrays.js';
9
9
 
10
10
  export async function generateDynamicCrudFlowSchemas(rootPath, options = {}) {
11
11
  const project = compileProject({ ...options, rootPath });
12
- const schemaInputs = await loadLocalSchemaArrays(project);
12
+ const schemaInputs = await loadLocalSchemaArrays(project, options);
13
13
  const plan = buildGenerationPlan(
14
14
  project,
15
15
  emitDynamicCrudFlowSchemas({
16
16
  ...schemaInputs,
17
- serviceTag: project.serviceTag
17
+ serviceTag: project.serviceTag,
18
+ logger: options.logger
18
19
  }),
19
20
  {
20
21
  managedPaths: dynamicCrudFlowSchemaPaths,
@@ -1,8 +1,8 @@
1
1
  import { loadLocalSchemaDirectory } from '../../compile/loadSchemas.js';
2
2
 
3
- export async function loadLocalSchemaArrays(project) {
3
+ export async function loadLocalSchemaArrays(project, options = {}) {
4
4
  return {
5
- objects: await loadLocalSchemaDirectory(project, 'ObjectSchemas'),
6
- flows: await loadLocalSchemaDirectory(project, 'FlowSchemas')
5
+ objects: await loadLocalSchemaDirectory(project, 'ObjectSchemas', options),
6
+ flows: await loadLocalSchemaDirectory(project, 'FlowSchemas', options)
7
7
  };
8
8
  }
@@ -52,7 +52,7 @@ export default async function CreateComplete(
52
52
  //(</additionalParams>)
53
53
  ) {
54
54
  try {
55
- _izContext.logger.debug('[CreateComplete] started', {
55
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateComplete] started`, {
56
56
  requestParams
57
57
  });
58
58
  const {
@@ -0,0 +1,54 @@
1
+ import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
2
+ import snsSharedLib from '@izara_project/izara-core-library-sns';
3
+ import { sns } from '@izara_project/izara-core-library-external-request';
4
+ import { consts } from '@izara_project/izara-core-library-service-schemas';
5
+
6
+ import {
7
+ buildCompletionPayload,
8
+ publishCompletionMessage
9
+ } from './CreateLogicalLib.js';
10
+
11
+ const { TOPIC_NAME_GENERATE_CODE } = consts;
12
+
13
+ /**
14
+ * Handles Create flow completion by publishing final response to Calling Flow
15
+ * @param {Object} _izContext - Izara context object
16
+ * @param {Object} requestParams - Final response parameters
17
+ * @param {Object} passBackProperties - Pass-back properties
18
+ * @returns {Promise<Object>} Parent pass-back result
19
+ */
20
+ export default async function CreateComplete(
21
+ _izContext,
22
+ requestParams,
23
+ passBackProperties
24
+ ) {
25
+ try {
26
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateComplete] started`, {
27
+ requestParams
28
+ });
29
+
30
+ const callingFlowConfig =
31
+ requestParams?.callingFlowProperties ||
32
+ passBackProperties ||
33
+ {};
34
+
35
+ const parentPassBack =
36
+ requestParams?.parentPassBackProperties ||
37
+ requestParams?.returnValue ||
38
+ requestParams;
39
+
40
+ // 1. Build completion response payload and attributes
41
+ const { message, messageAttributes } = buildCompletionPayload(
42
+ callingFlowConfig,
43
+ parentPassBack
44
+ );
45
+
46
+ // 2. Publish completion notification to SNS
47
+ await publishCompletionMessage(_izContext, message, messageAttributes);
48
+
49
+ return parentPassBack;
50
+ } catch (error) {
51
+ _izContext.logger.error('[CreateComplete] error:', error);
52
+ throw error;
53
+ }
54
+ }