@izara_project/izara-core-generate-service-code 1.0.87 → 1.0.88
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/loadSchemas.js +45 -10
- package/src/emit/crud/crudActionPlan.js +46 -5
- package/src/emit/crud/emitCrudApplicationArtifacts.js +63 -3
- 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 +126 -332
- package/src/emit/crud/templates/CreateLogicalLib.ejs +120 -22
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +80 -0
- package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +99 -0
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +141 -179
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +132 -26
- package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +112 -0
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +154 -185
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +2 -2
- package/src/emit/custom/customFlows.js +3 -1
- package/src/emit/resource/emitResourceArtifacts.js +110 -57
- package/test/crudApplicationArtifacts.test.js +531 -0
- package/test/resourceArtifacts.test.js +200 -12
|
@@ -102,27 +102,27 @@ export async function resolveSchemaAndIdentity(_izContext, requestParams, errors
|
|
|
102
102
|
targetIdentifiers.submittedByUserId = submittedByUserId;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
if (Array.isArray(objectSchema.identifiers)) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
requestParams.targetIdentifiers = targetIdentifiers;
|
|
105
|
+
// if (Array.isArray(objectSchema.identifiers)) {
|
|
106
|
+
// for (const identifier of objectSchema.identifiers) {
|
|
107
|
+
// if (identifier.fieldName) {
|
|
108
|
+
// if (targetIdentifiers[identifier.fieldName] === undefined) {
|
|
109
|
+
// targetIdentifiers[identifier.fieldName] = null;
|
|
110
|
+
// }
|
|
111
|
+
// } else if (Array.isArray(identifier.fieldNames)) {
|
|
112
|
+
// for (const fn of identifier.fieldNames) {
|
|
113
|
+
// if (targetIdentifiers[fn] === undefined) {
|
|
114
|
+
// targetIdentifiers[fn] = null;
|
|
115
|
+
// }
|
|
116
|
+
// }
|
|
117
|
+
// } else if (identifier.name) {
|
|
118
|
+
// if (targetIdentifiers[identifier.name] === undefined) {
|
|
119
|
+
// targetIdentifiers[identifier.name] = null;
|
|
120
|
+
// }
|
|
121
|
+
// }
|
|
122
|
+
// }
|
|
123
|
+
// }
|
|
124
|
+
|
|
125
|
+
// requestParams.targetIdentifiers = targetIdentifiers;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
|
|
@@ -136,7 +136,7 @@ export async function resolveSchemaAndIdentity(_izContext, requestParams, errors
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
requestParams.submittedByUserId = submittedByUserId;
|
|
139
|
-
return { objType, objectSchema };
|
|
139
|
+
return { objType, objectSchema, targetIdentifiers };
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
/**
|
|
@@ -1344,6 +1344,7 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
1344
1344
|
}
|
|
1345
1345
|
);
|
|
1346
1346
|
|
|
1347
|
+
const fieldsForHook = { ...objInstanceFullForDynamoDb.fields };
|
|
1347
1348
|
objInstanceFullForDynamoDb.fields = {};
|
|
1348
1349
|
|
|
1349
1350
|
// Auto-provision owner TargetRole for DynamoDB-only
|
|
@@ -1352,6 +1353,101 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
1352
1353
|
identifiersForCreateData,
|
|
1353
1354
|
requestParams
|
|
1354
1355
|
});
|
|
1356
|
+
|
|
1357
|
+
<%_ if (plan?.hasAfterHookSync) { _%>
|
|
1358
|
+
// ── Synchronous After Hooks ──
|
|
1359
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'lambdaSyncInv').forEach(hook => { _%>
|
|
1360
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
1361
|
+
if (objType.objectType === '<%= hook.objType.objectType %>') {
|
|
1362
|
+
<%_ } _%>
|
|
1363
|
+
try {
|
|
1364
|
+
const hookResult = await lambda.invokeSync(
|
|
1365
|
+
_izContext,
|
|
1366
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
1367
|
+
_izContext,
|
|
1368
|
+
'<%= hook.flowTag %>'
|
|
1369
|
+
),
|
|
1370
|
+
{
|
|
1371
|
+
requestParams: {
|
|
1372
|
+
objType,
|
|
1373
|
+
objInstanceFull: {
|
|
1374
|
+
identifiers: identifiersForCreateData,
|
|
1375
|
+
fields: fieldsForHook
|
|
1376
|
+
},
|
|
1377
|
+
relationships: requestParams.relationships || [],
|
|
1378
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
1379
|
+
submittedByUserId: requestParams.submittedByUserId
|
|
1380
|
+
},
|
|
1381
|
+
callingFlowConfig
|
|
1382
|
+
}
|
|
1383
|
+
);
|
|
1384
|
+
if (hookResult?.errorsFound?.length > 0 || hookResult?.status === 'error') {
|
|
1385
|
+
errorsFound.push(...(hookResult.errorsFound || ['Hook <%= hook.flowTag %> failed']));
|
|
1386
|
+
}
|
|
1387
|
+
} catch (hookErr) {
|
|
1388
|
+
_izContext.logger.error('[<%- flowTag %>LogicalLib] Sync hook <%= hook.flowTag %> error:', hookErr);
|
|
1389
|
+
errorsFound.push(hookErr.message || 'Hook <%= hook.flowTag %> failed');
|
|
1390
|
+
}
|
|
1391
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
1392
|
+
}
|
|
1393
|
+
<%_ } _%>
|
|
1394
|
+
<%_ }) _%>
|
|
1395
|
+
<%_ } _%>
|
|
1396
|
+
|
|
1397
|
+
<%_ if (plan?.hasAfterHookAsync) { _%>
|
|
1398
|
+
// ── Asynchronous After Hooks ──
|
|
1399
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'ownTopic').forEach(hook => { _%>
|
|
1400
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
1401
|
+
if (objType.objectType === '<%= hook.objType.objectType %>') {
|
|
1402
|
+
<%_ } _%>
|
|
1403
|
+
const hookMsg_<%= hook.flowTag %> = callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
1404
|
+
{
|
|
1405
|
+
objType,
|
|
1406
|
+
objInstanceFull: {
|
|
1407
|
+
identifiers: identifiersForCreateData,
|
|
1408
|
+
fields: fieldsForHook
|
|
1409
|
+
},
|
|
1410
|
+
relationships: requestParams.relationships || [],
|
|
1411
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
1412
|
+
submittedByUserId: requestParams.submittedByUserId
|
|
1413
|
+
},
|
|
1414
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
1415
|
+
callingFlowConfig,
|
|
1416
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
1417
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
1418
|
+
_izContext,
|
|
1419
|
+
'<%- flowTag %>AfterHookCallbackHdrSqs'
|
|
1420
|
+
),
|
|
1421
|
+
{
|
|
1422
|
+
actionData: {
|
|
1423
|
+
objType,
|
|
1424
|
+
objInstanceFull: {
|
|
1425
|
+
identifiers: identifiersForCreateData,
|
|
1426
|
+
fields: fieldsForHook
|
|
1427
|
+
},
|
|
1428
|
+
relationships: requestParams.relationships || [],
|
|
1429
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
1430
|
+
status: 'complete',
|
|
1431
|
+
errorsFound
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
)
|
|
1435
|
+
)
|
|
1436
|
+
);
|
|
1437
|
+
|
|
1438
|
+
await sns.publishAsync(_izContext, {
|
|
1439
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
1440
|
+
_izContext,
|
|
1441
|
+
'<%= hook.flowTag %>_In'
|
|
1442
|
+
),
|
|
1443
|
+
Message: JSON.stringify(hookMsg_<%= hook.flowTag %>),
|
|
1444
|
+
MessageAttributes: sns.createStringMessageAttributes(_izContext, {})
|
|
1445
|
+
});
|
|
1446
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
1447
|
+
}
|
|
1448
|
+
<%_ } _%>
|
|
1449
|
+
<%_ }) _%>
|
|
1450
|
+
<%_ } _%>
|
|
1355
1451
|
}
|
|
1356
1452
|
|
|
1357
1453
|
//(<afterCreateRecordDynamo>)
|
|
@@ -1505,11 +1601,13 @@ export async function <%- flowTag %>LogicalLib(
|
|
|
1505
1601
|
|
|
1506
1602
|
// 7. Handle DynamoDB-only Complete Path
|
|
1507
1603
|
if (allAwaitingStepsId.length === 0 && listOfObjectForCreates.length === 0) {
|
|
1604
|
+
<%_ if (!plan?.hasAfterHookAsync) { _%>
|
|
1508
1605
|
await handleDynamoDbOnlyComplete(_izContext, {
|
|
1509
1606
|
objType,
|
|
1510
1607
|
objInstanceFullForDynamoDb,
|
|
1511
1608
|
callingFlowConfig
|
|
1512
1609
|
});
|
|
1610
|
+
<%_ } _%>
|
|
1513
1611
|
}
|
|
1514
1612
|
|
|
1515
1613
|
return {
|
|
@@ -171,6 +171,43 @@ export default async function CreateNodeCallbackMain(
|
|
|
171
171
|
node,
|
|
172
172
|
submittedByUserId
|
|
173
173
|
});
|
|
174
|
+
|
|
175
|
+
<%_ if (plan?.hasAfterHookSync) { _%>
|
|
176
|
+
// ── Synchronous After Hooks ──
|
|
177
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'lambdaSyncInv').forEach(hook => { _%>
|
|
178
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
179
|
+
if (returnValue.requestParams?.objType?.objectType === '<%= hook.objType.objectType %>') {
|
|
180
|
+
<%_ } _%>
|
|
181
|
+
try {
|
|
182
|
+
const hookResult = await lambda.invokeSync(
|
|
183
|
+
_izContext,
|
|
184
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
185
|
+
_izContext,
|
|
186
|
+
'<%= hook.flowTag %>'
|
|
187
|
+
),
|
|
188
|
+
{
|
|
189
|
+
requestParams: {
|
|
190
|
+
objType: returnValue.requestParams.objType,
|
|
191
|
+
objInstanceFull: node.objInstanceFull,
|
|
192
|
+
relationships: node.relationships || [],
|
|
193
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
194
|
+
submittedByUserId
|
|
195
|
+
},
|
|
196
|
+
callingFlowConfig
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
if (hookResult?.errorsFound?.length > 0 || hookResult?.status === 'error') {
|
|
200
|
+
errorsFound.push(...(hookResult.errorsFound || ['Hook <%= hook.flowTag %> failed']));
|
|
201
|
+
}
|
|
202
|
+
} catch (hookErr) {
|
|
203
|
+
_izContext.logger.error('[CreateNodeCallback] Sync hook <%= hook.flowTag %> error:', hookErr);
|
|
204
|
+
errorsFound.push(hookErr.message || 'Hook <%= hook.flowTag %> failed');
|
|
205
|
+
}
|
|
206
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
207
|
+
}
|
|
208
|
+
<%_ } _%>
|
|
209
|
+
<%_ }) _%>
|
|
210
|
+
<%_ } _%>
|
|
174
211
|
}
|
|
175
212
|
|
|
176
213
|
const callingFlowConfig =
|
|
@@ -198,6 +235,48 @@ export default async function CreateNodeCallbackMain(
|
|
|
198
235
|
_izContext
|
|
199
236
|
);
|
|
200
237
|
|
|
238
|
+
<%_ if (plan?.hasAfterHookAsync) { _%>
|
|
239
|
+
// ── Asynchronous After Hooks ──
|
|
240
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'ownTopic').forEach(hook => { _%>
|
|
241
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
242
|
+
if (returnValue.requestParams?.objType?.objectType === '<%= hook.objType.objectType %>') {
|
|
243
|
+
<%_ } _%>
|
|
244
|
+
const hookMsg_<%= hook.flowTag %> = callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
245
|
+
{
|
|
246
|
+
objType: returnValue.requestParams.objType,
|
|
247
|
+
objInstanceFull: node.objInstanceFull,
|
|
248
|
+
relationships: node.relationships || [],
|
|
249
|
+
targetIdentifiers: requestParams.targetIdentifiers,
|
|
250
|
+
submittedByUserId
|
|
251
|
+
},
|
|
252
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
253
|
+
callingFlowConfig,
|
|
254
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
255
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
256
|
+
_izContext,
|
|
257
|
+
'CreateAfterHookCallbackHdrSqs'
|
|
258
|
+
),
|
|
259
|
+
{
|
|
260
|
+
quotaKeys,
|
|
261
|
+
actionData
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
await sns.publishAsync(_izContext, {
|
|
268
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
269
|
+
_izContext,
|
|
270
|
+
'<%= hook.flowTag %>_In'
|
|
271
|
+
),
|
|
272
|
+
Message: JSON.stringify(hookMsg_<%= hook.flowTag %>),
|
|
273
|
+
MessageAttributes: sns.createStringMessageAttributes(_izContext, {})
|
|
274
|
+
});
|
|
275
|
+
<%_ if (hook.objType?.objectType) { _%>
|
|
276
|
+
}
|
|
277
|
+
<%_ } _%>
|
|
278
|
+
<%_ }) _%>
|
|
279
|
+
<%_ } else { _%>
|
|
201
280
|
await forwardToQuotaConfirmation(_izContext, {
|
|
202
281
|
status,
|
|
203
282
|
errorsFound,
|
|
@@ -205,6 +284,7 @@ export default async function CreateNodeCallbackMain(
|
|
|
205
284
|
actionData,
|
|
206
285
|
callingFlowConfig
|
|
207
286
|
});
|
|
287
|
+
<%_ } _%>
|
|
208
288
|
}
|
|
209
289
|
|
|
210
290
|
await asyncFlowSharedLib.removeAwaitingMultipleStep(
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2026 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
<%- flowTag %>LogicalLib,
|
|
20
|
+
handleDeleteError
|
|
21
|
+
} from './<%- upperCaseFlowTag %>LogicalLib.js';
|
|
22
|
+
|
|
23
|
+
//(<optionalRequire>)
|
|
24
|
+
//(</optionalRequire>)
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Handles callback after async BeforeHook completion
|
|
28
|
+
* @param {Object} _izContext - Izara context object
|
|
29
|
+
* @param {Object} requestParams - Callback request parameters
|
|
30
|
+
* @param {Object} passBackProperties - Pass-back properties
|
|
31
|
+
* @returns {Promise<Object>} Result object
|
|
32
|
+
*/
|
|
33
|
+
export default async function <%- upperCaseFlowTag %>BeforeHookCallbackMain(
|
|
34
|
+
_izContext,
|
|
35
|
+
requestParams,
|
|
36
|
+
passBackProperties
|
|
37
|
+
//(<additionalParams>)
|
|
38
|
+
//(</additionalParams>)
|
|
39
|
+
) {
|
|
40
|
+
try {
|
|
41
|
+
_izContext.logger.debug('[<%- upperCaseFlowTag %>BeforeHookCallback] started', {
|
|
42
|
+
requestParams,
|
|
43
|
+
passBackProperties
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const {
|
|
47
|
+
status,
|
|
48
|
+
errorsFound = [],
|
|
49
|
+
returnValue,
|
|
50
|
+
parentFlowId
|
|
51
|
+
} = requestParams;
|
|
52
|
+
|
|
53
|
+
const mergedErrors = Array.isArray(errorsFound) ? [...errorsFound] : [];
|
|
54
|
+
if (status === 'error' && mergedErrors.length === 0) {
|
|
55
|
+
mergedErrors.push('BeforeHook execution reported error');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const callingFlowConfig =
|
|
59
|
+
passBackProperties?.callingFlowConfig ||
|
|
60
|
+
requestParams?.passBackProperties?.callingFlowConfig ||
|
|
61
|
+
{};
|
|
62
|
+
|
|
63
|
+
const originalRequestParams =
|
|
64
|
+
passBackProperties?.originalRequestParams ||
|
|
65
|
+
requestParams?.passBackProperties?.originalRequestParams ||
|
|
66
|
+
passBackProperties?.requestParams ||
|
|
67
|
+
passBackProperties;
|
|
68
|
+
|
|
69
|
+
if (mergedErrors.length > 0) {
|
|
70
|
+
_izContext.logger.warn(
|
|
71
|
+
'[<%- upperCaseFlowTag %>BeforeHookCallback] BeforeHook reported errors:',
|
|
72
|
+
mergedErrors
|
|
73
|
+
);
|
|
74
|
+
return await handleDeleteError(_izContext, {
|
|
75
|
+
objType: originalRequestParams?.objType,
|
|
76
|
+
identifiers: originalRequestParams?.identifiers || {},
|
|
77
|
+
targetIdentifiers: originalRequestParams?.targetIdentifiers,
|
|
78
|
+
callingFlowConfig,
|
|
79
|
+
errorsFound: mergedErrors
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (returnValue?.identifiers && originalRequestParams?.identifiers) {
|
|
84
|
+
Object.assign(originalRequestParams.identifiers, returnValue.identifiers);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//(<beforeLogicalExecution>)
|
|
88
|
+
//(</beforeLogicalExecution>)
|
|
89
|
+
|
|
90
|
+
return await <%- flowTag %>LogicalLib(
|
|
91
|
+
_izContext,
|
|
92
|
+
originalRequestParams,
|
|
93
|
+
callingFlowConfig
|
|
94
|
+
);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
_izContext.logger.error('[<%- upperCaseFlowTag %>BeforeHookCallback] error:', error);
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|