@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
@@ -7,7 +7,8 @@ import {
7
7
  flowExtTopicSteps,
8
8
  generatedDsqFlows,
9
9
  generatedOwnTopicFlows,
10
- supportedCustomFlows
10
+ supportedCustomFlows,
11
+ flowHasRbac
11
12
  } from '../custom/customFlows.js';
12
13
  import { hasSystemWebSocket } from '../system/emitSystemWebSocketArtifacts.js';
13
14
  import { rbacFlowTag } from '../rbac/rbacFlowTag.js';
@@ -38,7 +39,13 @@ const RBAC_ACTIONS = [
38
39
  'CreateUserRole',
39
40
  'ListUserInRoles',
40
41
  'DeleteUserFromRole',
41
- 'ValidatorRbac'
42
+ 'ValidatorRbac',
43
+ 'CreateRoleLimit',
44
+ 'ListRoleLimits',
45
+ 'DeleteRoleLimit',
46
+ 'ReservedDynamicUsage',
47
+ 'ConfirmUsage',
48
+ 'CancelUsage'
42
49
  ];
43
50
  const SYSTEM_TABLES = [
44
51
  'WebSocketTask',
@@ -57,6 +64,9 @@ const RBAC_TABLES = [
57
64
  'RoleUsers',
58
65
  'UserRoles',
59
66
  'RbacPermissionCaches',
67
+ 'RoleLimit',
68
+ 'RunningTotalUsage',
69
+ 'RunningTotalReservedUsage',
60
70
  'WebSocketTask'
61
71
  ];
62
72
  const LEGACY_PROCESS_QUEUES = [
@@ -93,8 +103,23 @@ export async function emitResourceArtifacts({
93
103
  throw new TypeError('objects, relationships, and flows must be arrays');
94
104
  }
95
105
  const state = createResourceState({ objects, relationships, flows });
96
- const [inSqs, out, dynamo, iam, lambdaRoleConfig, s3] = await Promise.all([
97
- renderInSqs(state),
106
+ const [
107
+ crudInSqs,
108
+ relationshipInSqs,
109
+ rbacInSqs,
110
+ customFlowInSqs,
111
+ systemInSqs,
112
+ out,
113
+ dynamo,
114
+ iam,
115
+ lambdaRoleConfig,
116
+ s3
117
+ ] = await Promise.all([
118
+ renderCrudInSqs(state),
119
+ renderRelationshipInSqs(state),
120
+ renderRbacInSqs(state),
121
+ renderCustomFlowInSqs(state),
122
+ renderSystemInSqs(state),
98
123
  renderOut(state),
99
124
  renderDynamo(state),
100
125
  renderIam(state),
@@ -102,10 +127,6 @@ export async function emitResourceArtifacts({
102
127
  renderS3(state)
103
128
  ]);
104
129
  const artifacts = [
105
- {
106
- path: `${RESOURCE_ROOT}/generated-sns-in-sqs.yml`,
107
- content: normalizeYaml(inSqs)
108
- },
109
130
  {
110
131
  path: `${RESOURCE_ROOT}/generated-sns-out.yml`,
111
132
  content: normalizeYaml(out)
@@ -123,6 +144,36 @@ export async function emitResourceArtifacts({
123
144
  content: normalizeYaml(iam.roleNameConfigContent)
124
145
  }
125
146
  ];
147
+ if (crudInSqs) {
148
+ artifacts.push({
149
+ path: `${RESOURCE_ROOT}/generated-sns-sqs-crud.yml`,
150
+ content: normalizeYaml(crudInSqs)
151
+ });
152
+ }
153
+ if (relationshipInSqs) {
154
+ artifacts.push({
155
+ path: `${RESOURCE_ROOT}/generated-sns-sqs-relationship.yml`,
156
+ content: normalizeYaml(relationshipInSqs)
157
+ });
158
+ }
159
+ if (rbacInSqs) {
160
+ artifacts.push({
161
+ path: `${RESOURCE_ROOT}/generated-sns-sqs-rbac.yml`,
162
+ content: normalizeYaml(rbacInSqs)
163
+ });
164
+ }
165
+ if (customFlowInSqs) {
166
+ artifacts.push({
167
+ path: `${RESOURCE_ROOT}/generated-sns-sqs-custom-flows.yml`,
168
+ content: normalizeYaml(customFlowInSqs)
169
+ });
170
+ }
171
+ if (systemInSqs) {
172
+ artifacts.push({
173
+ path: `${RESOURCE_ROOT}/generated-sns-sqs-system.yml`,
174
+ content: normalizeYaml(systemInSqs)
175
+ });
176
+ }
126
177
  if (state.s3Buckets.length > 0) {
127
178
  artifacts.push({
128
179
  path: `${RESOURCE_ROOT}/generated-s3.yml`,
@@ -140,6 +191,11 @@ export async function emitResourceArtifacts({
140
191
 
141
192
  export const resourceArtifactPaths = [
142
193
  `${RESOURCE_ROOT}/generated-sns-in-sqs.yml`,
194
+ `${RESOURCE_ROOT}/generated-sns-sqs-crud.yml`,
195
+ `${RESOURCE_ROOT}/generated-sns-sqs-relationship.yml`,
196
+ `${RESOURCE_ROOT}/generated-sns-sqs-rbac.yml`,
197
+ `${RESOURCE_ROOT}/generated-sns-sqs-custom-flows.yml`,
198
+ `${RESOURCE_ROOT}/generated-sns-sqs-system.yml`,
143
199
  `${RESOURCE_ROOT}/generated-sns-out.yml`,
144
200
  `${RESOURCE_ROOT}/generated-dynamoDB-table.yml`,
145
201
  `${RESOURCE_ROOT}/generated-s3.yml`,
@@ -153,65 +209,37 @@ function createResourceState({ objects, relationships, flows }) {
153
209
  const selfRbac = objects.some(hasSelfRbacAddOn);
154
210
  const rbac = objects.some(hasSelfRbacAddOn);
155
211
  const crudActionPlans = createCrudActionPlans(objects);
156
- const ownTopics = new Set([
157
- 'ProcessLogical',
158
- 'FindData',
159
- ...flows
160
- .filter((flow) => includesEvent(flow, 'ownTopic'))
161
- .map((flow) => upperFirst(flow.flowTag))
162
- ]);
163
- const sqsQueues = new Set([
164
- 'PaginateProcessLogicalHdrDsq',
165
- 'PaginateProcessLogicalHdrSqs',
166
- ...flows
167
- .filter((flow) => includesEvent(flow, 'extTopic'))
168
- .map((flow) => `Process${upperFirst(flow.flowTag)}HdrSqs`),
169
- ...flows
170
- .filter((flow) => flow?.outputTopic && !flow?.generatedCodeConfig && upperFirst(flow.flowTag))
171
- .map((flow) => `${upperFirst(flow.flowTag)}CompleteHdrSqs`)
172
- ]);
173
- for (const { flowTag, stepName } of flowExtTopicSteps(flows)) {
174
- sqsQueues.add(`${flowTag}${stepName}HdrSqs`);
175
- }
176
- for (const flow of flows.filter((flow) => includesEvent(flow, 's3'))) {
177
- const tag = upperFirst(flow.flowTag);
178
- sqsQueues.add(`${tag}CreatePreSignUrlHdrSqs`);
179
- sqsQueues.add(`${tag}ReservedLimitHdrSqs`);
180
- sqsQueues.add(`${tag}ConfirmAfterUploadHdrSqs`);
181
- }
182
- const dsqQueues = new Set(
183
- flows
184
- .filter((flow) => includesEvent(flow, 'dsq'))
185
- .map((flow) => `${upperFirst(flow.flowTag)}HdrDsq`)
186
- );
187
- for (const { flowTag, stepName } of flowDsqSteps(flows)) {
188
- dsqQueues.add(`${flowTag}${stepName}HdrDsq`);
189
- }
212
+
213
+ const crudOwnTopics = crud ? [...CRUD_ACTIONS] : [];
214
+ const crudSqsQueues = [];
190
215
  if (crud) {
191
- for (const action of CRUD_ACTIONS) {
192
- ownTopics.add(action);
193
- }
194
216
  for (const action of ['Create', 'Update', 'Delete']) {
195
217
  const plan = crudActionPlans[action];
196
- if (plan.hasComplete) {
197
- sqsQueues.add(`${action}CompleteHdrSqs`);
218
+ if (plan.hasCreateNodeCallback) {
219
+ crudSqsQueues.push(`${action}NodeCallbackHdrSqs`);
198
220
  }
199
- if (plan.hasRbacCallback) {
200
- sqsQueues.add(`${action}RbacCallbackHdrSqs`);
221
+ if (plan.hasComplete) {
222
+ crudSqsQueues.push(`${action}CompleteHdrSqs`);
201
223
  }
202
224
  }
203
225
  }
204
- if (relationships.length > 0) {
205
- for (const action of RELATIONSHIP_ACTIONS) {
206
- ownTopics.add(action);
207
- sqsQueues.add(`${action}CompleteHdrSqs`);
208
- }
209
- dsqQueues.add('GetRelationshipHdrDsq');
210
- }
226
+
227
+ const relationshipOwnTopics = relationships.length > 0
228
+ ? [...RELATIONSHIP_ACTIONS]
229
+ : [];
230
+ const relationshipSqsQueues = relationships.length > 0
231
+ ? RELATIONSHIP_ACTIONS.map((action) => `${action}CompleteHdrSqs`)
232
+ : [];
233
+ const relationshipDsqQueues = relationships.length > 0
234
+ ? ['GetRelationshipHdrDsq']
235
+ : [];
236
+
237
+ const rbacOwnTopics = [];
238
+ const rbacSqsQueues = [];
211
239
  if (selfRbac) {
212
240
  for (const action of RBAC_ACTIONS) {
213
- ownTopics.add(action);
214
- sqsQueues.add(`Process${action}HdrSqs`);
241
+ rbacOwnTopics.push(action);
242
+ rbacSqsQueues.push(`Process${action}HdrSqs`);
215
243
  }
216
244
  }
217
245
  if (rbac) {
@@ -219,9 +247,93 @@ function createResourceState({ objects, relationships, flows }) {
219
247
  ...new Set(objects.filter(hasRbacAddOn).map(rbacFlowTag))
220
248
  ];
221
249
  for (const flowTag of flowTags) {
222
- ownTopics.add(flowTag);
250
+ rbacOwnTopics.push(flowTag);
251
+ }
252
+ }
253
+ if (crud) {
254
+ for (const action of ['Create', 'Update', 'Delete']) {
255
+ const plan = crudActionPlans[action];
256
+ if (plan.hasRbacCallback) {
257
+ rbacSqsQueues.push(`${action}RbacCallbackHdrSqs`);
258
+ }
259
+ }
260
+ }
261
+
262
+ const customOwnTopics = flows
263
+ .filter((flow) => includesEvent(flow, 'ownTopic'))
264
+ .map((flow) => upperFirst(flow.flowTag));
265
+
266
+ const customSqsQueues = [
267
+ ...flows
268
+ .filter((flow) => includesEvent(flow, 'extTopic'))
269
+ .map((flow) => `Process${upperFirst(flow.flowTag)}HdrSqs`),
270
+ ...flows
271
+ .filter(
272
+ (flow) =>
273
+ flow?.outputTopic &&
274
+ !flow?.generatedCodeConfig &&
275
+ upperFirst(flow.flowTag)
276
+ )
277
+ .map((flow) => `${upperFirst(flow.flowTag)}CompleteHdrSqs`)
278
+ ];
279
+ for (const { flowTag, stepName } of flowExtTopicSteps(flows)) {
280
+ customSqsQueues.push(`${flowTag}${stepName}HdrSqs`);
281
+ }
282
+ for (const flow of flows) {
283
+ if (flowHasRbac(flow, objects)) {
284
+ const tag = upperFirst(flow.flowTag);
285
+ customSqsQueues.push(`${tag}RbacCallbackHdrSqs`);
223
286
  }
224
287
  }
288
+ for (const flow of flows.filter((flow) => includesEvent(flow, 's3'))) {
289
+ const tag = upperFirst(flow.flowTag);
290
+ customSqsQueues.push(`${tag}CreatePreSignUrlHdrSqs`);
291
+ customSqsQueues.push(`${tag}ReservedLimitHdrSqs`);
292
+ customSqsQueues.push(`${tag}ConfirmAfterUploadHdrSqs`);
293
+ }
294
+
295
+ const customDsqQueues = flows
296
+ .filter((flow) => includesEvent(flow, 'dsq'))
297
+ .map((flow) => `${upperFirst(flow.flowTag)}HdrDsq`);
298
+ for (const { flowTag, stepName } of flowDsqSteps(flows)) {
299
+ customDsqQueues.push(`${flowTag}${stepName}HdrDsq`);
300
+ }
301
+
302
+ const websocket = hasSystemWebSocket(flows, {
303
+ includeRelationshipOwnTopic: true,
304
+ objects,
305
+ relationships
306
+ });
307
+
308
+ const systemOwnTopics = ['ProcessLogical', 'FindData'];
309
+ const systemSqsQueues = [
310
+ 'PaginateProcessLogicalHdrSqs',
311
+ ...(websocket
312
+ ? ['WebSocketCompleteHdrSqs', 'RegisterCompleteHdrSqs']
313
+ : [])
314
+ ];
315
+ const systemDsqQueues = ['PaginateProcessLogicalHdrDsq'];
316
+
317
+ const ownTopics = new Set([
318
+ ...systemOwnTopics,
319
+ ...crudOwnTopics,
320
+ ...relationshipOwnTopics,
321
+ ...rbacOwnTopics,
322
+ ...customOwnTopics
323
+ ]);
324
+ const sqsQueues = new Set([
325
+ ...systemSqsQueues,
326
+ ...crudSqsQueues,
327
+ ...relationshipSqsQueues,
328
+ ...rbacSqsQueues,
329
+ ...customSqsQueues
330
+ ]);
331
+ const dsqQueues = new Set([
332
+ ...systemDsqQueues,
333
+ ...relationshipDsqQueues,
334
+ ...customDsqQueues
335
+ ]);
336
+
225
337
  const customRoles = [
226
338
  ...new Set([
227
339
  ...supportedCustomFlows(flows).map((flow) =>
@@ -236,12 +348,11 @@ function createResourceState({ objects, relationships, flows }) {
236
348
  ...flowExtTopicSteps(flows).map(({ flow }) =>
237
349
  customFlowRoleName(flow.flowTag)
238
350
  ),
239
- ...flowDsqSteps(flows).map(({ flow }) => customFlowRoleName(flow.flowTag))
351
+ ...flowDsqSteps(flows).map(({ flow }) =>
352
+ customFlowRoleName(flow.flowTag)
353
+ )
240
354
  ])
241
355
  ];
242
- const websocket = hasSystemWebSocket(flows, {
243
- includeRelationshipOwnTopic: true
244
- });
245
356
  const webSocketRoles = new Set();
246
357
  if (websocket) {
247
358
  webSocketRoles.add('WebSocketMainRole');
@@ -286,7 +397,8 @@ function createResourceState({ objects, relationships, flows }) {
286
397
  .filter((flow) => includesEvent(flow, 's3'))
287
398
  .map((flow) => {
288
399
  const tag = upperFirst(flow.flowTag);
289
- const outputTopicStr = typeof flow.outputTopic === 'string' ? flow.outputTopic : null;
400
+ const outputTopicStr =
401
+ typeof flow.outputTopic === 'string' ? flow.outputTopic : null;
290
402
  const topicName = outputTopicStr
291
403
  ? (outputTopicStr.startsWith('Out')
292
404
  ? outputTopicStr
@@ -301,7 +413,16 @@ function createResourceState({ objects, relationships, flows }) {
301
413
  });
302
414
  const systemTables = [...SYSTEM_TABLES];
303
415
  if (rbac) {
304
- systemTables.push('TargetRoles', 'RolePermissions', 'RoleUsers', 'UserRoles', 'RbacPermissionCaches');
416
+ systemTables.push(
417
+ 'TargetRoles',
418
+ 'RolePermissions',
419
+ 'RoleUsers',
420
+ 'UserRoles',
421
+ 'RbacPermissionCaches',
422
+ 'RoleLimit',
423
+ 'RunningTotalUsage',
424
+ 'RunningTotalReservedUsage'
425
+ );
305
426
  }
306
427
  if (s3FlowTags.length > 0) {
307
428
  systemTables.push('ReservedDataMain');
@@ -315,6 +436,25 @@ function createResourceState({ objects, relationships, flows }) {
315
436
  crud,
316
437
  rbac,
317
438
  crudActionPlans,
439
+ crudOwnTopics: [...new Set(crudOwnTopics)].filter(Boolean).sort(),
440
+ crudSqsQueues: [...new Set(crudSqsQueues)].filter(Boolean).sort(),
441
+ relationshipOwnTopics: [...new Set(relationshipOwnTopics)]
442
+ .filter(Boolean)
443
+ .sort(),
444
+ relationshipSqsQueues: [...new Set(relationshipSqsQueues)]
445
+ .filter(Boolean)
446
+ .sort(),
447
+ relationshipDsqQueues: [...new Set(relationshipDsqQueues)]
448
+ .filter(Boolean)
449
+ .sort(),
450
+ rbacOwnTopics: [...new Set(rbacOwnTopics)].filter(Boolean).sort(),
451
+ rbacSqsQueues: [...new Set(rbacSqsQueues)].filter(Boolean).sort(),
452
+ customOwnTopics: [...new Set(customOwnTopics)].filter(Boolean).sort(),
453
+ customSqsQueues: [...new Set(customSqsQueues)].filter(Boolean).sort(),
454
+ customDsqQueues: [...new Set(customDsqQueues)].filter(Boolean).sort(),
455
+ systemOwnTopics: [...new Set(systemOwnTopics)].filter(Boolean).sort(),
456
+ systemSqsQueues: [...new Set(systemSqsQueues)].filter(Boolean).sort(),
457
+ systemDsqQueues: [...new Set(systemDsqQueues)].filter(Boolean).sort(),
318
458
  s3Subscriptions,
319
459
  s3FlowTags,
320
460
  hasHttpApi,
@@ -337,6 +477,9 @@ function createResourceState({ objects, relationships, flows }) {
337
477
  flow.initiateBy === 'systemWithUser'))) &&
338
478
  upperFirst(flow.flowTag) === topic
339
479
  ) ||
480
+ (objects.length > 0 &&
481
+ topic !== 'Get' &&
482
+ CRUD_ACTIONS.includes(topic)) ||
340
483
  (relationships.length > 0 &&
341
484
  topic !== 'GetRelationship' &&
342
485
  RELATIONSHIP_ACTIONS.includes(topic))
@@ -396,35 +539,39 @@ async function renderS3(state) {
396
539
  return `Resources:\n${indentYaml(chunks.join('\n'), 2)}`;
397
540
  }
398
541
 
399
- async function renderInSqs(state) {
542
+ async function renderResourceGroup({
543
+ ownTopics = [],
544
+ sqsQueues = [],
545
+ dsqQueues = [],
546
+ webSocketSubscriptions = [],
547
+ s3Subscriptions = []
548
+ }) {
549
+ const hasResources =
550
+ ownTopics.length > 0 ||
551
+ sqsQueues.length > 0 ||
552
+ dsqQueues.length > 0 ||
553
+ webSocketSubscriptions.length > 0 ||
554
+ s3Subscriptions.length > 0;
555
+ if (!hasResources) return '';
556
+
400
557
  const chunks = await Promise.all([
401
- ...state.ownTopics.map((queueName) =>
558
+ ...ownTopics.map((queueName) =>
402
559
  render('ResourceYaml.ejs', { queueName })
403
560
  ),
404
- ...state.sqsQueues.map((queueName) =>
561
+ ...sqsQueues.map((queueName) =>
405
562
  render('ResourceSqsYaml.ejs', { queueName })
406
563
  ),
407
- ...state.dsqQueues.map((queueName) =>
564
+ ...dsqQueues.map((queueName) =>
408
565
  render('ResourceSqsYaml.ejs', { queueName })
409
- ),
410
- ...(state.websocket
411
- ? [
412
- render('ResourceSqsYaml.ejs', {
413
- queueName: 'WebSocketCompleteHdrSqs'
414
- }),
415
- render('ResourceSqsYaml.ejs', {
416
- queueName: 'RegisterCompleteHdrSqs'
417
- })
418
- ]
419
- : [])
566
+ )
420
567
  ]);
421
- const webSocketSubscriptions = await Promise.all(
422
- state.webSocketSubscriptions.map((topicName) =>
568
+ const wsSubs = await Promise.all(
569
+ webSocketSubscriptions.map((topicName) =>
423
570
  renderWebSocketSubscription(topicName)
424
571
  )
425
572
  );
426
- const s3Subscriptions = await Promise.all(
427
- (state.s3Subscriptions ?? []).map(
573
+ const s3Subs = await Promise.all(
574
+ s3Subscriptions.map(
428
575
  ({ subscriptionName, topicName, queueName }) =>
429
576
  render('S3Subscription_Yaml.ejs', {
430
577
  subscriptionName,
@@ -434,16 +581,53 @@ async function renderInSqs(state) {
434
581
  )
435
582
  );
436
583
  const parts = [chunks.join('\n')];
437
- if (webSocketSubscriptions.length > 0) {
438
- parts.push(webSocketSubscriptions.join('\n'));
439
- }
440
- if (s3Subscriptions.length > 0) {
441
- parts.push(s3Subscriptions.join('\n'));
442
- }
443
- const body = parts.join('\n');
584
+ if (wsSubs.length > 0) parts.push(wsSubs.join('\n'));
585
+ if (s3Subs.length > 0) parts.push(s3Subs.join('\n'));
586
+ const body = parts.filter(Boolean).join('\n');
587
+ if (!body.trim()) return '';
444
588
  return `Resources:\n${indentYaml(body, 2)}`;
445
589
  }
446
590
 
591
+ async function renderCrudInSqs(state) {
592
+ return renderResourceGroup({
593
+ ownTopics: state.crudOwnTopics,
594
+ sqsQueues: state.crudSqsQueues
595
+ });
596
+ }
597
+
598
+ async function renderRelationshipInSqs(state) {
599
+ return renderResourceGroup({
600
+ ownTopics: state.relationshipOwnTopics,
601
+ sqsQueues: state.relationshipSqsQueues,
602
+ dsqQueues: state.relationshipDsqQueues
603
+ });
604
+ }
605
+
606
+ async function renderRbacInSqs(state) {
607
+ return renderResourceGroup({
608
+ ownTopics: state.rbacOwnTopics,
609
+ sqsQueues: state.rbacSqsQueues
610
+ });
611
+ }
612
+
613
+ async function renderCustomFlowInSqs(state) {
614
+ return renderResourceGroup({
615
+ ownTopics: state.customOwnTopics,
616
+ sqsQueues: state.customSqsQueues,
617
+ dsqQueues: state.customDsqQueues,
618
+ s3Subscriptions: state.s3Subscriptions
619
+ });
620
+ }
621
+
622
+ async function renderSystemInSqs(state) {
623
+ return renderResourceGroup({
624
+ ownTopics: state.systemOwnTopics,
625
+ sqsQueues: state.systemSqsQueues,
626
+ dsqQueues: state.systemDsqQueues,
627
+ webSocketSubscriptions: state.webSocketSubscriptions
628
+ });
629
+ }
630
+
447
631
  async function renderOut(state) {
448
632
  const body = (
449
633
  await Promise.all(
@@ -517,7 +701,13 @@ function roleStatements(state, roleName) {
517
701
  statements.push({
518
702
  action: ['s3:GetObject'],
519
703
  resource: [
520
- 'arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}/perServiceSchemas/*'
704
+ 'arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}/*'
705
+ ]
706
+ });
707
+ statements.push({
708
+ action: ['s3:ListBucket'],
709
+ resource: [
710
+ 'arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}'
521
711
  ]
522
712
  });
523
713
  }
@@ -572,7 +762,17 @@ function roleTableNames(state, roleName) {
572
762
  ...state.objectTableNames,
573
763
  'AwaitingMultipleSteps',
574
764
  'AwaitingMultipleStepByPending',
575
- 'WebSocketTask'
765
+ 'WebSocketTask',
766
+ ...(state.rbac
767
+ ? [
768
+ 'TargetRoles',
769
+ 'RoleUsers',
770
+ 'UserRoles',
771
+ 'RoleLimit',
772
+ 'RunningTotalUsage',
773
+ 'RunningTotalReservedUsage'
774
+ ]
775
+ : [])
576
776
  ];
577
777
  if (roleName === 'FlowRelationshipRole')
578
778
  return [
@@ -611,7 +811,7 @@ function dynamoActionsForRole(roleName) {
611
811
  return ['dynamodb:GetItem', 'dynamodb:Query', 'dynamodb:UpdateItem'];
612
812
  if (roleName === 'WebSocketMainRole')
613
813
  return ['dynamodb:DeleteItem', 'dynamodb:PutItem', 'dynamodb:Query'];
614
- if (roleName === 'FlowRbacRole')
814
+ if (roleName === 'FlowRbacRole' || roleName === 'FlowObjectsRole')
615
815
  return [...DYNAMO_ACTIONS, 'dynamodb:TransactWriteItems'];
616
816
  return DYNAMO_ACTIONS;
617
817
  }
@@ -638,6 +838,9 @@ function roleQueueNames(state, roleName) {
638
838
  if (!plan.outputTopic) return [];
639
839
  return [
640
840
  `${action}HdrSqs`,
841
+ ...(plan.hasCreateNodeCallback
842
+ ? [`${action}NodeCallbackHdrSqs`]
843
+ : []),
641
844
  ...(plan.hasRbacCallback
642
845
  ? [`${action}RbacCallbackHdrSqs`]
643
846
  : []),
@@ -677,6 +880,9 @@ function roleQueueNames(state, roleName) {
677
880
  if (includesEvent(flow, 'dsq')) {
678
881
  queueList.push(`${tag}HdrDsq`);
679
882
  }
883
+ if (flowHasRbac(flow, state.objects)) {
884
+ queueList.push(`${tag}RbacCallbackHdrSqs`);
885
+ }
680
886
  queueList.push(
681
887
  ...flowExtTopicSteps([flow]).map(
682
888
  ({ flowTag, stepName }) => `${flowTag}${stepName}HdrSqs`
@@ -708,21 +914,58 @@ function roleDlqQueueNames(state, roleName) {
708
914
 
709
915
  function roleTopicNames(state, roleName) {
710
916
  if (roleName === 'ProcFindDataRole')
711
- return state.outTopics.filter((topic) => topic === 'FindData');
712
- if (roleName === 'FlowObjectsRole')
713
- return state.outTopics.filter((topic) => CRUD_ACTIONS.includes(topic));
714
- if (roleName === 'FlowRelationshipRole')
715
- return state.outTopics.filter((topic) =>
716
- RELATIONSHIP_ACTIONS.includes(topic)
717
- );
718
- if (roleName === 'FlowRbacRole')
719
- return state.outTopics.filter((topic) => RBAC_ACTIONS.includes(topic));
917
+ return state.outTopics.filter((topic) => topic === 'FindData').map((t) => `${t}_Out`);
918
+ if (roleName === 'FlowObjectsRole') {
919
+ const actions = state.outTopics.filter((topic) => CRUD_ACTIONS.includes(topic));
920
+ const topics = [];
921
+ for (const action of actions) {
922
+ if (action === 'Get') {
923
+ topics.push(`${action}_Out`);
924
+ } else {
925
+ topics.push(`${action}_In`, `${action}_Out`);
926
+ }
927
+ }
928
+ return topics;
929
+ }
930
+ if (roleName === 'FlowRelationshipRole') {
931
+ const actions = state.outTopics.filter((topic) => RELATIONSHIP_ACTIONS.includes(topic));
932
+ const topics = [];
933
+ for (const action of actions) {
934
+ if (action === 'GetRelationship') {
935
+ topics.push(`${action}_Out`);
936
+ } else {
937
+ topics.push(`${action}_In`, `${action}_Out`);
938
+ }
939
+ }
940
+ return topics;
941
+ }
942
+ if (roleName === 'FlowRbacRole') {
943
+ const actions = state.outTopics.filter((topic) => RBAC_ACTIONS.includes(topic));
944
+ const topics = [];
945
+ for (const action of actions) {
946
+ if (action.startsWith('List')) {
947
+ topics.push(`${action}_Out`);
948
+ } else {
949
+ topics.push(`${action}_In`, `${action}_Out`);
950
+ }
951
+ }
952
+ return topics;
953
+ }
720
954
  const flow = state.flows.find(
721
955
  (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
722
956
  );
723
- return flow
724
- ? state.outTopics.filter((topic) => topic === upperFirst(flow.flowTag))
725
- : [];
957
+ if (flow && flow.flowTag) {
958
+ const name = upperFirst(flow.flowTag);
959
+ const topics = [];
960
+ if (state.outTopics.includes(name)) {
961
+ topics.push(`${name}_Out`);
962
+ }
963
+ if (includesEvent(flow, 'ownTopic')) {
964
+ topics.push(`${name}_In`);
965
+ }
966
+ return topics;
967
+ }
968
+ return [];
726
969
  }
727
970
 
728
971
  function dynamoArns(tableNames) {
@@ -794,7 +1037,7 @@ function topicArns(topicNames) {
794
1037
  .sort()
795
1038
  .map(
796
1039
  (topic) =>
797
- `arn:aws:sns:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_serviceTag}'}_${'${self:custom.iz_stage}'}_${topic}_Out`
1040
+ `arn:aws:sns:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_serviceTag}'}_${'${self:custom.iz_stage}'}_${topic}`
798
1041
  );
799
1042
  }
800
1043
 
@@ -903,7 +1146,7 @@ function keyName(identifier) {
903
1146
  const VALID_CRUD_GENERATED_BY = new Set([
904
1147
  'user',
905
1148
  'systemWithUser',
906
- 'systemWithNoUser'
1149
+ 'systemNoUser'
907
1150
  ]);
908
1151
 
909
1152
  function isCrudObject(object) {
@@ -56,7 +56,9 @@ export function generatedLambdaRole() {
56
56
  Effect: 'Allow',
57
57
  Action: ['sns:Publish'],
58
58
  Resource: [
59
- `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
59
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`,
60
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', 'Rbac')}`,
61
+ `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
60
62
  `arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
61
63
  ]
62
64
  }<% } %>