omnigateway 0.12.3 → 0.12.5

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.
package/README.md CHANGED
@@ -332,7 +332,10 @@ changed without a restart: the six routing weights, `maxAttempts`,
332
332
  `ponytailMode` (`off` | `lite` | `full` | `ultra`),
333
333
  and the two body-capture switches. Edit them with `omni settings set` or in the
334
334
  console. `quotaPollIntervalMs` is the one exception: the poller reads it once at
335
- boot, so a change to it takes a restart. Snapshot retention —
335
+ boot, so a change to it takes a restart. `requestDeadlineMs` defaults to `0`,
336
+ which imposes no deadline at all; what that means for whatever sits in front of
337
+ the gateway is
338
+ [Behind a reverse proxy](docs/deploying.md#behind-a-reverse-proxy). Snapshot retention —
336
339
  `snapshotKeepLatest` and `snapshotMaxAgeDays` — is stored alongside them but
337
340
  deliberately edited on the Database screen instead; see
338
341
  [Snapshots and restore](docs/operations.md#snapshots-and-restore) for why.
package/bin/omni.js CHANGED
@@ -19590,9 +19590,16 @@ function memoryCoord(options = {}) {
19590
19590
  const now = options.now ?? (() => Date.now());
19591
19591
  const windows = new Map;
19592
19592
  const gauges = new Map;
19593
+ const named = (holder) => {
19594
+ if (holder === undefined)
19595
+ return;
19596
+ if (holder === "")
19597
+ throw new TypeError("gauge holder must be a non-empty string");
19598
+ return holder;
19599
+ };
19593
19600
  const liveSlots = (key) => {
19594
19601
  const at = now();
19595
- const held = (gauges.get(key) ?? []).filter((expiresAt) => expiresAt > at);
19602
+ const held = (gauges.get(key) ?? []).filter((slot) => slot.expiresAt > at);
19596
19603
  if (held.length === 0)
19597
19604
  gauges.delete(key);
19598
19605
  else
@@ -19647,18 +19654,45 @@ function memoryCoord(options = {}) {
19647
19654
  }
19648
19655
  },
19649
19656
  gauge: {
19650
- acquire(key, ttlMs) {
19657
+ acquire(key, ttlMs, rawHolder) {
19658
+ const holder = named(rawHolder);
19651
19659
  const held = liveSlots(key);
19660
+ const expiresAt = now() + ttlMs;
19661
+ const mine = holder === undefined ? -1 : held.findIndex((s) => s.holder === holder);
19662
+ if (mine !== -1 && holder !== undefined) {
19663
+ held[mine] = { expiresAt, holder };
19664
+ gauges.set(key, held);
19665
+ return Promise.resolve(held.length - 1);
19666
+ }
19652
19667
  const before = held.length;
19653
- held.push(now() + ttlMs);
19668
+ held.push(holder === undefined ? { expiresAt } : { expiresAt, holder });
19654
19669
  gauges.set(key, held);
19655
19670
  return Promise.resolve(before);
19656
19671
  },
19657
- release(key) {
19672
+ renew(key, holder, ttlMs) {
19673
+ named(holder);
19674
+ const held = liveSlots(key);
19675
+ const mine = held.findIndex((slot) => slot.holder === holder);
19676
+ if (mine !== -1) {
19677
+ held[mine] = { expiresAt: now() + ttlMs, holder };
19678
+ gauges.set(key, held);
19679
+ }
19680
+ return Promise.resolve();
19681
+ },
19682
+ release(key, holder) {
19683
+ named(holder);
19658
19684
  const held = liveSlots(key);
19659
- held.sort((x, y) => x - y).shift();
19685
+ if (holder === undefined) {
19686
+ held.sort((x, y) => x.expiresAt - y.expiresAt).shift();
19687
+ } else {
19688
+ const mine = held.findIndex((slot) => slot.holder === holder);
19689
+ if (mine !== -1)
19690
+ held.splice(mine, 1);
19691
+ }
19660
19692
  if (held.length === 0)
19661
19693
  gauges.delete(key);
19694
+ else
19695
+ gauges.set(key, held);
19662
19696
  return Promise.resolve();
19663
19697
  },
19664
19698
  read(key) {
@@ -21194,7 +21228,7 @@ var NODE_GRACE_MS = 60000;
21194
21228
  var DEFAULT_SETTINGS = {
21195
21229
  weights: { tier: 10, health: 3, quota: 2, load: 2, cost: 1, latency: 1 },
21196
21230
  maxAttempts: 3,
21197
- requestDeadlineMs: 120000,
21231
+ requestDeadlineMs: 0,
21198
21232
  breakerThreshold: 3,
21199
21233
  breakerCooldownMs: 30000,
21200
21234
  logRetentionDays: 30,
@@ -27707,12 +27741,29 @@ function closingTurn(contents, note2) {
27707
27741
  var hasCacheControl = (block) => ("cacheControl" in block) && block.cacheControl !== undefined;
27708
27742
  var PRUNED = "antigravity:tool-schema-pruned";
27709
27743
  var AGENT_PREAMBLE_DROPPED = "antigravity:agent-preamble-dropped";
27710
- function dropAgentPreamble(system, note2) {
27744
+ var BILLING_HEADER_DROPPED = "antigravity:billing-header-dropped";
27745
+ function dropFingerprints(system, note2) {
27711
27746
  const paragraphs = system.split(/(?:\r?\n){2,}/);
27712
- const kept = paragraphs.filter((p) => p.trim() !== AGENT_PREAMBLE);
27747
+ let preamble = false;
27748
+ let billing = false;
27749
+ const kept = paragraphs.filter((p) => {
27750
+ const trimmed = p.trim();
27751
+ if (trimmed === AGENT_PREAMBLE) {
27752
+ preamble = true;
27753
+ return false;
27754
+ }
27755
+ if (trimmed.startsWith(BILLING_PREFIX)) {
27756
+ billing = true;
27757
+ return false;
27758
+ }
27759
+ return true;
27760
+ });
27713
27761
  if (kept.length === paragraphs.length)
27714
27762
  return system;
27715
- note2(AGENT_PREAMBLE_DROPPED);
27763
+ if (preamble)
27764
+ note2(AGENT_PREAMBLE_DROPPED);
27765
+ if (billing)
27766
+ note2(BILLING_HEADER_DROPPED);
27716
27767
  return kept.join(`
27717
27768
 
27718
27769
  `);
@@ -28010,7 +28061,7 @@ function toAntigravityWire(req, model, identity) {
28010
28061
  contents: closingTurn(openingTurn(mergeSameRole(contents), note2), note2)
28011
28062
  };
28012
28063
  const joined = systemText(req.system, "antigravity", note2);
28013
- const system = joined === undefined ? undefined : dropAgentPreamble(joined, note2);
28064
+ const system = joined === undefined ? undefined : dropFingerprints(joined, note2);
28014
28065
  if (system !== undefined && system.trim().length > 0) {
28015
28066
  request2.systemInstruction = { parts: [{ text: system }] };
28016
28067
  }
@@ -37474,7 +37525,7 @@ function createServiceDeps(input2) {
37474
37525
  }
37475
37526
 
37476
37527
  // apps/cli/src/version.ts
37477
- var VERSION = "0.12.3";
37528
+ var VERSION = "0.12.5";
37478
37529
 
37479
37530
  // apps/cli/src/commands/service.ts
37480
37531
  function gatewayArgv(root) {
package/gateway.js CHANGED
@@ -24789,9 +24789,16 @@ function memoryCoord(options = {}) {
24789
24789
  const now = options.now ?? (() => Date.now());
24790
24790
  const windows = new Map;
24791
24791
  const gauges = new Map;
24792
+ const named = (holder) => {
24793
+ if (holder === undefined)
24794
+ return;
24795
+ if (holder === "")
24796
+ throw new TypeError("gauge holder must be a non-empty string");
24797
+ return holder;
24798
+ };
24792
24799
  const liveSlots = (key) => {
24793
24800
  const at = now();
24794
- const held = (gauges.get(key) ?? []).filter((expiresAt) => expiresAt > at);
24801
+ const held = (gauges.get(key) ?? []).filter((slot) => slot.expiresAt > at);
24795
24802
  if (held.length === 0)
24796
24803
  gauges.delete(key);
24797
24804
  else
@@ -24846,18 +24853,45 @@ function memoryCoord(options = {}) {
24846
24853
  }
24847
24854
  },
24848
24855
  gauge: {
24849
- acquire(key, ttlMs) {
24856
+ acquire(key, ttlMs, rawHolder) {
24857
+ const holder = named(rawHolder);
24850
24858
  const held = liveSlots(key);
24859
+ const expiresAt = now() + ttlMs;
24860
+ const mine = holder === undefined ? -1 : held.findIndex((s) => s.holder === holder);
24861
+ if (mine !== -1 && holder !== undefined) {
24862
+ held[mine] = { expiresAt, holder };
24863
+ gauges.set(key, held);
24864
+ return Promise.resolve(held.length - 1);
24865
+ }
24851
24866
  const before = held.length;
24852
- held.push(now() + ttlMs);
24867
+ held.push(holder === undefined ? { expiresAt } : { expiresAt, holder });
24853
24868
  gauges.set(key, held);
24854
24869
  return Promise.resolve(before);
24855
24870
  },
24856
- release(key) {
24871
+ renew(key, holder, ttlMs) {
24872
+ named(holder);
24857
24873
  const held = liveSlots(key);
24858
- held.sort((x, y) => x - y).shift();
24874
+ const mine = held.findIndex((slot) => slot.holder === holder);
24875
+ if (mine !== -1) {
24876
+ held[mine] = { expiresAt: now() + ttlMs, holder };
24877
+ gauges.set(key, held);
24878
+ }
24879
+ return Promise.resolve();
24880
+ },
24881
+ release(key, holder) {
24882
+ named(holder);
24883
+ const held = liveSlots(key);
24884
+ if (holder === undefined) {
24885
+ held.sort((x, y) => x.expiresAt - y.expiresAt).shift();
24886
+ } else {
24887
+ const mine = held.findIndex((slot) => slot.holder === holder);
24888
+ if (mine !== -1)
24889
+ held.splice(mine, 1);
24890
+ }
24859
24891
  if (held.length === 0)
24860
24892
  gauges.delete(key);
24893
+ else
24894
+ gauges.set(key, held);
24861
24895
  return Promise.resolve();
24862
24896
  },
24863
24897
  read(key) {
@@ -26626,7 +26660,7 @@ var NODE_GRACE_MS = 60000;
26626
26660
  var DEFAULT_SETTINGS = {
26627
26661
  weights: { tier: 10, health: 3, quota: 2, load: 2, cost: 1, latency: 1 },
26628
26662
  maxAttempts: 3,
26629
- requestDeadlineMs: 120000,
26663
+ requestDeadlineMs: 0,
26630
26664
  breakerThreshold: 3,
26631
26665
  breakerCooldownMs: 30000,
26632
26666
  logRetentionDays: 30,
@@ -33269,12 +33303,29 @@ function closingTurn(contents, note) {
33269
33303
  var hasCacheControl = (block) => ("cacheControl" in block) && block.cacheControl !== undefined;
33270
33304
  var PRUNED = "antigravity:tool-schema-pruned";
33271
33305
  var AGENT_PREAMBLE_DROPPED = "antigravity:agent-preamble-dropped";
33272
- function dropAgentPreamble(system, note) {
33306
+ var BILLING_HEADER_DROPPED = "antigravity:billing-header-dropped";
33307
+ function dropFingerprints(system, note) {
33273
33308
  const paragraphs = system.split(/(?:\r?\n){2,}/);
33274
- const kept = paragraphs.filter((p) => p.trim() !== AGENT_PREAMBLE);
33309
+ let preamble = false;
33310
+ let billing = false;
33311
+ const kept = paragraphs.filter((p) => {
33312
+ const trimmed = p.trim();
33313
+ if (trimmed === AGENT_PREAMBLE) {
33314
+ preamble = true;
33315
+ return false;
33316
+ }
33317
+ if (trimmed.startsWith(BILLING_PREFIX)) {
33318
+ billing = true;
33319
+ return false;
33320
+ }
33321
+ return true;
33322
+ });
33275
33323
  if (kept.length === paragraphs.length)
33276
33324
  return system;
33277
- note(AGENT_PREAMBLE_DROPPED);
33325
+ if (preamble)
33326
+ note(AGENT_PREAMBLE_DROPPED);
33327
+ if (billing)
33328
+ note(BILLING_HEADER_DROPPED);
33278
33329
  return kept.join(`
33279
33330
 
33280
33331
  `);
@@ -33572,7 +33623,7 @@ function toAntigravityWire(req, model, identity) {
33572
33623
  contents: closingTurn(openingTurn(mergeSameRole(contents), note), note)
33573
33624
  };
33574
33625
  const joined = systemText(req.system, "antigravity", note);
33575
- const system = joined === undefined ? undefined : dropAgentPreamble(joined, note);
33626
+ const system = joined === undefined ? undefined : dropFingerprints(joined, note);
33576
33627
  if (system !== undefined && system.trim().length > 0) {
33577
33628
  request2.systemInstruction = { parts: [{ text: system }] };
33578
33629
  }
@@ -54861,6 +54912,8 @@ var LONG_WINDOWS = ["5h", "1w"];
54861
54912
  var GRAIN_MS = { "5h": 60000, "1w": 3600000 };
54862
54913
  var SEED_LOCK_MS = 5000;
54863
54914
  var GAUGE_TTL_MS = 300000;
54915
+ var RENEW_INTERVAL_MS = 1e5;
54916
+ var MAX_RENEWED_MS = 86400000;
54864
54917
  function bucketKey(keyId, window2) {
54865
54918
  return `lim:${keyId}:${window2}`;
54866
54919
  }
@@ -54919,10 +54972,11 @@ class ApiKeyRateLimiter {
54919
54972
  }
54920
54973
  async admit(keyId, limits, requestId) {
54921
54974
  if (!anyLimit(limits))
54922
- return { release: () => {}, headroom: {} };
54975
+ return { release: () => {}, renew: async () => {}, headroom: {} };
54923
54976
  const now = this.now();
54924
54977
  this.limits.set(keyId, limits);
54925
- const claim2 = await this.claim(keyId, now, true);
54978
+ const holder = configured(limits.concurrency) ? crypto.randomUUID() : undefined;
54979
+ const claim2 = await this.claim(keyId, now, true, holder);
54926
54980
  let admitted = false;
54927
54981
  try {
54928
54982
  const counters = await this.counters(keyId, limits, claim2, now, requestId);
@@ -54930,13 +54984,29 @@ class ApiKeyRateLimiter {
54930
54984
  await this.refuse(keyId, decision, now, requestId);
54931
54985
  admitted = true;
54932
54986
  let released = false;
54987
+ const renewUntil = now + MAX_RENEWED_MS;
54988
+ const renew = async () => {
54989
+ if (released || holder === undefined)
54990
+ return;
54991
+ await this.coord.gauge.renew(keyId, holder, GAUGE_TTL_MS);
54992
+ };
54993
+ const renewal = holder === undefined ? null : setInterval(() => {
54994
+ if (this.now() >= renewUntil) {
54995
+ clearInterval(renewal ?? undefined);
54996
+ return;
54997
+ }
54998
+ renew();
54999
+ }, RENEW_INTERVAL_MS);
55000
+ renewal?.unref?.();
54933
55001
  const release = () => {
54934
55002
  if (released)
54935
55003
  return;
54936
55004
  released = true;
54937
- this.coord.gauge.release(keyId);
55005
+ if (renewal !== null)
55006
+ clearInterval(renewal);
55007
+ this.coord.gauge.release(keyId, holder);
54938
55008
  };
54939
- return { release, headroom: decision.headroom };
55009
+ return { release, renew, headroom: decision.headroom };
54940
55010
  } finally {
54941
55011
  if (!admitted)
54942
55012
  await this.rollback(keyId, claim2);
@@ -54959,15 +55029,15 @@ class ApiKeyRateLimiter {
54959
55029
  await this.rollback(keyId, claim2);
54960
55030
  }
54961
55031
  }
54962
- async claim(keyId, now, gauge) {
55032
+ async claim(keyId, now, gauge, holder) {
54963
55033
  const ring = await this.coord.window.claim(keyId, WINDOW_MS["1m"], now);
54964
- const concurrency = gauge ? await this.coord.gauge.acquire(keyId, GAUGE_TTL_MS) : await this.coord.gauge.read(keyId);
54965
- return { stamp: ring.stamp, gauge, before: { requests: ring.before, concurrency } };
55034
+ const concurrency = gauge ? await this.coord.gauge.acquire(keyId, GAUGE_TTL_MS, holder) : await this.coord.gauge.read(keyId);
55035
+ return { stamp: ring.stamp, gauge, holder, before: { requests: ring.before, concurrency } };
54966
55036
  }
54967
55037
  async rollback(keyId, claim2) {
54968
55038
  await this.coord.window.rollback(keyId, claim2.stamp);
54969
55039
  if (claim2.gauge)
54970
- await this.coord.gauge.release(keyId);
55040
+ await this.coord.gauge.release(keyId, claim2.holder);
54971
55041
  }
54972
55042
  debit(keyId, usage) {
54973
55043
  const limits = this.limits.get(keyId);
@@ -55094,6 +55164,8 @@ function withReset(headroom, window2, resetAt) {
55094
55164
  // apps/gateway/src/dispatch/loadRegistry.ts
55095
55165
  var PREFIX6 = "load:";
55096
55166
  var SLOT_TTL_MS = 300000;
55167
+ var RENEW_INTERVAL_MS2 = 1e5;
55168
+ var MAX_RENEWED_MS2 = 86400000;
55097
55169
  var EWMA_ALPHA = 0.3;
55098
55170
  function createLoadRegistry(coord = memoryCoord(), now = Date.now) {
55099
55171
  const local = new Map;
@@ -55106,12 +55178,23 @@ function createLoadRegistry(coord = memoryCoord(), now = Date.now) {
55106
55178
  local.set(key, (local.get(key) ?? 0) + 1);
55107
55179
  if (provider !== undefined)
55108
55180
  providers.set(provider, (providers.get(provider) ?? 0) + 1);
55109
- coord.gauge.acquire(PREFIX6 + key, SLOT_TTL_MS);
55181
+ const holder = crypto.randomUUID();
55182
+ coord.gauge.acquire(PREFIX6 + key, SLOT_TTL_MS, holder);
55183
+ const renewUntil = now() + MAX_RENEWED_MS2;
55184
+ const renewal = setInterval(() => {
55185
+ if (now() >= renewUntil) {
55186
+ clearInterval(renewal);
55187
+ return;
55188
+ }
55189
+ coord.gauge.renew(PREFIX6 + key, holder, SLOT_TTL_MS);
55190
+ }, RENEW_INTERVAL_MS2);
55191
+ renewal.unref?.();
55110
55192
  let released = false;
55111
55193
  return (ttftMs) => {
55112
55194
  if (released)
55113
55195
  return;
55114
55196
  released = true;
55197
+ clearInterval(renewal);
55115
55198
  const prior = history.get(key)?.ewmaTtftMs ?? null;
55116
55199
  history.set(key, {
55117
55200
  lastReleasedAt: now(),
@@ -55129,7 +55212,7 @@ function createLoadRegistry(coord = memoryCoord(), now = Date.now) {
55129
55212
  else
55130
55213
  providers.delete(provider);
55131
55214
  }
55132
- coord.gauge.release(PREFIX6 + key);
55215
+ coord.gauge.release(PREFIX6 + key, holder);
55133
55216
  };
55134
55217
  },
55135
55218
  counts() {
@@ -62302,7 +62385,7 @@ function createRing(limits = DEFAULT_RING_LIMITS) {
62302
62385
  }
62303
62386
 
62304
62387
  // apps/gateway/src/version.ts
62305
- var VERSION = "0.12.3";
62388
+ var VERSION = "0.12.5";
62306
62389
 
62307
62390
  // apps/gateway/src/app.ts
62308
62391
  var ADMIN_SESSION_TTL_MS = 12 * 60 * 60 * 1000;
@@ -62580,19 +62663,35 @@ var WINDOW_ROLLBACK = `
62580
62663
  `;
62581
62664
  var GAUGE_ACQUIRE = `
62582
62665
  redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
62666
+ local mine = redis.call('ZSCORE', KEYS[1], ARGV[3])
62583
62667
  local before = redis.call('ZCARD', KEYS[1])
62668
+ if mine then before = before - 1 end
62584
62669
  redis.call('ZADD', KEYS[1], tonumber(ARGV[1]) + tonumber(ARGV[2]), ARGV[3])
62585
- redis.call('PEXPIRE', KEYS[1], ARGV[2])
62670
+ if redis.call('PTTL', KEYS[1]) < tonumber(ARGV[2]) then
62671
+ redis.call('PEXPIRE', KEYS[1], ARGV[2])
62672
+ end
62586
62673
  redis.call('SADD', KEYS[2], KEYS[1])
62587
62674
  return before
62588
62675
  `;
62676
+ var GAUGE_RENEW = `
62677
+ redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
62678
+ redis.call('ZADD', KEYS[1], 'XX', tonumber(ARGV[1]) + tonumber(ARGV[2]), ARGV[3])
62679
+ if redis.call('PTTL', KEYS[1]) < tonumber(ARGV[2]) then
62680
+ redis.call('PEXPIRE', KEYS[1], ARGV[2])
62681
+ end
62682
+ return 0
62683
+ `;
62589
62684
  var GAUGE_READ = `
62590
62685
  redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
62591
62686
  return redis.call('ZCARD', KEYS[1])
62592
62687
  `;
62593
62688
  var GAUGE_RELEASE = `
62594
62689
  redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
62595
- redis.call('ZPOPMIN', KEYS[1])
62690
+ if ARGV[2] == '' then
62691
+ redis.call('ZPOPMIN', KEYS[1])
62692
+ else
62693
+ redis.call('ZREM', KEYS[1], ARGV[2])
62694
+ end
62596
62695
  return 0
62597
62696
  `;
62598
62697
  var GAUGE_SNAPSHOT = `
@@ -62601,8 +62700,10 @@ var GAUGE_SNAPSHOT = `
62601
62700
  redis.call('ZREMRANGEBYSCORE', key, '-inf', ARGV[1])
62602
62701
  local count = redis.call('ZCARD', key)
62603
62702
  if count > 0 then
62604
- out[#out + 1] = key
62605
- out[#out + 1] = count
62703
+ if string.sub(key, 1, string.len(ARGV[2])) == ARGV[2] then
62704
+ out[#out + 1] = key
62705
+ out[#out + 1] = count
62706
+ end
62606
62707
  else
62607
62708
  redis.call('SREM', KEYS[1], key)
62608
62709
  end
@@ -62667,6 +62768,7 @@ var SCRIPTS = [
62667
62768
  WINDOW_CLAIM,
62668
62769
  WINDOW_ROLLBACK,
62669
62770
  GAUGE_ACQUIRE,
62771
+ GAUGE_RENEW,
62670
62772
  GAUGE_READ,
62671
62773
  GAUGE_RELEASE,
62672
62774
  GAUGE_SNAPSHOT,
@@ -62701,6 +62803,10 @@ function redisCoord(deps) {
62701
62803
  const colon = name.indexOf(":");
62702
62804
  return `${NS}gidx:${colon === -1 ? name : name.slice(0, colon + 1)}`;
62703
62805
  };
62806
+ const blankHolder = (holder) => {
62807
+ if (holder === "")
62808
+ throw new TypeError("gauge holder must be a non-empty string");
62809
+ };
62704
62810
  let faults = 0;
62705
62811
  const fault = (error62) => {
62706
62812
  healthy = false;
@@ -62836,20 +62942,28 @@ function redisCoord(deps) {
62836
62942
  }
62837
62943
  },
62838
62944
  gauge: {
62839
- acquire(name, ttlMs) {
62840
- return attempt2(async () => await evalScript(GAUGE_ACQUIRE, [key("g", name), indexOf2(name)], [now(), ttlMs, crypto.randomUUID()]), () => fallback.gauge.acquire(name, ttlMs));
62945
+ acquire(name, ttlMs, holder) {
62946
+ blankHolder(holder);
62947
+ return attempt2(async () => await evalScript(GAUGE_ACQUIRE, [key("g", name), indexOf2(name)], [now(), ttlMs, holder ?? crypto.randomUUID()]), () => fallback.gauge.acquire(name, ttlMs, holder));
62948
+ },
62949
+ renew(name, holder, ttlMs) {
62950
+ blankHolder(holder);
62951
+ return attempt2(async () => {
62952
+ await evalScript(GAUGE_RENEW, [key("g", name)], [now(), ttlMs, holder]);
62953
+ }, () => fallback.gauge.renew(name, holder, ttlMs));
62841
62954
  },
62842
- release(name) {
62955
+ release(name, holder) {
62956
+ blankHolder(holder);
62843
62957
  return attempt2(async () => {
62844
- await evalScript(GAUGE_RELEASE, [key("g", name)], [now()]);
62845
- }, () => fallback.gauge.release(name));
62958
+ await evalScript(GAUGE_RELEASE, [key("g", name)], [now(), holder ?? ""]);
62959
+ }, () => fallback.gauge.release(name, holder));
62846
62960
  },
62847
62961
  read(name) {
62848
62962
  return attempt2(async () => await evalScript(GAUGE_READ, [key("g", name)], [now()]), () => fallback.gauge.read(name));
62849
62963
  },
62850
62964
  snapshot(prefix2) {
62851
62965
  return attempt2(async () => {
62852
- const flat = await evalScript(GAUGE_SNAPSHOT, [indexOf2(prefix2)], [now()]);
62966
+ const flat = await evalScript(GAUGE_SNAPSHOT, [indexOf2(prefix2)], [now(), key("g", prefix2)]);
62853
62967
  const out = new Map;
62854
62968
  for (let i = 0;i + 1 < flat.length; i += 2) {
62855
62969
  out.set(String(flat[i]).slice(key("g", "").length), Number(flat[i + 1]));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnigateway",
3
- "version": "0.12.3",
3
+ "version": "0.12.5",
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>",