@omnicross/core 0.1.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.
- package/LICENSE +21 -0
- package/NOTICE +57 -0
- package/README.md +15 -0
- package/dist/ApiKeyPoolService-BmMkau07.d.cts +170 -0
- package/dist/ApiKeyPoolService-BmMkau07.d.ts +170 -0
- package/dist/ProviderProxy-f_8ziIhW.d.cts +120 -0
- package/dist/ProviderProxy-vjt8sQQk.d.ts +120 -0
- package/dist/SubscriptionAuthSource-Cr4fVEYY.d.cts +264 -0
- package/dist/SubscriptionAuthSource-D89zmiSS.d.ts +264 -0
- package/dist/auth/GeminiCodeAssistProjectResolver.cjs +218 -0
- package/dist/auth/GeminiCodeAssistProjectResolver.d.cts +68 -0
- package/dist/auth/GeminiCodeAssistProjectResolver.d.ts +68 -0
- package/dist/auth/GeminiCodeAssistProjectResolver.js +189 -0
- package/dist/completion/ApiKeyPoolService.cjs +331 -0
- package/dist/completion/ApiKeyPoolService.d.cts +2 -0
- package/dist/completion/ApiKeyPoolService.d.ts +2 -0
- package/dist/completion/ApiKeyPoolService.js +306 -0
- package/dist/completion.cjs +4027 -0
- package/dist/completion.d.cts +17 -0
- package/dist/completion.d.ts +17 -0
- package/dist/completion.js +3983 -0
- package/dist/index-BTSmc9Sm.d.ts +645 -0
- package/dist/index-DXazdTzZ.d.cts +645 -0
- package/dist/index.cjs +10428 -0
- package/dist/index.d.cts +128 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.js +10339 -0
- package/dist/outbound-api/subscriptionRegistryPort.cjs +38 -0
- package/dist/outbound-api/subscriptionRegistryPort.d.cts +73 -0
- package/dist/outbound-api/subscriptionRegistryPort.d.ts +73 -0
- package/dist/outbound-api/subscriptionRegistryPort.js +12 -0
- package/dist/outbound-api.cjs +5264 -0
- package/dist/outbound-api.d.cts +320 -0
- package/dist/outbound-api.d.ts +320 -0
- package/dist/outbound-api.js +5218 -0
- package/dist/pipeline/SubscriptionAuthSource.cjs +131 -0
- package/dist/pipeline/SubscriptionAuthSource.d.cts +3 -0
- package/dist/pipeline/SubscriptionAuthSource.d.ts +3 -0
- package/dist/pipeline/SubscriptionAuthSource.js +103 -0
- package/dist/pipeline/SubscriptionAuthStrategy.cjs +18 -0
- package/dist/pipeline/SubscriptionAuthStrategy.d.cts +61 -0
- package/dist/pipeline/SubscriptionAuthStrategy.d.ts +61 -0
- package/dist/pipeline/SubscriptionAuthStrategy.js +0 -0
- package/dist/ports/gemini-code-assist-resolver.cjs +38 -0
- package/dist/ports/gemini-code-assist-resolver.d.cts +26 -0
- package/dist/ports/gemini-code-assist-resolver.d.ts +26 -0
- package/dist/ports/gemini-code-assist-resolver.js +12 -0
- package/dist/ports.cjs +18 -0
- package/dist/ports.d.cts +15 -0
- package/dist/ports.d.ts +15 -0
- package/dist/ports.js +0 -0
- package/dist/provider-proxy/ingress/providerProxyShared.cjs +2958 -0
- package/dist/provider-proxy/ingress/providerProxyShared.d.cts +77 -0
- package/dist/provider-proxy/ingress/providerProxyShared.d.ts +77 -0
- package/dist/provider-proxy/ingress/providerProxyShared.js +2925 -0
- package/dist/provider-proxy/matchText.cjs +73 -0
- package/dist/provider-proxy/matchText.d.cts +47 -0
- package/dist/provider-proxy/matchText.d.ts +47 -0
- package/dist/provider-proxy/matchText.js +45 -0
- package/dist/provider-proxy/types.cjs +18 -0
- package/dist/provider-proxy/types.d.cts +12 -0
- package/dist/provider-proxy/types.d.ts +12 -0
- package/dist/provider-proxy/types.js +0 -0
- package/dist/provider-proxy.cjs +4667 -0
- package/dist/provider-proxy.d.cts +69 -0
- package/dist/provider-proxy.d.ts +69 -0
- package/dist/provider-proxy.js +4636 -0
- package/dist/serializeError.cjs +82 -0
- package/dist/serializeError.d.cts +24 -0
- package/dist/serializeError.d.ts +24 -0
- package/dist/serializeError.js +57 -0
- package/dist/sse-parser.cjs +456 -0
- package/dist/sse-parser.d.cts +143 -0
- package/dist/sse-parser.d.ts +143 -0
- package/dist/sse-parser.js +430 -0
- package/dist/transformer/TransformerChainExecutor.cjs +321 -0
- package/dist/transformer/TransformerChainExecutor.d.cts +104 -0
- package/dist/transformer/TransformerChainExecutor.d.ts +104 -0
- package/dist/transformer/TransformerChainExecutor.js +294 -0
- package/dist/transformer/TransformerService.cjs +290 -0
- package/dist/transformer/TransformerService.d.cts +138 -0
- package/dist/transformer/TransformerService.d.ts +138 -0
- package/dist/transformer/TransformerService.js +265 -0
- package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +1115 -0
- package/dist/transformer/transformers/GeminiCodeAssistTransformer.d.cts +102 -0
- package/dist/transformer/transformers/GeminiCodeAssistTransformer.d.ts +102 -0
- package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +1085 -0
- package/dist/transformer/transformers/GeminiTransformer.cjs +1013 -0
- package/dist/transformer/transformers/GeminiTransformer.d.cts +70 -0
- package/dist/transformer/transformers/GeminiTransformer.d.ts +70 -0
- package/dist/transformer/transformers/GeminiTransformer.js +986 -0
- package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +538 -0
- package/dist/transformer/transformers/OpenAIResponseTransformer.d.cts +53 -0
- package/dist/transformer/transformers/OpenAIResponseTransformer.d.ts +53 -0
- package/dist/transformer/transformers/OpenAIResponseTransformer.js +513 -0
- package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +73 -0
- package/dist/transformer/transformers/OpenCodeGoTransformer.d.cts +51 -0
- package/dist/transformer/transformers/OpenCodeGoTransformer.d.ts +51 -0
- package/dist/transformer/transformers/OpenCodeGoTransformer.js +48 -0
- package/dist/transformer/types.cjs +18 -0
- package/dist/transformer/types.d.cts +405 -0
- package/dist/transformer/types.d.ts +405 -0
- package/dist/transformer/types.js +0 -0
- package/dist/transformer.cjs +3736 -0
- package/dist/transformer.d.cts +33 -0
- package/dist/transformer.d.ts +33 -0
- package/dist/transformer.js +3712 -0
- package/dist/types-CGGrKqC_.d.cts +142 -0
- package/dist/types-CbCN2NQP.d.ts +142 -0
- package/dist/types-DCzHkhJt.d.ts +467 -0
- package/dist/types-DZIQbgp0.d.cts +467 -0
- package/dist/usage-event-sink-BX7FE1NL.d.cts +59 -0
- package/dist/usage-event-sink-BX7FE1NL.d.ts +59 -0
- package/package.json +62 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { E as EndpointRoutingConfig, a as OutboundApiDeps, e as OutboundApiServerStatus, g as OutboundFormatUrls, d as OutboundApiServerConfig, O as OutboundKeyDb, b as OutboundApiKeyCreated, R as RequestRole, f as OutboundEndpoint } from './types-CGGrKqC_.cjs';
|
|
2
|
+
export { c as OutboundApiKeyInfo, h as OutboundKeyDbRow } from './types-CGGrKqC_.cjs';
|
|
3
|
+
import { I as IngressFormat, P as ProviderConfigSource, g as RouteContext } from './types-DZIQbgp0.cjs';
|
|
4
|
+
import { SubscriptionProviderId } from '@omnicross/contracts/subscription-types';
|
|
5
|
+
import './ProviderProxy-f_8ziIhW.cjs';
|
|
6
|
+
import 'node:http';
|
|
7
|
+
import '@omnicross/contracts/completion-types';
|
|
8
|
+
import '@omnicross/contracts/usage-types';
|
|
9
|
+
import './ApiKeyPoolService-BmMkau07.cjs';
|
|
10
|
+
import '@omnicross/contracts/llm-config';
|
|
11
|
+
import './SubscriptionAuthSource-Cr4fVEYY.cjs';
|
|
12
|
+
import './pipeline/SubscriptionAuthStrategy.cjs';
|
|
13
|
+
import './transformer/types.cjs';
|
|
14
|
+
import './transformer/TransformerService.cjs';
|
|
15
|
+
import '@omnicross/contracts/websearch-types';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* OutboundApiServer — the external-facing HTTP listener for the outbound API
|
|
19
|
+
* server (`outbound-api-server`, design D1/D4/D5).
|
|
20
|
+
*
|
|
21
|
+
* A SEPARATE long-lived `http.Server` (distinct from the resident loopback
|
|
22
|
+
* `ProviderProxy`). It binds `127.0.0.1` by default, or `0.0.0.0` when network
|
|
23
|
+
* binding is enabled. Every request — INCLUDING loopback — is authenticated by
|
|
24
|
+
* a named API key (no loopback bypass). Each authenticated request mints a route
|
|
25
|
+
* on the SHARED `ProviderProxyRouteMap` and delegates to the existing
|
|
26
|
+
* `routeRequest()` dispatch so the four ingress parsers + transformer are
|
|
27
|
+
* reused (one conversion stack).
|
|
28
|
+
*
|
|
29
|
+
* Lifecycle:
|
|
30
|
+
* - `applyConfig({ enabled, networkBinding, endpoints, port })` — restart ONLY
|
|
31
|
+
* when the bind address or port changes; per-endpoint routing config is read
|
|
32
|
+
* live per request (no restart).
|
|
33
|
+
* - `getStatus()` — running, actual port, loopback + optional LAN URLs, the
|
|
34
|
+
* four format URLs.
|
|
35
|
+
* - `EADDRINUSE` → fall back to an ephemeral port, persist it (via the caller's
|
|
36
|
+
* `onPortChange`), and surface the actual port.
|
|
37
|
+
*
|
|
38
|
+
* @module outbound-api/OutboundApiServer
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** Fixed default port (design D5). Persisted + configurable. */
|
|
42
|
+
declare const DEFAULT_OUTBOUND_PORT = 8765;
|
|
43
|
+
/** Per-call apply config (the persisted server config minus runtime state). */
|
|
44
|
+
interface ApplyConfigInput {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
networkBinding: boolean;
|
|
47
|
+
endpoints: EndpointRoutingConfig[];
|
|
48
|
+
port?: number;
|
|
49
|
+
}
|
|
50
|
+
declare class OutboundApiServer {
|
|
51
|
+
private readonly deps;
|
|
52
|
+
/** Called when the actual bound port differs from the requested one. */
|
|
53
|
+
private readonly onPortChange?;
|
|
54
|
+
private server;
|
|
55
|
+
private boundPort;
|
|
56
|
+
private boundAddr;
|
|
57
|
+
private endpoints;
|
|
58
|
+
private readonly rateLimiter;
|
|
59
|
+
constructor(deps: OutboundApiDeps,
|
|
60
|
+
/** Called when the actual bound port differs from the requested one. */
|
|
61
|
+
onPortChange?: ((port: number) => void) | undefined);
|
|
62
|
+
/**
|
|
63
|
+
* Apply a config. Restarts the listener ONLY when the bind address or port
|
|
64
|
+
* changes (or when toggling enabled); per-endpoint routing config is updated
|
|
65
|
+
* in place (read live per request — no restart).
|
|
66
|
+
*/
|
|
67
|
+
applyConfig(input: ApplyConfigInput): Promise<void>;
|
|
68
|
+
/** Start the listener on `bindAddr:port`, falling back on EADDRINUSE. */
|
|
69
|
+
start(bindAddr: string, port: number): Promise<number>;
|
|
70
|
+
/** Bind once; on EADDRINUSE retry with an ephemeral port (port 0). */
|
|
71
|
+
private listen;
|
|
72
|
+
/** Per-request handler. Auth is enforced on EVERY request (incl. loopback). */
|
|
73
|
+
private onRequest;
|
|
74
|
+
/** Stop the listener and release the port. */
|
|
75
|
+
stop(): Promise<void>;
|
|
76
|
+
/** A live status snapshot for the Settings tab. */
|
|
77
|
+
getStatus(): OutboundApiServerStatus;
|
|
78
|
+
}
|
|
79
|
+
/** Build the four format endpoint URLs for a base URL. */
|
|
80
|
+
declare function formatUrls(base: string): OutboundFormatUrls;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* apiServerConfig — load / save / default the outbound API server config
|
|
84
|
+
* (`outbound-api-server`, design D4).
|
|
85
|
+
*
|
|
86
|
+
* The config (`{ enabled, networkBinding, endpoints, port }`) is persisted via
|
|
87
|
+
* a small key/value store (the app SettingsService) under a single key, so it
|
|
88
|
+
* survives restart. Defaults: disabled, loopback, four endpoints with empty
|
|
89
|
+
* models + `useSubscription` OFF, default port. Shared by the router and the
|
|
90
|
+
* bootstrap wiring so both read/write the same shape.
|
|
91
|
+
*
|
|
92
|
+
* @module outbound-api/apiServerConfig
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/** The settings key the config persists under. */
|
|
96
|
+
declare const OUTBOUND_API_SERVER_CONFIG_KEY = "outboundApiServer.config";
|
|
97
|
+
/** Structural subset of the settings store the config loader needs. */
|
|
98
|
+
interface ApiServerSettingsStore {
|
|
99
|
+
get<T = unknown>(key: string): Promise<T | undefined>;
|
|
100
|
+
set<T = unknown>(key: string, value: T): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
/** The default server config: disabled, loopback, four blank endpoints. */
|
|
103
|
+
declare function defaultServerConfig(): OutboundApiServerConfig;
|
|
104
|
+
/**
|
|
105
|
+
* Normalize a (possibly partial / legacy) persisted config to the full shape:
|
|
106
|
+
* ensure all four endpoints exist, `useSubscription` defaults OFF, and a port
|
|
107
|
+
* is present.
|
|
108
|
+
*/
|
|
109
|
+
declare function normalizeServerConfig(raw: Partial<OutboundApiServerConfig> | undefined | null): OutboundApiServerConfig;
|
|
110
|
+
/** Load the persisted config (normalized), defaulting on a missing/blank key. */
|
|
111
|
+
declare function loadServerConfig(store: ApiServerSettingsStore): Promise<OutboundApiServerConfig>;
|
|
112
|
+
/** Persist the config. */
|
|
113
|
+
declare function saveServerConfig(store: ApiServerSettingsStore, config: OutboundApiServerConfig): Promise<void>;
|
|
114
|
+
/** Apply a partial patch to a config, returning the merged whole. */
|
|
115
|
+
declare function mergeServerConfig(current: OutboundApiServerConfig, patch: Partial<OutboundApiServerConfig>): OutboundApiServerConfig;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* outboundApiKeyAuth — named-key generation, hashing, and verification for the
|
|
119
|
+
* outbound API server (`outbound-api-server`).
|
|
120
|
+
*
|
|
121
|
+
* Keys are 128-bit+ random secrets (`sk-omnicross-<base62>`), NOT human passwords,
|
|
122
|
+
* so a single fast hash (sha256) is sufficient and keeps the hot auth path
|
|
123
|
+
* cheap (design D3). Only the hash + a short display prefix are persisted; the
|
|
124
|
+
* full plaintext is returned exactly once at creation.
|
|
125
|
+
*
|
|
126
|
+
* @module outbound-api/outboundApiKeyAuth
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/** Hash a presented/generated secret (sha256 hex). */
|
|
130
|
+
declare function hashKey(secret: string): string;
|
|
131
|
+
/**
|
|
132
|
+
* Create + persist a named key. Returns the plaintext ONCE; only the hash +
|
|
133
|
+
* prefix are stored.
|
|
134
|
+
*/
|
|
135
|
+
declare function createNamedKey(db: OutboundKeyDb, name: string): Promise<OutboundApiKeyCreated>;
|
|
136
|
+
/** The id of a verified key (for rate-limiting + last-used bookkeeping). */
|
|
137
|
+
interface VerifiedKey {
|
|
138
|
+
id: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Verify a presented key against the DB. Matches by hash where the stored row
|
|
142
|
+
* is enabled AND not revoked (the DB query enforces this). On success bumps
|
|
143
|
+
* `lastUsedAt` (best-effort, fire-and-forget) and returns the key id; returns
|
|
144
|
+
* `null` on any miss / disabled / revoked key.
|
|
145
|
+
*/
|
|
146
|
+
declare function verifyPresentedKey(db: OutboundKeyDb, presentedKey: string | undefined): Promise<VerifiedKey | null>;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* outboundRateLimiter — per-API-key in-memory sliding-window rate limiter for
|
|
150
|
+
* the outbound API server (`outbound-api-server`, design D6).
|
|
151
|
+
*
|
|
152
|
+
* A simple fixed-size sliding window keyed by `apiKeyId`. In-memory only (resets
|
|
153
|
+
* on app restart, acceptable for v1). Exceeding the limit returns a deny with a
|
|
154
|
+
* `Retry-After` (seconds). Limits are conservative defaults, not user-
|
|
155
|
+
* configurable in v1.
|
|
156
|
+
*
|
|
157
|
+
* @module outbound-api/outboundRateLimiter
|
|
158
|
+
*/
|
|
159
|
+
interface RateLimitDecision {
|
|
160
|
+
allowed: boolean;
|
|
161
|
+
/** Seconds until the window frees up (only meaningful when `!allowed`). */
|
|
162
|
+
retryAfterSeconds: number;
|
|
163
|
+
}
|
|
164
|
+
interface RateLimiterOptions {
|
|
165
|
+
windowMs?: number;
|
|
166
|
+
maxRequests?: number;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Per-key sliding-window limiter. `check(apiKeyId)` records the request and
|
|
170
|
+
* returns whether it is allowed.
|
|
171
|
+
*/
|
|
172
|
+
declare class OutboundRateLimiter {
|
|
173
|
+
private readonly windowMs;
|
|
174
|
+
private readonly maxRequests;
|
|
175
|
+
/** apiKeyId → ascending request timestamps within the current window. */
|
|
176
|
+
private readonly hits;
|
|
177
|
+
constructor(options?: RateLimiterOptions);
|
|
178
|
+
/**
|
|
179
|
+
* Record a request for `apiKeyId` and decide whether it is allowed. Prunes
|
|
180
|
+
* timestamps older than the window first; when allowed, the request's
|
|
181
|
+
* timestamp is appended.
|
|
182
|
+
*/
|
|
183
|
+
check(apiKeyId: string, now?: number): RateLimitDecision;
|
|
184
|
+
/** Drop all recorded state (tests / teardown). */
|
|
185
|
+
reset(): void;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* roleDetection — classify an outbound request's ROLE (vision / background /
|
|
190
|
+
* default) so the route resolver can pick the endpoint's model for that role
|
|
191
|
+
* (`outbound-api-server`, design D2).
|
|
192
|
+
*
|
|
193
|
+
* Precedence: vision > background > default.
|
|
194
|
+
* - vision — the body carries image/vision content parts (per-format
|
|
195
|
+
* detection). The route resolver applies the vision→default
|
|
196
|
+
* fallback when the endpoint has no vision model.
|
|
197
|
+
* - background — the requested model id is in the endpoint's optional
|
|
198
|
+
* background-model-id override list (human decision after the
|
|
199
|
+
* proposal), OR the registry small/haiku-class name signal
|
|
200
|
+
* matches (Claude Code's haiku probe sends exactly this).
|
|
201
|
+
* - default — everything else.
|
|
202
|
+
*
|
|
203
|
+
* Each ingress's body shape is handled here in ONE place.
|
|
204
|
+
*
|
|
205
|
+
* @module outbound-api/roleDetection
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Detect the request's role. `backgroundModelIds` is the endpoint's optional
|
|
210
|
+
* override list: when an incoming requested model id matches an entry there, the
|
|
211
|
+
* request is BACKGROUND regardless of the name signal; otherwise the registry
|
|
212
|
+
* small/haiku-class name signal is the baseline. Precedence vision > background
|
|
213
|
+
* > default.
|
|
214
|
+
*/
|
|
215
|
+
declare function detectRequestRole(ingressFormat: IngressFormat, body: Record<string, unknown>, options?: {
|
|
216
|
+
backgroundModelIds?: string[];
|
|
217
|
+
}): RequestRole;
|
|
218
|
+
/** Map a settings endpoint id to the provider-proxy ingress format. */
|
|
219
|
+
declare function endpointToIngressFormat(endpoint: 'chat' | 'responses' | 'messages' | 'gemini'): IngressFormat;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* subscriptionSupport — single source of truth for (a) which provider ids are
|
|
223
|
+
* subscription-backed and (b) which outbound endpoints can soundly serve a
|
|
224
|
+
* subscription route (`outbound-api-server`, design D2 + review M1/m1).
|
|
225
|
+
*
|
|
226
|
+
* The subscription-id catalog mirrors `SubscriptionProviderRegistry`'s ids; the
|
|
227
|
+
* static fast-path is backstopped at runtime by a live registry lookup (see
|
|
228
|
+
* `isSubscriptionProviderId`) so it degrades gracefully if it drifts. Both
|
|
229
|
+
* `routeResolver` and `apiServerHandlers` import from here — no duplicated set.
|
|
230
|
+
*
|
|
231
|
+
* @module outbound-api/subscriptionSupport
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The registry-aligned subscription provider ids — the outbound layer's SSOT
|
|
236
|
+
* fast-path. NOTE: `SubscriptionProviderId` is currently a `z.string()` alias,
|
|
237
|
+
* so this `readonly SubscriptionProviderId[]` typing does NOT compile-enforce
|
|
238
|
+
* alignment with the registry; drift is instead tolerated at runtime by
|
|
239
|
+
* `isSubscriptionProviderId`'s live `registry.getProfile` fallback.
|
|
240
|
+
*/
|
|
241
|
+
declare const SUBSCRIPTION_PROVIDER_IDS: readonly SubscriptionProviderId[];
|
|
242
|
+
/**
|
|
243
|
+
* True when a provider id refers to a subscription-backed provider. Checks the
|
|
244
|
+
* registry-aligned static catalog first, then falls back to a live registry
|
|
245
|
+
* lookup (so a registry addition is honored even before this list is updated).
|
|
246
|
+
*
|
|
247
|
+
* NOTE (review m2): this classifies by id string. The resolver MUST confirm the
|
|
248
|
+
* id does not resolve to a real BYO provider row before treating it as
|
|
249
|
+
* subscription-backed — see `routeResolver` (BYO rows win).
|
|
250
|
+
*/
|
|
251
|
+
declare function isSubscriptionProviderId(providerId: string): boolean;
|
|
252
|
+
/** True when the endpoint's ingress can soundly serve a subscription route. */
|
|
253
|
+
declare function endpointSupportsSubscription(endpoint: OutboundEndpoint): boolean;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* routeResolver — turn an endpoint's `EndpointRoutingConfig` + the detected
|
|
257
|
+
* request role into a `RouteContext` for the shared `provider-proxy` dispatch
|
|
258
|
+
* (`outbound-api-server`, design D2).
|
|
259
|
+
*
|
|
260
|
+
* Steps:
|
|
261
|
+
* 1. Pick the model for the role (vision → default fallback when `visionModel`
|
|
262
|
+
* is unset; vision is optional).
|
|
263
|
+
* 2. Parse the chosen `"providerId,modelId"` ref.
|
|
264
|
+
* 3. Gate by `useSubscription`: OFF → only BYO-key providers are eligible
|
|
265
|
+
* (subscription-backed providers excluded); ON → subscription-backed
|
|
266
|
+
* providers are eligible.
|
|
267
|
+
* 4. Resolve the provider (BYO via the `ProviderConfigSource`; subscription via the
|
|
268
|
+
* subscription registry) and build the `RouteContext` exactly as the
|
|
269
|
+
* internal callers do.
|
|
270
|
+
* 5. Return a clear `503`-style error when the role's required model is unset,
|
|
271
|
+
* the provider is unavailable, or the subscription gate excludes it.
|
|
272
|
+
*
|
|
273
|
+
* @module outbound-api/routeResolver
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
/** A 503-style resolution failure. */
|
|
277
|
+
interface RouteResolveError {
|
|
278
|
+
status: number;
|
|
279
|
+
message: string;
|
|
280
|
+
}
|
|
281
|
+
type RouteResolveResult = {
|
|
282
|
+
ok: true;
|
|
283
|
+
route: RouteContext;
|
|
284
|
+
usedRole: RequestRole;
|
|
285
|
+
} | {
|
|
286
|
+
ok: false;
|
|
287
|
+
error: RouteResolveError;
|
|
288
|
+
};
|
|
289
|
+
/** Resolve a route for one authenticated outbound request. */
|
|
290
|
+
declare function resolveRoute(args: {
|
|
291
|
+
config: EndpointRoutingConfig;
|
|
292
|
+
role: RequestRole;
|
|
293
|
+
ingressFormat: IngressFormat;
|
|
294
|
+
llmConfig: ProviderConfigSource;
|
|
295
|
+
sessionId?: string | null;
|
|
296
|
+
}): Promise<RouteResolveResult>;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Outbound API server module — barrel + singleton accessor.
|
|
300
|
+
*
|
|
301
|
+
* The outbound server is constructed ONCE at app bootstrap (sharing the
|
|
302
|
+
* resident `ProviderProxy`'s route map + deps) and started only when the
|
|
303
|
+
* persisted `enabled` setting is true. `getOutboundApiServer(deps)` mirrors
|
|
304
|
+
* `getProviderProxy()`: the first call constructs the instance from the supplied
|
|
305
|
+
* deps; later calls return it.
|
|
306
|
+
*
|
|
307
|
+
* @module outbound-api/index
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get (or lazily construct) the outbound API server singleton.
|
|
312
|
+
*
|
|
313
|
+
* @param deps Required on the FIRST call (app bootstrap). Ignored afterward.
|
|
314
|
+
* @param onPortChange Optional persistence hook for the EADDRINUSE fallback.
|
|
315
|
+
*/
|
|
316
|
+
declare function getOutboundApiServer(deps?: OutboundApiDeps, onPortChange?: (port: number) => void): OutboundApiServer;
|
|
317
|
+
/** Reset the singleton (tests / teardown only). */
|
|
318
|
+
declare function __resetOutboundApiServerForTests(): void;
|
|
319
|
+
|
|
320
|
+
export { type ApiServerSettingsStore, type ApplyConfigInput, DEFAULT_OUTBOUND_PORT, EndpointRoutingConfig, OUTBOUND_API_SERVER_CONFIG_KEY, OutboundApiDeps, OutboundApiKeyCreated, OutboundApiServer, OutboundApiServerConfig, OutboundApiServerStatus, OutboundEndpoint, OutboundFormatUrls, OutboundKeyDb, OutboundRateLimiter, RequestRole, SUBSCRIPTION_PROVIDER_IDS, __resetOutboundApiServerForTests, createNamedKey, defaultServerConfig, detectRequestRole, endpointSupportsSubscription, endpointToIngressFormat, formatUrls, getOutboundApiServer, hashKey, isSubscriptionProviderId, loadServerConfig, mergeServerConfig, normalizeServerConfig, resolveRoute, saveServerConfig, verifyPresentedKey };
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import { E as EndpointRoutingConfig, a as OutboundApiDeps, e as OutboundApiServerStatus, g as OutboundFormatUrls, d as OutboundApiServerConfig, O as OutboundKeyDb, b as OutboundApiKeyCreated, R as RequestRole, f as OutboundEndpoint } from './types-CbCN2NQP.js';
|
|
2
|
+
export { c as OutboundApiKeyInfo, h as OutboundKeyDbRow } from './types-CbCN2NQP.js';
|
|
3
|
+
import { I as IngressFormat, P as ProviderConfigSource, g as RouteContext } from './types-DCzHkhJt.js';
|
|
4
|
+
import { SubscriptionProviderId } from '@omnicross/contracts/subscription-types';
|
|
5
|
+
import './ProviderProxy-vjt8sQQk.js';
|
|
6
|
+
import 'node:http';
|
|
7
|
+
import '@omnicross/contracts/completion-types';
|
|
8
|
+
import '@omnicross/contracts/usage-types';
|
|
9
|
+
import './ApiKeyPoolService-BmMkau07.js';
|
|
10
|
+
import '@omnicross/contracts/llm-config';
|
|
11
|
+
import './SubscriptionAuthSource-D89zmiSS.js';
|
|
12
|
+
import './pipeline/SubscriptionAuthStrategy.js';
|
|
13
|
+
import './transformer/types.js';
|
|
14
|
+
import './transformer/TransformerService.js';
|
|
15
|
+
import '@omnicross/contracts/websearch-types';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* OutboundApiServer — the external-facing HTTP listener for the outbound API
|
|
19
|
+
* server (`outbound-api-server`, design D1/D4/D5).
|
|
20
|
+
*
|
|
21
|
+
* A SEPARATE long-lived `http.Server` (distinct from the resident loopback
|
|
22
|
+
* `ProviderProxy`). It binds `127.0.0.1` by default, or `0.0.0.0` when network
|
|
23
|
+
* binding is enabled. Every request — INCLUDING loopback — is authenticated by
|
|
24
|
+
* a named API key (no loopback bypass). Each authenticated request mints a route
|
|
25
|
+
* on the SHARED `ProviderProxyRouteMap` and delegates to the existing
|
|
26
|
+
* `routeRequest()` dispatch so the four ingress parsers + transformer are
|
|
27
|
+
* reused (one conversion stack).
|
|
28
|
+
*
|
|
29
|
+
* Lifecycle:
|
|
30
|
+
* - `applyConfig({ enabled, networkBinding, endpoints, port })` — restart ONLY
|
|
31
|
+
* when the bind address or port changes; per-endpoint routing config is read
|
|
32
|
+
* live per request (no restart).
|
|
33
|
+
* - `getStatus()` — running, actual port, loopback + optional LAN URLs, the
|
|
34
|
+
* four format URLs.
|
|
35
|
+
* - `EADDRINUSE` → fall back to an ephemeral port, persist it (via the caller's
|
|
36
|
+
* `onPortChange`), and surface the actual port.
|
|
37
|
+
*
|
|
38
|
+
* @module outbound-api/OutboundApiServer
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/** Fixed default port (design D5). Persisted + configurable. */
|
|
42
|
+
declare const DEFAULT_OUTBOUND_PORT = 8765;
|
|
43
|
+
/** Per-call apply config (the persisted server config minus runtime state). */
|
|
44
|
+
interface ApplyConfigInput {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
networkBinding: boolean;
|
|
47
|
+
endpoints: EndpointRoutingConfig[];
|
|
48
|
+
port?: number;
|
|
49
|
+
}
|
|
50
|
+
declare class OutboundApiServer {
|
|
51
|
+
private readonly deps;
|
|
52
|
+
/** Called when the actual bound port differs from the requested one. */
|
|
53
|
+
private readonly onPortChange?;
|
|
54
|
+
private server;
|
|
55
|
+
private boundPort;
|
|
56
|
+
private boundAddr;
|
|
57
|
+
private endpoints;
|
|
58
|
+
private readonly rateLimiter;
|
|
59
|
+
constructor(deps: OutboundApiDeps,
|
|
60
|
+
/** Called when the actual bound port differs from the requested one. */
|
|
61
|
+
onPortChange?: ((port: number) => void) | undefined);
|
|
62
|
+
/**
|
|
63
|
+
* Apply a config. Restarts the listener ONLY when the bind address or port
|
|
64
|
+
* changes (or when toggling enabled); per-endpoint routing config is updated
|
|
65
|
+
* in place (read live per request — no restart).
|
|
66
|
+
*/
|
|
67
|
+
applyConfig(input: ApplyConfigInput): Promise<void>;
|
|
68
|
+
/** Start the listener on `bindAddr:port`, falling back on EADDRINUSE. */
|
|
69
|
+
start(bindAddr: string, port: number): Promise<number>;
|
|
70
|
+
/** Bind once; on EADDRINUSE retry with an ephemeral port (port 0). */
|
|
71
|
+
private listen;
|
|
72
|
+
/** Per-request handler. Auth is enforced on EVERY request (incl. loopback). */
|
|
73
|
+
private onRequest;
|
|
74
|
+
/** Stop the listener and release the port. */
|
|
75
|
+
stop(): Promise<void>;
|
|
76
|
+
/** A live status snapshot for the Settings tab. */
|
|
77
|
+
getStatus(): OutboundApiServerStatus;
|
|
78
|
+
}
|
|
79
|
+
/** Build the four format endpoint URLs for a base URL. */
|
|
80
|
+
declare function formatUrls(base: string): OutboundFormatUrls;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* apiServerConfig — load / save / default the outbound API server config
|
|
84
|
+
* (`outbound-api-server`, design D4).
|
|
85
|
+
*
|
|
86
|
+
* The config (`{ enabled, networkBinding, endpoints, port }`) is persisted via
|
|
87
|
+
* a small key/value store (the app SettingsService) under a single key, so it
|
|
88
|
+
* survives restart. Defaults: disabled, loopback, four endpoints with empty
|
|
89
|
+
* models + `useSubscription` OFF, default port. Shared by the router and the
|
|
90
|
+
* bootstrap wiring so both read/write the same shape.
|
|
91
|
+
*
|
|
92
|
+
* @module outbound-api/apiServerConfig
|
|
93
|
+
*/
|
|
94
|
+
|
|
95
|
+
/** The settings key the config persists under. */
|
|
96
|
+
declare const OUTBOUND_API_SERVER_CONFIG_KEY = "outboundApiServer.config";
|
|
97
|
+
/** Structural subset of the settings store the config loader needs. */
|
|
98
|
+
interface ApiServerSettingsStore {
|
|
99
|
+
get<T = unknown>(key: string): Promise<T | undefined>;
|
|
100
|
+
set<T = unknown>(key: string, value: T): Promise<void>;
|
|
101
|
+
}
|
|
102
|
+
/** The default server config: disabled, loopback, four blank endpoints. */
|
|
103
|
+
declare function defaultServerConfig(): OutboundApiServerConfig;
|
|
104
|
+
/**
|
|
105
|
+
* Normalize a (possibly partial / legacy) persisted config to the full shape:
|
|
106
|
+
* ensure all four endpoints exist, `useSubscription` defaults OFF, and a port
|
|
107
|
+
* is present.
|
|
108
|
+
*/
|
|
109
|
+
declare function normalizeServerConfig(raw: Partial<OutboundApiServerConfig> | undefined | null): OutboundApiServerConfig;
|
|
110
|
+
/** Load the persisted config (normalized), defaulting on a missing/blank key. */
|
|
111
|
+
declare function loadServerConfig(store: ApiServerSettingsStore): Promise<OutboundApiServerConfig>;
|
|
112
|
+
/** Persist the config. */
|
|
113
|
+
declare function saveServerConfig(store: ApiServerSettingsStore, config: OutboundApiServerConfig): Promise<void>;
|
|
114
|
+
/** Apply a partial patch to a config, returning the merged whole. */
|
|
115
|
+
declare function mergeServerConfig(current: OutboundApiServerConfig, patch: Partial<OutboundApiServerConfig>): OutboundApiServerConfig;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* outboundApiKeyAuth — named-key generation, hashing, and verification for the
|
|
119
|
+
* outbound API server (`outbound-api-server`).
|
|
120
|
+
*
|
|
121
|
+
* Keys are 128-bit+ random secrets (`sk-omnicross-<base62>`), NOT human passwords,
|
|
122
|
+
* so a single fast hash (sha256) is sufficient and keeps the hot auth path
|
|
123
|
+
* cheap (design D3). Only the hash + a short display prefix are persisted; the
|
|
124
|
+
* full plaintext is returned exactly once at creation.
|
|
125
|
+
*
|
|
126
|
+
* @module outbound-api/outboundApiKeyAuth
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/** Hash a presented/generated secret (sha256 hex). */
|
|
130
|
+
declare function hashKey(secret: string): string;
|
|
131
|
+
/**
|
|
132
|
+
* Create + persist a named key. Returns the plaintext ONCE; only the hash +
|
|
133
|
+
* prefix are stored.
|
|
134
|
+
*/
|
|
135
|
+
declare function createNamedKey(db: OutboundKeyDb, name: string): Promise<OutboundApiKeyCreated>;
|
|
136
|
+
/** The id of a verified key (for rate-limiting + last-used bookkeeping). */
|
|
137
|
+
interface VerifiedKey {
|
|
138
|
+
id: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Verify a presented key against the DB. Matches by hash where the stored row
|
|
142
|
+
* is enabled AND not revoked (the DB query enforces this). On success bumps
|
|
143
|
+
* `lastUsedAt` (best-effort, fire-and-forget) and returns the key id; returns
|
|
144
|
+
* `null` on any miss / disabled / revoked key.
|
|
145
|
+
*/
|
|
146
|
+
declare function verifyPresentedKey(db: OutboundKeyDb, presentedKey: string | undefined): Promise<VerifiedKey | null>;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* outboundRateLimiter — per-API-key in-memory sliding-window rate limiter for
|
|
150
|
+
* the outbound API server (`outbound-api-server`, design D6).
|
|
151
|
+
*
|
|
152
|
+
* A simple fixed-size sliding window keyed by `apiKeyId`. In-memory only (resets
|
|
153
|
+
* on app restart, acceptable for v1). Exceeding the limit returns a deny with a
|
|
154
|
+
* `Retry-After` (seconds). Limits are conservative defaults, not user-
|
|
155
|
+
* configurable in v1.
|
|
156
|
+
*
|
|
157
|
+
* @module outbound-api/outboundRateLimiter
|
|
158
|
+
*/
|
|
159
|
+
interface RateLimitDecision {
|
|
160
|
+
allowed: boolean;
|
|
161
|
+
/** Seconds until the window frees up (only meaningful when `!allowed`). */
|
|
162
|
+
retryAfterSeconds: number;
|
|
163
|
+
}
|
|
164
|
+
interface RateLimiterOptions {
|
|
165
|
+
windowMs?: number;
|
|
166
|
+
maxRequests?: number;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Per-key sliding-window limiter. `check(apiKeyId)` records the request and
|
|
170
|
+
* returns whether it is allowed.
|
|
171
|
+
*/
|
|
172
|
+
declare class OutboundRateLimiter {
|
|
173
|
+
private readonly windowMs;
|
|
174
|
+
private readonly maxRequests;
|
|
175
|
+
/** apiKeyId → ascending request timestamps within the current window. */
|
|
176
|
+
private readonly hits;
|
|
177
|
+
constructor(options?: RateLimiterOptions);
|
|
178
|
+
/**
|
|
179
|
+
* Record a request for `apiKeyId` and decide whether it is allowed. Prunes
|
|
180
|
+
* timestamps older than the window first; when allowed, the request's
|
|
181
|
+
* timestamp is appended.
|
|
182
|
+
*/
|
|
183
|
+
check(apiKeyId: string, now?: number): RateLimitDecision;
|
|
184
|
+
/** Drop all recorded state (tests / teardown). */
|
|
185
|
+
reset(): void;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* roleDetection — classify an outbound request's ROLE (vision / background /
|
|
190
|
+
* default) so the route resolver can pick the endpoint's model for that role
|
|
191
|
+
* (`outbound-api-server`, design D2).
|
|
192
|
+
*
|
|
193
|
+
* Precedence: vision > background > default.
|
|
194
|
+
* - vision — the body carries image/vision content parts (per-format
|
|
195
|
+
* detection). The route resolver applies the vision→default
|
|
196
|
+
* fallback when the endpoint has no vision model.
|
|
197
|
+
* - background — the requested model id is in the endpoint's optional
|
|
198
|
+
* background-model-id override list (human decision after the
|
|
199
|
+
* proposal), OR the registry small/haiku-class name signal
|
|
200
|
+
* matches (Claude Code's haiku probe sends exactly this).
|
|
201
|
+
* - default — everything else.
|
|
202
|
+
*
|
|
203
|
+
* Each ingress's body shape is handled here in ONE place.
|
|
204
|
+
*
|
|
205
|
+
* @module outbound-api/roleDetection
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Detect the request's role. `backgroundModelIds` is the endpoint's optional
|
|
210
|
+
* override list: when an incoming requested model id matches an entry there, the
|
|
211
|
+
* request is BACKGROUND regardless of the name signal; otherwise the registry
|
|
212
|
+
* small/haiku-class name signal is the baseline. Precedence vision > background
|
|
213
|
+
* > default.
|
|
214
|
+
*/
|
|
215
|
+
declare function detectRequestRole(ingressFormat: IngressFormat, body: Record<string, unknown>, options?: {
|
|
216
|
+
backgroundModelIds?: string[];
|
|
217
|
+
}): RequestRole;
|
|
218
|
+
/** Map a settings endpoint id to the provider-proxy ingress format. */
|
|
219
|
+
declare function endpointToIngressFormat(endpoint: 'chat' | 'responses' | 'messages' | 'gemini'): IngressFormat;
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* subscriptionSupport — single source of truth for (a) which provider ids are
|
|
223
|
+
* subscription-backed and (b) which outbound endpoints can soundly serve a
|
|
224
|
+
* subscription route (`outbound-api-server`, design D2 + review M1/m1).
|
|
225
|
+
*
|
|
226
|
+
* The subscription-id catalog mirrors `SubscriptionProviderRegistry`'s ids; the
|
|
227
|
+
* static fast-path is backstopped at runtime by a live registry lookup (see
|
|
228
|
+
* `isSubscriptionProviderId`) so it degrades gracefully if it drifts. Both
|
|
229
|
+
* `routeResolver` and `apiServerHandlers` import from here — no duplicated set.
|
|
230
|
+
*
|
|
231
|
+
* @module outbound-api/subscriptionSupport
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The registry-aligned subscription provider ids — the outbound layer's SSOT
|
|
236
|
+
* fast-path. NOTE: `SubscriptionProviderId` is currently a `z.string()` alias,
|
|
237
|
+
* so this `readonly SubscriptionProviderId[]` typing does NOT compile-enforce
|
|
238
|
+
* alignment with the registry; drift is instead tolerated at runtime by
|
|
239
|
+
* `isSubscriptionProviderId`'s live `registry.getProfile` fallback.
|
|
240
|
+
*/
|
|
241
|
+
declare const SUBSCRIPTION_PROVIDER_IDS: readonly SubscriptionProviderId[];
|
|
242
|
+
/**
|
|
243
|
+
* True when a provider id refers to a subscription-backed provider. Checks the
|
|
244
|
+
* registry-aligned static catalog first, then falls back to a live registry
|
|
245
|
+
* lookup (so a registry addition is honored even before this list is updated).
|
|
246
|
+
*
|
|
247
|
+
* NOTE (review m2): this classifies by id string. The resolver MUST confirm the
|
|
248
|
+
* id does not resolve to a real BYO provider row before treating it as
|
|
249
|
+
* subscription-backed — see `routeResolver` (BYO rows win).
|
|
250
|
+
*/
|
|
251
|
+
declare function isSubscriptionProviderId(providerId: string): boolean;
|
|
252
|
+
/** True when the endpoint's ingress can soundly serve a subscription route. */
|
|
253
|
+
declare function endpointSupportsSubscription(endpoint: OutboundEndpoint): boolean;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* routeResolver — turn an endpoint's `EndpointRoutingConfig` + the detected
|
|
257
|
+
* request role into a `RouteContext` for the shared `provider-proxy` dispatch
|
|
258
|
+
* (`outbound-api-server`, design D2).
|
|
259
|
+
*
|
|
260
|
+
* Steps:
|
|
261
|
+
* 1. Pick the model for the role (vision → default fallback when `visionModel`
|
|
262
|
+
* is unset; vision is optional).
|
|
263
|
+
* 2. Parse the chosen `"providerId,modelId"` ref.
|
|
264
|
+
* 3. Gate by `useSubscription`: OFF → only BYO-key providers are eligible
|
|
265
|
+
* (subscription-backed providers excluded); ON → subscription-backed
|
|
266
|
+
* providers are eligible.
|
|
267
|
+
* 4. Resolve the provider (BYO via the `ProviderConfigSource`; subscription via the
|
|
268
|
+
* subscription registry) and build the `RouteContext` exactly as the
|
|
269
|
+
* internal callers do.
|
|
270
|
+
* 5. Return a clear `503`-style error when the role's required model is unset,
|
|
271
|
+
* the provider is unavailable, or the subscription gate excludes it.
|
|
272
|
+
*
|
|
273
|
+
* @module outbound-api/routeResolver
|
|
274
|
+
*/
|
|
275
|
+
|
|
276
|
+
/** A 503-style resolution failure. */
|
|
277
|
+
interface RouteResolveError {
|
|
278
|
+
status: number;
|
|
279
|
+
message: string;
|
|
280
|
+
}
|
|
281
|
+
type RouteResolveResult = {
|
|
282
|
+
ok: true;
|
|
283
|
+
route: RouteContext;
|
|
284
|
+
usedRole: RequestRole;
|
|
285
|
+
} | {
|
|
286
|
+
ok: false;
|
|
287
|
+
error: RouteResolveError;
|
|
288
|
+
};
|
|
289
|
+
/** Resolve a route for one authenticated outbound request. */
|
|
290
|
+
declare function resolveRoute(args: {
|
|
291
|
+
config: EndpointRoutingConfig;
|
|
292
|
+
role: RequestRole;
|
|
293
|
+
ingressFormat: IngressFormat;
|
|
294
|
+
llmConfig: ProviderConfigSource;
|
|
295
|
+
sessionId?: string | null;
|
|
296
|
+
}): Promise<RouteResolveResult>;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Outbound API server module — barrel + singleton accessor.
|
|
300
|
+
*
|
|
301
|
+
* The outbound server is constructed ONCE at app bootstrap (sharing the
|
|
302
|
+
* resident `ProviderProxy`'s route map + deps) and started only when the
|
|
303
|
+
* persisted `enabled` setting is true. `getOutboundApiServer(deps)` mirrors
|
|
304
|
+
* `getProviderProxy()`: the first call constructs the instance from the supplied
|
|
305
|
+
* deps; later calls return it.
|
|
306
|
+
*
|
|
307
|
+
* @module outbound-api/index
|
|
308
|
+
*/
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get (or lazily construct) the outbound API server singleton.
|
|
312
|
+
*
|
|
313
|
+
* @param deps Required on the FIRST call (app bootstrap). Ignored afterward.
|
|
314
|
+
* @param onPortChange Optional persistence hook for the EADDRINUSE fallback.
|
|
315
|
+
*/
|
|
316
|
+
declare function getOutboundApiServer(deps?: OutboundApiDeps, onPortChange?: (port: number) => void): OutboundApiServer;
|
|
317
|
+
/** Reset the singleton (tests / teardown only). */
|
|
318
|
+
declare function __resetOutboundApiServerForTests(): void;
|
|
319
|
+
|
|
320
|
+
export { type ApiServerSettingsStore, type ApplyConfigInput, DEFAULT_OUTBOUND_PORT, EndpointRoutingConfig, OUTBOUND_API_SERVER_CONFIG_KEY, OutboundApiDeps, OutboundApiKeyCreated, OutboundApiServer, OutboundApiServerConfig, OutboundApiServerStatus, OutboundEndpoint, OutboundFormatUrls, OutboundKeyDb, OutboundRateLimiter, RequestRole, SUBSCRIPTION_PROVIDER_IDS, __resetOutboundApiServerForTests, createNamedKey, defaultServerConfig, detectRequestRole, endpointSupportsSubscription, endpointToIngressFormat, formatUrls, getOutboundApiServer, hashKey, isSubscriptionProviderId, loadServerConfig, mergeServerConfig, normalizeServerConfig, resolveRoute, saveServerConfig, verifyPresentedKey };
|