@izara_project/izara-core-generate-service-code 1.0.83 → 1.0.85

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 (63) hide show
  1. package/package.json +4 -4
  2. package/src/compile/flowValidator.js +13 -2
  3. package/src/compile/loadSchemas.js +116 -7
  4. package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
  5. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +34 -1
  6. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +29 -7
  7. package/src/emit/crud/crudActionPlan.js +41 -6
  8. package/src/emit/crud/emitCrudApplicationArtifacts.js +56 -8
  9. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +153 -27
  10. package/src/emit/crud/generateCrudApplicationArtifacts.js +3 -2
  11. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +3 -2
  12. package/src/emit/crud/loadLocalSchemaArrays.js +3 -3
  13. package/src/emit/crud/templates/CreateComplete_Main.ejs +1 -1
  14. package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
  15. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +252 -154
  16. package/src/emit/crud/templates/CreateLogicalLib.ejs +1163 -236
  17. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
  18. package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
  19. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +33 -8
  20. package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
  21. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
  22. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +79 -10
  23. package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
  24. package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
  25. package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
  26. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +52 -3
  27. package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
  28. package/src/emit/custom/customFlows.js +47 -0
  29. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
  30. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
  31. package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
  32. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
  33. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  34. package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
  35. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
  36. package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
  37. package/src/emit/rbac/templates/CancelUsage_Main.ejs +163 -0
  38. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +187 -0
  39. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +68 -6
  40. package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
  41. package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
  42. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +166 -0
  43. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +84 -23
  44. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +11 -8
  45. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
  46. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +4 -4
  47. package/src/emit/resource/emitResourceArtifacts.js +351 -108
  48. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +3 -1
  49. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +55 -2
  50. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
  51. package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -5
  52. package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
  53. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +6 -0
  54. package/src/emit/systemText/emitSystemTextSchemas.js +1 -1
  55. package/src/generate.js +41 -10
  56. package/test/attributeTreeSchemas.test.js +219 -0
  57. package/test/createTargetRoleHandler.test.js +59 -4
  58. package/test/crudApplicationArtifacts.test.js +20 -3
  59. package/test/customFlowApplicationArtifacts.test.js +5 -5
  60. package/test/dynamicCrudFlowSchemas.test.js +107 -6
  61. package/test/dynamicRbacFlowSchemas.test.js +15 -2
  62. package/test/publicApi.test.js +6 -6
  63. package/test/resourceArtifacts.test.js +89 -27
@@ -0,0 +1,221 @@
1
+ /*
2
+ Copyright (C) 2021 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 dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
21
+ import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
22
+ import snsSharedLib from '@izara_project/izara-core-library-sns';
23
+ import { sns } from '@izara_project/izara-core-library-external-request';
24
+ import { consts } from '@izara_project/izara-core-library-service-schemas';
25
+ import {
26
+ consts as coreConsts,
27
+ NoRetryError
28
+ } from '@izara_project/izara-core-library-core';
29
+
30
+ import {
31
+ saveDynamoDbRecords,
32
+ autoProvisionOwnerTargetRole,
33
+ resolveQuotaDeductionKeys,
34
+ forwardToQuotaConfirmation
35
+ } from './CreateLogicalLib.js';
36
+
37
+ //(<optionalRequire>)
38
+ //(</optionalRequire>)
39
+
40
+ const PREFIX = { ASYNC: 'CreateAsyncEndpoint' };
41
+
42
+ function empty(value) {
43
+ return (
44
+ value == null ||
45
+ (typeof value === 'object' && Object.keys(value).length === 0)
46
+ );
47
+ }
48
+
49
+ function validateInput(returnValue, status, graphServiceTag, errorsFound) {
50
+ if (!returnValue?.queryResult)
51
+ errorsFound.push(
52
+ 'message is not have property queryResult, should be not happen'
53
+ );
54
+ if (!returnValue?.requestParams?.objType)
55
+ errorsFound.push(
56
+ 'message is not have property objType, should be not happen'
57
+ );
58
+ if (!returnValue?.requestParams?.objInstanceFull)
59
+ errorsFound.push(
60
+ 'message is not have property objInstance, should be not objInstance'
61
+ );
62
+ if (status === 'error' && errorsFound.length === 0)
63
+ errorsFound.push(
64
+ '[invalid]status is error not have errorsFound form graphService'
65
+ );
66
+ if (status === 'complete' && errorsFound.length > 0)
67
+ errorsFound.push(
68
+ '[Invalid] status is complete should be not have errorsFound'
69
+ );
70
+ if (graphServiceTag == null)
71
+ errorsFound.push('[Invalid] graphServerTag is not empty string');
72
+ }
73
+
74
+ /**
75
+ * Handles callback after Graph creation node completion
76
+ * @param {Object} _izContext - Izara context object
77
+ * @param {Object} requestParams - Callback request parameters
78
+ * @param {Object} passBackProperties - Pass-back properties
79
+ * @returns {Promise<Object>} Result object
80
+ */
81
+ export default async function CreateNodeCallbackMain(
82
+ _izContext,
83
+ requestParams,
84
+ passBackProperties
85
+ //(<additionalParams>)
86
+ //(</additionalParams>)
87
+ ) {
88
+ try {
89
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:CreateNodeCallback] started`, {
90
+ requestParams,
91
+ passBackProperties
92
+ });
93
+ const {
94
+ returnValue,
95
+ status,
96
+ errorsFound = [],
97
+ graphServiceTag,
98
+ parentFlowId
99
+ } = requestParams;
100
+ if (empty(returnValue?.requestParams))
101
+ throw new NoRetryError('message not an object');
102
+ validateInput(returnValue, status, graphServiceTag, errorsFound);
103
+ if (errorsFound.length > 0) errorsFound.push(errorsFound.join(','));
104
+
105
+ const awaitingStepId = await asyncFlowSharedLib.createAwaitingStepId(
106
+ parentFlowId,
107
+ PREFIX.ASYNC
108
+ );
109
+ const pending =
110
+ await asyncFlowSharedLib.findPendingStepAwaitingMultipleSteps(
111
+ _izContext,
112
+ awaitingStepId
113
+ );
114
+ _izContext.logger.debug('[CreateNodeCallback] awaiting step', {
115
+ awaitingStepId,
116
+ pending
117
+ });
118
+ if (!pending) {
119
+ _izContext.logger.warn(
120
+ `No pending step found for awaitingStepId: ${awaitingStepId}`
121
+ );
122
+ return { returnValue, status, errorsFound };
123
+ }
124
+ const result =
125
+ await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
126
+ _izContext,
127
+ pending.pendingStepId,
128
+ awaitingStepId,
129
+ errorsFound
130
+ );
131
+ _izContext.logger.debug(
132
+ '[CreateNodeCallback] all awaiting steps result',
133
+ {
134
+ isComplete: result.isComplete,
135
+ awaitingStepId,
136
+ pendingStepId: pending.pendingStepId
137
+ }
138
+ );
139
+
140
+ if (result.isComplete) {
141
+ const nodeResultKey = `returnCreatedNode`;
142
+ const fallbackNodeResultKey = `returnCreateNode`;
143
+ const nodeResult =
144
+ returnValue.queryResult[nodeResultKey] ??
145
+ returnValue.queryResult[fallbackNodeResultKey] ??
146
+ {};
147
+ const node = nodeResult.createNodeResult ?? nodeResult;
148
+ const existsNode =
149
+ node.existsNode && Object.keys(node.existsNode).length
150
+ ? {
151
+ objType: returnValue.requestParams.objType,
152
+ objInstanceFull: node.existsNode.objInstanceFull
153
+ }
154
+ : null;
155
+
156
+ // ── Step 1: Persist DynamoDB records ──────────────────────────────────
157
+ if (status === 'complete' && errorsFound.length === 0) {
158
+ const listOfRecords = result?.additionalAttributes?.listOfRecords ?? [];
159
+ await saveDynamoDbRecords(_izContext, listOfRecords);
160
+
161
+ // ── Step 2: Auto-provision TargetRole (Owner) after DynamoDB write ─
162
+ const submittedByUserId =
163
+ returnValue?.requestParams?.submittedByUserId ||
164
+ node?.objInstanceFull?.identifiers?.submittedByUserId ||
165
+ requestParams?.passBackProperties?.submittedByUserId ||
166
+ passBackProperties?.passBackProperties?.submittedByUserId ||
167
+ _izContext.correlationIds?.get(coreConsts.SUBMITTED_BY_USER_ID) ||
168
+ _izContext.correlationIds?.get('submittedByUserId');
169
+
170
+ await autoProvisionOwnerTargetRole(_izContext, {
171
+ node,
172
+ submittedByUserId
173
+ });
174
+ }
175
+
176
+ const callingFlowConfig =
177
+ result?.additionalAttributes?.callingFlowConfig ||
178
+ requestParams?.passBackProperties?.parentPassBackProperties ||
179
+ passBackProperties?.passBackProperties?.parentPassBackProperties ||
180
+ passBackProperties;
181
+
182
+ const actionData = {
183
+ objType: returnValue.requestParams.objType,
184
+ objInstanceFull: node.objInstanceFull,
185
+ relationships: node.relationships,
186
+ parentFlowId: parentFlowId || returnValue?.parentFlowId,
187
+ existsNode,
188
+ status,
189
+ errorsFound
190
+ };
191
+
192
+ // ── Step 3: Resolve Quota deduction keys and forward confirmation ─────
193
+ const quotaKeys = resolveQuotaDeductionKeys(
194
+ requestParams,
195
+ passBackProperties,
196
+ returnValue,
197
+ callingFlowConfig,
198
+ _izContext
199
+ );
200
+
201
+ await forwardToQuotaConfirmation(_izContext, {
202
+ status,
203
+ errorsFound,
204
+ quotaKeys,
205
+ actionData,
206
+ callingFlowConfig
207
+ });
208
+ }
209
+
210
+ await asyncFlowSharedLib.removeAwaitingMultipleStep(
211
+ _izContext,
212
+ awaitingStepId,
213
+ pending.pendingStepId,
214
+ errorsFound
215
+ );
216
+ return { returnValue, status, errorsFound };
217
+ } catch (error) {
218
+ _izContext.logger.error('[CreateNodeCallback] error:', error);
219
+ throw error;
220
+ }
221
+ }
@@ -52,7 +52,7 @@ export default async function DeleteComplete(
52
52
  //(</additionalParams>)
53
53
  ) {
54
54
  try {
55
- _izContext.logger.debug('[DeleteComplete] started', {
55
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:DeleteComplete] started`, {
56
56
  requestParams
57
57
  });
58
58
  const {
@@ -56,7 +56,7 @@ export default async function <%- flowTag %>(
56
56
  //(</additionalParams>)
57
57
  ) {
58
58
  try {
59
- _izContext.logger.debug('[<%- flowTag %>]', {
59
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] deleteMain:`, {
60
60
  requestParams,
61
61
  callingFlowConfig
62
62
  });
@@ -72,18 +72,42 @@ export default async function <%- flowTag %>(
72
72
  _izContext,
73
73
  objType
74
74
  );
75
- _izContext.logger.debug('objectSchema', objectSchema);
75
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] objectSchema:`, objectSchema);
76
76
 
77
- // ── Resolve userId / targetId ─────────────────────────────────────────────
77
+ // ── Resolve submittedByUserId / targetIdentifiers ─────────────────────────
78
+ let submittedByUserId, targetIdentifiers;
78
79
  if (
79
80
  objectSchema.generatedBy === 'user' ||
80
81
  objectSchema.generatedBy === 'systemWithUser'
81
82
  ) {
82
- const userId = _izContext.correlationIds.get(coreConsts.BASE_USER_ID);
83
- const targetId = _izContext.correlationIds.get(coreConsts.TARGET_ID);
84
- if (!userId) errorsFound.push('Not have userId');
85
- if (objectSchema.hasOwnProperty('belongTo') && !targetId)
86
- errorsFound.push('not have targetId');
83
+ submittedByUserId =
84
+ requestParams.submittedByUserId ||
85
+ _izContext.correlationIds.get(coreConsts.SUBMITTED_BY_USER_ID);
86
+
87
+ targetIdentifiers = requestParams.targetIdentifiers;
88
+
89
+ if (!targetIdentifiers && objectSchema.belongTo?.objectType === 'user' && submittedByUserId) {
90
+ targetIdentifiers = { submittedByUserId };
91
+ }
92
+
93
+ if (!submittedByUserId) errorsFound.push('Not have submittedByUserId');
94
+ if (objectSchema.hasOwnProperty('belongTo') && !targetIdentifiers)
95
+ errorsFound.push('not have targetIdentifiers');
96
+
97
+ requestParams.submittedByUserId = submittedByUserId;
98
+ if (targetIdentifiers) {
99
+ if (!targetIdentifiers.submittedByUserId && submittedByUserId) {
100
+ targetIdentifiers.submittedByUserId = submittedByUserId;
101
+ }
102
+ requestParams.targetIdentifiers = targetIdentifiers;
103
+ }
104
+
105
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Identity & Target Context Resolved:`, {
106
+ submittedByUserId: requestParams.submittedByUserId,
107
+ targetIdentifiers: requestParams.targetIdentifiers,
108
+ belongTo: objectSchema.belongTo,
109
+ generatedBy: objectSchema.generatedBy
110
+ });
87
111
  }
88
112
 
89
113
  //(<beforeQuery>)
@@ -315,6 +339,7 @@ export default async function <%- flowTag %>(
315
339
  errorsFound
316
340
  );
317
341
  } catch (err) {
342
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, err);
318
343
  throw err;
319
344
  }
320
345
  }
@@ -62,7 +62,7 @@ export async function <%- flowTag %>LogicalLib(
62
62
  phaseResults = {}
63
63
  ) {
64
64
  try {
65
- _izContext.logger.debug('[<%- flowTag %>LogicalLib] started', {
65
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] started`, {
66
66
  requestParams,
67
67
  callingFlowConfig,
68
68
  phaseResults
@@ -78,14 +78,14 @@ export async function <%- flowTag %>LogicalLib(
78
78
  _izContext,
79
79
  objType
80
80
  );
81
- _izContext.logger.debug('objectSchema', objectSchema);
81
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] objectSchema:`, objectSchema);
82
82
 
83
83
  // ── Build deleteDataDetails ───────────────────────────────────────────────
84
84
  const deleteDataDetails = await createDeleteDataDetail(
85
85
  _izContext,
86
86
  objectSchema
87
87
  );
88
- _izContext.logger.debug('deleteDataDetails', deleteDataDetails);
88
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] deleteDataDetails:`, deleteDataDetails);
89
89
 
90
90
  if (objectSchema.canDelete === false || objectSchema.canDelete == null) {
91
91
  errorsFound.push("this objectSchema can't delete");
@@ -119,6 +119,7 @@ export async function <%- flowTag %>LogicalLib(
119
119
  return {
120
120
  objType,
121
121
  identifiers: requestParams.identifiers,
122
+ targetIdentifiers: requestParams.targetIdentifiers,
122
123
  status: 'error',
123
124
  errorsFound
124
125
  };
@@ -201,10 +202,12 @@ export async function <%- flowTag %>LogicalLib(
201
202
  return {
202
203
  objType,
203
204
  identifiers: requestParams.identifiers,
205
+ targetIdentifiers: requestParams.targetIdentifiers,
204
206
  status: 'complete',
205
207
  errorsFound
206
208
  };
207
209
  } catch (err) {
210
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>LogicalLib] error:`, err);
208
211
  throw err;
209
212
  }
210
213
  }
@@ -30,7 +30,11 @@ import { sns } from '@izara_project/izara-core-library-external-request';
30
30
 
31
31
  const { createObjType } = utils;
32
32
 
33
- import { <%- flowTag %>LogicalLib } from './<%- upperCaseFlowTag %>LogicalLib.js';
33
+ import {
34
+ <%- flowTag %>LogicalLib,
35
+ collectRbacAwaitingResults,
36
+ assertRbacPermission
37
+ } from './<%- upperCaseFlowTag %>LogicalLib.js';
34
38
 
35
39
  //(<optionalRequire>)
36
40
  //(</optionalRequire>)
@@ -39,6 +43,7 @@ import { <%- flowTag %>LogicalLib } from './<%- upperCaseFlowTag %>LogicalLib.js
39
43
  * Handles callback after RbacCallback phase — verifies awaitingStep then proceeds to next phase
40
44
  * @param {Object} _izContext - Context object with logger
41
45
  * @param {Object} requestParams - { fieldNames, relationships[] }
46
+ * @param {string} flowTag - Flow tag name
42
47
  * @param {Object} callingFlowConfig - Calling flow configuration
43
48
  * @returns {Promise<Object>}
44
49
  */
@@ -49,149 +54,44 @@ export default async function <%- flowTag %>RbacCallbackMain(
49
54
  callingFlowConfig = {}
50
55
  ) {
51
56
  try {
52
- _izContext.logger.debug('[<%- flowTag %>RbacCallbackMain] Started with params:', {
57
+ _izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] Started with params:`, {
53
58
  requestParams,
54
59
  flowTag,
55
60
  callingFlowConfig
56
61
  });
57
62
 
58
- const parts = requestParams.parentFlowId.split('_');
59
- const rbacType = parts.pop();
60
- const rbacPendingStepId = '<%- flowTag %>RbacCallback_' + parts.join('_');
61
- const currentAwaitingStepId = requestParams.parentFlowId;
62
-
63
- _izContext.logger.debug(
64
- '[<%- flowTag %>RbacCallbackMain] Parsed RBAC pending details:',
65
- {
66
- rbacType,
67
- rbacPendingStepId,
68
- currentAwaitingStepId,
69
- parentFlowId: requestParams.parentFlowId
70
- }
71
- );
72
-
73
- const rbacAwaitingStepsResult =
74
- await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
75
- _izContext,
76
- rbacPendingStepId,
77
- currentAwaitingStepId,
78
- requestParams.errorsFound,
79
- {
80
- returnValue: requestParams.returnValue,
81
- rbacType
82
- }
83
- );
84
-
85
- _izContext.logger.debug(
86
- '[<%- flowTag %>RbacCallbackMain] checkAllAwaitingStepsFinishedWithReturnParams result:',
87
- {
88
- rbacAwaitingStepsResult
89
- }
90
- );
91
-
63
+ // 1. Wait until all awaiting steps (App/Target RBAC) are complete
92
64
  const {
93
65
  isComplete,
94
- collectedReturnValueByAwaitingStepId,
95
- collectedErrors: errorsFound = [],
96
- additionalAttributes
97
- } = rbacAwaitingStepsResult;
66
+ rbacResults,
67
+ originalRequestParams,
68
+ collectedErrors = []
69
+ } = await collectRbacAwaitingResults(_izContext, requestParams);
98
70
 
99
71
  if (isComplete === false) {
100
- _izContext.logger.debug(
101
- '[<%- flowTag %>RbacCallbackMain] Awaiting steps still pending completion:',
102
- {
103
- rbacPendingStepId,
104
- isComplete
105
- }
106
- );
107
-
108
72
  return 'all task not completed';
109
73
  }
110
74
 
111
- _izContext.logger.debug(
112
- '[<%- flowTag %>RbacCallbackMain] All awaiting steps completed — clearing awaiting steps:',
113
- {
114
- rbacPendingStepId
115
- }
116
- );
75
+ const errorsFound = [...collectedErrors];
117
76
 
118
- await asyncFlowSharedLib.clearAllAwaitingSteps(
77
+ // 2. Validate RBAC permission results
78
+ const { hasError, errorResult, rbacCallbackResults } = await assertRbacPermission(
119
79
  _izContext,
120
- rbacPendingStepId
121
- );
122
-
123
- const originalRequestParams = additionalAttributes?.requestParams || {};
124
-
125
- _izContext.logger.debug(
126
- '[<%- flowTag %>RbacCallbackMain] Retrieved originalRequestParams:',
127
80
  {
128
- originalRequestParams
129
- }
130
- );
131
-
132
- const rbacResults = Object.fromEntries(
133
- Object.entries(collectedReturnValueByAwaitingStepId || {}).map(
134
- ([stepId, attrs]) => {
135
- const type = stepId.split('_').pop();
136
- return [type, attrs];
137
- }
138
- )
139
- );
140
-
141
- const rbacCallbackResults = {};
142
- const hasError = Object.entries(rbacResults).some(([type, result]) => {
143
- if (result && result.error) {
144
- errorsFound.push(result.error);
145
- return true;
146
- }
147
- rbacCallbackResults[type] = result;
148
- return false;
149
- });
150
-
151
- const isAllowed = Object.values(rbacCallbackResults).some(
152
- item => item?.returnValue?.permission === true
153
- );
154
-
155
- if (!isAllowed) {
156
- errorsFound.push('Permission denied');
157
- }
158
-
159
- _izContext.logger.debug(
160
- '[<%- flowTag %>RbacCallbackMain] Final rbacCallbackResults before calling <%- flowTag %>MainLogical:',
161
- {
162
- rbacCallbackResults,
163
- isAllowed,
81
+ rbacResults,
82
+ originalRequestParams,
164
83
  errorsFound
165
84
  }
166
85
  );
167
86
 
168
- if (hasError || errorsFound.length > 0) {
169
- const errorResult = {
170
- errorsFound,
171
- status: 'rejected',
172
- requestParams: originalRequestParams
173
- };
174
-
175
- _izContext.logger.debug(
176
- '[<%- flowTag %>RbacCallbackMain] RBAC check failed, publishing rejected status:',
177
- errorResult
178
- );
179
-
180
- await sns.publishAsync(_izContext, {
181
- TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
182
- _izContext,
183
- '<%- upperCaseFlowTag %>_Out',
184
- process.env.iz_serviceTag
185
- ),
186
- Message: JSON.stringify(errorResult)
187
- });
188
-
87
+ if (hasError) {
189
88
  return errorResult;
190
89
  }
191
90
 
192
91
  //(<rbacCallbackMain>)
193
92
  //(</rbacCallbackMain>)
194
93
 
94
+ // 3. Permission granted -> Proceed with core logical processing
195
95
  const logicalResult = await <%- flowTag %>LogicalLib(
196
96
  _izContext,
197
97
  originalRequestParams,
@@ -209,7 +109,7 @@ export default async function <%- flowTag %>RbacCallbackMain(
209
109
 
210
110
  return logicalResult;
211
111
  } catch (err) {
212
- _izContext.logger.error('[<%- flowTag %>RbacCallbackMain] Error caught:', {
112
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] Error caught:`, {
213
113
  error: err
214
114
  });
215
115
  throw err;
@@ -39,7 +39,7 @@ import <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag
39
39
  //(</optionalRequire>)
40
40
 
41
41
  export const main = middleware.wrap(async (event, context) => {
42
- event._izContext.logger.debug('Event:', event);
42
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] WebSocket event received', { event });
43
43
 
44
44
  try {
45
45
  if (event.requestContext) {
@@ -49,12 +49,21 @@ export const main = middleware.wrap(async (event, context) => {
49
49
  consts.X_CORRELATION_ID
50
50
  );
51
51
 
52
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] request context info', {
53
+ route,
54
+ connectionId,
55
+ correlationId
56
+ });
57
+
52
58
  switch (route) {
53
59
  case '$default':
54
- console.log('Received unknown route:', route);
60
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] Received unknown route', { route });
55
61
  break;
56
62
  case '<%- flowTag %>':
57
- console.log('event in route webSocket', event);
63
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] matched route <%- flowTag %>', {
64
+ route,
65
+ body: event.body
66
+ });
58
67
  let eventParams = JSON.parse(event.body);
59
68
 
60
69
  //(<createIdentifiersFlow>)
@@ -69,11 +78,22 @@ export const main = middleware.wrap(async (event, context) => {
69
78
  }
70
79
  );
71
80
 
81
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] flow schema resolved', {
82
+ flowTag: '<%- flowTag %>',
83
+ statusType: flowSchema?.statusType
84
+ });
85
+
72
86
  if (
73
87
  flowSchema.statusType === 'statusField' ||
74
88
  flowSchema.statusType === 'storedCache' ||
75
89
  flowSchema.statusType === 'triggerCache'
76
90
  ) {
91
+ const taskKey = `${createFlowTypeConcat(event._izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${identifiers}`;
92
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] registering WebSocketTask with ttl', {
93
+ taskKey,
94
+ connectionId,
95
+ ttl: 600
96
+ });
77
97
  await dynamodbSharedLib.putItem(
78
98
  event._izContext,
79
99
  await dynamodbSharedLib.tableName(
@@ -81,12 +101,17 @@ export const main = middleware.wrap(async (event, context) => {
81
101
  'WebSocketTask'
82
102
  ),
83
103
  {
84
- taskKey: `${createFlowTypeConcat(event._izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${identifiers}`,
104
+ taskKey,
85
105
  connectionId: connectionId,
86
106
  ttl: 600
87
107
  }
88
108
  );
89
109
  } else if (flowSchema.statusType === 'none') {
110
+ const taskKey = `${createFlowTypeConcat(event._izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${correlationId}`;
111
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] registering WebSocketTask for status none', {
112
+ taskKey,
113
+ connectionId
114
+ });
90
115
  await dynamodbSharedLib.putItem(
91
116
  event._izContext,
92
117
  await dynamodbSharedLib.tableName(
@@ -94,15 +119,52 @@ export const main = middleware.wrap(async (event, context) => {
94
119
  'WebSocketTask'
95
120
  ),
96
121
  {
97
- taskKey: `${createFlowTypeConcat(event._izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${correlationId}`,
122
+ taskKey,
98
123
  connectionId: connectionId
99
124
  }
100
125
  );
101
126
  }
102
127
 
128
+ const authorizerUserId =
129
+ event.requestContext?.authorizer?.submittedByUserId ||
130
+ event.requestContext?.authorizer?.principalId;
131
+ const resolvedUserId =
132
+ authorizerUserId ||
133
+ eventParams.submittedByUserId ||
134
+ event._izContext?.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
135
+
136
+ if (resolvedUserId) {
137
+ if (event._izContext?.correlationIds) {
138
+ event._izContext.correlationIds.set(
139
+ consts.SUBMITTED_BY_USER_ID,
140
+ resolvedUserId
141
+ );
142
+ }
143
+ if (
144
+ !eventParams.targetIdentifiers ||
145
+ typeof eventParams.targetIdentifiers !== 'object'
146
+ ) {
147
+ eventParams.targetIdentifiers = {};
148
+ }
149
+ eventParams.targetIdentifiers.submittedByUserId = resolvedUserId;
150
+ }
151
+
152
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] resolved user and target identifiers', {
153
+ authorizerUserId,
154
+ resolvedUserId,
155
+ targetIdentifiers: eventParams.targetIdentifiers
156
+ });
157
+
103
158
  let callingFlow = eventParams?.callingFlow
104
159
  ? eventParams.callingFlow
105
160
  : {};
161
+
162
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] invoking main function', {
163
+ flowTag: '<%- flowTag %>',
164
+ eventParams,
165
+ callingFlow
166
+ });
167
+
106
168
  await <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
107
169
  event._izContext,
108
170
  eventParams,
@@ -115,16 +177,23 @@ export const main = middleware.wrap(async (event, context) => {
115
177
  }
116
178
  } else {
117
179
  const connId = event.connId;
118
- // await postMessage({ message: event.message }, connId);
180
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] direct postToConnection', {
181
+ connId,
182
+ message: event.message
183
+ });
119
184
  await postToConnection(event._izContext, { message: event.message }, connId);
120
185
  }
121
186
 
122
187
  return response.webSocketSuccess();
123
188
  } catch (err) {
124
- const connId = event.requestContext.connectionId;
125
- event._izContext.logger.error('Error, WebSocket: ', err);
126
- // await sendErrorMessage({ message: err.message }, connId);
127
- await postToConnection(event._izContext, { message: err.message }, connId);
189
+ const connId = event.requestContext?.connectionId;
190
+ event._izContext.logger.error('[FlowEndpoint_HdrWbs] Error, WebSocket: ', {
191
+ error: err,
192
+ connectionId: connId
193
+ });
194
+ if (connId) {
195
+ await postToConnection(event._izContext, { message: err.message }, connId);
196
+ }
128
197
  return response.failure(err);
129
198
  }
130
199
  });