@izara_project/izara-core-generate-service-code 1.0.88 → 1.0.90

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 (29) hide show
  1. package/package.json +1 -1
  2. package/src/compile/flowValidator.js +25 -0
  3. package/src/compile/loadSchemas.js +154 -0
  4. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
  5. package/src/emit/crud/crudActionPlan.js +67 -9
  6. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
  7. package/src/emit/crud/templates/CreateComplete_Main.ejs +135 -10
  8. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +33 -27
  9. package/src/emit/crud/templates/CreateLogicalLib.ejs +282 -95
  10. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +38 -21
  11. package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
  12. package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
  13. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +26 -16
  14. package/src/emit/crud/templates/DeleteLogicalLib.ejs +113 -4
  15. package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
  16. package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +34 -22
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +121 -4
  19. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +8 -2
  20. package/src/emit/rbac/templates/CancelUsage_Main.ejs +34 -14
  21. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +34 -14
  22. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +20 -13
  23. package/src/emit/resource/emitResourceArtifacts.js +55 -14
  24. package/test/createTargetRoleHandler.test.js +11 -8
  25. package/test/crudApplicationArtifacts.test.js +440 -0
  26. package/test/dynamicCrudFlowSchemas.test.js +10 -5
  27. package/test/dynamicRbacFlowSchemas.test.js +24 -2
  28. package/test/graphDrivenFlowSchema.test.js +36 -0
  29. package/test/resourceArtifacts.test.js +113 -0
@@ -204,6 +204,38 @@ test('rejects deprecated FlowHook schemas', async () => {
204
204
  );
205
205
  });
206
206
 
207
+ test('rejects invalid generateCodeTag configuration', async () => {
208
+ const rootPath = await createProject();
209
+ const flowDirectory = join(rootPath, 'app/src/schemas/FlowSchemas');
210
+ await writeFile(
211
+ join(flowDirectory, 'InvalidTag.js'),
212
+ "export default { flowTag: 'invalidHook', event: ['ownTopic'], " +
213
+ "generatedCodeConfig: { generateCodeTag: ['invalidAction'], " +
214
+ "codeHookTag: 'before' } };\n"
215
+ );
216
+
217
+ await assert.rejects(
218
+ generateResourceArtifacts(rootPath),
219
+ /generatedCodeConfig\.generateCodeTag contains invalid tag 'invalidAction'/
220
+ );
221
+ });
222
+
223
+ test('rejects empty generateCodeTag array configuration', async () => {
224
+ const rootPath = await createProject();
225
+ const flowDirectory = join(rootPath, 'app/src/schemas/FlowSchemas');
226
+ await writeFile(
227
+ join(flowDirectory, 'EmptyTag.js'),
228
+ "export default { flowTag: 'emptyHook', event: ['ownTopic'], " +
229
+ "generatedCodeConfig: { generateCodeTag: [], " +
230
+ "codeHookTag: 'before' } };\n"
231
+ );
232
+
233
+ await assert.rejects(
234
+ generateResourceArtifacts(rootPath),
235
+ /generatedCodeConfig\.generateCodeTag array must not be empty/
236
+ );
237
+ });
238
+
207
239
  test('emits the shared WebSocket completion queue and output-topic subscriptions', async () => {
208
240
  const rootPath = await createProject();
209
241
  await generateResourceArtifacts(rootPath);
@@ -382,6 +414,50 @@ test('emits CreateNodeCallbackHdrSqs in FlowObjectsRole when object has graph an
382
414
  assert.match(role, /RolePermissions/);
383
415
  assert.match(role, /ValidatorRbac_In/);
384
416
  assert.match(role, /Rbac_\$\{self:custom\.iz_stage\}_ValidatorRbac_In/);
417
+ assert.match(role, /ConfirmUsageHdrInv/);
418
+ assert.match(role, /CancelUsageHdrInv/);
419
+ });
420
+
421
+ test('emits correct permissions in FlowObjectsRole when object is child RBAC node with graph', async () => {
422
+ const rootPath = await createProject();
423
+ const schemas = join(rootPath, 'app/src/schemas');
424
+ await rm(join(schemas, 'ObjectSchemas/Order.js'));
425
+ await writeFile(
426
+ join(schemas, 'ObjectSchemas/ChildNode.js'),
427
+ "export default { objectType: 'childNode', generatedBy: 'user', belongTo: [{ serviceTag: 'UserAccount', objectType: 'user' }], identifiers: [{ type: 'partitionKey', fieldName: 'childId' }], storageResources: { main: { storageType: 'graph', tableName: 'ChildNodes' } } };\n"
428
+ );
429
+ await generateResourceArtifacts(rootPath);
430
+
431
+ const iam = await readFile(
432
+ join(
433
+ rootPath,
434
+ 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
435
+ ),
436
+ 'utf8'
437
+ );
438
+ const role = roleBlock(iam, 'FlowObjectsRole');
439
+ assert.match(role, /CreateNodeCallbackHdrSqs/);
440
+ assert.match(role, /CreateNodeCallbackHdrSqsDLQ/);
441
+ assert.match(role, /ValidatorRbac_In/);
442
+ assert.match(role, /Rbac_\$\{self:custom\.iz_stage\}_ValidatorRbac_In/);
443
+ assert.match(role, /UserAccount_\$\{self:custom\.iz_stage\}_ValidatorRbac_In/);
444
+ assert.match(role, /ConfirmUsageHdrInv/);
445
+ assert.match(role, /CancelUsageHdrInv/);
446
+ assert.match(role, /UserAccount\$\{self:custom\.iz_stage\}ValidatorRbacHdrInv/);
447
+ // Child node service is not RBAC provider: no TargetRoles or Roles table in DynamoDB permissions
448
+ assert.doesNotMatch(role, /TargetRoles/);
449
+ assert.doesNotMatch(role, /RolePermissions/);
450
+ assert.doesNotMatch(iam, /FlowRbacRole:/);
451
+
452
+ const dynamo = await readFile(
453
+ join(
454
+ rootPath,
455
+ 'resource/sls_yaml/generatedCode/source/generated-dynamoDB-table.yml'
456
+ ),
457
+ 'utf8'
458
+ );
459
+ assert.doesNotMatch(dynamo, /TargetRolesTable:/);
460
+ assert.doesNotMatch(dynamo, /RolesTable:/);
385
461
  });
386
462
 
387
463
  test('emits CreateAfterHookCallbackHdrSqs in SQS resources and FlowObjectsRole when flow has after hook with ownTopic', async () => {
@@ -559,6 +635,43 @@ test('emits lambda:InvokeFunction in FlowObjectsRole when flow has after hook wi
559
635
  assert.match(role, /AuditAfterCreate/);
560
636
  });
561
637
 
638
+ test('emits SQS queues and deduplicated IAM policies when generateCodeTag is an array for multiple actions', async () => {
639
+ const rootPath = await createProject();
640
+ const schemas = join(rootPath, 'app/src/schemas');
641
+ await writeFile(
642
+ join(schemas, 'FlowSchemas/NotifyMultiAfter.js'),
643
+ "export default { flowTag: 'notifyMultiAfter', event: ['ownTopic'], " +
644
+ "generatedCodeConfig: { generateCodeTag: ['create', 'update'], " +
645
+ "codeHookTag: 'after', invocationType: 'ownTopic', " +
646
+ "objType: { objectType: 'order' } } };\n"
647
+ );
648
+ await generateResourceArtifacts(rootPath);
649
+
650
+ const crudResources = await readFile(
651
+ join(
652
+ rootPath,
653
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-crud.yml'
654
+ ),
655
+ 'utf8'
656
+ );
657
+ assert.match(crudResources, /^ CreateAfterHookCallbackHdrSqs:/m);
658
+ assert.match(crudResources, /^ UpdateAfterHookCallbackHdrSqs:/m);
659
+
660
+ const iam = await readFile(
661
+ join(
662
+ rootPath,
663
+ 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
664
+ ),
665
+ 'utf8'
666
+ );
667
+ const role = roleBlock(iam, 'FlowObjectsRole');
668
+ assert.match(role, /CreateAfterHookCallbackHdrSqs/);
669
+ assert.match(role, /UpdateAfterHookCallbackHdrSqs/);
670
+
671
+ const notifyTopicMatches = role.match(/NotifyMultiAfter_In/g);
672
+ assert.strictEqual(notifyTopicMatches?.length, 1);
673
+ });
674
+
562
675
  function roleBlock(iam, roleName) {
563
676
  const match = iam.match(
564
677
  new RegExp(