@askalf/dario 3.31.14 → 3.31.15
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.js +46 -29
- package/dist/request-queue.d.ts +11 -0
- package/dist/request-queue.js +5 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,34 +12,22 @@
|
|
|
12
12
|
// ── Bun auto-relaunch ──
|
|
13
13
|
// Bun's TLS fingerprint matches Claude Code's runtime (both use Bun/BoringSSL).
|
|
14
14
|
// If Bun is installed and we're running on Node, relaunch under Bun for
|
|
15
|
-
// network-level fingerprint fidelity.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// Check if bun exists
|
|
20
|
-
execFileSync('bun', ['--version'], { stdio: 'ignore', timeout: 3000 });
|
|
21
|
-
// Relaunch under bun
|
|
22
|
-
const { spawn } = await import('node:child_process');
|
|
23
|
-
const child = spawn('bun', ['run', ...process.argv.slice(1)], {
|
|
24
|
-
stdio: 'inherit',
|
|
25
|
-
env: { ...process.env, DARIO_NO_BUN: '1' },
|
|
26
|
-
});
|
|
27
|
-
child.on('exit', (code) => process.exit(code ?? 0));
|
|
28
|
-
// Prevent this process from continuing
|
|
29
|
-
await new Promise(() => { });
|
|
30
|
-
}
|
|
31
|
-
catch {
|
|
32
|
-
// Bun not available, continue with Node
|
|
33
|
-
}
|
|
34
|
-
}
|
|
15
|
+
// network-level fingerprint fidelity. Moved below into the main-entry guard
|
|
16
|
+
// at the bottom of the file so importing this module (e.g. from tests that
|
|
17
|
+
// just want `parsePositiveIntEnv`) doesn't trigger a Bun relaunch or any
|
|
18
|
+
// other startup side effect.
|
|
35
19
|
import { unlink } from 'node:fs/promises';
|
|
36
20
|
import { join } from 'node:path';
|
|
37
21
|
import { homedir } from 'node:os';
|
|
22
|
+
import { pathToFileURL } from 'node:url';
|
|
38
23
|
import { startAutoOAuthFlow, startManualOAuthFlow, detectHeadlessEnvironment, getStatus, refreshTokens, loadCredentials } from './oauth.js';
|
|
39
24
|
import { startProxy, sanitizeError } from './proxy.js';
|
|
40
25
|
import { VALID_EFFORT_VALUES } from './cc-template.js';
|
|
41
26
|
import { listAccountAliases, loadAllAccounts, addAccountViaOAuth, removeAccount, ensureLoginCredentialsInPool, MIGRATED_LOGIN_ALIAS } from './accounts.js';
|
|
42
27
|
import { listBackends, saveBackend, removeBackend } from './openai-backend.js';
|
|
28
|
+
// `args` / `command` at module scope — command handlers below close over
|
|
29
|
+
// `args` to read their own flags. Reading argv is harmless on import; only
|
|
30
|
+
// the handler dispatch at the bottom is gated behind the main-entry check.
|
|
43
31
|
const args = process.argv.slice(2);
|
|
44
32
|
const command = args[0] ?? 'proxy';
|
|
45
33
|
async function login() {
|
|
@@ -1159,13 +1147,42 @@ const commands = {
|
|
|
1159
1147
|
'--version': version,
|
|
1160
1148
|
'-V': version,
|
|
1161
1149
|
};
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1150
|
+
// Main-entry guard. Only run the Bun auto-relaunch and handler dispatch when
|
|
1151
|
+
// this module is the direct entry point — importing it (from tests or for
|
|
1152
|
+
// a library helper like `parsePositiveIntEnv`) must NOT start the proxy.
|
|
1153
|
+
// Before this guard, `import { parsePositiveIntEnv } from './cli.js'` would
|
|
1154
|
+
// fall through to `command = args[0] ?? 'proxy'` and fire `handler()`, which
|
|
1155
|
+
// tried to run `startProxy()` and failed the test with "Not authenticated".
|
|
1156
|
+
const isDirectEntry = typeof process.argv[1] === 'string' &&
|
|
1157
|
+
import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
1158
|
+
if (isDirectEntry) {
|
|
1159
|
+
// Bun auto-relaunch for TLS fingerprint fidelity. Only meaningful when
|
|
1160
|
+
// dario is the direct entry — if we're imported, whoever imported us
|
|
1161
|
+
// already chose their runtime.
|
|
1162
|
+
if (!('Bun' in globalThis) && !process.env.DARIO_NO_BUN) {
|
|
1163
|
+
try {
|
|
1164
|
+
const { execFileSync, spawn } = await import('node:child_process');
|
|
1165
|
+
execFileSync('bun', ['--version'], { stdio: 'ignore', timeout: 3000 });
|
|
1166
|
+
const child = spawn('bun', ['run', ...process.argv.slice(1)], {
|
|
1167
|
+
stdio: 'inherit',
|
|
1168
|
+
env: { ...process.env, DARIO_NO_BUN: '1' },
|
|
1169
|
+
});
|
|
1170
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
1171
|
+
// Prevent this process from continuing
|
|
1172
|
+
await new Promise(() => { });
|
|
1173
|
+
}
|
|
1174
|
+
catch {
|
|
1175
|
+
// Bun not available, continue with Node
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
const handler = commands[command];
|
|
1179
|
+
if (!handler) {
|
|
1180
|
+
console.error(`Unknown command: ${command}`);
|
|
1181
|
+
console.error('Run `dario help` for usage.');
|
|
1182
|
+
process.exit(1);
|
|
1183
|
+
}
|
|
1184
|
+
handler().catch(err => {
|
|
1185
|
+
console.error('Fatal error:', sanitizeError(err));
|
|
1186
|
+
process.exit(1);
|
|
1187
|
+
});
|
|
1167
1188
|
}
|
|
1168
|
-
handler().catch(err => {
|
|
1169
|
-
console.error('Fatal error:', sanitizeError(err));
|
|
1170
|
-
process.exit(1);
|
|
1171
|
-
});
|
package/dist/request-queue.d.ts
CHANGED
|
@@ -50,6 +50,16 @@ export interface RequestQueueOptions {
|
|
|
50
50
|
maxConcurrent?: number;
|
|
51
51
|
maxQueued?: number;
|
|
52
52
|
queueTimeoutMs?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Whether timeout timers are `unref`'d so they don't by themselves keep
|
|
55
|
+
* the Node event loop alive. Default `true` — appropriate for the proxy,
|
|
56
|
+
* where a leaked queue entry should never hang shutdown. Pass `false` in
|
|
57
|
+
* tests where the queue is the only pending work on the loop: an
|
|
58
|
+
* `unref`'d timer won't fire in that case (Node exits with "unsettled
|
|
59
|
+
* top-level await" before the 50ms timeout elapses), so the reject the
|
|
60
|
+
* test is waiting for never arrives.
|
|
61
|
+
*/
|
|
62
|
+
unrefTimers?: boolean;
|
|
53
63
|
}
|
|
54
64
|
export declare const DEFAULT_MAX_CONCURRENT = 10;
|
|
55
65
|
export declare const DEFAULT_MAX_QUEUED = 128;
|
|
@@ -58,6 +68,7 @@ export declare class RequestQueue {
|
|
|
58
68
|
readonly maxConcurrent: number;
|
|
59
69
|
readonly maxQueued: number;
|
|
60
70
|
readonly queueTimeoutMs: number;
|
|
71
|
+
readonly unrefTimers: boolean;
|
|
61
72
|
private active;
|
|
62
73
|
private queue;
|
|
63
74
|
constructor(opts?: RequestQueueOptions);
|
package/dist/request-queue.js
CHANGED
|
@@ -47,12 +47,14 @@ export class RequestQueue {
|
|
|
47
47
|
maxConcurrent;
|
|
48
48
|
maxQueued;
|
|
49
49
|
queueTimeoutMs;
|
|
50
|
+
unrefTimers;
|
|
50
51
|
active = 0;
|
|
51
52
|
queue = [];
|
|
52
53
|
constructor(opts = {}) {
|
|
53
54
|
this.maxConcurrent = opts.maxConcurrent ?? DEFAULT_MAX_CONCURRENT;
|
|
54
55
|
this.maxQueued = opts.maxQueued ?? DEFAULT_MAX_QUEUED;
|
|
55
56
|
this.queueTimeoutMs = opts.queueTimeoutMs ?? DEFAULT_QUEUE_TIMEOUT_MS;
|
|
57
|
+
this.unrefTimers = opts.unrefTimers ?? true;
|
|
56
58
|
}
|
|
57
59
|
/**
|
|
58
60
|
* Acquire a concurrency slot. Resolves when admitted; throws
|
|
@@ -80,7 +82,9 @@ export class RequestQueue {
|
|
|
80
82
|
}, this.queueTimeoutMs);
|
|
81
83
|
// Keep the timer from pinning the event loop open on shutdown. A queued
|
|
82
84
|
// request waiting for a slot shouldn't by itself keep the process alive.
|
|
83
|
-
|
|
85
|
+
// Opt-out for tests — see `unrefTimers` comment in RequestQueueOptions.
|
|
86
|
+
if (this.unrefTimers)
|
|
87
|
+
timeoutHandle.unref?.();
|
|
84
88
|
const entry = { resolve, reject, enqueuedAt, timeoutHandle };
|
|
85
89
|
this.queue.push(entry);
|
|
86
90
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "3.31.
|
|
3
|
+
"version": "3.31.15",
|
|
4
4
|
"description": "A local LLM router. One endpoint, every provider — Claude subscriptions, OpenAI, OpenRouter, Groq, local LiteLLM, any OpenAI-compat endpoint — your tools don't need to change.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|