@vymalo/opencode-ratelimit 0.12.0 → 0.14.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/config.d.ts +14 -14
- package/dist/config.js +103 -108
- package/dist/config.js.map +1 -1
- package/dist/headers.d.ts +15 -15
- package/dist/headers.js +71 -70
- package/dist/headers.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/logging.d.ts +6 -6
- package/dist/logging.js +58 -62
- package/dist/logging.js.map +1 -1
- package/dist/opencode.d.ts +4 -4
- package/dist/opencode.js +51 -56
- package/dist/opencode.js.map +1 -1
- package/dist/plugin.d.ts +49 -49
- package/dist/plugin.js +442 -423
- package/dist/plugin.js.map +1 -1
- package/dist/types.d.ts +53 -53
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
package/dist/config.d.ts
CHANGED
|
@@ -4,20 +4,20 @@ export declare const DEFAULT_MAX_RETRIES = 5;
|
|
|
4
4
|
export declare const DEFAULT_HEADER_PREFIX = "x-ratelimit";
|
|
5
5
|
export declare const DEFAULT_SCOPE: RateLimitScope;
|
|
6
6
|
/**
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
* Parse a provider's `options.meta.rateLimit` block into resolved
|
|
8
|
+
* {@link RateLimitOptions}. Returns `null` when the provider has NOT opted in
|
|
9
|
+
* (no `meta.rateLimit`) or has explicitly disabled it (`enabled: false`).
|
|
10
|
+
*
|
|
11
|
+
* Two config styles, both supported:
|
|
12
|
+
* - **Flat**: `maxWaitMs` / `maxRetries` → normalized into a single catch-all
|
|
13
|
+
* `"wait"` tier (the 0.5.0 behavior).
|
|
14
|
+
* - **Tiered**: a `tiers` array, each entry `{ maxResetSeconds?, action?,
|
|
15
|
+
* maxWaitMs?, maxRetries? }`, matched by reset magnitude.
|
|
16
|
+
*/
|
|
17
17
|
export declare function parseRateLimitOptions(providerOptions: Record<string, unknown> | undefined): RateLimitOptions | null;
|
|
18
18
|
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
* Select the policy tier for an observed reset. `tiers` is pre-sorted ascending
|
|
20
|
+
* with a catch-all last, so the first tier whose bound covers `resetSeconds`
|
|
21
|
+
* wins. An unknown reset is treated as the smallest band (wait a default backoff).
|
|
22
|
+
*/
|
|
23
23
|
export declare function selectTier(tiers: RateLimitTier[], resetSeconds: number | undefined): RateLimitTier;
|
package/dist/config.js
CHANGED
|
@@ -1,143 +1,138 @@
|
|
|
1
|
-
export const DEFAULT_MAX_WAIT_MS = 0;
|
|
1
|
+
export const DEFAULT_MAX_WAIT_MS = 0;
|
|
2
2
|
export const DEFAULT_MAX_RETRIES = 5;
|
|
3
3
|
export const DEFAULT_HEADER_PREFIX = "x-ratelimit";
|
|
4
4
|
export const DEFAULT_SCOPE = "model";
|
|
5
5
|
const META_KEY = "meta";
|
|
6
6
|
const RATE_LIMIT_KEY = "rateLimit";
|
|
7
7
|
function asRecord(value) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
return value;
|
|
12
12
|
}
|
|
13
13
|
function asString(value) {
|
|
14
|
-
|
|
14
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
|
15
15
|
}
|
|
16
16
|
function asBoolean(value, fallback) {
|
|
17
|
-
|
|
17
|
+
return typeof value === "boolean" ? value : fallback;
|
|
18
18
|
}
|
|
19
19
|
function asPositiveInt(value, fallback) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
21
|
+
return Math.floor(value);
|
|
22
|
+
}
|
|
23
|
+
return fallback;
|
|
24
24
|
}
|
|
25
25
|
/** Like {@link asPositiveInt} but accepts `0` — used for `maxWaitMs` where 0 means unlimited. */
|
|
26
26
|
function asNonNegativeInt(value, fallback) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
28
|
+
return Math.floor(value);
|
|
29
|
+
}
|
|
30
|
+
return fallback;
|
|
31
31
|
}
|
|
32
32
|
function asScope(value) {
|
|
33
|
-
|
|
33
|
+
return value === "provider" || value === "model" ? value : DEFAULT_SCOPE;
|
|
34
34
|
}
|
|
35
35
|
function asAction(value) {
|
|
36
|
-
|
|
36
|
+
return value === "error" ? "error" : "wait";
|
|
37
37
|
}
|
|
38
38
|
/** A positive int, or `null` (the catch-all sentinel) when absent/non-positive. */
|
|
39
39
|
function asMaxResetSeconds(value) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
41
|
+
return Math.floor(value);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
44
|
}
|
|
45
45
|
function parseTier(raw) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
return {
|
|
47
|
+
maxResetSeconds: asMaxResetSeconds(raw.maxResetSeconds),
|
|
48
|
+
action: asAction(raw.action),
|
|
49
|
+
maxWaitMs: asNonNegativeInt(raw.maxWaitMs, DEFAULT_MAX_WAIT_MS),
|
|
50
|
+
maxRetries: asPositiveInt(raw.maxRetries, DEFAULT_MAX_RETRIES)
|
|
51
|
+
};
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
* Sort ascending by `maxResetSeconds` (catch-all `null` last) and guarantee a
|
|
55
|
+
* trailing catch-all so every reset magnitude matches some tier. Without an
|
|
56
|
+
* explicit catch-all the ultimate fallback is "wait the full window" — the safe
|
|
57
|
+
* direction (never hammer the gateway).
|
|
58
|
+
*/
|
|
59
59
|
function normalizeTiers(tiers) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
return sorted;
|
|
60
|
+
const sorted = [...tiers].sort((a, b) => {
|
|
61
|
+
if (a.maxResetSeconds === b.maxResetSeconds) return 0;
|
|
62
|
+
if (a.maxResetSeconds === null) return 1;
|
|
63
|
+
if (b.maxResetSeconds === null) return -1;
|
|
64
|
+
return a.maxResetSeconds - b.maxResetSeconds;
|
|
65
|
+
});
|
|
66
|
+
if (!sorted.some((t) => t.maxResetSeconds === null)) {
|
|
67
|
+
sorted.push({
|
|
68
|
+
maxResetSeconds: null,
|
|
69
|
+
action: "wait",
|
|
70
|
+
maxWaitMs: DEFAULT_MAX_WAIT_MS,
|
|
71
|
+
maxRetries: DEFAULT_MAX_RETRIES
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return sorted;
|
|
78
75
|
}
|
|
79
76
|
/**
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
77
|
+
* Parse a provider's `options.meta.rateLimit` block into resolved
|
|
78
|
+
* {@link RateLimitOptions}. Returns `null` when the provider has NOT opted in
|
|
79
|
+
* (no `meta.rateLimit`) or has explicitly disabled it (`enabled: false`).
|
|
80
|
+
*
|
|
81
|
+
* Two config styles, both supported:
|
|
82
|
+
* - **Flat**: `maxWaitMs` / `maxRetries` → normalized into a single catch-all
|
|
83
|
+
* `"wait"` tier (the 0.5.0 behavior).
|
|
84
|
+
* - **Tiered**: a `tiers` array, each entry `{ maxResetSeconds?, action?,
|
|
85
|
+
* maxWaitMs?, maxRetries? }`, matched by reset magnitude.
|
|
86
|
+
*/
|
|
90
87
|
export function parseRateLimitOptions(providerOptions) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
headerPrefix: (asString(rateLimit.headerPrefix) ?? DEFAULT_HEADER_PREFIX).toLowerCase(),
|
|
126
|
-
tiers
|
|
127
|
-
};
|
|
88
|
+
if (!providerOptions) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const meta = asRecord(providerOptions[META_KEY]);
|
|
92
|
+
if (!meta) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const rateLimit = asRecord(meta[RATE_LIMIT_KEY]);
|
|
96
|
+
if (!rateLimit) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const enabled = asBoolean(rateLimit.enabled, true);
|
|
100
|
+
if (!enabled) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const rawTiers = Array.isArray(rateLimit.tiers) ? rateLimit.tiers : undefined;
|
|
104
|
+
let tiers;
|
|
105
|
+
if (rawTiers && rawTiers.length > 0) {
|
|
106
|
+
tiers = normalizeTiers(rawTiers.map((t) => parseTier(asRecord(t) ?? {})));
|
|
107
|
+
} else {
|
|
108
|
+
// Flat config → one catch-all "wait" tier (backward compatible with 0.5.0).
|
|
109
|
+
tiers = [{
|
|
110
|
+
maxResetSeconds: null,
|
|
111
|
+
action: "wait",
|
|
112
|
+
maxWaitMs: asNonNegativeInt(rateLimit.maxWaitMs, DEFAULT_MAX_WAIT_MS),
|
|
113
|
+
maxRetries: asPositiveInt(rateLimit.maxRetries, DEFAULT_MAX_RETRIES)
|
|
114
|
+
}];
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
enabled: true,
|
|
118
|
+
scope: asScope(rateLimit.scope),
|
|
119
|
+
headerPrefix: (asString(rateLimit.headerPrefix) ?? DEFAULT_HEADER_PREFIX).toLowerCase(),
|
|
120
|
+
tiers
|
|
121
|
+
};
|
|
128
122
|
}
|
|
129
123
|
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
124
|
+
* Select the policy tier for an observed reset. `tiers` is pre-sorted ascending
|
|
125
|
+
* with a catch-all last, so the first tier whose bound covers `resetSeconds`
|
|
126
|
+
* wins. An unknown reset is treated as the smallest band (wait a default backoff).
|
|
127
|
+
*/
|
|
134
128
|
export function selectTier(tiers, resetSeconds) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
const reset = resetSeconds ?? 0;
|
|
130
|
+
for (const tier of tiers) {
|
|
131
|
+
if (tier.maxResetSeconds === null || reset <= tier.maxResetSeconds) {
|
|
132
|
+
return tier;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return tiers[tiers.length - 1];
|
|
142
136
|
}
|
|
137
|
+
|
|
143
138
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/config.ts"],"version":3,"file":"config.js","sourceRoot":""}
|
package/dist/headers.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { RateLimitSnapshot } from "./types.js";
|
|
2
2
|
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
* Parse the IETF draft-03 rate-limit triple (as emitted by Envoy Gateway's
|
|
4
|
+
* global rate limit) plus an optional `Retry-After` fallback into a
|
|
5
|
+
* {@link RateLimitSnapshot}.
|
|
6
|
+
*
|
|
7
|
+
* Envoy emits these on BOTH 200 and 429 responses, e.g.:
|
|
8
|
+
* x-ratelimit-limit: 3, 3;w=60
|
|
9
|
+
* x-ratelimit-remaining: 2
|
|
10
|
+
* x-ratelimit-reset: 48 (seconds until the bucket resets)
|
|
11
|
+
*
|
|
12
|
+
* `Retry-After` is NOT emitted by Envoy Gateway today, so it is only consulted
|
|
13
|
+
* as a fallback when present (all-digits → seconds; otherwise an HTTP-date).
|
|
14
|
+
*
|
|
15
|
+
* Header names are case-insensitive (the Fetch `Headers` object lowercases
|
|
16
|
+
* them); `prefix` should already be lowercased by the caller.
|
|
17
|
+
*/
|
|
18
18
|
export declare function parseRateLimit(headers: Headers, prefix: string, nowMs: number): RateLimitSnapshot;
|
package/dist/headers.js
CHANGED
|
@@ -1,82 +1,83 @@
|
|
|
1
1
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
2
|
+
* Parse the IETF draft-03 rate-limit triple (as emitted by Envoy Gateway's
|
|
3
|
+
* global rate limit) plus an optional `Retry-After` fallback into a
|
|
4
|
+
* {@link RateLimitSnapshot}.
|
|
5
|
+
*
|
|
6
|
+
* Envoy emits these on BOTH 200 and 429 responses, e.g.:
|
|
7
|
+
* x-ratelimit-limit: 3, 3;w=60
|
|
8
|
+
* x-ratelimit-remaining: 2
|
|
9
|
+
* x-ratelimit-reset: 48 (seconds until the bucket resets)
|
|
10
|
+
*
|
|
11
|
+
* `Retry-After` is NOT emitted by Envoy Gateway today, so it is only consulted
|
|
12
|
+
* as a fallback when present (all-digits → seconds; otherwise an HTTP-date).
|
|
13
|
+
*
|
|
14
|
+
* Header names are case-insensitive (the Fetch `Headers` object lowercases
|
|
15
|
+
* them); `prefix` should already be lowercased by the caller.
|
|
16
|
+
*/
|
|
17
17
|
export function parseRateLimit(headers, prefix, nowMs) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
18
|
+
const snapshot = {};
|
|
19
|
+
const limit = parseLimit(headers.get(`${prefix}-limit`));
|
|
20
|
+
if (limit !== undefined) {
|
|
21
|
+
snapshot.limit = limit;
|
|
22
|
+
}
|
|
23
|
+
const remaining = parseInteger(headers.get(`${prefix}-remaining`));
|
|
24
|
+
if (remaining !== undefined) {
|
|
25
|
+
snapshot.remaining = remaining;
|
|
26
|
+
}
|
|
27
|
+
const resetSeconds = parseInteger(headers.get(`${prefix}-reset`));
|
|
28
|
+
if (resetSeconds !== undefined) {
|
|
29
|
+
snapshot.resetSeconds = resetSeconds;
|
|
30
|
+
snapshot.resetAtMs = nowMs + resetSeconds * 1e3;
|
|
31
|
+
}
|
|
32
|
+
const retryAfterMs = parseRetryAfter(headers.get("retry-after"), nowMs);
|
|
33
|
+
if (retryAfterMs !== undefined) {
|
|
34
|
+
snapshot.retryAfterMs = retryAfterMs;
|
|
35
|
+
}
|
|
36
|
+
return snapshot;
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
* `x-ratelimit-limit` carries the effective limit followed by optional
|
|
40
|
+
* window descriptors, e.g. `"3, 3;w=60"`. We take the first comma-separated
|
|
41
|
+
* token and strip any `;w=...` quota-policy suffix → `3`. A plain `"3"` works too.
|
|
42
|
+
*/
|
|
43
43
|
function parseLimit(raw) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
if (raw === null) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
const firstToken = raw.split(",", 1)[0]?.split(";", 1)[0];
|
|
48
|
+
return parseInteger(firstToken);
|
|
49
49
|
}
|
|
50
50
|
function parseInteger(raw) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
if (raw === null || raw === undefined) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const trimmed = raw.trim();
|
|
55
|
+
if (trimmed.length === 0 || !/^-?\d+$/.test(trimmed)) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const value = Number.parseInt(trimmed, 10);
|
|
59
|
+
return Number.isFinite(value) ? value : undefined;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
* `Retry-After` is either a non-negative integer (delay-seconds) or an
|
|
63
|
+
* HTTP-date. Returns the wait in ms, never negative.
|
|
64
|
+
*/
|
|
65
65
|
function parseRetryAfter(raw, nowMs) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
if (raw === null) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
const trimmed = raw.trim();
|
|
70
|
+
if (trimmed.length === 0) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
if (/^\d+$/.test(trimmed)) {
|
|
74
|
+
return Number.parseInt(trimmed, 10) * 1e3;
|
|
75
|
+
}
|
|
76
|
+
const dateMs = Date.parse(trimmed);
|
|
77
|
+
if (Number.isNaN(dateMs)) {
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
return Math.max(0, dateMs - nowMs);
|
|
81
81
|
}
|
|
82
|
+
|
|
82
83
|
//# sourceMappingURL=headers.js.map
|
package/dist/headers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":";;;;;;;;;;;;;;;;AAkBA,OAAO,SAAS,eAAe,SAAkB,QAAgB,OAAkC;CACjG,MAAM,WAA8B,CAAC;CAErC,MAAM,QAAQ,WAAW,QAAQ,IAAI,GAAG,OAAO,OAAO,CAAC;CACvD,IAAI,UAAU,WAAW;EACvB,SAAS,QAAQ;CACnB;CAEA,MAAM,YAAY,aAAa,QAAQ,IAAI,GAAG,OAAO,WAAW,CAAC;CACjE,IAAI,cAAc,WAAW;EAC3B,SAAS,YAAY;CACvB;CAEA,MAAM,eAAe,aAAa,QAAQ,IAAI,GAAG,OAAO,OAAO,CAAC;CAChE,IAAI,iBAAiB,WAAW;EAC9B,SAAS,eAAe;EACxB,SAAS,YAAY,QAAQ,eAAe;CAC9C;CAEA,MAAM,eAAe,gBAAgB,QAAQ,IAAI,aAAa,GAAG,KAAK;CACtE,IAAI,iBAAiB,WAAW;EAC9B,SAAS,eAAe;CAC1B;CAEA,OAAO;AACT;;;;;;AAOA,SAAS,WAAW,KAAwC;CAC1D,IAAI,QAAQ,MAAM;EAChB,OAAO;CACT;CACA,MAAM,aAAa,IAAI,MAAM,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC;CACvD,OAAO,aAAa,UAAU;AAChC;AAEA,SAAS,aAAa,KAAoD;CACxE,IAAI,QAAQ,QAAQ,QAAQ,WAAW;EACrC,OAAO;CACT;CACA,MAAM,UAAU,IAAI,KAAK;CACzB,IAAI,QAAQ,WAAW,KAAK,CAAC,UAAU,KAAK,OAAO,GAAG;EACpD,OAAO;CACT;CACA,MAAM,QAAQ,OAAO,SAAS,SAAS,EAAE;CACzC,OAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AAC1C;;;;;AAMA,SAAS,gBAAgB,KAAoB,OAAmC;CAC9E,IAAI,QAAQ,MAAM;EAChB,OAAO;CACT;CACA,MAAM,UAAU,IAAI,KAAK;CACzB,IAAI,QAAQ,WAAW,GAAG;EACxB,OAAO;CACT;CACA,IAAI,QAAQ,KAAK,OAAO,GAAG;EACzB,OAAO,OAAO,SAAS,SAAS,EAAE,IAAI;CACxC;CACA,MAAM,SAAS,KAAK,MAAM,OAAO;CACjC,IAAI,OAAO,MAAM,MAAM,GAAG;EACxB,OAAO;CACT;CACA,OAAO,KAAK,IAAI,GAAG,SAAS,KAAK;AACnC","names":[],"sources":["../src/headers.ts"],"version":3,"file":"headers.js","sourceRoot":""}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":";;;AAGA,SAAS,eAAe","names":[],"sources":["../src/index.ts"],"version":3,"file":"index.js","sourceRoot":""}
|
package/dist/lib.js
CHANGED
|
@@ -3,4 +3,5 @@ export { DEFAULT_HEADER_PREFIX, DEFAULT_MAX_RETRIES, DEFAULT_MAX_WAIT_MS, DEFAUL
|
|
|
3
3
|
export { parseRateLimit } from "./headers.js";
|
|
4
4
|
export { createJsonConsoleLogger, DEFAULT_LOG_LEVEL, fromOpenCodeLogLevel } from "./logging.js";
|
|
5
5
|
export { createProviderState, DEFAULT_BACKOFF_MS, installRateLimiter, makeRateLimitFetch } from "./plugin.js";
|
|
6
|
+
|
|
6
7
|
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":"AAAA,SACE,+BACA,+BAEK;AAEP,SACE,uBACA,qBACA,qBACA,eACA,uBACA,kBACK;AAEP,SAAS,sBAAsB;AAE/B,SACE,yBACA,mBACA,4BAIK;AAEP,SACE,qBACA,oBAEA,oBACA,0BAKK","names":[],"sources":["../src/lib.ts"],"version":3,"file":"lib.js","sourceRoot":""}
|
package/dist/logging.d.ts
CHANGED
|
@@ -3,14 +3,14 @@ export type { LogLevel } from "./types.js";
|
|
|
3
3
|
export declare const LOG_LEVEL_PRIORITY: Record<LogLevel, number>;
|
|
4
4
|
export declare const DEFAULT_LOG_LEVEL: LogLevel;
|
|
5
5
|
export interface LogFields {
|
|
6
|
-
|
|
6
|
+
[key: string]: unknown;
|
|
7
7
|
}
|
|
8
8
|
export interface Logger {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
trace(event: string, fields?: LogFields): void;
|
|
10
|
+
debug(event: string, fields?: LogFields): void;
|
|
11
|
+
info(event: string, fields?: LogFields): void;
|
|
12
|
+
warn(event: string, fields?: LogFields): void;
|
|
13
|
+
error(event: string, fields?: LogFields): void;
|
|
14
14
|
}
|
|
15
15
|
export declare function createJsonConsoleLogger(minLevel?: LogLevel): Logger;
|
|
16
16
|
export declare function fromOpenCodeLogLevel(value: unknown): LogLevel | undefined;
|