@cortexkit/anthropic-auth-core 1.23.0 → 2.0.1

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.
Files changed (136) hide show
  1. package/README.md +18 -1
  2. package/dist/accounts.d.ts +4 -163
  3. package/dist/cachekeep.d.ts +9 -0
  4. package/dist/claude-code.d.ts +16 -0
  5. package/dist/claustrum-enrollment.d.ts +2 -0
  6. package/dist/claustrum.d.ts +0 -209
  7. package/dist/commands/account.d.ts +2 -3
  8. package/dist/index.d.ts +45 -4
  9. package/dist/index.js +27569 -38
  10. package/dist/internal-types/LICENSE +21 -0
  11. package/dist/internal-types/commands/builtins.d.ts +71 -0
  12. package/dist/internal-types/commands/index.d.ts +10 -0
  13. package/dist/internal-types/commands/menu.d.ts +61 -0
  14. package/dist/internal-types/commands/model.d.ts +238 -0
  15. package/dist/internal-types/commands/pi.d.ts +23 -0
  16. package/dist/internal-types/commands/seam.d.ts +72 -0
  17. package/dist/internal-types/fs/refresh-file-lock.d.ts +33 -0
  18. package/dist/internal-types/logger/capture-sink.d.ts +14 -0
  19. package/dist/internal-types/logger/engine.d.ts +98 -0
  20. package/dist/internal-types/logger/index.d.ts +6 -0
  21. package/dist/internal-types/logger/redact.d.ts +11 -0
  22. package/dist/internal-types/pi-slot/index.d.ts +3 -0
  23. package/dist/internal-types/pi-slot/slot.d.ts +51 -0
  24. package/dist/internal-types/quota/codec.d.ts +11 -0
  25. package/dist/internal-types/quota/format.d.ts +46 -0
  26. package/dist/internal-types/quota/index.d.ts +10 -0
  27. package/dist/internal-types/quota/map.d.ts +63 -0
  28. package/dist/internal-types/quota/merge.d.ts +48 -0
  29. package/dist/internal-types/quota/projection.d.ts +64 -0
  30. package/dist/internal-types/store/attribution.d.ts +28 -0
  31. package/dist/internal-types/store/errors.d.ts +55 -0
  32. package/dist/internal-types/store/hooks.d.ts +12 -0
  33. package/dist/internal-types/store/identity.d.ts +39 -0
  34. package/dist/internal-types/store/index.d.ts +21 -0
  35. package/dist/internal-types/store/mutate.d.ts +189 -0
  36. package/dist/internal-types/store/pool.d.ts +197 -0
  37. package/dist/internal-types/store/provider-state.d.ts +131 -0
  38. package/dist/internal-types/store/publication.d.ts +47 -0
  39. package/dist/internal-types/store/pull.d.ts +36 -0
  40. package/dist/internal-types/store/refresh-lock.d.ts +67 -0
  41. package/dist/internal-types/store/refresh.d.ts +72 -0
  42. package/dist/internal-types/store/rows.d.ts +313 -0
  43. package/dist/internal-types/store/runtime.d.ts +36 -0
  44. package/dist/internal-types/store/schema.d.ts +443 -0
  45. package/dist/internal-types/store/settings.d.ts +63 -0
  46. package/dist/internal-types/store/torn.d.ts +78 -0
  47. package/dist/migration-source.d.ts +33 -0
  48. package/dist/models.d.ts +41 -0
  49. package/dist/native-account-runtime.d.ts +121 -0
  50. package/dist/native-account-view.d.ts +126 -0
  51. package/dist/native-command-effects.d.ts +59 -0
  52. package/dist/native-credential-validation.d.ts +42 -0
  53. package/dist/native-custody-activation.d.ts +45 -0
  54. package/dist/native-custody.d.ts +114 -0
  55. package/dist/native-enrollment-authority.d.ts +2 -0
  56. package/dist/native-host-auth-read.d.ts +3 -0
  57. package/dist/native-host-auth-write.d.ts +51 -0
  58. package/dist/native-host-auth.d.ts +12 -0
  59. package/dist/native-local-credential-service.d.ts +76 -0
  60. package/dist/native-local-runtime-readers.d.ts +22 -0
  61. package/dist/native-lock-observer.d.ts +12 -0
  62. package/dist/native-menu-executor.d.ts +243 -0
  63. package/dist/native-menu-model.d.ts +142 -0
  64. package/dist/native-migration-proof.d.ts +28 -0
  65. package/dist/native-migration-source.d.ts +47 -0
  66. package/dist/native-migration.d.ts +66 -0
  67. package/dist/native-quota-codec.d.ts +32 -0
  68. package/dist/native-refresh-coordinator.d.ts +240 -0
  69. package/dist/native-roster-seed.d.ts +115 -0
  70. package/dist/native-runtime-registry.d.ts +19 -0
  71. package/dist/native-runtime.d.ts +204 -0
  72. package/dist/native-settings.d.ts +6 -0
  73. package/dist/native-transient-account.d.ts +38 -0
  74. package/dist/native-ui.d.ts +45 -0
  75. package/dist/native-usage-publication.d.ts +12 -0
  76. package/dist/native-vault-admission.d.ts +8 -0
  77. package/dist/native-vault-connection.d.ts +33 -0
  78. package/dist/native-vault-paths.d.ts +13 -0
  79. package/dist/native-vault-runtime.d.ts +102 -0
  80. package/dist/native-vault-seed.d.ts +16 -0
  81. package/dist/pool-authority.d.ts +159 -0
  82. package/dist/pool-binding.d.ts +32 -0
  83. package/dist/pool-paths.d.ts +21 -0
  84. package/dist/pool-store.d.ts +32 -0
  85. package/dist/provider-error.d.ts +139 -0
  86. package/dist/quota-manager.d.ts +18 -7
  87. package/dist/relay.d.ts +14 -1
  88. package/dist/request-history.d.ts +34 -0
  89. package/dist/routing.d.ts +1 -2
  90. package/dist/sse.d.ts +81 -0
  91. package/dist/sticky-routing.d.ts +28 -0
  92. package/package.json +10 -4
  93. package/dist/accounts.js +0 -3881
  94. package/dist/auth.js +0 -185
  95. package/dist/cache1h.js +0 -97
  96. package/dist/cachekeep-registry.js +0 -124
  97. package/dist/cachekeep.js +0 -604
  98. package/dist/cch.js +0 -172
  99. package/dist/claude-code.js +0 -403
  100. package/dist/claustrum-enrollment-registry.d.ts +0 -17
  101. package/dist/claustrum-enrollment-registry.js +0 -194
  102. package/dist/claustrum-enrollment.js +0 -485
  103. package/dist/claustrum-scoped-roster.d.ts +0 -23
  104. package/dist/claustrum-scoped-roster.js +0 -194
  105. package/dist/claustrum-scoped-runtime.d.ts +0 -28
  106. package/dist/claustrum-scoped-runtime.js +0 -230
  107. package/dist/claustrum-scoped.d.ts +0 -39
  108. package/dist/claustrum-scoped.js +0 -193
  109. package/dist/claustrum.js +0 -1471
  110. package/dist/commands/account.js +0 -368
  111. package/dist/constants.js +0 -83
  112. package/dist/custom-headers.js +0 -102
  113. package/dist/dump.js +0 -616
  114. package/dist/fast.js +0 -66
  115. package/dist/json.js +0 -10
  116. package/dist/killswitch.js +0 -132
  117. package/dist/logger.js +0 -288
  118. package/dist/logging.js +0 -59
  119. package/dist/mid-conversation-output-config.js +0 -89
  120. package/dist/model-remap.js +0 -72
  121. package/dist/models.js +0 -177
  122. package/dist/network-errors.js +0 -27
  123. package/dist/oauth-profile.js +0 -60
  124. package/dist/pkce.js +0 -17
  125. package/dist/prime.js +0 -841
  126. package/dist/provider.js +0 -0
  127. package/dist/quota-header-feed.js +0 -331
  128. package/dist/quota-headers.js +0 -121
  129. package/dist/quota-manager.js +0 -856
  130. package/dist/quotas.js +0 -141
  131. package/dist/relay.js +0 -1303
  132. package/dist/routing.js +0 -94
  133. package/dist/start.js +0 -29
  134. package/dist/sticky-routing.js +0 -541
  135. package/dist/thinking-binding.js +0 -54
  136. 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
- }
@@ -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
- }