@prosopo/load-balancer 2.10.49 → 2.10.50

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @prosopo/load-balancer@2.10.49 build:cjs
2
+ > @prosopo/load-balancer@2.10.50 build:cjs
3
3
  > NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
4
4
 
5
5
  ViteCommonJSConfig: .
@@ -7,8 +7,8 @@ ViteCommonJSConfig: .
7
7
  tsConfigPaths: [
8
8
  '/home/runner/work/captcha/captcha/packages/common/tsconfig.json',
9
9
  '/home/runner/work/captcha/captcha/packages/locale/tsconfig.json',
10
- '/home/runner/work/captcha/captcha/packages/logger/tsconfig.json',
11
10
  '/home/runner/work/captcha/captcha/packages/util/tsconfig.json',
11
+ '/home/runner/work/captcha/captcha/packages/logger/tsconfig.json',
12
12
  '/home/runner/work/captcha/captcha/packages/types/tsconfig.json',
13
13
  '/home/runner/work/captcha/captcha/packages/util-crypto/tsconfig.json'
14
14
  ]
@@ -17,8 +17,8 @@ ViteCommonJSConfig: .
17
17
  externals: [
18
18
  '@prosopo/common',
19
19
  '@prosopo/locale',
20
- '@prosopo/logger',
21
20
  '@prosopo/util',
21
+ '@prosopo/logger',
22
22
  '@prosopo/types',
23
23
  '@prosopo/util-crypto'
24
24
  ]
@@ -33,7 +33,7 @@ computing gzip size...
33
33
  dist/cjs/retry.cjs 1.13 kB │ gzip: 0.56 kB
34
34
  dist/cjs/index.cjs 1.39 kB │ gzip: 0.39 kB
35
35
  dist/cjs/developmentProviderUrl.cjs 1.81 kB │ gzip: 0.88 kB
36
- dist/cjs/balancer.cjs 2.08 kB │ gzip: 0.97 kB
36
+ dist/cjs/balancer.cjs 2.56 kB │ gzip: 1.17 kB
37
37
  dist/cjs/providers.cjs 5.92 kB │ gzip: 2.04 kB
38
38
 
39
- ✓ built in 78ms
39
+ ✓ built in 51ms
@@ -1,32 +1,32 @@
1
1
 
2
- > @prosopo/load-balancer@2.10.49 build:tsc
2
+ > @prosopo/load-balancer@2.10.50 build:tsc
3
3
  > tsc --build --verbose
4
4
 
5
- 11:04:05 AM - Projects in this build:
5
+ 3:28:37 PM - Projects in this build:
6
6
  * ../../dev/config/tsconfig.json
7
- * ../locale/tsconfig.json
8
7
  * ../util/tsconfig.json
8
+ * ../locale/tsconfig.json
9
9
  * ../logger/tsconfig.json
10
10
  * ../util-crypto/tsconfig.json
11
11
  * ../types/tsconfig.json
12
12
  * ../common/tsconfig.json
13
13
  * tsconfig.json
14
14
 
15
- 11:04:05 AM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/vite/NodejsPolarsDirnamePlugin.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
15
+ 3:28:37 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
16
16
 
17
- 11:04:05 AM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/process.ts' is older than output '../locale/tsconfig.tsbuildinfo'
17
+ 3:28:37 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
18
18
 
19
- 11:04:05 AM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/ofLen.ts' is older than output '../util/tsconfig.tsbuildinfo'
19
+ 3:28:37 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
20
20
 
21
- 11:04:05 AM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
21
+ 3:28:37 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/logger.ts' is older than output '../logger/tsconfig.tsbuildinfo'
22
22
 
23
- 11:04:05 AM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
23
+ 3:28:37 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
24
24
 
25
- 11:04:05 AM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
25
+ 3:28:37 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/types.test-d.ts' is older than output '../types/tsconfig.tsbuildinfo'
26
26
 
27
- 11:04:05 AM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/utils/batches.ts' is older than output '../common/tsconfig.tsbuildinfo'
27
+ 3:28:37 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/index.ts' is older than output '../common/tsconfig.tsbuildinfo'
28
28
 
29
- 11:04:05 AM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
29
+ 3:28:37 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
30
30
 
31
- 11:04:05 AM - Building project '/home/runner/work/captcha/captcha/packages/load-balancer/tsconfig.json'...
31
+ 3:28:37 PM - Building project '/home/runner/work/captcha/captcha/packages/load-balancer/tsconfig.json'...
32
32
 
@@ -1,9 +1,9 @@
1
1
 
2
- > @prosopo/load-balancer@2.10.49 build
2
+ > @prosopo/load-balancer@2.10.50 build
3
3
  > npm run build:cross-env -- --mode ${NODE_ENV:-development}
4
4
 
5
5
 
6
- > @prosopo/load-balancer@2.10.49 build:cross-env
6
+ > @prosopo/load-balancer@2.10.50 build:cross-env
7
7
  > vite build --config vite.esm.config.ts --mode production
8
8
 
9
9
  ViteEsmConfig: .
@@ -11,23 +11,23 @@ ViteEsmConfig: .
11
11
  tsConfigPaths: [
12
12
  '/home/runner/work/captcha/captcha/packages/common/tsconfig.json',
13
13
  '/home/runner/work/captcha/captcha/packages/locale/tsconfig.json',
14
- '/home/runner/work/captcha/captcha/packages/logger/tsconfig.json',
15
14
  '/home/runner/work/captcha/captcha/packages/util/tsconfig.json',
15
+ '/home/runner/work/captcha/captcha/packages/logger/tsconfig.json',
16
16
  '/home/runner/work/captcha/captcha/packages/types/tsconfig.json',
17
17
  '/home/runner/work/captcha/captcha/packages/util-crypto/tsconfig.json'
18
18
  ]
19
19
  }
20
20
  {
21
+ The plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the resolve.tsconfigPaths option. You can remove the plugin and set resolve.tsconfigPaths: true in your Vite config instead.
21
22
  externals: [
22
23
  '@prosopo/common',
23
24
  '@prosopo/locale',
24
- '@prosopo/logger',
25
25
  '@prosopo/util',
26
+ '@prosopo/logger',
26
27
  '@prosopo/types',
27
28
  '@prosopo/util-crypto'
28
29
  ]
29
30
  }
30
- The plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the resolve.tsconfigPaths option. You can remove the plugin and set resolve.tsconfigPaths: true in your Vite config instead.
31
31
  vite v8.1.5 building ssr environment for production...
32
32
  Bundle build started
33
33
  
@@ -38,7 +38,7 @@ dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
38
38
  dist/index.js 0.86 kB │ gzip: 0.30 kB
39
39
  dist/retry.js 1.09 kB │ gzip: 0.55 kB
40
40
  dist/developmentProviderUrl.js 1.70 kB │ gzip: 0.87 kB
41
- dist/balancer.js 1.88 kB │ gzip: 0.94 kB
41
+ dist/balancer.js 2.38 kB │ gzip: 1.15 kB
42
42
  dist/providers.js 5.64 kB │ gzip: 2.01 kB
43
43
 
44
- ✓ built in 61ms
44
+ ✓ built in 108ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @prosopo/load-balancer
2
2
 
3
+ ## 2.10.50
4
+ ### Patch Changes
5
+
6
+ - a9141c3: Stop loading zod before the widget can draw itself. Takes another 13KB gzipped off the critical path.
7
+
8
+ zod is 14KB gzipped and it was being downloaded and parsed before the checkbox appeared, because six small things on the startup path happened to use it:
9
+
10
+ - two lists of strings in `@prosopo/logger` (log levels, output format)
11
+ - two lists of strings in `@prosopo/locale` (language codes, translation keys)
12
+ - two lists of two strings in `@prosopo/types` (start mode, challenge placement)
13
+ - one four-field object in `@prosopo/load-balancer` (a provider entry)
14
+ - an `instanceof ZodError` check in `@prosopo/common`
15
+ - `INPUT_LIMITS`, a plain table of numbers, that happened to live in the same file as zod-based string builders
16
+
17
+ None of these need a validation library. They are now plain TypeScript: a list, a type, and where input is untrusted, a one-line guard. `INPUT_LIMITS` moved to its own file so reading it no longer drags the builders along.
18
+
19
+ zod has not gone anywhere — the real request and response schemas in `@prosopo/types` still use it, and still validate exactly as before. It now arrives with the code that needs it, after the widget is on screen, rather than in front of it.
20
+
21
+ Two API changes for anyone importing these directly:
22
+
23
+ - `LanguageSchema`, `TranslationKeysSchema`, `StartModeSchema` and `Placement` are no longer exported as zod schemas. Use `isLanguage()`, `isStartMode()`, `isPlacement()` to check a value, and `LanguageCodes`, `translationKeys`, `StartModes`, `Placements` for the lists.
24
+ - `isZodError()` now recognises a zod error by its name rather than `instanceof`. That is strictly more tolerant: the name still matches when an error crosses a realm boundary or comes from a second copy of zod, which `instanceof` misses — it was already the fallback arm of the same check.
25
+
26
+ Two behaviour notes: a malformed entry in the fetched provider list now throws a plain `Error` naming the entry, where it used to throw an untranslated zod error; and the language codes accepted are unchanged.
27
+
28
+ Covered by the existing suites for every package touched (types, types-database, locale, logger, common, load-balancer, all five procaptcha packages, api, cli, api-express-router, server, and the provider's 1322 unit tests), all passing. The built bundle was also loaded in a real browser: the widget renders from the first eight chunks, zod arrives in the second wave, and the provider's error came back translated into German.
29
+ - Updated dependencies [a9141c3]
30
+ - Updated dependencies [a9141c3]
31
+ - @prosopo/common@3.1.59
32
+ - @prosopo/types@5.10.0
33
+
3
34
  ## 2.10.49
4
35
  ### Patch Changes
5
36
 
@@ -1,22 +1,10 @@
1
1
  import type { EnvironmentTypes } from "@prosopo/types";
2
- import { z } from "zod";
3
- declare const HardcodedProviderSchema: z.ZodObject<{
4
- address: z.ZodString;
5
- url: z.ZodString;
6
- datasetId: z.ZodString;
7
- weight: z.ZodEffects<z.ZodDefault<z.ZodOptional<z.ZodNumber>>, number, number | undefined>;
8
- }, "strip", z.ZodTypeAny, {
2
+ export interface HardcodedProvider {
9
3
  address: string;
10
4
  url: string;
11
5
  datasetId: string;
12
6
  weight: number;
13
- }, {
14
- address: string;
15
- url: string;
16
- datasetId: string;
17
- weight?: number | undefined;
18
- }>;
19
- export type HardcodedProvider = z.infer<typeof HardcodedProviderSchema>;
7
+ }
20
8
  export type IpMode = "ipv4" | "ipv6";
21
9
  type hostedProviders = Record<string, unknown>;
22
10
  export declare const convertHostedProvider: (provider: hostedProviders, ipMode?: IpMode) => HardcodedProvider[];
@@ -1 +1 @@
1
- {"version":3,"file":"balancer.d.ts","sourceRoot":"","sources":["../src/balancer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,QAAA,MAAM,uBAAuB;;;;;;;;;;;;;;;EAa3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAQrC,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAK/C,eAAO,MAAM,qBAAqB,aACvB,eAAe,WAChB,MAAM,KACb,iBAAiB,EAUnB,CAAC;AAKF,eAAO,MAAM,gBAAgB,aAAc,MAAM,KAAG,MACjB,CAAC;AAEpC,eAAO,MAAM,mBAAmB,aAAc,iBAAiB,KAAG,MACjB,CAAC;AAElD,eAAO,MAAM,kBAAkB,gBAAiB,gBAAgB,KAAG,MAUlE,CAAC;AAEF,eAAO,MAAM,YAAY,gBACX,gBAAgB,WACpB,MAAM,KACb,OAAO,CAAC,iBAAiB,EAAE,CAyB7B,CAAC"}
1
+ {"version":3,"file":"balancer.d.ts","sourceRoot":"","sources":["../src/balancer.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CACf;AAkCD,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAQrC,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAK/C,eAAO,MAAM,qBAAqB,aACvB,eAAe,WAChB,MAAM,KACb,iBAAiB,EAUnB,CAAC;AAKF,eAAO,MAAM,gBAAgB,aAAc,MAAM,KAAG,MACjB,CAAC;AAEpC,eAAO,MAAM,mBAAmB,aAAc,iBAAiB,KAAG,MACjB,CAAC;AAElD,eAAO,MAAM,kBAAkB,gBAAiB,gBAAgB,KAAG,MAUlE,CAAC;AAEF,eAAO,MAAM,YAAY,gBACX,gBAAgB,WACpB,MAAM,KACb,OAAO,CAAC,iBAAiB,EAAE,CAyB7B,CAAC"}
package/dist/balancer.js CHANGED
@@ -1,20 +1,27 @@
1
1
  import { getDevelopmentProviderUrl } from "./developmentProviderUrl.js";
2
2
  import { ProsopoEnvError } from "@prosopo/common";
3
- import { z } from "zod";
4
3
  //#region src/balancer.ts
5
- var HardcodedProviderSchema = z.object({
6
- address: z.string(),
7
- url: z.string(),
8
- datasetId: z.string(),
9
- weight: z.number().optional().default(1).transform((val) => {
10
- return Math.max(1, Math.min(100, Math.round(val)));
11
- })
12
- });
4
+ /**
5
+ * The provider list is fetched JSON, so entries are checked rather than
6
+ * trusted. Hand-written rather than a zod schema: this module is on the
7
+ * widget's critical path and zod costs 14KB gzipped to validate three strings
8
+ * and a number.
9
+ */
10
+ var parseHardcodedProvider = (value) => {
11
+ const entry = value;
12
+ if (!isProviderRecord(value) || typeof entry.address !== "string" || typeof entry.url !== "string" || typeof entry.datasetId !== "string" || entry.weight !== void 0 && typeof entry.weight !== "number") throw new Error(`Malformed provider entry in the provider list: ${JSON.stringify(value)}`);
13
+ return {
14
+ address: entry.address,
15
+ url: entry.url,
16
+ datasetId: entry.datasetId,
17
+ weight: Math.max(1, Math.min(100, Math.round(entry.weight ?? 1)))
18
+ };
19
+ };
13
20
  var IP_MODE_KEYS = ["ipv4", "ipv6"];
14
21
  var isProviderRecord = (value) => typeof value === "object" && value !== null;
15
22
  var convertHostedProvider = (provider, ipMode) => {
16
23
  const source = ipMode && isProviderRecord(provider[ipMode]) ? provider[ipMode] : provider;
17
- return Object.entries(source).filter(([key]) => !IP_MODE_KEYS.includes(key)).map(([, value]) => HardcodedProviderSchema.parse(value)).sort((a, b) => a.url.localeCompare(b.url));
24
+ return Object.entries(source).filter(([key]) => !IP_MODE_KEYS.includes(key)).map(([, value]) => parseHardcodedProvider(value)).sort((a, b) => a.url.localeCompare(b.url));
18
25
  };
19
26
  var stripIpModeLabel = (hostname) => hostname.replace(/^ipv[46]\./, "");
20
27
  var getProviderHostname = (provider) => stripIpModeLabel(new URL(provider.url).hostname);
@@ -1 +1 @@
1
- {"version":3,"file":"balancer.js","sourceRoot":"","sources":["../src/balancer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"balancer.js","sourceRoot":"","sources":["../src/balancer.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,27 @@
1
1
  const require_developmentProviderUrl = require("./developmentProviderUrl.cjs");
2
2
  let _prosopo_common = require("@prosopo/common");
3
- let zod = require("zod");
4
3
  //#region src/balancer.ts
5
- var HardcodedProviderSchema = zod.z.object({
6
- address: zod.z.string(),
7
- url: zod.z.string(),
8
- datasetId: zod.z.string(),
9
- weight: zod.z.number().optional().default(1).transform((val) => {
10
- return Math.max(1, Math.min(100, Math.round(val)));
11
- })
12
- });
4
+ /**
5
+ * The provider list is fetched JSON, so entries are checked rather than
6
+ * trusted. Hand-written rather than a zod schema: this module is on the
7
+ * widget's critical path and zod costs 14KB gzipped to validate three strings
8
+ * and a number.
9
+ */
10
+ var parseHardcodedProvider = (value) => {
11
+ const entry = value;
12
+ if (!isProviderRecord(value) || typeof entry.address !== "string" || typeof entry.url !== "string" || typeof entry.datasetId !== "string" || entry.weight !== void 0 && typeof entry.weight !== "number") throw new Error(`Malformed provider entry in the provider list: ${JSON.stringify(value)}`);
13
+ return {
14
+ address: entry.address,
15
+ url: entry.url,
16
+ datasetId: entry.datasetId,
17
+ weight: Math.max(1, Math.min(100, Math.round(entry.weight ?? 1)))
18
+ };
19
+ };
13
20
  var IP_MODE_KEYS = ["ipv4", "ipv6"];
14
21
  var isProviderRecord = (value) => typeof value === "object" && value !== null;
15
22
  var convertHostedProvider = (provider, ipMode) => {
16
23
  const source = ipMode && isProviderRecord(provider[ipMode]) ? provider[ipMode] : provider;
17
- return Object.entries(source).filter(([key]) => !IP_MODE_KEYS.includes(key)).map(([, value]) => HardcodedProviderSchema.parse(value)).sort((a, b) => a.url.localeCompare(b.url));
24
+ return Object.entries(source).filter(([key]) => !IP_MODE_KEYS.includes(key)).map(([, value]) => parseHardcodedProvider(value)).sort((a, b) => a.url.localeCompare(b.url));
18
25
  };
19
26
  var stripIpModeLabel = (hostname) => hostname.replace(/^ipv[46]\./, "");
20
27
  var getProviderHostname = (provider) => stripIpModeLabel(new URL(provider.url).hostname);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/load-balancer",
3
- "version": "2.10.49",
3
+ "version": "2.10.50",
4
4
  "description": "Provider load balancer",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,9 +37,8 @@
37
37
  },
38
38
  "homepage": "https://github.com/prosopo/captcha#readme",
39
39
  "dependencies": {
40
- "@prosopo/common": "3.1.58",
41
- "@prosopo/types": "5.9.2",
42
- "zod": "3.23.8"
40
+ "@prosopo/common": "3.1.59",
41
+ "@prosopo/types": "5.10.0"
43
42
  },
44
43
  "devDependencies": {
45
44
  "@prosopo/config": "3.4.0",
package/src/balancer.ts CHANGED
@@ -13,25 +13,46 @@
13
13
  // limitations under the License.
14
14
  import { ProsopoEnvError } from "@prosopo/common";
15
15
  import type { EnvironmentTypes } from "@prosopo/types";
16
- import { z } from "zod";
17
16
  import { getDevelopmentProviderUrl } from "./developmentProviderUrl.js";
18
17
 
19
- const HardcodedProviderSchema = z.object({
20
- address: z.string(),
21
- url: z.string(),
22
- datasetId: z.string(),
23
- weight: z
24
- .number()
25
- .optional()
26
- .default(1)
27
- .transform((val) => {
28
- // weight coerced to int 1-100
29
- const weight = Math.round(val);
30
- return Math.max(1, Math.min(100, weight));
31
- }),
32
- });
18
+ export interface HardcodedProvider {
19
+ address: string;
20
+ url: string;
21
+ datasetId: string;
22
+ weight: number;
23
+ }
33
24
 
34
- export type HardcodedProvider = z.infer<typeof HardcodedProviderSchema>;
25
+ /**
26
+ * The provider list is fetched JSON, so entries are checked rather than
27
+ * trusted. Hand-written rather than a zod schema: this module is on the
28
+ * widget's critical path and zod costs 14KB gzipped to validate three strings
29
+ * and a number.
30
+ */
31
+ const parseHardcodedProvider = (value: unknown): HardcodedProvider => {
32
+ const entry = value as Record<string, unknown>;
33
+ if (
34
+ !isProviderRecord(value) ||
35
+ typeof entry.address !== "string" ||
36
+ typeof entry.url !== "string" ||
37
+ typeof entry.datasetId !== "string" ||
38
+ (entry.weight !== undefined && typeof entry.weight !== "number")
39
+ ) {
40
+ // A plain Error, as before: zod threw an untranslated ZodError here,
41
+ // and a malformed provider list is a deployment fault rather than
42
+ // something to show a visitor.
43
+ throw new Error(
44
+ `Malformed provider entry in the provider list: ${JSON.stringify(value)}`,
45
+ );
46
+ }
47
+
48
+ return {
49
+ address: entry.address,
50
+ url: entry.url,
51
+ datasetId: entry.datasetId,
52
+ // weight coerced to int 1-100
53
+ weight: Math.max(1, Math.min(100, Math.round(entry.weight ?? 1))),
54
+ };
55
+ };
35
56
 
36
57
  export type IpMode = "ipv4" | "ipv6";
37
58
 
@@ -57,7 +78,7 @@ export const convertHostedProvider = (
57
78
 
58
79
  const providers = Object.entries(source)
59
80
  .filter(([key]) => !IP_MODE_KEYS.includes(key as IpMode))
60
- .map(([, value]) => HardcodedProviderSchema.parse(value));
81
+ .map(([, value]) => parseHardcodedProvider(value));
61
82
  return providers.sort((a, b) => a.url.localeCompare(b.url));
62
83
  };
63
84