@izara_project/izara-core-generate-service-code 1.0.98 → 1.0.100
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 +1 -1
- package/src/compile/compileProject.js +16 -5
- package/src/compile/flowValidator.js +47 -8
- package/src/compile/loadSchemas.js +18 -7
- package/src/compile/schemaValidatorSetup.js +16 -0
- package/src/emit/application/coreFunction/emitCoreFunctionArtifacts.js +123 -109
- package/src/emit/application/coreFunction/templates/InitialSetupConfig.ejs +8 -4
- package/src/emit/application/coreFunction/templates/InitialSetupRunner.ejs +2 -2
- package/src/emit/application/crud/templates/CreateComplete_Main.ejs +2 -0
- package/src/emit/application/crud/templates/CreateEndpoint_Main.ejs +4 -4
- package/src/emit/application/crud/templates/CreateLogicalLib.ejs +74 -15
- package/src/emit/application/crud/templates/DeleteComplete_Main.ejs +2 -0
- package/src/emit/application/crud/templates/DeleteEndpoint_Main.ejs +4 -4
- package/src/emit/application/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -5
- package/src/emit/application/crud/templates/UpdateComplete_Main.ejs +2 -0
- package/src/emit/application/crud/templates/UpdateEndpoint_Main.ejs +4 -4
- package/src/emit/application/custom/customFlowPaths.js +13 -16
- package/src/emit/application/custom/customFlowS3.js +277 -66
- package/src/emit/application/custom/customFlows.js +131 -0
- package/src/emit/application/custom/emitCustomFlowApplicationArtifacts.js +3 -1
- package/src/emit/application/custom/templates/FlowEndpoint_Main.ejs +2 -2
- package/src/emit/application/custom/templates/s3/ConfirmAfterUpload_HdrSqs.ejs +110 -0
- package/src/emit/application/custom/templates/s3/ConfirmAfterUpload_Main.ejs +89 -0
- package/src/emit/application/custom/templates/s3/ConfirmComplete_HdrSqs.ejs +110 -0
- package/src/emit/application/custom/templates/s3/ConfirmComplete_Main.ejs +89 -0
- package/src/emit/application/custom/templates/s3/CreateObject_HdrWbs.ejs +2 -1
- package/src/emit/application/custom/templates/s3/CreateObject_Main.ejs +4 -0
- package/src/emit/application/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +42 -0
- package/src/emit/application/custom/templates/s3/CreatePreSignUrl_Main.ejs +23 -0
- package/src/emit/application/custom/templates/s3/ProcessS3File_Main.ejs +135 -27
- package/src/emit/application/custom/templates/s3/Start_Main.ejs +197 -0
- package/src/emit/application/rbac/emitDynamicRbacFlowSchemas.js +8 -1
- package/src/emit/application/rbac/emitRbacApplicationArtifacts.js +107 -25
- package/src/emit/application/rbac/templates/ReservedDynamicUsage_Main.ejs +29 -9
- package/src/emit/application/rbac/templates/ReservedUsageTtlExpired_HdrDss.ejs +176 -0
- package/src/emit/application/rbac/templates/UserRbacFlow_Main.ejs +4 -3
- package/src/emit/application/system/templates/Register_HdrWbs.ejs +2 -1
- package/src/emit/infrastructure/functions/functionYamlArtifact.js +31 -8
- package/src/emit/infrastructure/functions/templates/DssFunction_Yaml.ejs +21 -0
- package/src/emit/infrastructure/functions/templates/S3Function_Yaml.ejs +2 -3
- package/src/emit/infrastructure/resources/iamResourceArtifacts.js +67 -5
- package/src/emit/infrastructure/resources/resourceState.js +15 -5
- package/src/emit/infrastructure/resources/s3ResourceArtifacts.js +19 -3
- package/src/emit/infrastructure/resources/templates/GeneratedLambdaRoleServiceConfig.ejs +5 -3
- package/src/emit/infrastructure/resources/templates/S3Bucket_Yaml.ejs +1 -1
- package/src/emit/infrastructure/resources/templates/SystemDynamoDB_Yaml.ejs +2 -2
- package/src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js +62 -1
- package/src/emit/schemas/error/emitErrorSchemas.js +120 -10
- package/src/emit/schemas/error/templates/errorConsts.ejs +12 -0
- package/src/generate.js +32 -34
- package/src/output/mergeHooks.js +105 -5
- package/src/plan/domainRegistry.js +0 -10
- package/task.md +40 -96
- package/test/integration/graphDrivenFlowSchema.test.js +58 -0
- package/test/integration/publicApi.test.js +33 -24
- package/test/unit/application/createTargetRoleHandler.test.js +101 -9
- package/test/unit/application/crudApplicationArtifacts.test.js +4 -0
- package/test/unit/application/customFlowApplicationArtifacts.test.js +6 -6
- package/test/unit/application/customFlowS3.test.js +730 -0
- package/test/unit/infrastructure/functionYamlArtifact.test.js +6 -4
- package/test/unit/infrastructure/resourceArtifacts.test.js +103 -0
- package/test/unit/output/mergeHooks.test.js +137 -0
- package/test/unit/schemas/attributeTreeSchemas.test.js +32 -3
- package/test/unit/schemas/attributeTreeSingleService.test.js +175 -0
- package/test/unit/schemas/dynamicRbacFlowSchemas.test.js +8 -6
- package/test/unit/schemas/dynamicRelationshipFlowSchemas.test.js +51 -0
- package/test/unit/schemas/errorSchemas.test.js +84 -5
- package/test/unit/templates/hookTagsValidation.test.js +83 -0
- package/src/emit/schemas/attributeTree/emitAttributeTreeTargetValueStandard.js +0 -132
- package/test/unit/schemas/attributeTreeDirectives.test.js +0 -177
|
@@ -181,6 +181,7 @@ export function renderS3FunctionYaml({
|
|
|
181
181
|
handlerPath,
|
|
182
182
|
roleName,
|
|
183
183
|
bucketName,
|
|
184
|
+
s3KeyPrefix,
|
|
184
185
|
flowTag,
|
|
185
186
|
flowStepName
|
|
186
187
|
}) {
|
|
@@ -189,6 +190,35 @@ export function renderS3FunctionYaml({
|
|
|
189
190
|
handlerPath,
|
|
190
191
|
roleName,
|
|
191
192
|
bucketName,
|
|
193
|
+
s3KeyPrefix,
|
|
194
|
+
environmentSetting: _environmentSetting(
|
|
195
|
+
functionName,
|
|
196
|
+
flowTag,
|
|
197
|
+
flowStepName
|
|
198
|
+
),
|
|
199
|
+
functionSetting: _functionSetting(functionName)
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function renderDssFunctionYaml({
|
|
204
|
+
functionName,
|
|
205
|
+
handlerPath,
|
|
206
|
+
roleName,
|
|
207
|
+
tableName,
|
|
208
|
+
batchSize = 100,
|
|
209
|
+
startingPosition = 'TRIM_HORIZON',
|
|
210
|
+
filterPatterns = [],
|
|
211
|
+
flowTag,
|
|
212
|
+
flowStepName
|
|
213
|
+
}) {
|
|
214
|
+
return _renderFunctionTemplate('DssFunction_Yaml.ejs', {
|
|
215
|
+
functionName,
|
|
216
|
+
handlerPath,
|
|
217
|
+
roleName,
|
|
218
|
+
tableName,
|
|
219
|
+
batchSize,
|
|
220
|
+
startingPosition,
|
|
221
|
+
filterPatterns,
|
|
192
222
|
environmentSetting: _environmentSetting(
|
|
193
223
|
functionName,
|
|
194
224
|
flowTag,
|
|
@@ -314,15 +344,8 @@ function _sqsFilterPatterns(
|
|
|
314
344
|
- body:
|
|
315
345
|
MessageAttributes:
|
|
316
346
|
callingFlow:
|
|
317
|
-
|
|
347
|
+
StringValue:
|
|
318
348
|
- \${self:custom.iz_resourcePrefix}${callingFlowName}
|
|
319
|
-
- body:
|
|
320
|
-
MessageAttributes:
|
|
321
|
-
callingFlow:
|
|
322
|
-
- exists: false
|
|
323
|
-
- body:
|
|
324
|
-
MessageAttributes:
|
|
325
|
-
- exists: false
|
|
326
349
|
#<#/${hookFunctionName}FilterPatterns#>
|
|
327
350
|
`;
|
|
328
351
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<%= functionName %>:
|
|
2
|
+
handler: <%= handlerPath %>
|
|
3
|
+
name: ${self:custom.iz_resourcePrefix}<%= functionName %>
|
|
4
|
+
role: <%= roleName %>
|
|
5
|
+
<%- environmentSetting %><%- functionSetting %>
|
|
6
|
+
events:
|
|
7
|
+
- stream:
|
|
8
|
+
type: dynamodb
|
|
9
|
+
arn:
|
|
10
|
+
Fn::GetAtt: [<%= tableName %>Table, StreamArn]
|
|
11
|
+
batchSize: <%= batchSize %>
|
|
12
|
+
startingPosition: <%= startingPosition %>
|
|
13
|
+
<% if (Array.isArray(filterPatterns) && filterPatterns.length > 0) { -%>
|
|
14
|
+
filterPatterns:
|
|
15
|
+
<% filterPatterns.forEach(function(pattern) { -%>
|
|
16
|
+
- eventName: <%- JSON.stringify(pattern.eventName) %>
|
|
17
|
+
userIdentity:
|
|
18
|
+
type: <%- JSON.stringify(pattern.userIdentity.type) %>
|
|
19
|
+
principalId: <%- JSON.stringify(pattern.userIdentity.principalId) %>
|
|
20
|
+
<% }); -%>
|
|
21
|
+
<% } -%>
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
bucket: <%= bucketName %>
|
|
9
9
|
event: s3:ObjectCreated:*
|
|
10
10
|
existing: true
|
|
11
|
-
rules
|
|
11
|
+
rules:<% if (s3KeyPrefix) { %>
|
|
12
|
+
- prefix: <%- s3KeyPrefix %><% } %>
|
|
12
13
|
#<#<%= functionName %>rules#>
|
|
13
14
|
#<#/<%= functionName %>rules#>
|
|
14
|
-
- prefix: uploads/
|
|
15
|
-
- suffix: .csv
|
|
16
15
|
forceDeploy: true
|
|
@@ -96,9 +96,26 @@ export function getRbacValidatorServiceTags(state) {
|
|
|
96
96
|
export async function renderLambdaRoleConfig(state) {
|
|
97
97
|
const s3Flows = state.flows
|
|
98
98
|
.filter((flow) => includesEvent(flow, 's3'))
|
|
99
|
-
.map((flow) =>
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
.map((flow) => {
|
|
100
|
+
let quotaServiceTag = flow.quotaServiceTag;
|
|
101
|
+
if (!quotaServiceTag && flow.belongTo) {
|
|
102
|
+
if (Array.isArray(flow.belongTo)) {
|
|
103
|
+
quotaServiceTag = flow.belongTo[0]?.serviceTag;
|
|
104
|
+
} else if (flow.belongTo.serviceTag) {
|
|
105
|
+
quotaServiceTag = flow.belongTo.serviceTag;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (!quotaServiceTag && flow.objType?.serviceTag) {
|
|
109
|
+
quotaServiceTag = flow.objType.serviceTag;
|
|
110
|
+
}
|
|
111
|
+
if (!quotaServiceTag) {
|
|
112
|
+
quotaServiceTag = state.project?.serviceTag || 'Rbac';
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
roleName: upperFirst(flow.flowTag),
|
|
116
|
+
quotaServiceTag
|
|
117
|
+
};
|
|
118
|
+
});
|
|
102
119
|
const rbacValidatorServiceTags = getRbacValidatorServiceTags(state);
|
|
103
120
|
return renderResourceTemplate('GeneratedLambdaRoleServiceConfig.ejs', {
|
|
104
121
|
crud: state.crud,
|
|
@@ -122,6 +139,25 @@ export function roleStatements(state, roleName) {
|
|
|
122
139
|
resource: ['arn:aws:s3:::${self:custom.iz_serviceSchemaBucketName}']
|
|
123
140
|
});
|
|
124
141
|
}
|
|
142
|
+
const s3FlowsForRole = (state.flows || []).filter((candidate) => {
|
|
143
|
+
const roleCandidate = customFlowRoleName(candidate?.flowTag ?? '');
|
|
144
|
+
return (
|
|
145
|
+
roleCandidate === roleName &&
|
|
146
|
+
includesEvent(candidate, 's3') &&
|
|
147
|
+
Boolean(candidate.bucketName)
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
if (s3FlowsForRole.length > 0) {
|
|
151
|
+
const bucketResources = [
|
|
152
|
+
...new Set(
|
|
153
|
+
s3FlowsForRole.map((flow) => `arn:aws:s3:::${flow.bucketName}/*`)
|
|
154
|
+
)
|
|
155
|
+
].sort();
|
|
156
|
+
statements.push({
|
|
157
|
+
action: ['s3:GetObject'],
|
|
158
|
+
resource: bucketResources
|
|
159
|
+
});
|
|
160
|
+
}
|
|
125
161
|
addStatement(statements, dynamoActionsForRole(roleName), [
|
|
126
162
|
...dynamoArns(roleTableNames(state, roleName)),
|
|
127
163
|
...externalDynamoArns(roleExternalDynamoTables(state, roleName))
|
|
@@ -160,6 +196,19 @@ export function roleStatements(state, roleName) {
|
|
|
160
196
|
]
|
|
161
197
|
});
|
|
162
198
|
}
|
|
199
|
+
if (roleName === 'FlowRbacRole' && state.selfRbac) {
|
|
200
|
+
statements.push({
|
|
201
|
+
action: [
|
|
202
|
+
'dynamodb:DescribeStream',
|
|
203
|
+
'dynamodb:GetRecords',
|
|
204
|
+
'dynamodb:GetShardIterator',
|
|
205
|
+
'dynamodb:ListStreams'
|
|
206
|
+
],
|
|
207
|
+
resource: [
|
|
208
|
+
'arn:aws:dynamodb:${self:custom.iz_region}:${self:custom.iz_accountId}:table/${self:custom.iz_resourcePrefix}RunningTotalReservedUsage/stream/*'
|
|
209
|
+
]
|
|
210
|
+
});
|
|
211
|
+
}
|
|
163
212
|
return statements;
|
|
164
213
|
}
|
|
165
214
|
|
|
@@ -449,6 +498,9 @@ export function roleTopicNames(state, roleName) {
|
|
|
449
498
|
if (flowHasOwnTopic(flow)) {
|
|
450
499
|
topics.push(`${name}_In`);
|
|
451
500
|
}
|
|
501
|
+
if (includesEvent(flow, 's3')) {
|
|
502
|
+
topics.push('Create_In');
|
|
503
|
+
}
|
|
452
504
|
return topics;
|
|
453
505
|
}
|
|
454
506
|
return [];
|
|
@@ -508,11 +560,16 @@ export function roleExternalTopicArns(state, roleName) {
|
|
|
508
560
|
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_ValidatorRbac_In`
|
|
509
561
|
);
|
|
510
562
|
if (roleName === 'FlowObjectsRole') {
|
|
563
|
+
const extraCrudTopics = extraTags.flatMap((tag) => [
|
|
564
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_ValidatorRbac_In`,
|
|
565
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_ConfirmUsage_In`,
|
|
566
|
+
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:${tag}_\${self:custom.iz_stage}_CancelUsage_In`
|
|
567
|
+
]);
|
|
511
568
|
return [
|
|
512
569
|
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ValidatorRbac_In`,
|
|
513
570
|
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_ConfirmUsage_In`,
|
|
514
571
|
`arn:aws:sns:\${self:custom.iz_region}:\${self:custom.iz_accountId}:Rbac_\${self:custom.iz_stage}_CancelUsage_In`,
|
|
515
|
-
...
|
|
572
|
+
...extraCrudTopics
|
|
516
573
|
];
|
|
517
574
|
}
|
|
518
575
|
if (roleName === 'FlowRbacRole' || roleName === 'FlowRelationshipRole') {
|
|
@@ -536,11 +593,16 @@ export function roleExternalLambdaArns(state, roleName) {
|
|
|
536
593
|
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ValidatorRbacHdrInv`
|
|
537
594
|
);
|
|
538
595
|
if (roleName === 'FlowObjectsRole') {
|
|
596
|
+
const extraCrudLambdas = extraTags.flatMap((tag) => [
|
|
597
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ValidatorRbacHdrInv`,
|
|
598
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}ConfirmUsageHdrInv`,
|
|
599
|
+
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:${tag}\${self:custom.iz_stage}CancelUsageHdrInv`
|
|
600
|
+
]);
|
|
539
601
|
return [
|
|
540
602
|
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ValidatorRbacHdrInv`,
|
|
541
603
|
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}ConfirmUsageHdrInv`,
|
|
542
604
|
`arn:aws:lambda:\${self:custom.iz_region}:\${self:custom.iz_accountId}:function:Rbac\${self:custom.iz_stage}CancelUsageHdrInv`,
|
|
543
|
-
...
|
|
605
|
+
...extraCrudLambdas
|
|
544
606
|
];
|
|
545
607
|
}
|
|
546
608
|
if (roleName === 'FlowRbacRole' || roleName === 'FlowRelationshipRole') {
|
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
flowExtTopicSteps,
|
|
5
5
|
generatedDsqFlows,
|
|
6
6
|
generatedOwnTopicFlows,
|
|
7
|
-
supportedCustomFlows
|
|
7
|
+
supportedCustomFlows,
|
|
8
|
+
resolveS3Parts
|
|
8
9
|
} from '../../application/custom/customFlows.js';
|
|
9
10
|
import { hasSystemWebSocket } from '../../application/system/emitSystemWebSocketArtifacts.js';
|
|
10
11
|
import { rbacFlowTag } from '../../application/rbac/rbacFlowTag.js';
|
|
@@ -161,9 +162,12 @@ export function createResourceState({ objects, relationships, flows }) {
|
|
|
161
162
|
|
|
162
163
|
for (const flow of flows.filter((flow) => includesEvent(flow, 's3'))) {
|
|
163
164
|
const tag = upperFirst(flow.flowTag);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
const parts = resolveS3Parts(flow);
|
|
166
|
+
for (const part of parts) {
|
|
167
|
+
if (part.type === 'sqs') {
|
|
168
|
+
customSqsQueues.push(`${tag}${part.action}HdrSqs`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
const customDsqQueues = flows
|
|
@@ -281,8 +285,14 @@ export function createResourceState({ objects, relationships, flows }) {
|
|
|
281
285
|
topicName = `Out${upperFirst(flow.outputTopic)}`;
|
|
282
286
|
}
|
|
283
287
|
}
|
|
288
|
+
let targetAction = 'ReservedLimit';
|
|
289
|
+
const parts = resolveS3Parts(flow);
|
|
290
|
+
const firstSqsPart = parts.find((p) => p.type === 'sqs');
|
|
291
|
+
if (firstSqsPart && firstSqsPart.action) {
|
|
292
|
+
targetAction = firstSqsPart.action;
|
|
293
|
+
}
|
|
284
294
|
const queueName =
|
|
285
|
-
flow.s3Subscription?.queueName || `${tag}
|
|
295
|
+
flow.s3Subscription?.queueName || `${tag}${targetAction}HdrSqs`;
|
|
286
296
|
const subscriptionName =
|
|
287
297
|
flow.s3Subscription?.subscriptionName ||
|
|
288
298
|
`Subscription${topicName}To${queueName}`;
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import { indentYaml, renderResourceTemplate } from './resourceTemplate.js';
|
|
2
2
|
|
|
3
|
+
export function toAlphanumericPascalCase(str) {
|
|
4
|
+
if (!str) {
|
|
5
|
+
return '';
|
|
6
|
+
}
|
|
7
|
+
const parts = str.split(/[^a-zA-Z0-9]+/);
|
|
8
|
+
const validParts = parts.filter(Boolean);
|
|
9
|
+
const capitalizedParts = validParts.map((word) => {
|
|
10
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
11
|
+
});
|
|
12
|
+
return capitalizedParts.join('');
|
|
13
|
+
}
|
|
14
|
+
|
|
3
15
|
export async function renderS3(state) {
|
|
4
16
|
if (state.s3Buckets.length === 0) {
|
|
5
17
|
return '';
|
|
6
18
|
}
|
|
7
19
|
const renderedBuckets = await Promise.all(
|
|
8
|
-
state.s3Buckets.map((bucketName) =>
|
|
9
|
-
|
|
10
|
-
|
|
20
|
+
state.s3Buckets.map((bucketName) => {
|
|
21
|
+
const bucketLogicalId = `${toAlphanumericPascalCase(bucketName)}S3Bucket`;
|
|
22
|
+
return renderResourceTemplate('S3Bucket_Yaml.ejs', {
|
|
23
|
+
bucketName,
|
|
24
|
+
bucketLogicalId
|
|
25
|
+
});
|
|
26
|
+
})
|
|
11
27
|
);
|
|
12
28
|
const body = renderedBuckets.join('\n');
|
|
13
29
|
return `Resources:\n${indentYaml(body, 2)}`;
|
|
@@ -60,7 +60,9 @@ export function generatedLambdaRole() {
|
|
|
60
60
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', 'Rbac')}`,
|
|
61
61
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', 'Rbac')}`<% if (rbac) { %>,
|
|
62
62
|
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In')}`<% } %><% (rbacValidatorServiceTags || []).forEach(function(tag) { %>,
|
|
63
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}
|
|
63
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ValidatorRbac_In', '<%= tag %>')}`,
|
|
64
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmUsage_In', '<%= tag %>')}`,
|
|
65
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'CancelUsage_In', '<%= tag %>')}`<% }); %>
|
|
64
66
|
]
|
|
65
67
|
}<% } %>
|
|
66
68
|
//(<createFlowObjectsRole>)
|
|
@@ -144,7 +146,7 @@ export function generatedLambdaRole() {
|
|
|
144
146
|
Effect: 'Allow',
|
|
145
147
|
Action: ['sns:Publish'],
|
|
146
148
|
Resource: [
|
|
147
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ReservedDynamicUsage_In', '
|
|
149
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ReservedDynamicUsage_In', '<%= flow.quotaServiceTag || 'Rbac' %>')}`
|
|
148
150
|
]
|
|
149
151
|
},
|
|
150
152
|
|
|
@@ -153,7 +155,7 @@ export function generatedLambdaRole() {
|
|
|
153
155
|
Effect: 'Allow',
|
|
154
156
|
Action: ['sns:Publish'],
|
|
155
157
|
Resource: [
|
|
156
|
-
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmDynamicAfterUpload_In', '
|
|
158
|
+
`arn:aws:sns:${process.env.iz_region}:${process.env.iz_accountId}:${snsSharedLib.snsTopicNameByFlowSchema(_izContext, 'ConfirmDynamicAfterUpload_In', '<%= flow.quotaServiceTag || 'Rbac' %>')}`
|
|
157
159
|
]
|
|
158
160
|
}
|
|
159
161
|
//(<create<%= flow.roleName %>Role>)
|
|
@@ -230,7 +230,7 @@ Resources:
|
|
|
230
230
|
- AttributeName: cacheKey
|
|
231
231
|
KeyType: RANGE
|
|
232
232
|
TimeToLiveSpecification:
|
|
233
|
-
AttributeName:
|
|
233
|
+
AttributeName: expirationTime
|
|
234
234
|
Enabled: true
|
|
235
235
|
|
|
236
236
|
RunningTotalUsageTable:
|
|
@@ -265,7 +265,7 @@ Resources:
|
|
|
265
265
|
- AttributeName: usedTimestampId
|
|
266
266
|
KeyType: RANGE
|
|
267
267
|
TimeToLiveSpecification:
|
|
268
|
-
AttributeName:
|
|
268
|
+
AttributeName: expirationTime
|
|
269
269
|
Enabled: true
|
|
270
270
|
StreamSpecification:
|
|
271
271
|
StreamViewType: NEW_AND_OLD_IMAGES
|
|
@@ -62,6 +62,60 @@ function _renderRelationshipSchema(relationshipTag, content) {
|
|
|
62
62
|
return `export default ${JSON.stringify(wrapper, null, 2)};\n`;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function _renderValueStandardSchema(tag, storageResources) {
|
|
66
|
+
const storageResourceTags = Object.keys(storageResources);
|
|
67
|
+
if (storageResourceTags.length === 0) {
|
|
68
|
+
storageResourceTags.push('myGraph');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const storageJson = JSON.stringify(storageResources, null, 2)
|
|
72
|
+
.replace(/\n/g, '\n ');
|
|
73
|
+
const tagsJson = JSON.stringify(storageResourceTags);
|
|
74
|
+
|
|
75
|
+
return `export default [
|
|
76
|
+
{
|
|
77
|
+
objectType: '${tag}ValueStandard',
|
|
78
|
+
canDelete: true,
|
|
79
|
+
generatedBy: 'user',
|
|
80
|
+
storageResources: ${storageJson},
|
|
81
|
+
addOnDataStructure: [
|
|
82
|
+
//(<addOnDataStructure${tag}ValueStandard>)
|
|
83
|
+
// {
|
|
84
|
+
// type: 'propertyValue',
|
|
85
|
+
// propertyValuePrefix: '${tag}ValueStandard'
|
|
86
|
+
// }
|
|
87
|
+
//(</addOnDataStructure${tag}ValueStandard>)
|
|
88
|
+
],
|
|
89
|
+
fieldNames: {
|
|
90
|
+
${tag}ValueStandardId: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
randomOnCreate: true,
|
|
93
|
+
canUpdate: false,
|
|
94
|
+
storageResourceTags: ${tagsJson}
|
|
95
|
+
},
|
|
96
|
+
label: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
canUpdate: true,
|
|
99
|
+
storageResourceTags: ${tagsJson}
|
|
100
|
+
},
|
|
101
|
+
value: {
|
|
102
|
+
type: 'string',
|
|
103
|
+
requiredOnCreate: true,
|
|
104
|
+
canUpdate: true,
|
|
105
|
+
storageResourceTags: ${tagsJson}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
identifiers: [
|
|
109
|
+
{
|
|
110
|
+
type: 'identifier',
|
|
111
|
+
fieldName: '${tag}ValueStandardId'
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
|
|
65
119
|
export function attributeTreeObjectSchemaManagedPaths(objects = []) {
|
|
66
120
|
const trees = _extractAttributeTrees(objects);
|
|
67
121
|
const paths = [];
|
|
@@ -71,7 +125,8 @@ export function attributeTreeObjectSchemaManagedPaths(objects = []) {
|
|
|
71
125
|
paths.push(
|
|
72
126
|
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}Link.js`,
|
|
73
127
|
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}Value.js`,
|
|
74
|
-
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}Label.js
|
|
128
|
+
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}Label.js`,
|
|
129
|
+
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}ValueStandard.js`
|
|
75
130
|
);
|
|
76
131
|
}
|
|
77
132
|
|
|
@@ -205,6 +260,12 @@ export function emitAttributeTreeObjectSchemas({ objects = [] } = {}) {
|
|
|
205
260
|
path: `app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}Label.js`,
|
|
206
261
|
content: _renderObjectSchema(labelSchema)
|
|
207
262
|
});
|
|
263
|
+
|
|
264
|
+
// 4. {tag}ValueStandard.js
|
|
265
|
+
artifacts.push({
|
|
266
|
+
path: `app/src/schemas/ObjectSchemas/generatedCode/attributeTree/${tag}ValueStandard.js`,
|
|
267
|
+
content: _renderValueStandardSchema(tag, graphStorageResources)
|
|
268
|
+
});
|
|
208
269
|
}
|
|
209
270
|
|
|
210
271
|
return artifacts;
|
|
@@ -1,19 +1,43 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
1
2
|
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
import ejsLib from 'ejs';
|
|
3
5
|
|
|
4
6
|
const TEMPLATE_URL = new URL('./templates/', import.meta.url);
|
|
5
7
|
export const ERROR_SCHEMA_PATH =
|
|
6
|
-
'app/src/schemas/ErrorSchemas/generateCode/
|
|
8
|
+
'app/src/schemas/ErrorSchemas/generateCode/errorConsts.js';
|
|
9
|
+
export const ERROR_CONSTS_PATH = ERROR_SCHEMA_PATH;
|
|
10
|
+
|
|
11
|
+
export const SHARED_ERROR_PACKAGE_PATH = 'libs/errorLib/package.json';
|
|
12
|
+
export const SHARED_ERROR_INDEX_PATH = 'libs/errorLib/index.js';
|
|
13
|
+
export const SHARED_ERROR_CONSTS_PATH = 'libs/errorLib/src/errorConsts.js';
|
|
7
14
|
|
|
8
15
|
export function errorSchemaManagedPaths(errors = []) {
|
|
9
16
|
if (!errors || errors.length === 0) {
|
|
10
17
|
return [];
|
|
11
18
|
}
|
|
12
|
-
|
|
19
|
+
const paths = [ERROR_SCHEMA_PATH];
|
|
20
|
+
const safeErrors = Array.isArray(errors) ? errors : [];
|
|
21
|
+
let hasShared = false;
|
|
22
|
+
for (const item of safeErrors) {
|
|
23
|
+
if (item && item.sharedLibrary === true) {
|
|
24
|
+
hasShared = true;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (hasShared) {
|
|
29
|
+
paths.push(
|
|
30
|
+
SHARED_ERROR_PACKAGE_PATH,
|
|
31
|
+
SHARED_ERROR_INDEX_PATH,
|
|
32
|
+
SHARED_ERROR_CONSTS_PATH
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
return paths;
|
|
13
36
|
}
|
|
14
37
|
|
|
15
38
|
/**
|
|
16
|
-
* Emits
|
|
39
|
+
* Emits errorConsts.js artifact and shared library artifacts based on
|
|
40
|
+
* loaded ErrorSchemas
|
|
17
41
|
*
|
|
18
42
|
* @param {Object} params
|
|
19
43
|
* @param {Object} params.project
|
|
@@ -31,21 +55,28 @@ export async function emitErrorSchemas({
|
|
|
31
55
|
return [];
|
|
32
56
|
}
|
|
33
57
|
|
|
34
|
-
const defaultGraphServiceTag =
|
|
35
|
-
objectGraphServiceTags[0] || 'GraphHandler';
|
|
36
58
|
const defaultServiceTag = project?.serviceTag || '';
|
|
37
59
|
|
|
38
60
|
const errorTypes = {};
|
|
61
|
+
const sharedErrorTypes = {};
|
|
62
|
+
|
|
39
63
|
for (const item of safeErrors) {
|
|
40
64
|
if (!item || typeof item !== 'object' || !item.errorTag) {
|
|
41
65
|
continue;
|
|
42
66
|
}
|
|
43
67
|
const errorTag = item.errorTag;
|
|
44
|
-
|
|
45
|
-
|
|
68
|
+
let serviceTag = item.serviceTag;
|
|
69
|
+
if (!serviceTag) {
|
|
70
|
+
serviceTag = defaultServiceTag;
|
|
71
|
+
}
|
|
72
|
+
const errorEntry = {
|
|
46
73
|
errorTag,
|
|
47
74
|
serviceTag
|
|
48
75
|
};
|
|
76
|
+
errorTypes[errorTag] = errorEntry;
|
|
77
|
+
if (item.sharedLibrary === true) {
|
|
78
|
+
sharedErrorTypes[errorTag] = errorEntry;
|
|
79
|
+
}
|
|
49
80
|
}
|
|
50
81
|
|
|
51
82
|
const sortedKeys = Object.keys(errorTypes).sort();
|
|
@@ -58,16 +89,95 @@ export async function emitErrorSchemas({
|
|
|
58
89
|
sortedErrorTypes[key] = errorTypes[key];
|
|
59
90
|
}
|
|
60
91
|
|
|
61
|
-
const templatePath = new URL('
|
|
92
|
+
const templatePath = new URL('errorConsts.ejs', TEMPLATE_URL);
|
|
62
93
|
const template = await readFile(templatePath, 'utf8');
|
|
63
94
|
const content = ejsLib.render(template, {
|
|
64
|
-
errorTypes: sortedErrorTypes
|
|
95
|
+
errorTypes: sortedErrorTypes,
|
|
96
|
+
headerComment: null
|
|
65
97
|
});
|
|
66
98
|
|
|
67
|
-
|
|
99
|
+
const artifacts = [
|
|
68
100
|
{
|
|
69
101
|
path: ERROR_SCHEMA_PATH,
|
|
70
102
|
content
|
|
71
103
|
}
|
|
72
104
|
];
|
|
105
|
+
|
|
106
|
+
const sortedSharedKeys = Object.keys(sharedErrorTypes).sort();
|
|
107
|
+
if (sortedSharedKeys.length > 0) {
|
|
108
|
+
const sortedSharedErrorTypes = {};
|
|
109
|
+
for (const key of sortedSharedKeys) {
|
|
110
|
+
sortedSharedErrorTypes[key] = sharedErrorTypes[key];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const sharedContent = ejsLib.render(template, {
|
|
114
|
+
errorTypes: sortedSharedErrorTypes,
|
|
115
|
+
headerComment: '// only generate error that sharedLibrary: true'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
let serviceName = 'service';
|
|
119
|
+
if (project?.serviceTag) {
|
|
120
|
+
serviceName = project.serviceTag.toLowerCase();
|
|
121
|
+
}
|
|
122
|
+
const packageName = `@izara_project/izara-${serviceName}-library-errorlib`;
|
|
123
|
+
|
|
124
|
+
let packageJson = {
|
|
125
|
+
name: packageName,
|
|
126
|
+
version: '1.0.0',
|
|
127
|
+
description: '',
|
|
128
|
+
type: 'module',
|
|
129
|
+
main: 'index.js',
|
|
130
|
+
scripts: {},
|
|
131
|
+
keywords: [],
|
|
132
|
+
author: '',
|
|
133
|
+
license: 'ISC',
|
|
134
|
+
devDependencies: {},
|
|
135
|
+
dependencies: {}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
let targetDir = project?.outputPath;
|
|
139
|
+
if (!targetDir) {
|
|
140
|
+
targetDir = project?.rootPath;
|
|
141
|
+
}
|
|
142
|
+
if (targetDir) {
|
|
143
|
+
const existingPkgPath = join(targetDir, SHARED_ERROR_PACKAGE_PATH);
|
|
144
|
+
if (existsSync(existingPkgPath)) {
|
|
145
|
+
try {
|
|
146
|
+
const raw = readFileSync(existingPkgPath, 'utf8');
|
|
147
|
+
const parsed = JSON.parse(raw);
|
|
148
|
+
if (parsed && typeof parsed === 'object') {
|
|
149
|
+
packageJson = {
|
|
150
|
+
...parsed,
|
|
151
|
+
name: packageName,
|
|
152
|
+
type: 'module',
|
|
153
|
+
main: 'index.js'
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
// If parsing fails (e.g. comments in JSON), use default packageJson
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const packageJsonContent = `${JSON.stringify(packageJson, null, 2)}\n`;
|
|
163
|
+
const indexContent =
|
|
164
|
+
"import * as errorLib from './src/errorConsts.js';\n\nexport { errorLib };\n";
|
|
165
|
+
|
|
166
|
+
artifacts.push(
|
|
167
|
+
{
|
|
168
|
+
path: SHARED_ERROR_PACKAGE_PATH,
|
|
169
|
+
content: packageJsonContent
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
path: SHARED_ERROR_INDEX_PATH,
|
|
173
|
+
content: indexContent
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
path: SHARED_ERROR_CONSTS_PATH,
|
|
177
|
+
content: sharedContent
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return artifacts;
|
|
73
183
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<% if (locals.headerComment) { -%>
|
|
2
|
+
<%- headerComment %>
|
|
3
|
+
<% } -%>
|
|
4
|
+
export const ERROR_TYPES = {
|
|
5
|
+
<% const keys = Object.keys(errorTypes); -%>
|
|
6
|
+
<% keys.forEach((key, index) => { -%>
|
|
7
|
+
<%- key %>: {
|
|
8
|
+
errorTag: '<%- errorTypes[key].errorTag %>',
|
|
9
|
+
serviceTag: '<%- errorTypes[key].serviceTag %>'
|
|
10
|
+
}<%- index < keys.length - 1 ? ',' : '' %>
|
|
11
|
+
<% }); -%>
|
|
12
|
+
};
|