omnigateway 0.4.4 → 0.4.6

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 (3) hide show
  1. package/bin/omni.js +20 -15
  2. package/gateway.js +36 -23
  3. package/package.json +1 -1
package/bin/omni.js CHANGED
@@ -237,6 +237,12 @@ var RETRYABLE = {
237
237
  ALL_CANDIDATES_FAILED: false,
238
238
  INTERNAL: false
239
239
  };
240
+ function describeError(error, fallback) {
241
+ if (!(error instanceof Error))
242
+ return fallback;
243
+ return error.message.length > 0 ? error.message : error.name;
244
+ }
245
+
240
246
  class GatewayError extends Error {
241
247
  code;
242
248
  retryable;
@@ -20131,7 +20137,7 @@ function createPluginRepo(db) {
20131
20137
  applied,
20132
20138
  failed: {
20133
20139
  version: migration.version,
20134
- reason: error51 instanceof Error ? error51.message : String(error51)
20140
+ reason: describeError(error51, String(error51))
20135
20141
  }
20136
20142
  };
20137
20143
  }
@@ -20975,14 +20981,14 @@ async function swapIn(deps, candidate) {
20975
20981
  await deps.store.usage.rebuildRollup();
20976
20982
  } catch (error51) {
20977
20983
  (deps.logger ?? noopLogger).warn("usage rollup not rebuilt after the swap; run omni doctor", {
20978
- reason: error51 instanceof Error ? error51.message : "unknown"
20984
+ reason: describeError(error51, "unknown")
20979
20985
  });
20980
20986
  }
20981
20987
  try {
20982
20988
  await deps.reapplyPluginSchema?.();
20983
20989
  } catch (error51) {
20984
20990
  (deps.logger ?? noopLogger).warn("plugin schema not reapplied after the swap; restart", {
20985
- reason: error51 instanceof Error ? error51.message : "unknown"
20991
+ reason: describeError(error51, "unknown")
20986
20992
  });
20987
20993
  }
20988
20994
  return {
@@ -21386,7 +21392,7 @@ function readManifest(fs, home) {
21386
21392
  try {
21387
21393
  document = JSON.parse(raw);
21388
21394
  } catch (error51) {
21389
- const detail = error51 instanceof Error ? error51.message : String(error51);
21395
+ const detail = describeError(error51, String(error51));
21390
21396
  return {
21391
21397
  check: "manifest",
21392
21398
  reason: `${MANIFEST_FILENAME} is not valid JSON: ${detail}`,
@@ -21592,7 +21598,7 @@ function gunzipIfNeeded(bytes) {
21592
21598
  try {
21593
21599
  return Bun.gunzipSync(new Uint8Array(bytes));
21594
21600
  } catch (error51) {
21595
- const detail = error51 instanceof Error ? error51.message : String(error51);
21601
+ const detail = describeError(error51, String(error51));
21596
21602
  throw new GatewayError("BAD_REQUEST", `could not decompress the archive: ${detail}`);
21597
21603
  }
21598
21604
  }
@@ -21774,7 +21780,7 @@ function parseJson(bytes, what) {
21774
21780
  try {
21775
21781
  return JSON.parse(decoder2.decode(bytes));
21776
21782
  } catch (error51) {
21777
- const detail = error51 instanceof Error ? error51.message : String(error51);
21783
+ const detail = describeError(error51, String(error51));
21778
21784
  throw new GatewayError("BAD_REQUEST", `${what} is not valid JSON: ${detail}`);
21779
21785
  }
21780
21786
  }
@@ -21812,7 +21818,7 @@ async function installPlugin(deps, root, spec) {
21812
21818
  try {
21813
21819
  document = JSON.parse(decoder2.decode(raw));
21814
21820
  } catch (error51) {
21815
- const detail = error51 instanceof Error ? error51.message : String(error51);
21821
+ const detail = describeError(error51, String(error51));
21816
21822
  throw new GatewayError("BAD_REQUEST", `${MANIFEST_FILENAME} is not valid JSON: ${detail}`);
21817
21823
  }
21818
21824
  const parsed = safeParseManifest(document);
@@ -23033,7 +23039,7 @@ function settingsObject(existing) {
23033
23039
  }
23034
23040
  return parsed;
23035
23041
  } catch (error51) {
23036
- const reason = error51 instanceof Error ? error51.message : "invalid JSON";
23042
+ const reason = describeError(error51, "invalid JSON");
23037
23043
  throw new Error(`cannot parse existing settings.json: ${reason}`);
23038
23044
  }
23039
23045
  }
@@ -23179,7 +23185,6 @@ async function recentLogs(store, requested) {
23179
23185
  }
23180
23186
  // apps/cli/src/args.ts
23181
23187
  import { parseArgs } from "util";
23182
-
23183
23188
  class UsageError extends Error {
23184
23189
  }
23185
23190
  var GLOBAL_OPTIONS = {
@@ -23201,7 +23206,7 @@ function parse5(argv, options = {}) {
23201
23206
  });
23202
23207
  return { positionals: result.positionals, values: result.values };
23203
23208
  } catch (error51) {
23204
- throw new UsageError(error51 instanceof Error ? error51.message : "could not parse arguments");
23209
+ throw new UsageError(describeError(error51, "could not parse arguments"));
23205
23210
  }
23206
23211
  }
23207
23212
  function stringFlag(values2, name) {
@@ -23303,7 +23308,7 @@ function createContext(parsed, options = {}) {
23303
23308
  try {
23304
23309
  config2 = loadConfig(env2);
23305
23310
  } catch (error51) {
23306
- configError = error51 instanceof Error ? error51.message : "invalid configuration";
23311
+ configError = describeError(error51, "invalid configuration");
23307
23312
  }
23308
23313
  const configuredPath = dbFlag ?? config2?.databasePath ?? "omnigateway.db";
23309
23314
  const databasePath = isAbsolute(configuredPath) ? configuredPath : resolve3(root.root, configuredPath);
@@ -25376,7 +25381,7 @@ var status2 = {
25376
25381
  try {
25377
25382
  store = await ctx.store();
25378
25383
  } catch (error51) {
25379
- storeError = error51 instanceof Error ? error51.message : "could not open the database";
25384
+ storeError = describeError(error51, "could not open the database");
25380
25385
  }
25381
25386
  const persistent = store === null ? { adminConfigured: false, credentials: [] } : await credentialStatus(store, { now: ctx.now });
25382
25387
  const { adminConfigured: configured, credentials } = persistent;
@@ -25432,7 +25437,7 @@ var adminSetPassword = {
25432
25437
  try {
25433
25438
  await admin.setPassword(password);
25434
25439
  } catch (error51) {
25435
- throw new CliError(error51 instanceof Error ? error51.message : "could not set the password");
25440
+ throw new CliError(describeError(error51, "could not set the password"));
25436
25441
  }
25437
25442
  note(ctx, writer, "restart the gateway to end sessions signed in with the old password");
25438
25443
  emit(ctx, writer, { ok: true }, () => "admin password set");
@@ -25799,7 +25804,7 @@ async function run(argv, writer, options = {}) {
25799
25804
  try {
25800
25805
  args = parse5(resolved.rest, resolved.command.options ?? {});
25801
25806
  } catch (error51) {
25802
- writer.err(error51 instanceof Error ? error51.message : "could not parse arguments");
25807
+ writer.err(describeError(error51, "could not parse arguments"));
25803
25808
  writer.err(`usage: omni ${resolved.command.usage}`);
25804
25809
  return 2;
25805
25810
  }
@@ -25849,7 +25854,7 @@ async function run(argv, writer, options = {}) {
25849
25854
  writer.err(`${error51.code}: ${error51.message}`);
25850
25855
  return 1;
25851
25856
  }
25852
- writer.err(error51 instanceof Error ? error51.message : "unknown error");
25857
+ writer.err(describeError(error51, "unknown error"));
25853
25858
  return 1;
25854
25859
  } finally {
25855
25860
  ctx.close();
package/gateway.js CHANGED
@@ -5375,6 +5375,11 @@ var HTTP_STATUS = {
5375
5375
  ALL_CANDIDATES_FAILED: 503,
5376
5376
  INTERNAL: 500
5377
5377
  };
5378
+ function describeError(error, fallback) {
5379
+ if (!(error instanceof Error))
5380
+ return fallback;
5381
+ return error.message.length > 0 ? error.message : error.name;
5382
+ }
5378
5383
 
5379
5384
  class GatewayError extends Error {
5380
5385
  code;
@@ -25605,7 +25610,7 @@ function createPluginRepo(db) {
25605
25610
  applied,
25606
25611
  failed: {
25607
25612
  version: migration.version,
25608
- reason: error51 instanceof Error ? error51.message : String(error51)
25613
+ reason: describeError(error51, String(error51))
25609
25614
  }
25610
25615
  };
25611
25616
  }
@@ -26460,14 +26465,14 @@ async function swapIn(deps, candidate) {
26460
26465
  await deps.store.usage.rebuildRollup();
26461
26466
  } catch (error51) {
26462
26467
  (deps.logger ?? noopLogger).warn("usage rollup not rebuilt after the swap; run omni doctor", {
26463
- reason: error51 instanceof Error ? error51.message : "unknown"
26468
+ reason: describeError(error51, "unknown")
26464
26469
  });
26465
26470
  }
26466
26471
  try {
26467
26472
  await deps.reapplyPluginSchema?.();
26468
26473
  } catch (error51) {
26469
26474
  (deps.logger ?? noopLogger).warn("plugin schema not reapplied after the swap; restart", {
26470
- reason: error51 instanceof Error ? error51.message : "unknown"
26475
+ reason: describeError(error51, "unknown")
26471
26476
  });
26472
26477
  }
26473
26478
  return {
@@ -28009,7 +28014,7 @@ async function poll(deps) {
28009
28014
  credentialId: credential.id,
28010
28015
  code: error51 instanceof GatewayError ? error51.code : "INTERNAL",
28011
28016
  ...rateLimited ? { retryAfterMs: RATE_LIMIT_COOLDOWN_MS } : {},
28012
- reason: error51 instanceof Error ? error51.message : "unknown"
28017
+ reason: describeError(error51, "unknown")
28013
28018
  });
28014
28019
  }
28015
28020
  }
@@ -28062,7 +28067,7 @@ function settingsObject(existing) {
28062
28067
  }
28063
28068
  return parsed;
28064
28069
  } catch (error51) {
28065
- const reason = error51 instanceof Error ? error51.message : "invalid JSON";
28070
+ const reason = describeError(error51, "invalid JSON");
28066
28071
  throw new Error(`cannot parse existing settings.json: ${reason}`);
28067
28072
  }
28068
28073
  }
@@ -42885,7 +42890,7 @@ class ApiKeyRateLimiter {
42885
42890
  this.logger.warn("rate limit reset unavailable", {
42886
42891
  ...requestId === undefined ? {} : { requestId },
42887
42892
  apiKeyId: keyId,
42888
- reason: error51 instanceof Error ? error51.message : "unknown"
42893
+ reason: describeError(error51, "unknown")
42889
42894
  });
42890
42895
  return null;
42891
42896
  }
@@ -42951,7 +42956,7 @@ class ApiKeyRateLimiter {
42951
42956
  this.logger.warn("rate limit counters unavailable", {
42952
42957
  ...requestId === undefined ? {} : { requestId },
42953
42958
  apiKeyId: keyId,
42954
- reason: error51 instanceof Error ? error51.message : "unknown"
42959
+ reason: describeError(error51, "unknown")
42955
42960
  });
42956
42961
  state.debits = trimDebits(state.debits, now);
42957
42962
  return null;
@@ -43796,7 +43801,7 @@ function adminRoutes(deps) {
43796
43801
  try {
43797
43802
  created = await deps.admin.setInitialPassword(body2.password);
43798
43803
  } catch (error51) {
43799
- throw new GatewayError("BAD_REQUEST", error51 instanceof Error ? error51.message : "invalid password");
43804
+ throw new GatewayError("BAD_REQUEST", describeError(error51, "invalid password"));
43800
43805
  }
43801
43806
  if (!created) {
43802
43807
  set2.status = 409;
@@ -43888,7 +43893,7 @@ function adminRoutes(deps) {
43888
43893
  })
43889
43894
  };
43890
43895
  } catch (error51) {
43891
- throw new GatewayError("BAD_REQUEST", error51 instanceof Error ? error51.message : "invalid Claude model mapping");
43896
+ throw new GatewayError("BAD_REQUEST", describeError(error51, "invalid Claude model mapping"));
43892
43897
  }
43893
43898
  }).get("/api/keys", async ({ request: request2 }) => {
43894
43899
  await requireAdmin(request2, deps.admin);
@@ -46157,7 +46162,7 @@ function reportRejection(logger2, requestId, log, error51, surface) {
46157
46162
  function report(logger2, what, requestId, error51) {
46158
46163
  logger2.warn(what, {
46159
46164
  requestId,
46160
- reason: error51 instanceof Error ? error51.message : "unknown"
46165
+ reason: describeError(error51, "unknown")
46161
46166
  });
46162
46167
  }
46163
46168
  async function beginLog(store, log, keyId, logger2 = noopLogger) {
@@ -46272,6 +46277,14 @@ function classify(error51) {
46272
46277
  if (error51 instanceof DOMException && error51.name === "AbortError") {
46273
46278
  return { code: "TIMEOUT" };
46274
46279
  }
46280
+ if (error51 instanceof AggregateError && Array.isArray(error51.errors)) {
46281
+ for (const inner of error51.errors) {
46282
+ const classified = classify(inner);
46283
+ if (classified.code !== "INTERNAL")
46284
+ return classified;
46285
+ }
46286
+ return { code: "INTERNAL" };
46287
+ }
46275
46288
  if (error51 instanceof Error) {
46276
46289
  const text = `${error51.name} ${error51.message}`.toLowerCase();
46277
46290
  if (NETWORK_HINTS.some((hint) => text.includes(hint)))
@@ -46380,7 +46393,7 @@ async function dispatch(request2, deps, signal, requestId) {
46380
46393
  if (isClientAbort(error51))
46381
46394
  return fail("TIMEOUT", "client disconnected", true);
46382
46395
  const { code } = classify(error51);
46383
- return fail(code, error51 instanceof Error ? error51.message : "unresolvable model");
46396
+ return fail(code, describeError(error51, "unresolvable model"));
46384
46397
  }
46385
46398
  const { candidates, excluded } = rank({
46386
46399
  request: dispatchRequest,
@@ -46545,7 +46558,7 @@ async function dispatch(request2, deps, signal, requestId) {
46545
46558
  requestId,
46546
46559
  provider: candidate.target.provider,
46547
46560
  credentialId: candidate.credential.id,
46548
- reason: healthError instanceof Error ? healthError.message : "unknown"
46561
+ reason: describeError(healthError, "unknown")
46549
46562
  });
46550
46563
  }
46551
46564
  return;
@@ -46580,7 +46593,7 @@ async function dispatch(request2, deps, signal, requestId) {
46580
46593
  throw signal.reason;
46581
46594
  const classifiedError = deadlineAt !== null && dispatchSignal.aborted ? { code: "TIMEOUT" } : classify(error51);
46582
46595
  const { code: code2 } = classifiedError;
46583
- const message2 = error51 instanceof Error ? error51.message : "attempt failed";
46596
+ const message2 = describeError(error51, "attempt failed");
46584
46597
  lastError = rewrap(classifiedError, message2);
46585
46598
  if (code2 === "AUTH" && !committed && !authRefreshRetried && !preemptiveRefreshRequired && candidate.credential.authType === "oauth" && candidate.credential.hasRefreshToken) {
46586
46599
  authRefreshRetried = true;
@@ -46599,7 +46612,7 @@ async function dispatch(request2, deps, signal, requestId) {
46599
46612
  if (signal.aborted)
46600
46613
  throw signal.reason;
46601
46614
  const classified = deadlineAt !== null && dispatchSignal.aborted ? { code: "TIMEOUT" } : classify(refreshError);
46602
- const refreshMessage = refreshError instanceof Error ? refreshError.message : "credential refresh failed";
46615
+ const refreshMessage = describeError(refreshError, "credential refresh failed");
46603
46616
  lastError = rewrap(classified, refreshMessage);
46604
46617
  logger2.warn("credential refresh failed", {
46605
46618
  requestId,
@@ -47652,7 +47665,7 @@ function errorResponse(surface, code, message3, headers = {}) {
47652
47665
  function asGatewayError(error51) {
47653
47666
  if (error51 instanceof GatewayError)
47654
47667
  return error51;
47655
- return new GatewayError("INTERNAL", error51 instanceof Error ? error51.message : "internal error");
47668
+ return new GatewayError("INTERNAL", describeError(error51, "internal error"));
47656
47669
  }
47657
47670
  function sseResponse(frames, onDone, keepaliveMs, source, limitHeaders, onFrame) {
47658
47671
  const encoder4 = new TextEncoder;
@@ -48141,7 +48154,7 @@ function createShutdown(deps) {
48141
48154
  }, (error51) => {
48142
48155
  clearTimeout(timer);
48143
48156
  deps.logger.error("shutdown failed", {
48144
- reason: error51 instanceof Error ? error51.message : "unknown"
48157
+ reason: describeError(error51, "unknown")
48145
48158
  });
48146
48159
  exitAfterClosingStore(1);
48147
48160
  });
@@ -48185,7 +48198,7 @@ function startMaintenance(deps) {
48185
48198
  const timer = setInterval(() => {
48186
48199
  pruneFiles(files).then(({ snapshots, staging }) => logger2.debug("snapshots and staging files swept", { count: snapshots + staging })).catch((error51) => {
48187
48200
  logger2.error("snapshot sweeping failed", {
48188
- reason: error51 instanceof Error ? error51.message : "unknown"
48201
+ reason: describeError(error51, "unknown")
48189
48202
  });
48190
48203
  });
48191
48204
  pruneLogs(deps.store, deps.now()).then(({ raw, daily, quotaSamples, bodies, bodiesOverCap, bodyOrphans }) => logger2.debug("request logs pruned", {
@@ -48195,7 +48208,7 @@ function startMaintenance(deps) {
48195
48208
  count: bodies + bodiesOverCap + bodyOrphans
48196
48209
  })).catch((error51) => {
48197
48210
  logger2.error("log pruning failed", {
48198
- reason: error51 instanceof Error ? error51.message : "unknown"
48211
+ reason: describeError(error51, "unknown")
48199
48212
  });
48200
48213
  });
48201
48214
  }, SWEEP_INTERVAL_MS);
@@ -48232,7 +48245,7 @@ async function sweep(deps) {
48232
48245
  provider: credential.provider,
48233
48246
  credentialId: credential.id,
48234
48247
  code,
48235
- reason: error51 instanceof Error ? error51.message : "unknown"
48248
+ reason: describeError(error51, "unknown")
48236
48249
  });
48237
48250
  }
48238
48251
  }
@@ -48247,7 +48260,7 @@ function startRefreshScheduler(deps) {
48247
48260
  running = true;
48248
48261
  sweep(deps).catch((error51) => {
48249
48262
  logger2.error("token refresh sweep failed", {
48250
- reason: error51 instanceof Error ? error51.message : "unknown"
48263
+ reason: describeError(error51, "unknown")
48251
48264
  });
48252
48265
  }).finally(() => {
48253
48266
  running = false;
@@ -48478,7 +48491,7 @@ function buildContext(deps) {
48478
48491
  };
48479
48492
  }
48480
48493
  function reason(error51) {
48481
- return error51 instanceof Error ? error51.message : String(error51);
48494
+ return describeError(error51, String(error51));
48482
48495
  }
48483
48496
  async function loadPlugins(deps) {
48484
48497
  const logger2 = deps.logger ?? noopLogger;
@@ -48598,7 +48611,7 @@ async function startQuotaPoller(deps) {
48598
48611
  running = true;
48599
48612
  poll(deps).catch((error51) => {
48600
48613
  logger2.error("quota poll failed", {
48601
- reason: error51 instanceof Error ? error51.message : "unknown"
48614
+ reason: describeError(error51, "unknown")
48602
48615
  });
48603
48616
  }).finally(() => {
48604
48617
  running = false;
@@ -48760,7 +48773,7 @@ try {
48760
48773
  await main();
48761
48774
  } catch (error51) {
48762
48775
  logger2.error("gateway boot failed", {
48763
- reason: error51 instanceof Error ? error51.message : "unknown"
48776
+ reason: describeError(error51, "unknown")
48764
48777
  });
48765
48778
  process.exit(1);
48766
48779
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnigateway",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "Self-hosted AI gateway with Anthropic- and OpenAI-compatible APIs, an admin console, and a CLI",
5
5
  "license": "MIT",
6
6
  "author": "Harismawan <mail@harismawan.com>",