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

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 (36) hide show
  1. package/package.json +7 -10
  2. package/src/compile/flowValidator.js +6 -0
  3. package/src/compile/loadSchemas.js +195 -69
  4. package/src/emit/coreFunction/templates/UploadSchema_Main.ejs +2 -2
  5. package/src/emit/crud/generateCrudApplicationArtifacts.js +15 -17
  6. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +16 -21
  7. package/src/emit/crud/loadLocalSchemaArrays.js +4 -8
  8. package/src/emit/custom/customFlowPaths.js +149 -0
  9. package/src/emit/custom/customFlowS3.js +156 -0
  10. package/src/emit/custom/customFlowSteps.js +385 -0
  11. package/src/emit/custom/customFlowTemplates.js +28 -0
  12. package/src/emit/custom/customFlows.js +48 -19
  13. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +57 -692
  14. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +27 -25
  15. package/src/emit/error/emitErrorSchemas.js +73 -0
  16. package/src/emit/error/templates/errorSchema.ejs +8 -0
  17. package/src/emit/rbac/generateCreateTargetRoleHandler.js +11 -13
  18. package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +14 -18
  19. package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +16 -19
  20. package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +19 -19
  21. package/src/emit/resource/dynamoResourceArtifacts.js +18 -0
  22. package/src/emit/resource/emitResourceArtifacts.js +13 -1247
  23. package/src/emit/resource/generateResourceArtifacts.js +20 -20
  24. package/src/emit/resource/iamResourceArtifacts.js +612 -0
  25. package/src/emit/resource/resourceState.js +564 -0
  26. package/src/emit/resource/resourceTemplate.js +30 -0
  27. package/src/emit/resource/s3ResourceArtifacts.js +14 -0
  28. package/src/emit/resource/sqsResourceArtifacts.js +113 -0
  29. package/src/emit/shared/runSubsystemGeneration.js +55 -0
  30. package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
  31. package/src/generate.js +37 -4
  32. package/test/crudApplicationArtifacts.test.js +72 -0
  33. package/test/customFlowApplicationArtifacts.test.js +98 -0
  34. package/test/errorSchemas.test.js +154 -0
  35. package/test/publicApi.test.js +1 -1
  36. package/test/resourceArtifacts.test.js +99 -0
@@ -1,29 +1,29 @@
1
- import { buildGenerationPlan } from '../../plan/buildGenerationPlan.js';
2
- import { commitArtifacts } from '../../output/commitArtifacts.js';
3
- import { compileProject } from '../../compile/compileProject.js';
4
1
  import { loadLocalSchemaDirectory } from '../../compile/loadSchemas.js';
2
+ import { runSubsystemGeneration } from '../shared/runSubsystemGeneration.js';
5
3
  import {
6
4
  emitResourceArtifacts,
7
5
  resourceArtifactPaths
8
6
  } from './emitResourceArtifacts.js';
9
7
 
10
8
  export async function generateResourceArtifacts(rootPath, options = {}) {
11
- const project = compileProject({ ...options, rootPath });
12
- const [objects, relationships, flows] = await Promise.all([
13
- loadLocalSchemaDirectory(project, 'ObjectSchemas'),
14
- loadLocalSchemaDirectory(project, 'RelationshipSchemas'),
15
- loadLocalSchemaDirectory(project, 'FlowSchemas')
16
- ]);
17
- const artifacts = await emitResourceArtifacts({
18
- objects,
19
- relationships,
20
- flows
9
+ return await runSubsystemGeneration({
10
+ rootPath,
11
+ options,
12
+ loadInputs: async (project) => {
13
+ const [objects, relationships, flows] = await Promise.all([
14
+ loadLocalSchemaDirectory(project, 'ObjectSchemas'),
15
+ loadLocalSchemaDirectory(project, 'RelationshipSchemas'),
16
+ loadLocalSchemaDirectory(project, 'FlowSchemas')
17
+ ]);
18
+ return { objects, relationships, flows };
19
+ },
20
+ emitArtifacts: ({ objects, relationships, flows }) =>
21
+ emitResourceArtifacts({
22
+ objects,
23
+ relationships,
24
+ flows
25
+ }),
26
+ managedScope: 'shared-resources',
27
+ resolveManagedPaths: resourceArtifactPaths
21
28
  });
22
- const files = await commitArtifacts(
23
- buildGenerationPlan(project, artifacts, {
24
- managedPaths: resourceArtifactPaths,
25
- managedScope: 'shared-resources'
26
- })
27
- );
28
- return { project, files };
29
29
  }
@@ -0,0 +1,612 @@
1
+ import { renderResourceTemplate } from './resourceTemplate.js';
2
+ import { CRUD_ACTIONS } from '../crud/crudActionPlan.js';
3
+ import {
4
+ customFlowRoleName,
5
+ flowDsqSteps,
6
+ flowExtTopicSteps,
7
+ flowHasRbac
8
+ } from '../custom/customFlows.js';
9
+ import {
10
+ RELATIONSHIP_ACTIONS,
11
+ RBAC_ACTIONS,
12
+ RBAC_TABLES,
13
+ rbacFlowQueueNames,
14
+ includesEvent,
15
+ flowHasOwnTopic,
16
+ upperFirst
17
+ } from './resourceState.js';
18
+
19
+ export const DYNAMO_ACTIONS = [
20
+ 'dynamodb:DeleteItem',
21
+ 'dynamodb:GetItem',
22
+ 'dynamodb:PutItem',
23
+ 'dynamodb:Query',
24
+ 'dynamodb:UpdateItem'
25
+ ];
26
+
27
+ export const SQS_CONSUMER_ACTIONS = [
28
+ 'sqs:DeleteMessage',
29
+ 'sqs:GetQueueAttributes',
30
+ 'sqs:ReceiveMessage'
31
+ ];
32
+
33
+ export const SQS_DLQ_ACTIONS = [
34
+ 'sqs:DeleteMessage',
35
+ 'sqs:GetQueueAttributes',
36
+ 'sqs:ReceiveMessage',
37
+ 'sqs:SendMessage'
38
+ ];
39
+
40
+ export const LEGACY_PROCESS_QUEUES = [
41
+ 'FindDataHdrSqs',
42
+ 'ProcessLogicalHdrSqs',
43
+ 'PaginateProcessLogicalHdrDsq',
44
+ 'PaginateProcessLogicalHdrSqs'
45
+ ];
46
+
47
+ export async function renderIam(state) {
48
+ const roles = ['ProcFindDataRole', 'RegisterRole'];
49
+ if (state.crud) {
50
+ roles.push('FlowObjectsRole');
51
+ }
52
+ if (state.relationships) {
53
+ roles.push('FlowRelationshipRole');
54
+ }
55
+ if (state.selfRbac) {
56
+ roles.push('FlowRbacRole');
57
+ }
58
+ if (state.websocket) {
59
+ roles.push('WebSocketMainRole');
60
+ }
61
+ roles.push(...state.customRoles);
62
+ const sortedRoles = roles.sort();
63
+ return {
64
+ iamContent: await renderResourceTemplate('SharedResource_Yaml.ejs', {
65
+ roles: sortedRoles.map((roleName) => ({
66
+ roleName,
67
+ statements: roleStatements(state, roleName)
68
+ }))
69
+ }),
70
+ roleNameConfigContent: renderRoleNameConfigYaml(sortedRoles)
71
+ };
72
+ }
73
+
74
+ export function getRbacValidatorServiceTags(state) {
75
+ const tags = new Set();
76
+ for (const obj of state.objects || []) {
77
+ const targets = obj?.belongTo
78
+ ? Array.isArray(obj.belongTo)
79
+ ? obj.belongTo
80
+ : [obj.belongTo]
81
+ : [];
82
+ for (const target of targets) {
83
+ if (target?.serviceTag && target.serviceTag !== 'Rbac') {
84
+ tags.add(target.serviceTag);
85
+ }
86
+ }
87
+ if (
88
+ obj.belongToSchema?.serviceTag &&
89
+ obj.belongToSchema.serviceTag !== 'Rbac'
90
+ ) {
91
+ tags.add(obj.belongToSchema.serviceTag);
92
+ }
93
+ }
94
+ return Array.from(tags).sort();
95
+ }
96
+
97
+ export async function renderLambdaRoleConfig(state) {
98
+ const s3Flows = state.flows
99
+ .filter((flow) => includesEvent(flow, 's3'))
100
+ .map((flow) => ({
101
+ roleName: upperFirst(flow.flowTag)
102
+ }));
103
+ const rbacValidatorServiceTags = getRbacValidatorServiceTags(state);
104
+ return renderResourceTemplate('GeneratedLambdaRoleServiceConfig.ejs', {
105
+ crud: state.crud,
106
+ relationships: state.relationships,
107
+ rbac: state.rbac,
108
+ rbacValidatorServiceTags,
109
+ objectGraphServiceTags: state.objectGraphServiceTags,
110
+ s3Flows
111
+ });
112
+ }
113
+
114
+ export function roleStatements(state, roleName) {
115
+ const statements = [];
116
+ if (roleNeedsSchemaRead(state, roleName)) {
117
+ statements.push({
118
+ action: ['s3:GetObject'],
119
+ resource: ['arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}/*']
120
+ });
121
+ statements.push({
122
+ action: ['s3:ListBucket'],
123
+ resource: ['arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}']
124
+ });
125
+ }
126
+ addStatement(statements, dynamoActionsForRole(roleName), [
127
+ ...dynamoArns(roleTableNames(state, roleName)),
128
+ ...externalDynamoArns(roleExternalDynamoTables(state, roleName))
129
+ ]);
130
+ addStatement(
131
+ statements,
132
+ SQS_CONSUMER_ACTIONS,
133
+ queueArns(roleQueueNames(state, roleName))
134
+ );
135
+ addStatement(
136
+ statements,
137
+ SQS_DLQ_ACTIONS,
138
+ queueArns(roleDlqQueueNames(state, roleName))
139
+ );
140
+ addStatement(
141
+ statements,
142
+ ['sns:Publish'],
143
+ [
144
+ ...topicArns(roleTopicNames(state, roleName)),
145
+ ...roleExternalTopicArns(state, roleName)
146
+ ]
147
+ );
148
+ addStatement(
149
+ statements,
150
+ ['lambda:InvokeFunction'],
151
+ [
152
+ ...roleExternalLambdaArns(state, roleName),
153
+ ...roleHookLambdaArns(state, roleName)
154
+ ]
155
+ );
156
+ if (state.webSocketRoles.has(roleName)) {
157
+ statements.push({
158
+ action: ['execute-api:ManageConnections'],
159
+ resource: [
160
+ 'arn:aws:execute-api:${self:custom.iz_region}:${self:custom.iz_accountId}:*/*'
161
+ ]
162
+ });
163
+ }
164
+ return statements;
165
+ }
166
+
167
+ export function addStatement(statements, action, resource) {
168
+ if (resource.length > 0) {
169
+ statements.push({ action, resource });
170
+ }
171
+ }
172
+
173
+ export function roleNeedsSchemaRead(state, roleName) {
174
+ if (!roleName.endsWith('Role') || !roleName) {
175
+ return false;
176
+ }
177
+ return roleName !== 'FlowRbacRole' || state.selfRbac;
178
+ }
179
+
180
+ export function roleTableNames(state, roleName) {
181
+ if (roleName === 'RegisterRole') {
182
+ if (state.websocket) {
183
+ return ['WebSocketTask', 'RegisterRecords'];
184
+ }
185
+ return [];
186
+ }
187
+ if (roleName === 'WebSocketMainRole') {
188
+ return ['UserUploadRecords', 'WebSocketTask'];
189
+ }
190
+ if (roleName === 'FlowObjectsRole') {
191
+ const tables = [
192
+ ...state.objectTableNames,
193
+ 'AwaitingMultipleSteps',
194
+ 'AwaitingMultipleStepByPending',
195
+ 'WebSocketTask'
196
+ ];
197
+ if (state.selfRbac) {
198
+ tables.push(
199
+ 'Roles',
200
+ 'TargetRoles',
201
+ 'RolePermissions',
202
+ 'RoleUsers',
203
+ 'UserRoles',
204
+ 'RunningTotalUsage',
205
+ 'RunningTotalReservedUsage'
206
+ );
207
+ }
208
+ return tables;
209
+ }
210
+ if (roleName === 'FlowRelationshipRole') {
211
+ return [
212
+ ...state.objectTableNames,
213
+ ...state.relationshipTableNames,
214
+ 'AwaitingMultipleSteps',
215
+ 'AwaitingMultipleStepByPending',
216
+ 'WebSocketTask'
217
+ ];
218
+ }
219
+ if (roleName === 'FlowRbacRole') {
220
+ return RBAC_TABLES;
221
+ }
222
+ if (roleName === 'ProcFindDataRole') {
223
+ return [
224
+ ...state.objectTableNames,
225
+ ...state.relationshipTableNames,
226
+ 'FindDataMain',
227
+ 'LogicalResultsMain',
228
+ 'LogicalResultsData'
229
+ ];
230
+ }
231
+ const flow = state.flows.find(
232
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
233
+ );
234
+ if (!flow) {
235
+ return [];
236
+ }
237
+ const tables = [];
238
+ if (flowHasOwnTopic(flow) || includesEvent(flow, 's3')) {
239
+ tables.push('WebSocketTask');
240
+ }
241
+ if (includesEvent(flow, 's3')) {
242
+ tables.push('UserUploadRecords', 'ReservedDataMain');
243
+ }
244
+ if (flow.statusType === 'storedCache') {
245
+ const object = state.objectTablesByType.get(flow.objType?.objectType);
246
+ if (object) {
247
+ tables.push(object);
248
+ }
249
+ }
250
+ return [...new Set(tables)];
251
+ }
252
+
253
+ export function dynamoActionsForRole(roleName) {
254
+ if (roleName === 'ProcFindDataRole') {
255
+ return [
256
+ 'dynamodb:GetItem',
257
+ 'dynamodb:PutItem',
258
+ 'dynamodb:Query',
259
+ 'dynamodb:UpdateItem'
260
+ ];
261
+ }
262
+ if (roleName === 'WebSocketMainRole') {
263
+ return ['dynamodb:DeleteItem', 'dynamodb:PutItem', 'dynamodb:Query'];
264
+ }
265
+ if (roleName === 'FlowRbacRole' || roleName === 'FlowObjectsRole') {
266
+ return [...DYNAMO_ACTIONS, 'dynamodb:TransactWriteItems'];
267
+ }
268
+ return DYNAMO_ACTIONS;
269
+ }
270
+
271
+ export function roleQueueNames(state, roleName) {
272
+ if (roleName === 'ProcFindDataRole') {
273
+ return LEGACY_PROCESS_QUEUES;
274
+ }
275
+ if (roleName === 'WebSocketMainRole') {
276
+ if (state.websocket) {
277
+ return ['WebSocketCompleteHdrSqs'];
278
+ }
279
+ return [];
280
+ }
281
+ if (roleName === 'RegisterRole') {
282
+ if (state.websocket) {
283
+ return ['RegisterCompleteHdrSqs'];
284
+ }
285
+ return [];
286
+ }
287
+ if (roleName === 'FlowObjectsRole') {
288
+ return CRUD_ACTIONS.flatMap((action) => {
289
+ const plan = state.crudActionPlans[action];
290
+ if (!plan.outputTopic) return [];
291
+ return [
292
+ `${action}HdrSqs`,
293
+ ...(plan.hasCreateNodeCallback ? [`${action}NodeCallbackHdrSqs`] : []),
294
+ ...(plan.hasBeforeHookCallback
295
+ ? [`${action}BeforeHookCallbackHdrSqs`]
296
+ : []),
297
+ ...(plan.hasAfterHookCallback
298
+ ? [`${action}AfterHookCallbackHdrSqs`]
299
+ : []),
300
+ ...(plan.hasRbacCallback ? [`${action}RbacCallbackHdrSqs`] : []),
301
+ ...(plan.hasComplete ? [`${action}CompleteHdrSqs`] : [])
302
+ ];
303
+ });
304
+ }
305
+ if (roleName === 'FlowRelationshipRole') {
306
+ return [
307
+ ...RELATIONSHIP_ACTIONS.flatMap((action) => [
308
+ `${action}HdrSqs`,
309
+ `${action}CompleteHdrSqs`
310
+ ]),
311
+ 'GetRelationshipHdrDsq'
312
+ ];
313
+ }
314
+ if (roleName === 'FlowRbacRole') {
315
+ return [
316
+ ...RBAC_ACTIONS.map((action) => `${action}HdrSqs`),
317
+ ...rbacFlowQueueNames(state)
318
+ ];
319
+ }
320
+ const flow = state.flows.find(
321
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
322
+ );
323
+ if (!flow) {
324
+ return [];
325
+ }
326
+ const tag = upperFirst(flow.flowTag);
327
+ const queueList = [];
328
+ if (includesEvent(flow, 'extTopic')) {
329
+ queueList.push(`${tag}HdrSqs`);
330
+ }
331
+ if (flowHasOwnTopic(flow)) {
332
+ queueList.push(`${tag}HdrSqs`);
333
+ }
334
+ if (includesEvent(flow, 'dsq')) {
335
+ queueList.push(`${tag}HdrDsq`);
336
+ }
337
+ if (flowHasRbac(flow, state.objects)) {
338
+ queueList.push(`${tag}RbacCallbackHdrSqs`);
339
+ }
340
+ queueList.push(
341
+ ...flowExtTopicSteps([flow]).map(
342
+ ({ flowTag, stepName }) => `${flowTag}${stepName}HdrSqs`
343
+ )
344
+ );
345
+ queueList.push(
346
+ ...flowDsqSteps([flow]).map(
347
+ ({ flowTag, stepName }) => `${flowTag}${stepName}HdrDsq`
348
+ )
349
+ );
350
+ queueList.push(
351
+ ...state.sqsQueues.filter(
352
+ (queueName) => includesEvent(flow, 's3') && queueName.startsWith(tag)
353
+ )
354
+ );
355
+ if (flow.outputTopic) {
356
+ queueList.push(`${tag}CompleteHdrSqs`);
357
+ }
358
+ return queueList;
359
+ }
360
+
361
+ export function roleDlqQueueNames(state, roleName) {
362
+ const queues = roleQueueNames(state, roleName);
363
+ if (!Array.isArray(queues) || queues.length === 0) {
364
+ return [];
365
+ }
366
+ return queues.map((q) => (q.endsWith('DLQ') ? q : `${q}DLQ`));
367
+ }
368
+
369
+ export function roleTopicNames(state, roleName) {
370
+ if (roleName === 'ProcFindDataRole') {
371
+ return state.outTopics
372
+ .filter((topic) => topic === 'FindData')
373
+ .map((t) => `${t}_Out`);
374
+ }
375
+ if (roleName === 'FlowObjectsRole') {
376
+ const actions = state.outTopics.filter((topic) =>
377
+ CRUD_ACTIONS.includes(topic)
378
+ );
379
+ const topics = [];
380
+ for (const action of actions) {
381
+ if (action === 'Get') {
382
+ topics.push(`${action}_Out`);
383
+ } else {
384
+ topics.push(`${action}_In`, `${action}_Out`);
385
+ }
386
+ }
387
+ if (state.rbac) {
388
+ topics.push('ValidatorRbac_In');
389
+ }
390
+ for (const action of ['Create', 'Update', 'Delete']) {
391
+ const plan = state.crudActionPlans?.[action];
392
+ if (plan?.hasBeforeHookAsync) {
393
+ for (const hook of plan.beforeHooks) {
394
+ if (hook?.generatedCodeConfig?.invocationType === 'ownTopic') {
395
+ topics.push(`${upperFirst(hook.flowTag)}_In`);
396
+ }
397
+ }
398
+ }
399
+ if (plan?.hasAfterHookAsync) {
400
+ for (const hook of plan.afterHooks) {
401
+ if (hook?.generatedCodeConfig?.invocationType === 'ownTopic') {
402
+ topics.push(`${upperFirst(hook.flowTag)}_In`);
403
+ }
404
+ }
405
+ }
406
+ }
407
+ return [...new Set(topics)];
408
+ }
409
+ if (roleName === 'FlowRelationshipRole') {
410
+ const actions = state.outTopics.filter((topic) =>
411
+ RELATIONSHIP_ACTIONS.includes(topic)
412
+ );
413
+ const topics = [];
414
+ for (const action of actions) {
415
+ if (action === 'GetRelationship') {
416
+ topics.push(`${action}_Out`);
417
+ } else {
418
+ topics.push(`${action}_In`, `${action}_Out`);
419
+ }
420
+ }
421
+ if (state.rbac) {
422
+ topics.push('ValidatorRbac_In');
423
+ }
424
+ return topics;
425
+ }
426
+ if (roleName === 'FlowRbacRole') {
427
+ const actions = state.outTopics.filter((topic) =>
428
+ RBAC_ACTIONS.includes(topic)
429
+ );
430
+ const topics = [];
431
+ for (const action of actions) {
432
+ if (action.startsWith('List')) {
433
+ topics.push(`${action}_Out`);
434
+ } else {
435
+ topics.push(`${action}_In`, `${action}_Out`);
436
+ }
437
+ }
438
+ return topics;
439
+ }
440
+ const flow = state.flows.find(
441
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
442
+ );
443
+ if (flow && flow.flowTag) {
444
+ const name = upperFirst(flow.flowTag);
445
+ const topics = [];
446
+ if (state.outTopics.includes(name)) {
447
+ topics.push(`${name}_Out`);
448
+ }
449
+ if (flowHasOwnTopic(flow)) {
450
+ topics.push(`${name}_In`);
451
+ }
452
+ return topics;
453
+ }
454
+ return [];
455
+ }
456
+
457
+ export function dynamoArns(tableNames) {
458
+ return [...new Set(tableNames)]
459
+ .sort()
460
+ .map(
461
+ (tableName) =>
462
+ `arn:aws:dynamodb:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:table/${'${self:custom.iz_resourcePrefix}'}${tableName}`
463
+ );
464
+ }
465
+
466
+ export function externalDynamoArns(externalTables) {
467
+ const seen = new Set();
468
+ const unique = [];
469
+ for (const table of externalTables) {
470
+ const dedupeKey = `${table.serviceTag}::${table.tableName}`;
471
+ if (!seen.has(dedupeKey)) {
472
+ seen.add(dedupeKey);
473
+ unique.push(table);
474
+ }
475
+ }
476
+ return unique
477
+ .sort((a, b) =>
478
+ `${a.serviceTag}_${a.tableName}`.localeCompare(
479
+ `${b.serviceTag}_${b.tableName}`
480
+ )
481
+ )
482
+ .map(
483
+ ({ serviceTag, tableName }) =>
484
+ `arn:aws:dynamodb:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:table/${serviceTag}${'${self:custom.iz_stage}'}${tableName}`
485
+ );
486
+ }
487
+
488
+ export function roleExternalDynamoTables(state, roleName) {
489
+ if (
490
+ roleName === 'FlowObjectsRole' ||
491
+ roleName === 'FlowRelationshipRole' ||
492
+ roleName === 'ProcFindDataRole'
493
+ ) {
494
+ return state.externalDynamoTables;
495
+ }
496
+ return [];
497
+ }
498
+
499
+ export function roleExternalTopicArns(state, roleName) {
500
+ if (!state.rbac) {
501
+ return [];
502
+ }
503
+ const extraTags = getRbacValidatorServiceTags(state).filter(
504
+ (tag) => tag && tag !== 'Rbac'
505
+ );
506
+ const extraTopics = extraTags.map(
507
+ (tag) =>
508
+ `arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_ValidatorRbac_In`
509
+ );
510
+ if (roleName === 'FlowObjectsRole') {
511
+ return [
512
+ `arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
513
+ `arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ConfirmUsage_In`,
514
+ `arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_CancelUsage_In`,
515
+ ...extraTopics
516
+ ];
517
+ }
518
+ if (roleName === 'FlowRbacRole' || roleName === 'FlowRelationshipRole') {
519
+ return [
520
+ `arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
521
+ ...extraTopics
522
+ ];
523
+ }
524
+ return [];
525
+ }
526
+
527
+ export function roleExternalLambdaArns(state, roleName) {
528
+ if (!state.rbac) {
529
+ return [];
530
+ }
531
+ const extraTags = getRbacValidatorServiceTags(state).filter(
532
+ (tag) => tag && tag !== 'Rbac'
533
+ );
534
+ const extraLambdas = extraTags.map(
535
+ (tag) =>
536
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ValidatorRbacHdrInv`
537
+ );
538
+ if (roleName === 'FlowObjectsRole') {
539
+ return [
540
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ValidatorRbacHdrInv`,
541
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ConfirmUsageHdrInv`,
542
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}CancelUsageHdrInv`,
543
+ ...extraLambdas
544
+ ];
545
+ }
546
+ if (roleName === 'FlowRbacRole' || roleName === 'FlowRelationshipRole') {
547
+ return [
548
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ValidatorRbacHdrInv`,
549
+ ...extraLambdas
550
+ ];
551
+ }
552
+ return [];
553
+ }
554
+
555
+ export function roleHookLambdaArns(state, roleName) {
556
+ if (roleName !== 'FlowObjectsRole') {
557
+ return [];
558
+ }
559
+ const hookLambdas = [];
560
+ for (const action of ['Create', 'Update', 'Delete']) {
561
+ const plan = state.crudActionPlans?.[action];
562
+ if (plan?.hasBeforeHookSync) {
563
+ for (const hook of plan.beforeHooks) {
564
+ if (hook?.generatedCodeConfig?.invocationType === 'lambdaSyncInv') {
565
+ const hookTag = upperFirst(hook.flowTag);
566
+ hookLambdas.push(
567
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:\${self:custom.iz_resourcePrefix}${hookTag}*`
568
+ );
569
+ }
570
+ }
571
+ }
572
+ if (plan?.hasAfterHookSync) {
573
+ for (const hook of plan.afterHooks) {
574
+ if (hook?.generatedCodeConfig?.invocationType === 'lambdaSyncInv') {
575
+ const hookTag = upperFirst(hook.flowTag);
576
+ hookLambdas.push(
577
+ `arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:\${self:custom.iz_resourcePrefix}${hookTag}*`
578
+ );
579
+ }
580
+ }
581
+ }
582
+ }
583
+ return [...new Set(hookLambdas)];
584
+ }
585
+
586
+ export function queueArns(queueNames) {
587
+ return [...new Set(queueNames)]
588
+ .sort()
589
+ .map(
590
+ (queueName) =>
591
+ `arn:aws:sqs:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_resourcePrefix}'}${queueName}`
592
+ );
593
+ }
594
+
595
+ export function topicArns(topicNames) {
596
+ return [...new Set(topicNames)]
597
+ .sort()
598
+ .map(
599
+ (topic) =>
600
+ `arn:aws:sns:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_serviceTag}'}_${'${self:custom.iz_stage}'}_${topic}`
601
+ );
602
+ }
603
+
604
+ export function renderRoleNameConfigYaml(roles) {
605
+ return [
606
+ '# for createIamRole',
607
+ ...roles.map(
608
+ (roleName) =>
609
+ `- arn:aws:iam::\${self:custom.iz_accountId}:role/\${self:custom.iz_resourcePrefix}${roleName}`
610
+ )
611
+ ].join('\n');
612
+ }