@khanglvm/llm-router 2.3.5 → 2.3.7

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.
@@ -12,7 +12,6 @@ import {
12
12
  areLocalServerSettingsEqual,
13
13
  formatStartupDetail,
14
14
  formatStartupLabel,
15
- getFixedLocalRouterOrigin,
16
15
  readLocalServerSettings
17
16
  } from "./local-server-settings.js";
18
17
  import { appendActivityLogEntry, clearActivityLogFile, createActivityLogEntry, readActivityLogEntries, resolveActivityLogPath } from "./activity-log.js";
@@ -444,8 +443,17 @@ function formatHostForUrl(host, port) {
444
443
  return `[${value}]:${port}`;
445
444
  }
446
445
 
446
+ function buildManagedRouterOrigin(settings = {}) {
447
+ const port = Number.isInteger(Number(settings?.port)) ? Number(settings.port) : FIXED_LOCAL_ROUTER_PORT;
448
+ const configuredHost = normalizeRuntimeHost(settings?.host || FIXED_LOCAL_ROUTER_HOST);
449
+ const host = isWildcardRuntimeHost(configuredHost) || isLoopbackRuntimeHost(configuredHost)
450
+ ? FIXED_LOCAL_ROUTER_HOST
451
+ : configuredHost;
452
+ return `http://${formatHostForUrl(host, port)}`;
453
+ }
454
+
447
455
  function buildAmpClientEndpointUrl(settings = {}) {
448
- return getFixedLocalRouterOrigin();
456
+ return buildManagedRouterOrigin(settings);
449
457
  }
450
458
 
451
459
  function buildCodexCliEndpointUrl(settings = {}) {
@@ -465,7 +473,7 @@ function buildFactoryDroidEndpointUrl(settings = {}) {
465
473
 
466
474
  function buildRouterEndpoints({ host, port, running }) {
467
475
  if (!running) return [];
468
- const origin = getFixedLocalRouterOrigin();
476
+ const origin = buildManagedRouterOrigin({ host, port });
469
477
  return [
470
478
  { label: "Unified", url: `${origin}/route` },
471
479
  { label: "Anthropic", url: `${origin}/anthropic` },
@@ -805,8 +813,10 @@ function writeJsonLine(res, payload) {
805
813
 
806
814
  function resolveRouterOptions(current, body) {
807
815
  return {
808
- host: FIXED_LOCAL_ROUTER_HOST,
809
- port: FIXED_LOCAL_ROUTER_PORT,
816
+ host: normalizeRuntimeHost(body?.host || current?.host || FIXED_LOCAL_ROUTER_HOST),
817
+ port: Number.isInteger(Number(body?.port))
818
+ ? Number(body.port)
819
+ : (Number.isInteger(Number(current?.port)) ? Number(current.port) : FIXED_LOCAL_ROUTER_PORT),
810
820
  watchConfig: body?.watchConfig === undefined ? current.watchConfig : body.watchConfig === true,
811
821
  requireAuth: body?.requireAuth === undefined ? current.requireAuth : body.requireAuth === true,
812
822
  watchBinary: body?.watchBinary === undefined ? current.watchBinary : body.watchBinary === true
@@ -815,8 +825,8 @@ function resolveRouterOptions(current, body) {
815
825
 
816
826
  function getRouterStateSettings(routerState) {
817
827
  return {
818
- host: FIXED_LOCAL_ROUTER_HOST,
819
- port: FIXED_LOCAL_ROUTER_PORT,
828
+ host: normalizeRuntimeHost(routerState?.host || FIXED_LOCAL_ROUTER_HOST),
829
+ port: Number.isInteger(Number(routerState?.port)) ? Number(routerState.port) : FIXED_LOCAL_ROUTER_PORT,
820
830
  watchConfig: routerState?.watchConfig !== false,
821
831
  watchBinary: routerState?.watchBinary !== false,
822
832
  requireAuth: routerState?.requireAuth === true
@@ -882,6 +892,14 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
882
892
  : loadWebConsoleDevAssets;
883
893
  const resolvedRouterCliPath = String(cliPathForRouter || process.env.LLM_ROUTER_CLI_PATH || process.argv[1] || "").trim();
884
894
  const resolvedActivityLogPath = resolveActivityLogPath(configPath, activityLogPath);
895
+ const startupControlsEnabled = !devMode;
896
+ const defaultRouterSettings = {
897
+ host: normalizeRuntimeHost(routerHost || FIXED_LOCAL_ROUTER_HOST),
898
+ port: Number.isInteger(Number(routerPort)) ? Number(routerPort) : FIXED_LOCAL_ROUTER_PORT,
899
+ watchConfig: routerWatchConfig !== false,
900
+ watchBinary: routerWatchBinary !== false,
901
+ requireAuth: routerRequireAuth === true
902
+ };
885
903
 
886
904
  async function readWebSearchState(config = null) {
887
905
  if (!config || typeof config !== "object") return null;
@@ -1488,7 +1506,8 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
1488
1506
  const endpointUrl = buildAmpClientEndpointUrl(settings);
1489
1507
  try {
1490
1508
  const state = await readFactoryDroidRoutingState({
1491
- endpointUrl
1509
+ endpointUrl,
1510
+ config
1492
1511
  });
1493
1512
  return {
1494
1513
  ...state,
@@ -1512,6 +1531,13 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
1512
1531
  missionValidatorModel: "",
1513
1532
  reasoningEffort: ""
1514
1533
  },
1534
+ bindingIds: {
1535
+ defaultModel: "",
1536
+ missionOrchestratorModel: "",
1537
+ missionWorkerModel: "",
1538
+ missionValidatorModel: "",
1539
+ reasoningEffort: ""
1540
+ },
1515
1541
  endpointUrl,
1516
1542
  error: error instanceof Error ? error.message : String(error)
1517
1543
  };
@@ -1551,6 +1577,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
1551
1577
  endpointUrl: nextEndpointUrl,
1552
1578
  apiKey: nextMasterKey,
1553
1579
  bindings,
1580
+ config: nextConfig,
1554
1581
  captureBackup: false
1555
1582
  });
1556
1583
  if (endpointOrKeyChanged) {
@@ -1709,11 +1736,11 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
1709
1736
  let activityLogEnabled = true;
1710
1737
 
1711
1738
  const routerState = {
1712
- host: FIXED_LOCAL_ROUTER_HOST,
1713
- port: FIXED_LOCAL_ROUTER_PORT,
1714
- watchConfig: routerWatchConfig,
1715
- watchBinary: routerWatchBinary,
1716
- requireAuth: routerRequireAuth,
1739
+ host: defaultRouterSettings.host,
1740
+ port: defaultRouterSettings.port,
1741
+ watchConfig: defaultRouterSettings.watchConfig,
1742
+ watchBinary: defaultRouterSettings.watchBinary,
1743
+ requireAuth: defaultRouterSettings.requireAuth,
1717
1744
  lastError: ""
1718
1745
  };
1719
1746
 
@@ -1978,6 +2005,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
1978
2005
  }
1979
2006
 
1980
2007
  async function stopUntrackedStartupRuntime({ reason = "Stopped startup-managed LLM Router." } = {}) {
2008
+ if (!startupControlsEnabled) return false;
1981
2009
  const startup = await startupStatusFn().catch(() => null);
1982
2010
  if (!startup?.running) return false;
1983
2011
  await stopStartupFn();
@@ -1987,6 +2015,12 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
1987
2015
  }
1988
2016
 
1989
2017
  async function startStartupOwnedRouter(settings, { restart = false } = {}) {
2018
+ if (!startupControlsEnabled) {
2019
+ const error = new Error("Startup service controls are disabled in dev mode.");
2020
+ error.statusCode = 409;
2021
+ throw error;
2022
+ }
2023
+
1990
2024
  await clearRuntimeStateFn();
1991
2025
  const detail = await installStartupFn({
1992
2026
  configPath,
@@ -2049,7 +2083,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
2049
2083
  };
2050
2084
  }
2051
2085
 
2052
- const startup = await startupStatusFn().catch(() => null);
2086
+ const startup = startupControlsEnabled ? await startupStatusFn().catch(() => null) : null;
2053
2087
  const activeRuntime = await readManagedRuntime(configLocalServer);
2054
2088
  if (activeRuntime) {
2055
2089
  return {
@@ -2066,7 +2100,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
2066
2100
  await stopExternalRuntime(externalRuntime, {
2067
2101
  reason: `Stopped an existing LLM Router instance so the web console can manage ${configLocalServer.host}:${configLocalServer.port} during ${reason}.`
2068
2102
  });
2069
- } else {
2103
+ } else if (startupControlsEnabled) {
2070
2104
  await stopUntrackedStartupRuntime({
2071
2105
  reason: `Stopped the startup-managed LLM Router instance so the web console can manage ${configLocalServer.host}:${configLocalServer.port} during ${reason}.`
2072
2106
  });
@@ -2261,13 +2295,21 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
2261
2295
  const configState = await readConfigState(configPath);
2262
2296
  const configLocalServer = getConfigLocalServer(configState);
2263
2297
  const activityLog = resolveActivityLogSnapshot(configState.normalizedConfig);
2264
- const startup = await startupStatusFn().catch((error) => ({
2265
- manager: "unknown",
2266
- serviceId: "llm-router",
2267
- installed: false,
2268
- running: false,
2269
- detail: error instanceof Error ? error.message : String(error)
2270
- }));
2298
+ const startup = startupControlsEnabled
2299
+ ? await startupStatusFn().catch((error) => ({
2300
+ manager: "unknown",
2301
+ serviceId: "llm-router",
2302
+ installed: false,
2303
+ running: false,
2304
+ detail: error instanceof Error ? error.message : String(error)
2305
+ }))
2306
+ : {
2307
+ manager: "disabled",
2308
+ serviceId: "llm-router",
2309
+ installed: false,
2310
+ running: false,
2311
+ detail: "Startup service controls are disabled in dev mode."
2312
+ };
2271
2313
  const managedRuntime = await readManagedRuntime(configLocalServer);
2272
2314
  const externalRuntime = managedRuntime ? null : await readExternalRuntime(configLocalServer);
2273
2315
  const portProbe = probeRouterPort(configLocalServer);
@@ -2306,9 +2348,12 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
2306
2348
  router: routerSnapshot,
2307
2349
  startup: {
2308
2350
  ...startup,
2309
- label: formatStartupLabel(startup),
2310
- friendlyDetail: formatStartupDetail(startup),
2311
- defaults: configLocalServer
2351
+ label: startupControlsEnabled ? formatStartupLabel(startup) : "Startup disabled in dev mode",
2352
+ friendlyDetail: startupControlsEnabled
2353
+ ? formatStartupDetail(startup)
2354
+ : "Development web console will not install, stop, or replace startup-managed routers.",
2355
+ defaults: configLocalServer,
2356
+ available: startupControlsEnabled
2312
2357
  },
2313
2358
  ampClient: {
2314
2359
  global: ampClientGlobal
@@ -2464,8 +2509,8 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
2464
2509
  nextOptions = persisted.savedSettings;
2465
2510
  }
2466
2511
 
2467
- const startup = await startupStatusFn().catch(() => null);
2468
- const preferStartupOwnership = Boolean(startup?.installed);
2512
+ const startup = startupControlsEnabled ? await startupStatusFn().catch(() => null) : null;
2513
+ const preferStartupOwnership = startupControlsEnabled && Boolean(startup?.installed);
2469
2514
  const runningRuntime = await readManagedRuntime(nextOptions);
2470
2515
  const webConsoleConflict = getWebConsoleConflictMessage(nextOptions);
2471
2516
 
@@ -2492,7 +2537,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
2492
2537
  await stopExternalRuntime(externalRuntime, {
2493
2538
  reason: "Stopped another LLM Router instance before starting the managed router."
2494
2539
  });
2495
- } else {
2540
+ } else if (startupControlsEnabled) {
2496
2541
  await stopUntrackedStartupRuntime({
2497
2542
  reason: "Stopped the startup-managed LLM Router instance before starting the managed router."
2498
2543
  });
@@ -3487,6 +3532,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
3487
3532
  endpointUrl,
3488
3533
  apiKey,
3489
3534
  bindings,
3535
+ config: nextConfig,
3490
3536
  captureBackup: true
3491
3537
  });
3492
3538
  addLog("success", "Factory Droid routing enabled.", patchResult.baseUrl);
@@ -3537,6 +3583,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
3537
3583
  endpointUrl,
3538
3584
  apiKey,
3539
3585
  bindings,
3586
+ config: configState.normalizedConfig,
3540
3587
  captureBackup: false
3541
3588
  });
3542
3589
  addLog("success", "Factory Droid model bindings updated.", patchResult.bindings.defaultModel || "Default");
@@ -3722,6 +3769,10 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
3722
3769
  }
3723
3770
 
3724
3771
  if (method === "POST" && requestUrl.pathname === "/api/startup/enable") {
3772
+ if (!startupControlsEnabled) {
3773
+ sendJson(res, 409, { error: "Startup service controls are unavailable in dev mode." });
3774
+ return;
3775
+ }
3725
3776
  const body = await readJsonBody(req);
3726
3777
  const configState = await readConfigState(configPath);
3727
3778
  if (configState.parseError) {
@@ -3784,6 +3835,10 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
3784
3835
  }
3785
3836
 
3786
3837
  if (method === "POST" && requestUrl.pathname === "/api/startup/disable") {
3838
+ if (!startupControlsEnabled) {
3839
+ sendJson(res, 409, { error: "Startup service controls are unavailable in dev mode." });
3840
+ return;
3841
+ }
3787
3842
  await readJsonBody(req);
3788
3843
  const statusBefore = await startupStatusFn().catch(() => null);
3789
3844
  if (!statusBefore?.installed) {
@@ -4234,6 +4289,7 @@ export async function startWebConsoleServer(options = {}, deps = {}) {
4234
4289
 
4235
4290
  addLog("info", `Web console listening on http://${formatHostForUrl(host, actualWebPort)}`);
4236
4291
  if (devMode) addLog("info", "Development mode enabled for web assets.");
4292
+ if (!startupControlsEnabled) addLog("info", "Startup service controls disabled in dev mode.");
4237
4293
  startConfigWatcher();
4238
4294
  startActivityLogWatcher();
4239
4295
 
@@ -64,6 +64,160 @@ export const FACTORY_DROID_REASONING_EFFORT_VALUES = Object.freeze([
64
64
  "high"
65
65
  ]);
66
66
 
67
+ function stripFactoryDroidRouterModelIdPrefix(value) {
68
+ const normalized = String(value || "").trim();
69
+ if (normalized.startsWith("custom:")) return normalized.slice("custom:".length).trim();
70
+ return normalized;
71
+ }
72
+
73
+ function sanitizeFactoryDroidRouterModelIdPart(value) {
74
+ return String(value || "")
75
+ .trim()
76
+ .replace(/[/:]+/g, "-")
77
+ .replace(/\s+/g, "-")
78
+ .replace(/[^A-Za-z0-9._-]+/g, "-")
79
+ .replace(/-+/g, "-")
80
+ .replace(/^-+|-+$/g, "");
81
+ }
82
+
83
+ function formatFactoryDroidDisplayNameBase(value) {
84
+ const normalized = String(value || "").trim();
85
+ if (!normalized) return "";
86
+ let next = normalized;
87
+ if (/^gpt(?=[-\s.]|$)/i.test(next)) next = `GPT${next.slice(3)}`;
88
+ else if (/^glm(?=[-\s.]|$)/i.test(next)) next = `GLM${next.slice(3)}`;
89
+ else if (/^claude(?=[-\s.]|$)/i.test(next)) next = `Claude${next.slice(6)}`;
90
+
91
+ return next
92
+ .replace(/(\d)-(\d)(?=(?:-|$))/g, "$1.$2")
93
+ .replace(/[_-]+/g, " ")
94
+ .replace(/\s+/g, " ")
95
+ .trim();
96
+ }
97
+
98
+ function formatFactoryDroidProviderLabel(value) {
99
+ const normalized = String(value || "").trim();
100
+ if (!normalized) return "Provider";
101
+ if (normalized.toLowerCase() === "openrouter") return "OpenRouter";
102
+ if (normalized.toLowerCase() === "deepseek") return "DeepSeek";
103
+ if (/^[A-Za-z]{2,5}$/.test(normalized)) return normalized.toUpperCase();
104
+ return normalized
105
+ .replace(/[_-]+/g, " ")
106
+ .replace(/\s+/g, " ")
107
+ .split(" ")
108
+ .filter(Boolean)
109
+ .map((part) => part[0].toUpperCase() + part.slice(1))
110
+ .join(" ");
111
+ }
112
+
113
+ export function isFactoryDroidRouterModelId(value) {
114
+ const normalized = stripFactoryDroidRouterModelIdPrefix(value);
115
+ return normalized.startsWith("llm-");
116
+ }
117
+
118
+ export function parseFactoryDroidRouterModelId(value) {
119
+ const normalized = stripFactoryDroidRouterModelIdPrefix(value);
120
+ if (!normalized.startsWith("llm-")) return null;
121
+
122
+ if (normalized.startsWith("llm-alias:")) {
123
+ const aliasId = normalized.slice("llm-alias:".length).trim();
124
+ return aliasId
125
+ ? {
126
+ kind: "alias",
127
+ aliasId,
128
+ routeRef: aliasId
129
+ }
130
+ : null;
131
+ }
132
+
133
+ if (normalized.startsWith("llm-alias-")) {
134
+ const aliasId = normalized.slice("llm-alias-".length).trim();
135
+ return aliasId
136
+ ? {
137
+ kind: "alias",
138
+ aliasId,
139
+ routeRef: ""
140
+ }
141
+ : null;
142
+ }
143
+
144
+ const body = normalized.slice("llm-".length);
145
+ const separatorIndex = body.indexOf(":");
146
+ if (separatorIndex <= 0) return null;
147
+
148
+ const providerId = body.slice(0, separatorIndex).trim();
149
+ const modelId = body.slice(separatorIndex + 1).trim();
150
+ if (!providerId || !modelId) return null;
151
+
152
+ return {
153
+ kind: "model",
154
+ providerId,
155
+ modelId,
156
+ routeRef: `${providerId}/${modelId}`
157
+ };
158
+ }
159
+
160
+ export function resolveFactoryDroidRouterModelRef(value) {
161
+ const normalized = String(value || "").trim();
162
+ if (!normalized) return "";
163
+ return parseFactoryDroidRouterModelId(normalized)?.routeRef || normalized;
164
+ }
165
+
166
+ export function buildFactoryDroidRouterModelId(modelRef, { kind = "" } = {}) {
167
+ const normalizedModelRef = String(modelRef || "").trim();
168
+ if (!normalizedModelRef) return "";
169
+ if (normalizedModelRef.startsWith("custom:llm-")) {
170
+ const parsed = parseFactoryDroidRouterModelId(normalizedModelRef);
171
+ return parsed?.routeRef
172
+ ? buildFactoryDroidRouterModelId(parsed.routeRef, { kind: parsed.kind })
173
+ : normalizedModelRef;
174
+ }
175
+ if (normalizedModelRef.startsWith("llm-")) {
176
+ const parsed = parseFactoryDroidRouterModelId(normalizedModelRef);
177
+ return parsed?.routeRef
178
+ ? buildFactoryDroidRouterModelId(parsed.routeRef, { kind: parsed.kind })
179
+ : `custom:${normalizedModelRef}`;
180
+ }
181
+
182
+ const explicitKind = String(kind || "").trim().toLowerCase();
183
+ if (explicitKind === "alias") {
184
+ const aliasId = sanitizeFactoryDroidRouterModelIdPart(normalizedModelRef);
185
+ return aliasId ? `custom:llm-alias-${aliasId}` : "";
186
+ }
187
+
188
+ if (explicitKind === "model") {
189
+ const separatorIndex = normalizedModelRef.indexOf("/");
190
+ if (separatorIndex <= 0 || separatorIndex >= normalizedModelRef.length - 1) return "";
191
+ const providerId = normalizedModelRef.slice(0, separatorIndex).trim();
192
+ const modelId = normalizedModelRef.slice(separatorIndex + 1).trim();
193
+ const providerSlug = sanitizeFactoryDroidRouterModelIdPart(providerId);
194
+ const modelSlug = sanitizeFactoryDroidRouterModelIdPart(modelId);
195
+ return providerSlug && modelSlug ? `custom:llm-${providerSlug}-${modelSlug}` : "";
196
+ }
197
+
198
+ if (!normalizedModelRef.includes("/")) {
199
+ return buildFactoryDroidRouterModelId(normalizedModelRef, { kind: "alias" });
200
+ }
201
+
202
+ return buildFactoryDroidRouterModelId(normalizedModelRef, { kind: "model" });
203
+ }
204
+
205
+ export function buildFactoryDroidRouterDisplayName(modelRef, { kind = "", providerName = "" } = {}) {
206
+ const normalizedModelRef = String(modelRef || "").trim();
207
+ if (!normalizedModelRef) return "";
208
+
209
+ const explicitKind = String(kind || "").trim().toLowerCase();
210
+ const inferredKind = explicitKind || (normalizedModelRef.includes("/") ? "model" : "alias");
211
+ if (inferredKind === "alias") {
212
+ return `${formatFactoryDroidDisplayNameBase(normalizedModelRef)} - LLM Router (Alias)`;
213
+ }
214
+
215
+ const modelName = normalizedModelRef.includes("/")
216
+ ? normalizedModelRef.slice(normalizedModelRef.indexOf("/") + 1).trim()
217
+ : normalizedModelRef;
218
+ return `${formatFactoryDroidDisplayNameBase(modelName)} - LLM Router (${formatFactoryDroidProviderLabel(providerName)})`;
219
+ }
220
+
67
221
  export function normalizeFactoryDroidReasoningEffort(value) {
68
222
  const normalized = String(value || "").trim().toLowerCase();
69
223
  return FACTORY_DROID_REASONING_EFFORT_VALUES.includes(normalized) ? normalized : "";
@@ -20,16 +20,29 @@ function isPlainObject(value) {
20
20
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
21
21
  }
22
22
 
23
+ function normalizeHost(value, fallback = LOCAL_ROUTER_HOST) {
24
+ const text = String(value || fallback).trim();
25
+ return text || fallback;
26
+ }
27
+
28
+ function normalizePort(value, fallback = LOCAL_ROUTER_PORT) {
29
+ const parsed = Number.parseInt(String(value ?? ""), 10);
30
+ if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) return fallback;
31
+ return parsed;
32
+ }
33
+
23
34
  export function buildLocalRouterSettings(source = {}, fallback = {}) {
24
35
  const base = {
36
+ host: normalizeHost(fallback?.host, LOCAL_ROUTER_HOST),
37
+ port: normalizePort(fallback?.port, LOCAL_ROUTER_PORT),
25
38
  watchConfig: toBoolean(fallback?.watchConfig, true),
26
39
  watchBinary: toBoolean(fallback?.watchBinary, true),
27
40
  requireAuth: toBoolean(fallback?.requireAuth, false)
28
41
  };
29
42
 
30
43
  return {
31
- host: LOCAL_ROUTER_HOST,
32
- port: LOCAL_ROUTER_PORT,
44
+ host: normalizeHost(source?.host, base.host),
45
+ port: normalizePort(source?.port, base.port),
33
46
  watchConfig: toBoolean(source?.watchConfig, base.watchConfig),
34
47
  watchBinary: toBoolean(source?.watchBinary, base.watchBinary),
35
48
  requireAuth: toBoolean(source?.requireAuth, base.requireAuth)
@@ -3,14 +3,13 @@ export function buildTimeoutSignal(timeoutMs) {
3
3
  return { signal: undefined, cleanup: () => {} };
4
4
  }
5
5
 
6
- if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") {
7
- return {
8
- signal: AbortSignal.timeout(timeoutMs),
9
- cleanup: () => {}
10
- };
11
- }
12
-
13
6
  if (typeof AbortController === "undefined") {
7
+ if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") {
8
+ return {
9
+ signal: AbortSignal.timeout(timeoutMs),
10
+ cleanup: () => {}
11
+ };
12
+ }
14
13
  return { signal: undefined, cleanup: () => {} };
15
14
  }
16
15