@prosopo/provider 5.9.0 → 5.10.0

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 (47) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +8 -7
  2. package/.turbo/turbo-build$colon$tsc.log +27 -27
  3. package/.turbo/turbo-build.log +9 -8
  4. package/CHANGELOG.md +51 -0
  5. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
  6. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +3 -1
  7. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
  8. package/dist/api/healthzGeo.d.ts +54 -0
  9. package/dist/api/healthzGeo.d.ts.map +1 -0
  10. package/dist/api/healthzGeo.js +205 -0
  11. package/dist/api/healthzGeo.js.map +1 -0
  12. package/dist/api/metrics.d.ts +3 -0
  13. package/dist/api/metrics.d.ts.map +1 -1
  14. package/dist/api/metrics.js +11 -1
  15. package/dist/api/metrics.js.map +1 -1
  16. package/dist/api/public.d.ts.map +1 -1
  17. package/dist/api/public.js +13 -3
  18. package/dist/api/public.js.map +1 -1
  19. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +3 -1
  20. package/dist/cjs/api/healthzGeo.cjs +209 -0
  21. package/dist/cjs/api/metrics.cjs +11 -0
  22. package/dist/cjs/api/public.cjs +13 -2
  23. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +5 -0
  24. package/dist/tasks/frictionless/frictionlessTasks.d.ts +1 -0
  25. package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
  26. package/dist/tasks/frictionless/frictionlessTasks.js +5 -0
  27. package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
  28. package/dist/tests/integration/trafficFilterHierarchy.integration.test.js +1 -0
  29. package/dist/tests/integration/trafficFilterHierarchy.integration.test.js.map +1 -1
  30. package/dist/tests/integration/webBotAuthAuthenticated.integration.test.js +1 -0
  31. package/dist/tests/integration/webBotAuthAuthenticated.integration.test.js.map +1 -1
  32. package/dist/tests/unit/api/healthzGeo.unit.test.d.ts +2 -0
  33. package/dist/tests/unit/api/healthzGeo.unit.test.d.ts.map +1 -0
  34. package/dist/tests/unit/api/healthzGeo.unit.test.js +272 -0
  35. package/dist/tests/unit/api/healthzGeo.unit.test.js.map +1 -0
  36. package/dist/tests/unit/api/public.unit.test.js +132 -2
  37. package/dist/tests/unit/api/public.unit.test.js.map +1 -1
  38. package/dist/tests/unit/services/ipComparison.unit.test.js +2 -0
  39. package/dist/tests/unit/services/ipComparison.unit.test.js.map +1 -1
  40. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js +35 -0
  41. package/dist/tests/unit/tasks/frictionless/decryptPayload.unit.test.js.map +1 -1
  42. package/dist/tests/unit/testUtils/mockProviderEnv.d.ts.map +1 -1
  43. package/dist/tests/unit/testUtils/mockProviderEnv.js +1 -0
  44. package/dist/tests/unit/testUtils/mockProviderEnv.js.map +1 -1
  45. package/dist/tests/unit/util.ipDistance.unit.test.js +1 -0
  46. package/dist/tests/unit/util.ipDistance.unit.test.js.map +1 -1
  47. package/package.json +13 -13
@@ -0,0 +1,205 @@
1
+ import { PublicApiPaths } from "@prosopo/types";
2
+ import { z } from "zod";
3
+ //#region src/api/healthzGeo.ts
4
+ /**
5
+ * Geo steering for `/healthz`.
6
+ *
7
+ * `/healthz` tells a client which node to pin its captcha calls to. By default
8
+ * a node answers with its own name, so the pin is whatever the DNS layer
9
+ * picked. With steering enabled the node instead answers with the node the
10
+ * caller's country is mapped to, when that node is known to be up.
11
+ *
12
+ * Off by default. With the flag off nothing here runs: no lookup, no poller,
13
+ * no response header, no counter.
14
+ *
15
+ * Configuration (all read once, at first use):
16
+ *
17
+ * PROSOPO_HEALTHZ_GEO_STEERING
18
+ * "true" enables steering. Anything else, including unset, disables it.
19
+ *
20
+ * PROSOPO_HEALTHZ_GEO_ROUTES
21
+ * JSON object mapping ISO 3166-1 alpha-2 country code to hostname, e.g.
22
+ * `{"XX":"node1.example.com","YY":"node2.example.com"}`. Keys are
23
+ * case-insensitive. Countries absent from the map are not steered.
24
+ *
25
+ * The map is the candidate set: a host that must not receive traffic
26
+ * simply does not appear in it. Nothing here derives candidates from
27
+ * anywhere else, so the deployment that generates the map is the single
28
+ * place that decides which nodes are in rotation.
29
+ *
30
+ * PROSOPO_HEALTHZ_GEO_PROBE_INTERVAL_MS (default 30000)
31
+ * PROSOPO_HEALTHZ_GEO_PROBE_TIMEOUT_MS (default 2000)
32
+ * Background health-probe period and per-probe timeout.
33
+ *
34
+ * An invalid or unparseable route map disables steering rather than failing
35
+ * startup — the fallback is the node's own name, which is the default
36
+ * behaviour.
37
+ */
38
+ var DEFAULT_PROBE_INTERVAL_MS = 3e4;
39
+ var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
40
+ var MIN_PROBE_INTERVAL_MS = 1e3;
41
+ /** Hostname, not a URL: no scheme, no path, no port. */
42
+ var hostnameSchema = z.string().min(1).max(253).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i);
43
+ var routesSchema = z.record(z.string().regex(/^[a-z]{2}$/i), hostnameSchema);
44
+ var parsePositiveInt = (raw, fallback) => {
45
+ if (raw === void 0) return fallback;
46
+ const parsed = Number.parseInt(raw, 10);
47
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
48
+ };
49
+ var parseRoutes = (raw, logger) => {
50
+ if (!raw || raw.trim().length === 0) return /* @__PURE__ */ new Map();
51
+ try {
52
+ const parsed = routesSchema.parse(JSON.parse(raw));
53
+ return new Map(Object.entries(parsed).map(([country, host]) => [country.toUpperCase(), host]));
54
+ } catch (err) {
55
+ logger?.warn(() => ({
56
+ msg: "PROSOPO_HEALTHZ_GEO_ROUTES is not a valid country->host map; healthz geo steering stays off",
57
+ err
58
+ }));
59
+ return /* @__PURE__ */ new Map();
60
+ }
61
+ };
62
+ var readHealthzGeoConfig = (envVars = process.env, logger) => {
63
+ const routes = parseRoutes(envVars.PROSOPO_HEALTHZ_GEO_ROUTES, logger);
64
+ return {
65
+ enabled: envVars.PROSOPO_HEALTHZ_GEO_STEERING === "true" && routes.size > 0,
66
+ routes,
67
+ probeIntervalMs: Math.max(MIN_PROBE_INTERVAL_MS, parsePositiveInt(envVars.PROSOPO_HEALTHZ_GEO_PROBE_INTERVAL_MS, DEFAULT_PROBE_INTERVAL_MS)),
68
+ probeTimeoutMs: parsePositiveInt(envVars.PROSOPO_HEALTHZ_GEO_PROBE_TIMEOUT_MS, DEFAULT_PROBE_TIMEOUT_MS)
69
+ };
70
+ };
71
+ var fetchHealthzProbe = async (host, timeoutMs) => {
72
+ try {
73
+ return (await fetch(`https://${host}${PublicApiPaths.Healthz}`, {
74
+ method: "GET",
75
+ signal: AbortSignal.timeout(timeoutMs)
76
+ })).ok;
77
+ } catch {
78
+ return false;
79
+ }
80
+ };
81
+ /**
82
+ * Tracks whether each candidate host is answering, in the background.
83
+ *
84
+ * `/healthz` is served before the request pipeline that would otherwise
85
+ * observe a node's health, so nothing else here knows whether a candidate is
86
+ * reachable. Every host starts `false` and only becomes `true` on a successful
87
+ * probe, so a poller that has not run, cannot run, or is failing leaves every
88
+ * candidate down and steering off — degrading to the default behaviour by
89
+ * construction rather than by a fallback branch.
90
+ *
91
+ * The probe never touches the request path: `isUp()` reads a boolean.
92
+ */
93
+ var TargetHealthMonitor = class {
94
+ constructor(options) {
95
+ this.up = /* @__PURE__ */ new Map();
96
+ this.hosts = [...new Set(options.hosts)];
97
+ this.intervalMs = options.intervalMs;
98
+ this.timeoutMs = options.timeoutMs;
99
+ this.probe = options.probe ?? fetchHealthzProbe;
100
+ this.logger = options.logger;
101
+ }
102
+ isUp(host) {
103
+ return this.up.get(host) === true;
104
+ }
105
+ start() {
106
+ if (this.timer !== void 0 || this.hosts.length === 0) return;
107
+ this.pollAll();
108
+ this.timer = setInterval(() => {
109
+ this.pollAll();
110
+ }, this.intervalMs);
111
+ this.timer.unref?.();
112
+ }
113
+ stop() {
114
+ if (this.timer !== void 0) {
115
+ clearInterval(this.timer);
116
+ this.timer = void 0;
117
+ }
118
+ }
119
+ /** One probe round over every candidate. Exposed so tests can await it. */
120
+ async pollAll() {
121
+ await Promise.all(this.hosts.map(async (host) => {
122
+ let healthy = false;
123
+ try {
124
+ healthy = await this.probe(host, this.timeoutMs);
125
+ } catch {
126
+ healthy = false;
127
+ }
128
+ const previous = this.up.get(host);
129
+ this.up.set(host, healthy);
130
+ if (previous !== healthy) this.logger?.info(() => ({
131
+ msg: "healthz geo target health changed",
132
+ data: {
133
+ host,
134
+ healthy
135
+ }
136
+ }));
137
+ }));
138
+ }
139
+ };
140
+ /**
141
+ * Picks the host `/healthz` should answer with. Pure apart from reading the
142
+ * monitor's booleans and the memory-mapped country lookup — it never awaits
143
+ * anything, so it cannot delay or fail a health check.
144
+ */
145
+ var HealthzGeoRouter = class {
146
+ constructor(config, env, monitor) {
147
+ this.enabled = config.enabled;
148
+ this.routes = config.routes;
149
+ this.ipInfoService = env.ipInfoService;
150
+ this.monitor = monitor ?? new TargetHealthMonitor({
151
+ hosts: [...new Set(config.routes.values())],
152
+ intervalMs: config.probeIntervalMs,
153
+ timeoutMs: config.probeTimeoutMs,
154
+ logger: env.logger
155
+ });
156
+ }
157
+ start() {
158
+ if (this.enabled) this.monitor.start();
159
+ }
160
+ stop() {
161
+ this.monitor.stop();
162
+ }
163
+ resolveHost(clientIp, ownHost) {
164
+ if (!this.enabled) return {
165
+ host: ownHost,
166
+ outcome: "not_steered"
167
+ };
168
+ if (!clientIp) return {
169
+ host: ownHost,
170
+ outcome: "geo_unavailable"
171
+ };
172
+ if (!this.ipInfoService.isAvailable()) return {
173
+ host: ownHost,
174
+ outcome: "geo_unavailable"
175
+ };
176
+ const country = this.ipInfoService.country(clientIp);
177
+ if (!country) return {
178
+ host: ownHost,
179
+ outcome: "geo_unavailable"
180
+ };
181
+ const target = this.routes.get(country.toUpperCase());
182
+ if (target === void 0 || target === ownHost) return {
183
+ host: ownHost,
184
+ outcome: "not_steered"
185
+ };
186
+ if (!this.monitor.isUp(target)) return {
187
+ host: ownHost,
188
+ outcome: "target_down"
189
+ };
190
+ return {
191
+ host: target,
192
+ outcome: "steered"
193
+ };
194
+ }
195
+ };
196
+ var cachedRouter;
197
+ var getHealthzGeoRouter = (env) => {
198
+ if (!cachedRouter) {
199
+ cachedRouter = new HealthzGeoRouter(readHealthzGeoConfig(process.env, env.logger), env);
200
+ cachedRouter.start();
201
+ }
202
+ return cachedRouter;
203
+ };
204
+ //#endregion
205
+ export { HealthzGeoRouter, TargetHealthMonitor, fetchHealthzProbe, getHealthzGeoRouter, readHealthzGeoConfig };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healthzGeo.js","sourceRoot":"","sources":["../../src/api/healthzGeo.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import type { ProviderEnvironment } from "@prosopo/env";
2
2
  import { type CaptchaType } from "@prosopo/types";
3
3
  import type { RequestHandler } from "express";
4
4
  import { Counter, Gauge, Histogram, Registry } from "prom-client";
5
+ import type { HealthzGeoOutcome } from "./healthzGeo.js";
5
6
  export declare const metricsEnabled: () => boolean;
6
7
  interface ProviderMetrics {
7
8
  registry: Registry;
@@ -18,6 +19,7 @@ interface ProviderMetrics {
18
19
  spamEmailTotal: Counter<"result">;
19
20
  maintenanceMode: Gauge<never>;
20
21
  redisReady: Gauge<"actor">;
22
+ healthzGeoOutcomesTotal: Counter<"outcome">;
21
23
  }
22
24
  export declare const getMetrics: () => ProviderMetrics;
23
25
  export declare const recordCaptchaIssued: (type: CaptchaType) => void;
@@ -33,6 +35,7 @@ export declare const recordDetectorTriggered: (detectors: Array<string | number>
33
35
  export declare const recordBlockedRequest: (reason: string) => void;
34
36
  export declare const recordDomainValidation: (result: string) => void;
35
37
  export declare const recordSpamEmail: (result: string) => void;
38
+ export declare const recordHealthzGeoOutcome: (outcome: HealthzGeoOutcome) => void;
36
39
  export declare const setMaintenanceModeGauge: (on: boolean) => void;
37
40
  export declare const metricsMiddleware: () => RequestHandler;
38
41
  export declare const metricsHandler: (env: ProviderEnvironment) => RequestHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/api/metrics.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAEN,KAAK,WAAW,EAGhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAC/E,OAAO,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,QAAQ,EAER,MAAM,aAAa,CAAC;AAMrB,eAAO,MAAM,cAAc,QAAO,OACc,CAAC;AAmCjD,UAAU,eAAe;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAC1D,mBAAmB,EAAE,SAAS,CAAC,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAC9D,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,uBAAuB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,kBAAkB,EAAE,OAAO,CAAC,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAC1D,uBAAuB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7C,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3B,sBAAsB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,oBAAoB,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,qBAAqB,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;CAC3B;AA+GD,eAAO,MAAM,UAAU,QAAO,eAK7B,CAAC;AAQF,eAAO,MAAM,mBAAmB,SAAU,WAAW,KAAG,IAGvD,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAAU,WAAW,KAAG,IAG3D,CAAC;AAEF,eAAO,MAAM,mBAAmB,SAAU;IACzC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,QAAQ,CAAC;CACvD,KAAG,IAOH,CAAC;AAEF,eAAO,MAAM,0BAA0B,aAAc,MAAM,KAAG,IAG7D,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,IAG9C,CAAC;AAEF,eAAO,MAAM,uBAAuB,cACxB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAC/B,IAMF,CAAC;AAEF,eAAO,MAAM,oBAAoB,WAAY,MAAM,KAAG,IAGrD,CAAC;AAEF,eAAO,MAAM,sBAAsB,WAAY,MAAM,KAAG,IAGvD,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,MAAM,KAAG,IAGhD,CAAC;AAEF,eAAO,MAAM,uBAAuB,OAAQ,OAAO,KAAG,IAGrD,CAAC;AASF,eAAO,MAAM,iBAAiB,QAAO,cAkBpC,CAAC;AASF,eAAO,MAAM,cAAc,QAAS,mBAAmB,KAAG,cA4BzD,CAAC"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/api/metrics.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAEN,KAAK,WAAW,EAGhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAC/E,OAAO,EACN,OAAO,EACP,KAAK,EACL,SAAS,EACT,QAAQ,EAER,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAMzD,eAAO,MAAM,cAAc,QAAO,OACc,CAAC;AAmCjD,UAAU,eAAe;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAC1D,mBAAmB,EAAE,SAAS,CAAC,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAC9D,kBAAkB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,uBAAuB,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,kBAAkB,EAAE,OAAO,CAAC,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAC1D,uBAAuB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7C,QAAQ,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IAC3B,sBAAsB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,oBAAoB,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,qBAAqB,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzC,cAAc,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,eAAe,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,uBAAuB,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CAC5C;AA0HD,eAAO,MAAM,UAAU,QAAO,eAK7B,CAAC;AAQF,eAAO,MAAM,mBAAmB,SAAU,WAAW,KAAG,IAGvD,CAAC;AAEF,eAAO,MAAM,uBAAuB,SAAU,WAAW,KAAG,IAG3D,CAAC;AAEF,eAAO,MAAM,mBAAmB,SAAU;IACzC,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,QAAQ,CAAC;CACvD,KAAG,IAOH,CAAC;AAEF,eAAO,MAAM,0BAA0B,aAAc,MAAM,KAAG,IAG7D,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,KAAG,IAG9C,CAAC;AAEF,eAAO,MAAM,uBAAuB,cACxB,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,KAC/B,IAMF,CAAC;AAEF,eAAO,MAAM,oBAAoB,WAAY,MAAM,KAAG,IAGrD,CAAC;AAEF,eAAO,MAAM,sBAAsB,WAAY,MAAM,KAAG,IAGvD,CAAC;AAEF,eAAO,MAAM,eAAe,WAAY,MAAM,KAAG,IAGhD,CAAC;AAEF,eAAO,MAAM,uBAAuB,YAAa,iBAAiB,KAAG,IAGpE,CAAC;AAEF,eAAO,MAAM,uBAAuB,OAAQ,OAAO,KAAG,IAGrD,CAAC;AASF,eAAO,MAAM,iBAAiB,QAAO,cAkBpC,CAAC;AASF,eAAO,MAAM,cAAc,QAAS,mBAAmB,KAAG,cA4BzD,CAAC"}
@@ -154,6 +154,12 @@ var buildMetrics = () => {
154
154
  help: "1 when the given redis connection is ready, else 0",
155
155
  labelNames: ["actor"],
156
156
  registers: [registry]
157
+ }),
158
+ healthzGeoOutcomesTotal: new Counter({
159
+ name: `${PREFIX}healthz_geo_outcomes_total`,
160
+ help: "Healthz geo steering outcomes (steered/not_steered/target_down/geo_unavailable)",
161
+ labelNames: ["outcome"],
162
+ registers: [registry]
157
163
  })
158
164
  };
159
165
  };
@@ -202,6 +208,10 @@ var recordSpamEmail = (result) => {
202
208
  if (!metricsEnabled()) return;
203
209
  getMetrics().spamEmailTotal.inc({ result });
204
210
  };
211
+ var recordHealthzGeoOutcome = (outcome) => {
212
+ if (!metricsEnabled()) return;
213
+ getMetrics().healthzGeoOutcomesTotal.inc({ outcome });
214
+ };
205
215
  var setMaintenanceModeGauge = (on) => {
206
216
  if (!metricsEnabled()) return;
207
217
  getMetrics().maintenanceMode.set(on ? 1 : 0);
@@ -245,4 +255,4 @@ var metricsHandler = (env) => {
245
255
  };
246
256
  };
247
257
  //#endregion
248
- export { getMetrics, metricsEnabled, metricsHandler, metricsMiddleware, recordBlockedRequest, recordBotScore, recordCaptchaIssueError, recordCaptchaIssued, recordCaptchaVerify, recordDetectorTriggered, recordDomainValidation, recordFrictionlessDecision, recordSpamEmail, setMaintenanceModeGauge };
258
+ export { getMetrics, metricsEnabled, metricsHandler, metricsMiddleware, recordBlockedRequest, recordBotScore, recordCaptchaIssueError, recordCaptchaIssued, recordCaptchaVerify, recordDetectorTriggered, recordDomainValidation, recordFrictionlessDecision, recordHealthzGeoOutcome, recordSpamEmail, setMaintenanceModeGauge };
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/api/metrics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/api/metrics.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/api/public.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGxD,OAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAQ/C,wBAAgB,YAAY,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CA4E7D"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/api/public.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGxD,OAAgB,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAa/C,wBAAgB,YAAY,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,CA2G7D"}
@@ -1,4 +1,5 @@
1
- import { metricsEnabled, metricsHandler } from "./metrics.js";
1
+ import { metricsEnabled, metricsHandler, recordHealthzGeoOutcome } from "./metrics.js";
2
+ import { getHealthzGeoRouter } from "./healthzGeo.js";
2
3
  import { ProsopoApiError } from "@prosopo/common";
3
4
  import { PublicApiPaths } from "@prosopo/types";
4
5
  import { version } from "@prosopo/util";
@@ -12,11 +13,19 @@ import express from "express";
12
13
  */
13
14
  function publicRouter(env) {
14
15
  const router = express.Router();
16
+ const geo = getHealthzGeoRouter(env);
15
17
  router.get(PublicApiPaths.Healthz, (req, res) => {
16
- const host = env.config.host && env.config.host.length > 0 ? env.config.host : req.hostname;
18
+ const ownHost = env.config.host && env.config.host.length > 0 ? env.config.host : req.hostname;
19
+ if (!geo.enabled) return res.status(200).json({
20
+ ok: true,
21
+ host: ownHost
22
+ });
23
+ res.set("Cache-Control", "no-store, private");
24
+ const decision = geo.resolveHost(req.ip, ownHost);
25
+ recordHealthzGeoOutcome(decision.outcome);
17
26
  return res.status(200).json({
18
27
  ok: true,
19
- host
28
+ host: decision.host
20
29
  });
21
30
  });
22
31
  if (metricsEnabled()) router.get(PublicApiPaths.Metrics, metricsHandler(env));
@@ -31,6 +40,7 @@ function publicRouter(env) {
31
40
  const response = {
32
41
  version,
33
42
  message: "Provider online",
43
+ host: env.config.host && env.config.host.length > 0 ? env.config.host : req.hostname,
34
44
  redis: [{
35
45
  actor: "General",
36
46
  isReady: redisConnection.isReady(),
@@ -1 +1 @@
1
- {"version":3,"file":"public.js","sourceRoot":"","sources":["../../src/api/public.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAwB,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,OAAwB,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAO9D,MAAM,UAAU,YAAY,CAAC,GAAwB;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQhC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC/C,MAAM,IAAI,GACT,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;YAC5C,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI;YACjB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;QACjB,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAKH,IAAI,cAAc,EAAE,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,CAAC;IAKD,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,kBAAkB,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACtE,IAAI,CAAC;YACJ,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;YAEvB,MAAM,eAAe,GAAG,EAAE,CAAC,kBAAkB,EAAE,CAAC;YAChD,MAAM,0BAA0B,GAAG,EAAE,CAAC,6BAA6B,EAAE,CAAC;YAEtE,MAAM,QAAQ,GAAoB;gBACjC,OAAO;gBACP,OAAO,EAAE,iBAAiB;gBAC1B,KAAK,EAAE;oBACN;wBACC,KAAK,EAAE,SAAS;wBAChB,OAAO,EAAE,eAAe,CAAC,OAAO,EAAE;wBAClC,mBAAmB,EAAE,IAAI,CAAC,IAAI,CAC7B,eAAe,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAC1C;qBACD;oBACD;wBACC,KAAK,EAAE,KAAK;wBACZ,OAAO,EAAE,0BAA0B,CAAC,OAAO,EAAE;wBAC7C,mBAAmB,EAAE,IAAI,CAAC,IAAI,CAC7B,0BAA0B,CAAC,iBAAiB,EAAE,GAAG,IAAI,CACrD;qBACD;iBACD;aACD,CAAC;YAEF,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;gBACvB,GAAG;gBACH,IAAI,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE;gBAC/B,GAAG,EAAE,gCAAgC;aACrC,CAAC,CAAC,CAAC;YACJ,OAAO,IAAI,CACV,IAAI,eAAe,CAAC,iBAAiB,EAAE;gBACtC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE;aACtB,CAAC,CACF,CAAC;QACH,CAAC;IACF,CAAC,CAAC,CAAC;IAKH,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAEzB,OAAO,MAAM,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"public.js","sourceRoot":"","sources":["../../src/api/public.ts"],"names":[],"mappings":"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"}
@@ -267,7 +267,7 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
267
267
  ...verifiedSignerUrl && { agent: verifiedSignerUrl }
268
268
  });
269
269
  }
270
- const { baseBotScore: rawBaseBotScore, timestamp: rawTimestamp, userId: rawUserId, userAgent: rawUserAgent, webView, iFrame, decryptedHeadHash, decryptionFailed: rawDecryptionFailed, triggeredDetectors, shadowDomPenalty, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, g, sw, md, bn, fs, bundleId } = decryptedPayload;
270
+ const { baseBotScore: rawBaseBotScore, timestamp: rawTimestamp, userId: rawUserId, userAgent: rawUserAgent, webView, iFrame, decryptedHeadHash, decryptionFailed: rawDecryptionFailed, triggeredDetectors, shadowDomPenalty, entropyMathRandomFingerprint, entropyCryptoFingerprint, entropyWallClockOffsetMs, entropyMathRandomFirst, g, i, b, sw, md, bn, fs, bundleId } = decryptedPayload;
271
271
  const detectorOverride = process.env.PROSOPO_TEST_FRICTIONLESS_DETECTOR_OVERRIDE === "1";
272
272
  const baseBotScore = detectorOverride ? 0 : rawBaseBotScore;
273
273
  const timestamp = detectorOverride ? Date.now() : rawTimestamp;
@@ -328,6 +328,8 @@ var handler_default = (env, userAccessRulesStorage) => async (req, res, next) =>
328
328
  ...entropyWallClockOffsetMs !== void 0 && { entropyWallClockOffsetMs },
329
329
  ...entropyMathRandomFirst !== void 0 && { entropyMathRandomFirst },
330
330
  ...g !== void 0 && { g },
331
+ ...i !== void 0 && { i },
332
+ ...b !== void 0 && { b },
331
333
  ...sw !== void 0 && { sw },
332
334
  ...md !== void 0 && { md },
333
335
  ...bn !== void 0 && { bn },
@@ -0,0 +1,209 @@
1
+ let _prosopo_types = require("@prosopo/types");
2
+ let zod = require("zod");
3
+ //#region src/api/healthzGeo.ts
4
+ /**
5
+ * Geo steering for `/healthz`.
6
+ *
7
+ * `/healthz` tells a client which node to pin its captcha calls to. By default
8
+ * a node answers with its own name, so the pin is whatever the DNS layer
9
+ * picked. With steering enabled the node instead answers with the node the
10
+ * caller's country is mapped to, when that node is known to be up.
11
+ *
12
+ * Off by default. With the flag off nothing here runs: no lookup, no poller,
13
+ * no response header, no counter.
14
+ *
15
+ * Configuration (all read once, at first use):
16
+ *
17
+ * PROSOPO_HEALTHZ_GEO_STEERING
18
+ * "true" enables steering. Anything else, including unset, disables it.
19
+ *
20
+ * PROSOPO_HEALTHZ_GEO_ROUTES
21
+ * JSON object mapping ISO 3166-1 alpha-2 country code to hostname, e.g.
22
+ * `{"XX":"node1.example.com","YY":"node2.example.com"}`. Keys are
23
+ * case-insensitive. Countries absent from the map are not steered.
24
+ *
25
+ * The map is the candidate set: a host that must not receive traffic
26
+ * simply does not appear in it. Nothing here derives candidates from
27
+ * anywhere else, so the deployment that generates the map is the single
28
+ * place that decides which nodes are in rotation.
29
+ *
30
+ * PROSOPO_HEALTHZ_GEO_PROBE_INTERVAL_MS (default 30000)
31
+ * PROSOPO_HEALTHZ_GEO_PROBE_TIMEOUT_MS (default 2000)
32
+ * Background health-probe period and per-probe timeout.
33
+ *
34
+ * An invalid or unparseable route map disables steering rather than failing
35
+ * startup — the fallback is the node's own name, which is the default
36
+ * behaviour.
37
+ */
38
+ var DEFAULT_PROBE_INTERVAL_MS = 3e4;
39
+ var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
40
+ var MIN_PROBE_INTERVAL_MS = 1e3;
41
+ /** Hostname, not a URL: no scheme, no path, no port. */
42
+ var hostnameSchema = zod.z.string().min(1).max(253).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i);
43
+ var routesSchema = zod.z.record(zod.z.string().regex(/^[a-z]{2}$/i), hostnameSchema);
44
+ var parsePositiveInt = (raw, fallback) => {
45
+ if (raw === void 0) return fallback;
46
+ const parsed = Number.parseInt(raw, 10);
47
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
48
+ };
49
+ var parseRoutes = (raw, logger) => {
50
+ if (!raw || raw.trim().length === 0) return /* @__PURE__ */ new Map();
51
+ try {
52
+ const parsed = routesSchema.parse(JSON.parse(raw));
53
+ return new Map(Object.entries(parsed).map(([country, host]) => [country.toUpperCase(), host]));
54
+ } catch (err) {
55
+ logger?.warn(() => ({
56
+ msg: "PROSOPO_HEALTHZ_GEO_ROUTES is not a valid country->host map; healthz geo steering stays off",
57
+ err
58
+ }));
59
+ return /* @__PURE__ */ new Map();
60
+ }
61
+ };
62
+ var readHealthzGeoConfig = (envVars = process.env, logger) => {
63
+ const routes = parseRoutes(envVars.PROSOPO_HEALTHZ_GEO_ROUTES, logger);
64
+ return {
65
+ enabled: envVars.PROSOPO_HEALTHZ_GEO_STEERING === "true" && routes.size > 0,
66
+ routes,
67
+ probeIntervalMs: Math.max(MIN_PROBE_INTERVAL_MS, parsePositiveInt(envVars.PROSOPO_HEALTHZ_GEO_PROBE_INTERVAL_MS, DEFAULT_PROBE_INTERVAL_MS)),
68
+ probeTimeoutMs: parsePositiveInt(envVars.PROSOPO_HEALTHZ_GEO_PROBE_TIMEOUT_MS, DEFAULT_PROBE_TIMEOUT_MS)
69
+ };
70
+ };
71
+ var fetchHealthzProbe = async (host, timeoutMs) => {
72
+ try {
73
+ return (await fetch(`https://${host}${_prosopo_types.PublicApiPaths.Healthz}`, {
74
+ method: "GET",
75
+ signal: AbortSignal.timeout(timeoutMs)
76
+ })).ok;
77
+ } catch {
78
+ return false;
79
+ }
80
+ };
81
+ /**
82
+ * Tracks whether each candidate host is answering, in the background.
83
+ *
84
+ * `/healthz` is served before the request pipeline that would otherwise
85
+ * observe a node's health, so nothing else here knows whether a candidate is
86
+ * reachable. Every host starts `false` and only becomes `true` on a successful
87
+ * probe, so a poller that has not run, cannot run, or is failing leaves every
88
+ * candidate down and steering off — degrading to the default behaviour by
89
+ * construction rather than by a fallback branch.
90
+ *
91
+ * The probe never touches the request path: `isUp()` reads a boolean.
92
+ */
93
+ var TargetHealthMonitor = class {
94
+ constructor(options) {
95
+ this.up = /* @__PURE__ */ new Map();
96
+ this.hosts = [...new Set(options.hosts)];
97
+ this.intervalMs = options.intervalMs;
98
+ this.timeoutMs = options.timeoutMs;
99
+ this.probe = options.probe ?? fetchHealthzProbe;
100
+ this.logger = options.logger;
101
+ }
102
+ isUp(host) {
103
+ return this.up.get(host) === true;
104
+ }
105
+ start() {
106
+ if (this.timer !== void 0 || this.hosts.length === 0) return;
107
+ this.pollAll();
108
+ this.timer = setInterval(() => {
109
+ this.pollAll();
110
+ }, this.intervalMs);
111
+ this.timer.unref?.();
112
+ }
113
+ stop() {
114
+ if (this.timer !== void 0) {
115
+ clearInterval(this.timer);
116
+ this.timer = void 0;
117
+ }
118
+ }
119
+ /** One probe round over every candidate. Exposed so tests can await it. */
120
+ async pollAll() {
121
+ await Promise.all(this.hosts.map(async (host) => {
122
+ let healthy = false;
123
+ try {
124
+ healthy = await this.probe(host, this.timeoutMs);
125
+ } catch {
126
+ healthy = false;
127
+ }
128
+ const previous = this.up.get(host);
129
+ this.up.set(host, healthy);
130
+ if (previous !== healthy) this.logger?.info(() => ({
131
+ msg: "healthz geo target health changed",
132
+ data: {
133
+ host,
134
+ healthy
135
+ }
136
+ }));
137
+ }));
138
+ }
139
+ };
140
+ /**
141
+ * Picks the host `/healthz` should answer with. Pure apart from reading the
142
+ * monitor's booleans and the memory-mapped country lookup — it never awaits
143
+ * anything, so it cannot delay or fail a health check.
144
+ */
145
+ var HealthzGeoRouter = class {
146
+ constructor(config, env, monitor) {
147
+ this.enabled = config.enabled;
148
+ this.routes = config.routes;
149
+ this.ipInfoService = env.ipInfoService;
150
+ this.monitor = monitor ?? new TargetHealthMonitor({
151
+ hosts: [...new Set(config.routes.values())],
152
+ intervalMs: config.probeIntervalMs,
153
+ timeoutMs: config.probeTimeoutMs,
154
+ logger: env.logger
155
+ });
156
+ }
157
+ start() {
158
+ if (this.enabled) this.monitor.start();
159
+ }
160
+ stop() {
161
+ this.monitor.stop();
162
+ }
163
+ resolveHost(clientIp, ownHost) {
164
+ if (!this.enabled) return {
165
+ host: ownHost,
166
+ outcome: "not_steered"
167
+ };
168
+ if (!clientIp) return {
169
+ host: ownHost,
170
+ outcome: "geo_unavailable"
171
+ };
172
+ if (!this.ipInfoService.isAvailable()) return {
173
+ host: ownHost,
174
+ outcome: "geo_unavailable"
175
+ };
176
+ const country = this.ipInfoService.country(clientIp);
177
+ if (!country) return {
178
+ host: ownHost,
179
+ outcome: "geo_unavailable"
180
+ };
181
+ const target = this.routes.get(country.toUpperCase());
182
+ if (target === void 0 || target === ownHost) return {
183
+ host: ownHost,
184
+ outcome: "not_steered"
185
+ };
186
+ if (!this.monitor.isUp(target)) return {
187
+ host: ownHost,
188
+ outcome: "target_down"
189
+ };
190
+ return {
191
+ host: target,
192
+ outcome: "steered"
193
+ };
194
+ }
195
+ };
196
+ var cachedRouter;
197
+ var getHealthzGeoRouter = (env) => {
198
+ if (!cachedRouter) {
199
+ cachedRouter = new HealthzGeoRouter(readHealthzGeoConfig(process.env, env.logger), env);
200
+ cachedRouter.start();
201
+ }
202
+ return cachedRouter;
203
+ };
204
+ //#endregion
205
+ exports.HealthzGeoRouter = HealthzGeoRouter;
206
+ exports.TargetHealthMonitor = TargetHealthMonitor;
207
+ exports.fetchHealthzProbe = fetchHealthzProbe;
208
+ exports.getHealthzGeoRouter = getHealthzGeoRouter;
209
+ exports.readHealthzGeoConfig = readHealthzGeoConfig;
@@ -154,6 +154,12 @@ var buildMetrics = () => {
154
154
  help: "1 when the given redis connection is ready, else 0",
155
155
  labelNames: ["actor"],
156
156
  registers: [registry]
157
+ }),
158
+ healthzGeoOutcomesTotal: new prom_client.Counter({
159
+ name: `${PREFIX}healthz_geo_outcomes_total`,
160
+ help: "Healthz geo steering outcomes (steered/not_steered/target_down/geo_unavailable)",
161
+ labelNames: ["outcome"],
162
+ registers: [registry]
157
163
  })
158
164
  };
159
165
  };
@@ -202,6 +208,10 @@ var recordSpamEmail = (result) => {
202
208
  if (!metricsEnabled()) return;
203
209
  getMetrics().spamEmailTotal.inc({ result });
204
210
  };
211
+ var recordHealthzGeoOutcome = (outcome) => {
212
+ if (!metricsEnabled()) return;
213
+ getMetrics().healthzGeoOutcomesTotal.inc({ outcome });
214
+ };
205
215
  var setMaintenanceModeGauge = (on) => {
206
216
  if (!metricsEnabled()) return;
207
217
  getMetrics().maintenanceMode.set(on ? 1 : 0);
@@ -257,5 +267,6 @@ exports.recordCaptchaVerify = recordCaptchaVerify;
257
267
  exports.recordDetectorTriggered = recordDetectorTriggered;
258
268
  exports.recordDomainValidation = recordDomainValidation;
259
269
  exports.recordFrictionlessDecision = recordFrictionlessDecision;
270
+ exports.recordHealthzGeoOutcome = recordHealthzGeoOutcome;
260
271
  exports.recordSpamEmail = recordSpamEmail;
261
272
  exports.setMaintenanceModeGauge = setMaintenanceModeGauge;