@izara_project/izara-core-generate-service-code 1.0.78 → 1.0.79

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 (61) hide show
  1. package/package.json +2 -2
  2. package/src/compile/flowValidator.js +163 -0
  3. package/src/compile/loadSchemas.js +15 -5
  4. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +137 -7
  5. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +132 -17
  6. package/src/emit/crud/crudActionPlan.js +82 -0
  7. package/src/emit/crud/emitCrudApplicationArtifacts.js +162 -112
  8. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +43 -65
  9. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
  10. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +84 -512
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +536 -0
  12. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +87 -202
  13. package/src/emit/crud/templates/DeleteLogicalLib.ejs +213 -0
  14. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +217 -0
  15. package/src/emit/crud/templates/GetEndpoint_Main.ejs +1 -1
  16. package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +9 -2
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +87 -444
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +472 -0
  19. package/src/emit/custom/customFlows.js +27 -2
  20. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +1 -2
  21. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +10 -3
  22. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  23. package/src/emit/custom/templates/s3/CreateObject_Main.ejs +1 -1
  24. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +2 -2
  25. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +3 -9
  26. package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -16
  27. package/src/emit/rbac/rbacFlowTag.js +2 -7
  28. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +148 -21
  29. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +4 -2
  30. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +1 -1
  31. package/src/emit/relationship/templates/CreateRelationship_Main.ejs +1 -1
  32. package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +1 -1
  33. package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
  34. package/src/emit/relationship/templates/MoveRelationship_Main.ejs +1 -1
  35. package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +1 -1
  36. package/src/emit/resource/emitResourceArtifacts.js +83 -68
  37. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +31 -5
  38. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +21 -0
  39. package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
  40. package/src/emit/shared/templates/FlowHandler_HdrApi.ejs +1 -1
  41. package/src/emit/shared/templates/FlowHandler_HdrDsq.ejs +2 -2
  42. package/src/emit/shared/templates/FlowHandler_HdrInv.ejs +1 -1
  43. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +2 -2
  44. package/src/emit/systemText/emitSystemTextSchemas.js +246 -0
  45. package/src/emit/systemText/templates/SystemTextSchemas.ejs +10 -0
  46. package/src/generate.js +55 -8
  47. package/test/crudApplicationArtifacts.test.js +147 -19
  48. package/test/customFlowApplicationArtifacts.test.js +308 -16
  49. package/test/dynamicCrudFlowSchemas.test.js +150 -14
  50. package/test/dynamicRbacFlowSchemas.test.js +2 -2
  51. package/test/dynamicRelationshipFlowSchemas.test.js +1 -1
  52. package/test/graphDrivenFlowSchema.test.js +257 -0
  53. package/test/publicApi.test.js +14 -5
  54. package/test/resourceArtifacts.test.js +25 -19
  55. package/test/systemTextSchemas.test.js +154 -0
  56. package/src/emit/crud/templates/CreateComplete_HdrSqs.ejs +0 -99
  57. package/src/emit/crud/templates/DeleteComplete_HdrSqs.ejs +0 -99
  58. package/src/emit/crud/templates/FlowEndpointBeforeLogical_Main.ejs +0 -174
  59. package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +0 -187
  60. package/src/emit/crud/templates/UpdateComplete_HdrSqs.ejs +0 -99
  61. package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +0 -47
@@ -53,424 +53,13 @@ import {
53
53
  lambda
54
54
  } from '@izara_project/izara-core-library-external-request';
55
55
 
56
+ import { <%- flowTag %>LogicalLib } from './<%- upperCaseFlowTag %>LogicalLib.js';
57
+
56
58
  //(<optionalRequire>)
57
59
  //(</optionalRequire>)
58
60
 
59
61
  /**
60
- * Core logical processing after beforeLogical phase completes
61
- * Called by both updateMain (no beforeLogical) and updateBeforeLogicalMain (after callback)
62
- * @param {Object} _izContext - Context object with logger
63
- * @param {Object} requestParams - { objectType, objInstanceFull, versionedDataIds, additionalParams }
64
- * @param {Object} callingFlowConfig - Calling flow configuration
65
- * @param {Object} beforeLogicalResults - Results from beforeLogical phase
66
- * @returns {Promise<Object>}
67
- */
68
- export async function <%- flowTag %>MainLogical(
69
- _izContext,
70
- requestParams,
71
- callingFlowConfig = {},
72
- errorsFound = [],
73
- beforeLogicalResults = {}
74
- ) {
75
- try {
76
- _izContext.logger.debug('[<%- flowTag %>MainLogical] started', {
77
- requestParams,
78
- callingFlowConfig,
79
- beforeLogicalResults
80
- });
81
-
82
- //(<beforeUpdateMainLogical>)
83
- //(</beforeUpdateMainLogical>)
84
-
85
- // ── Settings ──────────────────────────────────────────────────────────────
86
- const settings = requestParams.additionalParams?.settings ?? {};
87
- const returnSystemFieldsName = settings.returnSystemFieldsName === true;
88
- const returnOldData = settings.returnOldData === true;
89
-
90
- const objType = createObjType(requestParams.objectType);
91
- const identifiers = requestParams.objInstanceFull.identifiers;
92
- const fields = requestParams.objInstanceFull.fields;
93
- const versionedDataIds = requestParams.versionedDataIds ?? {};
94
- const parentFlowId = identifierUuid();
95
- // ── Load schema ───────────────────────────────────────────────────────────
96
- const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
97
- _izContext,
98
- objType
99
- );
100
- _izContext.logger.debug('objectSchema', objectSchema);
101
-
102
- const objectSchemas =
103
- await uploadUseCase.generateObjectSchemaForCombineFieldNames(
104
- _izContext,
105
- objectSchema
106
- );
107
- _izContext.logger.debug('objectSchemas', objectSchemas);
108
-
109
- // ── Build updateDataDetails ───────────────────────────────────────────────
110
- const updateDataDetails = await createUpdateDataDetail(
111
- _izContext,
112
- objectSchemas
113
- );
114
- _izContext.logger.debug('updateDataDetails', updateDataDetails);
115
-
116
- const originTimestamp = Date.now();
117
-
118
- // ── Validate versionedDataIds ─────────────────────────────────────────────
119
- const haveVersionedDataIdsToUpdate =
120
- Object.keys(versionedDataIds).length > 0;
121
- if (haveVersionedDataIdsToUpdate) {
122
- const updateMainNodeData = {};
123
- const updateVersionedData = {};
124
-
125
- for (const [fieldProp, fieldVal] of Object.entries(
126
- requestParams.objInstanceFull.fields
127
- )) {
128
- const fieldSetting = objectSchema.fieldNames[fieldProp];
129
- if (fieldSetting.hasOwnProperty('versionedDataLabel')) {
130
- updateVersionedData[fieldSetting.versionedDataLabel] ??= {};
131
- Object.assign(updateVersionedData[fieldSetting.versionedDataLabel], {
132
- [fieldProp]: fieldVal
133
- });
134
- } else {
135
- Object.assign(updateMainNodeData, { [fieldProp]: fieldVal });
136
- }
137
- }
138
-
139
- _izContext.logger.debug('updateMainNodeData::', updateMainNodeData);
140
- _izContext.logger.debug('updateVersionedData::', updateVersionedData);
141
-
142
- const versionedDataIdLabelKeys = Object.keys(versionedDataIds);
143
- const updateVersionedDataLabelKeys = Object.keys(updateVersionedData);
144
-
145
- const missingVersionedDataIdLabels = updateVersionedDataLabelKeys.filter(
146
- (l) => !versionedDataIdLabelKeys.includes(l)
147
- );
148
- const missingDataVersionedDataLabels = versionedDataIdLabelKeys.filter(
149
- (l) => !updateVersionedDataLabelKeys.includes(l)
150
- );
151
-
152
- if (missingVersionedDataIdLabels.length)
153
- errorsFound.push(
154
- `missing versionedDataIds of versionedDataLabel '${missingVersionedDataIdLabels.join(', ')}'`
155
- );
156
- if (missingDataVersionedDataLabels.length)
157
- errorsFound.push(
158
- `missing data of versionedDataLabels '${missingDataVersionedDataLabels.join(', ')}'`
159
- );
160
- if (Object.keys(updateMainNodeData).length)
161
- errorsFound.push('cannot update mainNode if have versionedDataIds');
162
- }
163
-
164
- //(<validateBeforeUpdate>)
165
- //(</validateBeforeUpdate>)
166
-
167
- // ── Early exit on errors ──────────────────────────────────────────────────
168
- if (errorsFound.length) {
169
- const updateNodeCompleteMessage =
170
- callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
171
- callingFlowConfig,
172
- {
173
- objType,
174
- objInstanceFull: { identifiers, fields },
175
- versionedDataIds,
176
- status: 'error',
177
- errorsFound
178
- }
179
- );
180
-
181
- _izContext.logger.debug(
182
- 'messageParams OutUpdateNodeComplete:::',
183
- updateNodeCompleteMessage
184
- );
185
- await sns.publishAsync(_izContext, {
186
- Message: JSON.stringify(updateNodeCompleteMessage),
187
- MessageAttributes: sns.createStringMessageAttributes(
188
- _izContext,
189
- callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
190
- callingFlowConfig,
191
- {}
192
- )
193
- ),
194
- TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
195
- _izContext,
196
- TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
197
- )
198
- });
199
-
200
- return updateNodeCompleteMessage;
201
- }
202
-
203
- // ── Helper: extract fields per storageTag ─────────────────────────────────
204
- function createObjInstanceFullFieldsByStorageTag(
205
- _izContext,
206
- storageTag,
207
- updateDataDetail
208
- ) {
209
- const result = {};
210
- for (const fieldName of Object.keys(
211
- requestParams.objInstanceFull.fields
212
- )) {
213
- if (
214
- updateDataDetails[storageTag].fieldNames.includes(fieldName) &&
215
- updateDataDetail.fieldNames.includes(fieldName) &&
216
- !identifiers.hasOwnProperty(fieldName) &&
217
- !result.hasOwnProperty(fieldName)
218
- ) {
219
- Object.assign(result, {
220
- [fieldName]: requestParams.objInstanceFull.fields[fieldName]
221
- });
222
- }
223
- }
224
- return result;
225
- }
226
-
227
- // ── Helper: build objInstanceFull from updateItem ─────────────────────────
228
- function createObjInstanceFullFromParams(object, requestParams) {
229
- const objInstanceFull = { identifiers: {}, fields: {} };
230
- for (const field of Object.keys(object)) {
231
- if (requestParams.objInstanceFull.identifiers.hasOwnProperty(field)) {
232
- Object.assign(objInstanceFull.identifiers, {
233
- [field]: requestParams.objInstanceFull.identifiers[field]
234
- });
235
- }
236
- if (requestParams.objInstanceFull.fields.hasOwnProperty(field)) {
237
- Object.assign(objInstanceFull.fields, {
238
- [field]: requestParams.objInstanceFull.fields[field]
239
- });
240
- }
241
- }
242
- return objInstanceFull;
243
- }
244
-
245
- // ── Process storage resources ─────────────────────────────────────────────
246
- const awaitingStepIds = [];
247
- const listOfRecords = [];
248
- let updateItem;
249
-
250
- await Promise.all(
251
- Object.entries(updateDataDetails).map(
252
- async ([storageTag, updateDataDetail]) => {
253
- // ── Graph ─────────────────────────────────────────────────────────────
254
- if (updateDataDetail.storageType === consts.STORAGE_TYPES.graph) {
255
- //(<beforeUpdateGraph>)
256
- //(</beforeUpdateGraph>)
257
-
258
- const graphFields = createObjInstanceFullFieldsByStorageTag(
259
- _izContext,
260
- storageTag,
261
- updateDataDetail
262
- );
263
- if (!Object.keys(graphFields).length) return;
264
-
265
- //(<beforeUpdateNode>)
266
- //(</beforeUpdateNode>)
267
-
268
- //(<additionalAttributes>)
269
- const additionalAttributes = {};
270
- //(</additionalAttributes>)
271
-
272
- const records = awaitingStepIds.length === 0 ? listOfRecords : [];
273
- awaitingStepIds.push({
274
- awaitingStepId: asyncFlowSharedLib.createAwaitingStepId(
275
- parentFlowId,
276
- PREFIX.updateNode
277
- ),
278
- additionalAttributes: {
279
- listOfRecords: records,
280
- additionalAttributes: additionalAttributes
281
- }
282
- });
283
-
284
- if (awaitingStepIds.length) {
285
- const awaitingMultipleStep =
286
- await asyncFlowSharedLib.createAwaitingMultipleSteps(
287
- _izContext,
288
- asyncFlowSharedLib.createPendingStepId(
289
- _izContext.uniqueRequestId
290
- ),
291
- awaitingStepIds
292
- );
293
- _izContext.logger.debug(
294
- 'awaitingMultipleStep',
295
- awaitingMultipleStep
296
- );
297
- }
298
-
299
- let updateNodeParams = {
300
- objType,
301
- objInstanceFull: { identifiers, fields: graphFields },
302
- versionedDataIds,
303
- originTimestamp,
304
- settings: { returnSystemFieldsName, returnOldData },
305
- parentFlowId
306
- };
307
-
308
- updateNodeParams =
309
- callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
310
- updateNodeParams,
311
- callingFlowSharedLib.addParentCallingFlowConfig(
312
- callingFlowConfig,
313
- callingFlowSharedLib.createCallingFlowConfig(
314
- //(<callingFlowProperties>)
315
- await lambdaSharedLib.lambdaFunctionName(
316
- _izContext,
317
- TOPIC_NAME_GENERATE_CODE.updateNodeComplete
318
- ),
319
- {}
320
- //(</callingFlowProperties>)
321
- )
322
- )
323
- );
324
-
325
- _izContext.logger.debug(
326
- 'messageObject before send message:',
327
- updateNodeParams
328
- );
329
-
330
- const resSNS = await sns.publishAsync(_izContext, {
331
- Message: JSON.stringify(updateNodeParams),
332
- MessageAttributes: sns.createStringMessageAttributes(
333
- _izContext,
334
- callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
335
- callingFlowConfig,
336
- {}
337
- )
338
- ),
339
- TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
340
- _izContext,
341
- TOPIC_NAME_GRAPH_HANDLER.inUpdateNode,
342
- storageTag
343
- )
344
- });
345
- _izContext.logger.debug(
346
- 'resSNS send to topic InUpdateNode finish!',
347
- resSNS
348
- );
349
-
350
- // ── DynamoDB ──────────────────────────────────────────────────────────
351
- } else if (
352
- updateDataDetail.storageType === consts.STORAGE_TYPES.dynamoDB
353
- ) {
354
- const dynamoFields = createObjInstanceFullFieldsByStorageTag(
355
- _izContext,
356
- storageTag,
357
- updateDataDetail
358
- );
359
- if (!Object.keys(dynamoFields).length) return;
360
-
361
- //(<beforeUpdateDynamoDb>)
362
- //(</beforeUpdateDynamoDb>)
363
-
364
- const identifiersForUpdateData =
365
- await dynamoDbIdentifiersByStorageResource(
366
- _izContext,
367
- objectSchema,
368
- updateDataDetail,
369
- identifiers
370
- );
371
- _izContext.logger.debug(
372
- 'identifiersForUpdateData',
373
- identifiersForUpdateData
374
- );
375
-
376
- if (
377
- Object.values(updateDataDetails).some(
378
- (updateDataDetail) =>
379
- updateDataDetail.storageType === consts.STORAGE_TYPES.graph
380
- )
381
- ) {
382
- _izContext.logger.debug('must process graph first');
383
- listOfRecords.push({
384
- [storageTag]: {
385
- serviceTag: updateDataDetail.serviceTag,
386
- tableName: updateDataDetail.tableName,
387
- objInstanceFull: {
388
- identifiers: identifiersForUpdateData,
389
- fields: dynamoFields
390
- }
391
- }
392
- });
393
- } else {
394
- _izContext.logger.debug('can process record dynamo');
395
- updateItem = await dynamodbSharedLib.updateItem(
396
- _izContext,
397
- await dynamodbSharedLib.tableName(
398
- _izContext,
399
- updateDataDetail.tableName,
400
- updateDataDetail.serviceTag
401
- ),
402
- identifiersForUpdateData,
403
- dynamoFields,
404
- { returnValues: 'ALL_NEW' }
405
- );
406
-
407
- _izContext.logger.debug('updateItem:', updateItem);
408
- }
409
- }
410
- }
411
- )
412
- );
413
-
414
- // ── DynamoDB-only complete path ───────────────────────────────────────────
415
- if (awaitingStepIds.length === 0) {
416
- let messageObject = {
417
- objType,
418
- objInstanceFull: createObjInstanceFullFromParams(
419
- updateItem,
420
- requestParams
421
- )
422
- };
423
-
424
- //(<additionalProperties>)
425
- //(</additionalProperties>)
426
-
427
- if (
428
- callingFlowConfig[
429
- callingFlowSharedLib.consts.CALLINGFLOWPROPERTIES_PROPERTYNAME
430
- ]
431
- ) {
432
- _izContext.logger.debug('HAVE CALLING FLOW');
433
- messageObject =
434
- callingFlowSharedLib.addPassBackPropertiesToSnsResponseMessageObject(
435
- callingFlowConfig,
436
- messageObject
437
- );
438
-
439
- _izContext.logger.debug('after create callingFlow', messageObject);
440
- await sns.publishAsync(_izContext, {
441
- Message: JSON.stringify(messageObject),
442
- MessageAttributes: sns.createStringMessageAttributes(
443
- _izContext,
444
- callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
445
- callingFlowConfig,
446
- {}
447
- )
448
- ),
449
- TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
450
- _izContext,
451
- TOPIC_NAME_GENERATE_CODE.outUpdateNodeComplete
452
- )
453
- });
454
- }
455
- }
456
-
457
- return {
458
- returnValues: {
459
- objType,
460
- objInstanceFull: { identifiers, fields },
461
- versionedDataIds
462
- },
463
- status: 'complete',
464
- errorsFound
465
- };
466
- } catch (err) {
467
- _izContext.logger.error('[<%- flowTag %>MainLogical] error:', err);
468
- throw err;
469
- }
470
- }
471
-
472
- /**
473
- * Updates an object instance — handles beforeLogical phase routing or proceeds directly to logical
62
+ * Updates an object instance with optional RBAC routing
474
63
  * @param {Object} _izContext - Context object with logger
475
64
  * @param {Object} requestParams - { objectType, objInstanceFull, versionedDataIds, additionalParams }
476
65
  * @param {Object} callingFlowConfig - Calling flow configuration
@@ -479,7 +68,7 @@ export async function <%- flowTag %>MainLogical(
479
68
  export default async function <%- flowTag %>(
480
69
  _izContext,
481
70
  requestParams,
482
- callingFlowConfig = {}
71
+ callingFlowConfig = {},
483
72
  //(<additionalParams>)
484
73
  //(</additionalParams>)
485
74
  ) {
@@ -489,7 +78,7 @@ export default async function <%- flowTag %>(
489
78
  callingFlowConfig
490
79
  });
491
80
 
492
- // ── Build identifiers (used for hash in beforeLogical) ──────────────────
81
+ // ── Build identifiers used by asynchronous processing ────────────────────
493
82
  const identifiers = requestParams.objInstanceFull.identifiers;
494
83
  const errorsFound = [];
495
84
 
@@ -497,23 +86,76 @@ export default async function <%- flowTag %>(
497
86
  //(</validateBeforeUpdate>)
498
87
 
499
88
  if (errorsFound.length > 0)
500
- return await createMainLogical(
89
+ return await <%- flowTag %>LogicalLib(
501
90
  _izContext,
502
91
  requestParams,
503
92
  callingFlowConfig,
504
93
  errorsFound
505
94
  );
506
95
 
507
- // ── beforeLogical phase check ─────────────────────────────────────────────
508
96
  <%_
509
- const groupedByObjType = generateCode
510
- .filter(c => c.codeHookTag === 'beforeLogical')
511
- .reduce((acc, config) => {
512
- const key = config.objType.objectType;
513
- if (!acc[key]) acc[key] = [];
514
- acc[key].push(config);
515
- return acc;
516
- }, {});
97
+ const rbacObjects = objects.filter(o => (o?.generatedBy === 'userGenerated' || o?.generatedBy === 'systemGenerated') && hasRbacAddOn(o));
98
+ const rbacObjectTypes = rbacObjects.map(o => o.objectType);
99
+ const rbacServiceTagMap = {};
100
+ for (const o of rbacObjects) {
101
+ const belongToTargets = o?.belongTo
102
+ ? Array.isArray(o.belongTo)
103
+ ? o.belongTo
104
+ : [o.belongTo]
105
+ : [];
106
+ if (belongToTargets.length > 0 && belongToTargets[0]?.serviceTag) {
107
+ rbacServiceTagMap[o.objectType] = `'${belongToTargets[0].serviceTag}'`;
108
+ } else if (o?.belongToSchema?.serviceTag) {
109
+ rbacServiceTagMap[o.objectType] = `'${o.belongToSchema.serviceTag}'`;
110
+ } else if (o?.serviceTag) {
111
+ rbacServiceTagMap[o.objectType] = `'${o.serviceTag}'`;
112
+ } else {
113
+ rbacServiceTagMap[o.objectType] = 'process.env.iz_serviceTag';
114
+ }
115
+ }
116
+ const rbacServiceTags = Array.from(new Set(Object.values(rbacServiceTagMap)));
117
+ _%>
118
+ <%_ if (rbacObjectTypes.length > 0) { _%>
119
+ // ── rbacCallback phase check ─────────────────────────────────────────────
120
+ if ([<%- rbacObjectTypes.map(t => `'${t}'`).join(', ') %>].includes(requestParams.objectType)) {
121
+ const { checkRbacPermission } =
122
+ await import('@izara_project/izara-authorization');
123
+
124
+ //(<rbacParameterGroups_<%- flowTag %>)
125
+ const parameterGroups = {};
126
+ //(</rbacParameterGroups_<%- flowTag %>)
127
+
128
+ const resultPermissionCheck = await checkRbacPermission(
129
+ _izContext,
130
+ {
131
+ flowTag: '<%- flowTag %>',
132
+ serviceTag: process.env.iz_serviceTag
133
+ },
134
+ parameterGroups,
135
+ {
136
+ rbacObjType: {
137
+ serviceTag: <%- rbacServiceTags.length === 1 ? rbacServiceTags[0] : `{ ${Object.entries(rbacServiceTagMap).map(([k, v]) => `'${k}': ${v}`).join(', ')} }[requestParams.objectType] || process.env.iz_serviceTag` %>
138
+ },
139
+ requestParams: requestParams,
140
+ nextFlowStepName: '<%- flowTag %>RbacCallback'
141
+ }
142
+ );
143
+
144
+ _izContext.logger.debug(
145
+ '[lib:auth:checkRbacPermission] resultPermissionCheck:',
146
+ resultPermissionCheck
147
+ );
148
+
149
+ //(<rbacPublish_<%- flowTag %>)
150
+ //(</rbacPublish_<%- flowTag %>)
151
+
152
+ return resultPermissionCheck;
153
+ }
154
+ <%_ } _%>
155
+
156
+ // ── Optional phase extension point ────────────────────────────────────────
157
+ <%_
158
+ const groupedByObjType = [];
517
159
  _%>
518
160
  <%_ Object.entries(groupedByObjType).forEach(([objectType, configs]) => { _%>
519
161
  <%_
@@ -556,7 +198,7 @@ export default async function <%- flowTag %>(
556
198
  awaitingMultipleStepIds.push({
557
199
  awaitingStepId: await asyncFlowSharedLib.createAwaitingStepId(
558
200
  hash(identifiers),
559
- '<%= config.codeHookTag %>_<%= objectType %>_<%= config.flowTag.charAt(0).toUpperCase() + config.flowTag.slice(1) %>'
201
+ 'logical_<%= objectType %>_<%= config.flowTag.charAt(0).toUpperCase() + config.flowTag.slice(1) %>'
560
202
  ),
561
203
  additionalAttributes: {}
562
204
  });
@@ -570,7 +212,7 @@ export default async function <%- flowTag %>(
570
212
  //(<callingFlowProperties_<%= config.flowTag %>>)
571
213
  await lambdaSharedLib.lambdaFunctionName(
572
214
  _izContext,
573
- '<%= config.generatedCodeTag %><%= config.codeHookTag.charAt(0).toUpperCase() + config.codeHookTag.slice(1) %>'
215
+ '<%= flowTag.toLowerCase() %>Complete'
574
216
  ),
575
217
  {}
576
218
  //(</callingFlowProperties_<%= config.flowTag %>>)
@@ -587,7 +229,7 @@ export default async function <%- flowTag %>(
587
229
  awaitingMultipleStepIds.push({
588
230
  awaitingStepId: await asyncFlowSharedLib.createAwaitingStepId(
589
231
  hash(identifiers),
590
- '<%= configs[0].codeHookTag %>_<%= objectType %>_' + syncResult.flowTag
232
+ 'logical_<%= objectType %>_' + syncResult.flowTag
591
233
  ),
592
234
  additionalAttributes: {
593
235
  complete: true,
@@ -598,13 +240,13 @@ export default async function <%- flowTag %>(
598
240
  }
599
241
  <%_ } _%>
600
242
 
601
- await asyncFlowSharedLib.initAwaitingStepsWithAttrs(
243
+ await asyncFlowSharedLib.createAwaitingMultipleSteps(
602
244
  _izContext,
603
- awaitingMultipleStepIds,
604
245
  asyncFlowSharedLib.createPendingStepId(
605
246
  _izContext.uniqueRequestId,
606
- 'beforeLogical_<%= objectType %>'
607
- )
247
+ 'logical_<%= objectType %>'
248
+ ),
249
+ awaitingMultipleStepIds
608
250
  );
609
251
 
610
252
  //(<beforePublish_<%= objectType %>>)
@@ -631,20 +273,20 @@ export default async function <%- flowTag %>(
631
273
  });
632
274
  }
633
275
 
634
- return 'complete beforeLogical <%= objectType %>';
276
+ return 'complete logical <%= objectType %>';
635
277
 
636
278
  <%_ } else { _%>
637
- // ── lambdaSyncInv only — collect results and proceed to updateMainLogical
638
- const beforeLogicalResults = lambdaSyncInvResults.reduce((acc, r) => {
639
- acc[r.flowTag] = r.returnValue;
640
- return acc;
641
- }, {});
279
+ // ── lambdaSyncInv only — collect results and proceed to updateLogicalLib
280
+ const phaseResults = Object.fromEntries(
281
+ lambdaSyncInvResults.map(({ flowTag: tag, returnValue }) => [tag, returnValue])
282
+ );
642
283
 
643
- return await <%- flowTag %>MainLogical(
284
+ return await <%- flowTag %>LogicalLib(
644
285
  _izContext,
645
286
  requestParams,
646
287
  callingFlowConfig,
647
- beforeLogicalResults
288
+ errorsFound,
289
+ phaseResults
648
290
  );
649
291
  <%_ } _%>
650
292
  }
@@ -653,11 +295,12 @@ export default async function <%- flowTag %>(
653
295
  //(<beforeUpdateMainLogical>)
654
296
  //(</beforeUpdateMainLogical>)
655
297
 
656
- // ── No beforeLogical → proceed directly to logical ────────────────────────
657
- return await <%- flowTag %>MainLogical(
298
+ // ── No optional phase → proceed directly to logical ──────────────────────
299
+ return await <%- flowTag %>LogicalLib(
658
300
  _izContext,
659
301
  requestParams,
660
- callingFlowConfig
302
+ callingFlowConfig,
303
+ errorsFound
661
304
  );
662
305
  } catch (err) {
663
306
  _izContext.logger.error('[<%- flowTag %>] error:', err);