@izara_project/izara-core-generate-service-code 1.0.68 → 1.0.70

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 (129) hide show
  1. package/package.json +1 -1
  2. package/scripts/format-ejs.js +36 -32
  3. package/src/compile/compileProject.js +26 -10
  4. package/src/compile/loadSchemas.js +122 -59
  5. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +163 -0
  6. package/src/emit/coreFunction/templates/CoreFunction_Yaml.ejs +38 -0
  7. package/src/emit/coreFunction/templates/CoreResource_Yaml.ejs +235 -0
  8. package/src/emit/coreFunction/templates/GenerateSeedDataDynamo_HdrInv.ejs +16 -0
  9. package/src/emit/coreFunction/templates/GenerateSeedDataDynamo_Main.ejs +38 -0
  10. package/src/emit/coreFunction/templates/GenerateSeedDataGraphData_HdrInv.ejs +16 -0
  11. package/src/emit/coreFunction/templates/GenerateSeedDataGraphData_Main.ejs +32 -0
  12. package/src/emit/coreFunction/templates/GenerateSeedDataGraphSchema_HdrInv.ejs +16 -0
  13. package/src/emit/coreFunction/templates/GenerateSeedDataGraphSchema_Main.ejs +71 -0
  14. package/src/emit/coreFunction/templates/GeneratedGraphNodeSchemas.ejs +47 -0
  15. package/src/emit/coreFunction/templates/GeneratedGraphRelSchemas.ejs +27 -0
  16. package/src/emit/coreFunction/templates/GeneratedTableConfigs.ejs +34 -0
  17. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +108 -0
  18. package/src/emit/coreFunction/templates/InitialSetup_HdrInv.ejs +12 -0
  19. package/src/emit/coreFunction/templates/InitialSetup_Main.ejs +51 -0
  20. package/src/emit/coreFunction/templates/RemoveSeedDataDynamo_HdrInv.ejs +16 -0
  21. package/src/emit/coreFunction/templates/RemoveSeedDataDynamo_Main.ejs +31 -0
  22. package/src/emit/coreFunction/templates/UploadSchema_HdrInv.ejs +37 -0
  23. package/src/emit/coreFunction/templates/UploadSchema_Main.ejs +52 -0
  24. package/src/emit/crud/emitCrudApplicationArtifacts.js +194 -41
  25. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +34 -17
  26. package/src/emit/crud/generateCrudApplicationArtifacts.js +14 -6
  27. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
  28. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +1 -1
  29. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +1 -1
  30. package/src/emit/crud/templates/GetEndpoint_Main.ejs +2 -2
  31. package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +1 -1
  32. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +1 -1
  33. package/src/emit/custom/customFlows.js +23 -13
  34. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +535 -114
  35. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +28 -8
  36. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +2 -2
  37. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  38. package/src/emit/custom/templates/s3/CreateObject_Main.ejs +1 -1
  39. package/src/emit/custom/templates/s3/FlowHandler_HdrS3.ejs +2 -2
  40. package/src/emit/custom/templates/s3/ReservedLimit_HdrSqs.ejs +1 -1
  41. package/src/emit/custom/templates/s3/ReservedLimit_Main.ejs +1 -1
  42. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +4 -4
  43. package/src/emit/function/functionYamlArtifact.js +273 -97
  44. package/src/emit/function/templates/ApiFunction_Yaml.ejs +7 -0
  45. package/src/emit/function/templates/EventBridgeFunction_Yaml.ejs +6 -0
  46. package/src/emit/function/templates/InvFunction_Yaml.ejs +5 -0
  47. package/src/emit/function/templates/S3Function_Yaml.ejs +16 -0
  48. package/src/emit/function/templates/SqsFunction_Yaml.ejs +10 -0
  49. package/src/emit/function/templates/WbsFunction_Yaml.ejs +10 -0
  50. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +28 -30
  51. package/src/emit/rbac/emitRbacApplicationArtifacts.js +6 -6
  52. package/src/emit/rbac/generateCreateTargetRoleHandler.js +6 -4
  53. package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +8 -2
  54. package/src/emit/rbac/rbacFlowTag.js +3 -1
  55. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +1 -1
  56. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +26 -10
  57. package/src/emit/relationship/emitRelationshipApplicationArtifacts.js +189 -37
  58. package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +8 -2
  59. package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +15 -6
  60. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +1 -1
  61. package/src/emit/relationship/templates/CreateRelationship_Main.ejs +1 -1
  62. package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +1 -1
  63. package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
  64. package/src/emit/relationship/templates/MoveRelationship_Main.ejs +1 -1
  65. package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +1 -1
  66. package/src/emit/resource/emitResourceArtifacts.js +249 -123
  67. package/src/emit/resource/generateResourceArtifacts.js +15 -6
  68. package/src/emit/resource/templates/DynamoDBTable_Yaml.ejs +18 -18
  69. package/src/emit/resource/templates/FlowOut_Yaml.ejs +5 -5
  70. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +10 -9
  71. package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +44 -44
  72. package/src/emit/resource/templates/ResourceSqsYaml.ejs +36 -36
  73. package/src/emit/resource/templates/ResourceYaml.ejs +48 -48
  74. package/src/emit/resource/templates/S3Subscription_Yaml.ejs +7 -0
  75. package/src/emit/resource/templates/SharedResource_Yaml.ejs +11 -11
  76. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +122 -105
  77. package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
  78. package/src/emit/shared/templates/FindData_HdrSqs.ejs +120 -0
  79. package/src/emit/shared/templates/FindData_Main.ejs +345 -0
  80. package/src/emit/{crud → shared}/templates/FlowHandler_HdrApi.ejs +1 -1
  81. package/src/emit/{relationship → shared}/templates/FlowHandler_HdrDsq.ejs +4 -4
  82. package/src/emit/{crud → shared}/templates/FlowHandler_HdrInv.ejs +1 -1
  83. package/src/emit/{crud → shared}/templates/FlowHandler_HdrSqs.ejs +4 -4
  84. package/src/emit/shared/templates/PaginateProcessLogical_HdrDsq.ejs +162 -0
  85. package/src/emit/shared/templates/PaginateProcessLogical_HdrSqs.ejs +140 -0
  86. package/src/emit/shared/templates/PaginateProcessLogical_Main.ejs +268 -0
  87. package/src/emit/{relationship/templates/FlowHandler_HdrSqs.ejs → shared/templates/ProcessLogical_HdrSqs.ejs} +40 -55
  88. package/src/emit/shared/templates/ProcessLogical_Main.ejs +448 -0
  89. package/src/emit/system/emitSystemFindDataArtifacts.js +266 -0
  90. package/src/emit/system/emitSystemWebSocketArtifacts.js +61 -165
  91. package/src/emit/system/templates/WebSocketComplete_HdrSqs.ejs +48 -0
  92. package/src/emit/system/templates/WebSocketComplete_Main.ejs +91 -0
  93. package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +19 -0
  94. package/src/emit/system/templates/WebSocketConnect.ejs +45 -0
  95. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +11 -0
  96. package/src/generate.js +166 -36
  97. package/src/generateIntTest.js +76 -28
  98. package/src/generateResourceIntTest.js +35 -12
  99. package/src/generateResources/IntTest/generateResources/generateResources.js +5 -2
  100. package/src/generateResources/IntTest/generateResources/templateResources.ejs +18 -30
  101. package/src/generateResources/IntTest/generateTests/events/events.js +1 -1
  102. package/src/generateResources/IntTest/generateTests/events/templateEvents.ejs +13 -10
  103. package/src/generateResources/IntTest/generateTests/generateTemplate.js +2 -2
  104. package/src/generateResources/IntTest/generateTests/pathIntTest/pathIntTest.js +2 -1
  105. package/src/generateResources/IntTest/generateTests/pathIntTest/template.ejs +1 -3
  106. package/src/generateResources/IntTest/generateTests/tests/templateTests.ejs +1 -1
  107. package/src/generateResources/IntTest/generateTests/tests/tests.js +7 -3
  108. package/src/generateResources/IntTest/libs/{libs.js → IntTestGenerateLib.js} +34 -23
  109. package/src/generateResources/IntTest/upload/uploadIntTest.js +33 -19
  110. package/src/intTestGeneratorShared.js +15 -10
  111. package/src/output/commitArtifacts.js +99 -39
  112. package/src/output/mergeHooks.js +34 -21
  113. package/src/output/validateArtifacts.js +37 -27
  114. package/src/plan/buildGenerationPlan.js +24 -13
  115. package/test/core.test.js +117 -58
  116. package/test/createTargetRoleHandler.test.js +1 -1
  117. package/test/crudApplicationArtifacts.test.js +132 -31
  118. package/test/customFlowApplicationArtifacts.test.js +353 -71
  119. package/test/dynamicCrudFlowSchemas.test.js +74 -26
  120. package/test/dynamicRbacFlowSchemas.test.js +61 -14
  121. package/test/dynamicRelationshipFlowSchemas.test.js +65 -18
  122. package/test/functionYamlArtifact.test.js +67 -10
  123. package/test/intTestApi.test.js +9 -10
  124. package/test/publicApi.test.js +178 -36
  125. package/test/relationshipApplicationArtifacts.test.js +90 -19
  126. package/test/resourceArtifacts.test.js +173 -33
  127. package/src/emit/relationship/dynamicRelationshipFlowSchemaTemplate.js +0 -11
  128. package/src/emit/relationship/templates/FlowHandler_HdrApi.ejs +0 -59
  129. package/src/emit/relationship/templates/FlowHandler_HdrInv.ejs +0 -47
@@ -66,7 +66,7 @@ import { consts as coreConsts } from '@izara_project/izara-core-library-core';
66
66
  export default async function getRelationship(
67
67
  _izContext,
68
68
  requestParams,
69
- callingFlowConfig = {}
69
+ callingFlowConfig = {},
70
70
  //(<additionalParams>)
71
71
  //(</additionalParams>)
72
72
  ) {
@@ -69,7 +69,7 @@ import { consts as coreConsts } from '@izara_project/izara-core-library-core';
69
69
  export default async function moveRelationship(
70
70
  _izContext,
71
71
  requestParams,
72
- callingFlowConfig = {}
72
+ callingFlowConfig = {},
73
73
  //(<additionalParams>)
74
74
  //(</additionalParams>)
75
75
  ) {
@@ -62,7 +62,7 @@ const { PREFIX, TOPIC_NAME_GENERATE_CODE, TOPIC_NAME_GRAPH_HANDLER } = consts;
62
62
  export default async function updateRelationship(
63
63
  _izContext,
64
64
  requestParams,
65
- callingFlowConfig = {}
65
+ callingFlowConfig = {},
66
66
  //(<additionalParams>)
67
67
  //(</additionalParams>)
68
68
  ) {
@@ -1,4 +1,4 @@
1
- import ejs from 'ejs';
1
+ import ejsLib from 'ejs';
2
2
  import { readFile } from 'node:fs/promises';
3
3
 
4
4
  import {
@@ -92,7 +92,7 @@ export async function emitResourceArtifacts({
92
92
  renderLambdaRoleConfig(state),
93
93
  renderS3(state)
94
94
  ]);
95
- return [
95
+ const artifacts = [
96
96
  {
97
97
  path: `${RESOURCE_ROOT}/generated-sns-in-sqs.yml`,
98
98
  content: normalizeYaml(inSqs)
@@ -106,18 +106,31 @@ export async function emitResourceArtifacts({
106
106
  content: normalizeYaml(dynamo)
107
107
  },
108
108
  {
109
- path: `${RESOURCE_ROOT}/generated-s3.yml`,
110
- content: normalizeYaml(s3)
109
+ path: `${APP_ROOT}/generate-shared-resource.yml`,
110
+ content: normalizeYaml(iam.iamContent)
111
111
  },
112
112
  {
113
- path: `${APP_ROOT}/generate-shared-resource.yml`,
114
- content: normalizeYaml(iam)
113
+ path: `${APP_ROOT}/role-name-config.yml`,
114
+ content: normalizeYaml(iam.roleNameConfigContent)
115
115
  },
116
116
  {
117
117
  path: `${INITIAL_SETUP_ROOT}/generatedLambdaRoleServiceConfig.js`,
118
118
  content: lambdaRoleConfig
119
119
  }
120
120
  ];
121
+ if (state.s3Buckets.length > 0) {
122
+ artifacts.push({
123
+ path: `${RESOURCE_ROOT}/generated-s3.yml`,
124
+ content: normalizeYaml(s3)
125
+ });
126
+ }
127
+ if (state.hasHttpApi) {
128
+ artifacts.push({
129
+ path: `${APP_ROOT}/cors.yml`,
130
+ content: renderCorsYaml()
131
+ });
132
+ }
133
+ return artifacts;
121
134
  }
122
135
 
123
136
  export const resourceArtifactPaths = [
@@ -126,7 +139,9 @@ export const resourceArtifactPaths = [
126
139
  `${RESOURCE_ROOT}/generated-dynamoDB-table.yml`,
127
140
  `${RESOURCE_ROOT}/generated-s3.yml`,
128
141
  `${APP_ROOT}/generate-shared-resource.yml`,
129
- `${INITIAL_SETUP_ROOT}/generatedLambdaRoleServiceConfig.js`
142
+ `${APP_ROOT}/role-name-config.yml`,
143
+ `${INITIAL_SETUP_ROOT}/generatedLambdaRoleServiceConfig.js`,
144
+ `${APP_ROOT}/cors.yml`
130
145
  ];
131
146
 
132
147
  function createResourceState({ objects, relationships, flows }) {
@@ -134,62 +149,60 @@ function createResourceState({ objects, relationships, flows }) {
134
149
  const rbac = objects.some(hasRbacAddOn);
135
150
  const ownTopics = new Set(
136
151
  flows
137
- .filter(flow => includesEvent(flow, 'ownTopic'))
138
- .map(flow => upperFirst(flow.flowTag))
152
+ .filter((flow) => includesEvent(flow, 'ownTopic'))
153
+ .map((flow) => upperFirst(flow.flowTag))
139
154
  );
140
155
  const sqsQueues = new Set([
141
156
  ...LEGACY_PROCESS_QUEUES,
142
157
  ...flows
143
- .filter(flow => includesEvent(flow, 'extTopic'))
144
- .map(flow => `Process${upperFirst(flow.flowTag)}HdrSqs`)
158
+ .filter((flow) => includesEvent(flow, 'extTopic'))
159
+ .map((flow) => `Process${upperFirst(flow.flowTag)}HdrSqs`)
145
160
  ]);
146
- flowExtTopicSteps(flows).forEach(({ flowTag, stepName }) =>
147
- sqsQueues.add(`${flowTag}${stepName}HdrSqs`)
148
- );
149
- flows
150
- .filter(flow => includesEvent(flow, 's3'))
151
- .forEach(flow => {
152
- const tag = upperFirst(flow.flowTag);
153
- sqsQueues.add(`${tag}CreatePreSignUrlHdrSqs`);
154
- sqsQueues.add(`${tag}ReservedLimitHdrSqs`);
155
- sqsQueues.add(`${tag}ConfirmAfterUploadHdrSqs`);
156
- });
161
+ for (const { flowTag, stepName } of flowExtTopicSteps(flows)) {
162
+ sqsQueues.add(`${flowTag}${stepName}HdrSqs`);
163
+ }
164
+ for (const flow of flows.filter((flow) => includesEvent(flow, 's3'))) {
165
+ const tag = upperFirst(flow.flowTag);
166
+ sqsQueues.add(`${tag}CreatePreSignUrlHdrSqs`);
167
+ sqsQueues.add(`${tag}ReservedLimitHdrSqs`);
168
+ sqsQueues.add(`${tag}ConfirmAfterUploadHdrSqs`);
169
+ }
157
170
  const dsqQueues = new Set(
158
171
  flows
159
- .filter(flow => includesEvent(flow, 'dsq'))
160
- .map(flow => `${upperFirst(flow.flowTag)}HdrDsq`)
161
- );
162
- flowDsqSteps(flows).forEach(({ flowTag, stepName }) =>
163
- dsqQueues.add(`${flowTag}${stepName}HdrDsq`)
172
+ .filter((flow) => includesEvent(flow, 'dsq'))
173
+ .map((flow) => `${upperFirst(flow.flowTag)}HdrDsq`)
164
174
  );
175
+ for (const { flowTag, stepName } of flowDsqSteps(flows)) {
176
+ dsqQueues.add(`${flowTag}${stepName}HdrDsq`);
177
+ }
165
178
  if (crud) {
166
- CRUD_ACTIONS.forEach(action => ownTopics.add(action));
167
- ['Create', 'Update', 'Delete'].forEach(action =>
168
- sqsQueues.add(`${action}CompleteHdrSqs`)
169
- );
179
+ for (const action of CRUD_ACTIONS) {
180
+ ownTopics.add(action);
181
+ }
182
+ for (const action of ['Create', 'Update', 'Delete']) {
183
+ sqsQueues.add(`${action}CompleteHdrSqs`);
184
+ }
170
185
  }
171
186
  if (relationships.length > 0) {
172
- RELATIONSHIP_ACTIONS.forEach(action => {
187
+ for (const action of RELATIONSHIP_ACTIONS) {
173
188
  ownTopics.add(action);
174
189
  sqsQueues.add(`${action}CompleteHdrSqs`);
175
- });
190
+ }
176
191
  dsqQueues.add('GetRelationshipHdrDsq');
177
192
  }
178
193
  if (rbac) {
179
- RBAC_ACTIONS.forEach(action => {
194
+ for (const action of RBAC_ACTIONS) {
180
195
  ownTopics.add(action);
181
196
  sqsQueues.add(`Process${action}HdrSqs`);
182
- });
183
- objects
184
- .filter(hasRbacAddOn)
185
- .forEach(object => {
186
- const flowTag = upperFirst(object.objectType) + 'RbacFlow';
187
- ownTopics.add(flowTag);
188
- });
197
+ }
198
+ for (const object of objects.filter(hasRbacAddOn)) {
199
+ const flowTag = upperFirst(object.objectType) + 'RbacFlow';
200
+ ownTopics.add(flowTag);
201
+ }
189
202
  }
190
203
  const beforeLogicalByAction = new Map();
191
204
  for (const flow of flows.filter(
192
- flow => flow?.generatedCodeConfig?.codeHookTag === 'beforeLogical'
205
+ (flow) => flow?.generatedCodeConfig?.codeHookTag === 'beforeLogical'
193
206
  )) {
194
207
  const action = upperFirst(flow.generatedCodeConfig.generatedCodeTag);
195
208
  if (!action || !flow.flowTag) continue;
@@ -202,10 +215,10 @@ function createResourceState({ objects, relationships, flows }) {
202
215
  );
203
216
  const customRoles = [
204
217
  ...new Set([
205
- ...supportedCustomFlows(flows).map(flow =>
218
+ ...supportedCustomFlows(flows).map((flow) =>
206
219
  customFlowRoleName(flow.flowTag)
207
220
  ),
208
- ...generatedOwnTopicFlows(flows).map(flow =>
221
+ ...generatedOwnTopicFlows(flows).map((flow) =>
209
222
  customFlowRoleName(flow.flowTag)
210
223
  ),
211
224
  ...flowExtTopicSteps(flows).map(({ flow }) =>
@@ -217,21 +230,28 @@ function createResourceState({ objects, relationships, flows }) {
217
230
  const websocket = hasSystemWebSocket(flows, {
218
231
  includeRelationshipOwnTopic: true
219
232
  });
220
- const webSocketRoles = new Set(websocket ? ['WebSocketMainRole'] : []);
233
+ const webSocketRoles = new Set();
234
+ if (websocket) {
235
+ webSocketRoles.add('WebSocketMainRole');
236
+ }
221
237
  if (crud) webSocketRoles.add('FlowObjectsRole');
222
238
  if (relationships.length > 0) webSocketRoles.add('FlowRelationshipRole');
223
239
  if (rbac) webSocketRoles.add('FlowRbacRole');
224
- [...supportedCustomFlows(flows), ...generatedOwnTopicFlows(flows)]
225
- .filter(
226
- flow => includesEvent(flow, 'ownTopic') || includesEvent(flow, 's3')
227
- )
228
- .forEach(flow => webSocketRoles.add(customFlowRoleName(flow.flowTag)));
240
+ const filteredWsFlows = [
241
+ ...supportedCustomFlows(flows),
242
+ ...generatedOwnTopicFlows(flows)
243
+ ].filter(
244
+ (flow) => includesEvent(flow, 'ownTopic') || includesEvent(flow, 's3')
245
+ );
246
+ for (const flow of filteredWsFlows) {
247
+ webSocketRoles.add(customFlowRoleName(flow.flowTag));
248
+ }
229
249
  const outTopics = new Set([
230
250
  ...ownTopics,
231
251
  ...beforeLogical.map(({ action }) => action),
232
252
  ...flows
233
- .filter(flow => flow?.outputTopic && upperFirst(flow.flowTag))
234
- .map(flow => upperFirst(flow.flowTag))
253
+ .filter((flow) => flow?.outputTopic && upperFirst(flow.flowTag))
254
+ .map((flow) => upperFirst(flow.flowTag))
235
255
  ]);
236
256
  const objectTableNames = [...collectTables(objects).keys()];
237
257
  const relationshipTableNames = [...collectTables(relationships).keys()];
@@ -240,15 +260,46 @@ function createResourceState({ objects, relationships, flows }) {
240
260
  ...collectTables(relationships)
241
261
  ]);
242
262
  const externalDynamoTables = objects.flatMap(
243
- object => object.externalDynamoResources ?? []
263
+ (object) => object.externalDynamoResources ?? []
244
264
  );
245
265
  const s3Buckets = flows
246
- .filter(flow => includesEvent(flow, 's3') && flow.createBucket === true)
247
- .map(flow => flow.bucketName)
266
+ .filter((flow) => includesEvent(flow, 's3') && flow.createBucket === true)
267
+ .map((flow) => flow.bucketName)
248
268
  .filter(Boolean);
269
+ const s3FlowTags = flows
270
+ .filter((flow) => includesEvent(flow, 's3'))
271
+ .map((flow) => upperFirst(flow.flowTag));
272
+ const s3Subscriptions = flows
273
+ .filter((flow) => includesEvent(flow, 's3'))
274
+ .map((flow) => {
275
+ const tag = upperFirst(flow.flowTag);
276
+ const topicName = flow.outputTopic
277
+ ? flow.outputTopic.startsWith('Out')
278
+ ? flow.outputTopic
279
+ : `Out${upperFirst(flow.outputTopic)}`
280
+ : flow.s3Subscription?.topicName || 'OutCreate';
281
+ const queueName =
282
+ flow.s3Subscription?.queueName || `${tag}ReservedLimitHdrSqs`;
283
+ const subscriptionName =
284
+ flow.s3Subscription?.subscriptionName ||
285
+ `Subscription${topicName}To${queueName}`;
286
+ return { subscriptionName, topicName, queueName };
287
+ });
288
+ const systemTables = [...SYSTEM_TABLES];
289
+ if (s3FlowTags.length > 0) {
290
+ systemTables.push('ReservedDataMain');
291
+ }
292
+ const hasHttpApi =
293
+ crud ||
294
+ relationships.length > 0 ||
295
+ rbac ||
296
+ flows.some((flow) => includesEvent(flow, 'lambdaSyncApi'));
249
297
  return {
250
298
  crud,
251
299
  rbac,
300
+ s3Subscriptions,
301
+ s3FlowTags,
302
+ hasHttpApi,
252
303
  relationships: relationships.length > 0,
253
304
  ownTopics: [...ownTopics].filter(Boolean).sort(),
254
305
  sqsQueues: [...sqsQueues].filter(Boolean).sort(),
@@ -260,9 +311,9 @@ function createResourceState({ objects, relationships, flows }) {
260
311
  webSocketSubscriptions: websocket
261
312
  ? [...outTopics]
262
313
  .filter(
263
- topic =>
314
+ (topic) =>
264
315
  flows.some(
265
- flow =>
316
+ (flow) =>
266
317
  (flow?.outputTopic ||
267
318
  (includesEvent(flow, 'ownTopic') &&
268
319
  flow.initiateBy === 'user')) &&
@@ -279,16 +330,16 @@ function createResourceState({ objects, relationships, flows }) {
279
330
  tableName,
280
331
  ...keys
281
332
  })),
282
- allTableNames: [...new Set([...SYSTEM_TABLES, ...tableMap.keys()])].sort(),
333
+ allTableNames: [...new Set([...systemTables, ...tableMap.keys()])].sort(),
283
334
  objectTableNames,
284
335
  relationshipTableNames,
285
336
  externalDynamoTables,
286
337
  objectTablesByType: new Map(
287
338
  objects
288
- .map(object => [
339
+ .map((object) => [
289
340
  object.objectType,
290
341
  Object.values(object.storageResources ?? {}).find(
291
- resource => resource?.storageType === 'dynamoDB'
342
+ (resource) => resource?.storageType === 'dynamoDB'
292
343
  )?.tableName
293
344
  ])
294
345
  .filter(([, tableName]) => tableName)
@@ -300,22 +351,25 @@ function createResourceState({ objects, relationships, flows }) {
300
351
 
301
352
  async function renderS3(state) {
302
353
  if (state.s3Buckets.length === 0) return 'Resources:';
303
- const template = await readFile(new URL('S3Bucket_Yaml.ejs', TEMPLATE_URL), 'utf8');
354
+ const template = await readFile(
355
+ new URL('S3Bucket_Yaml.ejs', TEMPLATE_URL),
356
+ 'utf8'
357
+ );
304
358
  const chunks = await Promise.all(
305
- state.s3Buckets.map(bucketName => ejs.render(template, { bucketName }))
359
+ state.s3Buckets.map((bucketName) => ejsLib.render(template, { bucketName }))
306
360
  );
307
361
  return `Resources:\n${chunks.join('\n')}`;
308
362
  }
309
363
 
310
364
  async function renderInSqs(state) {
311
365
  const chunks = await Promise.all([
312
- ...state.ownTopics.map(queueName =>
366
+ ...state.ownTopics.map((queueName) =>
313
367
  render('ResourceYaml.ejs', { queueName })
314
368
  ),
315
- ...state.sqsQueues.map(queueName =>
369
+ ...state.sqsQueues.map((queueName) =>
316
370
  render('ResourceSqsYaml.ejs', { queueName })
317
371
  ),
318
- ...state.dsqQueues.map(queueName =>
372
+ ...state.dsqQueues.map((queueName) =>
319
373
  render('ResourceSqsYaml.ejs', { queueName })
320
374
  ),
321
375
  ...state.beforeLogical.map(({ action, flowTags }) =>
@@ -332,17 +386,39 @@ async function renderInSqs(state) {
332
386
  ]
333
387
  : [])
334
388
  ]);
335
- return `Resources:\n${chunks.join('\n')}\n${state.webSocketSubscriptions.map(renderWebSocketSubscription).join('\n')}`;
389
+ const webSocketSubscriptions = await Promise.all(
390
+ state.webSocketSubscriptions.map((topicName) =>
391
+ renderWebSocketSubscription(topicName)
392
+ )
393
+ );
394
+ const s3Subscriptions = await Promise.all(
395
+ (state.s3Subscriptions ?? []).map(
396
+ ({ subscriptionName, topicName, queueName }) =>
397
+ render('S3Subscription_Yaml.ejs', {
398
+ subscriptionName,
399
+ topicName,
400
+ queueName
401
+ })
402
+ )
403
+ );
404
+ const parts = [chunks.join('\n')];
405
+ if (webSocketSubscriptions.length > 0) {
406
+ parts.push(webSocketSubscriptions.join('\n'));
407
+ }
408
+ if (s3Subscriptions.length > 0) {
409
+ parts.push(s3Subscriptions.join('\n'));
410
+ }
411
+ return `Resources:\n${parts.join('\n')}`;
336
412
  }
337
413
 
338
414
  async function renderOut(state) {
339
- return `Resources:\n${(await Promise.all(state.outTopics.map(topicName => render('FlowOut_Yaml.ejs', { topicName })))).join('\n')}`;
415
+ return `Resources:\n${(await Promise.all(state.outTopics.map((topicName) => render('FlowOut_Yaml.ejs', { topicName })))).join('\n')}`;
340
416
  }
341
417
 
342
418
  async function renderDynamo(state) {
343
419
  const [system, ...tables] = await Promise.all([
344
- render('SystemDynamoDB_Yaml.ejs', {}),
345
- ...state.tables.map(table => render('DynamoDBTable_Yaml.ejs', table))
420
+ render('SystemDynamoDB_Yaml.ejs', { hasS3: state.s3FlowTags.length > 0 }),
421
+ ...state.tables.map((table) => render('DynamoDBTable_Yaml.ejs', table))
346
422
  ]);
347
423
  return `${system}\n${tables.join('\n')}`;
348
424
  }
@@ -354,18 +430,22 @@ async function renderIam(state) {
354
430
  if (state.rbac) roles.push('FlowRbacRole');
355
431
  if (state.websocket) roles.push('WebSocketMainRole');
356
432
  roles.push(...state.customRoles);
357
- return render('SharedResource_Yaml.ejs', {
358
- roles: roles.sort().map(roleName => ({
359
- roleName,
360
- statements: roleStatements(state, roleName)
361
- }))
362
- });
433
+ const sortedRoles = roles.sort();
434
+ return {
435
+ iamContent: await render('SharedResource_Yaml.ejs', {
436
+ roles: sortedRoles.map((roleName) => ({
437
+ roleName,
438
+ statements: roleStatements(state, roleName)
439
+ }))
440
+ }),
441
+ roleNameConfigContent: renderRoleNameConfigYaml(sortedRoles)
442
+ };
363
443
  }
364
444
 
365
445
  async function renderLambdaRoleConfig(state) {
366
446
  const s3Flows = state.flows
367
- .filter(flow => includesEvent(flow, 's3'))
368
- .map(flow => ({
447
+ .filter((flow) => includesEvent(flow, 's3'))
448
+ .map((flow) => ({
369
449
  roleName: upperFirst(flow.flowTag)
370
450
  }));
371
451
  return render('GeneratedLambdaRoleServiceConfig.ejs', {
@@ -385,14 +465,10 @@ function roleStatements(state, roleName) {
385
465
  ]
386
466
  });
387
467
  }
388
- addStatement(
389
- statements,
390
- dynamoActionsForRole(roleName),
391
- [
392
- ...dynamoArns(roleTableNames(state, roleName)),
393
- ...externalDynamoArns(roleExternalDynamoTables(state, roleName))
394
- ]
395
- );
468
+ addStatement(statements, dynamoActionsForRole(roleName), [
469
+ ...dynamoArns(roleTableNames(state, roleName)),
470
+ ...externalDynamoArns(roleExternalDynamoTables(state, roleName))
471
+ ]);
396
472
  addStatement(
397
473
  statements,
398
474
  SQS_CONSUMER_ACTIONS,
@@ -452,13 +528,13 @@ function roleTableNames(state, roleName) {
452
528
  'LogicalResultsData'
453
529
  ];
454
530
  const flow = state.flows.find(
455
- candidate => customFlowRoleName(candidate?.flowTag ?? '') === roleName
531
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
456
532
  );
457
533
  if (!flow) return [];
458
534
  const tables = [];
459
535
  if (includesEvent(flow, 'ownTopic') || includesEvent(flow, 's3'))
460
536
  tables.push('WebSocketTask');
461
- if (includesEvent(flow, 's3')) tables.push('UserUploadRecords');
537
+ if (includesEvent(flow, 's3')) tables.push('UserUploadRecords', 'ReservedDataMain');
462
538
  if (flow.statusType === 'storedCache') {
463
539
  const object = state.objectTablesByType.get(flow.objType?.objectType);
464
540
  if (object) tables.push(object);
@@ -477,68 +553,91 @@ function dynamoActionsForRole(roleName) {
477
553
  }
478
554
 
479
555
  function roleQueueNames(state, roleName) {
480
- if (roleName === 'ProcFindDataRole') return LEGACY_PROCESS_QUEUES;
481
- if (roleName === 'WebSocketMainRole')
482
- return state.websocket ? ['WebSocketCompleteHdrSqs'] : [];
483
- if (roleName === 'FlowObjectsRole')
556
+ if (roleName === 'ProcFindDataRole') {
557
+ return LEGACY_PROCESS_QUEUES;
558
+ }
559
+ if (roleName === 'WebSocketMainRole') {
560
+ if (state.websocket) {
561
+ return ['WebSocketCompleteHdrSqs'];
562
+ }
563
+ return [];
564
+ }
565
+ if (roleName === 'FlowObjectsRole') {
484
566
  return [
485
- ...CRUD_ACTIONS.map(action => `${action}HdrSqs`),
486
- ...CRUD_ACTIONS.filter(action => action !== 'Get').map(
487
- action => `${action}CompleteHdrSqs`
567
+ ...CRUD_ACTIONS.map((action) => `${action}HdrSqs`),
568
+ ...CRUD_ACTIONS.filter((action) => action !== 'Get').map(
569
+ (action) => `${action}CompleteHdrSqs`
488
570
  ),
489
571
  ...state.beforeLogical
490
572
  .filter(({ action }) => CRUD_ACTIONS.includes(action))
491
573
  .map(({ action }) => `${action}BeforeLogicalHdrSqs`)
492
574
  ];
493
- if (roleName === 'FlowRelationshipRole')
575
+ }
576
+ if (roleName === 'FlowRelationshipRole') {
494
577
  return [
495
- ...RELATIONSHIP_ACTIONS.flatMap(action => [
578
+ ...RELATIONSHIP_ACTIONS.flatMap((action) => [
496
579
  `${action}HdrSqs`,
497
580
  `${action}CompleteHdrSqs`
498
581
  ]),
499
582
  'GetRelationshipHdrDsq'
500
583
  ];
501
- if (roleName === 'FlowRbacRole')
502
- return RBAC_ACTIONS.flatMap(action => [
584
+ }
585
+ if (roleName === 'FlowRbacRole') {
586
+ return RBAC_ACTIONS.flatMap((action) => [
503
587
  `${action}HdrSqs`,
504
588
  `Process${action}HdrSqs`
505
589
  ]);
590
+ }
506
591
  const flow = state.flows.find(
507
- candidate => customFlowRoleName(candidate?.flowTag ?? '') === roleName
592
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
508
593
  );
509
- if (!flow) return [];
594
+ if (!flow) {
595
+ return [];
596
+ }
510
597
  const tag = upperFirst(flow.flowTag);
511
- return [
512
- ...(includesEvent(flow, 'extTopic') ? [`${tag}HdrSqs`] : []),
513
- ...(includesEvent(flow, 'ownTopic') ? [`${tag}HdrSqs`] : []),
514
- ...(includesEvent(flow, 'dsq') ? [`${tag}HdrDsq`] : []),
598
+ const queueList = [];
599
+ if (includesEvent(flow, 'extTopic')) {
600
+ queueList.push(`${tag}HdrSqs`);
601
+ }
602
+ if (includesEvent(flow, 'ownTopic')) {
603
+ queueList.push(`${tag}HdrSqs`);
604
+ }
605
+ if (includesEvent(flow, 'dsq')) {
606
+ queueList.push(`${tag}HdrDsq`);
607
+ }
608
+ queueList.push(
515
609
  ...flowExtTopicSteps([flow]).map(
516
610
  ({ flowTag, stepName }) => `${flowTag}${stepName}HdrSqs`
517
- ),
611
+ )
612
+ );
613
+ queueList.push(
518
614
  ...flowDsqSteps([flow]).map(
519
615
  ({ flowTag, stepName }) => `${flowTag}${stepName}HdrDsq`
520
- ),
616
+ )
617
+ );
618
+ queueList.push(
521
619
  ...state.sqsQueues.filter(
522
- queueName => includesEvent(flow, 's3') && queueName.startsWith(tag)
620
+ (queueName) => includesEvent(flow, 's3') && queueName.startsWith(tag)
523
621
  )
524
- ];
622
+ );
623
+ return queueList;
525
624
  }
526
625
 
527
626
  function roleTopicNames(state, roleName) {
528
627
  if (roleName === 'ProcFindDataRole') return [];
529
628
  if (roleName === 'FlowObjectsRole')
530
- return state.outTopics.filter(topic => CRUD_ACTIONS.includes(topic));
629
+ return state.outTopics.filter((topic) => CRUD_ACTIONS.includes(topic));
531
630
  if (roleName === 'FlowRelationshipRole')
532
- return state.outTopics.filter(topic =>
631
+ return state.outTopics.filter((topic) =>
533
632
  RELATIONSHIP_ACTIONS.includes(topic)
534
633
  );
535
634
  if (roleName === 'FlowRbacRole')
536
- return state.outTopics.filter(topic => RBAC_ACTIONS.includes(topic));
635
+ return state.outTopics.filter((topic) => RBAC_ACTIONS.includes(topic));
537
636
  const flow = state.flows.find(
538
- candidate => customFlowRoleName(candidate?.flowTag ?? '') === roleName
637
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
539
638
  );
540
639
  return flow
541
- ? state.outTopics.filter(topic => topic === upperFirst(flow.flowTag))
640
+ ? state.outTopics.filter((topic) => topic === upperFirst(flow.flowTag))
542
641
  : [];
543
642
  }
544
643
 
@@ -546,7 +645,7 @@ function dynamoArns(tableNames) {
546
645
  return [...new Set(tableNames)]
547
646
  .sort()
548
647
  .map(
549
- tableName =>
648
+ (tableName) =>
550
649
  `arn:aws:dynamodb:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:table/${'${self:custom.iz_resourcePrefix}'}${tableName}`
551
650
  );
552
651
  }
@@ -601,7 +700,7 @@ function queueArns(queueNames) {
601
700
  return [...new Set(queueNames)]
602
701
  .sort()
603
702
  .map(
604
- queueName =>
703
+ (queueName) =>
605
704
  `arn:aws:sqs:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_resourcePrefix}'}${queueName}`
606
705
  );
607
706
  }
@@ -610,13 +709,13 @@ function topicArns(topicNames) {
610
709
  return [...new Set(topicNames)]
611
710
  .sort()
612
711
  .map(
613
- topic =>
712
+ (topic) =>
614
713
  `arn:aws:sns:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_serviceTag}'}_${'${self:custom.iz_stage}'}_${topic}_Out`
615
714
  );
616
715
  }
617
716
 
618
717
  function renderWebSocketSubscription(topicName) {
619
- return `##===== WebSocket completion subscription\n SubscriptionToOut${topicName}WebSocketComplete:\n Type: AWS::SNS::Subscription\n Properties:\n TopicArn: !Ref Out${topicName}\n Endpoint: "arn:aws:sqs:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_resourcePrefix}'}WebSocketCompleteHdrSqs"\n Protocol: "sqs"`;
718
+ return render('WebSocketSubscription_Yaml.ejs', { topicName });
620
719
  }
621
720
 
622
721
  function collectTables(schemas) {
@@ -629,13 +728,13 @@ function collectTables(schemas) {
629
728
  const pk =
630
729
  keyName(
631
730
  identifiers.find(
632
- identifier =>
731
+ (identifier) =>
633
732
  identifier.type === 'partitionKey' ||
634
733
  identifier.type === 'identifier'
635
734
  )
636
735
  ) ?? 'PK';
637
736
  const sk = keyName(
638
- identifiers.find(identifier => identifier.type === 'sortKey')
737
+ identifiers.find((identifier) => identifier.type === 'sortKey')
639
738
  );
640
739
  for (const resource of Object.values(schema.storageResources)) {
641
740
  if (
@@ -650,13 +749,13 @@ function collectTables(schemas) {
650
749
  }
651
750
 
652
751
  function keyName(identifier) {
653
- if (!identifier) return undefined;
752
+ if (!identifier) return null;
654
753
  return (
655
754
  identifier.name ??
656
755
  identifier.fieldName ??
657
756
  (Array.isArray(identifier.fieldNames)
658
757
  ? identifier.fieldNames.join(identifier.deliminator ?? '_')
659
- : undefined)
758
+ : null)
660
759
  );
661
760
  }
662
761
 
@@ -669,7 +768,7 @@ function isCrudObject(object) {
669
768
  function hasRbacAddOn(object) {
670
769
  return (
671
770
  Array.isArray(object?.addOnDataStructure) &&
672
- object.addOnDataStructure.some(addOn => addOn?.type === 'rbac')
771
+ object.addOnDataStructure.some((addOn) => addOn?.type === 'rbac')
673
772
  );
674
773
  }
675
774
  function includesEvent(flow, event) {
@@ -683,8 +782,35 @@ function upperFirst(value) {
683
782
  function normalizeYaml(content) {
684
783
  return `${content.trimEnd()}\n`;
685
784
  }
785
+ function renderCorsYaml() {
786
+ return `allowedOrigins:
787
+ - '*'
788
+ allowedHeaders:
789
+ - content-type
790
+ - x-amz-date
791
+ - authorization
792
+ - x-api-key
793
+ - x-amz-security-token
794
+ - x-amz-user-agent
795
+ - x-amzn-trace-id
796
+ allowedMethods:
797
+ - POST
798
+ - OPTIONS
799
+ maxAge: 0
800
+ allowCredentials: false
801
+ `;
802
+ }
803
+ function renderRoleNameConfigYaml(roles) {
804
+ return [
805
+ '# for createIamRole',
806
+ ...roles.map(
807
+ (roleName) =>
808
+ `- arn:aws:iam::\${self:custom.iz_accountId}:role/\${self:custom.iz_resourcePrefix}${roleName}`
809
+ )
810
+ ].join('\n');
811
+ }
686
812
  async function render(templateName, data) {
687
- return ejs.render(
813
+ return ejsLib.render(
688
814
  await readFile(new URL(templateName, TEMPLATE_URL), 'utf8'),
689
815
  { resourceQueueName: data.queueName, ...data }
690
816
  );