@swttch/extend-kit 0.6.0 → 0.6.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.
- package/dist/battery/api/client.js +53 -6
- package/dist/battery/api/client.js.map +1 -1
- package/dist/battery/api/http.d.ts +22 -1
- package/dist/battery/api/http.js +151 -34
- package/dist/battery/api/http.js.map +1 -1
- package/dist/battery/api/index.d.ts +1 -1
- package/dist/battery/api/types.d.ts +44 -0
- package/dist/battery/errors.d.ts +24 -1
- package/dist/battery/errors.js +4 -1
- package/dist/battery/errors.js.map +1 -1
- package/dist/battery/index.d.ts +2 -1
- package/dist/battery/index.js.map +1 -1
- package/dist/proxy.d.ts +30 -1
- package/dist/proxy.js +70 -7
- package/dist/proxy.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OAuthApi } from './oauth.js';
|
|
2
|
-
import { getJson } from './http.js';
|
|
2
|
+
import { getJson, proxyInUseFor } from './http.js';
|
|
3
3
|
import { getCredentials, getAccessToken, isApiKeyAuth } from '../auth/index.js';
|
|
4
4
|
import { CcbError } from '../errors.js';
|
|
5
5
|
const BASE_URL = 'https://api.anthropic.com';
|
|
@@ -58,14 +58,61 @@ export class ClaudeCodeClient {
|
|
|
58
58
|
...headers,
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
-
// getJson rather than fetch: fetch
|
|
62
|
-
//
|
|
63
|
-
// See src/proxy.ts.
|
|
64
|
-
const
|
|
61
|
+
// getJson rather than fetch: fetch takes no `http.Agent`, and `ws` proxies
|
|
62
|
+
// only when handed one, so a single proxy implementation has to be built on
|
|
63
|
+
// something both transports accept. See src/proxy.ts.
|
|
64
|
+
const url = `${this.baseUrl}${path}`;
|
|
65
|
+
const response = await getJson(url, requestHeaders);
|
|
65
66
|
if (!response.ok) {
|
|
66
|
-
throw
|
|
67
|
+
throw describeApiFailure(response, url);
|
|
67
68
|
}
|
|
68
69
|
return response.body;
|
|
69
70
|
}
|
|
70
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Turn an HTTP status into an error a caller can route on and a person can act on.
|
|
74
|
+
*
|
|
75
|
+
* Every non-2xx used to become one `api_error` reading "API error 403: Forbidden",
|
|
76
|
+
* which is the same sentence for an expired login, a rate limit, and a request the
|
|
77
|
+
* gateway blocked. Nothing downstream could tell them apart, so the plugin's usage
|
|
78
|
+
* panel classified all of them as an authentication problem and told people to log
|
|
79
|
+
* in again no matter what had actually happened.
|
|
80
|
+
*
|
|
81
|
+
* The proxy is named whenever one is in play. A refusal that reaches this function
|
|
82
|
+
* came from the destination — {@link getJson} throws before this point when the
|
|
83
|
+
* proxy itself refused the tunnel — but knowing which route the request took is
|
|
84
|
+
* what makes the difference checkable rather than guessable.
|
|
85
|
+
*/
|
|
86
|
+
function describeApiFailure(response, url) {
|
|
87
|
+
const { status, statusText, retryAfterSec } = response;
|
|
88
|
+
const message = `API error ${status}: ${statusText}`;
|
|
89
|
+
const proxyUrl = proxyInUseFor(url);
|
|
90
|
+
const route = proxyUrl
|
|
91
|
+
? `The request reached the API through the proxy at ${proxyUrl}.`
|
|
92
|
+
: 'The request went straight to the API, with no proxy configured for this process.';
|
|
93
|
+
// Repeated on every branch so a caller never has to know which code carries
|
|
94
|
+
// which facts. `reachedDestination` is true throughout: getJson throws before
|
|
95
|
+
// this point when a proxy refused the tunnel, so anything here was answered by
|
|
96
|
+
// the destination itself.
|
|
97
|
+
const details = { status, ...(proxyUrl && { proxyUrl }), reachedDestination: true };
|
|
98
|
+
if (status === 401) {
|
|
99
|
+
return new CcbError(message, 'token_expired', 'The saved login is no longer accepted. Run `claude` once to refresh it.', details);
|
|
100
|
+
}
|
|
101
|
+
if (status === 403) {
|
|
102
|
+
// The case this whole taxonomy came out of: a machine that can only reach
|
|
103
|
+
// Anthropic through a proxy, with the request going direct because the proxy
|
|
104
|
+
// was configured under a variable this tool was not reading. The gateway
|
|
105
|
+
// answers 403, which looks like an account problem and is not one.
|
|
106
|
+
return new CcbError(message, 'forbidden', `${route} A 403 here is usually the network refusing the request rather than the account lacking access.`, details);
|
|
107
|
+
}
|
|
108
|
+
if (status === 429) {
|
|
109
|
+
return new CcbError(message, 'rate_limited', retryAfterSec !== undefined
|
|
110
|
+
? `Too many requests. The API asked us to wait ${retryAfterSec}s.`
|
|
111
|
+
: 'Too many requests in a short window. Try again shortly.', { ...details, ...(retryAfterSec !== undefined && { retryAfterSec }) });
|
|
112
|
+
}
|
|
113
|
+
if (status >= 500) {
|
|
114
|
+
return new CcbError(message, 'server_error', `${route} The API itself reported an error.`, details);
|
|
115
|
+
}
|
|
116
|
+
return new CcbError(message, 'api_error', route, details);
|
|
117
|
+
}
|
|
71
118
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/battery/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/battery/api/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,21 @@ export interface JsonResponse<T> {
|
|
|
5
5
|
status: number;
|
|
6
6
|
statusText: string;
|
|
7
7
|
body: T;
|
|
8
|
+
/**
|
|
9
|
+
* Seconds the destination asked us to wait, parsed from Retry-After.
|
|
10
|
+
*
|
|
11
|
+
* Surfaced as a number because the only alternative is for a caller to find it
|
|
12
|
+
* by matching prose, and a caller that reads prose breaks when the prose changes.
|
|
13
|
+
* Absent when the header was missing or was an HTTP-date rather than a count.
|
|
14
|
+
*/
|
|
15
|
+
retryAfterSec?: number;
|
|
16
|
+
}
|
|
17
|
+
/** Options that change how a request is made, rather than what is requested. */
|
|
18
|
+
export interface GetJsonOptions {
|
|
19
|
+
/** Use this agent instead of resolving one from the proxy environment. */
|
|
20
|
+
agent?: Agent;
|
|
21
|
+
/** Total budget for the request, covering connect, tunnel, and response. */
|
|
22
|
+
deadlineMs?: number;
|
|
8
23
|
}
|
|
9
24
|
/**
|
|
10
25
|
* GET a JSON document, through a proxy when one is configured.
|
|
@@ -14,4 +29,10 @@ export interface JsonResponse<T> {
|
|
|
14
29
|
* proxy is what failed. Since the proxy is invisible in the URL the user asked
|
|
15
30
|
* for, the error says so explicitly.
|
|
16
31
|
*/
|
|
17
|
-
export declare function getJson<T>(url: string, headers: Record<string, string>,
|
|
32
|
+
export declare function getJson<T>(url: string, headers: Record<string, string>, options?: GetJsonOptions): Promise<JsonResponse<T>>;
|
|
33
|
+
/**
|
|
34
|
+
* The proxy in play for `url`, safe to print, so a caller can name it in its own
|
|
35
|
+
* errors. Credentials are stripped here rather than at each call site, because a
|
|
36
|
+
* call site that forgets is a call site that prints a password.
|
|
37
|
+
*/
|
|
38
|
+
export declare function proxyInUseFor(url: string): string | undefined;
|
package/dist/battery/api/http.js
CHANGED
|
@@ -1,14 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HTTP transport for everything this package fetches.
|
|
3
|
+
*
|
|
4
|
+
* Global `fetch` cannot be handed an `http.Agent`, and `ws` proxies only when it
|
|
5
|
+
* is handed one, so routing both transports through a single proxy
|
|
6
|
+
* implementation means using `node:https` here. Proxying `fetch` itself is
|
|
7
|
+
* possible by other means — undici's ProxyAgent with setGlobalDispatcher — but a
|
|
8
|
+
* dispatcher does not cover `ws`, which is why that route was not taken.
|
|
9
|
+
* See {@link proxyAgentFor}.
|
|
10
|
+
*/
|
|
1
11
|
import { request as httpsRequest } from 'node:https';
|
|
2
12
|
import { request as httpRequest } from 'node:http';
|
|
3
|
-
import { proxyAgentFor } from '../../proxy.js';
|
|
13
|
+
import { proxyAgentFor, resolveProxyUrl, redactProxyUrl } from '../../proxy.js';
|
|
4
14
|
import { CcbError } from '../errors.js';
|
|
15
|
+
/** Retry-After is either a count of seconds or an HTTP-date; only the former is useful here. */
|
|
16
|
+
function parseRetryAfter(value) {
|
|
17
|
+
const raw = Array.isArray(value) ? value[0] : value;
|
|
18
|
+
if (!raw)
|
|
19
|
+
return undefined;
|
|
20
|
+
const seconds = Number(raw.trim());
|
|
21
|
+
if (Number.isFinite(seconds) && seconds >= 0)
|
|
22
|
+
return seconds;
|
|
23
|
+
const at = Date.parse(raw);
|
|
24
|
+
if (Number.isNaN(at))
|
|
25
|
+
return undefined;
|
|
26
|
+
return Math.max(0, Math.round((at - Date.now()) / 1000));
|
|
27
|
+
}
|
|
5
28
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
29
|
+
* How long a request may take in total: connecting, opening the tunnel when a
|
|
30
|
+
* proxy is in the way, and reading the response.
|
|
31
|
+
*
|
|
32
|
+
* One budget rather than a socket timeout, because a socket timeout starts when
|
|
33
|
+
* there is a socket. A proxy that is slow to answer CONNECT has not produced one
|
|
34
|
+
* yet, so the guard that was here before did not cover the very case its comment
|
|
35
|
+
* described: a proxy asked to open a tunnel and left to think about it for 70
|
|
36
|
+
* seconds ran to completion, unguarded, while the same 70-second silence after
|
|
37
|
+
* the tunnel opened was cut off at 60. Measured, not reasoned about.
|
|
10
38
|
*/
|
|
11
|
-
const
|
|
39
|
+
const DEFAULT_DEADLINE_MS = 60_000;
|
|
40
|
+
/**
|
|
41
|
+
* How long a request may take in total, before the caller's own option.
|
|
42
|
+
*
|
|
43
|
+
* A spawner with a shorter budget than ours can say so here. The plugin backend
|
|
44
|
+
* gives `ccb` 15 seconds and kills the process at that mark, which produces a
|
|
45
|
+
* dead child and whatever its login shell had printed by then rather than an
|
|
46
|
+
* explanation — the user was shown `(eval):1: can't change option: zle`. Told the
|
|
47
|
+
* budget, `ccb` finishes first and says what actually went wrong.
|
|
48
|
+
*/
|
|
49
|
+
function defaultDeadlineMs() {
|
|
50
|
+
const raw = Number(process.env.CCB_REQUEST_TIMEOUT_MS);
|
|
51
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_DEADLINE_MS;
|
|
52
|
+
}
|
|
12
53
|
/**
|
|
13
54
|
* GET a JSON document, through a proxy when one is configured.
|
|
14
55
|
*
|
|
@@ -17,45 +58,121 @@ const SOCKET_TIMEOUT_MS = 60_000;
|
|
|
17
58
|
* proxy is what failed. Since the proxy is invisible in the URL the user asked
|
|
18
59
|
* for, the error says so explicitly.
|
|
19
60
|
*/
|
|
20
|
-
export async function getJson(url, headers,
|
|
21
|
-
const agent
|
|
61
|
+
export async function getJson(url, headers, options = {}) {
|
|
62
|
+
const { agent: agentOverride, deadlineMs = defaultDeadlineMs() } = options;
|
|
63
|
+
// Built before the agent, because the agent needs it: see the note in
|
|
64
|
+
// proxyAgentFor on why a signal given only to the request cannot end a wait
|
|
65
|
+
// that has not produced a socket yet.
|
|
66
|
+
const abort = new AbortController();
|
|
67
|
+
const agent = agentOverride
|
|
68
|
+
?? proxyAgentFor(url, process.env, { signal: abort.signal, timeoutMs: deadlineMs });
|
|
22
69
|
const viaProxy = agent !== undefined;
|
|
70
|
+
// Only meaningful for the agent this function built: an override comes from a
|
|
71
|
+
// caller that knows its own routing, and naming an environment proxy it is not
|
|
72
|
+
// using would be worse than saying nothing.
|
|
73
|
+
const proxyUrl = agentOverride ? undefined : redactProxyUrl(resolveProxyUrl(url));
|
|
23
74
|
// The API is always https; plain http is here so tests can run against a local
|
|
24
75
|
// server without a certificate, and it costs one branch.
|
|
25
76
|
const request = new URL(url).protocol === 'http:' ? httpRequest : httpsRequest;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
77
|
+
// Aborting is what actually stops the work, rather than only telling the caller
|
|
78
|
+
// to stop waiting for it. One signal covers both halves: the agent destroys the
|
|
79
|
+
// socket it is reading the CONNECT response from, and the request tears down a
|
|
80
|
+
// socket it has already been handed.
|
|
81
|
+
let socketToKill;
|
|
82
|
+
let phase = 'connecting';
|
|
83
|
+
let proxyConnectStatus;
|
|
84
|
+
let timedOut = false;
|
|
85
|
+
const deadline = setTimeout(() => {
|
|
86
|
+
timedOut = true;
|
|
87
|
+
abort.abort();
|
|
88
|
+
socketToKill?.destroy();
|
|
89
|
+
}, deadlineMs);
|
|
90
|
+
const describeTimeout = () => new CcbError(`Request to ${url} timed out after ${Math.round(deadlineMs / 1000)}s`, 'timeout', phase === 'connecting' && viaProxy
|
|
91
|
+
? `The proxy${proxyUrl ? ` at ${proxyUrl}` : ''} never finished opening the tunnel.`
|
|
92
|
+
: viaProxy
|
|
93
|
+
? 'The tunnel was open, but the destination never replied.'
|
|
94
|
+
: undefined, { ...(proxyUrl && { proxyUrl }), reachedDestination: phase === 'tunnelled' });
|
|
95
|
+
let result;
|
|
96
|
+
try {
|
|
97
|
+
result = await new Promise((resolve, reject) => {
|
|
98
|
+
const req = request(url, { method: 'GET', headers, agent, signal: abort.signal }, (res) => {
|
|
99
|
+
const chunks = [];
|
|
100
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
101
|
+
res.on('end', () => resolve({
|
|
102
|
+
status: res.statusCode ?? 0,
|
|
103
|
+
statusText: res.statusMessage ?? '',
|
|
104
|
+
text: Buffer.concat(chunks).toString('utf-8'),
|
|
105
|
+
retryAfterSec: parseRetryAfter(res.headers['retry-after']),
|
|
106
|
+
}));
|
|
107
|
+
res.on('error', reject);
|
|
108
|
+
});
|
|
109
|
+
// https-proxy-agent announces the CONNECT response here before it decides
|
|
110
|
+
// what to do with it. Recording the status is what lets a refusal be told
|
|
111
|
+
// apart from an answer by the destination — see the throw below.
|
|
112
|
+
req.on('proxyConnect', (connect) => {
|
|
113
|
+
proxyConnectStatus = connect.statusCode;
|
|
114
|
+
if (connect.statusCode === 200)
|
|
115
|
+
phase = 'tunnelled';
|
|
116
|
+
});
|
|
117
|
+
req.on('socket', (socket) => {
|
|
118
|
+
socketToKill = socket;
|
|
119
|
+
// Without a proxy there is no CONNECT step to leave behind: once the
|
|
120
|
+
// socket exists, any further wait is the destination's.
|
|
121
|
+
if (!viaProxy)
|
|
122
|
+
phase = 'tunnelled';
|
|
123
|
+
});
|
|
124
|
+
req.on('error', (err) => {
|
|
125
|
+
if (timedOut)
|
|
126
|
+
return reject(describeTimeout());
|
|
127
|
+
if (err instanceof CcbError)
|
|
128
|
+
return reject(err);
|
|
129
|
+
reject(new CcbError(`Could not reach ${new URL(url).host}: ${err.message}`, 'network_error', viaProxy
|
|
130
|
+
? 'This connection went through the proxy from HTTP_PROXY/HTTPS_PROXY/ALL_PROXY. Check that the proxy is running and reachable.'
|
|
131
|
+
: undefined, { ...(proxyUrl && { proxyUrl }), reachedDestination: false }));
|
|
132
|
+
});
|
|
133
|
+
req.end();
|
|
48
134
|
});
|
|
49
|
-
|
|
50
|
-
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
clearTimeout(deadline);
|
|
138
|
+
}
|
|
139
|
+
// A proxy that refuses the CONNECT does not fail the request. https-proxy-agent
|
|
140
|
+
// replays the refusal onto a stand-in socket so node's HTTP parser reads it,
|
|
141
|
+
// which means the proxy's own "403 Forbidden" arrives here shaped exactly like a
|
|
142
|
+
// 403 from the API.
|
|
143
|
+
//
|
|
144
|
+
// That replay is deliberate on the library's part, not something to route around:
|
|
145
|
+
// it destroys the real socket first so the request — Authorization header and all
|
|
146
|
+
// — is never written to a proxy that just declined to carry it (HackerOne
|
|
147
|
+
// #541502). The status is therefore the only thing that survives, and it survives
|
|
148
|
+
// wearing the destination's clothes. Reporting it as an API error sends the user
|
|
149
|
+
// to look at their account when the answer is their proxy, so the two are told
|
|
150
|
+
// apart here rather than left for a person to guess at.
|
|
151
|
+
//
|
|
152
|
+
// Verified against https-proxy-agent 9.1.0 (dist/index.js:104, 134-157): the
|
|
153
|
+
// proxyConnect event fires before the stand-in socket is built.
|
|
154
|
+
if (proxyConnectStatus !== undefined && proxyConnectStatus !== 200) {
|
|
155
|
+
throw new CcbError(`The proxy refused to open a tunnel to ${new URL(url).host} (${proxyConnectStatus} ${result.statusText})`, 'proxy_rejected', proxyConnectStatus === 407
|
|
156
|
+
? `The proxy${proxyUrl ? ` at ${proxyUrl}` : ''} requires authentication. Put the credentials in the proxy URL, as in http://user:pass@host:port.`
|
|
157
|
+
: `This is the proxy${proxyUrl ? ` at ${proxyUrl}` : ''} answering, not the Anthropic API.`, { ...(proxyUrl && { proxyUrl }), proxyConnectStatus, reachedDestination: false });
|
|
158
|
+
}
|
|
159
|
+
const { status, statusText, text, retryAfterSec } = result;
|
|
51
160
|
if (status < 200 || status >= 300) {
|
|
52
|
-
return { ok: false, status, statusText, body: undefined };
|
|
161
|
+
return { ok: false, status, statusText, body: undefined, ...(retryAfterSec !== undefined && { retryAfterSec }) };
|
|
53
162
|
}
|
|
54
163
|
try {
|
|
55
164
|
return { ok: true, status, statusText, body: JSON.parse(text) };
|
|
56
165
|
}
|
|
57
166
|
catch {
|
|
58
|
-
throw new CcbError(`Expected JSON from ${url} but got something else`, 'api_error', viaProxy ? 'A proxy that returns an error page instead of the response looks like this.' : undefined);
|
|
167
|
+
throw new CcbError(`Expected JSON from ${url} but got something else`, 'api_error', viaProxy ? 'A proxy that returns an error page instead of the response looks like this.' : undefined, { status, ...(proxyUrl && { proxyUrl }), reachedDestination: true });
|
|
59
168
|
}
|
|
60
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* The proxy in play for `url`, safe to print, so a caller can name it in its own
|
|
172
|
+
* errors. Credentials are stripped here rather than at each call site, because a
|
|
173
|
+
* call site that forgets is a call site that prints a password.
|
|
174
|
+
*/
|
|
175
|
+
export function proxyInUseFor(url) {
|
|
176
|
+
return redactProxyUrl(resolveProxyUrl(url));
|
|
177
|
+
}
|
|
61
178
|
//# sourceMappingURL=http.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/battery/api/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,OAAO,IAAI,WAAW,
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/battery/api/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ClaudeCodeClient } from './client.js';
|
|
2
2
|
export type { ClaudeCodeClientOptions } from './client.js';
|
|
3
3
|
export { OAuthApi } from './oauth.js';
|
|
4
|
-
export type { UsageResponse, UsageBucket, ExtraUsage, ProfileResponse, AccountInfo, OrganizationInfo, ApplicationInfo, } from './types.js';
|
|
4
|
+
export type { UsageResponse, UsageBucket, UsageLimit, ExtraUsage, ProfileResponse, AccountInfo, OrganizationInfo, ApplicationInfo, } from './types.js';
|
|
@@ -1,13 +1,55 @@
|
|
|
1
1
|
export interface UsageBucket {
|
|
2
2
|
utilization: number;
|
|
3
3
|
resets_at: string | null;
|
|
4
|
+
limit_dollars?: number | null;
|
|
5
|
+
used_dollars?: number | null;
|
|
6
|
+
remaining_dollars?: number | null;
|
|
7
|
+
locked_reason?: string | null;
|
|
4
8
|
}
|
|
5
9
|
export interface ExtraUsage {
|
|
6
10
|
is_enabled: boolean;
|
|
7
11
|
monthly_limit: number | null;
|
|
8
12
|
used_credits: number | null;
|
|
9
13
|
utilization: number | null;
|
|
14
|
+
currency?: string | null;
|
|
15
|
+
decimal_places?: number | null;
|
|
16
|
+
disabled_reason?: string | null;
|
|
17
|
+
user_disabled?: boolean;
|
|
18
|
+
spend_limit_reached?: boolean;
|
|
10
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* A limit the API describes by name rather than by giving it a top-level key.
|
|
22
|
+
*
|
|
23
|
+
* Newer per-model windows arrive only in the `limits` array, so a reader that
|
|
24
|
+
* walks the top-level keys never sees them. That is why a Fable weekly limit is
|
|
25
|
+
* absent from the usage display while the API is plainly reporting it: the array
|
|
26
|
+
* is not a duplicate of the flat fields, it is where the entries the flat fields
|
|
27
|
+
* have no name for live.
|
|
28
|
+
*/
|
|
29
|
+
export interface UsageLimit {
|
|
30
|
+
kind: string;
|
|
31
|
+
percent: number;
|
|
32
|
+
resets_at?: string | null;
|
|
33
|
+
scope?: {
|
|
34
|
+
model?: {
|
|
35
|
+
display_name?: string;
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
};
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
[key: string]: unknown;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The usage payload, as far as it is worth naming.
|
|
44
|
+
*
|
|
45
|
+
* The index signature is deliberate. Anthropic ships new windows under
|
|
46
|
+
* codenames (`nimbus_quill`, `juniper_tide`, `tangelo`) without warning, and a
|
|
47
|
+
* closed type would mean cutting a release of this package every time one
|
|
48
|
+
* appears. More importantly, a closed type reads as a promise that these are all
|
|
49
|
+
* the fields there are, and a reader that believed that promise is exactly how
|
|
50
|
+
* the `limits` array came to be overlooked. The runtime payload was never
|
|
51
|
+
* trimmed; only the type claimed it was complete.
|
|
52
|
+
*/
|
|
11
53
|
export interface UsageResponse {
|
|
12
54
|
five_hour: UsageBucket | null;
|
|
13
55
|
seven_day: UsageBucket | null;
|
|
@@ -17,6 +59,8 @@ export interface UsageResponse {
|
|
|
17
59
|
seven_day_cowork: UsageBucket | null;
|
|
18
60
|
iguana_necktie: unknown | null;
|
|
19
61
|
extra_usage: ExtraUsage | null;
|
|
62
|
+
limits?: UsageLimit[] | null;
|
|
63
|
+
[key: string]: unknown;
|
|
20
64
|
}
|
|
21
65
|
export interface AccountInfo {
|
|
22
66
|
uuid: string;
|
package/dist/battery/errors.d.ts
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facts a caller may need to act on, carried as fields rather than folded into
|
|
3
|
+
* the message.
|
|
4
|
+
*
|
|
5
|
+
* A caller that has to recover the retry delay by matching a regular expression
|
|
6
|
+
* against prose is a caller that breaks the next time the prose is reworded. The
|
|
7
|
+
* plugin backend does exactly that today, and every one of these fields exists
|
|
8
|
+
* because something downstream would otherwise have to read the sentence.
|
|
9
|
+
*/
|
|
10
|
+
export interface CcbErrorDetails {
|
|
11
|
+
/** HTTP status the destination answered with, when there was one. */
|
|
12
|
+
status?: number;
|
|
13
|
+
/** How long to wait before trying again, from a Retry-After header. */
|
|
14
|
+
retryAfterSec?: number;
|
|
15
|
+
/** The proxy the request was routed through, when one applied. */
|
|
16
|
+
proxyUrl?: string;
|
|
17
|
+
/** The status a proxy answered a CONNECT with, when it refused the tunnel. */
|
|
18
|
+
proxyConnectStatus?: number;
|
|
19
|
+
/** Whether the request reached the destination, or stalled before the tunnel opened. */
|
|
20
|
+
reachedDestination?: boolean;
|
|
21
|
+
}
|
|
1
22
|
export declare class CcbError extends Error {
|
|
2
23
|
readonly code: string;
|
|
3
24
|
readonly hint?: string | undefined;
|
|
4
|
-
|
|
25
|
+
readonly details?: CcbErrorDetails | undefined;
|
|
26
|
+
constructor(message: string, code: string, hint?: string | undefined, details?: CcbErrorDetails | undefined);
|
|
5
27
|
toJSON(): {
|
|
6
28
|
error: {
|
|
29
|
+
details?: CcbErrorDetails | undefined;
|
|
7
30
|
hint?: string | undefined;
|
|
8
31
|
code: string;
|
|
9
32
|
message: string;
|
package/dist/battery/errors.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
export class CcbError extends Error {
|
|
2
2
|
code;
|
|
3
3
|
hint;
|
|
4
|
-
|
|
4
|
+
details;
|
|
5
|
+
constructor(message, code, hint, details) {
|
|
5
6
|
super(message);
|
|
6
7
|
this.code = code;
|
|
7
8
|
this.hint = hint;
|
|
9
|
+
this.details = details;
|
|
8
10
|
this.name = 'CcbError';
|
|
9
11
|
}
|
|
10
12
|
toJSON() {
|
|
@@ -13,6 +15,7 @@ export class CcbError extends Error {
|
|
|
13
15
|
code: this.code,
|
|
14
16
|
message: this.message,
|
|
15
17
|
...(this.hint && { hint: this.hint }),
|
|
18
|
+
...(this.details && Object.keys(this.details).length > 0 && { details: this.details }),
|
|
16
19
|
},
|
|
17
20
|
};
|
|
18
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/battery/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/battery/errors.ts"],"names":[],"mappings":"AAsBA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IACA;IACA;IAJlB,YACE,OAAe,EACC,IAAY,EACZ,IAAa,EACb,OAAyB;QAEzC,KAAK,CAAC,OAAO,CAAC,CAAC;QAJC,SAAI,GAAJ,IAAI,CAAQ;QACZ,SAAI,GAAJ,IAAI,CAAS;QACb,YAAO,GAAP,OAAO,CAAkB;QAGzC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;IAED,MAAM;QACJ,OAAO;YACL,KAAK,EAAE;gBACL,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACrC,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;aACvF;SACF,CAAC;IACJ,CAAC;CACF"}
|
package/dist/battery/index.d.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* user's own machine and their own login.
|
|
9
9
|
*/
|
|
10
10
|
export { CcbError } from './errors.js';
|
|
11
|
+
export type { CcbErrorDetails } from './errors.js';
|
|
11
12
|
export { getCredentials, getAccessToken, isTokenExpired, isApiKeyAuth } from './auth/index.js';
|
|
12
13
|
export type { ClaudeCredentials, ClaudeOAuthCredentials, ApiKeyAuth, ClientAuth } from './auth/index.js';
|
|
13
14
|
export { ClaudeCodeClient, OAuthApi } from './api/index.js';
|
|
14
|
-
export type { UsageResponse, UsageBucket, ExtraUsage, ProfileResponse, AccountInfo, OrganizationInfo, ApplicationInfo, } from './api/index.js';
|
|
15
|
+
export type { UsageResponse, UsageBucket, UsageLimit, ExtraUsage, ProfileResponse, AccountInfo, OrganizationInfo, ApplicationInfo, } from './api/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battery/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/battery/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/F,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
import type { Agent } from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* A proxy URL with any username and password taken out, safe to show a person.
|
|
4
|
+
*
|
|
5
|
+
* Proxy credentials live in the URL itself, and the URL is the most useful thing
|
|
6
|
+
* an error about a proxy can name. Those two facts together are how a password
|
|
7
|
+
* ends up in an error message, and from there in the screenshot someone attaches
|
|
8
|
+
* to a bug report. Every message this package writes goes through here first.
|
|
9
|
+
*
|
|
10
|
+
* The reporter on Swttch/swttch#181 configured exactly such a URL, so this is not
|
|
11
|
+
* a hypothetical shape.
|
|
12
|
+
*/
|
|
13
|
+
export declare function redactProxyUrl(proxyUrl: string | undefined): string | undefined;
|
|
2
14
|
/**
|
|
3
15
|
* Whether NO_PROXY exempts this host, following the de-facto rules curl uses:
|
|
4
16
|
* a comma-separated list, `*` meaning everything, a leading dot ignored, and a
|
|
@@ -12,6 +24,20 @@ export declare function isProxyBypassed(host: string, port: string, noProxy: str
|
|
|
12
24
|
* `wss:`/`ws:` are resolved as their HTTP equivalents because that is how the
|
|
13
25
|
* connection is actually made — a WebSocket starts life as an HTTP upgrade, so
|
|
14
26
|
* a user who set HTTPS_PROXY expects `wss://` to go through it.
|
|
27
|
+
*
|
|
28
|
+
* **An https target falls back to HTTP_PROXY, and that is a deliberate departure
|
|
29
|
+
* from curl.** curl reads only the variable matching the target's scheme, so
|
|
30
|
+
* HTTP_PROXY never applies to an https URL there. The `claude` CLI does not
|
|
31
|
+
* follow that rule: given HTTP_PROXY alone, whether exported in the environment
|
|
32
|
+
* or written into settings.json's `env` block, it tunnels api.anthropic.com
|
|
33
|
+
* through it. Both behaviours were measured against a local CONNECT proxy.
|
|
34
|
+
*
|
|
35
|
+
* Matching curl instead of `claude` is what broke Swttch/swttch#432 for the
|
|
36
|
+
* person who reported it: one settings.json, chat working because the CLI
|
|
37
|
+
* honored HTTP_PROXY, and the usage panel going out direct because this function
|
|
38
|
+
* did not. The user writes that file for `claude`, so `claude` is the behaviour
|
|
39
|
+
* to match — the plugin's whole premise is that anything possible from the CLI
|
|
40
|
+
* is possible from the GUI.
|
|
15
41
|
*/
|
|
16
42
|
export declare function resolveProxyUrl(targetUrl: string, env?: NodeJS.ProcessEnv): string | undefined;
|
|
17
43
|
/**
|
|
@@ -29,4 +55,7 @@ export declare function resolveProxyUrl(targetUrl: string, env?: NodeJS.ProcessE
|
|
|
29
55
|
* attempt fails anyway, and it fails with a connection error that says nothing
|
|
30
56
|
* about the real cause; naming the bad setting is far more useful.
|
|
31
57
|
*/
|
|
32
|
-
export declare function proxyAgentFor(targetUrl: string, env?: NodeJS.ProcessEnv
|
|
58
|
+
export declare function proxyAgentFor(targetUrl: string, env?: NodeJS.ProcessEnv, options?: {
|
|
59
|
+
signal?: AbortSignal;
|
|
60
|
+
timeoutMs?: number;
|
|
61
|
+
}): Agent | undefined;
|
package/dist/proxy.js
CHANGED
|
@@ -18,6 +18,36 @@ import { CcbError } from './battery/errors.js';
|
|
|
18
18
|
*/
|
|
19
19
|
/** Proxy URL schemes that mean SOCKS rather than an HTTP CONNECT proxy. */
|
|
20
20
|
const SOCKS_PROTOCOLS = new Set(['socks:', 'socks4:', 'socks4a:', 'socks5:', 'socks5h:']);
|
|
21
|
+
/**
|
|
22
|
+
* A proxy URL with any username and password taken out, safe to show a person.
|
|
23
|
+
*
|
|
24
|
+
* Proxy credentials live in the URL itself, and the URL is the most useful thing
|
|
25
|
+
* an error about a proxy can name. Those two facts together are how a password
|
|
26
|
+
* ends up in an error message, and from there in the screenshot someone attaches
|
|
27
|
+
* to a bug report. Every message this package writes goes through here first.
|
|
28
|
+
*
|
|
29
|
+
* The reporter on Swttch/swttch#181 configured exactly such a URL, so this is not
|
|
30
|
+
* a hypothetical shape.
|
|
31
|
+
*/
|
|
32
|
+
export function redactProxyUrl(proxyUrl) {
|
|
33
|
+
if (!proxyUrl)
|
|
34
|
+
return undefined;
|
|
35
|
+
try {
|
|
36
|
+
const url = new URL(proxyUrl);
|
|
37
|
+
if (!url.username && !url.password)
|
|
38
|
+
return proxyUrl;
|
|
39
|
+
url.username = '';
|
|
40
|
+
url.password = '';
|
|
41
|
+
// A URL that carried credentials should still look like it did, so the user
|
|
42
|
+
// recognises which setting is being talked about.
|
|
43
|
+
return url.toString().replace('//', '//***@');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Not parseable, so it cannot be picked apart safely. Say nothing rather than
|
|
47
|
+
// risk printing a password that happens to sit in an unparseable string.
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
21
51
|
/**
|
|
22
52
|
* Read a proxy variable in either spelling.
|
|
23
53
|
*
|
|
@@ -73,6 +103,20 @@ export function isProxyBypassed(host, port, noProxy) {
|
|
|
73
103
|
* `wss:`/`ws:` are resolved as their HTTP equivalents because that is how the
|
|
74
104
|
* connection is actually made — a WebSocket starts life as an HTTP upgrade, so
|
|
75
105
|
* a user who set HTTPS_PROXY expects `wss://` to go through it.
|
|
106
|
+
*
|
|
107
|
+
* **An https target falls back to HTTP_PROXY, and that is a deliberate departure
|
|
108
|
+
* from curl.** curl reads only the variable matching the target's scheme, so
|
|
109
|
+
* HTTP_PROXY never applies to an https URL there. The `claude` CLI does not
|
|
110
|
+
* follow that rule: given HTTP_PROXY alone, whether exported in the environment
|
|
111
|
+
* or written into settings.json's `env` block, it tunnels api.anthropic.com
|
|
112
|
+
* through it. Both behaviours were measured against a local CONNECT proxy.
|
|
113
|
+
*
|
|
114
|
+
* Matching curl instead of `claude` is what broke Swttch/swttch#432 for the
|
|
115
|
+
* person who reported it: one settings.json, chat working because the CLI
|
|
116
|
+
* honored HTTP_PROXY, and the usage panel going out direct because this function
|
|
117
|
+
* did not. The user writes that file for `claude`, so `claude` is the behaviour
|
|
118
|
+
* to match — the plugin's whole premise is that anything possible from the CLI
|
|
119
|
+
* is possible from the GUI.
|
|
76
120
|
*/
|
|
77
121
|
export function resolveProxyUrl(targetUrl, env = process.env) {
|
|
78
122
|
const target = new URL(targetUrl);
|
|
@@ -80,7 +124,9 @@ export function resolveProxyUrl(targetUrl, env = process.env) {
|
|
|
80
124
|
const port = target.port || (isSecure ? '443' : '80');
|
|
81
125
|
if (isProxyBypassed(target.hostname, port, readProxyEnv(env, 'NO_PROXY')))
|
|
82
126
|
return undefined;
|
|
83
|
-
const specific = isSecure
|
|
127
|
+
const specific = isSecure
|
|
128
|
+
? readProxyEnv(env, 'HTTPS_PROXY') ?? readProxyEnv(env, 'HTTP_PROXY')
|
|
129
|
+
: readProxyEnv(env, 'HTTP_PROXY');
|
|
84
130
|
return specific ?? readProxyEnv(env, 'ALL_PROXY');
|
|
85
131
|
}
|
|
86
132
|
/**
|
|
@@ -98,7 +144,7 @@ export function resolveProxyUrl(targetUrl, env = process.env) {
|
|
|
98
144
|
* attempt fails anyway, and it fails with a connection error that says nothing
|
|
99
145
|
* about the real cause; naming the bad setting is far more useful.
|
|
100
146
|
*/
|
|
101
|
-
export function proxyAgentFor(targetUrl, env = process.env) {
|
|
147
|
+
export function proxyAgentFor(targetUrl, env = process.env, options = {}) {
|
|
102
148
|
const proxyUrl = resolveProxyUrl(targetUrl, env);
|
|
103
149
|
if (!proxyUrl)
|
|
104
150
|
return undefined;
|
|
@@ -109,12 +155,29 @@ export function proxyAgentFor(targetUrl, env = process.env) {
|
|
|
109
155
|
catch {
|
|
110
156
|
throw new CcbError(`Proxy setting is not a valid URL: ${proxyUrl}`, 'invalid_proxy', 'Expected something like http://host:port or socks5://host:port');
|
|
111
157
|
}
|
|
112
|
-
|
|
113
|
-
|
|
158
|
+
// A deadline has to reach the AGENT, not just the request.
|
|
159
|
+
//
|
|
160
|
+
// While an agent is negotiating with the proxy there is no socket on the
|
|
161
|
+
// request yet, so aborting the request reaches nothing: measured against a
|
|
162
|
+
// proxy that accepted a CONNECT and stayed silent, an aborted request produced
|
|
163
|
+
// no 'socket', no 'error' and no 'close', and simply hung. The caller would get
|
|
164
|
+
// its timeout while the connection attempt carried on behind it.
|
|
165
|
+
//
|
|
166
|
+
// The two agents take different instruments for the same job, so each is given
|
|
167
|
+
// the one it honors rather than one being forced on both.
|
|
168
|
+
if (SOCKS_PROTOCOLS.has(protocol)) {
|
|
169
|
+
// socks-proxy-agent hands `timeout` to SocksClient, which applies it to the
|
|
170
|
+
// handshake. It does not read `signal`, and passing one is not merely
|
|
171
|
+
// ignored — its options type has no room for it.
|
|
172
|
+
return new SocksProxyAgent(proxyUrl, options.timeoutMs ? { timeout: options.timeoutMs } : undefined);
|
|
173
|
+
}
|
|
114
174
|
if (protocol === 'http:' || protocol === 'https:') {
|
|
115
|
-
// HttpsProxyAgent covers
|
|
116
|
-
// is https/wss and therefore always reached by a CONNECT
|
|
117
|
-
|
|
175
|
+
// HttpsProxyAgent covers http: and https: alike, because every endpoint this
|
|
176
|
+
// package talks to is https/wss and therefore always reached by a CONNECT
|
|
177
|
+
// tunnel. Its options are spread into what it passes to net.connect, so a
|
|
178
|
+
// signal here destroys the socket the CONNECT wait is parked on and lets the
|
|
179
|
+
// failure surface. Measured: the error arrived 8ms after the abort.
|
|
180
|
+
return new HttpsProxyAgent(proxyUrl, options.signal ? { signal: options.signal } : undefined);
|
|
118
181
|
}
|
|
119
182
|
throw new CcbError(`Unsupported proxy scheme "${protocol.replace(':', '')}" in ${proxyUrl}`, 'invalid_proxy', 'Supported schemes: http, https, socks, socks4, socks4a, socks5, socks5h');
|
|
120
183
|
}
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AAEH,2EAA2E;AAC3E,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;AAE1F;;;;;;;;;GASG;AACH,SAAS,YAAY,CAAC,GAAsB,EAAE,IAAY;IACxD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACnE,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACnE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,IAAY,EAAE,OAA2B;IACrF,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtF,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,SAA6B,CAAC;QAClC,4EAA4E;QAC5E,sDAAsD;QACtD,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,SAAS,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/G,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;YACzC,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAChE,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACxD,OAAO,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swttch/extend-kit",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Companion tools for Swttch that live outside the plugin bundle: Claude Code account/usage SDK, the ccb CLI, and speech-to-text.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|