berget 0.0.4 → 0.1.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/src/client.js +15 -13
- package/dist/src/services/auth-service.js +9 -9
- package/package.json +1 -1
- package/src/client.ts +68 -58
- package/src/services/auth-service.ts +91 -44
package/dist/src/client.js
CHANGED
|
@@ -48,8 +48,8 @@ exports.apiClient = (0, openapi_fetch_1.default)({
|
|
|
48
48
|
baseUrl: API_BASE_URL,
|
|
49
49
|
headers: {
|
|
50
50
|
'Content-Type': 'application/json',
|
|
51
|
-
|
|
52
|
-
}
|
|
51
|
+
Accept: 'application/json',
|
|
52
|
+
},
|
|
53
53
|
});
|
|
54
54
|
// Authentication functions
|
|
55
55
|
const getAuthToken = () => {
|
|
@@ -72,7 +72,7 @@ const isTokenExpired = (token) => {
|
|
|
72
72
|
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
73
73
|
const jsonPayload = decodeURIComponent(atob(base64)
|
|
74
74
|
.split('')
|
|
75
|
-
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
75
|
+
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
76
76
|
.join(''));
|
|
77
77
|
const payload = JSON.parse(jsonPayload);
|
|
78
78
|
// Check if token has expired
|
|
@@ -127,20 +127,22 @@ const createAuthenticatedClient = () => {
|
|
|
127
127
|
baseUrl: API_BASE_URL,
|
|
128
128
|
headers: {
|
|
129
129
|
'Content-Type': 'application/json',
|
|
130
|
-
|
|
131
|
-
}
|
|
130
|
+
Accept: 'application/json',
|
|
131
|
+
},
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
return (0, openapi_fetch_1.default)({
|
|
135
135
|
baseUrl: API_BASE_URL,
|
|
136
|
-
headers: token
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
136
|
+
headers: token
|
|
137
|
+
? {
|
|
138
|
+
Authorization: `Bearer ${token}`,
|
|
139
|
+
'Content-Type': 'application/json',
|
|
140
|
+
Accept: 'application/json',
|
|
141
|
+
}
|
|
142
|
+
: {
|
|
143
|
+
'Content-Type': 'application/json',
|
|
144
|
+
Accept: 'application/json',
|
|
145
|
+
},
|
|
144
146
|
});
|
|
145
147
|
};
|
|
146
148
|
exports.createAuthenticatedClient = createAuthenticatedClient;
|
|
@@ -36,7 +36,9 @@ class AuthService {
|
|
|
36
36
|
// Step 1: Initiate device authorization
|
|
37
37
|
const { data: deviceData, error: deviceError } = yield client_1.apiClient.POST('/v1/auth/device', {});
|
|
38
38
|
if (deviceError || !deviceData) {
|
|
39
|
-
throw new Error(deviceError
|
|
39
|
+
throw new Error(deviceError
|
|
40
|
+
? JSON.stringify(deviceError)
|
|
41
|
+
: 'Failed to get device authorization data');
|
|
40
42
|
}
|
|
41
43
|
// Display information to user
|
|
42
44
|
console.log(chalk_1.default.cyan('\nTo complete login:'));
|
|
@@ -46,7 +48,7 @@ class AuthService {
|
|
|
46
48
|
try {
|
|
47
49
|
if (deviceData.verification_url) {
|
|
48
50
|
yield (0, open_1.default)(deviceData.verification_url);
|
|
49
|
-
console.log(chalk_1.default.dim(
|
|
51
|
+
console.log(chalk_1.default.dim("Browser opened automatically. If it didn't open, please use the URL above."));
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
catch (error) {
|
|
@@ -56,13 +58,13 @@ class AuthService {
|
|
|
56
58
|
// Step 2: Poll for completion
|
|
57
59
|
const startTime = Date.now();
|
|
58
60
|
const expiresIn = deviceData.expires_in !== undefined ? deviceData.expires_in : 900;
|
|
59
|
-
const expiresAt = startTime +
|
|
61
|
+
const expiresAt = startTime + expiresIn * 1000;
|
|
60
62
|
let pollInterval = (deviceData.interval || 5) * 1000;
|
|
61
63
|
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
62
64
|
let spinnerIdx = 0;
|
|
63
65
|
while (Date.now() < expiresAt) {
|
|
64
66
|
// Wait for the polling interval
|
|
65
|
-
yield new Promise(resolve => setTimeout(resolve, pollInterval));
|
|
67
|
+
yield new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
66
68
|
// Update spinner
|
|
67
69
|
process.stdout.write(`\r${chalk_1.default.blue(spinner[spinnerIdx])} Waiting for authentication...`);
|
|
68
70
|
spinnerIdx = (spinnerIdx + 1) % spinner.length;
|
|
@@ -70,14 +72,12 @@ class AuthService {
|
|
|
70
72
|
const deviceCode = deviceData.device_code || '';
|
|
71
73
|
const { data: tokenData, error: tokenError } = yield client_1.apiClient.POST('/v1/auth/device/token', {
|
|
72
74
|
body: {
|
|
73
|
-
device_code: deviceCode
|
|
74
|
-
}
|
|
75
|
+
device_code: deviceCode,
|
|
76
|
+
},
|
|
75
77
|
});
|
|
76
78
|
if (tokenError) {
|
|
77
79
|
// Parse the error to get status and other details
|
|
78
|
-
const errorObj = typeof tokenError === 'string'
|
|
79
|
-
? JSON.parse(tokenError)
|
|
80
|
-
: tokenError;
|
|
80
|
+
const errorObj = typeof tokenError === 'string' ? JSON.parse(tokenError) : tokenError;
|
|
81
81
|
const status = errorObj.status || 0;
|
|
82
82
|
const errorCode = errorObj.code || '';
|
|
83
83
|
if (status === 401 || errorCode === 'AUTHORIZATION_PENDING') {
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import createClient from 'openapi-fetch'
|
|
2
|
-
import type { paths } from './types/api'
|
|
3
|
-
import * as fs from 'fs'
|
|
4
|
-
import * as path from 'path'
|
|
5
|
-
import * as os from 'os'
|
|
6
|
-
import chalk from 'chalk'
|
|
1
|
+
import createClient from 'openapi-fetch'
|
|
2
|
+
import type { paths } from './types/api'
|
|
3
|
+
import * as fs from 'fs'
|
|
4
|
+
import * as path from 'path'
|
|
5
|
+
import * as os from 'os'
|
|
6
|
+
import chalk from 'chalk'
|
|
7
7
|
|
|
8
8
|
// Configuration directory
|
|
9
|
-
const CONFIG_DIR = path.join(os.homedir(), '.berget')
|
|
10
|
-
const TOKEN_FILE = path.join(CONFIG_DIR, 'token.json')
|
|
9
|
+
const CONFIG_DIR = path.join(os.homedir(), '.berget')
|
|
10
|
+
const TOKEN_FILE = path.join(CONFIG_DIR, 'token.json')
|
|
11
11
|
|
|
12
12
|
// API Base URL
|
|
13
13
|
// Use --local flag to test against local API
|
|
14
|
-
const isLocalMode = process.argv.includes('--local')
|
|
15
|
-
const API_BASE_URL =
|
|
16
|
-
|
|
14
|
+
const isLocalMode = process.argv.includes('--local')
|
|
15
|
+
const API_BASE_URL =
|
|
16
|
+
process.env.BERGET_API_URL ||
|
|
17
|
+
(isLocalMode ? 'http://localhost:3000' : 'https://api.berget.ai')
|
|
17
18
|
|
|
18
19
|
if (isLocalMode && !process.env.BERGET_API_URL) {
|
|
19
|
-
console.log(chalk.yellow('Using local API endpoint: http://localhost:3000'))
|
|
20
|
+
console.log(chalk.yellow('Using local API endpoint: http://localhost:3000'))
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
// Create a typed client for the Berget API
|
|
@@ -24,100 +25,109 @@ export const apiClient = createClient<paths>({
|
|
|
24
25
|
baseUrl: API_BASE_URL,
|
|
25
26
|
headers: {
|
|
26
27
|
'Content-Type': 'application/json',
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
})
|
|
28
|
+
Accept: 'application/json',
|
|
29
|
+
},
|
|
30
|
+
})
|
|
30
31
|
|
|
31
32
|
// Authentication functions
|
|
32
33
|
export const getAuthToken = (): string | null => {
|
|
33
34
|
try {
|
|
34
35
|
if (fs.existsSync(TOKEN_FILE)) {
|
|
35
|
-
const tokenData = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8'))
|
|
36
|
-
return tokenData.accessToken
|
|
36
|
+
const tokenData = JSON.parse(fs.readFileSync(TOKEN_FILE, 'utf8'))
|
|
37
|
+
return tokenData.accessToken
|
|
37
38
|
}
|
|
38
39
|
} catch (error) {
|
|
39
|
-
console.error('Error reading auth token:', error)
|
|
40
|
+
console.error('Error reading auth token:', error)
|
|
40
41
|
}
|
|
41
|
-
return null
|
|
42
|
-
}
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
43
44
|
|
|
44
45
|
// Check if token is expired (JWT tokens have an exp claim)
|
|
45
46
|
export const isTokenExpired = (token: string): boolean => {
|
|
46
47
|
try {
|
|
47
|
-
const base64Url = token.split('.')[1]
|
|
48
|
-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
|
|
48
|
+
const base64Url = token.split('.')[1]
|
|
49
|
+
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
|
|
49
50
|
const jsonPayload = decodeURIComponent(
|
|
50
51
|
atob(base64)
|
|
51
52
|
.split('')
|
|
52
|
-
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
53
|
+
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
53
54
|
.join('')
|
|
54
|
-
)
|
|
55
|
-
const payload = JSON.parse(jsonPayload)
|
|
56
|
-
|
|
55
|
+
)
|
|
56
|
+
const payload = JSON.parse(jsonPayload)
|
|
57
|
+
|
|
57
58
|
// Check if token has expired
|
|
58
59
|
if (payload.exp) {
|
|
59
|
-
return payload.exp * 1000 < Date.now()
|
|
60
|
+
return payload.exp * 1000 < Date.now()
|
|
60
61
|
}
|
|
61
62
|
} catch (error) {
|
|
62
63
|
// If we can't decode the token, assume it's expired
|
|
63
|
-
return true
|
|
64
|
+
return true
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
// If there's no exp claim, assume it's valid
|
|
67
|
-
return false
|
|
68
|
-
}
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
69
70
|
|
|
70
71
|
export const saveAuthToken = (token: string): void => {
|
|
71
72
|
try {
|
|
72
73
|
if (!fs.existsSync(CONFIG_DIR)) {
|
|
73
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true })
|
|
74
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true })
|
|
74
75
|
}
|
|
75
|
-
fs.writeFileSync(TOKEN_FILE, JSON.stringify({ accessToken: token }), 'utf8')
|
|
76
|
+
fs.writeFileSync(TOKEN_FILE, JSON.stringify({ accessToken: token }), 'utf8')
|
|
76
77
|
// Set file permissions to be readable only by the owner
|
|
77
|
-
fs.chmodSync(TOKEN_FILE, 0o600)
|
|
78
|
+
fs.chmodSync(TOKEN_FILE, 0o600)
|
|
78
79
|
} catch (error) {
|
|
79
|
-
console.error('Error saving auth token:', error)
|
|
80
|
+
console.error('Error saving auth token:', error)
|
|
80
81
|
}
|
|
81
|
-
}
|
|
82
|
+
}
|
|
82
83
|
|
|
83
84
|
export const clearAuthToken = (): void => {
|
|
84
85
|
try {
|
|
85
86
|
if (fs.existsSync(TOKEN_FILE)) {
|
|
86
|
-
fs.unlinkSync(TOKEN_FILE)
|
|
87
|
+
fs.unlinkSync(TOKEN_FILE)
|
|
87
88
|
}
|
|
88
89
|
} catch (error) {
|
|
89
|
-
console.error('Error clearing auth token:', error)
|
|
90
|
+
console.error('Error clearing auth token:', error)
|
|
90
91
|
}
|
|
91
|
-
}
|
|
92
|
+
}
|
|
92
93
|
|
|
93
94
|
// Create an authenticated client
|
|
94
95
|
export const createAuthenticatedClient = () => {
|
|
95
|
-
const token = getAuthToken()
|
|
96
|
-
|
|
96
|
+
const token = getAuthToken()
|
|
97
97
|
if (!token) {
|
|
98
|
-
console.warn(
|
|
98
|
+
console.warn(
|
|
99
|
+
chalk.yellow(
|
|
100
|
+
'No authentication token found. Please run `berget login` first.'
|
|
101
|
+
)
|
|
102
|
+
)
|
|
99
103
|
} else if (isTokenExpired(token)) {
|
|
100
|
-
console.warn(
|
|
104
|
+
console.warn(
|
|
105
|
+
chalk.yellow(
|
|
106
|
+
'Your authentication token has expired. Please run `berget login` to get a new token.'
|
|
107
|
+
)
|
|
108
|
+
)
|
|
101
109
|
// Optionally clear the expired token
|
|
102
|
-
clearAuthToken()
|
|
110
|
+
clearAuthToken()
|
|
103
111
|
return createClient<paths>({
|
|
104
112
|
baseUrl: API_BASE_URL,
|
|
105
113
|
headers: {
|
|
106
114
|
'Content-Type': 'application/json',
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
})
|
|
115
|
+
Accept: 'application/json',
|
|
116
|
+
},
|
|
117
|
+
})
|
|
110
118
|
}
|
|
111
|
-
|
|
119
|
+
|
|
112
120
|
return createClient<paths>({
|
|
113
121
|
baseUrl: API_BASE_URL,
|
|
114
|
-
headers: token
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
122
|
+
headers: token
|
|
123
|
+
? {
|
|
124
|
+
Authorization: `Bearer ${token}`,
|
|
125
|
+
'Content-Type': 'application/json',
|
|
126
|
+
Accept: 'application/json',
|
|
127
|
+
}
|
|
128
|
+
: {
|
|
129
|
+
'Content-Type': 'application/json',
|
|
130
|
+
Accept: 'application/json',
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createAuthenticatedClient,
|
|
3
|
+
saveAuthToken,
|
|
4
|
+
clearAuthToken,
|
|
5
|
+
apiClient,
|
|
6
|
+
} from '../client'
|
|
2
7
|
import open from 'open'
|
|
3
8
|
import chalk from 'chalk'
|
|
4
9
|
import { handleError } from '../utils/error-handler'
|
|
@@ -20,67 +25,97 @@ export class AuthService {
|
|
|
20
25
|
try {
|
|
21
26
|
// Clear any existing token to ensure a fresh login
|
|
22
27
|
clearAuthToken()
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
console.log(chalk.blue('Initiating login process...'))
|
|
25
30
|
|
|
26
31
|
// Step 1: Initiate device authorization
|
|
27
|
-
const { data: deviceData, error: deviceError } = await apiClient.POST(
|
|
28
|
-
|
|
32
|
+
const { data: deviceData, error: deviceError } = await apiClient.POST(
|
|
33
|
+
'/v1/auth/device',
|
|
34
|
+
{}
|
|
35
|
+
)
|
|
36
|
+
|
|
29
37
|
if (deviceError || !deviceData) {
|
|
30
|
-
throw new Error(
|
|
38
|
+
throw new Error(
|
|
39
|
+
deviceError
|
|
40
|
+
? JSON.stringify(deviceError)
|
|
41
|
+
: 'Failed to get device authorization data'
|
|
42
|
+
)
|
|
31
43
|
}
|
|
32
|
-
|
|
44
|
+
|
|
33
45
|
// Display information to user
|
|
34
46
|
console.log(chalk.cyan('\nTo complete login:'))
|
|
35
|
-
console.log(
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
console.log(
|
|
48
|
+
chalk.cyan(
|
|
49
|
+
`1. Open this URL: ${chalk.bold(
|
|
50
|
+
deviceData.verification_url || 'https://auth.berget.ai/device'
|
|
51
|
+
)}`
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
console.log(
|
|
55
|
+
chalk.cyan(
|
|
56
|
+
`2. Enter this code: ${chalk.bold(deviceData.user_code || '')}\n`
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
|
|
38
60
|
// Try to open browser automatically
|
|
39
61
|
try {
|
|
40
62
|
if (deviceData.verification_url) {
|
|
41
63
|
await open(deviceData.verification_url)
|
|
42
|
-
console.log(
|
|
64
|
+
console.log(
|
|
65
|
+
chalk.dim(
|
|
66
|
+
"Browser opened automatically. If it didn't open, please use the URL above."
|
|
67
|
+
)
|
|
68
|
+
)
|
|
43
69
|
}
|
|
44
70
|
} catch (error) {
|
|
45
|
-
console.log(
|
|
71
|
+
console.log(
|
|
72
|
+
chalk.yellow(
|
|
73
|
+
'Could not open browser automatically. Please open the URL manually.'
|
|
74
|
+
)
|
|
75
|
+
)
|
|
46
76
|
}
|
|
47
|
-
|
|
77
|
+
|
|
48
78
|
console.log(chalk.dim('\nWaiting for authentication to complete...'))
|
|
49
|
-
|
|
79
|
+
|
|
50
80
|
// Step 2: Poll for completion
|
|
51
81
|
const startTime = Date.now()
|
|
52
|
-
const expiresIn =
|
|
53
|
-
|
|
82
|
+
const expiresIn =
|
|
83
|
+
deviceData.expires_in !== undefined ? deviceData.expires_in : 900
|
|
84
|
+
const expiresAt = startTime + expiresIn * 1000
|
|
54
85
|
let pollInterval = (deviceData.interval || 5) * 1000
|
|
55
|
-
|
|
86
|
+
|
|
56
87
|
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
57
88
|
let spinnerIdx = 0
|
|
58
|
-
|
|
89
|
+
|
|
59
90
|
while (Date.now() < expiresAt) {
|
|
60
91
|
// Wait for the polling interval
|
|
61
|
-
await new Promise(resolve => setTimeout(resolve, pollInterval))
|
|
62
|
-
|
|
92
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval))
|
|
93
|
+
|
|
63
94
|
// Update spinner
|
|
64
|
-
process.stdout.write(
|
|
95
|
+
process.stdout.write(
|
|
96
|
+
`\r${chalk.blue(spinner[spinnerIdx])} Waiting for authentication...`
|
|
97
|
+
)
|
|
65
98
|
spinnerIdx = (spinnerIdx + 1) % spinner.length
|
|
66
|
-
|
|
99
|
+
|
|
67
100
|
// Check if authentication is complete
|
|
68
101
|
const deviceCode = deviceData.device_code || ''
|
|
69
|
-
const { data: tokenData, error: tokenError } = await apiClient.POST(
|
|
70
|
-
|
|
71
|
-
|
|
102
|
+
const { data: tokenData, error: tokenError } = await apiClient.POST(
|
|
103
|
+
'/v1/auth/device/token',
|
|
104
|
+
{
|
|
105
|
+
body: {
|
|
106
|
+
device_code: deviceCode,
|
|
107
|
+
},
|
|
72
108
|
}
|
|
73
|
-
|
|
74
|
-
|
|
109
|
+
)
|
|
110
|
+
|
|
75
111
|
if (tokenError) {
|
|
76
112
|
// Parse the error to get status and other details
|
|
77
|
-
const errorObj =
|
|
78
|
-
? JSON.parse(tokenError)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
113
|
+
const errorObj =
|
|
114
|
+
typeof tokenError === 'string' ? JSON.parse(tokenError) : tokenError
|
|
115
|
+
|
|
116
|
+
const status = errorObj.status || 0
|
|
117
|
+
const errorCode = errorObj.code || ''
|
|
118
|
+
|
|
84
119
|
if (status === 401 || errorCode === 'AUTHORIZATION_PENDING') {
|
|
85
120
|
// Still waiting for user to complete authorization
|
|
86
121
|
continue
|
|
@@ -91,10 +126,12 @@ export class AuthService {
|
|
|
91
126
|
} else if (status === 400) {
|
|
92
127
|
// Error or expired
|
|
93
128
|
if (errorCode === 'EXPIRED_TOKEN') {
|
|
94
|
-
console.log(
|
|
129
|
+
console.log(
|
|
130
|
+
chalk.red('\n\nAuthentication timed out. Please try again.')
|
|
131
|
+
)
|
|
95
132
|
} else if (errorCode !== 'AUTHORIZATION_PENDING') {
|
|
96
133
|
// Only show error if it's not the expected "still waiting" error
|
|
97
|
-
const errorMessage = errorObj.message || JSON.stringify(errorObj)
|
|
134
|
+
const errorMessage = errorObj.message || JSON.stringify(errorObj)
|
|
98
135
|
console.log(chalk.red(`\n\nError: ${errorMessage}`))
|
|
99
136
|
return false
|
|
100
137
|
} else {
|
|
@@ -106,28 +143,38 @@ export class AuthService {
|
|
|
106
143
|
// For any other error, log it but continue polling
|
|
107
144
|
// This makes the flow more resilient to temporary issues
|
|
108
145
|
if (process.env.DEBUG) {
|
|
109
|
-
console.log(
|
|
110
|
-
|
|
111
|
-
|
|
146
|
+
console.log(
|
|
147
|
+
chalk.yellow(`\n\nReceived error: ${JSON.stringify(errorObj)}`)
|
|
148
|
+
)
|
|
149
|
+
console.log(
|
|
150
|
+
chalk.yellow('Continuing to wait for authentication...')
|
|
151
|
+
)
|
|
152
|
+
process.stdout.write(
|
|
153
|
+
`\r${chalk.blue(
|
|
154
|
+
spinner[spinnerIdx]
|
|
155
|
+
)} Waiting for authentication...`
|
|
156
|
+
)
|
|
112
157
|
}
|
|
113
158
|
continue
|
|
114
159
|
}
|
|
115
160
|
} else if (tokenData && tokenData.token) {
|
|
116
161
|
// Success!
|
|
117
162
|
saveAuthToken(tokenData.token)
|
|
118
|
-
|
|
163
|
+
|
|
119
164
|
process.stdout.write('\r' + ' '.repeat(50) + '\r') // Clear the spinner line
|
|
120
165
|
console.log(chalk.green('✓ Successfully logged in to Berget'))
|
|
121
|
-
|
|
166
|
+
|
|
122
167
|
if (tokenData.user) {
|
|
123
168
|
const user = tokenData.user as any
|
|
124
|
-
console.log(
|
|
169
|
+
console.log(
|
|
170
|
+
chalk.green(`Logged in as ${user.name || user.email || 'User'}`)
|
|
171
|
+
)
|
|
125
172
|
}
|
|
126
|
-
|
|
173
|
+
|
|
127
174
|
return true
|
|
128
175
|
}
|
|
129
176
|
}
|
|
130
|
-
|
|
177
|
+
|
|
131
178
|
console.log(chalk.red('\n\nAuthentication timed out. Please try again.'))
|
|
132
179
|
return false
|
|
133
180
|
} catch (error) {
|
|
@@ -145,7 +192,7 @@ export class AuthService {
|
|
|
145
192
|
return false
|
|
146
193
|
}
|
|
147
194
|
}
|
|
148
|
-
|
|
195
|
+
|
|
149
196
|
public async getUserProfile() {
|
|
150
197
|
try {
|
|
151
198
|
const { data, error } = await this.client.GET('/v1/users/me')
|