@cortexkit/anthropic-auth-core 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +335 -77
- package/dist/internal-types/quota/codec.d.ts +2 -0
- package/dist/internal-types/quota/index.d.ts +2 -2
- package/dist/internal-types/quota/map.d.ts +11 -0
- package/dist/internal-types/quota/merge.d.ts +3 -1
- package/dist/internal-types/quota/projection.d.ts +2 -1
- package/dist/internal-types/store/schema.d.ts +2 -0
- package/dist/native-account-view.d.ts +3 -1
- package/dist/pool-authority.d.ts +1 -1
- package/dist/sticky-routing.d.ts +3 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -8042,7 +8042,8 @@ function parseEntry(raw, codec) {
|
|
|
8042
8042
|
return;
|
|
8043
8043
|
if ("disabledReason" in raw && typeof raw.disabledReason !== "string")
|
|
8044
8044
|
return;
|
|
8045
|
-
|
|
8045
|
+
const quota = "quota" in raw && codec.decode ? codec.decode(raw.quota) : raw.quota;
|
|
8046
|
+
if ("quota" in raw && !codec.validate(quota))
|
|
8046
8047
|
return;
|
|
8047
8048
|
if ("staged" in raw && !parseReservation(raw.staged))
|
|
8048
8049
|
return;
|
|
@@ -8050,7 +8051,7 @@ function parseEntry(raw, codec) {
|
|
|
8050
8051
|
credentialEpoch: epoch,
|
|
8051
8052
|
needsFirstReading: raw.needsFirstReading === true,
|
|
8052
8053
|
...typeof raw.disabledReason === "string" ? { disabledReason: raw.disabledReason } : {},
|
|
8053
|
-
..."quota" in raw ? { quota
|
|
8054
|
+
..."quota" in raw ? { quota } : {}
|
|
8054
8055
|
};
|
|
8055
8056
|
}
|
|
8056
8057
|
function credentialFor(raw, stateEntry) {
|
|
@@ -10701,6 +10702,29 @@ function isCreditBudgetEntry(value) {
|
|
|
10701
10702
|
return true;
|
|
10702
10703
|
return value.kind === "reading" && typeof value.reached === "boolean" && optional(value, "remainingPercent", isFiniteNumber) && optional(value, "usedPercent", isFiniteNumber) && optional(value, "resetsAt", isString) && optional(value, "limit", isFiniteNumber) && optional(value, "used", isFiniteNumber) && optional(value, "remaining", isFiniteNumber) && optional(value, "unit", isString);
|
|
10703
10704
|
}
|
|
10705
|
+
function isQuotaCounter(value) {
|
|
10706
|
+
return isRecord6(value) && isFiniteNumber(value.value) && Number.isInteger(value.value) && value.value >= 0 && isFiniteNumber(value.checkedAt);
|
|
10707
|
+
}
|
|
10708
|
+
function isQuotaCounters(value) {
|
|
10709
|
+
return isRecord6(value) && Object.values(value).every(isQuotaCounter);
|
|
10710
|
+
}
|
|
10711
|
+
function readQuotaCounters(value) {
|
|
10712
|
+
if (!isRecord6(value))
|
|
10713
|
+
return;
|
|
10714
|
+
const entries = Object.entries(value).filter(([, entry]) => isQuotaCounter(entry));
|
|
10715
|
+
return entries.length === 0 ? undefined : Object.fromEntries(entries);
|
|
10716
|
+
}
|
|
10717
|
+
function decodeQuotaMap(value) {
|
|
10718
|
+
if (isQuotaMap(value))
|
|
10719
|
+
return value;
|
|
10720
|
+
if (!isRecord6(value))
|
|
10721
|
+
return;
|
|
10722
|
+
const { counters: rawCounters, ...rest } = value;
|
|
10723
|
+
if (!isQuotaMap(rest))
|
|
10724
|
+
return;
|
|
10725
|
+
const counters = readQuotaCounters(rawCounters);
|
|
10726
|
+
return { ...rest, ...counters === undefined ? {} : { counters } };
|
|
10727
|
+
}
|
|
10704
10728
|
function isQuotaMap(value) {
|
|
10705
10729
|
if (!isRecord6(value) || !Array.isArray(value.limits))
|
|
10706
10730
|
return false;
|
|
@@ -10713,7 +10737,7 @@ function isQuotaMap(value) {
|
|
|
10713
10737
|
return false;
|
|
10714
10738
|
seen.add(key);
|
|
10715
10739
|
}
|
|
10716
|
-
return optional(value, "budget", isCreditBudgetEntry);
|
|
10740
|
+
return optional(value, "budget", isCreditBudgetEntry) && optional(value, "counters", isQuotaCounters);
|
|
10717
10741
|
}
|
|
10718
10742
|
|
|
10719
10743
|
// ../../node_modules/@cortexkit/common-auth/dist/quota/merge.js
|
|
@@ -10772,7 +10796,7 @@ function isQuotaObservation(value) {
|
|
|
10772
10796
|
}
|
|
10773
10797
|
if (!coverage.every(isObservedPair))
|
|
10774
10798
|
return false;
|
|
10775
|
-
return value.budget === undefined || isObservedBudget(value.budget);
|
|
10799
|
+
return (value.budget === undefined || isObservedBudget(value.budget)) && (value.counters === undefined || isQuotaCounters(value.counters));
|
|
10776
10800
|
}
|
|
10777
10801
|
function compareEntries(left, right) {
|
|
10778
10802
|
if (left.scope !== right.scope)
|
|
@@ -10788,14 +10812,25 @@ function mergeBudget(stored, observed, checkedAt) {
|
|
|
10788
10812
|
return stored;
|
|
10789
10813
|
return { ...observed, checkedAt };
|
|
10790
10814
|
}
|
|
10815
|
+
function mergeCounters(stored, observed) {
|
|
10816
|
+
const counters = new Map(Object.entries(stored ?? {}));
|
|
10817
|
+
for (const [name, counter] of Object.entries(observed ?? {})) {
|
|
10818
|
+
const existing = counters.get(name);
|
|
10819
|
+
if (existing === undefined || counter.checkedAt >= existing.checkedAt) {
|
|
10820
|
+
counters.set(name, counter);
|
|
10821
|
+
}
|
|
10822
|
+
}
|
|
10823
|
+
return counters.size === 0 ? undefined : Object.fromEntries(counters);
|
|
10824
|
+
}
|
|
10791
10825
|
function mergeQuotaObservation(stored, observation) {
|
|
10792
|
-
|
|
10826
|
+
const decoded = stored === undefined ? undefined : decodeQuotaMap(stored);
|
|
10827
|
+
if (stored !== undefined && decoded === undefined) {
|
|
10793
10828
|
throw new QuotaCodecError("stored quota map is malformed");
|
|
10794
10829
|
}
|
|
10795
10830
|
if (!isQuotaObservation(observation)) {
|
|
10796
10831
|
throw new QuotaCodecError("quota observation is malformed");
|
|
10797
10832
|
}
|
|
10798
|
-
const base =
|
|
10833
|
+
const base = decoded ?? { limits: [] };
|
|
10799
10834
|
const at = observation.checkedAt;
|
|
10800
10835
|
const entries = new Map;
|
|
10801
10836
|
for (const entry of base.limits) {
|
|
@@ -10830,18 +10865,21 @@ function mergeQuotaObservation(stored, observation) {
|
|
|
10830
10865
|
const existing = entries.get(key);
|
|
10831
10866
|
entries.set(key, existing === undefined || existing.kind === "absent" ? { scope, label: pair.label, kind: "absent", checkedAt: at } : { scope, label: pair.label, kind: "retired", retiredAt: at });
|
|
10832
10867
|
}
|
|
10833
|
-
const { limits: _limits, budget: _budget, ...unknownKeys } = base;
|
|
10868
|
+
const { limits: _limits, budget: _budget, counters: _counters, ...unknownKeys } = base;
|
|
10834
10869
|
const budget = mergeBudget(base.budget, observation.budget, at);
|
|
10870
|
+
const counters = mergeCounters(base.counters, observation.counters);
|
|
10835
10871
|
return {
|
|
10836
10872
|
...unknownKeys,
|
|
10837
10873
|
limits: [...entries.values()].sort(compareEntries),
|
|
10838
|
-
...budget === undefined ? {} : { budget }
|
|
10874
|
+
...budget === undefined ? {} : { budget },
|
|
10875
|
+
...counters === undefined ? {} : { counters }
|
|
10839
10876
|
};
|
|
10840
10877
|
}
|
|
10841
10878
|
|
|
10842
10879
|
// ../../node_modules/@cortexkit/common-auth/dist/quota/codec.js
|
|
10843
10880
|
var quotaCodec = Object.freeze({
|
|
10844
10881
|
validate: isQuotaMap,
|
|
10882
|
+
decode: decodeQuotaMap,
|
|
10845
10883
|
merge: mergeQuotaObservation
|
|
10846
10884
|
});
|
|
10847
10885
|
// ../../node_modules/@cortexkit/common-auth/dist/quota/format.js
|
|
@@ -13305,11 +13343,103 @@ function logCommittedNativeAccountAdded(account) {
|
|
|
13305
13343
|
|
|
13306
13344
|
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/index.js
|
|
13307
13345
|
import { ClaustrumClient } from "@cortexkit/claustrum-client";
|
|
13346
|
+
|
|
13347
|
+
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/insula.js
|
|
13348
|
+
import { resolve as resolve4 } from "node:path";
|
|
13349
|
+
import { storeIdentity } from "@cortexkit/claustrum-client";
|
|
13350
|
+
import { SubcClient } from "@cortexkit/subc-client";
|
|
13351
|
+
var MINUTE = 60000;
|
|
13352
|
+
var MAX_AGE = 4 * MINUTE;
|
|
13353
|
+
var sources = new Map;
|
|
13354
|
+
var attempts = new Map;
|
|
13355
|
+
function record7(value) {
|
|
13356
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13357
|
+
}
|
|
13358
|
+
|
|
13359
|
+
class InsulaQuotaSource {
|
|
13360
|
+
transport;
|
|
13361
|
+
key;
|
|
13362
|
+
#entries = [];
|
|
13363
|
+
#pending;
|
|
13364
|
+
constructor(transport, key) {
|
|
13365
|
+
this.transport = transport;
|
|
13366
|
+
this.key = key;
|
|
13367
|
+
}
|
|
13368
|
+
refresh(now) {
|
|
13369
|
+
if (this.#pending)
|
|
13370
|
+
return this.#pending;
|
|
13371
|
+
for (const [key, time4] of attempts) {
|
|
13372
|
+
if (now - time4 >= MINUTE)
|
|
13373
|
+
attempts.delete(key);
|
|
13374
|
+
}
|
|
13375
|
+
const lastAttempt = attempts.get(this.key);
|
|
13376
|
+
if (lastAttempt !== undefined && now - lastAttempt < MINUTE)
|
|
13377
|
+
return Promise.resolve();
|
|
13378
|
+
attempts.set(this.key, now);
|
|
13379
|
+
this.#pending = (async () => {
|
|
13380
|
+
try {
|
|
13381
|
+
const reply = await this.transport.getUsage();
|
|
13382
|
+
if (!record7(reply) || !Array.isArray(reply.result) || reply.error !== undefined)
|
|
13383
|
+
throw new Error("unavailable insula usage");
|
|
13384
|
+
this.#entries = reply.result.filter((entry2) => record7(entry2) && typeof entry2.provider === "string");
|
|
13385
|
+
} catch {
|
|
13386
|
+
this.#entries = [];
|
|
13387
|
+
}
|
|
13388
|
+
})().finally(() => {
|
|
13389
|
+
this.#pending = undefined;
|
|
13390
|
+
});
|
|
13391
|
+
return this.#pending;
|
|
13392
|
+
}
|
|
13393
|
+
current(provider, accountId, now) {
|
|
13394
|
+
for (const entry2 of this.#entries) {
|
|
13395
|
+
if (entry2.provider !== provider || typeof entry2.account !== "string" || entry2.account.trim() !== accountId)
|
|
13396
|
+
continue;
|
|
13397
|
+
if (entry2.stale !== undefined || entry2.errorClass !== undefined || !record7(entry2.usage))
|
|
13398
|
+
continue;
|
|
13399
|
+
const fetchedAt = typeof entry2.fetchedAt === "string" ? Date.parse(entry2.fetchedAt) : Number.NaN;
|
|
13400
|
+
if (!Number.isFinite(fetchedAt) || now - fetchedAt >= MAX_AGE)
|
|
13401
|
+
continue;
|
|
13402
|
+
return {
|
|
13403
|
+
entry: entry2,
|
|
13404
|
+
context: {
|
|
13405
|
+
fetchedAt,
|
|
13406
|
+
...typeof entry2.source === "string" && { source: entry2.source }
|
|
13407
|
+
}
|
|
13408
|
+
};
|
|
13409
|
+
}
|
|
13410
|
+
return;
|
|
13411
|
+
}
|
|
13412
|
+
}
|
|
13413
|
+
function acquireInsulaQuotaSource(transport, tokenPath) {
|
|
13414
|
+
const key = JSON.stringify([
|
|
13415
|
+
resolve4(transport.connectionFile),
|
|
13416
|
+
resolve4(tokenPath)
|
|
13417
|
+
]);
|
|
13418
|
+
let shared = sources.get(key);
|
|
13419
|
+
if (!shared) {
|
|
13420
|
+
shared = { source: new InsulaQuotaSource(transport, key), refs: 0 };
|
|
13421
|
+
sources.set(key, shared);
|
|
13422
|
+
}
|
|
13423
|
+
shared.refs++;
|
|
13424
|
+
let released = false;
|
|
13425
|
+
return {
|
|
13426
|
+
source: shared.source,
|
|
13427
|
+
release() {
|
|
13428
|
+
if (released)
|
|
13429
|
+
return;
|
|
13430
|
+
released = true;
|
|
13431
|
+
if (--shared.refs === 0)
|
|
13432
|
+
sources.delete(key);
|
|
13433
|
+
}
|
|
13434
|
+
};
|
|
13435
|
+
}
|
|
13436
|
+
|
|
13437
|
+
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/index.js
|
|
13308
13438
|
import { ClaustrumCredentialError as ClaustrumCredentialError4 } from "@cortexkit/claustrum-client";
|
|
13309
13439
|
// ../../node_modules/@cortexkit/common-auth/dist/logger/engine.js
|
|
13310
13440
|
import { appendFileSync as appendFileSync2, chmodSync, existsSync as existsSync2, renameSync as renameSync2, statSync as statSync3 } from "node:fs";
|
|
13311
13441
|
import { open as open5 } from "node:fs/promises";
|
|
13312
|
-
import { dirname as dirname7, resolve as
|
|
13442
|
+
import { dirname as dirname7, resolve as resolve5 } from "node:path";
|
|
13313
13443
|
|
|
13314
13444
|
// ../../node_modules/@cortexkit/common-auth/dist/logger/redact.js
|
|
13315
13445
|
var SECRET_KEY_EXACT2 = /^(authorization|x-api-key|cookie|set-cookie|refresh|access|token)$/i;
|
|
@@ -13432,7 +13562,7 @@ async function openWindowsFile(sink, file) {
|
|
|
13432
13562
|
return sink.handle;
|
|
13433
13563
|
}
|
|
13434
13564
|
async function flushWindowsFile(sink, file, text4) {
|
|
13435
|
-
file =
|
|
13565
|
+
file = resolve5(file);
|
|
13436
13566
|
try {
|
|
13437
13567
|
if (sink.file !== file)
|
|
13438
13568
|
await closeWindowsFile(sink);
|
|
@@ -13685,7 +13815,7 @@ import { ClaustrumCredentialError as ClaustrumCredentialError3 } from "@cortexki
|
|
|
13685
13815
|
import { createHash as createHash11, randomBytes as randomBytes4, randomUUID as randomUUID11 } from "node:crypto";
|
|
13686
13816
|
import { constants as fsConstants2 } from "node:fs";
|
|
13687
13817
|
import { chmod as chmod2, mkdir as mkdir8, open as open6, readFile as readFile8, realpath as realpath2, rename as rename9, stat as stat4, unlink as unlink4 } from "node:fs/promises";
|
|
13688
|
-
import { basename as basename3, dirname as dirname8, extname as extname2, isAbsolute as isAbsolute3, join as join9, resolve as
|
|
13818
|
+
import { basename as basename3, dirname as dirname8, extname as extname2, isAbsolute as isAbsolute3, join as join9, resolve as resolve6 } from "node:path";
|
|
13689
13819
|
import { ClaustrumCredentialError as ClaustrumCredentialError2, ClaustrumClient as ClaustrumWireClient2, writeEnrollmentTokenFile as writeEnrollmentTokenFile2 } from "@cortexkit/claustrum-client";
|
|
13690
13820
|
|
|
13691
13821
|
// ../../node_modules/@cortexkit/common-auth/dist/claustrum/errors.js
|
|
@@ -14361,8 +14491,8 @@ function accessTokenFromMaterial(material) {
|
|
|
14361
14491
|
}
|
|
14362
14492
|
if (!parsed || typeof parsed !== "object")
|
|
14363
14493
|
throw invalidMaterial();
|
|
14364
|
-
const
|
|
14365
|
-
const value =
|
|
14494
|
+
const record8 = parsed;
|
|
14495
|
+
const value = record8.access_token ?? record8.access;
|
|
14366
14496
|
access = typeof value === "string" ? value : "";
|
|
14367
14497
|
}
|
|
14368
14498
|
if (!/^[\x21-\x7e]+$/.test(access) || access.startsWith(CUSTODY_PLACEHOLDER_PREFIX)) {
|
|
@@ -14489,8 +14619,8 @@ class ClaustrumScopedCustody {
|
|
|
14489
14619
|
...row.orgName !== undefined && { orgName: row.orgName }
|
|
14490
14620
|
}));
|
|
14491
14621
|
}
|
|
14492
|
-
for (const
|
|
14493
|
-
this.#logger.warn("skipped malformed vault record",
|
|
14622
|
+
for (const record8 of skipped)
|
|
14623
|
+
this.#logger.warn("skipped malformed vault record", record8);
|
|
14494
14624
|
return {
|
|
14495
14625
|
view: inventory.view,
|
|
14496
14626
|
credentials: Object.freeze(credentials),
|
|
@@ -14640,8 +14770,8 @@ function projectVaultRoster(previous, inventory, options = {}) {
|
|
|
14640
14770
|
const declined = [...previous?.declined ?? []];
|
|
14641
14771
|
const complete = inventory.skipped.length === 0;
|
|
14642
14772
|
const listed = new Set(inventory.credentials.map((credential2) => credential2.credentialId));
|
|
14643
|
-
const rejectedIds = new Set(inventory.skipped.flatMap((
|
|
14644
|
-
const unrecoverable = inventory.skipped.some((
|
|
14773
|
+
const rejectedIds = new Set(inventory.skipped.flatMap((record8) => record8.credentialId === undefined ? [] : [record8.credentialId]));
|
|
14774
|
+
const unrecoverable = inventory.skipped.some((record8) => record8.credentialId === undefined);
|
|
14645
14775
|
const unaccounted = (id2) => !listed.has(id2) && (rejectedIds.has(id2) || unrecoverable);
|
|
14646
14776
|
const lastKnown = new Map;
|
|
14647
14777
|
for (const row of previousRows) {
|
|
@@ -14748,11 +14878,11 @@ function projectVaultRoster(previous, inventory, options = {}) {
|
|
|
14748
14878
|
view: inventory.view,
|
|
14749
14879
|
complete,
|
|
14750
14880
|
...!complete && {
|
|
14751
|
-
rejected: inventory.skipped.map((
|
|
14752
|
-
...
|
|
14753
|
-
credentialId:
|
|
14881
|
+
rejected: inventory.skipped.map((record8) => ({
|
|
14882
|
+
...record8.credentialId !== undefined && {
|
|
14883
|
+
credentialId: record8.credentialId
|
|
14754
14884
|
},
|
|
14755
|
-
reason:
|
|
14885
|
+
reason: record8.reason
|
|
14756
14886
|
}))
|
|
14757
14887
|
},
|
|
14758
14888
|
rows: projected.map((entry2) => entry2.row),
|
|
@@ -14773,9 +14903,13 @@ function optionalString2(value) {
|
|
|
14773
14903
|
return value === undefined || typeof value === "string";
|
|
14774
14904
|
}
|
|
14775
14905
|
function decodeRow(value) {
|
|
14776
|
-
|
|
14906
|
+
const quota2 = isRecord9(value) ? decodeQuotaMap(value.quota) : undefined;
|
|
14907
|
+
if (!isRecord9(value) || typeof value.routeId !== "string" || typeof value.credentialId !== "string" || value.credentialType !== "oauth" && value.credentialType !== "api_key" || typeof value.state !== "string" || typeof value.label !== "string" || typeof value.enabled !== "boolean" || typeof value.addedAt !== "number" || !optionalString2(value.accountIdentity) || !optionalString2(value.email) || !optionalString2(value.orgName) || value.aliases !== undefined && (!Array.isArray(value.aliases) || !value.aliases.every((alias) => typeof alias === "string")) || value.quota !== undefined && quota2 === undefined || value.stale !== undefined && value.stale !== true || value.unclaimed !== undefined && value.unclaimed !== true)
|
|
14777
14908
|
return;
|
|
14778
|
-
return
|
|
14909
|
+
return {
|
|
14910
|
+
...value,
|
|
14911
|
+
...quota2 === undefined ? {} : { quota: quota2 }
|
|
14912
|
+
};
|
|
14779
14913
|
}
|
|
14780
14914
|
var SKIPPED_REASONS = new Set([
|
|
14781
14915
|
"empty credential id",
|
|
@@ -14920,6 +15054,21 @@ function recordVaultQuota(path2, input) {
|
|
|
14920
15054
|
};
|
|
14921
15055
|
});
|
|
14922
15056
|
}
|
|
15057
|
+
function recordVaultAccountQuota(path2, input) {
|
|
15058
|
+
return mutateVaultRoster(path2, (current) => {
|
|
15059
|
+
const row = current?.rows.find((entry2) => entry2.routeId === input.routeId);
|
|
15060
|
+
if (!current || !row || row.accountIdentity === undefined || row.accountIdentity !== input.accountIdentity)
|
|
15061
|
+
return { result: false };
|
|
15062
|
+
const quota2 = mergeQuotaObservation(row.quota, input.observation);
|
|
15063
|
+
return {
|
|
15064
|
+
next: {
|
|
15065
|
+
...current,
|
|
15066
|
+
rows: current.rows.map((entry2) => entry2 === row ? { ...entry2, quota: quota2 } : entry2)
|
|
15067
|
+
},
|
|
15068
|
+
result: true
|
|
15069
|
+
};
|
|
15070
|
+
});
|
|
15071
|
+
}
|
|
14923
15072
|
async function refreshVaultRoster(options) {
|
|
14924
15073
|
options.signal?.throwIfAborted();
|
|
14925
15074
|
const active = async () => await options.isActive?.() ?? true;
|
|
@@ -14966,6 +15115,7 @@ class ClaustrumConsumer {
|
|
|
14966
15115
|
#roster;
|
|
14967
15116
|
#timer;
|
|
14968
15117
|
#started = false;
|
|
15118
|
+
#insula;
|
|
14969
15119
|
constructor(options) {
|
|
14970
15120
|
this.#options = options;
|
|
14971
15121
|
this.#logger = options.logger ?? createLogger("claustrum");
|
|
@@ -14982,7 +15132,7 @@ class ClaustrumConsumer {
|
|
|
14982
15132
|
this.#shutdown.signal,
|
|
14983
15133
|
...signal ? [signal] : []
|
|
14984
15134
|
]);
|
|
14985
|
-
return new Promise((
|
|
15135
|
+
return new Promise((resolve7, reject) => {
|
|
14986
15136
|
const cleanup2 = () => {
|
|
14987
15137
|
combined.signal.removeEventListener("abort", abort);
|
|
14988
15138
|
combined.dispose();
|
|
@@ -14997,7 +15147,7 @@ class ClaustrumConsumer {
|
|
|
14997
15147
|
if (combined.signal.aborted)
|
|
14998
15148
|
reject(combined.signal.reason);
|
|
14999
15149
|
else
|
|
15000
|
-
|
|
15150
|
+
resolve7(value);
|
|
15001
15151
|
}, (error) => {
|
|
15002
15152
|
cleanup2();
|
|
15003
15153
|
reject(error);
|
|
@@ -15025,6 +15175,9 @@ class ClaustrumConsumer {
|
|
|
15025
15175
|
now: this.#options.now,
|
|
15026
15176
|
logger: this.#logger
|
|
15027
15177
|
});
|
|
15178
|
+
if (this.#options.insula && client.insula) {
|
|
15179
|
+
this.#insula = acquireInsulaQuotaSource(client.insula, this.#options.tokenPath);
|
|
15180
|
+
}
|
|
15028
15181
|
return this.#custody;
|
|
15029
15182
|
}).finally(() => {
|
|
15030
15183
|
this.#connecting = undefined;
|
|
@@ -15047,6 +15200,8 @@ class ClaustrumConsumer {
|
|
|
15047
15200
|
this.#roster = undefined;
|
|
15048
15201
|
this.#custody?.close();
|
|
15049
15202
|
this.#custody = undefined;
|
|
15203
|
+
this.#insula?.release();
|
|
15204
|
+
this.#insula = undefined;
|
|
15050
15205
|
return;
|
|
15051
15206
|
}
|
|
15052
15207
|
const custody = await this.#getCustody();
|
|
@@ -15081,6 +15236,7 @@ class ClaustrumConsumer {
|
|
|
15081
15236
|
const tick = async () => {
|
|
15082
15237
|
try {
|
|
15083
15238
|
await this.refresh();
|
|
15239
|
+
await this.refreshInsulaQuota();
|
|
15084
15240
|
} catch (error) {
|
|
15085
15241
|
if (!this.#shutdown.signal.aborted)
|
|
15086
15242
|
this.#options.onError?.(error);
|
|
@@ -15098,6 +15254,43 @@ class ClaustrumConsumer {
|
|
|
15098
15254
|
};
|
|
15099
15255
|
tick();
|
|
15100
15256
|
}
|
|
15257
|
+
async refreshInsulaQuota() {
|
|
15258
|
+
if (!this.#options.insula || this.#shutdown.signal.aborted || !await this.#active())
|
|
15259
|
+
return;
|
|
15260
|
+
try {
|
|
15261
|
+
await readClaustrumEnrollmentToken2(this.#options.tokenPath);
|
|
15262
|
+
await this.#getCustody();
|
|
15263
|
+
await this.#insula?.source.refresh((this.#options.now ?? Date.now)());
|
|
15264
|
+
} catch {}
|
|
15265
|
+
}
|
|
15266
|
+
async cachedInsulaQuota(receipt) {
|
|
15267
|
+
if (!this.#options.insula || this.#shutdown.signal.aborted || !await this.#active())
|
|
15268
|
+
return;
|
|
15269
|
+
try {
|
|
15270
|
+
await readClaustrumEnrollmentToken2(this.#options.tokenPath);
|
|
15271
|
+
return this.#normalizeInsulaQuota(receipt.assertedAccountIdentity);
|
|
15272
|
+
} catch {
|
|
15273
|
+
return;
|
|
15274
|
+
}
|
|
15275
|
+
}
|
|
15276
|
+
async cachedInsulaQuotaForRoute(routeId) {
|
|
15277
|
+
if (!this.#options.insula || this.#shutdown.signal.aborted || !await this.#active())
|
|
15278
|
+
return;
|
|
15279
|
+
try {
|
|
15280
|
+
await readClaustrumEnrollmentToken2(this.#options.tokenPath);
|
|
15281
|
+
const roster = await readVaultRoster(this.#options.rosterPath);
|
|
15282
|
+
const row = roster?.rows.find((entry2) => entry2.routeId === routeId);
|
|
15283
|
+
return this.#normalizeInsulaQuota(row?.accountIdentity);
|
|
15284
|
+
} catch {
|
|
15285
|
+
return;
|
|
15286
|
+
}
|
|
15287
|
+
}
|
|
15288
|
+
#normalizeInsulaQuota(accountIdentity) {
|
|
15289
|
+
if (!this.#options.insula || !accountIdentity)
|
|
15290
|
+
return;
|
|
15291
|
+
const current = this.#insula?.source.current(this.#options.insula.provider, accountIdentity, (this.#options.now ?? Date.now)());
|
|
15292
|
+
return current ? this.#options.insula.normalize(current.entry, current.context) : undefined;
|
|
15293
|
+
}
|
|
15101
15294
|
async authorize(routeId, signal) {
|
|
15102
15295
|
this.#assertOpen(signal);
|
|
15103
15296
|
const roster = this.#roster ?? await this.#wait(this.refresh(), signal);
|
|
@@ -15186,6 +15379,17 @@ class ClaustrumConsumer {
|
|
|
15186
15379
|
this.#roster = await readVaultRoster(this.#options.rosterPath);
|
|
15187
15380
|
return kept;
|
|
15188
15381
|
}
|
|
15382
|
+
async recordAccountQuota(routeId, accountIdentity, observation) {
|
|
15383
|
+
this.#assertOpen();
|
|
15384
|
+
const kept = await recordVaultAccountQuota(this.#options.rosterPath, {
|
|
15385
|
+
routeId,
|
|
15386
|
+
accountIdentity,
|
|
15387
|
+
observation
|
|
15388
|
+
});
|
|
15389
|
+
if (kept)
|
|
15390
|
+
this.#roster = await readVaultRoster(this.#options.rosterPath);
|
|
15391
|
+
return kept;
|
|
15392
|
+
}
|
|
15189
15393
|
close() {
|
|
15190
15394
|
if (this.#shutdown.signal.aborted)
|
|
15191
15395
|
return;
|
|
@@ -15194,6 +15398,8 @@ class ClaustrumConsumer {
|
|
|
15194
15398
|
(this.#options.clearTimeoutImpl ?? clearTimeout)(this.#timer);
|
|
15195
15399
|
this.#timer = undefined;
|
|
15196
15400
|
this.#custody?.close();
|
|
15401
|
+
this.#insula?.release();
|
|
15402
|
+
this.#insula = undefined;
|
|
15197
15403
|
this.#roster = undefined;
|
|
15198
15404
|
}
|
|
15199
15405
|
}
|
|
@@ -15715,7 +15921,7 @@ function createNativeRefreshCoordinator(options) {
|
|
|
15715
15921
|
name: spec.name,
|
|
15716
15922
|
timeoutMs: POOL_LOCK_DEFAULTS.timeoutMs
|
|
15717
15923
|
});
|
|
15718
|
-
await new Promise((
|
|
15924
|
+
await new Promise((resolve7) => setTimeout(resolve7, Math.min(POOL_LOCK_DEFAULTS.retryMs, remaining)));
|
|
15719
15925
|
}
|
|
15720
15926
|
}
|
|
15721
15927
|
async function run(job, request) {
|
|
@@ -16579,6 +16785,7 @@ async function requireNativePoolAuthority(paths) {
|
|
|
16579
16785
|
if (!nativeMigrationAuthorityPhase(journal)) {
|
|
16580
16786
|
throw new NativeAuthorityError("migration-incomplete");
|
|
16581
16787
|
}
|
|
16788
|
+
return journal;
|
|
16582
16789
|
}
|
|
16583
16790
|
function deepFreeze(value) {
|
|
16584
16791
|
if (value === null || typeof value !== "object")
|
|
@@ -16929,7 +17136,7 @@ function createNativeLocalCredentialService(options) {
|
|
|
16929
17136
|
}
|
|
16930
17137
|
|
|
16931
17138
|
// src/native-runtime-registry.ts
|
|
16932
|
-
import { resolve as
|
|
17139
|
+
import { resolve as resolve7 } from "node:path";
|
|
16933
17140
|
var identities = new WeakMap;
|
|
16934
17141
|
var nextIdentity = 0;
|
|
16935
17142
|
function nativeRuntimeOptionIdentity(value) {
|
|
@@ -16958,14 +17165,14 @@ function nativeRuntimeStorageKey(options) {
|
|
|
16958
17165
|
"runtime",
|
|
16959
17166
|
"journal",
|
|
16960
17167
|
"roster"
|
|
16961
|
-
].map((field) =>
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
17168
|
+
].map((field) => resolve7(paths[field])),
|
|
17169
|
+
resolve7(enrollment.tokenPath),
|
|
17170
|
+
resolve7(enrollment.statePath),
|
|
17171
|
+
resolve7(connection)
|
|
16965
17172
|
]);
|
|
16966
17173
|
}
|
|
16967
17174
|
function nativeRuntimeConnectionFile(host, env) {
|
|
16968
|
-
return
|
|
17175
|
+
return resolve7(resolveClaustrumConnectionPath(host === "pi" ? env.PI_ANTHROPIC_AUTH_CLAUSTRUM_CONNECTION_FILE : undefined, host === "pi" ? {
|
|
16969
17176
|
...env,
|
|
16970
17177
|
OPENCODE_ANTHROPIC_AUTH_CLAUSTRUM_CONNECTION_FILE: undefined
|
|
16971
17178
|
} : env));
|
|
@@ -17082,12 +17289,12 @@ async function joinNativePoolWrite(paths, signals, check, now = Date.now) {
|
|
|
17082
17289
|
function pause(ms, signals) {
|
|
17083
17290
|
if (signals.some((signal) => signal.aborted))
|
|
17084
17291
|
return Promise.resolve();
|
|
17085
|
-
return new Promise((
|
|
17292
|
+
return new Promise((resolve8) => {
|
|
17086
17293
|
const wake = () => {
|
|
17087
17294
|
clearTimeout(timer);
|
|
17088
17295
|
for (const signal of signals)
|
|
17089
17296
|
signal.removeEventListener("abort", wake);
|
|
17090
|
-
|
|
17297
|
+
resolve8();
|
|
17091
17298
|
};
|
|
17092
17299
|
const timer = setTimeout(wake, ms);
|
|
17093
17300
|
for (const signal of signals)
|
|
@@ -17218,12 +17425,12 @@ function expectedSeed(input, boundary, refuse3) {
|
|
|
17218
17425
|
const inventory = capture(top("inventory", "roster-incomplete"), ["view", "credentials", "skipped"], "roster-incomplete", refuse3);
|
|
17219
17426
|
const view = inventory.view;
|
|
17220
17427
|
const skipped = items(inventory.skipped, "roster-incomplete", refuse3);
|
|
17221
|
-
const credentialRecords = items(inventory.credentials, "roster-incomplete", refuse3).map((
|
|
17428
|
+
const credentialRecords = items(inventory.credentials, "roster-incomplete", refuse3).map((record8) => capture(record8, ["credentialId", "credentialType", "accountIdentity", "state"], "roster-incomplete", refuse3));
|
|
17222
17429
|
if (!filled(view) || skipped.length > 0)
|
|
17223
17430
|
refuse3("roster-incomplete");
|
|
17224
17431
|
const listed = new Map;
|
|
17225
|
-
for (const
|
|
17226
|
-
const { credentialId, credentialType, accountIdentity, state } =
|
|
17432
|
+
for (const record8 of credentialRecords) {
|
|
17433
|
+
const { credentialId, credentialType, accountIdentity, state } = record8;
|
|
17227
17434
|
if (!filled(credentialId) || !filled(accountIdentity) || !filled(state) || listed.has(credentialId)) {
|
|
17228
17435
|
refuse3("roster-incomplete");
|
|
17229
17436
|
}
|
|
@@ -17234,7 +17441,7 @@ function expectedSeed(input, boundary, refuse3) {
|
|
|
17234
17441
|
const primaryIdentity = primary.accountIdentity;
|
|
17235
17442
|
boundary.fallback = "seed-conflict";
|
|
17236
17443
|
const primaryRouteId = top("primaryRouteId", "seed-conflict");
|
|
17237
|
-
const legacyRecords = items(top("legacyRows", "seed-conflict"), "seed-conflict", refuse3).map((
|
|
17444
|
+
const legacyRecords = items(top("legacyRows", "seed-conflict"), "seed-conflict", refuse3).map((record8) => capture(record8, [
|
|
17238
17445
|
"routeId",
|
|
17239
17446
|
"scopedCredentialId",
|
|
17240
17447
|
"anthropicAccountUuid",
|
|
@@ -18022,7 +18229,7 @@ function recencyOnly(patch) {
|
|
|
18022
18229
|
return keys4.length === 1 && keys4[0] === "lastUsed" && typeof patch.lastUsed === "number";
|
|
18023
18230
|
}
|
|
18024
18231
|
function waitFor(pending, signal) {
|
|
18025
|
-
return new Promise((
|
|
18232
|
+
return new Promise((resolve8, reject) => {
|
|
18026
18233
|
const abort = () => {
|
|
18027
18234
|
cleanup2();
|
|
18028
18235
|
reject(signal.reason);
|
|
@@ -18031,7 +18238,7 @@ function waitFor(pending, signal) {
|
|
|
18031
18238
|
signal.addEventListener("abort", abort, { once: true });
|
|
18032
18239
|
pending.then((value) => {
|
|
18033
18240
|
cleanup2();
|
|
18034
|
-
signal.aborted ? reject(signal.reason) :
|
|
18241
|
+
signal.aborted ? reject(signal.reason) : resolve8(value);
|
|
18035
18242
|
}, (error) => {
|
|
18036
18243
|
cleanup2();
|
|
18037
18244
|
reject(error);
|
|
@@ -18348,6 +18555,7 @@ function stickyRetryAfterWithJitter(sessionId, retryAfterSeconds) {
|
|
|
18348
18555
|
const hash2 = createHash16("sha256").update(sessionId).digest().readUInt32BE(0);
|
|
18349
18556
|
return Math.max(1, Math.ceil(retryAfterSeconds)) + hash2 % 21;
|
|
18350
18557
|
}
|
|
18558
|
+
var localRecoveries = new Map;
|
|
18351
18559
|
|
|
18352
18560
|
class StickySessionRouter {
|
|
18353
18561
|
options;
|
|
@@ -18408,7 +18616,7 @@ class StickySessionRouter {
|
|
|
18408
18616
|
this.stateMtimeNs = await this.readStateMtimeNs();
|
|
18409
18617
|
this.loaded = true;
|
|
18410
18618
|
}
|
|
18411
|
-
async acquireLock() {
|
|
18619
|
+
async acquireLock(wait = true) {
|
|
18412
18620
|
await mkdir9(dirname10(this.options.path), { recursive: true, mode: 448 });
|
|
18413
18621
|
const deadline = this.now() + STICKY_ROUTING_LOCK_WAIT_MS;
|
|
18414
18622
|
while (true) {
|
|
@@ -18420,10 +18628,53 @@ class StickySessionRouter {
|
|
|
18420
18628
|
});
|
|
18421
18629
|
if (lock)
|
|
18422
18630
|
return lock;
|
|
18423
|
-
if (this.now() >= deadline) {
|
|
18631
|
+
if (!wait || this.now() >= deadline) {
|
|
18424
18632
|
throw new Error("Timed out acquiring sticky routing state lock");
|
|
18425
18633
|
}
|
|
18426
|
-
await new Promise((
|
|
18634
|
+
await new Promise((resolve8) => setTimeout(resolve8, STICKY_ROUTING_LOCK_POLL_MS));
|
|
18635
|
+
}
|
|
18636
|
+
}
|
|
18637
|
+
async recoverLocalPins() {
|
|
18638
|
+
const source2 = this.options.localRecoveryPath;
|
|
18639
|
+
if (!source2 || source2 === this.options.path)
|
|
18640
|
+
return;
|
|
18641
|
+
const key = JSON.stringify([this.options.path, source2]);
|
|
18642
|
+
let recovery = localRecoveries.get(key);
|
|
18643
|
+
if (!recovery) {
|
|
18644
|
+
recovery = this.fillLocalPins(source2).catch(() => {
|
|
18645
|
+
logger.warn("sticky-routing", "local pin recovery unavailable", {
|
|
18646
|
+
reason: "recovery-failed"
|
|
18647
|
+
});
|
|
18648
|
+
});
|
|
18649
|
+
localRecoveries.set(key, recovery);
|
|
18650
|
+
}
|
|
18651
|
+
await recovery;
|
|
18652
|
+
}
|
|
18653
|
+
async fillLocalPins(source2) {
|
|
18654
|
+
const lock = await this.acquireLock(false);
|
|
18655
|
+
try {
|
|
18656
|
+
let legacy;
|
|
18657
|
+
try {
|
|
18658
|
+
legacy = normalizeState(JSON.parse(await readFile9(source2, "utf8")));
|
|
18659
|
+
} catch (error) {
|
|
18660
|
+
if (error.code === "ENOENT")
|
|
18661
|
+
return;
|
|
18662
|
+
throw error;
|
|
18663
|
+
}
|
|
18664
|
+
if (!legacy)
|
|
18665
|
+
return;
|
|
18666
|
+
const state = await this.readState();
|
|
18667
|
+
let changed = false;
|
|
18668
|
+
for (const [key, assignment] of Object.entries(legacy.assignments)) {
|
|
18669
|
+
if (!/^[0-9a-f]{64}$/.test(key) || Object.hasOwn(state.assignments, key))
|
|
18670
|
+
continue;
|
|
18671
|
+
state.assignments[key] = assignment;
|
|
18672
|
+
changed = true;
|
|
18673
|
+
}
|
|
18674
|
+
if (changed)
|
|
18675
|
+
await this.writeState(state, () => lock.assertOwned(), false);
|
|
18676
|
+
} finally {
|
|
18677
|
+
await lock.release();
|
|
18427
18678
|
}
|
|
18428
18679
|
}
|
|
18429
18680
|
assignmentIsActive(assignment) {
|
|
@@ -18586,6 +18837,7 @@ class StickySessionRouter {
|
|
|
18586
18837
|
async resolve(input) {
|
|
18587
18838
|
if (!input.sessionId)
|
|
18588
18839
|
return null;
|
|
18840
|
+
await this.recoverLocalPins();
|
|
18589
18841
|
await this.prepareLegacySeed();
|
|
18590
18842
|
await this.refreshStateIfChanged();
|
|
18591
18843
|
const key = sessionKey(input.sessionId);
|
|
@@ -18677,6 +18929,7 @@ class StickySessionRouter {
|
|
|
18677
18929
|
async clear(sessionId) {
|
|
18678
18930
|
if (!sessionId)
|
|
18679
18931
|
return;
|
|
18932
|
+
await this.recoverLocalPins();
|
|
18680
18933
|
const key = sessionKey(sessionId);
|
|
18681
18934
|
const lock = await this.acquireLock();
|
|
18682
18935
|
try {
|
|
@@ -18794,11 +19047,12 @@ function createNativeAccountRuntime(options) {
|
|
|
18794
19047
|
throw new NativeCustodyError("closed");
|
|
18795
19048
|
signal?.throwIfAborted();
|
|
18796
19049
|
}
|
|
19050
|
+
let localRouting;
|
|
18797
19051
|
async function authority(signal) {
|
|
18798
19052
|
check(signal);
|
|
18799
19053
|
let mode = await readNativeEnrollmentMode(options.host, env);
|
|
18800
19054
|
if (mode === "local") {
|
|
18801
|
-
await requireNativePoolAuthority(paths);
|
|
19055
|
+
localRouting = (await requireNativePoolAuthority(paths)).routingPaths;
|
|
18802
19056
|
mode = await readNativeEnrollmentMode(options.host, env);
|
|
18803
19057
|
}
|
|
18804
19058
|
check(signal);
|
|
@@ -18965,6 +19219,10 @@ function createNativeAccountRuntime(options) {
|
|
|
18965
19219
|
await vaultRouter.prepareLegacySeed(roster ?? null);
|
|
18966
19220
|
snapshot.routingPath = vaultPaths.routing;
|
|
18967
19221
|
snapshot.routingSeed = { ...routingSeed };
|
|
19222
|
+
} else if (localRouting) {
|
|
19223
|
+
snapshot.routingPath = localRouting.destination;
|
|
19224
|
+
if (localRouting.source !== localRouting.destination)
|
|
19225
|
+
snapshot.routingRecoveryPath = localRouting.source;
|
|
18968
19226
|
}
|
|
18969
19227
|
return {
|
|
18970
19228
|
snapshot,
|
|
@@ -19769,9 +20027,9 @@ import { dirname as dirname13, isAbsolute as isAbsolute6 } from "node:path";
|
|
|
19769
20027
|
// src/pool-paths.ts
|
|
19770
20028
|
import { createHash as createHash17 } from "node:crypto";
|
|
19771
20029
|
import { realpath as realpath3 } from "node:fs/promises";
|
|
19772
|
-
import { basename as basename6, dirname as dirname12, join as join13, resolve as
|
|
20030
|
+
import { basename as basename6, dirname as dirname12, join as join13, resolve as resolve8 } from "node:path";
|
|
19773
20031
|
async function canonicalPath(path2) {
|
|
19774
|
-
const absolute =
|
|
20032
|
+
const absolute = resolve8(path2);
|
|
19775
20033
|
try {
|
|
19776
20034
|
return await realpath3(absolute);
|
|
19777
20035
|
} catch (error) {
|
|
@@ -20078,7 +20336,7 @@ async function checkPaths(input, captured) {
|
|
|
20078
20336
|
refuse3();
|
|
20079
20337
|
}
|
|
20080
20338
|
async function retire(input, journal, assertOwned, hooks) {
|
|
20081
|
-
const
|
|
20339
|
+
const sources2 = [
|
|
20082
20340
|
{
|
|
20083
20341
|
role: "config",
|
|
20084
20342
|
path: input.legacyConfigPath ?? input.paths.legacyConfig,
|
|
@@ -20097,7 +20355,7 @@ async function retire(input, journal, assertOwned, hooks) {
|
|
|
20097
20355
|
}
|
|
20098
20356
|
]
|
|
20099
20357
|
];
|
|
20100
|
-
const snapshots = await Promise.all(
|
|
20358
|
+
const snapshots = await Promise.all(sources2.map(async (source2) => {
|
|
20101
20359
|
const snapshot = await readNativeMigrationSource(source2.role, source2.path);
|
|
20102
20360
|
owned(snapshot);
|
|
20103
20361
|
if (snapshot.data && snapshot.digest !== source2.digest)
|
|
@@ -20116,7 +20374,7 @@ async function retire(input, journal, assertOwned, hooks) {
|
|
|
20116
20374
|
}
|
|
20117
20375
|
return advanceNativeMigration(input.paths, "committed", "retired", {
|
|
20118
20376
|
assertOwned: async () => {
|
|
20119
|
-
for (const source2 of
|
|
20377
|
+
for (const source2 of sources2)
|
|
20120
20378
|
if (!await absent(source2.path))
|
|
20121
20379
|
refuse3("retirement-refused");
|
|
20122
20380
|
await input.processFence();
|
|
@@ -21133,8 +21391,8 @@ async function runNativeCustodyActivation(options, hooks = {}) {
|
|
|
21133
21391
|
}
|
|
21134
21392
|
async function commitMode(paths, routingPath, plan, context) {
|
|
21135
21393
|
let openGate = () => {};
|
|
21136
|
-
const gate = new Promise((
|
|
21137
|
-
openGate =
|
|
21394
|
+
const gate = new Promise((resolve9) => {
|
|
21395
|
+
openGate = resolve9;
|
|
21138
21396
|
});
|
|
21139
21397
|
let leases;
|
|
21140
21398
|
let scope;
|
|
@@ -22800,7 +23058,7 @@ function createNativeUsagePublisher(channel) {
|
|
|
22800
23058
|
return {
|
|
22801
23059
|
observe,
|
|
22802
23060
|
publish(write) {
|
|
22803
|
-
observe(new Promise((
|
|
23061
|
+
observe(new Promise((resolve9) => setTimeout(resolve9, 0)).then(write));
|
|
22804
23062
|
},
|
|
22805
23063
|
async drain() {
|
|
22806
23064
|
while (pending.size)
|
|
@@ -22861,11 +23119,11 @@ async function refreshForRequest(runtime2, ready) {
|
|
|
22861
23119
|
break;
|
|
22862
23120
|
if (combined.aborted)
|
|
22863
23121
|
break;
|
|
22864
|
-
await new Promise((
|
|
23122
|
+
await new Promise((resolve9) => {
|
|
22865
23123
|
const finish = () => {
|
|
22866
23124
|
clearTimeout(pause2);
|
|
22867
23125
|
combined.removeEventListener("abort", finish);
|
|
22868
|
-
|
|
23126
|
+
resolve9();
|
|
22869
23127
|
};
|
|
22870
23128
|
const pause2 = setTimeout(finish, 25);
|
|
22871
23129
|
combined.addEventListener("abort", finish, { once: true });
|
|
@@ -22881,16 +23139,16 @@ async function refreshForRequest(runtime2, ready) {
|
|
|
22881
23139
|
function waitForRequest(pending, signal) {
|
|
22882
23140
|
if (!signal)
|
|
22883
23141
|
return pending;
|
|
22884
|
-
return new Promise((
|
|
23142
|
+
return new Promise((resolve9, reject) => {
|
|
22885
23143
|
const abort = () => reject(signal.reason);
|
|
22886
23144
|
signal.addEventListener("abort", abort, { once: true });
|
|
22887
|
-
pending.then(
|
|
23145
|
+
pending.then(resolve9, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
22888
23146
|
if (signal.aborted)
|
|
22889
23147
|
abort();
|
|
22890
23148
|
});
|
|
22891
23149
|
}
|
|
22892
23150
|
// src/native-vault-connection.ts
|
|
22893
|
-
import { dirname as dirname15, join as join14, resolve as
|
|
23151
|
+
import { dirname as dirname15, join as join14, resolve as resolve10 } from "node:path";
|
|
22894
23152
|
// ../../node_modules/@cortexkit/common-auth/dist/opencode2/integration.js
|
|
22895
23153
|
var PLACEHOLDER_PREFIX = "common-auth-placeholder";
|
|
22896
23154
|
var PLACEHOLDER_LIFETIME_MS = 365 * 24 * 60 * 60 * 1000;
|
|
@@ -22901,7 +23159,7 @@ function placeholderSecret(integrationID) {
|
|
|
22901
23159
|
import { createHash as createHash19 } from "node:crypto";
|
|
22902
23160
|
import { constants as constants3 } from "node:fs";
|
|
22903
23161
|
import { lstat as lstat8, mkdir as mkdir12, open as open9, unlink as unlink7 } from "node:fs/promises";
|
|
22904
|
-
import { dirname as dirname14, resolve as
|
|
23162
|
+
import { dirname as dirname14, resolve as resolve9 } from "node:path";
|
|
22905
23163
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
22906
23164
|
|
|
22907
23165
|
// ../../node_modules/@cortexkit/common-auth/dist/pi-slot/lock.js
|
|
@@ -23288,8 +23546,8 @@ function createPiSlot(options, onStep, hooks) {
|
|
|
23288
23546
|
if (!provider || !options.authPath || !options.stashPath || !placeholderKey || placeholderKey.startsWith("!") || placeholderKey.includes("$") || !Number.isFinite(timeout) || timeout < 0) {
|
|
23289
23547
|
throw new PiSlotError("invalid-options");
|
|
23290
23548
|
}
|
|
23291
|
-
const authPath =
|
|
23292
|
-
const stashPath =
|
|
23549
|
+
const authPath = resolve9(options.authPath);
|
|
23550
|
+
const stashPath = resolve9(options.stashPath);
|
|
23293
23551
|
if (authPath === stashPath || stashPath === `${authPath}.lock`) {
|
|
23294
23552
|
throw new PiSlotError("invalid-options");
|
|
23295
23553
|
}
|
|
@@ -23427,7 +23685,7 @@ function createPiSlot(options, onStep, hooks) {
|
|
|
23427
23685
|
// src/native-vault-connection.ts
|
|
23428
23686
|
function nativePiAuthSlotPaths(options) {
|
|
23429
23687
|
return {
|
|
23430
|
-
authPath:
|
|
23688
|
+
authPath: resolve10(options.authPath),
|
|
23431
23689
|
stashPath: join14(dirname15(getHostClaustrumEnrollmentPaths("pi", options.env).tokenPath), "pi-auth-slot", "anthropic.json"),
|
|
23432
23690
|
provider: "anthropic",
|
|
23433
23691
|
placeholderKey: placeholderSecret("anthropic")
|
|
@@ -23446,7 +23704,7 @@ import { createHash as createHash20 } from "node:crypto";
|
|
|
23446
23704
|
import { realpathSync } from "node:fs";
|
|
23447
23705
|
import { mkdir as mkdir13, readdir as readdir3, rm as rm7, stat as stat7, writeFile as writeFile6 } from "node:fs/promises";
|
|
23448
23706
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
23449
|
-
import { join as join15, resolve as
|
|
23707
|
+
import { join as join15, resolve as resolve11 } from "node:path";
|
|
23450
23708
|
var CLAUDE_PRIME_COMMAND_NAME = "claude-prime";
|
|
23451
23709
|
var PRIME_TICK_MS = 60000;
|
|
23452
23710
|
var PRIME_DUE_OFFSET_MS = 60000;
|
|
@@ -23637,7 +23895,7 @@ function defaultMarkerDir() {
|
|
|
23637
23895
|
return join15(tmpdir5(), "opencode-anthropic-auth", "prime");
|
|
23638
23896
|
}
|
|
23639
23897
|
function primeStorageFingerprint(storagePath) {
|
|
23640
|
-
const absolutePath =
|
|
23898
|
+
const absolutePath = resolve11(storagePath);
|
|
23641
23899
|
let canonicalPath2;
|
|
23642
23900
|
try {
|
|
23643
23901
|
canonicalPath2 = realpathSync(absolutePath);
|
|
@@ -24317,9 +24575,9 @@ class QuotaHeaderFeedRegistry {
|
|
|
24317
24575
|
await this.reapStaleSiblingLeases(directory);
|
|
24318
24576
|
let entries = {};
|
|
24319
24577
|
try {
|
|
24320
|
-
const
|
|
24321
|
-
if (
|
|
24322
|
-
entries =
|
|
24578
|
+
const record8 = JSON.parse(await readFile10(this.filePath, "utf8"));
|
|
24579
|
+
if (record8.version === QUOTA_HEADER_FEED_SCHEMA_VERSION && record8.entries && typeof record8.entries === "object")
|
|
24580
|
+
entries = record8.entries;
|
|
24323
24581
|
} catch {}
|
|
24324
24582
|
entries[accountKey] = cleanEntry;
|
|
24325
24583
|
const tempPath = `${this.filePath}.${randomUUID16()}.tmp`;
|
|
@@ -24373,10 +24631,10 @@ class QuotaHeaderFeedRegistry {
|
|
|
24373
24631
|
const newest = new Map;
|
|
24374
24632
|
await Promise.all(names2.map(async (name) => {
|
|
24375
24633
|
try {
|
|
24376
|
-
const
|
|
24377
|
-
if (
|
|
24634
|
+
const record8 = JSON.parse(await readFile10(join16(directory, name), "utf8"));
|
|
24635
|
+
if (record8.version !== QUOTA_HEADER_FEED_SCHEMA_VERSION || !record8.entries || typeof record8.entries !== "object")
|
|
24378
24636
|
return;
|
|
24379
|
-
for (const [accountKey, candidate] of Object.entries(
|
|
24637
|
+
for (const [accountKey, candidate] of Object.entries(record8.entries)) {
|
|
24380
24638
|
if (!candidate || typeof candidate !== "object" || candidate.schema_version !== QUOTA_HEADER_FEED_SCHEMA_VERSION || candidate.provider !== "anthropic" || !validIdentity(candidate))
|
|
24381
24639
|
continue;
|
|
24382
24640
|
const observed = candidate.observed_at_ms;
|
|
@@ -24946,8 +25204,8 @@ class QuotaManager {
|
|
|
24946
25204
|
if (this.lastApiCallAt !== undefined) {
|
|
24947
25205
|
const remaining = QuotaManager.API_CALL_GAP_MS - (this.now() - this.lastApiCallAt);
|
|
24948
25206
|
if (remaining > 0)
|
|
24949
|
-
await new Promise((
|
|
24950
|
-
const id2 = nativeSetTimeout(
|
|
25207
|
+
await new Promise((resolve12) => {
|
|
25208
|
+
const id2 = nativeSetTimeout(resolve12, remaining);
|
|
24951
25209
|
if (typeof id2 === "object" && "unref" in id2)
|
|
24952
25210
|
id2.unref();
|
|
24953
25211
|
});
|
|
@@ -25850,7 +26108,7 @@ class PersistentRelaySession {
|
|
|
25850
26108
|
return;
|
|
25851
26109
|
if (this.connecting)
|
|
25852
26110
|
return await this.connecting;
|
|
25853
|
-
this.connecting = new Promise((
|
|
26111
|
+
this.connecting = new Promise((resolve12, reject) => {
|
|
25854
26112
|
const url = toWebSocketUrl(this.config.url, this.config.token);
|
|
25855
26113
|
const parsed = new URL(url);
|
|
25856
26114
|
parsed.searchParams.set("affinity", this.affinity);
|
|
@@ -25872,7 +26130,7 @@ class PersistentRelaySession {
|
|
|
25872
26130
|
if (message.type === "ready") {
|
|
25873
26131
|
this.timers.clearTimeout(timeout);
|
|
25874
26132
|
this.serverState = message.state;
|
|
25875
|
-
|
|
26133
|
+
resolve12();
|
|
25876
26134
|
return;
|
|
25877
26135
|
}
|
|
25878
26136
|
this.handleMessage(message);
|
|
@@ -25924,15 +26182,15 @@ class PersistentRelaySession {
|
|
|
25924
26182
|
const sentAt = perfNowMs();
|
|
25925
26183
|
let resolveDone;
|
|
25926
26184
|
let rejectDone;
|
|
25927
|
-
const done2 = new Promise((
|
|
25928
|
-
resolveDone =
|
|
26185
|
+
const done2 = new Promise((resolve12, reject) => {
|
|
26186
|
+
resolveDone = resolve12;
|
|
25929
26187
|
rejectDone = reject;
|
|
25930
26188
|
});
|
|
25931
|
-
const response = new Promise((
|
|
26189
|
+
const response = new Promise((resolve12, reject) => {
|
|
25932
26190
|
const pending = {
|
|
25933
26191
|
payload,
|
|
25934
26192
|
bodyText,
|
|
25935
|
-
resolve:
|
|
26193
|
+
resolve: resolve12,
|
|
25936
26194
|
reject,
|
|
25937
26195
|
streamDone: false,
|
|
25938
26196
|
accepted: false,
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface QuotaCodec {
|
|
2
2
|
readonly validate: (value: unknown) => boolean;
|
|
3
|
+
/** Normalize persisted data before validation; older codecs may omit this. */
|
|
4
|
+
readonly decode?: (value: unknown) => unknown;
|
|
3
5
|
readonly merge: (stored: unknown, observation: unknown) => unknown;
|
|
4
6
|
}
|
|
5
7
|
/**
|
|
@@ -2,8 +2,8 @@ export type { QuotaCodec } from './codec.js';
|
|
|
2
2
|
export { quotaCodec } from './codec.js';
|
|
3
3
|
export type { QuotaTextForm, QuotaTextOptions } from './format.js';
|
|
4
4
|
export { formatQuota, NO_LIMITS_REPORTED, NO_QUOTA_READING, QUOTA_STALE_AFTER_MS, quotaTextParts, quotaWindowName, } from './format.js';
|
|
5
|
-
export type { CreditBudgetCleared, CreditBudgetEntry, CreditBudgetReading, QuotaAbsentEntry, QuotaEntry, QuotaMap, QuotaReadingEntry, QuotaRetiredEntry, } from './map.js';
|
|
6
|
-
export { ALL_SCOPE, DEFAULT_REQUIRED_LABELS, emptyQuotaMap, isQuotaMap, } from './map.js';
|
|
5
|
+
export type { CreditBudgetCleared, CreditBudgetEntry, CreditBudgetReading, QuotaAbsentEntry, QuotaCounter, QuotaEntry, QuotaMap, QuotaReadingEntry, QuotaRetiredEntry, } from './map.js';
|
|
6
|
+
export { ALL_SCOPE, DEFAULT_REQUIRED_LABELS, decodeQuotaMap, emptyQuotaMap, isQuotaMap, } from './map.js';
|
|
7
7
|
export type { ObservedBudget, ObservedPair, ObservedReading, QuotaObservation, } from './merge.js';
|
|
8
8
|
export { isQuotaObservation, mergeQuotaObservation, QuotaCodecError, } from './merge.js';
|
|
9
9
|
export type { ExhaustionReset, ProjectedBudget, ProjectedLimit, ProjectedQuota, } from './projection.js';
|
|
@@ -44,16 +44,27 @@ export interface CreditBudgetCleared {
|
|
|
44
44
|
checkedAt: number;
|
|
45
45
|
}
|
|
46
46
|
export type CreditBudgetEntry = CreditBudgetReading | CreditBudgetCleared;
|
|
47
|
+
export interface QuotaCounter {
|
|
48
|
+
value: number;
|
|
49
|
+
checkedAt: number;
|
|
50
|
+
}
|
|
47
51
|
export interface QuotaMap {
|
|
48
52
|
limits: QuotaEntry[];
|
|
49
53
|
/** Absent means no observation has reported on the budget yet. */
|
|
50
54
|
budget?: CreditBudgetEntry;
|
|
55
|
+
/** Provider-named counts, each with its own observation time. */
|
|
56
|
+
counters?: Record<string, QuotaCounter>;
|
|
51
57
|
}
|
|
52
58
|
export declare function emptyQuotaMap(): QuotaMap;
|
|
53
59
|
/** The time an entry speaks for: its reading, retirement or absence time. */
|
|
54
60
|
export declare function entryTime(entry: QuotaEntry): number;
|
|
55
61
|
export declare function limitKey(scope: string, label: string): string;
|
|
56
62
|
export declare function isCreditBudgetEntry(value: unknown): value is CreditBudgetEntry;
|
|
63
|
+
export declare function isQuotaCounters(value: unknown): value is Record<string, QuotaCounter>;
|
|
64
|
+
/** Keep usable counters without letting one malformed count hide a quota map. */
|
|
65
|
+
export declare function readQuotaCounters(value: unknown): Record<string, QuotaCounter> | undefined;
|
|
66
|
+
/** Decode persisted quota, dropping malformed counters but not limit evidence. */
|
|
67
|
+
export declare function decodeQuotaMap(value: unknown): QuotaMap | undefined;
|
|
57
68
|
/**
|
|
58
69
|
* True when `value` is a well-formed quota map. Unrecognised top-level keys
|
|
59
70
|
* are tolerated (and preserved by merge) so a newer writer's additions
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type QuotaMap } from './map.js';
|
|
1
|
+
import { type QuotaCounter, type QuotaMap } from './map.js';
|
|
2
2
|
export interface ObservedReading {
|
|
3
3
|
/** Defaults to `all`. */
|
|
4
4
|
scope?: string;
|
|
@@ -32,6 +32,8 @@ export interface QuotaObservation {
|
|
|
32
32
|
coverage?: ObservedPair[];
|
|
33
33
|
/** Absent means the observation says nothing about the budget. */
|
|
34
34
|
budget?: ObservedBudget;
|
|
35
|
+
/** Each named count uses its own time, independently of limits and budget. */
|
|
36
|
+
counters?: Record<string, QuotaCounter>;
|
|
35
37
|
}
|
|
36
38
|
/** Thrown by `mergeQuotaObservation` when either argument is malformed. */
|
|
37
39
|
export declare class QuotaCodecError extends TypeError {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type QuotaMap } from './map.js';
|
|
1
|
+
import { type QuotaCounter, type QuotaMap } from './map.js';
|
|
2
2
|
export interface ProjectedLimit {
|
|
3
3
|
scope: string;
|
|
4
4
|
label: string;
|
|
@@ -30,6 +30,7 @@ export interface ProjectedQuota {
|
|
|
30
30
|
checkedAt?: number;
|
|
31
31
|
/** Present only when the stored budget is a reading, not cleared. */
|
|
32
32
|
budget?: ProjectedBudget;
|
|
33
|
+
counters?: Record<string, QuotaCounter>;
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
35
36
|
* Resolves `map` for a request in `scope` (`all` or a model family). A family
|
|
@@ -49,6 +49,8 @@ export type StoredCredential = (OAuthCredential & {
|
|
|
49
49
|
/** Quota codec supplied by `/quota`: the store never interprets the map itself. */
|
|
50
50
|
export interface QuotaCodec {
|
|
51
51
|
validate(value: unknown): boolean;
|
|
52
|
+
/** Normalize persisted quota before validation, when the codec supports it. */
|
|
53
|
+
decode?(value: unknown): unknown;
|
|
52
54
|
merge(stored: unknown | undefined, observation: unknown): unknown;
|
|
53
55
|
}
|
|
54
56
|
/**
|
|
@@ -42,8 +42,10 @@ export interface NativeAccountSnapshot {
|
|
|
42
42
|
mode: 'local' | 'claustrum';
|
|
43
43
|
settings: Record<string, unknown>;
|
|
44
44
|
accounts: NativeAccountView[];
|
|
45
|
-
/** Vault
|
|
45
|
+
/** Vault storage, or the local destination recorded by the authorized migration journal. */
|
|
46
46
|
routingPath?: string;
|
|
47
|
+
/** Distinct pre-migration routing file that OpenCode local serving may have recreated. */
|
|
48
|
+
routingRecoveryPath?: string;
|
|
47
49
|
routingSeed?: NativeVaultRoutingSeed;
|
|
48
50
|
/** AccountStorage-shaped input for pure policy predicates, never a credential or persistence authority. */
|
|
49
51
|
policyStorage: AccountStorage;
|
package/dist/pool-authority.d.ts
CHANGED
|
@@ -126,7 +126,7 @@ export declare function readNativeMigrationJournal(paths: NativePoolPaths): Prom
|
|
|
126
126
|
*/
|
|
127
127
|
export declare function nativeMigrationAuthorityPhase(journal: NativeMigrationJournal | undefined): 'committed' | 'retired' | undefined;
|
|
128
128
|
/** An empty or readable store is not proof that the offline authority flip completed. */
|
|
129
|
-
export declare function requireNativePoolAuthority(paths: NativePoolPaths): Promise<
|
|
129
|
+
export declare function requireNativePoolAuthority(paths: NativePoolPaths): Promise<NativeMigrationJournal>;
|
|
130
130
|
interface JournalHooks {
|
|
131
131
|
/** Outer controller and pool leases remain held through the atomic journal rename. */
|
|
132
132
|
assertOwned?: () => Promise<void>;
|
package/dist/sticky-routing.d.ts
CHANGED
|
@@ -106,12 +106,15 @@ export declare class StickySessionRouter {
|
|
|
106
106
|
now?: () => number;
|
|
107
107
|
assignmentTtlMs?: number;
|
|
108
108
|
vaultSeed?: NativeVaultRoutingSeed;
|
|
109
|
+
localRecoveryPath?: string;
|
|
109
110
|
});
|
|
110
111
|
private now;
|
|
111
112
|
private readState;
|
|
112
113
|
private readStateMtimeNs;
|
|
113
114
|
private refreshStateIfChanged;
|
|
114
115
|
private acquireLock;
|
|
116
|
+
private recoverLocalPins;
|
|
117
|
+
private fillLocalPins;
|
|
115
118
|
private assignmentIsActive;
|
|
116
119
|
private prune;
|
|
117
120
|
private writeState;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cortexkit/anthropic-auth-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,11 +30,12 @@
|
|
|
30
30
|
"prepublishOnly": "bun run build"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@cortexkit/common-auth": "0.
|
|
33
|
+
"@cortexkit/common-auth": "0.17.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@cortexkit/claustrum-client": "0.9.0",
|
|
37
37
|
"@cortexkit/private-files": "0.2.1",
|
|
38
|
+
"@cortexkit/subc-client": "^0.16.0",
|
|
38
39
|
"jsonc-parser": "^3.3.1",
|
|
39
40
|
"xxhash-wasm": "^1.1.0"
|
|
40
41
|
}
|