mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-02 21:32:10 +03:00
First slice of the TypeScript 7 migration split requested on #7697: resolve the type diagnostics under `open-sse/tsconfig.json` in the lowest-risk modules, with no toolchain change. 12 diagnostics across 8 files, all outside the hot path — `chatCore.ts` and `stream.ts` are deliberately left for a later, standalone slice. Fixes, by cause: * `Transformer.cancel` (progressTracker, sseHeartbeat, and stream.ts's existing handler) — the WHATWG Streams standard defines `transformer.cancel(reason)` and Node implements it (verified on v24: cancelling the readable side invokes it), but `lib.dom.d.ts` still omits it from `Transformer`, so every such handler was TS2353. These handlers clear the heartbeat/progress intervals when an SSE client disconnects, so deleting them to satisfy the checker would leak a timer per abandoned stream. The interface is patched in `open-sse/types.d.ts` instead. * `earlyStreamKeepalive` — `SettledHandler` was discriminated by `ok: true | false`. This workspace compiles with `strictNullChecks: false`, where a boolean-literal discriminant narrows the positive branch but not the negative one, so reading `.error` off the rejected arm did not type-check (the two `.response` reads elsewhere in the file did, which is why only one site errored). Retagged with a string discriminant, which narrows both branches under the same settings. * `toolCallShim` / `openai-responses` — assigning back to a property declared `unknown` resets the `typeof` narrowing, so the following comparison no longer saw a number/array. Both now read through a local. The `Read` limit clamp is behavior-identical: its two branches are mutually exclusive at READ_MAX_LIMIT 2000. * `sanitizeToolResultId` — takes `unknown` but forwards to a `string` parameter; a non-string id previously reached `.replace()` and threw. Coerced instead. * `openaiHelper` — `opts = {}` inferred `{}`; typed as `FilterToOpenAIFormatOptions`. * `cursorAgentProtobuf` — `Buffer.alloc(0)` infers `Buffer<ArrayBuffer>` under @types/node 26 while the decoded field is `Buffer<ArrayBufferLike>`; the locals now use bare `Buffer`, matching `requestMetadata` a few lines above. Validation: 335 -> 321 diagnostics with zero new errors (full tsc error-set diff against the base config). typecheck:core clean, lint clean, check:type-coverage 92.17% -> 94.17%. All 114 existing test files that import a touched module pass; `plan3-p0.test.ts` fails identically with and without this change (it reads the developer's real ~/.omniroute DB instead of a test-scoped DATA_DIR). The new test covers the three behavioral surfaces rather than the refactors the existing keepalive/heartbeat suites already hold: that `transformer.cancel()` really fires and can clear an interval, the id coercion, and the limit-clamp bounds.
161 lines
5.1 KiB
TypeScript
161 lines
5.1 KiB
TypeScript
/**
|
|
* Core type definitions for omniroute.
|
|
*
|
|
* These types describe the main data structures flowing through the proxy
|
|
* pipeline: credentials, model info, executor results, and chat parameters.
|
|
*
|
|
* Usage (JSDoc reference):
|
|
* /** @type {import("./types").ProviderCredentials} *\/
|
|
*/
|
|
|
|
// ============ Provider & Auth ============
|
|
|
|
export interface ProviderCredentials {
|
|
/** OAuth access token (short-lived) */
|
|
accessToken: string;
|
|
/** OAuth refresh token (long-lived) */
|
|
refreshToken?: string;
|
|
/** Internal connection ID */
|
|
connectionId: string;
|
|
/** Optional per-account concurrency cap */
|
|
maxConcurrent?: number | null;
|
|
/** User email associated with the connection */
|
|
email?: string;
|
|
/** API key (for apikey auth type) */
|
|
apiKey?: string;
|
|
/** Token expiry timestamp */
|
|
expiresAt?: string;
|
|
/** Provider-specific extra data (e.g., AWS region, auth method) */
|
|
providerSpecificData?: Record<string, unknown>;
|
|
}
|
|
|
|
export interface ModelInfo {
|
|
/** Canonical provider ID (e.g., "claude", "antigravity") */
|
|
provider: string;
|
|
/** Model identifier (e.g., "claude-opus-4-6") */
|
|
model: string;
|
|
/** Optional original model string from client (e.g., "cc/opus-4-6") */
|
|
originalModel?: string;
|
|
}
|
|
|
|
// ============ Executor ============
|
|
|
|
export interface ExecutorResult {
|
|
/** Whether the upstream request succeeded (2xx) */
|
|
success: boolean;
|
|
/** The HTTP Response from the upstream provider */
|
|
response: Response;
|
|
/** HTTP status code (present on failure) */
|
|
status?: number;
|
|
/** Human-readable error message (present on failure) */
|
|
error?: string;
|
|
/** Suggested retry delay in ms (present on rate-limit) */
|
|
retryAfterMs?: number;
|
|
}
|
|
|
|
// ============ Chat Pipeline ============
|
|
|
|
export interface ChatCoreParams {
|
|
/** Parsed request body */
|
|
body: Record<string, unknown>;
|
|
/** Resolved model info */
|
|
modelInfo: ModelInfo;
|
|
/** Provider credentials to use */
|
|
credentials: ProviderCredentials;
|
|
/** Request-scoped logger */
|
|
log: Logger;
|
|
/** Raw client request body (before translation) */
|
|
clientRawRequest?: Record<string, unknown>;
|
|
/** Connection ID for usage tracking */
|
|
connectionId: string;
|
|
/** API key metadata for usage attribution */
|
|
apiKeyInfo?: { id?: string; name?: string } | null;
|
|
/** Client User-Agent header */
|
|
userAgent?: string;
|
|
/** Callback when credentials are refreshed mid-request */
|
|
onCredentialsRefreshed?: (creds: ProviderCredentials) => Promise<void>;
|
|
/** Callback on successful upstream response */
|
|
onRequestSuccess?: () => Promise<void>;
|
|
}
|
|
|
|
// ============ Logger ============
|
|
|
|
export interface Logger {
|
|
debug(tag: string, message: string, data?: Record<string, unknown>): void;
|
|
info(tag: string, message: string, data?: Record<string, unknown>): void;
|
|
warn(tag: string, message: string, data?: Record<string, unknown>): void;
|
|
error(tag: string, message: string, data?: Record<string, unknown>): void;
|
|
}
|
|
|
|
export interface TaggedLogger {
|
|
debug(message: string, meta?: Record<string, unknown>): void;
|
|
info(message: string, meta?: Record<string, unknown>): void;
|
|
warn(message: string, meta?: Record<string, unknown>): void;
|
|
error(message: string, meta?: Record<string, unknown>): void;
|
|
}
|
|
|
|
// ============ Configuration ============
|
|
|
|
export interface ProviderConfig {
|
|
/** Primary base URL */
|
|
baseUrl?: string;
|
|
/** Multiple base URLs for failover */
|
|
baseUrls?: string[];
|
|
/** API format identifier */
|
|
format: string;
|
|
/** Default HTTP headers */
|
|
headers?: Record<string, string>;
|
|
/** OAuth client ID */
|
|
clientId?: string;
|
|
/** OAuth client secret */
|
|
clientSecret?: string;
|
|
/** Token refresh endpoint */
|
|
tokenUrl?: string;
|
|
/** Authorization endpoint */
|
|
authUrl?: string;
|
|
}
|
|
|
|
// ============ Translator ============
|
|
|
|
export interface TranslationState {
|
|
/** Source format to translate TO */
|
|
sourceFormat: string;
|
|
/** Current accumulated content */
|
|
content?: string;
|
|
/** Provider that generated the response */
|
|
provider?: string;
|
|
/** Map of tool names for translation */
|
|
toolNameMap?: Record<string, string> | null;
|
|
/** Accumulated usage data */
|
|
usage?: UsageData | null;
|
|
/** Finish reason from provider */
|
|
finishReason?: string | null;
|
|
}
|
|
|
|
export interface UsageData {
|
|
prompt_tokens: number;
|
|
completion_tokens: number;
|
|
total_tokens: number;
|
|
}
|
|
|
|
// ============ Lib gap: Transformer.cancel ============
|
|
|
|
declare global {
|
|
/**
|
|
* The WHATWG Streams standard defines `transformer.cancel(reason)`, invoked when
|
|
* the readable side is cancelled (for us: an SSE client disconnecting). Node
|
|
* implements it — verified on v24 — but `lib.dom.d.ts` still omits it from
|
|
* `Transformer`, so every `new TransformStream({ ..., cancel() {} })` in the
|
|
* codebase fails with TS2353 ("'cancel' does not exist in type 'Transformer'").
|
|
*
|
|
* These `cancel` handlers are load-bearing: they clear heartbeat/progress
|
|
* intervals and idle timers on disconnect. Deleting them to satisfy the checker
|
|
* would leak a timer per abandoned stream, so the type is patched instead.
|
|
*
|
|
* Remove once the bundled lib declares it.
|
|
*/
|
|
interface Transformer<I = unknown, O = unknown> {
|
|
cancel?: (reason?: unknown) => void | PromiseLike<void>;
|
|
}
|
|
}
|