@cortexkit/anthropic-auth-core 1.21.0 → 1.23.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 +1 -1
- package/dist/accounts.d.ts +100 -3
- package/dist/accounts.js +1099 -169
- package/dist/auth.js +6 -10
- package/dist/cachekeep.d.ts +18 -1
- package/dist/cachekeep.js +108 -82
- package/dist/cch.d.ts +23 -9
- package/dist/cch.js +104 -21
- package/dist/claude-code.d.ts +8 -3
- package/dist/claude-code.js +24 -7
- package/dist/claustrum-enrollment-registry.d.ts +17 -0
- package/dist/claustrum-enrollment-registry.js +194 -0
- package/dist/claustrum-enrollment.d.ts +70 -0
- package/dist/claustrum-enrollment.js +485 -0
- package/dist/claustrum-scoped-roster.d.ts +23 -0
- package/dist/claustrum-scoped-roster.js +194 -0
- package/dist/claustrum-scoped-runtime.d.ts +28 -0
- package/dist/claustrum-scoped-runtime.js +230 -0
- package/dist/claustrum-scoped.d.ts +39 -0
- package/dist/claustrum-scoped.js +193 -0
- package/dist/claustrum.d.ts +252 -0
- package/dist/claustrum.js +1471 -0
- package/dist/commands/account.d.ts +43 -11
- package/dist/commands/account.js +147 -4
- package/dist/constants.d.ts +5 -5
- package/dist/constants.js +5 -5
- package/dist/custom-headers.d.ts +3 -0
- package/dist/custom-headers.js +102 -0
- package/dist/dump.js +2 -1
- package/dist/fast.js +1 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/dist/json.d.ts +1 -0
- package/dist/json.js +10 -0
- package/dist/logger.js +3 -1
- package/dist/mid-conversation-output-config.d.ts +13 -0
- package/dist/mid-conversation-output-config.js +89 -0
- package/dist/model-remap.d.ts +27 -0
- package/dist/model-remap.js +72 -0
- package/dist/models.d.ts +46 -1
- package/dist/models.js +87 -8
- package/dist/network-errors.d.ts +1 -0
- package/dist/network-errors.js +27 -0
- package/dist/oauth-profile.d.ts +2 -1
- package/dist/oauth-profile.js +6 -0
- package/dist/prime.d.ts +11 -3
- package/dist/prime.js +25 -7
- package/dist/quota-header-feed.d.ts +32 -7
- package/dist/quota-header-feed.js +93 -10
- package/dist/quota-headers.js +59 -6
- package/dist/quota-manager.d.ts +20 -2
- package/dist/quota-manager.js +101 -24
- package/dist/relay.d.ts +8 -0
- package/dist/relay.js +72 -12
- package/dist/sticky-routing.d.ts +2 -0
- package/dist/sticky-routing.js +19 -1
- package/dist/thinking-binding.d.ts +7 -0
- package/dist/thinking-binding.js +54 -0
- package/package.json +4 -1
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import { type AccountStorage, type OAuthQuotaSnapshot } from './accounts.ts';
|
|
2
|
-
export declare const QUOTA_HEADER_FEED_SCHEMA_VERSION =
|
|
1
|
+
import { type AccountStorage, type OAuthQuotaSnapshot, type QuotaFieldName, type QuotaFieldSource, type QuotaFieldSources } from './accounts.ts';
|
|
2
|
+
export declare const QUOTA_HEADER_FEED_SCHEMA_VERSION = 3;
|
|
3
3
|
export declare const QUOTA_HEADER_FEED_LEASE_MS = 180000;
|
|
4
|
+
/**
|
|
5
|
+
* Lease files are per process; each carries only the accounts whose response
|
|
6
|
+
* headers THAT process harvested. Consumers MUST union entries across all files
|
|
7
|
+
* inside `lease_horizon_ms`, deduplicating by account; "newest file wins" is wrong.
|
|
8
|
+
* `anthropic_account_uuid` is always present: null is unresolvable, while absence
|
|
9
|
+
* identifies an old producer. A fallback `account_ref` is store-local.
|
|
10
|
+
*/
|
|
4
11
|
export type QuotaHeaderFeedIdentity = {
|
|
5
12
|
identity_source: 'credential_id';
|
|
6
13
|
credential_id: string;
|
|
@@ -10,12 +17,28 @@ export type QuotaHeaderFeedIdentity = {
|
|
|
10
17
|
} | {
|
|
11
18
|
identity_source: 'none';
|
|
12
19
|
};
|
|
13
|
-
export type
|
|
20
|
+
export type QuotaHeaderFeedProvenance = Partial<Record<QuotaFieldName, QuotaFieldSource>>;
|
|
21
|
+
type QuotaHeaderFeedQuota = Pick<OAuthQuotaSnapshot, 'five_hour' | 'seven_day' | 'bindingWindow' | 'fallbackAdvised' | 'scoped' | 'extraUsage'> & {
|
|
22
|
+
provenance?: QuotaHeaderFeedProvenance;
|
|
23
|
+
};
|
|
24
|
+
type QuotaHeaderFeedMetadata = {
|
|
14
25
|
schema_version: typeof QUOTA_HEADER_FEED_SCHEMA_VERSION;
|
|
15
26
|
provider: 'anthropic';
|
|
16
27
|
configured_account_count: number;
|
|
28
|
+
/** Header observation time; merged poll-owned fields retain their own checkedAt. */
|
|
17
29
|
observed_at_ms: number;
|
|
18
|
-
|
|
30
|
+
};
|
|
31
|
+
export type QuotaHeaderFeedEntry = QuotaHeaderFeedIdentity & QuotaHeaderFeedMetadata & {
|
|
32
|
+
/** Always present: null means UUID resolution failed; absence denotes an old producer. */
|
|
33
|
+
anthropic_account_uuid: string | null;
|
|
34
|
+
quota: QuotaHeaderFeedQuota;
|
|
35
|
+
};
|
|
36
|
+
export type QuotaHeaderFeedPublishEntry = QuotaHeaderFeedIdentity & QuotaHeaderFeedMetadata & {
|
|
37
|
+
anthropic_account_uuid: string | null;
|
|
38
|
+
quota: Omit<QuotaHeaderFeedQuota, 'provenance'> & {
|
|
39
|
+
fieldSources?: QuotaFieldSources;
|
|
40
|
+
};
|
|
41
|
+
accountKey: string;
|
|
19
42
|
};
|
|
20
43
|
export declare function getDefaultQuotaHeaderFeedDirectory(): string;
|
|
21
44
|
export declare function configuredAnthropicOAuthAccountCount(input: {
|
|
@@ -31,10 +54,12 @@ export declare class QuotaHeaderFeedRegistry {
|
|
|
31
54
|
now?: () => number;
|
|
32
55
|
leaseMs?: number;
|
|
33
56
|
instanceId?: string;
|
|
57
|
+
removeFile?: (path: string) => Promise<void>;
|
|
58
|
+
beforeRemoveFile?: (path: string) => Promise<void>;
|
|
34
59
|
});
|
|
35
|
-
publish(entry:
|
|
36
|
-
|
|
37
|
-
}): Promise<void>;
|
|
60
|
+
publish(entry: QuotaHeaderFeedPublishEntry): Promise<void>;
|
|
61
|
+
private reapStaleSiblingLeases;
|
|
38
62
|
list(): Promise<QuotaHeaderFeedEntry[]>;
|
|
39
63
|
dispose(): Promise<void>;
|
|
40
64
|
}
|
|
65
|
+
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { chmod, mkdir, readdir, readFile, rename, rm, writeFile, } from 'node:fs/promises';
|
|
2
|
+
import { chmod, lstat, mkdir, readdir, readFile, rename, rm, stat, writeFile, } from 'node:fs/promises';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import { isOAuthAccount, } from './accounts.js';
|
|
6
|
-
export const QUOTA_HEADER_FEED_SCHEMA_VERSION =
|
|
5
|
+
import { isOAuthAccount, QUOTA_FIELD_NAMES, } from './accounts.js';
|
|
6
|
+
export const QUOTA_HEADER_FEED_SCHEMA_VERSION = 3;
|
|
7
7
|
export const QUOTA_HEADER_FEED_LEASE_MS = 180_000;
|
|
8
8
|
export function getDefaultQuotaHeaderFeedDirectory() {
|
|
9
9
|
return (process.env.OPENCODE_ANTHROPIC_AUTH_QUOTA_FEED_DIR ??
|
|
@@ -22,6 +22,10 @@ function validIdentity(entry) {
|
|
|
22
22
|
return false;
|
|
23
23
|
if (!entry.quota || typeof entry.quota !== 'object')
|
|
24
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;
|
|
25
29
|
if (entry.identity_source === 'none') {
|
|
26
30
|
return !('credential_id' in entry) && !('account_ref' in entry);
|
|
27
31
|
}
|
|
@@ -129,6 +133,20 @@ function projectExtraUsage(value) {
|
|
|
129
133
|
exhausted: candidate.exhausted,
|
|
130
134
|
};
|
|
131
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
|
+
}
|
|
132
150
|
function projectQuota(quota) {
|
|
133
151
|
const fiveHour = projectQuotaWindow(quota.five_hour);
|
|
134
152
|
const sevenDay = projectQuotaWindow(quota.seven_day);
|
|
@@ -138,6 +156,22 @@ function projectQuota(quota) {
|
|
|
138
156
|
.filter((entry) => entry != null)
|
|
139
157
|
: undefined;
|
|
140
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);
|
|
141
175
|
return {
|
|
142
176
|
...(fiveHour && { five_hour: fiveHour }),
|
|
143
177
|
...(sevenDay && { seven_day: sevenDay }),
|
|
@@ -149,6 +183,7 @@ function projectQuota(quota) {
|
|
|
149
183
|
}),
|
|
150
184
|
...(scoped && { scoped }),
|
|
151
185
|
...(extraUsage && { extraUsage }),
|
|
186
|
+
...(provenance && { provenance }),
|
|
152
187
|
};
|
|
153
188
|
}
|
|
154
189
|
export class QuotaHeaderFeedRegistry {
|
|
@@ -161,17 +196,33 @@ export class QuotaHeaderFeedRegistry {
|
|
|
161
196
|
this.filePath = join(options.directory ?? getDefaultQuotaHeaderFeedDirectory(), `${instanceId}.json`);
|
|
162
197
|
}
|
|
163
198
|
publish(entry) {
|
|
164
|
-
const { accountKey, quota
|
|
165
|
-
const cleanEntry = {
|
|
166
|
-
...entryWithoutQuota,
|
|
167
|
-
quota: projectQuota(quota),
|
|
168
|
-
};
|
|
199
|
+
const { accountKey, quota } = entry;
|
|
169
200
|
try {
|
|
170
|
-
validatePublishEntry(
|
|
201
|
+
validatePublishEntry(entry);
|
|
171
202
|
}
|
|
172
203
|
catch (error) {
|
|
173
204
|
return Promise.reject(error);
|
|
174
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
|
+
};
|
|
175
226
|
if (!accountKey)
|
|
176
227
|
return Promise.reject(new Error('Invalid quota header feed account key'));
|
|
177
228
|
this.writeChain = this.writeChain
|
|
@@ -180,6 +231,7 @@ export class QuotaHeaderFeedRegistry {
|
|
|
180
231
|
const directory = this.options.directory ?? getDefaultQuotaHeaderFeedDirectory();
|
|
181
232
|
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
182
233
|
await chmod(directory, 0o700);
|
|
234
|
+
await this.reapStaleSiblingLeases(directory);
|
|
183
235
|
let entries = {};
|
|
184
236
|
try {
|
|
185
237
|
const record = JSON.parse(await readFile(this.filePath, 'utf8'));
|
|
@@ -192,7 +244,7 @@ export class QuotaHeaderFeedRegistry {
|
|
|
192
244
|
entries[accountKey] = cleanEntry;
|
|
193
245
|
const tempPath = `${this.filePath}.${randomUUID()}.tmp`;
|
|
194
246
|
try {
|
|
195
|
-
await writeFile(tempPath, `${JSON.stringify({ version: QUOTA_HEADER_FEED_SCHEMA_VERSION, entries })}\n`, { mode: 0o600 });
|
|
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 });
|
|
196
248
|
await chmod(tempPath, 0o600);
|
|
197
249
|
await rename(tempPath, this.filePath);
|
|
198
250
|
}
|
|
@@ -202,6 +254,37 @@ export class QuotaHeaderFeedRegistry {
|
|
|
202
254
|
});
|
|
203
255
|
return this.writeChain;
|
|
204
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
|
+
}
|
|
205
288
|
async list() {
|
|
206
289
|
await this.writeChain.catch(() => { });
|
|
207
290
|
const directory = this.options.directory ?? getDefaultQuotaHeaderFeedDirectory();
|
package/dist/quota-headers.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { QUOTA_FIELD_NAMES, quotaFieldSource } from './accounts.js';
|
|
1
2
|
const PREFIX = 'anthropic-ratelimit-unified-';
|
|
2
3
|
const WINDOW_KEYS = {
|
|
3
4
|
'5h': 'five_hour',
|
|
@@ -31,38 +32,90 @@ function normalizeWindow(headers, suffix, checkedAt) {
|
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
34
|
export function normalizeQuotaHeaders(headers, now = Date.now()) {
|
|
35
|
+
const fieldSources = {};
|
|
36
|
+
const fallbackHeader = headers.get(`${PREFIX}fallback`);
|
|
34
37
|
const snapshot = {
|
|
35
|
-
fallbackAdvised:
|
|
38
|
+
fallbackAdvised: fallbackHeader === 'available',
|
|
36
39
|
source: 'headers',
|
|
37
40
|
checkedAt: now,
|
|
38
41
|
};
|
|
39
42
|
for (const [suffix, key] of Object.entries(WINDOW_KEYS)) {
|
|
40
43
|
const window = normalizeWindow(headers, suffix, now);
|
|
41
|
-
if (window)
|
|
44
|
+
if (window) {
|
|
42
45
|
snapshot[key] = window;
|
|
46
|
+
fieldSources[key] = 'headers';
|
|
47
|
+
}
|
|
43
48
|
}
|
|
44
49
|
const representativeClaim = headers.get(`${PREFIX}representative-claim`);
|
|
45
50
|
if (representativeClaim) {
|
|
46
51
|
snapshot.bindingWindow = representativeClaim;
|
|
47
52
|
snapshot.bindingWindowSource = 'headers';
|
|
53
|
+
fieldSources.bindingWindow = 'headers';
|
|
48
54
|
}
|
|
49
|
-
|
|
55
|
+
if (fallbackHeader !== null)
|
|
56
|
+
fieldSources.fallbackAdvised = 'headers';
|
|
57
|
+
return {
|
|
58
|
+
...snapshot,
|
|
59
|
+
fieldSources,
|
|
60
|
+
};
|
|
50
61
|
}
|
|
51
62
|
export function mergeHeaderQuotaSnapshot(existing, incoming) {
|
|
52
|
-
const { scoped: existingScoped, extraUsage: existingExtraUsage, ...existingWithoutPollOwnedFields } = existing ?? {};
|
|
53
|
-
const { scoped: _incomingScoped, extraUsage: _incomingExtraUsage, ...incomingWithoutPollOwnedFields } = 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
|
+
}
|
|
54
103
|
return {
|
|
55
104
|
...existingWithoutPollOwnedFields,
|
|
56
105
|
...incomingWithoutPollOwnedFields,
|
|
57
106
|
...(Array.isArray(existingScoped) && { scoped: existingScoped }),
|
|
58
107
|
...(existingExtraUsage != null && { extraUsage: existingExtraUsage }),
|
|
108
|
+
fallbackAdvised: incomingFieldSources?.fallbackAdvised !== undefined
|
|
109
|
+
? incoming.fallbackAdvised
|
|
110
|
+
: (existing?.fallbackAdvised ?? incoming.fallbackAdvised),
|
|
59
111
|
bindingWindow: existing?.bindingWindowSource === 'poll'
|
|
60
112
|
? existing.bindingWindow
|
|
61
113
|
: (incoming.bindingWindow ?? existing?.bindingWindow),
|
|
62
114
|
bindingWindowSource: existing?.bindingWindowSource === 'poll'
|
|
63
115
|
? 'poll'
|
|
64
116
|
: (incoming.bindingWindowSource ?? existing?.bindingWindowSource),
|
|
65
|
-
|
|
117
|
+
...(Object.keys(fieldSources).length > 0 && { fieldSources }),
|
|
118
|
+
// Top-level source remains headers for compatibility; fieldSources records ownership after partial harvests.
|
|
66
119
|
source: 'headers',
|
|
67
120
|
};
|
|
68
121
|
}
|
package/dist/quota-manager.d.ts
CHANGED
|
@@ -20,9 +20,17 @@ export type QuotaRefreshResult = {
|
|
|
20
20
|
export type QuotaManagerOptions = {
|
|
21
21
|
storage: AccountStorage | null;
|
|
22
22
|
fetchImpl?: typeof fetch;
|
|
23
|
+
/** Resolve custody credentials at the actual HTTP boundary, after quota gates. */
|
|
24
|
+
fetchQuotaSnapshot?: (request: {
|
|
25
|
+
kind: 'main' | 'fallback';
|
|
26
|
+
accountId: string | undefined;
|
|
27
|
+
accessToken: string;
|
|
28
|
+
}) => Promise<OAuthQuotaSnapshot>;
|
|
23
29
|
now?: () => number;
|
|
24
30
|
onMainQuotaFetched?: (quota: OAuthQuotaSnapshot, checkedAt: number, tokenFingerprint: string, fetchStartedAt: number, quotaErrorGeneration: number, quotaErrorClearedAt: number | undefined) => void;
|
|
25
31
|
onApiError?: (error: AccountOperationError, quotaErrorGeneration: number) => void;
|
|
32
|
+
onFallbackQuotaFetched?: (accountId: string, quota: OAuthQuotaSnapshot, checkedAt: number, fetchStartedAt: number) => void;
|
|
33
|
+
onFallbackApiError?: (accountId: string, error: AccountOperationError) => void;
|
|
26
34
|
};
|
|
27
35
|
export declare class QuotaManager {
|
|
28
36
|
private main;
|
|
@@ -37,6 +45,8 @@ export declare class QuotaManager {
|
|
|
37
45
|
private fallbackGenerations;
|
|
38
46
|
private inflightMain;
|
|
39
47
|
private inflightMainAccountId;
|
|
48
|
+
private inflightMainAccessToken;
|
|
49
|
+
private inflightMainToken;
|
|
40
50
|
private inflightFallbacks;
|
|
41
51
|
private mainLastApiError;
|
|
42
52
|
private fallbackApiErrors;
|
|
@@ -44,9 +54,12 @@ export declare class QuotaManager {
|
|
|
44
54
|
private lastApiCallAt;
|
|
45
55
|
private storage;
|
|
46
56
|
private readonly fetchImpl;
|
|
57
|
+
private readonly fetchQuotaSnapshot;
|
|
47
58
|
private readonly now;
|
|
48
59
|
private readonly onMainQuotaFetched;
|
|
49
60
|
private readonly onApiError;
|
|
61
|
+
private readonly onFallbackQuotaFetched;
|
|
62
|
+
private readonly onFallbackApiError;
|
|
50
63
|
constructor(opts: QuotaManagerOptions);
|
|
51
64
|
/**
|
|
52
65
|
* Cached main quota entry, scoped to the account behind the main credential.
|
|
@@ -57,10 +70,13 @@ export declare class QuotaManager {
|
|
|
57
70
|
* Cached fallback quota entry, scoped to the configured account id.
|
|
58
71
|
*/
|
|
59
72
|
getFallback(accountId: string, account?: Pick<OAuthAccount, 'authLineageId'>): QuotaEntry | null;
|
|
73
|
+
/** A host transport resolves scoped credentials at dispatch time. */
|
|
74
|
+
canFetchWithoutAccessToken(): boolean;
|
|
60
75
|
getAllFallbacks(): Map<string, QuotaEntry>;
|
|
61
76
|
setMain(mainAccountId: string | undefined, entry: QuotaEntry): void;
|
|
77
|
+
clearMain(): void;
|
|
62
78
|
/** Bind quota state to the account behind the current main credential. */
|
|
63
|
-
setMainQuotaAccountIdentity(accountIdentity: string | undefined, strict?: boolean): number | undefined;
|
|
79
|
+
setMainQuotaAccountIdentity(accountIdentity: string | undefined, strict?: boolean, force?: boolean): number | undefined;
|
|
64
80
|
setFallback(accountId: string, entry: QuotaEntry, account: Pick<OAuthAccount, 'authLineageId'> | undefined): void;
|
|
65
81
|
clearFallback(accountId: string): void;
|
|
66
82
|
pushMainFromHeaders(mainAccountId: string | undefined, incoming: OAuthQuotaSnapshot): QuotaEntry;
|
|
@@ -69,7 +85,7 @@ export declare class QuotaManager {
|
|
|
69
85
|
refreshMainWithMetadata(mainAccountIdOrAccessToken: string | undefined, accessToken?: string, expectedIdentityGeneration?: number): Promise<QuotaRefreshResult>;
|
|
70
86
|
refreshFallback(accountId: string, accessToken: string, account: Pick<OAuthAccount, 'authLineageId'> | undefined): Promise<OAuthQuotaSnapshot>;
|
|
71
87
|
refreshFallbackWithMetadata(accountId: string, accessToken: string, account: Pick<OAuthAccount, 'authLineageId'> | undefined): Promise<QuotaRefreshResult>;
|
|
72
|
-
refreshAllFallbacks(accounts: OAuthAccount[]): Promise<void>;
|
|
88
|
+
refreshAllFallbacks(accounts: OAuthAccount[], resolveAccessToken?: (account: OAuthAccount) => string | undefined): Promise<void>;
|
|
73
89
|
/**
|
|
74
90
|
* Fire-and-forget refresh. Does not await, swallows errors.
|
|
75
91
|
*/
|
|
@@ -118,6 +134,8 @@ export declare class QuotaManager {
|
|
|
118
134
|
private static quotaLockName;
|
|
119
135
|
private bindFallbackLineage;
|
|
120
136
|
private acceptFallbackQuotaObservation;
|
|
137
|
+
private isClosed;
|
|
138
|
+
close(): void;
|
|
121
139
|
/**
|
|
122
140
|
* Serialize API calls through a shared gate so only one
|
|
123
141
|
* quota API request runs at a time, with a minimum gap
|