@izara_project/izara-core-generate-service-code 1.0.77 → 1.0.79
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.
- package/package.json +2 -2
- package/src/compile/flowValidator.js +163 -0
- package/src/compile/loadSchemas.js +15 -5
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +137 -7
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +132 -17
- package/src/emit/crud/crudActionPlan.js +82 -0
- package/src/emit/crud/emitCrudApplicationArtifacts.js +162 -112
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +43 -65
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +84 -512
- package/src/emit/crud/templates/CreateLogicalLib.ejs +536 -0
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +87 -202
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +213 -0
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +217 -0
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +1 -1
- package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +9 -2
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +87 -444
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +472 -0
- package/src/emit/custom/customFlows.js +27 -2
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +1 -2
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +10 -3
- package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
- package/src/emit/custom/templates/s3/CreateObject_Main.ejs +1 -1
- package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +2 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +3 -9
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -16
- package/src/emit/rbac/rbacFlowTag.js +2 -7
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +148 -21
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +4 -2
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +1 -1
- package/src/emit/resource/emitResourceArtifacts.js +85 -70
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +31 -5
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +21 -0
- package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
- package/src/emit/shared/templates/FlowHandler_HdrApi.ejs +1 -1
- package/src/emit/shared/templates/FlowHandler_HdrDsq.ejs +2 -2
- package/src/emit/shared/templates/FlowHandler_HdrInv.ejs +1 -1
- package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +2 -2
- package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -2
- package/src/emit/system/templates/RegisterComplete_Yaml.ejs +4 -4
- package/src/emit/systemText/emitSystemTextSchemas.js +246 -0
- package/src/emit/systemText/templates/SystemTextSchemas.ejs +10 -0
- package/src/generate.js +55 -8
- package/test/crudApplicationArtifacts.test.js +147 -19
- package/test/customFlowApplicationArtifacts.test.js +308 -16
- package/test/dynamicCrudFlowSchemas.test.js +150 -14
- package/test/dynamicRbacFlowSchemas.test.js +2 -2
- package/test/dynamicRelationshipFlowSchemas.test.js +1 -1
- package/test/graphDrivenFlowSchema.test.js +257 -0
- package/test/publicApi.test.js +15 -6
- package/test/resourceArtifacts.test.js +25 -19
- package/test/systemTextSchemas.test.js +154 -0
- package/src/emit/crud/templates/CreateComplete_HdrSqs.ejs +0 -99
- package/src/emit/crud/templates/DeleteComplete_HdrSqs.ejs +0 -99
- package/src/emit/crud/templates/FlowEndpointBeforeLogical_Main.ejs +0 -174
- package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +0 -187
- package/src/emit/crud/templates/UpdateComplete_HdrSqs.ejs +0 -99
- package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +0 -47
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izara_project/izara-core-generate-service-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.79",
|
|
4
4
|
"description": "Code for locally generating per service files",
|
|
5
5
|
"homepage": "https://bitbucket.org/izara-core-support-services/izara-core-support-services-generate-service-code#readme",
|
|
6
6
|
"repository": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"exports": "./index.js",
|
|
14
14
|
"main": "index.js",
|
|
15
15
|
"scripts": {
|
|
16
|
-
"test": "
|
|
16
|
+
"test": "node --test",
|
|
17
17
|
"format:ejs": "node scripts/format-ejs.js"
|
|
18
18
|
},
|
|
19
19
|
"jest": {
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export function validateFlowSchema(flowSchema) {
|
|
2
|
+
if (!flowSchema || typeof flowSchema !== 'object') {
|
|
3
|
+
throw new TypeError('flowSchema must be an object');
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const steps = flowSchema.flowSteps;
|
|
7
|
+
if (!Array.isArray(steps) || steps.length === 0) {
|
|
8
|
+
throw new Error(
|
|
9
|
+
'FlowSchema validation error: flowSteps must be a non-empty array'
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const entryStep = steps[0];
|
|
14
|
+
if (
|
|
15
|
+
!entryStep ||
|
|
16
|
+
typeof entryStep !== 'object' ||
|
|
17
|
+
entryStep.stepName !== 'Start'
|
|
18
|
+
) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"FlowSchema validation error: Entry step flowSteps[0] must have stepName fixed to 'Start'"
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (
|
|
25
|
+
entryStep.previousSteps &&
|
|
26
|
+
Array.isArray(entryStep.previousSteps) &&
|
|
27
|
+
entryStep.previousSteps.length > 0
|
|
28
|
+
) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"FlowSchema validation error: Entry step flowSteps[0] must not define 'previousSteps'"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (entryStep.event) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
"FlowSchema validation error: Entry step flowSteps[0] must not define step-level 'event'"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (let idx = 0; idx < steps.length; idx++) {
|
|
41
|
+
const step = steps[idx];
|
|
42
|
+
if (!step || typeof step !== 'object') {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`FlowSchema validation error: flowSteps[${idx}] must be an object`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (Array.isArray(step.nextSteps) && step.nextSteps.length > 0) {
|
|
49
|
+
for (let nIdx = 0; nIdx < step.nextSteps.length; nIdx++) {
|
|
50
|
+
const item = step.nextSteps[nIdx];
|
|
51
|
+
if (!item || typeof item !== 'object') {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] must be an object`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (
|
|
57
|
+
item.targetType !== 'ownTopic' &&
|
|
58
|
+
item.targetType !== 'extTopic' &&
|
|
59
|
+
item.targetType !== 'lambdaSyncInv'
|
|
60
|
+
) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] must have targetType ('ownTopic' | 'extTopic' | 'lambdaSyncInv')`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (item.targetType === 'ownTopic') {
|
|
66
|
+
if (
|
|
67
|
+
typeof item.stepName !== 'string' ||
|
|
68
|
+
item.stepName.trim() === ''
|
|
69
|
+
) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] ownTopic target requires non-empty 'stepName'`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
} else if (item.targetType === 'extTopic') {
|
|
75
|
+
if (
|
|
76
|
+
typeof item.serviceTag !== 'string' ||
|
|
77
|
+
item.serviceTag.trim() === ''
|
|
78
|
+
) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] extTopic target requires non-empty 'serviceTag'`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
if (
|
|
84
|
+
typeof item.topicName !== 'string' ||
|
|
85
|
+
item.topicName.trim() === ''
|
|
86
|
+
) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] extTopic target requires non-empty 'topicName'`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (
|
|
92
|
+
!Array.isArray(item.toStepNames) ||
|
|
93
|
+
item.toStepNames.length === 0
|
|
94
|
+
) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] extTopic target requires non-empty 'toStepNames' array`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
} else if (item.targetType === 'lambdaSyncInv') {
|
|
100
|
+
const fnName = item.functionName || item.topicName || item.topic;
|
|
101
|
+
if (typeof fnName !== 'string' || fnName.trim() === '') {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`FlowSchema validation error: flowSteps[${idx}].nextSteps[${nIdx}] lambdaSyncInv target requires non-empty 'functionName'`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (Array.isArray(step.previousSteps) && step.previousSteps.length > 0) {
|
|
111
|
+
for (let pIdx = 0; pIdx < step.previousSteps.length; pIdx++) {
|
|
112
|
+
const item = step.previousSteps[pIdx];
|
|
113
|
+
if (!item || typeof item !== 'object') {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`FlowSchema validation error: flowSteps[${idx}].previousSteps[${pIdx}] must be an object`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (item.sourceType !== 'ownTopic' && item.sourceType !== 'extTopic') {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`FlowSchema validation error: flowSteps[${idx}].previousSteps[${pIdx}] must have sourceType ('ownTopic' | 'extTopic')`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
if (item.sourceType === 'ownTopic') {
|
|
124
|
+
if (
|
|
125
|
+
typeof item.stepName !== 'string' ||
|
|
126
|
+
item.stepName.trim() === ''
|
|
127
|
+
) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`FlowSchema validation error: flowSteps[${idx}].previousSteps[${pIdx}] ownTopic source requires non-empty 'stepName'`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
} else if (item.sourceType === 'extTopic') {
|
|
133
|
+
if (
|
|
134
|
+
typeof item.serviceTag !== 'string' ||
|
|
135
|
+
item.serviceTag.trim() === ''
|
|
136
|
+
) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`FlowSchema validation error: flowSteps[${idx}].previousSteps[${pIdx}] extTopic source requires non-empty 'serviceTag'`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (
|
|
142
|
+
typeof item.topicName !== 'string' ||
|
|
143
|
+
item.topicName.trim() === ''
|
|
144
|
+
) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`FlowSchema validation error: flowSteps[${idx}].previousSteps[${pIdx}] extTopic source requires non-empty 'topicName'`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (
|
|
150
|
+
!Array.isArray(item.fromStepNames) ||
|
|
151
|
+
item.fromStepNames.length === 0
|
|
152
|
+
) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`FlowSchema validation error: flowSteps[${idx}].previousSteps[${pIdx}] extTopic source requires non-empty 'fromStepNames' array`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from '@izara_project/izara-core-library-service-schemas';
|
|
8
8
|
import { s3 } from '@izara_project/izara-core-library-s3';
|
|
9
9
|
import Logger from '@izara_project/izara-core-library-logger';
|
|
10
|
+
import { validateFlowSchema } from './flowValidator.js';
|
|
10
11
|
|
|
11
12
|
export async function loadLocalSchemaDirectory(project, directoryName) {
|
|
12
13
|
const directoryPath = join(project.schemaRoot, directoryName);
|
|
@@ -42,6 +43,16 @@ export async function loadLocalSchemaDirectory(project, directoryName) {
|
|
|
42
43
|
loadedSchemas = module.default;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
if (directoryName === 'FlowSchemas') {
|
|
47
|
+
for (const schema of loadedSchemas) {
|
|
48
|
+
if (Object.prototype.hasOwnProperty.call(schema?.generatedCodeConfig ?? {}, 'codeHookTag')) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Unsupported FlowHook configuration in ${entry.name}: generatedCodeConfig.codeHookTag is no longer supported`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
45
56
|
if (process.env.NODE_ENV && process.env.NODE_ENV !== 'test') {
|
|
46
57
|
for (const schema of loadedSchemas) {
|
|
47
58
|
let status = true;
|
|
@@ -69,6 +80,9 @@ export async function loadLocalSchemaDirectory(project, directoryName) {
|
|
|
69
80
|
{ logger: Logger },
|
|
70
81
|
schema
|
|
71
82
|
);
|
|
83
|
+
if (status) {
|
|
84
|
+
validateFlowSchema(schema);
|
|
85
|
+
}
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
if (!status) {
|
|
@@ -159,10 +173,7 @@ export async function resolveExtendedObjectSchemas(
|
|
|
159
173
|
}
|
|
160
174
|
}
|
|
161
175
|
|
|
162
|
-
if (
|
|
163
|
-
currentSchema.hasOwnProperty('belongTo') &&
|
|
164
|
-
currentSchema.belongTo
|
|
165
|
-
) {
|
|
176
|
+
if (currentSchema.hasOwnProperty('belongTo') && currentSchema.belongTo) {
|
|
166
177
|
const belongToTarget = Array.isArray(currentSchema.belongTo)
|
|
167
178
|
? currentSchema.belongTo[0]
|
|
168
179
|
: currentSchema.belongTo;
|
|
@@ -269,4 +280,3 @@ export async function resolveGraphServiceTags(
|
|
|
269
280
|
|
|
270
281
|
return Array.from(resolvedTags);
|
|
271
282
|
}
|
|
272
|
-
|
|
@@ -9,7 +9,44 @@ const SRC_ROOT = 'app/src/generatedCode/CoreFunctions';
|
|
|
9
9
|
const INITIAL_SETUP_ROOT = 'app/initial_setup/generatedCode/source';
|
|
10
10
|
const INITIAL_SETUP_DATA_ROOT = 'app/initial_setup/generatedCode/data';
|
|
11
11
|
|
|
12
|
-
function
|
|
12
|
+
function hasSelfRbacAddOn(object) {
|
|
13
|
+
return (
|
|
14
|
+
Array.isArray(object?.addOnDataStructure) &&
|
|
15
|
+
object.addOnDataStructure.some((addOn) => addOn?.type === 'rbac')
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function hasRbacAddOn(object, objects = []) {
|
|
20
|
+
const selfHasRbac = hasSelfRbacAddOn(object);
|
|
21
|
+
const belongToTargets = object?.belongTo
|
|
22
|
+
? Array.isArray(object.belongTo)
|
|
23
|
+
? object.belongTo
|
|
24
|
+
: [object.belongTo]
|
|
25
|
+
: [];
|
|
26
|
+
const belongToHasRbac =
|
|
27
|
+
(Array.isArray(object?.belongToSchema?.addOnDataStructure) &&
|
|
28
|
+
object.belongToSchema.addOnDataStructure.some(
|
|
29
|
+
(addOn) => addOn?.type === 'rbac'
|
|
30
|
+
)) ||
|
|
31
|
+
belongToTargets.some((target) => {
|
|
32
|
+
if (target?.serviceTag === 'UserAccount') return true;
|
|
33
|
+
const matched = objects.find(
|
|
34
|
+
(candidate) =>
|
|
35
|
+
candidate?.serviceTag === target?.serviceTag &&
|
|
36
|
+
candidate?.objectType === target?.objectType
|
|
37
|
+
);
|
|
38
|
+
return hasSelfRbacAddOn(matched);
|
|
39
|
+
});
|
|
40
|
+
return selfHasRbac || belongToHasRbac;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function _extractDynamoTableNames({
|
|
44
|
+
objects = [],
|
|
45
|
+
relationships = [],
|
|
46
|
+
flows = [],
|
|
47
|
+
rbac = false,
|
|
48
|
+
s3Flows = []
|
|
49
|
+
} = {}) {
|
|
13
50
|
const dynamoTableNames = new Set();
|
|
14
51
|
for (const obj of objects || []) {
|
|
15
52
|
if (obj && obj.storageResources) {
|
|
@@ -26,18 +63,95 @@ function _extractDynamoTableNames(objects = []) {
|
|
|
26
63
|
}
|
|
27
64
|
}
|
|
28
65
|
}
|
|
66
|
+
for (const rel of relationships || []) {
|
|
67
|
+
if (rel && rel.storageResources) {
|
|
68
|
+
for (const res of Object.values(rel.storageResources)) {
|
|
69
|
+
if (
|
|
70
|
+
res &&
|
|
71
|
+
res.tableName &&
|
|
72
|
+
(res.storageType === 'dynamo' ||
|
|
73
|
+
res.storageType === 'dynamoDB' ||
|
|
74
|
+
!res.storageType)
|
|
75
|
+
) {
|
|
76
|
+
dynamoTableNames.add(res.tableName);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const flow of flows || []) {
|
|
82
|
+
if (flow && flow.storageResources) {
|
|
83
|
+
for (const res of Object.values(flow.storageResources)) {
|
|
84
|
+
if (
|
|
85
|
+
res &&
|
|
86
|
+
res.tableName &&
|
|
87
|
+
(res.storageType === 'dynamo' ||
|
|
88
|
+
res.storageType === 'dynamoDB' ||
|
|
89
|
+
!res.storageType)
|
|
90
|
+
) {
|
|
91
|
+
dynamoTableNames.add(res.tableName);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (rbac) {
|
|
97
|
+
dynamoTableNames.add('TargetRoles');
|
|
98
|
+
dynamoTableNames.add('RolePermissions');
|
|
99
|
+
dynamoTableNames.add('RoleUsers');
|
|
100
|
+
dynamoTableNames.add('UserRoles');
|
|
101
|
+
dynamoTableNames.add('RbacPermissionCaches');
|
|
102
|
+
}
|
|
103
|
+
if ((s3Flows || []).length > 0) {
|
|
104
|
+
dynamoTableNames.add('ReservedDataMain');
|
|
105
|
+
}
|
|
29
106
|
return dynamoTableNames;
|
|
30
107
|
}
|
|
31
108
|
|
|
32
109
|
export function coreFunctionManagedPaths(
|
|
33
|
-
|
|
110
|
+
firstArg = [],
|
|
34
111
|
objectGraphServiceTags = [],
|
|
35
|
-
relationshipGraphServiceTags = []
|
|
112
|
+
relationshipGraphServiceTags = [],
|
|
113
|
+
relationships = [],
|
|
114
|
+
flows = [],
|
|
115
|
+
rbac = false
|
|
36
116
|
) {
|
|
37
|
-
|
|
117
|
+
let objects = [];
|
|
118
|
+
let objTags = objectGraphServiceTags;
|
|
119
|
+
let relTags = relationshipGraphServiceTags;
|
|
120
|
+
let rels = relationships;
|
|
121
|
+
let fls = flows;
|
|
122
|
+
let isRbac = rbac;
|
|
123
|
+
|
|
124
|
+
if (firstArg && typeof firstArg === 'object' && !Array.isArray(firstArg)) {
|
|
125
|
+
objects = firstArg.objects || [];
|
|
126
|
+
objTags = firstArg.objectGraphServiceTags || [];
|
|
127
|
+
relTags = firstArg.relationshipGraphServiceTags || [];
|
|
128
|
+
rels = firstArg.relationships || [];
|
|
129
|
+
fls = firstArg.flows || [];
|
|
130
|
+
isRbac =
|
|
131
|
+
firstArg.project?.rbac === true ||
|
|
132
|
+
(objects || []).some((o) => o.rbac === true) ||
|
|
133
|
+
(fls || []).some((f) => f.type === 'rbac');
|
|
134
|
+
} else {
|
|
135
|
+
objects = firstArg || [];
|
|
136
|
+
isRbac =
|
|
137
|
+
(objects || []).some((o) => o.rbac === true) ||
|
|
138
|
+
(fls || []).some((f) => f.type === 'rbac');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const s3Flows = (fls || []).filter(
|
|
142
|
+
(flow) => Array.isArray(flow?.event) && flow.event.includes('s3')
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
const dynamoTableNames = _extractDynamoTableNames({
|
|
146
|
+
objects,
|
|
147
|
+
relationships: rels,
|
|
148
|
+
flows: fls,
|
|
149
|
+
rbac: isRbac,
|
|
150
|
+
s3Flows
|
|
151
|
+
});
|
|
38
152
|
const graphTags = new Set([
|
|
39
|
-
...(
|
|
40
|
-
...(
|
|
153
|
+
...(objTags || []),
|
|
154
|
+
...(relTags || [])
|
|
41
155
|
]);
|
|
42
156
|
|
|
43
157
|
const paths = [
|
|
@@ -91,6 +205,14 @@ export async function emitCoreFunctionArtifacts({ project, objects = [], relatio
|
|
|
91
205
|
return { roleName };
|
|
92
206
|
});
|
|
93
207
|
|
|
208
|
+
const rbac =
|
|
209
|
+
project?.rbac === true ||
|
|
210
|
+
(objects || []).some((o) => hasRbacAddOn(o, objects)) ||
|
|
211
|
+
(flows || []).some((f) => f.type === 'rbac');
|
|
212
|
+
const rbacValidatorServiceTags = Array.from(new Set(
|
|
213
|
+
(objects || []).filter(o => o.belongTo?.serviceTag && o.belongTo.serviceTag !== 'Rbac').map(o => o.belongTo.serviceTag)
|
|
214
|
+
)).sort();
|
|
215
|
+
|
|
94
216
|
const state = {
|
|
95
217
|
project,
|
|
96
218
|
objects,
|
|
@@ -101,6 +223,8 @@ export async function emitCoreFunctionArtifacts({ project, objects = [], relatio
|
|
|
101
223
|
relationshipGraphServiceTags,
|
|
102
224
|
crud,
|
|
103
225
|
hasRelationships,
|
|
226
|
+
rbac,
|
|
227
|
+
rbacValidatorServiceTags,
|
|
104
228
|
s3Flows,
|
|
105
229
|
hasGenerateGraph: objects.length > 0 || relationships.length > 0
|
|
106
230
|
};
|
|
@@ -250,7 +374,13 @@ export async function emitCoreFunctionArtifacts({ project, objects = [], relatio
|
|
|
250
374
|
writeWhenFileExist: false
|
|
251
375
|
});
|
|
252
376
|
|
|
253
|
-
const dynamoTableNames = _extractDynamoTableNames(
|
|
377
|
+
const dynamoTableNames = _extractDynamoTableNames({
|
|
378
|
+
objects,
|
|
379
|
+
relationships,
|
|
380
|
+
flows,
|
|
381
|
+
rbac,
|
|
382
|
+
s3Flows
|
|
383
|
+
});
|
|
254
384
|
for (const tableName of dynamoTableNames) {
|
|
255
385
|
baseArtifacts.push({
|
|
256
386
|
path: `${INITIAL_SETUP_DATA_ROOT}/dynamo/test/${tableName}.json`,
|
|
@@ -26,12 +26,12 @@ const _izContext = { logger: Logger };
|
|
|
26
26
|
// ============================================================
|
|
27
27
|
// External Service Config
|
|
28
28
|
// ============================================================
|
|
29
|
-
//
|
|
29
|
+
//(<InitialSetupConfig_ExternalServices>)
|
|
30
30
|
const externalServices = {
|
|
31
31
|
serviceTagGraphHandler: 'GraphHandler',
|
|
32
32
|
serviceTagRbac: 'Rbac'
|
|
33
33
|
};
|
|
34
|
-
//
|
|
34
|
+
//(</InitialSetupConfig_ExternalServices>)
|
|
35
35
|
|
|
36
36
|
// ============================================================
|
|
37
37
|
// Table Configs (generated + manual merge)
|
|
@@ -47,39 +47,68 @@ const externalServices = {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
|
+
(relationships || []).forEach(rel => {
|
|
51
|
+
if (rel && rel.storageResources) {
|
|
52
|
+
Object.values(rel.storageResources).forEach(res => {
|
|
53
|
+
if (res && res.tableName && (res.storageType === 'dynamo' || res.storageType === 'dynamoDB' || !res.storageType)) {
|
|
54
|
+
dynamoTableNames.add(res.tableName);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
(flows || []).forEach(flow => {
|
|
60
|
+
if (flow && flow.storageResources) {
|
|
61
|
+
Object.values(flow.storageResources).forEach(res => {
|
|
62
|
+
if (res && res.tableName && (res.storageType === 'dynamo' || res.storageType === 'dynamoDB' || !res.storageType)) {
|
|
63
|
+
dynamoTableNames.add(res.tableName);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (typeof rbac !== 'undefined' && rbac) {
|
|
69
|
+
dynamoTableNames.add('TargetRoles');
|
|
70
|
+
dynamoTableNames.add('RolePermissions');
|
|
71
|
+
dynamoTableNames.add('RoleUsers');
|
|
72
|
+
dynamoTableNames.add('UserRoles');
|
|
73
|
+
}
|
|
74
|
+
if (typeof s3Flows !== 'undefined' && (s3Flows || []).length > 0) {
|
|
75
|
+
dynamoTableNames.add('ReservedDataMain');
|
|
76
|
+
}
|
|
50
77
|
-%>
|
|
51
78
|
const tableConfigs = {
|
|
52
79
|
prod: {
|
|
53
80
|
Config: {
|
|
54
|
-
//
|
|
55
|
-
//
|
|
81
|
+
//(<InitialSetupConfig_Prod_Config_TableConfig>)
|
|
82
|
+
//(</InitialSetupConfig_Prod_Config_TableConfig>)
|
|
56
83
|
},
|
|
57
84
|
<% dynamoTableNames.forEach(tableName => { -%>
|
|
58
85
|
<%= tableName %>: {
|
|
59
|
-
//
|
|
60
|
-
//
|
|
86
|
+
//(<InitialSetupConfig_Prod_<%= tableName %>_TableConfig>)
|
|
87
|
+
//(</InitialSetupConfig_Prod_<%= tableName %>_TableConfig>)
|
|
61
88
|
},
|
|
62
89
|
<% }); -%>
|
|
63
|
-
//
|
|
64
|
-
//
|
|
90
|
+
//(<InitialSetupConfig_ExtraProdTableConfigs>)
|
|
91
|
+
//(</InitialSetupConfig_ExtraProdTableConfigs>)
|
|
65
92
|
},
|
|
66
93
|
test: {
|
|
67
94
|
Config: {
|
|
68
|
-
//
|
|
95
|
+
//(<InitialSetupConfig_Test_Config_TableConfig>)
|
|
69
96
|
clearDataWhenRefresh: true,
|
|
70
97
|
rawSource: false
|
|
71
|
-
//
|
|
98
|
+
//(</InitialSetupConfig_Test_Config_TableConfig>)
|
|
72
99
|
},
|
|
73
100
|
<% dynamoTableNames.forEach(tableName => { -%>
|
|
74
101
|
<%= tableName %>: {
|
|
75
|
-
//
|
|
102
|
+
//(<InitialSetupConfig_Test_<%= tableName %>_TableConfig>)
|
|
76
103
|
clearDataWhenRefresh: true
|
|
77
|
-
//
|
|
104
|
+
//(</InitialSetupConfig_Test_<%= tableName %>_TableConfig>)
|
|
78
105
|
},
|
|
79
106
|
<% }); -%>
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
}
|
|
107
|
+
//(<InitialSetupConfig_ExtraTestTableConfigs>)
|
|
108
|
+
//(</InitialSetupConfig_ExtraTestTableConfigs>)
|
|
109
|
+
},
|
|
110
|
+
//(<InitialSetupConfig_ExtraTableConfigs>)
|
|
111
|
+
//(</InitialSetupConfig_ExtraTableConfigs>)
|
|
83
112
|
};
|
|
84
113
|
|
|
85
114
|
// ============================================================
|
|
@@ -100,6 +129,32 @@ const tableConfigs = {
|
|
|
100
129
|
nodeSubs.push({ serviceTag: tag, topicName: 'UpdateNode_Out', sqsEndpoint: 'UpdateCompleteHdrSqs' });
|
|
101
130
|
nodeSubs.push({ serviceTag: tag, topicName: 'CreateNode_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
|
|
102
131
|
});
|
|
132
|
+
|
|
133
|
+
const customSubs = [];
|
|
134
|
+
(flows || []).forEach(function(flow) {
|
|
135
|
+
if (flow && flow.outputTopic && !flow.generatedCodeConfig && typeof flow.flowTag === 'string' && flow.flowTag) {
|
|
136
|
+
const tag = flow.flowTag[0].toUpperCase() + flow.flowTag.slice(1);
|
|
137
|
+
const serviceTag = flow.objType?.serviceTag || (project && project.serviceTag) || '';
|
|
138
|
+
const topicName = typeof flow.outputTopic === 'string'
|
|
139
|
+
? (flow.outputTopic.endsWith('_Out') ? flow.outputTopic : `${flow.outputTopic}_Out`)
|
|
140
|
+
: `${tag}_Out`;
|
|
141
|
+
customSubs.push({
|
|
142
|
+
serviceTag: serviceTag,
|
|
143
|
+
topicName: topicName,
|
|
144
|
+
sqsEndpoint: `${tag}CompleteHdrSqs`
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const rbacSubs = [];
|
|
150
|
+
if (crud && typeof rbacValidatorServiceTags !== 'undefined' && rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0) {
|
|
151
|
+
const allRbacTags = Array.from(new Set(['Rbac', ...rbacValidatorServiceTags]));
|
|
152
|
+
allRbacTags.forEach(function(tag) {
|
|
153
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
|
|
154
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'UpdateCompleteHdrSqs' });
|
|
155
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'DeleteCompleteHdrSqs' });
|
|
156
|
+
});
|
|
157
|
+
}
|
|
103
158
|
-%>
|
|
104
159
|
const snsTopicSubscriptions = [
|
|
105
160
|
<% if (relSubs.length > 0) { -%>
|
|
@@ -126,6 +181,32 @@ const snsTopicSubscriptions = [
|
|
|
126
181
|
sqsEndpoint: '<%= sub.sqsEndpoint %>'
|
|
127
182
|
},
|
|
128
183
|
<% }); -%>
|
|
184
|
+
<% } -%>
|
|
185
|
+
<% if (customSubs.length > 0) { -%>
|
|
186
|
+
|
|
187
|
+
// ------------------------------------------------------------
|
|
188
|
+
// Custom Flow Subscriptions
|
|
189
|
+
// ------------------------------------------------------------
|
|
190
|
+
<% customSubs.forEach(function(sub, idx) { -%>
|
|
191
|
+
{
|
|
192
|
+
serviceTag: '<%= sub.serviceTag %>',
|
|
193
|
+
topicName: '<%= sub.topicName %>',
|
|
194
|
+
sqsEndpoint: '<%= sub.sqsEndpoint %>'
|
|
195
|
+
},
|
|
196
|
+
<% }); -%>
|
|
197
|
+
<% } -%>
|
|
198
|
+
<% if (rbacSubs.length > 0) { -%>
|
|
199
|
+
|
|
200
|
+
// ------------------------------------------------------------
|
|
201
|
+
// RBAC Validator Subscriptions
|
|
202
|
+
// ------------------------------------------------------------
|
|
203
|
+
<% rbacSubs.forEach(function(sub, idx) { -%>
|
|
204
|
+
{
|
|
205
|
+
serviceTag: '<%= sub.serviceTag %>',
|
|
206
|
+
topicName: '<%= sub.topicName %>',
|
|
207
|
+
sqsEndpoint: '<%= sub.sqsEndpoint %>'
|
|
208
|
+
},
|
|
209
|
+
<% }); -%>
|
|
129
210
|
<% } -%>
|
|
130
211
|
|
|
131
212
|
//(<additionalSubscription>)
|
|
@@ -137,10 +218,11 @@ const snsTopicSubscriptions = [
|
|
|
137
218
|
// ============================================================
|
|
138
219
|
function roleConfigs() {
|
|
139
220
|
const externalLambdaRole = [
|
|
140
|
-
<% if (crud
|
|
221
|
+
<% if (crud) { -%>
|
|
141
222
|
{
|
|
142
223
|
roleName: 'FlowObjects',
|
|
143
224
|
statement: [
|
|
225
|
+
<% if (objectGraphServiceTags && objectGraphServiceTags.length > 0) { -%>
|
|
144
226
|
<% objectGraphServiceTags.forEach(function(tag, idx) { -%>
|
|
145
227
|
{
|
|
146
228
|
Sid: 'FlowObjectsInvokeGetNode<%= tag %>',
|
|
@@ -161,14 +243,46 @@ function roleConfigs() {
|
|
|
161
243
|
]
|
|
162
244
|
},
|
|
163
245
|
<% }); -%>
|
|
246
|
+
<% } -%>
|
|
247
|
+
<% if (rbac || (rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0)) { -%>
|
|
248
|
+
{
|
|
249
|
+
Sid: 'FlowObjectsPublishValidatorRbacTopics',
|
|
250
|
+
Effect: 'Allow',
|
|
251
|
+
Action: ['sns:Publish'],
|
|
252
|
+
Resource: [
|
|
253
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
254
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
<% } -%>
|
|
164
258
|
//(<createFlowObjectsRole>)
|
|
165
259
|
//(</createFlowObjectsRole>)
|
|
166
260
|
]
|
|
167
261
|
},
|
|
168
262
|
|
|
263
|
+
<% if (rbac) { -%>
|
|
264
|
+
{
|
|
265
|
+
roleName: 'FlowRbac',
|
|
266
|
+
statement: [
|
|
267
|
+
{
|
|
268
|
+
Sid: 'FlowRbacPublishValidatorRbacTopics',
|
|
269
|
+
Effect: 'Allow',
|
|
270
|
+
Action: ['sns:Publish'],
|
|
271
|
+
Resource: [
|
|
272
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
273
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
//(<createFlowRbacRole>)
|
|
277
|
+
//(</createFlowRbacRole>)
|
|
278
|
+
]
|
|
279
|
+
},
|
|
280
|
+
<% } -%>
|
|
281
|
+
|
|
169
282
|
{
|
|
170
283
|
roleName: 'ProcFindData',
|
|
171
284
|
statement: [
|
|
285
|
+
<% if (objectGraphServiceTags && objectGraphServiceTags.length > 0) { -%>
|
|
172
286
|
<% objectGraphServiceTags.forEach(function(tag, idx) { -%>
|
|
173
287
|
{
|
|
174
288
|
Sid: 'ProcFindDataInvokeGetNode<%= tag %>',
|
|
@@ -179,6 +293,7 @@ function roleConfigs() {
|
|
|
179
293
|
]
|
|
180
294
|
}
|
|
181
295
|
<% }); -%>
|
|
296
|
+
<% } -%>
|
|
182
297
|
//(<createProcFindDataRole>)
|
|
183
298
|
//(</createProcFindDataRole>)
|
|
184
299
|
]
|
|
@@ -303,7 +418,7 @@ function roleConfigs() {
|
|
|
303
418
|
comma = ',';
|
|
304
419
|
}
|
|
305
420
|
-%>
|
|
306
|
-
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, '<%- item.topic %>'<%- tagArg %>)}`<%= comma %>
|
|
421
|
+
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, '<%- item.functionName || item.topicName || item.topic %>'<%- tagArg %>)}`<%= comma %>
|
|
307
422
|
<% } -%>
|
|
308
423
|
]
|
|
309
424
|
}
|