@askalf/dario 4.8.73 → 4.8.74
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/health-response.d.ts +28 -0
- package/dist/health-response.js +34 -0
- package/dist/proxy.js +6 -11
- package/package.json +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /health response builder — extracted so the public-vs-internal disclosure rule
|
|
3
|
+
* is unit-testable without spinning a proxy.
|
|
4
|
+
*
|
|
5
|
+
* dario's /health is auth-free (docker healthchecks + `depends_on: service_healthy`
|
|
6
|
+
* need it before any secret is configured). When dario sits behind a Cloudflare
|
|
7
|
+
* tunnel with a public /health bypass (uptime monitoring), that endpoint is
|
|
8
|
+
* world-readable — so it must not leak OAuth internals (token countdown, request
|
|
9
|
+
* volume, refresh errors). The Cloudflare edge stamps `cf-ray` on every request it
|
|
10
|
+
* proxies, so its presence marks a request as having come from the public internet.
|
|
11
|
+
* Internal callers (the docker healthcheck, `dario doctor`, the self-probe) hit
|
|
12
|
+
* dario directly on loopback with no CF headers and still get the full detail.
|
|
13
|
+
*
|
|
14
|
+
* The HTTP status (200 healthy / 503 degraded) is identical either way, so external
|
|
15
|
+
* uptime monitoring that keys on the status code is unaffected.
|
|
16
|
+
*/
|
|
17
|
+
export interface HealthStatusLike {
|
|
18
|
+
status: string;
|
|
19
|
+
canRefresh?: boolean;
|
|
20
|
+
expiresIn?: string;
|
|
21
|
+
refreshFailures?: number;
|
|
22
|
+
lastRefreshError?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface HealthResponse {
|
|
25
|
+
httpStatus: number;
|
|
26
|
+
body: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
export declare function buildHealthResponse(s: HealthStatusLike, requestCount: number, viaPublicTunnel: boolean): HealthResponse;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /health response builder — extracted so the public-vs-internal disclosure rule
|
|
3
|
+
* is unit-testable without spinning a proxy.
|
|
4
|
+
*
|
|
5
|
+
* dario's /health is auth-free (docker healthchecks + `depends_on: service_healthy`
|
|
6
|
+
* need it before any secret is configured). When dario sits behind a Cloudflare
|
|
7
|
+
* tunnel with a public /health bypass (uptime monitoring), that endpoint is
|
|
8
|
+
* world-readable — so it must not leak OAuth internals (token countdown, request
|
|
9
|
+
* volume, refresh errors). The Cloudflare edge stamps `cf-ray` on every request it
|
|
10
|
+
* proxies, so its presence marks a request as having come from the public internet.
|
|
11
|
+
* Internal callers (the docker healthcheck, `dario doctor`, the self-probe) hit
|
|
12
|
+
* dario directly on loopback with no CF headers and still get the full detail.
|
|
13
|
+
*
|
|
14
|
+
* The HTTP status (200 healthy / 503 degraded) is identical either way, so external
|
|
15
|
+
* uptime monitoring that keys on the status code is unaffected.
|
|
16
|
+
*/
|
|
17
|
+
export function buildHealthResponse(s, requestCount, viaPublicTunnel) {
|
|
18
|
+
const dead = s.status === 'broken' ||
|
|
19
|
+
s.status === 'none' ||
|
|
20
|
+
(s.status === 'expired' && s.canRefresh === false);
|
|
21
|
+
const httpStatus = dead ? 503 : 200;
|
|
22
|
+
const liveness = { status: dead ? 'degraded' : 'ok' };
|
|
23
|
+
const body = viaPublicTunnel
|
|
24
|
+
? liveness
|
|
25
|
+
: {
|
|
26
|
+
...liveness,
|
|
27
|
+
oauth: s.status,
|
|
28
|
+
expiresIn: s.expiresIn,
|
|
29
|
+
requests: requestCount,
|
|
30
|
+
...(s.refreshFailures ? { refreshFailures: s.refreshFailures } : {}),
|
|
31
|
+
...(s.lastRefreshError ? { lastRefreshError: s.lastRefreshError } : {}),
|
|
32
|
+
};
|
|
33
|
+
return { httpStatus, body };
|
|
34
|
+
}
|
package/dist/proxy.js
CHANGED
|
@@ -7,6 +7,7 @@ import { homedir } from 'node:os';
|
|
|
7
7
|
import { setDefaultResultOrder } from 'node:dns';
|
|
8
8
|
import { arch, platform } from 'node:process';
|
|
9
9
|
import { getAccessToken, getStatus } from './oauth.js';
|
|
10
|
+
import { buildHealthResponse } from './health-response.js';
|
|
10
11
|
import { buildCCRequest, applyCcPromptCaching, parseEffortSuffix, reverseMapResponse, createStreamingReverseMapper, orderHeadersForOutbound, CC_TEMPLATE } from './cc-template.js';
|
|
11
12
|
import { describeTemplate, detectDrift, checkCCCompat } from './live-fingerprint.js';
|
|
12
13
|
import { AccountPool, computeStickyKey, parseRateLimits, modelFamily, isInAuthCooldown, authCooldownMs } from './pool.js';
|
|
@@ -1110,18 +1111,12 @@ export async function startProxy(opts = {}) {
|
|
|
1110
1111
|
// react instead of cheerfully passing while every /v1/messages 401s.
|
|
1111
1112
|
if (urlPath === '/health' || urlPath === '/') {
|
|
1112
1113
|
const s = await getStatus();
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1114
|
+
// Public requests arrive through the Cloudflare tunnel (the edge stamps
|
|
1115
|
+
// `cf-ray`); they get only the liveness verdict, never the OAuth internals.
|
|
1116
|
+
// See buildHealthResponse for the full rationale.
|
|
1117
|
+
const { httpStatus, body } = buildHealthResponse(s, requestCount, req.headers['cf-ray'] !== undefined);
|
|
1116
1118
|
res.writeHead(httpStatus, JSON_HEADERS);
|
|
1117
|
-
res.end(JSON.stringify(
|
|
1118
|
-
status: dead ? 'degraded' : 'ok',
|
|
1119
|
-
oauth: s.status,
|
|
1120
|
-
expiresIn: s.expiresIn,
|
|
1121
|
-
requests: requestCount,
|
|
1122
|
-
...(s.refreshFailures ? { refreshFailures: s.refreshFailures } : {}),
|
|
1123
|
-
...(s.lastRefreshError ? { lastRefreshError: s.lastRefreshError } : {}),
|
|
1124
|
-
}));
|
|
1119
|
+
res.end(JSON.stringify(body));
|
|
1125
1120
|
return;
|
|
1126
1121
|
}
|
|
1127
1122
|
if (!checkAuth(req)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.74",
|
|
4
4
|
"description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|