@izara_project/izara-core-generate-service-code 1.0.86 → 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.
Files changed (38) hide show
  1. package/package.json +1 -1
  2. package/src/compile/loadSchemas.js +45 -10
  3. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -1
  4. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +22 -15
  5. package/src/emit/crud/crudActionPlan.js +47 -6
  6. package/src/emit/crud/emitCrudApplicationArtifacts.js +63 -3
  7. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +6 -4
  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 +138 -335
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +205 -42
  12. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +80 -0
  13. package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +99 -0
  14. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +153 -182
  15. package/src/emit/crud/templates/DeleteLogicalLib.ejs +132 -26
  16. package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +112 -0
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +166 -188
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +2 -2
  19. package/src/emit/custom/customFlows.js +3 -1
  20. package/src/emit/function/functionYamlArtifact.js +4 -2
  21. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +0 -3
  22. package/src/emit/rbac/emitRbacApplicationArtifacts.js +1 -116
  23. package/src/emit/rbac/templates/CancelUsage_Main.ejs +14 -10
  24. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +14 -10
  25. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +22 -12
  26. package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +14 -10
  27. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +76 -34
  28. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +12 -9
  29. package/src/emit/resource/emitResourceArtifacts.js +141 -62
  30. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +14 -18
  31. package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +4 -2
  32. package/test/createTargetRoleHandler.test.js +1 -15
  33. package/test/crudApplicationArtifacts.test.js +540 -3
  34. package/test/customFlowApplicationArtifacts.test.js +3 -5
  35. package/test/dynamicCrudFlowSchemas.test.js +5 -17
  36. package/test/dynamicRbacFlowSchemas.test.js +0 -3
  37. package/test/functionYamlArtifact.test.js +4 -2
  38. package/test/resourceArtifacts.test.js +203 -14
@@ -0,0 +1,112 @@
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
+ handleUpdateError
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 handleUpdateError(_izContext, {
75
+ objType: originalRequestParams?.objType,
76
+ identifiers:
77
+ originalRequestParams?.objInstanceFull?.identifiers ||
78
+ originalRequestParams?.identifiers ||
79
+ {},
80
+ fields:
81
+ originalRequestParams?.objInstanceFull?.fields ||
82
+ {},
83
+ versionedDataIds: originalRequestParams?.versionedDataIds,
84
+ callingFlowConfig,
85
+ errorsFound: mergedErrors
86
+ });
87
+ }
88
+
89
+ if (returnValue?.fields && originalRequestParams?.objInstanceFull?.fields) {
90
+ Object.assign(originalRequestParams.objInstanceFull.fields, returnValue.fields);
91
+ } else if (returnValue?.fieldNames && originalRequestParams?.objInstanceFull?.fields) {
92
+ Object.assign(originalRequestParams.objInstanceFull.fields, returnValue.fieldNames);
93
+ } else if (returnValue?.fieldNames && originalRequestParams?.fieldNames) {
94
+ Object.assign(originalRequestParams.fieldNames, returnValue.fieldNames);
95
+ }
96
+ if (returnValue?.relationships && originalRequestParams) {
97
+ originalRequestParams.relationships = returnValue.relationships;
98
+ }
99
+
100
+ //(<beforeLogicalExecution>)
101
+ //(</beforeLogicalExecution>)
102
+
103
+ return await <%- flowTag %>LogicalLib(
104
+ _izContext,
105
+ originalRequestParams,
106
+ callingFlowConfig
107
+ );
108
+ } catch (error) {
109
+ _izContext.logger.error('[<%- upperCaseFlowTag %>BeforeHookCallback] error:', error);
110
+ throw error;
111
+ }
112
+ }
@@ -21,14 +21,10 @@ import {
21
21
  objectHash as hash,
22
22
  identifierUuid
23
23
  } from '@izara_project/izara-shared-core';
24
- import {
25
- consts as coreConsts,
26
- NoRetryError
27
- } from '@izara_project/izara-core-library-core';
24
+ import { NoRetryError } from '@izara_project/izara-core-library-core';
28
25
 
29
26
  // ==================== Core Service Schemas ====================
30
27
  import {
31
- getObjectSchema,
32
28
  consts,
33
29
  utils,
34
30
  identifiersObject,
@@ -53,7 +49,10 @@ import {
53
49
  lambda
54
50
  } from '@izara_project/izara-core-library-external-request';
55
51
 
56
- import { <%- flowTag %>LogicalLib } from './<%- upperCaseFlowTag %>LogicalLib.js';
52
+ import {
53
+ <%- flowTag %>LogicalLib,
54
+ resolveSchemaAndIdentity
55
+ } from './<%- upperCaseFlowTag %>LogicalLib.js';
57
56
 
58
57
  //(<optionalRequire>)
59
58
  //(</optionalRequire>)
@@ -79,88 +78,44 @@ export default async function <%- flowTag %>(
79
78
  });
80
79
 
81
80
  const errorsFound = [];
82
- const objType = createObjType(requestParams.objectType);
83
-
84
- // ── Load schema ───────────────────────────────────────────────────────────
85
- const objectSchema = await getObjectSchema.getObjSchemaS3WithHierarchy(
86
- _izContext,
87
- objType
88
- );
89
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
90
-
91
- // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
92
- let submittedByUserId, targetIdentifiers;
93
- if (
94
- objectSchema.generatedBy === 'user' ||
95
- objectSchema.generatedBy === 'systemWithUser'
96
- ) {
97
- submittedByUserId =
98
- requestParams.submittedByUserId ||
99
- _izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID);
100
-
101
- targetIdentifiers = requestParams.targetIdentifiers;
102
- delete requestParams.targetIdentifiers;
103
-
104
- if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
105
- targetIdentifiers = { submittedByUserId };
106
- }
107
81
 
108
- if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
109
- if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
110
- errorsFound.push('not have targetIdentifiers');
111
-
112
- requestParams.submittedByUserId = submittedByUserId;
113
- if (targetIdentifiers) {
114
- if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
115
- targetIdentifiers.submittedByUserId = submittedByUserId;
116
- }
117
- }
118
-
119
- _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
120
- submittedByUserId: requestParams.submittedByUserId,
121
- targetIdentifiers,
122
- belongTo: objectSchema.belongTo,
123
- generatedBy: objectSchema.generatedBy
124
- });
125
- } else if (objectSchema.generatedBy === 'searchResultGenerated') {
126
- throw new NoRetryError(
127
- 'error searchResultGenerated should not happen here'
128
- );
129
- }
82
+ // ── Resolve Schema & Identity ─────────────────────────────────────────────
83
+ const { objType, objectSchema, targetIdentifiers } =
84
+ await resolveSchemaAndIdentity(_izContext, requestParams, errorsFound);
130
85
 
131
86
  // ── Build identifiers used by asynchronous processing ────────────────────
132
87
  const identifiers = requestParams.objInstanceFull?.identifiers;
133
88
 
134
- if (!objectSchema.hasOwnProperty('belongTo')) {
135
- if (!targetIdentifiers && identifiers) {
136
- targetIdentifiers = { ...identifiers };
137
- } else if (targetIdentifiers && identifiers) {
138
- for (const [key, value] of Object.entries(identifiers)) {
139
- if (targetIdentifiers[key] === undefined && value !== undefined) {
140
- targetIdentifiers[key] = value;
141
- }
142
- }
143
- }
144
- if (targetIdentifiers) {
145
- if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
146
- targetIdentifiers.submittedByUserId = submittedByUserId;
147
- }
148
- }
149
- }
150
-
151
- if (targetIdentifiers && identifiers) {
152
- for (const [key, value] of Object.entries(identifiers)) {
153
- if (
154
- targetIdentifiers[key] !== undefined &&
155
- value !== undefined &&
156
- targetIdentifiers[key] !== value
157
- ) {
158
- errorsFound.push(
159
- `targetIdentifiers.${key} must match objInstanceFull.identifiers.${key}`
160
- );
161
- }
162
- }
163
- }
89
+ // if (!objectSchema.hasOwnProperty('belongTo')) {
90
+ // if (!targetIdentifiers && identifiers) {
91
+ // targetIdentifiers = { ...identifiers };
92
+ // } else if (targetIdentifiers && identifiers) {
93
+ // for (const [key, value] of Object.entries(identifiers)) {
94
+ // if (targetIdentifiers[key] === undefined && value !== undefined) {
95
+ // targetIdentifiers[key] = value;
96
+ // }
97
+ // }
98
+ // }
99
+ // if (targetIdentifiers) {
100
+ // if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
101
+ // targetIdentifiers.submittedByUserId = submittedByUserId;
102
+ // }
103
+ // }
104
+ // }
105
+
106
+ // if (targetIdentifiers && identifiers) {
107
+ // for (const [key, value] of Object.entries(identifiers)) {
108
+ // if (
109
+ // targetIdentifiers[key] !== undefined &&
110
+ // value !== undefined &&
111
+ // targetIdentifiers[key] !== value
112
+ // ) {
113
+ // errorsFound.push(
114
+ // `targetIdentifiers.${key} must match objInstanceFull.identifiers.${key}`
115
+ // );
116
+ // }
117
+ // }
118
+ // }
164
119
 
165
120
  //(<validateBeforeUpdate>)
166
121
  //(</validateBeforeUpdate>)
@@ -218,7 +173,8 @@ export default async function <%- flowTag %>(
218
173
  serviceTag: <%- rbacServiceTags.length === 1 ? rbacServiceTags[0] : `{ ${Object.entries(rbacServiceTagMap).map(([k, v]) => `'${k}': ${v}`).join(', ')} }[requestParams.objectType] || process.env.iz_serviceTag` %>
219
174
  },
220
175
  requestParams: requestParams,
221
- nextFlowStepName: '<%- plan?.hasRbacCallback ? `${flowTag}RbacCallback` : `${flowTag}Complete` %>'
176
+ nextFlowStepName: '<%- plan?.hasRbacCallback ? `${flowTag}RbacCallback` : `${flowTag}Complete` %>',
177
+ sync: true
222
178
  }
223
179
  );
224
180
 
@@ -227,119 +183,137 @@ export default async function <%- flowTag %>(
227
183
  resultPermissionCheck
228
184
  );
229
185
 
186
+ if (resultPermissionCheck && resultPermissionCheck.permission !== true) {
187
+ errorsFound.push('Permission denied');
188
+ return await <%- flowTag %>LogicalLib(
189
+ _izContext,
190
+ requestParams,
191
+ callingFlowConfig,
192
+ errorsFound
193
+ );
194
+ }
195
+
230
196
  //(<rbacPublish_<%- flowTag %>)
231
197
  //(</rbacPublish_<%- flowTag %>)
232
-
233
- return resultPermissionCheck;
234
198
  }
235
199
  <%_ } _%>
236
200
 
237
201
  // ── Optional phase extension point ────────────────────────────────────────
238
202
  <%_
239
- const groupedByObjType = [];
203
+ const beforeHooksByObjType = (plan?.beforeHooks || []).reduce((acc, hook) => {
204
+ const key = hook?.objType?.objectType;
205
+ if (!key) return acc;
206
+ if (!acc[key]) acc[key] = [];
207
+ acc[key].push(hook);
208
+ return acc;
209
+ }, {});
240
210
  _%>
241
- <%_ Object.entries(groupedByObjType).forEach(([objectType, configs]) => { _%>
211
+ <%_ Object.entries(beforeHooksByObjType).forEach(([objectType, configs]) => { _%>
242
212
  <%_
243
- const hasOwnTopic = configs.some(c => c.invocationType === 'ownTopic');
244
- const hasLambdaSyncInv = configs.some(c => c.invocationType === 'lambdaSyncInv');
245
- _%>
213
+ const hasOwnTopic = configs.some(c => c?.generatedCodeConfig?.invocationType === 'ownTopic' || c?.event?.includes('ownTopic'));
214
+ const hasLambdaSyncInv = configs.some(c => c?.generatedCodeConfig?.invocationType === 'lambdaSyncInv' || c?.event?.includes('lambdaSyncInv'));
215
+ _%>
246
216
  if (requestParams.objectType === '<%= objectType %>') {
247
217
  <%_ if (hasLambdaSyncInv) { _%>
248
- const lambdaSyncInvResults = await Promise.all([
249
- <%_ configs.filter(c => c.invocationType === 'lambdaSyncInv').forEach((config, index, arr) => { _%>
250
- // lambdaSyncInv <%= config.flowTag %>
251
- lambda
252
- .invokeSync(
218
+ const lambdaSyncInvResults = [];
219
+ <%_ for (const config of configs.filter(c => c?.generatedCodeConfig?.invocationType === 'lambdaSyncInv' || c?.event?.includes('lambdaSyncInv'))) { _%>
220
+ try {
221
+ const returnValue = await lambda.invokeSync(
222
+ _izContext,
223
+ await lambdaSharedLib.lambdaFunctionName(
253
224
  _izContext,
254
- await lambdaSharedLib.lambdaFunctionName(
255
- _izContext,
256
- 'Process<%= config.flowTag %>HdrInv'
257
- ),
258
- { requestParams, callingFlowConfig }
259
- )
260
- .then((returnValue) => ({
261
- flowTag: '<%= config.flowTag %>',
262
- returnValue
263
- })) /*__EJS_COMMA_14__*/
264
- // lambdaSyncInv <%= config.flowTag %>
265
- <%_ }) _%>
266
- ]);
225
+ '<%= config.flowTag %>'
226
+ ),
227
+ {
228
+ requestParams: {
229
+ objType,
230
+ objInstanceFull: requestParams.objInstanceFull,
231
+ identifiers: requestParams.objInstanceFull?.identifiers,
232
+ fieldNames: requestParams.objInstanceFull?.fields || requestParams.fieldNames,
233
+ relationships: requestParams.relationships || [],
234
+ targetIdentifiers,
235
+ submittedByUserId: requestParams.submittedByUserId
236
+ },
237
+ callingFlowConfig
238
+ }
239
+ );
240
+ lambdaSyncInvResults.push({
241
+ flowTag: '<%= config.flowTag %>',
242
+ returnValue
243
+ });
244
+ if (returnValue?.errorsFound?.length > 0) {
245
+ errorsFound.push(...returnValue.errorsFound);
246
+ } else if (returnValue?.status === 'error') {
247
+ errorsFound.push('Error from <%= config.flowTag %>');
248
+ } else {
249
+ if (returnValue?.fields && requestParams?.objInstanceFull?.fields) {
250
+ Object.assign(requestParams.objInstanceFull.fields, returnValue.fields);
251
+ } else if (returnValue?.fieldNames && requestParams?.objInstanceFull?.fields) {
252
+ Object.assign(requestParams.objInstanceFull.fields, returnValue.fieldNames);
253
+ } else if (returnValue?.fieldNames && requestParams?.fieldNames) {
254
+ Object.assign(requestParams.fieldNames, returnValue.fieldNames);
255
+ }
256
+ if (returnValue?.relationships && requestParams) {
257
+ requestParams.relationships = returnValue.relationships;
258
+ }
259
+ }
260
+ } catch (hookErr) {
261
+ _izContext.logger.error(
262
+ '[<%- flowTag %>] Sync hook <%= config.flowTag %> error:',
263
+ hookErr
264
+ );
265
+ errorsFound.push(hookErr.message || 'Hook <%= config.flowTag %> failed');
266
+ }
267
+ <%_ } _%>
268
+
269
+ if (errorsFound.length > 0) {
270
+ return await <%- flowTag %>LogicalLib(
271
+ _izContext,
272
+ requestParams,
273
+ callingFlowConfig,
274
+ errorsFound
275
+ );
276
+ }
267
277
  <%_ } _%>
268
278
 
269
279
  //(<afterBeforeLogical_<%= objectType %>>)
270
280
  //(</afterBeforeLogical_<%= objectType %>>)
271
281
 
272
282
  <%_ if (hasOwnTopic) { _%>
273
- // ── ownTopic (async — create awaitingSteps and then publish) ──────────
274
- const awaitingMultipleStepIds = [];
275
- const recordMsgs = [];
276
-
277
- <%_ configs.filter(c => c.invocationType === 'ownTopic').forEach(config => { _%>
278
- // ownTopic <%= config.flowTag %>
279
- awaitingMultipleStepIds.push({
280
- awaitingStepId: await asyncFlowSharedLib.createAwaitingStepId(
281
- hash(identifiers),
282
- 'logical_<%= objectType %>_<%= config.flowTag.charAt(0).toUpperCase() + config.flowTag.slice(1) %>'
283
- ),
284
- additionalAttributes: {}
285
- });
286
-
287
- recordMsgs.push({
288
- msg: callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
289
- requestParams,
283
+ // ── ownTopic (async — dispatch to before-hook and await callback) ──────────
284
+ <%_ configs.filter(c => c?.generatedCodeConfig?.invocationType === 'ownTopic' || c?.event?.includes('ownTopic')).forEach(config => { _%>
285
+ const hookMsg_<%= config.flowTag %> =
286
+ callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
287
+ {
288
+ objType,
289
+ objInstanceFull: requestParams.objInstanceFull,
290
+ identifiers: requestParams.objInstanceFull?.identifiers,
291
+ fieldNames: requestParams.objInstanceFull?.fields || requestParams.fieldNames,
292
+ relationships: requestParams.relationships || [],
293
+ targetIdentifiers,
294
+ submittedByUserId: requestParams.submittedByUserId
295
+ },
290
296
  callingFlowSharedLib.addParentCallingFlowConfig(
291
297
  callingFlowConfig,
292
298
  callingFlowSharedLib.createCallingFlowConfig(
293
- //(<callingFlowProperties_<%= config.flowTag %>>)
294
299
  await lambdaSharedLib.lambdaFunctionName(
295
300
  _izContext,
296
- '<%= flowTag.toLowerCase() %>Complete'
301
+ '<%- flowTag %>BeforeHookCallbackHdrSqs'
297
302
  ),
298
- {}
299
- //(</callingFlowProperties_<%= config.flowTag %>>)
303
+ {
304
+ originalRequestParams: {
305
+ ...requestParams,
306
+ objType,
307
+ targetIdentifiers
308
+ },
309
+ callingFlowConfig
310
+ }
300
311
  )
301
312
  )
302
- ),
303
- flowTag: '<%= config.flowTag.charAt(0).toUpperCase() + config.flowTag.slice(1) %>'
304
- });
305
- <%_ }) _%>
306
-
307
- <%_ if (hasLambdaSyncInv) { _%>
308
- // ── Add lambdaSyncInv results to awaitingSteps ────────────────────────
309
- for (const syncResult of lambdaSyncInvResults) {
310
- awaitingMultipleStepIds.push({
311
- awaitingStepId: await asyncFlowSharedLib.createAwaitingStepId(
312
- hash(identifiers),
313
- 'logical_<%= objectType %>_' + syncResult.flowTag
314
- ),
315
- additionalAttributes: {
316
- complete: true,
317
- errorsFound: [],
318
- returnValue: syncResult.returnValue
319
- }
320
- });
321
- }
322
- <%_ } _%>
323
-
324
- await asyncFlowSharedLib.createAwaitingMultipleSteps(
325
- _izContext,
326
- asyncFlowSharedLib.createPendingStepId(
327
- _izContext.uniqueRequestId,
328
- 'logical_<%= objectType %>'
329
- ),
330
- awaitingMultipleStepIds,
331
- {
332
- additionalAttributes: {
333
- callingFlowConfig
334
- }
335
- }
336
- );
337
-
338
- //(<beforePublish_<%= objectType %>>)
339
- //(</beforePublish_<%= objectType %>>)
313
+ );
340
314
 
341
- for (const recordMsg of recordMsgs) {
342
- const messageAttributes = sns.createStringMessageAttributes(
315
+ const messageAttributes_<%= config.flowTag %> =
316
+ sns.createStringMessageAttributes(
343
317
  _izContext,
344
318
  callingFlowSharedLib.addCallingFlowToSnsResponseMessageAttributes(
345
319
  callingFlowConfig,
@@ -347,32 +321,36 @@ export default async function <%- flowTag %>(
347
321
  )
348
322
  );
349
323
 
350
- const topicArn = snsSharedLib.snsTopicArnByFlowSchema(
351
- _izContext,
352
- `${recordMsg.flowTag}_In`
353
- );
324
+ const topicArn_<%= config.flowTag %> = snsSharedLib.snsTopicArnByFlowSchema(
325
+ _izContext,
326
+ '<%= config.flowTag %>_In'
327
+ );
354
328
 
355
- await sns.publishAsync(_izContext, {
356
- Message: JSON.stringify(recordMsg.msg),
357
- MessageAttributes: messageAttributes,
358
- TopicArn: topicArn
359
- });
360
- }
329
+ _izContext.logger.debug(
330
+ `[${process.env.iz_serviceTag}:<%- flowTag %>] Dispatching to BeforeHook:`,
331
+ {
332
+ topicArn: topicArn_<%= config.flowTag %>,
333
+ flowTag: '<%= config.flowTag %>'
334
+ }
335
+ );
361
336
 
362
- return 'complete logical <%= objectType %>';
337
+ await sns.publishAsync(_izContext, {
338
+ Message: JSON.stringify(hookMsg_<%= config.flowTag %>),
339
+ MessageAttributes: messageAttributes_<%= config.flowTag %>,
340
+ TopicArn: topicArn_<%= config.flowTag %>
341
+ });
342
+ <%_ }) _%>
363
343
 
344
+ return {
345
+ status: 'pending',
346
+ message: 'Dispatched to BeforeHook'
347
+ };
364
348
  <%_ } else { _%>
365
- // ── lambdaSyncInv only — collect results and proceed to updateLogicalLib
366
- const phaseResults = Object.fromEntries(
367
- lambdaSyncInvResults.map(({ flowTag: tag, returnValue }) => [tag, returnValue])
368
- );
369
-
370
349
  return await <%- flowTag %>LogicalLib(
371
350
  _izContext,
372
351
  requestParams,
373
352
  callingFlowConfig,
374
- errorsFound,
375
- phaseResults
353
+ errorsFound
376
354
  );
377
355
  <%_ } _%>
378
356
  }
@@ -108,7 +108,7 @@ export async function resolveSchemaAndIdentity(_izContext, requestParams, errors
108
108
  if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
109
109
  targetIdentifiers.submittedByUserId = submittedByUserId;
110
110
  }
111
- requestParams.targetIdentifiers = targetIdentifiers;
111
+ // requestParams.targetIdentifiers = targetIdentifiers;
112
112
  }
113
113
 
114
114
  _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
@@ -124,7 +124,7 @@ export async function resolveSchemaAndIdentity(_izContext, requestParams, errors
124
124
  }
125
125
 
126
126
  requestParams.submittedByUserId = submittedByUserId;
127
- return { objType, objectSchema };
127
+ return { objType, objectSchema, targetIdentifiers };
128
128
  }
129
129
 
130
130
  // ── 2. UpdateRbacCallback_Main Helpers ────────────────────────────────────────
@@ -16,7 +16,9 @@ export function supportedCustomFlows(flows) {
16
16
  (flow) =>
17
17
  typeof flow?.flowTag === 'string' &&
18
18
  flow.flowTag !== '' &&
19
- !flow.generatedCodeConfig &&
19
+ (!flow.generatedCodeConfig ||
20
+ (flow.generatedCodeConfig.codeHookTag &&
21
+ !flow.event.includes('ownTopic'))) &&
20
22
  Array.isArray(flow.event) &&
21
23
  flow.event.some((event) => SUPPORTED_EVENTS.has(event))
22
24
  );
@@ -319,8 +319,10 @@ function _sqsFilterPatterns(
319
319
  - body:
320
320
  MessageAttributes:
321
321
  callingFlow:
322
- Value:
323
- - exists: false
322
+ - exists: false
323
+ - body:
324
+ MessageAttributes:
325
+ - exists: false
324
326
  #<#/${hookFunctionName}FilterPatterns#>
325
327
  `;
326
328
  }
@@ -18,9 +18,6 @@ const RBAC_CORE_FLOW_DEFINITIONS = [
18
18
  ];
19
19
 
20
20
  const LIMIT_FLOW_DEFINITIONS = [
21
- { flowTag: 'CreateRoleLimit', event: ['ownTopic'] },
22
- { flowTag: 'ListRoleLimits', event: ['lambdaSyncApi'] },
23
- { flowTag: 'DeleteRoleLimit', event: ['ownTopic'] },
24
21
  { flowTag: 'ReservedDynamicUsage', event: ['ownTopic'] },
25
22
  { flowTag: 'ConfirmUsage', event: ['ownTopic'] },
26
23
  { flowTag: 'CancelUsage', event: ['ownTopic'] }