@urun-sh/openai 0.5.5 → 0.6.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 (56) hide show
  1. package/dist/{ResponsesClient-BYx3YLGo.d.ts → ResponsesClient-CSSrOYD8.d.ts} +7 -1
  2. package/dist/{ResponsesClient-Dft3bg3b.d.cts → ResponsesClient-_OZERUjH.d.cts} +11 -1
  3. package/dist/chunk-3JWYIKHM.js +2 -0
  4. package/dist/chunk-45FJ5GTP.js +7 -0
  5. package/dist/chunk-6M5JK4YC.js +1 -0
  6. package/dist/chunk-QTVTCMJU.js +1 -0
  7. package/dist/chunk-TDRZZGUK.js +1 -0
  8. package/dist/chunk-TPH77ZOW.js +58 -0
  9. package/dist/chunk-WCMX5VOF.js +4 -0
  10. package/dist/chunk-YXK42SKC.js +1 -0
  11. package/dist/gemini-live.cjs +2 -2
  12. package/dist/gemini-live.d.cts +79 -7
  13. package/dist/gemini-live.d.ts +32 -7
  14. package/dist/gemini-live.js +1 -1
  15. package/dist/hosted/bin.cjs +43 -27
  16. package/dist/hosted/bin.js +4 -4
  17. package/dist/hosted/index.cjs +41 -26
  18. package/dist/hosted/index.d.cts +710 -17
  19. package/dist/hosted/index.d.ts +171 -6
  20. package/dist/hosted/index.js +1 -1
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.d.cts +5 -5
  23. package/dist/index.d.ts +5 -5
  24. package/dist/index.js +1 -1
  25. package/dist/{models-NYMZrklp.d.cts → models-DUdx_Y6X.d.cts} +1 -1
  26. package/dist/pi-extension/index.cjs +7 -7
  27. package/dist/pi-extension/index.d.cts +2 -2
  28. package/dist/pi-extension/index.d.ts +2 -2
  29. package/dist/pi-extension/index.js +1 -1
  30. package/dist/pi-extension/standalone.cjs +53 -53
  31. package/dist/proxy/cli.cjs +55 -43
  32. package/dist/proxy/cli.js +14 -13
  33. package/dist/proxy/index.cjs +31 -28
  34. package/dist/proxy/index.d.cts +132 -18
  35. package/dist/proxy/index.d.ts +28 -11
  36. package/dist/proxy/index.js +1 -6
  37. package/dist/responses-turn-BfdBbey8.d.cts +2394 -0
  38. package/dist/responses-turn-CdhIre_a.d.ts +652 -0
  39. package/dist/{translator-CcDBEfvm.d.cts → translator-CO8W_hmJ.d.cts} +3 -3
  40. package/dist/{translator-C9uPKypK.d.ts → translator-Ddd65sXR.d.ts} +1 -1
  41. package/dist/{types-lsVTbNcH.d.cts → types-CHPtJx6d.d.cts} +13 -0
  42. package/dist/{types-lsVTbNcH.d.ts → types-CHPtJx6d.d.ts} +4 -0
  43. package/dist/{video-out-D20UuJ8G.d.cts → video-out-BsuLqlID.d.cts} +6 -6
  44. package/dist/{video-out-CWesbk12.d.ts → video-out-Cawtm7SF.d.ts} +1 -1
  45. package/package.json +14 -11
  46. package/dist/chunk-5BZCM3RS.js +0 -4
  47. package/dist/chunk-5NXM4IO3.js +0 -2
  48. package/dist/chunk-CWJRDBDC.js +0 -1
  49. package/dist/chunk-DMD5UENK.js +0 -1
  50. package/dist/chunk-GBBY3PCZ.js +0 -1
  51. package/dist/chunk-I2Q3B3OG.js +0 -6
  52. package/dist/chunk-OI2OY32M.js +0 -1
  53. package/dist/chunk-QVF7NF7G.js +0 -44
  54. package/dist/responses-turn-KOAoIqZ-.d.ts +0 -200
  55. package/dist/responses-turn-OrO4euEN.d.cts +0 -513
  56. /package/dist/{models-NYMZrklp.d.ts → models-DUdx_Y6X.d.ts} +0 -0
@@ -1,10 +1,147 @@
1
1
  import { Server } from 'node:http';
2
+ import * as _prometheus_io_client from '@prometheus-io/client';
3
+ import { Registry } from '@prometheus-io/client';
4
+ import { c as LedgerOutcome, I as InferenceRecord, S as SessionGoneError, P as ProxyClients, M as ModelRouter, i as UsageRowReporter, b as InferenceUsageRecord, e as LedgerWrite, d as LedgerRecorded, L as LedgerFailure } from '../responses-turn-BfdBbey8.cjs';
2
5
  import { createClientToken } from '@urun-sh/core';
3
- import { U as UrunResponses } from '../ResponsesClient-Dft3bg3b.cjs';
4
- import { b as UrunSessionLike } from '../types-lsVTbNcH.cjs';
5
- import { S as SessionGoneError, P as ProxyClients, M as ModelRouter } from '../responses-turn-OrO4euEN.cjs';
6
- import '../models-NYMZrklp.cjs';
7
- import '../video-out-D20UuJ8G.cjs';
6
+ import { U as UrunResponses } from '../ResponsesClient-_OZERUjH.cjs';
7
+ import { b as UrunSessionLike } from '../types-CHPtJx6d.cjs';
8
+ import '../models-DUdx_Y6X.cjs';
9
+ import '../video-out-BsuLqlID.cjs';
10
+
11
+ /**
12
+ * The container's metrics port — a MODULE CONSTANT, not an env var, per the
13
+ * hosted config mandate (`hosted/config.ts`: "env vars are NOT a config
14
+ * mechanism"). 9464 is the Prometheus exporter port the OpenTelemetry
15
+ * ecosystem registered, and it is the interface contract the deployment chart
16
+ * and its ServiceMonitor are built against.
17
+ *
18
+ * PRIVATE, and private STRUCTURALLY rather than by convention: the public
19
+ * HTTPRoute allowlist (`k8s-manifests` `_public-matches.tpl`) routes only
20
+ * `/v1` to the Service's 8080 port, so nothing on this port is reachable from
21
+ * the internet. It is served by its OWN `http.Server`
22
+ * ({@link createMetricsServer}) rather than as a route on the main server, so
23
+ * a future public path can never accidentally expose it.
24
+ */
25
+ declare const METRICS_PORT = 9464;
26
+ /** The path the ServiceMonitor scrapes. */
27
+ declare const METRICS_PATH = "/metrics";
28
+ /** The label value every bounded label collapses to once its budget is spent. */
29
+ declare const OTHER_LABEL = "(other)";
30
+ /** The label value for a request that named no model. */
31
+ declare const NO_MODEL_LABEL = "(none)";
32
+ /**
33
+ * Distinct `model` values that get their own series. Above this the label
34
+ * collapses to {@link OTHER_LABEL} — a caller sending a fresh random model
35
+ * string per request must not be able to grow this process's series set (and
36
+ * therefore Prometheus's) without bound.
37
+ */
38
+ declare const MAX_MODEL_LABELS = 64;
39
+ /**
40
+ * Distinct `org` values that get their own series. Bounded for the same reason
41
+ * even though org ids come from the control plane rather than the caller: the
42
+ * number of orgs is unbounded over time, and a metric's cardinality must be a
43
+ * property of the code, not of how successful sales were.
44
+ */
45
+ declare const MAX_ORG_LABELS = 128;
46
+ /** Collapse a client-supplied path onto the bounded lane label. */
47
+ declare function laneOf(path: string): string;
48
+ /**
49
+ * The status class label. `none` is its own class rather than being folded
50
+ * into 5xx: it means NO head ever flushed (an aborted upload, a client that
51
+ * vanished during the body read), which `inferenceRequestRecord` records as a
52
+ * null status precisely so nothing downstream invents a 200 the client was
53
+ * never sent.
54
+ */
55
+ declare function statusClassOf(status: number | null): string;
56
+ /**
57
+ * A label whose distinct-value budget is FIXED at construction. The first
58
+ * `max` distinct values are ADMITTED; everything after is {@link OTHER_LABEL},
59
+ * permanently. Deliberately NOT an LRU: an LRU would let a flooding caller
60
+ * evict the real models and quietly rewrite history in the TSDB, where each
61
+ * admitted-then-evicted-then-readmitted value leaves a broken series behind.
62
+ *
63
+ * ADMISSION IS EARNED, AND THAT IS THE WHOLE DEFENCE. A budget alone does not
64
+ * protect anything: one authenticated caller sending `MAX_MODEL_LABELS`
65
+ * requests naming random models — every one of them answered 404, because an
66
+ * unknown model is refused — would spend the entire budget and collapse every
67
+ * REAL model onto `(other)` until the pod restarts. That kills the per-model
68
+ * TTFT and rate panels, which are exactly the two the Hugging Face latency
69
+ * gate is read from. So a value is admitted only when `admit` is true, and the
70
+ * caller passes `admit` for answers that were actually served; a refusal can
71
+ * still be COUNTED (under `(other)`) but can never consume budget.
72
+ */
73
+ declare class BoundedLabel {
74
+ private readonly max;
75
+ private readonly admitted;
76
+ private overflows;
77
+ constructor(max: number);
78
+ /**
79
+ * @param admit whether this observation may spend budget on a new value.
80
+ * False for refused requests, so a caller cannot blind the label by naming
81
+ * models that do not exist.
82
+ */
83
+ of(value: string | null, admit?: boolean): string;
84
+ /** Distinct values admitted so far — published as a gauge (see below). */
85
+ get size(): number;
86
+ /** Admissible observations refused because the budget was spent. */
87
+ get overflowCount(): number;
88
+ }
89
+ /**
90
+ * The hosted proxy's metric set, over its OWN {@link Registry} rather than the
91
+ * library's global `register`. Per-instance because the alternative is
92
+ * process-global mutable state that two tests (or two embedders) silently
93
+ * share — `Counter` construction on an already-registered name throws, so a
94
+ * global registry would make the second `createHostedProxy` in a process fail.
95
+ */
96
+ declare class InferenceMetrics {
97
+ readonly registry: Registry<_prometheus_io_client.RegistryContentType>;
98
+ private readonly modelLabel;
99
+ private readonly orgLabel;
100
+ private readonly requests;
101
+ private readonly duration;
102
+ private readonly ttft;
103
+ private readonly streamErrors;
104
+ private readonly undelivered;
105
+ private readonly ledgerWrites;
106
+ private readonly ledgerQueue;
107
+ private readonly labelCardinality;
108
+ private readonly labelOverflows;
109
+ constructor(options?: {
110
+ defaultMetrics?: boolean;
111
+ });
112
+ /**
113
+ * Count ONE terminal ledger outcome — the third sink for a request that
114
+ * `proxy/ledger.ts` already logs, counted so it can be alerted on.
115
+ *
116
+ * Takes the very {@link LedgerOutcome} the log line carries, for the same
117
+ * reason {@link observe} takes the record verbatim: a counter derived from a
118
+ * second walk would eventually disagree with the billing log, and the
119
+ * disagreement would be invisible.
120
+ */
121
+ observeLedger(outcome: LedgerOutcome): void;
122
+ /**
123
+ * Count ONE completed `/v1` request. Takes the very record
124
+ * `inferenceRequestLine` serializes, so the counters and the billing log can
125
+ * never drift apart.
126
+ */
127
+ observe(record: InferenceRecord): void;
128
+ /** The exposition text a scrape answers with. */
129
+ scrape(): Promise<string>;
130
+ /** The `Content-Type` that exposition must be served under. */
131
+ get contentType(): string;
132
+ }
133
+ /**
134
+ * The PRIVATE metrics listener — its own `http.Server` on
135
+ * {@link METRICS_PORT}, serving exactly `GET /metrics` and 404 for everything
136
+ * else.
137
+ *
138
+ * A SEPARATE SERVER, not a route on the main one, is the whole point: the
139
+ * public gateway forwards only to the main port, so "not public" is a property
140
+ * of the socket rather than a rule the `/v1` router has to keep remembering.
141
+ * It also means a scrape can still be answered while the main server is
142
+ * draining, which is exactly when the numbers matter most.
143
+ */
144
+ declare function createMetricsServer(metrics: InferenceMetrics): Server;
8
145
 
9
146
  /**
10
147
  * HOSTED AUTH — the Bearer key IS the identity AND the tenancy.
@@ -128,17 +265,24 @@ declare class OrgResolver {
128
265
  * `consecutiveFailures` resets on every healthy sync, so a recovered
129
266
  * blip never trips this.
130
267
  *
131
- * 2. Core Session's own phase surface (`Session.onPhase` → 'paused' /
132
- * 'error') — the compute binding the pool already tracks (the same signal
133
- * cli.ts `onSessionEnd` rides).
268
+ * Core Session's own phase surface (`Session.onPhase` → 'live' /
269
+ * 'paused' / 'error'). The verdict arms ONLY on a `live` sighting: a
270
+ * binding must EXIST before it can be lost. A session born into its
271
+ * pre-live wait (the cold wake) or re-attached in `error` (resume runs
272
+ * the function from the top, session-semantics.md) is ACQUIRING
273
+ * compute, never losing it — core's own whenLive gate treats both as
274
+ * WAITABLE, and the unguarded latch 502-looped every shared chat/agent
275
+ * model on exactly those sightings (prod 2026-09-14: the entry was
276
+ * evicted before it ever served, and "retry to get a fresh session"
277
+ * re-dialed into the same verdict forever).
134
278
  *
135
- * NOTE what "gone" means HERE, because it is narrower than it reads: this
136
- * pool holds a session with COMPUTE BOUND to it, and a `paused` phase says
137
- * that binding is gone. The session ITSELF is not gone — it is parked,
138
- * listed, and attachable by name (see
139
- * urun-python/docs/design/session-semantics.md). The eviction is correct
140
- * because the POOL ENTRY is what became unusable; nothing here is entitled
141
- * to conclude the session is over.
279
+ * NOTE what "gone" means HERE, because it is narrower than it reads:
280
+ * this pool holds a session with COMPUTE BOUND to it, and a post-live
281
+ * `paused` phase says that binding is gone. The session ITSELF is not
282
+ * gone — it is parked, listed, and attachable by name (see
283
+ * urun-python/docs/design/session-semantics.md). The eviction is
284
+ * correct because the POOL ENTRY is what became unusable; nothing here
285
+ * is entitled to conclude the session is over.
142
286
  *
143
287
  * Consumers (cli.ts):
144
288
  * - {@link watchSessionGone} per pooled entry; `onGone` → `router.evict`
@@ -220,6 +364,19 @@ type OwnedSession = UrunSessionLike & {
220
364
  name: string;
221
365
  reason?: string;
222
366
  }) => void) => () => void;
367
+ whenLive?: (options?: {
368
+ timeout?: number;
369
+ signal?: AbortSignal;
370
+ }) => Promise<void>;
371
+ /**
372
+ * Core's NATIVE admission-ticket cancel (`Session.cancel`): hands back the
373
+ * claim a still-QUEUED call waits on — once the call HAS a session, the
374
+ * installed handler refuses loudly. Optional here because only the
375
+ * client-gone abandon path requires it; that path falls back to the native
376
+ * `detach` when a session object lacks it (the queued shape does not exist
377
+ * there), and never approximates with `end()`.
378
+ */
379
+ cancel?: () => Promise<unknown>;
223
380
  };
224
381
  /**
225
382
  * One pooled backhaul: the session, its (stateful) Responses client, and the
@@ -301,6 +458,24 @@ interface TenantRegistryOptions {
301
458
  apiUrl: string;
302
459
  /** The model-catalog oracle for routing rule 5, or null. */
303
460
  catalog: CatalogConfig | null;
461
+ /**
462
+ * THE STATELESS DIRECT PATH (urun-ts #497): present ⇒ every tenant's
463
+ * clients carry a per-caller decision dial — discovery over the CALLER'S
464
+ * own key (`GET {apiUrl}/runtimes`), tokens minted with the caller's
465
+ * org/app/fn, the flat body POSTed to the ready runtime's `:8099/v1/decision`.
466
+ * `shared` (the shared org's API key, when mounted) extends the same dial
467
+ * to SHARED-catalog models: discovery under the shared key, the token's
468
+ * `tenant` stays the caller and `provider` names the pod org from the
469
+ * block's `shared_org_id` (the intake's provider-aware org gate). Absent
470
+ * ⇒ shared models keep the session dial. Absent ⇒ no dial exists and every
471
+ * decision rides the session lane byte-for-byte.
472
+ */
473
+ decisionIntake?: {
474
+ secret: string;
475
+ shared?: {
476
+ apiKey: string;
477
+ };
478
+ };
304
479
  /** Injected in tests; production builds real uRun backhauls. */
305
480
  build?: (caller: CallerIdentity) => {
306
481
  router: ModelRouter<PoolEntry>;
@@ -319,6 +494,24 @@ declare class TenantRegistry {
319
494
  /** Insertion-ordered = LRU order, because a hit re-inserts at the end. */
320
495
  private readonly tenants;
321
496
  constructor(opts: TenantRegistryOptions);
497
+ /**
498
+ * THE NON-SECRET TENANCY LABEL, attached by the REGISTRY rather than by
499
+ * whichever builder produced the backhaul.
500
+ *
501
+ * The caller's org id is what the per-request record and the Prometheus
502
+ * series are broken down by (`proxy/responses-turn.ts` `ProxyClients.tenant`)
503
+ * — never `caller.apiKey`, which is the credential on this surface and would
504
+ * become a credential on every dashboard. Attaching it here means a backhaul
505
+ * can never come back unlabelled because a builder forgot.
506
+ *
507
+ * `Object.create`, not a mutation and not a spread: the source object keeps
508
+ * its identity and its prototype (so a class-based `ProxyClients` keeps its
509
+ * methods), and no other caller's backhaul is touched. Done ONCE per tenant,
510
+ * at build time — the returned object is then cached and reused for every
511
+ * later request from that key, which matters because the `/v1/responses`
512
+ * thread store is keyed on this very object identity.
513
+ */
514
+ private label;
322
515
  private build;
323
516
  /** The backhaul for THIS caller, opened on first use and reused after. */
324
517
  clientsFor(caller: CallerIdentity): ProxyClients;
@@ -443,6 +636,243 @@ declare class ConversationBackhauls {
443
636
  detachAll(): Promise<void>;
444
637
  }
445
638
 
639
+ /**
640
+ * THE HOSTED USAGE READ — the control-plane half of the canonical usage lane.
641
+ *
642
+ * The proxy holds no database credential and no standing platform secret
643
+ * (hosted/auth.ts). So the ledger read rides the CALLER'S OWN org API key to
644
+ * the control plane's `inference-usage` edge function — the same mechanism and
645
+ * the same credential `TenantRegistry` uses for `GET {apiUrl}/apps` — and the
646
+ * control plane derives the org from that key server-side and runs the
647
+ * org-scoped `urun_inference_usage_lookup` RPC.
648
+ *
649
+ * THAT IS WHY THIS LANE DOES NOT PRE-VERIFY THE KEY WITH `OrgResolver`. The
650
+ * surface that owns the data authenticates the key itself, so a second
651
+ * verification here would be a second source of truth about the same
652
+ * credential — and the org binding it produced would not be the one the read
653
+ * was actually scoped by. `bearerFrom` still runs at the call site, so a
654
+ * missing or malformed Authorization header is a loud 401 without a round trip.
655
+ *
656
+ * EVERY FAILURE IS LOUD. There is no shape of failure that answers with an
657
+ * empty `requests` list, because "we hold nothing for these ids" is precisely
658
+ * the answer that makes a billing caller stop asking — Hugging Face writes a
659
+ * request off ~30 minutes after it was served — so an outage that could wear
660
+ * that costume would be an invisible revenue hole.
661
+ */
662
+
663
+ interface UsageClientOptions {
664
+ /** The org control-plane API base (`{apiUrl}`) the function is mounted under. */
665
+ apiUrl: string;
666
+ /** Injected in tests; production uses the platform fetch. */
667
+ fetchImpl?: typeof fetch;
668
+ /**
669
+ * Where a row this lane REFUSED TO ANSWER ABOUT is reported (ENG-416).
670
+ *
671
+ * A malformed ledger row is isolated rather than allowed to 502 the whole
672
+ * 10,000-id batch, and the row it dropped is then MISSING from the answer —
673
+ * which a billing caller cannot tell apart from an id we do not hold, and
674
+ * reads as "not priced yet" until the request is written off unbilled. So
675
+ * the drop must be an event somebody can alert on. Absent, it goes to this
676
+ * process's stdout (`parseUsageRecords`'s own default), never nowhere.
677
+ *
678
+ * It may be async — a sink that ships the line somewhere usually is — and a
679
+ * rejected promise from it is contained exactly as a synchronous throw is.
680
+ */
681
+ onRejectedRow?: UsageRowReporter;
682
+ }
683
+ /** The batch ledger read, as one call per request. */
684
+ declare class UsageClient {
685
+ private readonly opts;
686
+ private readonly fetchImpl;
687
+ constructor(opts: UsageClientOptions);
688
+ /**
689
+ * Look up what we hold for these ids, as the holder of `apiKey`.
690
+ *
691
+ * Three outcomes, all explicit:
692
+ * - the control plane answers → validated {@link InferenceUsageRecord}s;
693
+ * - it rejects the key (401/403) → {@link ProxyAuthError} (401);
694
+ * - anything else → {@link UsageSurfaceError} (502).
695
+ */
696
+ lookup(apiKey: string, inferenceIds: readonly string[]): Promise<InferenceUsageRecord[]>;
697
+ }
698
+
699
+ /**
700
+ * THE HOSTED LEDGER WRITE — the control-plane half of the per-request ledger.
701
+ *
702
+ * The proxy holds no database credential and no standing platform secret
703
+ * (hosted/auth.ts: "NO STANDING CREDENTIAL... every upstream call it makes
704
+ * rides the CALLER'S OWN key"). So the ledger write rides the caller's own org
705
+ * API key to the control plane's `inference-ledger` function — the same
706
+ * mechanism and the same credential the ENG-318 read already uses — and the
707
+ * control plane derives the org AND the api_key_id from that key server-side
708
+ * before calling `urun_record_inference_request`.
709
+ *
710
+ * THAT PROPERTY IS SOUND ON THE READ AND INVERTED ON THE WRITE, and it is
711
+ * stated here because it is invisible in the code. On a read, riding the
712
+ * caller's key is precisely what enforces org scoping. On a WRITE TO A BILLING
713
+ * LEDGER it means the party being billed is the party authenticated to write
714
+ * the bill: a caller can read its `Inference-Id` off a streaming response head
715
+ * and race a fabricated row in ahead of this one. The control plane refuses
716
+ * the second write rather than upserting, so the attempt is LOUD instead of
717
+ * silent — see {@link LedgerDuplicateError}.
718
+ *
719
+ * ============================ THE ENG-410 RULING ============================
720
+ *
721
+ * That is a DETECTION, and it is the DELIBERATE, OWNER-APPROVED choice — not a
722
+ * gap somebody failed to close. The decision and the condition that reopens it
723
+ * are recorded here because the next person to read this file will otherwise
724
+ * re-derive the wrong answer from first principles.
725
+ *
726
+ * WHAT THE ATTACK ACTUALLY IS, bounded honestly. `org_id` and `api_key_id` are
727
+ * derived from the credential and the control-plane surface REFUSES both as
728
+ * body fields, so cross-tenant billing INJECTION is structurally impossible: a
729
+ * forged row can only ever land in the forger's OWN org. The only rational
730
+ * attack is therefore SELF-under-billing, it is not really a race (the header
731
+ * flushes at the head of a stream and this write happens on close, so the
732
+ * attacker has the whole generation), and it cannot be made quiet — every
733
+ * stolen request costs the attacker one refused write and one error line.
734
+ *
735
+ * REJECTED — GIVE THE PROXY A STANDING PLATFORM CREDENTIAL FOR THE WRITE. This
736
+ * is the obvious-sounding move and it is STRICTLY WORSE THAN THE FLAW. For a
737
+ * platform credential to REPLACE the caller's key on this write, `org_id` has
738
+ * to come back into the request body — there is nothing else left to carry
739
+ * tenancy. That deletes the one structural property that makes this surface
740
+ * safe at all, and it converts a proxy compromise from "whatever caller keys
741
+ * happen to be in flight" into "arbitrary billing rows for EVERY org, written
742
+ * from an internet-facing pod". The generalised rule, which outlives this
743
+ * module: A CREDENTIAL MAY BE ADDITIVE TO THE CALLER'S KEY, NEVER A
744
+ * REPLACEMENT FOR IT, because the caller's key is what carries tenancy.
745
+ *
746
+ * REJECTED — HAVE THE CONTROL PLANE DERIVE MORE AND TRUST THE BODY LESS. It
747
+ * already derives everything it can (`org_id`, `api_key_id`) and refuses what
748
+ * it must (`gpu_seconds`). Of what is left, the fields that DECIDE MONEY are
749
+ * exactly the fields it has no independent source for: nothing in the platform
750
+ * reports per-request token counts anywhere except this wire, and the
751
+ * `inference_id` is minted here. Authenticating the id would not help either —
752
+ * the attacker holds a LEGITIMATE id, read from its own response head.
753
+ *
754
+ * DEFERRED, WITH A TRIGGER — MAKE THE ROW UNFORGEABLE (a proxy-held key that
755
+ * signs the row's CONTENT, verified by the control plane, ADDITIVE to the
756
+ * caller's key so tenancy is untouched). This is the real fix and its blast
757
+ * radius is small: a stolen signing key only restores today's position,
758
+ * because the row still lands in whatever org the thief's own key names. It is
759
+ * NOT built yet because its own failure mode is worse than the flaw's while
760
+ * nothing bills off this table: a misconfigured or badly-rotated key takes
761
+ * 100% OF LEDGER ROWS TO ZERO ACROSS EVERY ORG, where the flaw takes some rows
762
+ * to zero for one customer attacking itself, loudly. Fitting a cryptographic
763
+ * gate to a writer that has never once run in production, in the week it first
764
+ * writes a row, is how a remedy costs more than the bug.
765
+ *
766
+ * THE TRIGGER, EXPLICITLY: BUILD IT BEFORE ANY PRODUCT BILLS OFF
767
+ * `public.inference_requests`. Today HF traffic authenticates as HF's own
768
+ * org (the end user never holds a uRun key) and self-serve is billed off
769
+ * `usage_events`, so no party both can run the attack and benefits from it.
770
+ * The credits / concurrency-tier / retention-tier product is the moment that
771
+ * stops being true, and it must not be the moment this is discovered.
772
+ *
773
+ * UNTIL THEN THE DETECTION IS THE CONTROL, so it is built to be OPERATED
774
+ * rather than merely to exist: the refusal carries a machine-readable
775
+ * `ledgerFailureReason` (`proxy/ledger.ts` {@link LedgerFailure}) that reaches
776
+ * both the structured log line and a Prometheus counter, so the alert is a
777
+ * field match and not a regex over this paragraph's prose.
778
+ *
779
+ * ===========================================================================
780
+ *
781
+ * EVERY FAILURE IS LOUD AND NONE OF THEM REACHES THE CUSTOMER. This runs from
782
+ * the response's `'close'` hook, after the answer is delivered, so there is no
783
+ * request left to fail: `proxy/ledger.ts` catches everything here and writes
784
+ * one structured log line. A write that did not land is revenue that was never
785
+ * recorded, which is exactly the thing that must never be silent.
786
+ */
787
+
788
+ /**
789
+ * The control-plane route this writes. Relative to the org control-plane API
790
+ * base (`{apiUrl}`, i.e. `https://api.urun.sh/v1`), which the deployment's
791
+ * gateway rewrites onto the Supabase Edge Functions host — the same base and
792
+ * the same rewrite `GET {apiUrl}/apps` and the usage read already ride.
793
+ */
794
+ declare const LEDGER_FUNCTION_PATH = "/inference-ledger";
795
+ /**
796
+ * How long one write may take before it is abandoned. A single-row insert plus
797
+ * two indexed price lookups is milliseconds; this bound exists so a stalled
798
+ * socket becomes a log line rather than a promise retained for the life of the
799
+ * pod. Deliberately TIGHTER than the usage read's 15s: that read answers a
800
+ * live poller that is waiting, while this write has nobody waiting on it and
801
+ * every second it holds is a slot in the in-flight bound.
802
+ */
803
+ declare const LEDGER_WRITE_TIMEOUT_MS = 10000;
804
+ /**
805
+ * The row was already in the ledger. Its own type because it is not a fault
806
+ * and must not be logged as one: it means somebody wrote this `inference_id`
807
+ * before us, which is either a double-write defect in this proxy or a row
808
+ * fabricated by the org being billed. Nothing was written and nothing was
809
+ * overwritten.
810
+ */
811
+ declare class LedgerDuplicateError extends Error implements LedgerFailure {
812
+ /**
813
+ * THE ENG-410 SIGNAL, as a field an alert can match.
814
+ *
815
+ * `duplicate` now means PROVABLY NOT OURS. Since the 409 carries the stored
816
+ * row (ENG-415), a conflict whose row matches what we are re-sending is our
817
+ * OWN earlier attempt and resolves as {@link LedgerAlreadyWrittenError}
818
+ * instead — so what is left here is a row somebody else wrote, or a row we
819
+ * could not read back to check. Both fail to the LOUD side on purpose.
820
+ *
821
+ * `duplicate_foreign` is the loudest state in the lane: the id is taken by a
822
+ * row THIS ORG CANNOT READ. `inference_requests.inference_id` is a global
823
+ * primary key, so it is reachable, and it can never be our own write.
824
+ */
825
+ readonly ledgerFailureReason: 'duplicate' | 'duplicate_foreign';
826
+ constructor(message: string, reason?: 'duplicate' | 'duplicate_foreign');
827
+ }
828
+ /** The control-plane write surface could not be reached or refused the row. */
829
+ declare class LedgerSurfaceError extends Error implements LedgerFailure {
830
+ readonly ledgerFailureReason: "surface";
831
+ constructor(message: string);
832
+ }
833
+ interface LedgerClientOptions {
834
+ /** The org control-plane API base (`{apiUrl}`) the function is mounted under. */
835
+ apiUrl: string;
836
+ /** Injected in tests; production uses the platform fetch. */
837
+ fetchImpl?: typeof fetch;
838
+ }
839
+ /**
840
+ * Validate the control plane's answer into the record the caller logs.
841
+ *
842
+ * IT IS VALIDATED RATHER THAN TRUSTED because what it carries is a COST. A
843
+ * surface that changed shape under us must not be able to produce a log line
844
+ * claiming a request was priced at a number nobody returned — and
845
+ * `unpriced_reason` is what tells an operator that traffic is being served
846
+ * that nobody can bill, so a missing one is not a detail.
847
+ */
848
+ declare function parseLedgerRecorded(raw: unknown, where: string): LedgerRecorded;
849
+ /** One ledger row, written as the holder of the caller's own org API key. */
850
+ declare class LedgerClient {
851
+ private readonly opts;
852
+ private readonly fetchImpl;
853
+ constructor(opts: LedgerClientOptions);
854
+ /**
855
+ * Write one row. Five outcomes, all explicit:
856
+ * - the control plane records it → the validated {@link LedgerRecorded},
857
+ * priced or with an `unpriced_reason`;
858
+ * - the id is already there AND the stored row is OURS (409) →
859
+ * {@link LedgerAlreadyWrittenError}, which is a SUCCESS: an earlier
860
+ * attempt landed;
861
+ * - the id is already there and the row is NOT ours, or cannot be read
862
+ * back to check (409) → {@link LedgerDuplicateError};
863
+ * - it rejects the key (401/403) → {@link LedgerAuthError};
864
+ * - anything else → {@link LedgerSurfaceError}.
865
+ *
866
+ * THE CALLER RETRIES, NOT THIS METHOD (ENG-415). One call is one attempt;
867
+ * `proxy/ledger.ts` owns the queue, the backoff and the dwell bound, and it
868
+ * retries only the one reason that is safe to retry. What makes any of it
869
+ * safe is the fifth outcome above: a retry whose first attempt secretly
870
+ * landed comes back as {@link LedgerAlreadyWrittenError}, not as something
871
+ * indistinguishable from a forged row.
872
+ */
873
+ write(apiKey: string, entry: LedgerWrite): Promise<LedgerRecorded>;
874
+ }
875
+
446
876
  /**
447
877
  * The hosted endpoint's configuration.
448
878
  *
@@ -491,6 +921,39 @@ interface HostedConfig {
491
921
  apiUrl: string;
492
922
  /** The `model_catalog` oracle for routing rule 5, or null when unconfigured. */
493
923
  catalog: CatalogConfig | null;
924
+ /**
925
+ * THE STATELESS DIRECT PATH's credential (URUN_SESSION_TOKEN_SECRET) — the
926
+ * runtime scoped-token signing secret the decision intake verifies
927
+ * (urun-python decision_intake). A SECRET input, not a behavior knob: it is
928
+ * the mandate's allowed env class, and it is the SAME predicate the local
929
+ * lane enables on (cli.ts statelessDialEnabled), so the two lanes can never
930
+ * disagree. Absent ('') the stateless lane does not exist and every
931
+ * decision rides the session lane byte-for-byte. Present, decisions for
932
+ * CALLER-ORG serves="openai" apps dispatch straight to a ready runtime's
933
+ * `:8099/v1/decision`: discovery rides the CALLER'S OWN key
934
+ * (`GET {apiUrl}/runtimes`), and the per-decision token is minted with the
935
+ * caller's org/app/fn identity. Shared-catalog models keep the session
936
+ * dial — the v1 boundary #497 declares (the dial's own targetFor refuses
937
+ * them).
938
+ *
939
+ * OPTIONAL on this bag because legacy constructors may omit it
940
+ * (resolveHostedConfig always supplies it — '' when the env is absent);
941
+ * consumers read it as `?? ''`.
942
+ */
943
+ decisionSecret?: string;
944
+ /**
945
+ * THE SHARED LANE'S credential (URUN_SHARED_ORG_API_KEY): the shared org's
946
+ * API key, so the decision dial can discover — and its tokens can name via
947
+ * the block's `shared_org_id` — the SHARED org's pods. Optional: absent ⇒
948
+ * shared models keep the session dial (the stateless boundary narrows to
949
+ * "no shared credential mounted"). URUN_SHARED_ORG_ID must ride WITH it
950
+ * (both-or-neither, loud) purely as the identity statement of the key —
951
+ * the dial never re-spells the pod org; it reads `shared_org_id` from the
952
+ * block that resolved the lane, so key and pod org cannot drift.
953
+ */
954
+ sharedOrgKey?: string;
955
+ /** Identity statement accompanying `sharedOrgKey` (URUN_SHARED_ORG_ID). */
956
+ sharedOrgId?: string;
494
957
  }
495
958
  /**
496
959
  * Read and VALIDATE the deployment's external inputs. Every failure is loud
@@ -520,11 +983,23 @@ declare function resolveHostedConfig(env?: NodeJS.ProcessEnv): HostedConfig;
520
983
  * reachable, because a replica that cannot verify API keys
521
984
  * or list apps can serve nothing and must be pulled out of
522
985
  * the Service rather than answering 502s.
523
- * * /v1/... the compat surface, org-scoped by the Bearer key.
986
+ * * /v1/... the compat surface, org-scoped by the Bearer key, including
987
+ * the canonical usage-query lane POST /v1/usage/requests
988
+ * (proxy/usage.ts — a batch read of the per-request
989
+ * inference ledger).
990
+ * POST /partners/<name>/... the ENG-376 partner ADAPTER surface: a
991
+ * partner's own wire shape translated onto a canonical lane,
992
+ * sharing its auth and error mapping. Today: the Hugging
993
+ * Face billing poll. Ingress/charts must allowlist it.
524
994
  * WS /ws/google.ai.generativelanguage.v1beta.GenerativeService.
525
995
  * BidiGenerateContent — the Gemini Live surface, org-scoped by the
526
996
  * Gemini credential (x-goog-api-key / Authorization: Bearer; `?key=`
527
997
  * refused). Ingress/charts must allowlist that path.
998
+ * WS /v1/realtime — the OpenAI Realtime surface (GA protocol subset),
999
+ * org-scoped by the SAME Bearer api key as the /v1 lane; the
1000
+ * caller-org catalog's `task` column (stt | tts) gates which models
1001
+ * may bind an audio session. Ingress/charts must allowlist that
1002
+ * path too.
528
1003
  * * anything else → 404 in the OpenAI error envelope (unclaimed WS
529
1004
  * upgrades get their own final refusal).
530
1005
  *
@@ -555,6 +1030,40 @@ interface HostedProxyOptions extends HostedConfig {
555
1030
  registry?: TenantRegistry;
556
1031
  /** Injected in tests so conversation backhauls are stubbed at the seam. */
557
1032
  conversations?: ConversationBackhauls;
1033
+ /**
1034
+ * Injected in tests so the canonical usage lane is exercised without a
1035
+ * control plane. Production builds one against `apiUrl` — the same base and
1036
+ * the same caller-key credential `GET {apiUrl}/apps` rides.
1037
+ */
1038
+ usageClient?: UsageClient;
1039
+ /**
1040
+ * Injected in tests so the per-request LEDGER WRITE is exercised without a
1041
+ * control plane. Production builds one against `apiUrl` — the same base and
1042
+ * the same caller-key credential the usage read and `GET {apiUrl}/apps`
1043
+ * ride.
1044
+ */
1045
+ ledgerClient?: LedgerClient;
1046
+ /**
1047
+ * Sink for the ledger lane's own structured diagnostics (proxy/ledger.ts:
1048
+ * one JSON object per write, skip or failure). DELIBERATELY SEPARATE from
1049
+ * {@link requestLog}, which carries exactly one `inference_request` record
1050
+ * per `/v1` request and whose readers count on that. Production leaves it
1051
+ * unset, which is this container's stdout.
1052
+ */
1053
+ ledgerLog?: (line: string) => void;
1054
+ /**
1055
+ * Sink for the shared handler's per-request billing log line (the
1056
+ * `Inference-Id` record — proxy/responses-turn.ts `ProxyHandlerOptions`).
1057
+ * Injected in tests; production leaves it unset, which is this container's
1058
+ * stdout — the log stream the platform collects.
1059
+ */
1060
+ requestLog?: (line: string) => void;
1061
+ /**
1062
+ * Collect Node process metrics (event-loop lag, heap, GC) alongside the
1063
+ * request metrics. Production leaves it on; tests turn it off so an
1064
+ * assertion on the exposition text is not swamped by process noise.
1065
+ */
1066
+ defaultMetrics?: boolean;
558
1067
  }
559
1068
  /**
560
1069
  * Build (not listen) the hosted endpoint. The caller owns listen/close,
@@ -565,8 +1074,192 @@ interface HostedProxyOptions extends HostedConfig {
565
1074
  */
566
1075
  declare function createHostedProxy(options: HostedProxyOptions): {
567
1076
  server: Server;
1077
+ /**
1078
+ * The PRIVATE Prometheus listener (`proxy/metrics.ts` — GET /metrics on
1079
+ * {@link METRICS_PORT}). Its own server, not a route on the one above, so
1080
+ * "the metrics port is not public" is a property of the socket rather than
1081
+ * a rule the `/v1` router must keep remembering. The caller owns
1082
+ * listen/close, exactly as it does for `server`.
1083
+ */
1084
+ metricsServer: Server;
1085
+ metrics: InferenceMetrics;
1086
+ /**
1087
+ * The PRIVATE ext-auth listener the edge calls to turn the caller's Bearer
1088
+ * key into a non-secret bucket id (`hosted/edge-identity.ts`). Its own
1089
+ * socket for the same reason the metrics port is: the public HTTPRoutes
1090
+ * forward only to the `/v1` port, so it cannot be reached from outside.
1091
+ * The caller owns listen/close.
1092
+ */
1093
+ edgeIdentityServer: Server;
1094
+ /**
1095
+ * The tenant registry this proxy built (production wiring). Tests assert
1096
+ * the per-caller stateless dial through it; production code goes through
1097
+ * `callerOf`, never here.
1098
+ */
1099
+ registry: TenantRegistry;
568
1100
  closeAll: () => Promise<void>;
569
1101
  closeWebSockets: () => Promise<void>;
570
1102
  };
571
1103
 
572
- export { BIND_HOST, type CallerIdentity, ControlPlaneUnavailableError, type ConversationBackhaulOptions, ConversationBackhauls, ConversationCapacityError, DEFAULT_PORT, type HostedConfig, type HostedProxyOptions, MAX_CACHED_KEYS, MAX_CONVERSATIONS, MAX_CONVERSATION_HANDLES, MAX_TENANTS, ORG_BINDING_TTL_MS, OrgResolver, type OrgResolverOptions, type PrivateConversationBackhaul, type PrivateConversationConnection, ProxyAuthError, READINESS_TIMEOUT_MS, READINESS_TTL_MS, SERVE_FUNCTION, TenantRegistry, type TenantRegistryOptions, bearerFrom, createHostedProxy, resolveHostedConfig, tenantSubject };
1104
+ /**
1105
+ * THE EDGE IDENTITY SURFACE — the one thing Envoy cannot compute for itself.
1106
+ *
1107
+ * WHY IT EXISTS. Envoy Gateway's per-caller rate limiting needs a DISTINCT
1108
+ * bucket per caller, and the only caller identity on this endpoint is the
1109
+ * Bearer org API key (`hosted/auth.ts`: "the Bearer key IS the identity AND
1110
+ * the tenancy"). Envoy Gateway can key a global rate limit on a header's
1111
+ * distinct values — but the descriptor VALUE is what the rate-limit service
1112
+ * sends to Redis and what Redis stores as part of its key. Keying directly on
1113
+ * `Authorization` would therefore park live customer API keys, in plaintext,
1114
+ * in an in-cluster Redis whose NetworkPolicy is inert on both prod clusters
1115
+ * today (the VPC CNI node agent runs without `--enable-network-policy`, as the
1116
+ * valkey chart already documents). That is a credential store nobody designed,
1117
+ * audited, or rotates.
1118
+ *
1119
+ * Envoy's Lua filter has no hashing primitive and its rate-limit actions have
1120
+ * no transform, so SOMETHING has to turn the key into a non-secret id before
1121
+ * the rate-limit filter runs. Envoy Gateway's own mechanism for that is
1122
+ * `SecurityPolicy.extAuth`, whose response headers are merged into the request
1123
+ * ("coexisting headers will be overridden") before the later rate-limit filter
1124
+ * reads them. This module is that service.
1125
+ *
1126
+ * IT IS NOT AN AUTHORIZATION GATE, AND IT MUST NEVER BECOME ONE. It answers
1127
+ * 200 to everything. Authentication stays where it already is — in the proxy,
1128
+ * which alone can answer 401 in the lane's native error envelope with the
1129
+ * `Inference-Id` header HF bills on. A deny here would instead produce Envoy's
1130
+ * bodiless refusal, which an OpenAI SDK surfaces as an unparseable error.
1131
+ *
1132
+ * IT HAS NO DEPENDENCIES, ON PURPOSE. Read a header, hash it, answer. No
1133
+ * control-plane call, no cache, no I/O, nothing that can be slow or down. It
1134
+ * sits in the request path of `inference.urun.sh`, so the only acceptable
1135
+ * failure budget is none — and the `SecurityPolicy` that calls it is
1136
+ * additionally configured `failOpen`, so even losing it entirely degrades to
1137
+ * "no rate limiting", never to "no inference".
1138
+ */
1139
+
1140
+ /**
1141
+ * The container's edge-identity port — a MODULE CONSTANT, not an env var, per
1142
+ * the hosted config mandate (`hosted/config.ts`). Its own socket, like the
1143
+ * metrics port: private by construction, since the public HTTPRoutes forward
1144
+ * only to the `/v1` port.
1145
+ */
1146
+ declare const EDGE_IDENTITY_PORT = 9465;
1147
+ /**
1148
+ * THE BUCKET ID. Envoy Gateway's `BackendTrafficPolicy` keys the caller's
1149
+ * rate-limit counter on this header's DISTINCT values, which means the value
1150
+ * here IS the input the rate-limit service builds its Redis counter key from.
1151
+ *
1152
+ * THAT IS WHY IT MUST NOT BE THE VALUE COMMITTED IN `values.yaml`. The tier
1153
+ * fingerprint below is written into a git-tracked manifest so an operator can
1154
+ * give one caller its own limit. If the bucket id were the same digest, then
1155
+ * ANYONE WHO CAN READ THE REPO could reconstruct a tiered caller's counter key
1156
+ * — and the counter store is reachable by any pod in the cluster with
1157
+ * `+incrby` and `+expire` granted, so they could spend Hugging Face's
1158
+ * allowance or stretch the window and hold HF's own probe at 429. That is the
1159
+ * delisting event this whole pair exists to prevent, and non-invertibility of
1160
+ * SHA-256 does nothing about it: the attacker never needs the key, only the
1161
+ * digest, and the digest was published on purpose.
1162
+ *
1163
+ * So the two digests are DIFFERENT one-way functions of the same token, split
1164
+ * by domain separator ({@link BUCKET_DOMAIN} vs {@link TIER_DOMAIN}). Knowing
1165
+ * the tier fingerprint gives no path to the bucket id: getting there would
1166
+ * require recovering the token from its digest, which is a preimage attack on
1167
+ * SHA-256 over 256 bits of `randomBytes` entropy.
1168
+ */
1169
+ declare const EDGE_KEY_ID_HEADER = "x-urun-key-id";
1170
+ /**
1171
+ * THE TIER SELECTOR — matched with `Exact` / `RegularExpression` in the
1172
+ * BackendTrafficPolicy to decide WHICH limit applies, never to bucket.
1173
+ *
1174
+ * This is the digest an operator commits to `rateLimit.tiers[].keyIdSha256` in
1175
+ * k8s-manifests, so treat it as PUBLIC: everything about the design has to
1176
+ * hold when an attacker knows it.
1177
+ *
1178
+ * WHY A SECOND HEADER AT ALL. An Envoy Gateway rate-limit rule needs both
1179
+ * kinds of match on the caller at once: `Distinct` (give this caller their own
1180
+ * counter) AND an exact/inverted match (is this the partner key, or everyone
1181
+ * else). Whether a single selector may list the SAME header name under two
1182
+ * different match types is not something this repo can verify without a
1183
+ * cluster, and getting it wrong means Envoy Gateway rejects the policy —
1184
+ * which, on a fail-open limiter, is indistinguishable from "rate limiting
1185
+ * works" until somebody floods us. Two headers remove the question; carrying
1186
+ * two DIFFERENT digests is what makes publishing one of them safe.
1187
+ */
1188
+ declare const EDGE_KEY_FINGERPRINT_HEADER = "x-urun-key-fingerprint";
1189
+ /**
1190
+ * Domain separator for the BUCKET digest. Never appears in a manifest, a log,
1191
+ * or a metric — the bucket id is derived here and read only by Envoy.
1192
+ */
1193
+ declare const BUCKET_DOMAIN = "urun-ratelimit-bucket:";
1194
+ /**
1195
+ * Domain separator for the TIER digest — the one an operator reproduces from a
1196
+ * key with `printf 'urun-ratelimit-tier:%s' "$KEY" | sha256sum | cut -d' ' -f1`.
1197
+ *
1198
+ * A plain `sha256sum "$KEY"` would be the OLD, unsafe value: identical to the
1199
+ * bucket id, and therefore a published counter key. The separator is what
1200
+ * keeps the two apart, so it is part of the operator contract and cannot drift.
1201
+ */
1202
+ declare const TIER_DOMAIN = "urun-ratelimit-tier:";
1203
+ /**
1204
+ * The bucket every request WITHOUT a Bearer token shares. A single shared
1205
+ * bucket rather than no bucket at all: unauthenticated floods must be limited
1206
+ * too, and they have no identity to spread across. They cannot consume a real
1207
+ * caller's bucket because no real key hashes to this value.
1208
+ */
1209
+ declare const ANONYMOUS_KEY_ID = "anonymous";
1210
+ /**
1211
+ * The caller's BUCKET id — `sha256(BUCKET_DOMAIN || token)`, hex.
1212
+ *
1213
+ * SECRET BY CONSTRUCTION, not because the digest is one-way but because the
1214
+ * only published digest is a DIFFERENT one. This value is the input Envoy's
1215
+ * rate-limit descriptor carries, so it is what the counter key in the
1216
+ * rate-limit cache is built from; publishing it would publish a writable
1217
+ * counter key (see {@link EDGE_KEY_ID_HEADER}).
1218
+ */
1219
+ declare function edgeBucketId(bearerToken: string): string;
1220
+ /**
1221
+ * The caller's TIER fingerprint — `sha256(TIER_DOMAIN || token)`, hex.
1222
+ *
1223
+ * PUBLIC BY DESIGN: this is the value an operator commits to
1224
+ * `rateLimit.tiers[].keyIdSha256`. The runbook is
1225
+ * `printf 'urun-ratelimit-tier:%s' "$KEY" | sha256sum | cut -d' ' -f1`.
1226
+ *
1227
+ * The domain prefix is not decoration — a bare `sha256sum "$KEY"` reproduces
1228
+ * the BUCKET id, which is exactly the value that must never be committed. The
1229
+ * `cut` is load-bearing too: `sha256sum` prints the digest, two spaces, then
1230
+ * the input name, and a tier carrying that trailing ` -` matches nothing and
1231
+ * silently leaves the caller on the default limit.
1232
+ */
1233
+ declare function edgeTierFingerprint(bearerToken: string): string;
1234
+ /**
1235
+ * The bearer token of an `Authorization` header, or null.
1236
+ *
1237
+ * Deliberately NOT `hosted/auth.ts` `bearerFrom`: that one THROWS a 401-shaped
1238
+ * error for a missing or malformed header, which is the correct behaviour for
1239
+ * the lane that authenticates. Here a malformed header must produce the
1240
+ * anonymous bucket and a 200, because refusing is the proxy's job and this
1241
+ * service must never refuse.
1242
+ */
1243
+ declare function bearerTokenOf(headerValue: string | undefined): string | null;
1244
+ /**
1245
+ * The PRIVATE ext-auth listener. Answers 200 to every method and every path —
1246
+ * Envoy appends the ORIGINAL request path to the configured ext-auth path, so
1247
+ * this service sees `/ratelimit-identity/v1/chat/completions` and friends and
1248
+ * must not care.
1249
+ *
1250
+ * The response carries exactly the two identity headers below, and the
1251
+ * `SecurityPolicy` forwards exactly those two (`headersToBackend`). Nothing
1252
+ * about the caller's request, and certainly not their key, is echoed.
1253
+ *
1254
+ * A CALLER CANNOT PRESENT THEIR OWN. `headersToBackend` is documented as
1255
+ * overriding coexisting headers, so whatever a client sent under these names is
1256
+ * replaced on every request this service answers. There is deliberately NO
1257
+ * `ClientTrafficPolicy` stripping them at the listener: that policy would
1258
+ * attach to the shared `public-gw` (api.urun.sh rides it too) to close a gap
1259
+ * that grants nothing — in the only case where a client value survives, the
1260
+ * ext-auth hop has already failed open, and fail-open grants MORE than any
1261
+ * spoofed bucket could. The k8s half records the same decision.
1262
+ */
1263
+ declare function createEdgeIdentityServer(): Server;
1264
+
1265
+ export { ANONYMOUS_KEY_ID, BIND_HOST, BUCKET_DOMAIN, BoundedLabel, type CallerIdentity, ControlPlaneUnavailableError, type ConversationBackhaulOptions, ConversationBackhauls, ConversationCapacityError, DEFAULT_PORT, EDGE_IDENTITY_PORT, EDGE_KEY_FINGERPRINT_HEADER, EDGE_KEY_ID_HEADER, type HostedConfig, type HostedProxyOptions, InferenceMetrics, LEDGER_FUNCTION_PATH, LEDGER_WRITE_TIMEOUT_MS, LedgerClient, type LedgerClientOptions, LedgerDuplicateError, LedgerSurfaceError, MAX_CACHED_KEYS, MAX_CONVERSATIONS, MAX_CONVERSATION_HANDLES, MAX_MODEL_LABELS, MAX_ORG_LABELS, MAX_TENANTS, METRICS_PATH, METRICS_PORT, NO_MODEL_LABEL, ORG_BINDING_TTL_MS, OTHER_LABEL, OrgResolver, type OrgResolverOptions, type PrivateConversationBackhaul, type PrivateConversationConnection, ProxyAuthError, READINESS_TIMEOUT_MS, READINESS_TTL_MS, SERVE_FUNCTION, TIER_DOMAIN, TenantRegistry, type TenantRegistryOptions, bearerFrom, bearerTokenOf, createEdgeIdentityServer, createHostedProxy, createMetricsServer, edgeBucketId, edgeTierFingerprint, laneOf, parseLedgerRecorded, resolveHostedConfig, statusClassOf, tenantSubject };