@prosopo/provider 5.0.0 → 5.0.3

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 (104) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +15 -15
  2. package/.turbo/turbo-build$colon$tsc.log +24 -24
  3. package/.turbo/turbo-build.log +16 -16
  4. package/CHANGELOG.md +99 -0
  5. package/dist/api/captcha/assignDetectorBundle.d.ts.map +1 -1
  6. package/dist/api/captcha/assignDetectorBundle.js +2 -3
  7. package/dist/api/captcha/assignDetectorBundle.js.map +1 -1
  8. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts +2 -0
  9. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.d.ts.map +1 -1
  10. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js.map +1 -1
  11. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.d.ts +1 -0
  12. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.d.ts.map +1 -1
  13. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +38 -0
  14. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js.map +1 -1
  15. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
  16. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +9 -6
  17. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
  18. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts +2 -2
  19. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
  20. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +34 -37
  21. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
  22. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.js +11 -20
  23. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.powFallback.test.js.map +1 -1
  24. package/dist/api/captcha/submitPoWCaptchaSolution.d.ts.map +1 -1
  25. package/dist/api/captcha/submitPoWCaptchaSolution.js +1 -1
  26. package/dist/api/captcha/submitPoWCaptchaSolution.js.map +1 -1
  27. package/dist/api/startProviderApi.d.ts.map +1 -1
  28. package/dist/api/startProviderApi.js +29 -14
  29. package/dist/api/startProviderApi.js.map +1 -1
  30. package/dist/api/verify.d.ts.map +1 -1
  31. package/dist/api/verify.js +1 -1
  32. package/dist/api/verify.js.map +1 -1
  33. package/dist/cjs/api/captcha/assignDetectorBundle.cjs +2 -3
  34. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +38 -0
  35. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +8 -5
  36. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +34 -37
  37. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +1 -1
  38. package/dist/cjs/api/startProviderApi.cjs +29 -14
  39. package/dist/cjs/api/verify.cjs +1 -1
  40. package/dist/cjs/tasks/captchaManager.cjs +60 -14
  41. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +2 -1
  42. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +32 -2
  43. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +32 -2
  44. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +35 -3
  45. package/dist/cjs/tasks/spam/evaluateEmailSpamRules.cjs +23 -0
  46. package/dist/tasks/captchaManager.d.ts +1 -0
  47. package/dist/tasks/captchaManager.d.ts.map +1 -1
  48. package/dist/tasks/captchaManager.js +60 -14
  49. package/dist/tasks/captchaManager.js.map +1 -1
  50. package/dist/tasks/frictionless/frictionlessTasks.d.ts +1 -1
  51. package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
  52. package/dist/tasks/frictionless/frictionlessTasks.js +2 -1
  53. package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
  54. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -1
  55. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +33 -3
  56. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -1
  57. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  58. package/dist/tasks/powCaptcha/powTasks.js +33 -3
  59. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  60. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts +2 -2
  61. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  62. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +35 -3
  63. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  64. package/dist/tasks/spam/evaluateEmailSpamRules.d.ts +1 -0
  65. package/dist/tasks/spam/evaluateEmailSpamRules.d.ts.map +1 -1
  66. package/dist/tasks/spam/evaluateEmailSpamRules.js +23 -1
  67. package/dist/tasks/spam/evaluateEmailSpamRules.js.map +1 -1
  68. package/dist/tests/integration/clientSettingsPersistence.integration.test.js +23 -1
  69. package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
  70. package/dist/tests/integration/decisionMachines.integration.test.js +3 -56
  71. package/dist/tests/integration/decisionMachines.integration.test.js.map +1 -1
  72. package/dist/tests/integration/escalationPeekBeforeConsume.integration.test.js +2 -2
  73. package/dist/tests/integration/escalationPeekBeforeConsume.integration.test.js.map +1 -1
  74. package/dist/tests/integration/imgCaptcha.integration.test.js +3 -56
  75. package/dist/tests/integration/imgCaptcha.integration.test.js.map +1 -1
  76. package/dist/tests/integration/maintenanceModeAdmin.integration.test.js +2 -1
  77. package/dist/tests/integration/maintenanceModeAdmin.integration.test.js.map +1 -1
  78. package/dist/tests/integration/powCaptcha.integration.test.js +3 -56
  79. package/dist/tests/integration/powCaptcha.integration.test.js.map +1 -1
  80. package/dist/tests/integration/routingDecisionMachines.integration.test.js +2 -2
  81. package/dist/tests/integration/routingDecisionMachines.integration.test.js.map +1 -1
  82. package/dist/tests/integration/testUtils.d.ts +1 -0
  83. package/dist/tests/integration/testUtils.d.ts.map +1 -1
  84. package/dist/tests/integration/testUtils.js +14 -0
  85. package/dist/tests/integration/testUtils.js.map +1 -1
  86. package/dist/tests/integration/testUtils.unit.test.d.ts +2 -0
  87. package/dist/tests/integration/testUtils.unit.test.d.ts.map +1 -0
  88. package/dist/tests/integration/testUtils.unit.test.js +30 -0
  89. package/dist/tests/integration/testUtils.unit.test.js.map +1 -0
  90. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js +50 -0
  91. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.unit.test.js.map +1 -1
  92. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.unit.test.js +53 -1
  93. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.unit.test.js.map +1 -1
  94. package/dist/tests/unit/tasks/captchaManager.unit.test.js +178 -0
  95. package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
  96. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js +99 -0
  97. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js.map +1 -1
  98. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js +108 -0
  99. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +1 -1
  100. package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js +102 -0
  101. package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js.map +1 -1
  102. package/dist/tests/unit/tasks/spam/evaluateEmailSpamRules.unit.test.js +37 -1
  103. package/dist/tests/unit/tasks/spam/evaluateEmailSpamRules.unit.test.js.map +1 -1
  104. package/package.json +19 -19
@@ -13,6 +13,44 @@ var runDecisionMachine = async (input, handle) => {
13
13
  const { tasks, env, clientRecord, dapp, userSitekeyIpHash, flatHeaders, ipInfo } = input;
14
14
  const { req, res } = handle;
15
15
  let { botScore, scoreComponents } = input;
16
+ if (!input.token) {
17
+ req.logger.info(() => ({
18
+ msg: "Frictionless decision",
19
+ data: {
20
+ decision: "missing_token",
21
+ captchaType: _prosopo_types.CaptchaType.image
22
+ }
23
+ }));
24
+ require_metrics.recordFrictionlessDecision("missing_token");
25
+ require_honeypotResponse.attachHoneypot(res, clientRecord);
26
+ return res.json(await tasks.frictionlessManager.sendImageCaptcha({
27
+ solvedImagesCount: Math.min(3, clientRecord.settings.imageMaxRounds),
28
+ userSitekeyIpHash,
29
+ reason: _prosopo_types.FrictionlessReason.MISSING_TOKEN,
30
+ siteKey: dapp,
31
+ ipInfo,
32
+ headers: flatHeaders
33
+ }));
34
+ }
35
+ if (!input.headHash) {
36
+ req.logger.info(() => ({
37
+ msg: "Frictionless decision",
38
+ data: {
39
+ decision: "missing_head_hash",
40
+ captchaType: _prosopo_types.CaptchaType.image
41
+ }
42
+ }));
43
+ require_metrics.recordFrictionlessDecision("missing_head_hash");
44
+ require_honeypotResponse.attachHoneypot(res, clientRecord);
45
+ return res.json(await tasks.frictionlessManager.sendImageCaptcha({
46
+ solvedImagesCount: Math.min(2, clientRecord.settings.imageMaxRounds),
47
+ userSitekeyIpHash,
48
+ reason: _prosopo_types.FrictionlessReason.MISSING_HEAD_HASH,
49
+ siteKey: dapp,
50
+ ipInfo,
51
+ headers: flatHeaders
52
+ }));
53
+ }
16
54
  if (input.decryptionFailed) {
17
55
  req.logger.info(() => ({
18
56
  msg: "Frictionless decision",
@@ -20,6 +20,7 @@ const require_shortCircuit = require("./shortCircuit.cjs");
20
20
  let _prosopo_common = require("@prosopo/common");
21
21
  let _prosopo_types = require("@prosopo/types");
22
22
  let _prosopo_util = require("@prosopo/util");
23
+ let uuid = require("uuid");
23
24
  let _prosopo_user_access_policy = require("@prosopo/user-access-policy");
24
25
  //#region src/api/captcha/getFrictionlessCaptchaChallenge/handler.ts
25
26
  var handler_default = (env, userAccessRulesStorage) => async (req, res, next) => {
@@ -34,10 +35,11 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
34
35
  }
35
36
  }));
36
37
  });
37
- const { token, headHash, dapp, user, mode, simdReadings, detectorSessionId, detectorUnavailable, currentUrl: reportedCurrentUrl, iframeUrl: reportedIframeUrl } = _prosopo_types.GetFrictionlessCaptchaChallengeRequestBody.parse(req.body);
38
+ const { token, headHash, dapp, user, mode, simdReadings, detectorSessionId, currentUrl: reportedCurrentUrl, iframeUrl: reportedIframeUrl } = _prosopo_types.GetFrictionlessCaptchaChallengeRequestBody.parse(req.body);
38
39
  const currentUrl = (0, _prosopo_util.sanitisePageUrl)(reportedCurrentUrl);
39
40
  const iframeUrl = (0, _prosopo_util.sanitisePageUrl)(reportedIframeUrl);
40
41
  const isProtect = (0, _prosopo_util.isProtectDeployment)(currentUrl, iframeUrl);
42
+ const sessionToken = token || `notoken-${(0, uuid.v4)()}`;
41
43
  const normalizedIp = require_normalizeRequestIp.normalizeRequestIp(req.ip, req.logger);
42
44
  const sessionMode = mode === _prosopo_types.ModeEnum.invisible ? _prosopo_types.ModeEnum.invisible : void 0;
43
45
  req.logger.info(() => ({
@@ -195,14 +197,14 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
195
197
  userSitekeyIpHash,
196
198
  requestId: req.requestId,
197
199
  logger: req.logger,
198
- detectorUnavailable: detectorUnavailable ?? false,
200
+ ...detectorSessionId && { detectorSessionId },
199
201
  ...req.tcpToChelloUs !== void 0 && { tcpToChelloUs: req.tcpToChelloUs },
200
202
  ...req.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: req.chelloToHandshakeUs }
201
203
  };
202
204
  const shortCircuitResponse = await require_shortCircuit.runConfiguredCaptchaTypeShortCircuit(shortCircuitInput, res);
203
205
  if (shortCircuitResponse) return shortCircuitResponse;
204
- const noDetectorResponse = await require_shortCircuit.runNoDetectorPowFallback(shortCircuitInput, res);
205
- if (noDetectorResponse) return noDetectorResponse;
206
+ const emptyPoolResponse = await require_shortCircuit.runEmptyDetectorPoolPowFallback(shortCircuitInput, res);
207
+ if (emptyPoolResponse) return emptyPoolResponse;
206
208
  const lScore = tasks.frictionlessManager.checkLangRules(req.headers["accept-language"] || "");
207
209
  const userScope = require_blacklistRequestInspector.getRequestUserScope((0, _prosopo_util.flatten)(req.headers), req.ja4, normalizedIp, user, void 0, void 0, countryCode, asn);
208
210
  const [decryptedPayload, validation, accessPolicies] = await Promise.all([
@@ -249,7 +251,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
249
251
  ...shadowDomPenalty !== void 0 && { shadowDomPenalty }
250
252
  };
251
253
  tasks.frictionlessManager.setSessionParams({
252
- token,
254
+ token: sessionToken,
253
255
  score: botScore,
254
256
  threshold: botThreshold,
255
257
  scoreComponents,
@@ -329,6 +331,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
329
331
  botScore,
330
332
  scoreComponents,
331
333
  token,
334
+ headHash,
332
335
  botThreshold,
333
336
  currentUrl,
334
337
  iframeUrl
@@ -4,58 +4,55 @@ require("./constants.cjs");
4
4
  let _prosopo_types = require("@prosopo/types");
5
5
  let uuid = require("uuid");
6
6
  //#region src/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.ts
7
- var buildBypassSessionParams = (input) => ({
8
- token: input.token || `nodetector-${(0, uuid.v4)()}`,
9
- score: 0,
10
- threshold: input.clientRecord.settings?.frictionlessThreshold ?? .5,
11
- scoreComponents: { baseScore: 0 },
12
- ipAddress: input.ipAddress,
13
- webView: false,
14
- iFrame: false,
15
- decryptedHeadHash: "",
16
- siteKey: input.dapp,
17
- ipInfo: input.ipInfo,
18
- headers: input.flatHeaders,
19
- mode: input.sessionMode,
20
- userSitekeyIpHash: input.userSitekeyIpHash,
21
- ...input.tcpToChelloUs !== void 0 && { tcpToChelloUs: input.tcpToChelloUs },
22
- ...input.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: input.chelloToHandshakeUs }
23
- });
7
+ var buildBypassSessionParams = async (input) => {
8
+ const bundleId = input.detectorSessionId ? (await input.tasks.frictionlessManager.resolveBundleByDetectorSession(input.detectorSessionId))?.bundleId : void 0;
9
+ return {
10
+ token: input.token || `nodetector-${(0, uuid.v4)()}`,
11
+ score: 0,
12
+ threshold: input.clientRecord.settings?.frictionlessThreshold ?? .5,
13
+ scoreComponents: { baseScore: 0 },
14
+ ipAddress: input.ipAddress,
15
+ webView: false,
16
+ iFrame: false,
17
+ decryptedHeadHash: "",
18
+ siteKey: input.dapp,
19
+ ipInfo: input.ipInfo,
20
+ headers: input.flatHeaders,
21
+ mode: input.sessionMode,
22
+ userSitekeyIpHash: input.userSitekeyIpHash,
23
+ ...bundleId && { bundleId },
24
+ ...input.tcpToChelloUs !== void 0 && { tcpToChelloUs: input.tcpToChelloUs },
25
+ ...input.chelloToHandshakeUs !== void 0 && { chelloToHandshakeUs: input.chelloToHandshakeUs }
26
+ };
27
+ };
24
28
  /**
25
- * Universal "no detector ⇒ PoW" fallback. The detector lives only in the
26
- * provider-served pool bundles; when none is available for this request there
27
- * is no way to run (or decrypt) frictionless detection, so the provider serves
28
- * a real PoW challenge rather than the request failing or silently passing.
29
- *
30
- * Fires when EITHER:
31
- * - the pool is empty (missing dir, empty dir, or all bundles failed to
32
- * load) — no provider has a bundle to assign; or
33
- * - the client reported `detectorUnavailable` (it couldn't fetch/run a
34
- * bundle this session) — even if the pool itself is populated.
29
+ * Empty-pool PoW fallback. The detector lives only in the provider-served pool
30
+ * bundles; when this provider has none to assign (missing dir, empty dir, or
31
+ * all bundles failed to load) no client could have run detection, so it serves
32
+ * a real PoW challenge rather than failing the request.
35
33
  *
36
- * Returns null (proceed with normal scored detection) only when the pool has at
37
- * least one bundle AND the client ran one.
34
+ * This is a provider-side condition only. Nothing a client sends — an empty
35
+ * token included — can reach this path; a client that ran no detector is
36
+ * handled by the decision machine's missing-token gate.
38
37
  */
39
- var runNoDetectorPowFallback = async (input, res) => {
38
+ var runEmptyDetectorPoolPowFallback = async (input, res) => {
40
39
  const pool = require_bundlePool.getDetectorBundlePool();
41
- const poolEmpty = !pool || pool.size() === 0;
42
- if (!poolEmpty && !input.detectorUnavailable) return null;
43
- const reason = poolEmpty ? "empty_detector_pool_pow_fallback" : "client_detector_unavailable_pow_fallback";
40
+ if (pool && pool.size() > 0) return null;
44
41
  input.logger.warn(() => ({
45
42
  msg: "Frictionless decision",
46
43
  data: {
47
44
  requestId: input.requestId,
48
- decision: reason,
45
+ decision: "empty_detector_pool_pow_fallback",
49
46
  captchaType: _prosopo_types.CaptchaType.pow
50
47
  }
51
48
  }));
52
49
  require_honeypotResponse.attachHoneypot(res, input.clientRecord);
53
- return res.json(await input.tasks.frictionlessManager.sendPowCaptcha(buildBypassSessionParams(input)));
50
+ return res.json(await input.tasks.frictionlessManager.sendPowCaptcha(await buildBypassSessionParams(input)));
54
51
  };
55
52
  var runConfiguredCaptchaTypeShortCircuit = async (input, res) => {
56
53
  const configuredType = input.clientRecord.settings?.captchaType;
57
54
  if (!configuredType || configuredType === _prosopo_types.CaptchaType.frictionless) return null;
58
- const sessionParams = buildBypassSessionParams(input);
55
+ const sessionParams = await buildBypassSessionParams(input);
59
56
  input.logger.info(() => ({
60
57
  msg: "Frictionless decision",
61
58
  data: {
@@ -76,4 +73,4 @@ var runConfiguredCaptchaTypeShortCircuit = async (input, res) => {
76
73
  };
77
74
  //#endregion
78
75
  exports.runConfiguredCaptchaTypeShortCircuit = runConfiguredCaptchaTypeShortCircuit;
79
- exports.runNoDetectorPowFallback = runNoDetectorPowFallback;
76
+ exports.runEmptyDetectorPoolPowFallback = runEmptyDetectorPoolPowFallback;
@@ -131,7 +131,7 @@ var buildEscalation = async (tasks, result, challenge, handshakeTiming) => {
131
131
  if (!originSession) return void 0;
132
132
  const routed = result.routingOutput;
133
133
  const selectionReason = routed.reason ?? originSession.reason;
134
- const newSession = await tasks.frictionlessManager.createSession(originSession.token, originSession.score, originSession.threshold, originSession.scoreComponents, originSession.ipAddress, routed.captchaType, originSession.siteKey ?? powRecord.dappAccount, routed.captchaType === _prosopo_types.CaptchaType.image ? routed.solvedImagesCount ?? originSession.solvedImagesCount : void 0, void 0, originSession.userSitekeyIpHash, originSession.webView, originSession.iFrame, originSession.decryptedHeadHash, selectionReason, void 0, void 0, originSession.ipInfo, originSession.headers, originSession.mode, originSession.simdReadings, originSession.entropyMathRandomFingerprint, originSession.entropyCryptoFingerprint, originSession.entropyWallClockOffsetMs, originSession.entropyMathRandomFirst, originSession.bundleId, originSession.currentUrl, handshakeTiming?.tcpToChelloUs, handshakeTiming?.chelloToHandshakeUs, true, originSession.iframeUrl, originSession.isProtect);
134
+ const newSession = await tasks.frictionlessManager.createSession(originSession.token, originSession.score, originSession.threshold, originSession.scoreComponents, originSession.ipAddress, routed.captchaType, originSession.siteKey ?? powRecord.dappAccount, routed.captchaType === _prosopo_types.CaptchaType.image ? routed.solvedImagesCount ?? originSession.solvedImagesCount : void 0, void 0, originSession.userSitekeyIpHash, originSession.webView, originSession.iFrame, originSession.decryptedHeadHash, selectionReason, void 0, void 0, originSession.ipInfo, originSession.headers, originSession.mode, originSession.simdReadings, originSession.entropyMathRandomFingerprint, originSession.entropyCryptoFingerprint, originSession.entropyWallClockOffsetMs, originSession.entropyMathRandomFirst, originSession.bundleId, originSession.currentUrl, handshakeTiming?.tcpToChelloUs, handshakeTiming?.chelloToHandshakeUs, true, originSession.iframeUrl, originSession.isProtect, originSession.sessionId);
135
135
  if (tasks.writeQueue) await tasks.writeQueue.cacheSessionEscalation(powRecord.sessionId, newSession.sessionId);
136
136
  return {
137
137
  captchaType: routed.captchaType,
@@ -76,6 +76,19 @@ var getUserFromJWT = (req) => {
76
76
  }
77
77
  };
78
78
  /**
79
+ * `.listen()` returns before the socket is bound, so a bind failure such as
80
+ * EADDRINUSE arrives later as an 'error' event — an uncaught exception unless
81
+ * something is waiting on it. Settle on whichever event comes first so the
82
+ * caller gets a rejection it can handle.
83
+ */
84
+ var awaitListening = (server) => new Promise((resolve, reject) => {
85
+ server.once("error", reject);
86
+ server.once("listening", () => {
87
+ server.removeListener("error", reject);
88
+ resolve();
89
+ });
90
+ });
91
+ /**
79
92
  * Start the Prosopo Provider API server
80
93
  *
81
94
  * This function creates and configures an Express server with all necessary middleware
@@ -223,22 +236,24 @@ async function startProviderApi(env, admin = false, port) {
223
236
  key: node_fs.default.readFileSync(keyPath),
224
237
  cert: node_fs.default.readFileSync(crtPath)
225
238
  };
226
- return node_https.default.createServer(httpsOptions, apiApp).listen(apiPort, () => {
227
- env.logger.info(() => ({
228
- data: {
229
- apiPort,
230
- protocol: "https"
231
- },
232
- msg: "Prosopo app listening with HTTPS"
233
- }));
234
- });
235
- }
236
- return apiApp.listen(apiPort, () => {
239
+ const httpsServer = node_https.default.createServer(httpsOptions, apiApp).listen(apiPort);
240
+ await awaitListening(httpsServer);
237
241
  env.logger.info(() => ({
238
- data: { apiPort },
239
- msg: "Prosopo app listening"
242
+ data: {
243
+ apiPort,
244
+ protocol: "https"
245
+ },
246
+ msg: "Prosopo app listening with HTTPS"
240
247
  }));
241
- });
248
+ return httpsServer;
249
+ }
250
+ const server = apiApp.listen(apiPort);
251
+ await awaitListening(server);
252
+ env.logger.info(() => ({
253
+ data: { apiPort },
254
+ msg: "Prosopo app listening"
255
+ }));
256
+ return server;
242
257
  }
243
258
  //#endregion
244
259
  exports.getClientApiPathsExpectingProsopoHeaders = getClientApiPathsExpectingProsopoHeaders;
@@ -317,7 +317,7 @@ function prosopoVerifyRouter(env) {
317
317
  }
318
318
  const dappPair = env.keyring.addFromAddress(dapp);
319
319
  (0, _prosopo_api_express_router.verifySignature)(dappSignature, timestamp.toString(), dappPair);
320
- const { verified, score } = await tasks.puzzleCaptchaManager.serverVerifyPuzzleCaptchaSolution(dapp, challenge, clientRecord.settings.verifiedTimeout, env, ip, userAccessRulesStorage, email, clientRecord.settings.spamEmailDomainCheckEnabled, clientRecord.settings.trafficFilter, clientRecord.settings.storeMetadata);
320
+ const { verified, score } = await tasks.puzzleCaptchaManager.serverVerifyPuzzleCaptchaSolution(dapp, challenge, clientRecord.settings.verifiedTimeout, env, ip, userAccessRulesStorage, email, clientRecord.settings.spamEmailDomainCheckEnabled, clientRecord.settings.spamFilter, clientRecord.settings.trafficFilter, clientRecord.settings.storeMetadata);
321
321
  const verificationResponse = tasks.puzzleCaptchaManager.getVerificationResponse(verified, clientRecord, req.i18n.t, score);
322
322
  return res.json(verificationResponse);
323
323
  } catch (err) {
@@ -71,6 +71,51 @@ var CaptchaManager = class CaptchaManager {
71
71
  return readings;
72
72
  }
73
73
  /**
74
+ * Read a session and, if it's an escalation missing one of the
75
+ * inherently-origin-populated fields, walk to `originSessionId` and fill
76
+ * the gap. Intended for the decision-machine input read path only —
77
+ * `simdReadings`, `dnsEvent`, `entropyMathRandomFingerprint` etc. are
78
+ * populated on the origin session (SIMD via pow-submit's fire-and-forget
79
+ * attach; DNS via the sidecar's origin-TLS-scoped patch) and don't
80
+ * automatically end up on the escalation record because
81
+ * `buildEscalation` reads the origin from Mongo before the async writes
82
+ * settle. Rather than duplicating the origin's state onto every
83
+ * escalation at write time, keep the origin as the source of truth and
84
+ * fall back to it at read time.
85
+ *
86
+ * Fields intentionally NOT walked:
87
+ * - captchaType / sessionId / score / threshold / scoreComponents /
88
+ * ipAddress / ipInfo / headers — these describe the escalation
89
+ * itself and must never be overridden by the origin.
90
+ * - Anything already present on the escalation — first-write wins.
91
+ *
92
+ * Non-escalation sessions and escalations without `originSessionId`
93
+ * (older records) fall through as no-op.
94
+ */
95
+ async getSessionRecordWithOriginFallback(sessionId) {
96
+ const session = await this.db.getSessionRecordBySessionId(sessionId);
97
+ if (!session) return void 0;
98
+ if (!session.originSessionId) return session;
99
+ const needsSimd = session.simdReadings === void 0 || session.simdReadings === null;
100
+ const needsDns = session.dnsEvent === void 0 || session.dnsEvent === null;
101
+ const needsEntropyMath = session.entropyMathRandomFingerprint === void 0;
102
+ const needsEntropyCrypto = session.entropyCryptoFingerprint === void 0;
103
+ const needsEntropyWall = session.entropyWallClockOffsetMs === void 0;
104
+ const needsEntropyFirst = session.entropyMathRandomFirst === void 0;
105
+ if (!needsSimd && !needsDns && !needsEntropyMath && !needsEntropyCrypto && !needsEntropyWall && !needsEntropyFirst) return session;
106
+ const origin = await this.db.getSessionRecordBySessionId(session.originSessionId);
107
+ if (!origin) return session;
108
+ return {
109
+ ...session,
110
+ ...needsSimd && origin.simdReadings && { simdReadings: origin.simdReadings },
111
+ ...needsDns && origin.dnsEvent && { dnsEvent: origin.dnsEvent },
112
+ ...needsEntropyMath && origin.entropyMathRandomFingerprint !== void 0 && { entropyMathRandomFingerprint: origin.entropyMathRandomFingerprint },
113
+ ...needsEntropyCrypto && origin.entropyCryptoFingerprint !== void 0 && { entropyCryptoFingerprint: origin.entropyCryptoFingerprint },
114
+ ...needsEntropyWall && origin.entropyWallClockOffsetMs !== void 0 && { entropyWallClockOffsetMs: origin.entropyWallClockOffsetMs },
115
+ ...needsEntropyFirst && origin.entropyMathRandomFirst !== void 0 && { entropyMathRandomFirst: origin.entropyMathRandomFirst }
116
+ };
117
+ }
118
+ /**
74
119
  * Decrypt + first-hop-wins attach. Resolves the session's detector pool
75
120
  * bundle (promoted onto the session record at frictionless time) to decrypt.
76
121
  * No-op on decrypt failure / no bundle.
@@ -130,20 +175,6 @@ var CaptchaManager = class CaptchaManager {
130
175
  sessionId
131
176
  }
132
177
  }));
133
- if (userAccessPolicy?.captchaType !== void 0 && userAccessPolicy.captchaType !== requestedCaptchaType) {
134
- this.logger.warn(() => ({
135
- msg: "Invalid captcha type for user access policy",
136
- data: {
137
- account: clientSettings.account,
138
- captchaType: userAccessPolicy.captchaType
139
- }
140
- }));
141
- return {
142
- valid: false,
143
- reason: _prosopo_types.ResultReason.INCORRECT_CAPTCHA_TYPE,
144
- type: requestedCaptchaType
145
- };
146
- }
147
178
  if (sessionId) {
148
179
  const cachedBeforeRemove = this.writeQueue ? await this.writeQueue.getCachedSession(sessionId) : null;
149
180
  const cachedHash = typeof cachedBeforeRemove?.userSitekeyIpHash === "string" ? cachedBeforeRemove.userSitekeyIpHash : void 0;
@@ -246,6 +277,21 @@ var CaptchaManager = class CaptchaManager {
246
277
  ipInfo: sessionRecord.ipInfo
247
278
  };
248
279
  }
280
+ if (userAccessPolicy?.captchaType !== void 0 && userAccessPolicy.captchaType !== requestedCaptchaType) {
281
+ this.logger.warn(() => ({
282
+ msg: "Invalid captcha type for user access policy (sessionless)",
283
+ data: {
284
+ account: clientSettings.account,
285
+ captchaType: userAccessPolicy.captchaType,
286
+ requestedCaptchaType
287
+ }
288
+ }));
289
+ return {
290
+ valid: false,
291
+ reason: _prosopo_types.ResultReason.INCORRECT_CAPTCHA_TYPE,
292
+ type: requestedCaptchaType
293
+ };
294
+ }
249
295
  if (clientSettings?.settings?.captchaType !== requestedCaptchaType) {
250
296
  this.logger.warn(() => ({
251
297
  msg: `Invalid ${requestedCaptchaType} request`,
@@ -82,7 +82,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
82
82
  checkLangRules(acceptLanguage) {
83
83
  return require_lang.checkLangRules(this.config, acceptLanguage);
84
84
  }
85
- async createSession(token, score, threshold, scoreComponents, ipAddress, captchaType, siteKey, solvedImagesCount, powDifficulty, userSitekeyIpHash, webView = false, iFrame = false, decryptedHeadHash = "", reason, blocked, deleted, ipInfo, headers, mode, simdReadings, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, bundleId, currentUrl, tcpToChelloUs, chelloToHandshakeUs, isEscalation, iframeUrl, isProtect) {
85
+ async createSession(token, score, threshold, scoreComponents, ipAddress, captchaType, siteKey, solvedImagesCount, powDifficulty, userSitekeyIpHash, webView = false, iFrame = false, decryptedHeadHash = "", reason, blocked, deleted, ipInfo, headers, mode, simdReadings, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, bundleId, currentUrl, tcpToChelloUs, chelloToHandshakeUs, isEscalation, iframeUrl, isProtect, originSessionId) {
86
86
  const sessionRecord = {
87
87
  sessionId: `${getSessionIDPrefix(this.config.host)}-${(0, uuid.v4)()}`,
88
88
  createdAt: /* @__PURE__ */ new Date(),
@@ -99,6 +99,7 @@ var FrictionlessManager = class extends require_captchaManager.CaptchaManager {
99
99
  webView,
100
100
  iFrame,
101
101
  ...isEscalation && { isEscalation: true },
102
+ ...originSessionId && { originSessionId },
102
103
  decryptedHeadHash,
103
104
  bundleId,
104
105
  reason,
@@ -394,7 +394,34 @@ var ImgCaptchaManager = class extends require_captchaManager.CaptchaManager {
394
394
  failStatus = _prosopo_types.ResultReason.SPAM_EMAIL_RULE;
395
395
  }
396
396
  }
397
- const sessionRecord = solution.sessionId ? await this.db.getSessionRecordBySessionId(solution.sessionId) : void 0;
397
+ const maxEmailSubmissionCount = spamFilter?.enabled && spamFilter.emailRules?.enabled ? spamFilter.emailRules.maxEmailSubmissionCount : void 0;
398
+ let emailNormalised;
399
+ if (!failStatus && maxEmailSubmissionCount !== void 0 && email && storeMetadata) {
400
+ emailNormalised = require_evaluateEmailSpamRules.normaliseEmailForMatching(email);
401
+ if (emailNormalised) try {
402
+ const priorCount = await this.db.countCommitmentsByNormalisedEmail(dapp, emailNormalised);
403
+ if (priorCount >= maxEmailSubmissionCount) {
404
+ logger.info(() => ({
405
+ msg: "Email submission count exceeded in image verification",
406
+ data: {
407
+ priorCount,
408
+ maxEmailSubmissionCount
409
+ }
410
+ }));
411
+ commitmentUpdates.result = {
412
+ status: _prosopo_types.CaptchaStatus.disapproved,
413
+ reason: _prosopo_types.ResultReason.SPAM_EMAIL_COUNT_EXCEEDED
414
+ };
415
+ failStatus = _prosopo_types.ResultReason.SPAM_EMAIL_COUNT_EXCEEDED;
416
+ }
417
+ } catch (error) {
418
+ logger.warn(() => ({
419
+ msg: "Failed to check email submission count in image verification",
420
+ error
421
+ }));
422
+ }
423
+ }
424
+ const sessionRecord = solution.sessionId ? await this.getSessionRecordWithOriginFallback(solution.sessionId) : void 0;
398
425
  const enrichedDnsEvent = await require_enrichDnsEvent.enrichDnsEvent(sessionRecord?.dnsEvent, env.ipInfoService, ip ?? solution.ipInfo?.ip);
399
426
  if (!failStatus) {
400
427
  const check = await this.resolveTrafficFilterCheck(env, solution.ipInfo, trafficFilter, ip, enrichedDnsEvent);
@@ -418,7 +445,10 @@ var ImgCaptchaManager = class extends require_captchaManager.CaptchaManager {
418
445
  failStatus = check.reason;
419
446
  }
420
447
  }
421
- if (storeMetadata && email) commitmentUpdates.metadata = { email };
448
+ if (storeMetadata && email) commitmentUpdates.metadata = {
449
+ email,
450
+ emailNormalised: emailNormalised ?? require_evaluateEmailSpamRules.normaliseEmailForMatching(email)
451
+ };
422
452
  if (ip) {
423
453
  const solutionIpAddress = require_compositeIpAddress.getIpAddressFromComposite(solution.ipAddress);
424
454
  const ipValidationRules = (await this.db.getClientRecord(dapp))?.settings?.ipValidationRules;
@@ -353,7 +353,34 @@ var PowCaptchaManager = class extends require_captchaManager.CaptchaManager {
353
353
  failReason = "API.SPAM_EMAIL_RULE";
354
354
  }
355
355
  }
356
- const sessionRecord = challengeRecord.sessionId ? await this.db.getSessionRecordBySessionId(challengeRecord.sessionId) : void 0;
356
+ const maxEmailSubmissionCount = spamFilter?.enabled && spamFilter.emailRules?.enabled ? spamFilter.emailRules.maxEmailSubmissionCount : void 0;
357
+ let emailNormalised;
358
+ if (!failResult && maxEmailSubmissionCount !== void 0 && email && storeMetadata) {
359
+ emailNormalised = require_evaluateEmailSpamRules.normaliseEmailForMatching(email);
360
+ if (emailNormalised) try {
361
+ const priorCount = await this.db.countCommitmentsByNormalisedEmail(dappAccount, emailNormalised);
362
+ if (priorCount >= maxEmailSubmissionCount) {
363
+ logger.info(() => ({
364
+ msg: "Email submission count exceeded in PoW verification",
365
+ data: {
366
+ priorCount,
367
+ maxEmailSubmissionCount
368
+ }
369
+ }));
370
+ failResult = {
371
+ status: _prosopo_types.CaptchaStatus.disapproved,
372
+ reason: _prosopo_types.ResultReason.SPAM_EMAIL_COUNT_EXCEEDED
373
+ };
374
+ failReason = "API.SPAM_EMAIL_COUNT_EXCEEDED";
375
+ }
376
+ } catch (error) {
377
+ logger.warn(() => ({
378
+ msg: "Failed to check email submission count in PoW verification",
379
+ error
380
+ }));
381
+ }
382
+ }
383
+ const sessionRecord = challengeRecord.sessionId ? await this.getSessionRecordWithOriginFallback(challengeRecord.sessionId) : void 0;
357
384
  const enrichedDnsEvent = await require_enrichDnsEvent.enrichDnsEvent(sessionRecord?.dnsEvent, env.ipInfoService, ip ?? challengeRecord.ipInfo?.ip);
358
385
  if (!failResult) {
359
386
  const check = await this.resolveTrafficFilterCheck(env, challengeRecord.ipInfo, trafficFilter, ip, enrichedDnsEvent);
@@ -377,7 +404,10 @@ var PowCaptchaManager = class extends require_captchaManager.CaptchaManager {
377
404
  failReason = check.reason;
378
405
  }
379
406
  }
380
- if (storeMetadata && email) powRecordUpdates.metadata = { email };
407
+ if (storeMetadata && email) powRecordUpdates.metadata = {
408
+ email,
409
+ emailNormalised: emailNormalised ?? require_evaluateEmailSpamRules.normaliseEmailForMatching(email)
410
+ };
381
411
  if (!failResult && ip) {
382
412
  const challengeIpAddress = require_compositeIpAddress.getIpAddressFromComposite(challengeRecord.ipAddress);
383
413
  const ipValidationRules = (await this.db.getClientRecord(dappAccount))?.settings?.ipValidationRules;
@@ -5,6 +5,7 @@ const require_enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
5
5
  const require_captchaManager = require("../captchaManager.cjs");
6
6
  const require_util = require("../../util.cjs");
7
7
  const require_frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
8
+ const require_evaluateEmailSpamRules = require("../spam/evaluateEmailSpamRules.cjs");
8
9
  const require_powTasksUtils = require("../powCaptcha/powTasksUtils.cjs");
9
10
  const require_puzzleTasksUtils = require("./puzzleTasksUtils.cjs");
10
11
  let _prosopo_common = require("@prosopo/common");
@@ -184,11 +185,12 @@ var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
184
185
  * @param userAccessRulesStorage - storage for querying user access policies
185
186
  * @param email
186
187
  * @param spamEmailDomainCheckingEnabled
188
+ * @param spamFilter
187
189
  * @param trafficFilter
188
190
  * @param storeMetadata - when true, persists the dapp-server-provided
189
191
  * `email` on the captcha record for spam-rate analysis.
190
192
  */
191
- async serverVerifyPuzzleCaptchaSolution(dappAccount, challenge, timeout, env, ip, userAccessRulesStorage, email, spamEmailDomainCheckingEnabled = false, trafficFilter, storeMetadata = false) {
193
+ async serverVerifyPuzzleCaptchaSolution(dappAccount, challenge, timeout, env, ip, userAccessRulesStorage, email, spamEmailDomainCheckingEnabled = false, spamFilter, trafficFilter, storeMetadata = false) {
192
194
  const notVerifiedResponse = { verified: false };
193
195
  const logger = this.logger.with({
194
196
  challenge,
@@ -274,7 +276,34 @@ var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
274
276
  error
275
277
  }));
276
278
  }
277
- const sessionRecord = challengeRecord.sessionId ? await this.db.getSessionRecordBySessionId(challengeRecord.sessionId) : void 0;
279
+ const maxEmailSubmissionCount = spamFilter?.enabled && spamFilter.emailRules?.enabled ? spamFilter.emailRules.maxEmailSubmissionCount : void 0;
280
+ let emailNormalised;
281
+ if (maxEmailSubmissionCount !== void 0 && email && storeMetadata) {
282
+ emailNormalised = require_evaluateEmailSpamRules.normaliseEmailForMatching(email);
283
+ if (emailNormalised) try {
284
+ const priorCount = await this.db.countCommitmentsByNormalisedEmail(dappAccount, emailNormalised);
285
+ if (priorCount >= maxEmailSubmissionCount) {
286
+ logger.info(() => ({
287
+ msg: "Email submission count exceeded in server puzzle verification",
288
+ data: {
289
+ priorCount,
290
+ maxEmailSubmissionCount
291
+ }
292
+ }));
293
+ await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: {
294
+ status: _prosopo_types.CaptchaStatus.disapproved,
295
+ reason: _prosopo_types.ResultReason.SPAM_EMAIL_COUNT_EXCEEDED
296
+ } });
297
+ return notVerifiedResponse;
298
+ }
299
+ } catch (error) {
300
+ logger.warn(() => ({
301
+ msg: "Failed to check email submission count in server puzzle verification",
302
+ error
303
+ }));
304
+ }
305
+ }
306
+ const sessionRecord = challengeRecord.sessionId ? await this.getSessionRecordWithOriginFallback(challengeRecord.sessionId) : void 0;
278
307
  const enrichedDnsEvent = await require_enrichDnsEvent.enrichDnsEvent(sessionRecord?.dnsEvent, env.ipInfoService, ip ?? challengeRecord.ipInfo?.ip);
279
308
  {
280
309
  const check = await this.resolveTrafficFilterCheck(env, challengeRecord.ipInfo, trafficFilter, ip, enrichedDnsEvent);
@@ -303,7 +332,10 @@ var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
303
332
  return notVerifiedResponse;
304
333
  }
305
334
  }
306
- if (storeMetadata && email) await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { metadata: { email } });
335
+ if (storeMetadata && email) await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { metadata: {
336
+ email,
337
+ emailNormalised: emailNormalised ?? require_evaluateEmailSpamRules.normaliseEmailForMatching(email)
338
+ } });
307
339
  if (ip) {
308
340
  const challengeIpAddress = require_compositeIpAddress.getIpAddressFromComposite(challengeRecord.ipAddress);
309
341
  const ipValidationRules = (await this.db.getClientRecord(dappAccount))?.settings?.ipValidationRules;
@@ -28,6 +28,28 @@ var normaliseGmailAddress = (email) => {
28
28
  if (!GMAIL_DOMAINS.has(parts.domain)) return `${parts.local}@${parts.domain}`;
29
29
  return `${parts.local.replace(/\./g, "").split("+")[0] ?? ""}@gmail.com`;
30
30
  };
31
+ /**
32
+ * Normalises an email for equality-based rate-limit matching:
33
+ * - lowercases and trims
34
+ * - strips `+tag` from the local part for every domain (RFC 5233
35
+ * subaddressing is widely honoured — Gmail, Fastmail, iCloud, Outlook,
36
+ * ProtonMail — and rotating `+tag` suffixes is the cheapest evasion
37
+ * against per-address rate limits)
38
+ * - additionally removes dots from the local part for gmail /
39
+ * googlemail (Gmail is the only major provider that treats dots as
40
+ * insignificant)
41
+ *
42
+ * Returns the input trimmed/lowercased if it cannot be split into
43
+ * local@domain. Never returns an empty string for a non-empty input.
44
+ */
45
+ var normaliseEmailForMatching = (email) => {
46
+ const parts = splitEmail(email);
47
+ if (!parts) return email.trim().toLowerCase();
48
+ const beforePlus = parts.local.split("+")[0];
49
+ const withoutPlusTag = beforePlus ? beforePlus : parts.local;
50
+ if (GMAIL_DOMAINS.has(parts.domain)) return `${withoutPlusTag.replace(/\./g, "") || withoutPlusTag}@gmail.com`;
51
+ return `${withoutPlusTag}@${parts.domain}`;
52
+ };
31
53
  var countDots = (s) => {
32
54
  let n = 0;
33
55
  for (const c of s) if (c === ".") n += 1;
@@ -80,4 +102,5 @@ var evaluateEmailSpamRules = (email, rules) => {
80
102
  //#endregion
81
103
  exports.DEFAULT_EMAIL_SPAM_PATTERNS = DEFAULT_EMAIL_SPAM_PATTERNS;
82
104
  exports.evaluateEmailSpamRules = evaluateEmailSpamRules;
105
+ exports.normaliseEmailForMatching = normaliseEmailForMatching;
83
106
  exports.normaliseGmailAddress = normaliseGmailAddress;
@@ -21,6 +21,7 @@ export declare class CaptchaManager {
21
21
  constructor(db: IProviderDatabase, pair: KeyringPair, config: ProsopoConfigOutput, logger?: Logger, writeQueue?: RedisWriteQueue | null);
22
22
  updateSessionRecordWithCache(sessionId: string, updates: Partial<Session>, streamToCentral?: boolean): Promise<void>;
23
23
  decryptSimdReadingsForAttach(simdReadingsCiphertext: string, bundle: PoolBundleDecrypt | undefined): Promise<NonNullable<Session["simdReadings"]> | undefined>;
24
+ getSessionRecordWithOriginFallback(sessionId: string): Promise<Session | undefined>;
24
25
  decryptAndAttachSimdReadingsIfAbsent(sessionId: string, simdReadingsCiphertext: string, stage: SimdReadingsStage): Promise<void>;
25
26
  recordSessionSimdReadingsIfAbsentWithCache(sessionId: string, readings: NonNullable<Session["simdReadings"]>, stage: SimdReadingsStage): Promise<void>;
26
27
  scheduleMongoSessionUpdate(sessionId: string, updates: Partial<Session>, streamToCentral?: boolean): void;
@@ -1 +1 @@
1
- {"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captchaManager.d.ts","sourceRoot":"","sources":["../../src/tasks/captchaManager.ts"],"names":[],"mappings":"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"}