@omnicross/daemon 0.1.6 → 0.1.8
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/dist/cli.cjs +1186 -200
- package/dist/cli.js +1200 -191
- package/dist/index.cjs +1118 -147
- package/dist/index.d.cts +101 -26
- package/dist/index.d.ts +101 -26
- package/dist/index.js +1135 -139
- package/package.json +63 -63
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import * as _omnicross_core from '@omnicross/core';
|
|
|
2
2
|
import { OutboundApiServerConfig, Logger, ProviderConfigSource, TransformerService, Transformer, ResolvedTransformerChain, ApiServerSettingsStore, PricingStore, AutomaticPricingSource, OutboundKeyDb, OutboundKeyDbRow, OutboundKeyPolicy, PricingEngine as PricingEngine$1 } from '@omnicross/core';
|
|
3
3
|
import { ApiKeyPoolService } from '@omnicross/core/completion/ApiKeyPoolService';
|
|
4
4
|
import { AllowanceSchedulingConfig, AccountProbeConfig, OutboundKeyDb as OutboundKeyDb$1, VoucherDb, KeySpendReader, OutboundApiServer } from '@omnicross/core/outbound-api';
|
|
5
|
-
import { ProviderProxy } from '@omnicross/core/provider-proxy';
|
|
5
|
+
import { RouteLeaseManager, ProviderProxy } from '@omnicross/core/provider-proxy';
|
|
6
6
|
import { UsageRecorder, PricingEngine } from '@omnicross/core/usage';
|
|
7
7
|
import { SubscriptionCredentialStore, FetchLike, SubscriptionProviderRegistry, SubscriptionAccountService } from '@omnicross/subscriptions';
|
|
8
8
|
import { AccountAllowanceSnapshot } from '@omnicross/contracts/account-allowance-types';
|
|
@@ -15,7 +15,7 @@ import { SubscriptionIdentityStore } from '@omnicross/core/provider-proxy/identi
|
|
|
15
15
|
import { LoggingConfig, HealthReport } from '@omnicross/contracts/health-logging-types';
|
|
16
16
|
import { SubscriptionAccountHealth } from '@omnicross/core/pipeline/SubscriptionAccountHealth';
|
|
17
17
|
import { fetchUpstream } from '@omnicross/core/pipeline/upstreamFetch';
|
|
18
|
-
import { AuditRecord, AuditConfig } from '@omnicross/contracts/audit-types';
|
|
18
|
+
import { AuditRecord, AuditStats, AuditConfig } from '@omnicross/contracts/audit-types';
|
|
19
19
|
import { BillingDeliveryStatus, BillingConfig, BillingEvent } from '@omnicross/contracts/billing-types';
|
|
20
20
|
import http from 'node:http';
|
|
21
21
|
import { LLMProvider, AgentDefaultModels, GlobalModelParameters } from '@omnicross/contracts/llm-config';
|
|
@@ -579,6 +579,12 @@ declare class JsonSubscriptionCredentialStore implements SubscriptionCredentialS
|
|
|
579
579
|
* TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
|
|
580
580
|
* through {@link fetchUpstream} with the account's `{ providerId, accountId }`
|
|
581
581
|
* ctx so the per-account/provider proxy applies. `@internal` also a test seam.
|
|
582
|
+
*
|
|
583
|
+
* `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
|
|
584
|
+
* receives a fresh access/refresh token pair. Carrying a `providerId` opts the
|
|
585
|
+
* call into the upstream trace (so a failing refresh is diagnosable), and the
|
|
586
|
+
* trace captures bodies verbatim — without this flag every refresh would write
|
|
587
|
+
* a plaintext token pair into `upstream-trace.jsonl`.
|
|
582
588
|
*/
|
|
583
589
|
buildRefreshFetch(providerId: string, accountId?: string): FetchLike;
|
|
584
590
|
/**
|
|
@@ -923,11 +929,12 @@ interface SubscriptionTokenWriter {
|
|
|
923
929
|
* app-parity child 4, design D1).
|
|
924
930
|
*
|
|
925
931
|
* `start` mints a crypto-random `sessionId` and stashes the per-session PKCE
|
|
926
|
-
* `{ providerId, codeVerifier, state }` here; `complete`
|
|
927
|
-
* `
|
|
932
|
+
* `{ providerId, codeVerifier, state }` here; `complete` `peek`s the session,
|
|
933
|
+
* exchanges the code, and `consume`s it ONLY once a token was minted — so a
|
|
934
|
+
* failed exchange leaves the session retryable instead of burning it. The map is
|
|
928
935
|
* NEVER serialized to the client — only the opaque `sessionId` + the public
|
|
929
936
|
* `authUrl` cross the wire. Sessions are short-lived (OQ3 = 10-min TTL); a sweep
|
|
930
|
-
* reaps abandoned sessions, and `
|
|
937
|
+
* reaps abandoned sessions, and `peek` re-checks the TTL so an expired-but-not-
|
|
931
938
|
* yet-swept session is still rejected. A daemon restart simply drops in-flight
|
|
932
939
|
* logins (correct fail-safe — no partial token is ever written).
|
|
933
940
|
*
|
|
@@ -963,13 +970,25 @@ declare class OAuthSessionStore {
|
|
|
963
970
|
*/
|
|
964
971
|
put(session: Omit<PendingOAuthSession, 'createdAt'>): string;
|
|
965
972
|
/**
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
* dropped). A `null` return means the completer must reject (no
|
|
969
|
-
* write).
|
|
973
|
+
* NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
|
|
974
|
+
* it is unknown, already consumed, or past its TTL (an expired entry is
|
|
975
|
+
* dropped here). A `null` return means the completer must reject (no
|
|
976
|
+
* exchange, no write).
|
|
977
|
+
*
|
|
978
|
+
* Deliberately NOT a consume: the completer peeks, runs the token exchange,
|
|
979
|
+
* and only {@link consume}s once a token has actually been minted. Consuming
|
|
980
|
+
* up-front burned the session on EVERY failed exchange (a mistyped/expired
|
|
981
|
+
* pasted code, a proxy hiccup), so the user's natural retry hit
|
|
982
|
+
* "session is unknown, expired, or already used" and the login became
|
|
983
|
+
* unrecoverable without restarting the whole flow.
|
|
984
|
+
*/
|
|
985
|
+
peek(sessionId: string): PendingOAuthSession | null;
|
|
986
|
+
/**
|
|
987
|
+
* SINGLE-USE burn: drop the session so the same `sessionId` can never be
|
|
988
|
+
* completed twice. Called ONLY after a successful token exchange.
|
|
970
989
|
*/
|
|
971
|
-
|
|
972
|
-
/** Drop every session past its TTL. Called on each put/
|
|
990
|
+
consume(sessionId: string): void;
|
|
991
|
+
/** Drop every session past its TTL. Called on each put/peek. */
|
|
973
992
|
private sweep;
|
|
974
993
|
}
|
|
975
994
|
|
|
@@ -983,10 +1002,12 @@ declare class OAuthSessionStore {
|
|
|
983
1002
|
* provider's authorize params and stashes the per-session `{ codeVerifier, state }`
|
|
984
1003
|
* in the `OAuthSessionStore` keyed by a minted opaque `sessionId`, returning ONLY
|
|
985
1004
|
* `{ authUrl, sessionId }` (the `authUrl` carries client_id + PKCE challenge +
|
|
986
|
-
* state — all public). `complete`
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
* it active, and responds ONLY
|
|
1005
|
+
* state — all public). `complete` `peek`s the session, validates state (claude's
|
|
1006
|
+
* `code#state`), `exchangeCodeForTokens(...)`, then — and ONLY then — `consume`s
|
|
1007
|
+
* the session (single-use), persists the minted token through the encrypted
|
|
1008
|
+
* credential store (`appendProviderAccount`) + marks it active, and responds ONLY
|
|
1009
|
+
* the sanitized `SubscriptionListEntry`. A FAILED exchange leaves the session
|
|
1010
|
+
* intact so the user can retry within its TTL instead of being locked out by a 410.
|
|
990
1011
|
*
|
|
991
1012
|
* SECRET SPINE (the load-bearing invariant): the minted access/refresh token
|
|
992
1013
|
* NEVER appears in any response body or log; the `codeVerifier` / session map is
|
|
@@ -1283,7 +1304,14 @@ interface ProbeRecord {
|
|
|
1283
1304
|
/** Upstream round-trip latency (ms); absent for a local-tier record. */
|
|
1284
1305
|
latencyMs?: number;
|
|
1285
1306
|
/** Which tier produced this record. */
|
|
1286
|
-
tier: 'local' | 'upstream';
|
|
1307
|
+
tier: 'local' | 'upstream' | 'generation';
|
|
1308
|
+
}
|
|
1309
|
+
/** Secret-free outcome returned by the manual account connection-test route. */
|
|
1310
|
+
interface AccountConnectionProbeOutcome {
|
|
1311
|
+
ok: boolean;
|
|
1312
|
+
marked: boolean;
|
|
1313
|
+
tier: ProbeRecord['tier'];
|
|
1314
|
+
model?: string;
|
|
1287
1315
|
}
|
|
1288
1316
|
/** Per-account probe history for the authed admin surface (names account ids). */
|
|
1289
1317
|
interface AccountProbeHistorySnapshot {
|
|
@@ -1303,6 +1331,8 @@ interface AccountProbeHistoryReader {
|
|
|
1303
1331
|
interface ProbeCredentialStore {
|
|
1304
1332
|
getFullConfig(): Promise<AccountTokensConfig>;
|
|
1305
1333
|
getAccessTokenForAccount(providerId: SubscriptionProviderId, accountId: string): Promise<string | null>;
|
|
1334
|
+
/** Optional serving-parity retry seam for an upstream Codex 401. */
|
|
1335
|
+
refreshAccountToken?(providerId: SubscriptionProviderId, accountId: string): Promise<boolean>;
|
|
1306
1336
|
}
|
|
1307
1337
|
/** Proxy-aware upstream fetch signature (#3 `fetchUpstream`). */
|
|
1308
1338
|
type ProbeFetch = typeof fetchUpstream;
|
|
@@ -1352,10 +1382,13 @@ declare class AccountHealthProbeScheduler implements AccountProbeHistoryReader {
|
|
|
1352
1382
|
* no upstream); else the upstream tier when a verified endpoint exists. Records
|
|
1353
1383
|
* the rolling history entry either way; returns whether the tracker was MARKED.
|
|
1354
1384
|
*/
|
|
1355
|
-
probeAccount(providerId: SubscriptionProviderId, accountId: string): Promise<
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1385
|
+
probeAccount(providerId: SubscriptionProviderId, accountId: string): Promise<AccountConnectionProbeOutcome>;
|
|
1386
|
+
/**
|
|
1387
|
+
* Manual connection test. Codex performs a real, quota-consuming generation;
|
|
1388
|
+
* every other provider keeps its existing cheap probe. Scheduled sweeps never
|
|
1389
|
+
* call this method, so they remain non-billable.
|
|
1390
|
+
*/
|
|
1391
|
+
testAccountConnection(providerId: SubscriptionProviderId, accountId: string): Promise<AccountConnectionProbeOutcome>;
|
|
1359
1392
|
/** Per-account rolling history for the authed admin surface (design D5). */
|
|
1360
1393
|
getAllHistory(): AccountProbeHistorySnapshot[];
|
|
1361
1394
|
/**
|
|
@@ -1374,6 +1407,7 @@ declare class AccountHealthProbeScheduler implements AccountProbeHistoryReader {
|
|
|
1374
1407
|
private record;
|
|
1375
1408
|
/** Read a bounded slice of the response body for the 403-ban sniff (never throws). */
|
|
1376
1409
|
private readBounded;
|
|
1410
|
+
private runCodexGenerationAttempt;
|
|
1377
1411
|
private key;
|
|
1378
1412
|
private parseKey;
|
|
1379
1413
|
}
|
|
@@ -1400,6 +1434,18 @@ interface AuditQuery {
|
|
|
1400
1434
|
limit?: number;
|
|
1401
1435
|
}
|
|
1402
1436
|
|
|
1437
|
+
/**
|
|
1438
|
+
* Metadata-only audit aggregation. The overview needs request/error counts, not
|
|
1439
|
+
* multi-gigabyte request/response bodies. A compact per-day sidecar is updated
|
|
1440
|
+
* with each new record; legacy files are scanned once with a bounded prefix per
|
|
1441
|
+
* JSONL row and then cached in the same sidecar.
|
|
1442
|
+
*/
|
|
1443
|
+
|
|
1444
|
+
interface AuditStatsQuery {
|
|
1445
|
+
from?: number;
|
|
1446
|
+
to?: number;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1403
1449
|
/**
|
|
1404
1450
|
* auditQueryApi — the AUTHED `GET /admin/api/audit?keyId=&from=&to=&limit=`
|
|
1405
1451
|
* handler (request-audit-log, design D6).
|
|
@@ -1419,6 +1465,8 @@ interface AuditQuery {
|
|
|
1419
1465
|
|
|
1420
1466
|
/** The read surface the AdminServer consumes (bootstrap binds it to the store). */
|
|
1421
1467
|
type AuditQueryReader = (query: AuditQuery) => AuditRecord[];
|
|
1468
|
+
/** Metadata-only aggregate reader used by the overview. */
|
|
1469
|
+
type AuditStatsReader = (query: AuditStatsQuery) => Promise<AuditStats> | AuditStats;
|
|
1422
1470
|
|
|
1423
1471
|
/**
|
|
1424
1472
|
* billingStatusApi — the AUTHED `GET /admin/api/billing-status` handler
|
|
@@ -1783,6 +1831,7 @@ declare class IntegrationManager {
|
|
|
1783
1831
|
/** Injectable PATH probe (tests stub this; default scans `process.env.PATH`). */
|
|
1784
1832
|
type PathProbe = (candidate: string) => string | null;
|
|
1785
1833
|
/** Open a NEW terminal window running `command [extraArgs…]` with `env` injected. */
|
|
1834
|
+
type TerminalCleanup = () => void;
|
|
1786
1835
|
type TerminalOpener = (input: {
|
|
1787
1836
|
cli: string;
|
|
1788
1837
|
command: string;
|
|
@@ -1790,7 +1839,8 @@ type TerminalOpener = (input: {
|
|
|
1790
1839
|
env: Record<string, string>;
|
|
1791
1840
|
cwd?: string;
|
|
1792
1841
|
platform: NodeJS.Platform;
|
|
1793
|
-
|
|
1842
|
+
onFailure?: () => void;
|
|
1843
|
+
}) => void | TerminalCleanup;
|
|
1794
1844
|
/**
|
|
1795
1845
|
* Injectable shell runner for `POST /cli/:cli/install` (tests stub this; the
|
|
1796
1846
|
* default execs the install command with a bounded timeout). Returns the host's
|
|
@@ -1899,6 +1949,8 @@ interface AdminApiDeps {
|
|
|
1899
1949
|
readonly settingsStore: JsonApiServerSettingsStore;
|
|
1900
1950
|
/** The running outbound server (status + live applyConfig). */
|
|
1901
1951
|
readonly outboundApiServer: OutboundApiServer;
|
|
1952
|
+
/** Process-local machine-managed routing leases (optional for light embedders). */
|
|
1953
|
+
readonly routeLeaseManager?: RouteLeaseManager;
|
|
1902
1954
|
/** Subscription accounts (token-free `listAll`). */
|
|
1903
1955
|
readonly subscriptionAccounts: AdminAccountsLister;
|
|
1904
1956
|
/**
|
|
@@ -1914,6 +1966,12 @@ interface AdminApiDeps {
|
|
|
1914
1966
|
ok: boolean;
|
|
1915
1967
|
marked: boolean;
|
|
1916
1968
|
}>;
|
|
1969
|
+
testAccountConnection(providerId: _omnicross_contracts_subscription_types.SubscriptionProviderId, accountId: string): Promise<{
|
|
1970
|
+
ok: boolean;
|
|
1971
|
+
marked: boolean;
|
|
1972
|
+
tier: 'local' | 'upstream' | 'generation';
|
|
1973
|
+
model?: string;
|
|
1974
|
+
}>;
|
|
1917
1975
|
};
|
|
1918
1976
|
/**
|
|
1919
1977
|
* Least-authority subscription-token WRITER (design D4) — ONLY the mutation
|
|
@@ -1936,11 +1994,13 @@ interface AdminApiDeps {
|
|
|
1936
1994
|
*/
|
|
1937
1995
|
readonly oauthSessions: OAuthSessionStore;
|
|
1938
1996
|
/**
|
|
1939
|
-
* Injected token-exchange `FetchLike` (oauth design D2-a) —
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
1997
|
+
* Injected token-exchange `FetchLike` FACTORY (oauth design D2-a) — built per
|
|
1998
|
+
* provider in `bootstrap.ts` so the exchange carries a `{ providerId }` egress
|
|
1999
|
+
* ctx (per-provider proxy layer + upstream trace, bodies redacted); tests
|
|
2000
|
+
* inject a mock so no real token endpoint is hit. Mirrors how `login.ts`
|
|
2001
|
+
* injects its exchange fetch.
|
|
1942
2002
|
*/
|
|
1943
|
-
readonly oauthExchangeFetch: FetchLike;
|
|
2003
|
+
readonly oauthExchangeFetch: (providerId: SubscriptionProviderId) => FetchLike;
|
|
1944
2004
|
/**
|
|
1945
2005
|
* NARROW append handle (oauth design D2-a) — the OAuth complete handler needs
|
|
1946
2006
|
* `appendProviderAccount` (NOT on the least-authority `SubscriptionTokenWriter`).
|
|
@@ -2062,6 +2122,8 @@ interface AdminServerDeps extends AdminApiDeps {
|
|
|
2062
2122
|
* unauthenticated, NEVER on `/health`.
|
|
2063
2123
|
*/
|
|
2064
2124
|
auditReader?: AuditQueryReader;
|
|
2125
|
+
/** Metadata-only audit aggregate used by the overview error-rate metric. */
|
|
2126
|
+
auditStatsReader?: AuditStatsReader;
|
|
2065
2127
|
/**
|
|
2066
2128
|
* OPTIONAL billing delivery-status reader (billing-event-stream, design D5).
|
|
2067
2129
|
* When wired (bootstrap → the ledger dir), the AUTHED `GET /admin/api/billing-status`
|
|
@@ -2106,7 +2168,16 @@ declare class AdminServer {
|
|
|
2106
2168
|
|
|
2107
2169
|
declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
2108
2170
|
private readonly keysPath;
|
|
2109
|
-
|
|
2171
|
+
private readonly secretBox?;
|
|
2172
|
+
/**
|
|
2173
|
+
* @param secretBox OPTIONAL reversible-secret codec. When present, a created
|
|
2174
|
+
* key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
|
|
2175
|
+
* operator "view key" affordance via `outboundApiKeysReveal`). When absent the
|
|
2176
|
+
* store stays hash-only (byte-identical to the legacy behavior) and reveal
|
|
2177
|
+
* always returns `null`. Existing 1-arg call sites (tests, lightweight
|
|
2178
|
+
* embedders) keep working.
|
|
2179
|
+
*/
|
|
2180
|
+
constructor(keysPath: string, secretBox?: SecretBox | undefined);
|
|
2110
2181
|
outboundApiKeysList(): Promise<OutboundKeyDbRow[]>;
|
|
2111
2182
|
outboundApiKeysGetByHash(hash: string): Promise<OutboundKeyDbRow | null>;
|
|
2112
2183
|
outboundApiKeysCreate(input: {
|
|
@@ -2118,7 +2189,10 @@ declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
|
2118
2189
|
kind?: 'client' | 'integration';
|
|
2119
2190
|
allowedEndpoints?: _omnicross_core.OutboundEndpoint[];
|
|
2120
2191
|
loopbackOnly?: boolean;
|
|
2192
|
+
plaintext?: string;
|
|
2121
2193
|
}): Promise<OutboundKeyDbRow>;
|
|
2194
|
+
outboundApiKeysReveal(id: string): Promise<string | null>;
|
|
2195
|
+
outboundApiKeysDelete(id: string): Promise<boolean>;
|
|
2122
2196
|
outboundApiKeysRevoke(id: string): Promise<boolean>;
|
|
2123
2197
|
outboundApiKeysTouchLastUsed(id: string): Promise<boolean>;
|
|
2124
2198
|
outboundApiKeysSetEnabled(id: string, enabled: boolean): Promise<boolean>;
|
|
@@ -2642,6 +2716,7 @@ interface Daemon {
|
|
|
2642
2716
|
readonly keyDb: JsonOutboundKeyDb;
|
|
2643
2717
|
readonly settingsStore: JsonApiServerSettingsStore;
|
|
2644
2718
|
readonly providerProxy: ProviderProxy;
|
|
2719
|
+
readonly routeLeaseManager: RouteLeaseManager;
|
|
2645
2720
|
readonly outboundApiServer: OutboundApiServer;
|
|
2646
2721
|
/**
|
|
2647
2722
|
* Multi-key load balancer. Wired into the proxy deps slot
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as _omnicross_core from '@omnicross/core';
|
|
|
2
2
|
import { OutboundApiServerConfig, Logger, ProviderConfigSource, TransformerService, Transformer, ResolvedTransformerChain, ApiServerSettingsStore, PricingStore, AutomaticPricingSource, OutboundKeyDb, OutboundKeyDbRow, OutboundKeyPolicy, PricingEngine as PricingEngine$1 } from '@omnicross/core';
|
|
3
3
|
import { ApiKeyPoolService } from '@omnicross/core/completion/ApiKeyPoolService';
|
|
4
4
|
import { AllowanceSchedulingConfig, AccountProbeConfig, OutboundKeyDb as OutboundKeyDb$1, VoucherDb, KeySpendReader, OutboundApiServer } from '@omnicross/core/outbound-api';
|
|
5
|
-
import { ProviderProxy } from '@omnicross/core/provider-proxy';
|
|
5
|
+
import { RouteLeaseManager, ProviderProxy } from '@omnicross/core/provider-proxy';
|
|
6
6
|
import { UsageRecorder, PricingEngine } from '@omnicross/core/usage';
|
|
7
7
|
import { SubscriptionCredentialStore, FetchLike, SubscriptionProviderRegistry, SubscriptionAccountService } from '@omnicross/subscriptions';
|
|
8
8
|
import { AccountAllowanceSnapshot } from '@omnicross/contracts/account-allowance-types';
|
|
@@ -15,7 +15,7 @@ import { SubscriptionIdentityStore } from '@omnicross/core/provider-proxy/identi
|
|
|
15
15
|
import { LoggingConfig, HealthReport } from '@omnicross/contracts/health-logging-types';
|
|
16
16
|
import { SubscriptionAccountHealth } from '@omnicross/core/pipeline/SubscriptionAccountHealth';
|
|
17
17
|
import { fetchUpstream } from '@omnicross/core/pipeline/upstreamFetch';
|
|
18
|
-
import { AuditRecord, AuditConfig } from '@omnicross/contracts/audit-types';
|
|
18
|
+
import { AuditRecord, AuditStats, AuditConfig } from '@omnicross/contracts/audit-types';
|
|
19
19
|
import { BillingDeliveryStatus, BillingConfig, BillingEvent } from '@omnicross/contracts/billing-types';
|
|
20
20
|
import http from 'node:http';
|
|
21
21
|
import { LLMProvider, AgentDefaultModels, GlobalModelParameters } from '@omnicross/contracts/llm-config';
|
|
@@ -579,6 +579,12 @@ declare class JsonSubscriptionCredentialStore implements SubscriptionCredentialS
|
|
|
579
579
|
* TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
|
|
580
580
|
* through {@link fetchUpstream} with the account's `{ providerId, accountId }`
|
|
581
581
|
* ctx so the per-account/provider proxy applies. `@internal` also a test seam.
|
|
582
|
+
*
|
|
583
|
+
* `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
|
|
584
|
+
* receives a fresh access/refresh token pair. Carrying a `providerId` opts the
|
|
585
|
+
* call into the upstream trace (so a failing refresh is diagnosable), and the
|
|
586
|
+
* trace captures bodies verbatim — without this flag every refresh would write
|
|
587
|
+
* a plaintext token pair into `upstream-trace.jsonl`.
|
|
582
588
|
*/
|
|
583
589
|
buildRefreshFetch(providerId: string, accountId?: string): FetchLike;
|
|
584
590
|
/**
|
|
@@ -923,11 +929,12 @@ interface SubscriptionTokenWriter {
|
|
|
923
929
|
* app-parity child 4, design D1).
|
|
924
930
|
*
|
|
925
931
|
* `start` mints a crypto-random `sessionId` and stashes the per-session PKCE
|
|
926
|
-
* `{ providerId, codeVerifier, state }` here; `complete`
|
|
927
|
-
* `
|
|
932
|
+
* `{ providerId, codeVerifier, state }` here; `complete` `peek`s the session,
|
|
933
|
+
* exchanges the code, and `consume`s it ONLY once a token was minted — so a
|
|
934
|
+
* failed exchange leaves the session retryable instead of burning it. The map is
|
|
928
935
|
* NEVER serialized to the client — only the opaque `sessionId` + the public
|
|
929
936
|
* `authUrl` cross the wire. Sessions are short-lived (OQ3 = 10-min TTL); a sweep
|
|
930
|
-
* reaps abandoned sessions, and `
|
|
937
|
+
* reaps abandoned sessions, and `peek` re-checks the TTL so an expired-but-not-
|
|
931
938
|
* yet-swept session is still rejected. A daemon restart simply drops in-flight
|
|
932
939
|
* logins (correct fail-safe — no partial token is ever written).
|
|
933
940
|
*
|
|
@@ -963,13 +970,25 @@ declare class OAuthSessionStore {
|
|
|
963
970
|
*/
|
|
964
971
|
put(session: Omit<PendingOAuthSession, 'createdAt'>): string;
|
|
965
972
|
/**
|
|
966
|
-
*
|
|
967
|
-
*
|
|
968
|
-
* dropped). A `null` return means the completer must reject (no
|
|
969
|
-
* write).
|
|
973
|
+
* NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
|
|
974
|
+
* it is unknown, already consumed, or past its TTL (an expired entry is
|
|
975
|
+
* dropped here). A `null` return means the completer must reject (no
|
|
976
|
+
* exchange, no write).
|
|
977
|
+
*
|
|
978
|
+
* Deliberately NOT a consume: the completer peeks, runs the token exchange,
|
|
979
|
+
* and only {@link consume}s once a token has actually been minted. Consuming
|
|
980
|
+
* up-front burned the session on EVERY failed exchange (a mistyped/expired
|
|
981
|
+
* pasted code, a proxy hiccup), so the user's natural retry hit
|
|
982
|
+
* "session is unknown, expired, or already used" and the login became
|
|
983
|
+
* unrecoverable without restarting the whole flow.
|
|
984
|
+
*/
|
|
985
|
+
peek(sessionId: string): PendingOAuthSession | null;
|
|
986
|
+
/**
|
|
987
|
+
* SINGLE-USE burn: drop the session so the same `sessionId` can never be
|
|
988
|
+
* completed twice. Called ONLY after a successful token exchange.
|
|
970
989
|
*/
|
|
971
|
-
|
|
972
|
-
/** Drop every session past its TTL. Called on each put/
|
|
990
|
+
consume(sessionId: string): void;
|
|
991
|
+
/** Drop every session past its TTL. Called on each put/peek. */
|
|
973
992
|
private sweep;
|
|
974
993
|
}
|
|
975
994
|
|
|
@@ -983,10 +1002,12 @@ declare class OAuthSessionStore {
|
|
|
983
1002
|
* provider's authorize params and stashes the per-session `{ codeVerifier, state }`
|
|
984
1003
|
* in the `OAuthSessionStore` keyed by a minted opaque `sessionId`, returning ONLY
|
|
985
1004
|
* `{ authUrl, sessionId }` (the `authUrl` carries client_id + PKCE challenge +
|
|
986
|
-
* state — all public). `complete`
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
* it active, and responds ONLY
|
|
1005
|
+
* state — all public). `complete` `peek`s the session, validates state (claude's
|
|
1006
|
+
* `code#state`), `exchangeCodeForTokens(...)`, then — and ONLY then — `consume`s
|
|
1007
|
+
* the session (single-use), persists the minted token through the encrypted
|
|
1008
|
+
* credential store (`appendProviderAccount`) + marks it active, and responds ONLY
|
|
1009
|
+
* the sanitized `SubscriptionListEntry`. A FAILED exchange leaves the session
|
|
1010
|
+
* intact so the user can retry within its TTL instead of being locked out by a 410.
|
|
990
1011
|
*
|
|
991
1012
|
* SECRET SPINE (the load-bearing invariant): the minted access/refresh token
|
|
992
1013
|
* NEVER appears in any response body or log; the `codeVerifier` / session map is
|
|
@@ -1283,7 +1304,14 @@ interface ProbeRecord {
|
|
|
1283
1304
|
/** Upstream round-trip latency (ms); absent for a local-tier record. */
|
|
1284
1305
|
latencyMs?: number;
|
|
1285
1306
|
/** Which tier produced this record. */
|
|
1286
|
-
tier: 'local' | 'upstream';
|
|
1307
|
+
tier: 'local' | 'upstream' | 'generation';
|
|
1308
|
+
}
|
|
1309
|
+
/** Secret-free outcome returned by the manual account connection-test route. */
|
|
1310
|
+
interface AccountConnectionProbeOutcome {
|
|
1311
|
+
ok: boolean;
|
|
1312
|
+
marked: boolean;
|
|
1313
|
+
tier: ProbeRecord['tier'];
|
|
1314
|
+
model?: string;
|
|
1287
1315
|
}
|
|
1288
1316
|
/** Per-account probe history for the authed admin surface (names account ids). */
|
|
1289
1317
|
interface AccountProbeHistorySnapshot {
|
|
@@ -1303,6 +1331,8 @@ interface AccountProbeHistoryReader {
|
|
|
1303
1331
|
interface ProbeCredentialStore {
|
|
1304
1332
|
getFullConfig(): Promise<AccountTokensConfig>;
|
|
1305
1333
|
getAccessTokenForAccount(providerId: SubscriptionProviderId, accountId: string): Promise<string | null>;
|
|
1334
|
+
/** Optional serving-parity retry seam for an upstream Codex 401. */
|
|
1335
|
+
refreshAccountToken?(providerId: SubscriptionProviderId, accountId: string): Promise<boolean>;
|
|
1306
1336
|
}
|
|
1307
1337
|
/** Proxy-aware upstream fetch signature (#3 `fetchUpstream`). */
|
|
1308
1338
|
type ProbeFetch = typeof fetchUpstream;
|
|
@@ -1352,10 +1382,13 @@ declare class AccountHealthProbeScheduler implements AccountProbeHistoryReader {
|
|
|
1352
1382
|
* no upstream); else the upstream tier when a verified endpoint exists. Records
|
|
1353
1383
|
* the rolling history entry either way; returns whether the tracker was MARKED.
|
|
1354
1384
|
*/
|
|
1355
|
-
probeAccount(providerId: SubscriptionProviderId, accountId: string): Promise<
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1385
|
+
probeAccount(providerId: SubscriptionProviderId, accountId: string): Promise<AccountConnectionProbeOutcome>;
|
|
1386
|
+
/**
|
|
1387
|
+
* Manual connection test. Codex performs a real, quota-consuming generation;
|
|
1388
|
+
* every other provider keeps its existing cheap probe. Scheduled sweeps never
|
|
1389
|
+
* call this method, so they remain non-billable.
|
|
1390
|
+
*/
|
|
1391
|
+
testAccountConnection(providerId: SubscriptionProviderId, accountId: string): Promise<AccountConnectionProbeOutcome>;
|
|
1359
1392
|
/** Per-account rolling history for the authed admin surface (design D5). */
|
|
1360
1393
|
getAllHistory(): AccountProbeHistorySnapshot[];
|
|
1361
1394
|
/**
|
|
@@ -1374,6 +1407,7 @@ declare class AccountHealthProbeScheduler implements AccountProbeHistoryReader {
|
|
|
1374
1407
|
private record;
|
|
1375
1408
|
/** Read a bounded slice of the response body for the 403-ban sniff (never throws). */
|
|
1376
1409
|
private readBounded;
|
|
1410
|
+
private runCodexGenerationAttempt;
|
|
1377
1411
|
private key;
|
|
1378
1412
|
private parseKey;
|
|
1379
1413
|
}
|
|
@@ -1400,6 +1434,18 @@ interface AuditQuery {
|
|
|
1400
1434
|
limit?: number;
|
|
1401
1435
|
}
|
|
1402
1436
|
|
|
1437
|
+
/**
|
|
1438
|
+
* Metadata-only audit aggregation. The overview needs request/error counts, not
|
|
1439
|
+
* multi-gigabyte request/response bodies. A compact per-day sidecar is updated
|
|
1440
|
+
* with each new record; legacy files are scanned once with a bounded prefix per
|
|
1441
|
+
* JSONL row and then cached in the same sidecar.
|
|
1442
|
+
*/
|
|
1443
|
+
|
|
1444
|
+
interface AuditStatsQuery {
|
|
1445
|
+
from?: number;
|
|
1446
|
+
to?: number;
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1403
1449
|
/**
|
|
1404
1450
|
* auditQueryApi — the AUTHED `GET /admin/api/audit?keyId=&from=&to=&limit=`
|
|
1405
1451
|
* handler (request-audit-log, design D6).
|
|
@@ -1419,6 +1465,8 @@ interface AuditQuery {
|
|
|
1419
1465
|
|
|
1420
1466
|
/** The read surface the AdminServer consumes (bootstrap binds it to the store). */
|
|
1421
1467
|
type AuditQueryReader = (query: AuditQuery) => AuditRecord[];
|
|
1468
|
+
/** Metadata-only aggregate reader used by the overview. */
|
|
1469
|
+
type AuditStatsReader = (query: AuditStatsQuery) => Promise<AuditStats> | AuditStats;
|
|
1422
1470
|
|
|
1423
1471
|
/**
|
|
1424
1472
|
* billingStatusApi — the AUTHED `GET /admin/api/billing-status` handler
|
|
@@ -1783,6 +1831,7 @@ declare class IntegrationManager {
|
|
|
1783
1831
|
/** Injectable PATH probe (tests stub this; default scans `process.env.PATH`). */
|
|
1784
1832
|
type PathProbe = (candidate: string) => string | null;
|
|
1785
1833
|
/** Open a NEW terminal window running `command [extraArgs…]` with `env` injected. */
|
|
1834
|
+
type TerminalCleanup = () => void;
|
|
1786
1835
|
type TerminalOpener = (input: {
|
|
1787
1836
|
cli: string;
|
|
1788
1837
|
command: string;
|
|
@@ -1790,7 +1839,8 @@ type TerminalOpener = (input: {
|
|
|
1790
1839
|
env: Record<string, string>;
|
|
1791
1840
|
cwd?: string;
|
|
1792
1841
|
platform: NodeJS.Platform;
|
|
1793
|
-
|
|
1842
|
+
onFailure?: () => void;
|
|
1843
|
+
}) => void | TerminalCleanup;
|
|
1794
1844
|
/**
|
|
1795
1845
|
* Injectable shell runner for `POST /cli/:cli/install` (tests stub this; the
|
|
1796
1846
|
* default execs the install command with a bounded timeout). Returns the host's
|
|
@@ -1899,6 +1949,8 @@ interface AdminApiDeps {
|
|
|
1899
1949
|
readonly settingsStore: JsonApiServerSettingsStore;
|
|
1900
1950
|
/** The running outbound server (status + live applyConfig). */
|
|
1901
1951
|
readonly outboundApiServer: OutboundApiServer;
|
|
1952
|
+
/** Process-local machine-managed routing leases (optional for light embedders). */
|
|
1953
|
+
readonly routeLeaseManager?: RouteLeaseManager;
|
|
1902
1954
|
/** Subscription accounts (token-free `listAll`). */
|
|
1903
1955
|
readonly subscriptionAccounts: AdminAccountsLister;
|
|
1904
1956
|
/**
|
|
@@ -1914,6 +1966,12 @@ interface AdminApiDeps {
|
|
|
1914
1966
|
ok: boolean;
|
|
1915
1967
|
marked: boolean;
|
|
1916
1968
|
}>;
|
|
1969
|
+
testAccountConnection(providerId: _omnicross_contracts_subscription_types.SubscriptionProviderId, accountId: string): Promise<{
|
|
1970
|
+
ok: boolean;
|
|
1971
|
+
marked: boolean;
|
|
1972
|
+
tier: 'local' | 'upstream' | 'generation';
|
|
1973
|
+
model?: string;
|
|
1974
|
+
}>;
|
|
1917
1975
|
};
|
|
1918
1976
|
/**
|
|
1919
1977
|
* Least-authority subscription-token WRITER (design D4) — ONLY the mutation
|
|
@@ -1936,11 +1994,13 @@ interface AdminApiDeps {
|
|
|
1936
1994
|
*/
|
|
1937
1995
|
readonly oauthSessions: OAuthSessionStore;
|
|
1938
1996
|
/**
|
|
1939
|
-
* Injected token-exchange `FetchLike` (oauth design D2-a) —
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
1997
|
+
* Injected token-exchange `FetchLike` FACTORY (oauth design D2-a) — built per
|
|
1998
|
+
* provider in `bootstrap.ts` so the exchange carries a `{ providerId }` egress
|
|
1999
|
+
* ctx (per-provider proxy layer + upstream trace, bodies redacted); tests
|
|
2000
|
+
* inject a mock so no real token endpoint is hit. Mirrors how `login.ts`
|
|
2001
|
+
* injects its exchange fetch.
|
|
1942
2002
|
*/
|
|
1943
|
-
readonly oauthExchangeFetch: FetchLike;
|
|
2003
|
+
readonly oauthExchangeFetch: (providerId: SubscriptionProviderId) => FetchLike;
|
|
1944
2004
|
/**
|
|
1945
2005
|
* NARROW append handle (oauth design D2-a) — the OAuth complete handler needs
|
|
1946
2006
|
* `appendProviderAccount` (NOT on the least-authority `SubscriptionTokenWriter`).
|
|
@@ -2062,6 +2122,8 @@ interface AdminServerDeps extends AdminApiDeps {
|
|
|
2062
2122
|
* unauthenticated, NEVER on `/health`.
|
|
2063
2123
|
*/
|
|
2064
2124
|
auditReader?: AuditQueryReader;
|
|
2125
|
+
/** Metadata-only audit aggregate used by the overview error-rate metric. */
|
|
2126
|
+
auditStatsReader?: AuditStatsReader;
|
|
2065
2127
|
/**
|
|
2066
2128
|
* OPTIONAL billing delivery-status reader (billing-event-stream, design D5).
|
|
2067
2129
|
* When wired (bootstrap → the ledger dir), the AUTHED `GET /admin/api/billing-status`
|
|
@@ -2106,7 +2168,16 @@ declare class AdminServer {
|
|
|
2106
2168
|
|
|
2107
2169
|
declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
2108
2170
|
private readonly keysPath;
|
|
2109
|
-
|
|
2171
|
+
private readonly secretBox?;
|
|
2172
|
+
/**
|
|
2173
|
+
* @param secretBox OPTIONAL reversible-secret codec. When present, a created
|
|
2174
|
+
* key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
|
|
2175
|
+
* operator "view key" affordance via `outboundApiKeysReveal`). When absent the
|
|
2176
|
+
* store stays hash-only (byte-identical to the legacy behavior) and reveal
|
|
2177
|
+
* always returns `null`. Existing 1-arg call sites (tests, lightweight
|
|
2178
|
+
* embedders) keep working.
|
|
2179
|
+
*/
|
|
2180
|
+
constructor(keysPath: string, secretBox?: SecretBox | undefined);
|
|
2110
2181
|
outboundApiKeysList(): Promise<OutboundKeyDbRow[]>;
|
|
2111
2182
|
outboundApiKeysGetByHash(hash: string): Promise<OutboundKeyDbRow | null>;
|
|
2112
2183
|
outboundApiKeysCreate(input: {
|
|
@@ -2118,7 +2189,10 @@ declare class JsonOutboundKeyDb implements OutboundKeyDb {
|
|
|
2118
2189
|
kind?: 'client' | 'integration';
|
|
2119
2190
|
allowedEndpoints?: _omnicross_core.OutboundEndpoint[];
|
|
2120
2191
|
loopbackOnly?: boolean;
|
|
2192
|
+
plaintext?: string;
|
|
2121
2193
|
}): Promise<OutboundKeyDbRow>;
|
|
2194
|
+
outboundApiKeysReveal(id: string): Promise<string | null>;
|
|
2195
|
+
outboundApiKeysDelete(id: string): Promise<boolean>;
|
|
2122
2196
|
outboundApiKeysRevoke(id: string): Promise<boolean>;
|
|
2123
2197
|
outboundApiKeysTouchLastUsed(id: string): Promise<boolean>;
|
|
2124
2198
|
outboundApiKeysSetEnabled(id: string, enabled: boolean): Promise<boolean>;
|
|
@@ -2642,6 +2716,7 @@ interface Daemon {
|
|
|
2642
2716
|
readonly keyDb: JsonOutboundKeyDb;
|
|
2643
2717
|
readonly settingsStore: JsonApiServerSettingsStore;
|
|
2644
2718
|
readonly providerProxy: ProviderProxy;
|
|
2719
|
+
readonly routeLeaseManager: RouteLeaseManager;
|
|
2645
2720
|
readonly outboundApiServer: OutboundApiServer;
|
|
2646
2721
|
/**
|
|
2647
2722
|
* Multi-key load balancer. Wired into the proxy deps slot
|