@askalf/dario 4.8.125 → 4.8.127
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/live-fingerprint.d.ts +1 -1
- package/dist/live-fingerprint.js +1 -1
- package/dist/oauth.js +7 -4
- package/dist/proxy.d.ts +29 -0
- package/dist/proxy.js +56 -1
- package/package.json +1 -1
|
@@ -282,7 +282,7 @@ export declare function _resetInstalledVersionProbeForTest(): void;
|
|
|
282
282
|
*/
|
|
283
283
|
export declare const SUPPORTED_CC_RANGE: {
|
|
284
284
|
readonly min: "1.0.0";
|
|
285
|
-
readonly maxTested: "2.1.
|
|
285
|
+
readonly maxTested: "2.1.199";
|
|
286
286
|
};
|
|
287
287
|
/**
|
|
288
288
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/live-fingerprint.js
CHANGED
|
@@ -786,7 +786,7 @@ export function _resetInstalledVersionProbeForTest() {
|
|
|
786
786
|
*/
|
|
787
787
|
export const SUPPORTED_CC_RANGE = {
|
|
788
788
|
min: '1.0.0',
|
|
789
|
-
maxTested: '2.1.
|
|
789
|
+
maxTested: '2.1.199',
|
|
790
790
|
};
|
|
791
791
|
/**
|
|
792
792
|
* Compare two dotted-numeric version strings. Returns negative if `a<b`,
|
package/dist/oauth.js
CHANGED
|
@@ -454,8 +454,8 @@ export async function startAutoOAuthFlow() {
|
|
|
454
454
|
// Exchange the code for tokens
|
|
455
455
|
server.close();
|
|
456
456
|
exchangeCodeWithRedirect(code, codeVerifier, state, port)
|
|
457
|
-
.then(resolve)
|
|
458
|
-
.catch(reject);
|
|
457
|
+
.then((tokens) => { clearTimeout(loginTimeout); resolve(tokens); })
|
|
458
|
+
.catch((e) => { clearTimeout(loginTimeout); reject(e); });
|
|
459
459
|
});
|
|
460
460
|
let port = 0;
|
|
461
461
|
server.listen(0, 'localhost', async () => {
|
|
@@ -490,11 +490,14 @@ export async function startAutoOAuthFlow() {
|
|
|
490
490
|
server.on('error', (err) => {
|
|
491
491
|
reject(new Error(`Failed to start OAuth callback server: ${err.message}`));
|
|
492
492
|
});
|
|
493
|
-
// Timeout after 5 minutes
|
|
494
|
-
|
|
493
|
+
// Timeout after 5 minutes. unref so a completed login (server already
|
|
494
|
+
// closed, promise resolved on the success path) does not pin the process
|
|
495
|
+
// for 5 min — the #642-audit CLI hang. Also cleared on success below.
|
|
496
|
+
const loginTimeout = setTimeout(() => {
|
|
495
497
|
server.close();
|
|
496
498
|
reject(new Error('OAuth flow timed out. Try again with `dario login`.'));
|
|
497
499
|
}, 300_000);
|
|
500
|
+
loginTimeout.unref();
|
|
498
501
|
});
|
|
499
502
|
}
|
|
500
503
|
/**
|
package/dist/proxy.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type IncomingMessage } from 'node:http';
|
|
2
2
|
import { type WriteStream } from 'node:fs';
|
|
3
|
+
import { getAccessToken, getStatus } from './oauth.js';
|
|
3
4
|
import { type EffortValue } from './cc-template.js';
|
|
4
5
|
/**
|
|
5
6
|
* Resolve a Claude-side model name through the family-alias rules if it's a
|
|
@@ -454,5 +455,33 @@ export declare function upstreamAuthHeaders(upstreamApiKey: string, accessToken:
|
|
|
454
455
|
* testing.
|
|
455
456
|
*/
|
|
456
457
|
export declare function shouldUsePool(accountCount: number, adminEnabled: boolean): boolean;
|
|
458
|
+
/**
|
|
459
|
+
* Resolve the single-account startup auth outcome, refreshing an expired-but-
|
|
460
|
+
* refreshable access token before giving up.
|
|
461
|
+
*
|
|
462
|
+
* The classic single-account startup used to read getStatus() once and, on any
|
|
463
|
+
* un-authenticated result, log "Not authenticated" and process.exit(1) WITHOUT
|
|
464
|
+
* attempting a refresh. Because Docker restarts the container, that turned a
|
|
465
|
+
* routine access-token expiry into a CRASH LOOP whenever the container was
|
|
466
|
+
* (re)started while the access token was expired — even when the refresh token
|
|
467
|
+
* was still valid and a single refresh would have recovered cleanly (dario
|
|
468
|
+
* outage-hardening gap #1, 2026-07-02).
|
|
469
|
+
*
|
|
470
|
+
* getAccessToken() refreshes an expired-but-refreshable token on demand, but it
|
|
471
|
+
* SWALLOWS a failed refresh (returns the stale token, throwing only when there
|
|
472
|
+
* are no credentials at all), so its success/throw can't gate the exit. Instead:
|
|
473
|
+
* when the initial status is un-authenticated but merely 'expired' with a live
|
|
474
|
+
* refresh token, attempt the refresh via getAccessToken() and then RE-READ
|
|
475
|
+
* getStatus() — its `authenticated` flag is the authority on whether we
|
|
476
|
+
* actually recovered. A dead / invalid_grant refresh token leaves status
|
|
477
|
+
* un-authenticated on the re-read, so the caller still exit(1)s with the same
|
|
478
|
+
* message (no infinite loop). 'none' (no credentials) and 'broken' (refresh
|
|
479
|
+
* already known-dead) skip the doomed attempt entirely. Pure + injectable for
|
|
480
|
+
* unit testing.
|
|
481
|
+
*/
|
|
482
|
+
export declare function resolveSingleAccountStartupStatus(deps?: {
|
|
483
|
+
getStatus: typeof getStatus;
|
|
484
|
+
getAccessToken: typeof getAccessToken;
|
|
485
|
+
}): Promise<Awaited<ReturnType<typeof getStatus>>>;
|
|
457
486
|
export declare function startProxy(opts?: ProxyOptions): Promise<void>;
|
|
458
487
|
export {};
|
package/dist/proxy.js
CHANGED
|
@@ -720,6 +720,57 @@ export function upstreamAuthHeaders(upstreamApiKey, accessToken) {
|
|
|
720
720
|
export function shouldUsePool(accountCount, adminEnabled) {
|
|
721
721
|
return accountCount >= 1 || adminEnabled;
|
|
722
722
|
}
|
|
723
|
+
/**
|
|
724
|
+
* Resolve the single-account startup auth outcome, refreshing an expired-but-
|
|
725
|
+
* refreshable access token before giving up.
|
|
726
|
+
*
|
|
727
|
+
* The classic single-account startup used to read getStatus() once and, on any
|
|
728
|
+
* un-authenticated result, log "Not authenticated" and process.exit(1) WITHOUT
|
|
729
|
+
* attempting a refresh. Because Docker restarts the container, that turned a
|
|
730
|
+
* routine access-token expiry into a CRASH LOOP whenever the container was
|
|
731
|
+
* (re)started while the access token was expired — even when the refresh token
|
|
732
|
+
* was still valid and a single refresh would have recovered cleanly (dario
|
|
733
|
+
* outage-hardening gap #1, 2026-07-02).
|
|
734
|
+
*
|
|
735
|
+
* getAccessToken() refreshes an expired-but-refreshable token on demand, but it
|
|
736
|
+
* SWALLOWS a failed refresh (returns the stale token, throwing only when there
|
|
737
|
+
* are no credentials at all), so its success/throw can't gate the exit. Instead:
|
|
738
|
+
* when the initial status is un-authenticated but merely 'expired' with a live
|
|
739
|
+
* refresh token, attempt the refresh via getAccessToken() and then RE-READ
|
|
740
|
+
* getStatus() — its `authenticated` flag is the authority on whether we
|
|
741
|
+
* actually recovered. A dead / invalid_grant refresh token leaves status
|
|
742
|
+
* un-authenticated on the re-read, so the caller still exit(1)s with the same
|
|
743
|
+
* message (no infinite loop). 'none' (no credentials) and 'broken' (refresh
|
|
744
|
+
* already known-dead) skip the doomed attempt entirely. Pure + injectable for
|
|
745
|
+
* unit testing.
|
|
746
|
+
*/
|
|
747
|
+
export async function resolveSingleAccountStartupStatus(deps = {
|
|
748
|
+
getStatus,
|
|
749
|
+
getAccessToken,
|
|
750
|
+
}) {
|
|
751
|
+
let status = await deps.getStatus();
|
|
752
|
+
if (status.authenticated)
|
|
753
|
+
return status;
|
|
754
|
+
// Only an expired token with a live, non-broken refresh token is worth a
|
|
755
|
+
// refresh attempt. canRefresh already encodes "has refresh token && !broken".
|
|
756
|
+
if (status.status === 'expired' && status.canRefresh) {
|
|
757
|
+
console.error('[dario] Access token expired at startup — attempting refresh before giving up…');
|
|
758
|
+
try {
|
|
759
|
+
await deps.getAccessToken(); // refreshes an expired-but-refreshable token in place
|
|
760
|
+
}
|
|
761
|
+
catch {
|
|
762
|
+
// getAccessToken only throws when there are no credentials at all; a
|
|
763
|
+
// failed refresh is swallowed there. The re-read below is authoritative.
|
|
764
|
+
}
|
|
765
|
+
// saveCredentials() updated the on-disk tokens + in-memory cache on a
|
|
766
|
+
// successful refresh, so this reflects the post-refresh reality.
|
|
767
|
+
status = await deps.getStatus();
|
|
768
|
+
if (status.authenticated) {
|
|
769
|
+
console.error('[dario] Token refresh succeeded at startup — continuing.');
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return status;
|
|
773
|
+
}
|
|
723
774
|
export async function startProxy(opts = {}) {
|
|
724
775
|
const port = opts.port ?? DEFAULT_PORT;
|
|
725
776
|
const host = opts.host ?? process.env.DARIO_HOST ?? DEFAULT_HOST;
|
|
@@ -1002,7 +1053,11 @@ export async function startProxy(opts = {}) {
|
|
|
1002
1053
|
// ~/.dario/accounts/ is empty. Any accounts/ entry routes through the pool
|
|
1003
1054
|
// above (#618), and admin mode always does (#599) — it starts even with
|
|
1004
1055
|
// zero accounts and returns a clean 503 until one is added.
|
|
1005
|
-
|
|
1056
|
+
// An expired-but-refreshable access token here is self-healing: attempt a
|
|
1057
|
+
// refresh before giving up so a container (re)started shortly after a normal
|
|
1058
|
+
// token expiry recovers instead of crash-looping on exit(1) (gap #1). Only a
|
|
1059
|
+
// dead refresh token or no credentials at all still exits.
|
|
1060
|
+
status = await resolveSingleAccountStartupStatus();
|
|
1006
1061
|
if (!status.authenticated) {
|
|
1007
1062
|
console.error('[dario] Not authenticated. Run `dario login` first.');
|
|
1008
1063
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "4.8.
|
|
3
|
+
"version": "4.8.127",
|
|
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": {
|