@prosopo/provider 3.13.0 → 3.13.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,103 @@
1
1
  # @prosopo/provider
2
2
 
3
+ ## 3.13.6
4
+ ### Patch Changes
5
+
6
+ - 93d92a7: little bump for publish all
7
+ - Updated dependencies [93d92a7]
8
+ - @prosopo/api@3.1.36
9
+ - @prosopo/api-express-router@3.0.39
10
+ - @prosopo/api-route@2.6.33
11
+ - @prosopo/common@3.1.25
12
+ - @prosopo/database@3.5.5
13
+ - @prosopo/datasets@3.0.48
14
+ - @prosopo/env@3.2.27
15
+ - @prosopo/keyring@2.8.39
16
+ - @prosopo/load-balancer@2.8.12
17
+ - @prosopo/locale@3.1.25
18
+ - @prosopo/types@3.6.3
19
+ - @prosopo/types-database@4.0.5
20
+ - @prosopo/types-env@2.7.52
21
+ - @prosopo/user-access-policy@3.5.31
22
+ - @prosopo/util@3.2.3
23
+ - @prosopo/util-crypto@13.5.27
24
+
25
+ ## 3.13.5
26
+ ### Patch Changes
27
+
28
+ - 8ee8434: bump node engines to 24 and npm version to 11
29
+ - cfee479: make @prosopo/config a dev dep
30
+ - e843e62: Adding more sensible punishment for invalid decryption key
31
+ - Updated dependencies [8ee8434]
32
+ - Updated dependencies [cfee479]
33
+ - @prosopo/api-express-router@3.0.38
34
+ - @prosopo/user-access-policy@3.5.30
35
+ - @prosopo/types-database@4.0.4
36
+ - @prosopo/load-balancer@2.8.11
37
+ - @prosopo/util-crypto@13.5.26
38
+ - @prosopo/api-route@2.6.32
39
+ - @prosopo/types-env@2.7.51
40
+ - @prosopo/database@3.5.4
41
+ - @prosopo/datasets@3.0.47
42
+ - @prosopo/keyring@2.8.38
43
+ - @prosopo/common@3.1.24
44
+ - @prosopo/locale@3.1.24
45
+ - @prosopo/types@3.6.2
46
+ - @prosopo/util@3.2.2
47
+ - @prosopo/api@3.1.35
48
+ - @prosopo/env@3.2.26
49
+
50
+ ## 3.13.4
51
+ ### Patch Changes
52
+
53
+ - e926831: mega mini bump for all to trigger publish all
54
+ - Updated dependencies [e926831]
55
+ - @prosopo/config@3.1.23
56
+ - @prosopo/api@3.1.34
57
+ - @prosopo/api-express-router@3.0.37
58
+ - @prosopo/api-route@2.6.31
59
+ - @prosopo/common@3.1.23
60
+ - @prosopo/database@3.5.3
61
+ - @prosopo/datasets@3.0.46
62
+ - @prosopo/env@3.2.25
63
+ - @prosopo/keyring@2.8.37
64
+ - @prosopo/load-balancer@2.8.10
65
+ - @prosopo/locale@3.1.23
66
+ - @prosopo/types@3.6.1
67
+ - @prosopo/types-database@4.0.3
68
+ - @prosopo/types-env@2.7.50
69
+ - @prosopo/user-access-policy@3.5.29
70
+ - @prosopo/util@3.2.1
71
+ - @prosopo/util-crypto@13.5.25
72
+
73
+ ## 3.13.3
74
+ ### Patch Changes
75
+
76
+ - 3be9174: Create scheduled task status
77
+ - Updated dependencies [0a9887c]
78
+ - @prosopo/types-database@4.0.2
79
+ - @prosopo/database@3.5.2
80
+ - @prosopo/datasets@3.0.45
81
+ - @prosopo/types-env@2.7.49
82
+ - @prosopo/env@3.2.24
83
+ - @prosopo/api-express-router@3.0.36
84
+
85
+ ## 3.13.2
86
+ ### Patch Changes
87
+
88
+ - Updated dependencies [3e5d80a]
89
+ - @prosopo/types-database@4.0.1
90
+ - @prosopo/database@3.5.1
91
+ - @prosopo/datasets@3.0.44
92
+ - @prosopo/types-env@2.7.48
93
+ - @prosopo/env@3.2.23
94
+ - @prosopo/api-express-router@3.0.35
95
+
96
+ ## 3.13.1
97
+ ### Patch Changes
98
+
99
+ - 447179c: Fix config and client getter
100
+
3
101
  ## 3.13.0
4
102
  ### Minor Changes
5
103
 
@@ -90,7 +90,8 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
90
90
  userAgent,
91
91
  webView,
92
92
  iFrame,
93
- decryptedHeadHash
93
+ decryptedHeadHash,
94
+ decryptionFailed
94
95
  } = await tasks.frictionlessManager.decryptPayload(token, headHash);
95
96
  req.logger.debug(() => ({
96
97
  msg: "Decrypted payload",
@@ -160,29 +161,6 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
160
161
  dapp,
161
162
  userScope
162
163
  ))[0];
163
- const headersUserAgent = req.headers["user-agent"];
164
- const hashedHeadersUserAgent = headersUserAgent ? hashUserAgent(headersUserAgent) : "";
165
- const headersProsopoUser = req.headers["prosopo-user"];
166
- if (hashedHeadersUserAgent !== userAgent || headersProsopoUser !== userId) {
167
- req.logger.info(() => ({
168
- msg: "User agent or user id does not match",
169
- data: {
170
- headersUserAgent,
171
- hashedHeadersUserAgent,
172
- userAgent,
173
- // This is the hashed user agent from the token
174
- headersProsopoUser,
175
- userId
176
- }
177
- }));
178
- return res.json(
179
- await tasks.frictionlessManager.sendImageCaptcha({
180
- solvedImagesCount: timestampDecayFunction(timestamp),
181
- userSitekeyIpHash,
182
- reason: FrictionlessReason.USER_AGENT_MISMATCH
183
- })
184
- );
185
- }
186
164
  if (userAccessPolicy) {
187
165
  const scoreUpdate = tasks.frictionlessManager.scoreIncreaseAccessPolicy(
188
166
  userAccessPolicy,
@@ -211,6 +189,32 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
211
189
  );
212
190
  }
213
191
  }
192
+ const headersUserAgent = req.headers["user-agent"];
193
+ const hashedHeadersUserAgent = headersUserAgent ? hashUserAgent(headersUserAgent) : "";
194
+ const headersProsopoUser = req.headers["prosopo-user"];
195
+ if (hashedHeadersUserAgent !== userAgent || headersProsopoUser !== userId) {
196
+ req.logger.info(() => ({
197
+ msg: "User agent or user id does not match",
198
+ data: {
199
+ headersUserAgent,
200
+ hashedHeadersUserAgent,
201
+ userAgent,
202
+ // This is the hashed user agent from the token
203
+ headersProsopoUser,
204
+ userId
205
+ }
206
+ }));
207
+ return res.json(
208
+ await tasks.frictionlessManager.sendImageCaptcha({
209
+ solvedImagesCount: timestampDecayFunction(
210
+ timestamp,
211
+ decryptionFailed
212
+ ),
213
+ userSitekeyIpHash,
214
+ reason: FrictionlessReason.USER_AGENT_MISMATCH
215
+ })
216
+ );
217
+ }
214
218
  if (clientRecord.settings.contextAware?.enabled) {
215
219
  const clientEntropy = await tasks.frictionlessManager.getClientEntropy(
216
220
  clientRecord.account
@@ -277,7 +281,10 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
277
281
  tasks.frictionlessManager.updateScore(botScore, scoreComponents);
278
282
  return res.json(
279
283
  await tasks.frictionlessManager.sendImageCaptcha({
280
- solvedImagesCount: timestampDecayFunction(timestamp),
284
+ solvedImagesCount: timestampDecayFunction(
285
+ timestamp,
286
+ decryptionFailed
287
+ ),
281
288
  userSitekeyIpHash,
282
289
  reason: FrictionlessReason.OLD_TIMESTAMP
283
290
  })
@@ -91,7 +91,8 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
91
91
  userAgent,
92
92
  webView,
93
93
  iFrame,
94
- decryptedHeadHash
94
+ decryptedHeadHash,
95
+ decryptionFailed
95
96
  } = await tasks$1.frictionlessManager.decryptPayload(token, headHash);
96
97
  req.logger.debug(() => ({
97
98
  msg: "Decrypted payload",
@@ -161,29 +162,6 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
161
162
  dapp,
162
163
  userScope
163
164
  ))[0];
164
- const headersUserAgent = req.headers["user-agent"];
165
- const hashedHeadersUserAgent = headersUserAgent ? hashUserAgent.hashUserAgent(headersUserAgent) : "";
166
- const headersProsopoUser = req.headers["prosopo-user"];
167
- if (hashedHeadersUserAgent !== userAgent || headersProsopoUser !== userId) {
168
- req.logger.info(() => ({
169
- msg: "User agent or user id does not match",
170
- data: {
171
- headersUserAgent,
172
- hashedHeadersUserAgent,
173
- userAgent,
174
- // This is the hashed user agent from the token
175
- headersProsopoUser,
176
- userId
177
- }
178
- }));
179
- return res.json(
180
- await tasks$1.frictionlessManager.sendImageCaptcha({
181
- solvedImagesCount: frictionlessTasksUtils.timestampDecayFunction(timestamp),
182
- userSitekeyIpHash,
183
- reason: frictionlessTasks.FrictionlessReason.USER_AGENT_MISMATCH
184
- })
185
- );
186
- }
187
165
  if (userAccessPolicy) {
188
166
  const scoreUpdate = tasks$1.frictionlessManager.scoreIncreaseAccessPolicy(
189
167
  userAccessPolicy,
@@ -212,6 +190,32 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
212
190
  );
213
191
  }
214
192
  }
193
+ const headersUserAgent = req.headers["user-agent"];
194
+ const hashedHeadersUserAgent = headersUserAgent ? hashUserAgent.hashUserAgent(headersUserAgent) : "";
195
+ const headersProsopoUser = req.headers["prosopo-user"];
196
+ if (hashedHeadersUserAgent !== userAgent || headersProsopoUser !== userId) {
197
+ req.logger.info(() => ({
198
+ msg: "User agent or user id does not match",
199
+ data: {
200
+ headersUserAgent,
201
+ hashedHeadersUserAgent,
202
+ userAgent,
203
+ // This is the hashed user agent from the token
204
+ headersProsopoUser,
205
+ userId
206
+ }
207
+ }));
208
+ return res.json(
209
+ await tasks$1.frictionlessManager.sendImageCaptcha({
210
+ solvedImagesCount: frictionlessTasksUtils.timestampDecayFunction(
211
+ timestamp,
212
+ decryptionFailed
213
+ ),
214
+ userSitekeyIpHash,
215
+ reason: frictionlessTasks.FrictionlessReason.USER_AGENT_MISMATCH
216
+ })
217
+ );
218
+ }
215
219
  if (clientRecord.settings.contextAware?.enabled) {
216
220
  const clientEntropy = await tasks$1.frictionlessManager.getClientEntropy(
217
221
  clientRecord.account
@@ -278,7 +282,10 @@ const getFrictionlessCaptchaChallenge = (env, userAccessRulesStorage) => async (
278
282
  tasks$1.frictionlessManager.updateScore(botScore, scoreComponents);
279
283
  return res.json(
280
284
  await tasks$1.frictionlessManager.sendImageCaptcha({
281
- solvedImagesCount: frictionlessTasksUtils.timestampDecayFunction(timestamp),
285
+ solvedImagesCount: frictionlessTasksUtils.timestampDecayFunction(
286
+ timestamp,
287
+ decryptionFailed
288
+ ),
282
289
  userSitekeyIpHash,
283
290
  reason: frictionlessTasks.FrictionlessReason.OLD_TIMESTAMP
284
291
  })
@@ -163,7 +163,13 @@ class ClientTaskManager {
163
163
  this.logger
164
164
  );
165
165
  const tenMinuteWindow = 10 * 60 * 1e3;
166
- const updatedAtTimestamp = lastTask?.updated ? lastTask.updated.getTime() - tenMinuteWindow || 0 : 0;
166
+ const updatedAtTimestamp = (() => {
167
+ const raw = lastTask?.updated;
168
+ if (!raw) return 0;
169
+ const ts = raw instanceof Date ? raw.getTime() : Date.parse(String(raw));
170
+ if (Number.isNaN(ts)) return 0;
171
+ return Math.max(ts - tenMinuteWindow, 0);
172
+ })();
167
173
  this.logger.info(() => ({
168
174
  msg: `Getting updated client records since ${new Date(updatedAtTimestamp).toDateString()}`
169
175
  }));
@@ -201,14 +207,46 @@ class ClientTaskManager {
201
207
  * @returns Promise<void>
202
208
  */
203
209
  async calculateClientEntropy() {
204
- const clients = await this.providerDB.getAllClientRecords();
205
- for (const client of clients) {
206
- const sampleEntropies = await this.providerDB.sampleEntropy(
207
- 100,
208
- client.account
210
+ const taskID = await this.providerDB.createScheduledTaskStatus(
211
+ types.ScheduledTaskNames.SetClientEntropy,
212
+ types.ScheduledTaskStatus.Running
213
+ );
214
+ try {
215
+ const clients = await this.providerDB.getAllClientRecords();
216
+ for (const client of clients) {
217
+ const sampleEntropies = await this.providerDB.sampleEntropy(
218
+ 100,
219
+ client.account
220
+ );
221
+ const avgEntropy = util.majorityAverage(sampleEntropies);
222
+ await this.providerDB.setClientEntropy(client.account, avgEntropy);
223
+ }
224
+ await this.providerDB.updateScheduledTaskStatus(
225
+ taskID,
226
+ types.ScheduledTaskStatus.Completed,
227
+ {
228
+ data: {
229
+ clientRecords: clients.length
230
+ }
231
+ }
232
+ );
233
+ } catch (e) {
234
+ const calculateClientEntropiesError = new common.ProsopoApiError(
235
+ "DATABASE.UNKNOWN",
236
+ {
237
+ context: { error: e },
238
+ logger: this.logger
239
+ }
240
+ );
241
+ this.logger.error(() => ({
242
+ err: calculateClientEntropiesError,
243
+ msg: "Error calculating client entropy"
244
+ }));
245
+ await this.providerDB.updateScheduledTaskStatus(
246
+ taskID,
247
+ types.ScheduledTaskStatus.Failed,
248
+ { error: String(e) }
209
249
  );
210
- const avgEntropy = util.majorityAverage(sampleEntropies);
211
- await this.providerDB.setClientEntropy(client.account, avgEntropy);
212
250
  }
213
251
  }
214
252
  async registerSiteKey(siteKey, tier, settings) {
@@ -249,6 +249,7 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
249
249
  let webView;
250
250
  let iFrame;
251
251
  let decryptedHeadHash = "";
252
+ let decryptionFailed = false;
252
253
  for (const [keyIndex, key] of decryptKeys.entries()) {
253
254
  try {
254
255
  this.logger.info(() => ({
@@ -296,6 +297,7 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
296
297
  timestamp = 0;
297
298
  providerSelectEntropy = DEFAULT_ENTROPY + 1;
298
299
  decryptedHeadHash = "";
300
+ decryptionFailed = true;
299
301
  }
300
302
  }
301
303
  }
@@ -311,6 +313,7 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
311
313
  timestamp = 0;
312
314
  providerSelectEntropy = DEFAULT_ENTROPY - undefinedCount;
313
315
  decryptedHeadHash = "";
316
+ decryptionFailed = true;
314
317
  }
315
318
  this.logger.info(() => ({
316
319
  msg: "decryptPayload result",
@@ -322,7 +325,8 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
322
325
  userAgent,
323
326
  webView,
324
327
  iFrame,
325
- decryptedHeadHash
328
+ decryptedHeadHash,
329
+ decryptionFailed
326
330
  }
327
331
  }));
328
332
  return {
@@ -333,7 +337,8 @@ class FrictionlessManager extends captchaManager.CaptchaManager {
333
337
  userAgent,
334
338
  webView: webView || false,
335
339
  iFrame: iFrame || false,
336
- decryptedHeadHash
340
+ decryptedHeadHash,
341
+ decryptionFailed
337
342
  };
338
343
  }
339
344
  async getClientEntropy(siteKey) {
@@ -8,7 +8,10 @@ const computeFrictionlessScore = (scoreComponents) => {
8
8
  ).toFixed(2)
9
9
  );
10
10
  };
11
- const timestampDecayFunction = (timestamp) => {
11
+ const timestampDecayFunction = (timestamp, decryptionFailed) => {
12
+ if (decryptionFailed) {
13
+ return 6;
14
+ }
12
15
  const max = (/* @__PURE__ */ new Date()).getTime();
13
16
  if (max - timestamp > 36e5) {
14
17
  return 12;
@@ -161,7 +161,13 @@ class ClientTaskManager {
161
161
  this.logger
162
162
  );
163
163
  const tenMinuteWindow = 10 * 60 * 1e3;
164
- const updatedAtTimestamp = lastTask?.updated ? lastTask.updated.getTime() - tenMinuteWindow || 0 : 0;
164
+ const updatedAtTimestamp = (() => {
165
+ const raw = lastTask?.updated;
166
+ if (!raw) return 0;
167
+ const ts = raw instanceof Date ? raw.getTime() : Date.parse(String(raw));
168
+ if (Number.isNaN(ts)) return 0;
169
+ return Math.max(ts - tenMinuteWindow, 0);
170
+ })();
165
171
  this.logger.info(() => ({
166
172
  msg: `Getting updated client records since ${new Date(updatedAtTimestamp).toDateString()}`
167
173
  }));
@@ -199,14 +205,46 @@ class ClientTaskManager {
199
205
  * @returns Promise<void>
200
206
  */
201
207
  async calculateClientEntropy() {
202
- const clients = await this.providerDB.getAllClientRecords();
203
- for (const client of clients) {
204
- const sampleEntropies = await this.providerDB.sampleEntropy(
205
- 100,
206
- client.account
208
+ const taskID = await this.providerDB.createScheduledTaskStatus(
209
+ ScheduledTaskNames.SetClientEntropy,
210
+ ScheduledTaskStatus.Running
211
+ );
212
+ try {
213
+ const clients = await this.providerDB.getAllClientRecords();
214
+ for (const client of clients) {
215
+ const sampleEntropies = await this.providerDB.sampleEntropy(
216
+ 100,
217
+ client.account
218
+ );
219
+ const avgEntropy = majorityAverage(sampleEntropies);
220
+ await this.providerDB.setClientEntropy(client.account, avgEntropy);
221
+ }
222
+ await this.providerDB.updateScheduledTaskStatus(
223
+ taskID,
224
+ ScheduledTaskStatus.Completed,
225
+ {
226
+ data: {
227
+ clientRecords: clients.length
228
+ }
229
+ }
230
+ );
231
+ } catch (e) {
232
+ const calculateClientEntropiesError = new ProsopoApiError(
233
+ "DATABASE.UNKNOWN",
234
+ {
235
+ context: { error: e },
236
+ logger: this.logger
237
+ }
238
+ );
239
+ this.logger.error(() => ({
240
+ err: calculateClientEntropiesError,
241
+ msg: "Error calculating client entropy"
242
+ }));
243
+ await this.providerDB.updateScheduledTaskStatus(
244
+ taskID,
245
+ ScheduledTaskStatus.Failed,
246
+ { error: String(e) }
207
247
  );
208
- const avgEntropy = majorityAverage(sampleEntropies);
209
- await this.providerDB.setClientEntropy(client.account, avgEntropy);
210
248
  }
211
249
  }
212
250
  async registerSiteKey(siteKey, tier, settings) {
@@ -247,6 +247,7 @@ class FrictionlessManager extends CaptchaManager {
247
247
  let webView;
248
248
  let iFrame;
249
249
  let decryptedHeadHash = "";
250
+ let decryptionFailed = false;
250
251
  for (const [keyIndex, key] of decryptKeys.entries()) {
251
252
  try {
252
253
  this.logger.info(() => ({
@@ -294,6 +295,7 @@ class FrictionlessManager extends CaptchaManager {
294
295
  timestamp = 0;
295
296
  providerSelectEntropy = DEFAULT_ENTROPY + 1;
296
297
  decryptedHeadHash = "";
298
+ decryptionFailed = true;
297
299
  }
298
300
  }
299
301
  }
@@ -309,6 +311,7 @@ class FrictionlessManager extends CaptchaManager {
309
311
  timestamp = 0;
310
312
  providerSelectEntropy = DEFAULT_ENTROPY - undefinedCount;
311
313
  decryptedHeadHash = "";
314
+ decryptionFailed = true;
312
315
  }
313
316
  this.logger.info(() => ({
314
317
  msg: "decryptPayload result",
@@ -320,7 +323,8 @@ class FrictionlessManager extends CaptchaManager {
320
323
  userAgent,
321
324
  webView,
322
325
  iFrame,
323
- decryptedHeadHash
326
+ decryptedHeadHash,
327
+ decryptionFailed
324
328
  }
325
329
  }));
326
330
  return {
@@ -331,7 +335,8 @@ class FrictionlessManager extends CaptchaManager {
331
335
  userAgent,
332
336
  webView: webView || false,
333
337
  iFrame: iFrame || false,
334
- decryptedHeadHash
338
+ decryptedHeadHash,
339
+ decryptionFailed
335
340
  };
336
341
  }
337
342
  async getClientEntropy(siteKey) {
@@ -6,7 +6,10 @@ const computeFrictionlessScore = (scoreComponents) => {
6
6
  ).toFixed(2)
7
7
  );
8
8
  };
9
- const timestampDecayFunction = (timestamp) => {
9
+ const timestampDecayFunction = (timestamp, decryptionFailed) => {
10
+ if (decryptionFailed) {
11
+ return 6;
12
+ }
10
13
  const max = (/* @__PURE__ */ new Date()).getTime();
11
14
  if (max - timestamp > 36e5) {
12
15
  return 12;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@prosopo/provider",
3
- "version": "3.13.0",
3
+ "version": "3.13.6",
4
4
  "author": "PROSOPO LIMITED <info@prosopo.io>",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "engines": {
8
- "node": ">=v20.0.0",
9
- "npm": ">=10.6.0"
8
+ "node": "^24",
9
+ "npm": "^11"
10
10
  },
11
11
  "scripts": {
12
12
  "clean": "del-cli --verbose dist tsconfig.tsbuildinfo",
@@ -22,23 +22,22 @@
22
22
  "dependencies": {
23
23
  "@noble/hashes": "1.8.0",
24
24
  "@polkadot/util": "13.5.7",
25
- "@prosopo/api": "3.1.33",
26
- "@prosopo/api-express-router": "3.0.34",
27
- "@prosopo/api-route": "2.6.30",
28
- "@prosopo/common": "3.1.22",
29
- "@prosopo/config": "3.1.22",
30
- "@prosopo/database": "3.5.0",
31
- "@prosopo/datasets": "3.0.43",
32
- "@prosopo/env": "3.2.22",
33
- "@prosopo/keyring": "2.8.36",
34
- "@prosopo/load-balancer": "2.8.9",
35
- "@prosopo/locale": "3.1.22",
36
- "@prosopo/types": "3.6.0",
37
- "@prosopo/types-database": "4.0.0",
38
- "@prosopo/types-env": "2.7.47",
39
- "@prosopo/user-access-policy": "3.5.28",
40
- "@prosopo/util": "3.2.0",
41
- "@prosopo/util-crypto": "13.5.24",
25
+ "@prosopo/api": "3.1.36",
26
+ "@prosopo/api-express-router": "3.0.39",
27
+ "@prosopo/api-route": "2.6.33",
28
+ "@prosopo/common": "3.1.25",
29
+ "@prosopo/database": "3.5.5",
30
+ "@prosopo/datasets": "3.0.48",
31
+ "@prosopo/env": "3.2.27",
32
+ "@prosopo/keyring": "2.8.39",
33
+ "@prosopo/load-balancer": "2.8.12",
34
+ "@prosopo/locale": "3.1.25",
35
+ "@prosopo/types": "3.6.3",
36
+ "@prosopo/types-database": "4.0.5",
37
+ "@prosopo/types-env": "2.7.52",
38
+ "@prosopo/user-access-policy": "3.5.31",
39
+ "@prosopo/util": "3.2.3",
40
+ "@prosopo/util-crypto": "13.5.27",
42
41
  "cron": "3.1.7",
43
42
  "express": "4.21.2",
44
43
  "geolib": "3.3.4",
@@ -50,6 +49,7 @@
50
49
  "zod": "3.23.8"
51
50
  },
52
51
  "devDependencies": {
52
+ "@prosopo/config": "3.1.25",
53
53
  "@types/node": "22.5.5",
54
54
  "@types/uuid": "10.0.0",
55
55
  "@vitest/coverage-v8": "3.2.4",