@izara_project/izara-core-generate-service-code 1.0.84 → 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 (26) hide show
  1. package/package.json +1 -1
  2. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +5 -0
  3. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +13 -4
  4. package/src/emit/crud/crudActionPlan.js +3 -1
  5. package/src/emit/crud/emitCrudApplicationArtifacts.js +37 -4
  6. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +126 -21
  7. package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
  8. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +248 -181
  9. package/src/emit/crud/templates/CreateLogicalLib.ejs +1155 -293
  10. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
  11. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
  12. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +76 -14
  13. package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
  14. package/src/emit/rbac/templates/CancelUsage_Main.ejs +82 -22
  15. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +130 -14
  16. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +29 -10
  17. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +30 -11
  18. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +28 -3
  19. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +10 -7
  20. package/src/emit/resource/emitResourceArtifacts.js +9 -0
  21. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +3 -1
  22. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +2 -0
  23. package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
  24. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +0 -1
  25. package/test/dynamicCrudFlowSchemas.test.js +16 -2
  26. package/test/resourceArtifacts.test.js +21 -0
@@ -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
+ }
@@ -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(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] 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(`[${process.env.iz_serviceTag}:<%- flowTag %>RbacCallback] 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,22 +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
 
103
- if (!eventParams.submittedByUserId) {
104
- const contextUserId = event._izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
105
- if (contextUserId) {
106
- eventParams.submittedByUserId = contextUserId;
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
+ );
107
142
  }
143
+ if (
144
+ !eventParams.targetIdentifiers ||
145
+ typeof eventParams.targetIdentifiers !== 'object'
146
+ ) {
147
+ eventParams.targetIdentifiers = {};
148
+ }
149
+ eventParams.targetIdentifiers.submittedByUserId = resolvedUserId;
108
150
  }
109
151
 
152
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] resolved user and target identifiers', {
153
+ authorizerUserId,
154
+ resolvedUserId,
155
+ targetIdentifiers: eventParams.targetIdentifiers
156
+ });
157
+
110
158
  let callingFlow = eventParams?.callingFlow
111
159
  ? eventParams.callingFlow
112
160
  : {};
161
+
162
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] invoking main function', {
163
+ flowTag: '<%- flowTag %>',
164
+ eventParams,
165
+ callingFlow
166
+ });
167
+
113
168
  await <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
114
169
  event._izContext,
115
170
  eventParams,
@@ -122,16 +177,23 @@ export const main = middleware.wrap(async (event, context) => {
122
177
  }
123
178
  } else {
124
179
  const connId = event.connId;
125
- // await postMessage({ message: event.message }, connId);
180
+ event._izContext.logger.debug('[FlowEndpoint_HdrWbs] direct postToConnection', {
181
+ connId,
182
+ message: event.message
183
+ });
126
184
  await postToConnection(event._izContext, { message: event.message }, connId);
127
185
  }
128
186
 
129
187
  return response.webSocketSuccess();
130
188
  } catch (err) {
131
- const connId = event.requestContext.connectionId;
132
- event._izContext.logger.error('Error, WebSocket: ', err);
133
- // await sendErrorMessage({ message: err.message }, connId);
134
- 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
+ }
135
197
  return response.failure(err);
136
198
  }
137
199
  });
@@ -33,34 +33,27 @@ const { postToConnection } = webSocket;
33
33
  //(</optionalRequire>)
34
34
 
35
35
  /**
36
- *
37
- *
38
- * description of function.
36
+ * WebSocket handler entry for <%- upperCaseFlowTag %> Flow
39
37
  * @param {Object} _izContext
40
- * @param {CorrelationIds} _izContext.correlationIds - property of _izContext
41
- * @param {Logger} _izContext.logger - property of _izContext
42
- * @param {Object} requestParams - request params
43
- * @param {Object} requestParams.identifiers - identifiers for get data
44
- * @param {Object} requestParams.additionalRequest - additionalRequest
45
- *
46
- * @returns {object} description of return value
38
+ * @param {CorrelationIds} _izContext.correlationIds - Context correlation IDs
39
+ * @param {Logger} _izContext.logger - Context logger
40
+ * @param {Object} requestParams - Request parameters
41
+ * @param {Object} callingFlowConfig - Calling flow configuration
42
+ * @returns {Promise<void>}
47
43
  */
48
44
  export default async function <%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>(
49
45
  _izContext,
50
46
  requestParams,
51
- //(<additionalParams>)
52
- //(</additionalParams>)
53
- callingFlowConfig = {}
47
+ callingFlowConfig
54
48
  ) {
55
49
  try {
56
- _izContext.logger.debug('<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> _izContext', _izContext);
57
- _izContext.logger.debug('<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> requestParams', requestParams);
58
50
  _izContext.logger.debug(
59
- '<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %> callingFlowConfig',
51
+ `[${process.env.iz_serviceTag}:<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>Wbs] started`,
52
+ requestParams,
60
53
  callingFlowConfig
61
54
  );
62
55
 
63
- let flowSchema = await getObjectSchema.getFlowSchemaS3WithCache(
56
+ const flowSchema = await getObjectSchema.getFlowSchemaS3WithCache(
64
57
  _izContext,
65
58
  {
66
59
  flowTag: '<%- flowTag %>',
@@ -70,6 +63,23 @@ export default async function <%- typeof functionName !== 'undefined' ? function
70
63
 
71
64
  _izContext.logger.debug('flowSchema', flowSchema);
72
65
 
66
+ const connectionId = _izContext.correlationIds?.get(coreConsts.CONNECTION_ID);
67
+
68
+ if (!flowSchema) {
69
+ if (connectionId) {
70
+ await postToConnection(
71
+ _izContext,
72
+ {
73
+ message: {
74
+ error: `flowTag not found ${requestParams.action}`
75
+ }
76
+ },
77
+ connectionId
78
+ );
79
+ }
80
+ throw new NoRetryError(`flowTag not found ${requestParams.action}`);
81
+ }
82
+
73
83
  if (
74
84
  flowSchema.initiateBy === 'user' ||
75
85
  flowSchema.initiateBy === 'systemWithUser'
@@ -77,24 +87,9 @@ export default async function <%- typeof functionName !== 'undefined' ? function
77
87
  _izContext.correlationIds.set(coreConsts.USER_AGENT, 'webSocket');
78
88
  }
79
89
 
80
- let connectionId = _izContext.correlationIds.get(coreConsts.CONNECTION_ID);
81
-
82
- if (!flowSchema) {
83
- await postToConnection(
84
- _izContext,
85
- {
86
- message: {
87
- error: `flowTag not found ${requestParams.action}`
88
- }
89
- },
90
- connectionId
91
- );
92
- throw new NoRetryError(`flowTag not found ${requestParams.action}`);
93
- }
94
-
95
90
  let messageObject = requestParams;
96
91
 
97
- // create callingFlow
92
+ // Attach calling flow configuration pointing to WebSocketCompleteHdrSqs
98
93
  messageObject =
99
94
  callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
100
95
  messageObject,
@@ -110,17 +105,18 @@ export default async function <%- typeof functionName !== 'undefined' ? function
110
105
  )
111
106
  );
112
107
 
113
- let sendMessageToEndpoint = {
108
+ const sendMessageToEndpoint = {
114
109
  Message: JSON.stringify(messageObject),
115
110
  TopicArn: snsSharedLib.snsTopicArnByFlowSchema(
116
111
  _izContext,
117
112
  '<%- upperCaseFlowTag %>_In'
118
113
  )
119
114
  };
115
+
120
116
  _izContext.logger.debug('sendMessageToEndpoint', sendMessageToEndpoint);
121
117
  await sns.publishAsync(_izContext, sendMessageToEndpoint);
122
118
  } catch (err) {
123
- _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- typeof functionName !== undefined ? functionName : upperCaseFlowTag %>Wbs] error:`, err);
119
+ _izContext.logger.error(`[${process.env.iz_serviceTag}:<%- typeof functionName !== 'undefined' ? functionName : upperCaseFlowTag %>Wbs] error:`, err);
124
120
  throw err;
125
121
  }
126
122
  }