@izara_project/izara-core-generate-service-code 1.0.99 → 1.0.101

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/package.json +1 -1
  2. package/src/compile/compileProject.js +16 -5
  3. package/src/compile/flowValidator.js +3 -1
  4. package/src/compile/loadSchemas.js +18 -4
  5. package/src/compile/schemaValidatorSetup.js +16 -0
  6. package/src/emit/application/coreFunction/emitCoreFunctionArtifacts.js +108 -108
  7. package/src/emit/application/coreFunction/templates/InitialSetupRunner.ejs +2 -2
  8. package/src/emit/application/crud/templates/CreateComplete_Main.ejs +2 -0
  9. package/src/emit/application/crud/templates/CreateLogicalLib.ejs +20 -7
  10. package/src/emit/application/crud/templates/DeleteComplete_Main.ejs +2 -0
  11. package/src/emit/application/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -5
  12. package/src/emit/application/crud/templates/UpdateComplete_Main.ejs +2 -0
  13. package/src/emit/application/custom/customFlowPaths.js +13 -16
  14. package/src/emit/application/custom/customFlowS3.js +456 -63
  15. package/src/emit/application/custom/customFlows.js +131 -0
  16. package/src/emit/application/custom/emitCustomFlowApplicationArtifacts.js +7 -4
  17. package/src/emit/application/custom/templates/s3/ConfirmAfterUpload_HdrSqs.ejs +111 -0
  18. package/src/emit/application/custom/templates/s3/ConfirmAfterUpload_Main.ejs +89 -0
  19. package/src/emit/application/custom/templates/s3/ConfirmComplete_HdrSqs.ejs +111 -0
  20. package/src/emit/application/custom/templates/s3/ConfirmComplete_Main.ejs +100 -0
  21. package/src/emit/application/custom/templates/s3/CreateObject_HdrWbs.ejs +2 -1
  22. package/src/emit/application/custom/templates/s3/CreateObject_Main.ejs +4 -0
  23. package/src/emit/application/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +42 -0
  24. package/src/emit/application/custom/templates/s3/CreatePreSignUrl_Main.ejs +23 -0
  25. package/src/emit/application/custom/templates/s3/ProcessS3File_Main.ejs +240 -27
  26. package/src/emit/application/custom/templates/s3/Start_Main.ejs +216 -0
  27. package/src/emit/application/rbac/emitDynamicRbacFlowSchemas.js +5 -1
  28. package/src/emit/application/rbac/emitRbacApplicationArtifacts.js +67 -60
  29. package/src/emit/application/rbac/templates/ReservedDynamicUsage_Main.ejs +27 -9
  30. package/src/emit/application/rbac/templates/UserRbacFlow_Main.ejs +4 -3
  31. package/src/emit/application/system/templates/Register_HdrWbs.ejs +2 -1
  32. package/src/emit/infrastructure/functions/functionYamlArtifact.js +3 -8
  33. package/src/emit/infrastructure/functions/templates/S3Function_Yaml.ejs +2 -3
  34. package/src/emit/infrastructure/resources/iamResourceArtifacts.js +22 -0
  35. package/src/emit/infrastructure/resources/resourceState.js +15 -5
  36. package/src/emit/infrastructure/resources/s3ResourceArtifacts.js +19 -3
  37. package/src/emit/infrastructure/resources/templates/S3Bucket_Yaml.ejs +1 -1
  38. package/src/emit/infrastructure/resources/templates/SystemDynamoDB_Yaml.ejs +2 -2
  39. package/src/emit/schemas/error/emitErrorSchemas.js +120 -10
  40. package/src/emit/schemas/error/templates/errorConsts.ejs +12 -0
  41. package/src/generate.js +32 -30
  42. package/src/plan/domainRegistry.js +2 -1
  43. package/test/integration/publicApi.test.js +33 -24
  44. package/test/unit/application/createTargetRoleHandler.test.js +33 -10
  45. package/test/unit/application/customFlowApplicationArtifacts.test.js +6 -6
  46. package/test/unit/application/customFlowS3.test.js +858 -0
  47. package/test/unit/infrastructure/functionYamlArtifact.test.js +6 -4
  48. package/test/unit/infrastructure/resourceArtifacts.test.js +51 -0
  49. package/test/unit/schemas/dynamicRbacFlowSchemas.test.js +8 -6
  50. package/test/unit/schemas/dynamicRelationshipFlowSchemas.test.js +51 -0
  51. package/test/unit/schemas/errorSchemas.test.js +84 -5
@@ -1,5 +1,5 @@
1
1
  /*
2
- Copyright (C) 2021 Sven Mason <http://izara.io>
2
+ Copyright (C) 2026 Sven Mason <http://izara.io>
3
3
 
4
4
  This program is free software: you can redistribute it and/or modify
5
5
  it under the terms of the GNU Affero General Public License as
@@ -8,42 +8,42 @@ License, or (at your option) any later version.
8
8
 
9
9
  This program is distributed in the hope that it will be useful,
10
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
12
  GNU Affero General Public License for more details.
13
13
 
14
14
  You should have received a copy of the GNU Affero General Public License
15
- along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
16
  */
17
17
 
18
18
  import {
19
19
  S3Client,
20
20
  GetObjectCommand,
21
- DeleteObjectCommand,
22
- PutObjectCommand,
23
- CopyObjectCommand
21
+ HeadObjectCommand
24
22
  } from '@aws-sdk/client-s3';
25
23
  const s3 = new S3Client({ region: process.env.AWS_REGION });
26
24
 
25
+ import snsSharedLib from '@izara_project/izara-core-library-sns';
26
+ import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
27
+ import lambdaSharedLib from '@izara_project/izara-core-library-lambda';
28
+ import { sns } from '@izara_project/izara-core-library-external-request';
29
+ import { consts } from '@izara_project/izara-middleware';
30
+
27
31
  //(<optionalRequired>)
28
32
  //(</optionalRequired>)
29
33
 
30
34
  /**
31
- * description of function.
32
- * @param {Object} _izContext
33
- * @param {CorrelationIds} _izContext.correlationIds - property of _izContext
34
- * @param {Logger} _izContext.logger - property of _izContext
35
- * @param {Logger} _izContext.logger.debug - property of _izContext
36
- * @param {Object} bucket - bucket's data
37
- * @param {Array} field - image's data
38
- * @param {Array} importBy - 'webSocket' || 'importData'
39
- * @param {Array} imageImportId - from importData
40
- * @param {Array} realImageSize - from importData
41
- * @param {Array} passBackProperties - from importData
35
+ * Step 2: ProcessAfterUpload (Deferred-Node S3 Pipeline - ADR-016)
36
+ * Triggered by S3 ObjectCreated event. Inspects file, prepares entity payload,
37
+ * and publishes to Create_In SNS topic with callingFlow
38
+ * targeting ConfirmAfterUpload.
42
39
  *
43
- * @returns {object} returnResponse
40
+ * @param {Object} _izContext
41
+ * @param {Object} bucket - S3 bucket record
42
+ * @param {Object} field - S3 object record ({ key, size, eTag })
43
+ * @param {Object} passBackProperties
44
+ * @returns {Promise<Object>}
44
45
  */
45
-
46
- export default async function processAfterUpload(
46
+ export default async function <%- functionName %>(
47
47
  _izContext,
48
48
  bucket,
49
49
  field,
@@ -52,18 +52,231 @@ export default async function processAfterUpload(
52
52
  passBackProperties = {}
53
53
  ) {
54
54
  try {
55
- _izContext.logger.debug('----- process AfterUpload event params ----- ', {
56
- bucket: bucket,
57
- field: field,
58
- //(<loggerAdditionalParams>)
59
- //(</loggerAdditionalParams>)
60
- passBackProperties: passBackProperties
55
+ _izContext.logger.info(
56
+ '----- <%- functionName %> started -----',
57
+ {
58
+ bucketName: bucket.name,
59
+ key: field.key,
60
+ size: field.size
61
+ }
62
+ );
63
+ _izContext.logger.debug('<%- functionName %> incoming parameters:', {
64
+ bucket,
65
+ field,
66
+ passBackProperties
67
+ });
68
+
69
+ const s3Key = field.key;
70
+ const actualByteSize = field.size;
71
+ const actualSizeMb = actualByteSize / (1024 * 1024);
72
+
73
+ _izContext.logger.debug('S3 file details:', {
74
+ s3Key,
75
+ actualByteSize,
76
+ actualSizeMb
61
77
  });
62
78
 
79
+ let s3Metadata = {};
80
+ try {
81
+ const headResult = await s3.send(
82
+ new HeadObjectCommand({
83
+ Bucket: bucket.name,
84
+ Key: s3Key
85
+ })
86
+ );
87
+
88
+ _izContext.logger.debug('HeadObjectCommand raw result:', headResult);
89
+ s3Metadata = headResult.Metadata || {};
90
+ _izContext.logger.info('Parsed S3 Metadata:', { s3Metadata });
91
+ } catch (headErr) {
92
+ _izContext.logger.warn(
93
+ 'Could not retrieve S3 object metadata via HeadObjectCommand:',
94
+ {
95
+ bucket: bucket.name,
96
+ key: s3Key,
97
+ error: headErr.message
98
+ }
99
+ );
100
+ }
101
+
102
+ //(<extractIdentifiersFromKeyOrMetadata>)
103
+ const keyParts = s3Key.split('/');
104
+ let fileNameWithExt = '';
105
+ if (keyParts.length > 0) {
106
+ fileNameWithExt = keyParts[keyParts.length - 1];
107
+ }
108
+ const rawId = fileNameWithExt.split('.')[0];
109
+ let parentId = '';
110
+ if (keyParts.length > 2) {
111
+ parentId = keyParts[keyParts.length - 2];
112
+ }
113
+ <% if (typeof parentIdKeys !== 'undefined' && parentIdKeys && parentIdKeys.length > 1) { -%>
114
+ <% for (let i = 1; i < parentIdKeys.length; i++) { -%>
115
+ let <%- parentIdKeys[i] %> = '';
116
+ if (keyParts.length > <%- 2 + i %>) {
117
+ <%- parentIdKeys[i] %> = keyParts[keyParts.length - <%- 2 + i %>];
118
+ }
119
+ <% } -%>
120
+ <% } -%>
121
+ //(</extractIdentifiersFromKeyOrMetadata>)
122
+
63
123
  //(<endpointHook>)
64
124
  //(</endpointHook>)
125
+
126
+ <% if (typeof nextStepFunctionName === 'string' && nextStepFunctionName) { -%>
127
+ const metaUserId = s3Metadata.submittedbyuserid || '';
128
+ <% if (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) { -%>
129
+ <% for (const rel of flowRelationships) { -%>
130
+ <% const targetIdKey = rel.targetIdentifierKey || `${rel.targetObjType.objectType}Id`; -%>
131
+ <% const metaKey = targetIdKey.toLowerCase(); -%>
132
+ const meta<%- targetIdKey.charAt(0).toUpperCase() + targetIdKey.slice(1) %> = s3Metadata.<%- metaKey %> || '';
133
+ <% } -%>
134
+ <% } -%>
135
+
136
+ _izContext.logger.info('Extracted identifiers and metadata:', {
137
+ <%- objectType %>Id: rawId,
138
+ parentId,
139
+ submittedByUserId: metaUserId,
140
+ <% if (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) { -%>
141
+ <% for (const rel of flowRelationships) { -%>
142
+ <% const targetIdKey = rel.targetIdentifierKey || `${rel.targetObjType.objectType}Id`; -%>
143
+ <%- targetIdKey %>: meta<%- targetIdKey.charAt(0).toUpperCase() + targetIdKey.slice(1) %>,
144
+ <% } -%>
145
+ <% } -%>
146
+ fileName: fileNameWithExt
147
+ });
148
+
149
+ if (metaUserId) {
150
+ _izContext.correlationIds?.set(consts.SUBMITTED_BY_USER_ID, metaUserId);
151
+ }
152
+
153
+ //(<relationshipsHook>)
154
+ let relationships = [];
155
+ <% if (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) { -%>
156
+ <% for (const rel of flowRelationships) { -%>
157
+ <% const targetIdKey = rel.targetIdentifierKey || `${rel.targetObjType.objectType}Id`; -%>
158
+ <% const targetObj = rel.targetObjType || {}; -%>
159
+ <% const relTypeObj = rel.relType || {}; -%>
160
+ <% const relDir = rel.relationshipDirection || 'to'; -%>
161
+ <% const varName = `meta${targetIdKey.charAt(0).toUpperCase() + targetIdKey.slice(1)}`; -%>
162
+ if (<%- varName %>) {
163
+ relationships.push({
164
+ targetObjType: {
165
+ objectType: '<%- targetObj.objectType %>',
166
+ serviceTag: '<%- targetObj.serviceTag %>'
167
+ },
168
+ targetIdentifiers: {
169
+ <%- targetIdKey %>: <%- varName %>
170
+ },
171
+ relType: {
172
+ relationshipTag: '<%- relTypeObj.relationshipTag %>',
173
+ serviceTag: '<%- relTypeObj.serviceTag %>'
174
+ },
175
+ relationshipProperties: <%- JSON.stringify(rel.relationshipProperties || {}) %>,
176
+ relationshipDirection: '<%- relDir %>'
177
+ });
178
+ _izContext.logger.info('Built relationship for <%- targetObj.objectType %>:', {
179
+ relationships
180
+ });
181
+ } else {
182
+ _izContext.logger.warn(
183
+ '<%- varName %> is empty! ' +
184
+ 'No <%- relTypeObj.relationshipTag %> relationship attached.'
185
+ );
186
+ }
187
+ <% } -%>
188
+ <% } -%>
189
+ //(</relationshipsHook>)
190
+
191
+ let messageObject = {
192
+ objectType: '<%- objectType %>',
193
+ submittedByUserId: metaUserId,
194
+ identifiers: {
195
+ <%- objectType %>Id: rawId
196
+ },
197
+ <% if (typeof parentIdKeys !== 'undefined' && parentIdKeys && parentIdKeys.length > 1) { -%>
198
+ targetIdentifiers: {
199
+ <%- parentIdKeys[0] %>: parentId,
200
+ <% for (let i = 1; i < parentIdKeys.length; i++) { -%>
201
+ <%- parentIdKeys[i] %>: <%- parentIdKeys[i] %><%- i < parentIdKeys.length - 1 ? ',' : '' %>
202
+ <% } -%>
203
+ },
204
+ <% } else if (typeof parentIdKey !== 'undefined' && parentIdKey) { -%>
205
+ targetIdentifiers: {
206
+ <%- parentIdKey %>: parentId
207
+ },
208
+ <% } -%>
209
+ relationships,
210
+ fieldNames: {
211
+ //(<fieldNamesHook>)
212
+ //(</fieldNamesHook>)
213
+ fileName: fileNameWithExt
214
+ }
215
+ };
216
+
217
+ const confirmCallbackFunction =
218
+ await lambdaSharedLib.lambdaFunctionName(
219
+ _izContext,
220
+ '<%- nextStepFunctionName %>'
221
+ );
222
+ _izContext.logger.debug('Resolved confirm callback function:', {
223
+ confirmCallbackFunction
224
+ });
225
+
226
+ messageObject =
227
+ callingFlowSharedLib.addCallingFlowToSnsRequestMessageObject(
228
+ messageObject,
229
+ callingFlowSharedLib.addParentCallingFlowConfig(
230
+ passBackProperties,
231
+ callingFlowSharedLib.createCallingFlowConfig(
232
+ confirmCallbackFunction,
233
+ { rawId: rawId, <%- objectType %>Id: rawId }
234
+ )
235
+ )
236
+ );
237
+
238
+ const topicArn =
239
+ snsSharedLib.snsTopicArnByFlowSchema(_izContext, 'Create_In');
240
+
241
+ let sendMessageToCreateEndpoint = {
242
+ Message: JSON.stringify(messageObject),
243
+ TopicArn: topicArn
244
+ };
245
+
246
+ _izContext.logger.info('Publishing to Create_In SNS topic:', {
247
+ topicArn,
248
+ <%- objectType %>Id: rawId,
249
+ parentId<%- (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) ? flowRelationships.map(r => { const k = r.targetIdentifierKey || `${r.targetObjType.objectType}Id`; return `,\n ${k}: meta${k.charAt(0).toUpperCase() + k.slice(1)}`; }).join('') : '' %>
250
+ });
251
+ _izContext.logger.debug(
252
+ 'Full Create_In message payload:',
253
+ sendMessageToCreateEndpoint
254
+ );
255
+
256
+ const publishResult = await sns.publishAsync(
257
+ _izContext,
258
+ sendMessageToCreateEndpoint
259
+ );
260
+ _izContext.logger.info('Successfully published to Create_In SNS:', {
261
+ publishResult,
262
+ s3Key,
263
+ <%- objectType %>Id: rawId
264
+ });
265
+
266
+ return {
267
+ status: 'dispatched',
268
+ s3Key,
269
+ messageObject
270
+ };
271
+ <% } else { -%>
272
+ return {
273
+ status: 'processed',
274
+ s3Key
275
+ };
276
+ <% } -%>
65
277
  } catch (err) {
66
- _izContext.logger.error('error ProcessImageAfterUploadMain: ', err);
278
+ _izContext.logger.error('Error in <%- functionName %>: ', err);
67
279
  throw err;
68
280
  }
69
281
  }
282
+
@@ -0,0 +1,216 @@
1
+ /*
2
+ Copyright (C) 2026 Sven Mason <http://izara.io>
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU Affero General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU Affero General Public License for more details.
13
+
14
+ You should have received a copy of the GNU Affero General Public License
15
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ import { v7 as uuidv7 } from 'uuid';
19
+ import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
20
+ import { S3Client } from '@aws-sdk/client-s3';
21
+ import { consts } from '@izara_project/izara-middleware';
22
+ import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
23
+ import { webSocket } from '@izara_project/izara-core-library-external-request';
24
+ const { postToConnection } = webSocket;
25
+ import { utils } from '@izara_project/izara-core-library-service-schemas';
26
+ const { createFlowTypeConcat } = utils;
27
+
28
+ const client = new S3Client({ region: process.env.AWS_REGION });
29
+
30
+ //(<optionalRequired>)
31
+ //(</optionalRequired>)
32
+
33
+ /**
34
+ * Step 1: Start (Deferred-Node S3 Pipeline - ADR-016)
35
+ * Generates UUIDv7, computes S3 Presigned POST in-memory, writes ephemeral WebSocketTask,
36
+ * and returns upload parameters to client without writing entity records to the database.
37
+ *
38
+ * @param {Object} _izContext
39
+ * @param {Object} requestParams
40
+ * @param {Object} callingFlowConfig
41
+ * @returns {Promise<Object>}
42
+ */
43
+ export default async function <%- functionName %>(
44
+ _izContext,
45
+ requestParams,
46
+ callingFlowConfig = {}
47
+ //(<additionalParams>)
48
+ //(</additionalParams>)
49
+ ) {
50
+ try {
51
+ _izContext.logger.debug('<%- functionName %> started', {
52
+ requestParams,
53
+ callingFlowConfig
54
+ });
55
+
56
+ const connectionId = _izContext.correlationIds.get(consts.CONNECTION_ID);
57
+ const submittedByUserId = _izContext.correlationIds?.get(
58
+ consts.SUBMITTED_BY_USER_ID
59
+ );
60
+ if (!submittedByUserId) {
61
+ throw new Error('Submitted by user id is required');
62
+ }
63
+
64
+ //(<beforeCreateObjectHook>)
65
+ //(</beforeCreateObjectHook>)
66
+
67
+ <% if (isRbac) { -%>
68
+ const { checkRbacPermission } =
69
+ await import('@izara_project/izara-authorization');
70
+
71
+ //(<rbacParameterGroups_<%- flowTag %>>)
72
+ const parameterGroups = {};
73
+ //(</rbacParameterGroups_<%- flowTag %>>)
74
+
75
+ const resultPermissionCheck = await checkRbacPermission(
76
+ _izContext,
77
+ {
78
+ flowTag: requestParams.flowTag || '<%- flowTag %>',
79
+ serviceTag: process.env.iz_serviceTag
80
+ },
81
+ parameterGroups,
82
+ {
83
+ targetIdentifiers: requestParams.targetIdentifiers,
84
+ rbacObjType: {
85
+ serviceTag: '<%- parentServiceTag || rbacServiceTag %>',
86
+ objectType: '<%- parentObjectType || objectType %>'
87
+ },
88
+ sync: true
89
+ }
90
+ );
91
+
92
+ _izContext.logger.debug(
93
+ `[${process.env.iz_serviceTag}:<%- flowTag %>] checkRbacPermission result:`,
94
+ resultPermissionCheck
95
+ );
96
+
97
+ if (resultPermissionCheck && resultPermissionCheck.permission !== true) {
98
+ throw new Error('Permission denied');
99
+ }
100
+ <% } -%>
101
+
102
+ const <%- objectType %>Id = uuidv7();
103
+
104
+ <% if (typeof parentIdKeys !== 'undefined' && parentIdKeys && parentIdKeys.length > 0) { -%>
105
+ const targetParentId = requestParams.targetIdentifiers?.<%- parentIdKeys[0] %>;
106
+ <% for (const key of parentIdKeys) { -%>
107
+ const target<%- key.charAt(0).toUpperCase() + key.slice(1) %> = requestParams.targetIdentifiers?.<%- key %>;
108
+ if (!target<%- key.charAt(0).toUpperCase() + key.slice(1) %>) {
109
+ throw new Error('targetIdentifiers.<%- key %> is required');
110
+ }
111
+ <% } -%>
112
+ <% } -%>
113
+
114
+ let maxFileSizeMb = <%- maxFileSizeMb %>;
115
+ if (requestParams.file?.size) {
116
+ maxFileSizeMb = Math.ceil(requestParams.file.size / 1048576);
117
+ } else if (requestParams.file?.fileSize) {
118
+ maxFileSizeMb = requestParams.file.fileSize;
119
+ } else if (requestParams.fieldNames?.fileSize) {
120
+ maxFileSizeMb = requestParams.fieldNames.fileSize;
121
+ }
122
+
123
+ //(<createKeyForUploadFile>)
124
+ let importType = '<%- defaultImportType %>';
125
+ let uploadPath = '';
126
+ <% if (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) { -%>
127
+ <% for (const rel of flowRelationships) { -%>
128
+ <% const relIdKey = rel.targetIdentifierKey || `${rel.targetObjType.objectType}Id`; -%>
129
+ const <%- relIdKey %> =
130
+ requestParams.fieldNames?.<%- relIdKey %> || requestParams.file?.<%- relIdKey %>;
131
+ <% } -%>
132
+ <% } -%>
133
+ //(</createKeyForUploadFile>)
134
+ const Key = `<%- s3KeyPrefix %>${uploadPath}`;
135
+ const maximumSize = maxFileSizeMb * 1048576;
136
+
137
+ let createPreSignUrlParam = {
138
+ Bucket: '<%- bucketName %>',
139
+ Key: Key,
140
+ Conditions: [
141
+ ['content-length-range', 0, maximumSize],
142
+ ['eq', '$x-amz-meta-<%- objectType %>Id', <%- objectType %>Id],
143
+ <% if (typeof parentIdKeys !== 'undefined' && parentIdKeys && parentIdKeys.length > 0) { -%>
144
+ <% for (const key of parentIdKeys) { -%>
145
+ ['eq', '$x-amz-meta-<%- key %>', target<%- key.charAt(0).toUpperCase() + key.slice(1) %>],
146
+ <% } -%>
147
+ <% } -%>
148
+ ['starts-with', '$x-amz-meta-submittedByUserId', ''],
149
+ ['starts-with', '$Content-Type', '<%- contentTypePrefix %>'],
150
+ <% if (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) { -%>
151
+ <% for (const rel of flowRelationships) { -%>
152
+ <% const relIdKey = rel.targetIdentifierKey || `${rel.targetObjType.objectType}Id`; -%>
153
+ ['starts-with', '$x-amz-meta-<%- relIdKey %>', ''],
154
+ <% } -%>
155
+ <% } -%>
156
+ //(<conditionCreateUrlLink>)
157
+ //(</conditionCreateUrlLink>)
158
+ ],
159
+ Fields: {
160
+ 'x-amz-meta-<%- objectType %>Id': <%- objectType %>Id,
161
+ <% if (typeof parentIdKeys !== 'undefined' && parentIdKeys && parentIdKeys.length > 0) { -%>
162
+ <% for (const key of parentIdKeys) { -%>
163
+ 'x-amz-meta-<%- key %>': target<%- key.charAt(0).toUpperCase() + key.slice(1) %>,
164
+ <% } -%>
165
+ <% } -%>
166
+ 'x-amz-meta-submittedByUserId': submittedByUserId,
167
+ <% if (typeof flowRelationships !== 'undefined' && Array.isArray(flowRelationships) && flowRelationships.length > 0) { -%>
168
+ <% for (const rel of flowRelationships) { -%>
169
+ <% const relIdKey = rel.targetIdentifierKey || `${rel.targetObjType.objectType}Id`; -%>
170
+ 'x-amz-meta-<%- relIdKey %>': <%- relIdKey %> || '',
171
+ <% } -%>
172
+ <% } -%>
173
+ //(<fieldCreateUrlLink>)
174
+ //(</fieldCreateUrlLink>)
175
+ },
176
+ Expires: <%- expires %>
177
+ };
178
+
179
+ //(<modifyPreSignUrlParam>)
180
+ //(</modifyPreSignUrlParam>)
181
+
182
+ const uploadUrl = await createPresignedPost(client, createPreSignUrlParam);
183
+
184
+ if (connectionId) {
185
+ await dynamodbSharedLib.putItem(
186
+ _izContext,
187
+ await dynamodbSharedLib.tableName(_izContext, 'WebSocketTask'),
188
+ {
189
+ taskKey: `${createFlowTypeConcat(_izContext, { flowTag: '<%- flowTag %>', serviceTag: process.env.iz_serviceTag })}${<%- objectType %>Id}`,
190
+ connectionId: connectionId,
191
+ expirationTime: Math.floor(Date.now() / 1000) + 7200
192
+ }
193
+ );
194
+
195
+ await postToConnection(
196
+ _izContext,
197
+ {
198
+ status: 'success',
199
+ data: {
200
+ uploadUrl: uploadUrl,
201
+ <%- objectType %>Id: <%- objectType %>Id
202
+ }
203
+ },
204
+ connectionId
205
+ );
206
+ }
207
+
208
+ return {
209
+ uploadUrl: uploadUrl,
210
+ <%- objectType %>Id: <%- objectType %>Id
211
+ };
212
+ } catch (err) {
213
+ _izContext.logger.error('Error in <%- functionName %>:', err);
214
+ throw err;
215
+ }
216
+ }
@@ -20,7 +20,7 @@ const RBAC_CORE_FLOW_DEFINITIONS = [
20
20
  const LIMIT_FLOW_DEFINITIONS = [
21
21
  {
22
22
  flowTag: 'ReservedDynamicUsage',
23
- event: ['ownTopic', 'lambdaSyncInv', 'lambdaSyncApi']
23
+ event: ['lambdaSyncInv', 'lambdaSyncApi']
24
24
  },
25
25
  {
26
26
  flowTag: 'ConfirmUsage',
@@ -29,6 +29,10 @@ const LIMIT_FLOW_DEFINITIONS = [
29
29
  {
30
30
  flowTag: 'CancelUsage',
31
31
  event: ['ownTopic', 'lambdaSyncInv', 'lambdaSyncApi']
32
+ },
33
+ {
34
+ flowTag: 'ReservedUsageTtlExpired',
35
+ event: ['dss']
32
36
  }
33
37
  ];
34
38
 
@@ -174,14 +174,21 @@ const STATIC_RBAC_APPLICATION_PATHS = [
174
174
  ];
175
175
 
176
176
  const STATIC_LIMIT_APPLICATION_PATHS = [
177
- ...ACCOUNT_LIMIT_HANDLERS.flatMap((flowTag) => [
178
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_Main.js`,
179
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrSqs.js`,
180
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrInv.js`,
181
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrApi.js`,
182
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_WbsMain.js`,
183
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrWbs.js`
184
- ]),
177
+ ...ACCOUNT_LIMIT_HANDLERS.flatMap((flowTag) => {
178
+ const paths = [
179
+ `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_Main.js`,
180
+ `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrInv.js`,
181
+ `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrApi.js`
182
+ ];
183
+ if (flowTag !== 'ReservedDynamicUsage') {
184
+ paths.splice(
185
+ 1,
186
+ 0,
187
+ `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrSqs.js`
188
+ );
189
+ }
190
+ return paths;
191
+ }),
185
192
  'app/src/generatedCode/FlowLimit/ReservedUsageTtlExpired/source/ReservedUsageTtlExpired_HdrDss.js',
186
193
  FLOW_LIMITS_YAML_PATH
187
194
  ];
@@ -212,65 +219,65 @@ export function rbacApplicationManagedPaths(objects = []) {
212
219
  async function createAccountLimitHandler(flowTag) {
213
220
  const sourcePath = `app/src/generatedCode/FlowLimit/${flowTag}/source`;
214
221
  const handlerPath = `src/generatedCode/FlowLimit/${flowTag}/source`;
215
- const webSocket = await createWebSocketEntry(
216
- flowTag,
217
- sourcePath,
218
- handlerPath
219
- );
220
222
  const shared = {
221
223
  flowTag,
222
224
  flowStepName: '',
223
225
  mainFileName: `${flowTag}_Main`,
224
226
  functionName: flowTag
225
227
  };
228
+ const artifacts = [
229
+ {
230
+ path: `${sourcePath}/${flowTag}_Main.js`,
231
+ content: await renderRbacTemplate(`${flowTag}_Main.ejs`, { flowTag })
232
+ }
233
+ ];
234
+ const functions = [];
235
+ if (flowTag !== 'ReservedDynamicUsage') {
236
+ artifacts.push({
237
+ path: `${sourcePath}/${flowTag}_HdrSqs.js`,
238
+ content: await renderRbacTemplate('ListRbac_HdrSqs.ejs', { flowTag })
239
+ });
240
+ functions.push({
241
+ type: 'sqs',
242
+ functionName: `${flowTag}HdrSqs`,
243
+ handlerPath: `${handlerPath}/${flowTag}_HdrSqs.main`,
244
+ roleName: 'FlowRbacRole',
245
+ queueName: `${flowTag}HdrSqs`,
246
+ flowTag: flowTag,
247
+ flowStepName: ''
248
+ });
249
+ }
250
+ artifacts.push(
251
+ {
252
+ path: `${sourcePath}/${flowTag}_HdrInv.js`,
253
+ content: await renderSharedTemplate('FlowHandler_HdrInv.ejs', shared)
254
+ },
255
+ {
256
+ path: `${sourcePath}/${flowTag}_HdrApi.js`,
257
+ content: await renderSharedTemplate('FlowHandler_HdrApi.ejs', shared)
258
+ }
259
+ );
260
+ functions.push(
261
+ {
262
+ type: 'inv',
263
+ functionName: `${flowTag}HdrInv`,
264
+ handlerPath: `${handlerPath}/${flowTag}_HdrInv.main`,
265
+ roleName: 'FlowRbacRole',
266
+ flowTag: flowTag,
267
+ flowStepName: ''
268
+ },
269
+ {
270
+ type: 'api',
271
+ functionName: `${flowTag}HdrApi`,
272
+ handlerPath: `${handlerPath}/${flowTag}_HdrApi.main`,
273
+ roleName: 'FlowRbacRole',
274
+ flowTag: flowTag,
275
+ flowStepName: ''
276
+ }
277
+ );
226
278
  return {
227
- artifacts: [
228
- {
229
- path: `${sourcePath}/${flowTag}_Main.js`,
230
- content: await renderRbacTemplate(`${flowTag}_Main.ejs`, { flowTag })
231
- },
232
- {
233
- path: `${sourcePath}/${flowTag}_HdrSqs.js`,
234
- content: await renderRbacTemplate('ListRbac_HdrSqs.ejs', { flowTag })
235
- },
236
- {
237
- path: `${sourcePath}/${flowTag}_HdrInv.js`,
238
- content: await renderSharedTemplate('FlowHandler_HdrInv.ejs', shared)
239
- },
240
- {
241
- path: `${sourcePath}/${flowTag}_HdrApi.js`,
242
- content: await renderSharedTemplate('FlowHandler_HdrApi.ejs', shared)
243
- },
244
- ...webSocket.artifacts
245
- ],
246
- functions: [
247
- {
248
- type: 'sqs',
249
- functionName: `${flowTag}HdrSqs`,
250
- handlerPath: `${handlerPath}/${flowTag}_HdrSqs.main`,
251
- roleName: 'FlowRbacRole',
252
- queueName: `${flowTag}HdrSqs`,
253
- flowTag: flowTag,
254
- flowStepName: ''
255
- },
256
- {
257
- type: 'inv',
258
- functionName: `${flowTag}HdrInv`,
259
- handlerPath: `${handlerPath}/${flowTag}_HdrInv.main`,
260
- roleName: 'FlowRbacRole',
261
- flowTag: flowTag,
262
- flowStepName: ''
263
- },
264
- {
265
- type: 'api',
266
- functionName: `${flowTag}HdrApi`,
267
- handlerPath: `${handlerPath}/${flowTag}_HdrApi.main`,
268
- roleName: 'FlowRbacRole',
269
- flowTag: flowTag,
270
- flowStepName: ''
271
- },
272
- ...webSocket.functions
273
- ]
279
+ artifacts,
280
+ functions
274
281
  };
275
282
  }
276
283