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

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 (60) hide show
  1. package/package.json +4 -4
  2. package/src/compile/flowValidator.js +34 -0
  3. package/src/compile/loadSchemas.js +121 -7
  4. package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
  5. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +29 -1
  6. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +16 -3
  7. package/src/emit/crud/crudActionPlan.js +43 -7
  8. package/src/emit/crud/emitCrudApplicationArtifacts.js +19 -4
  9. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +27 -6
  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/CreateEndpoint_Main.ejs +75 -21
  15. package/src/emit/crud/templates/CreateLogicalLib.ejs +73 -8
  16. package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
  17. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +39 -11
  18. package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
  19. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +2 -2
  20. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -0
  21. package/src/emit/crud/templates/FlowMain_Wbs.ejs +5 -2
  22. package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
  23. package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
  24. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +53 -4
  25. package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
  26. package/src/emit/custom/customFlows.js +49 -0
  27. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
  28. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
  29. package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
  30. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
  31. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  32. package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
  33. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
  34. package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
  35. package/src/emit/rbac/templates/CancelUsage_Main.ejs +103 -0
  36. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +71 -0
  37. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +49 -6
  38. package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
  39. package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
  40. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +147 -0
  41. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +59 -23
  42. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +1 -1
  43. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
  44. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +10 -3
  45. package/src/emit/resource/emitResourceArtifacts.js +350 -112
  46. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +53 -2
  47. package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -4
  48. package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
  49. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +7 -0
  50. package/src/emit/systemText/emitSystemTextSchemas.js +3 -2
  51. package/src/generate.js +41 -10
  52. package/test/attributeTreeSchemas.test.js +219 -0
  53. package/test/createTargetRoleHandler.test.js +59 -4
  54. package/test/crudApplicationArtifacts.test.js +23 -6
  55. package/test/customFlowApplicationArtifacts.test.js +5 -5
  56. package/test/dynamicCrudFlowSchemas.test.js +110 -13
  57. package/test/dynamicRbacFlowSchemas.test.js +15 -2
  58. package/test/publicApi.test.js +7 -7
  59. package/test/resourceArtifacts.test.js +70 -29
  60. package/test/systemTextSchemas.test.js +1 -1
@@ -56,7 +56,7 @@ export default async function <%- flowTag %>(
56
56
  //(</additionalParams>)
57
57
  ) {
58
58
  try {
59
- _izContext.logger.debug('[<%- flowTag %>]', {
59
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] deleteMain:`, {
60
60
  requestParams,
61
61
  callingFlowConfig
62
62
  });
@@ -72,15 +72,42 @@ export default async function <%- flowTag %>(
72
72
  _izContext,
73
73
  objType
74
74
  );
75
- _izContext.logger.debug('objectSchema', objectSchema);
76
-
77
- // ── Resolve userId / targetId ─────────────────────────────────────────────
78
- if (objectSchema.generatedBy === 'userGenerated') {
79
- const userId = _izContext.correlationIds.get(coreConsts.BASE_USER_ID);
80
- const targetId = _izContext.correlationIds.get(coreConsts.TARGET_ID);
81
- if (!userId) errorsFound.push('Not have userId');
82
- if (objectSchema.hasOwnProperty('belongTo') && !targetId)
83
- errorsFound.push('not have targetId');
75
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
76
+
77
+ // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
78
+ let submittedByUserId, targetIdentifiers;
79
+ if (
80
+ objectSchema.generatedBy === 'user' ||
81
+ objectSchema.generatedBy === 'systemWithUser'
82
+ ) {
83
+ submittedByUserId =
84
+ requestParams.submittedByUserId ||
85
+ _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
86
+
87
+ targetIdentifiers = requestParams.targetIdentifiers;
88
+
89
+ if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
90
+ targetIdentifiers = { submittedByUserId };
91
+ }
92
+
93
+ if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
94
+ if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
95
+ errorsFound.push('not have targetIdentifiers');
96
+
97
+ requestParams.submittedByUserId = submittedByUserId;
98
+ if (targetIdentifiers) {
99
+ if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
100
+ targetIdentifiers.submittedByUserId = submittedByUserId;
101
+ }
102
+ requestParams.targetIdentifiers = targetIdentifiers;
103
+ }
104
+
105
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
106
+ submittedByUserId: requestParams.submittedByUserId,
107
+ targetIdentifiers: requestParams.targetIdentifiers,
108
+ belongTo: objectSchema.belongTo,
109
+ generatedBy: objectSchema.generatedBy
110
+ });
84
111
  }
85
112
 
86
113
  //(<beforeQuery>)
@@ -98,7 +125,7 @@ export default async function <%- flowTag %>(
98
125
  );
99
126
 
100
127
  <%_
101
- const rbacObjects = objects.filter(o => (o?.generatedBy === 'userGenerated' || o?.generatedBy === 'systemGenerated') && hasRbacAddOn(o));
128
+ const rbacObjects = objects.filter(o => isCrudObject(o) && hasRbacAddOn(o));
102
129
  const rbacObjectTypes = rbacObjects.map(o => o.objectType);
103
130
  const rbacServiceTagMap = {};
104
131
  for (const o of rbacObjects) {
@@ -312,6 +339,7 @@ export default async function <%- flowTag %>(
312
339
  errorsFound
313
340
  );
314
341
  } catch (err) {
342
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, err);
315
343
  throw err;
316
344
  }
317
345
  }
@@ -62,7 +62,7 @@ export async function <%- flowTag %>LogicalLib(
62
62
  phaseResults = {}
63
63
  ) {
64
64
  try {
65
- _izContext.logger.debug('[<%- flowTag %>LogicalLib] started', {
65
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
66
66
  requestParams,
67
67
  callingFlowConfig,
68
68
  phaseResults
@@ -78,14 +78,14 @@ export async function <%- flowTag %>LogicalLib(
78
78
  _izContext,
79
79
  objType
80
80
  );
81
- _izContext.logger.debug('objectSchema', objectSchema);
81
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
82
82
 
83
83
  // ── Build deleteDataDetails ───────────────────────────────────────────────
84
84
  const deleteDataDetails = await createDeleteDataDetail(
85
85
  _izContext,
86
86
  objectSchema
87
87
  );
88
- _izContext.logger.debug('deleteDataDetails', deleteDataDetails);
88
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] deleteDataDetails:`, deleteDataDetails);
89
89
 
90
90
  if (objectSchema.canDelete === false || objectSchema.canDelete == null) {
91
91
  errorsFound.push("this objectSchema can't delete");
@@ -119,6 +119,7 @@ export async function <%- flowTag %>LogicalLib(
119
119
  return {
120
120
  objType,
121
121
  identifiers: requestParams.identifiers,
122
+ targetIdentifiers: requestParams.targetIdentifiers,
122
123
  status: 'error',
123
124
  errorsFound
124
125
  };
@@ -201,10 +202,12 @@ export async function <%- flowTag %>LogicalLib(
201
202
  return {
202
203
  objType,
203
204
  identifiers: requestParams.identifiers,
205
+ targetIdentifiers: requestParams.targetIdentifiers,
204
206
  status: 'complete',
205
207
  errorsFound
206
208
  };
207
209
  } catch (err) {
210
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
208
211
  throw err;
209
212
  }
210
213
  }
@@ -49,7 +49,7 @@ export default async function <%- flowTag %>RbacCallbackMain(
49
49
  callingFlowConfig = {}
50
50
  ) {
51
51
  try {
52
- _izContext.logger.debug('[<%- flowTag %>RbacCallbackMain] Started with params:', {
52
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] Started with params:`, {
53
53
  requestParams,
54
54
  flowTag,
55
55
  callingFlowConfig
@@ -209,7 +209,7 @@ export default async function <%- flowTag %>RbacCallbackMain(
209
209
 
210
210
  return logicalResult;
211
211
  } catch (err) {
212
- _izContext.logger.error('[<%- flowTag %>RbacCallbackMain] Error caught:', {
212
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] Error caught:`, {
213
213
  error: err
214
214
  });
215
215
  throw err;
@@ -100,6 +100,13 @@ export const main = middleware.wrap(async (event, context) => {
100
100
  );
101
101
  }
102
102
 
103
+ if (!eventParams.submittedByUserId) {
104
+ const contextUserId = event._izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
105
+ if (contextUserId) {
106
+ eventParams.submittedByUserId = contextUserId;
107
+ }
108
+ }
109
+
103
110
  let callingFlow = eventParams?.callingFlow
104
111
  ? eventParams.callingFlow
105
112
  : {};
@@ -70,7 +70,10 @@ export default async function <%- typeof functionName !== 'undefined' ? function
70
70
 
71
71
  _izContext.logger.debug('flowSchema', flowSchema);
72
72
 
73
- if (flowSchema.initiateBy === 'user') {
73
+ if (
74
+ flowSchema.initiateBy === 'user' ||
75
+ flowSchema.initiateBy === 'systemWithUser'
76
+ ) {
74
77
  _izContext.correlationIds.set(coreConsts.USER_AGENT, 'webSocket');
75
78
  }
76
79
 
@@ -117,7 +120,7 @@ export default async function <%- typeof functionName !== 'undefined' ? function
117
120
  _izContext.logger.debug('sendMessageToEndpoint', sendMessageToEndpoint);
118
121
  await sns.publishAsync(_izContext, sendMessageToEndpoint);
119
122
  } catch (err) {
120
- _izContext.logger.error('error WebSocketInvoke: ', err);
123
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- typeof functionName !== undefined ? functionName : upperCaseFlowTag %>Wbs] error:`, err);
121
124
  throw err;
122
125
  }
123
126
  }
@@ -68,6 +68,19 @@ export default async function <%- flowTag %>(
68
68
  callingFlowConfig
69
69
  });
70
70
 
71
+ // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
72
+ const submittedByUserId =
73
+ requestParams.submittedByUserId ||
74
+ _izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID);
75
+ if (submittedByUserId) {
76
+ requestParams.submittedByUserId = submittedByUserId;
77
+ }
78
+
79
+ const targetIdentifiers = requestParams.targetIdentifiers;
80
+ if (targetIdentifiers) {
81
+ requestParams.targetIdentifiers = targetIdentifiers;
82
+ }
83
+
71
84
  // ── Settings ──────────────────────────────────────────────────────────────
72
85
  const settings = requestParams.additionalParams?.settings ?? {};
73
86
  const returnSystemFieldsName = settings.returnSystemFieldsName === true;
@@ -52,7 +52,7 @@ export default async function UpdateComplete(
52
52
  //(</additionalParams>)
53
53
  ) {
54
54
  try {
55
- _izContext.logger.debug('[UpdateComplete] started', {
55
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:UpdateComplete] started`, {
56
56
  requestParams
57
57
  });
58
58
  const {
@@ -78,9 +78,58 @@ export default async function <%- flowTag %>(
78
78
  callingFlowConfig
79
79
  });
80
80
 
81
+ const errorsFound = [];
82
+ const objType = createObjType(requestParams.objectType);
83
+
84
+ // ── Load schema ───────────────────────────────────────────────────────────
85
+ const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
86
+ _izContext,
87
+ objType
88
+ );
89
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
90
+
91
+ // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
92
+ let submittedByUserId, targetIdentifiers;
93
+ if (
94
+ objectSchema.generatedBy === 'user' ||
95
+ objectSchema.generatedBy === 'systemWithUser'
96
+ ) {
97
+ submittedByUserId =
98
+ requestParams.submittedByUserId ||
99
+ _izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID);
100
+
101
+ targetIdentifiers = requestParams.targetIdentifiers;
102
+
103
+ if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
104
+ targetIdentifiers = { submittedByUserId };
105
+ }
106
+
107
+ if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
108
+ if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
109
+ errorsFound.push('not have targetIdentifiers');
110
+
111
+ requestParams.submittedByUserId = submittedByUserId;
112
+ if (targetIdentifiers) {
113
+ if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
114
+ targetIdentifiers.submittedByUserId = submittedByUserId;
115
+ }
116
+ requestParams.targetIdentifiers = targetIdentifiers;
117
+ }
118
+
119
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
120
+ submittedByUserId: requestParams.submittedByUserId,
121
+ targetIdentifiers: requestParams.targetIdentifiers,
122
+ belongTo: objectSchema.belongTo,
123
+ generatedBy: objectSchema.generatedBy
124
+ });
125
+ } else if (objectSchema.generatedBy === 'searchResultGenerated') {
126
+ throw new NoRetryError(
127
+ 'error searchResultGenerated should not happen here'
128
+ );
129
+ }
130
+
81
131
  // ── Build identifiers used by asynchronous processing ────────────────────
82
132
  const identifiers = requestParams.objInstanceFull.identifiers;
83
- const errorsFound = [];
84
133
 
85
134
  //(<validateBeforeUpdate>)
86
135
  //(</validateBeforeUpdate>)
@@ -94,7 +143,7 @@ export default async function <%- flowTag %>(
94
143
  );
95
144
 
96
145
  <%_
97
- const rbacObjects = objects.filter(o => (o?.generatedBy === 'userGenerated' || o?.generatedBy === 'systemGenerated') && hasRbacAddOn(o));
146
+ const rbacObjects = objects.filter(o => isCrudObject(o) && hasRbacAddOn(o));
98
147
  const rbacObjectTypes = rbacObjects.map(o => o.objectType);
99
148
  const rbacServiceTagMap = {};
100
149
  for (const o of rbacObjects) {
@@ -142,7 +191,7 @@ export default async function <%- flowTag %>(
142
191
  );
143
192
 
144
193
  _izContext.logger.debug(
145
- '[lib:auth:checkRbacPermission] resultPermissionCheck:',
194
+ `[${process.env.iz_serviceTag}:<%- flowTag %>] checkRbacPermission result:`,
146
195
  resultPermissionCheck
147
196
  );
148
197
 
@@ -308,7 +357,7 @@ export default async function <%- flowTag %>(
308
357
  errorsFound
309
358
  );
310
359
  } catch (err) {
311
- _izContext.logger.error('[<%- flowTag %>] error:', err);
360
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, err);
312
361
  throw err;
313
362
  }
314
363
  }
@@ -72,7 +72,7 @@ export async function <%- flowTag %>LogicalLib(
72
72
  phaseResults = {}
73
73
  ) {
74
74
  try {
75
- _izContext.logger.debug('[<%- flowTag %>LogicalLib] started', {
75
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
76
76
  requestParams,
77
77
  callingFlowConfig,
78
78
  phaseResults
@@ -96,7 +96,7 @@ export async function <%- flowTag %>LogicalLib(
96
96
  _izContext,
97
97
  objType
98
98
  );
99
- _izContext.logger.debug('objectSchema', objectSchema);
99
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
100
100
 
101
101
  const objectSchemas =
102
102
  await uploadUseCase.generateObjectSchemaForCombineFieldNames(
@@ -110,7 +110,7 @@ export async function <%- flowTag %>LogicalLib(
110
110
  _izContext,
111
111
  objectSchemas
112
112
  );
113
- _izContext.logger.debug('updateDataDetails', updateDataDetails);
113
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] updateDataDetails:`, updateDataDetails);
114
114
 
115
115
  const originTimestamp = Date.now();
116
116
 
@@ -468,6 +468,7 @@ export async function <%- flowTag %>LogicalLib(
468
468
  errorsFound
469
469
  };
470
470
  } catch (err) {
471
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
471
472
  _izContext.logger.error('[<%- flowTag %>LogicalLib] error:', err);
472
473
  throw err;
473
474
  }
@@ -23,6 +23,7 @@ export function supportedCustomFlows(flows) {
23
23
  }
24
24
 
25
25
  export function customFlowRoleName(flowTag) {
26
+ if (!flowTag || typeof flowTag !== 'string') return '';
26
27
  return `${upperFirst(flowTag)}Role`;
27
28
  }
28
29
 
@@ -48,6 +49,7 @@ export function flowExtTopicSteps(flows) {
48
49
  typeof step?.stepName !== 'string' ||
49
50
  step.stepName === '' ||
50
51
  step.stepName.toLowerCase() === 'start' ||
52
+ step.stepName.toLowerCase() === 'rbaccallback' ||
51
53
  !Array.isArray(step.event) ||
52
54
  !step.event.includes('extTopic')
53
55
  ) {
@@ -137,6 +139,7 @@ export function generatedDsqFlows(flows) {
137
139
  }
138
140
 
139
141
  export function upperFirst(value) {
142
+ if (typeof value !== 'string' || value.length === 0) return '';
140
143
  return value[0].toUpperCase() + value.slice(1);
141
144
  }
142
145
 
@@ -240,3 +243,49 @@ export function customFlowNextSteps(flows) {
240
243
  }
241
244
  return results;
242
245
  }
246
+
247
+ export function flowHasRbac(flow, objects = []) {
248
+ if (!flow || !flow.objType || typeof flow.objType !== "object") return false;
249
+ const candidates = objects.filter(
250
+ (o) => o.objectType === flow.objType.objectType
251
+ );
252
+ const object = flow.objType.serviceTag
253
+ ? (candidates.find((o) => o.serviceTag === flow.objType.serviceTag) ??
254
+ candidates.find((o) => o.serviceTag === undefined) ??
255
+ candidates[0])
256
+ : candidates[0];
257
+ if (!object) return false;
258
+ return hasRbacObject(object, objects);
259
+ }
260
+
261
+ function hasRbacObject(object, objects = []) {
262
+ return (
263
+ hasSelfRbac(object) ||
264
+ (Array.isArray(object?.belongToSchema?.addOnDataStructure) &&
265
+ object.belongToSchema.addOnDataStructure.some(
266
+ (addOn) => addOn?.type === "rbac"
267
+ )) ||
268
+ normalizeBelongTo(object).some((target) => {
269
+ if (target?.serviceTag === "UserAccount") return true;
270
+ const matched = objects.find(
271
+ (candidate) =>
272
+ candidate?.serviceTag === target?.serviceTag &&
273
+ candidate?.objectType === target?.objectType
274
+ );
275
+ return hasSelfRbac(matched);
276
+ })
277
+ );
278
+ }
279
+
280
+ function hasSelfRbac(object) {
281
+ return (
282
+ Array.isArray(object?.addOnDataStructure) &&
283
+ object.addOnDataStructure.some((addOn) => addOn?.type === "rbac")
284
+ );
285
+ }
286
+
287
+ function normalizeBelongTo(object) {
288
+ const belongTo = object?.belongTo;
289
+ if (!belongTo) return [];
290
+ return Array.isArray(belongTo) ? belongTo : [belongTo];
291
+ }