@openlimiter/connectors 0.2.0 → 1.2.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/dist/antigravity.d.ts +50 -1
- package/dist/antigravity.d.ts.map +1 -1
- package/dist/antigravity.js +150 -19
- package/dist/antigravity.js.map +1 -1
- package/dist/claude.d.ts +72 -6
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +467 -35
- package/dist/claude.js.map +1 -1
- package/dist/codex.d.ts +23 -1
- package/dist/codex.d.ts.map +1 -1
- package/dist/codex.js +112 -13
- package/dist/codex.js.map +1 -1
- package/dist/contract-gate.d.ts +56 -0
- package/dist/contract-gate.d.ts.map +1 -0
- package/dist/contract-gate.js +100 -0
- package/dist/contract-gate.js.map +1 -0
- package/dist/fixtures.d.ts +274 -2
- package/dist/fixtures.d.ts.map +1 -1
- package/dist/fixtures.js +947 -17
- package/dist/fixtures.js.map +1 -1
- package/dist/gemini-cli.d.ts +13 -0
- package/dist/gemini-cli.d.ts.map +1 -0
- package/dist/gemini-cli.js +86 -0
- package/dist/gemini-cli.js.map +1 -0
- package/dist/grok.d.ts +13 -0
- package/dist/grok.d.ts.map +1 -0
- package/dist/grok.js +143 -0
- package/dist/grok.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/kimi.d.ts +13 -0
- package/dist/kimi.d.ts.map +1 -0
- package/dist/kimi.js +141 -0
- package/dist/kimi.js.map +1 -0
- package/dist/manual.d.ts +3 -1
- package/dist/manual.d.ts.map +1 -1
- package/dist/manual.js +7 -3
- package/dist/manual.js.map +1 -1
- package/dist/opencode.d.ts +103 -1
- package/dist/opencode.d.ts.map +1 -1
- package/dist/opencode.js +428 -21
- package/dist/opencode.js.map +1 -1
- package/dist/openrouter.d.ts +3 -1
- package/dist/openrouter.d.ts.map +1 -1
- package/dist/openrouter.js +7 -3
- package/dist/openrouter.js.map +1 -1
- package/dist/shared.d.ts +105 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +190 -0
- package/dist/shared.js.map +1 -1
- package/package.json +4 -3
package/dist/claude.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { boundedNumber,
|
|
1
|
+
import { boundedNumber, connectorConnection, futureInstantFromEpochSeconds, futureInstantFromRfc3339, plausibleResetHorizon, rawMeter, record, shortExpiry } from "./shared.js";
|
|
2
2
|
export const claudeLabels = {
|
|
3
3
|
credentialOrigin: "official-local-tool",
|
|
4
4
|
dataInterfaceStatus: "native-statusline-payload",
|
|
@@ -10,58 +10,489 @@ export const claudeInput = {
|
|
|
10
10
|
path: null,
|
|
11
11
|
readMode: "read_only"
|
|
12
12
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const FIVE_HOURS = 18_000;
|
|
14
|
+
const SEVEN_DAYS = 604_800;
|
|
15
|
+
/**
|
|
16
|
+
* The longest a window this reader was never told the length of may run.
|
|
17
|
+
*
|
|
18
|
+
* A bucket whose key spells out no cadence still needs SOME plausibility bound,
|
|
19
|
+
* or a corrupt reset becomes a countdown to the year 2038. A month is the
|
|
20
|
+
* longest subscription window any provider in this product uses, so a reset
|
|
21
|
+
* beyond it is a corrupt field rather than a long wait.
|
|
22
|
+
*/
|
|
23
|
+
export const CLAUDE_UNKNOWN_WINDOW_SECONDS = 2_678_400;
|
|
24
|
+
/**
|
|
25
|
+
* The buckets whose names this build knows, and how long each one runs.
|
|
26
|
+
*
|
|
27
|
+
* Being on this list buys one thing: a fixed meter code that never moves, so a
|
|
28
|
+
* surface can style the weekly Opus bar and keep styling it. It is NOT what
|
|
29
|
+
* makes a bucket readable. Everything else in the table is read too, under a
|
|
30
|
+
* code derived from its own key, because the failure this parser is fixing was
|
|
31
|
+
* a frozen two entry table silently dropping every bucket Anthropic added
|
|
32
|
+
* after it was written.
|
|
33
|
+
*/
|
|
34
|
+
const KNOWN_WINDOWS = {
|
|
35
|
+
five_hour: { meter: "FIVE_HOUR", durationSeconds: FIVE_HOURS },
|
|
36
|
+
seven_day: { meter: "SEVEN_DAY", durationSeconds: SEVEN_DAYS },
|
|
37
|
+
seven_day_opus: { meter: "SEVEN_DAY_OPUS", durationSeconds: SEVEN_DAYS },
|
|
38
|
+
seven_day_sonnet: { meter: "SEVEN_DAY_SONNET", durationSeconds: SEVEN_DAYS },
|
|
39
|
+
seven_day_oauth_apps: {
|
|
40
|
+
meter: "SEVEN_DAY_OAUTH_APPS",
|
|
41
|
+
durationSeconds: SEVEN_DAYS
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
/** Keys that carry something other than one window, so never read as one. */
|
|
45
|
+
const RESERVED_KEYS = new Set([
|
|
46
|
+
"model_scoped",
|
|
47
|
+
"limits",
|
|
48
|
+
"extra_usage"
|
|
49
|
+
]);
|
|
50
|
+
/** The prefix every model scoped weekly bucket's code is built on. */
|
|
51
|
+
export const CLAUDE_MODEL_WEEKLY_PREFIX = "SEVEN_DAY_";
|
|
52
|
+
/** Longest source string this reader will turn into a meter code. */
|
|
53
|
+
export const MAX_METER_CODE_SOURCE_CHARS = 64;
|
|
54
|
+
/**
|
|
55
|
+
* A meter code built from text the provider chose, or null.
|
|
56
|
+
*
|
|
57
|
+
* The one place provider supplied text is allowed anywhere near a field a human
|
|
58
|
+
* reads, and it is allowed only after being reduced to upper snake case with
|
|
59
|
+
* every other character removed and the result held against a strict pattern.
|
|
60
|
+
* A display name is a sentence the provider controls; a meter code is a token
|
|
61
|
+
* this product controls, and this function is the border between them.
|
|
62
|
+
*/
|
|
63
|
+
function meterCode(value) {
|
|
64
|
+
if (typeof value !== "string")
|
|
16
65
|
return null;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
66
|
+
if (value.length === 0 || value.length > MAX_METER_CODE_SOURCE_CHARS)
|
|
67
|
+
return null;
|
|
68
|
+
/* Printable ASCII only. A right to left override or a zero width space in a
|
|
69
|
+
model name has no business reaching a label. */
|
|
70
|
+
if (!/^[\x20-\x7E]+$/u.test(value))
|
|
71
|
+
return null;
|
|
72
|
+
const code = value
|
|
73
|
+
.toUpperCase()
|
|
74
|
+
.replace(/[^A-Z0-9]+/gu, "_")
|
|
75
|
+
.replace(/^_+|_+$/gu, "");
|
|
76
|
+
return /^[A-Z][A-Z0-9_]{0,47}$/u.test(code) ? code : null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The share of a window consumed, however this document happens to state it.
|
|
80
|
+
*
|
|
81
|
+
* The statusline says `used_percentage`. The usage document behind the same
|
|
82
|
+
* credential says `utilization`. They mean the same thing, and a reader that
|
|
83
|
+
* knows only one of them reports nothing at all against the other, which is
|
|
84
|
+
* finding F-201 in one sentence.
|
|
85
|
+
*
|
|
86
|
+
* Every name is tried until one of them is usable, rather than stopping at the
|
|
87
|
+
* first one PRESENT. A key that exists and holds null is not an answer, and a
|
|
88
|
+
* reader that treats it as one throws away the answer sitting beside it, which
|
|
89
|
+
* is the same failure in a smaller box.
|
|
90
|
+
*/
|
|
91
|
+
function statedPercent(input) {
|
|
92
|
+
for (const field of ["used_percentage", "utilization", "percent"]) {
|
|
93
|
+
const value = boundedNumber(input[field]);
|
|
94
|
+
if (value !== null)
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* A reset instant, in either encoding these two documents use.
|
|
101
|
+
*
|
|
102
|
+
* The statusline writes Unix epoch SECONDS. The usage document writes an ISO
|
|
103
|
+
* timestamp. Nothing is repaired in either branch: a number that is really
|
|
104
|
+
* milliseconds and a string that is really a date in the past both fail, and
|
|
105
|
+
* the window that stated them is dropped on its own.
|
|
106
|
+
*/
|
|
107
|
+
/**
|
|
108
|
+
* An epoch written as digits in quotes, and long enough to be one.
|
|
109
|
+
*
|
|
110
|
+
* Nine digits is 1973 and thirteen is a millisecond stamp of today; outside
|
|
111
|
+
* that range a bare number is not an epoch at all, it is a year, an identifier,
|
|
112
|
+
* or a truncation, and it belongs in the date branch or nowhere.
|
|
113
|
+
*/
|
|
114
|
+
const QUOTED_EPOCH = /^\d{9,13}$/u;
|
|
115
|
+
/** Digit count above which a quoted epoch is milliseconds rather than seconds. */
|
|
116
|
+
const EPOCH_MILLISECOND_DIGITS = 13;
|
|
117
|
+
function resetInstant(value, now, maxAheadSeconds) {
|
|
118
|
+
if (typeof value === "number") {
|
|
119
|
+
return futureInstantFromEpochSeconds(value, now, maxAheadSeconds);
|
|
120
|
+
}
|
|
121
|
+
if (typeof value !== "string")
|
|
21
122
|
return null;
|
|
123
|
+
/*
|
|
124
|
+
* A quoted epoch is read as an epoch BEFORE it is offered to the date
|
|
125
|
+
* parser, and the order is the whole point: Date.parse is willing to read
|
|
126
|
+
* "1767243600" as a year, so a reset five hours away reaches the wrong
|
|
127
|
+
* branch and becomes an instant thirty thousand years out or nothing at all.
|
|
128
|
+
* A JSON writer that quotes its numbers is not drift; the instant it names
|
|
129
|
+
* is unambiguous once the unit is settled, and the unit settles on length.
|
|
130
|
+
*/
|
|
131
|
+
const trimmed = value.trim();
|
|
132
|
+
if (QUOTED_EPOCH.test(trimmed)) {
|
|
133
|
+
const digits = Number.parseInt(trimmed, 10);
|
|
134
|
+
const seconds = trimmed.length >= EPOCH_MILLISECOND_DIGITS
|
|
135
|
+
? digits / 1_000
|
|
136
|
+
: digits;
|
|
137
|
+
return futureInstantFromEpochSeconds(seconds, now, maxAheadSeconds);
|
|
138
|
+
}
|
|
139
|
+
return futureInstantFromRfc3339(value, now, maxAheadSeconds);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* How long an unrecognised bucket runs, when its own key says so.
|
|
143
|
+
*
|
|
144
|
+
* Anthropic names these buckets after their cadence, so `seven_day_haiku` is a
|
|
145
|
+
* week whether or not this build has heard of it. That is worth reading,
|
|
146
|
+
* because the alternative is the loosest plausibility bound for a window whose
|
|
147
|
+
* length the key states outright. A key that spells out no cadence gets null
|
|
148
|
+
* and an honestly unknown window rather than an invented five hours.
|
|
149
|
+
*/
|
|
150
|
+
function durationForKey(key) {
|
|
151
|
+
if (key.startsWith("seven_day"))
|
|
152
|
+
return SEVEN_DAYS;
|
|
153
|
+
if (key.startsWith("five_hour"))
|
|
154
|
+
return FIVE_HOURS;
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
function windowFor(durationSeconds) {
|
|
158
|
+
return durationSeconds === null
|
|
159
|
+
? { kind: "unknown" }
|
|
160
|
+
: { kind: "rolling", durationSeconds };
|
|
161
|
+
}
|
|
162
|
+
function buildMeter(input, now, expiresAt, source) {
|
|
22
163
|
return rawMeter({
|
|
23
164
|
provider: "CLAUDE",
|
|
24
|
-
meter,
|
|
25
|
-
value: percent,
|
|
26
|
-
window:
|
|
27
|
-
resetAt,
|
|
28
|
-
source
|
|
165
|
+
meter: input.meter,
|
|
166
|
+
value: input.percent,
|
|
167
|
+
window: windowFor(input.durationSeconds),
|
|
168
|
+
resetAt: input.resetAt,
|
|
169
|
+
source,
|
|
29
170
|
precision: "exact",
|
|
30
171
|
observedAt: now,
|
|
31
172
|
expiresAt,
|
|
32
|
-
labels: claudeLabels
|
|
173
|
+
labels: claudeLabels,
|
|
174
|
+
...(input.amounts === undefined ? {} : { amounts: input.amounts })
|
|
33
175
|
});
|
|
34
176
|
}
|
|
35
|
-
const windows = [
|
|
36
|
-
{ key: "five_hour", meter: "FIVE_HOUR", durationSeconds: 18_000 },
|
|
37
|
-
{ key: "seven_day", meter: "SEVEN_DAY", durationSeconds: 604_800 }
|
|
38
|
-
];
|
|
39
177
|
/**
|
|
40
|
-
*
|
|
178
|
+
* One bucket, or null.
|
|
179
|
+
*
|
|
180
|
+
* The reset has to belong to the window that named it. A five hour window
|
|
181
|
+
* resetting years from now is a corrupt field, not a long wait, and it is
|
|
182
|
+
* dropped on its own so the other buckets still report.
|
|
183
|
+
*/
|
|
184
|
+
function parseWindow(value, now, meter, durationSeconds) {
|
|
185
|
+
const input = record(value);
|
|
186
|
+
if (input === null)
|
|
187
|
+
return null;
|
|
188
|
+
const percent = statedPercent(input);
|
|
189
|
+
const resetAt = resetInstant(input["resets_at"], now, plausibleResetHorizon(durationSeconds ?? CLAUDE_UNKNOWN_WINDOW_SECONDS));
|
|
190
|
+
if (percent === null || resetAt === null)
|
|
191
|
+
return null;
|
|
192
|
+
return { meter, percent, durationSeconds, resetAt };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Every bucket in a window table, keyed generically.
|
|
196
|
+
*
|
|
197
|
+
* Known keys keep their fixed codes. Anything else that is an object carrying
|
|
198
|
+
* both a percentage and a reset becomes a meter under a code derived from its
|
|
199
|
+
* own key, so a bucket Anthropic ships next month appears in this product the
|
|
200
|
+
* day it appears in the payload rather than the day someone edits a table here.
|
|
201
|
+
* Everything else in the table is ignored in silence, because a statusline
|
|
202
|
+
* payload legitimately carries session identifiers and workspace paths beside
|
|
203
|
+
* its meters and none of those are readings.
|
|
204
|
+
*
|
|
205
|
+
* The order is this build's, never the document's. Meter order used to follow
|
|
206
|
+
* JSON key order, which no provider promises and which a proxy, a
|
|
207
|
+
* re-serialiser or a client version bump changes for free, so the same account
|
|
208
|
+
* could produce two different meter lists on two consecutive reads.
|
|
209
|
+
*/
|
|
210
|
+
function orderedWindowKeys(table) {
|
|
211
|
+
const remaining = new Set(Object.keys(table).filter((key) => !RESERVED_KEYS.has(key)));
|
|
212
|
+
const ordered = [];
|
|
213
|
+
/* The buckets this build knows lead, shortest window first, which is the
|
|
214
|
+
order a person reads them in and the order every surface ranks them in. */
|
|
215
|
+
for (const key of Object.keys(KNOWN_WINDOWS)) {
|
|
216
|
+
if (!remaining.delete(key))
|
|
217
|
+
continue;
|
|
218
|
+
ordered.push(key);
|
|
219
|
+
}
|
|
220
|
+
return [...ordered, ...[...remaining].sort()];
|
|
221
|
+
}
|
|
222
|
+
function parseWindowTable(table, now, seen) {
|
|
223
|
+
const found = [];
|
|
224
|
+
for (const key of orderedWindowKeys(table)) {
|
|
225
|
+
const value = table[key];
|
|
226
|
+
const known = KNOWN_WINDOWS[key];
|
|
227
|
+
const meter = known?.meter ?? meterCode(key);
|
|
228
|
+
if (meter === null || seen.has(meter))
|
|
229
|
+
continue;
|
|
230
|
+
const parsed = parseWindow(value, now, meter, known?.durationSeconds ?? durationForKey(key));
|
|
231
|
+
if (parsed === null)
|
|
232
|
+
continue;
|
|
233
|
+
seen.add(meter);
|
|
234
|
+
found.push(parsed);
|
|
235
|
+
}
|
|
236
|
+
return found;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* The model scoped weekly buckets the statusline adds beside the root table.
|
|
240
|
+
*
|
|
241
|
+
* Each entry names a model in words a human reads, so the code is built from
|
|
242
|
+
* that name and prefixed with the cadence it belongs to: a Fable 5 entry is
|
|
243
|
+
* SEVEN_DAY_FABLE_5. Deduplicated against whatever the root table already
|
|
244
|
+
* reported, because Opus arrives twice on a payload that carries both
|
|
245
|
+
* `seven_day_opus` and a model scoped Opus entry, and two bars for one pool is
|
|
246
|
+
* the same lie as no bar at all.
|
|
247
|
+
*/
|
|
248
|
+
function parseModelScoped(value, now, seen) {
|
|
249
|
+
if (!Array.isArray(value))
|
|
250
|
+
return [];
|
|
251
|
+
const found = [];
|
|
252
|
+
for (const entry of value) {
|
|
253
|
+
const scoped = record(entry);
|
|
254
|
+
if (scoped === null)
|
|
255
|
+
continue;
|
|
256
|
+
const name = meterCode(scoped["display_name"]);
|
|
257
|
+
if (name === null)
|
|
258
|
+
continue;
|
|
259
|
+
const meter = CLAUDE_MODEL_WEEKLY_PREFIX + name;
|
|
260
|
+
if (seen.has(meter))
|
|
261
|
+
continue;
|
|
262
|
+
const parsed = parseWindow(scoped, now, meter, SEVEN_DAYS);
|
|
263
|
+
if (parsed === null)
|
|
264
|
+
continue;
|
|
265
|
+
seen.add(meter);
|
|
266
|
+
found.push(parsed);
|
|
267
|
+
}
|
|
268
|
+
return found;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The `limits[]` list the usage document carries, which the statusline does not.
|
|
272
|
+
*
|
|
273
|
+
* Only `weekly_scoped` is read. Another kind names a cadence this build cannot
|
|
274
|
+
* work out and a scope it cannot name, and guessing either would produce a bar
|
|
275
|
+
* labelled with the wrong week, so an unrecognised kind is dropped alone and
|
|
276
|
+
* the recognised ones beside it still report.
|
|
277
|
+
*/
|
|
278
|
+
function parseScopedLimits(value, now, seen) {
|
|
279
|
+
if (!Array.isArray(value))
|
|
280
|
+
return [];
|
|
281
|
+
const found = [];
|
|
282
|
+
for (const entry of value) {
|
|
283
|
+
const limit = record(entry);
|
|
284
|
+
if (limit === null || limit["kind"] !== "weekly_scoped")
|
|
285
|
+
continue;
|
|
286
|
+
const scope = record(limit["scope"]);
|
|
287
|
+
const model = record(scope?.["model"]);
|
|
288
|
+
const name = meterCode(model?.["display_name"]);
|
|
289
|
+
if (name === null)
|
|
290
|
+
continue;
|
|
291
|
+
const meter = CLAUDE_MODEL_WEEKLY_PREFIX + name;
|
|
292
|
+
if (seen.has(meter))
|
|
293
|
+
continue;
|
|
294
|
+
const parsed = parseWindow(limit, now, meter, SEVEN_DAYS);
|
|
295
|
+
if (parsed === null)
|
|
296
|
+
continue;
|
|
297
|
+
seen.add(meter);
|
|
298
|
+
found.push(parsed);
|
|
299
|
+
}
|
|
300
|
+
return found;
|
|
301
|
+
}
|
|
302
|
+
/** Money as the usage document states it, under any of the names it uses. */
|
|
303
|
+
function amountField(input, names) {
|
|
304
|
+
for (const name of names) {
|
|
305
|
+
const value = input[name];
|
|
306
|
+
if (value === undefined)
|
|
307
|
+
continue;
|
|
308
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0
|
|
309
|
+
? value
|
|
310
|
+
: null;
|
|
311
|
+
}
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* The extra usage pool, as a percentage with the money that produced it.
|
|
316
|
+
*
|
|
317
|
+
* Extra usage is spend beyond the plan, so it is the one Claude bucket stated
|
|
318
|
+
* in dollars rather than in a share of a window. The percentage is derived from
|
|
319
|
+
* the pair, and the pair travels with it so a surface can print "$12.47 of $20"
|
|
320
|
+
* beside the bar instead of a bare percentage nobody can act on. A pool with no
|
|
321
|
+
* ceiling states no percentage and produces no meter: an unbounded spend has no
|
|
322
|
+
* denominator, and inventing one would be the worst kind of wrong answer.
|
|
323
|
+
*
|
|
324
|
+
* The amounts are handed on exactly as they were read. The core normalizer is
|
|
325
|
+
* the only thing that decides whether they are believable, and it drops all
|
|
326
|
+
* three together or keeps all three together, which leaves the percentage
|
|
327
|
+
* standing either way.
|
|
328
|
+
*/
|
|
329
|
+
function parseExtraUsage(value, now) {
|
|
330
|
+
const input = record(value);
|
|
331
|
+
if (input === null)
|
|
332
|
+
return null;
|
|
333
|
+
const used = amountField(input, ["used_amount", "used_credits", "used"]);
|
|
334
|
+
const limit = amountField(input, ["limit_amount", "limit_credits", "monthly_limit", "limit", "cap"]);
|
|
335
|
+
const stated = statedPercent(input);
|
|
336
|
+
/*
|
|
337
|
+
* Spend past the ceiling is capped, not dropped. The pool somebody has
|
|
338
|
+
* overspent is the pool they most need to see, and refusing it made the one
|
|
339
|
+
* bucket that was over its limit the one bucket that vanished. A percentage
|
|
340
|
+
* cannot exceed a hundred, so a hundred is what it reads, and the money that
|
|
341
|
+
* produced it travels on untouched for the normalizer to judge: it refuses a
|
|
342
|
+
* used figure larger than its own limit and drops all three money fields,
|
|
343
|
+
* which leaves the capped percentage standing on its own.
|
|
344
|
+
*/
|
|
345
|
+
const derived = used === null || limit === null || limit <= 0
|
|
346
|
+
? null
|
|
347
|
+
: Math.min(100, (used / limit) * 100);
|
|
348
|
+
const percent = stated ?? derived;
|
|
349
|
+
if (percent === null || !Number.isFinite(percent) || percent < 0 || percent > 100) {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
const currency = input["currency"];
|
|
353
|
+
const usable = used !== null &&
|
|
354
|
+
limit !== null &&
|
|
355
|
+
(currency === undefined ||
|
|
356
|
+
(typeof currency === "string" && currency.toUpperCase() === "USD"));
|
|
357
|
+
return {
|
|
358
|
+
meter: "EXTRA_USAGE",
|
|
359
|
+
percent,
|
|
360
|
+
durationSeconds: null,
|
|
361
|
+
resetAt: resetInstant(input["resets_at"], now, plausibleResetHorizon(CLAUDE_UNKNOWN_WINDOW_SECONDS)),
|
|
362
|
+
...(usable
|
|
363
|
+
? {
|
|
364
|
+
amounts: {
|
|
365
|
+
usedAmount: used,
|
|
366
|
+
limitAmount: limit,
|
|
367
|
+
currency: "USD"
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
: {})
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Whether a document with no `rate_limits` is a usage document at all.
|
|
375
|
+
*
|
|
376
|
+
* A free account's statusline payload has no rate limits either, and it must
|
|
377
|
+
* stay the honest unknown rather than being scanned for anything that looks
|
|
378
|
+
* like a number. So the usage branch is entered only for a document that
|
|
379
|
+
* announces itself: a scoped limits list, an extra usage pool, a model scoped
|
|
380
|
+
* list, or at least one window whose key this build already knows.
|
|
381
|
+
*/
|
|
382
|
+
function looksLikeUsageDocument(root) {
|
|
383
|
+
if (Array.isArray(root["limits"]))
|
|
384
|
+
return true;
|
|
385
|
+
if (Array.isArray(root["model_scoped"]))
|
|
386
|
+
return true;
|
|
387
|
+
if (record(root["extra_usage"]) !== null)
|
|
388
|
+
return true;
|
|
389
|
+
return Object.keys(KNOWN_WINDOWS).some((key) => record(root[key]) !== null);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Parse a Claude usage document, in either shape the same credential produces.
|
|
393
|
+
*
|
|
394
|
+
* SHAPE ONE, the statusline payload, from
|
|
395
|
+
* https://code.claude.com/docs/en/statusline and observed on Claude Code
|
|
396
|
+
* 2.1.261 on 2026-09-04:
|
|
397
|
+
*
|
|
398
|
+
* ```json
|
|
399
|
+
* {
|
|
400
|
+
* "rate_limits": {
|
|
401
|
+
* "five_hour": { "used_percentage": 23.5, "resets_at": 1738425600 },
|
|
402
|
+
* "seven_day": { "used_percentage": 41.2, "resets_at": 1738857600 },
|
|
403
|
+
* "seven_day_oauth_apps": { "used_percentage": 3.1, "resets_at": 1738857600 },
|
|
404
|
+
* "seven_day_opus": { "used_percentage": 61.0, "resets_at": 1738857600 },
|
|
405
|
+
* "seven_day_sonnet": { "used_percentage": 12.4, "resets_at": 1738857600 },
|
|
406
|
+
* "model_scoped": [
|
|
407
|
+
* { "display_name": "Fable 5", "utilization": 12, "resets_at": "2026-09-11T00:00:00Z" }
|
|
408
|
+
* ]
|
|
409
|
+
* }
|
|
410
|
+
* }
|
|
411
|
+
* ```
|
|
412
|
+
*
|
|
413
|
+
* SHAPE TWO, the `api/oauth/usage` document, which is what `openlimiter ingest`
|
|
414
|
+
* is handed. Its windows sit at the root, state `utilization` and an ISO reset,
|
|
415
|
+
* and it carries two things the statusline does not: an `extra_usage` pool
|
|
416
|
+
* stated in money, and a `limits` list of model scoped weekly buckets:
|
|
417
|
+
*
|
|
418
|
+
* ```json
|
|
419
|
+
* {
|
|
420
|
+
* "five_hour": { "utilization": 90, "resets_at": "2026-09-04T17:00:00Z" },
|
|
421
|
+
* "seven_day": { "utilization": 18, "resets_at": "2026-09-09T00:00:00Z" },
|
|
422
|
+
* "extra_usage": { "used_amount": 12.47, "limit_amount": 20, "currency": "USD" },
|
|
423
|
+
* "limits": [
|
|
424
|
+
* {
|
|
425
|
+
* "kind": "weekly_scoped",
|
|
426
|
+
* "percent": 61,
|
|
427
|
+
* "resets_at": "2026-09-09T00:00:00Z",
|
|
428
|
+
* "scope": { "model": { "display_name": "Opus" } }
|
|
429
|
+
* }
|
|
430
|
+
* ]
|
|
431
|
+
* }
|
|
432
|
+
* ```
|
|
433
|
+
*
|
|
434
|
+
* Refusing the second shape was finding F-201: a real document, from a real
|
|
435
|
+
* account, over a healthy connection, answered null because this parser knew
|
|
436
|
+
* only `used_percentage` and only epoch seconds.
|
|
41
437
|
*
|
|
42
|
-
*
|
|
43
|
-
* "resets_at": "2026-09-01T05:00:00.000Z" }, "seven_day": { ... } } }
|
|
438
|
+
* Three absences the documentation states, and none of them is an error:
|
|
44
439
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
440
|
+
* 1. `rate_limits` appears only for Claude.ai subscribers on Pro or Max, and
|
|
441
|
+
* only after the first API response in the session. A payload without it and
|
|
442
|
+
* without any usage document field is an ordinary payload from a free
|
|
443
|
+
* account or a session that has not called the API yet.
|
|
444
|
+
* 2. Each bucket may be independently absent, so one present bucket is one
|
|
445
|
+
* meter and is a complete answer.
|
|
446
|
+
* 3. No bucket present is the honest unknown, not zero.
|
|
447
|
+
*
|
|
448
|
+
* A bucket that fails validation is dropped and the rest still count, because
|
|
449
|
+
* one corrupt reset is not a reason to forget the whole session.
|
|
47
450
|
*/
|
|
48
451
|
export function parseClaudePayload(payload, now) {
|
|
49
452
|
const root = record(payload);
|
|
50
|
-
|
|
51
|
-
if (limits === null)
|
|
453
|
+
if (root === null)
|
|
52
454
|
return null;
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
455
|
+
const rateLimits = record(root["rate_limits"]);
|
|
456
|
+
const statusline = rateLimits !== null;
|
|
457
|
+
if (!statusline && !looksLikeUsageDocument(root))
|
|
458
|
+
return null;
|
|
459
|
+
const table = rateLimits ?? root;
|
|
460
|
+
const expiresAt = shortExpiry(now);
|
|
461
|
+
if (expiresAt === null)
|
|
462
|
+
return null;
|
|
463
|
+
/*
|
|
464
|
+
* One identity set across all four sources, which is what makes the dedupe
|
|
465
|
+
* mean something: the root table claims its codes first, so a model scoped
|
|
466
|
+
* entry naming a model the root already reported is the same pool twice and
|
|
467
|
+
* is skipped rather than drawn twice.
|
|
468
|
+
*/
|
|
469
|
+
const seen = new Set();
|
|
470
|
+
const inputs = [
|
|
471
|
+
...parseWindowTable(table, now, seen),
|
|
472
|
+
...parseModelScoped(table["model_scoped"], now, seen),
|
|
473
|
+
...parseScopedLimits(table["limits"], now, seen)
|
|
474
|
+
];
|
|
475
|
+
const extra = parseExtraUsage(table["extra_usage"], now);
|
|
476
|
+
if (extra !== null && !seen.has(extra.meter)) {
|
|
477
|
+
seen.add(extra.meter);
|
|
478
|
+
inputs.push(extra);
|
|
60
479
|
}
|
|
61
|
-
|
|
480
|
+
if (inputs.length === 0)
|
|
481
|
+
return null;
|
|
482
|
+
/*
|
|
483
|
+
* The statusline is the payload Claude Code hands us directly. The usage
|
|
484
|
+
* document is a private route read with the same credential, and calling it
|
|
485
|
+
* a native payload would overstate what it is, so the two carry different
|
|
486
|
+
* sources and the honesty labels above stay identical for both.
|
|
487
|
+
*/
|
|
488
|
+
const source = statusline ? "native_payload" : "internal_payload";
|
|
489
|
+
return inputs.map((input) => buildMeter(input, now, expiresAt, source));
|
|
62
490
|
}
|
|
491
|
+
/** The local application that owns this credential. */
|
|
492
|
+
export const CLAUDE_TOOL = "Claude Code";
|
|
63
493
|
export const claudeConnector = {
|
|
64
494
|
id: "claude",
|
|
495
|
+
encoding: "json",
|
|
65
496
|
displayName: "Claude",
|
|
66
497
|
labels: claudeLabels,
|
|
67
498
|
detect(environment) {
|
|
@@ -69,9 +500,10 @@ export const claudeConnector = {
|
|
|
69
500
|
},
|
|
70
501
|
async read(context) {
|
|
71
502
|
const meters = parseClaudePayload(context.payload, context.now);
|
|
503
|
+
const connection = connectorConnection(meters !== null, context.payload, CLAUDE_TOOL);
|
|
72
504
|
return meters === null
|
|
73
|
-
? { ok: false, reason: "unknown" }
|
|
74
|
-
: { ok: true, meters };
|
|
505
|
+
? { ok: false, reason: "unknown", connection }
|
|
506
|
+
: { ok: true, meters, connection };
|
|
75
507
|
}
|
|
76
508
|
};
|
|
77
509
|
//# sourceMappingURL=claude.js.map
|
package/dist/claude.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../src/claude.ts"],"names":[],"mappings":"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"}
|
package/dist/codex.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
|
-
import type { ConnectorContract, RawMeter } from "@openlimiter/core";
|
|
1
|
+
import type { ConnectionTool, ConnectorContract, RawMeter } from "@openlimiter/core";
|
|
2
|
+
/**
|
|
3
|
+
* The Codex usage reader.
|
|
4
|
+
*
|
|
5
|
+
* The shape below is the one a working reader observed against a real account
|
|
6
|
+
* on 2026-08-07, recorded in `Product Idea/reference-implementation`. OpenAI
|
|
7
|
+
* publishes nothing about it, so it is DESIGN evidence and not verification
|
|
8
|
+
* evidence: it tells us what to parse, and it does not turn an internal
|
|
9
|
+
* endpoint into an official API. The labels below stay as they are, and the
|
|
10
|
+
* provider stays UNVERIFIED, until a sanitized capture lands in the fixture
|
|
11
|
+
* slot and even then the interface is still internal.
|
|
12
|
+
*
|
|
13
|
+
* The reader used to parse `rate_limits` with an s, a shape carried over from
|
|
14
|
+
* an early prototype and never seen on the wire. The real field is
|
|
15
|
+
* `rate_limit`, singular. That one letter is the whole reason the drift
|
|
16
|
+
* machinery exists: both shapes are well formed JSON, both would have arrived
|
|
17
|
+
* with a 200, and the wrong one produces no reading at all rather than a wrong
|
|
18
|
+
* one only because this parser refuses whatever it was not told to expect.
|
|
19
|
+
*/
|
|
2
20
|
export declare const codexLabels: {
|
|
3
21
|
readonly credentialOrigin: "official-local-tool";
|
|
4
22
|
readonly dataInterfaceStatus: "internal-endpoint";
|
|
@@ -10,6 +28,10 @@ export declare const codexInput: {
|
|
|
10
28
|
readonly pathTemplate: "{providerState}/usage.json";
|
|
11
29
|
readonly readMode: "read_only";
|
|
12
30
|
};
|
|
31
|
+
/** What this reader reads. JSON, because the endpoint answers JSON. */
|
|
32
|
+
export declare const codexEncoding: "json";
|
|
13
33
|
export declare function parseCodexPayload(payload: unknown, now: string): RawMeter[] | null;
|
|
34
|
+
/** The local application that owns this credential. */
|
|
35
|
+
export declare const CODEX_TOOL: ConnectionTool;
|
|
14
36
|
export declare const codexConnector: ConnectorContract;
|
|
15
37
|
//# sourceMappingURL=codex.d.ts.map
|
package/dist/codex.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EAGjB,QAAQ,EACT,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../src/codex.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EAGjB,QAAQ,EACT,MAAM,mBAAmB,CAAC;AAY3B;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,WAAW;;;;;CAKY,CAAC;AAErC,eAAO,MAAM,UAAU;;;;CAIb,CAAC;AAEX,uEAAuE;AACvE,eAAO,MAAM,aAAa,EAAG,MAAe,CAAC;AAoC7C,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI,CA+DlF;AAED,uDAAuD;AACvD,eAAO,MAAM,UAAU,EAAE,cAA4B,CAAC;AAEtD,eAAO,MAAM,cAAc,EAAE,iBAmB5B,CAAC"}
|