@izara_project/izara-core-generate-service-code 1.0.86 → 1.0.88

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 (38) hide show
  1. package/package.json +1 -1
  2. package/src/compile/loadSchemas.js +45 -10
  3. package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -1
  4. package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +22 -15
  5. package/src/emit/crud/crudActionPlan.js +47 -6
  6. package/src/emit/crud/emitCrudApplicationArtifacts.js +63 -3
  7. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +6 -4
  8. package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +121 -0
  9. package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +108 -0
  10. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +138 -335
  11. package/src/emit/crud/templates/CreateLogicalLib.ejs +205 -42
  12. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +80 -0
  13. package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +99 -0
  14. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +153 -182
  15. package/src/emit/crud/templates/DeleteLogicalLib.ejs +132 -26
  16. package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +112 -0
  17. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +166 -188
  18. package/src/emit/crud/templates/UpdateLogicalLib.ejs +2 -2
  19. package/src/emit/custom/customFlows.js +3 -1
  20. package/src/emit/function/functionYamlArtifact.js +4 -2
  21. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +0 -3
  22. package/src/emit/rbac/emitRbacApplicationArtifacts.js +1 -116
  23. package/src/emit/rbac/templates/CancelUsage_Main.ejs +14 -10
  24. package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +14 -10
  25. package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +22 -12
  26. package/src/emit/rbac/templates/GetMyPermissions_Main.ejs +14 -10
  27. package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +76 -34
  28. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +12 -9
  29. package/src/emit/resource/emitResourceArtifacts.js +141 -62
  30. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +14 -18
  31. package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +4 -2
  32. package/test/createTargetRoleHandler.test.js +1 -15
  33. package/test/crudApplicationArtifacts.test.js +540 -3
  34. package/test/customFlowApplicationArtifacts.test.js +3 -5
  35. package/test/dynamicCrudFlowSchemas.test.js +5 -17
  36. package/test/dynamicRbacFlowSchemas.test.js +0 -3
  37. package/test/functionYamlArtifact.test.js +4 -2
  38. package/test/resourceArtifacts.test.js +203 -14
@@ -52,11 +52,7 @@ export async function emitRbacApplicationArtifacts(objects) {
52
52
 
53
53
  const limitHandlers = await Promise.all(
54
54
  hasSelfRbac
55
- ? [
56
- ...LIMIT_LIST_DEFINITIONS.map(createLimitListHandler),
57
- ...LIMIT_MUTATION_DEFINITIONS.map(createLimitMutationHandler),
58
- ...ACCOUNT_LIMIT_HANDLERS.map(createAccountLimitHandler)
59
- ]
55
+ ? ACCOUNT_LIMIT_HANDLERS.map(createAccountLimitHandler)
60
56
  : []
61
57
  );
62
58
 
@@ -104,14 +100,6 @@ const LIST_DEFINITIONS = [
104
100
  }
105
101
  ];
106
102
 
107
- const LIMIT_LIST_DEFINITIONS = [
108
- {
109
- flowTag: 'ListRoleLimits',
110
- tableName: 'RoleLimit',
111
- requestProperty: 'roleLimitId'
112
- }
113
- ];
114
-
115
103
  const MUTATION_DEFINITIONS = [
116
104
  {
117
105
  flowTag: 'CreateRolePermissions',
@@ -127,21 +115,6 @@ const MUTATION_DEFINITIONS = [
127
115
  }
128
116
  ];
129
117
 
130
- const LIMIT_MUTATION_DEFINITIONS = [
131
- {
132
- flowTag: 'CreateRoleLimit',
133
- tableName: 'RoleLimit',
134
- method: 'putItem',
135
- fields: ['roleLimitId', 'limitType', 'limitValue', 'actionType']
136
- },
137
- {
138
- flowTag: 'DeleteRoleLimit',
139
- tableName: 'RoleLimit',
140
- method: 'deleteItem',
141
- fields: ['roleLimitId', 'limitType']
142
- }
143
- ];
144
-
145
118
  const USER_ROLE_MUTATIONS = [
146
119
  { flowTag: 'CreateUserRole', operation: 'Put' },
147
120
  { flowTag: 'DeleteUserFromRole', operation: 'Delete' }
@@ -197,17 +170,6 @@ const STATIC_RBAC_APPLICATION_PATHS = [
197
170
  ];
198
171
 
199
172
  const STATIC_LIMIT_APPLICATION_PATHS = [
200
- ...LIMIT_LIST_DEFINITIONS.flatMap(({ flowTag }) => [
201
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_Main.js`,
202
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrSqs.js`,
203
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrApi.js`
204
- ]),
205
- ...LIMIT_MUTATION_DEFINITIONS.flatMap(({ flowTag }) => [
206
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_Main.js`,
207
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrSqs.js`,
208
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_WbsMain.js`,
209
- `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrWbs.js`
210
- ]),
211
173
  ...ACCOUNT_LIMIT_HANDLERS.flatMap((flowTag) => [
212
174
  `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_Main.js`,
213
175
  `app/src/generatedCode/FlowLimit/${flowTag}/source/${flowTag}_HdrSqs.js`,
@@ -274,83 +236,6 @@ async function createAccountLimitHandler(flowTag) {
274
236
  };
275
237
  }
276
238
 
277
- async function createLimitListHandler(definition) {
278
- const sourcePath = `app/src/generatedCode/FlowLimit/${definition.flowTag}/source`;
279
- const handlerPath = `src/generatedCode/FlowLimit/${definition.flowTag}/source`;
280
- return {
281
- artifacts: [
282
- {
283
- path: `${sourcePath}/${definition.flowTag}_Main.js`,
284
- content: await renderRbacTemplate('ListRbac_Main.ejs', {
285
- ...definition,
286
- useContextUserId: definition.useContextUserId ?? false
287
- })
288
- },
289
- {
290
- path: `${sourcePath}/${definition.flowTag}_HdrSqs.js`,
291
- content: await renderRbacTemplate('ListRbac_HdrSqs.ejs', definition)
292
- },
293
- {
294
- path: `${sourcePath}/${definition.flowTag}_HdrApi.js`,
295
- content: await renderRbacTemplate('ListRbac_HdrApi.ejs', definition)
296
- }
297
- ],
298
- functions: [
299
- {
300
- type: 'sqs',
301
- functionName: `${definition.flowTag}HdrSqs`,
302
- handlerPath: `${handlerPath}/${definition.flowTag}_HdrSqs.main`,
303
- roleName: 'FlowRbacRole',
304
- queueName: `${definition.flowTag}HdrSqs`,
305
- flowTag: definition.flowTag,
306
- flowStepName: ''
307
- },
308
- {
309
- type: 'api',
310
- functionName: `${definition.flowTag}HdrApi`,
311
- handlerPath: `${handlerPath}/${definition.flowTag}_HdrApi.main`,
312
- roleName: 'FlowRbacRole',
313
- flowTag: definition.flowTag,
314
- flowStepName: ''
315
- }
316
- ]
317
- };
318
- }
319
-
320
- async function createLimitMutationHandler(definition) {
321
- const sourcePath = `app/src/generatedCode/FlowLimit/${definition.flowTag}/source`;
322
- const handlerPath = `src/generatedCode/FlowLimit/${definition.flowTag}/source`;
323
- const webSocket = await createWebSocketEntry(
324
- definition.flowTag,
325
- sourcePath,
326
- handlerPath
327
- );
328
- return {
329
- artifacts: [
330
- {
331
- path: `${sourcePath}/${definition.flowTag}_Main.js`,
332
- content: await renderRbacTemplate('RbacMutation_Main.ejs', definition)
333
- },
334
- {
335
- path: `${sourcePath}/${definition.flowTag}_HdrSqs.js`,
336
- content: await renderRbacTemplate('ListRbac_HdrSqs.ejs', definition)
337
- },
338
- ...webSocket.artifacts
339
- ],
340
- functions: [
341
- {
342
- type: 'sqs',
343
- functionName: `${definition.flowTag}HdrSqs`,
344
- handlerPath: `${handlerPath}/${definition.flowTag}_HdrSqs.main`,
345
- roleName: 'FlowRbacRole',
346
- queueName: `${definition.flowTag}HdrSqs`,
347
- flowTag: definition.flowTag,
348
- flowStepName: ''
349
- },
350
- ...webSocket.functions
351
- ]
352
- };
353
- }
354
239
 
355
240
  async function createCustomRbacOwnTopicHandler(flowTag, mainTemplateName) {
356
241
  const sourcePath = `app/src/generatedCode/FlowRbac/${flowTag}/source`;
@@ -39,21 +39,25 @@ export default async function CancelUsage(_izContext, requestParams) {
39
39
  requestParams?.limitTag;
40
40
 
41
41
  const targetIdentifiers = requestParams?.targetIdentifiers;
42
- let identifiersConcat = requestParams?.identifiersConcat;
42
+ let identifiersConcat =
43
+ requestParams?.identifiersConcat || requestParams?.identifierConcat;
43
44
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
44
- if (targetIdentifiers.identifierConcat) {
45
- identifiersConcat = targetIdentifiers.identifierConcat;
45
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
46
+ identifiersConcat =
47
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
46
48
  } else {
47
- const sortedKeys = Object.keys(targetIdentifiers).sort();
49
+ const sortedKeys = Object.keys(targetIdentifiers)
50
+ .filter(
51
+ (k) =>
52
+ k !== 'submittedByUserId' &&
53
+ k !== 'identifierConcat' &&
54
+ k !== 'identifiersConcat'
55
+ )
56
+ .sort();
48
57
  const parts = [];
49
58
  for (const key of sortedKeys) {
50
59
  const value = targetIdentifiers[key];
51
- if (
52
- key !== 'submittedByUserId' &&
53
- key !== 'identifierConcat' &&
54
- value !== undefined &&
55
- value !== null
56
- ) {
60
+ if (value !== undefined && value !== null) {
57
61
  parts.push(`${key}#${value}`);
58
62
  }
59
63
  }
@@ -39,21 +39,25 @@ export default async function ConfirmUsage(_izContext, requestParams) {
39
39
  requestParams?.limitTag;
40
40
 
41
41
  const targetIdentifiers = requestParams?.targetIdentifiers;
42
- let identifiersConcat = requestParams?.identifiersConcat;
42
+ let identifiersConcat =
43
+ requestParams?.identifiersConcat || requestParams?.identifierConcat;
43
44
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
44
- if (targetIdentifiers.identifierConcat) {
45
- identifiersConcat = targetIdentifiers.identifierConcat;
45
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
46
+ identifiersConcat =
47
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
46
48
  } else {
47
- const sortedKeys = Object.keys(targetIdentifiers).sort();
49
+ const sortedKeys = Object.keys(targetIdentifiers)
50
+ .filter(
51
+ (k) =>
52
+ k !== 'submittedByUserId' &&
53
+ k !== 'identifierConcat' &&
54
+ k !== 'identifiersConcat'
55
+ )
56
+ .sort();
48
57
  const parts = [];
49
58
  for (const key of sortedKeys) {
50
59
  const value = targetIdentifiers[key];
51
- if (
52
- key !== 'submittedByUserId' &&
53
- key !== 'identifierConcat' &&
54
- value !== undefined &&
55
- value !== null
56
- ) {
60
+ if (value !== undefined && value !== null) {
57
61
  parts.push(`${key}#${value}`);
58
62
  }
59
63
  }
@@ -28,21 +28,25 @@ export default async function CreateTargetRole(_izContext, requestParams) {
28
28
  _izContext.correlationIds?.get(consts.SUBMITTED_BY_USER_ID);
29
29
 
30
30
  const targetIdentifiers = requestParams.targetIdentifiers;
31
- let identifiersConcat = requestParams.identifiersConcat;
31
+ let identifiersConcat =
32
+ requestParams.identifiersConcat || requestParams.identifierConcat;
32
33
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
33
- if (targetIdentifiers.identifierConcat) {
34
- identifiersConcat = targetIdentifiers.identifierConcat;
34
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
35
+ identifiersConcat =
36
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
35
37
  } else {
36
- const sortedKeys = Object.keys(targetIdentifiers).sort();
38
+ const sortedKeys = Object.keys(targetIdentifiers)
39
+ .filter(
40
+ (k) =>
41
+ k !== 'submittedByUserId' &&
42
+ k !== 'identifierConcat' &&
43
+ k !== 'identifiersConcat'
44
+ )
45
+ .sort();
37
46
  const parts = [];
38
47
  for (const key of sortedKeys) {
39
48
  const value = targetIdentifiers[key];
40
- if (
41
- key !== 'submittedByUserId' &&
42
- key !== 'identifierConcat' &&
43
- value !== undefined &&
44
- value !== null
45
- ) {
49
+ if (value !== undefined && value !== null) {
46
50
  parts.push(`${key}#${value}`);
47
51
  }
48
52
  }
@@ -61,7 +65,11 @@ export default async function CreateTargetRole(_izContext, requestParams) {
61
65
  permissions = [],
62
66
  assignUserIds = []
63
67
  } = requestParams;
64
- const roleId = inputRoleId || roleName || identifierUuid();
68
+ let defaultRoleId = identifierUuid();
69
+ if (roleName === 'owner') {
70
+ defaultRoleId = 'owner';
71
+ }
72
+ const roleId = inputRoleId || defaultRoleId;
65
73
  const roleIdKey = `${identifiersConcat}_${roleId}`;
66
74
 
67
75
  await dynamodbSharedLib.putItem(
@@ -70,8 +78,10 @@ export default async function CreateTargetRole(_izContext, requestParams) {
70
78
  {
71
79
  identifiersConcat,
72
80
  roleIdKey,
81
+ roleType: 'tenant_role',
73
82
  roleName,
74
- submittedByUserId
83
+ submittedByUserId,
84
+ createdAt: new Date().toISOString()
75
85
  }
76
86
  );
77
87
 
@@ -31,21 +31,25 @@ export default async function GetMyPermissions(_izContext, requestParams) {
31
31
  }
32
32
 
33
33
  const targetIdentifiers = requestParams.targetIdentifiers;
34
- let identifiersConcat = requestParams.identifiersConcat;
34
+ let identifiersConcat =
35
+ requestParams.identifiersConcat || requestParams.identifierConcat;
35
36
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
36
- if (targetIdentifiers.identifierConcat) {
37
- identifiersConcat = targetIdentifiers.identifierConcat;
37
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
38
+ identifiersConcat =
39
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
38
40
  } else {
39
- const sortedKeys = Object.keys(targetIdentifiers).sort();
41
+ const sortedKeys = Object.keys(targetIdentifiers)
42
+ .filter(
43
+ (k) =>
44
+ k !== 'submittedByUserId' &&
45
+ k !== 'identifierConcat' &&
46
+ k !== 'identifiersConcat'
47
+ )
48
+ .sort();
40
49
  const parts = [];
41
50
  for (const key of sortedKeys) {
42
51
  const value = targetIdentifiers[key];
43
- if (
44
- key !== 'submittedByUserId' &&
45
- key !== 'identifierConcat' &&
46
- value !== undefined &&
47
- value !== null
48
- ) {
52
+ if (value !== undefined && value !== null) {
49
53
  parts.push(`${key}#${value}`);
50
54
  }
51
55
  }
@@ -35,21 +35,25 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
35
35
  } = requestParams;
36
36
 
37
37
  const targetIdentifiers = requestParams.targetIdentifiers;
38
- let identifiersConcat = requestParams.identifiersConcat;
38
+ let identifiersConcat =
39
+ requestParams.identifiersConcat || requestParams.identifierConcat;
39
40
  if (!identifiersConcat && targetIdentifiers && typeof targetIdentifiers === 'object') {
40
- if (targetIdentifiers.identifierConcat) {
41
- identifiersConcat = targetIdentifiers.identifierConcat;
41
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
42
+ identifiersConcat =
43
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
42
44
  } else {
43
- const sortedKeys = Object.keys(targetIdentifiers).sort();
45
+ const sortedKeys = Object.keys(targetIdentifiers)
46
+ .filter(
47
+ (k) =>
48
+ k !== 'submittedByUserId' &&
49
+ k !== 'identifierConcat' &&
50
+ k !== 'identifiersConcat'
51
+ )
52
+ .sort();
44
53
  const parts = [];
45
54
  for (const key of sortedKeys) {
46
55
  const value = targetIdentifiers[key];
47
- if (
48
- key !== 'submittedByUserId' &&
49
- key !== 'identifierConcat' &&
50
- value !== undefined &&
51
- value !== null
52
- ) {
56
+ if (value !== undefined && value !== null) {
53
57
  parts.push(`${key}#${value}`);
54
58
  }
55
59
  }
@@ -70,41 +74,79 @@ export default async function ReservedDynamicUsage(_izContext, requestParams) {
70
74
  }
71
75
 
72
76
  const uniqueIdentify = `${usedTimestamp}_${_izContext.uniqueRequestId || Date.now()}`;
73
- const roleLimitKeys = Array.isArray(requestParams.roleLimitIds)
74
- ? requestParams.roleLimitIds
75
- : [roleLimitId || `${identifiersConcat}_${flowTypeConcat}`];
76
77
 
77
- let maxLimit = Infinity;
78
- const limitRecords = [];
79
-
80
- for (const key of roleLimitKeys) {
81
- const record = await dynamodbSharedLib.getItem(
78
+ let targetPlanTier = requestParams.planTier || null;
79
+ if (!targetPlanTier && identifiersConcat) {
80
+ const targetRolesResult = await dynamodbSharedLib.query(
82
81
  _izContext,
83
- dynamodbSharedLib.tableName(_izContext, 'RoleLimit'),
84
- { roleLimitId: key, limitType: 'runningTotal' }
82
+ dynamodbSharedLib.tableName(_izContext, 'TargetRoles'),
83
+ { identifiersConcat }
85
84
  );
86
- if (record && typeof record.limitValue === 'number') {
87
- limitRecords.push(record);
85
+ let targetRoleItems = [];
86
+ if (Array.isArray(targetRolesResult)) {
87
+ targetRoleItems = targetRolesResult;
88
+ } else if (targetRolesResult && targetRolesResult.Items) {
89
+ targetRoleItems = targetRolesResult.Items;
90
+ }
91
+ for (const roleItem of targetRoleItems) {
92
+ if (roleItem.roleType === 'plan_tier') {
93
+ targetPlanTier = roleItem.roleIdKey;
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ if (!targetPlanTier) {
99
+ targetPlanTier = 'tier-free';
100
+ }
101
+
102
+ const limitRecords = [];
103
+ const tierPermission = await dynamodbSharedLib.getItem(
104
+ _izContext,
105
+ dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
106
+ { roleIdKey: targetPlanTier, flowTypeConcat }
107
+ );
108
+ if (tierPermission && typeof tierPermission.limitValue === 'number') {
109
+ limitRecords.push(tierPermission);
110
+ }
111
+
112
+ if (Array.isArray(requestParams.roleIdKeys)) {
113
+ for (const rKey of requestParams.roleIdKeys) {
114
+ const perm = await dynamodbSharedLib.getItem(
115
+ _izContext,
116
+ dynamodbSharedLib.tableName(_izContext, 'RolePermissions'),
117
+ { roleIdKey: rKey, flowTypeConcat }
118
+ );
119
+ if (perm && typeof perm.limitValue === 'number') {
120
+ limitRecords.push(perm);
121
+ }
88
122
  }
89
123
  }
90
124
 
125
+ let maxLimit = Infinity;
91
126
  if (limitRecords.length > 0) {
92
- const isDecrease = (rec) =>
93
- rec.effect === 'decrease' ||
94
- rec.actionType === 'decrease' ||
95
- rec.action === 'decrease';
127
+ const isDecrease = function (rec) {
128
+ if (
129
+ rec.effect === 'decrease' ||
130
+ rec.actionType === 'decrease' ||
131
+ rec.action === 'decrease'
132
+ ) {
133
+ return true;
134
+ }
135
+ return false;
136
+ };
96
137
 
97
138
  const increaseLimits = limitRecords.filter((rec) => !isDecrease(rec));
98
139
  const decreaseLimits = limitRecords.filter((rec) => isDecrease(rec));
99
140
 
100
- const maxIncrease =
101
- increaseLimits.length > 0
102
- ? Math.max(...increaseLimits.map((r) => r.limitValue))
103
- : Infinity;
104
- const minDecrease =
105
- decreaseLimits.length > 0
106
- ? Math.min(...decreaseLimits.map((r) => r.limitValue))
107
- : Infinity;
141
+ let maxIncrease = Infinity;
142
+ if (increaseLimits.length > 0) {
143
+ maxIncrease = Math.max(...increaseLimits.map((r) => r.limitValue));
144
+ }
145
+
146
+ let minDecrease = Infinity;
147
+ if (decreaseLimits.length > 0) {
148
+ minDecrease = Math.min(...decreaseLimits.map((r) => r.limitValue));
149
+ }
108
150
 
109
151
  maxLimit = Math.min(maxIncrease, minDecrease);
110
152
  }
@@ -101,19 +101,22 @@ export default async function <%- flowTag %>(_izContext, requestParams = {}) {
101
101
  if (typeof targetIdentifiers === 'string') {
102
102
  targetId = targetIdentifiers;
103
103
  } else if (typeof targetIdentifiers === 'object') {
104
- if (targetIdentifiers.identifierConcat) {
105
- targetId = targetIdentifiers.identifierConcat;
104
+ if (targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat) {
105
+ targetId =
106
+ targetIdentifiers.identifiersConcat || targetIdentifiers.identifierConcat;
106
107
  } else {
107
- const sortedKeys = Object.keys(targetIdentifiers).sort();
108
+ const sortedKeys = Object.keys(targetIdentifiers)
109
+ .filter(
110
+ (k) =>
111
+ k !== 'submittedByUserId' &&
112
+ k !== 'identifierConcat' &&
113
+ k !== 'identifiersConcat'
114
+ )
115
+ .sort();
108
116
  const parts = [];
109
117
  for (const key of sortedKeys) {
110
118
  const value = targetIdentifiers[key];
111
- if (
112
- key !== 'submittedByUserId' &&
113
- key !== 'identifierConcat' &&
114
- value !== undefined &&
115
- value !== null
116
- ) {
119
+ if (value !== undefined && value !== null) {
117
120
  parts.push(`${key}#${value}`);
118
121
  }
119
122
  }