@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.
Files changed (32) hide show
  1. package/package.json +1 -1
  2. package/src/compile/flowValidator.js +25 -0
  3. package/src/compile/loadSchemas.js +199 -10
  4. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
  5. package/src/emit/crud/crudActionPlan.js +105 -6
  6. package/src/emit/crud/emitCrudApplicationArtifacts.js +63 -3
  7. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
  8. package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +121 -0
  9. package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +108 -0
  10. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +140 -340
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +338 -82
  12. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +90 -0
  13. package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
  14. package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +99 -0
  15. package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
  16. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +151 -179
  17. package/src/emit/crud/templates/DeleteLogicalLib.ejs +244 -27
  18. package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
  19. package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +112 -0
  20. package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
  21. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +166 -185
  22. package/src/emit/crud/templates/UpdateLogicalLib.ejs +123 -3
  23. package/src/emit/custom/customFlows.js +3 -1
  24. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +8 -2
  25. package/src/emit/rbac/templates/CancelUsage_Main.ejs +34 -14
  26. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +34 -14
  27. package/src/emit/resource/emitResourceArtifacts.js +119 -59
  28. package/test/crudApplicationArtifacts.test.js +876 -0
  29. package/test/dynamicCrudFlowSchemas.test.js +10 -5
  30. package/test/dynamicRbacFlowSchemas.test.js +24 -2
  31. package/test/graphDrivenFlowSchema.test.js +36 -0
  32. 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 { sns } from '@izara_project/izara-core-library-external-request';
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
  }