@prosopo/load-balancer 2.10.50 → 2.11.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 (38) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +7 -6
  2. package/.turbo/turbo-build$colon$tsc.log +11 -11
  3. package/.turbo/turbo-build.log +9 -8
  4. package/CHANGELOG.md +51 -0
  5. package/README.md +34 -0
  6. package/dist/balancer.d.ts +1 -0
  7. package/dist/balancer.d.ts.map +1 -1
  8. package/dist/balancer.js +44 -1
  9. package/dist/balancer.js.map +1 -1
  10. package/dist/cjs/balancer.cjs +44 -0
  11. package/dist/cjs/index.cjs +3 -0
  12. package/dist/cjs/providerUrlOverride.cjs +33 -0
  13. package/dist/cjs/providers.cjs +5 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/providerUrlOverride.d.ts +2 -0
  19. package/dist/providerUrlOverride.d.ts.map +1 -0
  20. package/dist/providerUrlOverride.js +33 -0
  21. package/dist/providerUrlOverride.js.map +1 -0
  22. package/dist/providers.d.ts.map +1 -1
  23. package/dist/providers.js +6 -1
  24. package/dist/providers.js.map +1 -1
  25. package/dist/tests/providerUrlOverride.unit.test.d.ts +2 -0
  26. package/dist/tests/providerUrlOverride.unit.test.d.ts.map +1 -0
  27. package/dist/tests/providerUrlOverride.unit.test.js +144 -0
  28. package/dist/tests/providerUrlOverride.unit.test.js.map +1 -0
  29. package/dist/tests/providers.unit.test.js +2 -0
  30. package/dist/tests/providers.unit.test.js.map +1 -1
  31. package/package.json +3 -3
  32. package/src/balancer.ts +73 -0
  33. package/src/index.ts +1 -0
  34. package/src/providerUrlOverride.ts +44 -0
  35. package/src/providers.ts +13 -0
  36. package/src/tests/providerUrlOverride.unit.test.ts +182 -0
  37. package/src/tests/providers.unit.test.ts +6 -0
  38. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,144 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { getProviderListOverride, loadBalancer } from "../balancer.js";
3
+ import { readProviderListOverride } from "../providerUrlOverride.js";
4
+ const ENV_KEY = "PROSOPO_PROVIDER_LIST";
5
+ const original = process.env[ENV_KEY];
6
+ const originalFetch = globalThis.fetch;
7
+ afterEach(() => {
8
+ if (original === undefined)
9
+ delete process.env[ENV_KEY];
10
+ else
11
+ process.env[ENV_KEY] = original;
12
+ globalThis.fetch = originalFetch;
13
+ });
14
+ const PROVIDER_LIST_JSON = JSON.stringify({
15
+ one: {
16
+ address: "5Provider1",
17
+ url: "https://one.example.com/",
18
+ datasetId: "0xabc",
19
+ weight: 3,
20
+ },
21
+ two: {
22
+ address: "5Provider2",
23
+ url: "https://two.example.com",
24
+ datasetId: "0xdef",
25
+ },
26
+ });
27
+ describe("reading the override", () => {
28
+ it("returns undefined when unset", () => {
29
+ delete process.env[ENV_KEY];
30
+ expect(readProviderListOverride()).toBeUndefined();
31
+ });
32
+ it("returns the raw value when set", () => {
33
+ process.env[ENV_KEY] = "https://captcha.example.com";
34
+ expect(readProviderListOverride()).toBe("https://captcha.example.com");
35
+ });
36
+ });
37
+ describe("parsing the override", () => {
38
+ it("is empty when unset or blank, so normal discovery is untouched", () => {
39
+ expect(getProviderListOverride(undefined)).toEqual([]);
40
+ expect(getProviderListOverride("")).toEqual([]);
41
+ expect(getProviderListOverride(" ")).toEqual([]);
42
+ });
43
+ it("accepts a single bare url", () => {
44
+ expect(getProviderListOverride("https://captcha.example.com")).toEqual([
45
+ {
46
+ address: "self-hosted",
47
+ url: "https://captcha.example.com",
48
+ datasetId: "",
49
+ weight: 1,
50
+ },
51
+ ]);
52
+ });
53
+ it("accepts several comma-separated urls", () => {
54
+ const providers = getProviderListOverride("https://one.example.com, https://two.example.com");
55
+ expect(providers.map((p) => p.url)).toEqual([
56
+ "https://one.example.com",
57
+ "https://two.example.com",
58
+ ]);
59
+ });
60
+ it("strips trailing slashes from both forms", () => {
61
+ expect(getProviderListOverride("https://captcha.example.com/")[0]?.url).toBe("https://captcha.example.com");
62
+ const fromJson = getProviderListOverride(PROVIDER_LIST_JSON);
63
+ expect(fromJson.map((p) => p.url)).toEqual([
64
+ "https://one.example.com",
65
+ "https://two.example.com",
66
+ ]);
67
+ });
68
+ it("accepts the hosted provider-list JSON, preserving address and weight", () => {
69
+ const providers = getProviderListOverride(PROVIDER_LIST_JSON);
70
+ expect(providers).toEqual([
71
+ {
72
+ address: "5Provider1",
73
+ url: "https://one.example.com",
74
+ datasetId: "0xabc",
75
+ weight: 3,
76
+ },
77
+ {
78
+ address: "5Provider2",
79
+ url: "https://two.example.com",
80
+ datasetId: "0xdef",
81
+ weight: 1,
82
+ },
83
+ ]);
84
+ });
85
+ it("reads the ipv4 / ipv6 sub-lists when the JSON carries them", () => {
86
+ const raw = JSON.stringify({
87
+ dual: {
88
+ address: "5Dual",
89
+ url: "https://dual.example.com",
90
+ datasetId: "0x1",
91
+ },
92
+ ipv4: {
93
+ four: {
94
+ address: "5Four",
95
+ url: "https://v4.example.com",
96
+ datasetId: "0x2",
97
+ },
98
+ },
99
+ });
100
+ expect(getProviderListOverride(raw, "ipv4").map((p) => p.url)).toEqual([
101
+ "https://v4.example.com",
102
+ ]);
103
+ expect(getProviderListOverride(raw).map((p) => p.url)).toEqual([
104
+ "https://dual.example.com",
105
+ ]);
106
+ });
107
+ it("falls back to normal discovery rather than throwing on malformed JSON", () => {
108
+ expect(getProviderListOverride("{not json")).toEqual([]);
109
+ expect(getProviderListOverride('{"one":{"url":"missing-other-fields"}}')).toEqual([]);
110
+ });
111
+ });
112
+ describe("loadBalancer with an override", () => {
113
+ it("returns the override without fetching the hosted list", async () => {
114
+ process.env[ENV_KEY] = "https://captcha.example.com/";
115
+ const fetchSpy = vi.fn();
116
+ globalThis.fetch = fetchSpy;
117
+ await expect(loadBalancer("production")).resolves.toEqual([
118
+ {
119
+ address: "self-hosted",
120
+ url: "https://captcha.example.com",
121
+ datasetId: "",
122
+ weight: 1,
123
+ },
124
+ ]);
125
+ expect(fetchSpy).not.toHaveBeenCalled();
126
+ });
127
+ it("applies in every environment, not just development", async () => {
128
+ process.env[ENV_KEY] = "https://captcha.example.com";
129
+ for (const env of ["development", "staging", "production"]) {
130
+ const providers = await loadBalancer(env);
131
+ expect(providers.map((p) => p.url)).toEqual([
132
+ "https://captcha.example.com",
133
+ ]);
134
+ }
135
+ });
136
+ it("does not prefix ipv4/ipv6 labels onto a bare-url override", async () => {
137
+ process.env[ENV_KEY] = "https://captcha.example.com";
138
+ const providers = await loadBalancer("production", "ipv4");
139
+ expect(providers.map((p) => p.url)).toEqual([
140
+ "https://captcha.example.com",
141
+ ]);
142
+ });
143
+ });
144
+ //# sourceMappingURL=providerUrlOverride.unit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providerUrlOverride.unit.test.js","sourceRoot":"","sources":["../../src/tests/providerUrlOverride.unit.test.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAErE,MAAM,OAAO,GAAG,uBAAuB,CAAC;AACxC,MAAM,QAAQ,GAAuB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC1D,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;AAEvC,SAAS,CAAC,GAAG,EAAE;IACd,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;;QACnD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC;IACrC,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;AAClC,CAAC,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC;IACzC,GAAG,EAAE;QACJ,OAAO,EAAE,YAAY;QACrB,GAAG,EAAE,0BAA0B;QAC/B,SAAS,EAAE,OAAO;QAClB,MAAM,EAAE,CAAC;KACT;IACD,GAAG,EAAE;QACJ,OAAO,EAAE,YAAY;QACrB,GAAG,EAAE,yBAAyB;QAC9B,SAAS,EAAE,OAAO;KAClB;CACD,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACvC,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5B,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,6BAA6B,CAAC;QACrD,MAAM,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAChD,MAAM,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,uBAAuB,CAAC,6BAA6B,CAAC,CAAC,CAAC,OAAO,CAAC;YACtE;gBACC,OAAO,EAAE,aAAa;gBACtB,GAAG,EAAE,6BAA6B;gBAClC,SAAS,EAAE,EAAE;gBACb,MAAM,EAAE,CAAC;aACT;SACD,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,MAAM,SAAS,GAAG,uBAAuB,CACxC,kDAAkD,CAClD,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3C,yBAAyB;YACzB,yBAAyB;SACzB,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QAGlD,MAAM,CACL,uBAAuB,CAAC,8BAA8B,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAC/D,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,kBAAkB,CAAC,CAAC;QAC7D,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1C,yBAAyB;YACzB,yBAAyB;SACzB,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC/E,MAAM,SAAS,GAAG,uBAAuB,CAAC,kBAAkB,CAAC,CAAC;QAC9D,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;YACzB;gBACC,OAAO,EAAE,YAAY;gBACrB,GAAG,EAAE,yBAAyB;gBAC9B,SAAS,EAAE,OAAO;gBAClB,MAAM,EAAE,CAAC;aACT;YACD;gBACC,OAAO,EAAE,YAAY;gBACrB,GAAG,EAAE,yBAAyB;gBAC9B,SAAS,EAAE,OAAO;gBAClB,MAAM,EAAE,CAAC;aACT;SACD,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE;gBACL,OAAO,EAAE,OAAO;gBAChB,GAAG,EAAE,0BAA0B;gBAC/B,SAAS,EAAE,KAAK;aAChB;YACD,IAAI,EAAE;gBACL,IAAI,EAAE;oBACL,OAAO,EAAE,OAAO;oBAChB,GAAG,EAAE,wBAAwB;oBAC7B,SAAS,EAAE,KAAK;iBAChB;aACD;SACD,CAAC,CAAC;QACH,MAAM,CAAC,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YACtE,wBAAwB;SACxB,CAAC,CAAC;QACH,MAAM,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,0BAA0B;SAC1B,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAEhF,MAAM,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzD,MAAM,CACL,uBAAuB,CAAC,wCAAwC,CAAC,CACjE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACtE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,8BAA8B,CAAC;QACtD,MAAM,QAAQ,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAEzB,UAAU,CAAC,KAAK,GAAG,QAAe,CAAC;QAEnC,MAAM,MAAM,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;YACzD;gBACC,OAAO,EAAE,aAAa;gBACtB,GAAG,EAAE,6BAA6B;gBAClC,SAAS,EAAE,EAAE;gBACb,MAAM,EAAE,CAAC;aACT;SACD,CAAC,CAAC;QACH,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QACnE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,6BAA6B,CAAC;QACrD,KAAK,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE,YAAY,CAAU,EAAE,CAAC;YACrE,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC3C,6BAA6B;aAC7B,CAAC,CAAC;QACJ,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,KAAK,IAAI,EAAE;QAE1E,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,6BAA6B,CAAC;QACrD,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC3D,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3C,6BAA6B;SAC7B,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -1,8 +1,10 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { _resetHealthzRetryPolicy, _resetPinCache, _resetProviderListCache, _setHealthzRetryPolicy, getProviders, getRandomActiveProvider, getRandomProviderFromList, } from "../providers.js";
3
3
  const loadBalancer = vi.fn();
4
+ const getProviderListOverride = vi.fn(() => []);
4
5
  vi.mock("../balancer.js", () => ({
5
6
  loadBalancer: (...args) => loadBalancer(...args),
7
+ getProviderListOverride: (...args) => getProviderListOverride(...args),
6
8
  }));
7
9
  const originalFetch = globalThis.fetch;
8
10
  const mockHealthzFetch = (host, ok = true, status = 200) => {
@@ -1 +1 @@
1
- {"version":3,"file":"providers.unit.test.js","sourceRoot":"","sources":["../../src/tests/providers.unit.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"providers.unit.test.js","sourceRoot":"","sources":["../../src/tests/providers.unit.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/load-balancer",
3
- "version": "2.10.50",
3
+ "version": "2.11.0",
4
4
  "description": "Provider load balancer",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,10 +38,10 @@
38
38
  "homepage": "https://github.com/prosopo/captcha#readme",
39
39
  "dependencies": {
40
40
  "@prosopo/common": "3.1.59",
41
- "@prosopo/types": "5.10.0"
41
+ "@prosopo/types": "5.10.1"
42
42
  },
43
43
  "devDependencies": {
44
- "@prosopo/config": "3.4.0",
44
+ "@prosopo/config": "3.4.1",
45
45
  "@types/node": "22.10.2",
46
46
  "@vitest/coverage-v8": "4.1.11",
47
47
  "concurrently": "9.0.1",
package/src/balancer.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  import { ProsopoEnvError } from "@prosopo/common";
15
15
  import type { EnvironmentTypes } from "@prosopo/types";
16
16
  import { getDevelopmentProviderUrl } from "./developmentProviderUrl.js";
17
+ import { readProviderListOverride } from "./providerUrlOverride.js";
17
18
 
18
19
  export interface HardcodedProvider {
19
20
  address: string;
@@ -91,6 +92,68 @@ export const stripIpModeLabel = (hostname: string): string =>
91
92
  export const getProviderHostname = (provider: HardcodedProvider): string =>
92
93
  stripIpModeLabel(new URL(provider.url).hostname);
93
94
 
95
+ // Placeholders for the fields a bare-URL override cannot supply. `address`
96
+ // surfaces as `RandomProvider.providerAccount`, which the DNS-routed
97
+ // production path already fills with a constant rather than a real account;
98
+ // `datasetId` is vestigial on this path because clients stopped sending one
99
+ // and the provider falls back to its own most-recently-loaded dataset.
100
+ const SELF_HOSTED_ADDRESS = "self-hosted";
101
+ const SELF_HOSTED_DATASET_ID = "";
102
+
103
+ const stripTrailingSlash = (url: string): string => url.replace(/\/$/, "");
104
+
105
+ const providersFromUrlList = (raw: string): HardcodedProvider[] =>
106
+ raw
107
+ .split(",")
108
+ .map((url) => stripTrailingSlash(url.trim()))
109
+ .filter((url) => url.length > 0)
110
+ .map((url) => ({
111
+ address: SELF_HOSTED_ADDRESS,
112
+ url,
113
+ datasetId: SELF_HOSTED_DATASET_ID,
114
+ weight: 1,
115
+ }));
116
+
117
+ /**
118
+ * Parses `PROSOPO_PROVIDER_LIST` into providers, or returns empty when unset.
119
+ *
120
+ * Two accepted forms:
121
+ *
122
+ * - The same JSON the hosted provider list serves, so weights and the
123
+ * `ipv4` / `ipv6` sub-lists behave identically. See the README.
124
+ * - One or more bare URLs, comma-separated, for a deployment that has
125
+ * nothing to say about weights or addresses.
126
+ *
127
+ * Trailing slashes are stripped throughout: a token embeds the provider URL
128
+ * it was minted against and `@prosopo/server` finds the issuer by exact
129
+ * string match, so `https://host/` and `https://host` must not disagree.
130
+ *
131
+ * A malformed override returns empty rather than throwing, falling back to
132
+ * normal discovery. Throwing would take every captcha on the page down over
133
+ * what is a deployment-time typo.
134
+ */
135
+ export const getProviderListOverride = (
136
+ raw: string | undefined = readProviderListOverride(),
137
+ ipMode?: IpMode,
138
+ ): HardcodedProvider[] => {
139
+ const trimmed = raw?.trim();
140
+ if (!trimmed) return [];
141
+
142
+ // Anything not starting an object is the bare-URL shorthand.
143
+ if (!trimmed.startsWith("{")) return providersFromUrlList(trimmed);
144
+
145
+ try {
146
+ return convertHostedProvider(JSON.parse(trimmed), ipMode).map(
147
+ (provider) => ({
148
+ ...provider,
149
+ url: stripTrailingSlash(provider.url),
150
+ }),
151
+ );
152
+ } catch {
153
+ return [];
154
+ }
155
+ };
156
+
94
157
  export const getLoadBalancerUrl = (environment: EnvironmentTypes): string => {
95
158
  if (environment === "production") {
96
159
  return "https://provider-list.prosopo.io/";
@@ -107,6 +170,16 @@ export const loadBalancer = async (
107
170
  environment: EnvironmentTypes,
108
171
  ipMode?: IpMode,
109
172
  ): Promise<HardcodedProvider[]> => {
173
+ // An override supplies the whole list. Checked before the environment
174
+ // branches so a self-hosted deployment answers for `production` too, and
175
+ // ahead of the fetch so no request reaches Prosopo's hosted list at all.
176
+ // `ipMode` is honoured only for the JSON form, which can carry its own
177
+ // `ipv4` / `ipv6` sub-lists; the bare-URL form ignores it, because those
178
+ // labels are a property of our fleet's DNS and prefixing `ipv4.` onto
179
+ // someone else's hostname would resolve to nothing.
180
+ const override = getProviderListOverride(undefined, ipMode);
181
+ if (override.length > 0) return override;
182
+
110
183
  if (environment === "development") {
111
184
  return [
112
185
  {
package/src/index.ts CHANGED
@@ -14,3 +14,4 @@
14
14
  export * from "./providers.js";
15
15
  export * from "./balancer.js";
16
16
  export * from "./developmentProviderUrl.js";
17
+ export * from "./providerUrlOverride.js";
@@ -0,0 +1,44 @@
1
+ // Copyright 2021-2026 Prosopo (UK) Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ /**
16
+ * Supplies the provider list directly instead of fetching Prosopo's.
17
+ *
18
+ * A self-hosted deployment has its own providers and no hosted list to
19
+ * discover them from. Setting this replaces both halves of discovery — the
20
+ * endpoint the widget calls and the list a verifier matches a token against —
21
+ * with whatever it names. See `getProviderListOverride` in `balancer.ts` for
22
+ * the accepted forms.
23
+ *
24
+ * Distinct from `PROSOPO_PROVIDER_URL_DEVELOPMENT`, which only applies when
25
+ * the environment is `development`. That coupling forced self-hosters to ship
26
+ * a development build of the widget purely to redirect it; this override is
27
+ * environment-independent, so `production` stays correct everywhere.
28
+ *
29
+ * Kept in its own module, holding nothing but the read, so that parsing can
30
+ * live next to `convertHostedProvider` in `balancer.ts` without the two
31
+ * modules importing each other. A cycle here would be bundled into the widget
32
+ * and this package has already lost a release to one.
33
+ *
34
+ * Written as a static `process.env.X` access for the same reason as the
35
+ * development override: frontend bundlers substitute that exact expression
36
+ * for a literal, which a computed lookup would not match.
37
+ */
38
+ export const readProviderListOverride = (): string | undefined => {
39
+ try {
40
+ return process.env.PROSOPO_PROVIDER_LIST;
41
+ } catch {
42
+ return undefined;
43
+ }
44
+ };
package/src/providers.ts CHANGED
@@ -16,6 +16,7 @@ import type { EnvironmentTypes, RandomProvider } from "@prosopo/types";
16
16
  import {
17
17
  type HardcodedProvider,
18
18
  type IpMode,
19
+ getProviderListOverride,
19
20
  loadBalancer,
20
21
  } from "./balancer.js";
21
22
  import { getDevelopmentProviderUrl } from "./developmentProviderUrl.js";
@@ -105,6 +106,18 @@ const resolvePinnedUrl = async (
105
106
  env: EnvironmentTypes,
106
107
  ipMode?: IpMode,
107
108
  ): Promise<string> => {
109
+ // An overridden list needs no discovery: healthz exists to report which
110
+ // pronode the DNS layer picked, and an override already names the nodes.
111
+ // Returning early also keeps the widget off Prosopo's hostnames entirely.
112
+ // The pick is weighted and per-call rather than cached, so traffic spreads
113
+ // across a multi-provider override instead of every page in a browser
114
+ // session pinning to whichever node was drawn first.
115
+ const override = getProviderListOverride(undefined, ipMode);
116
+ if (override.length > 0) {
117
+ const chosen = pickWeightedProvider(override, Math.random);
118
+ if (chosen) return chosen.url;
119
+ }
120
+
108
121
  // The base for /healthz already carries the ipv4./ipv6. label when one is
109
122
  // requested, so DNS keeps the discovery request on the same single-stack
110
123
  // path as the captcha calls that follow.
@@ -0,0 +1,182 @@
1
+ // Copyright 2021-2026 Prosopo (UK) Ltd.
2
+ //
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+
15
+ import { afterEach, describe, expect, it, vi } from "vitest";
16
+ import { getProviderListOverride, loadBalancer } from "../balancer.js";
17
+ import { readProviderListOverride } from "../providerUrlOverride.js";
18
+
19
+ const ENV_KEY = "PROSOPO_PROVIDER_LIST";
20
+ const original: string | undefined = process.env[ENV_KEY];
21
+ const originalFetch = globalThis.fetch;
22
+
23
+ afterEach(() => {
24
+ if (original === undefined) delete process.env[ENV_KEY];
25
+ else process.env[ENV_KEY] = original;
26
+ globalThis.fetch = originalFetch;
27
+ });
28
+
29
+ const PROVIDER_LIST_JSON = JSON.stringify({
30
+ one: {
31
+ address: "5Provider1",
32
+ url: "https://one.example.com/",
33
+ datasetId: "0xabc",
34
+ weight: 3,
35
+ },
36
+ two: {
37
+ address: "5Provider2",
38
+ url: "https://two.example.com",
39
+ datasetId: "0xdef",
40
+ },
41
+ });
42
+
43
+ describe("reading the override", () => {
44
+ it("returns undefined when unset", () => {
45
+ delete process.env[ENV_KEY];
46
+ expect(readProviderListOverride()).toBeUndefined();
47
+ });
48
+
49
+ it("returns the raw value when set", () => {
50
+ process.env[ENV_KEY] = "https://captcha.example.com";
51
+ expect(readProviderListOverride()).toBe("https://captcha.example.com");
52
+ });
53
+ });
54
+
55
+ describe("parsing the override", () => {
56
+ it("is empty when unset or blank, so normal discovery is untouched", () => {
57
+ expect(getProviderListOverride(undefined)).toEqual([]);
58
+ expect(getProviderListOverride("")).toEqual([]);
59
+ expect(getProviderListOverride(" ")).toEqual([]);
60
+ });
61
+
62
+ it("accepts a single bare url", () => {
63
+ expect(getProviderListOverride("https://captcha.example.com")).toEqual([
64
+ {
65
+ address: "self-hosted",
66
+ url: "https://captcha.example.com",
67
+ datasetId: "",
68
+ weight: 1,
69
+ },
70
+ ]);
71
+ });
72
+
73
+ it("accepts several comma-separated urls", () => {
74
+ const providers = getProviderListOverride(
75
+ "https://one.example.com, https://two.example.com",
76
+ );
77
+ expect(providers.map((p) => p.url)).toEqual([
78
+ "https://one.example.com",
79
+ "https://two.example.com",
80
+ ]);
81
+ });
82
+
83
+ it("strips trailing slashes from both forms", () => {
84
+ // A token embeds the provider url it was minted against and the verifier
85
+ // matches it by exact string, so the two spellings must normalise.
86
+ expect(
87
+ getProviderListOverride("https://captcha.example.com/")[0]?.url,
88
+ ).toBe("https://captcha.example.com");
89
+ const fromJson = getProviderListOverride(PROVIDER_LIST_JSON);
90
+ expect(fromJson.map((p) => p.url)).toEqual([
91
+ "https://one.example.com",
92
+ "https://two.example.com",
93
+ ]);
94
+ });
95
+
96
+ it("accepts the hosted provider-list JSON, preserving address and weight", () => {
97
+ const providers = getProviderListOverride(PROVIDER_LIST_JSON);
98
+ expect(providers).toEqual([
99
+ {
100
+ address: "5Provider1",
101
+ url: "https://one.example.com",
102
+ datasetId: "0xabc",
103
+ weight: 3,
104
+ },
105
+ {
106
+ address: "5Provider2",
107
+ url: "https://two.example.com",
108
+ datasetId: "0xdef",
109
+ weight: 1,
110
+ },
111
+ ]);
112
+ });
113
+
114
+ it("reads the ipv4 / ipv6 sub-lists when the JSON carries them", () => {
115
+ const raw = JSON.stringify({
116
+ dual: {
117
+ address: "5Dual",
118
+ url: "https://dual.example.com",
119
+ datasetId: "0x1",
120
+ },
121
+ ipv4: {
122
+ four: {
123
+ address: "5Four",
124
+ url: "https://v4.example.com",
125
+ datasetId: "0x2",
126
+ },
127
+ },
128
+ });
129
+ expect(getProviderListOverride(raw, "ipv4").map((p) => p.url)).toEqual([
130
+ "https://v4.example.com",
131
+ ]);
132
+ expect(getProviderListOverride(raw).map((p) => p.url)).toEqual([
133
+ "https://dual.example.com",
134
+ ]);
135
+ });
136
+
137
+ it("falls back to normal discovery rather than throwing on malformed JSON", () => {
138
+ // A deployment-time typo must not take down every captcha on the page.
139
+ expect(getProviderListOverride("{not json")).toEqual([]);
140
+ expect(
141
+ getProviderListOverride('{"one":{"url":"missing-other-fields"}}'),
142
+ ).toEqual([]);
143
+ });
144
+ });
145
+
146
+ describe("loadBalancer with an override", () => {
147
+ it("returns the override without fetching the hosted list", async () => {
148
+ process.env[ENV_KEY] = "https://captcha.example.com/";
149
+ const fetchSpy = vi.fn();
150
+ // biome-ignore lint/suspicious/noExplicitAny: asserting the fetch never happens
151
+ globalThis.fetch = fetchSpy as any;
152
+
153
+ await expect(loadBalancer("production")).resolves.toEqual([
154
+ {
155
+ address: "self-hosted",
156
+ url: "https://captcha.example.com",
157
+ datasetId: "",
158
+ weight: 1,
159
+ },
160
+ ]);
161
+ expect(fetchSpy).not.toHaveBeenCalled();
162
+ });
163
+
164
+ it("applies in every environment, not just development", async () => {
165
+ process.env[ENV_KEY] = "https://captcha.example.com";
166
+ for (const env of ["development", "staging", "production"] as const) {
167
+ const providers = await loadBalancer(env);
168
+ expect(providers.map((p) => p.url)).toEqual([
169
+ "https://captcha.example.com",
170
+ ]);
171
+ }
172
+ });
173
+
174
+ it("does not prefix ipv4/ipv6 labels onto a bare-url override", async () => {
175
+ // Those labels only resolve inside our own fleet's DNS.
176
+ process.env[ENV_KEY] = "https://captcha.example.com";
177
+ const providers = await loadBalancer("production", "ipv4");
178
+ expect(providers.map((p) => p.url)).toEqual([
179
+ "https://captcha.example.com",
180
+ ]);
181
+ });
182
+ });
@@ -28,8 +28,14 @@ import {
28
28
  // can be exercised without real network calls. getRandomActiveProvider tests
29
29
  // don't use loadBalancer, so this mock leaves them unaffected.
30
30
  const loadBalancer = vi.fn();
31
+ // Defaults to "no override" so these cases exercise the normal healthz
32
+ // discovery path; the override's own behaviour is covered in
33
+ // providerUrlOverride.unit.test.ts.
34
+ const getProviderListOverride = vi.fn<() => HardcodedProvider[]>(() => []);
31
35
  vi.mock("../balancer.js", () => ({
32
36
  loadBalancer: (...args: unknown[]) => loadBalancer(...args),
37
+ getProviderListOverride: (...args: unknown[]) =>
38
+ getProviderListOverride(...(args as [])),
33
39
  }));
34
40
 
35
41
  const originalFetch = globalThis.fetch;