@izara_project/izara-core-generate-service-code 1.0.78 → 1.0.80
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 +137 -17
- package/src/emit/crud/crudActionPlan.js +82 -0
- package/src/emit/crud/emitCrudApplicationArtifacts.js +169 -112
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +43 -65
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
- package/src/emit/crud/templates/CreateComplete_Main.ejs +8 -3
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +90 -513
- package/src/emit/crud/templates/CreateLogicalLib.ejs +541 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +8 -3
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +93 -203
- 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 +118 -37
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +8 -3
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +92 -444
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +477 -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/ChangeRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/CreateRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/DeleteRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/MoveRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +6 -2
- package/src/emit/relationship/templates/UpdateRelationshipComplete_Main.ejs +7 -2
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +6 -2
- package/src/emit/resource/emitResourceArtifacts.js +149 -79
- package/src/emit/resource/templates/DynamoDBTable_Yaml.ejs +4 -4
- 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/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 +158 -19
- package/test/customFlowApplicationArtifacts.test.js +307 -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 +14 -5
- package/test/resourceArtifacts.test.js +66 -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.80",
|
|
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,37 @@ 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
|
+
const hasGraph = typeof objectGraphServiceTags !== 'undefined' && objectGraphServiceTags && objectGraphServiceTags.length > 0;
|
|
153
|
+
const updateEndpoint = hasGraph ? 'UpdateRbacCallbackHdrSqs' : 'UpdateCompleteHdrSqs';
|
|
154
|
+
const deleteEndpoint = hasGraph ? 'DeleteRbacCallbackHdrSqs' : 'DeleteCompleteHdrSqs';
|
|
155
|
+
allRbacTags.forEach(function(tag) {
|
|
156
|
+
if (!hasGraph) {
|
|
157
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: 'CreateCompleteHdrSqs' });
|
|
158
|
+
}
|
|
159
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: updateEndpoint });
|
|
160
|
+
rbacSubs.push({ serviceTag: tag, topicName: 'ValidatorRbac_Out', sqsEndpoint: deleteEndpoint });
|
|
161
|
+
});
|
|
162
|
+
}
|
|
103
163
|
-%>
|
|
104
164
|
const snsTopicSubscriptions = [
|
|
105
165
|
<% if (relSubs.length > 0) { -%>
|
|
@@ -126,6 +186,32 @@ const snsTopicSubscriptions = [
|
|
|
126
186
|
sqsEndpoint: '<%= sub.sqsEndpoint %>'
|
|
127
187
|
},
|
|
128
188
|
<% }); -%>
|
|
189
|
+
<% } -%>
|
|
190
|
+
<% if (customSubs.length > 0) { -%>
|
|
191
|
+
|
|
192
|
+
// ------------------------------------------------------------
|
|
193
|
+
// Custom Flow Subscriptions
|
|
194
|
+
// ------------------------------------------------------------
|
|
195
|
+
<% customSubs.forEach(function(sub, idx) { -%>
|
|
196
|
+
{
|
|
197
|
+
serviceTag: '<%= sub.serviceTag %>',
|
|
198
|
+
topicName: '<%= sub.topicName %>',
|
|
199
|
+
sqsEndpoint: '<%= sub.sqsEndpoint %>'
|
|
200
|
+
},
|
|
201
|
+
<% }); -%>
|
|
202
|
+
<% } -%>
|
|
203
|
+
<% if (rbacSubs.length > 0) { -%>
|
|
204
|
+
|
|
205
|
+
// ------------------------------------------------------------
|
|
206
|
+
// RBAC Validator Subscriptions
|
|
207
|
+
// ------------------------------------------------------------
|
|
208
|
+
<% rbacSubs.forEach(function(sub, idx) { -%>
|
|
209
|
+
{
|
|
210
|
+
serviceTag: '<%= sub.serviceTag %>',
|
|
211
|
+
topicName: '<%= sub.topicName %>',
|
|
212
|
+
sqsEndpoint: '<%= sub.sqsEndpoint %>'
|
|
213
|
+
},
|
|
214
|
+
<% }); -%>
|
|
129
215
|
<% } -%>
|
|
130
216
|
|
|
131
217
|
//(<additionalSubscription>)
|
|
@@ -137,10 +223,11 @@ const snsTopicSubscriptions = [
|
|
|
137
223
|
// ============================================================
|
|
138
224
|
function roleConfigs() {
|
|
139
225
|
const externalLambdaRole = [
|
|
140
|
-
<% if (crud
|
|
226
|
+
<% if (crud) { -%>
|
|
141
227
|
{
|
|
142
228
|
roleName: 'FlowObjects',
|
|
143
229
|
statement: [
|
|
230
|
+
<% if (objectGraphServiceTags && objectGraphServiceTags.length > 0) { -%>
|
|
144
231
|
<% objectGraphServiceTags.forEach(function(tag, idx) { -%>
|
|
145
232
|
{
|
|
146
233
|
Sid: 'FlowObjectsInvokeGetNode<%= tag %>',
|
|
@@ -161,14 +248,46 @@ function roleConfigs() {
|
|
|
161
248
|
]
|
|
162
249
|
},
|
|
163
250
|
<% }); -%>
|
|
251
|
+
<% } -%>
|
|
252
|
+
<% if (rbac || (rbacValidatorServiceTags && rbacValidatorServiceTags.length > 0)) { -%>
|
|
253
|
+
{
|
|
254
|
+
Sid: 'FlowObjectsPublishValidatorRbacTopics',
|
|
255
|
+
Effect: 'Allow',
|
|
256
|
+
Action: ['sns:Publish'],
|
|
257
|
+
Resource: [
|
|
258
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
259
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
260
|
+
]
|
|
261
|
+
},
|
|
262
|
+
<% } -%>
|
|
164
263
|
//(<createFlowObjectsRole>)
|
|
165
264
|
//(</createFlowObjectsRole>)
|
|
166
265
|
]
|
|
167
266
|
},
|
|
168
267
|
|
|
268
|
+
<% if (rbac) { -%>
|
|
269
|
+
{
|
|
270
|
+
roleName: 'FlowRbac',
|
|
271
|
+
statement: [
|
|
272
|
+
{
|
|
273
|
+
Sid: 'FlowRbacPublishValidatorRbacTopics',
|
|
274
|
+
Effect: 'Allow',
|
|
275
|
+
Action: ['sns:Publish'],
|
|
276
|
+
Resource: [
|
|
277
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', 'Rbac')}`<% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
278
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`<% }); %>
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
//(<createFlowRbacRole>)
|
|
282
|
+
//(</createFlowRbacRole>)
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
<% } -%>
|
|
286
|
+
|
|
169
287
|
{
|
|
170
288
|
roleName: 'ProcFindData',
|
|
171
289
|
statement: [
|
|
290
|
+
<% if (objectGraphServiceTags && objectGraphServiceTags.length > 0) { -%>
|
|
172
291
|
<% objectGraphServiceTags.forEach(function(tag, idx) { -%>
|
|
173
292
|
{
|
|
174
293
|
Sid: 'ProcFindDataInvokeGetNode<%= tag %>',
|
|
@@ -179,6 +298,7 @@ function roleConfigs() {
|
|
|
179
298
|
]
|
|
180
299
|
}
|
|
181
300
|
<% }); -%>
|
|
301
|
+
<% } -%>
|
|
182
302
|
//(<createProcFindDataRole>)
|
|
183
303
|
//(</createProcFindDataRole>)
|
|
184
304
|
]
|
|
@@ -303,7 +423,7 @@ function roleConfigs() {
|
|
|
303
423
|
comma = ',';
|
|
304
424
|
}
|
|
305
425
|
-%>
|
|
306
|
-
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, '<%- item.topic %>'<%- tagArg %>)}`<%= comma %>
|
|
426
|
+
`arn:aws:lambda:${process.env.iz_region}:${process.env.iz_accountId}:function:${lambdaSharedLib.lambdaFunctionName(_izContext, '<%- item.functionName || item.topicName || item.topic %>'<%- tagArg %>)}`<%= comma %>
|
|
307
427
|
<% } -%>
|
|
308
428
|
]
|
|
309
429
|
}
|