@cortexkit/anthropic-auth-core 1.23.0 → 2.0.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 +2 -0
- package/dist/accounts.d.ts +3 -16
- package/dist/cachekeep.d.ts +9 -0
- package/dist/claude-code.d.ts +16 -0
- package/dist/claustrum-enrollment.d.ts +2 -0
- package/dist/claustrum-scoped-roster.d.ts +4 -0
- package/dist/claustrum-scoped-runtime.d.ts +3 -0
- package/dist/claustrum-scoped.d.ts +14 -0
- package/dist/claustrum.d.ts +0 -209
- package/dist/commands/account.d.ts +2 -3
- package/dist/index.d.ts +44 -1
- package/dist/index.js +29700 -38
- package/dist/internal-types/LICENSE +21 -0
- package/dist/internal-types/commands/builtins.d.ts +71 -0
- package/dist/internal-types/commands/index.d.ts +10 -0
- package/dist/internal-types/commands/menu.d.ts +61 -0
- package/dist/internal-types/commands/model.d.ts +238 -0
- package/dist/internal-types/commands/pi.d.ts +23 -0
- package/dist/internal-types/commands/seam.d.ts +72 -0
- package/dist/internal-types/fs/refresh-file-lock.d.ts +33 -0
- package/dist/internal-types/logger/capture-sink.d.ts +14 -0
- package/dist/internal-types/logger/engine.d.ts +100 -0
- package/dist/internal-types/logger/index.d.ts +6 -0
- package/dist/internal-types/logger/redact.d.ts +11 -0
- package/dist/internal-types/pi-slot/index.d.ts +3 -0
- package/dist/internal-types/pi-slot/slot.d.ts +49 -0
- package/dist/internal-types/quota/codec.d.ts +11 -0
- package/dist/internal-types/quota/format.d.ts +46 -0
- package/dist/internal-types/quota/index.d.ts +10 -0
- package/dist/internal-types/quota/map.d.ts +63 -0
- package/dist/internal-types/quota/merge.d.ts +48 -0
- package/dist/internal-types/quota/projection.d.ts +64 -0
- package/dist/internal-types/store/attribution.d.ts +28 -0
- package/dist/internal-types/store/errors.d.ts +55 -0
- package/dist/internal-types/store/hooks.d.ts +12 -0
- package/dist/internal-types/store/identity.d.ts +39 -0
- package/dist/internal-types/store/index.d.ts +21 -0
- package/dist/internal-types/store/mutate.d.ts +189 -0
- package/dist/internal-types/store/pool.d.ts +196 -0
- package/dist/internal-types/store/provider-state.d.ts +131 -0
- package/dist/internal-types/store/publication.d.ts +47 -0
- package/dist/internal-types/store/pull.d.ts +36 -0
- package/dist/internal-types/store/refresh-lock.d.ts +63 -0
- package/dist/internal-types/store/refresh.d.ts +72 -0
- package/dist/internal-types/store/rows.d.ts +313 -0
- package/dist/internal-types/store/runtime.d.ts +36 -0
- package/dist/internal-types/store/schema.d.ts +443 -0
- package/dist/internal-types/store/settings.d.ts +63 -0
- package/dist/internal-types/store/torn.d.ts +78 -0
- package/dist/migration-source.d.ts +33 -0
- package/dist/models.d.ts +41 -0
- package/dist/native-account-runtime.d.ts +121 -0
- package/dist/native-account-view.d.ts +126 -0
- package/dist/native-command-effects.d.ts +59 -0
- package/dist/native-credential-validation.d.ts +42 -0
- package/dist/native-custody-activation.d.ts +45 -0
- package/dist/native-custody.d.ts +114 -0
- package/dist/native-enrollment-authority.d.ts +2 -0
- package/dist/native-host-auth-read.d.ts +3 -0
- package/dist/native-host-auth-write.d.ts +51 -0
- package/dist/native-host-auth.d.ts +12 -0
- package/dist/native-local-credential-service.d.ts +76 -0
- package/dist/native-local-runtime-readers.d.ts +22 -0
- package/dist/native-lock-observer.d.ts +12 -0
- package/dist/native-menu-executor.d.ts +243 -0
- package/dist/native-menu-model.d.ts +142 -0
- package/dist/native-migration-proof.d.ts +28 -0
- package/dist/native-migration-source.d.ts +47 -0
- package/dist/native-migration.d.ts +66 -0
- package/dist/native-quota-codec.d.ts +32 -0
- package/dist/native-refresh-coordinator.d.ts +240 -0
- package/dist/native-roster-seed.d.ts +115 -0
- package/dist/native-runtime-registry.d.ts +19 -0
- package/dist/native-runtime.d.ts +204 -0
- package/dist/native-transient-account.d.ts +38 -0
- package/dist/native-ui.d.ts +45 -0
- package/dist/native-usage-publication.d.ts +11 -0
- package/dist/native-vault-admission.d.ts +8 -0
- package/dist/native-vault-connection.d.ts +33 -0
- package/dist/native-vault-paths.d.ts +13 -0
- package/dist/native-vault-runtime.d.ts +102 -0
- package/dist/native-vault-seed.d.ts +16 -0
- package/dist/pool-authority.d.ts +159 -0
- package/dist/pool-binding.d.ts +32 -0
- package/dist/pool-paths.d.ts +21 -0
- package/dist/pool-store.d.ts +32 -0
- package/dist/provider-error.d.ts +139 -0
- package/dist/quota-manager.d.ts +18 -7
- package/dist/relay.d.ts +14 -1
- package/dist/request-history.d.ts +34 -0
- package/dist/sse.d.ts +81 -0
- package/dist/sticky-routing.d.ts +27 -0
- package/package.json +9 -4
- package/dist/accounts.js +0 -3881
- package/dist/auth.js +0 -185
- package/dist/cache1h.js +0 -97
- package/dist/cachekeep-registry.js +0 -124
- package/dist/cachekeep.js +0 -604
- package/dist/cch.js +0 -172
- package/dist/claude-code.js +0 -403
- package/dist/claustrum-enrollment-registry.d.ts +0 -17
- package/dist/claustrum-enrollment-registry.js +0 -194
- package/dist/claustrum-enrollment.js +0 -485
- package/dist/claustrum-scoped-roster.js +0 -194
- package/dist/claustrum-scoped-runtime.js +0 -230
- package/dist/claustrum-scoped.js +0 -193
- package/dist/claustrum.js +0 -1471
- package/dist/commands/account.js +0 -368
- package/dist/constants.js +0 -83
- package/dist/custom-headers.js +0 -102
- package/dist/dump.js +0 -616
- package/dist/fast.js +0 -66
- package/dist/json.js +0 -10
- package/dist/killswitch.js +0 -132
- package/dist/logger.js +0 -288
- package/dist/logging.js +0 -59
- package/dist/mid-conversation-output-config.js +0 -89
- package/dist/model-remap.js +0 -72
- package/dist/models.js +0 -177
- package/dist/network-errors.js +0 -27
- package/dist/oauth-profile.js +0 -60
- package/dist/pkce.js +0 -17
- package/dist/prime.js +0 -841
- package/dist/provider.js +0 -0
- package/dist/quota-header-feed.js +0 -331
- package/dist/quota-headers.js +0 -121
- package/dist/quota-manager.js +0 -856
- package/dist/quotas.js +0 -141
- package/dist/relay.js +0 -1303
- package/dist/routing.js +0 -94
- package/dist/start.js +0 -29
- package/dist/sticky-routing.js +0 -541
- package/dist/thinking-binding.js +0 -54
- package/dist/token-fingerprint.js +0 -8
package/dist/provider.js
DELETED
|
File without changes
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { chmod, lstat, mkdir, readdir, readFile, rename, rm, stat, writeFile, } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
|
-
import { isOAuthAccount, QUOTA_FIELD_NAMES, } from './accounts.js';
|
|
6
|
-
export const QUOTA_HEADER_FEED_SCHEMA_VERSION = 3;
|
|
7
|
-
export const QUOTA_HEADER_FEED_LEASE_MS = 180_000;
|
|
8
|
-
export function getDefaultQuotaHeaderFeedDirectory() {
|
|
9
|
-
return (process.env.OPENCODE_ANTHROPIC_AUTH_QUOTA_FEED_DIR ??
|
|
10
|
-
join(tmpdir(), 'opencode-anthropic-auth', 'quota-header-feed'));
|
|
11
|
-
}
|
|
12
|
-
export function configuredAnthropicOAuthAccountCount(input) {
|
|
13
|
-
const fallbackCount = input.storage?.accounts.filter(isOAuthAccount).length ?? 0;
|
|
14
|
-
return fallbackCount + (input.mainOAuthConfigured ? 1 : 0);
|
|
15
|
-
}
|
|
16
|
-
function validIdentity(entry) {
|
|
17
|
-
if (entry.schema_version !== QUOTA_HEADER_FEED_SCHEMA_VERSION ||
|
|
18
|
-
entry.provider !== 'anthropic')
|
|
19
|
-
return false;
|
|
20
|
-
if (!Number.isFinite(entry.configured_account_count) ||
|
|
21
|
-
!Number.isFinite(entry.observed_at_ms))
|
|
22
|
-
return false;
|
|
23
|
-
if (!entry.quota || typeof entry.quota !== 'object')
|
|
24
|
-
return false;
|
|
25
|
-
if (!Object.hasOwn(entry, 'anthropic_account_uuid') ||
|
|
26
|
-
(entry.anthropic_account_uuid !== null &&
|
|
27
|
-
typeof entry.anthropic_account_uuid !== 'string'))
|
|
28
|
-
return false;
|
|
29
|
-
if (entry.identity_source === 'none') {
|
|
30
|
-
return !('credential_id' in entry) && !('account_ref' in entry);
|
|
31
|
-
}
|
|
32
|
-
if (entry.identity_source === 'credential_id') {
|
|
33
|
-
return (typeof entry.credential_id === 'string' &&
|
|
34
|
-
entry.credential_id.length > 0 &&
|
|
35
|
-
entry.credential_id !== 'main' &&
|
|
36
|
-
!('account_ref' in entry));
|
|
37
|
-
}
|
|
38
|
-
if (entry.identity_source === 'account_ref') {
|
|
39
|
-
return (typeof entry.account_ref === 'string' &&
|
|
40
|
-
entry.account_ref.length > 0 &&
|
|
41
|
-
entry.account_ref !== 'main' &&
|
|
42
|
-
!('credential_id' in entry));
|
|
43
|
-
}
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
function validatePublishEntry(entry) {
|
|
47
|
-
if (entry.schema_version !== QUOTA_HEADER_FEED_SCHEMA_VERSION ||
|
|
48
|
-
entry.provider !== 'anthropic' ||
|
|
49
|
-
!validIdentity(entry)) {
|
|
50
|
-
throw new Error('Invalid quota header feed entry');
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function finiteNumber(value) {
|
|
54
|
-
return typeof value === 'number' && Number.isFinite(value);
|
|
55
|
-
}
|
|
56
|
-
function projectQuotaWindow(value) {
|
|
57
|
-
if (!value || typeof value !== 'object')
|
|
58
|
-
return undefined;
|
|
59
|
-
const candidate = value;
|
|
60
|
-
if (!finiteNumber(candidate.usedPercent) ||
|
|
61
|
-
!finiteNumber(candidate.remainingPercent) ||
|
|
62
|
-
!finiteNumber(candidate.checkedAt)) {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
usedPercent: candidate.usedPercent,
|
|
67
|
-
remainingPercent: candidate.remainingPercent,
|
|
68
|
-
...(typeof candidate.resetsAt === 'string' && {
|
|
69
|
-
resetsAt: candidate.resetsAt,
|
|
70
|
-
}),
|
|
71
|
-
checkedAt: candidate.checkedAt,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function projectScopedQuotaWindow(value) {
|
|
75
|
-
if (!value || typeof value !== 'object')
|
|
76
|
-
return undefined;
|
|
77
|
-
const candidate = value;
|
|
78
|
-
const window = projectQuotaWindow(candidate);
|
|
79
|
-
if (!window ||
|
|
80
|
-
typeof candidate.id !== 'string' ||
|
|
81
|
-
!candidate.id.trim() ||
|
|
82
|
-
typeof candidate.title !== 'string' ||
|
|
83
|
-
!candidate.title.trim() ||
|
|
84
|
-
typeof candidate.modelName !== 'string' ||
|
|
85
|
-
!candidate.modelName.trim()) {
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
...window,
|
|
90
|
-
id: candidate.id,
|
|
91
|
-
title: candidate.title,
|
|
92
|
-
...(typeof candidate.modelId === 'string' &&
|
|
93
|
-
candidate.modelId.trim() && {
|
|
94
|
-
modelId: candidate.modelId,
|
|
95
|
-
}),
|
|
96
|
-
modelName: candidate.modelName,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
function projectQuotaMoney(value) {
|
|
100
|
-
if (!value || typeof value !== 'object')
|
|
101
|
-
return undefined;
|
|
102
|
-
const candidate = value;
|
|
103
|
-
if (!finiteNumber(candidate.amountMinor) ||
|
|
104
|
-
typeof candidate.currency !== 'string' ||
|
|
105
|
-
!candidate.currency.trim() ||
|
|
106
|
-
!finiteNumber(candidate.exponent)) {
|
|
107
|
-
return undefined;
|
|
108
|
-
}
|
|
109
|
-
return {
|
|
110
|
-
amountMinor: candidate.amountMinor,
|
|
111
|
-
currency: candidate.currency,
|
|
112
|
-
exponent: candidate.exponent,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function projectExtraUsage(value) {
|
|
116
|
-
if (!value || typeof value !== 'object')
|
|
117
|
-
return undefined;
|
|
118
|
-
const candidate = value;
|
|
119
|
-
const used = projectQuotaMoney(candidate.used);
|
|
120
|
-
const limit = projectQuotaMoney(candidate.limit);
|
|
121
|
-
if (!used || !limit || typeof candidate.exhausted !== 'boolean') {
|
|
122
|
-
return undefined;
|
|
123
|
-
}
|
|
124
|
-
return {
|
|
125
|
-
used,
|
|
126
|
-
limit,
|
|
127
|
-
...(finiteNumber(candidate.utilizationPercent) && {
|
|
128
|
-
utilizationPercent: candidate.utilizationPercent,
|
|
129
|
-
}),
|
|
130
|
-
...(typeof candidate.severity === 'string' && {
|
|
131
|
-
severity: candidate.severity,
|
|
132
|
-
}),
|
|
133
|
-
exhausted: candidate.exhausted,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function projectQuotaProvenance(value, presentFields) {
|
|
137
|
-
if (!value || typeof value !== 'object')
|
|
138
|
-
return undefined;
|
|
139
|
-
const candidate = value;
|
|
140
|
-
const provenance = {};
|
|
141
|
-
for (const field of QUOTA_FIELD_NAMES) {
|
|
142
|
-
if (!presentFields.has(field))
|
|
143
|
-
continue;
|
|
144
|
-
const source = candidate[field];
|
|
145
|
-
if (source === 'poll' || source === 'headers')
|
|
146
|
-
provenance[field] = source;
|
|
147
|
-
}
|
|
148
|
-
return Object.keys(provenance).length > 0 ? provenance : undefined;
|
|
149
|
-
}
|
|
150
|
-
function projectQuota(quota) {
|
|
151
|
-
const fiveHour = projectQuotaWindow(quota.five_hour);
|
|
152
|
-
const sevenDay = projectQuotaWindow(quota.seven_day);
|
|
153
|
-
const scoped = Array.isArray(quota.scoped)
|
|
154
|
-
? quota.scoped
|
|
155
|
-
.map(projectScopedQuotaWindow)
|
|
156
|
-
.filter((entry) => entry != null)
|
|
157
|
-
: undefined;
|
|
158
|
-
const extraUsage = projectExtraUsage(quota.extraUsage);
|
|
159
|
-
const presentFields = new Set();
|
|
160
|
-
if (fiveHour)
|
|
161
|
-
presentFields.add('five_hour');
|
|
162
|
-
if (sevenDay)
|
|
163
|
-
presentFields.add('seven_day');
|
|
164
|
-
if (typeof quota.bindingWindow === 'string') {
|
|
165
|
-
presentFields.add('bindingWindow');
|
|
166
|
-
}
|
|
167
|
-
if (typeof quota.fallbackAdvised === 'boolean') {
|
|
168
|
-
presentFields.add('fallbackAdvised');
|
|
169
|
-
}
|
|
170
|
-
if (scoped)
|
|
171
|
-
presentFields.add('scoped');
|
|
172
|
-
if (extraUsage)
|
|
173
|
-
presentFields.add('extraUsage');
|
|
174
|
-
const provenance = projectQuotaProvenance(quota.fieldSources, presentFields);
|
|
175
|
-
return {
|
|
176
|
-
...(fiveHour && { five_hour: fiveHour }),
|
|
177
|
-
...(sevenDay && { seven_day: sevenDay }),
|
|
178
|
-
...(typeof quota.bindingWindow === 'string' && {
|
|
179
|
-
bindingWindow: quota.bindingWindow,
|
|
180
|
-
}),
|
|
181
|
-
...(typeof quota.fallbackAdvised === 'boolean' && {
|
|
182
|
-
fallbackAdvised: quota.fallbackAdvised,
|
|
183
|
-
}),
|
|
184
|
-
...(scoped && { scoped }),
|
|
185
|
-
...(extraUsage && { extraUsage }),
|
|
186
|
-
...(provenance && { provenance }),
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
export class QuotaHeaderFeedRegistry {
|
|
190
|
-
options;
|
|
191
|
-
filePath;
|
|
192
|
-
writeChain = Promise.resolve();
|
|
193
|
-
constructor(options = {}) {
|
|
194
|
-
this.options = options;
|
|
195
|
-
const instanceId = options.instanceId ?? `${process.pid}-${randomUUID()}`;
|
|
196
|
-
this.filePath = join(options.directory ?? getDefaultQuotaHeaderFeedDirectory(), `${instanceId}.json`);
|
|
197
|
-
}
|
|
198
|
-
publish(entry) {
|
|
199
|
-
const { accountKey, quota } = entry;
|
|
200
|
-
try {
|
|
201
|
-
validatePublishEntry(entry);
|
|
202
|
-
}
|
|
203
|
-
catch (error) {
|
|
204
|
-
return Promise.reject(error);
|
|
205
|
-
}
|
|
206
|
-
const identity = entry.identity_source === 'credential_id'
|
|
207
|
-
? {
|
|
208
|
-
identity_source: 'credential_id',
|
|
209
|
-
credential_id: entry.credential_id,
|
|
210
|
-
}
|
|
211
|
-
: entry.identity_source === 'account_ref'
|
|
212
|
-
? {
|
|
213
|
-
identity_source: 'account_ref',
|
|
214
|
-
account_ref: entry.account_ref,
|
|
215
|
-
}
|
|
216
|
-
: { identity_source: 'none' };
|
|
217
|
-
const cleanEntry = {
|
|
218
|
-
...identity,
|
|
219
|
-
schema_version: entry.schema_version,
|
|
220
|
-
provider: entry.provider,
|
|
221
|
-
configured_account_count: entry.configured_account_count,
|
|
222
|
-
observed_at_ms: entry.observed_at_ms,
|
|
223
|
-
anthropic_account_uuid: entry.anthropic_account_uuid,
|
|
224
|
-
quota: projectQuota(quota),
|
|
225
|
-
};
|
|
226
|
-
if (!accountKey)
|
|
227
|
-
return Promise.reject(new Error('Invalid quota header feed account key'));
|
|
228
|
-
this.writeChain = this.writeChain
|
|
229
|
-
.catch(() => { })
|
|
230
|
-
.then(async () => {
|
|
231
|
-
const directory = this.options.directory ?? getDefaultQuotaHeaderFeedDirectory();
|
|
232
|
-
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
233
|
-
await chmod(directory, 0o700);
|
|
234
|
-
await this.reapStaleSiblingLeases(directory);
|
|
235
|
-
let entries = {};
|
|
236
|
-
try {
|
|
237
|
-
const record = JSON.parse(await readFile(this.filePath, 'utf8'));
|
|
238
|
-
if (record.version === QUOTA_HEADER_FEED_SCHEMA_VERSION &&
|
|
239
|
-
record.entries &&
|
|
240
|
-
typeof record.entries === 'object')
|
|
241
|
-
entries = record.entries;
|
|
242
|
-
}
|
|
243
|
-
catch { }
|
|
244
|
-
entries[accountKey] = cleanEntry;
|
|
245
|
-
const tempPath = `${this.filePath}.${randomUUID()}.tmp`;
|
|
246
|
-
try {
|
|
247
|
-
await writeFile(tempPath, `${JSON.stringify({ version: QUOTA_HEADER_FEED_SCHEMA_VERSION, lease_horizon_ms: this.options.leaseMs ?? QUOTA_HEADER_FEED_LEASE_MS, entries })}\n`, { mode: 0o600 });
|
|
248
|
-
await chmod(tempPath, 0o600);
|
|
249
|
-
await rename(tempPath, this.filePath);
|
|
250
|
-
}
|
|
251
|
-
finally {
|
|
252
|
-
await rm(tempPath, { force: true });
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
return this.writeChain;
|
|
256
|
-
}
|
|
257
|
-
async reapStaleSiblingLeases(directory) {
|
|
258
|
-
const now = this.options.now?.() ?? Date.now();
|
|
259
|
-
const leaseMs = this.options.leaseMs ?? QUOTA_HEADER_FEED_LEASE_MS;
|
|
260
|
-
let names;
|
|
261
|
-
try {
|
|
262
|
-
names = await readdir(directory);
|
|
263
|
-
}
|
|
264
|
-
catch {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
await Promise.all(names
|
|
268
|
-
.filter((name) => /^\d+-[0-9a-f-]+\.json$/i.test(name))
|
|
269
|
-
.map(async (name) => {
|
|
270
|
-
const path = join(directory, name);
|
|
271
|
-
if (path === this.filePath)
|
|
272
|
-
return;
|
|
273
|
-
try {
|
|
274
|
-
const file = await stat(path);
|
|
275
|
-
if (file.mtimeMs > now || now - file.mtimeMs < leaseMs)
|
|
276
|
-
return;
|
|
277
|
-
await this.options.beforeRemoveFile?.(path);
|
|
278
|
-
const current = await lstat(path);
|
|
279
|
-
if (current.ino !== file.ino || current.mtimeMs !== file.mtimeMs)
|
|
280
|
-
return;
|
|
281
|
-
await (this.options.removeFile ?? ((target) => rm(target)))(path);
|
|
282
|
-
}
|
|
283
|
-
catch {
|
|
284
|
-
// A missed cleanup must not prevent this process from refreshing its lease.
|
|
285
|
-
}
|
|
286
|
-
}));
|
|
287
|
-
}
|
|
288
|
-
async list() {
|
|
289
|
-
await this.writeChain.catch(() => { });
|
|
290
|
-
const directory = this.options.directory ?? getDefaultQuotaHeaderFeedDirectory();
|
|
291
|
-
const now = this.options.now?.() ?? Date.now();
|
|
292
|
-
const leaseMs = this.options.leaseMs ?? QUOTA_HEADER_FEED_LEASE_MS;
|
|
293
|
-
let names;
|
|
294
|
-
try {
|
|
295
|
-
names = (await readdir(directory)).filter((name) => name.endsWith('.json'));
|
|
296
|
-
}
|
|
297
|
-
catch {
|
|
298
|
-
return [];
|
|
299
|
-
}
|
|
300
|
-
const newest = new Map();
|
|
301
|
-
await Promise.all(names.map(async (name) => {
|
|
302
|
-
try {
|
|
303
|
-
const record = JSON.parse(await readFile(join(directory, name), 'utf8'));
|
|
304
|
-
if (record.version !== QUOTA_HEADER_FEED_SCHEMA_VERSION ||
|
|
305
|
-
!record.entries ||
|
|
306
|
-
typeof record.entries !== 'object')
|
|
307
|
-
return;
|
|
308
|
-
for (const [accountKey, candidate] of Object.entries(record.entries)) {
|
|
309
|
-
if (!candidate ||
|
|
310
|
-
typeof candidate !== 'object' ||
|
|
311
|
-
candidate.schema_version !== QUOTA_HEADER_FEED_SCHEMA_VERSION ||
|
|
312
|
-
candidate.provider !== 'anthropic' ||
|
|
313
|
-
!validIdentity(candidate))
|
|
314
|
-
continue;
|
|
315
|
-
const observed = candidate.observed_at_ms;
|
|
316
|
-
if (observed > now || now - observed >= leaseMs)
|
|
317
|
-
continue;
|
|
318
|
-
const existing = newest.get(accountKey);
|
|
319
|
-
if (!existing || observed > existing.observed_at_ms)
|
|
320
|
-
newest.set(accountKey, candidate);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
catch { }
|
|
324
|
-
}));
|
|
325
|
-
return [...newest.values()].sort((a, b) => a.observed_at_ms - b.observed_at_ms);
|
|
326
|
-
}
|
|
327
|
-
async dispose() {
|
|
328
|
-
await this.writeChain.catch(() => { });
|
|
329
|
-
await rm(this.filePath, { force: true });
|
|
330
|
-
}
|
|
331
|
-
}
|
package/dist/quota-headers.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { QUOTA_FIELD_NAMES, quotaFieldSource } from './accounts.js';
|
|
2
|
-
const PREFIX = 'anthropic-ratelimit-unified-';
|
|
3
|
-
const WINDOW_KEYS = {
|
|
4
|
-
'5h': 'five_hour',
|
|
5
|
-
'7d': 'seven_day',
|
|
6
|
-
};
|
|
7
|
-
export function isQuotaBearingHeaderFrame(headers) {
|
|
8
|
-
return Object.keys(WINDOW_KEYS).some((suffix) => Number.isFinite(finiteHeaderNumber(headers, `${PREFIX}${suffix}-utilization`)));
|
|
9
|
-
}
|
|
10
|
-
function finiteHeaderNumber(headers, name) {
|
|
11
|
-
const value = headers.get(name);
|
|
12
|
-
if (value == null || value.trim() === '')
|
|
13
|
-
return undefined;
|
|
14
|
-
const parsed = Number(value);
|
|
15
|
-
return Number.isFinite(parsed) ? parsed : undefined;
|
|
16
|
-
}
|
|
17
|
-
function normalizeWindow(headers, suffix, checkedAt) {
|
|
18
|
-
const utilization = finiteHeaderNumber(headers, `${PREFIX}${suffix}-utilization`);
|
|
19
|
-
if (utilization == null)
|
|
20
|
-
return undefined;
|
|
21
|
-
const usedPercent = Math.min(100, Math.max(0, Math.round(utilization * 100)));
|
|
22
|
-
const resetSeconds = finiteHeaderNumber(headers, `${PREFIX}${suffix}-reset`);
|
|
23
|
-
const resetDate = resetSeconds == null ? undefined : new Date(resetSeconds * 1000);
|
|
24
|
-
const resetsAt = resetDate && Number.isFinite(resetDate.getTime())
|
|
25
|
-
? resetDate.toISOString()
|
|
26
|
-
: undefined;
|
|
27
|
-
return {
|
|
28
|
-
usedPercent,
|
|
29
|
-
remainingPercent: 100 - usedPercent,
|
|
30
|
-
...(resetsAt && { resetsAt }),
|
|
31
|
-
checkedAt,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
export function normalizeQuotaHeaders(headers, now = Date.now()) {
|
|
35
|
-
const fieldSources = {};
|
|
36
|
-
const fallbackHeader = headers.get(`${PREFIX}fallback`);
|
|
37
|
-
const snapshot = {
|
|
38
|
-
fallbackAdvised: fallbackHeader === 'available',
|
|
39
|
-
source: 'headers',
|
|
40
|
-
checkedAt: now,
|
|
41
|
-
};
|
|
42
|
-
for (const [suffix, key] of Object.entries(WINDOW_KEYS)) {
|
|
43
|
-
const window = normalizeWindow(headers, suffix, now);
|
|
44
|
-
if (window) {
|
|
45
|
-
snapshot[key] = window;
|
|
46
|
-
fieldSources[key] = 'headers';
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
const representativeClaim = headers.get(`${PREFIX}representative-claim`);
|
|
50
|
-
if (representativeClaim) {
|
|
51
|
-
snapshot.bindingWindow = representativeClaim;
|
|
52
|
-
snapshot.bindingWindowSource = 'headers';
|
|
53
|
-
fieldSources.bindingWindow = 'headers';
|
|
54
|
-
}
|
|
55
|
-
if (fallbackHeader !== null)
|
|
56
|
-
fieldSources.fallbackAdvised = 'headers';
|
|
57
|
-
return {
|
|
58
|
-
...snapshot,
|
|
59
|
-
fieldSources,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
export function mergeHeaderQuotaSnapshot(existing, incoming) {
|
|
63
|
-
const { scoped: existingScoped, extraUsage: existingExtraUsage, fieldSources: existingFieldSources, ...existingWithoutPollOwnedFields } = existing ?? {};
|
|
64
|
-
const { scoped: _incomingScoped, extraUsage: _incomingExtraUsage, fieldSources: incomingFieldSources, ...incomingWithoutPollOwnedFields } = incoming;
|
|
65
|
-
const fieldSources = {};
|
|
66
|
-
for (const field of QUOTA_FIELD_NAMES) {
|
|
67
|
-
const value = field === 'scoped'
|
|
68
|
-
? existingScoped
|
|
69
|
-
: field === 'extraUsage'
|
|
70
|
-
? existingExtraUsage
|
|
71
|
-
: field === 'fallbackAdvised'
|
|
72
|
-
? incomingFieldSources?.fallbackAdvised !== undefined
|
|
73
|
-
? incoming.fallbackAdvised
|
|
74
|
-
: (existing?.fallbackAdvised ?? incoming.fallbackAdvised)
|
|
75
|
-
: field === 'bindingWindow'
|
|
76
|
-
? existing?.bindingWindowSource === 'poll'
|
|
77
|
-
? existing?.bindingWindow
|
|
78
|
-
: (incoming.bindingWindow ?? existing?.bindingWindow)
|
|
79
|
-
: (incoming[field] ?? existing?.[field]);
|
|
80
|
-
if (value === undefined)
|
|
81
|
-
continue;
|
|
82
|
-
const source = field === 'fallbackAdvised'
|
|
83
|
-
? (incomingFieldSources?.fallbackAdvised ??
|
|
84
|
-
(existing?.fallbackAdvised !== undefined
|
|
85
|
-
? existingFieldSources
|
|
86
|
-
? existingFieldSources.fallbackAdvised
|
|
87
|
-
: quotaFieldSource(existing, field)
|
|
88
|
-
: undefined))
|
|
89
|
-
: (field === 'scoped' || field === 'extraUsage') && value !== undefined
|
|
90
|
-
? 'poll'
|
|
91
|
-
: field === 'bindingWindow' &&
|
|
92
|
-
existing?.bindingWindowSource === 'poll' &&
|
|
93
|
-
existing.bindingWindow !== undefined
|
|
94
|
-
? 'poll'
|
|
95
|
-
: incoming[field] !== undefined
|
|
96
|
-
? (incomingFieldSources?.[field] ??
|
|
97
|
-
quotaFieldSource(incoming, field))
|
|
98
|
-
: (existingFieldSources?.[field] ??
|
|
99
|
-
quotaFieldSource(existing, field));
|
|
100
|
-
if (source)
|
|
101
|
-
fieldSources[field] = source;
|
|
102
|
-
}
|
|
103
|
-
return {
|
|
104
|
-
...existingWithoutPollOwnedFields,
|
|
105
|
-
...incomingWithoutPollOwnedFields,
|
|
106
|
-
...(Array.isArray(existingScoped) && { scoped: existingScoped }),
|
|
107
|
-
...(existingExtraUsage != null && { extraUsage: existingExtraUsage }),
|
|
108
|
-
fallbackAdvised: incomingFieldSources?.fallbackAdvised !== undefined
|
|
109
|
-
? incoming.fallbackAdvised
|
|
110
|
-
: (existing?.fallbackAdvised ?? incoming.fallbackAdvised),
|
|
111
|
-
bindingWindow: existing?.bindingWindowSource === 'poll'
|
|
112
|
-
? existing.bindingWindow
|
|
113
|
-
: (incoming.bindingWindow ?? existing?.bindingWindow),
|
|
114
|
-
bindingWindowSource: existing?.bindingWindowSource === 'poll'
|
|
115
|
-
? 'poll'
|
|
116
|
-
: (incoming.bindingWindowSource ?? existing?.bindingWindowSource),
|
|
117
|
-
...(Object.keys(fieldSources).length > 0 && { fieldSources }),
|
|
118
|
-
// Top-level source remains headers for compatibility; fieldSources records ownership after partial harvests.
|
|
119
|
-
source: 'headers',
|
|
120
|
-
};
|
|
121
|
-
}
|