opencode-auth-load-balancer 0.8.1 → 0.9.0
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 +44 -23
- package/dist/index.js +505 -51
- package/dist/login-rev.d.ts +14 -0
- 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/v1.js +505 -51
- package/dist/v2-entry.js +505 -51
- 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) {
|
|
@@ -42175,6 +42188,10 @@ function makeAccount(providerID, label, tokens) {
|
|
|
42175
42188
|
account.orgId = tokens.orgId;
|
|
42176
42189
|
if (tokens.refreshExpires)
|
|
42177
42190
|
account.refreshExpires = tokens.refreshExpires;
|
|
42191
|
+
if (tokens.refresh && !tokens.inferenceOnly) {
|
|
42192
|
+
account.loginRev = 1;
|
|
42193
|
+
account.loginAt = Date.now();
|
|
42194
|
+
}
|
|
42178
42195
|
return account;
|
|
42179
42196
|
}
|
|
42180
42197
|
function recordLostLogin(row, login, reason) {
|
|
@@ -42197,8 +42214,10 @@ function mergeLoginUsage(row, usage) {
|
|
|
42197
42214
|
};
|
|
42198
42215
|
}
|
|
42199
42216
|
function applyTokens(row, tokens) {
|
|
42200
|
-
if (tokens.refresh)
|
|
42217
|
+
if (tokens.refresh) {
|
|
42201
42218
|
row.refresh = tokens.refresh;
|
|
42219
|
+
bumpLoginRev(row);
|
|
42220
|
+
}
|
|
42202
42221
|
row.access = tokens.access;
|
|
42203
42222
|
row.expires = tokens.expires;
|
|
42204
42223
|
row.disabledReason = null;
|
|
@@ -42408,6 +42427,15 @@ function mergeHeaders(input, init) {
|
|
|
42408
42427
|
return headers;
|
|
42409
42428
|
}
|
|
42410
42429
|
|
|
42430
|
+
// src/refresh-hooks.ts
|
|
42431
|
+
function setRefreshHooks(hooks) {
|
|
42432
|
+
current = hooks;
|
|
42433
|
+
}
|
|
42434
|
+
function getRefreshHooks() {
|
|
42435
|
+
return current;
|
|
42436
|
+
}
|
|
42437
|
+
var current = null;
|
|
42438
|
+
|
|
42411
42439
|
// src/refresh.ts
|
|
42412
42440
|
function needsRefresh(account, now) {
|
|
42413
42441
|
return !account.access || account.expires - REFRESH_SKEW_MS <= now;
|
|
@@ -42466,6 +42494,7 @@ async function commitRefresh(accountId, attempt, next) {
|
|
|
42466
42494
|
if (!sameGeneration(stored, attempt))
|
|
42467
42495
|
return tokensOf(stored);
|
|
42468
42496
|
applyTokensTo(stored, next);
|
|
42497
|
+
bumpLoginRev(stored);
|
|
42469
42498
|
stored.tokenGen = attempt.gen + 1;
|
|
42470
42499
|
if (stored.disabledReason !== MANUAL_DISABLED_REASON)
|
|
42471
42500
|
stored.disabledReason = null;
|
|
@@ -42492,11 +42521,31 @@ async function resolveInvalidGrant(adapter, accountId, attempt, reason) {
|
|
|
42492
42521
|
return null;
|
|
42493
42522
|
});
|
|
42494
42523
|
}
|
|
42524
|
+
async function pullNewer(account, recovery) {
|
|
42525
|
+
try {
|
|
42526
|
+
const adopted = await getRefreshHooks()?.pull?.(account, recovery);
|
|
42527
|
+
return adopted ? await readPoolAccount(account.id) : undefined;
|
|
42528
|
+
} catch {
|
|
42529
|
+
return;
|
|
42530
|
+
}
|
|
42531
|
+
}
|
|
42532
|
+
function announceRefresh() {
|
|
42533
|
+
try {
|
|
42534
|
+
getRefreshHooks()?.afterRefresh?.();
|
|
42535
|
+
} catch {
|
|
42536
|
+
ignore();
|
|
42537
|
+
}
|
|
42538
|
+
}
|
|
42495
42539
|
async function runRefresh(adapter, account, now, rejectedAccess) {
|
|
42496
42540
|
return withLock(refreshLockDir(adapter.id, account.id), REFRESH_LOCK, async () => {
|
|
42497
|
-
const
|
|
42498
|
-
|
|
42499
|
-
|
|
42541
|
+
const read = await readPoolAccount(account.id) ?? account;
|
|
42542
|
+
const usable = (row) => row.access !== rejectedAccess && !needsRefresh(row, Math.max(now, Date.now()));
|
|
42543
|
+
if (usable(read))
|
|
42544
|
+
return tokensOf(read);
|
|
42545
|
+
const pulled = await pullNewer(read, false);
|
|
42546
|
+
if (pulled && usable(pulled))
|
|
42547
|
+
return tokensOf(pulled);
|
|
42548
|
+
const latest = pulled ?? read;
|
|
42500
42549
|
const attempt = {
|
|
42501
42550
|
refresh: latest.refresh,
|
|
42502
42551
|
gen: genOf(latest)
|
|
@@ -42507,6 +42556,9 @@ async function runRefresh(adapter, account, now, rejectedAccess) {
|
|
|
42507
42556
|
} catch (error) {
|
|
42508
42557
|
if (!(error instanceof Error) || !isInvalidGrant(error))
|
|
42509
42558
|
throw error;
|
|
42559
|
+
const recovered = await pullNewer(latest, true);
|
|
42560
|
+
if (recovered)
|
|
42561
|
+
return tokensOf(recovered);
|
|
42510
42562
|
const adopted = await resolveInvalidGrant(adapter, account.id, attempt, refusalReason(error));
|
|
42511
42563
|
if (adopted)
|
|
42512
42564
|
return adopted;
|
|
@@ -42534,7 +42586,9 @@ async function ensureAccessToken(adapter, account, now, rejectedAccess) {
|
|
|
42534
42586
|
const job = runRefresh(adapter, account, now, rejectedAccess);
|
|
42535
42587
|
inflight.set(account.id, job);
|
|
42536
42588
|
try {
|
|
42537
|
-
|
|
42589
|
+
const access = await settleRefresh(adapter, account, job);
|
|
42590
|
+
announceRefresh();
|
|
42591
|
+
return access;
|
|
42538
42592
|
} finally {
|
|
42539
42593
|
inflight.delete(account.id);
|
|
42540
42594
|
}
|
|
@@ -42733,7 +42787,7 @@ var init_session = __esm(() => {
|
|
|
42733
42787
|
// src/token-mint.ts
|
|
42734
42788
|
function autoTokenEnabled(env = process.env) {
|
|
42735
42789
|
const raw = env.OPENCODE_AUTH_LB_ANTHROPIC_AUTO_TOKEN?.trim().toLowerCase();
|
|
42736
|
-
return raw
|
|
42790
|
+
return raw === "1" || raw === "true" || raw === "yes" || raw === "on";
|
|
42737
42791
|
}
|
|
42738
42792
|
function tokenDue(account, now) {
|
|
42739
42793
|
if (!account.refresh || account.disabledReason)
|
|
@@ -42762,6 +42816,7 @@ async function mintToken(adapter, accountId) {
|
|
|
42762
42816
|
if (minted.refresh !== row.refresh) {
|
|
42763
42817
|
row.refresh = minted.refresh;
|
|
42764
42818
|
row.tokenGen = attempt.gen + 1;
|
|
42819
|
+
bumpLoginRev(row);
|
|
42765
42820
|
}
|
|
42766
42821
|
if (minted.refreshExpires)
|
|
42767
42822
|
row.refreshExpires = minted.refreshExpires;
|
|
@@ -43227,16 +43282,16 @@ function adopt(candidate) {
|
|
|
43227
43282
|
const trimmed = candidate.trim();
|
|
43228
43283
|
if (!VERSION_RE.test(trimmed))
|
|
43229
43284
|
return;
|
|
43230
|
-
if (compareVersions2(trimmed,
|
|
43285
|
+
if (compareVersions2(trimmed, current2) <= 0)
|
|
43231
43286
|
return;
|
|
43232
|
-
|
|
43287
|
+
current2 = trimmed;
|
|
43233
43288
|
}
|
|
43234
43289
|
function envOverride() {
|
|
43235
43290
|
const raw = process.env[CLAUDE_CODE_VERSION_ENV]?.trim();
|
|
43236
43291
|
return raw && VERSION_RE.test(raw) ? raw : undefined;
|
|
43237
43292
|
}
|
|
43238
43293
|
function claudeCodeVersion() {
|
|
43239
|
-
return envOverride() ??
|
|
43294
|
+
return envOverride() ?? current2;
|
|
43240
43295
|
}
|
|
43241
43296
|
function userAgent() {
|
|
43242
43297
|
return `claude-cli/${claudeCodeVersion()} (external, cli)`;
|
|
@@ -43271,7 +43326,7 @@ async function refreshClaudeCodeVersion(now) {
|
|
|
43271
43326
|
await persist(now);
|
|
43272
43327
|
}
|
|
43273
43328
|
async function persist(now) {
|
|
43274
|
-
await writeJsonAtomic(versionCacheFilePath(), JSON.stringify({ version:
|
|
43329
|
+
await writeJsonAtomic(versionCacheFilePath(), JSON.stringify({ version: current2, fetchedAt: now })).catch(ignore);
|
|
43275
43330
|
}
|
|
43276
43331
|
async function recoverClaudeCodeVersion(res, now) {
|
|
43277
43332
|
if (envOverride())
|
|
@@ -43284,12 +43339,12 @@ async function recoverClaudeCodeVersion(res, now) {
|
|
|
43284
43339
|
}
|
|
43285
43340
|
if (!text.includes(CLAUDE_CODE_VERSION_GATE_CODE))
|
|
43286
43341
|
return false;
|
|
43287
|
-
const before =
|
|
43342
|
+
const before = current2;
|
|
43288
43343
|
const required = CLAUDE_CODE_REQUIRED_VERSION_RE.exec(text)?.[1];
|
|
43289
43344
|
if (required !== undefined)
|
|
43290
43345
|
adopt(required);
|
|
43291
43346
|
await refreshClaudeCodeVersion(now).catch(ignore);
|
|
43292
|
-
if (
|
|
43347
|
+
if (current2 === before)
|
|
43293
43348
|
return false;
|
|
43294
43349
|
await persist(now);
|
|
43295
43350
|
return true;
|
|
@@ -43305,7 +43360,7 @@ async function primeClaudeCodeVersion(now) {
|
|
|
43305
43360
|
}
|
|
43306
43361
|
refreshClaudeCodeVersion(now).catch(ignore);
|
|
43307
43362
|
}
|
|
43308
|
-
var VERSION_RE,
|
|
43363
|
+
var VERSION_RE, current2;
|
|
43309
43364
|
var init_version = __esm(() => {
|
|
43310
43365
|
init_paths();
|
|
43311
43366
|
init_store();
|
|
@@ -43313,7 +43368,7 @@ var init_version = __esm(() => {
|
|
|
43313
43368
|
init_usage_http();
|
|
43314
43369
|
init_constants();
|
|
43315
43370
|
VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
43316
|
-
|
|
43371
|
+
current2 = FALLBACK_CLAUDE_CODE_VERSION;
|
|
43317
43372
|
});
|
|
43318
43373
|
|
|
43319
43374
|
// src/providers/anthropic/cch.ts
|
|
@@ -45625,6 +45680,12 @@ var init_prime = __esm(() => {
|
|
|
45625
45680
|
init_select();
|
|
45626
45681
|
});
|
|
45627
45682
|
|
|
45683
|
+
// src/sync/enabled.ts
|
|
45684
|
+
function syncEnabled(env = process.env) {
|
|
45685
|
+
const raw = env.OPENCODE_AUTH_LB_SYNC?.trim().toLowerCase();
|
|
45686
|
+
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
45687
|
+
}
|
|
45688
|
+
|
|
45628
45689
|
// src/sync/errors.ts
|
|
45629
45690
|
function describeSyncError(error) {
|
|
45630
45691
|
return error instanceof SyncError ? error.message : "Sync failed.";
|
|
@@ -45732,10 +45793,7 @@ var init_crypto = __esm(() => {
|
|
|
45732
45793
|
B64URL_RE = /^[\w-]+$/;
|
|
45733
45794
|
});
|
|
45734
45795
|
|
|
45735
|
-
// src/sync/
|
|
45736
|
-
function entryKey(entry) {
|
|
45737
|
-
return `${entry.origin}/${entry.id}`;
|
|
45738
|
-
}
|
|
45796
|
+
// src/sync/text.ts
|
|
45739
45797
|
function isControl(code) {
|
|
45740
45798
|
return code < 32 || code >= 127 && code <= 159 || code === 1564 || code >= 8203 && code <= 8207 || code >= 8232 && code <= 8238 || code >= 8288 && code <= 8297 || code === 65279;
|
|
45741
45799
|
}
|
|
@@ -45745,6 +45803,106 @@ function printable(text) {
|
|
|
45745
45803
|
function boundedString(value, max) {
|
|
45746
45804
|
return typeof value === "string" && value.length > 0 && value.length <= max ? value : undefined;
|
|
45747
45805
|
}
|
|
45806
|
+
var MAX_LABEL = 80;
|
|
45807
|
+
|
|
45808
|
+
// src/sync/login-payload.ts
|
|
45809
|
+
function loginKey(providerID, accountId) {
|
|
45810
|
+
return `${providerID}:${accountId}`;
|
|
45811
|
+
}
|
|
45812
|
+
function word(value, max) {
|
|
45813
|
+
const text = boundedString(value, max);
|
|
45814
|
+
return text !== undefined && NO_SPACE_RE.test(text) ? text : undefined;
|
|
45815
|
+
}
|
|
45816
|
+
function positive(value) {
|
|
45817
|
+
return isFiniteNumber(value) && value > 0 ? value : undefined;
|
|
45818
|
+
}
|
|
45819
|
+
function parseLogin(raw) {
|
|
45820
|
+
if (!isPlainObject4(raw))
|
|
45821
|
+
return null;
|
|
45822
|
+
const providerID = word(raw.providerID, MAX_ID);
|
|
45823
|
+
const accountId = word(raw.accountId, MAX_ID);
|
|
45824
|
+
const label = printable(boundedString(raw.label, MAX_LABEL) ?? "");
|
|
45825
|
+
const [access, refresh] = [
|
|
45826
|
+
word(raw.access, MAX_TOKEN),
|
|
45827
|
+
word(raw.refresh, MAX_TOKEN)
|
|
45828
|
+
];
|
|
45829
|
+
const { rev, at } = raw;
|
|
45830
|
+
if (!providerID || !LOGIN_PROVIDERS.has(providerID) || !accountId)
|
|
45831
|
+
return null;
|
|
45832
|
+
if (raw.key !== loginKey(providerID, accountId))
|
|
45833
|
+
return null;
|
|
45834
|
+
const expires = positive(raw.expires);
|
|
45835
|
+
if (!label || !access || !refresh || !expires)
|
|
45836
|
+
return null;
|
|
45837
|
+
if (typeof rev !== "number" || !Number.isSafeInteger(rev) || rev < 1)
|
|
45838
|
+
return null;
|
|
45839
|
+
if (!isFiniteNumber(at) || at < 0)
|
|
45840
|
+
return null;
|
|
45841
|
+
const orgId = word(raw.orgId, MAX_ID);
|
|
45842
|
+
const refreshExpires = positive(raw.refreshExpires);
|
|
45843
|
+
return {
|
|
45844
|
+
key: loginKey(providerID, accountId),
|
|
45845
|
+
providerID,
|
|
45846
|
+
label,
|
|
45847
|
+
access,
|
|
45848
|
+
refresh,
|
|
45849
|
+
expires,
|
|
45850
|
+
accountId,
|
|
45851
|
+
...orgId ? { orgId } : {},
|
|
45852
|
+
...refreshExpires ? { refreshExpires } : {},
|
|
45853
|
+
rev,
|
|
45854
|
+
at
|
|
45855
|
+
};
|
|
45856
|
+
}
|
|
45857
|
+
function sortLogins(logins) {
|
|
45858
|
+
return [...logins].sort((a, b) => a.key < b.key ? -1 : a.key > b.key ? 1 : 0);
|
|
45859
|
+
}
|
|
45860
|
+
function loginsDigest(logins) {
|
|
45861
|
+
return fingerprint(JSON.stringify(sortLogins(logins)));
|
|
45862
|
+
}
|
|
45863
|
+
function compareLogins(a, b) {
|
|
45864
|
+
if (a.rev !== b.rev)
|
|
45865
|
+
return a.rev < b.rev ? -1 : 1;
|
|
45866
|
+
if (a.at !== b.at)
|
|
45867
|
+
return a.at < b.at ? -1 : 1;
|
|
45868
|
+
const [x, y] = [fingerprint(a.refresh), fingerprint(b.refresh)];
|
|
45869
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
45870
|
+
}
|
|
45871
|
+
function parseLoginList(rawList) {
|
|
45872
|
+
const parsed = {
|
|
45873
|
+
logins: [],
|
|
45874
|
+
loginsListed: new Set,
|
|
45875
|
+
loginsUnreadable: 0
|
|
45876
|
+
};
|
|
45877
|
+
for (const raw of rawList) {
|
|
45878
|
+
const key = isPlainObject4(raw) ? boundedString(raw.key, MAX_KEY) : undefined;
|
|
45879
|
+
if (key)
|
|
45880
|
+
parsed.loginsListed.add(key);
|
|
45881
|
+
const login = parseLogin(raw);
|
|
45882
|
+
if (!login)
|
|
45883
|
+
parsed.loginsUnreadable += 1;
|
|
45884
|
+
else if (!parsed.logins.some((l) => l.key === login.key))
|
|
45885
|
+
parsed.logins.push(login);
|
|
45886
|
+
}
|
|
45887
|
+
return parsed;
|
|
45888
|
+
}
|
|
45889
|
+
var MAX_LOGINS = 64, MAX_TOKEN = 8192, MAX_ID = 128, MAX_KEY = 300, NO_SPACE_RE, LOGIN_PROVIDERS;
|
|
45890
|
+
var init_login_payload = __esm(() => {
|
|
45891
|
+
init_util4();
|
|
45892
|
+
init_crypto();
|
|
45893
|
+
NO_SPACE_RE = /^\S+$/;
|
|
45894
|
+
LOGIN_PROVIDERS = new Set([
|
|
45895
|
+
"anthropic",
|
|
45896
|
+
"openai",
|
|
45897
|
+
"kimi-code-plan-cn",
|
|
45898
|
+
"kimi-code-plan-global"
|
|
45899
|
+
]);
|
|
45900
|
+
});
|
|
45901
|
+
|
|
45902
|
+
// src/sync/payload.ts
|
|
45903
|
+
function entryKey(entry) {
|
|
45904
|
+
return `${entry.origin}/${entry.id}`;
|
|
45905
|
+
}
|
|
45748
45906
|
function keyOf(raw) {
|
|
45749
45907
|
if (!isPlainObject4(raw))
|
|
45750
45908
|
return null;
|
|
@@ -45785,11 +45943,12 @@ function sortEntries(entries) {
|
|
|
45785
45943
|
function entriesDigest(entries) {
|
|
45786
45944
|
return fingerprint(JSON.stringify(sortEntries(entries)));
|
|
45787
45945
|
}
|
|
45788
|
-
function buildPayload(entries, at) {
|
|
45946
|
+
function buildPayload(entries, at, logins = []) {
|
|
45789
45947
|
return JSON.stringify({
|
|
45790
45948
|
v: PAYLOAD_VERSION,
|
|
45791
45949
|
at,
|
|
45792
|
-
entries: sortEntries(entries)
|
|
45950
|
+
entries: sortEntries(entries),
|
|
45951
|
+
logins: sortLogins(logins)
|
|
45793
45952
|
});
|
|
45794
45953
|
}
|
|
45795
45954
|
function parsePayload(text) {
|
|
@@ -45801,11 +45960,12 @@ function parsePayload(text) {
|
|
|
45801
45960
|
}
|
|
45802
45961
|
if (!isPlainObject4(json) || !Array.isArray(json.entries))
|
|
45803
45962
|
throw new SyncError("bad-blob");
|
|
45804
|
-
if (json.v !== PAYLOAD_VERSION)
|
|
45963
|
+
if (json.v !== PAYLOAD_VERSION && json.v !== ENTRIES_ONLY_VERSION)
|
|
45805
45964
|
throw new SyncError("bad-version");
|
|
45806
|
-
|
|
45965
|
+
const rawLogins = json.v === PAYLOAD_VERSION ? json.logins ?? [] : [];
|
|
45966
|
+
if (!isFiniteNumber(json.at) || !Array.isArray(rawLogins))
|
|
45807
45967
|
throw new SyncError("bad-blob");
|
|
45808
|
-
if (json.entries.length > MAX_ENTRIES)
|
|
45968
|
+
if (json.entries.length > MAX_ENTRIES || rawLogins.length > MAX_LOGINS)
|
|
45809
45969
|
throw new SyncError("too-large");
|
|
45810
45970
|
const listed = new Set;
|
|
45811
45971
|
const entries = [];
|
|
@@ -45824,13 +45984,20 @@ function parsePayload(text) {
|
|
|
45824
45984
|
else
|
|
45825
45985
|
unreadable += 1;
|
|
45826
45986
|
}
|
|
45827
|
-
return {
|
|
45987
|
+
return {
|
|
45988
|
+
at: json.at,
|
|
45989
|
+
entries,
|
|
45990
|
+
listed,
|
|
45991
|
+
unreadable,
|
|
45992
|
+
...parseLoginList(rawLogins)
|
|
45993
|
+
};
|
|
45828
45994
|
}
|
|
45829
|
-
var PAYLOAD_VERSION =
|
|
45995
|
+
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
45996
|
var init_payload = __esm(() => {
|
|
45831
45997
|
init_util4();
|
|
45832
45998
|
init_crypto();
|
|
45833
45999
|
init_errors6();
|
|
46000
|
+
init_login_payload();
|
|
45834
46001
|
ID_RE = /^[\w-]{1,64}$/;
|
|
45835
46002
|
ORIGIN_RE = /^[\da-f]{32}$/;
|
|
45836
46003
|
CLAUDE_TOKEN_RE = /^sk-ant-oat\d+-[\w-]+$/;
|
|
@@ -46076,6 +46243,12 @@ function isRef(value) {
|
|
|
46076
46243
|
function isSkip(value) {
|
|
46077
46244
|
return isPlainObject4(value) && typeof value.fingerprint === "string" && typeof value.blocker === "string" && typeof value.holds === "string";
|
|
46078
46245
|
}
|
|
46246
|
+
function isMark(value) {
|
|
46247
|
+
return value === true;
|
|
46248
|
+
}
|
|
46249
|
+
function marks(from) {
|
|
46250
|
+
return from && Object.keys(from).length > 0 ? newMap(from) : undefined;
|
|
46251
|
+
}
|
|
46079
46252
|
function readMap(raw, accept) {
|
|
46080
46253
|
const map = newMap();
|
|
46081
46254
|
if (isPlainObject4(raw)) {
|
|
@@ -46099,6 +46272,8 @@ function parseState(text) {
|
|
|
46099
46272
|
return null;
|
|
46100
46273
|
const { owner, etag, syncedAt, uploadedDigest, write } = json;
|
|
46101
46274
|
const { uploadedAt, appliedAt, retryAt, pollAt, writeCheckAt } = json;
|
|
46275
|
+
const loginKnown = marks(readMap(json.loginKnown, isMark));
|
|
46276
|
+
const loginSuppressed = marks(readMap(json.loginSuppressed, isMark));
|
|
46102
46277
|
return {
|
|
46103
46278
|
v: 1,
|
|
46104
46279
|
gistId: json.gistId,
|
|
@@ -46106,6 +46281,8 @@ function parseState(text) {
|
|
|
46106
46281
|
creator: json.creator === true,
|
|
46107
46282
|
imported: readMap(json.imported, isRef),
|
|
46108
46283
|
skipped: readMap(json.skipped, isSkip),
|
|
46284
|
+
...loginKnown ? { loginKnown } : {},
|
|
46285
|
+
...loginSuppressed ? { loginSuppressed } : {},
|
|
46109
46286
|
...typeof owner === "string" ? { owner } : {},
|
|
46110
46287
|
...isWrite(write) ? { write } : {},
|
|
46111
46288
|
...typeof etag === "string" ? { etag } : {},
|
|
@@ -46335,6 +46512,179 @@ async function discoverGithubToken(run = ghAuthToken, env = process.env) {
|
|
|
46335
46512
|
var GH_TIMEOUT_MS = 5000;
|
|
46336
46513
|
var init_github_auth = () => {};
|
|
46337
46514
|
|
|
46515
|
+
// src/sync/logins.ts
|
|
46516
|
+
function loginsSyncEnabled(env = process.env) {
|
|
46517
|
+
const raw = env.OPENCODE_AUTH_LB_SYNC_LOGINS?.trim().toLowerCase();
|
|
46518
|
+
return raw !== "0" && raw !== "false" && raw !== "no" && raw !== "off";
|
|
46519
|
+
}
|
|
46520
|
+
function rowKey(row) {
|
|
46521
|
+
const live = row.refresh !== "" || row.inferenceToken !== undefined && row.lostLogins?.oauth !== undefined;
|
|
46522
|
+
return LOGIN_PROVIDERS.has(row.providerID) && row.accountId && live ? loginKey(row.providerID, row.accountId) : null;
|
|
46523
|
+
}
|
|
46524
|
+
function heldMarks(accounts) {
|
|
46525
|
+
const held = newMap();
|
|
46526
|
+
for (const row of accounts) {
|
|
46527
|
+
const key = rowKey(row);
|
|
46528
|
+
if (key)
|
|
46529
|
+
held[key] = true;
|
|
46530
|
+
}
|
|
46531
|
+
return held;
|
|
46532
|
+
}
|
|
46533
|
+
function ownLogins(pool) {
|
|
46534
|
+
const best = new Map;
|
|
46535
|
+
for (const row of pool.accounts) {
|
|
46536
|
+
if (!row.refresh || !row.accountId)
|
|
46537
|
+
continue;
|
|
46538
|
+
if (row.disabledReason || row.lostLogins?.oauth)
|
|
46539
|
+
continue;
|
|
46540
|
+
const login = parseLogin({
|
|
46541
|
+
key: loginKey(row.providerID, row.accountId),
|
|
46542
|
+
providerID: row.providerID,
|
|
46543
|
+
label: printable(row.label).slice(0, MAX_LABEL).trim() || row.providerID,
|
|
46544
|
+
access: row.access,
|
|
46545
|
+
refresh: row.refresh,
|
|
46546
|
+
expires: row.expires,
|
|
46547
|
+
accountId: row.accountId,
|
|
46548
|
+
orgId: row.orgId,
|
|
46549
|
+
refreshExpires: row.refreshExpires,
|
|
46550
|
+
...loginVersion(row)
|
|
46551
|
+
});
|
|
46552
|
+
const prior = login ? best.get(login.key) : undefined;
|
|
46553
|
+
if (login && (!prior || compareLogins(login, prior) > 0))
|
|
46554
|
+
best.set(login.key, login);
|
|
46555
|
+
}
|
|
46556
|
+
return sortLogins([...best.values()]).slice(0, MAX_LOGINS);
|
|
46557
|
+
}
|
|
46558
|
+
function mergeLogins(gist, own) {
|
|
46559
|
+
const merged = new Map(gist.map((login) => [login.key, login]));
|
|
46560
|
+
for (const login of own) {
|
|
46561
|
+
const prior = merged.get(login.key);
|
|
46562
|
+
if (prior ? compareLogins(login, prior) > 0 : merged.size < MAX_LOGINS)
|
|
46563
|
+
merged.set(login.key, login);
|
|
46564
|
+
}
|
|
46565
|
+
return sortLogins([...merged.values()]);
|
|
46566
|
+
}
|
|
46567
|
+
function ownCopies(next, own) {
|
|
46568
|
+
return own.filter((login) => next.some((n) => n.key === login.key && n.refresh === login.refresh)).length;
|
|
46569
|
+
}
|
|
46570
|
+
function publishDigest(entries, logins) {
|
|
46571
|
+
return logins.length === 0 ? entriesDigest(entries) : fingerprint(`${entriesDigest(entries)}/${loginsDigest(logins)}`);
|
|
46572
|
+
}
|
|
46573
|
+
function sameLogin(row, login) {
|
|
46574
|
+
return rowKey(row) === login.key && (row.orgId === undefined || login.orgId === undefined || row.orgId === login.orgId);
|
|
46575
|
+
}
|
|
46576
|
+
function versionOf(row) {
|
|
46577
|
+
return { ...loginVersion(row), refresh: row.refresh };
|
|
46578
|
+
}
|
|
46579
|
+
function overwriteLocked(row, login) {
|
|
46580
|
+
const attempt = { refresh: row.refresh, gen: genOf(row) };
|
|
46581
|
+
return mutatePool((pool) => {
|
|
46582
|
+
const cur = findAccount(pool, row.id);
|
|
46583
|
+
if (!cur || !sameGeneration(cur, attempt))
|
|
46584
|
+
return false;
|
|
46585
|
+
cur.access = login.access;
|
|
46586
|
+
cur.refresh = login.refresh;
|
|
46587
|
+
cur.expires = login.expires;
|
|
46588
|
+
if (login.refreshExpires)
|
|
46589
|
+
cur.refreshExpires = login.refreshExpires;
|
|
46590
|
+
else
|
|
46591
|
+
delete cur.refreshExpires;
|
|
46592
|
+
if (login.orgId)
|
|
46593
|
+
cur.orgId = login.orgId;
|
|
46594
|
+
cur.loginRev = login.rev;
|
|
46595
|
+
cur.loginAt = login.at;
|
|
46596
|
+
cur.tokenGen = genOf(cur) + 1;
|
|
46597
|
+
clearLostLogin(cur, "oauth");
|
|
46598
|
+
if (cur.disabledReason?.startsWith(AUTO_DISABLED_PREFIX))
|
|
46599
|
+
cur.disabledReason = null;
|
|
46600
|
+
return true;
|
|
46601
|
+
});
|
|
46602
|
+
}
|
|
46603
|
+
function overwrite(row, login) {
|
|
46604
|
+
return withRefreshLock(row.providerID, row.id, () => overwriteLocked(row, login));
|
|
46605
|
+
}
|
|
46606
|
+
async function create(login) {
|
|
46607
|
+
const tokens = {
|
|
46608
|
+
access: login.access,
|
|
46609
|
+
refresh: login.refresh,
|
|
46610
|
+
expires: login.expires,
|
|
46611
|
+
accountId: login.accountId,
|
|
46612
|
+
...login.orgId ? { orgId: login.orgId } : {},
|
|
46613
|
+
...login.refreshExpires ? { refreshExpires: login.refreshExpires } : {}
|
|
46614
|
+
};
|
|
46615
|
+
return mutatePool((pool) => {
|
|
46616
|
+
if (pool.accounts.some((row) => sameLogin(row, login)))
|
|
46617
|
+
return false;
|
|
46618
|
+
const manual = new Set(pool.accounts.filter((row) => row.disabledReason === MANUAL_DISABLED_REASON).map((row) => row.id));
|
|
46619
|
+
const row = placeTokens(pool, login.providerID, tokens, uniqueLabel(pool, login.label), undefined);
|
|
46620
|
+
row.loginRev = login.rev;
|
|
46621
|
+
row.loginAt = login.at;
|
|
46622
|
+
row.tokenGen = genOf(row) + 1;
|
|
46623
|
+
if (manual.has(row.id))
|
|
46624
|
+
row.disabledReason = MANUAL_DISABLED_REASON;
|
|
46625
|
+
return true;
|
|
46626
|
+
});
|
|
46627
|
+
}
|
|
46628
|
+
async function adopt2(login) {
|
|
46629
|
+
const row = (await readPool()).accounts.find((a) => sameLogin(a, login));
|
|
46630
|
+
if (!row)
|
|
46631
|
+
return create(login);
|
|
46632
|
+
return compareLogins(login, versionOf(row)) > 0 ? overwrite(row, login) : false;
|
|
46633
|
+
}
|
|
46634
|
+
async function outrank(login, now) {
|
|
46635
|
+
const row = (await readPool()).accounts.find((a) => sameLogin(a, login));
|
|
46636
|
+
if (!row || compareLogins(versionOf(row), login) > 0)
|
|
46637
|
+
return;
|
|
46638
|
+
const attempt = { refresh: row.refresh, gen: genOf(row) };
|
|
46639
|
+
await mutatePool((pool) => {
|
|
46640
|
+
const cur = findAccount(pool, row.id);
|
|
46641
|
+
if (!cur || !sameGeneration(cur, attempt))
|
|
46642
|
+
return;
|
|
46643
|
+
cur.loginRev = login.rev + 1;
|
|
46644
|
+
cur.loginAt = now;
|
|
46645
|
+
});
|
|
46646
|
+
}
|
|
46647
|
+
async function applyLogins(gist, marks, now) {
|
|
46648
|
+
const known = newMap(marks.known);
|
|
46649
|
+
const suppressed = newMap(marks.suppressed);
|
|
46650
|
+
const held = heldMarks((await readPool()).accounts);
|
|
46651
|
+
for (const key of Object.keys(known)) {
|
|
46652
|
+
if (held[key])
|
|
46653
|
+
continue;
|
|
46654
|
+
suppressed[key] = true;
|
|
46655
|
+
delete known[key];
|
|
46656
|
+
}
|
|
46657
|
+
for (const key of Object.keys(suppressed)) {
|
|
46658
|
+
if (!held[key])
|
|
46659
|
+
continue;
|
|
46660
|
+
delete suppressed[key];
|
|
46661
|
+
const login = gist.find((l) => l.key === key);
|
|
46662
|
+
if (login)
|
|
46663
|
+
await outrank(login, now);
|
|
46664
|
+
}
|
|
46665
|
+
let adopted = 0;
|
|
46666
|
+
for (const login of gist)
|
|
46667
|
+
if (!suppressed[login.key] && await adopt2(login))
|
|
46668
|
+
adopted += 1;
|
|
46669
|
+
return {
|
|
46670
|
+
adopted,
|
|
46671
|
+
known: heldMarks((await readPool()).accounts),
|
|
46672
|
+
suppressed
|
|
46673
|
+
};
|
|
46674
|
+
}
|
|
46675
|
+
var AUTO_DISABLED_PREFIX = "invalid_grant: re-login required";
|
|
46676
|
+
var init_logins = __esm(() => {
|
|
46677
|
+
init_accounts();
|
|
46678
|
+
init_store();
|
|
46679
|
+
init_refresh();
|
|
46680
|
+
init_types2();
|
|
46681
|
+
init_apply();
|
|
46682
|
+
init_crypto();
|
|
46683
|
+
init_login_payload();
|
|
46684
|
+
init_payload();
|
|
46685
|
+
init_state();
|
|
46686
|
+
});
|
|
46687
|
+
|
|
46338
46688
|
// src/sync/origin.ts
|
|
46339
46689
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
46340
46690
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
@@ -46435,6 +46785,10 @@ var init_timing = __esm(() => {
|
|
|
46435
46785
|
function count(n, one, many) {
|
|
46436
46786
|
return `${n} ${n === 1 ? one : many}`;
|
|
46437
46787
|
}
|
|
46788
|
+
function uploadedMessage(entries, logins) {
|
|
46789
|
+
const credentials = count(entries, "credential", "credentials");
|
|
46790
|
+
return logins === 0 ? `Uploaded ${credentials}.` : `Uploaded ${credentials} and ${count(logins, "login", "logins")}.`;
|
|
46791
|
+
}
|
|
46438
46792
|
function recordApplied(gistId, at, applied, syncedAt) {
|
|
46439
46793
|
return updateSyncState((cur) => cur?.gistId === gistId ? {
|
|
46440
46794
|
...cur,
|
|
@@ -46458,7 +46812,8 @@ async function runCycle(deps, force, report) {
|
|
|
46458
46812
|
const pool = await readPool();
|
|
46459
46813
|
const backedOff = state.write === "denied" && !force && now() < (state.writeCheckAt ?? 0);
|
|
46460
46814
|
const mayWrite = token !== null && !backedOff;
|
|
46461
|
-
const
|
|
46815
|
+
const sharing = loginsSyncEnabled();
|
|
46816
|
+
const before = publishDigest(ownEntries(pool, origin, state.imported), sharing ? ownLogins(pool) : []);
|
|
46462
46817
|
const dirty = mayWrite && before !== state.uploadedDigest;
|
|
46463
46818
|
report.retryMs = dirty ? PUBLISH_RETRY_MS : POLL_MS;
|
|
46464
46819
|
const reread = force || dirty || hasFreedSkips(pool.accounts, state.skipped);
|
|
@@ -46480,8 +46835,17 @@ async function runCycle(deps, force, report) {
|
|
|
46480
46835
|
...deps.adapters ? { adapters: deps.adapters } : {},
|
|
46481
46836
|
afterPass: (soFar) => recordApplied(state.gistId, snapshot.at, soFar, now())
|
|
46482
46837
|
});
|
|
46483
|
-
const
|
|
46484
|
-
|
|
46838
|
+
const adoptedLogins = stale || !sharing ? null : await applyLogins(snapshot.logins, { known: state.loginKnown, suppressed: state.loginSuppressed }, now());
|
|
46839
|
+
if (adoptedLogins)
|
|
46840
|
+
await updateSyncState((cur) => cur?.gistId === state.gistId ? {
|
|
46841
|
+
...cur,
|
|
46842
|
+
loginKnown: marks(adoptedLogins.known),
|
|
46843
|
+
loginSuppressed: marks(adoptedLogins.suppressed)
|
|
46844
|
+
} : cur);
|
|
46845
|
+
const settled = await readPool();
|
|
46846
|
+
const own = ownEntries(settled, origin, applied?.imported ?? state.imported);
|
|
46847
|
+
const ownShared = sharing ? ownLogins(settled) : [];
|
|
46848
|
+
const unreadable = snapshot.unreadable > 0 || snapshot.loginsUnreadable > 0;
|
|
46485
46849
|
let write = standing;
|
|
46486
46850
|
let wrote = null;
|
|
46487
46851
|
let stamped = 0;
|
|
@@ -46491,12 +46855,16 @@ async function runCycle(deps, force, report) {
|
|
|
46491
46855
|
if (mayWrite && !unreadable) {
|
|
46492
46856
|
const others = snapshot.entries.filter((e) => e.origin !== origin);
|
|
46493
46857
|
const next = sortEntries([...others, ...listable(own, others, origin)]);
|
|
46494
|
-
const
|
|
46858
|
+
const nextLogins = sharing ? mergeLogins(snapshot.logins, ownShared) : snapshot.logins;
|
|
46859
|
+
const same = JSON.stringify(next) === JSON.stringify(sortEntries(snapshot.entries)) && loginsDigest(nextLogins) === loginsDigest(snapshot.logins);
|
|
46495
46860
|
if (!same || stale) {
|
|
46496
46861
|
stamped = Math.max(now(), snapshot.at + 1, (state.uploadedAt ?? 0) + 1, (state.appliedAt ?? 0) + 1);
|
|
46497
46862
|
try {
|
|
46498
|
-
await updateGist(token, state.gistId, seal(buildPayload(next, stamped), key), now());
|
|
46499
|
-
wrote =
|
|
46863
|
+
await updateGist(token, state.gistId, seal(buildPayload(next, stamped, nextLogins), key), now());
|
|
46864
|
+
wrote = {
|
|
46865
|
+
entries: next.filter((e) => e.origin === origin).length,
|
|
46866
|
+
logins: ownCopies(nextLogins, ownShared)
|
|
46867
|
+
};
|
|
46500
46868
|
} catch (error) {
|
|
46501
46869
|
if (!(error instanceof SyncError) || error.code !== "write-denied")
|
|
46502
46870
|
throw error;
|
|
@@ -46512,18 +46880,22 @@ async function runCycle(deps, force, report) {
|
|
|
46512
46880
|
etag: wrote || stale || deferred > 0 || denied ? undefined : read.etag,
|
|
46513
46881
|
write,
|
|
46514
46882
|
writeCheckAt: denied ? now() + WRITE_BACKOFF_MS : backedOff ? cur.writeCheckAt : undefined,
|
|
46515
|
-
uploadedDigest: mayWrite && !unreadable && !denied ?
|
|
46883
|
+
uploadedDigest: mayWrite && !unreadable && !denied ? publishDigest(own, ownShared) : cur.uploadedDigest,
|
|
46516
46884
|
...wrote ? { uploadedAt: stamped } : {}
|
|
46517
46885
|
} : cur);
|
|
46518
46886
|
const parts = [];
|
|
46519
46887
|
const moved = applied ? applied.added + applied.updated + applied.removed + deferred : 0;
|
|
46888
|
+
const adopted = adoptedLogins?.adopted ?? 0;
|
|
46520
46889
|
if (applied && moved > 0) {
|
|
46521
46890
|
const tail = deferred > 0 ? `; ${count(deferred, "entry", "entries")} could not be verified yet` : "";
|
|
46522
|
-
|
|
46523
|
-
|
|
46891
|
+
const login = adopted > 0 ? `; ${count(adopted, "login", "logins")} adopted` : "";
|
|
46892
|
+
parts.push(`Synced: ${applied.added} added, ${applied.updated} updated, ${applied.removed} removed${tail}${login}.`);
|
|
46893
|
+
} else if (adopted > 0)
|
|
46894
|
+
parts.push(`Synced: ${count(adopted, "login", "logins")} adopted.`);
|
|
46895
|
+
else if (!wrote)
|
|
46524
46896
|
parts.push("Up to date.");
|
|
46525
46897
|
if (wrote)
|
|
46526
|
-
parts.push(
|
|
46898
|
+
parts.push(uploadedMessage(wrote.entries, wrote.logins));
|
|
46527
46899
|
if (denied)
|
|
46528
46900
|
parts.push(new SyncError("write-denied").message);
|
|
46529
46901
|
if (mayWrite && unreadable && state.write !== "unreadable")
|
|
@@ -46538,6 +46910,8 @@ var init_cycle = __esm(() => {
|
|
|
46538
46910
|
init_errors6();
|
|
46539
46911
|
init_gist();
|
|
46540
46912
|
init_github_auth();
|
|
46913
|
+
init_login_payload();
|
|
46914
|
+
init_logins();
|
|
46541
46915
|
init_merge();
|
|
46542
46916
|
init_origin();
|
|
46543
46917
|
init_own();
|
|
@@ -46547,9 +46921,6 @@ var init_cycle = __esm(() => {
|
|
|
46547
46921
|
});
|
|
46548
46922
|
|
|
46549
46923
|
// src/sync/engine.ts
|
|
46550
|
-
function count2(n, one, many) {
|
|
46551
|
-
return `${n} ${n === 1 ? one : many}`;
|
|
46552
|
-
}
|
|
46553
46924
|
function createEngine(deps) {
|
|
46554
46925
|
const { now } = deps;
|
|
46555
46926
|
async function settle(work, reqAt, scheduled) {
|
|
@@ -46582,10 +46953,14 @@ function createEngine(deps) {
|
|
|
46582
46953
|
if (!token)
|
|
46583
46954
|
throw new SyncError("no-auth");
|
|
46584
46955
|
const origin = await machineOrigin();
|
|
46585
|
-
const
|
|
46956
|
+
const pool = await readPool();
|
|
46957
|
+
const own = ownEntries(pool, origin, newRefs());
|
|
46958
|
+
const sharing = loginsSyncEnabled();
|
|
46959
|
+
const shared = sharing ? ownLogins(pool) : [];
|
|
46586
46960
|
const key = generateKey();
|
|
46587
46961
|
const at = now();
|
|
46588
|
-
const gist = await createGist(token, seal(buildPayload(own, at), key), now());
|
|
46962
|
+
const gist = await createGist(token, seal(buildPayload(own, at, shared), key), now());
|
|
46963
|
+
const loginKnown = sharing ? marks(heldMarks(pool.accounts)) : undefined;
|
|
46589
46964
|
await updateSyncState(() => ({
|
|
46590
46965
|
v: 1,
|
|
46591
46966
|
gistId: gist.id,
|
|
@@ -46594,21 +46969,23 @@ function createEngine(deps) {
|
|
|
46594
46969
|
...gist.owner ? { owner: gist.owner } : {},
|
|
46595
46970
|
write: "ok",
|
|
46596
46971
|
syncedAt: now(),
|
|
46597
|
-
uploadedDigest:
|
|
46972
|
+
uploadedDigest: publishDigest(own, shared),
|
|
46598
46973
|
uploadedAt: at,
|
|
46599
46974
|
appliedAt: at,
|
|
46600
46975
|
pollAt: now() + POLL_MS,
|
|
46601
46976
|
imported: newRefs(),
|
|
46602
|
-
skipped: newMap()
|
|
46977
|
+
skipped: newMap(),
|
|
46978
|
+
...loginKnown ? { loginKnown } : {}
|
|
46603
46979
|
}));
|
|
46604
|
-
|
|
46980
|
+
const message = uploadedMessage(own.length, shared.length);
|
|
46981
|
+
return own.length + shared.length === 0 ? `${message} ${NOTHING_TO_SHARE}` : message;
|
|
46605
46982
|
}
|
|
46606
46983
|
async function unpublishedDigest() {
|
|
46607
46984
|
const state = await readSyncState();
|
|
46608
46985
|
if (!state || state.write === "no-token" || state.write === "unreadable" || state.write === "denied" && now() < (state.writeCheckAt ?? 0))
|
|
46609
46986
|
return null;
|
|
46610
|
-
const
|
|
46611
|
-
const digest =
|
|
46987
|
+
const pool = await readPool();
|
|
46988
|
+
const digest = publishDigest(ownEntries(pool, await machineOrigin(), state.imported), loginsSyncEnabled() ? ownLogins(pool) : []);
|
|
46612
46989
|
return digest === state.uploadedDigest ? null : digest;
|
|
46613
46990
|
}
|
|
46614
46991
|
const engine = {
|
|
@@ -46630,7 +47007,9 @@ function createEngine(deps) {
|
|
|
46630
47007
|
creator: prior?.creator ?? false,
|
|
46631
47008
|
...prior?.owner ? { owner: prior.owner } : {},
|
|
46632
47009
|
imported: prior?.imported ?? newRefs(),
|
|
46633
|
-
skipped: prior?.skipped ?? newMap()
|
|
47010
|
+
skipped: prior?.skipped ?? newMap(),
|
|
47011
|
+
...prior?.loginKnown ? { loginKnown: prior.loginKnown } : {},
|
|
47012
|
+
...prior?.loginSuppressed ? { loginSuppressed: prior.loginSuppressed } : {}
|
|
46634
47013
|
};
|
|
46635
47014
|
});
|
|
46636
47015
|
return settle(cycle(false), reqAt, true);
|
|
@@ -46657,6 +47036,7 @@ function createEngine(deps) {
|
|
|
46657
47036
|
};
|
|
46658
47037
|
return engine;
|
|
46659
47038
|
}
|
|
47039
|
+
var NOTHING_TO_SHARE = "No static credential or shareable OAuth login on this machine.";
|
|
46660
47040
|
var init_engine = __esm(() => {
|
|
46661
47041
|
init_store();
|
|
46662
47042
|
init_crypto();
|
|
@@ -46664,6 +47044,7 @@ var init_engine = __esm(() => {
|
|
|
46664
47044
|
init_errors6();
|
|
46665
47045
|
init_gist();
|
|
46666
47046
|
init_github_auth();
|
|
47047
|
+
init_logins();
|
|
46667
47048
|
init_origin();
|
|
46668
47049
|
init_own();
|
|
46669
47050
|
init_payload();
|
|
@@ -46671,6 +47052,47 @@ var init_engine = __esm(() => {
|
|
|
46671
47052
|
init_timing();
|
|
46672
47053
|
});
|
|
46673
47054
|
|
|
47055
|
+
// src/sync/login-hooks.ts
|
|
47056
|
+
function createPullLogin(runGh) {
|
|
47057
|
+
return async function pullLogin(account, _recovery) {
|
|
47058
|
+
const { providerID, accountId } = account;
|
|
47059
|
+
if (!syncEnabled() || !loginsSyncEnabled())
|
|
47060
|
+
return false;
|
|
47061
|
+
if (!LOGIN_PROVIDERS.has(providerID) || !accountId || !account.refresh)
|
|
47062
|
+
return false;
|
|
47063
|
+
try {
|
|
47064
|
+
const state = await readSyncState();
|
|
47065
|
+
if (!state)
|
|
47066
|
+
return false;
|
|
47067
|
+
const token = await discoverGithubToken(runGh) ?? undefined;
|
|
47068
|
+
const read = await readGist(state.gistId, undefined, Date.now(), token);
|
|
47069
|
+
if (!read.changed)
|
|
47070
|
+
return false;
|
|
47071
|
+
const key = decodeKey(state.key) ?? Buffer.alloc(32);
|
|
47072
|
+
const wanted = loginKey(providerID, accountId);
|
|
47073
|
+
const login = parsePayload(open2(read.content, key)).logins.find((l) => l.key === wanted);
|
|
47074
|
+
if (!login || !sameLogin(account, login))
|
|
47075
|
+
return false;
|
|
47076
|
+
if (compareLogins(login, versionOf(account)) <= 0)
|
|
47077
|
+
return false;
|
|
47078
|
+
return await overwriteLocked(account, login);
|
|
47079
|
+
} catch {
|
|
47080
|
+
return false;
|
|
47081
|
+
}
|
|
47082
|
+
};
|
|
47083
|
+
}
|
|
47084
|
+
var pullLogin;
|
|
47085
|
+
var init_login_hooks = __esm(() => {
|
|
47086
|
+
init_crypto();
|
|
47087
|
+
init_gist();
|
|
47088
|
+
init_github_auth();
|
|
47089
|
+
init_login_payload();
|
|
47090
|
+
init_logins();
|
|
47091
|
+
init_payload();
|
|
47092
|
+
init_state();
|
|
47093
|
+
pullLogin = createPullLogin();
|
|
47094
|
+
});
|
|
47095
|
+
|
|
46674
47096
|
// src/sync/intent.ts
|
|
46675
47097
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
46676
47098
|
import { access, readFile as readFile7, rename as rename2, rm as rm3 } from "node:fs/promises";
|
|
@@ -46872,10 +47294,6 @@ var init_loop = __esm(() => {
|
|
|
46872
47294
|
});
|
|
46873
47295
|
|
|
46874
47296
|
// 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
47297
|
function startSync() {
|
|
46880
47298
|
if (!syncEnabled())
|
|
46881
47299
|
return null;
|
|
@@ -46884,11 +47302,45 @@ function startSync() {
|
|
|
46884
47302
|
now: Date.now
|
|
46885
47303
|
});
|
|
46886
47304
|
loop.start();
|
|
46887
|
-
|
|
47305
|
+
if (!loginsSyncEnabled())
|
|
47306
|
+
return loop;
|
|
47307
|
+
setRefreshHooks({
|
|
47308
|
+
pull: pullLogin,
|
|
47309
|
+
afterRefresh: () => void publishAfterLogin().catch(ignore)
|
|
47310
|
+
});
|
|
47311
|
+
return {
|
|
47312
|
+
...loop,
|
|
47313
|
+
dispose() {
|
|
47314
|
+
setRefreshHooks(null);
|
|
47315
|
+
return loop.dispose();
|
|
47316
|
+
}
|
|
47317
|
+
};
|
|
46888
47318
|
}
|
|
47319
|
+
async function publishAfterLogin(options = {}) {
|
|
47320
|
+
const { engine = createEngine({ now: Date.now }) } = options;
|
|
47321
|
+
const { timeoutMs = LOGIN_PUBLISH_MS } = options;
|
|
47322
|
+
let timer;
|
|
47323
|
+
const publish = async () => {
|
|
47324
|
+
if (!syncEnabled() || !loginsSyncEnabled() || !await readSyncState())
|
|
47325
|
+
return;
|
|
47326
|
+
await withCycleLock(() => engine.sync(), timeoutMs);
|
|
47327
|
+
};
|
|
47328
|
+
await Promise.race([
|
|
47329
|
+
publish().catch(ignore),
|
|
47330
|
+
new Promise((resolve) => {
|
|
47331
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
47332
|
+
})
|
|
47333
|
+
]);
|
|
47334
|
+
clearTimeout(timer);
|
|
47335
|
+
}
|
|
47336
|
+
var LOGIN_PUBLISH_MS = 20000;
|
|
46889
47337
|
var init_start = __esm(() => {
|
|
47338
|
+
init_util4();
|
|
46890
47339
|
init_engine();
|
|
47340
|
+
init_login_hooks();
|
|
47341
|
+
init_logins();
|
|
46891
47342
|
init_loop();
|
|
47343
|
+
init_state();
|
|
46892
47344
|
});
|
|
46893
47345
|
|
|
46894
47346
|
// src/legacy.ts
|
|
@@ -46916,6 +47368,8 @@ function buildAuthHook(adapter, client, pending) {
|
|
|
46916
47368
|
if (minted || account.inferenceToken !== undefined && account.refresh)
|
|
46917
47369
|
notifyPaired(client, adapter.id, account);
|
|
46918
47370
|
await refreshUsageInBackground(adapter, Date.now()).catch(ignore);
|
|
47371
|
+
if (tokens.refresh && !tokens.inferenceOnly)
|
|
47372
|
+
await publishAfterLogin();
|
|
46919
47373
|
};
|
|
46920
47374
|
const oauthSuccess = (tokens) => ({
|
|
46921
47375
|
type: "success",
|