opencode-auth-load-balancer 0.8.1 → 0.9.1
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/README.md +52 -23
- package/dist/index.js +641 -74
- package/dist/login-rev.d.ts +14 -0
- package/dist/providers/anthropic/usage.d.ts +2 -2
- package/dist/providers/kimi/usage.d.ts +1 -1
- package/dist/providers/openai/usage.d.ts +2 -1
- package/dist/providers/usage-http.d.ts +5 -8
- package/dist/refresh-hooks.d.ts +18 -0
- package/dist/sync/apply.d.ts +2 -0
- package/dist/sync/cycle.d.ts +2 -0
- package/dist/sync/enabled.d.ts +2 -0
- package/dist/sync/login-hooks.d.ts +14 -0
- package/dist/sync/login-payload.d.ts +40 -0
- package/dist/sync/logins.d.ts +63 -0
- package/dist/sync/payload.d.ts +13 -7
- package/dist/sync/start.d.ts +21 -3
- package/dist/sync/state.d.ts +6 -0
- package/dist/sync/text.d.ts +5 -0
- package/dist/token-mint.d.ts +10 -1
- package/dist/types.d.ts +10 -0
- package/dist/usage-merge.d.ts +5 -1
- package/dist/usage-poll.d.ts +11 -0
- package/dist/usage-refresh.d.ts +1 -12
- package/dist/v1.js +641 -74
- package/dist/v2-entry.js +641 -74
- package/package.json +1 -1
- package/tui/auth-load-balancer-tui.logic.ts +1 -1
package/dist/v2-entry.js
CHANGED
|
@@ -41438,6 +41438,15 @@ var init_tool = __esm(() => {
|
|
|
41438
41438
|
tool2.schema = exports_external2;
|
|
41439
41439
|
});
|
|
41440
41440
|
|
|
41441
|
+
// src/login-rev.ts
|
|
41442
|
+
function bumpLoginRev(row, now = Date.now()) {
|
|
41443
|
+
row.loginRev = (row.loginRev ?? 1) + 1;
|
|
41444
|
+
row.loginAt = now;
|
|
41445
|
+
}
|
|
41446
|
+
function loginVersion(row) {
|
|
41447
|
+
return { rev: row.loginRev ?? 1, at: row.loginAt ?? 0 };
|
|
41448
|
+
}
|
|
41449
|
+
|
|
41441
41450
|
// src/types.ts
|
|
41442
41451
|
function emptyUsage() {
|
|
41443
41452
|
return { hourly: null, weekly: null, capturedAt: 0 };
|
|
@@ -41868,6 +41877,10 @@ function normalizeAccounts(rows) {
|
|
|
41868
41877
|
delete row.orgId;
|
|
41869
41878
|
if (!isFiniteNumber(row.refreshExpires) || row.refreshExpires <= 0)
|
|
41870
41879
|
delete row.refreshExpires;
|
|
41880
|
+
if (typeof row.loginRev !== "number" || !Number.isSafeInteger(row.loginRev) || row.loginRev < 1)
|
|
41881
|
+
delete row.loginRev;
|
|
41882
|
+
if (!isFiniteNumber(row.loginAt) || row.loginAt < 0)
|
|
41883
|
+
delete row.loginAt;
|
|
41871
41884
|
if (row.inferenceToken === undefined || !isFiniteNumber(row.inferenceExpires) || row.inferenceExpires <= 0)
|
|
41872
41885
|
delete row.inferenceExpires;
|
|
41873
41886
|
if (row.lostLogins !== undefined) {
|
|
@@ -42130,6 +42143,14 @@ var init_score_core = __esm(() => {
|
|
|
42130
42143
|
});
|
|
42131
42144
|
|
|
42132
42145
|
// src/usage-merge.ts
|
|
42146
|
+
function reconcileQuotaCooldown(account, cfg, now) {
|
|
42147
|
+
if (account.cooldownKind === "auth" || account.cooldownKind === "transient")
|
|
42148
|
+
return;
|
|
42149
|
+
if (account.cooldownUntil > now + MAX_TRANSIENT_COOLDOWN_MS && !isExhausted(account, cfg, now)) {
|
|
42150
|
+
account.cooldownUntil = 0;
|
|
42151
|
+
delete account.cooldownKind;
|
|
42152
|
+
}
|
|
42153
|
+
}
|
|
42133
42154
|
function rollWeeklyAnchorForward(anchor, now) {
|
|
42134
42155
|
if (!Number.isFinite(anchor) || anchor <= 0)
|
|
42135
42156
|
return 0;
|
|
@@ -42146,8 +42167,10 @@ function preserveWeeklyAnchor(incoming, stored, now) {
|
|
|
42146
42167
|
return incoming;
|
|
42147
42168
|
return { utilization: incoming.utilization, resetAt: anchor };
|
|
42148
42169
|
}
|
|
42170
|
+
var MAX_TRANSIENT_COOLDOWN_MS;
|
|
42149
42171
|
var init_usage_merge = __esm(() => {
|
|
42150
42172
|
init_score_core();
|
|
42173
|
+
MAX_TRANSIENT_COOLDOWN_MS = 5 * 60 * 1000;
|
|
42151
42174
|
});
|
|
42152
42175
|
|
|
42153
42176
|
// src/accounts.ts
|
|
@@ -42175,6 +42198,10 @@ function makeAccount(providerID, label, tokens) {
|
|
|
42175
42198
|
account.orgId = tokens.orgId;
|
|
42176
42199
|
if (tokens.refreshExpires)
|
|
42177
42200
|
account.refreshExpires = tokens.refreshExpires;
|
|
42201
|
+
if (tokens.refresh && !tokens.inferenceOnly) {
|
|
42202
|
+
account.loginRev = 1;
|
|
42203
|
+
account.loginAt = Date.now();
|
|
42204
|
+
}
|
|
42178
42205
|
return account;
|
|
42179
42206
|
}
|
|
42180
42207
|
function recordLostLogin(row, login, reason) {
|
|
@@ -42195,10 +42222,14 @@ function mergeLoginUsage(row, usage) {
|
|
|
42195
42222
|
weekly: usage.weekly ? preserveWeeklyAnchor(usage.weekly, row.usage.weekly, usage.capturedAt) : row.usage.weekly,
|
|
42196
42223
|
capturedAt: usage.weekly ? usage.capturedAt : row.usage.capturedAt
|
|
42197
42224
|
};
|
|
42225
|
+
if (usage.weekly)
|
|
42226
|
+
reconcileQuotaCooldown(row, loadScoreConfig(), usage.capturedAt);
|
|
42198
42227
|
}
|
|
42199
42228
|
function applyTokens(row, tokens) {
|
|
42200
|
-
if (tokens.refresh)
|
|
42229
|
+
if (tokens.refresh) {
|
|
42201
42230
|
row.refresh = tokens.refresh;
|
|
42231
|
+
bumpLoginRev(row);
|
|
42232
|
+
}
|
|
42202
42233
|
row.access = tokens.access;
|
|
42203
42234
|
row.expires = tokens.expires;
|
|
42204
42235
|
row.disabledReason = null;
|
|
@@ -42286,6 +42317,7 @@ async function bootstrapFromOpencodeAuth(providerID, getAuth, tokensFromApiKey)
|
|
|
42286
42317
|
var init_accounts = __esm(() => {
|
|
42287
42318
|
init_pairing();
|
|
42288
42319
|
init_store();
|
|
42320
|
+
init_score_core();
|
|
42289
42321
|
init_types2();
|
|
42290
42322
|
init_usage_merge();
|
|
42291
42323
|
});
|
|
@@ -42408,6 +42440,15 @@ function mergeHeaders(input, init) {
|
|
|
42408
42440
|
return headers;
|
|
42409
42441
|
}
|
|
42410
42442
|
|
|
42443
|
+
// src/refresh-hooks.ts
|
|
42444
|
+
function setRefreshHooks(hooks) {
|
|
42445
|
+
current = hooks;
|
|
42446
|
+
}
|
|
42447
|
+
function getRefreshHooks() {
|
|
42448
|
+
return current;
|
|
42449
|
+
}
|
|
42450
|
+
var current = null;
|
|
42451
|
+
|
|
42411
42452
|
// src/refresh.ts
|
|
42412
42453
|
function needsRefresh(account, now) {
|
|
42413
42454
|
return !account.access || account.expires - REFRESH_SKEW_MS <= now;
|
|
@@ -42466,6 +42507,7 @@ async function commitRefresh(accountId, attempt, next) {
|
|
|
42466
42507
|
if (!sameGeneration(stored, attempt))
|
|
42467
42508
|
return tokensOf(stored);
|
|
42468
42509
|
applyTokensTo(stored, next);
|
|
42510
|
+
bumpLoginRev(stored);
|
|
42469
42511
|
stored.tokenGen = attempt.gen + 1;
|
|
42470
42512
|
if (stored.disabledReason !== MANUAL_DISABLED_REASON)
|
|
42471
42513
|
stored.disabledReason = null;
|
|
@@ -42492,11 +42534,31 @@ async function resolveInvalidGrant(adapter, accountId, attempt, reason) {
|
|
|
42492
42534
|
return null;
|
|
42493
42535
|
});
|
|
42494
42536
|
}
|
|
42537
|
+
async function pullNewer(account, recovery) {
|
|
42538
|
+
try {
|
|
42539
|
+
const adopted = await getRefreshHooks()?.pull?.(account, recovery);
|
|
42540
|
+
return adopted ? await readPoolAccount(account.id) : undefined;
|
|
42541
|
+
} catch {
|
|
42542
|
+
return;
|
|
42543
|
+
}
|
|
42544
|
+
}
|
|
42545
|
+
function announceRefresh() {
|
|
42546
|
+
try {
|
|
42547
|
+
getRefreshHooks()?.afterRefresh?.();
|
|
42548
|
+
} catch {
|
|
42549
|
+
ignore();
|
|
42550
|
+
}
|
|
42551
|
+
}
|
|
42495
42552
|
async function runRefresh(adapter, account, now, rejectedAccess) {
|
|
42496
42553
|
return withLock(refreshLockDir(adapter.id, account.id), REFRESH_LOCK, async () => {
|
|
42497
|
-
const
|
|
42498
|
-
|
|
42499
|
-
|
|
42554
|
+
const read = await readPoolAccount(account.id) ?? account;
|
|
42555
|
+
const usable = (row) => row.access !== rejectedAccess && !needsRefresh(row, Math.max(now, Date.now()));
|
|
42556
|
+
if (usable(read))
|
|
42557
|
+
return tokensOf(read);
|
|
42558
|
+
const pulled = await pullNewer(read, false);
|
|
42559
|
+
if (pulled && usable(pulled))
|
|
42560
|
+
return tokensOf(pulled);
|
|
42561
|
+
const latest = pulled ?? read;
|
|
42500
42562
|
const attempt = {
|
|
42501
42563
|
refresh: latest.refresh,
|
|
42502
42564
|
gen: genOf(latest)
|
|
@@ -42507,6 +42569,9 @@ async function runRefresh(adapter, account, now, rejectedAccess) {
|
|
|
42507
42569
|
} catch (error) {
|
|
42508
42570
|
if (!(error instanceof Error) || !isInvalidGrant(error))
|
|
42509
42571
|
throw error;
|
|
42572
|
+
const recovered = await pullNewer(latest, true);
|
|
42573
|
+
if (recovered)
|
|
42574
|
+
return tokensOf(recovered);
|
|
42510
42575
|
const adopted = await resolveInvalidGrant(adapter, account.id, attempt, refusalReason(error));
|
|
42511
42576
|
if (adopted)
|
|
42512
42577
|
return adopted;
|
|
@@ -42534,7 +42599,9 @@ async function ensureAccessToken(adapter, account, now, rejectedAccess) {
|
|
|
42534
42599
|
const job = runRefresh(adapter, account, now, rejectedAccess);
|
|
42535
42600
|
inflight.set(account.id, job);
|
|
42536
42601
|
try {
|
|
42537
|
-
|
|
42602
|
+
const access = await settleRefresh(adapter, account, job);
|
|
42603
|
+
announceRefresh();
|
|
42604
|
+
return access;
|
|
42538
42605
|
} finally {
|
|
42539
42606
|
inflight.delete(account.id);
|
|
42540
42607
|
}
|
|
@@ -42733,7 +42800,7 @@ var init_session = __esm(() => {
|
|
|
42733
42800
|
// src/token-mint.ts
|
|
42734
42801
|
function autoTokenEnabled(env = process.env) {
|
|
42735
42802
|
const raw = env.OPENCODE_AUTH_LB_ANTHROPIC_AUTO_TOKEN?.trim().toLowerCase();
|
|
42736
|
-
return raw
|
|
42803
|
+
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
42737
42804
|
}
|
|
42738
42805
|
function tokenDue(account, now) {
|
|
42739
42806
|
if (!account.refresh || account.disabledReason)
|
|
@@ -42762,6 +42829,7 @@ async function mintToken(adapter, accountId) {
|
|
|
42762
42829
|
if (minted.refresh !== row.refresh) {
|
|
42763
42830
|
row.refresh = minted.refresh;
|
|
42764
42831
|
row.tokenGen = attempt.gen + 1;
|
|
42832
|
+
bumpLoginRev(row);
|
|
42765
42833
|
}
|
|
42766
42834
|
if (minted.refreshExpires)
|
|
42767
42835
|
row.refreshExpires = minted.refreshExpires;
|
|
@@ -43191,24 +43259,46 @@ var init_usage_headers = __esm(() => {
|
|
|
43191
43259
|
});
|
|
43192
43260
|
|
|
43193
43261
|
// src/providers/usage-http.ts
|
|
43194
|
-
async function
|
|
43195
|
-
let response;
|
|
43262
|
+
async function request(url, headers, timeoutMs) {
|
|
43196
43263
|
try {
|
|
43197
|
-
|
|
43264
|
+
return await fetch(url, {
|
|
43198
43265
|
headers,
|
|
43199
43266
|
signal: AbortSignal.timeout(timeoutMs)
|
|
43200
43267
|
});
|
|
43201
43268
|
} catch {
|
|
43202
43269
|
return null;
|
|
43203
43270
|
}
|
|
43271
|
+
}
|
|
43272
|
+
async function readJson(response) {
|
|
43273
|
+
if (!response)
|
|
43274
|
+
return null;
|
|
43204
43275
|
if (!response.ok) {
|
|
43205
43276
|
await response.body?.cancel().catch(ignore);
|
|
43206
43277
|
return null;
|
|
43207
43278
|
}
|
|
43208
43279
|
return await response.json().catch(() => null);
|
|
43209
43280
|
}
|
|
43281
|
+
async function fetchJson(url, headers, timeoutMs) {
|
|
43282
|
+
return readJson(await request(url, headers, timeoutMs));
|
|
43283
|
+
}
|
|
43284
|
+
async function fetchUsageJson(url, headers, timeoutMs) {
|
|
43285
|
+
const response = await request(url, headers, timeoutMs);
|
|
43286
|
+
if (response?.status === 401) {
|
|
43287
|
+
await response.body?.cancel().catch(ignore);
|
|
43288
|
+
throw new UsageAuthenticationError;
|
|
43289
|
+
}
|
|
43290
|
+
return readJson(response);
|
|
43291
|
+
}
|
|
43292
|
+
var UsageAuthenticationError;
|
|
43210
43293
|
var init_usage_http = __esm(() => {
|
|
43211
43294
|
init_util4();
|
|
43295
|
+
UsageAuthenticationError = class UsageAuthenticationError extends Error {
|
|
43296
|
+
status = 401;
|
|
43297
|
+
constructor() {
|
|
43298
|
+
super("Usage endpoint rejected the access token (401)");
|
|
43299
|
+
this.name = "UsageAuthenticationError";
|
|
43300
|
+
}
|
|
43301
|
+
};
|
|
43212
43302
|
});
|
|
43213
43303
|
|
|
43214
43304
|
// src/providers/anthropic/version.ts
|
|
@@ -43227,16 +43317,16 @@ function adopt(candidate) {
|
|
|
43227
43317
|
const trimmed = candidate.trim();
|
|
43228
43318
|
if (!VERSION_RE.test(trimmed))
|
|
43229
43319
|
return;
|
|
43230
|
-
if (compareVersions2(trimmed,
|
|
43320
|
+
if (compareVersions2(trimmed, current2) <= 0)
|
|
43231
43321
|
return;
|
|
43232
|
-
|
|
43322
|
+
current2 = trimmed;
|
|
43233
43323
|
}
|
|
43234
43324
|
function envOverride() {
|
|
43235
43325
|
const raw = process.env[CLAUDE_CODE_VERSION_ENV]?.trim();
|
|
43236
43326
|
return raw && VERSION_RE.test(raw) ? raw : undefined;
|
|
43237
43327
|
}
|
|
43238
43328
|
function claudeCodeVersion() {
|
|
43239
|
-
return envOverride() ??
|
|
43329
|
+
return envOverride() ?? current2;
|
|
43240
43330
|
}
|
|
43241
43331
|
function userAgent() {
|
|
43242
43332
|
return `claude-cli/${claudeCodeVersion()} (external, cli)`;
|
|
@@ -43271,7 +43361,7 @@ async function refreshClaudeCodeVersion(now) {
|
|
|
43271
43361
|
await persist(now);
|
|
43272
43362
|
}
|
|
43273
43363
|
async function persist(now) {
|
|
43274
|
-
await writeJsonAtomic(versionCacheFilePath(), JSON.stringify({ version:
|
|
43364
|
+
await writeJsonAtomic(versionCacheFilePath(), JSON.stringify({ version: current2, fetchedAt: now })).catch(ignore);
|
|
43275
43365
|
}
|
|
43276
43366
|
async function recoverClaudeCodeVersion(res, now) {
|
|
43277
43367
|
if (envOverride())
|
|
@@ -43284,12 +43374,12 @@ async function recoverClaudeCodeVersion(res, now) {
|
|
|
43284
43374
|
}
|
|
43285
43375
|
if (!text.includes(CLAUDE_CODE_VERSION_GATE_CODE))
|
|
43286
43376
|
return false;
|
|
43287
|
-
const before =
|
|
43377
|
+
const before = current2;
|
|
43288
43378
|
const required = CLAUDE_CODE_REQUIRED_VERSION_RE.exec(text)?.[1];
|
|
43289
43379
|
if (required !== undefined)
|
|
43290
43380
|
adopt(required);
|
|
43291
43381
|
await refreshClaudeCodeVersion(now).catch(ignore);
|
|
43292
|
-
if (
|
|
43382
|
+
if (current2 === before)
|
|
43293
43383
|
return false;
|
|
43294
43384
|
await persist(now);
|
|
43295
43385
|
return true;
|
|
@@ -43305,7 +43395,7 @@ async function primeClaudeCodeVersion(now) {
|
|
|
43305
43395
|
}
|
|
43306
43396
|
refreshClaudeCodeVersion(now).catch(ignore);
|
|
43307
43397
|
}
|
|
43308
|
-
var VERSION_RE,
|
|
43398
|
+
var VERSION_RE, current2;
|
|
43309
43399
|
var init_version = __esm(() => {
|
|
43310
43400
|
init_paths();
|
|
43311
43401
|
init_store();
|
|
@@ -43313,7 +43403,7 @@ var init_version = __esm(() => {
|
|
|
43313
43403
|
init_usage_http();
|
|
43314
43404
|
init_constants();
|
|
43315
43405
|
VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
43316
|
-
|
|
43406
|
+
current2 = FALLBACK_CLAUDE_CODE_VERSION;
|
|
43317
43407
|
});
|
|
43318
43408
|
|
|
43319
43409
|
// src/providers/anthropic/cch.ts
|
|
@@ -43648,7 +43738,7 @@ async function probeUsage(access, now) {
|
|
|
43648
43738
|
async function fetchUsage(account, now) {
|
|
43649
43739
|
if (!account.refresh)
|
|
43650
43740
|
return probeUsage(account.access, now);
|
|
43651
|
-
const json = await
|
|
43741
|
+
const json = await fetchUsageJson(USAGE_URL, {
|
|
43652
43742
|
authorization: `Bearer ${account.access}`,
|
|
43653
43743
|
"anthropic-beta": "oauth-2025-04-20",
|
|
43654
43744
|
"user-agent": usageUserAgent(),
|
|
@@ -43980,7 +44070,7 @@ function parseUsages(json, now) {
|
|
|
43980
44070
|
return hourly || weekly ? { hourly, weekly, capturedAt: now } : null;
|
|
43981
44071
|
}
|
|
43982
44072
|
function getUsages(baseUrl, key) {
|
|
43983
|
-
return
|
|
44073
|
+
return fetchUsageJson(`${baseUrl}/usages`, { authorization: `Bearer ${key}`, accept: "application/json" }, USAGE_HTTP_TIMEOUT_MS);
|
|
43984
44074
|
}
|
|
43985
44075
|
function usageFetcher(baseUrl) {
|
|
43986
44076
|
return async (account, now) => parseUsages(await getUsages(baseUrl, account.access), now);
|
|
@@ -44254,7 +44344,7 @@ async function fetchUsage2(account, now) {
|
|
|
44254
44344
|
const accountId = resolveAccountId(account);
|
|
44255
44345
|
if (accountId)
|
|
44256
44346
|
headers["chatgpt-account-id"] = accountId;
|
|
44257
|
-
const json = await
|
|
44347
|
+
const json = await fetchUsageJson(USAGE_URL2, headers, USAGE_HTTP_TIMEOUT_MS);
|
|
44258
44348
|
const rateLimit = json?.rate_limit;
|
|
44259
44349
|
if (!isPlainObject4(rateLimit))
|
|
44260
44350
|
return null;
|
|
@@ -44343,7 +44433,7 @@ async function refreshUsage(adapters, now, poolSnapshot) {
|
|
|
44343
44433
|
aliveIds?.add(account.id);
|
|
44344
44434
|
if (account.disabledReason && account.disabledReason !== MANUAL_DISABLED_REASON)
|
|
44345
44435
|
continue;
|
|
44346
|
-
if (account.usage.capturedAt !== 0 && now - account.usage.capturedAt
|
|
44436
|
+
if (account.usage.capturedAt !== 0 && now - account.usage.capturedAt < USAGE_REFRESH_TTL_MS)
|
|
44347
44437
|
continue;
|
|
44348
44438
|
const adapter = adapterFor(adapters, account.providerID);
|
|
44349
44439
|
if (!adapter)
|
|
@@ -44365,7 +44455,16 @@ async function refreshUsage(adapters, now, poolSnapshot) {
|
|
|
44365
44455
|
await Promise.all(stale.map(async ({ adapter, account }) => {
|
|
44366
44456
|
try {
|
|
44367
44457
|
await ensureAccessToken(adapter, account, now);
|
|
44368
|
-
const
|
|
44458
|
+
const rejectedAccess = account.access;
|
|
44459
|
+
let snapshot;
|
|
44460
|
+
try {
|
|
44461
|
+
snapshot = await adapter.fetchUsage(account, now);
|
|
44462
|
+
} catch (error) {
|
|
44463
|
+
if (!(error instanceof UsageAuthenticationError) || !account.refresh)
|
|
44464
|
+
throw error;
|
|
44465
|
+
await ensureAccessToken(adapter, account, now, rejectedAccess);
|
|
44466
|
+
snapshot = await adapter.fetchUsage(account, now);
|
|
44467
|
+
}
|
|
44369
44468
|
if (snapshot) {
|
|
44370
44469
|
await mutatePool((p) => {
|
|
44371
44470
|
const stored = findAccount(p, account.id);
|
|
@@ -44375,10 +44474,8 @@ async function refreshUsage(adapters, now, poolSnapshot) {
|
|
|
44375
44474
|
weekly: snapshot.weekly === null ? stored.usage.weekly : preserveWeeklyAnchor(snapshot.weekly, stored.usage.weekly, now),
|
|
44376
44475
|
capturedAt: snapshot.weekly === null ? stored.usage.capturedAt : now
|
|
44377
44476
|
};
|
|
44378
|
-
if (snapshot.weekly !== null && stored.cooldownUntil
|
|
44379
|
-
stored
|
|
44380
|
-
delete stored.cooldownKind;
|
|
44381
|
-
}
|
|
44477
|
+
if (snapshot.weekly !== null && stored.cooldownUntil === account.cooldownUntil && stored.cooldownKind === account.cooldownKind)
|
|
44478
|
+
reconcileQuotaCooldown(stored, scoreCfg, now);
|
|
44382
44479
|
}
|
|
44383
44480
|
});
|
|
44384
44481
|
}
|
|
@@ -44391,16 +44488,17 @@ function refreshUsageInBackground(adapter, now, poolSnapshot) {
|
|
|
44391
44488
|
function refreshAllUsageInBackground(now, poolSnapshot) {
|
|
44392
44489
|
return refreshUsage(ADAPTERS, now, poolSnapshot);
|
|
44393
44490
|
}
|
|
44394
|
-
var USAGE_REFRESH_TTL_MS,
|
|
44491
|
+
var USAGE_REFRESH_TTL_MS, lastPoll;
|
|
44395
44492
|
var init_usage_refresh = __esm(() => {
|
|
44396
44493
|
init_store();
|
|
44397
44494
|
init_registry();
|
|
44495
|
+
init_usage_http();
|
|
44398
44496
|
init_refresh();
|
|
44399
44497
|
init_score_core();
|
|
44400
44498
|
init_types2();
|
|
44401
44499
|
init_usage_merge();
|
|
44500
|
+
init_usage_merge();
|
|
44402
44501
|
USAGE_REFRESH_TTL_MS = 5 * 60 * 1000;
|
|
44403
|
-
MAX_TRANSIENT_COOLDOWN_MS = 5 * 60 * 1000;
|
|
44404
44502
|
lastPoll = new Map;
|
|
44405
44503
|
});
|
|
44406
44504
|
|
|
@@ -45625,6 +45723,12 @@ var init_prime = __esm(() => {
|
|
|
45625
45723
|
init_select();
|
|
45626
45724
|
});
|
|
45627
45725
|
|
|
45726
|
+
// src/sync/enabled.ts
|
|
45727
|
+
function syncEnabled(env = process.env) {
|
|
45728
|
+
const raw = env.OPENCODE_AUTH_LB_SYNC?.trim().toLowerCase();
|
|
45729
|
+
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
45730
|
+
}
|
|
45731
|
+
|
|
45628
45732
|
// src/sync/errors.ts
|
|
45629
45733
|
function describeSyncError(error) {
|
|
45630
45734
|
return error instanceof SyncError ? error.message : "Sync failed.";
|
|
@@ -45732,10 +45836,7 @@ var init_crypto = __esm(() => {
|
|
|
45732
45836
|
B64URL_RE = /^[\w-]+$/;
|
|
45733
45837
|
});
|
|
45734
45838
|
|
|
45735
|
-
// src/sync/
|
|
45736
|
-
function entryKey(entry) {
|
|
45737
|
-
return `${entry.origin}/${entry.id}`;
|
|
45738
|
-
}
|
|
45839
|
+
// src/sync/text.ts
|
|
45739
45840
|
function isControl(code) {
|
|
45740
45841
|
return code < 32 || code >= 127 && code <= 159 || code === 1564 || code >= 8203 && code <= 8207 || code >= 8232 && code <= 8238 || code >= 8288 && code <= 8297 || code === 65279;
|
|
45741
45842
|
}
|
|
@@ -45745,6 +45846,106 @@ function printable(text) {
|
|
|
45745
45846
|
function boundedString(value, max) {
|
|
45746
45847
|
return typeof value === "string" && value.length > 0 && value.length <= max ? value : undefined;
|
|
45747
45848
|
}
|
|
45849
|
+
var MAX_LABEL = 80;
|
|
45850
|
+
|
|
45851
|
+
// src/sync/login-payload.ts
|
|
45852
|
+
function loginKey(providerID, accountId) {
|
|
45853
|
+
return `${providerID}:${accountId}`;
|
|
45854
|
+
}
|
|
45855
|
+
function word(value, max) {
|
|
45856
|
+
const text = boundedString(value, max);
|
|
45857
|
+
return text !== undefined && NO_SPACE_RE.test(text) ? text : undefined;
|
|
45858
|
+
}
|
|
45859
|
+
function positive(value) {
|
|
45860
|
+
return isFiniteNumber(value) && value > 0 ? value : undefined;
|
|
45861
|
+
}
|
|
45862
|
+
function parseLogin(raw) {
|
|
45863
|
+
if (!isPlainObject4(raw))
|
|
45864
|
+
return null;
|
|
45865
|
+
const providerID = word(raw.providerID, MAX_ID);
|
|
45866
|
+
const accountId = word(raw.accountId, MAX_ID);
|
|
45867
|
+
const label = printable(boundedString(raw.label, MAX_LABEL) ?? "");
|
|
45868
|
+
const [access, refresh] = [
|
|
45869
|
+
word(raw.access, MAX_TOKEN),
|
|
45870
|
+
word(raw.refresh, MAX_TOKEN)
|
|
45871
|
+
];
|
|
45872
|
+
const { rev, at } = raw;
|
|
45873
|
+
if (!providerID || !LOGIN_PROVIDERS.has(providerID) || !accountId)
|
|
45874
|
+
return null;
|
|
45875
|
+
if (raw.key !== loginKey(providerID, accountId))
|
|
45876
|
+
return null;
|
|
45877
|
+
const expires = positive(raw.expires);
|
|
45878
|
+
if (!label || !access || !refresh || !expires)
|
|
45879
|
+
return null;
|
|
45880
|
+
if (typeof rev !== "number" || !Number.isSafeInteger(rev) || rev < 1)
|
|
45881
|
+
return null;
|
|
45882
|
+
if (!isFiniteNumber(at) || at < 0)
|
|
45883
|
+
return null;
|
|
45884
|
+
const orgId = word(raw.orgId, MAX_ID);
|
|
45885
|
+
const refreshExpires = positive(raw.refreshExpires);
|
|
45886
|
+
return {
|
|
45887
|
+
key: loginKey(providerID, accountId),
|
|
45888
|
+
providerID,
|
|
45889
|
+
label,
|
|
45890
|
+
access,
|
|
45891
|
+
refresh,
|
|
45892
|
+
expires,
|
|
45893
|
+
accountId,
|
|
45894
|
+
...orgId ? { orgId } : {},
|
|
45895
|
+
...refreshExpires ? { refreshExpires } : {},
|
|
45896
|
+
rev,
|
|
45897
|
+
at
|
|
45898
|
+
};
|
|
45899
|
+
}
|
|
45900
|
+
function sortLogins(logins) {
|
|
45901
|
+
return [...logins].sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
45902
|
+
}
|
|
45903
|
+
function loginsDigest(logins) {
|
|
45904
|
+
return fingerprint(JSON.stringify(sortLogins(logins)));
|
|
45905
|
+
}
|
|
45906
|
+
function compareLogins(a, b) {
|
|
45907
|
+
if (a.rev !== b.rev)
|
|
45908
|
+
return a.rev < b.rev ? -1 : 1;
|
|
45909
|
+
if (a.at !== b.at)
|
|
45910
|
+
return a.at < b.at ? -1 : 1;
|
|
45911
|
+
const [x, y] = [fingerprint(a.refresh), fingerprint(b.refresh)];
|
|
45912
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
45913
|
+
}
|
|
45914
|
+
function parseLoginList(rawList) {
|
|
45915
|
+
const parsed = {
|
|
45916
|
+
logins: [],
|
|
45917
|
+
loginsListed: new Set,
|
|
45918
|
+
loginsUnreadable: 0
|
|
45919
|
+
};
|
|
45920
|
+
for (const raw of rawList) {
|
|
45921
|
+
const key = isPlainObject4(raw) ? boundedString(raw.key, MAX_KEY) : undefined;
|
|
45922
|
+
if (key)
|
|
45923
|
+
parsed.loginsListed.add(key);
|
|
45924
|
+
const login = parseLogin(raw);
|
|
45925
|
+
if (!login)
|
|
45926
|
+
parsed.loginsUnreadable += 1;
|
|
45927
|
+
else if (!parsed.logins.some((l) => l.key === login.key))
|
|
45928
|
+
parsed.logins.push(login);
|
|
45929
|
+
}
|
|
45930
|
+
return parsed;
|
|
45931
|
+
}
|
|
45932
|
+
var MAX_LOGINS = 64, MAX_TOKEN = 8192, MAX_ID = 128, MAX_KEY = 300, NO_SPACE_RE, LOGIN_PROVIDERS;
|
|
45933
|
+
var init_login_payload = __esm(() => {
|
|
45934
|
+
init_util4();
|
|
45935
|
+
init_crypto();
|
|
45936
|
+
NO_SPACE_RE = /^\S+$/;
|
|
45937
|
+
LOGIN_PROVIDERS = new Set([
|
|
45938
|
+
"anthropic",
|
|
45939
|
+
"openai",
|
|
45940
|
+
"kimi-code-plan-cn",
|
|
45941
|
+
"kimi-code-plan-global"
|
|
45942
|
+
]);
|
|
45943
|
+
});
|
|
45944
|
+
|
|
45945
|
+
// src/sync/payload.ts
|
|
45946
|
+
function entryKey(entry) {
|
|
45947
|
+
return `${entry.origin}/${entry.id}`;
|
|
45948
|
+
}
|
|
45748
45949
|
function keyOf(raw) {
|
|
45749
45950
|
if (!isPlainObject4(raw))
|
|
45750
45951
|
return null;
|
|
@@ -45785,11 +45986,12 @@ function sortEntries(entries) {
|
|
|
45785
45986
|
function entriesDigest(entries) {
|
|
45786
45987
|
return fingerprint(JSON.stringify(sortEntries(entries)));
|
|
45787
45988
|
}
|
|
45788
|
-
function buildPayload(entries, at) {
|
|
45989
|
+
function buildPayload(entries, at, logins = []) {
|
|
45789
45990
|
return JSON.stringify({
|
|
45790
45991
|
v: PAYLOAD_VERSION,
|
|
45791
45992
|
at,
|
|
45792
|
-
entries: sortEntries(entries)
|
|
45993
|
+
entries: sortEntries(entries),
|
|
45994
|
+
logins: sortLogins(logins)
|
|
45793
45995
|
});
|
|
45794
45996
|
}
|
|
45795
45997
|
function parsePayload(text) {
|
|
@@ -45801,11 +46003,12 @@ function parsePayload(text) {
|
|
|
45801
46003
|
}
|
|
45802
46004
|
if (!isPlainObject4(json) || !Array.isArray(json.entries))
|
|
45803
46005
|
throw new SyncError("bad-blob");
|
|
45804
|
-
if (json.v !== PAYLOAD_VERSION)
|
|
46006
|
+
if (json.v !== PAYLOAD_VERSION && json.v !== ENTRIES_ONLY_VERSION)
|
|
45805
46007
|
throw new SyncError("bad-version");
|
|
45806
|
-
|
|
46008
|
+
const rawLogins = json.v === PAYLOAD_VERSION ? json.logins ?? [] : [];
|
|
46009
|
+
if (!isFiniteNumber(json.at) || !Array.isArray(rawLogins))
|
|
45807
46010
|
throw new SyncError("bad-blob");
|
|
45808
|
-
if (json.entries.length > MAX_ENTRIES)
|
|
46011
|
+
if (json.entries.length > MAX_ENTRIES || rawLogins.length > MAX_LOGINS)
|
|
45809
46012
|
throw new SyncError("too-large");
|
|
45810
46013
|
const listed = new Set;
|
|
45811
46014
|
const entries = [];
|
|
@@ -45824,13 +46027,20 @@ function parsePayload(text) {
|
|
|
45824
46027
|
else
|
|
45825
46028
|
unreadable += 1;
|
|
45826
46029
|
}
|
|
45827
|
-
return {
|
|
46030
|
+
return {
|
|
46031
|
+
at: json.at,
|
|
46032
|
+
entries,
|
|
46033
|
+
listed,
|
|
46034
|
+
unreadable,
|
|
46035
|
+
...parseLoginList(rawLogins)
|
|
46036
|
+
};
|
|
45828
46037
|
}
|
|
45829
|
-
var PAYLOAD_VERSION =
|
|
46038
|
+
var PAYLOAD_VERSION = 3, ENTRIES_ONLY_VERSION = 2, MAX_ENTRIES = 64, MAX_SECRET = 512, MAX_FIELD = 128, ID_RE, ORIGIN_RE, CLAUDE_TOKEN_RE, API_KEY_RE, SECRET_SHAPES;
|
|
45830
46039
|
var init_payload = __esm(() => {
|
|
45831
46040
|
init_util4();
|
|
45832
46041
|
init_crypto();
|
|
45833
46042
|
init_errors6();
|
|
46043
|
+
init_login_payload();
|
|
45834
46044
|
ID_RE = /^[\w-]{1,64}$/;
|
|
45835
46045
|
ORIGIN_RE = /^[\da-f]{32}$/;
|
|
45836
46046
|
CLAUDE_TOKEN_RE = /^sk-ant-oat\d+-[\w-]+$/;
|
|
@@ -45920,7 +46130,7 @@ function backoffFrom(res, now) {
|
|
|
45920
46130
|
function isRateLimited(res) {
|
|
45921
46131
|
return res.status === 429 || res.status === 403 && (res.headers.get("x-ratelimit-remaining") === "0" || res.headers.has("retry-after"));
|
|
45922
46132
|
}
|
|
45923
|
-
async function
|
|
46133
|
+
async function request2(url, init, now) {
|
|
45924
46134
|
let res;
|
|
45925
46135
|
try {
|
|
45926
46136
|
res = await globalThis.fetch(url, {
|
|
@@ -45972,7 +46182,7 @@ async function boundedText(res) {
|
|
|
45972
46182
|
}
|
|
45973
46183
|
return Buffer.concat(chunks).toString("utf8");
|
|
45974
46184
|
}
|
|
45975
|
-
async function
|
|
46185
|
+
async function readJson2(res) {
|
|
45976
46186
|
if (!res.ok)
|
|
45977
46187
|
throw new SyncError("http");
|
|
45978
46188
|
const text = await boundedText(res);
|
|
@@ -45987,7 +46197,7 @@ async function readJson(res) {
|
|
|
45987
46197
|
return json;
|
|
45988
46198
|
}
|
|
45989
46199
|
async function createGist(token, content, now = Date.now()) {
|
|
45990
|
-
const res = await
|
|
46200
|
+
const res = await request2(API, {
|
|
45991
46201
|
method: "POST",
|
|
45992
46202
|
headers: { ...headers(token), "content-type": "application/json" },
|
|
45993
46203
|
body: JSON.stringify({
|
|
@@ -45996,7 +46206,7 @@ async function createGist(token, content, now = Date.now()) {
|
|
|
45996
46206
|
files: { [GIST_FILE]: { content } }
|
|
45997
46207
|
})
|
|
45998
46208
|
}, now);
|
|
45999
|
-
const json = await
|
|
46209
|
+
const json = await readJson2(res);
|
|
46000
46210
|
const owner = isPlainObject4(json.owner) ? json.owner.login : undefined;
|
|
46001
46211
|
if (typeof json.id !== "string" || !GIST_ID_RE.test(json.id))
|
|
46002
46212
|
throw new SyncError("http");
|
|
@@ -46008,7 +46218,7 @@ async function createGist(token, content, now = Date.now()) {
|
|
|
46008
46218
|
async function updateGist(token, id, content, now = Date.now()) {
|
|
46009
46219
|
let res;
|
|
46010
46220
|
try {
|
|
46011
|
-
res = await
|
|
46221
|
+
res = await request2(`${API}/${id}`, {
|
|
46012
46222
|
method: "PATCH",
|
|
46013
46223
|
headers: { ...headers(token), "content-type": "application/json" },
|
|
46014
46224
|
body: JSON.stringify({ files: { [GIST_FILE]: { content } } })
|
|
@@ -46020,10 +46230,10 @@ async function updateGist(token, id, content, now = Date.now()) {
|
|
|
46020
46230
|
}
|
|
46021
46231
|
if (res.status === 401 || res.status === 403)
|
|
46022
46232
|
throw new SyncError("write-denied");
|
|
46023
|
-
await
|
|
46233
|
+
await readJson2(res);
|
|
46024
46234
|
}
|
|
46025
46235
|
async function readGist(id, etag, now = Date.now(), token) {
|
|
46026
|
-
const ask = (auth) =>
|
|
46236
|
+
const ask = (auth) => request2(`${API}/${id}`, {
|
|
46027
46237
|
headers: {
|
|
46028
46238
|
...headers(auth),
|
|
46029
46239
|
...etag ? { "if-none-match": etag } : {}
|
|
@@ -46034,7 +46244,7 @@ async function readGist(id, etag, now = Date.now(), token) {
|
|
|
46034
46244
|
res = await ask();
|
|
46035
46245
|
if (res.status === 304)
|
|
46036
46246
|
return { changed: false };
|
|
46037
|
-
const json = await
|
|
46247
|
+
const json = await readJson2(res);
|
|
46038
46248
|
const file = isPlainObject4(json.files) ? json.files[GIST_FILE] : undefined;
|
|
46039
46249
|
if (!isPlainObject4(file) || typeof file.content !== "string")
|
|
46040
46250
|
throw new SyncError("bad-blob");
|
|
@@ -46076,6 +46286,12 @@ function isRef(value) {
|
|
|
46076
46286
|
function isSkip(value) {
|
|
46077
46287
|
return isPlainObject4(value) && typeof value.fingerprint === "string" && typeof value.blocker === "string" && typeof value.holds === "string";
|
|
46078
46288
|
}
|
|
46289
|
+
function isMark(value) {
|
|
46290
|
+
return value === true;
|
|
46291
|
+
}
|
|
46292
|
+
function marks(from) {
|
|
46293
|
+
return from && Object.keys(from).length > 0 ? newMap(from) : undefined;
|
|
46294
|
+
}
|
|
46079
46295
|
function readMap(raw, accept) {
|
|
46080
46296
|
const map = newMap();
|
|
46081
46297
|
if (isPlainObject4(raw)) {
|
|
@@ -46099,6 +46315,8 @@ function parseState(text) {
|
|
|
46099
46315
|
return null;
|
|
46100
46316
|
const { owner, etag, syncedAt, uploadedDigest, write } = json;
|
|
46101
46317
|
const { uploadedAt, appliedAt, retryAt, pollAt, writeCheckAt } = json;
|
|
46318
|
+
const loginKnown = marks(readMap(json.loginKnown, isMark));
|
|
46319
|
+
const loginSuppressed = marks(readMap(json.loginSuppressed, isMark));
|
|
46102
46320
|
return {
|
|
46103
46321
|
v: 1,
|
|
46104
46322
|
gistId: json.gistId,
|
|
@@ -46106,6 +46324,8 @@ function parseState(text) {
|
|
|
46106
46324
|
creator: json.creator === true,
|
|
46107
46325
|
imported: readMap(json.imported, isRef),
|
|
46108
46326
|
skipped: readMap(json.skipped, isSkip),
|
|
46327
|
+
...loginKnown ? { loginKnown } : {},
|
|
46328
|
+
...loginSuppressed ? { loginSuppressed } : {},
|
|
46109
46329
|
...typeof owner === "string" ? { owner } : {},
|
|
46110
46330
|
...isWrite(write) ? { write } : {},
|
|
46111
46331
|
...typeof etag === "string" ? { etag } : {},
|
|
@@ -46335,6 +46555,179 @@ async function discoverGithubToken(run = ghAuthToken, env = process.env) {
|
|
|
46335
46555
|
var GH_TIMEOUT_MS = 5000;
|
|
46336
46556
|
var init_github_auth = () => {};
|
|
46337
46557
|
|
|
46558
|
+
// src/sync/logins.ts
|
|
46559
|
+
function loginsSyncEnabled(env = process.env) {
|
|
46560
|
+
const raw = env.OPENCODE_AUTH_LB_SYNC_LOGINS?.trim().toLowerCase();
|
|
46561
|
+
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
46562
|
+
}
|
|
46563
|
+
function rowKey(row) {
|
|
46564
|
+
const live = row.refresh !== "" || row.inferenceToken !== undefined && row.lostLogins?.oauth !== undefined;
|
|
46565
|
+
return LOGIN_PROVIDERS.has(row.providerID) && row.accountId && live ? loginKey(row.providerID, row.accountId) : null;
|
|
46566
|
+
}
|
|
46567
|
+
function heldMarks(accounts) {
|
|
46568
|
+
const held = newMap();
|
|
46569
|
+
for (const row of accounts) {
|
|
46570
|
+
const key = rowKey(row);
|
|
46571
|
+
if (key)
|
|
46572
|
+
held[key] = true;
|
|
46573
|
+
}
|
|
46574
|
+
return held;
|
|
46575
|
+
}
|
|
46576
|
+
function ownLogins(pool) {
|
|
46577
|
+
const best = new Map;
|
|
46578
|
+
for (const row of pool.accounts) {
|
|
46579
|
+
if (!row.refresh || !row.accountId)
|
|
46580
|
+
continue;
|
|
46581
|
+
if (row.disabledReason || row.lostLogins?.oauth)
|
|
46582
|
+
continue;
|
|
46583
|
+
const login = parseLogin({
|
|
46584
|
+
key: loginKey(row.providerID, row.accountId),
|
|
46585
|
+
providerID: row.providerID,
|
|
46586
|
+
label: printable(row.label).slice(0, MAX_LABEL).trim() || row.providerID,
|
|
46587
|
+
access: row.access,
|
|
46588
|
+
refresh: row.refresh,
|
|
46589
|
+
expires: row.expires,
|
|
46590
|
+
accountId: row.accountId,
|
|
46591
|
+
orgId: row.orgId,
|
|
46592
|
+
refreshExpires: row.refreshExpires,
|
|
46593
|
+
...loginVersion(row)
|
|
46594
|
+
});
|
|
46595
|
+
const prior = login ? best.get(login.key) : undefined;
|
|
46596
|
+
if (login && (!prior || compareLogins(login, prior) > 0))
|
|
46597
|
+
best.set(login.key, login);
|
|
46598
|
+
}
|
|
46599
|
+
return sortLogins([...best.values()]).slice(0, MAX_LOGINS);
|
|
46600
|
+
}
|
|
46601
|
+
function mergeLogins(gist, own) {
|
|
46602
|
+
const merged = new Map(gist.map((login) => [login.key, login]));
|
|
46603
|
+
for (const login of own) {
|
|
46604
|
+
const prior = merged.get(login.key);
|
|
46605
|
+
if (prior ? compareLogins(login, prior) > 0 : merged.size < MAX_LOGINS)
|
|
46606
|
+
merged.set(login.key, login);
|
|
46607
|
+
}
|
|
46608
|
+
return sortLogins([...merged.values()]);
|
|
46609
|
+
}
|
|
46610
|
+
function ownCopies(next, own) {
|
|
46611
|
+
return own.filter((login) => next.some((n) => n.key === login.key && n.refresh === login.refresh)).length;
|
|
46612
|
+
}
|
|
46613
|
+
function publishDigest(entries, logins) {
|
|
46614
|
+
return logins.length === 0 ? entriesDigest(entries) : fingerprint(`${entriesDigest(entries)}/${loginsDigest(logins)}`);
|
|
46615
|
+
}
|
|
46616
|
+
function sameLogin(row, login) {
|
|
46617
|
+
return rowKey(row) === login.key && (row.orgId === undefined || login.orgId === undefined || row.orgId === login.orgId);
|
|
46618
|
+
}
|
|
46619
|
+
function versionOf(row) {
|
|
46620
|
+
return { ...loginVersion(row), refresh: row.refresh };
|
|
46621
|
+
}
|
|
46622
|
+
function overwriteLocked(row, login) {
|
|
46623
|
+
const attempt = { refresh: row.refresh, gen: genOf(row) };
|
|
46624
|
+
return mutatePool((pool) => {
|
|
46625
|
+
const cur = findAccount(pool, row.id);
|
|
46626
|
+
if (!cur || !sameGeneration(cur, attempt))
|
|
46627
|
+
return false;
|
|
46628
|
+
cur.access = login.access;
|
|
46629
|
+
cur.refresh = login.refresh;
|
|
46630
|
+
cur.expires = login.expires;
|
|
46631
|
+
if (login.refreshExpires)
|
|
46632
|
+
cur.refreshExpires = login.refreshExpires;
|
|
46633
|
+
else
|
|
46634
|
+
delete cur.refreshExpires;
|
|
46635
|
+
if (login.orgId)
|
|
46636
|
+
cur.orgId = login.orgId;
|
|
46637
|
+
cur.loginRev = login.rev;
|
|
46638
|
+
cur.loginAt = login.at;
|
|
46639
|
+
cur.tokenGen = genOf(cur) + 1;
|
|
46640
|
+
clearLostLogin(cur, "oauth");
|
|
46641
|
+
if (cur.disabledReason?.startsWith(AUTO_DISABLED_PREFIX))
|
|
46642
|
+
cur.disabledReason = null;
|
|
46643
|
+
return true;
|
|
46644
|
+
});
|
|
46645
|
+
}
|
|
46646
|
+
function overwrite(row, login) {
|
|
46647
|
+
return withRefreshLock(row.providerID, row.id, () => overwriteLocked(row, login));
|
|
46648
|
+
}
|
|
46649
|
+
async function create(login) {
|
|
46650
|
+
const tokens = {
|
|
46651
|
+
access: login.access,
|
|
46652
|
+
refresh: login.refresh,
|
|
46653
|
+
expires: login.expires,
|
|
46654
|
+
accountId: login.accountId,
|
|
46655
|
+
...login.orgId ? { orgId: login.orgId } : {},
|
|
46656
|
+
...login.refreshExpires ? { refreshExpires: login.refreshExpires } : {}
|
|
46657
|
+
};
|
|
46658
|
+
return mutatePool((pool) => {
|
|
46659
|
+
if (pool.accounts.some((row) => sameLogin(row, login)))
|
|
46660
|
+
return false;
|
|
46661
|
+
const manual = new Set(pool.accounts.filter((row) => row.disabledReason === MANUAL_DISABLED_REASON).map((row) => row.id));
|
|
46662
|
+
const row = placeTokens(pool, login.providerID, tokens, uniqueLabel(pool, login.label), undefined);
|
|
46663
|
+
row.loginRev = login.rev;
|
|
46664
|
+
row.loginAt = login.at;
|
|
46665
|
+
row.tokenGen = genOf(row) + 1;
|
|
46666
|
+
if (manual.has(row.id))
|
|
46667
|
+
row.disabledReason = MANUAL_DISABLED_REASON;
|
|
46668
|
+
return true;
|
|
46669
|
+
});
|
|
46670
|
+
}
|
|
46671
|
+
async function adopt2(login) {
|
|
46672
|
+
const row = (await readPool()).accounts.find((a) => sameLogin(a, login));
|
|
46673
|
+
if (!row)
|
|
46674
|
+
return create(login);
|
|
46675
|
+
return compareLogins(login, versionOf(row)) > 0 ? overwrite(row, login) : false;
|
|
46676
|
+
}
|
|
46677
|
+
async function outrank(login, now) {
|
|
46678
|
+
const row = (await readPool()).accounts.find((a) => sameLogin(a, login));
|
|
46679
|
+
if (!row || compareLogins(versionOf(row), login) > 0)
|
|
46680
|
+
return;
|
|
46681
|
+
const attempt = { refresh: row.refresh, gen: genOf(row) };
|
|
46682
|
+
await mutatePool((pool) => {
|
|
46683
|
+
const cur = findAccount(pool, row.id);
|
|
46684
|
+
if (!cur || !sameGeneration(cur, attempt))
|
|
46685
|
+
return;
|
|
46686
|
+
cur.loginRev = login.rev + 1;
|
|
46687
|
+
cur.loginAt = now;
|
|
46688
|
+
});
|
|
46689
|
+
}
|
|
46690
|
+
async function applyLogins(gist, marks, now) {
|
|
46691
|
+
const known = newMap(marks.known);
|
|
46692
|
+
const suppressed = newMap(marks.suppressed);
|
|
46693
|
+
const held = heldMarks((await readPool()).accounts);
|
|
46694
|
+
for (const key of Object.keys(known)) {
|
|
46695
|
+
if (held[key])
|
|
46696
|
+
continue;
|
|
46697
|
+
suppressed[key] = true;
|
|
46698
|
+
delete known[key];
|
|
46699
|
+
}
|
|
46700
|
+
for (const key of Object.keys(suppressed)) {
|
|
46701
|
+
if (!held[key])
|
|
46702
|
+
continue;
|
|
46703
|
+
delete suppressed[key];
|
|
46704
|
+
const login = gist.find((l) => l.key === key);
|
|
46705
|
+
if (login)
|
|
46706
|
+
await outrank(login, now);
|
|
46707
|
+
}
|
|
46708
|
+
let adopted = 0;
|
|
46709
|
+
for (const login of gist)
|
|
46710
|
+
if (!suppressed[login.key] && await adopt2(login))
|
|
46711
|
+
adopted += 1;
|
|
46712
|
+
return {
|
|
46713
|
+
adopted,
|
|
46714
|
+
known: heldMarks((await readPool()).accounts),
|
|
46715
|
+
suppressed
|
|
46716
|
+
};
|
|
46717
|
+
}
|
|
46718
|
+
var AUTO_DISABLED_PREFIX = "invalid_grant: re-login required";
|
|
46719
|
+
var init_logins = __esm(() => {
|
|
46720
|
+
init_accounts();
|
|
46721
|
+
init_store();
|
|
46722
|
+
init_refresh();
|
|
46723
|
+
init_types2();
|
|
46724
|
+
init_apply();
|
|
46725
|
+
init_crypto();
|
|
46726
|
+
init_login_payload();
|
|
46727
|
+
init_payload();
|
|
46728
|
+
init_state();
|
|
46729
|
+
});
|
|
46730
|
+
|
|
46338
46731
|
// src/sync/origin.ts
|
|
46339
46732
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
46340
46733
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
@@ -46435,6 +46828,10 @@ var init_timing = __esm(() => {
|
|
|
46435
46828
|
function count(n, one, many) {
|
|
46436
46829
|
return `${n} ${n === 1 ? one : many}`;
|
|
46437
46830
|
}
|
|
46831
|
+
function uploadedMessage(entries, logins) {
|
|
46832
|
+
const credentials = count(entries, "credential", "credentials");
|
|
46833
|
+
return logins === 0 ? `Uploaded ${credentials}.` : `Uploaded ${credentials} and ${count(logins, "login", "logins")}.`;
|
|
46834
|
+
}
|
|
46438
46835
|
function recordApplied(gistId, at, applied, syncedAt) {
|
|
46439
46836
|
return updateSyncState((cur) => cur?.gistId === gistId ? {
|
|
46440
46837
|
...cur,
|
|
@@ -46458,7 +46855,8 @@ async function runCycle(deps, force, report) {
|
|
|
46458
46855
|
const pool = await readPool();
|
|
46459
46856
|
const backedOff = state.write === "denied" && !force && now() < (state.writeCheckAt ?? 0);
|
|
46460
46857
|
const mayWrite = token !== null && !backedOff;
|
|
46461
|
-
const
|
|
46858
|
+
const sharing = loginsSyncEnabled();
|
|
46859
|
+
const before = publishDigest(ownEntries(pool, origin, state.imported), sharing ? ownLogins(pool) : []);
|
|
46462
46860
|
const dirty = mayWrite && before !== state.uploadedDigest;
|
|
46463
46861
|
report.retryMs = dirty ? PUBLISH_RETRY_MS : POLL_MS;
|
|
46464
46862
|
const reread = force || dirty || hasFreedSkips(pool.accounts, state.skipped);
|
|
@@ -46480,8 +46878,17 @@ async function runCycle(deps, force, report) {
|
|
|
46480
46878
|
...deps.adapters ? { adapters: deps.adapters } : {},
|
|
46481
46879
|
afterPass: (soFar) => recordApplied(state.gistId, snapshot.at, soFar, now())
|
|
46482
46880
|
});
|
|
46483
|
-
const
|
|
46484
|
-
|
|
46881
|
+
const adoptedLogins = stale || !sharing ? null : await applyLogins(snapshot.logins, { known: state.loginKnown, suppressed: state.loginSuppressed }, now());
|
|
46882
|
+
if (adoptedLogins)
|
|
46883
|
+
await updateSyncState((cur) => cur?.gistId === state.gistId ? {
|
|
46884
|
+
...cur,
|
|
46885
|
+
loginKnown: marks(adoptedLogins.known),
|
|
46886
|
+
loginSuppressed: marks(adoptedLogins.suppressed)
|
|
46887
|
+
} : cur);
|
|
46888
|
+
const settled = await readPool();
|
|
46889
|
+
const own = ownEntries(settled, origin, applied?.imported ?? state.imported);
|
|
46890
|
+
const ownShared = sharing ? ownLogins(settled) : [];
|
|
46891
|
+
const unreadable = snapshot.unreadable > 0 || snapshot.loginsUnreadable > 0;
|
|
46485
46892
|
let write = standing;
|
|
46486
46893
|
let wrote = null;
|
|
46487
46894
|
let stamped = 0;
|
|
@@ -46491,12 +46898,16 @@ async function runCycle(deps, force, report) {
|
|
|
46491
46898
|
if (mayWrite && !unreadable) {
|
|
46492
46899
|
const others = snapshot.entries.filter((e) => e.origin !== origin);
|
|
46493
46900
|
const next = sortEntries([...others, ...listable(own, others, origin)]);
|
|
46494
|
-
const
|
|
46901
|
+
const nextLogins = sharing ? mergeLogins(snapshot.logins, ownShared) : snapshot.logins;
|
|
46902
|
+
const same = JSON.stringify(next) === JSON.stringify(sortEntries(snapshot.entries)) && loginsDigest(nextLogins) === loginsDigest(snapshot.logins);
|
|
46495
46903
|
if (!same || stale) {
|
|
46496
46904
|
stamped = Math.max(now(), snapshot.at + 1, (state.uploadedAt ?? 0) + 1, (state.appliedAt ?? 0) + 1);
|
|
46497
46905
|
try {
|
|
46498
|
-
await updateGist(token, state.gistId, seal(buildPayload(next, stamped), key), now());
|
|
46499
|
-
wrote =
|
|
46906
|
+
await updateGist(token, state.gistId, seal(buildPayload(next, stamped, nextLogins), key), now());
|
|
46907
|
+
wrote = {
|
|
46908
|
+
entries: next.filter((e) => e.origin === origin).length,
|
|
46909
|
+
logins: ownCopies(nextLogins, ownShared)
|
|
46910
|
+
};
|
|
46500
46911
|
} catch (error) {
|
|
46501
46912
|
if (!(error instanceof SyncError) || error.code !== "write-denied")
|
|
46502
46913
|
throw error;
|
|
@@ -46512,18 +46923,22 @@ async function runCycle(deps, force, report) {
|
|
|
46512
46923
|
etag: wrote || stale || deferred > 0 || denied ? undefined : read.etag,
|
|
46513
46924
|
write,
|
|
46514
46925
|
writeCheckAt: denied ? now() + WRITE_BACKOFF_MS : backedOff ? cur.writeCheckAt : undefined,
|
|
46515
|
-
uploadedDigest: mayWrite && !unreadable && !denied ?
|
|
46926
|
+
uploadedDigest: mayWrite && !unreadable && !denied ? publishDigest(own, ownShared) : cur.uploadedDigest,
|
|
46516
46927
|
...wrote ? { uploadedAt: stamped } : {}
|
|
46517
46928
|
} : cur);
|
|
46518
46929
|
const parts = [];
|
|
46519
46930
|
const moved = applied ? applied.added + applied.updated + applied.removed + deferred : 0;
|
|
46931
|
+
const adopted = adoptedLogins?.adopted ?? 0;
|
|
46520
46932
|
if (applied && moved > 0) {
|
|
46521
46933
|
const tail = deferred > 0 ? `; ${count(deferred, "entry", "entries")} could not be verified yet` : "";
|
|
46522
|
-
|
|
46523
|
-
|
|
46934
|
+
const login = adopted > 0 ? `; ${count(adopted, "login", "logins")} adopted` : "";
|
|
46935
|
+
parts.push(`Synced: ${applied.added} added, ${applied.updated} updated, ${applied.removed} removed${tail}${login}.`);
|
|
46936
|
+
} else if (adopted > 0)
|
|
46937
|
+
parts.push(`Synced: ${count(adopted, "login", "logins")} adopted.`);
|
|
46938
|
+
else if (!wrote)
|
|
46524
46939
|
parts.push("Up to date.");
|
|
46525
46940
|
if (wrote)
|
|
46526
|
-
parts.push(
|
|
46941
|
+
parts.push(uploadedMessage(wrote.entries, wrote.logins));
|
|
46527
46942
|
if (denied)
|
|
46528
46943
|
parts.push(new SyncError("write-denied").message);
|
|
46529
46944
|
if (mayWrite && unreadable && state.write !== "unreadable")
|
|
@@ -46538,6 +46953,8 @@ var init_cycle = __esm(() => {
|
|
|
46538
46953
|
init_errors6();
|
|
46539
46954
|
init_gist();
|
|
46540
46955
|
init_github_auth();
|
|
46956
|
+
init_login_payload();
|
|
46957
|
+
init_logins();
|
|
46541
46958
|
init_merge();
|
|
46542
46959
|
init_origin();
|
|
46543
46960
|
init_own();
|
|
@@ -46547,9 +46964,6 @@ var init_cycle = __esm(() => {
|
|
|
46547
46964
|
});
|
|
46548
46965
|
|
|
46549
46966
|
// src/sync/engine.ts
|
|
46550
|
-
function count2(n, one, many) {
|
|
46551
|
-
return `${n} ${n === 1 ? one : many}`;
|
|
46552
|
-
}
|
|
46553
46967
|
function createEngine(deps) {
|
|
46554
46968
|
const { now } = deps;
|
|
46555
46969
|
async function settle(work, reqAt, scheduled) {
|
|
@@ -46582,10 +46996,14 @@ function createEngine(deps) {
|
|
|
46582
46996
|
if (!token)
|
|
46583
46997
|
throw new SyncError("no-auth");
|
|
46584
46998
|
const origin = await machineOrigin();
|
|
46585
|
-
const
|
|
46999
|
+
const pool = await readPool();
|
|
47000
|
+
const own = ownEntries(pool, origin, newRefs());
|
|
47001
|
+
const sharing = loginsSyncEnabled();
|
|
47002
|
+
const shared = sharing ? ownLogins(pool) : [];
|
|
46586
47003
|
const key = generateKey();
|
|
46587
47004
|
const at = now();
|
|
46588
|
-
const gist = await createGist(token, seal(buildPayload(own, at), key), now());
|
|
47005
|
+
const gist = await createGist(token, seal(buildPayload(own, at, shared), key), now());
|
|
47006
|
+
const loginKnown = sharing ? marks(heldMarks(pool.accounts)) : undefined;
|
|
46589
47007
|
await updateSyncState(() => ({
|
|
46590
47008
|
v: 1,
|
|
46591
47009
|
gistId: gist.id,
|
|
@@ -46594,21 +47012,23 @@ function createEngine(deps) {
|
|
|
46594
47012
|
...gist.owner ? { owner: gist.owner } : {},
|
|
46595
47013
|
write: "ok",
|
|
46596
47014
|
syncedAt: now(),
|
|
46597
|
-
uploadedDigest:
|
|
47015
|
+
uploadedDigest: publishDigest(own, shared),
|
|
46598
47016
|
uploadedAt: at,
|
|
46599
47017
|
appliedAt: at,
|
|
46600
47018
|
pollAt: now() + POLL_MS,
|
|
46601
47019
|
imported: newRefs(),
|
|
46602
|
-
skipped: newMap()
|
|
47020
|
+
skipped: newMap(),
|
|
47021
|
+
...loginKnown ? { loginKnown } : {}
|
|
46603
47022
|
}));
|
|
46604
|
-
|
|
47023
|
+
const message = uploadedMessage(own.length, shared.length);
|
|
47024
|
+
return own.length + shared.length === 0 ? `${message} ${NOTHING_TO_SHARE}` : message;
|
|
46605
47025
|
}
|
|
46606
47026
|
async function unpublishedDigest() {
|
|
46607
47027
|
const state = await readSyncState();
|
|
46608
47028
|
if (!state || state.write === "no-token" || state.write === "unreadable" || state.write === "denied" && now() < (state.writeCheckAt ?? 0))
|
|
46609
47029
|
return null;
|
|
46610
|
-
const
|
|
46611
|
-
const digest =
|
|
47030
|
+
const pool = await readPool();
|
|
47031
|
+
const digest = publishDigest(ownEntries(pool, await machineOrigin(), state.imported), loginsSyncEnabled() ? ownLogins(pool) : []);
|
|
46612
47032
|
return digest === state.uploadedDigest ? null : digest;
|
|
46613
47033
|
}
|
|
46614
47034
|
const engine = {
|
|
@@ -46630,7 +47050,9 @@ function createEngine(deps) {
|
|
|
46630
47050
|
creator: prior?.creator ?? false,
|
|
46631
47051
|
...prior?.owner ? { owner: prior.owner } : {},
|
|
46632
47052
|
imported: prior?.imported ?? newRefs(),
|
|
46633
|
-
skipped: prior?.skipped ?? newMap()
|
|
47053
|
+
skipped: prior?.skipped ?? newMap(),
|
|
47054
|
+
...prior?.loginKnown ? { loginKnown: prior.loginKnown } : {},
|
|
47055
|
+
...prior?.loginSuppressed ? { loginSuppressed: prior.loginSuppressed } : {}
|
|
46634
47056
|
};
|
|
46635
47057
|
});
|
|
46636
47058
|
return settle(cycle(false), reqAt, true);
|
|
@@ -46657,6 +47079,7 @@ function createEngine(deps) {
|
|
|
46657
47079
|
};
|
|
46658
47080
|
return engine;
|
|
46659
47081
|
}
|
|
47082
|
+
var NOTHING_TO_SHARE = "No static credential or shareable OAuth login on this machine.";
|
|
46660
47083
|
var init_engine = __esm(() => {
|
|
46661
47084
|
init_store();
|
|
46662
47085
|
init_crypto();
|
|
@@ -46664,6 +47087,7 @@ var init_engine = __esm(() => {
|
|
|
46664
47087
|
init_errors6();
|
|
46665
47088
|
init_gist();
|
|
46666
47089
|
init_github_auth();
|
|
47090
|
+
init_logins();
|
|
46667
47091
|
init_origin();
|
|
46668
47092
|
init_own();
|
|
46669
47093
|
init_payload();
|
|
@@ -46671,6 +47095,47 @@ var init_engine = __esm(() => {
|
|
|
46671
47095
|
init_timing();
|
|
46672
47096
|
});
|
|
46673
47097
|
|
|
47098
|
+
// src/sync/login-hooks.ts
|
|
47099
|
+
function createPullLogin(runGh) {
|
|
47100
|
+
return async function pullLogin(account, _recovery) {
|
|
47101
|
+
const { providerID, accountId } = account;
|
|
47102
|
+
if (!syncEnabled() || !loginsSyncEnabled())
|
|
47103
|
+
return false;
|
|
47104
|
+
if (!LOGIN_PROVIDERS.has(providerID) || !accountId || !account.refresh)
|
|
47105
|
+
return false;
|
|
47106
|
+
try {
|
|
47107
|
+
const state = await readSyncState();
|
|
47108
|
+
if (!state)
|
|
47109
|
+
return false;
|
|
47110
|
+
const token = await discoverGithubToken(runGh) ?? undefined;
|
|
47111
|
+
const read = await readGist(state.gistId, undefined, Date.now(), token);
|
|
47112
|
+
if (!read.changed)
|
|
47113
|
+
return false;
|
|
47114
|
+
const key = decodeKey(state.key) ?? Buffer.alloc(32);
|
|
47115
|
+
const wanted = loginKey(providerID, accountId);
|
|
47116
|
+
const login = parsePayload(open2(read.content, key)).logins.find((l) => l.key === wanted);
|
|
47117
|
+
if (!login || !sameLogin(account, login))
|
|
47118
|
+
return false;
|
|
47119
|
+
if (compareLogins(login, versionOf(account)) <= 0)
|
|
47120
|
+
return false;
|
|
47121
|
+
return await overwriteLocked(account, login);
|
|
47122
|
+
} catch {
|
|
47123
|
+
return false;
|
|
47124
|
+
}
|
|
47125
|
+
};
|
|
47126
|
+
}
|
|
47127
|
+
var pullLogin;
|
|
47128
|
+
var init_login_hooks = __esm(() => {
|
|
47129
|
+
init_crypto();
|
|
47130
|
+
init_gist();
|
|
47131
|
+
init_github_auth();
|
|
47132
|
+
init_login_payload();
|
|
47133
|
+
init_logins();
|
|
47134
|
+
init_payload();
|
|
47135
|
+
init_state();
|
|
47136
|
+
pullLogin = createPullLogin();
|
|
47137
|
+
});
|
|
47138
|
+
|
|
46674
47139
|
// src/sync/intent.ts
|
|
46675
47140
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
46676
47141
|
import { access, readFile as readFile7, rename as rename2, rm as rm3 } from "node:fs/promises";
|
|
@@ -46872,10 +47337,6 @@ var init_loop = __esm(() => {
|
|
|
46872
47337
|
});
|
|
46873
47338
|
|
|
46874
47339
|
// src/sync/start.ts
|
|
46875
|
-
function syncEnabled(env = process.env) {
|
|
46876
|
-
const raw = env.OPENCODE_AUTH_LB_SYNC?.trim().toLowerCase();
|
|
46877
|
-
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
46878
|
-
}
|
|
46879
47340
|
function startSync() {
|
|
46880
47341
|
if (!syncEnabled())
|
|
46881
47342
|
return null;
|
|
@@ -46884,11 +47345,110 @@ function startSync() {
|
|
|
46884
47345
|
now: Date.now
|
|
46885
47346
|
});
|
|
46886
47347
|
loop.start();
|
|
46887
|
-
|
|
47348
|
+
if (!loginsSyncEnabled())
|
|
47349
|
+
return loop;
|
|
47350
|
+
setRefreshHooks({
|
|
47351
|
+
pull: pullLogin,
|
|
47352
|
+
afterRefresh: () => void publishAfterLogin().catch(ignore)
|
|
47353
|
+
});
|
|
47354
|
+
return {
|
|
47355
|
+
...loop,
|
|
47356
|
+
dispose() {
|
|
47357
|
+
setRefreshHooks(null);
|
|
47358
|
+
return loop.dispose();
|
|
47359
|
+
}
|
|
47360
|
+
};
|
|
47361
|
+
}
|
|
47362
|
+
async function publishAfterLogin(options = {}) {
|
|
47363
|
+
const { engine = createEngine({ now: Date.now }) } = options;
|
|
47364
|
+
const { timeoutMs = LOGIN_PUBLISH_MS } = options;
|
|
47365
|
+
let timer;
|
|
47366
|
+
const publish = async () => {
|
|
47367
|
+
if (!syncEnabled() || !loginsSyncEnabled() || !await readSyncState())
|
|
47368
|
+
return;
|
|
47369
|
+
await withCycleLock(() => engine.sync(), timeoutMs);
|
|
47370
|
+
};
|
|
47371
|
+
await Promise.race([
|
|
47372
|
+
publish().catch(ignore),
|
|
47373
|
+
new Promise((resolve) => {
|
|
47374
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
47375
|
+
})
|
|
47376
|
+
]);
|
|
47377
|
+
clearTimeout(timer);
|
|
46888
47378
|
}
|
|
47379
|
+
var LOGIN_PUBLISH_MS = 20000;
|
|
46889
47380
|
var init_start = __esm(() => {
|
|
47381
|
+
init_util4();
|
|
46890
47382
|
init_engine();
|
|
47383
|
+
init_login_hooks();
|
|
47384
|
+
init_logins();
|
|
47385
|
+
init_loop();
|
|
47386
|
+
init_state();
|
|
47387
|
+
});
|
|
47388
|
+
|
|
47389
|
+
// src/usage-poll.ts
|
|
47390
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
47391
|
+
async function nextPollAt(path) {
|
|
47392
|
+
try {
|
|
47393
|
+
const value = JSON.parse(await readFile8(path, "utf8"));
|
|
47394
|
+
return isPlainObject4(value) && isFiniteNumber(value.nextPollAt) ? value.nextPollAt : 0;
|
|
47395
|
+
} catch (error) {
|
|
47396
|
+
if (error instanceof SyntaxError || error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
47397
|
+
return 0;
|
|
47398
|
+
throw error;
|
|
47399
|
+
}
|
|
47400
|
+
}
|
|
47401
|
+
function startUsagePoll(deps = {}) {
|
|
47402
|
+
const now = deps.now ?? Date.now;
|
|
47403
|
+
const refresh = deps.refresh ?? refreshAllUsageInBackground;
|
|
47404
|
+
const timers = deps.timers ?? realTimers;
|
|
47405
|
+
let disposed = false;
|
|
47406
|
+
let inflight;
|
|
47407
|
+
async function poll() {
|
|
47408
|
+
const path = `${poolFilePath()}.usage-poll.json`;
|
|
47409
|
+
try {
|
|
47410
|
+
await withLock(`${path}.lock`, {
|
|
47411
|
+
staleMs: 120000,
|
|
47412
|
+
timeoutMs: 0,
|
|
47413
|
+
retryMs: 25,
|
|
47414
|
+
heartbeatMs: 5000
|
|
47415
|
+
}, async () => {
|
|
47416
|
+
const at = now();
|
|
47417
|
+
if (at < await nextPollAt(path))
|
|
47418
|
+
return;
|
|
47419
|
+
await writeJsonAtomic(path, JSON.stringify({ nextPollAt: at + USAGE_REFRESH_TTL_MS }));
|
|
47420
|
+
await refresh(at);
|
|
47421
|
+
});
|
|
47422
|
+
} catch (error) {
|
|
47423
|
+
if (!(error instanceof LockTimeoutError))
|
|
47424
|
+
throw error;
|
|
47425
|
+
}
|
|
47426
|
+
}
|
|
47427
|
+
function tick() {
|
|
47428
|
+
if (disposed)
|
|
47429
|
+
return Promise.resolve();
|
|
47430
|
+
inflight ??= poll().finally(() => {
|
|
47431
|
+
inflight = undefined;
|
|
47432
|
+
});
|
|
47433
|
+
return inflight;
|
|
47434
|
+
}
|
|
47435
|
+
const timer = timers.set(() => void tick().catch(ignore), USAGE_REFRESH_TTL_MS);
|
|
47436
|
+
return {
|
|
47437
|
+
tick,
|
|
47438
|
+
async dispose() {
|
|
47439
|
+
disposed = true;
|
|
47440
|
+
timers.clear(timer);
|
|
47441
|
+
await inflight;
|
|
47442
|
+
}
|
|
47443
|
+
};
|
|
47444
|
+
}
|
|
47445
|
+
var init_usage_poll = __esm(() => {
|
|
47446
|
+
init_lock();
|
|
47447
|
+
init_paths();
|
|
47448
|
+
init_store();
|
|
46891
47449
|
init_loop();
|
|
47450
|
+
init_usage_refresh();
|
|
47451
|
+
init_util4();
|
|
46892
47452
|
});
|
|
46893
47453
|
|
|
46894
47454
|
// src/legacy.ts
|
|
@@ -46916,6 +47476,8 @@ function buildAuthHook(adapter, client, pending) {
|
|
|
46916
47476
|
if (minted || account.inferenceToken !== undefined && account.refresh)
|
|
46917
47477
|
notifyPaired(client, adapter.id, account);
|
|
46918
47478
|
await refreshUsageInBackground(adapter, Date.now()).catch(ignore);
|
|
47479
|
+
if (tokens.refresh && !tokens.inferenceOnly)
|
|
47480
|
+
await publishAfterLogin();
|
|
46919
47481
|
};
|
|
46920
47482
|
const oauthSuccess = (tokens) => ({
|
|
46921
47483
|
type: "success",
|
|
@@ -47043,8 +47605,12 @@ function createProviderPlugin(adapter) {
|
|
|
47043
47605
|
}
|
|
47044
47606
|
var PROVIDER_LABELS, AnthropicLoadBalancerPlugin, OpenAILoadBalancerPlugin, KimiCodeLoadBalancerPlugin, KimiCodeGlobalLoadBalancerPlugin, lbResult = (output) => ({ title: "Auth Load Balancer", output }), AuthLoadBalancerStatusPlugin = async (input) => {
|
|
47045
47607
|
const sync = startSync();
|
|
47608
|
+
const usage = startUsagePoll();
|
|
47046
47609
|
return {
|
|
47047
|
-
dispose: async () =>
|
|
47610
|
+
dispose: async () => {
|
|
47611
|
+
await usage.dispose();
|
|
47612
|
+
await sync?.dispose();
|
|
47613
|
+
},
|
|
47048
47614
|
tool: {
|
|
47049
47615
|
auth_lb_status: tool2({
|
|
47050
47616
|
description: "Show the auth load-balancer pool: the in-use account per provider, each account's weekly and 5h usage, cooldowns, and the ranked next-candidate accounts. Refreshes stale usage from the provider usage endpoints (throttled) before rendering.",
|
|
@@ -47133,6 +47699,7 @@ var init_legacy = __esm(() => {
|
|
|
47133
47699
|
init_start();
|
|
47134
47700
|
init_token_mint();
|
|
47135
47701
|
init_types2();
|
|
47702
|
+
init_usage_poll();
|
|
47136
47703
|
init_usage_refresh();
|
|
47137
47704
|
init_util4();
|
|
47138
47705
|
PROVIDER_LABELS = {
|