@izara_project/izara-core-generate-service-code 1.0.88 → 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 (26) hide show
  1. package/package.json +1 -1
  2. package/src/compile/flowValidator.js +25 -0
  3. package/src/compile/loadSchemas.js +154 -0
  4. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
  5. package/src/emit/crud/crudActionPlan.js +67 -9
  6. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
  7. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +33 -27
  8. package/src/emit/crud/templates/CreateLogicalLib.ejs +247 -89
  9. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +30 -20
  10. package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
  11. package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
  12. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +26 -16
  13. package/src/emit/crud/templates/DeleteLogicalLib.ejs +112 -1
  14. package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
  15. package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
  16. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +34 -22
  17. package/src/emit/crud/templates/UpdateLogicalLib.ejs +121 -1
  18. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +8 -2
  19. package/src/emit/rbac/templates/CancelUsage_Main.ejs +34 -14
  20. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +34 -14
  21. package/src/emit/resource/emitResourceArtifacts.js +9 -2
  22. package/test/crudApplicationArtifacts.test.js +345 -0
  23. package/test/dynamicCrudFlowSchemas.test.js +10 -5
  24. package/test/dynamicRbacFlowSchemas.test.js +24 -2
  25. package/test/graphDrivenFlowSchema.test.js +36 -0
  26. package/test/resourceArtifacts.test.js +71 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@izara_project/izara-core-generate-service-code",
3
- "version": "1.0.88",
3
+ "version": "1.0.89",
4
4
  "description": "Code for locally generating per service files",
5
5
  "homepage": "https://bitbucket.org/izara-core-support-services/izara-core-support-services-generate-service-code#readme",
6
6
  "repository": {
@@ -32,6 +32,31 @@ export function validateFlowSchema(flowSchema) {
32
32
  );
33
33
  }
34
34
 
35
+ let flowEvents = [];
36
+ if (Array.isArray(flowSchema.event)) {
37
+ flowEvents = flowSchema.event;
38
+ }
39
+ const syncEvents = ['lambdaSyncInv', 'lambdaSyncApi'];
40
+ let hasSyncEvent = false;
41
+ for (const eventName of flowEvents) {
42
+ if (syncEvents.includes(eventName)) {
43
+ hasSyncEvent = true;
44
+ break;
45
+ }
46
+ }
47
+
48
+ if (hasSyncEvent && steps.length > 1) {
49
+ let flowTag = 'unknown';
50
+ if (flowSchema.flowTag) {
51
+ flowTag = flowSchema.flowTag;
52
+ }
53
+ throw new Error(
54
+ `FlowSchema validation error: Flow '${flowTag}' with synchronous ` +
55
+ `events ('lambdaSyncInv' | 'lambdaSyncApi') must only define a ` +
56
+ `single entry step 'Start'`
57
+ );
58
+ }
59
+
35
60
  const entryStep = steps[0];
36
61
  if (
37
62
  !entryStep ||
@@ -23,6 +23,7 @@ const VALID_INITIATE_BY_ENUM = [
23
23
  ];
24
24
 
25
25
  const VALID_CODE_HOOK_TAG_ENUM = ['before', 'after'];
26
+ const VALID_GENERATE_CODE_TAG_ENUM = ['create', 'update', 'delete'];
26
27
 
27
28
  if (basicValidatorSchema?.basicFlowSchema?.properties?.initiateBy) {
28
29
  basicValidatorSchema.basicFlowSchema.properties.initiateBy.enum =
@@ -37,6 +38,50 @@ if (
37
38
  VALID_CODE_HOOK_TAG_ENUM;
38
39
  }
39
40
 
41
+ if (
42
+ basicValidatorSchema?.basicFlowSchema?.properties?.generatedCodeConfig
43
+ ?.properties?.generateCodeTag
44
+ ) {
45
+ basicValidatorSchema.basicFlowSchema.properties.generatedCodeConfig.properties.generateCodeTag = {
46
+ anyOf: [
47
+ {
48
+ type: 'array',
49
+ items: {
50
+ type: 'string',
51
+ enum: VALID_GENERATE_CODE_TAG_ENUM
52
+ }
53
+ },
54
+ {
55
+ type: 'string',
56
+ enum: VALID_GENERATE_CODE_TAG_ENUM
57
+ }
58
+ ]
59
+ };
60
+ }
61
+
62
+ if (
63
+ basicValidatorSchema?.basicFlowSchema?.properties?.generatedCodeConfig
64
+ ?.properties
65
+ ) {
66
+ basicValidatorSchema.basicFlowSchema.properties.generatedCodeConfig.properties.objType = {
67
+ anyOf: [
68
+ { type: 'string' },
69
+ {
70
+ type: 'array',
71
+ items: { type: 'string' }
72
+ },
73
+ {
74
+ type: 'object',
75
+ properties: {
76
+ objectType: { type: 'string' },
77
+ serviceTag: { type: 'string' }
78
+ },
79
+ required: ['objectType']
80
+ }
81
+ ]
82
+ };
83
+ }
84
+
40
85
  const VALID_GENERATED_BY_ENUM = [
41
86
  'user',
42
87
  'systemWithUser',
@@ -135,6 +180,90 @@ export async function loadLocalSchemaDirectory(
135
180
  );
136
181
  }
137
182
  }
183
+ if (
184
+ Object.prototype.hasOwnProperty.call(
185
+ schema?.generatedCodeConfig ?? {},
186
+ 'generateCodeTag'
187
+ )
188
+ ) {
189
+ const codeTag = schema.generatedCodeConfig.generateCodeTag;
190
+ if (Array.isArray(codeTag)) {
191
+ if (codeTag.length === 0) {
192
+ throw new Error(
193
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
194
+ `generatedCodeConfig.generateCodeTag array must not be empty`
195
+ );
196
+ }
197
+ for (const tag of codeTag) {
198
+ if (
199
+ typeof tag !== 'string' ||
200
+ !VALID_GENERATE_CODE_TAG_ENUM.includes(tag.toLowerCase())
201
+ ) {
202
+ throw new Error(
203
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
204
+ `generatedCodeConfig.generateCodeTag contains invalid ` +
205
+ `tag '${tag}'. Must be 'create', 'update', or 'delete'`
206
+ );
207
+ }
208
+ }
209
+ } else if (typeof codeTag === 'string') {
210
+ if (!VALID_GENERATE_CODE_TAG_ENUM.includes(codeTag.toLowerCase())) {
211
+ throw new Error(
212
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
213
+ `generatedCodeConfig.generateCodeTag '${codeTag}' ` +
214
+ `is invalid. Must be 'create', 'update', or 'delete'`
215
+ );
216
+ }
217
+ } else {
218
+ throw new Error(
219
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
220
+ `generatedCodeConfig.generateCodeTag must be an array or string`
221
+ );
222
+ }
223
+ }
224
+ if (
225
+ Object.prototype.hasOwnProperty.call(
226
+ schema?.generatedCodeConfig ?? {},
227
+ 'objType'
228
+ )
229
+ ) {
230
+ const hookObjType = schema.generatedCodeConfig.objType;
231
+ if (Array.isArray(hookObjType)) {
232
+ if (hookObjType.length === 0) {
233
+ throw new Error(
234
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
235
+ `generatedCodeConfig.objType array must not be empty`
236
+ );
237
+ }
238
+ for (const item of hookObjType) {
239
+ const strVal = typeof item === 'string' ? item : item?.objectType;
240
+ if (!strVal || typeof strVal !== 'string') {
241
+ throw new Error(
242
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
243
+ `generatedCodeConfig.objType array items must be non-empty strings or objects with objectType`
244
+ );
245
+ }
246
+ }
247
+ } else if (typeof hookObjType === 'object' && hookObjType !== null) {
248
+ if (
249
+ !hookObjType.objectType ||
250
+ typeof hookObjType.objectType !== 'string'
251
+ ) {
252
+ throw new Error(
253
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
254
+ `generatedCodeConfig.objType object must have string property objectType`
255
+ );
256
+ }
257
+ } else if (
258
+ typeof hookObjType !== 'string' ||
259
+ hookObjType.trim() === ''
260
+ ) {
261
+ throw new Error(
262
+ `Unsupported FlowHook configuration in ${entry.name}: ` +
263
+ `generatedCodeConfig.objType must be a non-empty string, array, or object`
264
+ );
265
+ }
266
+ }
138
267
  }
139
268
  }
140
269
 
@@ -219,6 +348,31 @@ export async function loadLocalSchemaDirectory(
219
348
  )
220
349
  );
221
350
  }
351
+ const generateCodeTag =
352
+ schema?.generatedCodeConfig?.generateCodeTag;
353
+ let isGenerateCodeTagValid = false;
354
+ if (Array.isArray(generateCodeTag)) {
355
+ isGenerateCodeTagValid =
356
+ generateCodeTag.length > 0 &&
357
+ generateCodeTag.every((t) => {
358
+ return (
359
+ typeof t === 'string' &&
360
+ VALID_GENERATE_CODE_TAG_ENUM.includes(t.toLowerCase())
361
+ );
362
+ });
363
+ } else if (typeof generateCodeTag === 'string') {
364
+ isGenerateCodeTagValid = VALID_GENERATE_CODE_TAG_ENUM.includes(
365
+ generateCodeTag.toLowerCase()
366
+ );
367
+ }
368
+ if (isGenerateCodeTagValid) {
369
+ errors = errors.filter((err) => {
370
+ return (
371
+ !err.includes('generateCodeTag') &&
372
+ !err.includes('must match a schema in "anyOf"')
373
+ );
374
+ });
375
+ }
222
376
  if (errors.length === 0) {
223
377
  status = true;
224
378
  }
@@ -181,12 +181,6 @@ const tableConfigs = {
181
181
 
182
182
  const currentServiceTag = (typeof serviceTag !== 'undefined' && serviceTag) ? serviceTag : ((typeof project !== 'undefined' && project?.serviceTag) ? project.serviceTag : '');
183
183
  const rbacSubs = [];
184
- if (crud && rbac) {
185
- if (typeof hasQuotaReservation !== 'undefined' && hasQuotaReservation) {
186
- rbacSubs.push({ serviceTag: 'Rbac', topicName: 'ConfirmUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
187
- rbacSubs.push({ serviceTag: 'Rbac', topicName: 'CancelUsage_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
188
- }
189
- }
190
184
 
191
185
  if (typeof customRbacFlowTags !== 'undefined' && customRbacFlowTags && customRbacFlowTags.length > 0) {
192
186
  const allRbacTags = Array.from(new Set([
@@ -309,7 +303,9 @@ function roleConfigs() {
309
303
  Effect: 'Allow',
310
304
  Action: ['lambda:InvokeFunction'],
311
305
  Resource: [
312
- `arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv', 'Rbac')}`<% if (rbac) { %>,
306
+ `arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv', 'Rbac')}`,
307
+ `arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ConfirmUsageHdrInv', 'Rbac')}`,
308
+ `arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'CancelUsageHdrInv', 'Rbac')}`<% if (rbac) { %>,
313
309
  `arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv')}`<% } %><% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
314
310
  `arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, 'ValidatorRbacHdrInv', '<%= tag %>')}`<% }); %>
315
311
  ]
@@ -1,12 +1,28 @@
1
1
  export const CRUD_ACTIONS = ['Create', 'Update', 'Delete', 'Get'];
2
2
 
3
3
  export function findHooksForAction(flows = [], action) {
4
- if (!Array.isArray(flows)) return [];
5
- return flows.filter((f) => {
6
- const config = f?.generatedCodeConfig;
7
- if (!config) return false;
4
+ if (!Array.isArray(flows)) {
5
+ return [];
6
+ }
7
+ const actionLower = action?.toLowerCase();
8
+ return flows.filter((flow) => {
9
+ const config = flow?.generatedCodeConfig;
10
+ if (!config) {
11
+ return false;
12
+ }
8
13
  const tag = config.generateCodeTag || config.generatedCodeTag;
9
- return Boolean(tag && tag.toLowerCase() === action.toLowerCase());
14
+ if (!tag) {
15
+ return false;
16
+ }
17
+ if (Array.isArray(tag)) {
18
+ return tag.some((t) => {
19
+ return typeof t === 'string' && t.toLowerCase() === actionLower;
20
+ });
21
+ }
22
+ if (typeof tag === 'string') {
23
+ return tag.toLowerCase() === actionLower;
24
+ }
25
+ return false;
10
26
  });
11
27
  }
12
28
 
@@ -27,6 +43,34 @@ export function createCrudActionPlans(objects = [], flows = []) {
27
43
  );
28
44
  }
29
45
 
46
+ export function resolveHookTargetObjectTypes(hook) {
47
+ const config = hook?.generatedCodeConfig;
48
+ const targetObjType = config?.objType ?? config?.objectType;
49
+ if (targetObjType) {
50
+ if (typeof targetObjType === 'string') {
51
+ return [targetObjType];
52
+ }
53
+ if (Array.isArray(targetObjType)) {
54
+ const types = targetObjType
55
+ .map((t) => (typeof t === 'string' ? t : t?.objectType))
56
+ .filter(Boolean);
57
+ if (types.length > 0) {
58
+ return types;
59
+ }
60
+ }
61
+ if (typeof targetObjType === 'object' && targetObjType?.objectType) {
62
+ return [targetObjType.objectType];
63
+ }
64
+ }
65
+ if (hook?.objType?.objectType) {
66
+ return [hook.objType.objectType];
67
+ }
68
+ if (typeof hook?.objType === 'string') {
69
+ return [hook.objType];
70
+ }
71
+ return null;
72
+ }
73
+
30
74
  export function createCrudActionPlan(
31
75
  action,
32
76
  { hasGraph = false, hasRbac = false, isBillable = true, flows = [] } = {}
@@ -35,7 +79,10 @@ export function createCrudActionPlan(
35
79
  const outputTopic = action !== 'Get';
36
80
  const hasQuotaReservation = action === 'Create' && hasRbac && isBillable;
37
81
 
38
- const actionHooks = findHooksForAction(flows, action);
82
+ const actionHooks = findHooksForAction(flows, action).map((h) => ({
83
+ ...h,
84
+ targetObjectTypes: resolveHookTargetObjectTypes(h)
85
+ }));
39
86
  const beforeHooks = actionHooks.filter(
40
87
  (h) => h?.generatedCodeConfig?.codeHookTag === 'before'
41
88
  );
@@ -58,16 +105,27 @@ export function createCrudActionPlan(
58
105
  );
59
106
  const hasAfterHookCallback = outputTopic && hasAfterHookAsync;
60
107
 
108
+ const hasCreateNodeCallback =
109
+ outputTopic &&
110
+ action === 'Create' &&
111
+ actionHasRbac &&
112
+ hasGraph &&
113
+ hasQuotaReservation;
114
+
115
+ const hasComplete =
116
+ outputTopic &&
117
+ !hasCreateNodeCallback &&
118
+ (actionHasRbac || hasGraph || hasAfterHookCallback);
119
+
61
120
  return {
62
121
  action,
63
122
  outputTopic,
64
123
  hasGraph: outputTopic && hasGraph,
65
124
  hasRbac: actionHasRbac,
66
125
  hasQuotaReservation,
67
- hasComplete: outputTopic && (actionHasRbac || hasGraph || hasAfterHookCallback),
126
+ hasComplete,
68
127
  hasRbacCallback: false,
69
- hasCreateNodeCallback:
70
- outputTopic && action === 'Create' && actionHasRbac && hasGraph && hasQuotaReservation,
128
+ hasCreateNodeCallback,
71
129
  hasBeforeHookSync,
72
130
  hasBeforeHookAsync,
73
131
  hasBeforeHookCallback,
@@ -72,8 +72,10 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
72
72
  toStepNames: ['RbacCallback']
73
73
  }
74
74
  );
75
- } else if (plan.hasComplete) {
76
- const nextStepName = plan.hasCreateNodeCallback ? 'CreateNodeCallback' : 'Complete';
75
+ } else if (plan.hasComplete || plan.hasCreateNodeCallback) {
76
+ const nextStepName = plan.hasCreateNodeCallback
77
+ ? 'CreateNodeCallback'
78
+ : 'Complete';
77
79
  startNextSteps.push({
78
80
  targetType: 'ownTopic',
79
81
  stepName: nextStepName
@@ -106,7 +108,9 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
106
108
  ];
107
109
 
108
110
  if (plan.hasRbacCallback) {
109
- const nextStepName = plan.hasCreateNodeCallback ? 'CreateNodeCallback' : 'Complete';
111
+ const nextStepName = plan.hasCreateNodeCallback
112
+ ? 'CreateNodeCallback'
113
+ : 'Complete';
110
114
  const rbacNextSteps = [
111
115
  {
112
116
  targetType: 'ownTopic',
@@ -162,14 +166,9 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
162
166
  ],
163
167
  nextSteps: [
164
168
  {
165
- targetType: 'ownTopic',
166
- stepName: 'Complete'
167
- },
168
- {
169
- targetType: 'extTopic',
169
+ targetType: 'lambdaSyncInv',
170
170
  serviceTag: 'Rbac',
171
- topicName: 'ConfirmUsage_In',
172
- toStepNames: ['Complete']
171
+ functionName: 'ConfirmUsageHdrInv'
173
172
  }
174
173
  ],
175
174
  properties: [
@@ -184,9 +183,7 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
184
183
  }
185
184
 
186
185
  if (plan.hasComplete) {
187
- const prevStepName = plan.hasCreateNodeCallback
188
- ? 'CreateNodeCallback'
189
- : (plan.hasRbacCallback ? 'RbacCallback' : 'Start');
186
+ const prevStepName = plan.hasRbacCallback ? 'RbacCallback' : 'Start';
190
187
 
191
188
  const completePrevSteps = [
192
189
  {
@@ -195,14 +192,7 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
195
192
  }
196
193
  ];
197
194
 
198
- if (plan.hasCreateNodeCallback) {
199
- completePrevSteps.push({
200
- sourceType: 'extTopic',
201
- serviceTag: 'Rbac',
202
- topicName: 'ConfirmUsage_Out',
203
- fromStepNames: ['CreateNodeCallback']
204
- });
205
- } else if (plan.hasGraph) {
195
+ if (plan.hasGraph) {
206
196
  completePrevSteps.push({
207
197
  sourceType: 'extTopic',
208
198
  serviceTag: 'GraphHandler',
@@ -215,22 +205,15 @@ function _createDynamicFlow(action, plan, serviceTag = '', initiateBy = 'user')
215
205
  stepName: 'Complete',
216
206
  event: ['extTopic'],
217
207
  previousSteps: completePrevSteps,
218
- properties: plan.hasCreateNodeCallback
208
+ properties: plan.hasGraph
219
209
  ? [
220
210
  'returnValue',
221
211
  'parentFlowId',
222
212
  'status',
223
- 'errorsFound'
213
+ 'errorsFound',
214
+ 'graphServiceTag'
224
215
  ]
225
- : (plan.hasGraph
226
- ? [
227
- 'returnValue',
228
- 'parentFlowId',
229
- 'status',
230
- 'errorsFound',
231
- 'graphServiceTag'
232
- ]
233
- : []),
216
+ : [],
234
217
  messageAttributes: MESSAGE_ATTRIBUTES
235
218
  });
236
219
  }
@@ -51,10 +51,6 @@ import {
51
51
  //(<optionalRequire>)
52
52
  //(</optionalRequire>)
53
53
 
54
- const { createObjType, firstLetterUpperCase } = utils;
55
- const { createDataDetailsLib } = dataDetailsLib;
56
- const { createIdentifiersByUseCase } = identifiersObject;
57
-
58
54
  // ── Main Entry Function ───────────────────────────────────────────────────────
59
55
 
60
56
  /**
@@ -83,7 +79,7 @@ export default async function <%- flowTag %>(
83
79
  const errorsFound = [];
84
80
 
85
81
  // Step 1: Resolve Schema & Identity
86
- const { objType, objectSchema, targetIdentifiers } =
82
+ const { objType, objectSchema } =
87
83
  await resolveSchemaAndIdentity(_izContext, requestParams, errorsFound);
88
84
 
89
85
  //(<beforeQuery>)
@@ -94,8 +90,6 @@ export default async function <%- flowTag %>(
94
90
  _izContext,
95
91
  requestParams,
96
92
  objectSchema,
97
- objType,
98
- targetIdentifiers,
99
93
  errorsFound
100
94
  );
101
95
 
@@ -167,7 +161,9 @@ export default async function <%- flowTag %>(
167
161
  },
168
162
  parameterGroups,
169
163
  {
170
- targetIdentifiers,
164
+ targetIdentifiers:
165
+ requestParams.rbacTargetIdentifiers ||
166
+ requestParams.targetIdentifiers,
171
167
  rbacObjType: {
172
168
  serviceTag: <%- rbacServiceTags.length === 1 ? rbacServiceTags[0] : `{ ${Object.entries(rbacServiceTagMap).map(([k, v]) => `'${k}': ${v}`).join(', ')} }[requestParams.objectType] || process.env.iz_serviceTag` %>
173
169
  },
@@ -198,11 +194,15 @@ export default async function <%- flowTag %>(
198
194
 
199
195
  // ── Optional phase extension point ────────────────────────────────────────
200
196
  <%_
197
+ const allCrudObjectTypes = (objects || []).filter(isCrudObject).map(o => o.objectType);
201
198
  const beforeHooksByObjType = (plan?.beforeHooks || []).reduce((acc, hook) => {
202
- const key = hook?.objType?.objectType;
203
- if (!key) return acc;
204
- if (!acc[key]) acc[key] = [];
205
- acc[key].push(hook);
199
+ const targets = (hook?.targetObjectTypes && hook.targetObjectTypes.length > 0)
200
+ ? hook.targetObjectTypes
201
+ : allCrudObjectTypes;
202
+ for (const key of targets) {
203
+ if (!acc[key]) acc[key] = [];
204
+ acc[key].push(hook);
205
+ }
206
206
  return acc;
207
207
  }, {});
208
208
  _%>
@@ -216,6 +216,15 @@ export default async function <%- flowTag %>(
216
216
  const lambdaSyncInvResults = [];
217
217
  <%_ for (const config of configs.filter(c => c?.generatedCodeConfig?.invocationType === 'lambdaSyncInv' || c?.event?.includes('lambdaSyncInv'))) { _%>
218
218
  try {
219
+ let hookPayload_<%= config.flowTag %> = {
220
+ objType,
221
+ fieldNames: requestParams.fieldNames,
222
+ relationships: requestParams.relationships || [],
223
+ targetIdentifiers: requestParams.targetIdentifiers,
224
+ submittedByUserId: requestParams.submittedByUserId
225
+ };
226
+ //(<beforeSendHook_<%= config.flowTag %>>)
227
+ //(</beforeSendHook_<%= config.flowTag %>>)
219
228
  const returnValue = await lambda.invokeSync(
220
229
  _izContext,
221
230
  await lambdaSharedLib.lambdaFunctionName(
@@ -223,13 +232,7 @@ export default async function <%- flowTag %>(
223
232
  '<%= config.flowTag %>'
224
233
  ),
225
234
  {
226
- requestParams: {
227
- objType,
228
- fieldNames: requestParams.fieldNames,
229
- relationships: requestParams.relationships || [],
230
- targetIdentifiers,
231
- submittedByUserId: requestParams.submittedByUserId
232
- },
235
+ requestParams: hookPayload_<%= config.flowTag %>,
233
236
  callingFlowConfig
234
237
  }
235
238
  );
@@ -274,15 +277,18 @@ export default async function <%- flowTag %>(
274
277
  <%_ if (hasOwnTopic) { _%>
275
278
  // ── ownTopic (async — dispatch to before-hook and await callback) ──────────
276
279
  <%_ configs.filter(c => c?.generatedCodeConfig?.invocationType === 'ownTopic' || c?.event?.includes('ownTopic')).forEach(config => { _%>
280
+ let hookPayload_<%= config.flowTag %> = {
281
+ objType,
282
+ fieldNames: requestParams.fieldNames,
283
+ relationships: requestParams.relationships || [],
284
+ targetIdentifiers: requestParams.targetIdentifiers,
285
+ submittedByUserId: requestParams.submittedByUserId
286
+ };
287
+ //(<beforeSendHook_<%= config.flowTag %>>)
288
+ //(</beforeSendHook_<%= config.flowTag %>>)
277
289
  const hookMsg_<%= config.flowTag %> =
278
290
  callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
279
- {
280
- objType,
281
- fieldNames: requestParams.fieldNames,
282
- relationships: requestParams.relationships || [],
283
- targetIdentifiers,
284
- submittedByUserId: requestParams.submittedByUserId
285
- },
291
+ hookPayload_<%= config.flowTag %>,
286
292
  callingFlowSharedLib.addParentCallingFlowConfig(
287
293
  callingFlowConfig,
288
294
  callingFlowSharedLib.createCallingFlowConfig(
@@ -294,7 +300,7 @@ export default async function <%- flowTag %>(
294
300
  originalRequestParams: {
295
301
  ...requestParams,
296
302
  objType,
297
- targetIdentifiers
303
+ targetIdentifiers: requestParams.targetIdentifiers
298
304
  },
299
305
  callingFlowConfig
300
306
  }