@izara_project/izara-core-generate-service-code 1.0.83 → 1.0.85
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 +4 -4
- package/src/compile/flowValidator.js +13 -2
- package/src/compile/loadSchemas.js +116 -7
- package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +34 -1
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +29 -7
- package/src/emit/crud/crudActionPlan.js +41 -6
- package/src/emit/crud/emitCrudApplicationArtifacts.js +56 -8
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +153 -27
- package/src/emit/crud/generateCrudApplicationArtifacts.js +3 -2
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +3 -2
- package/src/emit/crud/loadLocalSchemaArrays.js +3 -3
- package/src/emit/crud/templates/CreateComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/CreateConfirmComplete_Main.ejs +54 -0
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +252 -154
- package/src/emit/crud/templates/CreateLogicalLib.ejs +1163 -236
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +221 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +33 -8
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +20 -120
- package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +79 -10
- package/src/emit/crud/templates/FlowMain_Wbs.ejs +31 -35
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +52 -3
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
- package/src/emit/custom/customFlows.js +47 -0
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
- package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
- package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
- package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
- package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +163 -0
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +187 -0
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +68 -6
- package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
- package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
- package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +166 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +84 -23
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +11 -8
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +4 -4
- package/src/emit/resource/emitResourceArtifacts.js +351 -108
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +3 -1
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +55 -2
- package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +1 -1
- package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -5
- package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
- package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +6 -0
- package/src/emit/systemText/emitSystemTextSchemas.js +1 -1
- package/src/generate.js +41 -10
- package/test/attributeTreeSchemas.test.js +219 -0
- package/test/createTargetRoleHandler.test.js +59 -4
- package/test/crudApplicationArtifacts.test.js +20 -3
- package/test/customFlowApplicationArtifacts.test.js +5 -5
- package/test/dynamicCrudFlowSchemas.test.js +107 -6
- package/test/dynamicRbacFlowSchemas.test.js +15 -2
- package/test/publicApi.test.js +6 -6
- package/test/resourceArtifacts.test.js +89 -27
|
@@ -48,11 +48,11 @@ function _setL1Cache(key, value) {
|
|
|
48
48
|
// ── L2 Cache (Shared DynamoDB TTL Cache) ──────────────────────────────────────
|
|
49
49
|
const L2_TTL_SECONDS = 5 * 60; // 5 minutes
|
|
50
50
|
|
|
51
|
-
async function _getL2Cache(_izContext,
|
|
51
|
+
async function _getL2Cache(_izContext, submittedByUserId, cacheSubKey) {
|
|
52
52
|
try {
|
|
53
53
|
const tableName = dynamodbSharedLib.tableName(_izContext, 'RbacPermissionCaches');
|
|
54
54
|
const result = await dynamodbSharedLib.getItem(_izContext, tableName, {
|
|
55
|
-
|
|
55
|
+
submittedByUserId,
|
|
56
56
|
cacheKey: cacheSubKey
|
|
57
57
|
});
|
|
58
58
|
if (result && result.ttlTimestamp && result.ttlTimestamp > Math.floor(Date.now() / 1000)) {
|
|
@@ -72,12 +72,12 @@ async function _getL2Cache(_izContext, userId, cacheSubKey) {
|
|
|
72
72
|
return null;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
async function _setL2Cache(_izContext,
|
|
75
|
+
async function _setL2Cache(_izContext, submittedByUserId, cacheSubKey, value) {
|
|
76
76
|
try {
|
|
77
77
|
const tableName = dynamodbSharedLib.tableName(_izContext, 'RbacPermissionCaches');
|
|
78
78
|
const ttlTimestamp = Math.floor(Date.now() / 1000) + L2_TTL_SECONDS;
|
|
79
79
|
await dynamodbSharedLib.putItem(_izContext, tableName, {
|
|
80
|
-
|
|
80
|
+
submittedByUserId,
|
|
81
81
|
cacheKey: cacheSubKey,
|
|
82
82
|
permission: value.returnValue ? value.returnValue.permission : value.permission,
|
|
83
83
|
roleIdKey: value.returnValue ? value.returnValue.roleIdKey : value.roleIdKey,
|
|
@@ -90,10 +90,42 @@ async function _setL2Cache(_izContext, userId, cacheSubKey, value) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
const submittedByUserId =
|
|
94
|
+
requestParams.submittedByUserId ||
|
|
95
|
+
requestParams.targetIdentifiers?.submittedByUserId ||
|
|
96
|
+
_izContext.correlationIds.get(consts.SUBMITTED_BY_USER_ID);
|
|
97
|
+
|
|
98
|
+
const targetIdentifiers = requestParams.targetIdentifiers;
|
|
99
|
+
let targetId = '';
|
|
100
|
+
if (targetIdentifiers) {
|
|
101
|
+
if (typeof targetIdentifiers === 'string') {
|
|
102
|
+
targetId = targetIdentifiers;
|
|
103
|
+
} else if (typeof targetIdentifiers === 'object') {
|
|
104
|
+
if (targetIdentifiers.identifierConcat) {
|
|
105
|
+
targetId = targetIdentifiers.identifierConcat;
|
|
106
|
+
} else {
|
|
107
|
+
const sortedKeys = Object.keys(targetIdentifiers).sort();
|
|
108
|
+
const parts = [];
|
|
109
|
+
for (const key of sortedKeys) {
|
|
110
|
+
const value = targetIdentifiers[key];
|
|
111
|
+
if (
|
|
112
|
+
key !== 'submittedByUserId' &&
|
|
113
|
+
key !== 'identifierConcat' &&
|
|
114
|
+
value !== undefined &&
|
|
115
|
+
value !== null
|
|
116
|
+
) {
|
|
117
|
+
parts.push(`${key}#${value}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (parts.length > 0) {
|
|
121
|
+
targetId = parts.join('|');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!submittedByUserId || !targetIdentifiers) {
|
|
128
|
+
throw new Error('Missing required request parameters: submittedByUserId or targetIdentifiers');
|
|
97
129
|
}
|
|
98
130
|
|
|
99
131
|
const { flowTypeConcat, inputParameterGroups, parentFlowId } = requestParams;
|
|
@@ -101,40 +133,69 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
101
133
|
throw new Error('Missing flowTypeConcat in requestParams');
|
|
102
134
|
}
|
|
103
135
|
|
|
104
|
-
_izContext.logger.debug(
|
|
105
|
-
|
|
136
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] requestParams:', {
|
|
137
|
+
submittedByUserId,
|
|
106
138
|
targetId,
|
|
107
139
|
flowTypeConcat,
|
|
108
140
|
inputParameterGroups
|
|
109
141
|
});
|
|
110
142
|
|
|
111
143
|
const cacheSubKey = `${targetId}#${flowTypeConcat}#${JSON.stringify(inputParameterGroups || {})}`;
|
|
112
|
-
const fullCacheKey = `${
|
|
144
|
+
const fullCacheKey = `${submittedByUserId}:${cacheSubKey}`;
|
|
145
|
+
|
|
146
|
+
// ── Fast-path for User Self-Action (submittedByUserId === targetId) ───────────────────
|
|
147
|
+
const isSelfUser = Boolean(
|
|
148
|
+
submittedByUserId &&
|
|
149
|
+
targetId &&
|
|
150
|
+
(submittedByUserId === targetId ||
|
|
151
|
+
targetId === `user#${submittedByUserId}` ||
|
|
152
|
+
targetId === `submittedByUserId#${submittedByUserId}`)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
if (isSelfUser) {
|
|
156
|
+
_izContext.logger.debug(
|
|
157
|
+
'[<%- flowTag %>] Fast-path triggered: user self-action',
|
|
158
|
+
{ submittedByUserId, targetId }
|
|
159
|
+
);
|
|
160
|
+
const result = {
|
|
161
|
+
returnValue: {
|
|
162
|
+
permission: true,
|
|
163
|
+
roleIdKey: 'self_user',
|
|
164
|
+
rbacType: 'self_user'
|
|
165
|
+
},
|
|
166
|
+
errorsFound: [],
|
|
167
|
+
status: 'Completed'
|
|
168
|
+
};
|
|
169
|
+
_setL1Cache(fullCacheKey, result);
|
|
170
|
+
await _setL2Cache(_izContext, submittedByUserId, cacheSubKey, result);
|
|
171
|
+
await _publicMessageOut(_izContext, { ...result, parentFlowId });
|
|
172
|
+
return 'Completed';
|
|
173
|
+
}
|
|
113
174
|
|
|
114
175
|
// 1. Check L1 In-Memory Cache
|
|
115
176
|
const l1Hit = _getL1Cache(fullCacheKey);
|
|
116
177
|
if (l1Hit) {
|
|
117
|
-
_izContext.logger.debug(
|
|
178
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L1 Cache hit:', l1Hit);
|
|
118
179
|
await _publicMessageOut(_izContext, { ...l1Hit, parentFlowId });
|
|
119
180
|
return;
|
|
120
181
|
}
|
|
121
182
|
|
|
122
183
|
// 2. Check L2 Shared DynamoDB Cache
|
|
123
|
-
const l2Hit = await _getL2Cache(_izContext,
|
|
184
|
+
const l2Hit = await _getL2Cache(_izContext, submittedByUserId, cacheSubKey);
|
|
124
185
|
if (l2Hit) {
|
|
125
|
-
_izContext.logger.debug(
|
|
186
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] L2 Cache hit:', l2Hit);
|
|
126
187
|
_setL1Cache(fullCacheKey, l2Hit);
|
|
127
188
|
await _publicMessageOut(_izContext, { ...l2Hit, parentFlowId });
|
|
128
189
|
return;
|
|
129
190
|
}
|
|
130
191
|
|
|
131
|
-
_izContext.logger.debug(
|
|
192
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] Cache miss — querying DynamoDB');
|
|
132
193
|
|
|
133
194
|
// 3. Fallback to DB Query
|
|
134
195
|
const userRolesResult = await dynamodbSharedLib.query(
|
|
135
196
|
_izContext,
|
|
136
197
|
dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
|
|
137
|
-
{
|
|
198
|
+
{ submittedByUserId }
|
|
138
199
|
);
|
|
139
200
|
|
|
140
201
|
let userRoles = [];
|
|
@@ -144,7 +205,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
144
205
|
userRoles = userRolesResult.Items;
|
|
145
206
|
}
|
|
146
207
|
|
|
147
|
-
_izContext.logger.debug(
|
|
208
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] userRoles fetched:', { userRoles });
|
|
148
209
|
|
|
149
210
|
const targetIdPrefix = `${targetId}_`;
|
|
150
211
|
const targetRoles = [];
|
|
@@ -154,13 +215,13 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
154
215
|
}
|
|
155
216
|
}
|
|
156
217
|
|
|
157
|
-
_izContext.logger.debug(
|
|
218
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] targetRoles filtered:', {
|
|
158
219
|
targetIdPrefix,
|
|
159
220
|
targetRoles
|
|
160
221
|
});
|
|
161
222
|
|
|
162
223
|
if (targetRoles.length === 0) {
|
|
163
|
-
_izContext.logger.debug(
|
|
224
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] no targetRoles found, permission denied');
|
|
164
225
|
const result = {
|
|
165
226
|
returnValue: {
|
|
166
227
|
permission: false,
|
|
@@ -171,7 +232,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
171
232
|
status: 'Completed'
|
|
172
233
|
};
|
|
173
234
|
_setL1Cache(fullCacheKey, result);
|
|
174
|
-
await _setL2Cache(_izContext,
|
|
235
|
+
await _setL2Cache(_izContext, submittedByUserId, cacheSubKey, result);
|
|
175
236
|
await _publicMessageOut(_izContext, { ...result, parentFlowId });
|
|
176
237
|
return;
|
|
177
238
|
}
|
|
@@ -189,7 +250,7 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
189
250
|
})
|
|
190
251
|
);
|
|
191
252
|
|
|
192
|
-
_izContext.logger.debug(
|
|
253
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] rolePermissions fetched:', {
|
|
193
254
|
rolePermissions
|
|
194
255
|
});
|
|
195
256
|
|
|
@@ -217,11 +278,11 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
|
|
|
217
278
|
status: 'Completed'
|
|
218
279
|
};
|
|
219
280
|
|
|
220
|
-
_izContext.logger.debug(
|
|
281
|
+
_izContext.logger.debug(`[${process.env.iz_serviceTag}:<%- flowTag %>] validation result:', cacheResult);
|
|
221
282
|
|
|
222
283
|
// Store in L1 & L2 Cache
|
|
223
284
|
_setL1Cache(fullCacheKey, cacheResult);
|
|
224
|
-
await _setL2Cache(_izContext,
|
|
285
|
+
await _setL2Cache(_izContext, submittedByUserId, cacheSubKey, cacheResult);
|
|
225
286
|
|
|
226
287
|
await _publicMessageOut(_izContext, { ...cacheResult, parentFlowId });
|
|
227
288
|
|
|
@@ -16,7 +16,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
<%
|
|
19
|
-
const
|
|
19
|
+
const action = operation === 'Put' ? 'put' : 'delete';
|
|
20
|
+
const propName = operation === 'Put' ? 'attributes' : 'keyValues';
|
|
20
21
|
const roleUsersKey = operation === 'Put' ? 'userId, roleIdKey' : 'roleIdKey, userId';
|
|
21
22
|
-%> import dynamodbSharedLib from '@izara_project/izara-core-library-dynamodb';
|
|
22
23
|
import snsSharedLib from '@izara_project/izara-core-library-sns';
|
|
@@ -27,15 +28,17 @@ export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
|
27
28
|
const { roleIdKey, userId } = requestParams;
|
|
28
29
|
await dynamodbSharedLib.transactWriteItems(_izContext, [
|
|
29
30
|
{
|
|
30
|
-
<%-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
action: '<%- action %>',
|
|
32
|
+
params: {
|
|
33
|
+
tableName: dynamodbSharedLib.tableName(_izContext, 'RoleUsers'),
|
|
34
|
+
<%- propName %>: { <%- roleUsersKey %> }
|
|
33
35
|
}
|
|
34
36
|
},
|
|
35
37
|
{
|
|
36
|
-
<%-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
action: '<%- action %>',
|
|
39
|
+
params: {
|
|
40
|
+
tableName: dynamodbSharedLib.tableName(_izContext, 'UserRoles'),
|
|
41
|
+
<%- propName %>: { userId, roleIdKey }
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
]);
|
|
@@ -47,7 +50,7 @@ export default async function <%- flowTag %>(_izContext, requestParams) {
|
|
|
47
50
|
)
|
|
48
51
|
});
|
|
49
52
|
} catch (error) {
|
|
50
|
-
_izContext.logger.error(
|
|
53
|
+
_izContext.logger.error(`[${process.env.iz_serviceTag}:<%- flowTag %>] error:`, error);
|
|
51
54
|
throw error;
|
|
52
55
|
}
|
|
53
56
|
}
|
|
@@ -78,7 +78,7 @@ export default async function <%- functionName %>(
|
|
|
78
78
|
|
|
79
79
|
let originTimestamp = Date.now();
|
|
80
80
|
let changedByUserId = _izContext.correlationIds.get(
|
|
81
|
-
coreConsts.
|
|
81
|
+
coreConsts.SUBMITTED_BY_USER_ID
|
|
82
82
|
);
|
|
83
83
|
const {
|
|
84
84
|
firstObject,
|
|
@@ -191,14 +191,14 @@ export default async function <%- functionName %>(
|
|
|
191
191
|
*/
|
|
192
192
|
// ? [Fix]: The legacy logic incorrectly blocked "user" from regular execution and allowed non-user values.
|
|
193
193
|
// ? It has been corrected to require changeBy === "user" for normal execution.
|
|
194
|
-
const isUserProcess = Boolean(_izContext.correlationIds?.get(consts.
|
|
194
|
+
const isUserProcess = Boolean(_izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID));
|
|
195
195
|
if (isUserProcess) {
|
|
196
196
|
if (canChangeToRelType.changeBy !== 'user' && canChangeToRelType.changeBy !== 'systemWithUser') {
|
|
197
197
|
errorsFound.push(`CanChangeToRelType changeBy is not user or systemWithUser`);
|
|
198
198
|
}
|
|
199
199
|
} else {
|
|
200
|
-
if (canChangeToRelType.changeBy !== '
|
|
201
|
-
errorsFound.push(`CanChangeToRelType changeBy is not
|
|
200
|
+
if (canChangeToRelType.changeBy !== 'systemNoUser') {
|
|
201
|
+
errorsFound.push(`CanChangeToRelType changeBy is not systemNoUser`);
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
}
|