aweshare 0.5.1 → 0.5.6

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 (67) hide show
  1. package/README.ai.md +7 -6
  2. package/README.md +30 -13
  3. package/apps/agent/dist/cli.js +1 -1
  4. package/apps/agent/dist/config.d.ts +1 -1
  5. package/apps/agent/dist/config.js +11 -0
  6. package/apps/agent/dist/config.js.map +1 -1
  7. package/apps/agent/dist/connection.js +10 -5
  8. package/apps/agent/dist/connection.js.map +1 -1
  9. package/apps/agent/dist/doctor.js +27 -7
  10. package/apps/agent/dist/doctor.js.map +1 -1
  11. package/apps/agent/dist/table.d.ts +2 -0
  12. package/apps/agent/dist/table.js +7 -4
  13. package/apps/agent/dist/table.js.map +1 -1
  14. package/apps/consumer/dist/cli.js +1 -1
  15. package/apps/consumer/dist/cli.js.map +1 -1
  16. package/apps/consumer/dist/table.d.ts +2 -0
  17. package/apps/consumer/dist/table.js +4 -1
  18. package/apps/consumer/dist/table.js.map +1 -1
  19. package/apps/hub/dist/cli.js +119 -128
  20. package/apps/hub/dist/cli.js.map +1 -1
  21. package/apps/hub/dist/consumer.d.ts +1 -0
  22. package/apps/hub/dist/consumer.js +4 -2
  23. package/apps/hub/dist/consumer.js.map +1 -1
  24. package/apps/hub/dist/db.d.ts +9 -1
  25. package/apps/hub/dist/db.js +10 -2
  26. package/apps/hub/dist/db.js.map +1 -1
  27. package/apps/hub/dist/local.d.ts +12 -2
  28. package/apps/hub/dist/local.js +26 -7
  29. package/apps/hub/dist/local.js.map +1 -1
  30. package/apps/hub/dist/meter.d.ts +2 -1
  31. package/apps/hub/dist/meter.js +21 -10
  32. package/apps/hub/dist/meter.js.map +1 -1
  33. package/apps/hub/dist/sanitize.js +8 -0
  34. package/apps/hub/dist/sanitize.js.map +1 -1
  35. package/apps/hub/dist/table.d.ts +10 -3
  36. package/apps/hub/dist/table.js +44 -16
  37. package/apps/hub/dist/table.js.map +1 -1
  38. package/package.json +2 -1
  39. package/packages/producer-core/dist/adapters.d.ts +3 -0
  40. package/packages/producer-core/dist/adapters.js +52 -1
  41. package/packages/producer-core/dist/adapters.js.map +1 -1
  42. package/packages/producer-core/dist/catalog.d.ts +4 -0
  43. package/packages/producer-core/dist/catalog.js +30 -7
  44. package/packages/producer-core/dist/catalog.js.map +1 -1
  45. package/packages/producer-core/dist/credentials.d.ts +25 -0
  46. package/packages/producer-core/dist/credentials.js +86 -0
  47. package/packages/producer-core/dist/credentials.js.map +1 -0
  48. package/packages/producer-core/dist/health.d.ts +25 -2
  49. package/packages/producer-core/dist/health.js +77 -4
  50. package/packages/producer-core/dist/health.js.map +1 -1
  51. package/packages/producer-core/dist/index.d.ts +2 -0
  52. package/packages/producer-core/dist/index.js +2 -0
  53. package/packages/producer-core/dist/index.js.map +1 -1
  54. package/packages/producer-core/dist/job.js +22 -7
  55. package/packages/producer-core/dist/job.js.map +1 -1
  56. package/packages/producer-core/dist/probe.d.ts +1 -1
  57. package/packages/producer-core/dist/probe.js +26 -2
  58. package/packages/producer-core/dist/probe.js.map +1 -1
  59. package/packages/producer-core/dist/proxy.d.ts +21 -0
  60. package/packages/producer-core/dist/proxy.js +77 -0
  61. package/packages/producer-core/dist/proxy.js.map +1 -0
  62. package/packages/protocol/dist/errors.d.ts +1 -0
  63. package/packages/protocol/dist/errors.js +1 -0
  64. package/packages/protocol/dist/errors.js.map +1 -1
  65. package/packages/protocol/dist/messages.d.ts +9 -0
  66. package/packages/protocol/dist/messages.js +15 -0
  67. package/packages/protocol/dist/messages.js.map +1 -1
@@ -1,3 +1,4 @@
1
+ import { readCodexCredentials } from './credentials.js';
1
2
  /**
2
3
  * Rebuild the upstream request from the dispatch init.
3
4
  * The hub already stripped consumer credentials; the upstream key is
@@ -12,7 +13,20 @@ export function buildUpstreamRequest(backend, msg) {
12
13
  url.searchParams.set(key, value);
13
14
  }
14
15
  const headers = { ...msg.headers };
15
- if (backend.protocol === 'anthropic') {
16
+ stripEdgeHeaders(headers);
17
+ if (backend.login === 'codex') {
18
+ // the account login replaces an upstream key: strip any auth the consumer
19
+ // sent (belt-and-suspenders — the hub already stripped its own tokens)
20
+ // and inject the header recipe the Codex CLI itself sends
21
+ delete headers.authorization;
22
+ delete headers['x-api-key'];
23
+ const { accessToken, accountId } = readCodexCredentials();
24
+ headers.authorization = `Bearer ${accessToken}`;
25
+ headers['chatgpt-account-id'] = accountId;
26
+ headers['openai-beta'] = 'responses=experimental';
27
+ headers.originator = 'codex_cli_rs';
28
+ }
29
+ else if (backend.protocol === 'anthropic') {
16
30
  if (backend.apiKey)
17
31
  headers['x-api-key'] = backend.apiKey;
18
32
  headers['anthropic-version'] = headers['anthropic-version'] ?? '2023-06-01';
@@ -22,4 +36,41 @@ export function buildUpstreamRequest(backend, msg) {
22
36
  }
23
37
  return { url: url.toString(), headers };
24
38
  }
39
+ /** Exact edge-injected header names to strip (prefix families handled in code). */
40
+ const EDGE_INJECTED = new Set(['cdn-loop', 'true-client-ip', 'x-real-ip']);
41
+ /**
42
+ * Drop edge/CDN headers the hub's own fronting proxy (e.g. Cloudflare) added to
43
+ * the consumer request. They describe the hub's ingress, not this producer's
44
+ * egress — forwarded upstream they read as spoofed (cdn-loop/cf-*) and the
45
+ * upstream's edge answers with a 403 challenge page.
46
+ */
47
+ function stripEdgeHeaders(headers) {
48
+ for (const key of Object.keys(headers)) {
49
+ const lower = key.toLowerCase();
50
+ if (EDGE_INJECTED.has(lower) || lower.startsWith('cf-') || lower.startsWith('x-forwarded-')) {
51
+ delete headers[key];
52
+ }
53
+ }
54
+ }
55
+ /** Normalize a JSON request to the subset chatgpt's Codex backend accepts.
56
+ * Non-JSON bodies pass through untouched — the upstream rejects those itself. */
57
+ export function prepareCodexBody(body) {
58
+ if (body.byteLength === 0)
59
+ return body;
60
+ let parsed;
61
+ try {
62
+ parsed = JSON.parse(Buffer.from(body).toString('utf8'));
63
+ }
64
+ catch {
65
+ return body;
66
+ }
67
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed))
68
+ return body;
69
+ const request = parsed;
70
+ request.store = false;
71
+ // OpenCode's @ai-sdk/openai emits this standard Responses field, but the
72
+ // account backend rejects it. Codex CLI omits it as well.
73
+ delete request.max_output_tokens;
74
+ return Buffer.from(JSON.stringify(parsed), 'utf8');
75
+ }
25
76
  //# sourceMappingURL=adapters.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAwB,EACxB,GAA4D;IAE5D,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAChD,2FAA2F;IAC3F,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;IAC5D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,GAAG,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,CAAA;IAC7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IAClC,CAAC;IAED,MAAM,OAAO,GAA2B,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC1D,IAAI,OAAO,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACrC,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAA;QACzD,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,YAAY,CAAA;IAC7E,CAAC;SAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO,CAAC,aAAa,GAAG,UAAU,OAAO,CAAC,MAAM,EAAE,CAAA;IACpD,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAA;AACzC,CAAC"}
1
+ {"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,6 @@
1
1
  import { type Protocol } from 'aweshare-protocol';
2
+ /** CLI logins a backend can authenticate with (the producer machine's own login). */
3
+ export type LoginProvider = 'codex';
2
4
  export interface Backend {
3
5
  id: string;
4
6
  protocol: Protocol;
@@ -10,6 +12,8 @@ export interface Backend {
10
12
  */
11
13
  baseUrl: string;
12
14
  keyRef?: string;
15
+ /** Account auth instead of an upstream key; mutually exclusive with keyRef. */
16
+ login?: LoginProvider;
13
17
  }
14
18
  export interface CatalogOffering {
15
19
  alias: string;
@@ -31,24 +31,47 @@ export function parseCatalog(raw, secrets) {
31
31
  // parse, don't prefix-match: a malformed-but-http-prefixed URL (unclosed
32
32
  // IPv6 bracket, embedded space) would otherwise pass and only explode at
33
33
  // request time inside new URL()
34
- let baseUrlValid = false;
34
+ let parsedBaseUrl;
35
35
  if (/^https?:\/\//.test(baseUrl)) {
36
36
  try {
37
- new URL(baseUrl);
38
- baseUrlValid = true;
37
+ parsedBaseUrl = new URL(baseUrl);
39
38
  }
40
39
  catch {
41
- baseUrlValid = false;
40
+ parsedBaseUrl = undefined;
42
41
  }
43
42
  }
44
- if (!baseUrlValid) {
45
- problems.push(`backend '${id}': baseUrl must be a valid http(s) URL, got '${baseUrl || '(missing)'}'`);
43
+ if (!parsedBaseUrl) {
44
+ problems.push(`backend '${id || '?'}': baseUrl must be a valid http(s) URL, got '${baseUrl || '(missing)'}'`);
45
+ continue;
46
+ }
47
+ if (b.login !== undefined && b.login !== 'codex') {
48
+ problems.push(`backend '${id}': login must be "codex" (the only CLI login supported)`);
49
+ continue;
50
+ }
51
+ const login = b.login === 'codex' ? 'codex' : undefined;
52
+ if (login === 'codex' && protocol !== 'responses') {
53
+ problems.push(`backend '${id}': codex login protocol must be "responses"`);
54
+ continue;
55
+ }
56
+ const normalizedPath = parsedBaseUrl.pathname.replace(/\/+$/, '');
57
+ if (login === 'codex' &&
58
+ (parsedBaseUrl.origin !== 'https://chatgpt.com' ||
59
+ normalizedPath !== '/backend-api/codex' ||
60
+ parsedBaseUrl.username !== '' ||
61
+ parsedBaseUrl.password !== '' ||
62
+ parsedBaseUrl.search !== '' ||
63
+ parsedBaseUrl.hash !== '')) {
64
+ problems.push(`backend '${id}': codex login baseUrl must be https://chatgpt.com/backend-api/codex so account credentials are sent only to the official upstream`);
65
+ continue;
66
+ }
67
+ if (login !== undefined && keyRef !== undefined) {
68
+ problems.push(`backend '${id}': login and keyRef are mutually exclusive — an account login replaces an upstream key`);
46
69
  continue;
47
70
  }
48
71
  if (keyRef && !(keyRef in secrets)) {
49
72
  problems.push(`backend '${id}': keyRef '${keyRef}' not found in secrets.json`);
50
73
  }
51
- backends.push({ id, protocol: protocol, baseUrl, keyRef });
74
+ backends.push({ id, protocol: protocol, baseUrl, keyRef, login });
52
75
  }
53
76
  const backendIds = new Set(backends.map((b) => b.id));
54
77
  const protocolOf = new Map(backends.map((b) => [b.id, b.protocol]));
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /** What a login backend needs from the producer machine's own CLI login. */
2
+ export interface CodexCredentials {
3
+ accessToken: string;
4
+ accountId: string;
5
+ }
6
+ /** One unreadable CLI login; the message is user-ready and secret-free. */
7
+ export declare class CredentialError extends Error {
8
+ }
9
+ export declare function codexAuthPath(env?: NodeJS.ProcessEnv): string;
10
+ /**
11
+ * (access_token, account_id) from Codex's auth.json; a bare tokens block is
12
+ * accepted too. CredentialError when the shape is not recognized — the
13
+ * message never contains file content.
14
+ */
15
+ export declare function parseCodexAuth(text: string): CodexCredentials;
16
+ /**
17
+ * The codex login, cached per auth.json path: served straight from the cache
18
+ * while mtime/size are unchanged, re-read from disk otherwise or after
19
+ * invalidateCodexCredentials() (the 401 path — a rotation can land inside
20
+ * the stat granularity).
21
+ */
22
+ export declare function readCodexCredentials(env?: NodeJS.ProcessEnv): CodexCredentials;
23
+ /** Drop the cached login(s): the next read goes to disk. Called after an
24
+ * upstream 401 on a login backend. */
25
+ export declare function invalidateCodexCredentials(): void;
@@ -0,0 +1,86 @@
1
+ import { readFileSync, statSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ /** One unreadable CLI login; the message is user-ready and secret-free. */
5
+ export class CredentialError extends Error {
6
+ }
7
+ export function codexAuthPath(env = process.env) {
8
+ // Codex itself reads CODEX_HOME, so honoring it reads the same login the
9
+ // local CLI would use.
10
+ return join(env.CODEX_HOME ?? join(homedir(), '.codex'), 'auth.json');
11
+ }
12
+ /**
13
+ * (access_token, account_id) from Codex's auth.json; a bare tokens block is
14
+ * accepted too. CredentialError when the shape is not recognized — the
15
+ * message never contains file content.
16
+ */
17
+ export function parseCodexAuth(text) {
18
+ let payload;
19
+ try {
20
+ payload = JSON.parse(text);
21
+ }
22
+ catch {
23
+ throw new CredentialError('credential format not recognized — run `codex login` on this machine and retry');
24
+ }
25
+ const tokens = payload !== null && typeof payload === 'object' && 'tokens' in payload
26
+ ? payload.tokens
27
+ : payload;
28
+ const field = (name) => tokens !== null && typeof tokens === 'object' && name in tokens
29
+ ? tokens[name]
30
+ : undefined;
31
+ const accessToken = field('access_token');
32
+ const accountId = field('account_id');
33
+ if (typeof accessToken !== 'string' ||
34
+ !accessToken ||
35
+ typeof accountId !== 'string' ||
36
+ !accountId) {
37
+ throw new CredentialError('credential format not recognized — run `codex login` on this machine and retry');
38
+ }
39
+ return { accessToken, accountId };
40
+ }
41
+ const cache = new Map();
42
+ /**
43
+ * The codex login, cached per auth.json path: served straight from the cache
44
+ * while mtime/size are unchanged, re-read from disk otherwise or after
45
+ * invalidateCodexCredentials() (the 401 path — a rotation can land inside
46
+ * the stat granularity).
47
+ */
48
+ export function readCodexCredentials(env = process.env) {
49
+ const path = codexAuthPath(env);
50
+ let st;
51
+ try {
52
+ // stat before reading: a write landing between the two leaves the cache
53
+ // keyed on the older stat, so the next call re-reads — never serves the
54
+ // cached login over a newer file unnoticed
55
+ st = statSync(path);
56
+ }
57
+ catch (err) {
58
+ if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
59
+ throw new CredentialError(`the Codex login not found at ${path} — log in with \`codex login\` and retry`);
60
+ }
61
+ throw new CredentialError(`cannot read the Codex login at ${path}: ${err instanceof Error ? err.message : err}`);
62
+ }
63
+ const hit = cache.get(path);
64
+ if (hit && hit.stat.mtimeMs === st.mtimeMs && hit.stat.size === st.size) {
65
+ return hit.creds;
66
+ }
67
+ let text;
68
+ try {
69
+ text = readFileSync(path, 'utf8');
70
+ }
71
+ catch (err) {
72
+ throw new CredentialError(`cannot read the Codex login at ${path}: ${err instanceof Error ? err.message : err}`);
73
+ }
74
+ if (!text.trim()) {
75
+ throw new CredentialError(`the Codex login at ${path} is empty — log in with \`codex login\` and retry`);
76
+ }
77
+ const creds = parseCodexAuth(text);
78
+ cache.set(path, { stat: { mtimeMs: st.mtimeMs, size: st.size }, creds });
79
+ return creds;
80
+ }
81
+ /** Drop the cached login(s): the next read goes to disk. Called after an
82
+ * upstream 401 on a login backend. */
83
+ export function invalidateCodexCredentials() {
84
+ cache.clear();
85
+ }
86
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,38 @@
1
1
  import type { BackendStatus } from 'aweshare-protocol';
2
+ import type { Logger } from 'pino';
2
3
  export type FailureReason = 'AUTH' | 'QUOTA' | 'HTTP' | 'NETWORK' | 'CANCELLED';
4
+ /** Ladder transition a record() caused, for logging: entering degraded,
5
+ * clearing it, or nothing. */
6
+ export type HealthTransition = 'degraded' | 'recovered' | null;
3
7
  /**
4
8
  * Per-backend health state. Degraded backends are reported in heartbeats and
5
- * the hub stops dispatching to their offerings until they recover.
9
+ * the hub stops dispatching to their offerings until they recover. The
10
+ * ladder is two rungs — healthy -> degraded, latched until a success — which
11
+ * for a relay is what awewarm's deeper ladder collapses to: its intermediate
12
+ * rungs trade probe expense against recovery speed, and a relay's probes are
13
+ * cheap pings, not quota-consuming activations. What does carry over from
14
+ * awewarm is the escalating probe schedule above: the longer a backend has
15
+ * been continuously degraded, the quieter its recovery probes become, down
16
+ * to a daily last gasp that never fully gives up.
6
17
  */
7
18
  export declare class HealthGate {
19
+ private readonly now;
8
20
  private consecutive;
9
21
  private degraded;
10
- record(backendId: string, ok: boolean, reason?: FailureReason): void;
22
+ private degradedSince;
23
+ private probeDelayMs;
24
+ private probeNotBefore;
25
+ /** The clock is injected so tests can walk the cap ladder without waiting. */
26
+ constructor(now?: () => number);
27
+ record(backendId: string, ok: boolean, reason?: FailureReason): HealthTransition;
28
+ /** Epoch ms before which a recovery probe for this backend should be
29
+ * skipped (backoff); 0 when no failed probe is being held back. */
30
+ probeNotBeforeMs(backendId: string): number;
11
31
  isDegraded(backendId: string): boolean;
12
32
  statusMap(): Record<string, BackendStatus>;
13
33
  }
34
+ /** Log a ladder transition where it happened — the request path or a probe
35
+ * loop — so "why is it still degraded" is answerable from the logs. */
36
+ export declare function logHealthTransition(log: Logger, backendId: string, transition: HealthTransition, detail?: string): void;
14
37
  /** Map an upstream HTTP status to a failure class (ok responses pass null). */
15
38
  export declare function classifyStatus(status: number): FailureReason | null;
@@ -1,26 +1,89 @@
1
1
  /** AUTH/QUOTA consecutive failures >= threshold -> degraded until a success. */
2
2
  const DEGRADE_THRESHOLD = 2;
3
+ // Recovery-probe backoff, awewarm-style: while degraded, each failed probe
4
+ // doubles the wait before the next one, so an exhausted quota isn't pinged at
5
+ // the base cadence for hours on end. Any success clears the degraded state
6
+ // and the backoff with it. Unlike awewarm — whose probes are quota-consuming
7
+ // activations that must back off a full window — a relay's probes are free
8
+ // pings, so the cap escalates with how long the backend has stayed degraded
9
+ // rather than jumping straight to window-length silence:
10
+ // < 15h cap 5min covers ~3 GLM 5h-window rolls: refresh picked up fast
11
+ // < 45h cap 1h not a window roll anymore — likely needs a human
12
+ // < 105h cap 6h long dead; quiet but still self-healing
13
+ // else cap 24h daily last gasp, keeps auto-recovery alive forever
14
+ const PROBE_BACKOFF_BASE_MS = 30_000;
15
+ const PROBE_FALLBACK_CAP_MS = 24 * 3_600_000;
16
+ const PROBE_CAP_SCHEDULE = [
17
+ { afterMs: 15 * 3_600_000, capMs: 5 * 60_000 },
18
+ { afterMs: 45 * 3_600_000, capMs: 3_600_000 },
19
+ { afterMs: 105 * 3_600_000, capMs: 6 * 3_600_000 },
20
+ { afterMs: Number.POSITIVE_INFINITY, capMs: PROBE_FALLBACK_CAP_MS },
21
+ ];
3
22
  /**
4
23
  * Per-backend health state. Degraded backends are reported in heartbeats and
5
- * the hub stops dispatching to their offerings until they recover.
24
+ * the hub stops dispatching to their offerings until they recover. The
25
+ * ladder is two rungs — healthy -> degraded, latched until a success — which
26
+ * for a relay is what awewarm's deeper ladder collapses to: its intermediate
27
+ * rungs trade probe expense against recovery speed, and a relay's probes are
28
+ * cheap pings, not quota-consuming activations. What does carry over from
29
+ * awewarm is the escalating probe schedule above: the longer a backend has
30
+ * been continuously degraded, the quieter its recovery probes become, down
31
+ * to a daily last gasp that never fully gives up.
6
32
  */
7
33
  export class HealthGate {
34
+ now;
8
35
  consecutive = new Map();
9
36
  degraded = new Map();
37
+ degradedSince = new Map();
38
+ probeDelayMs = new Map();
39
+ probeNotBefore = new Map();
40
+ /** The clock is injected so tests can walk the cap ladder without waiting. */
41
+ constructor(now = Date.now) {
42
+ this.now = now;
43
+ }
10
44
  record(backendId, ok, reason) {
11
45
  if (ok) {
12
46
  this.consecutive.delete(backendId);
13
- this.degraded.delete(backendId);
14
- return;
47
+ const wasDegraded = this.degraded.delete(backendId);
48
+ this.degradedSince.delete(backendId);
49
+ this.probeDelayMs.delete(backendId);
50
+ this.probeNotBefore.delete(backendId);
51
+ return wasDegraded ? 'recovered' : null;
15
52
  }
16
53
  if (reason === undefined || reason === 'CANCELLED')
17
- return;
54
+ return null;
55
+ // failures recorded while already degraded are probe outcomes (admission
56
+ // 503s before dialing, so real traffic can't add any) — back the next
57
+ // probe off. The failure that causes the degradation does not: the first
58
+ // probe should stay immediate so a just-refreshed quota or a fresh login
59
+ // is picked up on the next tick.
60
+ const wasDegraded = this.degraded.has(backendId);
18
61
  const current = this.consecutive.get(backendId);
19
62
  const count = current?.reason === reason ? current.count + 1 : 1;
20
63
  this.consecutive.set(backendId, { reason, count });
64
+ let transition = null;
21
65
  if ((reason === 'AUTH' || reason === 'QUOTA') && count >= DEGRADE_THRESHOLD) {
66
+ if (!wasDegraded) {
67
+ transition = 'degraded';
68
+ this.degradedSince.set(backendId, this.now());
69
+ }
22
70
  this.degraded.set(backendId, { state: 'degraded', reason });
23
71
  }
72
+ if (wasDegraded) {
73
+ const since = this.degradedSince.get(backendId) ?? this.now();
74
+ // The final tier is Infinity, so the fallback is only a type-safe guard.
75
+ const cap = PROBE_CAP_SCHEDULE.find((tier) => this.now() - since < tier.afterMs)?.capMs ??
76
+ PROBE_FALLBACK_CAP_MS;
77
+ const delay = Math.min((this.probeDelayMs.get(backendId) ?? PROBE_BACKOFF_BASE_MS / 2) * 2, cap);
78
+ this.probeDelayMs.set(backendId, delay);
79
+ this.probeNotBefore.set(backendId, this.now() + delay);
80
+ }
81
+ return transition;
82
+ }
83
+ /** Epoch ms before which a recovery probe for this backend should be
84
+ * skipped (backoff); 0 when no failed probe is being held back. */
85
+ probeNotBeforeMs(backendId) {
86
+ return this.probeNotBefore.get(backendId) ?? 0;
24
87
  }
25
88
  isDegraded(backendId) {
26
89
  return this.degraded.has(backendId);
@@ -32,6 +95,16 @@ export class HealthGate {
32
95
  return out;
33
96
  }
34
97
  }
98
+ /** Log a ladder transition where it happened — the request path or a probe
99
+ * loop — so "why is it still degraded" is answerable from the logs. */
100
+ export function logHealthTransition(log, backendId, transition, detail) {
101
+ if (transition === 'degraded') {
102
+ log.warn(`backend ${backendId} degraded${detail ? ` (${detail})` : ''}`);
103
+ }
104
+ else if (transition === 'recovered') {
105
+ log.info(`backend ${backendId} recovered${detail ? ` — ${detail}` : ''}`);
106
+ }
107
+ }
35
108
  /** Map an upstream HTTP status to a failure class (ok responses pass null). */
36
109
  export function classifyStatus(status) {
37
110
  if (status < 400)
@@ -1 +1 @@
1
- {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"AAIA,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,CAAC,CAAA;AAE3B;;;GAGG;AACH,MAAM,OAAO,UAAU;IACb,WAAW,GAAG,IAAI,GAAG,EAAoD,CAAA;IACzE,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAA;IAEnD,MAAM,CAAC,SAAiB,EAAE,EAAW,EAAE,MAAsB;QAC3D,IAAI,EAAE,EAAE,CAAC;YACP,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YAC/B,OAAM;QACR,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,WAAW;YAAE,OAAM;QAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAChE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;QAClD,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,OAAO,CAAC,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAAC;YAC5E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAA;QAC7D,CAAC;IACH,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACrC,CAAC;IAED,SAAS;QACP,MAAM,GAAG,GAAkC,EAAE,CAAA;QAC7C,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ;YAAE,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAA;QAC1D,OAAO,GAAG,CAAA;IACZ,CAAC;CACF;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,IAAI,MAAM,GAAG,GAAG;QAAE,OAAO,IAAI,CAAA;IAC7B,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,MAAM,CAAA;IACnD,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,OAAO,CAAA;IACpD,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../src/health.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  export * from './adapters.js';
2
2
  export * from './catalog.js';
3
+ export * from './credentials.js';
3
4
  export * from './health.js';
4
5
  export * from './job.js';
5
6
  export * from './probe.js';
7
+ export * from './proxy.js';
@@ -1,6 +1,8 @@
1
1
  export * from './adapters.js';
2
2
  export * from './catalog.js';
3
+ export * from './credentials.js';
3
4
  export * from './health.js';
4
5
  export * from './job.js';
5
6
  export * from './probe.js';
7
+ export * from './proxy.js';
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA"}
@@ -1,5 +1,7 @@
1
- import { buildUpstreamRequest } from './adapters.js';
2
- import { classifyStatus } from './health.js';
1
+ import { buildUpstreamRequest, prepareCodexBody, } from './adapters.js';
2
+ import { CredentialError, invalidateCodexCredentials } from './credentials.js';
3
+ import { classifyStatus, logHealthTransition } from './health.js';
4
+ import { codexNetworkHint, fetchUpstream } from './proxy.js';
3
5
  /** Thrown by a sink whose transport died (e.g. a closed tunnel socket): the
4
6
  * job stops silently — no health record, no error frame nobody would read. */
5
7
  export class SinkClosedError extends Error {
@@ -39,18 +41,23 @@ export class UpstreamJob {
39
41
  // inside the try: a malformed URL must flow to sink.error like any other
40
42
  // failure — execute() must never reject
41
43
  const { url, headers } = buildUpstreamRequest(backend, init);
42
- const resp = await fetch(url, {
44
+ const body = backend.login !== undefined ? prepareCodexBody(init.body) : init.body;
45
+ const resp = await fetchUpstream(backend, url, {
43
46
  method: init.method,
44
47
  headers,
45
48
  // GET/HEAD must carry no body, even an empty one
46
- body: init.body.byteLength > 0 ? Buffer.from(init.body) : undefined,
49
+ body: body.byteLength > 0 ? Buffer.from(body) : undefined,
47
50
  signal: this.controller.signal,
48
51
  redirect: 'manual',
49
52
  });
50
53
  clearTimeout(connectTimer);
51
54
  log.debug(`request ${id} upstream ${backend.id} -> ${resp.status}`);
52
55
  const reason = classifyStatus(resp.status);
53
- health.record(backend.id, reason === null, reason ?? undefined);
56
+ logHealthTransition(log, backend.id, health.record(backend.id, reason === null, reason ?? undefined), `upstream ${resp.status}`);
57
+ // a 401 on a login backend means the token rotated or expired; drop the
58
+ // cached login so the next request re-reads auth.json
59
+ if (resp.status === 401 && backend.login !== undefined)
60
+ invalidateCodexCredentials();
54
61
  if (this.aborted)
55
62
  return;
56
63
  sink.head(resp.status, pickHeaders(resp));
@@ -70,10 +77,18 @@ export class UpstreamJob {
70
77
  clearTimeout(connectTimer);
71
78
  if (this.aborted || err instanceof SinkClosedError)
72
79
  return;
80
+ if (err instanceof CredentialError) {
81
+ // an unreadable login is an auth failure, not a network one: two in a
82
+ // row degrade the backend like any other AUTH loss
83
+ log.warn(`request ${id} upstream ${backend.id}: ${err.message}`);
84
+ logHealthTransition(log, backend.id, health.record(backend.id, false, 'AUTH'));
85
+ sink.error('BACKEND_LOGIN', err.message);
86
+ return;
87
+ }
73
88
  const timedOut = err instanceof ConnectTimeoutError;
74
89
  log.warn(`request ${id} upstream ${backend.id} failed: ${err instanceof Error ? err.message : err}`);
75
- health.record(backend.id, false, 'NETWORK');
76
- sink.error(timedOut ? 'BACKEND_TIMEOUT' : 'BACKEND_UNREACHABLE', `upstream ${backend.id} failed: ${err instanceof Error ? err.message : String(err)}`);
90
+ logHealthTransition(log, backend.id, health.record(backend.id, false, 'NETWORK'), err instanceof Error ? err.message : undefined);
91
+ sink.error(timedOut ? 'BACKEND_TIMEOUT' : 'BACKEND_UNREACHABLE', `upstream ${backend.id} failed: ${err instanceof Error ? err.message : String(err)}${codexNetworkHint(backend)}`);
77
92
  }
78
93
  }
79
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"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"}
@@ -3,4 +3,4 @@ export declare function probeTarget(backend: ResolvedBackend): {
3
3
  url: string;
4
4
  headers: Record<string, string>;
5
5
  };
6
- export declare function probeBody(model: string, protocol?: 'openai' | 'anthropic' | 'responses'): Record<string, unknown>;
6
+ export declare function probeBody(model: string, protocol?: 'openai' | 'anthropic' | 'responses', login?: boolean): Record<string, unknown>;
@@ -1,3 +1,4 @@
1
+ import { readCodexCredentials } from './credentials.js';
1
2
  export function probeTarget(backend) {
2
3
  const base = backend.baseUrl.replace(/\/+$/, '');
3
4
  const path = backend.protocol === 'anthropic'
@@ -6,7 +7,16 @@ export function probeTarget(backend) {
6
7
  ? '/responses'
7
8
  : '/chat/completions';
8
9
  const headers = { 'content-type': 'application/json' };
9
- if (backend.protocol === 'anthropic') {
10
+ if (backend.login === 'codex') {
11
+ // same recipe buildUpstreamRequest injects, so a green probe means a
12
+ // working login, not a working key path
13
+ const { accessToken, accountId } = readCodexCredentials();
14
+ headers.authorization = `Bearer ${accessToken}`;
15
+ headers['chatgpt-account-id'] = accountId;
16
+ headers['openai-beta'] = 'responses=experimental';
17
+ headers.originator = 'codex_cli_rs';
18
+ }
19
+ else if (backend.protocol === 'anthropic') {
10
20
  if (backend.apiKey)
11
21
  headers['x-api-key'] = backend.apiKey;
12
22
  headers['anthropic-version'] = '2023-06-01';
@@ -16,13 +26,27 @@ export function probeTarget(backend) {
16
26
  }
17
27
  return { url: base + path, headers };
18
28
  }
19
- export function probeBody(model, protocol = 'openai') {
29
+ export function probeBody(model, protocol = 'openai', login = false) {
20
30
  if (protocol === 'responses') {
31
+ // chatgpt's codex backend rejects stream:false ("Stream must be set to
32
+ // true") and max_output_tokens — a 400 probe would keep a degraded login
33
+ // backend stuck forever, so login probes speak the shape it accepts
34
+ if (login) {
35
+ return {
36
+ model,
37
+ input: [{ role: 'user', content: 'ping' }],
38
+ stream: true,
39
+ store: false,
40
+ };
41
+ }
21
42
  return {
22
43
  model,
23
44
  input: [{ role: 'user', content: 'ping' }],
24
45
  max_output_tokens: 1,
25
46
  stream: false,
47
+ // never persist a throwaway probe; chatgpt's responses backend also
48
+ // requires store:false on login accounts
49
+ store: false,
26
50
  };
27
51
  }
28
52
  return { model, messages: [{ role: 'user', content: 'ping' }], max_tokens: 1, stream: false };