@swttch/extend-kit 0.3.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/README.ko.md +445 -0
- package/README.md +445 -0
- package/dist/battery/api/client.d.ts +12 -0
- package/dist/battery/api/client.js +54 -0
- package/dist/battery/api/client.js.map +1 -0
- package/dist/battery/api/index.d.ts +3 -0
- package/dist/battery/api/index.js +3 -0
- package/dist/battery/api/index.js.map +1 -0
- package/dist/battery/api/oauth.d.ts +8 -0
- package/dist/battery/api/oauth.js +22 -0
- package/dist/battery/api/oauth.js.map +1 -0
- package/dist/battery/api/types.d.ts +49 -0
- package/dist/battery/api/types.js +2 -0
- package/dist/battery/api/types.js.map +1 -0
- package/dist/battery/auth/file-store.d.ts +2 -0
- package/dist/battery/auth/file-store.js +21 -0
- package/dist/battery/auth/file-store.js.map +1 -0
- package/dist/battery/auth/index.d.ts +6 -0
- package/dist/battery/auth/index.js +23 -0
- package/dist/battery/auth/index.js.map +1 -0
- package/dist/battery/auth/keychain.d.ts +2 -0
- package/dist/battery/auth/keychain.js +21 -0
- package/dist/battery/auth/keychain.js.map +1 -0
- package/dist/battery/auth/types.d.ts +16 -0
- package/dist/battery/auth/types.js +2 -0
- package/dist/battery/auth/types.js.map +1 -0
- package/dist/battery/errors.d.ts +12 -0
- package/dist/battery/errors.js +20 -0
- package/dist/battery/errors.js.map +1 -0
- package/dist/battery/index.d.ts +14 -0
- package/dist/battery/index.js +13 -0
- package/dist/battery/index.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +79 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/oauth.d.ts +2 -0
- package/dist/cli/oauth.js +63 -0
- package/dist/cli/oauth.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
# @swttch/extend-kit
|
|
2
|
+
|
|
3
|
+
[한국어](README.ko.md)
|
|
4
|
+
|
|
5
|
+
The companion tools [Swttch](https://github.com/Swttch/swttch) needs but cannot ship inside the plugin bundle, so they install on your machine instead. Each one is usable on its own — from a terminal or as a library — and the plugin is simply one caller among others.
|
|
6
|
+
|
|
7
|
+
| Tool | Why it lives outside the bundle |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| **battery** | Reads the Claude Code login stored on *your* machine (keychain, or a credentials file) |
|
|
10
|
+
| **stt** | Planned. Needs native binaries the plugin cannot carry |
|
|
11
|
+
|
|
12
|
+
## battery
|
|
13
|
+
|
|
14
|
+
A TypeScript SDK and CLI that wraps the internal API of Claude Code. This allows programmatic access to API usage metrics and account information for Claude Code users.
|
|
15
|
+
|
|
16
|
+
> **Moving from `claude-code-battery`?** Change the import to `@swttch/extend-kit` and everything else stays the same — the exports and the `ccb` command are unchanged. The old package still works; it now re-exports this one.
|
|
17
|
+
|
|
18
|
+
## Important Notes
|
|
19
|
+
|
|
20
|
+
- **Unofficial API**: This package uses the unofficial internal API of the Claude Code client. Anthropic does not officially support it, so it may change in the future.
|
|
21
|
+
- **Claude Code Login Required**: To use this SDK, you must have Claude Code installed and logged in on your local machine.
|
|
22
|
+
- **API Key Support**: You can also authenticate using Anthropic API Key. However, some OAuth-exclusive features (`getUsage()`, `getProfile()`) are not available with API Key authentication.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @swttch/extend-kit
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Node.js version 20 or higher is required.
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### SDK Usage
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { ClaudeCodeClient } from '@swttch/extend-kit';
|
|
38
|
+
|
|
39
|
+
// No token needed — credentials are resolved automatically on first API call
|
|
40
|
+
const client = new ClaudeCodeClient();
|
|
41
|
+
|
|
42
|
+
const usage = await client.oauth.getUsage();
|
|
43
|
+
console.log(usage);
|
|
44
|
+
|
|
45
|
+
const profile = await client.oauth.getProfile();
|
|
46
|
+
console.log(profile);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
You can also pass a token explicitly if needed:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// With OAuth access token explicitly
|
|
53
|
+
const client = new ClaudeCodeClient(myOAuthAccessToken);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
If you prefer using Anthropic API Key:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// With Anthropic API Key
|
|
60
|
+
const client = new ClaudeCodeClient({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### CLI Usage
|
|
64
|
+
|
|
65
|
+
After building, you can use the `ccb` command.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Build
|
|
69
|
+
npm run build
|
|
70
|
+
|
|
71
|
+
# Install globally (optional)
|
|
72
|
+
npm install -g .
|
|
73
|
+
|
|
74
|
+
# Get usage information
|
|
75
|
+
ccb oauth usage
|
|
76
|
+
|
|
77
|
+
# Get profile information
|
|
78
|
+
ccb oauth profile
|
|
79
|
+
|
|
80
|
+
# Output in JSON format
|
|
81
|
+
ccb oauth usage --json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API Documentation
|
|
85
|
+
|
|
86
|
+
### Authentication Functions
|
|
87
|
+
|
|
88
|
+
#### `getCredentials(): Promise<ClaudeCredentials>`
|
|
89
|
+
|
|
90
|
+
Reads credentials from the Claude Code storage.
|
|
91
|
+
|
|
92
|
+
- **macOS**: Reads from Keychain
|
|
93
|
+
- **Windows/Linux**: Reads from `~/.claude/.credentials.json` file
|
|
94
|
+
- **Customization**: Specify path with `CLAUDE_CONFIG_DIR` environment variable
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const credentials = await getCredentials();
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### `getAccessToken(credentials: ClaudeCredentials): string`
|
|
101
|
+
|
|
102
|
+
Extracts the access token from credentials.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const token = getAccessToken(credentials);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### `isTokenExpired(credentials: ClaudeCredentials): boolean`
|
|
109
|
+
|
|
110
|
+
Checks if the token has expired.
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
if (isTokenExpired(credentials)) {
|
|
114
|
+
console.log('Token has expired');
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Authentication Methods
|
|
119
|
+
|
|
120
|
+
| Method | Header | Use Case |
|
|
121
|
+
|--------|--------|----------|
|
|
122
|
+
| OAuth (auto) | `Authorization: Bearer {token}` | Claude Code logged-in users |
|
|
123
|
+
| OAuth (explicit) | `Authorization: Bearer {token}` | Manual OAuth token |
|
|
124
|
+
| API Key | `x-api-key: {key}` | Anthropic API users |
|
|
125
|
+
|
|
126
|
+
**Note**: OAuth-exclusive features (`getUsage()`, `getProfile()`) are not available with API Key authentication.
|
|
127
|
+
|
|
128
|
+
### ClaudeCodeClient
|
|
129
|
+
|
|
130
|
+
A client class for making API calls. Access API endpoints through sub-modules.
|
|
131
|
+
|
|
132
|
+
#### `constructor(auth?: string | { apiKey: string })`
|
|
133
|
+
|
|
134
|
+
Initializes the client with OAuth access token or API Key. If no argument is provided, credentials are resolved automatically.
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// Auto-resolve credentials
|
|
138
|
+
const client = new ClaudeCodeClient();
|
|
139
|
+
|
|
140
|
+
// Explicit OAuth token
|
|
141
|
+
const client = new ClaudeCodeClient(myAccessToken);
|
|
142
|
+
|
|
143
|
+
// API Key
|
|
144
|
+
const client = new ClaudeCodeClient({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### `oauth: OAuthApi`
|
|
148
|
+
|
|
149
|
+
A sub-module that provides OAuth-related API methods.
|
|
150
|
+
|
|
151
|
+
##### `oauth.getUsage(): Promise<UsageResponse>`
|
|
152
|
+
|
|
153
|
+
Retrieves usage information. Returns utilization data for 5-hour and 7-day buckets.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
const usage = await client.oauth.getUsage();
|
|
157
|
+
// {
|
|
158
|
+
// five_hour: { utilization: 45, resets_at: '2024-01-01T12:00:00Z' },
|
|
159
|
+
// seven_day: { utilization: 62, resets_at: '2024-01-08T00:00:00Z' },
|
|
160
|
+
// seven_day_opus: { utilization: 30, resets_at: '2024-01-08T00:00:00Z' },
|
|
161
|
+
// seven_day_sonnet: { utilization: 55, resets_at: '2024-01-08T00:00:00Z' },
|
|
162
|
+
// extra_usage: { is_enabled: true, monthly_limit: 1000, ... }
|
|
163
|
+
// }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
##### `oauth.getProfile(): Promise<ProfileResponse>`
|
|
167
|
+
|
|
168
|
+
Retrieves account and organization profile information.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const profile = await client.oauth.getProfile();
|
|
172
|
+
// {
|
|
173
|
+
// account: {
|
|
174
|
+
// uuid: '...',
|
|
175
|
+
// display_name: 'John Doe',
|
|
176
|
+
// email: 'john@example.com',
|
|
177
|
+
// has_claude_pro: true,
|
|
178
|
+
// ...
|
|
179
|
+
// },
|
|
180
|
+
// organization: {
|
|
181
|
+
// name: 'My Org',
|
|
182
|
+
// organization_type: 'free',
|
|
183
|
+
// subscription_status: 'active',
|
|
184
|
+
// ...
|
|
185
|
+
// },
|
|
186
|
+
// application: { ... }
|
|
187
|
+
// }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Error Handling
|
|
191
|
+
|
|
192
|
+
All errors thrown by the SDK are instances of `CcbError`, which includes a machine-readable `code` and optional `hint`.
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
import { ClaudeCodeClient, CcbError } from '@swttch/extend-kit';
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const usage = await client.oauth.getUsage();
|
|
199
|
+
} catch (err) {
|
|
200
|
+
if (err instanceof CcbError) {
|
|
201
|
+
console.log(err.code); // 'unsupported_auth'
|
|
202
|
+
console.log(err.hint); // 'Check usage at console.anthropic.com, ...'
|
|
203
|
+
console.log(err.toJSON()); // { error: { code, message, hint } }
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### Error Codes
|
|
209
|
+
|
|
210
|
+
| Code | Description | Hint |
|
|
211
|
+
|------|-------------|------|
|
|
212
|
+
| `unsupported_auth` | API Key does not support this operation | Check usage at console.anthropic.com, or use OAuth login |
|
|
213
|
+
| `credentials_not_found` | Credentials file not found | Run `claude login` to authenticate |
|
|
214
|
+
| `token_expired` | OAuth token has expired | Run `claude login` to refresh your token |
|
|
215
|
+
| `api_error` | API request failed (includes HTTP status) | — |
|
|
216
|
+
| `unsupported_platform` | Platform not supported | — |
|
|
217
|
+
|
|
218
|
+
## Type Definitions
|
|
219
|
+
|
|
220
|
+
### Authentication Types
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
interface ApiKeyAuth {
|
|
224
|
+
apiKey: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
type ClientAuth = string | ApiKeyAuth;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### UsageResponse
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
interface UsageResponse {
|
|
234
|
+
five_hour: UsageBucket | null;
|
|
235
|
+
seven_day: UsageBucket | null;
|
|
236
|
+
seven_day_oauth_apps: UsageBucket | null;
|
|
237
|
+
seven_day_opus: UsageBucket | null;
|
|
238
|
+
seven_day_sonnet: UsageBucket | null;
|
|
239
|
+
seven_day_cowork: UsageBucket | null;
|
|
240
|
+
extra_usage: ExtraUsage | null;
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### UsageBucket
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
interface UsageBucket {
|
|
248
|
+
utilization: number; // 0-100%
|
|
249
|
+
resets_at: string | null; // ISO 8601 format reset time
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### ExtraUsage
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
interface ExtraUsage {
|
|
257
|
+
is_enabled: boolean;
|
|
258
|
+
monthly_limit: number | null;
|
|
259
|
+
used_credits: number | null;
|
|
260
|
+
utilization: number | null;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### ProfileResponse
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface ProfileResponse {
|
|
268
|
+
account: AccountInfo;
|
|
269
|
+
organization: OrganizationInfo;
|
|
270
|
+
application: ApplicationInfo;
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### AccountInfo
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
interface AccountInfo {
|
|
278
|
+
uuid: string;
|
|
279
|
+
full_name: string;
|
|
280
|
+
display_name: string;
|
|
281
|
+
email: string;
|
|
282
|
+
has_claude_max: boolean;
|
|
283
|
+
has_claude_pro: boolean;
|
|
284
|
+
created_at: string;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### OrganizationInfo
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
interface OrganizationInfo {
|
|
292
|
+
uuid: string;
|
|
293
|
+
name: string;
|
|
294
|
+
organization_type: string;
|
|
295
|
+
billing_type: string;
|
|
296
|
+
rate_limit_tier: string;
|
|
297
|
+
has_extra_usage_enabled: boolean;
|
|
298
|
+
subscription_status: string;
|
|
299
|
+
subscription_created_at: string;
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### ApplicationInfo
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
interface ApplicationInfo {
|
|
307
|
+
uuid: string;
|
|
308
|
+
name: string;
|
|
309
|
+
slug: string;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### ClaudeCredentials
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
interface ClaudeCredentials {
|
|
317
|
+
claudeAiOauth: ClaudeOAuthCredentials;
|
|
318
|
+
organizationUuid: string;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface ClaudeOAuthCredentials {
|
|
322
|
+
accessToken: string;
|
|
323
|
+
refreshToken: string;
|
|
324
|
+
expiresAt: number;
|
|
325
|
+
scopes: string[];
|
|
326
|
+
subscriptionType: string;
|
|
327
|
+
rateLimitTier: string;
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## CLI Commands
|
|
332
|
+
|
|
333
|
+
### usage
|
|
334
|
+
|
|
335
|
+
Retrieves usage limit information.
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
ccb oauth usage
|
|
339
|
+
|
|
340
|
+
# Output example:
|
|
341
|
+
# Usage:
|
|
342
|
+
# five hour: 45%
|
|
343
|
+
# seven day: 62% (resets 2024-01-08T00:00:00)
|
|
344
|
+
# seven day opus: 30% (resets 2024-01-08T00:00:00)
|
|
345
|
+
# seven day sonnet: 55% (resets 2024-01-08T00:00:00)
|
|
346
|
+
# extra usage: enabled
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### profile
|
|
350
|
+
|
|
351
|
+
Retrieves account and organization profile.
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
ccb oauth profile
|
|
355
|
+
|
|
356
|
+
# Output example:
|
|
357
|
+
# Profile:
|
|
358
|
+
# name: John Doe
|
|
359
|
+
# email: john@example.com
|
|
360
|
+
# plan: free
|
|
361
|
+
# org: My Organization
|
|
362
|
+
# status: active
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Options
|
|
366
|
+
|
|
367
|
+
- `--json`: Output in JSON format
|
|
368
|
+
- `-h, --help`: Show help
|
|
369
|
+
- `-v, --version`: Show version information
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
ccb oauth usage --json
|
|
373
|
+
ccb oauth profile --json
|
|
374
|
+
ccb --version
|
|
375
|
+
ccb --help
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Error Output
|
|
379
|
+
|
|
380
|
+
Errors respect the `--json` flag:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
$ ccb oauth usage
|
|
384
|
+
Error: API Key authentication does not support usage/profile queries.
|
|
385
|
+
Hint: Check usage at console.anthropic.com, or use OAuth login (claude login)
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
```bash
|
|
389
|
+
$ ccb oauth usage --json
|
|
390
|
+
{
|
|
391
|
+
"error": {
|
|
392
|
+
"code": "unsupported_auth",
|
|
393
|
+
"message": "API Key authentication does not support usage/profile queries.",
|
|
394
|
+
"hint": "Check usage at console.anthropic.com, or use OAuth login (claude login)"
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Development
|
|
400
|
+
|
|
401
|
+
### Installation
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
npm install
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Build
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
npm run build
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Compiles TypeScript to JavaScript. Output is saved in the `dist/` directory.
|
|
414
|
+
|
|
415
|
+
### Watch Mode
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
npm run dev
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Automatically compiles on file changes.
|
|
422
|
+
|
|
423
|
+
### Type Checking
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
npm run lint
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Runs TypeScript type checking.
|
|
430
|
+
|
|
431
|
+
### Testing
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
npm test
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Runs test files in `dist/**/*.test.js`.
|
|
438
|
+
|
|
439
|
+
## License
|
|
440
|
+
|
|
441
|
+
MIT
|
|
442
|
+
|
|
443
|
+
## Author
|
|
444
|
+
|
|
445
|
+
yhk1038
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { OAuthApi } from './oauth.js';
|
|
2
|
+
import type { ClientAuth } from '../auth/index.js';
|
|
3
|
+
export declare class ClaudeCodeClient {
|
|
4
|
+
private auth?;
|
|
5
|
+
private accessToken?;
|
|
6
|
+
private _oauth?;
|
|
7
|
+
constructor(auth?: ClientAuth);
|
|
8
|
+
get isApiKeyMode(): boolean;
|
|
9
|
+
get oauth(): OAuthApi;
|
|
10
|
+
private resolveToken;
|
|
11
|
+
_request<T>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { OAuthApi } from './oauth.js';
|
|
2
|
+
import { getCredentials, getAccessToken, isApiKeyAuth } from '../auth/index.js';
|
|
3
|
+
import { CcbError } from '../errors.js';
|
|
4
|
+
const BASE_URL = 'https://api.anthropic.com';
|
|
5
|
+
export class ClaudeCodeClient {
|
|
6
|
+
auth;
|
|
7
|
+
accessToken;
|
|
8
|
+
_oauth;
|
|
9
|
+
constructor(auth) {
|
|
10
|
+
this.auth = auth;
|
|
11
|
+
if (typeof auth === 'string') {
|
|
12
|
+
this.accessToken = auth;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
get isApiKeyMode() {
|
|
16
|
+
return isApiKeyAuth(this.auth);
|
|
17
|
+
}
|
|
18
|
+
get oauth() {
|
|
19
|
+
return this._oauth ??= new OAuthApi(this);
|
|
20
|
+
}
|
|
21
|
+
async resolveToken() {
|
|
22
|
+
if (!this.accessToken) {
|
|
23
|
+
const credentials = await getCredentials();
|
|
24
|
+
this.accessToken = getAccessToken(credentials);
|
|
25
|
+
}
|
|
26
|
+
return this.accessToken;
|
|
27
|
+
}
|
|
28
|
+
async _request(path, headers) {
|
|
29
|
+
let requestHeaders;
|
|
30
|
+
if (this.auth !== undefined && isApiKeyAuth(this.auth)) {
|
|
31
|
+
requestHeaders = {
|
|
32
|
+
'x-api-key': this.auth.apiKey,
|
|
33
|
+
'anthropic-version': '2023-06-01',
|
|
34
|
+
...headers,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const token = await this.resolveToken();
|
|
39
|
+
requestHeaders = {
|
|
40
|
+
Authorization: `Bearer ${token}`,
|
|
41
|
+
...headers,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const response = await fetch(`${BASE_URL}${path}`, {
|
|
45
|
+
method: 'GET',
|
|
46
|
+
headers: requestHeaders,
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new CcbError(`API error ${response.status}: ${response.statusText}`, 'api_error');
|
|
50
|
+
}
|
|
51
|
+
return response.json();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +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,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhF,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,QAAQ,GAAG,2BAA2B,CAAC;AAE7C,MAAM,OAAO,gBAAgB;IACnB,IAAI,CAAc;IAClB,WAAW,CAAU;IACrB,MAAM,CAAY;IAE1B,YAAY,IAAiB;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,YAAY;QACd,OAAO,YAAY,CAAC,IAAI,CAAC,IAAkB,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;YAC3C,IAAI,CAAC,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,QAAQ,CAAI,IAAY,EAAE,OAAgC;QAC9D,IAAI,cAAsC,CAAC;QAE3C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,cAAc,GAAG;gBACf,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM;gBAC7B,mBAAmB,EAAE,YAAY;gBACjC,GAAG,OAAO;aACX,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;YACxC,cAAc,GAAG;gBACf,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,GAAG,OAAO;aACX,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,QAAQ,GAAG,IAAI,EAAE,EAAE;YACjD,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,cAAc;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,QAAQ,CAAC,aAAa,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,EAAE,WAAW,CAAC,CAAC;QAC1F,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACvC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/battery/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ClaudeCodeClient } from './client.js';
|
|
2
|
+
import type { UsageResponse, ProfileResponse } from './types.js';
|
|
3
|
+
export declare class OAuthApi {
|
|
4
|
+
private readonly client;
|
|
5
|
+
constructor(client: ClaudeCodeClient);
|
|
6
|
+
getUsage(): Promise<UsageResponse>;
|
|
7
|
+
getProfile(): Promise<ProfileResponse>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CcbError } from '../errors.js';
|
|
2
|
+
export class OAuthApi {
|
|
3
|
+
client;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
async getUsage() {
|
|
8
|
+
if (this.client.isApiKeyMode) {
|
|
9
|
+
throw new CcbError('API Key authentication does not support usage/profile queries.', 'unsupported_auth', 'Check usage at console.anthropic.com, or use OAuth login (claude login)');
|
|
10
|
+
}
|
|
11
|
+
return this.client._request('/api/oauth/usage', {
|
|
12
|
+
'anthropic-beta': 'oauth-2025-04-20',
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async getProfile() {
|
|
16
|
+
if (this.client.isApiKeyMode) {
|
|
17
|
+
throw new CcbError('API Key authentication does not support usage/profile queries.', 'unsupported_auth', 'Check usage at console.anthropic.com, or use OAuth login (claude login)');
|
|
18
|
+
}
|
|
19
|
+
return this.client._request('/api/oauth/profile');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/battery/api/oauth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,OAAO,QAAQ;IACU;IAA7B,YAA6B,MAAwB;QAAxB,WAAM,GAAN,MAAM,CAAkB;IAAG,CAAC;IAEzD,KAAK,CAAC,QAAQ;QACZ,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC7B,MAAM,IAAI,QAAQ,CAChB,gEAAgE,EAChE,kBAAkB,EAClB,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAgB,kBAAkB,EAAE;YAC7D,gBAAgB,EAAE,kBAAkB;SACrC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC7B,MAAM,IAAI,QAAQ,CAChB,gEAAgE,EAChE,kBAAkB,EAClB,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAkB,oBAAoB,CAAC,CAAC;IACrE,CAAC;CACF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export interface UsageBucket {
|
|
2
|
+
utilization: number;
|
|
3
|
+
resets_at: string | null;
|
|
4
|
+
}
|
|
5
|
+
export interface ExtraUsage {
|
|
6
|
+
is_enabled: boolean;
|
|
7
|
+
monthly_limit: number | null;
|
|
8
|
+
used_credits: number | null;
|
|
9
|
+
utilization: number | null;
|
|
10
|
+
}
|
|
11
|
+
export interface UsageResponse {
|
|
12
|
+
five_hour: UsageBucket | null;
|
|
13
|
+
seven_day: UsageBucket | null;
|
|
14
|
+
seven_day_oauth_apps: UsageBucket | null;
|
|
15
|
+
seven_day_opus: UsageBucket | null;
|
|
16
|
+
seven_day_sonnet: UsageBucket | null;
|
|
17
|
+
seven_day_cowork: UsageBucket | null;
|
|
18
|
+
iguana_necktie: unknown | null;
|
|
19
|
+
extra_usage: ExtraUsage | null;
|
|
20
|
+
}
|
|
21
|
+
export interface AccountInfo {
|
|
22
|
+
uuid: string;
|
|
23
|
+
full_name: string;
|
|
24
|
+
display_name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
has_claude_max: boolean;
|
|
27
|
+
has_claude_pro: boolean;
|
|
28
|
+
created_at: string;
|
|
29
|
+
}
|
|
30
|
+
export interface OrganizationInfo {
|
|
31
|
+
uuid: string;
|
|
32
|
+
name: string;
|
|
33
|
+
organization_type: string;
|
|
34
|
+
billing_type: string;
|
|
35
|
+
rate_limit_tier: string;
|
|
36
|
+
has_extra_usage_enabled: boolean;
|
|
37
|
+
subscription_status: string;
|
|
38
|
+
subscription_created_at: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ApplicationInfo {
|
|
41
|
+
uuid: string;
|
|
42
|
+
name: string;
|
|
43
|
+
slug: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ProfileResponse {
|
|
46
|
+
account: AccountInfo;
|
|
47
|
+
organization: OrganizationInfo;
|
|
48
|
+
application: ApplicationInfo;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/battery/api/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { CcbError } from '../errors.js';
|
|
5
|
+
function getCredentialsFilePath() {
|
|
6
|
+
const configDir = process.env['CLAUDE_CONFIG_DIR'] ?? path.join(os.homedir(), '.claude');
|
|
7
|
+
return path.join(configDir, '.credentials.json');
|
|
8
|
+
}
|
|
9
|
+
export async function readFileCredentials() {
|
|
10
|
+
const filePath = getCredentialsFilePath();
|
|
11
|
+
let raw;
|
|
12
|
+
try {
|
|
13
|
+
raw = await readFile(filePath, 'utf-8');
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
throw new CcbError(`Failed to read credentials file at ${filePath}: ${err.message}`, 'credentials_not_found', "Run 'claude login' to authenticate");
|
|
17
|
+
}
|
|
18
|
+
const parsed = JSON.parse(raw);
|
|
19
|
+
return parsed;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=file-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../../../src/battery/auth/file-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,SAAS,sBAAsB;IAC7B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACzF,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,QAAQ,GAAG,sBAAsB,EAAE,CAAC;IAE1C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,QAAQ,CAChB,sCAAsC,QAAQ,KAAM,GAAa,CAAC,OAAO,EAAE,EAC3E,uBAAuB,EACvB,oCAAoC,CACrC,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;IACpD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClaudeCredentials, ClientAuth, ApiKeyAuth } from './types.js';
|
|
2
|
+
export type { ClaudeCredentials, ClaudeOAuthCredentials, ApiKeyAuth, ClientAuth } from './types.js';
|
|
3
|
+
export declare function isApiKeyAuth(auth: ClientAuth): auth is ApiKeyAuth;
|
|
4
|
+
export declare function getCredentials(): Promise<ClaudeCredentials>;
|
|
5
|
+
export declare function getAccessToken(credentials: ClaudeCredentials): string;
|
|
6
|
+
export declare function isTokenExpired(credentials: ClaudeCredentials): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readKeychainCredentials } from './keychain.js';
|
|
2
|
+
import { readFileCredentials } from './file-store.js';
|
|
3
|
+
import { CcbError } from '../errors.js';
|
|
4
|
+
export function isApiKeyAuth(auth) {
|
|
5
|
+
return typeof auth === 'object' && 'apiKey' in auth;
|
|
6
|
+
}
|
|
7
|
+
export async function getCredentials() {
|
|
8
|
+
const platform = process.platform;
|
|
9
|
+
if (platform === 'darwin') {
|
|
10
|
+
return readKeychainCredentials();
|
|
11
|
+
}
|
|
12
|
+
if (platform === 'win32' || platform === 'linux') {
|
|
13
|
+
return readFileCredentials();
|
|
14
|
+
}
|
|
15
|
+
throw new CcbError(`Unsupported platform: ${platform}.`, 'unsupported_platform');
|
|
16
|
+
}
|
|
17
|
+
export function getAccessToken(credentials) {
|
|
18
|
+
return credentials.claudeAiOauth.accessToken;
|
|
19
|
+
}
|
|
20
|
+
export function isTokenExpired(credentials) {
|
|
21
|
+
return Date.now() >= credentials.claudeAiOauth.expiresAt;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/battery/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAIxC,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAI,IAAI,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,uBAAuB,EAAE,CAAC;IACnC,CAAC;IAED,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjD,OAAO,mBAAmB,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,IAAI,QAAQ,CAAC,yBAAyB,QAAQ,GAAG,EAAE,sBAAsB,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,WAA8B;IAC3D,OAAO,WAAW,CAAC,aAAa,CAAC,WAAW,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,WAA8B;IAC3D,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,WAAW,CAAC,aAAa,CAAC,SAAS,CAAC;AAC3D,CAAC"}
|