@cortexkit/anthropic-auth-core 2.4.5 → 2.4.7
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/accounts.d.ts +6 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +143 -19
- package/dist/insula-quota.d.ts +2 -3
- package/dist/native-account-runtime.d.ts +5 -1
- package/dist/native-vault-refusal.d.ts +28 -0
- package/dist/sticky-routing.d.ts +3 -0
- package/package.json +1 -1
package/dist/accounts.d.ts
CHANGED
|
@@ -400,6 +400,12 @@ export declare function getScopedQuotaWindowForModel(quota: OAuthQuotaSnapshot |
|
|
|
400
400
|
export declare function quotaSnapshotModelScopeIsExhausted(quota: OAuthQuotaSnapshot | undefined, model: unknown): boolean;
|
|
401
401
|
export declare function quotaSnapshotPassesModelScope(quota: OAuthQuotaSnapshot | undefined, model: unknown): boolean;
|
|
402
402
|
export declare function quotaSnapshotPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null): boolean;
|
|
403
|
+
/** A poll's omitted session window is evidence, unlike a partial header harvest. */
|
|
404
|
+
export declare function quotaSnapshotOmitsFiveHour(quota: OAuthQuotaSnapshot | undefined): quota is OAuthQuotaSnapshot & {
|
|
405
|
+
checkedAt: number;
|
|
406
|
+
five_hour?: undefined;
|
|
407
|
+
seven_day: AccountQuotaWindow;
|
|
408
|
+
};
|
|
403
409
|
export declare function quotaSnapshotHasStandardWindows(quota: OAuthQuotaSnapshot | undefined): quota is OAuthQuotaSnapshot;
|
|
404
410
|
export declare const DEFAULT_KILLSWITCH_THRESHOLDS: Record<QuotaWindowName | 'scoped', number>;
|
|
405
411
|
export declare function normalizeKillswitchThresholds(thresholds: KillswitchThresholds | undefined): Record<QuotaWindowName | 'scoped', number>;
|
package/dist/index.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export { CLAUDE_CODE_DEFAULT_BETAS, CLAUDE_MODEL_CAPABILITIES, getClaudeModelCap
|
|
|
25
25
|
export * from './model-remap.ts';
|
|
26
26
|
export * from './models.ts';
|
|
27
27
|
export * from './native-account-refusal.ts';
|
|
28
|
-
export type { NativeAccountRuntime, NativeAccountRuntimeOptions, NativeAccountWriteInput, NativeApiSubject, NativeLocalAuthorizeOptions, NativeRelayUpdate, } from './native-account-runtime.ts';
|
|
28
|
+
export type { NativeAccountPolicy, NativeAccountRuntime, NativeAccountRuntimeOptions, NativeAccountWriteInput, NativeApiSubject, NativeLocalAuthorizeOptions, NativeQuotaPolicyLimit, NativeRelayUpdate, } from './native-account-runtime.ts';
|
|
29
29
|
export { acquireNativeAccountRuntime, createNativeAccountRuntime, nativeAccountPolicy, } from './native-account-runtime.ts';
|
|
30
30
|
export type { NativeAccountMetadataPatch, NativeAccountSnapshot, NativeAccountView, } from './native-account-view.ts';
|
|
31
31
|
export { formatNativeAccountState, nativeAccountCanServe, } from './native-account-view.ts';
|
|
@@ -62,6 +62,7 @@ export * from './native-usage-publication.ts';
|
|
|
62
62
|
export { NATIVE_VAULT_NO_ACCOUNT_MESSAGE, NativeVaultNoAccountError, readNativeAccountsForRequest, } from './native-vault-admission.ts';
|
|
63
63
|
export type { NativePiAuthSlot, NativePiAuthSlotErrorCode, NativePiAuthSlotInspection, NativePiAuthSlotOptions, NativeVaultDisconnectOptions, NativeVaultDisconnectResult, } from './native-vault-connection.ts';
|
|
64
64
|
export { disconnectNativeVaultForHost, NativePiAuthSlotError, nativePiAuthSlotPaths, openNativePiAuthSlot, } from './native-vault-connection.ts';
|
|
65
|
+
export { createNativeVaultNoRouteResponse, NativeVaultQuotaPolicyError, } from './native-vault-refusal.ts';
|
|
65
66
|
export type { NativeVaultQuotaPurpose, NativeVaultRuntime, NativeVaultRuntimeOptions, NativeVaultWatch, NativeVaultWatchOptions, } from './native-vault-runtime.ts';
|
|
66
67
|
export { acquireNativeVaultRuntime, createNativeVaultRuntime, discoverNativeVaultInventory, publishNativeVaultRosterSeed, publishNativeVaultRuntimeSeed, } from './native-vault-runtime.ts';
|
|
67
68
|
export * from './oauth-origin.ts';
|
package/dist/index.js
CHANGED
|
@@ -4509,6 +4509,8 @@ function mergeHeaderOwnedWindow(existingSnapshot, incomingSnapshot, key) {
|
|
|
4509
4509
|
const incoming = incomingSnapshot[key];
|
|
4510
4510
|
if (!incoming)
|
|
4511
4511
|
return existing;
|
|
4512
|
+
if (key === "five_hour" && quotaSnapshotOmitsFiveHour(existingSnapshot) && incoming.checkedAt <= (existingSnapshot.checkedAt ?? 0))
|
|
4513
|
+
return;
|
|
4512
4514
|
if (!existing)
|
|
4513
4515
|
return incoming;
|
|
4514
4516
|
if (incoming.checkedAt > existing.checkedAt)
|
|
@@ -4545,6 +4547,8 @@ function fieldSourcesForMergedQuota(existing, incoming, merged) {
|
|
|
4545
4547
|
if (source)
|
|
4546
4548
|
fieldSources[field] = source;
|
|
4547
4549
|
}
|
|
4550
|
+
if (!merged.five_hour && quotaSnapshotOmitsFiveHour(existing))
|
|
4551
|
+
fieldSources.five_hour = "poll";
|
|
4548
4552
|
return Object.keys(fieldSources).length > 0 ? fieldSources : undefined;
|
|
4549
4553
|
}
|
|
4550
4554
|
function mergeHeaderQuotaForPersistence(existing, incoming) {
|
|
@@ -4560,7 +4564,10 @@ function mergeHeaderQuotaForPersistence(existing, incoming) {
|
|
|
4560
4564
|
extraUsage: existing.extraUsage ?? incoming.extraUsage,
|
|
4561
4565
|
fallbackAdvised: incoming.fieldSources?.fallbackAdvised !== undefined ? incoming.fallbackAdvised : existing.fallbackAdvised ?? incoming.fallbackAdvised,
|
|
4562
4566
|
bindingWindow: preservePollBinding ? existing.bindingWindow : incoming.bindingWindow ?? existing.bindingWindow,
|
|
4563
|
-
bindingWindowSource: preservePollBinding ? "poll" : incoming.bindingWindowSource ?? existing.bindingWindowSource
|
|
4567
|
+
bindingWindowSource: preservePollBinding ? "poll" : incoming.bindingWindowSource ?? existing.bindingWindowSource,
|
|
4568
|
+
...quotaSnapshotOmitsFiveHour(existing) && {
|
|
4569
|
+
checkedAt: existing.checkedAt
|
|
4570
|
+
}
|
|
4564
4571
|
};
|
|
4565
4572
|
const fieldSources = fieldSourcesForMergedQuota(existing, incoming, merged);
|
|
4566
4573
|
return {
|
|
@@ -4993,20 +5000,25 @@ function quotaSnapshotPassesPolicy(quota, storage) {
|
|
|
4993
5000
|
if (!quotaEnabled(storage))
|
|
4994
5001
|
return true;
|
|
4995
5002
|
const thresholds = getQuotaMinimumRemainingThresholds(storage);
|
|
5003
|
+
let sawUnknownWindow = false;
|
|
4996
5004
|
for (const key of ["five_hour", "seven_day"]) {
|
|
5005
|
+
if (key === "five_hour" && quotaSnapshotOmitsFiveHour(quota))
|
|
5006
|
+
continue;
|
|
4997
5007
|
const window = quota?.[key];
|
|
4998
|
-
if (!window)
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
return !failClosedOnUnknownQuota(storage);
|
|
5008
|
+
if (!window || !Number.isFinite(window.remainingPercent)) {
|
|
5009
|
+
sawUnknownWindow = true;
|
|
5010
|
+
continue;
|
|
5002
5011
|
}
|
|
5003
5012
|
if (window.remainingPercent < thresholds[key])
|
|
5004
5013
|
return false;
|
|
5005
5014
|
}
|
|
5006
|
-
return
|
|
5015
|
+
return !sawUnknownWindow || !failClosedOnUnknownQuota(storage);
|
|
5016
|
+
}
|
|
5017
|
+
function quotaSnapshotOmitsFiveHour(quota) {
|
|
5018
|
+
return Boolean((quota?.source === "poll" || quota?.fieldSources?.five_hour === "poll") && quota && !quota.five_hour && quota.seven_day && Number.isFinite(quota.checkedAt) && (quota.checkedAt ?? 0) > 0);
|
|
5007
5019
|
}
|
|
5008
5020
|
function quotaSnapshotHasStandardWindows(quota) {
|
|
5009
|
-
return Boolean(quota?.
|
|
5021
|
+
return Boolean(quota?.seven_day && (quota.five_hour || quotaSnapshotOmitsFiveHour(quota)));
|
|
5010
5022
|
}
|
|
5011
5023
|
var DEFAULT_KILLSWITCH_THRESHOLDS = {
|
|
5012
5024
|
five_hour: 5,
|
|
@@ -5040,6 +5052,8 @@ function killswitchPassesPolicy(quota, storage, accountId, modelId) {
|
|
|
5040
5052
|
const thresholds = getKillswitchThresholdsForAccount(storage, accountId);
|
|
5041
5053
|
let sawUnknownWindow = false;
|
|
5042
5054
|
for (const key of ["five_hour", "seven_day"]) {
|
|
5055
|
+
if (key === "five_hour" && quotaSnapshotOmitsFiveHour(quota))
|
|
5056
|
+
continue;
|
|
5043
5057
|
const window = quota?.[key];
|
|
5044
5058
|
if (!window || !Number.isFinite(window.remainingPercent)) {
|
|
5045
5059
|
if (thresholds[key] > 0)
|
|
@@ -5106,6 +5120,8 @@ function getQuotaNextRefreshAt(quota, storage, now) {
|
|
|
5106
5120
|
const thresholds = getQuotaMinimumRemainingThresholds(storage);
|
|
5107
5121
|
const blockedResetTimes = [];
|
|
5108
5122
|
for (const key of ["five_hour", "seven_day"]) {
|
|
5123
|
+
if (key === "five_hour" && quotaSnapshotOmitsFiveHour(quota))
|
|
5124
|
+
continue;
|
|
5109
5125
|
const window = quota?.[key];
|
|
5110
5126
|
if (!window)
|
|
5111
5127
|
return capAtOldestWindow(now + intervalMs);
|
|
@@ -18792,6 +18808,13 @@ var nativeQuotaCodec = {
|
|
|
18792
18808
|
return toNativeQuotaMap(mergeHeaderQuotaForPersistence(previous, incoming));
|
|
18793
18809
|
const previousTime = quotaSnapshotCheckedAt(previous);
|
|
18794
18810
|
const incomingTime = quotaSnapshotCheckedAt(incoming);
|
|
18811
|
+
if (incoming.source === "poll" && incoming.checkedAt !== undefined && previous.checkedAt !== undefined && (previous.source === "poll" || quotaSnapshotOmitsFiveHour(previous)) && incoming.checkedAt < previous.checkedAt)
|
|
18812
|
+
return toNativeQuotaMap(previous);
|
|
18813
|
+
if (incoming.source === "poll" && incoming.seven_day && !incoming.five_hour && incoming.checkedAt !== undefined && incoming.checkedAt > (previous.five_hour?.checkedAt ?? 0) && (previous.source !== "poll" || incoming.checkedAt >= (previous.checkedAt ?? 0)))
|
|
18814
|
+
return toNativeQuotaMap(previous.source === "headers" ? mergeHeaderQuotaForPersistence(incoming, {
|
|
18815
|
+
...previous,
|
|
18816
|
+
five_hour: undefined
|
|
18817
|
+
}) : incoming);
|
|
18795
18818
|
return toNativeQuotaMap(previousTime > incomingTime || previousTime === incomingTime && previous.source === "poll" && incoming.source !== "poll" ? previous : incoming);
|
|
18796
18819
|
}
|
|
18797
18820
|
};
|
|
@@ -20504,6 +20527,12 @@ function normalizeQuotaHeaders(headers, now = Date.now()) {
|
|
|
20504
20527
|
};
|
|
20505
20528
|
}
|
|
20506
20529
|
function mergeHeaderQuotaSnapshot(existing, incoming) {
|
|
20530
|
+
if (quotaSnapshotOmitsFiveHour(existing) && incoming.five_hour && incoming.five_hour.checkedAt <= existing.checkedAt) {
|
|
20531
|
+
return mergeHeaderQuotaSnapshot(existing, {
|
|
20532
|
+
...incoming,
|
|
20533
|
+
five_hour: undefined
|
|
20534
|
+
});
|
|
20535
|
+
}
|
|
20507
20536
|
const {
|
|
20508
20537
|
scoped: existingScoped,
|
|
20509
20538
|
extraUsage: existingExtraUsage,
|
|
@@ -20525,6 +20554,8 @@ function mergeHeaderQuotaSnapshot(existing, incoming) {
|
|
|
20525
20554
|
if (source2)
|
|
20526
20555
|
fieldSources2[field] = source2;
|
|
20527
20556
|
}
|
|
20557
|
+
if (quotaSnapshotOmitsFiveHour(existing) && !incoming.five_hour)
|
|
20558
|
+
fieldSources2.five_hour = "poll";
|
|
20528
20559
|
return {
|
|
20529
20560
|
...existingWithoutPollOwnedFields,
|
|
20530
20561
|
...incomingWithoutPollOwnedFields,
|
|
@@ -20534,7 +20565,10 @@ function mergeHeaderQuotaSnapshot(existing, incoming) {
|
|
|
20534
20565
|
bindingWindow: existing?.bindingWindowSource === "poll" ? existing.bindingWindow : incoming.bindingWindow ?? existing?.bindingWindow,
|
|
20535
20566
|
bindingWindowSource: existing?.bindingWindowSource === "poll" ? "poll" : incoming.bindingWindowSource ?? existing?.bindingWindowSource,
|
|
20536
20567
|
...Object.keys(fieldSources2).length > 0 && { fieldSources: fieldSources2 },
|
|
20537
|
-
source: "headers"
|
|
20568
|
+
source: "headers",
|
|
20569
|
+
...quotaSnapshotOmitsFiveHour(existing) && {
|
|
20570
|
+
checkedAt: existing.checkedAt
|
|
20571
|
+
}
|
|
20538
20572
|
};
|
|
20539
20573
|
}
|
|
20540
20574
|
|
|
@@ -20575,7 +20609,8 @@ function createStickyNoRouteResponse(input) {
|
|
|
20575
20609
|
const retryAfter = killswitchRetryAfterSeconds(firstQuota, remainingQuotas.map((quota2) => ({ quota: quota2 })), input.now ?? Date.now(), scopedBlocked ? modelId : undefined);
|
|
20576
20610
|
const minutes = Math.floor(retryAfter / 60);
|
|
20577
20611
|
const seconds = retryAfter % 60;
|
|
20578
|
-
const
|
|
20612
|
+
const limitNames = input.vaultPolicyLimits?.map((limit) => limit === "model-scoped" ? `${modelName ?? "Model"} scoped limit` : limit === "killswitch" ? "killswitch limit" : "quota floor");
|
|
20613
|
+
const reason = limitNames ? `No vault account currently satisfies quota policy: ${limitNames.join(", ")}. Open /claude → Killswitch / Quota to change these limits.` : scopedBlocked && modelName ? `${modelName} weekly limit reached, no routable OAuth accounts.` : "No OAuth account currently satisfies sticky-balanced quota policy.";
|
|
20579
20614
|
const message = `${reason} Retry in ${minutes}m ${seconds}s.`;
|
|
20580
20615
|
return new Response(JSON.stringify({
|
|
20581
20616
|
type: "error",
|
|
@@ -20686,6 +20721,8 @@ function sessionKey(sessionId) {
|
|
|
20686
20721
|
function stickyQuotaSnapshotIsFresh(quota2, storage, now = Date.now(), modelId) {
|
|
20687
20722
|
const maxAge = getQuotaCheckIntervalMs(storage);
|
|
20688
20723
|
const standardFresh = ["five_hour", "seven_day"].every((key) => {
|
|
20724
|
+
if (key === "five_hour" && quotaSnapshotOmitsFiveHour(quota2))
|
|
20725
|
+
return true;
|
|
20689
20726
|
const window2 = quota2?.[key];
|
|
20690
20727
|
return Boolean(window2 && now - window2.checkedAt < maxAge);
|
|
20691
20728
|
});
|
|
@@ -20740,14 +20777,23 @@ function stickyRouteCandidateWeight(input) {
|
|
|
20740
20777
|
}
|
|
20741
20778
|
const weights = [];
|
|
20742
20779
|
for (const key of ["five_hour", "seven_day"]) {
|
|
20780
|
+
if (key === "five_hour" && quotaSnapshotOmitsFiveHour(quota2))
|
|
20781
|
+
continue;
|
|
20743
20782
|
const window2 = quota2[key];
|
|
20744
20783
|
if (!window2 || !Number.isFinite(window2.remainingPercent))
|
|
20745
20784
|
return 0;
|
|
20746
|
-
|
|
20785
|
+
const threshold = remainingThreshold(storage, candidate.accountId, key);
|
|
20786
|
+
if (window2.remainingPercent <= threshold) {
|
|
20787
|
+
const quotaThreshold = getQuotaMinimumRemainingThresholds(storage)[key];
|
|
20788
|
+
input.onPolicyBlock?.(isKillswitchEnabled(storage) && threshold > quotaThreshold ? "killswitch" : "quota-floor");
|
|
20789
|
+
}
|
|
20790
|
+
weights.push(sustainableWindowWeight(window2.remainingPercent, threshold, window2.resetsAt, now));
|
|
20747
20791
|
}
|
|
20748
20792
|
if (input.family === "fable") {
|
|
20749
20793
|
const window2 = getScopedQuotaWindowForModel(quota2, input.modelId);
|
|
20750
20794
|
if (window2 && Number.isFinite(window2.remainingPercent)) {
|
|
20795
|
+
if (window2.remainingPercent <= remainingThreshold(storage, candidate.accountId, "scoped"))
|
|
20796
|
+
input.onPolicyBlock?.("model-scoped");
|
|
20751
20797
|
weights.push(sustainableWindowWeight(window2.remainingPercent, remainingThreshold(storage, candidate.accountId, "scoped"), window2.resetsAt, now));
|
|
20752
20798
|
}
|
|
20753
20799
|
}
|
|
@@ -26565,19 +26611,19 @@ function normalizeInsulaClaudeQuota(entry2, context) {
|
|
|
26565
26611
|
kind: "weekly",
|
|
26566
26612
|
minutes: 10080
|
|
26567
26613
|
});
|
|
26568
|
-
if (!
|
|
26614
|
+
if (!seven_day || usage?.primary != null && !five_hour)
|
|
26569
26615
|
return;
|
|
26570
26616
|
const scoped = scopedReadings(usage?.extraRateWindows, checkedAt);
|
|
26571
26617
|
const extraUsage2 = extraUsageReading(entry2.pools ?? usage?.pools);
|
|
26572
26618
|
return {
|
|
26573
|
-
five_hour,
|
|
26619
|
+
...five_hour && { five_hour },
|
|
26574
26620
|
seven_day,
|
|
26575
26621
|
scoped,
|
|
26576
26622
|
...extraUsage2 && { extraUsage: extraUsage2 },
|
|
26577
26623
|
source: "poll",
|
|
26578
26624
|
checkedAt,
|
|
26579
26625
|
fieldSources: {
|
|
26580
|
-
five_hour: "poll",
|
|
26626
|
+
...five_hour && { five_hour: "poll" },
|
|
26581
26627
|
seven_day: "poll",
|
|
26582
26628
|
scoped: "poll",
|
|
26583
26629
|
...extraUsage2 && { extraUsage: "poll" }
|
|
@@ -26594,7 +26640,7 @@ function newer(reading2, stored) {
|
|
|
26594
26640
|
function mergeInsulaQuota(reading2, stored) {
|
|
26595
26641
|
if (!stored || quotaSnapshotCheckedAt(stored) <= reading2.checkedAt)
|
|
26596
26642
|
return reading2;
|
|
26597
|
-
const five_hour = newer(reading2.five_hour, stored.five_hour);
|
|
26643
|
+
const five_hour = quotaSnapshotOmitsFiveHour(stored) ? undefined : !reading2.five_hour && (stored.five_hour?.checkedAt ?? 0) <= reading2.checkedAt ? undefined : newer(reading2.five_hour, stored.five_hour);
|
|
26598
26644
|
const seven_day = newer(reading2.seven_day, stored.seven_day);
|
|
26599
26645
|
const scoped = new Map(reading2.scoped.map((window2) => [window2.id, window2]));
|
|
26600
26646
|
for (const window2 of stored.scoped ?? []) {
|
|
@@ -26609,10 +26655,10 @@ function mergeInsulaQuota(reading2, stored) {
|
|
|
26609
26655
|
fieldSources2.seven_day = stored.fieldSources.seven_day;
|
|
26610
26656
|
return {
|
|
26611
26657
|
...reading2,
|
|
26612
|
-
|
|
26658
|
+
five_hour,
|
|
26613
26659
|
...seven_day && { seven_day },
|
|
26614
26660
|
scoped: [...scoped.values()],
|
|
26615
|
-
checkedAt: Math.max(reading2.checkedAt, quotaSnapshotCheckedAt(stored)),
|
|
26661
|
+
checkedAt: quotaSnapshotOmitsFiveHour(stored) ? stored.checkedAt : quotaSnapshotOmitsFiveHour(reading2) ? reading2.checkedAt : Math.max(reading2.checkedAt, quotaSnapshotCheckedAt(stored)),
|
|
26616
26662
|
fieldSources: fieldSources2
|
|
26617
26663
|
};
|
|
26618
26664
|
}
|
|
@@ -26898,9 +26944,11 @@ function pauseOnRealTimer(ms) {
|
|
|
26898
26944
|
class QuotaRefreshDeferred extends Error {
|
|
26899
26945
|
}
|
|
26900
26946
|
function mergePollCompletionWithNewerHeaders(current, polled) {
|
|
26947
|
+
if (quotaSnapshotOmitsFiveHour(current) && (polled.checkedAt ?? quotaSnapshotCheckedAt(polled)) < current.checkedAt)
|
|
26948
|
+
return current;
|
|
26901
26949
|
if (current?.source !== "headers")
|
|
26902
26950
|
return polled;
|
|
26903
|
-
const fiveHourIsNewer = Boolean(current.five_hour && current.five_hour.checkedAt > (polled.five_hour?.checkedAt ?? 0));
|
|
26951
|
+
const fiveHourIsNewer = Boolean(current.five_hour && current.five_hour.checkedAt > (polled.five_hour?.checkedAt ?? polled.checkedAt ?? 0));
|
|
26904
26952
|
const sevenDayIsNewer = Boolean(current.seven_day && current.seven_day.checkedAt > (polled.seven_day?.checkedAt ?? 0));
|
|
26905
26953
|
if (!fiveHourIsNewer && !sevenDayIsNewer)
|
|
26906
26954
|
return polled;
|
|
@@ -30239,8 +30287,15 @@ function acquireNativeAccountRuntime(options) {
|
|
|
30239
30287
|
function nativeAccountPolicy(account, snapshot, modelId) {
|
|
30240
30288
|
if (!nativeAccountCanServe(account))
|
|
30241
30289
|
return { status: "blocked", reason: "account-disabled" };
|
|
30242
|
-
|
|
30243
|
-
|
|
30290
|
+
const quotaPolicyLimits = [];
|
|
30291
|
+
if (!quotaSnapshotPassesPolicy(account.quota, snapshot.policyStorage))
|
|
30292
|
+
quotaPolicyLimits.push("quota-floor");
|
|
30293
|
+
if (!quotaSnapshotPassesModelScope(account.quota, modelId))
|
|
30294
|
+
quotaPolicyLimits.push("model-scoped");
|
|
30295
|
+
if (!killswitchPassesPolicy(account.quota, snapshot.policyStorage, account.id === "main" ? undefined : account.id, modelId))
|
|
30296
|
+
quotaPolicyLimits.push("killswitch");
|
|
30297
|
+
if (quotaPolicyLimits.length)
|
|
30298
|
+
return { status: "blocked", reason: "quota-ineligible", quotaPolicyLimits };
|
|
30244
30299
|
return { status: "allowed" };
|
|
30245
30300
|
}
|
|
30246
30301
|
function createNativeAccountRuntime(options) {
|
|
@@ -35238,6 +35293,60 @@ async function disconnectNativeVaultForHost(options) {
|
|
|
35238
35293
|
closeNativeVaultAuthority(paths.tokenPath);
|
|
35239
35294
|
return result;
|
|
35240
35295
|
}
|
|
35296
|
+
// src/native-vault-refusal.ts
|
|
35297
|
+
function createNativeVaultNoRouteResponse(input) {
|
|
35298
|
+
const { snapshot, modelId } = input;
|
|
35299
|
+
const accounts = snapshot.accounts.filter((account) => account.type === "oauth");
|
|
35300
|
+
if (accounts.some((account) => account.enabled && account.state === "needs_reauth"))
|
|
35301
|
+
throw new NativeVaultNoAccountError;
|
|
35302
|
+
const active2 = accounts.filter(nativeAccountCanServe);
|
|
35303
|
+
const limits = new Set;
|
|
35304
|
+
for (const account of active2) {
|
|
35305
|
+
const policy = input.policies?.get(account.id) ?? nativeAccountPolicy(account, snapshot, modelId);
|
|
35306
|
+
for (const limit of policy.quotaPolicyLimits ?? [])
|
|
35307
|
+
limits.add(limit);
|
|
35308
|
+
if (input.sticky) {
|
|
35309
|
+
stickyRouteCandidateWeight({
|
|
35310
|
+
candidate: {
|
|
35311
|
+
accountId: account.id,
|
|
35312
|
+
order: 0,
|
|
35313
|
+
quota: account.quota ?? { kind: "unknown" }
|
|
35314
|
+
},
|
|
35315
|
+
family: stickyRouteFamilyForModel(modelId),
|
|
35316
|
+
modelId,
|
|
35317
|
+
storage: snapshot.policyStorage,
|
|
35318
|
+
onPolicyBlock: (limit) => limits.add(limit)
|
|
35319
|
+
});
|
|
35320
|
+
}
|
|
35321
|
+
}
|
|
35322
|
+
if (!limits.size)
|
|
35323
|
+
throw new NativeVaultNoAccountError;
|
|
35324
|
+
return createStickyNoRouteResponse({
|
|
35325
|
+
routeQuotas: active2.flatMap((account) => account.quota ? [account.quota] : []),
|
|
35326
|
+
modelId,
|
|
35327
|
+
vaultPolicyLimits: [...limits]
|
|
35328
|
+
});
|
|
35329
|
+
}
|
|
35330
|
+
|
|
35331
|
+
class NativeVaultQuotaPolicyError extends Error {
|
|
35332
|
+
response;
|
|
35333
|
+
body;
|
|
35334
|
+
kind = "quota-policy";
|
|
35335
|
+
status = 429;
|
|
35336
|
+
headers;
|
|
35337
|
+
retryAfter;
|
|
35338
|
+
constructor(response, body) {
|
|
35339
|
+
super(body.error.message);
|
|
35340
|
+
this.response = response;
|
|
35341
|
+
this.body = body;
|
|
35342
|
+
this.name = "NativeVaultQuotaPolicyError";
|
|
35343
|
+
this.headers = new Headers(response.headers);
|
|
35344
|
+
this.retryAfter = Number(this.headers.get("retry-after"));
|
|
35345
|
+
}
|
|
35346
|
+
static async fromResponse(response) {
|
|
35347
|
+
return new NativeVaultQuotaPolicyError(response, await response.clone().json());
|
|
35348
|
+
}
|
|
35349
|
+
}
|
|
35241
35350
|
// src/oauth-origin.ts
|
|
35242
35351
|
var ANTHROPIC_OAUTH_ORIGIN = "https://api.anthropic.com";
|
|
35243
35352
|
var ANTHROPIC_OAUTH_ORIGIN_REFUSAL = "Claude OAuth requests can only go to https://api.anthropic.com. A provider baseURL that points elsewhere is not used for Claude sign-in accounts.";
|
|
@@ -35687,6 +35796,12 @@ class PrimeManager {
|
|
|
35687
35796
|
});
|
|
35688
35797
|
return;
|
|
35689
35798
|
}
|
|
35799
|
+
if (quotaSnapshotOmitsFiveHour(evaluation.storedQuota)) {
|
|
35800
|
+
logger.debug("prime", "no five-hour limit", {
|
|
35801
|
+
account: evaluation.label
|
|
35802
|
+
});
|
|
35803
|
+
return;
|
|
35804
|
+
}
|
|
35690
35805
|
const storedResetEpoch = storedResetMs(evaluation.storedFiveHour);
|
|
35691
35806
|
if (storedResetEpoch !== undefined && now < storedResetEpoch + PRIME_DUE_OFFSET_MS) {
|
|
35692
35807
|
logger.trace("prime", "not due", { account: evaluation.label });
|
|
@@ -35744,6 +35859,12 @@ class PrimeManager {
|
|
|
35744
35859
|
});
|
|
35745
35860
|
return;
|
|
35746
35861
|
}
|
|
35862
|
+
if (quotaSnapshotOmitsFiveHour(fresh)) {
|
|
35863
|
+
logger.debug("prime", "no five-hour limit", {
|
|
35864
|
+
account: evaluation.label
|
|
35865
|
+
});
|
|
35866
|
+
return;
|
|
35867
|
+
}
|
|
35747
35868
|
if (!killswitchPassesPolicy(fresh, reloaded, evaluation.id, CLAUDE_HAIKU_4_5_MODEL_ID)) {
|
|
35748
35869
|
logger.debug("prime", "ineligible", {
|
|
35749
35870
|
account: evaluation.label,
|
|
@@ -39153,6 +39274,7 @@ export {
|
|
|
39153
39274
|
quotaTextParts,
|
|
39154
39275
|
quotaSnapshotPassesPolicy,
|
|
39155
39276
|
quotaSnapshotPassesModelScope,
|
|
39277
|
+
quotaSnapshotOmitsFiveHour,
|
|
39156
39278
|
quotaSnapshotModelScopeIsExhausted,
|
|
39157
39279
|
quotaSnapshotHasStandardWindows,
|
|
39158
39280
|
quotaSnapshotCheckedAt,
|
|
@@ -39389,6 +39511,7 @@ export {
|
|
|
39389
39511
|
createProviderErrorRedactor,
|
|
39390
39512
|
createProcessFence,
|
|
39391
39513
|
createNativeVaultRuntime,
|
|
39514
|
+
createNativeVaultNoRouteResponse,
|
|
39392
39515
|
createNativeUsagePublisher,
|
|
39393
39516
|
createNativeUi,
|
|
39394
39517
|
createNativePoolStore,
|
|
@@ -39501,6 +39624,7 @@ export {
|
|
|
39501
39624
|
PARAGRAPH_REMOVAL_ANCHORS,
|
|
39502
39625
|
OPENCODE_IDENTITY_PREFIX,
|
|
39503
39626
|
OAUTH_SCOPES,
|
|
39627
|
+
NativeVaultQuotaPolicyError,
|
|
39504
39628
|
NativeVaultNoAccountError,
|
|
39505
39629
|
NativeTransientAccountError,
|
|
39506
39630
|
NativeRuntimeError,
|
package/dist/insula-quota.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { InsulaQuotaContext, InsulaUsageEntry } from "./internal-types/clau
|
|
|
2
2
|
import { type AccountQuotaWindow, type AccountScopedQuotaWindow, type OAuthQuotaSnapshot } from './accounts.ts';
|
|
3
3
|
/** An insula reading in the shape our usage poll produces, before the account identity is attached. */
|
|
4
4
|
export type InsulaClaudeQuota = OAuthQuotaSnapshot & {
|
|
5
|
-
five_hour: AccountQuotaWindow;
|
|
6
5
|
seven_day: AccountQuotaWindow;
|
|
7
6
|
scoped: AccountScopedQuotaWindow[];
|
|
8
7
|
checkedAt: number;
|
|
@@ -10,8 +9,8 @@ export type InsulaClaudeQuota = OAuthQuotaSnapshot & {
|
|
|
10
9
|
/**
|
|
11
10
|
* Convert insula's Claude entry into our usage-poll snapshot. Every window's
|
|
12
11
|
* checkedAt is when insula fetched the reading, never when we read its cache,
|
|
13
|
-
* so a newer header or poll reading still wins.
|
|
14
|
-
*
|
|
12
|
+
* so a newer header or poll reading still wins. The weekly window is required;
|
|
13
|
+
* an absent primary slot means the five-hour limit does not apply.
|
|
15
14
|
* The tertiary slot (legacy seven_day_opus/sonnet) is not a window we model.
|
|
16
15
|
*/
|
|
17
16
|
export declare function normalizeInsulaClaudeQuota(entry: InsulaUsageEntry, context: InsulaQuotaContext): InsulaClaudeQuota | undefined;
|
|
@@ -127,8 +127,12 @@ export interface NativeAccountRuntime {
|
|
|
127
127
|
}
|
|
128
128
|
/** Host instances own leases, while stores and the vault connection live until the last release. */
|
|
129
129
|
export declare function acquireNativeAccountRuntime(options: NativeAccountRuntimeOptions): NativeAccountRuntime;
|
|
130
|
+
export type NativeQuotaPolicyLimit = 'quota-floor' | 'killswitch' | 'model-scoped';
|
|
131
|
+
export type NativeAccountPolicy = NativeLocalExternalPolicy & {
|
|
132
|
+
quotaPolicyLimits?: readonly NativeQuotaPolicyLimit[];
|
|
133
|
+
};
|
|
130
134
|
/** Evaluate quota and killswitch policy for this caller's model, outside shared credential refresh work. */
|
|
131
|
-
export declare function nativeAccountPolicy(account: NativeAccountView, snapshot: NativeAccountSnapshot, modelId?: string):
|
|
135
|
+
export declare function nativeAccountPolicy(account: NativeAccountView, snapshot: NativeAccountSnapshot, modelId?: string): NativeAccountPolicy;
|
|
132
136
|
/** The local migration journal records completed transfer from host credentials and sidecars to the credential pool. Local use refuses without that record. Host vault enrollment instead selects independent settings and metadata, leaving local credentials, journal and metadata untouched. */
|
|
133
137
|
export declare function createNativeAccountRuntime(options: NativeAccountRuntimeOptions): NativeAccountRuntime;
|
|
134
138
|
export declare function primeDelta(delta: PrimeUsageDelta): {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type NativeAccountPolicy } from './native-account-runtime.ts';
|
|
2
|
+
import { type NativeAccountSnapshot } from './native-account-view.ts';
|
|
3
|
+
/** Preserve authentication precedence, then explain the shared policy's exclusions. */
|
|
4
|
+
export declare function createNativeVaultNoRouteResponse(input: {
|
|
5
|
+
snapshot: NativeAccountSnapshot;
|
|
6
|
+
modelId?: string;
|
|
7
|
+
policies?: ReadonlyMap<string, NativeAccountPolicy>;
|
|
8
|
+
sticky?: boolean;
|
|
9
|
+
}): Response;
|
|
10
|
+
type QuotaPolicyBody = {
|
|
11
|
+
type: 'error';
|
|
12
|
+
error: {
|
|
13
|
+
type: 'rate_limit_error';
|
|
14
|
+
message: string;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/** OpenCode 2 selection refuses before sending; its chooser cannot return a Response. */
|
|
18
|
+
export declare class NativeVaultQuotaPolicyError extends Error {
|
|
19
|
+
readonly response: Response;
|
|
20
|
+
readonly body: QuotaPolicyBody;
|
|
21
|
+
readonly kind = "quota-policy";
|
|
22
|
+
readonly status = 429;
|
|
23
|
+
readonly headers: Headers;
|
|
24
|
+
readonly retryAfter: number;
|
|
25
|
+
private constructor();
|
|
26
|
+
static fromResponse(response: Response): Promise<NativeVaultQuotaPolicyError>;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
package/dist/sticky-routing.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AccountOperationError, type AccountStorage, type OAuthQuotaSnapshot } from './accounts.ts';
|
|
2
|
+
import type { NativeQuotaPolicyLimit } from './native-account-runtime.ts';
|
|
2
3
|
import { type NativeLockEvent } from './native-lock-observer.ts';
|
|
3
4
|
import type { NativeVaultRosterDocument } from './native-roster-seed.ts';
|
|
4
5
|
import { type NativeVaultRoutingSeed } from './native-vault-seed.ts';
|
|
@@ -60,6 +61,7 @@ export declare function createStickyNoRouteResponse(input: {
|
|
|
60
61
|
mainRefreshError?: AccountOperationError;
|
|
61
62
|
fallbackReauthLabels?: readonly string[];
|
|
62
63
|
routeQuotas: readonly OAuthQuotaSnapshot[];
|
|
64
|
+
vaultPolicyLimits?: readonly NativeQuotaPolicyLimit[];
|
|
63
65
|
modelId?: string;
|
|
64
66
|
now?: number;
|
|
65
67
|
}): Response;
|
|
@@ -86,6 +88,7 @@ export declare function stickyRouteCandidateWeight(input: {
|
|
|
86
88
|
modelId?: string;
|
|
87
89
|
storage: AccountStorage | null;
|
|
88
90
|
now?: number;
|
|
91
|
+
onPolicyBlock?: (limit: NativeQuotaPolicyLimit) => void;
|
|
89
92
|
}): number;
|
|
90
93
|
export declare function stickyRouteKnownFableExhausted(candidate: StickyRouteCandidate, storage: AccountStorage | null, now?: number): boolean;
|
|
91
94
|
export declare function decideStickyQuotaFailure(input: {
|