@izara_project/izara-core-generate-service-code 1.0.84 → 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 (26) hide show
  1. package/package.json +1 -1
  2. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +5 -0
  3. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +13 -4
  4. package/src/emit/crud/crudActionPlan.js +3 -1
  5. package/src/emit/crud/emitCrudApplicationArtifacts.js +37 -4
  6. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +126 -21
  7. package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
  8. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +248 -181
  9. package/src/emit/crud/templates/CreateLogicalLib.ejs +1155 -293
  10. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
  11. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
  12. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +76 -14
  13. package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
  14. package/src/emit/rbac/templates/CancelUsage_Main.ejs +82 -22
  15. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +130 -14
  16. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +29 -10
  17. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +30 -11
  18. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +28 -3
  19. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +10 -7
  20. package/src/emit/resource/emitResourceArtifacts.js +9 -0
  21. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +3 -1
  22. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +2 -0
  23. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
  24. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +0 -1
  25. package/test/dynamicCrudFlowSchemas.test.js +16 -2
  26. package/test/resourceArtifacts.test.js +21 -0
@@ -50,228 +50,288 @@ const { createObjType, firstLetterUpperCase } = utils;
50
50
  const { createDataDetailsLib } = dataDetailsLib;
51
51
  const { createIdentifiersByUseCase } = identifiersObject;
52
52
 
53
+ // ── Helper Functions ──────────────────────────────────────────────────────────
54
+
53
55
  /**
54
- * Creates an object instance and proceeds directly to logical processing
55
- * @param {Object} _izContext - Context object with logger
56
- * @param {Object} requestParams - { fieldNames, relationships[] }
57
- * @param {Object} callingFlowConfig - Calling flow configuration
58
- * @returns {Promise<Object>}
56
+ * Loads Schema and resolves submittedByUserId and targetIdentifiers
57
+ * @param {Object} _izContext - Izara context object
58
+ * @param {Object} requestParams - Request parameters
59
+ * @param {Array<string>} errorsFound - Error list
60
+ * @returns {Promise<{ objType: Object, objectSchema: Object, targetIdentifiers?: Object }>}
59
61
  */
60
- export default async function <%- flowTag %>(
61
- _izContext,
62
- requestParams,
63
- callingFlowConfig = {},
64
- //(<additionalParams>)
65
- //(</additionalParams>)
66
- ) {
67
- try {
68
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createMain:`, {
69
- requestParams,
70
- callingFlowConfig
71
- });
72
-
73
- const errorsFound = [];
74
- const objType = createObjType(requestParams.objectType);
75
-
76
- // ── Load schema ───────────────────────────────────────────────────────────
77
- const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
78
- _izContext,
79
- objType
80
- );
81
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
82
-
83
- // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
84
- let submittedByUserId, targetIdentifiers;
85
- if (
86
- objectSchema.generatedBy === 'user' ||
87
- objectSchema.generatedBy === 'systemWithUser'
88
- ) {
89
- submittedByUserId =
90
- requestParams.submittedByUserId ||
91
- _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
62
+ async function resolveSchemaAndIdentity(_izContext, requestParams, errorsFound) {
63
+ const objType = createObjType(requestParams.objectType);
64
+ const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
65
+ _izContext,
66
+ objType
67
+ );
68
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
69
+
70
+ let submittedByUserId, targetIdentifiers;
71
+ if (
72
+ objectSchema.generatedBy === 'user' ||
73
+ objectSchema.generatedBy === 'systemWithUser'
74
+ ) {
75
+ submittedByUserId =
76
+ requestParams.submittedByUserId ||
77
+ _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
78
+
79
+ targetIdentifiers = requestParams.targetIdentifiers;
80
+
81
+ if (!targetIdentifiers && submittedByUserId) {
82
+ targetIdentifiers = { submittedByUserId };
83
+ }
92
84
 
93
- targetIdentifiers = requestParams.targetIdentifiers;
85
+ if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
86
+ if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
87
+ errorsFound.push('not have targetIdentifiers');
94
88
 
95
- if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
96
- targetIdentifiers = { submittedByUserId };
89
+ if (targetIdentifiers) {
90
+ if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
91
+ targetIdentifiers.submittedByUserId = submittedByUserId;
97
92
  }
98
93
 
99
- if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
100
- if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
101
- errorsFound.push('not have targetIdentifiers');
102
-
103
- requestParams.submittedByUserId = submittedByUserId;
104
- if (targetIdentifiers) {
105
- if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
106
- targetIdentifiers.submittedByUserId = submittedByUserId;
94
+ if (Array.isArray(objectSchema.identifiers)) {
95
+ for (const identifier of objectSchema.identifiers) {
96
+ if (identifier.fieldName) {
97
+ if (targetIdentifiers[identifier.fieldName] === undefined) {
98
+ targetIdentifiers[identifier.fieldName] = null;
99
+ }
100
+ } else if (Array.isArray(identifier.fieldNames)) {
101
+ for (const fn of identifier.fieldNames) {
102
+ if (targetIdentifiers[fn] === undefined) {
103
+ targetIdentifiers[fn] = null;
104
+ }
105
+ }
106
+ } else if (identifier.name) {
107
+ if (targetIdentifiers[identifier.name] === undefined) {
108
+ targetIdentifiers[identifier.name] = null;
109
+ }
110
+ }
107
111
  }
108
- requestParams.targetIdentifiers = targetIdentifiers;
109
112
  }
110
113
 
111
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
112
- submittedByUserId: requestParams.submittedByUserId,
113
- targetIdentifiers: requestParams.targetIdentifiers,
114
- belongTo: objectSchema.belongTo,
115
- generatedBy: objectSchema.generatedBy
116
- });
117
- } else if (objectSchema.generatedBy === 'searchResultGenerated') {
118
- throw new NoRetryError(
119
- 'error searchResultGenerated should not happen here'
120
- );
114
+ requestParams.targetIdentifiers = targetIdentifiers;
121
115
  }
122
116
 
123
- //(<beforeQuery>)
124
- //(</beforeQuery>)
117
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
118
+ submittedByUserId: requestParams.submittedByUserId,
119
+ targetIdentifiers: requestParams.targetIdentifiers,
120
+ belongTo: objectSchema.belongTo,
121
+ generatedBy: objectSchema.generatedBy
122
+ });
123
+ } else if (objectSchema.generatedBy === 'searchResultGenerated') {
124
+ throw new NoRetryError(
125
+ 'error searchResultGenerated should not happen here'
126
+ );
127
+ }
125
128
 
126
- // ── Build objectSchemas ───────────────────────────────────────────────────
127
- const objectSchemas =
128
- uploadUseCase.generateObjectSchemaForCombineFieldNames(
129
- _izContext,
130
- objectSchema
131
- );
132
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchemas:`, objectSchemas);
129
+ return { objType, objectSchema, targetIdentifiers };
130
+ }
133
131
 
134
- // ── Build createDataDetails ───────────────────────────────────────────────
135
- const createDataDetails = await createDataDetailsLib(
132
+ /**
133
+ * Resolves fromRequiredOnCreate fields and generates identifiers
134
+ * @param {Object} _izContext - Izara context object
135
+ * @param {Object} requestParams - Request parameters
136
+ * @param {Object} objectSchema - Base object schema
137
+ * @param {Object} objType - Object type
138
+ * @param {Object} targetIdentifiers - Target identifiers
139
+ * @param {Array<string>} errorsFound - Error list
140
+ * @returns {Promise<{ objectSchemas: Object, createDataDetails: Object }>}
141
+ */
142
+ async function resolveAndGenerateIdentifiers(
143
+ _izContext,
144
+ requestParams,
145
+ objectSchema,
146
+ objType,
147
+ targetIdentifiers,
148
+ errorsFound
149
+ ) {
150
+ const objectSchemas =
151
+ uploadUseCase.generateObjectSchemaForCombineFieldNames(
136
152
  _izContext,
137
- objectSchemas
153
+ objectSchema
138
154
  );
139
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createDataDetails:`, createDataDetails);
155
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchemas:`, objectSchemas);
140
156
 
141
- if (requestParams.relationships?.length > 0) {
142
- //(<beforeValidateRelationships>)
143
- //(</beforeValidateRelationships>)
144
- }
157
+ const createDataDetails = await createDataDetailsLib(
158
+ _izContext,
159
+ objectSchemas
160
+ );
161
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createDataDetails:`, createDataDetails);
145
162
 
146
- errorsFound.push(
147
- ...(await createNodeLib.validateRequiredOnCreateLinks(
148
- _izContext,
149
- objType,
150
- requestParams.relationships
151
- ))
152
- );
153
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound:`, errorsFound);
154
-
155
- // ── Resolve fromRequiredOnCreate fields ──────────────────────────────────
156
- if (objectSchemas.fieldNames) {
157
- if (!requestParams.fieldNames) requestParams.fieldNames = {};
158
- for (const [fieldName, val] of Object.entries(objectSchemas.fieldNames)) {
159
- if (val.fromRequiredOnCreate && requestParams.fieldNames[fieldName] === undefined) {
160
- const fromConfig = val.fromRequiredOnCreate;
161
- const sourceField = fromConfig.fieldName || fieldName;
162
- if (fromConfig.belongToObjType === true && targetIdentifiers) {
163
- const targetValue =
164
- targetIdentifiers[sourceField] !== undefined
165
- ? targetIdentifiers[sourceField]
166
- : Object.values(targetIdentifiers)[0];
167
- requestParams.fieldNames[fieldName] = targetValue;
168
- } else if (fromConfig.relType && requestParams.relationships?.length > 0) {
169
- const matchedRel = requestParams.relationships.find(
170
- (rel) =>
171
- rel.relType?.serviceTag === fromConfig.relType.serviceTag &&
172
- rel.relType?.relationshipTag === fromConfig.relType.relationshipTag
173
- );
174
- if (matchedRel?.targetIdentifiers?.[sourceField] !== undefined) {
175
- requestParams.fieldNames[fieldName] = matchedRel.targetIdentifiers[sourceField];
176
- }
163
+ if (requestParams.relationships?.length > 0) {
164
+ //(<beforeValidateRelationships>)
165
+ //(</beforeValidateRelationships>)
166
+ }
167
+
168
+ errorsFound.push(
169
+ ...(await createNodeLib.validateRequiredOnCreateLinks(
170
+ _izContext,
171
+ objType,
172
+ requestParams.relationships
173
+ ))
174
+ );
175
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound:`, errorsFound);
176
+
177
+ // ── Resolve fromRequiredOnCreate fields ──
178
+ if (objectSchemas.fieldNames) {
179
+ if (!requestParams.fieldNames) requestParams.fieldNames = {};
180
+ for (const [fieldName, val] of Object.entries(objectSchemas.fieldNames)) {
181
+ if (val.fromRequiredOnCreate && requestParams.fieldNames[fieldName] === undefined) {
182
+ const fromConfig = val.fromRequiredOnCreate;
183
+ const sourceField = fromConfig.fieldName || fieldName;
184
+ if (fromConfig.belongToObjType === true && targetIdentifiers) {
185
+ const targetValue =
186
+ targetIdentifiers[sourceField] !== undefined
187
+ ? targetIdentifiers[sourceField]
188
+ : Object.values(targetIdentifiers)[0];
189
+ requestParams.fieldNames[fieldName] = targetValue;
190
+ } else if (fromConfig.relType && requestParams.relationships?.length > 0) {
191
+ const matchedRel = requestParams.relationships.find(
192
+ (rel) =>
193
+ rel.relType?.serviceTag === fromConfig.relType.serviceTag &&
194
+ rel.relType?.relationshipTag === fromConfig.relType.relationshipTag
195
+ );
196
+ if (matchedRel?.targetIdentifiers?.[sourceField] !== undefined) {
197
+ requestParams.fieldNames[fieldName] = matchedRel.targetIdentifiers[sourceField];
177
198
  }
178
199
  }
179
200
  }
180
201
  }
202
+ }
181
203
 
182
- const listOfRequiredOnCreate = [];
183
- const listOfOptionalOnCreate = [];
184
-
185
- for (const [key, val] of Object.entries(objectSchemas.fieldNames)) {
186
- if (
187
- val.randomOnCreate === true ||
188
- val.requiredOnCreate === true ||
189
- val.fromRequiredOnCreate ||
190
- val.hashOnCreate?.length
191
- ) {
192
- listOfRequiredOnCreate.push(key);
193
- }
194
- if (val.requiredOnCreate === false && val.optionalOnCreate === true) {
195
- listOfOptionalOnCreate.push(key);
196
- }
204
+ // ── Resolve identifiers ──
205
+ let errors;
206
+ const identifiers = objectSchemas.identifiers;
207
+ let optionalOnCreateIdentifiers;
208
+
209
+ if (
210
+ identifiers.length === 1 &&
211
+ !identifiers[0].hasOwnProperty('fieldNames')
212
+ ) {
213
+ [requestParams, errors] = await createIdentifiersByUseCase(
214
+ _izContext,
215
+ requestParams,
216
+ objectSchemas,
217
+ identifiers[0],
218
+ optionalOnCreateIdentifiers
219
+ );
220
+ errorsFound.push(...errors);
221
+ } else if (identifiers.length > 1) {
222
+ for (const identifier of identifiers) {
223
+ [requestParams, errors] = await createIdentifiersByUseCase(
224
+ _izContext,
225
+ requestParams,
226
+ objectSchemas,
227
+ identifier,
228
+ optionalOnCreateIdentifiers
229
+ );
230
+ errorsFound.push(...errors);
197
231
  }
232
+ }
198
233
 
199
- _izContext.logger.debug('listOfRequiredOnCreate', listOfRequiredOnCreate);
200
- _izContext.logger.debug('listOfOptionalOnCreate', listOfOptionalOnCreate);
234
+ return { objectSchemas, createDataDetails };
235
+ }
201
236
 
202
- // ── Resolve identifiers ───────────────────────────────────────────────────
203
- let errors;
204
- const identifiers = objectSchemas.identifiers;
237
+ /**
238
+ * Validates request field names against schema
239
+ * @param {Object} requestParams - Request parameters
240
+ * @param {Object} objectSchemas - Combined schema
241
+ * @param {Array<string>} errorsFound - Error list
242
+ */
243
+ function validateFieldNames(requestParams, objectSchemas, errorsFound) {
244
+ const listOfRequiredOnCreate = [];
245
+ const listOfOptionalOnCreate = [];
205
246
 
206
- //(<createOptionalOnCreateIdentifiers>)
207
- let optionalOnCreateIdentifiers;
208
- //(</createOptionalOnCreateIdentifiers>)
247
+ for (const [key, val] of Object.entries(objectSchemas.fieldNames)) {
248
+ if (
249
+ val.randomOnCreate === true ||
250
+ val.requiredOnCreate === true ||
251
+ val.fromRequiredOnCreate ||
252
+ val.hashOnCreate?.length
253
+ ) {
254
+ listOfRequiredOnCreate.push(key);
255
+ }
256
+ if (val.requiredOnCreate === false && val.optionalOnCreate === true) {
257
+ listOfOptionalOnCreate.push(key);
258
+ }
259
+ }
209
260
 
261
+ for (const fieldName of Object.keys(requestParams.fieldNames)) {
210
262
  if (
211
- identifiers.length === 1 &&
212
- !identifiers[0].hasOwnProperty('fieldNames')
263
+ !listOfRequiredOnCreate.includes(fieldName) &&
264
+ !listOfOptionalOnCreate.includes(fieldName)
213
265
  ) {
214
- [requestParams, errors] = await createIdentifiersByUseCase(
266
+ errorsFound.push('[invalid] over fieldNames create object');
267
+ }
268
+ if (errorsFound.length > 0) {
269
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] HaveError:`, errorsFound);
270
+ break;
271
+ }
272
+ }
273
+ }
274
+
275
+ // ── Main Entry Function ───────────────────────────────────────────────────────
276
+
277
+ /**
278
+ * Creates an object instance and proceeds directly to logical processing
279
+ * @param {Object} _izContext - Context object with logger
280
+ * @param {Object} requestParams - { fieldNames, relationships[] }
281
+ * @param {Object} callingFlowConfig - Calling flow configuration
282
+ * @returns {Promise<Object>}
283
+ */
284
+ export default async function <%- flowTag %>(
285
+ _izContext,
286
+ requestParams,
287
+ callingFlowConfig = {},
288
+ //(<additionalParams>)
289
+ //(</additionalParams>)
290
+ ) {
291
+ try {
292
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] createMain:`, {
293
+ requestParams,
294
+ callingFlowConfig
295
+ });
296
+
297
+ const errorsFound = [];
298
+
299
+ // Step 1: Resolve Schema & Identity
300
+ const { objType, objectSchema, targetIdentifiers } =
301
+ await resolveSchemaAndIdentity(_izContext, requestParams, errorsFound);
302
+
303
+ //(<beforeQuery>)
304
+ //(</beforeQuery>)
305
+
306
+ // Step 2: Resolve fromRequiredOnCreate fields & Generate Identifiers
307
+ const { objectSchemas } = await resolveAndGenerateIdentifiers(
308
+ _izContext,
309
+ requestParams,
310
+ objectSchema,
311
+ objType,
312
+ targetIdentifiers,
313
+ errorsFound
314
+ );
315
+
316
+ if (errorsFound.length > 0) {
317
+ return await <%- flowTag %>LogicalLib(
215
318
  _izContext,
216
319
  requestParams,
217
- objectSchemas,
218
- identifiers[0],
219
- optionalOnCreateIdentifiers
320
+ callingFlowConfig,
321
+ errorsFound
220
322
  );
221
- } else if (identifiers.length > 1) {
222
- for (const identifier of identifiers) {
223
- [requestParams, errors] = await createIdentifiersByUseCase(
224
- _izContext,
225
- requestParams,
226
- objectSchemas,
227
- identifier,
228
- optionalOnCreateIdentifiers
229
- );
230
- }
231
323
  }
232
324
 
233
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams:`, requestParams);
234
- errorsFound.push(...errors);
235
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] errorsFound after identifiers:`, errorsFound);
325
+ // Step 3: Validate FieldNames
326
+ validateFieldNames(requestParams, objectSchemas, errorsFound);
236
327
 
237
- if (errorsFound.length > 0)
328
+ if (errorsFound.length > 0) {
238
329
  return await <%- flowTag %>LogicalLib(
239
330
  _izContext,
240
331
  requestParams,
241
332
  callingFlowConfig,
242
333
  errorsFound
243
334
  );
244
-
245
- // ── Validate fieldNames ───────────────────────────────────────────────────
246
- const objInstanceFull = { identifiers: {}, fields: {} };
247
-
248
- //(<optionalObjInstanceFull>)
249
- //(</optionalObjInstanceFull>)
250
-
251
- for (const fieldName of Object.keys(requestParams.fieldNames)) {
252
- if (
253
- !listOfRequiredOnCreate.includes(fieldName) &&
254
- !listOfOptionalOnCreate.includes(fieldName)
255
- ) {
256
- errorsFound.push('[invalid] over fieldNames create object');
257
- }
258
- if (
259
- listOfOptionalOnCreate.length > 0 &&
260
- listOfRequiredOnCreate.includes(fieldName)
261
- ) {
262
- //(<optionalParams>)
263
- //(</optionalParams>)
264
- }
265
- if (objectSchemas.identifierFieldNames.includes(fieldName)) {
266
- _izContext.logger.debug('identifiers is', fieldName);
267
- Object.assign(objInstanceFull.identifiers, {
268
- [fieldName]: requestParams.fieldNames[fieldName]
269
- });
270
- }
271
- if (errorsFound.length > 0) {
272
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] HaveError:`, errorsFound);
273
- break;
274
- }
275
335
  }
276
336
 
277
337
  <%_
@@ -306,6 +366,13 @@ export default async function <%- flowTag %>(
306
366
  const parameterGroups = {};
307
367
  //(</rbacParameterGroups_<%- flowTag %>)
308
368
 
369
+ const isBillable = objectSchema.addOnDataStructure?.some(
370
+ (item) => item.type === 'rbac' && item.billable === true
371
+ );
372
+ if (isBillable) {
373
+ requestParams.billable = true;
374
+ }
375
+
309
376
  const resultPermissionCheck = await checkRbacPermission(
310
377
  _izContext,
311
378
  {