@izara_project/izara-core-generate-service-code 1.0.66 → 1.0.68
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/.prettierrc +11 -0
- package/docs/TriggeredCache Flow.drawio +193 -0
- package/docs/TriggeredCacheFlow.mmd +47 -0
- package/package.json +16 -12
- package/scripts/format-ejs.js +105 -0
- package/src/compile/compileProject.js +16 -1
- package/src/compile/loadSchemas.js +108 -1
- package/src/emit/crud/emitCrudApplicationArtifacts.js +9 -5
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +1 -2
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +300 -109
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +221 -143
- package/src/emit/crud/templates/FlowEndpointBeforeLogical_Main.ejs +22 -6
- package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +150 -38
- package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +51 -31
- package/src/emit/crud/templates/FlowHandler_HdrApi.ejs +57 -31
- package/src/emit/crud/templates/FlowHandler_HdrInv.ejs +28 -26
- package/src/emit/crud/templates/FlowHandler_HdrSqs.ejs +15 -11
- package/src/emit/crud/templates/FlowMain_Wbs.ejs +53 -38
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +6 -3
- package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +2 -2
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +407 -252
- package/src/emit/custom/customFlows.js +112 -31
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +89 -77
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +49 -37
- package/src/emit/custom/templates/FlowStep_Main.ejs +7 -9
- package/src/emit/custom/templates/s3/ConfirmReserved_HdrSqs.ejs +59 -54
- package/src/emit/custom/templates/s3/ConfirmReserved_Main.ejs +33 -23
- package/src/emit/custom/templates/s3/CreateObject_HdrWbs.ejs +30 -23
- package/src/emit/custom/templates/s3/CreateObject_Main.ejs +56 -39
- package/src/emit/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +56 -51
- package/src/emit/custom/templates/s3/CreatePreSignUrl_Main.ejs +112 -75
- package/src/emit/custom/templates/s3/FlowHandler_HdrS3.ejs +12 -7
- package/src/emit/custom/templates/s3/ProcessS3File_Main.ejs +11 -8
- package/src/emit/custom/templates/s3/ReservedLimit_HdrSqs.ejs +64 -55
- package/src/emit/custom/templates/s3/ReservedLimit_Main.ejs +74 -52
- package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +58 -14
- package/src/emit/custom/templates/triggerCache/CheckTriggerCache_Main.ejs +12 -17
- package/src/emit/custom/templates/triggerCache/TriggerCacheComplete_Main.ejs +20 -13
- package/src/emit/custom/templates/triggerCache/TriggerCache_Main.ejs +4 -1
- package/src/emit/function/functionYamlArtifact.js +46 -12
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +28 -15
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +179 -66
- package/src/emit/rbac/templates/CreateTargetRole_HdrSqs.ejs +41 -18
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +23 -3
- package/src/emit/rbac/templates/ListRbac_HdrApi.ejs +27 -5
- package/src/emit/rbac/templates/ListRbac_HdrSqs.ejs +41 -8
- package/src/emit/rbac/templates/ListRbac_Main.ejs +26 -6
- package/src/emit/rbac/templates/RbacMutation_Main.ejs +23 -3
- package/src/emit/rbac/templates/UserRbacFlow_HdrSqs.ejs +46 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +152 -33
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +24 -4
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -2
- package/src/emit/relationship/emitRelationshipApplicationArtifacts.js +6 -5
- package/src/emit/relationship/templates/ChangeRelationshipComplete_Main.ejs +64 -37
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +260 -144
- package/src/emit/relationship/templates/CreateRelationshipComplete_Main.ejs +68 -43
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +315 -171
- package/src/emit/relationship/templates/DeleteRelationshipComplete_Main.ejs +67 -41
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +226 -115
- package/src/emit/relationship/templates/FlowHandler_HdrApi.ejs +41 -33
- package/src/emit/relationship/templates/FlowHandler_HdrDsq.ejs +15 -11
- package/src/emit/relationship/templates/FlowHandler_HdrInv.ejs +28 -26
- package/src/emit/relationship/templates/FlowHandler_HdrSqs.ejs +15 -11
- package/src/emit/relationship/templates/GetRelationshipComplete_Main.ejs +46 -26
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +233 -126
- package/src/emit/relationship/templates/MoveRelationshipComplete_Main.ejs +72 -44
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +266 -150
- package/src/emit/relationship/templates/UpdateRelationshipComplete_Main.ejs +74 -45
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +285 -152
- package/src/emit/resource/emitResourceArtifacts.js +499 -108
- package/src/emit/resource/templates/DynamoDBTable_Yaml.ejs +18 -18
- package/src/emit/resource/templates/FlowOut_Yaml.ejs +5 -5
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +138 -0
- package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +44 -44
- package/src/emit/resource/templates/ResourceSqsYaml.ejs +36 -36
- package/src/emit/resource/templates/ResourceYaml.ejs +48 -48
- package/src/emit/resource/templates/S3Bucket_Yaml.ejs +19 -0
- package/src/emit/resource/templates/SharedResource_Yaml.ejs +11 -11
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +105 -105
- package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
- package/src/generate.js +8 -4
- package/test/createTargetRoleHandler.test.js +63 -14
- package/test/crudApplicationArtifacts.test.js +1 -1
- package/test/customFlowApplicationArtifacts.test.js +71 -43
- package/test/dynamicCrudFlowSchemas.test.js +6 -6
- package/test/dynamicRbacFlowSchemas.test.js +8 -12
- package/test/dynamicRelationshipFlowSchemas.test.js +3 -3
- package/test/publicApi.test.js +11 -13
- package/test/resourceArtifacts.test.js +13 -3
- package/src/emit/rbac/templates/UserRbacFlow_HdrInv.ejs +0 -10
|
@@ -25,13 +25,13 @@ test('emits handlers, function YAML, and IAM roles for supported custom flow eve
|
|
|
25
25
|
const result = await generateCustomFlowApplicationArtifacts(rootPath);
|
|
26
26
|
await generateResourceArtifacts(rootPath);
|
|
27
27
|
|
|
28
|
-
assert.equal(result.files.length,
|
|
29
|
-
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Ext/source/
|
|
30
|
-
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Api/source/
|
|
28
|
+
assert.equal(result.files.length, 38);
|
|
29
|
+
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Ext/source/Ext_HdrSqs.js'), 'utf8'), /dummyId/);
|
|
30
|
+
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Api/source/Api_HdrApi.js'), 'utf8'), /Api/);
|
|
31
31
|
const yaml = await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8');
|
|
32
|
-
assert.match(yaml, /
|
|
32
|
+
assert.match(yaml, /EventHdrInv:/);
|
|
33
33
|
assert.match(yaml, /rate\(1 minute\)/);
|
|
34
|
-
assert.match(yaml, /
|
|
34
|
+
assert.match(yaml, /ExtHdrSqs:/);
|
|
35
35
|
const iam = await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'), 'utf8');
|
|
36
36
|
assert.match(iam, /EventRole:/);
|
|
37
37
|
assert.match(iam, /ExtRole:/);
|
|
@@ -50,13 +50,11 @@ test('emits handlers, function YAML, and IAM roles for supported custom flow eve
|
|
|
50
50
|
/"CurrentOrderTable"/
|
|
51
51
|
);
|
|
52
52
|
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Own/source/ProcessOwn_Main.js')));
|
|
53
|
-
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Mixed/source/Mixed_HdrSqs.js'), 'utf8'), /
|
|
54
|
-
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Mixed/source/ProcessMixed_HdrSqs.js'), 'utf8'), /ProcessMixed/);
|
|
53
|
+
assert.match(await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Mixed/source/Mixed_HdrSqs.js'), 'utf8'), /Mixed/);
|
|
55
54
|
assert.match(yaml, /OwnHdrWbs:/);
|
|
56
55
|
assert.match(yaml, /OwnHdrSqs:/);
|
|
57
56
|
assert.ok(yaml.indexOf('OwnHdrWbs:') < yaml.indexOf('OwnHdrSqs:'));
|
|
58
57
|
assert.match(yaml, /MixedHdrSqs:/);
|
|
59
|
-
assert.match(yaml, /ProcessMixedHdrSqs:/);
|
|
60
58
|
assert.match(yaml, /UploadProcessAfterUploadHdrS3:/);
|
|
61
59
|
assert.match(
|
|
62
60
|
await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Upload/source/UploadProcessAfterUpload_Main.js'), 'utf8'),
|
|
@@ -111,10 +109,10 @@ test('emits handlers, function YAML, and IAM roles for supported custom flow eve
|
|
|
111
109
|
test('removes only V2-owned custom-flow application artifacts when supported events are removed', async () => {
|
|
112
110
|
const rootPath = await createProject();
|
|
113
111
|
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
114
|
-
await writeFile(join(rootPath, 'app/src/schemas/FlowSchemas/Flows.js'), "export default [{ flowTag: 'later', event: ['
|
|
112
|
+
await writeFile(join(rootPath, 'app/src/schemas/FlowSchemas/Flows.js'), "export default [{ flowTag: 'later', event: ['unsupported'] }];\n");
|
|
115
113
|
|
|
116
114
|
assert.deepEqual((await generateCustomFlowApplicationArtifacts(rootPath)).files, []);
|
|
117
|
-
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Ext/source/
|
|
115
|
+
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Ext/source/Ext_HdrSqs.js')));
|
|
118
116
|
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Own/source/Own_HdrWbs.js')));
|
|
119
117
|
await assert.rejects(readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml')));
|
|
120
118
|
});
|
|
@@ -126,6 +124,7 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
|
|
|
126
124
|
|
|
127
125
|
assert.ok(result.files.some(file => file.path === 'app/src/generatedCode/FlowSchemas/Stepped/source/SteppedComplete_HdrSqs.js'));
|
|
128
126
|
assert.ok(result.files.some(file => file.path === 'app/src/generatedCode/FlowSchemas/Generated/source/GeneratedComplete_HdrSqs.js'));
|
|
127
|
+
assert.ok(result.files.some(file => file.path === 'app/src/generatedCode/FlowSchemas/DsqStep/source/DsqStepRetryDsq_HdrDsq.js'));
|
|
129
128
|
assert.match(
|
|
130
129
|
await readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Stepped/source/SteppedComplete_Main.js'), 'utf8'),
|
|
131
130
|
/identifierUuid/
|
|
@@ -134,10 +133,18 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
|
|
|
134
133
|
await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8'),
|
|
135
134
|
/SteppedCompleteHdrSqs:\n handler: src\/generatedCode\/FlowSchemas\/Stepped\/source\/SteppedComplete_HdrSqs.main/
|
|
136
135
|
);
|
|
136
|
+
assert.match(
|
|
137
|
+
await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8'),
|
|
138
|
+
/DsqStepRetryDsqHdrDsq:\n handler: src\/generatedCode\/FlowSchemas\/DsqStep\/source\/DsqStepRetryDsq_HdrDsq.main/
|
|
139
|
+
);
|
|
137
140
|
assert.match(
|
|
138
141
|
await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'), 'utf8'),
|
|
139
142
|
/^ SteppedCompleteHdrSqs:/m
|
|
140
143
|
);
|
|
144
|
+
assert.match(
|
|
145
|
+
await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'), 'utf8'),
|
|
146
|
+
/^ DsqStepRetryDsqHdrDsq:/m
|
|
147
|
+
);
|
|
141
148
|
assert.match(
|
|
142
149
|
await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'), 'utf8'),
|
|
143
150
|
/GeneratedRole:/
|
|
@@ -156,20 +163,15 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
|
|
|
156
163
|
);
|
|
157
164
|
});
|
|
158
165
|
|
|
159
|
-
test('emits and removes the
|
|
160
|
-
const rootPath = await createTriggerCacheProject();
|
|
166
|
+
test('emits and removes the trigger-cache artifact suite when triggerFlowTypes is set', async () => {
|
|
167
|
+
const rootPath = await createTriggerCacheProject(['OrderCheckout']);
|
|
161
168
|
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
162
169
|
await generateResourceArtifacts(rootPath);
|
|
163
170
|
|
|
164
171
|
const source = 'app/src/generatedCode/FlowSchemas/Cart/source';
|
|
165
172
|
for (const fileName of [
|
|
166
|
-
'
|
|
167
|
-
'
|
|
168
|
-
'CheckTriggerCacheCartComplete_Main.js',
|
|
169
|
-
'CheckTriggerCacheCartComplete_HdrSqs.js',
|
|
170
|
-
'TriggerCacheCartComplete_Main.js',
|
|
171
|
-
'TriggerCacheCartComplete_HdrSqs.js',
|
|
172
|
-
'TriggerCacheCartComplete_HdrDsq.js'
|
|
173
|
+
'CartCheckTriggerFlows_Main.js',
|
|
174
|
+
'CartCheckTriggerFlows_HdrSqs.js'
|
|
173
175
|
]) {
|
|
174
176
|
const path = join(rootPath, source, fileName);
|
|
175
177
|
await access(path);
|
|
@@ -177,39 +179,60 @@ test('emits and removes the legacy trigger-cache artifact suite', async () => {
|
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
const flowYaml = await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8');
|
|
180
|
-
|
|
181
|
-
'ProcessTriggerCacheCartHdrDsq',
|
|
182
|
-
'CheckTriggerCacheCartCompleteHdrSqs',
|
|
183
|
-
'TriggerCacheCartCompleteHdrSqs',
|
|
184
|
-
'TriggerCacheCartCompleteHdrDsq'
|
|
185
|
-
]) {
|
|
186
|
-
assert.match(flowYaml, new RegExp(`^${functionName}:`, 'm'));
|
|
187
|
-
}
|
|
182
|
+
assert.match(flowYaml, /^CartCheckTriggerFlowsHdrSqs:/m);
|
|
188
183
|
assert.match(
|
|
189
|
-
await readFile(join(rootPath, `${source}/
|
|
190
|
-
/
|
|
184
|
+
await readFile(join(rootPath, `${source}/CartCheckTriggerFlows_HdrSqs.js`), 'utf8'),
|
|
185
|
+
/CartCheckTriggerFlowsHdrSqs/
|
|
191
186
|
);
|
|
192
187
|
|
|
193
188
|
const resources = await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'), 'utf8');
|
|
194
|
-
assert.match(resources, /^
|
|
189
|
+
assert.match(resources, /^ CartHdrSqs:/m);
|
|
195
190
|
for (const queueName of [
|
|
196
|
-
'
|
|
197
|
-
'
|
|
198
|
-
'TriggerCacheCartCompleteHdrSqs',
|
|
199
|
-
'TriggerCacheCartCompleteHdrDsq'
|
|
191
|
+
'CartHdrSqs',
|
|
192
|
+
'CartCheckTriggerFlowsHdrSqs'
|
|
200
193
|
]) assert.match(resources, new RegExp('QueueName: \\$\\{self:custom\\.iz_resourcePrefix\\}' + queueName));
|
|
201
|
-
const iam = await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'), 'utf8');
|
|
202
|
-
for (const queueName of ['OrderCart_Main', 'CheckTriggerCacheCartCompleteHdrSqs', 'TriggerCacheCartCompleteHdrSqs', 'TriggerCacheCartCompleteHdrDsq']) {
|
|
203
|
-
assert.match(iam, new RegExp(`CartRole:[\\s\\S]*${queueName}`));
|
|
204
|
-
}
|
|
205
194
|
|
|
206
195
|
await writeFile(join(rootPath, 'app/src/schemas/FlowSchemas/Cart.js'), "export default { flowTag: 'cart', event: ['ownTopic'], statusType: 'none' };\n");
|
|
207
196
|
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
208
197
|
await generateResourceArtifacts(rootPath);
|
|
209
198
|
|
|
210
|
-
await assert.rejects(readFile(join(rootPath, `${source}/
|
|
211
|
-
assert.doesNotMatch(await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8'), /
|
|
212
|
-
|
|
199
|
+
await assert.rejects(readFile(join(rootPath, `${source}/CartCheckTriggerFlows_Main.js`)));
|
|
200
|
+
assert.doesNotMatch(await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8'), /CartCheckTriggerFlowsHdrSqs/);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test('uses custom CheckTrigger step if provided by developer in flowSteps', async () => {
|
|
204
|
+
const rootPath = await mkdtemp(join(tmpdir(), 'generate-service-code-v2-trigger-cache-custom-'));
|
|
205
|
+
roots.add(rootPath);
|
|
206
|
+
const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
|
|
207
|
+
await mkdir(schemaRoot, { recursive: true });
|
|
208
|
+
await writeFile(
|
|
209
|
+
join(schemaRoot, 'Cart.js'),
|
|
210
|
+
"export default { flowTag: 'cart', event: ['ownTopic'], statusType: 'triggerCache', triggerFlowTypes: ['OrderCheckout'], objType: { serviceTag: 'Order' }, flowSteps: [{ stepName: 'start' }, { stepName: 'CheckTriggerCustomStep', event: ['extTopic'] }] };\n"
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
214
|
+
const source = 'app/src/generatedCode/FlowSchemas/Cart/source';
|
|
215
|
+
const path = join(rootPath, source, 'CartCheckTriggerCustomStep_Main.js');
|
|
216
|
+
await access(path);
|
|
217
|
+
await parseAsEsm(path);
|
|
218
|
+
|
|
219
|
+
const flowYaml = await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8');
|
|
220
|
+
assert.match(flowYaml, /^CartCheckTriggerCustomStepHdrSqs:/m);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('does not emit check trigger-cache artifacts when triggerFlowTypes is empty, null, undefined, or missing', async () => {
|
|
224
|
+
for (const emptyTriggerFlowTypes of [[], null, undefined]) {
|
|
225
|
+
const rootPath = await createTriggerCacheProject(emptyTriggerFlowTypes);
|
|
226
|
+
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
227
|
+
await generateResourceArtifacts(rootPath);
|
|
228
|
+
|
|
229
|
+
const source = 'app/src/generatedCode/FlowSchemas/Cart/source';
|
|
230
|
+
await assert.rejects(readFile(join(rootPath, `${source}/CartCheckTriggerFlows_Main.js`)));
|
|
231
|
+
await assert.rejects(readFile(join(rootPath, `${source}/CartCheckTriggerFlows_HdrSqs.js`)));
|
|
232
|
+
|
|
233
|
+
const flowYaml = await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8');
|
|
234
|
+
assert.doesNotMatch(flowYaml, /CartCheckTriggerFlowsHdrSqs/);
|
|
235
|
+
}
|
|
213
236
|
});
|
|
214
237
|
|
|
215
238
|
test('rejects an EventBridge schedule without a deployable name and rate', () => {
|
|
@@ -278,17 +301,22 @@ async function createStepProject() {
|
|
|
278
301
|
join(schemaRoot, 'Generated.js'),
|
|
279
302
|
"export default { flowTag: 'generated', event: ['ownTopic'], generatedCodeConfig: { generatedCodeTag: 'create' }, flowSteps: [{ stepName: 'start' }, { stepName: 'Complete', event: ['extTopic'] }] };\n"
|
|
280
303
|
);
|
|
304
|
+
await writeFile(
|
|
305
|
+
join(schemaRoot, 'DsqStep.js'),
|
|
306
|
+
"export default { flowTag: 'dsqStep', event: ['extTopic'], flowSteps: [{ stepName: 'start' }, { stepName: 'RetryDsq', event: ['dsq'] }] };\n"
|
|
307
|
+
);
|
|
281
308
|
return rootPath;
|
|
282
309
|
}
|
|
283
310
|
|
|
284
|
-
async function createTriggerCacheProject() {
|
|
311
|
+
async function createTriggerCacheProject(triggerFlowTypes) {
|
|
285
312
|
const rootPath = await mkdtemp(join(tmpdir(), 'generate-service-code-v2-trigger-cache-'));
|
|
286
313
|
roots.add(rootPath);
|
|
287
314
|
const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
|
|
288
315
|
await mkdir(schemaRoot, { recursive: true });
|
|
316
|
+
const triggerFlowTypesAttr = Array.isArray(triggerFlowTypes) && triggerFlowTypes.length > 0 ? `triggerFlowTypes: ${JSON.stringify(triggerFlowTypes)}, ` : '';
|
|
289
317
|
await writeFile(
|
|
290
318
|
join(schemaRoot, 'Cart.js'),
|
|
291
|
-
|
|
319
|
+
`export default { flowTag: 'cart', event: ['ownTopic'], statusType: 'triggerCache', ${triggerFlowTypesAttr}objType: { serviceTag: 'Order' }, flowSteps: [{ stepName: 'start' }] };\n`
|
|
292
320
|
);
|
|
293
321
|
return rootPath;
|
|
294
322
|
}
|
|
@@ -15,10 +15,10 @@ test('generates dynamic CRUD schemas from local schema modules', async () => {
|
|
|
15
15
|
|
|
16
16
|
const result = await generateDynamicCrudFlowSchemas(rootPath);
|
|
17
17
|
assert.deepEqual(result.files.map(file => file.path), [
|
|
18
|
-
'app/src/schemas/FlowSchemas/generateCode/Create.js',
|
|
19
|
-
'app/src/schemas/FlowSchemas/generateCode/Update.js',
|
|
20
|
-
'app/src/schemas/FlowSchemas/generateCode/Delete.js',
|
|
21
|
-
'app/src/schemas/FlowSchemas/generateCode/Get.js'
|
|
18
|
+
'app/src/schemas/FlowSchemas/generateCode/FlowObjects/Create.js',
|
|
19
|
+
'app/src/schemas/FlowSchemas/generateCode/FlowObjects/Update.js',
|
|
20
|
+
'app/src/schemas/FlowSchemas/generateCode/FlowObjects/Delete.js',
|
|
21
|
+
'app/src/schemas/FlowSchemas/generateCode/FlowObjects/Get.js'
|
|
22
22
|
]);
|
|
23
23
|
|
|
24
24
|
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
@@ -127,10 +127,10 @@ function createHookFlow(event) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
async function readGeneratedFlow(rootPath, action) {
|
|
130
|
-
const filePath = join(rootPath, 'app/src/schemas/FlowSchemas/generateCode', `${action}.js`);
|
|
130
|
+
const filePath = join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowObjects', `${action}.js`);
|
|
131
131
|
return import(`${pathToFileURL(filePath).href}?test=${process.hrtime.bigint()}`).then(module => module.default);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
function readGeneratedFile(rootPath, action) {
|
|
135
|
-
return readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode', `${action}.js`), 'utf8');
|
|
135
|
+
return readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowObjects', `${action}.js`), 'utf8');
|
|
136
136
|
}
|
|
@@ -30,20 +30,16 @@ test('generates shared and object-specific RBAC flow schemas', async () => {
|
|
|
30
30
|
const result = await generateDynamicRbacFlowSchemas(rootPath, { serviceTag: 'UserAccount' });
|
|
31
31
|
|
|
32
32
|
assert.deepEqual(result.files.map(file => file.path), [
|
|
33
|
-
...STATIC_ACTIONS.map(action => `app/src/schemas/FlowSchemas/generateCode/${action}.js`),
|
|
34
|
-
'app/src/schemas/FlowSchemas/generateCode/UserRbacFlow.js'
|
|
33
|
+
...STATIC_ACTIONS.map(action => `app/src/schemas/FlowSchemas/generateCode/FlowRbac/${action}.js`),
|
|
34
|
+
'app/src/schemas/FlowSchemas/generateCode/FlowRbac/UserRbacFlow.js'
|
|
35
35
|
]);
|
|
36
36
|
const createTargetRole = await readGeneratedFlow(rootPath, 'CreateTargetRole');
|
|
37
|
-
const listTargetRole = await readGeneratedFlow(rootPath, 'ListTargetRole');
|
|
38
37
|
const user = await readGeneratedFlow(rootPath, 'UserRbacFlow');
|
|
39
38
|
assert.deepEqual(createTargetRole.flowSteps[0].returnValues, {
|
|
40
39
|
properties: ['returnResult'],
|
|
41
40
|
messageAttributes: []
|
|
42
41
|
});
|
|
43
|
-
assert.deepEqual(
|
|
44
|
-
assert.equal(listTargetRole.outputTopic, true);
|
|
45
|
-
assert.deepEqual(user.objType, { serviceTag: 'UserAccount', objectType: 'user' });
|
|
46
|
-
assert.deepEqual(user.flowSteps[0].messageAttributes, ['userId', 'correlationId']);
|
|
42
|
+
assert.deepEqual(user.event, ['ownTopic']);
|
|
47
43
|
assert.equal(user.steps, undefined);
|
|
48
44
|
});
|
|
49
45
|
|
|
@@ -56,8 +52,8 @@ test('removes RBAC schemas when the last RBAC object is removed', async () => {
|
|
|
56
52
|
const result = await generateDynamicRbacFlowSchemas(rootPath);
|
|
57
53
|
|
|
58
54
|
assert.deepEqual(result.files, []);
|
|
59
|
-
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/CreateTargetRole.js')));
|
|
60
|
-
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/UserRbacFlow.js')));
|
|
55
|
+
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowRbac/CreateTargetRole.js')));
|
|
56
|
+
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowRbac/UserRbacFlow.js')));
|
|
61
57
|
});
|
|
62
58
|
|
|
63
59
|
test('requires a serviceTag only when RBAC schemas are needed', async () => {
|
|
@@ -79,7 +75,7 @@ test('removes object-specific RBAC schemas when the ObjectSchema file is deleted
|
|
|
79
75
|
|
|
80
76
|
await generateDynamicRbacFlowSchemas(rootPath);
|
|
81
77
|
|
|
82
|
-
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/UserRbacFlow.js')));
|
|
78
|
+
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowRbac/UserRbacFlow.js')));
|
|
83
79
|
});
|
|
84
80
|
|
|
85
81
|
async function createProject({ hasRbac = false } = {}) {
|
|
@@ -89,13 +85,13 @@ async function createProject({ hasRbac = false } = {}) {
|
|
|
89
85
|
await mkdir(objectDirectory, { recursive: true });
|
|
90
86
|
await writeFile(
|
|
91
87
|
join(objectDirectory, 'User.js'),
|
|
92
|
-
`export default { objectType: 'user', addOnDataStructure: ${hasRbac ? "[{ type: 'rbac' }]" : '[]'} };\n`
|
|
88
|
+
`export default { objectType: 'user', fieldNames: [], identifiers: [], addOnDataStructure: ${hasRbac ? "[{ type: 'rbac' }]" : '[]'} };\n`
|
|
93
89
|
);
|
|
94
90
|
return rootPath;
|
|
95
91
|
}
|
|
96
92
|
|
|
97
93
|
async function readGeneratedFlow(rootPath, flowTag) {
|
|
98
|
-
const filePath = join(rootPath, 'app/src/schemas/FlowSchemas/generateCode', `${flowTag}.js`);
|
|
94
|
+
const filePath = join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowRbac', `${flowTag}.js`);
|
|
99
95
|
const module = await import(`${pathToFileURL(filePath).href}?test=${process.hrtime.bigint()}`);
|
|
100
96
|
return module.default;
|
|
101
97
|
}
|
|
@@ -30,7 +30,7 @@ test('generates dynamic relationship schemas even without declared relationships
|
|
|
30
30
|
|
|
31
31
|
assert.deepEqual(
|
|
32
32
|
result.files.map(file => file.path),
|
|
33
|
-
RELATIONSHIP_ACTIONS.map(action => `app/src/schemas/FlowSchemas/generateCode/${action}.js`)
|
|
33
|
+
RELATIONSHIP_ACTIONS.map(action => `app/src/schemas/FlowSchemas/generateCode/FlowRelationship/${action}.js`)
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
const create = await readGeneratedFlow(rootPath, 'CreateRelationship');
|
|
@@ -74,7 +74,7 @@ test('does not allow options to override the rootPath argument', async () => {
|
|
|
74
74
|
assert.equal(result.project.rootPath, rootPath);
|
|
75
75
|
assert.equal(result.files.length, 6);
|
|
76
76
|
assert.match(
|
|
77
|
-
await readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/CreateRelationship.js'), 'utf8'),
|
|
77
|
+
await readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowRelationship/CreateRelationship.js'), 'utf8'),
|
|
78
78
|
/export default/
|
|
79
79
|
);
|
|
80
80
|
});
|
|
@@ -93,7 +93,7 @@ async function createProject({ singletonExport = false } = {}) {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
async function readGeneratedFlow(rootPath, action) {
|
|
96
|
-
const filePath = join(rootPath, 'app/src/schemas/FlowSchemas/generateCode', `${action}.js`);
|
|
96
|
+
const filePath = join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowRelationship', `${action}.js`);
|
|
97
97
|
const module = await import(`${pathToFileURL(filePath).href}?test=${process.hrtime.bigint()}`);
|
|
98
98
|
return module.default;
|
|
99
99
|
}
|
package/test/publicApi.test.js
CHANGED
|
@@ -21,7 +21,7 @@ test('generate commits schemas, application artifacts, and resources in one publ
|
|
|
21
21
|
const rootPath = await createCrudProject();
|
|
22
22
|
const result = await generate(rootPath);
|
|
23
23
|
|
|
24
|
-
assert.
|
|
24
|
+
assert.strictEqual(result.files.length, 39);
|
|
25
25
|
assert.equal(result.project.rootPath, rootPath);
|
|
26
26
|
assert.match(
|
|
27
27
|
await readFile(join(rootPath, 'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'), 'utf8'),
|
|
@@ -99,22 +99,21 @@ test('generate commits the system WebSocket completion path for own-topic flows'
|
|
|
99
99
|
assert.match(webSocketHandler, /addCallingFlowToPassOnProperties/);
|
|
100
100
|
});
|
|
101
101
|
|
|
102
|
-
test('generate commits the
|
|
102
|
+
test('generate commits the trigger-cache suite with its queues when triggerFlowTypes is set', async () => {
|
|
103
103
|
const rootPath = await createTriggerCacheProject();
|
|
104
104
|
const result = await generate(rootPath);
|
|
105
105
|
|
|
106
106
|
for (const path of [
|
|
107
|
-
'app/src/generatedCode/FlowSchemas/Cart/source/
|
|
108
|
-
'app/src/generatedCode/FlowSchemas/Cart/source/
|
|
109
|
-
'app/src/generatedCode/FlowSchemas/Cart/source/TriggerCacheCartComplete_HdrDsq.js'
|
|
107
|
+
'app/src/generatedCode/FlowSchemas/Cart/source/CartCheckTriggerFlows_HdrSqs.js',
|
|
108
|
+
'app/src/generatedCode/FlowSchemas/Cart/source/CartCheckTriggerFlows_Main.js'
|
|
110
109
|
]) assert.ok(result.files.some(file => file.path === path));
|
|
111
110
|
assert.match(
|
|
112
111
|
await readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'), 'utf8'),
|
|
113
|
-
/
|
|
112
|
+
/CartCheckTriggerFlowsHdrSqs:/
|
|
114
113
|
);
|
|
115
114
|
assert.match(
|
|
116
115
|
await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'), 'utf8'),
|
|
117
|
-
/
|
|
116
|
+
/CartCheckTriggerFlowsHdrSqs/
|
|
118
117
|
);
|
|
119
118
|
});
|
|
120
119
|
|
|
@@ -127,7 +126,6 @@ test('generate removes the system WebSocket path when the last own-topic flow is
|
|
|
127
126
|
|
|
128
127
|
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/SystemFlowSchemas/WebSocketMain/source/WebSocketComplete_HdrSqs.js')));
|
|
129
128
|
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/FlowSchemas/Track/source/Track_HdrWbs.js')));
|
|
130
|
-
await assert.rejects(readFile(join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml')));
|
|
131
129
|
assert.doesNotMatch(
|
|
132
130
|
await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'), 'utf8'),
|
|
133
131
|
/WebSocketCompleteHdrSqs/
|
|
@@ -142,7 +140,7 @@ test('generate rolls back every slice when one output target conflicts', async (
|
|
|
142
140
|
generate(rootPath),
|
|
143
141
|
/not a file/
|
|
144
142
|
);
|
|
145
|
-
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/Create.js')));
|
|
143
|
+
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowObjects/Create.js')));
|
|
146
144
|
});
|
|
147
145
|
|
|
148
146
|
test('generate removes stale CRUD schemas and application artifacts', async () => {
|
|
@@ -155,8 +153,8 @@ test('generate removes stale CRUD schemas and application artifacts', async () =
|
|
|
155
153
|
|
|
156
154
|
const result = await generate(rootPath);
|
|
157
155
|
|
|
158
|
-
assert.equal(result.files.length,
|
|
159
|
-
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/Create.js')));
|
|
156
|
+
assert.equal(result.files.length, 11);
|
|
157
|
+
await assert.rejects(readFile(join(rootPath, 'app/src/schemas/FlowSchemas/generateCode/FlowObjects/Create.js')));
|
|
160
158
|
await assert.rejects(readFile(join(rootPath, 'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js')));
|
|
161
159
|
assert.match(
|
|
162
160
|
await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-dynamoDB-table.yml'), 'utf8'),
|
|
@@ -192,7 +190,7 @@ async function createOwnTopicProject() {
|
|
|
192
190
|
await mkdir(flowDirectory, { recursive: true });
|
|
193
191
|
await writeFile(
|
|
194
192
|
join(flowDirectory, 'Track.js'),
|
|
195
|
-
"export default { flowTag: 'track', event: ['ownTopic'], outputTopic: true, statusType: 'none', generatedCodeConfig: { generatedCodeTag: 'create', codeHookTag: 'beforeLogical', invocationType: 'ownTopic' } };\n"
|
|
193
|
+
"export default { flowTag: 'track', event: ['ownTopic'], initiateBy: 'user', outputTopic: true, statusType: 'none', generatedCodeConfig: { generatedCodeTag: 'create', codeHookTag: 'beforeLogical', invocationType: 'ownTopic' } };\n"
|
|
196
194
|
);
|
|
197
195
|
return rootPath;
|
|
198
196
|
}
|
|
@@ -203,7 +201,7 @@ async function createTriggerCacheProject() {
|
|
|
203
201
|
await mkdir(flowDirectory, { recursive: true });
|
|
204
202
|
await writeFile(
|
|
205
203
|
join(flowDirectory, 'Cart.js'),
|
|
206
|
-
"export default { flowTag: 'cart', event: ['ownTopic'], statusType: 'triggerCache', objType: { serviceTag: 'Order' } };\n"
|
|
204
|
+
"export default { flowTag: 'cart', event: ['ownTopic'], statusType: 'triggerCache', triggerFlowTypes: ['OrderCheckout'], objType: { serviceTag: 'Order' }, flowSteps: [{ stepName: 'start' }] };\n"
|
|
207
205
|
);
|
|
208
206
|
return rootPath;
|
|
209
207
|
}
|
|
@@ -13,7 +13,7 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
|
|
|
13
13
|
const rootPath = await createProject();
|
|
14
14
|
const result = await generateResourceArtifacts(rootPath);
|
|
15
15
|
|
|
16
|
-
assert.equal(result.files.length,
|
|
16
|
+
assert.equal(result.files.length, 5);
|
|
17
17
|
const resources = await readFile(join(rootPath, 'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'), 'utf8');
|
|
18
18
|
assert.match(resources, /InCreate:/);
|
|
19
19
|
for (const queueName of ['FindDataHdrSqs', 'ProcessLogicalHdrSqs', 'PaginateProcessLogicalHdrDsq', 'PaginateProcessLogicalHdrSqs']) {
|
|
@@ -47,11 +47,21 @@ test('emits queues, topics, tables, and IAM roles from schema data', async () =>
|
|
|
47
47
|
assert.doesNotMatch(roleBlock(iam, 'RegisterRole'), /dynamodb:|sqs:|sns:/);
|
|
48
48
|
assert.doesNotMatch(iam, /s3:GetObjectVersion|s3:ListBucket|sqs:DeleteMessageBatch|sqs:GetQueueUrl/);
|
|
49
49
|
assert.match(iam, /#<#\/\w+StatementHookCode#>\n\n \w+Role:/);
|
|
50
|
+
|
|
51
|
+
const lambdaRoleConfig = await readFile(join(rootPath, 'app/initial_setup/generatedCode/source/generatedLambdaRoleServiceConfig.js'), 'utf8');
|
|
52
|
+
assert.match(lambdaRoleConfig, /roleName: 'FlowObjects'/);
|
|
53
|
+
assert.match(lambdaRoleConfig, /roleName: 'ProcFindData'/);
|
|
54
|
+
assert.match(lambdaRoleConfig, /roleName: 'FlowRelationship'/);
|
|
55
|
+
assert.doesNotMatch(lambdaRoleConfig, /roleName: 'FlowObjectsRole'/);
|
|
56
|
+
assert.doesNotMatch(lambdaRoleConfig, /roleName: 'ProcFindDataRole'/);
|
|
57
|
+
assert.doesNotMatch(lambdaRoleConfig, /roleName: 'FlowRelationshipRole'/);
|
|
58
|
+
|
|
50
59
|
for (const filePath of [
|
|
51
60
|
'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml',
|
|
52
61
|
'resource/sls_yaml/generatedCode/source/generated-sns-out.yml',
|
|
53
62
|
'resource/sls_yaml/generatedCode/source/generated-dynamoDB-table.yml',
|
|
54
|
-
'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
|
|
63
|
+
'app/sls_yaml/generatedCode/source/generate-shared-resource.yml',
|
|
64
|
+
'app/initial_setup/generatedCode/source/generatedLambdaRoleServiceConfig.js'
|
|
55
65
|
]) {
|
|
56
66
|
assert.doesNotMatch(await readFile(join(rootPath, filePath), 'utf8'), /\n\n$/);
|
|
57
67
|
}
|
|
@@ -84,7 +94,7 @@ test('emits the shared WebSocket completion queue and output-topic subscriptions
|
|
|
84
94
|
for (const roleName of ['WebSocketMainRole', 'FlowObjectsRole', 'FlowRelationshipRole', 'FlowRbacRole', 'CustomRole', 'UploadRole']) {
|
|
85
95
|
const role = roleBlock(iam, roleName);
|
|
86
96
|
assert.match(role, /execute-api:ManageConnections/);
|
|
87
|
-
assert.match(role, /arn:aws:execute-api:\$\{self:custom\.iz_region\}:\$\{self:custom\.iz_accountId\}
|
|
97
|
+
assert.match(role, /arn:aws:execute-api:\$\{self:custom\.iz_region\}:\$\{self:custom\.iz_accountId\}:\*\/\*/);
|
|
88
98
|
}
|
|
89
99
|
assert.match(resources, /SubscriptionToOutCreateRelationshipWebSocketComplete:/);
|
|
90
100
|
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { middlewareHandler as middleware } from '@izara_project/izara-middleware';
|
|
2
|
-
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
3
|
-
import Process<%- flowTag %> from './Process<%- flowTag %>_Main.js';
|
|
4
|
-
|
|
5
|
-
middleware.setValidatorSchema({});
|
|
6
|
-
export const main = middleware.wrap(async event => Process<%- flowTag %>(
|
|
7
|
-
event._izContext,
|
|
8
|
-
event,
|
|
9
|
-
callingFlowSharedLib.addCallingFlowToPassOnProperties(event)
|
|
10
|
-
));
|