Skip to content

Commit 3c505a5

Browse files
committed
Cleanup for sdk/src/credentials
1 parent d4a15c5 commit 3c505a5

File tree

1 file changed

+39
-53
lines changed

1 file changed

+39
-53
lines changed

sdk/src/credentials.ts

Lines changed: 39 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,37 @@ import { getClaudeOAuthTokenFromEnv } from './env'
1212
import type { ClientEnv } from '@codebuff/common/types/contracts/env'
1313
import type { User } from '@codebuff/common/util/credentials'
1414

15-
const credentialsSchema = z
16-
.object({
17-
default: userSchema,
18-
})
19-
.catchall(userSchema)
15+
/**
16+
* Schema for Claude OAuth credentials.
17+
*/
18+
const claudeOAuthSchema = z.object({
19+
accessToken: z.string(),
20+
refreshToken: z.string(),
21+
expiresAt: z.number(),
22+
connectedAt: z.number(),
23+
})
24+
25+
/**
26+
* Unified schema for the credentials file.
27+
* Contains both Codebuff user credentials and Claude OAuth credentials.
28+
*/
29+
const credentialsFileSchema = z.object({
30+
default: userSchema.optional(),
31+
claudeOAuth: claudeOAuthSchema.optional(),
32+
})
2033

2134
const ensureDirectoryExistsSync = (dir: string) => {
2235
if (!fs.existsSync(dir)) {
2336
fs.mkdirSync(dir, { recursive: true })
2437
}
2538
}
2639

27-
export const userFromJson = (
28-
json: string,
29-
profileName: string = 'default',
30-
): User | undefined => {
40+
export const userFromJson = (json: string): User | null => {
3141
try {
32-
const allCredentials = credentialsSchema.parse(JSON.parse(json))
33-
const profile = allCredentials[profileName]
34-
return profile
35-
} catch (error) {
36-
console.error('Error parsing user JSON:', error)
37-
return
42+
const credentials = credentialsFileSchema.parse(JSON.parse(json))
43+
return credentials.default ?? null
44+
} catch {
45+
return null
3846
}
3947
}
4048

@@ -58,11 +66,6 @@ export const getCredentialsPath = (clientEnv: ClientEnv = env): string => {
5866
return path.join(getConfigDir(clientEnv), 'credentials.json')
5967
}
6068

61-
// Legacy exports for backward compatibility - use getConfigDir() and getCredentialsPath() for testability
62-
export const CONFIG_DIR = getConfigDir()
63-
ensureDirectoryExistsSync(CONFIG_DIR)
64-
export const CREDENTIALS_PATH = getCredentialsPath()
65-
6669
export const getUserCredentials = (clientEnv: ClientEnv = env): User | null => {
6770
const credentialsPath = getCredentialsPath(clientEnv)
6871
if (!fs.existsSync(credentialsPath)) {
@@ -89,24 +92,6 @@ export interface ClaudeOAuthCredentials {
8992
connectedAt: number // Unix timestamp in milliseconds
9093
}
9194

92-
/**
93-
* Schema for Claude OAuth credentials in the credentials file.
94-
*/
95-
const claudeOAuthSchema = z.object({
96-
accessToken: z.string(),
97-
refreshToken: z.string(),
98-
expiresAt: z.number(),
99-
connectedAt: z.number(),
100-
})
101-
102-
/**
103-
* Extended credentials file schema that includes Claude OAuth.
104-
*/
105-
const extendedCredentialsSchema = z.object({
106-
default: userSchema.optional(),
107-
claudeOAuth: claudeOAuthSchema.optional(),
108-
}).catchall(z.unknown())
109-
11095
/**
11196
* Get Claude OAuth credentials from file or environment variable.
11297
* Environment variable takes precedence.
@@ -135,7 +120,7 @@ export const getClaudeOAuthCredentials = (
135120

136121
try {
137122
const credentialsFile = fs.readFileSync(credentialsPath, 'utf8')
138-
const parsed = extendedCredentialsSchema.safeParse(JSON.parse(credentialsFile))
123+
const parsed = credentialsFileSchema.safeParse(JSON.parse(credentialsFile))
139124
if (!parsed.success || !parsed.data.claudeOAuth) {
140125
return null
141126
}
@@ -201,9 +186,7 @@ export const clearClaudeOAuthCredentials = (
201186
* Check if Claude OAuth credentials are valid (not expired).
202187
* Returns true if credentials exist and haven't expired.
203188
*/
204-
export const isClaudeOAuthValid = (
205-
clientEnv: ClientEnv = env,
206-
): boolean => {
189+
export const isClaudeOAuthValid = (clientEnv: ClientEnv = env): boolean => {
207190
const credentials = getClaudeOAuthCredentials(clientEnv)
208191
if (!credentials) {
209192
return false
@@ -237,17 +220,20 @@ export const refreshClaudeOAuthToken = async (
237220
// Start the refresh and store the promise
238221
refreshPromise = (async () => {
239222
try {
240-
const response = await fetch('https://console.anthropic.com/v1/oauth/token', {
241-
method: 'POST',
242-
headers: {
243-
'Content-Type': 'application/json',
223+
const response = await fetch(
224+
'https://console.anthropic.com/v1/oauth/token',
225+
{
226+
method: 'POST',
227+
headers: {
228+
'Content-Type': 'application/json',
229+
},
230+
body: JSON.stringify({
231+
grant_type: 'refresh_token',
232+
refresh_token: credentials.refreshToken,
233+
client_id: CLAUDE_OAUTH_CLIENT_ID,
234+
}),
244235
},
245-
body: JSON.stringify({
246-
grant_type: 'refresh_token',
247-
refresh_token: credentials.refreshToken,
248-
client_id: CLAUDE_OAUTH_CLIENT_ID,
249-
}),
250-
})
236+
)
251237

252238
if (!response.ok) {
253239
// Refresh failed, clear credentials
@@ -284,7 +270,7 @@ export const refreshClaudeOAuthToken = async (
284270
/**
285271
* Get valid Claude OAuth credentials, refreshing if necessary.
286272
* This is the main function to use when you need credentials for an API call.
287-
*
273+
*
288274
* - Returns credentials immediately if valid (>5 min until expiry)
289275
* - Attempts refresh if token is expired or near-expiry
290276
* - Returns null if no credentials or refresh fails

0 commit comments

Comments
 (0)