@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.
Files changed (53) hide show
  1. package/dist/antigravity.d.ts +50 -1
  2. package/dist/antigravity.d.ts.map +1 -1
  3. package/dist/antigravity.js +150 -19
  4. package/dist/antigravity.js.map +1 -1
  5. package/dist/claude.d.ts +72 -6
  6. package/dist/claude.d.ts.map +1 -1
  7. package/dist/claude.js +467 -35
  8. package/dist/claude.js.map +1 -1
  9. package/dist/codex.d.ts +23 -1
  10. package/dist/codex.d.ts.map +1 -1
  11. package/dist/codex.js +112 -13
  12. package/dist/codex.js.map +1 -1
  13. package/dist/contract-gate.d.ts +56 -0
  14. package/dist/contract-gate.d.ts.map +1 -0
  15. package/dist/contract-gate.js +100 -0
  16. package/dist/contract-gate.js.map +1 -0
  17. package/dist/fixtures.d.ts +274 -2
  18. package/dist/fixtures.d.ts.map +1 -1
  19. package/dist/fixtures.js +947 -17
  20. package/dist/fixtures.js.map +1 -1
  21. package/dist/gemini-cli.d.ts +13 -0
  22. package/dist/gemini-cli.d.ts.map +1 -0
  23. package/dist/gemini-cli.js +86 -0
  24. package/dist/gemini-cli.js.map +1 -0
  25. package/dist/grok.d.ts +13 -0
  26. package/dist/grok.d.ts.map +1 -0
  27. package/dist/grok.js +143 -0
  28. package/dist/grok.js.map +1 -0
  29. package/dist/index.d.ts +4 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +10 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/kimi.d.ts +13 -0
  34. package/dist/kimi.d.ts.map +1 -0
  35. package/dist/kimi.js +141 -0
  36. package/dist/kimi.js.map +1 -0
  37. package/dist/manual.d.ts +3 -1
  38. package/dist/manual.d.ts.map +1 -1
  39. package/dist/manual.js +7 -3
  40. package/dist/manual.js.map +1 -1
  41. package/dist/opencode.d.ts +103 -1
  42. package/dist/opencode.d.ts.map +1 -1
  43. package/dist/opencode.js +428 -21
  44. package/dist/opencode.js.map +1 -1
  45. package/dist/openrouter.d.ts +3 -1
  46. package/dist/openrouter.d.ts.map +1 -1
  47. package/dist/openrouter.js +7 -3
  48. package/dist/openrouter.js.map +1 -1
  49. package/dist/shared.d.ts +105 -1
  50. package/dist/shared.d.ts.map +1 -1
  51. package/dist/shared.js +190 -0
  52. package/dist/shared.js.map +1 -1
  53. package/package.json +4 -3
package/dist/claude.js CHANGED
@@ -1,4 +1,4 @@
1
- import { boundedNumber, futureInstant, rawMeter, record, shortExpiry } from "./shared.js";
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
- function parseWindow(value, now, meter, durationSeconds) {
14
- const input = record(value);
15
- if (input === null)
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
- const percent = boundedNumber(input["utilization"]);
18
- const resetAt = futureInstant(input["resets_at"], now);
19
- const expiresAt = shortExpiry(now);
20
- if (percent === null || resetAt === null || expiresAt === null)
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: { kind: "rolling", durationSeconds },
27
- resetAt,
28
- source: "native_payload",
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
- * Parse the rate limit block of a Claude Code statusline payload.
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
- * Shape: { "rate_limits": { "five_hour": { "utilization": 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
- * A window that fails validation is dropped and the other window still counts,
46
- * because one expired window is not a reason to forget the whole session.
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
- const limits = record(root?.["rate_limits"]);
51
- if (limits === null)
453
+ if (root === null)
52
454
  return null;
53
- const meters = [];
54
- for (const window of windows) {
55
- if (!(window.key in limits))
56
- continue;
57
- const parsed = parseWindow(limits[window.key], now, window.meter, window.durationSeconds);
58
- if (parsed !== null)
59
- meters.push(parsed);
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
- return meters.length === 0 ? null : meters;
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
@@ -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
@@ -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;AAG3B,eAAO,MAAM,WAAW;;;;;CAKY,CAAC;AAErC,eAAO,MAAM,UAAU;;;;CAIb,CAAC;AAEX,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI,CAoBlF;AAED,eAAO,MAAM,cAAc,EAAE,iBAa5B,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"}