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

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 (59) 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 +29 -1
  6. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +16 -3
  7. package/src/emit/crud/crudActionPlan.js +38 -5
  8. package/src/emit/crud/emitCrudApplicationArtifacts.js +19 -4
  9. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +27 -6
  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/CreateEndpoint_Main.ejs +50 -19
  15. package/src/emit/crud/templates/CreateLogicalLib.ejs +73 -8
  16. package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
  17. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +33 -8
  18. package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
  19. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +2 -2
  20. package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -0
  21. package/src/emit/crud/templates/FlowMain_Wbs.ejs +1 -1
  22. package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
  23. package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
  24. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +52 -3
  25. package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
  26. package/src/emit/custom/customFlows.js +47 -0
  27. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
  28. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
  29. package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
  30. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
  31. package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
  32. package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
  33. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
  34. package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
  35. package/src/emit/rbac/templates/CancelUsage_Main.ejs +103 -0
  36. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +71 -0
  37. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +49 -6
  38. package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
  39. package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
  40. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +147 -0
  41. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +59 -23
  42. package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +1 -1
  43. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
  44. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +4 -4
  45. package/src/emit/resource/emitResourceArtifacts.js +342 -108
  46. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +53 -2
  47. package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -5
  48. package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
  49. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +7 -0
  50. package/src/emit/systemText/emitSystemTextSchemas.js +1 -1
  51. package/src/generate.js +41 -10
  52. package/test/attributeTreeSchemas.test.js +219 -0
  53. package/test/createTargetRoleHandler.test.js +59 -4
  54. package/test/crudApplicationArtifacts.test.js +20 -3
  55. package/test/customFlowApplicationArtifacts.test.js +5 -5
  56. package/test/dynamicCrudFlowSchemas.test.js +91 -4
  57. package/test/dynamicRbacFlowSchemas.test.js +15 -2
  58. package/test/publicApi.test.js +6 -6
  59. package/test/resourceArtifacts.test.js +68 -27
@@ -340,7 +340,7 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
340
340
  await readFile(
341
341
  join(
342
342
  rootPath,
343
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
343
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
344
344
  ),
345
345
  'utf8'
346
346
  ),
@@ -350,7 +350,7 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
350
350
  await readFile(
351
351
  join(
352
352
  rootPath,
353
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
353
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
354
354
  ),
355
355
  'utf8'
356
356
  ),
@@ -398,7 +398,7 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
398
398
  await readFile(
399
399
  join(
400
400
  rootPath,
401
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
401
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
402
402
  ),
403
403
  'utf8'
404
404
  ),
@@ -437,7 +437,7 @@ test('emits and removes the trigger-cache artifact suite when triggerFlowTypes i
437
437
  const resources = await readFile(
438
438
  join(
439
439
  rootPath,
440
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
440
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
441
441
  ),
442
442
  'utf8'
443
443
  );
@@ -864,7 +864,7 @@ test('registers SQS queue, SNS subscription, and SNS out topic for custom flowSc
864
864
  const snsInSqs = await readFile(
865
865
  join(
866
866
  rootPath,
867
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
867
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
868
868
  ),
869
869
  'utf8'
870
870
  );
@@ -6,6 +6,7 @@ import test from 'node:test';
6
6
  import { pathToFileURL } from 'node:url';
7
7
 
8
8
  import { generateDynamicCrudFlowSchemas } from '../src/emit/crud/generateDynamicCrudFlowSchemas.js';
9
+ import { createCrudActionPlans } from '../src/emit/crud/crudActionPlan.js';
9
10
 
10
11
  test('generates dynamic CRUD schemas from local schema modules', async () => {
11
12
  const rootPath = await createProject({
@@ -141,7 +142,7 @@ test('generates a direct Complete step for RBAC-only Update flows', async () =>
141
142
  assert.equal(update.flowSteps[1].properties.length, 0);
142
143
  });
143
144
 
144
- test('ignores RBAC for Create even when Graph storage is present', async () => {
145
+ test('generates RbacCallback and Complete for Create when RBAC and Graph are present', async () => {
145
146
  const rootPath = await createProject({
146
147
  generatedBy: 'user',
147
148
  });
@@ -159,6 +160,7 @@ test('ignores RBAC for Create even when Graph storage is present', async () => {
159
160
  const create = await readGeneratedFlow(rootPath, 'Create');
160
161
  assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
161
162
  'Start',
163
+ 'RbacCallback',
162
164
  'Complete'
163
165
  ]);
164
166
  });
@@ -183,9 +185,10 @@ test('uses the renamed RBAC callback step when Graph storage is present', async
183
185
  const create = await readGeneratedFlow(rootPath, 'Create');
184
186
  assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
185
187
  'Start',
188
+ 'RbacCallback',
186
189
  'Complete'
187
190
  ]);
188
- assert.deepEqual(create.flowSteps[1].properties, [
191
+ assert.deepEqual(create.flowSteps[2].properties, [
189
192
  'returnValue',
190
193
  'parentFlowId',
191
194
  'status',
@@ -258,6 +261,57 @@ test('omits Complete step when no graph storage resources exist', async () => {
258
261
  assert.equal(create.flowSteps[0].nextSteps, undefined);
259
262
  });
260
263
 
264
+ test('evaluates hasQuotaReservation based on billable flag in belongTo and addOnDataStructure', () => {
265
+ const billableObj = {
266
+ objectType: 'unitType',
267
+ generatedBy: 'user',
268
+ addOnDataStructure: [{ type: 'rbac', billable: true }]
269
+ };
270
+ const plans1 = createCrudActionPlans([billableObj]);
271
+ assert.equal(plans1.Create.hasQuotaReservation, true);
272
+
273
+ const nonBillableObj1 = {
274
+ objectType: 'internalTag',
275
+ generatedBy: 'user',
276
+ addOnDataStructure: [{ type: 'rbac', billable: false }]
277
+ };
278
+ const plans2 = createCrudActionPlans([nonBillableObj1]);
279
+ assert.equal(plans2.Create.hasQuotaReservation, false);
280
+
281
+ const nonBillableObj2 = {
282
+ objectType: 'deliveryMethod',
283
+ generatedBy: 'user',
284
+ belongTo: {
285
+ objectType: 'supplyNetwork',
286
+ serviceTag: 'SupplyNetwork',
287
+ billable: false
288
+ },
289
+ belongToSchema: {
290
+ objectType: 'supplyNetwork',
291
+ addOnDataStructure: [{ type: 'rbac' }]
292
+ }
293
+ };
294
+ const plans3 = createCrudActionPlans([nonBillableObj2]);
295
+ assert.equal(plans3.Create.hasQuotaReservation, false);
296
+ assert.equal(plans3.Update.hasRbac, true);
297
+
298
+ const billableObj2 = {
299
+ objectType: 'unitType',
300
+ generatedBy: 'user',
301
+ belongTo: {
302
+ objectType: 'supplyNetwork',
303
+ serviceTag: 'SupplyNetwork',
304
+ billable: true
305
+ },
306
+ belongToSchema: {
307
+ objectType: 'supplyNetwork',
308
+ addOnDataStructure: [{ type: 'rbac' }]
309
+ }
310
+ };
311
+ const plans4 = createCrudActionPlans([billableObj2]);
312
+ assert.equal(plans4.Create.hasQuotaReservation, true);
313
+ });
314
+
261
315
  async function createProject({ generatedBy, flow, singletonExports = false }) {
262
316
  const rootPath = await mkdtemp(
263
317
  join(tmpdir(), 'generate-service-code-v2-crud-')
@@ -319,8 +373,8 @@ function readGeneratedFile(rootPath, action) {
319
373
  );
320
374
  }
321
375
 
322
- test('supports new standard generatedBy values (user, systemWithUser, systemWithNoUser)', async () => {
323
- for (const generatedBy of ['user', 'systemWithUser', 'systemWithNoUser']) {
376
+ test('supports standard generatedBy values (user, systemWithUser, systemNoUser)', async () => {
377
+ for (const generatedBy of ['user', 'systemWithUser', 'systemNoUser']) {
324
378
  const rootPath = await createProject({ generatedBy });
325
379
  await generateDynamicCrudFlowSchemas(rootPath);
326
380
  const create = await readGeneratedFlow(rootPath, 'Create');
@@ -328,3 +382,36 @@ test('supports new standard generatedBy values (user, systemWithUser, systemWith
328
382
  assert.deepEqual(create.flowSteps.map((s) => s.stepName), ['Start', 'Complete']);
329
383
  }
330
384
  });
385
+
386
+ test('logs warning when ObjectSchema has invalid or non-CRUD generatedBy', async () => {
387
+ const rootPath = await createProject({ generatedBy: 'user' });
388
+ await writeFile(
389
+ join(rootPath, 'app/src/schemas/ObjectSchemas/Order.js'),
390
+ "export default [{ objectType: 'order', generatedBy: 'invalidGeneratedBy' }];\n"
391
+ );
392
+
393
+ const warnings = [];
394
+ const logger = {
395
+ warn: (msg) => warnings.push(msg)
396
+ };
397
+
398
+ const result = await generateDynamicCrudFlowSchemas(rootPath, { logger });
399
+ assert.deepEqual(result.files, []);
400
+ assert.equal(warnings.length, 1);
401
+ assert.match(warnings[0], /\[WARN\] \[CRUD FlowSchemas\] Skipped FlowObjects FlowSchemas generation/);
402
+ assert.match(warnings[0], /invalidGeneratedBy/);
403
+ });
404
+
405
+ test('throws error when ObjectSchema validation fails with validateSchemas: true', async () => {
406
+ const rootPath = await createProject({ generatedBy: 'user' });
407
+ await writeFile(
408
+ join(rootPath, 'app/src/schemas/ObjectSchemas/Order.js'),
409
+ "export default [{ objectType: 'order', fieldNames: {}, identifiers: [] }];\n"
410
+ );
411
+
412
+ await assert.rejects(
413
+ generateDynamicCrudFlowSchemas(rootPath, { validateSchemas: true }),
414
+ /\[SCHEMA_VALIDATION_ERROR\] Schema validation failed for ObjectSchemas\/Order\.js/
415
+ );
416
+ });
417
+
@@ -8,7 +8,7 @@ import { pathToFileURL } from 'node:url';
8
8
  import { generateDynamicRbacFlowSchemas } from '../src/emit/rbac/generateDynamicRbacFlowSchemas.js';
9
9
 
10
10
  const projectRoots = new Set();
11
- const STATIC_ACTIONS = [
11
+ const STATIC_RBAC_ACTIONS = [
12
12
  'CreateTargetRole',
13
13
  'ListTargetRole',
14
14
  'DeleteTargetRole',
@@ -20,6 +20,15 @@ const STATIC_ACTIONS = [
20
20
  'DeleteUserFromRole'
21
21
  ];
22
22
 
23
+ const STATIC_LIMIT_ACTIONS = [
24
+ 'CreateRoleLimit',
25
+ 'ListRoleLimits',
26
+ 'DeleteRoleLimit',
27
+ 'ReservedDynamicUsage',
28
+ 'ConfirmUsage',
29
+ 'CancelUsage'
30
+ ];
31
+
23
32
  after(async () => {
24
33
  await Promise.all(
25
34
  [...projectRoots].map((rootPath) =>
@@ -38,10 +47,14 @@ test('generates shared and object-specific RBAC flow schemas', async () => {
38
47
  assert.deepEqual(
39
48
  result.files.map((file) => file.path),
40
49
  [
41
- ...STATIC_ACTIONS.map(
50
+ ...STATIC_RBAC_ACTIONS.map(
42
51
  (action) =>
43
52
  `app/src/schemas/FlowSchemas/generateCode/FlowRbac/${action}.js`
44
53
  ),
54
+ ...STATIC_LIMIT_ACTIONS.map(
55
+ (action) =>
56
+ `app/src/schemas/FlowSchemas/generateCode/FlowLimit/${action}.js`
57
+ ),
45
58
  'app/src/schemas/FlowSchemas/generateCode/FlowRbac/ValidatorRbac.js'
46
59
  ]
47
60
  );
@@ -23,7 +23,7 @@ test('generate commits schemas, application artifacts, and resources in one publ
23
23
  const rootPath = await createCrudProject();
24
24
  const result = await generate(rootPath);
25
25
 
26
- assert.strictEqual(result.files.length, 65);
26
+ assert.strictEqual(result.files.length, 74);
27
27
  assert.equal(result.project.rootPath, rootPath);
28
28
  assert.match(
29
29
  await readFile(
@@ -155,7 +155,7 @@ test('generate commits the system WebSocket completion path for own-topic flows'
155
155
  await readFile(
156
156
  join(
157
157
  rootPath,
158
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
158
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-system.yml'
159
159
  ),
160
160
  'utf8'
161
161
  ),
@@ -165,7 +165,7 @@ test('generate commits the system WebSocket completion path for own-topic flows'
165
165
  await readFile(
166
166
  join(
167
167
  rootPath,
168
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
168
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-system.yml'
169
169
  ),
170
170
  'utf8'
171
171
  ),
@@ -235,7 +235,7 @@ test('generate commits the trigger-cache suite with its queues when triggerFlowT
235
235
  await readFile(
236
236
  join(
237
237
  rootPath,
238
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
238
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
239
239
  ),
240
240
  'utf8'
241
241
  ),
@@ -273,7 +273,7 @@ test('generate removes the system WebSocket path when the last own-topic flow is
273
273
  await readFile(
274
274
  join(
275
275
  rootPath,
276
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
276
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-system.yml'
277
277
  ),
278
278
  'utf8'
279
279
  ),
@@ -309,7 +309,7 @@ test('generate removes stale CRUD schemas and application artifacts', async () =
309
309
 
310
310
  const result = await generate(rootPath);
311
311
 
312
- assert.equal(result.files.length, 29);
312
+ assert.equal(result.files.length, 38);
313
313
  await assert.rejects(
314
314
  readFile(
315
315
  join(
@@ -19,28 +19,52 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
19
19
  const rootPath = await createProject();
20
20
  const result = await generateResourceArtifacts(rootPath);
21
21
 
22
- assert.equal(result.files.length, 6);
23
- const resources = await readFile(
22
+ assert.equal(result.files.length, 10);
23
+ const crudResources = await readFile(
24
24
  join(
25
25
  rootPath,
26
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
26
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-crud.yml'
27
27
  ),
28
28
  'utf8'
29
29
  );
30
- assert.match(resources, /SubscriptionOutCreateToUploadReservedLimitHdrSqs:/);
31
- assert.match(resources, /TopicArn: !Ref OutCreate/);
30
+ assert.match(crudResources, /InCreate:/);
31
+ assert.match(crudResources, /^ CreateCompleteHdrSqs:/m);
32
+ assert.match(crudResources, /^ UpdateCompleteHdrSqs:/m);
33
+ assert.match(crudResources, /^ DeleteCompleteHdrSqs:/m);
34
+ assert.doesNotMatch(crudResources, /RbacCallbackHdrSqs/);
35
+ assert.doesNotMatch(crudResources, /FlowHook|beforeLogical/);
36
+
37
+ const customResources = await readFile(
38
+ join(
39
+ rootPath,
40
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
41
+ ),
42
+ 'utf8'
43
+ );
44
+ assert.match(
45
+ customResources,
46
+ /SubscriptionOutCreateToUploadReservedLimitHdrSqs:/
47
+ );
48
+ assert.match(customResources, /TopicArn: !Ref OutCreate/);
32
49
  assert.match(
33
- resources,
50
+ customResources,
34
51
  /Endpoint: 'arn:aws:sqs:\${self:custom\.iz_region}:\${self:custom\.iz_accountId}:\${self:custom\.iz_resourcePrefix}UploadReservedLimitHdrSqs'/
35
52
  );
36
- assert.match(resources, /InCreate:/);
53
+
54
+ const systemResources = await readFile(
55
+ join(
56
+ rootPath,
57
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-system.yml'
58
+ ),
59
+ 'utf8'
60
+ );
37
61
  for (const queueName of [
38
62
  'FindDataHdrSqs',
39
63
  'ProcessLogicalHdrSqs',
40
64
  'PaginateProcessLogicalHdrDsq',
41
65
  'PaginateProcessLogicalHdrSqs'
42
66
  ]) {
43
- assert.match(resources, new RegExp(`^ ${queueName}:`, 'm'));
67
+ assert.match(systemResources, new RegExp(`^ ${queueName}:`, 'm'));
44
68
  }
45
69
  const dynamoYaml = await readFile(
46
70
  join(
@@ -52,6 +76,10 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
52
76
  assert.match(dynamoYaml, /OrdersTable:/);
53
77
  assert.match(dynamoYaml, /#<#OrdersTableSetting#>/);
54
78
  assert.match(dynamoYaml, /#<#\/OrdersTableSetting#>/);
79
+ assert.match(dynamoYaml, /TargetRolesTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+AttributeName: identifiersConcat/);
80
+ assert.match(dynamoYaml, /RoleLimitTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RoleLimit/);
81
+ assert.match(dynamoYaml, /RunningTotalUsageTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RunningTotalUsage/);
82
+ assert.match(dynamoYaml, /RunningTotalReservedUsageTable:\s+Type: 'AWS::DynamoDB::Table'[\s\S]+TableName: \${self:custom\.iz_resourcePrefix}RunningTotalReservedUsage/);
55
83
  const iam = await readFile(
56
84
  join(
57
85
  rootPath,
@@ -80,22 +108,28 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
80
108
  roleBlock(iam, 'FlowRbacRole'),
81
109
  /RolePermissions|ProcessCreateTargetRoleHdrSqs/
82
110
  );
111
+ assert.match(roleBlock(iam, 'FlowRbacRole'), /RoleLimit/);
112
+ assert.match(roleBlock(iam, 'FlowRbacRole'), /RunningTotalUsage/);
113
+ assert.match(roleBlock(iam, 'FlowObjectsRole'), /RoleLimit/);
83
114
  // Per-object RBAC flow queue (e.g. ValidatorRbacHdrSqs from Order with rbac add-on)
84
115
  assert.match(roleBlock(iam, 'FlowRbacRole'), /ValidatorRbacHdrSqs/);
85
- assert.match(resources, /^ CreateRelationshipHdrSqs:/m);
86
- assert.doesNotMatch(resources, /^ CreateCompleteHdrSqs:/m);
87
- assert.match(resources, /^ UpdateCompleteHdrSqs:/m);
88
- assert.match(resources, /^ DeleteCompleteHdrSqs:/m);
89
- assert.doesNotMatch(resources, /RbacCallbackHdrSqs/);
90
- assert.doesNotMatch(resources, /FlowHook|beforeLogical/);
116
+
117
+ const relResources = await readFile(
118
+ join(
119
+ rootPath,
120
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-relationship.yml'
121
+ ),
122
+ 'utf8'
123
+ );
124
+ assert.match(relResources, /^ CreateRelationshipHdrSqs:/m);
91
125
  assert.equal(
92
- (resources.match(/^ CreateRelationshipHdrSqs:/gm) ?? []).length,
126
+ (relResources.match(/^ CreateRelationshipHdrSqs:/gm) ?? []).length,
93
127
  1
94
128
  );
95
- assert.match(resources, /^ CreateRelationshipCompleteHdrSqs:/m);
96
- assert.match(resources, /^ GetRelationshipHdrDsq:/m);
129
+ assert.match(relResources, /^ CreateRelationshipCompleteHdrSqs:/m);
130
+ assert.match(relResources, /^ GetRelationshipHdrDsq:/m);
97
131
  assert.doesNotMatch(
98
- resources,
132
+ relResources,
99
133
  /Process(?:Create|Update|Delete|Get|Change|Move)Relationship/
100
134
  );
101
135
  const relationshipRole = roleBlock(iam, 'FlowRelationshipRole');
@@ -107,9 +141,12 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
107
141
  /Process(?:Create|Update|Delete|Get|Change|Move)Relationship/
108
142
  );
109
143
  assert.match(roleBlock(iam, 'RegisterRole'), /s3:GetObject/);
144
+ assert.match(roleBlock(iam, 'RegisterRole'), /s3:ListBucket/);
110
145
  assert.match(roleBlock(iam, 'RegisterRole'), /RegisterComplete/);
111
146
  assert.match(roleBlock(iam, 'RegisterRole'), /dynamodb:/);
112
147
  assert.match(roleBlock(iam, 'RegisterRole'), /execute-api:ManageConnections/);
148
+ assert.match(roleBlock(iam, 'FlowObjectsRole'), /s3:GetObject/);
149
+ assert.match(roleBlock(iam, 'FlowObjectsRole'), /s3:ListBucket/);
113
150
  const procFindDataRole = roleBlock(iam, 'ProcFindDataRole');
114
151
  assert.match(procFindDataRole, /dynamodb:UpdateItem/);
115
152
  assert.match(procFindDataRole, /dynamodb:GetItem/);
@@ -118,12 +155,16 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
118
155
  assert.match(procFindDataRole, /FindData_Out/);
119
156
  assert.doesNotMatch(
120
157
  iam,
121
- /s3:GetObjectVersion|s3:ListBucket|sqs:DeleteMessageBatch|sqs:GetQueueUrl/
158
+ /s3:GetObjectVersion|sqs:DeleteMessageBatch|sqs:GetQueueUrl/
122
159
  );
123
160
  assert.match(iam, /#<#\/\w+StatementHookCode#>\n\n \w+Role:/);
124
161
 
125
162
  for (const filePath of [
126
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml',
163
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-crud.yml',
164
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-relationship.yml',
165
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-rbac.yml',
166
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml',
167
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-system.yml',
127
168
  'resource/sls_yaml/generatedCode/source/generated-sns-out.yml',
128
169
  'resource/sls_yaml/generatedCode/source/generated-dynamoDB-table.yml',
129
170
  'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
@@ -153,16 +194,16 @@ test('emits the shared WebSocket completion queue and output-topic subscriptions
153
194
  const rootPath = await createProject();
154
195
  await generateResourceArtifacts(rootPath);
155
196
 
156
- const resources = await readFile(
197
+ const systemResources = await readFile(
157
198
  join(
158
199
  rootPath,
159
- 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
200
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-system.yml'
160
201
  ),
161
202
  'utf8'
162
203
  );
163
- assert.match(resources, /^ WebSocketCompleteHdrSqs:/m);
164
- assert.match(resources, /SubscriptionToOutCustomWebSocketComplete:/);
165
- assert.match(resources, /SubscriptionToOutCustomRegisterComplete:/);
204
+ assert.match(systemResources, /^ WebSocketCompleteHdrSqs:/m);
205
+ assert.match(systemResources, /SubscriptionToOutCustomWebSocketComplete:/);
206
+ assert.match(systemResources, /SubscriptionToOutCustomRegisterComplete:/);
166
207
  const iam = await readFile(
167
208
  join(
168
209
  rootPath,
@@ -186,11 +227,11 @@ test('emits the shared WebSocket completion queue and output-topic subscriptions
186
227
  );
187
228
  }
188
229
  assert.match(
189
- resources,
230
+ systemResources,
190
231
  /SubscriptionToOutCreateRelationshipWebSocketComplete:/
191
232
  );
192
233
  assert.match(
193
- resources,
234
+ systemResources,
194
235
  /SubscriptionToOutCreateRelationshipRegisterComplete:/
195
236
  );
196
237
  });