@izara_project/izara-core-generate-service-code 1.0.87 → 1.0.89
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.
- package/package.json +1 -1
- package/src/compile/flowValidator.js +25 -0
- package/src/compile/loadSchemas.js +199 -10
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
- package/src/emit/crud/crudActionPlan.js +105 -6
- package/src/emit/crud/emitCrudApplicationArtifacts.js +63 -3
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
- package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +121 -0
- package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +108 -0
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +140 -340
- package/src/emit/crud/templates/CreateLogicalLib.ejs +338 -82
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +90 -0
- package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
- package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +99 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +151 -179
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +244 -27
- package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
- package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +112 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +166 -185
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +123 -3
- package/src/emit/custom/customFlows.js +3 -1
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +8 -2
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +34 -14
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +34 -14
- package/src/emit/resource/emitResourceArtifacts.js +119 -59
- package/test/crudApplicationArtifacts.test.js +876 -0
- package/test/dynamicCrudFlowSchemas.test.js +10 -5
- package/test/dynamicRbacFlowSchemas.test.js +24 -2
- package/test/graphDrivenFlowSchema.test.js +36 -0
- package/test/resourceArtifacts.test.js +271 -12
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
objectHash as hash,
|
|
20
20
|
identifierUuid
|
|
21
21
|
} from '@izara_project/izara-shared-core';
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
import {
|
|
24
24
|
sns,
|
|
25
25
|
lambda
|
|
@@ -29,17 +29,18 @@ import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow
|
|
|
29
29
|
import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
|
|
30
30
|
import {
|
|
31
31
|
consts,
|
|
32
|
-
getObjectSchema,
|
|
33
32
|
utils
|
|
34
33
|
} from '@izara_project/izara-core-library-service-schemas';
|
|
35
34
|
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
36
35
|
|
|
37
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
<%- flowTag %>LogicalLib,
|
|
38
|
+
resolveSchemaAndIdentity
|
|
39
|
+
} from './<%- upperCaseFlowTag %>LogicalLib.js';
|
|
38
40
|
|
|
39
41
|
//(<optionalRequire>)
|
|
40
42
|
//(</optionalRequire>)
|
|
41
43
|
|
|
42
|
-
const { createObjType } = utils;
|
|
43
44
|
|
|
44
45
|
/**
|
|
45
46
|
* Deletes an object instance with optional RBAC routing
|
|
@@ -62,53 +63,13 @@ export default async function <%- flowTag %>(
|
|
|
62
63
|
});
|
|
63
64
|
|
|
64
65
|
const errorsFound = [];
|
|
65
|
-
const objType = createObjType(requestParams.objectType);
|
|
66
66
|
|
|
67
67
|
//(<beforeDelete>)
|
|
68
68
|
//(</beforeDelete>)
|
|
69
69
|
|
|
70
|
-
// ──
|
|
71
|
-
const objectSchema
|
|
72
|
-
_izContext,
|
|
73
|
-
objType
|
|
74
|
-
);
|
|
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
|
-
delete requestParams.targetIdentifiers;
|
|
89
|
-
|
|
90
|
-
if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
|
|
91
|
-
targetIdentifiers = { submittedByUserId };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
|
|
95
|
-
if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
|
|
96
|
-
errorsFound.push('not have targetIdentifiers');
|
|
97
|
-
|
|
98
|
-
requestParams.submittedByUserId = submittedByUserId;
|
|
99
|
-
if (targetIdentifiers) {
|
|
100
|
-
if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
|
|
101
|
-
targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
|
|
106
|
-
submittedByUserId: requestParams.submittedByUserId,
|
|
107
|
-
targetIdentifiers,
|
|
108
|
-
belongTo: objectSchema.belongTo,
|
|
109
|
-
generatedBy: objectSchema.generatedBy
|
|
110
|
-
});
|
|
111
|
-
}
|
|
70
|
+
// ── Resolve Schema & Identity ─────────────────────────────────────────────
|
|
71
|
+
const { objType, objectSchema, targetIdentifiers } =
|
|
72
|
+
await resolveSchemaAndIdentity(_izContext, requestParams, errorsFound);
|
|
112
73
|
|
|
113
74
|
//(<beforeQuery>)
|
|
114
75
|
//(</beforeQuery>)
|
|
@@ -116,36 +77,36 @@ export default async function <%- flowTag %>(
|
|
|
116
77
|
// ── Build identifiers used by asynchronous processing ────────────────────
|
|
117
78
|
const identifiers = requestParams.identifiers;
|
|
118
79
|
|
|
119
|
-
if (!objectSchema.hasOwnProperty('belongTo')) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (targetIdentifiers && identifiers) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
80
|
+
// if (!objectSchema.hasOwnProperty('belongTo')) {
|
|
81
|
+
// if (!targetIdentifiers && identifiers) {
|
|
82
|
+
// targetIdentifiers = { ...identifiers };
|
|
83
|
+
// } else if (targetIdentifiers && identifiers) {
|
|
84
|
+
// for (const [key, value] of Object.entries(identifiers)) {
|
|
85
|
+
// if (targetIdentifiers[key] === undefined && value !== undefined) {
|
|
86
|
+
// targetIdentifiers[key] = value;
|
|
87
|
+
// }
|
|
88
|
+
// }
|
|
89
|
+
// }
|
|
90
|
+
// if (targetIdentifiers) {
|
|
91
|
+
// if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
|
|
92
|
+
// targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
93
|
+
// }
|
|
94
|
+
// }
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
// if (targetIdentifiers && identifiers) {
|
|
98
|
+
// for (const [key, value] of Object.entries(identifiers)) {
|
|
99
|
+
// if (
|
|
100
|
+
// targetIdentifiers[key] !== undefined &&
|
|
101
|
+
// value !== undefined &&
|
|
102
|
+
// targetIdentifiers[key] !== value
|
|
103
|
+
// ) {
|
|
104
|
+
// errorsFound.push(
|
|
105
|
+
// `targetIdentifiers.${key} must match identifiers.${key}`
|
|
106
|
+
// );
|
|
107
|
+
// }
|
|
108
|
+
// }
|
|
109
|
+
// }
|
|
149
110
|
|
|
150
111
|
if (errorsFound.length > 0)
|
|
151
112
|
return await <%- flowTag %>LogicalLib(
|
|
@@ -227,110 +188,117 @@ export default async function <%- flowTag %>(
|
|
|
227
188
|
|
|
228
189
|
// ── Optional phase extension point ────────────────────────────────────────
|
|
229
190
|
<%_
|
|
230
|
-
const
|
|
191
|
+
const allCrudObjectTypes = (objects || []).filter(isCrudObject).map(o => o.objectType);
|
|
192
|
+
const beforeHooksByObjType = (plan?.beforeHooks || []).reduce((acc, hook) => {
|
|
193
|
+
const targets = (hook?.targetObjectTypes && hook.targetObjectTypes.length > 0)
|
|
194
|
+
? hook.targetObjectTypes
|
|
195
|
+
: allCrudObjectTypes;
|
|
196
|
+
for (const key of targets) {
|
|
197
|
+
if (!acc[key]) acc[key] = [];
|
|
198
|
+
acc[key].push(hook);
|
|
199
|
+
}
|
|
200
|
+
return acc;
|
|
201
|
+
}, {});
|
|
231
202
|
_%>
|
|
232
|
-
<%_ Object.entries(
|
|
203
|
+
<%_ Object.entries(beforeHooksByObjType).forEach(([objectType, configs]) => { _%>
|
|
233
204
|
<%_
|
|
234
|
-
const hasOwnTopic
|
|
235
|
-
const hasLambdaSyncInv = configs.some(c => c
|
|
236
|
-
|
|
205
|
+
const hasOwnTopic = configs.some(c => c?.generatedCodeConfig?.invocationType === 'ownTopic' || c?.event?.includes('ownTopic'));
|
|
206
|
+
const hasLambdaSyncInv = configs.some(c => c?.generatedCodeConfig?.invocationType === 'lambdaSyncInv' || c?.event?.includes('lambdaSyncInv'));
|
|
207
|
+
_%>
|
|
237
208
|
if (requestParams.objectType === '<%= objectType %>') {
|
|
238
209
|
<%_ if (hasLambdaSyncInv) { _%>
|
|
239
|
-
const lambdaSyncInvResults =
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
210
|
+
const lambdaSyncInvResults = [];
|
|
211
|
+
<%_ for (const config of configs.filter(c => c?.generatedCodeConfig?.invocationType === 'lambdaSyncInv' || c?.event?.includes('lambdaSyncInv'))) { _%>
|
|
212
|
+
try {
|
|
213
|
+
let hookPayload_<%= config.flowTag %> = {
|
|
214
|
+
objType,
|
|
215
|
+
identifiers: requestParams.identifiers,
|
|
216
|
+
targetIdentifiers,
|
|
217
|
+
submittedByUserId: requestParams.submittedByUserId
|
|
218
|
+
};
|
|
219
|
+
//(<beforeSendHook_<%= config.flowTag %>>)
|
|
220
|
+
//(</beforeSendHook_<%= config.flowTag %>>)
|
|
221
|
+
const returnValue = await lambda.invokeSync(
|
|
222
|
+
_izContext,
|
|
223
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
244
224
|
_izContext,
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
225
|
+
'<%= config.flowTag %>'
|
|
226
|
+
),
|
|
227
|
+
{
|
|
228
|
+
requestParams: hookPayload_<%= config.flowTag %>,
|
|
229
|
+
callingFlowConfig
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
lambdaSyncInvResults.push({
|
|
233
|
+
flowTag: '<%= config.flowTag %>',
|
|
234
|
+
returnValue
|
|
235
|
+
});
|
|
236
|
+
if (returnValue?.errorsFound?.length > 0) {
|
|
237
|
+
errorsFound.push(...returnValue.errorsFound);
|
|
238
|
+
} else if (returnValue?.status === 'error') {
|
|
239
|
+
errorsFound.push('Error from <%= config.flowTag %>');
|
|
240
|
+
} else {
|
|
241
|
+
if (returnValue?.identifiers && requestParams?.identifiers) {
|
|
242
|
+
Object.assign(requestParams.identifiers, returnValue.identifiers);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} catch (hookErr) {
|
|
246
|
+
_izContext.logger.error(
|
|
247
|
+
'[<%- flowTag %>] Sync hook <%= config.flowTag %> error:',
|
|
248
|
+
hookErr
|
|
249
|
+
);
|
|
250
|
+
errorsFound.push(hookErr.message || 'Hook <%= config.flowTag %> failed');
|
|
251
|
+
}
|
|
252
|
+
<%_ } _%>
|
|
253
|
+
|
|
254
|
+
if (errorsFound.length > 0) {
|
|
255
|
+
return await <%- flowTag %>LogicalLib(
|
|
256
|
+
_izContext,
|
|
257
|
+
requestParams,
|
|
258
|
+
callingFlowConfig,
|
|
259
|
+
errorsFound
|
|
260
|
+
);
|
|
261
|
+
}
|
|
258
262
|
<%_ } _%>
|
|
259
263
|
|
|
260
264
|
//(<afterBeforeLogical_<%= objectType %>>)
|
|
261
265
|
//(</afterBeforeLogical_<%= objectType %>>)
|
|
262
266
|
|
|
263
267
|
<%_ if (hasOwnTopic) { _%>
|
|
264
|
-
// ── ownTopic (async —
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
recordMsgs.push({
|
|
279
|
-
msg: callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
280
|
-
requestParams,
|
|
268
|
+
// ── ownTopic (async — dispatch to before-hook and await callback) ──────────
|
|
269
|
+
<%_ configs.filter(c => c?.generatedCodeConfig?.invocationType === 'ownTopic' || c?.event?.includes('ownTopic')).forEach(config => { _%>
|
|
270
|
+
let hookPayload_<%= config.flowTag %> = {
|
|
271
|
+
objType,
|
|
272
|
+
identifiers: requestParams.identifiers,
|
|
273
|
+
targetIdentifiers,
|
|
274
|
+
submittedByUserId: requestParams.submittedByUserId
|
|
275
|
+
};
|
|
276
|
+
//(<beforeSendHook_<%= config.flowTag %>>)
|
|
277
|
+
//(</beforeSendHook_<%= config.flowTag %>>)
|
|
278
|
+
const hookMsg_<%= config.flowTag %> =
|
|
279
|
+
callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
280
|
+
hookPayload_<%= config.flowTag %>,
|
|
281
281
|
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
282
282
|
callingFlowConfig,
|
|
283
283
|
callingFlowSharedLib.createCallingFlowConfig(
|
|
284
|
-
//(<callingFlowProperties_<%= config.flowTag %>>)
|
|
285
284
|
await lambdaSharedLib.lambdaFunctionName(
|
|
286
285
|
_izContext,
|
|
287
|
-
'
|
|
286
|
+
'<%- flowTag %>BeforeHookCallbackHdrSqs'
|
|
288
287
|
),
|
|
289
|
-
{
|
|
290
|
-
|
|
288
|
+
{
|
|
289
|
+
originalRequestParams: {
|
|
290
|
+
...requestParams,
|
|
291
|
+
objType,
|
|
292
|
+
targetIdentifiers
|
|
293
|
+
},
|
|
294
|
+
callingFlowConfig
|
|
295
|
+
}
|
|
291
296
|
)
|
|
292
297
|
)
|
|
293
|
-
)
|
|
294
|
-
flowTag: '<%= config.flowTag.charAt(0).toUpperCase() + config.flowTag.slice(1) %>'
|
|
295
|
-
});
|
|
296
|
-
<%_ }) _%>
|
|
297
|
-
|
|
298
|
-
<%_ if (hasLambdaSyncInv) { _%>
|
|
299
|
-
// ── Add lambdaSyncInv results to awaitingSteps ────────────────────────
|
|
300
|
-
for (const syncResult of lambdaSyncInvResults) {
|
|
301
|
-
awaitingMultipleStepIds.push({
|
|
302
|
-
awaitingStepId: await asyncFlowSharedLib.createAwaitingStepId(
|
|
303
|
-
hash(identifiers),
|
|
304
|
-
'logical_<%= objectType %>_' + syncResult.flowTag
|
|
305
|
-
),
|
|
306
|
-
additionalAttributes: {
|
|
307
|
-
complete: true,
|
|
308
|
-
errorsFound: [],
|
|
309
|
-
returnValue: syncResult.returnValue
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
<%_ } _%>
|
|
314
|
-
|
|
315
|
-
await asyncFlowSharedLib.createAwaitingMultipleSteps(
|
|
316
|
-
_izContext,
|
|
317
|
-
asyncFlowSharedLib.createPendingStepId(
|
|
318
|
-
_izContext.uniqueRequestId,
|
|
319
|
-
'logical_<%= objectType %>'
|
|
320
|
-
),
|
|
321
|
-
awaitingMultipleStepIds,
|
|
322
|
-
{
|
|
323
|
-
additionalAttributes: {
|
|
324
|
-
callingFlowConfig
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
);
|
|
328
|
-
|
|
329
|
-
//(<beforePublish_<%= objectType %>>)
|
|
330
|
-
//(</beforePublish_<%= objectType %>>)
|
|
298
|
+
);
|
|
331
299
|
|
|
332
|
-
|
|
333
|
-
|
|
300
|
+
const messageAttributes_<%= config.flowTag %> =
|
|
301
|
+
sns.createStringMessageAttributes(
|
|
334
302
|
_izContext,
|
|
335
303
|
callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
|
|
336
304
|
callingFlowConfig,
|
|
@@ -338,32 +306,36 @@ export default async function <%- flowTag %>(
|
|
|
338
306
|
)
|
|
339
307
|
);
|
|
340
308
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
309
|
+
const topicArn_<%= config.flowTag %> = snsSharedLib.snsTopicArnByFlowSchema(
|
|
310
|
+
_izContext,
|
|
311
|
+
'<%= config.flowTag %>_In'
|
|
312
|
+
);
|
|
345
313
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
314
|
+
_izContext.logger.debug(
|
|
315
|
+
`[${process.env.iz_serviceTag}:<%- flowTag %>] Dispatching to BeforeHook:`,
|
|
316
|
+
{
|
|
317
|
+
topicArn: topicArn_<%= config.flowTag %>,
|
|
318
|
+
flowTag: '<%= config.flowTag %>'
|
|
319
|
+
}
|
|
320
|
+
);
|
|
352
321
|
|
|
353
|
-
|
|
322
|
+
await sns.publishAsync(_izContext, {
|
|
323
|
+
Message: JSON.stringify(hookMsg_<%= config.flowTag %>),
|
|
324
|
+
MessageAttributes: messageAttributes_<%= config.flowTag %>,
|
|
325
|
+
TopicArn: topicArn_<%= config.flowTag %>
|
|
326
|
+
});
|
|
327
|
+
<%_ }) _%>
|
|
354
328
|
|
|
329
|
+
return {
|
|
330
|
+
status: 'pending',
|
|
331
|
+
message: 'Dispatched to BeforeHook'
|
|
332
|
+
};
|
|
355
333
|
<%_ } else { _%>
|
|
356
|
-
// ── lambdaSyncInv only — collect results and proceed to deleteLogicalLib
|
|
357
|
-
const phaseResults = Object.fromEntries(
|
|
358
|
-
lambdaSyncInvResults.map(({ flowTag: tag, returnValue }) => [tag, returnValue])
|
|
359
|
-
);
|
|
360
|
-
|
|
361
334
|
return await <%- flowTag %>LogicalLib(
|
|
362
335
|
_izContext,
|
|
363
336
|
requestParams,
|
|
364
337
|
callingFlowConfig,
|
|
365
|
-
errorsFound
|
|
366
|
-
phaseResults
|
|
338
|
+
errorsFound
|
|
367
339
|
);
|
|
368
340
|
<%_ } _%>
|
|
369
341
|
}
|