@izara_project/izara-core-generate-service-code 1.0.84 → 1.0.86

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 (46) hide show
  1. package/package.json +1 -1
  2. package/src/compile/compileProject.js +1 -2
  3. package/src/compile/loadSchemas.js +29 -17
  4. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +6 -0
  5. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +26 -6
  6. package/src/emit/crud/crudActionPlan.js +3 -1
  7. package/src/emit/crud/emitCrudApplicationArtifacts.js +47 -8
  8. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +136 -25
  9. package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
  10. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +248 -181
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +1155 -293
  12. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
  13. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +36 -4
  14. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
  15. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +76 -14
  16. package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +35 -3
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +754 -353
  19. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +5 -2
  20. package/src/emit/rbac/emitRbacApplicationArtifacts.js +102 -6
  21. package/src/emit/rbac/templates/CancelUsage_Main.ejs +82 -22
  22. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +130 -14
  23. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +61 -12
  24. package/src/emit/rbac/templates/DeleteTargetRole_Main.ejs +96 -0
  25. package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +106 -0
  26. package/src/emit/rbac/templates/GetTargetRole_Main.ejs +62 -0
  27. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +30 -11
  28. package/src/emit/rbac/templates/UpdateTargetRole_Main.ejs +107 -0
  29. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +40 -15
  30. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +22 -7
  31. package/src/emit/resource/emitResourceArtifacts.js +52 -2
  32. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +6 -2
  33. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +2 -0
  34. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
  35. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +0 -1
  36. package/src/emit/systemText/emitSystemTextSchemas.js +5 -2
  37. package/src/generate.js +18 -12
  38. package/src/generateResources/IntTest/generateResources/generateResources.js +1 -1
  39. package/src/generateResources/IntTest/generateTests/generateTemplate.js +1 -1
  40. package/src/generateResources/IntTest/upload/uploadIntTest.js +8 -2
  41. package/test/createTargetRoleHandler.test.js +42 -1
  42. package/test/crudApplicationArtifacts.test.js +53 -0
  43. package/test/dynamicCrudFlowSchemas.test.js +16 -2
  44. package/test/dynamicRbacFlowSchemas.test.js +5 -2
  45. package/test/publicApi.test.js +18 -14
  46. package/test/resourceArtifacts.test.js +24 -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.84",
3
+ "version": "1.0.86",
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": {
@@ -1,4 +1,3 @@
1
- import Logger from '@izara_project/izara-core-library-logger';
2
1
  import { join, resolve } from 'node:path';
3
2
  import { readFileSync, existsSync } from 'node:fs';
4
3
  import { parse as parseYaml } from 'yaml';
@@ -33,7 +32,7 @@ export function compileProject(request = {}) {
33
32
  }
34
33
  }
35
34
  } catch (err) {
36
- Logger?.debug?.('Could not read serverless.config.yml', err);
35
+ console.log('Could not read serverless.config.yml', err);
37
36
  }
38
37
  }
39
38
 
@@ -7,9 +7,15 @@ import {
7
7
  } from '@izara_project/izara-core-library-service-schemas';
8
8
  import { basicValidatorSchema } from '@izara_project/izara-shared-service-schemas';
9
9
  import { s3 } from '@izara_project/izara-core-library-s3';
10
- import Logger from '@izara_project/izara-core-library-logger';
11
10
  import { validateFlowSchema } from './flowValidator.js';
12
11
 
12
+ const consoleLogger = {
13
+ debug: console.log,
14
+ info: console.log,
15
+ warn: console.log,
16
+ error: console.error
17
+ };
18
+
13
19
  const VALID_INITIATE_BY_ENUM = [
14
20
  'user',
15
21
  'systemWithUser',
@@ -66,7 +72,7 @@ export async function loadLocalSchemaDirectory(
66
72
  options = {}
67
73
  ) {
68
74
  const directoryPath = join(project.schemaRoot, directoryName);
69
- const logger = options.logger || Logger;
75
+ const logger = options.logger || consoleLogger;
70
76
  let entries;
71
77
  try {
72
78
  entries = await readdir(directoryPath, { withFileTypes: true });
@@ -229,8 +235,9 @@ export async function resolveExtendedObjectSchemas(
229
235
  let currentSchema = schema;
230
236
  if (currentSchema.hasOwnProperty('extendObjType')) {
231
237
  try {
232
- Logger.debug(
233
- `[DEBUG] [resolveExtendedObjectSchemas] Merging extendObjType for objectType=${currentSchema.objectType}`,
238
+ console.log(
239
+ `[DEBUG] [resolveExtendedObjectSchemas] Merging extendObjType ` +
240
+ `for objectType=${currentSchema.objectType}`,
234
241
  { extendObjType: currentSchema.extendObjType }
235
242
  );
236
243
  const initialResources = currentSchema.storageResources || {};
@@ -238,7 +245,7 @@ export async function resolveExtendedObjectSchemas(
238
245
  const parentServiceTag = currentSchema.extendObjType.serviceTag;
239
246
 
240
247
  const mergedSchema = await getObjectSchema.mergeExtendObjSchema(
241
- { logger: Logger },
248
+ { logger: consoleLogger },
242
249
  currentSchema,
243
250
  bucketName
244
251
  );
@@ -270,8 +277,9 @@ export async function resolveExtendedObjectSchemas(
270
277
 
271
278
  currentSchema = mergedSchema;
272
279
  } catch (error) {
273
- Logger.error(
274
- `[ERROR] [resolveExtendedObjectSchemas] Failed to merge extendObjType for objectType=${currentSchema.objectType}`,
280
+ console.log(
281
+ `[ERROR] [resolveExtendedObjectSchemas] Failed to merge ` +
282
+ `extendObjType for objectType=${currentSchema.objectType}`,
275
283
  { error }
276
284
  );
277
285
  throw error;
@@ -289,8 +297,9 @@ export async function resolveExtendedObjectSchemas(
289
297
  belongToTarget.objectType
290
298
  ) {
291
299
  try {
292
- Logger.debug(
293
- `[DEBUG] [resolveExtendedObjectSchemas] Fetching belongTo schema for objectType=${currentSchema.objectType}`,
300
+ console.log(
301
+ `[DEBUG] [resolveExtendedObjectSchemas] Fetching belongTo ` +
302
+ `schema for objectType=${currentSchema.objectType}`,
294
303
  { belongTo: belongToTarget }
295
304
  );
296
305
  const belongToObjType = {
@@ -298,19 +307,21 @@ export async function resolveExtendedObjectSchemas(
298
307
  objectType: belongToTarget.objectType
299
308
  };
300
309
  const belongToSchema = await getObjectSchema.getObjSchemaS3(
301
- { logger: Logger },
310
+ { logger: consoleLogger },
302
311
  belongToObjType,
303
312
  false,
304
313
  bucketName
305
314
  );
306
315
  currentSchema.belongToSchema = belongToSchema;
307
- Logger.debug(
308
- `[DEBUG] [resolveExtendedObjectSchemas] Successfully fetched belongTo schema for objectType=${currentSchema.objectType}`,
316
+ console.log(
317
+ `[DEBUG] [resolveExtendedObjectSchemas] Successfully fetched ` +
318
+ `belongTo schema for objectType=${currentSchema.objectType}`,
309
319
  { belongToObjectType: belongToSchema?.objectType }
310
320
  );
311
321
  } catch (error) {
312
- Logger.warn(
313
- `[WARN] [resolveExtendedObjectSchemas] Failed to fetch belongTo schema for objectType=${currentSchema.objectType}`,
322
+ console.log(
323
+ `[WARN] [resolveExtendedObjectSchemas] Failed to fetch ` +
324
+ `belongTo schema for objectType=${currentSchema.objectType}`,
314
325
  { error }
315
326
  );
316
327
  }
@@ -361,7 +372,7 @@ export async function resolveGraphServiceTags(
361
372
  let graphServerTagsMap = {};
362
373
  if (bucketName) {
363
374
  try {
364
- const _izContext = { logger: Logger };
375
+ const _izContext = { logger: consoleLogger };
365
376
  const s3Data = await s3.getObjectS3(_izContext, {
366
377
  Bucket: bucketName,
367
378
  Key: 'serviceConfig/GraphServerTags.json'
@@ -370,8 +381,9 @@ export async function resolveGraphServiceTags(
370
381
  graphServerTagsMap = s3Data;
371
382
  }
372
383
  } catch (error) {
373
- Logger.debug?.(
374
- `[DEBUG] [resolveGraphServiceTags] Could not fetch GraphServerTags.json from bucket=${bucketName}`,
384
+ console.log(
385
+ `[DEBUG] [resolveGraphServiceTags] Could not fetch ` +
386
+ `GraphServerTags.json from bucket=${bucketName}`,
375
387
  error
376
388
  );
377
389
  }
@@ -2,6 +2,7 @@ import ejsLib from 'ejs';
2
2
  import { readFile } from 'node:fs/promises';
3
3
 
4
4
  import { customFlowNextSteps, flowHasRbac, upperFirst } from '../custom/customFlows.js';
5
+ import { createCrudActionPlans } from '../crud/crudActionPlan.js';
5
6
 
6
7
  const TEMPLATE_URL = new URL('./templates/', import.meta.url);
7
8
  const APP_ROOT = 'app/sls_yaml/generatedCode/source';
@@ -239,7 +240,11 @@ export async function emitCoreFunctionArtifacts({ project, objects = [], relatio
239
240
  };
240
241
  });
241
242
 
243
+ const crudPlans = createCrudActionPlans(objects);
244
+ const hasQuotaReservation = crudPlans?.Create?.hasQuotaReservation ?? false;
245
+
242
246
  const state = {
247
+ serviceTag: project?.serviceTag || '',
243
248
  project,
244
249
  objects,
245
250
  relationships,
@@ -252,6 +257,7 @@ export async function emitCoreFunctionArtifacts({ project, objects = [], relatio
252
257
  crud,
253
258
  hasRelationships,
254
259
  rbac,
260
+ hasQuotaReservation,
255
261
  rbacValidatorServiceTags,
256
262
  s3Flows,
257
263
  hasGenerateGraph: objects.length > 0 || relationships.length > 0
@@ -131,7 +131,10 @@ const tableConfigs = {
131
131
  const nodeSubs = [];
132
132
  (objectGraphServiceTags || []).forEach(function(tag) {
133
133
  nodeSubs.push({ serviceTag: tag, topicName: 'UpdateNode_Out', sqsEndpoint: 'UpdateCompleteHdrSqs' });
134
- 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 });
135
138
  });
136
139
 
137
140
  const customSubs = [];
@@ -176,9 +179,14 @@ const tableConfigs = {
176
179
  });
177
180
  });
178
181
 
182
+ const currentServiceTag = (typeof serviceTag !== 'undefined' && serviceTag) ? serviceTag : ((typeof project !== 'undefined' && project?.serviceTag) ? project.serviceTag : '');
179
183
  const rbacSubs = [];
180
- if (crud && typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0) {
181
- const allRbacTags = Array.from(new Set(['Rbac', ...rbacValidatorServiceTags]));
184
+ if (crud && rbac) {
185
+ const allRbacTags = Array.from(new Set([
186
+ 'Rbac',
187
+ currentServiceTag,
188
+ ...(typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags ? rbacValidatorServiceTags : [])
189
+ ])).filter(Boolean);
182
190
  const hasGraph = typeof objectGraphServiceTags !== 'undefined' && objectGraphServiceTags && objectGraphServiceTags.length > 0;
183
191
  const createEndpoint = hasGraph ? 'CreateRbacCallbackHdrSqs' : 'CreateCompleteHdrSqs';
184
192
  const updateEndpoint = hasGraph ? 'UpdateRbacCallbackHdrSqs' : 'UpdateCompleteHdrSqs';
@@ -188,10 +196,18 @@ const tableConfigs = {
188
196
  rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: updateEndpoint });
189
197
  rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: deleteEndpoint });
190
198
  });
199
+ if (typeof hasQuotaReservation !== 'undefined' && hasQuotaReservation) {
200
+ rbacSubs.push({ serviceTag: 'Rbac', topicName: 'ConfirmUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
201
+ rbacSubs.push({ serviceTag: 'Rbac', topicName: 'CancelUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
202
+ }
191
203
  }
192
204
 
193
205
  if (typeof customRbacFlowTags !== 'undefined' && customRbacFlowTags && customRbacFlowTags.length > 0) {
194
- const allRbacTags = Array.from(new Set(['Rbac', ...(typeof rbacValidatorServiceTags !== 'undefined' ? rbacValidatorServiceTags : [])]));
206
+ const allRbacTags = Array.from(new Set([
207
+ 'Rbac',
208
+ currentServiceTag,
209
+ ...(typeof rbacValidatorServiceTags !== 'undefined' ? rbacValidatorServiceTags : [])
210
+ ])).filter(Boolean);
195
211
  customRbacFlowTags.forEach(function(flowTag) {
196
212
  const tagUpper = flowTag[0].toUpperCase() + flowTag.slice(1);
197
213
  allRbacTags.forEach(function(tag) {
@@ -307,7 +323,10 @@ function roleConfigs() {
307
323
  Effect: 'Allow',
308
324
  Action: ['sns:Publish'],
309
325
  Resource: [
310
- `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
326
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
327
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', 'Rbac')}`,
328
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<% if (rbac) { %>,
329
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% } %><% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
311
330
  `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
312
331
  ]
313
332
  },
@@ -326,7 +345,8 @@ function roleConfigs() {
326
345
  Effect: 'Allow',
327
346
  Action: ['sns:Publish'],
328
347
  Resource: [
329
- `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
348
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
349
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
330
350
  `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
331
351
  ]
332
352
  }
@@ -32,7 +32,9 @@ export function createCrudActionPlan(
32
32
  hasRbac: actionHasRbac,
33
33
  hasQuotaReservation,
34
34
  hasComplete: outputTopic && (actionHasRbac || hasGraph),
35
- hasRbacCallback: outputTopic && actionHasRbac && hasGraph
35
+ hasRbacCallback: outputTopic && actionHasRbac && hasGraph,
36
+ hasCreateNodeCallback:
37
+ outputTopic && action === 'Create' && actionHasRbac && hasGraph && hasQuotaReservation
36
38
  };
37
39
  }
38
40
 
@@ -35,11 +35,17 @@ export async function emitCrudApplicationArtifacts({
35
35
  objectType: obj?.objectType ?? '(undefined)',
36
36
  generatedBy: obj?.generatedBy ?? '(missing)'
37
37
  }));
38
- logger?.warn?.(
39
- `[WARN] [CRUD Application] Skipped FlowObjects application artifacts generation: No valid CRUD ObjectSchema found. ` +
38
+ const warnMsg =
39
+ `[WARN] [CRUD Application] Skipped FlowObjects application artifacts ` +
40
+ `generation: No valid CRUD ObjectSchema found. ` +
40
41
  `Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
41
- `Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
42
- );
42
+ `Expected "generatedBy" to be one of: ` +
43
+ `${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`;
44
+ if (logger?.warn) {
45
+ logger.warn(warnMsg);
46
+ } else {
47
+ console.log(warnMsg);
48
+ }
43
49
  }
44
50
  return [];
45
51
  }
@@ -80,6 +86,8 @@ export function crudApplicationManagedPaths() {
80
86
  `${source}/${action}_HdrWbs.js`,
81
87
  `${source}/${action}RbacCallback_Main.js`,
82
88
  `${source}/${action}RbacCallback_HdrSqs.js`,
89
+ `${source}/${action}NodeCallback_Main.js`,
90
+ `${source}/${action}NodeCallback_HdrSqs.js`,
83
91
  `${source}/${action}Complete_Main.js`,
84
92
  `${source}/${action}Complete_HdrSqs.js`
85
93
  );
@@ -290,12 +298,43 @@ async function emitAction(action, objects, serviceTag) {
290
298
  });
291
299
  }
292
300
 
301
+ if (plan.hasCreateNodeCallback) {
302
+ const nodeCallbackMain = `${action}NodeCallback_Main`;
303
+ artifacts.push(
304
+ {
305
+ path: `${source}/${nodeCallbackMain}.js`,
306
+ content: await render(`${action}NodeCallback_Main.ejs`, shared)
307
+ },
308
+ {
309
+ path: `${source}/${nodeCallbackMain.replace('_Main', '_HdrSqs')}.js`,
310
+ content: await renderShared('FlowHandler_HdrSqs.ejs', {
311
+ ...shared,
312
+ mainFileName: nodeCallbackMain,
313
+ functionName: `${action}NodeCallbackMain`,
314
+ queueName: `${action}NodeCallbackHdrSqs`
315
+ })
316
+ }
317
+ );
318
+ functions.push({
319
+ type: 'sqs',
320
+ functionName: `${action}NodeCallbackHdrSqs`,
321
+ handlerPath: `${handlerRoot}/${action}NodeCallback_HdrSqs.main`,
322
+ roleName: 'FlowObjectsRole',
323
+ queueName: `${action}NodeCallbackHdrSqs`,
324
+ flowTag: action,
325
+ flowStepName: 'CreateNodeCallback'
326
+ });
327
+ }
328
+
293
329
  if (plan.hasComplete) {
294
330
  const completeMain = `${action}Complete_Main`;
295
- const templateName =
296
- plan.hasRbac && !plan.hasGraph
297
- ? 'FlowEndpointRbacCallback_Main.ejs'
298
- : `${action}Complete_Main.ejs`;
331
+ let templateName = `${action}Complete_Main.ejs`;
332
+ if (plan.hasRbac && !plan.hasGraph) {
333
+ templateName = 'FlowEndpointRbacCallback_Main.ejs';
334
+ } else if (plan.hasCreateNodeCallback) {
335
+ templateName = 'CreateConfirmComplete_Main.ejs';
336
+ }
337
+
299
338
  const templateContext =
300
339
  plan.hasRbac && !plan.hasGraph
301
340
  ? shared
@@ -29,11 +29,17 @@ export function emitDynamicCrudFlowSchemas({
29
29
  objectType: obj?.objectType ?? '(undefined)',
30
30
  generatedBy: obj?.generatedBy ?? '(missing)'
31
31
  }));
32
- logger?.warn?.(
33
- `[WARN] [CRUD FlowSchemas] Skipped FlowObjects FlowSchemas generation: No valid CRUD ObjectSchema found. ` +
32
+ const warnMsg =
33
+ `[WARN] [CRUD FlowSchemas] Skipped FlowObjects FlowSchemas ` +
34
+ `generation: No valid CRUD ObjectSchema found. ` +
34
35
  `Checked ${objects.length} object(s): ${JSON.stringify(summary)}. ` +
35
- `Expected "generatedBy" to be one of: ${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`
36
- );
36
+ `Expected "generatedBy" to be one of: ` +
37
+ `${Array.from(VALID_CRUD_GENERATED_BY).join(', ')}`;
38
+ if (logger?.warn) {
39
+ logger.warn(warnMsg);
40
+ } else {
41
+ console.log(warnMsg);
42
+ }
37
43
  }
38
44
  return [];
39
45
  }
@@ -52,19 +58,39 @@ export function emitDynamicCrudFlowSchemas({
52
58
  }
53
59
 
54
60
  function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user') {
61
+ const startNextSteps = [];
62
+ if (plan.hasRbacCallback) {
63
+ startNextSteps.push(
64
+ {
65
+ targetType: 'ownTopic',
66
+ stepName: 'RbacCallback'
67
+ },
68
+ {
69
+ targetType: 'extTopic',
70
+ serviceTag: 'Rbac',
71
+ topicName: 'ValidatorRbac_In',
72
+ toStepNames: ['RbacCallback']
73
+ }
74
+ );
75
+ } else if (plan.hasComplete) {
76
+ startNextSteps.push({
77
+ targetType: 'ownTopic',
78
+ stepName: 'Complete'
79
+ });
80
+ if (plan.hasGraph) {
81
+ startNextSteps.push({
82
+ targetType: 'extTopic',
83
+ serviceTag: 'GraphHandler',
84
+ topicName: `${action}Node_In`,
85
+ toStepNames: ['Complete']
86
+ });
87
+ }
88
+ }
89
+
55
90
  const flowSteps = [
56
91
  {
57
92
  stepName: 'Start',
58
- ...(plan.hasRbacCallback || plan.hasComplete
59
- ? {
60
- nextSteps: [
61
- {
62
- targetType: 'ownTopic',
63
- stepName: plan.hasRbacCallback ? 'RbacCallback' : 'Complete'
64
- }
65
- ]
66
- }
67
- : {}),
93
+ ...(startNextSteps.length > 0 ? { nextSteps: startNextSteps } : {}),
68
94
  properties: [],
69
95
  messageAttributes: MESSAGE_ATTRIBUTES,
70
96
  ...(plan.outputTopic
@@ -79,6 +105,22 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
79
105
  ];
80
106
 
81
107
  if (plan.hasRbacCallback) {
108
+ const nextStepName = plan.hasCreateNodeCallback ? 'CreateNodeCallback' : 'Complete';
109
+ const rbacNextSteps = [
110
+ {
111
+ targetType: 'ownTopic',
112
+ stepName: nextStepName
113
+ }
114
+ ];
115
+ if (plan.hasGraph) {
116
+ rbacNextSteps.push({
117
+ targetType: 'extTopic',
118
+ serviceTag: 'GraphHandler',
119
+ topicName: `${action}Node_In`,
120
+ toStepNames: [nextStepName]
121
+ });
122
+ }
123
+
82
124
  flowSteps.push({
83
125
  stepName: 'RbacCallback',
84
126
  event: ['extTopic'],
@@ -86,38 +128,107 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
86
128
  {
87
129
  sourceType: 'ownTopic',
88
130
  stepName: 'Start'
131
+ },
132
+ {
133
+ sourceType: 'extTopic',
134
+ serviceTag: 'Rbac',
135
+ topicName: 'ValidatorRbac_Out',
136
+ fromStepNames: ['Start']
137
+ }
138
+ ],
139
+ nextSteps: rbacNextSteps,
140
+ properties: [],
141
+ messageAttributes: MESSAGE_ATTRIBUTES
142
+ });
143
+ }
144
+
145
+ if (plan.hasCreateNodeCallback) {
146
+ flowSteps.push({
147
+ stepName: 'CreateNodeCallback',
148
+ event: ['extTopic'],
149
+ previousSteps: [
150
+ {
151
+ sourceType: 'ownTopic',
152
+ stepName: 'RbacCallback'
153
+ },
154
+ {
155
+ sourceType: 'extTopic',
156
+ serviceTag: 'GraphHandler',
157
+ topicName: 'CreateNode_Out',
158
+ fromStepNames: ['RbacCallback']
89
159
  }
90
160
  ],
91
161
  nextSteps: [
92
162
  {
93
163
  targetType: 'ownTopic',
94
164
  stepName: 'Complete'
165
+ },
166
+ {
167
+ targetType: 'extTopic',
168
+ serviceTag: 'Rbac',
169
+ topicName: 'ConfirmUsage_In',
170
+ toStepNames: ['Complete']
95
171
  }
96
172
  ],
97
- properties: [],
173
+ properties: [
174
+ 'returnValue',
175
+ 'parentFlowId',
176
+ 'status',
177
+ 'errorsFound',
178
+ 'graphServiceTag'
179
+ ],
98
180
  messageAttributes: MESSAGE_ATTRIBUTES
99
181
  });
100
182
  }
101
183
 
102
184
  if (plan.hasComplete) {
185
+ const prevStepName = plan.hasCreateNodeCallback
186
+ ? 'CreateNodeCallback'
187
+ : (plan.hasRbacCallback ? 'RbacCallback' : 'Start');
188
+
189
+ const completePrevSteps = [
190
+ {
191
+ sourceType: 'ownTopic',
192
+ stepName: prevStepName
193
+ }
194
+ ];
195
+
196
+ if (plan.hasCreateNodeCallback) {
197
+ completePrevSteps.push({
198
+ sourceType: 'extTopic',
199
+ serviceTag: 'Rbac',
200
+ topicName: 'ConfirmUsage_Out',
201
+ fromStepNames: ['CreateNodeCallback']
202
+ });
203
+ } else if (plan.hasGraph) {
204
+ completePrevSteps.push({
205
+ sourceType: 'extTopic',
206
+ serviceTag: 'GraphHandler',
207
+ topicName: `${action}Node_Out`,
208
+ fromStepNames: [prevStepName]
209
+ });
210
+ }
211
+
103
212
  flowSteps.push({
104
213
  stepName: 'Complete',
105
214
  event: ['extTopic'],
106
- previousSteps: [
107
- {
108
- sourceType: 'ownTopic',
109
- stepName: plan.hasRbacCallback ? 'RbacCallback' : 'Start'
110
- }
111
- ],
112
- properties: plan.hasGraph
215
+ previousSteps: completePrevSteps,
216
+ properties: plan.hasCreateNodeCallback
113
217
  ? [
114
218
  'returnValue',
115
219
  'parentFlowId',
116
220
  'status',
117
- 'errorsFound',
118
- 'graphServiceTag'
221
+ 'errorsFound'
119
222
  ]
120
- : [],
223
+ : (plan.hasGraph
224
+ ? [
225
+ 'returnValue',
226
+ 'parentFlowId',
227
+ 'status',
228
+ 'errorsFound',
229
+ 'graphServiceTag'
230
+ ]
231
+ : []),
121
232
  messageAttributes: MESSAGE_ATTRIBUTES
122
233
  });
123
234
  }
@@ -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
+ }