@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
|
@@ -0,0 +1,118 @@
|
|
|
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 asyncFlowSharedLib from '@izara_project/izara-core-library-asynchronous-flow';
|
|
19
|
+
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
20
|
+
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
21
|
+
import { sns } from '@izara_project/izara-core-library-external-request';
|
|
22
|
+
import { consts } from '@izara_project/izara-core-library-service-schemas';
|
|
23
|
+
|
|
24
|
+
//(<optionalRequire>)
|
|
25
|
+
//(</optionalRequire>)
|
|
26
|
+
|
|
27
|
+
const { TOPIC_NAME_GENERATE_CODE } = consts;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Handles callback after async AfterHook completion for Delete
|
|
31
|
+
* @param {Object} _izContext - Izara context object
|
|
32
|
+
* @param {Object} requestParams - Callback request parameters
|
|
33
|
+
* @param {Object} passBackProperties - Pass-back properties
|
|
34
|
+
* @returns {Promise<Object>} Result object
|
|
35
|
+
*/
|
|
36
|
+
export default async function DeleteAfterHookCallbackMain(
|
|
37
|
+
_izContext,
|
|
38
|
+
requestParams,
|
|
39
|
+
passBackProperties
|
|
40
|
+
//(<additionalParams>)
|
|
41
|
+
//(</additionalParams>)
|
|
42
|
+
) {
|
|
43
|
+
try {
|
|
44
|
+
_izContext.logger.debug('[DeleteAfterHookCallback] started', {
|
|
45
|
+
requestParams,
|
|
46
|
+
passBackProperties
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const {
|
|
50
|
+
status,
|
|
51
|
+
errorsFound = [],
|
|
52
|
+
returnValue,
|
|
53
|
+
parentFlowId
|
|
54
|
+
} = requestParams;
|
|
55
|
+
|
|
56
|
+
const mergedErrors = Array.isArray(errorsFound) ? [...errorsFound] : [];
|
|
57
|
+
if (status === 'error' && mergedErrors.length === 0) {
|
|
58
|
+
mergedErrors.push('AfterHook execution reported error');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const callingFlowConfig =
|
|
62
|
+
passBackProperties?.callingFlowConfig ||
|
|
63
|
+
requestParams?.passBackProperties?.callingFlowConfig ||
|
|
64
|
+
passBackProperties;
|
|
65
|
+
|
|
66
|
+
const actionData =
|
|
67
|
+
passBackProperties?.actionData ||
|
|
68
|
+
requestParams?.passBackProperties?.actionData ||
|
|
69
|
+
{
|
|
70
|
+
objType: returnValue?.objType || requestParams?.objType,
|
|
71
|
+
identifiers:
|
|
72
|
+
returnValue?.identifiers || requestParams?.identifiers || {},
|
|
73
|
+
targetIdentifiers: requestParams?.targetIdentifiers,
|
|
74
|
+
parentFlowId: parentFlowId || returnValue?.parentFlowId,
|
|
75
|
+
status: mergedErrors.length > 0 ? 'error' : 'complete',
|
|
76
|
+
errorsFound: mergedErrors
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
|
|
80
|
+
_izContext,
|
|
81
|
+
TOPIC_NAME_GENERATE_CODE.outDeleteNodeComplete
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const completionPayload =
|
|
85
|
+
callingFlowSharedLib.addParentPassBackPropertiesToSnsResponseMessageObject(
|
|
86
|
+
callingFlowConfig,
|
|
87
|
+
{
|
|
88
|
+
...actionData,
|
|
89
|
+
status: mergedErrors.length > 0 ? 'error' : 'complete',
|
|
90
|
+
errorsFound: mergedErrors
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
await sns.publishAsync(_izContext, {
|
|
95
|
+
TopicArn: topicArn,
|
|
96
|
+
Message: JSON.stringify(completionPayload),
|
|
97
|
+
MessageAttributes: sns.createStringMessageAttributes(
|
|
98
|
+
_izContext,
|
|
99
|
+
callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(
|
|
100
|
+
callingFlowConfig,
|
|
101
|
+
{}
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
//(<afterProcessCallback>)
|
|
107
|
+
//(</afterProcessCallback>)
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
returnValue,
|
|
111
|
+
status: mergedErrors.length > 0 ? 'error' : 'complete',
|
|
112
|
+
errorsFound: mergedErrors
|
|
113
|
+
};
|
|
114
|
+
} catch (error) {
|
|
115
|
+
_izContext.logger.error('[DeleteAfterHookCallback] error:', error);
|
|
116
|
+
throw error;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import asyncFlowSharedLib from '@izara_project/izara-core-library-asynchronous-flow';
|
|
2
2
|
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
3
3
|
import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
4
|
+
import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
|
|
4
5
|
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
5
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
sns,
|
|
8
|
+
lambda
|
|
9
|
+
} from '@izara_project/izara-core-library-external-request';
|
|
6
10
|
import { consts } from '@izara_project/izara-core-library-service-schemas';
|
|
7
11
|
import { NoRetryError } from '@izara_project/izara-core-library-core';
|
|
8
12
|
|
|
@@ -142,18 +146,127 @@ export default async function DeleteComplete(
|
|
|
142
146
|
const callingFlowConfig =
|
|
143
147
|
result?.additionalAttributes?.callingFlowConfig ||
|
|
144
148
|
passBackProperties;
|
|
149
|
+
const actionData = {
|
|
150
|
+
objType: returnValue.requestParams.objType,
|
|
151
|
+
objInstanceFull: node.objInstanceFull,
|
|
152
|
+
identifiers:
|
|
153
|
+
node.objInstanceFull?.identifiers ||
|
|
154
|
+
requestParams?.targetIdentifiers ||
|
|
155
|
+
{},
|
|
156
|
+
relationships: node.relationships,
|
|
157
|
+
parentFlowId: parentFlowId || returnValue?.parentFlowId,
|
|
158
|
+
existsNode,
|
|
159
|
+
status,
|
|
160
|
+
errorsFound
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
<%_ if (plan?.hasAfterHookSync) { _%>
|
|
164
|
+
// ── Synchronous After Hooks ──
|
|
165
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'lambdaSyncInv').forEach(hook => { _%>
|
|
166
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length === 1) { _%>
|
|
167
|
+
if (returnValue.requestParams?.objType?.objectType === '<%= hook.targetObjectTypes[0] %>') {
|
|
168
|
+
<%_ } else if (hook.targetObjectTypes && hook.targetObjectTypes.length > 1) { _%>
|
|
169
|
+
if (<%- JSON.stringify(hook.targetObjectTypes) %>.includes(returnValue.requestParams?.objType?.objectType)) {
|
|
170
|
+
<%_ } _%>
|
|
171
|
+
try {
|
|
172
|
+
let hookPayload_<%= hook.flowTag %> = {
|
|
173
|
+
objType: returnValue.requestParams.objType,
|
|
174
|
+
identifiers:
|
|
175
|
+
node.objInstanceFull?.identifiers ||
|
|
176
|
+
requestParams.targetIdentifiers ||
|
|
177
|
+
{},
|
|
178
|
+
objInstanceFull: node.objInstanceFull,
|
|
179
|
+
relationships: node.relationships || [],
|
|
180
|
+
targetIdentifiers: requestParams.targetIdentifiers
|
|
181
|
+
};
|
|
182
|
+
//(<beforeSendHook_<%= hook.flowTag %>>)
|
|
183
|
+
//(</beforeSendHook_<%= hook.flowTag %>>)
|
|
184
|
+
const hookResult = await lambda.invokeSync(
|
|
185
|
+
_izContext,
|
|
186
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
187
|
+
_izContext,
|
|
188
|
+
'<%= hook.flowTag %>'
|
|
189
|
+
),
|
|
190
|
+
{
|
|
191
|
+
requestParams: hookPayload_<%= hook.flowTag %>,
|
|
192
|
+
callingFlowConfig
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
if (
|
|
196
|
+
hookResult?.errorsFound?.length > 0 ||
|
|
197
|
+
hookResult?.status === 'error'
|
|
198
|
+
) {
|
|
199
|
+
errorsFound.push(
|
|
200
|
+
...(hookResult.errorsFound || ['Hook <%= hook.flowTag %> failed'])
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
} catch (hookErr) {
|
|
204
|
+
_izContext.logger.error(
|
|
205
|
+
'[DeleteComplete] Sync hook <%= hook.flowTag %> error:',
|
|
206
|
+
hookErr
|
|
207
|
+
);
|
|
208
|
+
errorsFound.push(hookErr.message || 'Hook <%= hook.flowTag %> failed');
|
|
209
|
+
}
|
|
210
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length > 0) { _%>
|
|
211
|
+
}
|
|
212
|
+
<%_ } _%>
|
|
213
|
+
<%_ }) _%>
|
|
214
|
+
<%_ } _%>
|
|
215
|
+
|
|
216
|
+
<%_ if (plan?.hasAfterHookAsync) { _%>
|
|
217
|
+
// ── Asynchronous After Hooks ──
|
|
218
|
+
<%_ plan.afterHooks.filter(h => h?.generatedCodeConfig?.invocationType === 'ownTopic').forEach(hook => { _%>
|
|
219
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length === 1) { _%>
|
|
220
|
+
if (returnValue.requestParams?.objType?.objectType === '<%= hook.targetObjectTypes[0] %>') {
|
|
221
|
+
<%_ } else if (hook.targetObjectTypes && hook.targetObjectTypes.length > 1) { _%>
|
|
222
|
+
if (<%- JSON.stringify(hook.targetObjectTypes) %>.includes(returnValue.requestParams?.objType?.objectType)) {
|
|
223
|
+
<%_ } _%>
|
|
224
|
+
let hookPayload_<%= hook.flowTag %> = {
|
|
225
|
+
objType: returnValue.requestParams.objType,
|
|
226
|
+
identifiers:
|
|
227
|
+
node.objInstanceFull?.identifiers ||
|
|
228
|
+
requestParams.targetIdentifiers ||
|
|
229
|
+
{},
|
|
230
|
+
objInstanceFull: node.objInstanceFull,
|
|
231
|
+
relationships: node.relationships || [],
|
|
232
|
+
targetIdentifiers: requestParams.targetIdentifiers
|
|
233
|
+
};
|
|
234
|
+
//(<beforeSendHook_<%= hook.flowTag %>>)
|
|
235
|
+
//(</beforeSendHook_<%= hook.flowTag %>>)
|
|
236
|
+
const hookMsg_<%= hook.flowTag %> =
|
|
237
|
+
callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
|
|
238
|
+
hookPayload_<%= hook.flowTag %>,
|
|
239
|
+
callingFlowSharedLib.addParentCallingFlowConfig(
|
|
240
|
+
callingFlowConfig,
|
|
241
|
+
callingFlowSharedLib.createCallingFlowConfig(
|
|
242
|
+
await lambdaSharedLib.lambdaFunctionName(
|
|
243
|
+
_izContext,
|
|
244
|
+
'DeleteAfterHookCallbackHdrSqs'
|
|
245
|
+
),
|
|
246
|
+
{
|
|
247
|
+
actionData
|
|
248
|
+
}
|
|
249
|
+
)
|
|
250
|
+
)
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
await sns.publishAsync(_izContext, {
|
|
254
|
+
TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
|
|
255
|
+
_izContext,
|
|
256
|
+
'<%= hook.flowTag %>_In'
|
|
257
|
+
),
|
|
258
|
+
Message: JSON.stringify(hookMsg_<%= hook.flowTag %>),
|
|
259
|
+
MessageAttributes: sns.createStringMessageAttributes(_izContext, {})
|
|
260
|
+
});
|
|
261
|
+
<%_ if (hook.targetObjectTypes && hook.targetObjectTypes.length > 0) { _%>
|
|
262
|
+
}
|
|
263
|
+
<%_ } _%>
|
|
264
|
+
<%_ }) _%>
|
|
265
|
+
<%_ } else { _%>
|
|
145
266
|
const message =
|
|
146
267
|
callingFlowSharedLib.addParentPassBackPropertiesToSnsResponseMessageObject(
|
|
147
268
|
callingFlowConfig,
|
|
148
|
-
|
|
149
|
-
objType: returnValue.requestParams.objType,
|
|
150
|
-
objInstanceFull: node.objInstanceFull,
|
|
151
|
-
relationships: node.relationships,
|
|
152
|
-
parentFlowId: parentFlowId || returnValue?.parentFlowId,
|
|
153
|
-
existsNode,
|
|
154
|
-
status,
|
|
155
|
-
errorsFound
|
|
156
|
-
}
|
|
269
|
+
actionData
|
|
157
270
|
);
|
|
158
271
|
const messageAttributes =
|
|
159
272
|
callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(
|
|
@@ -176,6 +289,7 @@ export default async function DeleteComplete(
|
|
|
176
289
|
),
|
|
177
290
|
TopicArn: topicArn
|
|
178
291
|
});
|
|
292
|
+
<%_ } _%>
|
|
179
293
|
//(<afterSendMessage>)
|
|
180
294
|
//(</afterSendMessage>)
|
|
181
295
|
}
|