berget 1.2.0 → 1.3.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/-27b-it +0 -0
- package/dist/package.json +5 -1
- package/dist/src/client.js +33 -43
- package/dist/src/commands/chat.js +50 -22
- package/dist/src/commands/models.js +2 -2
- package/dist/src/services/chat-service.js +230 -125
- package/dist/src/utils/default-api-key.js +20 -37
- package/dist/src/utils/logger.js +160 -0
- package/dist/src/utils/markdown-renderer.js +73 -0
- package/dist/src/utils/token-manager.js +6 -9
- package/package.json +5 -1
- package/src/client.ts +75 -90
- package/src/commands/chat.ts +64 -29
- package/src/commands/models.ts +4 -4
- package/src/services/chat-service.ts +386 -184
- package/src/utils/default-api-key.ts +20 -37
- package/src/utils/logger.ts +159 -0
- package/src/utils/markdown-renderer.ts +68 -0
- package/src/utils/token-manager.ts +6 -5
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.logger = exports.Logger = exports.LogLevel = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
/**
|
|
9
|
+
* Log levels in order of increasing verbosity
|
|
10
|
+
*/
|
|
11
|
+
var LogLevel;
|
|
12
|
+
(function (LogLevel) {
|
|
13
|
+
LogLevel[LogLevel["NONE"] = 0] = "NONE";
|
|
14
|
+
LogLevel[LogLevel["ERROR"] = 1] = "ERROR";
|
|
15
|
+
LogLevel[LogLevel["WARN"] = 2] = "WARN";
|
|
16
|
+
LogLevel[LogLevel["INFO"] = 3] = "INFO";
|
|
17
|
+
LogLevel[LogLevel["DEBUG"] = 4] = "DEBUG";
|
|
18
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
19
|
+
/**
|
|
20
|
+
* Logger class for centralized logging with configurable log levels
|
|
21
|
+
*/
|
|
22
|
+
class Logger {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.logLevel = LogLevel.INFO; // Default log level
|
|
25
|
+
// Set log level from environment variable or command line argument
|
|
26
|
+
if (process.env.LOG_LEVEL) {
|
|
27
|
+
this.setLogLevelFromString(process.env.LOG_LEVEL);
|
|
28
|
+
}
|
|
29
|
+
else if (process.argv.includes('--debug')) {
|
|
30
|
+
this.logLevel = LogLevel.DEBUG;
|
|
31
|
+
}
|
|
32
|
+
else if (process.argv.includes('--quiet')) {
|
|
33
|
+
this.logLevel = LogLevel.ERROR;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
static getInstance() {
|
|
37
|
+
if (!Logger.instance) {
|
|
38
|
+
Logger.instance = new Logger();
|
|
39
|
+
}
|
|
40
|
+
return Logger.instance;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Set the log level from a string
|
|
44
|
+
*/
|
|
45
|
+
setLogLevelFromString(level) {
|
|
46
|
+
switch (level.toLowerCase()) {
|
|
47
|
+
case 'none':
|
|
48
|
+
this.logLevel = LogLevel.NONE;
|
|
49
|
+
break;
|
|
50
|
+
case 'error':
|
|
51
|
+
this.logLevel = LogLevel.ERROR;
|
|
52
|
+
break;
|
|
53
|
+
case 'warn':
|
|
54
|
+
this.logLevel = LogLevel.WARN;
|
|
55
|
+
break;
|
|
56
|
+
case 'info':
|
|
57
|
+
this.logLevel = LogLevel.INFO;
|
|
58
|
+
break;
|
|
59
|
+
case 'debug':
|
|
60
|
+
this.logLevel = LogLevel.DEBUG;
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
// Invalid log level, keep default
|
|
64
|
+
console.warn(`Invalid log level: ${level}. Using default (INFO).`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Set the log level
|
|
69
|
+
*/
|
|
70
|
+
setLogLevel(level) {
|
|
71
|
+
this.logLevel = level;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get the current log level
|
|
75
|
+
*/
|
|
76
|
+
getLogLevel() {
|
|
77
|
+
return this.logLevel;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Log a debug message (only shown at DEBUG level)
|
|
81
|
+
*/
|
|
82
|
+
debug(message, ...args) {
|
|
83
|
+
if (this.logLevel >= LogLevel.DEBUG) {
|
|
84
|
+
if (args.length > 0) {
|
|
85
|
+
console.log(chalk_1.default.yellow(`DEBUG: ${message}`), ...args);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.log(chalk_1.default.yellow(`DEBUG: ${message}`));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Log an info message (shown at INFO level and above)
|
|
94
|
+
*/
|
|
95
|
+
info(message, ...args) {
|
|
96
|
+
if (this.logLevel >= LogLevel.INFO) {
|
|
97
|
+
if (args.length > 0) {
|
|
98
|
+
console.log(chalk_1.default.blue(message), ...args);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
console.log(chalk_1.default.blue(message));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Log a warning message (shown at WARN level and above)
|
|
107
|
+
*/
|
|
108
|
+
warn(message, ...args) {
|
|
109
|
+
if (this.logLevel >= LogLevel.WARN) {
|
|
110
|
+
if (args.length > 0) {
|
|
111
|
+
console.log(chalk_1.default.yellow(message), ...args);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
console.log(chalk_1.default.yellow(message));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Log an error message (shown at ERROR level and above)
|
|
120
|
+
*/
|
|
121
|
+
error(message, ...args) {
|
|
122
|
+
if (this.logLevel >= LogLevel.ERROR) {
|
|
123
|
+
if (args.length > 0) {
|
|
124
|
+
console.error(chalk_1.default.red(message), ...args);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.error(chalk_1.default.red(message));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Log a success message (shown at INFO level and above)
|
|
133
|
+
*/
|
|
134
|
+
success(message, ...args) {
|
|
135
|
+
if (this.logLevel >= LogLevel.INFO) {
|
|
136
|
+
if (args.length > 0) {
|
|
137
|
+
console.log(chalk_1.default.green(message), ...args);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
console.log(chalk_1.default.green(message));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Log a plain message without color (shown at INFO level and above)
|
|
146
|
+
*/
|
|
147
|
+
log(message, ...args) {
|
|
148
|
+
if (this.logLevel >= LogLevel.INFO) {
|
|
149
|
+
if (args.length > 0) {
|
|
150
|
+
console.log(message, ...args);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log(message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.Logger = Logger;
|
|
159
|
+
// Export a singleton instance for easy import
|
|
160
|
+
exports.logger = Logger.getInstance();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.containsMarkdown = exports.renderMarkdown = void 0;
|
|
7
|
+
const marked_1 = require("marked");
|
|
8
|
+
const marked_terminal_1 = __importDefault(require("marked-terminal"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
// Configure marked to use the terminal renderer
|
|
11
|
+
marked_1.marked.setOptions({
|
|
12
|
+
renderer: new marked_terminal_1.default({
|
|
13
|
+
// Customize the rendering options
|
|
14
|
+
code: chalk_1.default.cyan,
|
|
15
|
+
blockquote: chalk_1.default.gray.italic,
|
|
16
|
+
table: chalk_1.default.white,
|
|
17
|
+
listitem: chalk_1.default.yellow,
|
|
18
|
+
strong: chalk_1.default.bold,
|
|
19
|
+
em: chalk_1.default.italic,
|
|
20
|
+
heading: chalk_1.default.bold.blueBright,
|
|
21
|
+
hr: chalk_1.default.gray,
|
|
22
|
+
link: chalk_1.default.blue.underline,
|
|
23
|
+
// Adjust the width to fit the terminal
|
|
24
|
+
width: process.stdout.columns || 80,
|
|
25
|
+
// Customize code block rendering
|
|
26
|
+
codespan: chalk_1.default.cyan
|
|
27
|
+
})
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Render markdown text to terminal-friendly formatted text
|
|
31
|
+
* @param markdown The markdown text to render
|
|
32
|
+
* @returns Formatted text for terminal display
|
|
33
|
+
*/
|
|
34
|
+
function renderMarkdown(markdown) {
|
|
35
|
+
if (!markdown)
|
|
36
|
+
return '';
|
|
37
|
+
try {
|
|
38
|
+
// Convert markdown to terminal-friendly text
|
|
39
|
+
return (0, marked_1.marked)(markdown);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
// If rendering fails, return the original text
|
|
43
|
+
console.error(`Error rendering markdown: ${error}`);
|
|
44
|
+
return markdown;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.renderMarkdown = renderMarkdown;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a string contains markdown formatting
|
|
50
|
+
* @param text The text to check
|
|
51
|
+
* @returns True if the text contains markdown formatting
|
|
52
|
+
*/
|
|
53
|
+
function containsMarkdown(text) {
|
|
54
|
+
if (!text)
|
|
55
|
+
return false;
|
|
56
|
+
// Check for common markdown patterns
|
|
57
|
+
const markdownPatterns = [
|
|
58
|
+
/^#+\s+/m, // Headers
|
|
59
|
+
/\*\*.*?\*\*/, // Bold
|
|
60
|
+
/\*.*?\*/, // Italic
|
|
61
|
+
/`.*?`/, // Inline code
|
|
62
|
+
/```[\s\S]*?```/, // Code blocks
|
|
63
|
+
/\[.*?\]\(.*?\)/, // Links
|
|
64
|
+
/^\s*[-*+]\s+/m, // Lists
|
|
65
|
+
/^\s*\d+\.\s+/m, // Numbered lists
|
|
66
|
+
/^\s*>\s+/m, // Blockquotes
|
|
67
|
+
/\|.*\|.*\|/, // Tables
|
|
68
|
+
/^---+$/m, // Horizontal rules
|
|
69
|
+
/^===+$/m // Alternative headers
|
|
70
|
+
];
|
|
71
|
+
return markdownPatterns.some(pattern => pattern.test(text));
|
|
72
|
+
}
|
|
73
|
+
exports.containsMarkdown = containsMarkdown;
|
|
@@ -22,15 +22,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
-
};
|
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
26
|
exports.TokenManager = void 0;
|
|
30
27
|
const fs = __importStar(require("fs"));
|
|
31
28
|
const path = __importStar(require("path"));
|
|
32
29
|
const os = __importStar(require("os"));
|
|
33
|
-
const
|
|
30
|
+
const logger_1 = require("./logger");
|
|
34
31
|
/**
|
|
35
32
|
* Manages authentication tokens including refresh functionality
|
|
36
33
|
*/
|
|
@@ -62,7 +59,7 @@ class TokenManager {
|
|
|
62
59
|
}
|
|
63
60
|
}
|
|
64
61
|
catch (error) {
|
|
65
|
-
|
|
62
|
+
logger_1.logger.error('Failed to load authentication token');
|
|
66
63
|
this.tokenData = null;
|
|
67
64
|
}
|
|
68
65
|
}
|
|
@@ -84,7 +81,7 @@ class TokenManager {
|
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
catch (error) {
|
|
87
|
-
|
|
84
|
+
logger_1.logger.error('Failed to save authentication token');
|
|
88
85
|
}
|
|
89
86
|
}
|
|
90
87
|
/**
|
|
@@ -117,14 +114,14 @@ class TokenManager {
|
|
|
117
114
|
// Using a larger buffer to be more proactive about refreshing
|
|
118
115
|
const expirationBuffer = 10 * 60 * 1000; // 10 minutes in milliseconds
|
|
119
116
|
const isExpired = Date.now() + expirationBuffer >= this.tokenData.expires_at;
|
|
120
|
-
if (isExpired
|
|
121
|
-
|
|
117
|
+
if (isExpired) {
|
|
118
|
+
logger_1.logger.debug(`Token expired or expiring soon. Current time: ${new Date().toISOString()}, Expiry: ${new Date(this.tokenData.expires_at).toISOString()}`);
|
|
122
119
|
}
|
|
123
120
|
return isExpired;
|
|
124
121
|
}
|
|
125
122
|
catch (error) {
|
|
126
123
|
// If there's any error checking expiration, assume token is expired
|
|
127
|
-
|
|
124
|
+
logger_1.logger.error(`Error checking token expiration: ${error instanceof Error ? error.message : String(error)}`);
|
|
128
125
|
return true;
|
|
129
126
|
}
|
|
130
127
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "berget",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"berget": "dist/index.js"
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"description": "This is a cli command for interacting with the AI infrastructure provider Berget",
|
|
21
21
|
"devDependencies": {
|
|
22
|
+
"@types/marked": "^5.0.2",
|
|
23
|
+
"@types/marked-terminal": "^6.1.1",
|
|
22
24
|
"@types/node": "^20.11.20",
|
|
23
25
|
"tsx": "^4.19.3",
|
|
24
26
|
"typescript": "^5.3.3"
|
|
@@ -27,6 +29,8 @@
|
|
|
27
29
|
"chalk": "^4.1.2",
|
|
28
30
|
"commander": "^12.0.0",
|
|
29
31
|
"fs-extra": "^11.3.0",
|
|
32
|
+
"marked": "^9.1.6",
|
|
33
|
+
"marked-terminal": "^6.2.0",
|
|
30
34
|
"open": "^9.1.0",
|
|
31
35
|
"openapi-fetch": "^0.9.1",
|
|
32
36
|
"openapi-typescript": "^6.7.4",
|
package/src/client.ts
CHANGED
|
@@ -5,16 +5,17 @@ import * as path from 'path'
|
|
|
5
5
|
import * as os from 'os'
|
|
6
6
|
import chalk from 'chalk'
|
|
7
7
|
import { TokenManager } from './utils/token-manager'
|
|
8
|
+
import { logger } from './utils/logger'
|
|
8
9
|
|
|
9
10
|
// API Base URL
|
|
10
11
|
// Use --local flag to test against local API
|
|
11
12
|
const isLocalMode = process.argv.includes('--local')
|
|
12
|
-
const API_BASE_URL =
|
|
13
|
+
export const API_BASE_URL =
|
|
13
14
|
process.env.BERGET_API_URL ||
|
|
14
15
|
(isLocalMode ? 'http://localhost:3000' : 'https://api.berget.ai')
|
|
15
16
|
|
|
16
|
-
if (isLocalMode && !process.env.BERGET_API_URL
|
|
17
|
-
|
|
17
|
+
if (isLocalMode && !process.env.BERGET_API_URL) {
|
|
18
|
+
logger.debug('Using local API endpoint: http://localhost:3000')
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
// Create a typed client for the Berget API
|
|
@@ -50,11 +51,9 @@ export const clearAuthToken = (): void => {
|
|
|
50
51
|
export const createAuthenticatedClient = () => {
|
|
51
52
|
const tokenManager = TokenManager.getInstance()
|
|
52
53
|
|
|
53
|
-
if (!tokenManager.getAccessToken()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
'No authentication token found. Please run `berget auth login` first.'
|
|
57
|
-
)
|
|
54
|
+
if (!tokenManager.getAccessToken()) {
|
|
55
|
+
logger.debug(
|
|
56
|
+
'No authentication token found. Please run `berget auth login` first.'
|
|
58
57
|
)
|
|
59
58
|
}
|
|
60
59
|
|
|
@@ -88,7 +87,10 @@ export const createAuthenticatedClient = () => {
|
|
|
88
87
|
}
|
|
89
88
|
|
|
90
89
|
// Update the Authorization header with the current token
|
|
91
|
-
if (
|
|
90
|
+
if (
|
|
91
|
+
!args[1]?.headers?.Authorization &&
|
|
92
|
+
tokenManager.getAccessToken()
|
|
93
|
+
) {
|
|
92
94
|
if (!args[1]) args[1] = {}
|
|
93
95
|
if (!args[1].headers) args[1].headers = {}
|
|
94
96
|
args[1].headers.Authorization = `Bearer ${tokenManager.getAccessToken()}`
|
|
@@ -101,17 +103,13 @@ export const createAuthenticatedClient = () => {
|
|
|
101
103
|
...args
|
|
102
104
|
)
|
|
103
105
|
} catch (requestError) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}`
|
|
112
|
-
)
|
|
113
|
-
)
|
|
114
|
-
}
|
|
106
|
+
logger.debug(
|
|
107
|
+
`Request error: ${
|
|
108
|
+
requestError instanceof Error
|
|
109
|
+
? requestError.message
|
|
110
|
+
: String(requestError)
|
|
111
|
+
}`
|
|
112
|
+
)
|
|
115
113
|
return {
|
|
116
114
|
error: {
|
|
117
115
|
message: `Request failed: ${
|
|
@@ -126,66 +124,59 @@ export const createAuthenticatedClient = () => {
|
|
|
126
124
|
// If we get an auth error, try to refresh the token and retry
|
|
127
125
|
if (result.error) {
|
|
128
126
|
// Detect various forms of authentication errors
|
|
129
|
-
let isAuthError = false
|
|
130
|
-
|
|
127
|
+
let isAuthError = false
|
|
128
|
+
|
|
131
129
|
try {
|
|
132
130
|
// Standard 401 Unauthorized
|
|
133
|
-
if (
|
|
134
|
-
|
|
131
|
+
if (
|
|
132
|
+
typeof result.error === 'object' &&
|
|
133
|
+
result.error.status === 401
|
|
134
|
+
) {
|
|
135
|
+
isAuthError = true
|
|
135
136
|
}
|
|
136
137
|
// OAuth specific errors
|
|
137
|
-
else if (
|
|
138
|
+
else if (
|
|
139
|
+
result.error.error &&
|
|
138
140
|
(result.error.error.code === 'invalid_token' ||
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
result.error.error.code === 'token_expired' ||
|
|
142
|
+
result.error.error.message === 'Invalid API key' ||
|
|
143
|
+
result.error.error.message?.toLowerCase().includes('token') ||
|
|
144
|
+
result.error.error.message
|
|
145
|
+
?.toLowerCase()
|
|
146
|
+
.includes('unauthorized'))
|
|
147
|
+
) {
|
|
148
|
+
isAuthError = true
|
|
144
149
|
}
|
|
145
150
|
// Message-based detection as fallback
|
|
146
|
-
else if (
|
|
151
|
+
else if (
|
|
152
|
+
typeof result.error === 'string' &&
|
|
147
153
|
(result.error.toLowerCase().includes('unauthorized') ||
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
result.error.toLowerCase().includes('token') ||
|
|
155
|
+
result.error.toLowerCase().includes('auth'))
|
|
156
|
+
) {
|
|
157
|
+
isAuthError = true
|
|
151
158
|
}
|
|
152
159
|
} catch (parseError) {
|
|
153
160
|
// If we can't parse the error structure, do a simple string check
|
|
154
|
-
const errorStr = String(result.error)
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
const errorStr = String(result.error)
|
|
162
|
+
if (
|
|
163
|
+
errorStr.toLowerCase().includes('unauthorized') ||
|
|
164
|
+
errorStr.toLowerCase().includes('token') ||
|
|
165
|
+
errorStr.toLowerCase().includes('auth')
|
|
166
|
+
) {
|
|
167
|
+
isAuthError = true
|
|
159
168
|
}
|
|
160
169
|
}
|
|
161
170
|
|
|
162
171
|
if (isAuthError && tokenManager.getRefreshToken()) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
)
|
|
168
|
-
)
|
|
169
|
-
console.log(
|
|
170
|
-
chalk.yellow(
|
|
171
|
-
`DEBUG: Error details: ${JSON.stringify(
|
|
172
|
-
result.error,
|
|
173
|
-
null,
|
|
174
|
-
2
|
|
175
|
-
)}`
|
|
176
|
-
)
|
|
177
|
-
)
|
|
178
|
-
}
|
|
172
|
+
logger.debug('Auth error detected, attempting token refresh')
|
|
173
|
+
logger.debug(
|
|
174
|
+
`Error details: ${JSON.stringify(result.error, null, 2)}`
|
|
175
|
+
)
|
|
179
176
|
|
|
180
177
|
const refreshed = await refreshAccessToken(tokenManager)
|
|
181
178
|
if (refreshed) {
|
|
182
|
-
|
|
183
|
-
console.log(
|
|
184
|
-
chalk.green(
|
|
185
|
-
'DEBUG: Token refreshed successfully, retrying request'
|
|
186
|
-
)
|
|
187
|
-
)
|
|
188
|
-
}
|
|
179
|
+
logger.debug('Token refreshed successfully, retrying request')
|
|
189
180
|
|
|
190
181
|
// Update the Authorization header with the new token
|
|
191
182
|
if (!args[1]) args[1] = {}
|
|
@@ -197,13 +188,12 @@ export const createAuthenticatedClient = () => {
|
|
|
197
188
|
...args
|
|
198
189
|
)
|
|
199
190
|
} else {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
191
|
+
logger.debug('Token refresh failed')
|
|
192
|
+
|
|
204
193
|
// Add a more helpful error message for users
|
|
205
194
|
if (typeof result.error === 'object') {
|
|
206
|
-
result.error.userMessage =
|
|
195
|
+
result.error.userMessage =
|
|
196
|
+
'Your session has expired. Please run `berget auth login` to log in again.'
|
|
207
197
|
}
|
|
208
198
|
}
|
|
209
199
|
}
|
|
@@ -227,9 +217,7 @@ async function refreshAccessToken(
|
|
|
227
217
|
const refreshToken = tokenManager.getRefreshToken()
|
|
228
218
|
if (!refreshToken) return false
|
|
229
219
|
|
|
230
|
-
|
|
231
|
-
console.log(chalk.yellow('DEBUG: Attempting to refresh access token'))
|
|
232
|
-
}
|
|
220
|
+
logger.debug('Attempting to refresh access token')
|
|
233
221
|
|
|
234
222
|
// Use fetch directly since this endpoint might not be in the OpenAPI spec
|
|
235
223
|
try {
|
|
@@ -240,15 +228,13 @@ async function refreshAccessToken(
|
|
|
240
228
|
Accept: 'application/json',
|
|
241
229
|
},
|
|
242
230
|
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
243
|
-
})
|
|
231
|
+
})
|
|
244
232
|
|
|
245
233
|
// Handle HTTP errors
|
|
246
234
|
if (!response.ok) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
)
|
|
251
|
-
}
|
|
235
|
+
logger.debug(
|
|
236
|
+
`Token refresh error: HTTP ${response.status} ${response.statusText}`
|
|
237
|
+
)
|
|
252
238
|
|
|
253
239
|
// Check if the refresh token itself is expired or invalid
|
|
254
240
|
if (response.status === 401 || response.status === 403) {
|
|
@@ -290,34 +276,33 @@ async function refreshAccessToken(
|
|
|
290
276
|
return false
|
|
291
277
|
}
|
|
292
278
|
|
|
293
|
-
|
|
294
|
-
console.log(chalk.green('DEBUG: Token refreshed successfully'))
|
|
295
|
-
}
|
|
279
|
+
logger.debug('Token refreshed successfully')
|
|
296
280
|
|
|
297
281
|
// Update the token
|
|
298
|
-
tokenManager.updateAccessToken(
|
|
299
|
-
|
|
300
|
-
data.expires_in || 3600
|
|
301
|
-
)
|
|
302
|
-
|
|
282
|
+
tokenManager.updateAccessToken(data.token, data.expires_in || 3600)
|
|
283
|
+
|
|
303
284
|
// If a new refresh token was provided, update that too
|
|
304
285
|
if (data.refresh_token) {
|
|
305
|
-
tokenManager.setTokens(
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
286
|
+
tokenManager.setTokens(
|
|
287
|
+
data.token,
|
|
288
|
+
data.refresh_token,
|
|
289
|
+
data.expires_in || 3600
|
|
290
|
+
)
|
|
291
|
+
logger.debug('Refresh token also updated')
|
|
309
292
|
}
|
|
310
293
|
} catch (fetchError) {
|
|
311
294
|
console.warn(
|
|
312
295
|
chalk.yellow(
|
|
313
296
|
`Failed to refresh token: ${
|
|
314
|
-
fetchError instanceof Error
|
|
297
|
+
fetchError instanceof Error
|
|
298
|
+
? fetchError.message
|
|
299
|
+
: String(fetchError)
|
|
315
300
|
}`
|
|
316
301
|
)
|
|
317
302
|
)
|
|
318
303
|
return false
|
|
319
304
|
}
|
|
320
|
-
|
|
305
|
+
|
|
321
306
|
return true
|
|
322
307
|
} catch (error) {
|
|
323
308
|
console.warn(
|