@izara_project/izara-core-generate-service-code 1.0.91 → 1.0.92

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 (30) hide show
  1. package/package.json +7 -10
  2. package/src/compile/flowValidator.js +6 -0
  3. package/src/compile/loadSchemas.js +177 -69
  4. package/src/emit/crud/generateCrudApplicationArtifacts.js +15 -17
  5. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +16 -21
  6. package/src/emit/crud/loadLocalSchemaArrays.js +4 -8
  7. package/src/emit/custom/customFlowPaths.js +149 -0
  8. package/src/emit/custom/customFlowS3.js +156 -0
  9. package/src/emit/custom/customFlowSteps.js +385 -0
  10. package/src/emit/custom/customFlowTemplates.js +28 -0
  11. package/src/emit/custom/customFlows.js +48 -19
  12. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +57 -692
  13. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +27 -25
  14. package/src/emit/rbac/generateCreateTargetRoleHandler.js +11 -13
  15. package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +14 -18
  16. package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +16 -19
  17. package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +19 -19
  18. package/src/emit/resource/dynamoResourceArtifacts.js +18 -0
  19. package/src/emit/resource/emitResourceArtifacts.js +13 -1247
  20. package/src/emit/resource/generateResourceArtifacts.js +20 -20
  21. package/src/emit/resource/iamResourceArtifacts.js +612 -0
  22. package/src/emit/resource/resourceState.js +564 -0
  23. package/src/emit/resource/resourceTemplate.js +30 -0
  24. package/src/emit/resource/s3ResourceArtifacts.js +14 -0
  25. package/src/emit/resource/sqsResourceArtifacts.js +113 -0
  26. package/src/emit/shared/runSubsystemGeneration.js +55 -0
  27. package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
  28. package/test/crudApplicationArtifacts.test.js +72 -0
  29. package/test/customFlowApplicationArtifacts.test.js +98 -0
  30. package/test/resourceArtifacts.test.js +99 -0
@@ -1,14 +1,3 @@
1
- import ejsLib from 'ejs';
2
- import { readFile } from 'node:fs/promises';
3
-
4
- import {
5
- renderApiFunctionYaml,
6
- renderEventBridgeFunctionYaml,
7
- renderInvFunctionYaml,
8
- renderS3FunctionYaml,
9
- renderSqsFunctionYaml,
10
- renderWbsFunctionYaml
11
- } from '../function/functionYamlArtifact.js';
12
1
  import {
13
2
  customFlowRoleName,
14
3
  flowDsqSteps,
@@ -19,11 +8,33 @@ import {
19
8
  upperFirst,
20
9
  flowHasRbac
21
10
  } from './customFlows.js';
11
+ import {
12
+ customFlowApplicationManagedPaths,
13
+ needsProcessMain,
14
+ YAML_PATH
15
+ } from './customFlowPaths.js';
16
+ import { emitS3Flow } from './customFlowS3.js';
17
+ import {
18
+ emitExtTopicStep,
19
+ emitDsqStep,
20
+ emitOwnTopicRoot,
21
+ renderEndpointMain,
22
+ stepConfig,
23
+ _startConfig
24
+ } from './customFlowSteps.js';
25
+ import {
26
+ renderCustom,
27
+ renderShared,
28
+ renderDsq
29
+ } from './customFlowTemplates.js';
30
+ import {
31
+ renderApiFunctionYaml,
32
+ renderEventBridgeFunctionYaml,
33
+ renderInvFunctionYaml,
34
+ renderSqsFunctionYaml
35
+ } from '../function/functionYamlArtifact.js';
22
36
 
23
- const YAML_PATH = 'app/sls_yaml/generatedCode/source/flow-schema.yml';
24
- const TEMPLATE_URL = new URL('../crud/templates/', import.meta.url);
25
- const SHARED_TEMPLATE_URL = new URL('../shared/templates/', import.meta.url);
26
- const CUSTOM_TEMPLATE_URL = new URL('./templates/', import.meta.url);
37
+ export { customFlowApplicationManagedPaths };
27
38
 
28
39
  export async function emitCustomFlowApplicationArtifacts(
29
40
  flows,
@@ -38,8 +49,9 @@ export async function emitCustomFlowApplicationArtifacts(
38
49
  generatedRoots.length === 0 &&
39
50
  steps.length === 0 &&
40
51
  dsqSteps.length === 0
41
- )
52
+ ) {
42
53
  return [];
54
+ }
43
55
 
44
56
  const emitted = await Promise.all(
45
57
  customFlows.map((flow) => emitFlow(flow, objects))
@@ -68,39 +80,6 @@ export async function emitCustomFlowApplicationArtifacts(
68
80
  ];
69
81
  }
70
82
 
71
- export function customFlowApplicationManagedPaths(flows, { objects = [] } = {}) {
72
- return [
73
- ...supportedCustomFlows(flows).flatMap((flow) => flowPaths(flow, objects)),
74
- ...generatedOwnTopicFlows(flows).flatMap((flow) => ownTopicRootPaths(flow, objects)),
75
- ...flowExtTopicSteps(flows).flatMap(({ flowTag, stepName }) => {
76
- const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
77
- return [
78
- `${source}/${flowTag}${stepName}_Main.js`,
79
- `${source}/${flowTag}${stepName}_HdrSqs.js`
80
- ];
81
- }),
82
- ...flowDsqSteps(flows).flatMap(({ flowTag, stepName, step }) => {
83
- const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
84
- let stepEvents = [];
85
- if (Array.isArray(step.event)) {
86
- stepEvents = step.event;
87
- }
88
- const files = [`${source}/${flowTag}${stepName}_HdrDsq.js`];
89
- if (!stepEvents.includes('extTopic')) {
90
- files.unshift(`${source}/${flowTag}${stepName}_Main.js`);
91
- }
92
- return files;
93
- }),
94
- ...(supportedCustomFlows(flows).length > 0 ||
95
- generatedOwnTopicFlows(flows).length > 0 ||
96
- generatedDsqFlows(flows).length > 0 ||
97
- flowExtTopicSteps(flows).length > 0 ||
98
- flowDsqSteps(flows).length > 0
99
- ? [YAML_PATH]
100
- : [])
101
- ];
102
- }
103
-
104
83
  async function emitFlow(flow, objects) {
105
84
  const tag = upperFirst(flow.flowTag);
106
85
  const process = tag;
@@ -113,22 +92,26 @@ async function emitFlow(flow, objects) {
113
92
  functionName: process,
114
93
  startConfig: _startConfig(flow)
115
94
  };
116
- const artifacts = needsProcessMain(flow)
117
- ? [
118
- {
119
- path: `${source}/${process}_Main.js`,
120
- content: await renderEndpointMain(flow, process, objects)
121
- }
122
- ]
123
- : [];
95
+ const artifacts = [];
96
+ if (needsProcessMain(flow)) {
97
+ artifacts.push({
98
+ path: `${source}/${process}_Main.js`,
99
+ content: await renderEndpointMain(flow, process, objects)
100
+ });
101
+ }
124
102
  const functions = [];
125
103
 
126
104
  const isRbac = flowHasRbac(flow, objects);
127
105
  if (isRbac && !flow.event.includes('ownTopic')) {
128
106
  const rbacStep = (flow.flowSteps || []).find(
129
- (s) => typeof s?.stepName === 'string' && s.stepName.toLowerCase() === 'rbaccallback'
107
+ (s) =>
108
+ typeof s?.stepName === 'string' &&
109
+ s.stepName.toLowerCase() === 'rbaccallback'
130
110
  );
131
- const rbacConfig = rbacStep ? stepConfig(flow, rbacStep) : null;
111
+ let rbacConfig = null;
112
+ if (rbacStep) {
113
+ rbacConfig = stepConfig(flow, rbacStep);
114
+ }
132
115
  artifacts.push(
133
116
  {
134
117
  path: `${source}/${tag}RbacCallback_Main.js`,
@@ -200,7 +183,11 @@ async function emitFlow(flow, objects) {
200
183
  })
201
184
  );
202
185
  }
203
- if (flow.event.includes('lambdaSyncInv')) {
186
+ if (
187
+ flow.event.includes('lambdaSyncInv') ||
188
+ (flow.event.includes('generateCode') &&
189
+ flow.generatedCodeConfig?.invocationType === 'lambdaSyncInv')
190
+ ) {
204
191
  artifacts.push({
205
192
  path: `${source}/${process}_HdrInv.js`,
206
193
  content: await renderShared('FlowHandler_HdrInv.ejs', shared)
@@ -235,6 +222,10 @@ async function emitFlow(flow, objects) {
235
222
  path: `${source}/${process}_HdrInv.js`,
236
223
  content: await renderShared('FlowHandler_HdrInv.ejs', shared)
237
224
  });
225
+ let schedules = [];
226
+ if (flow.schedules) {
227
+ schedules = flow.schedules;
228
+ }
238
229
  functions.push(
239
230
  renderEventBridgeFunctionYaml({
240
231
  functionName: `${process}HdrInv`,
@@ -242,11 +233,15 @@ async function emitFlow(flow, objects) {
242
233
  roleName: customFlowRoleName(flow.flowTag),
243
234
  flowTag: flow.flowTag,
244
235
  flowStepName: '',
245
- schedules: flow.schedules ?? []
236
+ schedules
246
237
  })
247
238
  );
248
239
  }
249
- if (flow.event.includes('ownTopic')) {
240
+ if (
241
+ flow.event.includes('ownTopic') ||
242
+ (flow.event.includes('generateCode') &&
243
+ flow.generatedCodeConfig?.invocationType === 'ownTopic')
244
+ ) {
250
245
  const root = await emitOwnTopicRoot(flow, objects);
251
246
  artifacts.push(...root.artifacts);
252
247
  functions.push(...root.functions);
@@ -258,633 +253,3 @@ async function emitFlow(flow, objects) {
258
253
  }
259
254
  return { artifacts, functions };
260
255
  }
261
-
262
- function flowPaths(flow, objects = []) {
263
- const tag = upperFirst(flow.flowTag);
264
- const process = tag;
265
- const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
266
- const paths = [];
267
- if (needsProcessMain(flow)) {
268
- paths.push(`${source}/${process}_Main.js`);
269
- }
270
- if (flowHasRbac(flow, objects)) {
271
- paths.push(
272
- `${source}/${tag}RbacCallback_Main.js`,
273
- `${source}/${tag}RbacCallback_HdrSqs.js`
274
- );
275
- }
276
- if (flow.event.includes('extTopic') && !flow.event.includes('ownTopic')) {
277
- paths.push(`${source}/${process}_HdrSqs.js`);
278
- }
279
- if (flow.event.includes('dsq')) {
280
- paths.push(`${source}/${process}_HdrDsq.js`);
281
- }
282
- if (
283
- flow.event.includes('lambdaSyncInv') ||
284
- flow.event.includes('eventBridge')
285
- ) {
286
- paths.push(`${source}/${process}_HdrInv.js`);
287
- }
288
- if (flow.event.includes('lambdaSyncApi')) {
289
- paths.push(`${source}/${process}_HdrApi.js`);
290
- }
291
- if (flow.event.includes('ownTopic')) {
292
- paths.push(...ownTopicRootPaths(flow));
293
- }
294
- if (flow.event.includes('s3')) {
295
- const s3Actions = [
296
- 'ConfirmAfterUpload',
297
- 'CreateObject',
298
- 'CreatePreSignUrl',
299
- 'ProcessAfterUpload',
300
- 'ReservedLimit'
301
- ];
302
- for (const action of s3Actions) {
303
- let handler = 'HdrSqs';
304
- if (action === 'CreateObject') {
305
- handler = 'HdrWbs';
306
- } else if (action === 'ProcessAfterUpload') {
307
- handler = 'HdrS3';
308
- }
309
- paths.push(
310
- `${source}/${tag}${action}_Main.js`,
311
- `${source}/${tag}${action}_${handler}.js`
312
- );
313
- }
314
- }
315
- return paths;
316
- }
317
-
318
- async function emitExtTopicStep({ flow, step, flowTag, stepName }) {
319
- const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
320
- const handlerRoot = `src/generatedCode/FlowSchemas/${flowTag}/source`;
321
- const functionName = stepName.startsWith(flowTag)
322
- ? stepName
323
- : `${flowTag}${stepName}`;
324
- const mainFileName = `${functionName}_Main`;
325
- const startConfig = stepConfig(flow, step);
326
-
327
- const hasTriggerFlowTypes =
328
- Array.isArray(flow.triggerFlowTypes) && flow.triggerFlowTypes.length > 0;
329
- const isCheckStep = stepName.toLowerCase().includes('checktrigger');
330
-
331
- if (isCheckStep && hasTriggerFlowTypes) {
332
- const queueName = `${functionName}HdrSqs`;
333
- return {
334
- artifacts: [
335
- {
336
- path: `${source}/${mainFileName}.js`,
337
- content: await renderCustom(
338
- 'triggerCache/CheckTriggerCache_Main.ejs',
339
- { functionName, flowTag }
340
- )
341
- },
342
- {
343
- path: `${source}/${functionName}_HdrSqs.js`,
344
- content: await renderCustom(
345
- 'triggerCache/CheckTriggerCache_HdrSqs.ejs',
346
- { functionName, queueName, startConfig }
347
- )
348
- }
349
- ],
350
- functions: [
351
- renderSqsFunctionYaml({
352
- functionName: queueName,
353
- handlerPath: `${handlerRoot}/${functionName}_HdrSqs.main`,
354
- roleName: customFlowRoleName(flow.flowTag),
355
- queueName,
356
- flowTag,
357
- flowStepName: step.stepName
358
- })
359
- ]
360
- };
361
- }
362
-
363
- const artifacts = [
364
- {
365
- path: `${source}/${mainFileName}.js`,
366
- content: await renderStepMain(functionName, _startConfig(flow))
367
- }
368
- ];
369
- const functions = [];
370
-
371
- let stepEvents = [];
372
- if (Array.isArray(step.event)) {
373
- stepEvents = step.event;
374
- }
375
- const hasSqs = stepEvents.includes('extTopic') || stepEvents.includes('sqs');
376
-
377
- if (hasSqs) {
378
- const queueName = `${functionName}HdrSqs`;
379
- artifacts.push({
380
- path: `${source}/${functionName}_HdrSqs.js`,
381
- content: await renderShared('FlowHandler_HdrSqs.ejs', {
382
- flowTag: flow.flowTag,
383
- flowStepName: step.stepName,
384
- functionName,
385
- mainFileName,
386
- startConfig,
387
- queueName
388
- })
389
- });
390
- functions.push(
391
- renderSqsFunctionYaml({
392
- functionName: queueName,
393
- handlerPath: `${handlerRoot}/${functionName}_HdrSqs.main`,
394
- roleName: customFlowRoleName(flow.flowTag),
395
- queueName,
396
- flowTag,
397
- flowStepName: step.stepName
398
- })
399
- );
400
- }
401
-
402
- return { artifacts, functions };
403
- }
404
-
405
- async function emitDsqStep({ flow, step, flowTag, stepName }) {
406
- const source = `app/src/generatedCode/FlowSchemas/${flowTag}/source`;
407
- const handlerRoot = `src/generatedCode/FlowSchemas/${flowTag}/source`;
408
- const functionName = `${flowTag}${stepName}`;
409
- const mainFileName = `${functionName}_Main`;
410
- const startConfig = stepConfig(flow, step);
411
-
412
- let stepEvents = [];
413
- if (Array.isArray(step.event)) {
414
- stepEvents = step.event;
415
- }
416
- const artifacts = [];
417
- if (!stepEvents.includes('extTopic')) {
418
- artifacts.push({
419
- path: `${source}/${mainFileName}.js`,
420
- content: await renderStepMain(functionName, startConfig)
421
- });
422
- }
423
- const functions = [];
424
-
425
- const hasDsq = stepEvents.includes('dsq');
426
-
427
- if (hasDsq) {
428
- const queueName = `${functionName}HdrDsq`;
429
- artifacts.push({
430
- path: `${source}/${functionName}_HdrDsq.js`,
431
- content: await renderDsq('FlowHandler_HdrDsq.ejs', {
432
- flowTag: flow.flowTag,
433
- flowStepName: step.stepName,
434
- functionName,
435
- mainFileName,
436
- startConfig,
437
- queueName
438
- })
439
- });
440
- functions.push(
441
- renderSqsFunctionYaml({
442
- functionName: queueName,
443
- handlerPath: `${handlerRoot}/${functionName}_HdrDsq.main`,
444
- roleName: customFlowRoleName(flow.flowTag),
445
- queueName,
446
- flowTag,
447
- flowStepName: step.stepName
448
- })
449
- );
450
- }
451
-
452
- return { artifacts, functions };
453
- }
454
-
455
- async function emitOwnTopicRoot(flow, objects) {
456
- const tag = upperFirst(flow.flowTag);
457
- const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
458
- const handlerRoot = `src/generatedCode/FlowSchemas/${tag}/source`;
459
- const mainFileName = `${tag}_Main`;
460
- const wbsMainFileName = `${tag}_WbsMain`;
461
- const shared = {
462
- flowTag: flow.flowTag,
463
- flowStepName: '',
464
- upperCaseFlowTag: tag,
465
- startConfig: _startConfig(flow)
466
- };
467
- const isRbac = flowHasRbac(flow, objects);
468
- const ownArtifacts = [
469
- {
470
- path: `${source}/${mainFileName}.js`,
471
- content: await renderEndpointMain(flow, mainFileName, objects)
472
- },
473
- {
474
- path: `${source}/${tag}_HdrSqs.js`,
475
- content: await renderShared('FlowHandler_HdrSqs.ejs', {
476
- ...shared,
477
- functionName: mainFileName,
478
- mainFileName,
479
- queueName: `${tag}HdrSqs`
480
- })
481
- },
482
- {
483
- path: `${source}/${wbsMainFileName}.js`,
484
- content: await renderCrudTemplate('FlowMain_Wbs.ejs', {
485
- ...shared,
486
- functionName: wbsMainFileName
487
- })
488
- },
489
- {
490
- path: `${source}/${tag}_HdrWbs.js`,
491
- content: await renderCrudTemplate('FlowEndpoint_HdrWbs.ejs', {
492
- ...shared,
493
- functionName: tag,
494
- mainFileName: wbsMainFileName,
495
- route: tag
496
- })
497
- }
498
- ];
499
-
500
- const ownFunctions = [
501
- renderWbsFunctionYaml({
502
- functionName: `${tag}HdrWbs`,
503
- handlerPath: `${handlerRoot}/${tag}_HdrWbs.main`,
504
- roleName: customFlowRoleName(flow.flowTag),
505
- routeName: tag,
506
- flowTag: flow.flowTag,
507
- flowStepName: ''
508
- }),
509
- renderSqsFunctionYaml({
510
- functionName: `${tag}HdrSqs`,
511
- handlerPath: `${handlerRoot}/${tag}_HdrSqs.main`,
512
- roleName: customFlowRoleName(flow.flowTag),
513
- queueName: `${tag}HdrSqs`,
514
- flowTag: flow.flowTag,
515
- flowStepName: ''
516
- })
517
- ];
518
-
519
- if (isRbac) {
520
- const rbacStep = (flow.flowSteps || []).find(
521
- (s) => typeof s?.stepName === 'string' && s.stepName.toLowerCase() === 'rbaccallback'
522
- );
523
- const rbacConfig = rbacStep ? stepConfig(flow, rbacStep) : null;
524
- ownArtifacts.push(
525
- {
526
- path: `${source}/${tag}RbacCallback_Main.js`,
527
- content: await renderCustom('FlowEndpointRbacCallback_Main.ejs', {
528
- flowTag: flow.flowTag,
529
- upperCaseFlowTag: tag,
530
- functionName: `${tag}RbacCallbackMain`
531
- })
532
- },
533
- {
534
- path: `${source}/${tag}RbacCallback_HdrSqs.js`,
535
- content: await renderShared('FlowHandler_HdrSqs.ejs', {
536
- flowTag: flow.flowTag,
537
- flowStepName: 'RbacCallback',
538
- mainFileName: `${tag}RbacCallback_Main`,
539
- functionName: `${tag}RbacCallbackMain`,
540
- queueName: `${tag}RbacCallbackHdrSqs`,
541
- startConfig: rbacConfig
542
- })
543
- }
544
- );
545
- ownFunctions.push(
546
- renderSqsFunctionYaml({
547
- functionName: `${tag}RbacCallbackHdrSqs`,
548
- handlerPath: `${handlerRoot}/${tag}RbacCallback_HdrSqs.main`,
549
- roleName: customFlowRoleName(flow.flowTag),
550
- queueName: `${tag}RbacCallbackHdrSqs`,
551
- flowTag: flow.flowTag,
552
- flowStepName: 'RbacCallback'
553
- })
554
- );
555
- }
556
-
557
- return {
558
- artifacts: ownArtifacts,
559
- functions: ownFunctions
560
- };
561
- }
562
-
563
- function ownTopicRootPaths(flow, objects = []) {
564
- const tag = upperFirst(flow.flowTag);
565
- const source = `app/src/generatedCode/FlowSchemas/${tag}/source`;
566
- const paths = [
567
- `${source}/${tag}_Main.js`,
568
- `${source}/${tag}_HdrSqs.js`,
569
- `${source}/${tag}_WbsMain.js`,
570
- `${source}/${tag}_HdrWbs.js`
571
- ];
572
- if (flowHasRbac(flow, objects)) {
573
- paths.push(
574
- `${source}/${tag}RbacCallback_Main.js`,
575
- `${source}/${tag}RbacCallback_HdrSqs.js`
576
- );
577
- }
578
- return paths;
579
- }
580
-
581
- function needsProcessMain(flow) {
582
- return (
583
- !isS3Only(flow) &&
584
- !flow.event.includes('ownTopic') &&
585
- flow.event.some((event) => event !== 'ownTopic' && event !== 's3')
586
- );
587
- }
588
-
589
- async function emitS3Flow(flow, source, handlerRoot) {
590
- const tag = upperFirst(flow.flowTag);
591
- const roleName = customFlowRoleName(flow.flowTag);
592
- const parts = [
593
- {
594
- action: 'CreateObject',
595
- handler: 'HdrWbs',
596
- type: 'wbs',
597
- mainTemplate: 'CreateObject_Main.ejs',
598
- handlerTemplate: 'CreateObject_HdrWbs.ejs'
599
- },
600
- {
601
- action: 'ReservedLimit',
602
- handler: 'HdrSqs',
603
- type: 'sqs',
604
- mainTemplate: 'ReservedLimit_Main.ejs',
605
- handlerTemplate: 'ReservedLimit_HdrSqs.ejs'
606
- },
607
- {
608
- action: 'CreatePreSignUrl',
609
- handler: 'HdrSqs',
610
- type: 'sqs',
611
- mainTemplate: 'CreatePreSignUrl_Main.ejs',
612
- handlerTemplate: 'CreatePreSignUrl_HdrSqs.ejs'
613
- },
614
- {
615
- action: 'ProcessAfterUpload',
616
- handler: 'HdrS3',
617
- type: 's3',
618
- mainTemplate: 'ProcessS3File_Main.ejs',
619
- handlerTemplate: 'FlowHandler_HdrS3.ejs'
620
- },
621
- {
622
- action: 'ConfirmAfterUpload',
623
- handler: 'HdrSqs',
624
- type: 'sqs',
625
- mainTemplate: 'ConfirmReserved_Main.ejs',
626
- handlerTemplate: 'ConfirmReserved_HdrSqs.ejs'
627
- }
628
- ];
629
- const emitted = await Promise.all(
630
- parts.map(
631
- async ({ action, handler, type, mainTemplate, handlerTemplate }) => {
632
- const functionName = `${tag}${action}`;
633
- const mainFileName = `${functionName}_Main`;
634
- const handlerFileName = `${functionName}_${handler}`;
635
- const mainContent = await renderCustom(
636
- `s3/${mainTemplate}`,
637
- _s3TemplateData({ action, flow, functionName })
638
- );
639
- const handlerContent = await renderCustom(
640
- `s3/${handlerTemplate}`,
641
- _s3HandlerData({ action, flow, functionName, mainFileName, handler })
642
- );
643
- const descriptor = {
644
- functionName: `${functionName}${handler}`,
645
- handlerPath: `${handlerRoot}/${handlerFileName}.main`,
646
- roleName
647
- };
648
- let functionYaml;
649
- if (type === 'wbs') {
650
- functionYaml = renderWbsFunctionYaml({
651
- ...descriptor,
652
- routeName: tag,
653
- flowTag: flow.flowTag,
654
- flowStepName: ''
655
- });
656
- } else if (type === 'sqs') {
657
- let filterPatternFunctionName = descriptor.functionName;
658
- if (action === 'CreatePreSignUrl') {
659
- filterPatternFunctionName = 'CreatePresignUrlHdrSqs';
660
- }
661
- functionYaml = renderSqsFunctionYaml({
662
- ...descriptor,
663
- queueName: descriptor.functionName,
664
- flowTag: flow.flowTag,
665
- flowStepName: '',
666
- filterPatternFunctionName
667
- });
668
- } else if (type === 's3') {
669
- let bucketName = '';
670
- if (flow.bucketName) {
671
- bucketName = flow.bucketName;
672
- }
673
- functionYaml = renderS3FunctionYaml({
674
- ...descriptor,
675
- bucketName,
676
- flowTag: flow.flowTag,
677
- flowStepName: ''
678
- });
679
- } else {
680
- functionYaml = renderInvFunctionYaml({
681
- ...descriptor,
682
- flowTag: flow.flowTag,
683
- flowStepName: ''
684
- });
685
- }
686
- return {
687
- artifacts: [
688
- { path: `${source}/${mainFileName}.js`, content: mainContent },
689
- { path: `${source}/${handlerFileName}.js`, content: handlerContent }
690
- ],
691
- functionYaml
692
- };
693
- }
694
- )
695
- );
696
- return {
697
- artifacts: emitted.flatMap((item) => item.artifacts),
698
- functions: emitted.map((item) => item.functionYaml)
699
- };
700
- }
701
-
702
- function _s3TemplateData({ action, flow, functionName }) {
703
- if (action === 'CreateObject') {
704
- return {
705
- flowTag: flow.flowTag,
706
- objectType: flow.objType?.objectType,
707
- functionName
708
- };
709
- }
710
- if (action === 'CreatePreSignUrl') {
711
- return { flowTag: flow.flowTag };
712
- }
713
- return { flowTag: flow.flowTag, functionName };
714
- }
715
-
716
- function _s3HandlerData({ action, flow, functionName, mainFileName, handler }) {
717
- if (action === 'CreateObject') {
718
- return { functionName, handlerType: handler, route: flow.flowTag };
719
- }
720
- if (action === 'ProcessAfterUpload') {
721
- let bucketName = '';
722
- if (flow.bucketName) {
723
- bucketName = flow.bucketName;
724
- }
725
- return {
726
- flowTag: flow.flowTag,
727
- functionName,
728
- mainFileName,
729
- s3Bucket: bucketName
730
- };
731
- }
732
- return { functionName, handlerType: handler };
733
- }
734
-
735
- function _startConfig(flow) {
736
- const steps = flow.flowSteps ?? [];
737
- const start =
738
- steps.find(
739
- (s) =>
740
- typeof s?.stepName === 'string' &&
741
- s.stepName.toLowerCase() === 'inprocess'
742
- ) ??
743
- steps.find(
744
- (s) =>
745
- typeof s?.stepName === 'string' && s.stepName.toLowerCase() === 'start'
746
- ) ??
747
- steps[0];
748
- if (start) {
749
- return stepConfig(flow, start);
750
- }
751
- return null;
752
- }
753
-
754
- function stepConfig(flow, step) {
755
- return {
756
- ...step,
757
- properties: mapFields(step.properties, flow.stepProperties),
758
- messageAttributes: mapFields(
759
- step.messageAttributes,
760
- flow.stepMessageAttributes
761
- )
762
- };
763
- }
764
-
765
- function mapFields(items = [], definitions = {}) {
766
- return items.map((item) => {
767
- if (typeof item === 'string') {
768
- const def = definitions?.[item] ?? {};
769
- return {
770
- propertyName: item,
771
- required: def.required ?? false,
772
- ...def
773
- };
774
- }
775
- if (typeof item === 'object' && item !== null) {
776
- const name = item.key ?? item.propertyName;
777
- const def = definitions?.[name] ?? {};
778
- return {
779
- propertyName: name,
780
- required: item.required ?? def.required ?? false,
781
- ...def,
782
- ...item
783
- };
784
- }
785
- return item;
786
- });
787
- }
788
-
789
- function isS3Only(flow) {
790
- return flow.event.length === 1 && flow.event[0] === 's3';
791
- }
792
-
793
- async function renderEndpointMain(flow, functionName, objects = []) {
794
- const isRbac = flowHasRbac(flow, objects);
795
- const matchedObject = objects.find(
796
- (o) => o.objectType === flow.objType?.objectType
797
- );
798
- let rbacServiceTag = null;
799
- if (matchedObject) {
800
- const belongTo = matchedObject.belongTo;
801
- if (belongTo) {
802
- rbacServiceTag = Array.isArray(belongTo)
803
- ? belongTo[0]?.serviceTag
804
- : belongTo?.serviceTag;
805
- }
806
- }
807
- if (!rbacServiceTag) {
808
- rbacServiceTag = flow.objType?.serviceTag || flow.serviceTag || 'Rbac';
809
- }
810
-
811
- const enrichedFlow = {
812
- ...flow,
813
- isRbac
814
- };
815
-
816
- return renderCustom('FlowEndpoint_Main.ejs', {
817
- flow: enrichedFlow,
818
- flowTag: flow.flowTag,
819
- upperCaseFlowTag: upperFirst(flow.flowTag),
820
- functionName,
821
- rbacServiceTag,
822
- tableName: storedCacheTableName(flow, objects),
823
- startConfig: _startConfig(flow)
824
- });
825
- }
826
-
827
- function storedCacheTableName(flow, objects) {
828
- if (flow.statusType !== 'storedCache') return null;
829
- const candidates = objects.filter(
830
- (object) => object.objectType === flow.objType?.objectType
831
- );
832
- const object = flow.objType?.serviceTag
833
- ? (candidates.find(
834
- (object) => object.serviceTag === flow.objType.serviceTag
835
- ) ?? candidates.find((object) => object.serviceTag === undefined))
836
- : candidates[0];
837
- return (
838
- Object.values(object?.storageResources ?? {}).find(
839
- (resource) =>
840
- resource?.storageType === 'dynamo' ||
841
- resource?.storageType === 'dynamoDB' ||
842
- !resource?.storageType
843
- )?.tableName ?? null
844
- );
845
- }
846
-
847
- async function renderStepMain(functionName, startConfig = null) {
848
- return renderCustom('FlowStep_Main.ejs', { functionName, startConfig });
849
- }
850
-
851
- function renderMain(functionName) {
852
- return `export default async function ${functionName}(_izContext, requestParams, callingFlowConfig = {}) {\n try {\n _izContext?.logger?.debug('${functionName} requestParams', requestParams);\n //(<endpointHook>)\n //(</endpointHook>)\n } catch (error) {\n _izContext?.logger?.error('${functionName} failed', error);\n throw error;\n }\n}\n`;
853
- }
854
-
855
- async function render(templateName, data) {
856
- return ejsLib.render(
857
- await readFile(new URL(templateName, TEMPLATE_URL), 'utf8'),
858
- data
859
- );
860
- }
861
-
862
- async function renderShared(templateName, data) {
863
- return ejsLib.render(
864
- await readFile(new URL(templateName, SHARED_TEMPLATE_URL), 'utf8'),
865
- data
866
- );
867
- }
868
-
869
- async function renderCrudTemplate(templateName, data) {
870
- return ejsLib.render(
871
- await readFile(new URL(templateName, TEMPLATE_URL), 'utf8'),
872
- data
873
- );
874
- }
875
-
876
- async function renderDsq(templateName, data) {
877
- return ejsLib.render(
878
- await readFile(new URL(templateName, SHARED_TEMPLATE_URL), 'utf8'),
879
- data
880
- );
881
- }
882
-
883
- async function renderCustom(templateName, data) {
884
- return ejsLib
885
- .render(
886
- await readFile(new URL(templateName, CUSTOM_TEMPLATE_URL), 'utf8'),
887
- data
888
- )
889
- .replace(/\n$/, '');
890
- }