@prosopo/provider 4.15.14 → 4.15.15

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 (232) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +106 -106
  2. package/.turbo/turbo-build$colon$tsc.log +24 -24
  3. package/.turbo/turbo-build.log +107 -104
  4. package/CHANGELOG.md +49 -0
  5. package/dist/_virtual/_rolldown/runtime.js +3 -0
  6. package/dist/api/admin/apiAdminRoutesProvider.js +27 -46
  7. package/dist/api/admin/apiClearAllCountersEndpoint.js +62 -57
  8. package/dist/api/admin/apiDnsEventEndpoint.js +79 -92
  9. package/dist/api/admin/apiGetAllDecisionMachinesEndpoint.js +43 -45
  10. package/dist/api/admin/apiGetDecisionMachineEndpoint.js +40 -40
  11. package/dist/api/admin/apiRegisterSiteKeyEndpoint.js +23 -22
  12. package/dist/api/admin/apiRegisterSiteKeysEndpoint.js +26 -30
  13. package/dist/api/admin/apiRemoveAllDecisionMachinesEndpoint.js +35 -37
  14. package/dist/api/admin/apiRemoveDecisionMachineEndpoint.js +40 -40
  15. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +1 -1
  16. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +29 -31
  17. package/dist/api/admin/apiRemoveSiteKeyEndpoint.js +33 -29
  18. package/dist/api/admin/apiRemoveSiteKeysEndpoint.js +32 -31
  19. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +43 -35
  20. package/dist/api/admin/apiUpdateDecisionMachineEndpoint.js +43 -63
  21. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +36 -35
  22. package/dist/api/admin/createApiAdminRoutesProvider.js +6 -8
  23. package/dist/api/blacklistRequestInspector.js +285 -377
  24. package/dist/api/block.js +17 -30
  25. package/dist/api/captcha/checkSpamEmail.js +88 -98
  26. package/dist/api/captcha/contextAwareValidation.js +21 -15
  27. package/dist/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.js +126 -140
  28. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js +11 -12
  29. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +236 -299
  30. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js +10 -13
  31. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +336 -462
  32. package/dist/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.js +17 -14
  33. package/dist/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.js +27 -27
  34. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +42 -63
  35. package/dist/api/captcha/getFrictionlessCaptchaChallenge.js +2 -4
  36. package/dist/api/captcha/getImageCaptchaChallenge.js +136 -207
  37. package/dist/api/captcha/getPoWCaptchaChallenge.js +128 -198
  38. package/dist/api/captcha/getPuzzleCaptchaChallenge.js +132 -201
  39. package/dist/api/captcha/maintenanceModeResponses.js +38 -47
  40. package/dist/api/captcha/submitImageCaptchaSolution.js +75 -101
  41. package/dist/api/captcha/submitPoWCaptchaSolution.js +137 -207
  42. package/dist/api/captcha/submitPuzzleCaptchaSolution.js +73 -105
  43. package/dist/api/captcha.js +76 -58
  44. package/dist/api/dnsEventUrl.js +20 -22
  45. package/dist/api/domainMiddleware.js +104 -115
  46. package/dist/api/forwardVerify.js +62 -48
  47. package/dist/api/handshakeTimingMiddleware.js +43 -62
  48. package/dist/api/hardBlockVerdictCache.js +114 -117
  49. package/dist/api/headerCheckMiddleware.js +34 -34
  50. package/dist/api/ignoreMiddleware.js +13 -15
  51. package/dist/api/ipInfoMiddleware.js +17 -19
  52. package/dist/api/ja4.js +149 -188
  53. package/dist/api/ja4Middleware.js +39 -54
  54. package/dist/api/metrics.js +245 -257
  55. package/dist/api/public.js +52 -54
  56. package/dist/api/robotsMiddleware.js +10 -10
  57. package/dist/api/startProviderApi.js +205 -232
  58. package/dist/api/testSiteKey.js +16 -16
  59. package/dist/api/validateAddress.js +23 -21
  60. package/dist/api/verify.js +334 -377
  61. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  62. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +40 -59
  63. package/dist/cjs/api/admin/apiClearAllCountersEndpoint.cjs +63 -58
  64. package/dist/cjs/api/admin/apiDnsEventEndpoint.cjs +82 -93
  65. package/dist/cjs/api/admin/apiGetAllDecisionMachinesEndpoint.cjs +46 -48
  66. package/dist/cjs/api/admin/apiGetDecisionMachineEndpoint.cjs +41 -41
  67. package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +25 -24
  68. package/dist/cjs/api/admin/apiRegisterSiteKeysEndpoint.cjs +28 -32
  69. package/dist/cjs/api/admin/apiRemoveAllDecisionMachinesEndpoint.cjs +38 -40
  70. package/dist/cjs/api/admin/apiRemoveDecisionMachineEndpoint.cjs +41 -41
  71. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +31 -33
  72. package/dist/cjs/api/admin/apiRemoveSiteKeyEndpoint.cjs +35 -31
  73. package/dist/cjs/api/admin/apiRemoveSiteKeysEndpoint.cjs +34 -33
  74. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +45 -35
  75. package/dist/cjs/api/admin/apiUpdateDecisionMachineEndpoint.cjs +45 -65
  76. package/dist/cjs/api/admin/apiUpdateDetectorKeyEndpoint.cjs +38 -37
  77. package/dist/cjs/api/admin/createApiAdminRoutesProvider.cjs +7 -8
  78. package/dist/cjs/api/blacklistRequestInspector.cjs +288 -376
  79. package/dist/cjs/api/block.cjs +18 -30
  80. package/dist/cjs/api/captcha/checkSpamEmail.cjs +90 -100
  81. package/dist/cjs/api/captcha/contextAwareValidation.cjs +21 -14
  82. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.cjs +125 -140
  83. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/constants.cjs +10 -10
  84. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +238 -301
  85. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.cjs +9 -12
  86. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +349 -473
  87. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.cjs +18 -14
  88. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.cjs +26 -26
  89. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +42 -63
  90. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge.cjs +2 -3
  91. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +138 -208
  92. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +131 -200
  93. package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +135 -203
  94. package/dist/cjs/api/captcha/maintenanceModeResponses.cjs +38 -44
  95. package/dist/cjs/api/captcha/submitImageCaptchaSolution.cjs +77 -102
  96. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +140 -209
  97. package/dist/cjs/api/captcha/submitPuzzleCaptchaSolution.cjs +76 -107
  98. package/dist/cjs/api/captcha.cjs +79 -58
  99. package/dist/cjs/api/dnsEventUrl.cjs +20 -21
  100. package/dist/cjs/api/domainMiddleware.cjs +106 -117
  101. package/dist/cjs/api/forwardVerify.cjs +63 -49
  102. package/dist/cjs/api/handshakeTimingMiddleware.cjs +43 -61
  103. package/dist/cjs/api/hardBlockVerdictCache.cjs +114 -114
  104. package/dist/cjs/api/headerCheckMiddleware.cjs +34 -34
  105. package/dist/cjs/api/ignoreMiddleware.cjs +12 -14
  106. package/dist/cjs/api/ipInfoMiddleware.cjs +16 -18
  107. package/dist/cjs/api/ja4.cjs +149 -187
  108. package/dist/cjs/api/ja4Middleware.cjs +40 -53
  109. package/dist/cjs/api/metrics.cjs +229 -228
  110. package/dist/cjs/api/public.cjs +57 -57
  111. package/dist/cjs/api/robotsMiddleware.cjs +9 -9
  112. package/dist/cjs/api/startProviderApi.cjs +219 -237
  113. package/dist/cjs/api/testSiteKey.cjs +15 -14
  114. package/dist/cjs/api/validateAddress.cjs +24 -21
  115. package/dist/cjs/api/verify.cjs +338 -379
  116. package/dist/cjs/compositeIpAddress.cjs +40 -47
  117. package/dist/cjs/index.cjs +65 -71
  118. package/dist/cjs/pairs.cjs +31 -35
  119. package/dist/cjs/rules/lang.cjs +10 -14
  120. package/dist/cjs/schedulers/captchaScheduler.cjs +26 -32
  121. package/dist/cjs/schedulers/getClientList.cjs +35 -33
  122. package/dist/cjs/schedulers/setClientEntropy.cjs +35 -33
  123. package/dist/cjs/schedulers/updateSpamEmailDomains.cjs +39 -43
  124. package/dist/cjs/services/ipComparison.cjs +122 -119
  125. package/dist/cjs/tasks/captchaManager.cjs +407 -486
  126. package/dist/cjs/tasks/client/clientTasks.cjs +347 -470
  127. package/dist/cjs/tasks/dataset/datasetTasks.cjs +25 -29
  128. package/dist/cjs/tasks/dataset/datasetTasksUtils.cjs +16 -32
  129. package/dist/cjs/tasks/decisionMachine/decisionMachineRunner.cjs +220 -307
  130. package/dist/cjs/tasks/detection/decodeBehavior.cjs +408 -317
  131. package/dist/cjs/tasks/detection/decodePayload.cjs +686 -468
  132. package/dist/cjs/tasks/detection/decodeSimd.cjs +462 -304
  133. package/dist/cjs/tasks/detection/getBotScore.cjs +37 -43
  134. package/dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs +88 -71
  135. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +348 -486
  136. package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +13 -30
  137. package/dist/cjs/tasks/frictionless/routingMachine.cjs +71 -55
  138. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +555 -806
  139. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasksUtils.cjs +22 -23
  140. package/dist/cjs/tasks/index.cjs +2 -4
  141. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +491 -687
  142. package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +17 -29
  143. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +422 -591
  144. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasksUtils.cjs +8 -5
  145. package/dist/cjs/tasks/spam/checkSpamEmail.cjs +133 -141
  146. package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +118 -76
  147. package/dist/cjs/tasks/spam/evaluateEmailSpamRules.cjs +75 -84
  148. package/dist/cjs/tasks/spam/updateSpamEmailDomains.cjs +40 -56
  149. package/dist/cjs/tasks/tasks.cjs +107 -158
  150. package/dist/cjs/util/usageCounters.cjs +220 -211
  151. package/dist/cjs/util.cjs +329 -359
  152. package/dist/cjs/utils/devicePlatform.cjs +14 -8
  153. package/dist/cjs/utils/dns.cjs +68 -93
  154. package/dist/cjs/utils/hashUserAgent.cjs +14 -7
  155. package/dist/cjs/utils/hashUserIp.cjs +14 -6
  156. package/dist/cjs/utils/honeypot/encoders.cjs +74 -80
  157. package/dist/cjs/utils/honeypot/phraseBank.cjs +51 -44
  158. package/dist/cjs/utils/normalizeRequestIp.cjs +33 -25
  159. package/dist/compositeIpAddress.js +38 -46
  160. package/dist/index.js +12 -56
  161. package/dist/pairs.js +31 -37
  162. package/dist/rules/lang.js +11 -15
  163. package/dist/schedulers/captchaScheduler.js +25 -31
  164. package/dist/schedulers/getClientList.js +34 -32
  165. package/dist/schedulers/setClientEntropy.js +34 -32
  166. package/dist/schedulers/updateSpamEmailDomains.js +38 -42
  167. package/dist/services/ipComparison.js +122 -119
  168. package/dist/tasks/captchaManager.js +403 -483
  169. package/dist/tasks/client/clientTasks.js +343 -467
  170. package/dist/tasks/dataset/datasetTasks.js +24 -28
  171. package/dist/tasks/dataset/datasetTasksUtils.js +15 -31
  172. package/dist/tasks/decisionMachine/decisionMachineRunner.js +217 -306
  173. package/dist/tasks/detection/getBotScore.js +37 -43
  174. package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts.map +1 -1
  175. package/dist/tasks/dnsEvent/enrichDnsEvent.js +88 -74
  176. package/dist/tasks/dnsEvent/enrichDnsEvent.js.map +1 -1
  177. package/dist/tasks/frictionless/frictionlessTasks.js +342 -479
  178. package/dist/tasks/frictionless/frictionlessTasksUtils.js +14 -32
  179. package/dist/tasks/frictionless/routingMachine.js +72 -56
  180. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +550 -801
  181. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js +21 -22
  182. package/dist/tasks/index.js +1 -3
  183. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  184. package/dist/tasks/powCaptcha/powTasks.js +486 -682
  185. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  186. package/dist/tasks/powCaptcha/powTasksUtils.js +15 -28
  187. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  188. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +417 -586
  189. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  190. package/dist/tasks/puzzleCaptcha/puzzleTasksUtils.js +9 -6
  191. package/dist/tasks/spam/checkSpamEmail.js +133 -141
  192. package/dist/tasks/spam/checkTrafficFilter.d.ts +1 -0
  193. package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
  194. package/dist/tasks/spam/checkTrafficFilter.js +117 -77
  195. package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
  196. package/dist/tasks/spam/evaluateEmailSpamRules.js +75 -86
  197. package/dist/tasks/spam/updateSpamEmailDomains.js +36 -54
  198. package/dist/tasks/tasks.js +98 -150
  199. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js +4 -1
  200. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js.map +1 -1
  201. package/dist/tests/unit/api/block.unit.test.js +8 -4
  202. package/dist/tests/unit/api/block.unit.test.js.map +1 -1
  203. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js +8 -6
  204. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js.map +1 -1
  205. package/dist/tests/unit/api/forwardVerify.unit.test.js +3 -1
  206. package/dist/tests/unit/api/forwardVerify.unit.test.js.map +1 -1
  207. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +15 -7
  208. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
  209. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js +24 -18
  210. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js.map +1 -1
  211. package/dist/tests/unit/schedulers/getClientList.unit.test.js +19 -13
  212. package/dist/tests/unit/schedulers/getClientList.unit.test.js.map +1 -1
  213. package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js +19 -13
  214. package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js.map +1 -1
  215. package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +1 -1
  216. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js +22 -16
  217. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +1 -1
  218. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +140 -0
  219. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
  220. package/dist/tests/unit/testUtils/mockProviderEnv.d.ts +7 -7
  221. package/dist/util/usageCounters.js +220 -212
  222. package/dist/util.d.ts.map +1 -1
  223. package/dist/util.js +327 -364
  224. package/dist/util.js.map +1 -1
  225. package/dist/utils/devicePlatform.js +15 -9
  226. package/dist/utils/dns.js +64 -77
  227. package/dist/utils/hashUserAgent.js +14 -7
  228. package/dist/utils/hashUserIp.js +14 -6
  229. package/dist/utils/honeypot/encoders.js +74 -80
  230. package/dist/utils/honeypot/phraseBank.js +49 -44
  231. package/dist/utils/normalizeRequestIp.js +34 -26
  232. package/package.json +24 -24
@@ -1,119 +1,116 @@
1
- const DEFAULT_VERDICT_CACHE_TTL_MS = 1e4;
2
- const DEFAULT_VERDICT_CACHE_MAX_ENTRIES = 5e4;
3
- class HardBlockVerdictCache {
4
- constructor(ttlMs = DEFAULT_VERDICT_CACHE_TTL_MS, maxEntries = DEFAULT_VERDICT_CACHE_MAX_ENTRIES) {
5
- this.ttlMs = ttlMs;
6
- this.maxEntries = maxEntries;
7
- this.store = /* @__PURE__ */ new Map();
8
- this.inflight = /* @__PURE__ */ new Map();
9
- }
10
- get(key) {
11
- const entry = this.store.get(key);
12
- if (entry === void 0) {
13
- return void 0;
14
- }
15
- if (entry.expiresAt <= Date.now()) {
16
- this.store.delete(key);
17
- return void 0;
18
- }
19
- this.store.delete(key);
20
- this.store.set(key, entry);
21
- return entry.value;
22
- }
23
- set(key, value) {
24
- this.store.delete(key);
25
- if (this.store.size >= this.maxEntries) {
26
- const oldest = this.store.keys().next().value;
27
- if (oldest !== void 0) {
28
- this.store.delete(oldest);
29
- }
30
- }
31
- this.store.set(key, {
32
- value,
33
- expiresAt: Date.now() + this.ttlMs
34
- });
35
- }
36
- /**
37
- * Cache lookup with singleflight dedupe of concurrent misses.
38
- *
39
- * Fast path: cache hit → return immediately (with LRU move-to-tail
40
- * via `get()`).
41
- *
42
- * Slow path: cache miss →
43
- * 1. If an in-flight Promise exists for this key, join it. This
44
- * is the coalescing behaviour — N concurrent identical misses
45
- * all await the same underlying storage call.
46
- * 2. Otherwise, invoke `compute()`, register the Promise, and
47
- * populate the cache with the result on resolve. The Promise
48
- * is removed from the in-flight map in a `finally` so a
49
- * rejection doesn't wedge future callers.
50
- *
51
- * Rejection semantics: if `compute()` throws, all joined waiters
52
- * see the same rejection. Callers should handle it — the underlying
53
- * `getPrioritisedAccessRule` catches its own storage errors and
54
- * returns `[]` (fail-open), so in practice this never propagates.
55
- */
56
- async getOrCompute(key, compute) {
57
- const cached = this.get(key);
58
- if (cached !== void 0) {
59
- return cached;
60
- }
61
- const existing = this.inflight.get(key);
62
- if (existing !== void 0) {
63
- return existing;
64
- }
65
- const promise = (async () => {
66
- const value = await compute();
67
- this.set(key, value);
68
- return value;
69
- })();
70
- this.inflight.set(key, promise);
71
- try {
72
- return await promise;
73
- } finally {
74
- if (this.inflight.get(key) === promise) {
75
- this.inflight.delete(key);
76
- }
77
- }
78
- }
79
- // Test/ops hook — the running cache is not exposed on the wire, but
80
- // admin tooling (e.g. a rule-mutation notifier) may need to flush
81
- // after a bulk insert to bound the staleness window. Clears both
82
- // the stored entries and any in-flight Promises so a rule mutation
83
- // can't leave a stale computation in flight.
84
- clear() {
85
- this.store.clear();
86
- this.inflight.clear();
87
- }
88
- size() {
89
- return this.store.size;
90
- }
91
- // Test hook: number of in-flight computations. Not on the hot path.
92
- inflightSize() {
93
- return this.inflight.size;
94
- }
95
- }
96
- const hardBlockCacheKey = (clientId, userScope, blockOnly) => {
97
- const bo = blockOnly ? "1" : "0";
98
- const parts = [
99
- clientId ?? "",
100
- userScope.numericIp === void 0 ? "" : userScope.numericIp.toString(),
101
- userScope.numericIpMaskMin === void 0 ? "" : userScope.numericIpMaskMin.toString(),
102
- userScope.numericIpMaskMax === void 0 ? "" : userScope.numericIpMaskMax.toString(),
103
- userScope.userId ?? "",
104
- userScope.ja4Hash ?? "",
105
- userScope.headersHash ?? "",
106
- userScope.userAgentHash ?? "",
107
- userScope.headHash ?? "",
108
- userScope.coords ?? "",
109
- userScope.countryCode ?? "",
110
- userScope.asn === void 0 ? "" : String(userScope.asn)
111
- ];
112
- return `${bo}|${parts.join("|")}`;
1
+ //#region src/api/hardBlockVerdictCache.ts
2
+ var DEFAULT_VERDICT_CACHE_TTL_MS = 1e4;
3
+ var DEFAULT_VERDICT_CACHE_MAX_ENTRIES = 5e4;
4
+ /**
5
+ * Bounded LRU + TTL cache for hard-block verdicts, with singleflight
6
+ * dedupe of concurrent misses.
7
+ *
8
+ * Eviction is real LRU: `get()` moves the hit entry to the tail of the
9
+ * Map's iteration order (Map iteration = insertion order in JS), so
10
+ * `set()` drops the least-recently-used entry once the cap is reached.
11
+ * Absolute TTL is preserved on hit — `expiresAt` is set at insert and
12
+ * never refreshed, so a hot key can't stay stale beyond ttlMs no matter
13
+ * how often it's accessed.
14
+ *
15
+ * `getOrCompute()` is the singleflight entry point: if a concurrent
16
+ * caller is already computing the value for `key`, joiners return the
17
+ * same in-flight Promise instead of racing to the underlying storage.
18
+ * Kills the wave-1 stampede where N identical concurrent requests all
19
+ * miss the cache simultaneously and all hit Redis before the first has
20
+ * populated the entry.
21
+ */
22
+ var HardBlockVerdictCache = class {
23
+ constructor(ttlMs = DEFAULT_VERDICT_CACHE_TTL_MS, maxEntries = DEFAULT_VERDICT_CACHE_MAX_ENTRIES) {
24
+ this.ttlMs = ttlMs;
25
+ this.maxEntries = maxEntries;
26
+ this.store = /* @__PURE__ */ new Map();
27
+ this.inflight = /* @__PURE__ */ new Map();
28
+ }
29
+ get(key) {
30
+ const entry = this.store.get(key);
31
+ if (entry === void 0) return;
32
+ if (entry.expiresAt <= Date.now()) {
33
+ this.store.delete(key);
34
+ return;
35
+ }
36
+ this.store.delete(key);
37
+ this.store.set(key, entry);
38
+ return entry.value;
39
+ }
40
+ set(key, value) {
41
+ this.store.delete(key);
42
+ if (this.store.size >= this.maxEntries) {
43
+ const oldest = this.store.keys().next().value;
44
+ if (oldest !== void 0) this.store.delete(oldest);
45
+ }
46
+ this.store.set(key, {
47
+ value,
48
+ expiresAt: Date.now() + this.ttlMs
49
+ });
50
+ }
51
+ /**
52
+ * Cache lookup with singleflight dedupe of concurrent misses.
53
+ *
54
+ * Fast path: cache hit → return immediately (with LRU move-to-tail
55
+ * via `get()`).
56
+ *
57
+ * Slow path: cache miss →
58
+ * 1. If an in-flight Promise exists for this key, join it. This
59
+ * is the coalescing behaviour — N concurrent identical misses
60
+ * all await the same underlying storage call.
61
+ * 2. Otherwise, invoke `compute()`, register the Promise, and
62
+ * populate the cache with the result on resolve. The Promise
63
+ * is removed from the in-flight map in a `finally` so a
64
+ * rejection doesn't wedge future callers.
65
+ *
66
+ * Rejection semantics: if `compute()` throws, all joined waiters
67
+ * see the same rejection. Callers should handle it — the underlying
68
+ * `getPrioritisedAccessRule` catches its own storage errors and
69
+ * returns `[]` (fail-open), so in practice this never propagates.
70
+ */
71
+ async getOrCompute(key, compute) {
72
+ const cached = this.get(key);
73
+ if (cached !== void 0) return cached;
74
+ const existing = this.inflight.get(key);
75
+ if (existing !== void 0) return existing;
76
+ const promise = (async () => {
77
+ const value = await compute();
78
+ this.set(key, value);
79
+ return value;
80
+ })();
81
+ this.inflight.set(key, promise);
82
+ try {
83
+ return await promise;
84
+ } finally {
85
+ if (this.inflight.get(key) === promise) this.inflight.delete(key);
86
+ }
87
+ }
88
+ clear() {
89
+ this.store.clear();
90
+ this.inflight.clear();
91
+ }
92
+ size() {
93
+ return this.store.size;
94
+ }
95
+ inflightSize() {
96
+ return this.inflight.size;
97
+ }
113
98
  };
114
- export {
115
- DEFAULT_VERDICT_CACHE_MAX_ENTRIES,
116
- DEFAULT_VERDICT_CACHE_TTL_MS,
117
- HardBlockVerdictCache,
118
- hardBlockCacheKey
99
+ var hardBlockCacheKey = (clientId, userScope, blockOnly) => {
100
+ return `${blockOnly ? "1" : "0"}|${[
101
+ clientId ?? "",
102
+ userScope.numericIp === void 0 ? "" : userScope.numericIp.toString(),
103
+ userScope.numericIpMaskMin === void 0 ? "" : userScope.numericIpMaskMin.toString(),
104
+ userScope.numericIpMaskMax === void 0 ? "" : userScope.numericIpMaskMax.toString(),
105
+ userScope.userId ?? "",
106
+ userScope.ja4Hash ?? "",
107
+ userScope.headersHash ?? "",
108
+ userScope.userAgentHash ?? "",
109
+ userScope.headHash ?? "",
110
+ userScope.coords ?? "",
111
+ userScope.countryCode ?? "",
112
+ userScope.asn === void 0 ? "" : String(userScope.asn)
113
+ ].join("|")}`;
119
114
  };
115
+ //#endregion
116
+ export { DEFAULT_VERDICT_CACHE_MAX_ENTRIES, DEFAULT_VERDICT_CACHE_TTL_MS, HardBlockVerdictCache, hardBlockCacheKey };
@@ -1,36 +1,36 @@
1
+ import { validateAddr, validateSiteKey } from "./validateAddress.js";
1
2
  import { handleErrors } from "@prosopo/api-express-router";
2
- import { validateSiteKey, validateAddr } from "./validateAddress.js";
3
- const headerCheckMiddleware = (env) => {
4
- return async (req, res, next) => {
5
- try {
6
- const user = req.headers["prosopo-user"];
7
- const siteKey = req.headers["prosopo-site-key"];
8
- if (!user) {
9
- unauthorised(res);
10
- return;
11
- }
12
- if (!siteKey) {
13
- unauthorised(res);
14
- return;
15
- }
16
- validateSiteKey(siteKey, req.logger);
17
- validateAddr(user, void 0, req.logger);
18
- req.user = user;
19
- req.siteKey = siteKey;
20
- req.logger = req.logger.with(
21
- {
22
- user,
23
- siteKey
24
- },
25
- "header-check"
26
- );
27
- next();
28
- } catch (err) {
29
- return handleErrors(err, req, res, next);
30
- }
31
- };
32
- };
33
- const unauthorised = (res) => res.status(401).json({ error: "Unauthorized", message: "Unauthorized" });
34
- export {
35
- headerCheckMiddleware
3
+ //#region src/api/headerCheckMiddleware.ts
4
+ var headerCheckMiddleware = (env) => {
5
+ return async (req, res, next) => {
6
+ try {
7
+ const user = req.headers["prosopo-user"];
8
+ const siteKey = req.headers["prosopo-site-key"];
9
+ if (!user) {
10
+ unauthorised(res);
11
+ return;
12
+ }
13
+ if (!siteKey) {
14
+ unauthorised(res);
15
+ return;
16
+ }
17
+ validateSiteKey(siteKey, req.logger);
18
+ validateAddr(user, void 0, req.logger);
19
+ req.user = user;
20
+ req.siteKey = siteKey;
21
+ req.logger = req.logger.with({
22
+ user,
23
+ siteKey
24
+ }, "header-check");
25
+ next();
26
+ } catch (err) {
27
+ return handleErrors(err, req, res, next);
28
+ }
29
+ };
36
30
  };
31
+ var unauthorised = (res) => res.status(401).json({
32
+ error: "Unauthorized",
33
+ message: "Unauthorized"
34
+ });
35
+ //#endregion
36
+ export { headerCheckMiddleware };
@@ -1,17 +1,15 @@
1
- import { PublicApiPaths, ApiPrefix } from "@prosopo/types";
1
+ import { ApiPrefix, PublicApiPaths } from "@prosopo/types";
2
+ //#region src/api/ignoreMiddleware.ts
2
3
  function ignoreMiddleware() {
3
- return (req, res, next) => {
4
- if (req.originalUrl.indexOf(PublicApiPaths.Healthz) !== -1) {
5
- return next();
6
- }
7
- if (req.originalUrl.indexOf(ApiPrefix) === -1) {
8
- res.statusCode = 404;
9
- res.send("Not Found");
10
- return;
11
- }
12
- next();
13
- };
4
+ return (req, res, next) => {
5
+ if (req.originalUrl.indexOf(PublicApiPaths.Healthz) !== -1) return next();
6
+ if (req.originalUrl.indexOf(ApiPrefix) === -1) {
7
+ res.statusCode = 404;
8
+ res.send("Not Found");
9
+ return;
10
+ }
11
+ next();
12
+ };
14
13
  }
15
- export {
16
- ignoreMiddleware
17
- };
14
+ //#endregion
15
+ export { ignoreMiddleware };
@@ -1,20 +1,18 @@
1
- const ipInfoMiddleware = (env) => {
2
- return async (req, _res, next) => {
3
- try {
4
- const ip = req.ip;
5
- if (ip && env.ipInfoService.isAvailable()) {
6
- req.ipInfo = await env.ipInfoService.lookup(ip);
7
- }
8
- next();
9
- } catch (err) {
10
- req.logger?.warn?.(() => ({
11
- msg: "IP info middleware failed",
12
- err
13
- }));
14
- next();
15
- }
16
- };
17
- };
18
- export {
19
- ipInfoMiddleware
1
+ //#region src/api/ipInfoMiddleware.ts
2
+ var ipInfoMiddleware = (env) => {
3
+ return async (req, _res, next) => {
4
+ try {
5
+ const ip = req.ip;
6
+ if (ip && env.ipInfoService.isAvailable()) req.ipInfo = await env.ipInfoService.lookup(ip);
7
+ next();
8
+ } catch (err) {
9
+ req.logger?.warn?.(() => ({
10
+ msg: "IP info middleware failed",
11
+ err
12
+ }));
13
+ next();
14
+ }
15
+ };
20
16
  };
17
+ //#endregion
18
+ export { ipInfoMiddleware };