@nestbox-ai/cli 1.0.48 → 1.0.49

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.
Files changed (100) hide show
  1. package/package.json +7 -1
  2. package/.github/workflows/generate-client.yml +0 -43
  3. package/.github/workflows/test.yml +0 -54
  4. package/.nestboxrc +0 -5
  5. package/src/commands/agent/apiUtils.ts +0 -113
  6. package/src/commands/agent/create.ts +0 -271
  7. package/src/commands/agent/deploy.ts +0 -523
  8. package/src/commands/agent/index.ts +0 -8
  9. package/src/commands/agent/list.ts +0 -104
  10. package/src/commands/agent/remove.ts +0 -103
  11. package/src/commands/agent/yaml-schema.ts +0 -57
  12. package/src/commands/agent.ts +0 -21
  13. package/src/commands/auth/index.ts +0 -3
  14. package/src/commands/auth/login.ts +0 -184
  15. package/src/commands/auth/logout.ts +0 -110
  16. package/src/commands/auth.ts +0 -12
  17. package/src/commands/compute/apiUtils.ts +0 -28
  18. package/src/commands/compute/create.ts +0 -195
  19. package/src/commands/compute/delete.ts +0 -147
  20. package/src/commands/compute/index.ts +0 -7
  21. package/src/commands/compute/list.ts +0 -117
  22. package/src/commands/compute.ts +0 -19
  23. package/src/commands/document/apiUtils.ts +0 -22
  24. package/src/commands/document/collectionCreate.ts +0 -46
  25. package/src/commands/document/collectionDelete.ts +0 -45
  26. package/src/commands/document/collectionGet.ts +0 -47
  27. package/src/commands/document/collectionList.ts +0 -52
  28. package/src/commands/document/collectionUpdate.ts +0 -53
  29. package/src/commands/document/docAdd.ts +0 -56
  30. package/src/commands/document/docDelete.ts +0 -47
  31. package/src/commands/document/docGet.ts +0 -49
  32. package/src/commands/document/docSearch.ts +0 -70
  33. package/src/commands/document/docUpdate.ts +0 -56
  34. package/src/commands/document/docUploadFile.ts +0 -55
  35. package/src/commands/document/index.ts +0 -17
  36. package/src/commands/document.ts +0 -48
  37. package/src/commands/generate/project.ts +0 -199
  38. package/src/commands/generate.ts +0 -15
  39. package/src/commands/image/apiUtils.ts +0 -22
  40. package/src/commands/image/display.ts +0 -34
  41. package/src/commands/image/index.ts +0 -4
  42. package/src/commands/image/list.ts +0 -61
  43. package/src/commands/image.ts +0 -15
  44. package/src/commands/project/add.ts +0 -47
  45. package/src/commands/project/apiUtils.ts +0 -20
  46. package/src/commands/project/index.ts +0 -5
  47. package/src/commands/project/list.ts +0 -78
  48. package/src/commands/project/use.ts +0 -45
  49. package/src/commands/project.ts +0 -19
  50. package/src/index.ts +0 -39
  51. package/src/types/agentType.ts +0 -7
  52. package/src/types/agentYaml.ts +0 -107
  53. package/src/types/auth.ts +0 -12
  54. package/src/types/statusMapping.ts +0 -8
  55. package/src/utils/agent.ts +0 -170
  56. package/src/utils/api.ts +0 -64
  57. package/src/utils/auth.ts +0 -140
  58. package/src/utils/config.ts +0 -37
  59. package/src/utils/error.ts +0 -168
  60. package/src/utils/plopGenerator.ts +0 -133
  61. package/src/utils/project.ts +0 -88
  62. package/src/utils/user.ts +0 -28
  63. package/src/utils/validation.ts +0 -22
  64. package/templates/base-js/index.js.hbs +0 -30
  65. package/templates/base-js/nestbox-agents.yaml.hbs +0 -12
  66. package/templates/base-js/package.json +0 -15
  67. package/templates/base-py/main.py.hbs +0 -42
  68. package/templates/base-py/nestbox-agents.yaml.hbs +0 -12
  69. package/templates/base-py/pyproject.toml +0 -19
  70. package/templates/base-ts/eslint.config.mjs +0 -27
  71. package/templates/base-ts/nestbox-agents.yaml.hbs +0 -12
  72. package/templates/base-ts/nestbox.config.json +0 -9
  73. package/templates/base-ts/package.json +0 -24
  74. package/templates/base-ts/src/index.ts.hbs +0 -29
  75. package/templates/base-ts/tsconfig.json +0 -14
  76. package/templates/chatbot-js/index.js.hbs +0 -18
  77. package/templates/chatbot-js/package-lock.json +0 -1571
  78. package/templates/chatbot-js/package.json +0 -15
  79. package/templates/chatbot-py/main.py.hbs +0 -42
  80. package/templates/chatbot-py/nestbox-agents.yaml.hbs +0 -12
  81. package/templates/chatbot-py/pyproject.toml +0 -19
  82. package/templates/chatbot-ts/eslint.config.mjs +0 -27
  83. package/templates/chatbot-ts/package.json +0 -24
  84. package/templates/chatbot-ts/src/index.ts.hbs +0 -18
  85. package/templates/chatbot-ts/tsconfig.json +0 -14
  86. package/test/README.md +0 -52
  87. package/test/agent.test.ts +0 -154
  88. package/test/auth.test.ts +0 -71
  89. package/test/compute.test.ts +0 -135
  90. package/test/document.test.ts +0 -217
  91. package/test/generate.test.ts +0 -67
  92. package/test/image.test.ts +0 -107
  93. package/test/mocks.ts +0 -122
  94. package/test/project.test.ts +0 -108
  95. package/test/setup.ts +0 -121
  96. package/tsconfig.json +0 -118
  97. package/vitest.config.d.ts +0 -2
  98. package/vitest.config.js +0 -23
  99. package/vitest.config.js.map +0 -1
  100. package/vitest.config.ts +0 -21
@@ -1,107 +0,0 @@
1
- /**
2
- * Type definition for Agent YAML configuration file
3
- */
4
-
5
- /**
6
- * Represents a parameter for an agent in the YAML configuration
7
- */
8
- export interface AgentParameter {
9
- /**
10
- * Name of the parameter
11
- */
12
- name: string;
13
-
14
- /**
15
- * Description of the parameter
16
- */
17
- description: string;
18
-
19
- /**
20
- * Default value for the parameter
21
- */
22
- default?: any;
23
-
24
- /**
25
- * Default value as a string (used internally)
26
- */
27
- default_value?: string;
28
-
29
- /**
30
- * Whether this parameter is configurable by users
31
- * @default true
32
- */
33
- isUserParam?: boolean;
34
- }
35
-
36
- /**
37
- * Represents a single agent definition in the YAML configuration
38
- */
39
- export interface AgentDefinition {
40
- /**
41
- * Name of the agent (required)
42
- */
43
- name: string;
44
-
45
- /**
46
- * Description of the agent's purpose
47
- * @default `AI agent for ${name}`
48
- */
49
- goal?: string;
50
-
51
- /**
52
- * Agent type ("CHAT" or "AGENT")
53
- * CHAT creates a chatbot, AGENT creates a regular agent
54
- * @default "CHAT"
55
- */
56
- type?: string;
57
-
58
- /**
59
- * Machine manifest ID for the agent
60
- * @default "llamaindex-agent"
61
- */
62
- machineManifestId?: string;
63
-
64
- /**
65
- * Instance IP address
66
- * @default "http://34.121.124.21"
67
- */
68
- instanceIP?: string;
69
-
70
- /**
71
- * Name of the machine
72
- * @default "agent-instance"
73
- */
74
- machineName?: string;
75
-
76
- /**
77
- * Machine instance ID
78
- * @default 17
79
- */
80
- machineInstanceId?: number;
81
-
82
- /**
83
- * Name of the instance
84
- */
85
- instanceName?: string;
86
-
87
- /**
88
- * Model base ID
89
- * @default ""
90
- */
91
- modelBaseId?: string;
92
-
93
- /**
94
- * Agent parameters
95
- */
96
- parameters?: AgentParameter[];
97
- }
98
-
99
- /**
100
- * Overall structure of the YAML configuration file
101
- */
102
- export interface AgentYamlConfig {
103
- /**
104
- * Array of agent definitions
105
- */
106
- agents: AgentDefinition[];
107
- }
package/src/types/auth.ts DELETED
@@ -1,12 +0,0 @@
1
- // types/auth.ts
2
-
3
- export interface UserCredentials {
4
- domain: string;
5
- email: string;
6
- token: string;
7
- accessToken: string; // Google OAuth token
8
- apiServerUrl: string;
9
- name?: string;
10
- picture?: string;
11
- timestamp: string;
12
- }
@@ -1,8 +0,0 @@
1
- // Export status mappings for potential future use
2
- export const statusMappings: Record<string, string> = {
3
- 'Job Scheduled': 'Scheduled',
4
- 'Job Executed': 'Ready',
5
- 'Job in Progress': 'Initializing',
6
- 'Job Failed': 'Failed',
7
- 'Deleting': 'Deleting',
8
- };
@@ -1,170 +0,0 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import chalk from "chalk";
4
- import ora from "ora";
5
- import { promisify } from "util";
6
- import { exec } from "child_process";
7
- import AdmZip from "adm-zip";
8
- import * as os from "os";
9
- import axios from "axios";
10
-
11
- const execAsync = promisify(exec);
12
-
13
- export async function findProjectRoot(startDir = process.cwd()) {
14
- let currentDir = startDir;
15
-
16
- while (currentDir !== path.parse(currentDir).root) {
17
- const nestboxConfigPath = path.join(currentDir, "nestbox.config.json");
18
- const packageJsonPath = path.join(currentDir, "package.json");
19
-
20
- if (
21
- fs.existsSync(nestboxConfigPath) ||
22
- fs.existsSync(packageJsonPath)
23
- ) {
24
- return currentDir;
25
- }
26
-
27
- currentDir = path.dirname(currentDir);
28
- }
29
-
30
- return startDir; // Fallback to current directory if no root markers found
31
- }
32
-
33
- // Function to load and parse nestbox.config.json if it exists
34
- export function loadNestboxConfig(projectRoot: any) {
35
- const configPath = path.join(projectRoot, "nestbox.config.json");
36
-
37
- if (fs.existsSync(configPath)) {
38
- try {
39
- const configContent = fs.readFileSync(configPath, "utf8");
40
- return JSON.parse(configContent);
41
- } catch (error: any) {
42
- console.warn(
43
- chalk.yellow(
44
- `Warning: Error parsing nestbox.config.json: ${error.message}`
45
- )
46
- );
47
- }
48
- }
49
-
50
- return null;
51
- }
52
-
53
- // Function to detect if a directory contains TypeScript files
54
- export function isTypeScriptProject(directoryPath: any) {
55
- // Check for tsconfig.json
56
- if (fs.existsSync(path.join(directoryPath, "tsconfig.json"))) {
57
- return true;
58
- }
59
-
60
- // Check for .ts files
61
- try {
62
- const files = fs.readdirSync(directoryPath);
63
- return files.some(
64
- file => file.endsWith(".ts") || file.endsWith(".tsx")
65
- );
66
- } catch (error) {
67
- return false;
68
- }
69
- }
70
-
71
- export async function runPredeployScripts(scripts: any, projectRoot: any) {
72
- if (!scripts || !Array.isArray(scripts) || scripts.length === 0) {
73
- return;
74
- }
75
-
76
- const spinner = ora("Running predeploy scripts...").start();
77
-
78
- try {
79
- for (const script of scripts) {
80
- spinner.text = `Running: ${script}`;
81
-
82
- // Make sure we're running in the correct directory
83
- await execAsync(script, {
84
- cwd: projectRoot,
85
- });
86
- }
87
- spinner.succeed("Predeploy scripts completed successfully");
88
- } catch (error: any) {
89
- spinner.fail(`Predeploy script failed: ${error.message}`);
90
- throw new Error(`Predeploy failed: ${error.message}`);
91
- }
92
- }
93
-
94
- export function createZipFromDirectory(
95
- dirPath: any,
96
- excludePatterns = ["node_modules"]
97
- ) {
98
- const dirName = path.basename(dirPath);
99
- const timestamp = Date.now();
100
-
101
- // Create zip in temp directory
102
- const tempZipFilePath = path.join(
103
- os.tmpdir(),
104
- `${dirName}_${timestamp}.zip`
105
- );
106
-
107
- const zip = new AdmZip();
108
-
109
- // Function to recursively add files to zip
110
- function addFilesToZip(currentPath: any, relativePath = "") {
111
- const items = fs.readdirSync(currentPath);
112
-
113
- for (const item of items) {
114
- const itemPath = path.join(currentPath, item);
115
- const itemRelativePath = path.join(relativePath, item);
116
-
117
- // Check if item should be excluded
118
- if (
119
- excludePatterns.some((pattern: any) =>
120
- typeof pattern === "string"
121
- ? itemRelativePath === pattern || item === pattern
122
- : pattern.test(itemRelativePath)
123
- )
124
- ) {
125
- continue;
126
- }
127
-
128
- const stats = fs.statSync(itemPath);
129
-
130
- if (stats.isDirectory()) {
131
- addFilesToZip(itemPath, itemRelativePath);
132
- } else {
133
- zip.addLocalFile(itemPath, path.dirname(itemRelativePath));
134
- }
135
- }
136
- }
137
-
138
- addFilesToZip(dirPath);
139
-
140
- // Write zip to temp directory (for upload)
141
- zip.writeZip(tempZipFilePath);
142
-
143
- // Return the temp path for upload
144
- return tempZipFilePath;
145
- }
146
-
147
- export interface TemplateInfo {
148
- name: string;
149
- description: string;
150
- fileId: string;
151
- lang: string;
152
- type: string;
153
- }
154
-
155
- export function createNestboxConfig(
156
- projectPath: string,
157
- isTypeScript: boolean
158
- ): void {
159
- if (!isTypeScript) return;
160
-
161
- const configPath = path.join(projectPath, "nestbox.config.json");
162
- const config = {
163
- agents: {
164
- predeploy: ["rm -rf dist", "npm run lint", "npm run build"],
165
- },
166
- };
167
-
168
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
169
- console.log(chalk.green(`Created nestbox.config.json at ${configPath}`));
170
- }
package/src/utils/api.ts DELETED
@@ -1,64 +0,0 @@
1
- import chalk from "chalk";
2
- import { Configuration } from "@nestbox-ai/admin";
3
- import { getAuthToken } from "./auth";
4
-
5
- export interface AuthResult {
6
- authToken: {
7
- token: string;
8
- serverUrl: string;
9
- accessToken?: string;
10
- };
11
- configuration: Configuration;
12
- }
13
-
14
- /**
15
- * Common authentication and configuration setup
16
- * Returns authentication token and configured API client
17
- * Exits the process if authentication fails
18
- */
19
- export function setupAuthAndConfig(): AuthResult | null {
20
- const authToken = getAuthToken();
21
-
22
- if (!authToken) {
23
- console.error(chalk.red('No authentication token found. Please login first.'));
24
- return null;
25
- }
26
-
27
- const configuration = new Configuration({
28
- basePath: authToken.serverUrl,
29
- baseOptions: {
30
- headers: {
31
- "Authorization": authToken.token,
32
- }
33
- }
34
- });
35
-
36
- return {
37
- authToken,
38
- configuration
39
- };
40
- }
41
-
42
- /**
43
- * Wrapper function that ensures authentication is set up before executing a callback
44
- * Automatically handles authentication errors and provides configured API instances
45
- */
46
- export async function withAuth<T>(
47
- callback: (authResult: AuthResult) => Promise<T>
48
- ): Promise<T | void> {
49
- const authResult = setupAuthAndConfig();
50
-
51
- if (!authResult) {
52
- return;
53
- }
54
-
55
- try {
56
- return await callback(authResult);
57
- } catch (error: any) {
58
- if (error.response && error.response.status === 401) {
59
- console.error(chalk.red('Authentication token has expired. Please login again using "nestbox login <domain>".'));
60
- } else {
61
- throw error; // Re-throw non-auth errors
62
- }
63
- }
64
- }
package/src/utils/auth.ts DELETED
@@ -1,140 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import os from 'os';
4
- import chalk from 'chalk';
5
- import { UserCredentials } from '../types/auth';
6
-
7
- // Config path
8
- const CONFIG_DIR = path.join(os.homedir(), '.config', '.nestbox');
9
-
10
- // Ensure config directory exists
11
- if (!fs.existsSync(CONFIG_DIR)) {
12
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
13
- }
14
-
15
- /**
16
- * Get authentication token for a specific domain
17
- */
18
- export function getAuthToken(domain?: string): {token: string, serverUrl: string, accessToken?: string} | null {
19
- try {
20
- const files = fs.readdirSync(CONFIG_DIR);
21
-
22
- if (!domain) {
23
- // If no domain is provided, return the first token found
24
- const tokenFiles = files.filter(file => file.endsWith('.json'));
25
- if (tokenFiles.length === 0) {
26
- return null;
27
- }
28
-
29
- const configData = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, tokenFiles[0])).toString());
30
- return {
31
- token: configData.token,
32
- serverUrl: configData.apiServerUrl,
33
- accessToken: configData.accessToken,
34
- };
35
- }
36
- const domainFiles = files.filter(file => file.endsWith(`_${domain}.json`));
37
-
38
- if (domainFiles.length === 0) {
39
- return null;
40
- }
41
-
42
- // If multiple accounts, sort by last used and take the most recent
43
- let configData: UserCredentials;
44
-
45
- if (domainFiles.length > 1) {
46
- const allConfigs = domainFiles.map(file => {
47
- const data = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, file)).toString()) as UserCredentials;
48
- return {
49
- file,
50
- data,
51
- };
52
- });
53
-
54
- // Sort by last used, most recent first
55
- configData = allConfigs[0].data;
56
- } else {
57
- // Just one file
58
- const configFile = domainFiles[0];
59
- configData = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, configFile)).toString());
60
- }
61
-
62
- return {
63
- token: configData.token,
64
- serverUrl: configData.apiServerUrl,
65
- accessToken: configData.accessToken,
66
- }
67
- } catch (error) {
68
- console.error('Error getting auth token:', error);
69
- return null;
70
- }
71
- }
72
-
73
- /**
74
- * List all saved credentials
75
- */
76
- export function listCredentials(): Array<{
77
- domain: string;
78
- email: string;
79
- name?: string;
80
- authMethod?: string;
81
- lastUsed?: number;
82
- }> {
83
- try {
84
- const files = fs.readdirSync(CONFIG_DIR);
85
- return files.map(file => {
86
- try {
87
- const data = JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, file)).toString()) as UserCredentials;
88
- return {
89
- domain: data.domain,
90
- email: data.email,
91
- name: data.name,
92
- };
93
- } catch (error) {
94
- // Skip invalid files
95
- return null;
96
- }
97
- }).filter(Boolean) as Array<{
98
- domain: string;
99
- email: string;
100
- name?: string;
101
- authMethod?: string;
102
- lastUsed?: number;
103
- }>;
104
- } catch (error) {
105
- console.error('Error listing credentials:', error);
106
- return [];
107
- }
108
- }
109
-
110
- /**
111
- * Remove credentials for a domain/email combination
112
- */
113
- export function removeCredentials(domain: string, email?: string): boolean {
114
- try {
115
- const files = fs.readdirSync(CONFIG_DIR);
116
- let domainFiles: string[];
117
-
118
- if (email) {
119
- // Remove specific email for domain
120
- const emailFile = email.replace('@', '_at_');
121
- domainFiles = files.filter(file => file === `${emailFile}_${domain}.json`);
122
- } else {
123
- // Remove all for domain
124
- domainFiles = files.filter(file => file.endsWith(`_${domain}.json`));
125
- }
126
-
127
- if (domainFiles.length === 0) {
128
- return false;
129
- }
130
-
131
- domainFiles.forEach(file => {
132
- fs.unlinkSync(path.join(CONFIG_DIR, file));
133
- });
134
-
135
- return true;
136
- } catch (error) {
137
- console.error('Error removing credentials:', error);
138
- return false;
139
- }
140
- }
@@ -1,37 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- // Define a type for the projects configuration
5
- interface ProjectsConfig {
6
- default?: string;
7
- [key: string]: string | undefined;
8
- }
9
-
10
- interface NestboxConfig {
11
- projects: ProjectsConfig;
12
- }
13
-
14
- // Utility functions for project configuration
15
- export function getNestboxConfigPath(): string {
16
- return path.join(process.cwd(), '.nestboxrc');
17
- }
18
-
19
- export function readNestboxConfig(): NestboxConfig {
20
- const configPath = getNestboxConfigPath();
21
- if (fs.existsSync(configPath)) {
22
- try {
23
- const content = fs.readFileSync(configPath, 'utf8');
24
- return JSON.parse(content);
25
- } catch (error) {
26
- return { projects: {} };
27
- }
28
- }
29
- return { projects: {} };
30
- }
31
-
32
- export function writeNestboxConfig(config: NestboxConfig): void {
33
- const configPath = getNestboxConfigPath();
34
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
35
- }
36
-
37
- export type { ProjectsConfig, NestboxConfig };
@@ -1,168 +0,0 @@
1
- // utils/error.ts
2
- import { AuthApi, Configuration, OAuthLoginRequestDTOTypeEnum } from '@nestbox-ai/admin';
3
- import { getAuthToken } from './auth';
4
- import fs from 'fs';
5
- import path from 'path';
6
- import os from 'os';
7
- import chalk from 'chalk';
8
-
9
- interface TokenRefreshResult {
10
- success: boolean;
11
- newToken?: string;
12
- error?: string;
13
- }
14
-
15
- /**
16
- * Attempts to refresh the authentication token using stored credentials
17
- */
18
- async function refreshAuthToken(serverUrl: string, accessToken: string): Promise<TokenRefreshResult> {
19
- try {
20
- // Get the stored credentials to extract user info
21
- const configDir = path.join(os.homedir(), '.config', '.nestbox');
22
- const files = fs.readdirSync(configDir);
23
-
24
- // Find the credential file that matches this server URL
25
- let userCredentials: any = null;
26
- for (const file of files) {
27
- try {
28
- const data = JSON.parse(fs.readFileSync(path.join(configDir, file), 'utf8'));
29
- if (data.apiServerUrl === serverUrl && data.accessToken === accessToken) {
30
- userCredentials = data;
31
- break;
32
- }
33
- } catch (e) {
34
- // Skip invalid files
35
- }
36
- }
37
-
38
- if (!userCredentials) {
39
- return { success: false, error: 'Could not find stored credentials' };
40
- }
41
-
42
- // Create new configuration with the access token
43
- const configuration = new Configuration({
44
- basePath: serverUrl,
45
- accessToken: accessToken,
46
- });
47
-
48
- const authApi = new AuthApi(configuration);
49
-
50
- // Try to re-authenticate using the stored Google OAuth token
51
- const response = await authApi.authControllerOAuthLogin({
52
- providerId: accessToken,
53
- type: OAuthLoginRequestDTOTypeEnum.Google,
54
- email: userCredentials.email,
55
- profilePictureUrl: userCredentials.picture || '',
56
- });
57
-
58
- const newToken = response.data.token;
59
-
60
- // Update the stored credentials with the new token
61
- const fileName = `${userCredentials.email.replace('@', '_at_')}_${userCredentials.domain}.json`;
62
- const filePath = path.join(configDir, fileName);
63
-
64
- userCredentials.token = newToken;
65
- userCredentials.timestamp = new Date().toISOString();
66
-
67
- fs.writeFileSync(filePath, JSON.stringify(userCredentials, null, 2));
68
-
69
- return { success: true, newToken };
70
- } catch (error: any) {
71
- console.error(chalk.yellow('Token refresh failed:'), error.message);
72
- return { success: false, error: error.message };
73
- }
74
- }
75
-
76
- /**
77
- * Enhanced 401 error handler with automatic token refresh
78
- */
79
- export async function handle401Error(error: any, retryCallback?: () => Promise<any>): Promise<any> {
80
- if (error.response && error.response.status === 401) {
81
- // Get current auth token info
82
- const authInfo = getAuthToken();
83
-
84
- if (!authInfo || !authInfo.accessToken) {
85
- throw new Error('Authentication token has expired. Please login again using "nestbox login <domain>".');
86
- }
87
-
88
- console.log(chalk.yellow('Authentication token expired. Attempting to refresh...'));
89
-
90
- // Try to refresh the token
91
- const refreshResult = await refreshAuthToken(authInfo.serverUrl, authInfo.accessToken);
92
-
93
- if (refreshResult.success && retryCallback) {
94
- console.log(chalk.green('Token refreshed successfully. Retrying request...'));
95
-
96
- try {
97
- // Retry the original request with the new token
98
- const result = await retryCallback();
99
- return { success: true, data: result };
100
- } catch (retryError: any) {
101
- // If retry also fails with 401, the refresh didn't work properly
102
- if (retryError.response && retryError.response.status === 401) {
103
- throw new Error('Authentication failed after token refresh. Please login again using "nestbox login <domain>".');
104
- }
105
- // Re-throw other errors
106
- throw retryError;
107
- }
108
- } else {
109
- // Refresh failed
110
- throw new Error('Authentication token has expired and automatic refresh failed. Please login again using "nestbox login <domain>".');
111
- }
112
- }
113
-
114
- return null;
115
- }
116
-
117
- /**
118
- * Wrapper function to make API calls with automatic retry on 401
119
- */
120
- export async function withTokenRefresh<T>(
121
- apiCall: () => Promise<T>,
122
- onRetry?: () => void
123
- ): Promise<T> {
124
- try {
125
- return await apiCall();
126
- } catch (error: any) {
127
- if (error.response && error.response.status === 401) {
128
- // Get current auth token info
129
- const authInfo = getAuthToken();
130
-
131
- if (!authInfo || !authInfo.accessToken) {
132
- throw new Error('Authentication token has expired. Please login again using "nestbox login <domain>".');
133
- }
134
-
135
- console.log(chalk.yellow('Authentication token expired. Attempting to refresh...'));
136
-
137
- // Try to refresh the token
138
- const refreshResult = await refreshAuthToken(authInfo.serverUrl, authInfo.accessToken);
139
-
140
- if (refreshResult.success) {
141
- console.log(chalk.green('Token refreshed successfully. Retrying request...'));
142
-
143
- // If onRetry callback is provided, call it to reinitialize API clients
144
- if (onRetry) {
145
- onRetry();
146
- }
147
-
148
- try {
149
- // Retry the original API call
150
- return await apiCall();
151
- } catch (retryError: any) {
152
- // If retry also fails with 401, the refresh didn't work properly
153
- if (retryError.response && retryError.response.status === 401) {
154
- throw new Error('Authentication failed after token refresh. Please login again using "nestbox login <domain>".');
155
- }
156
- // Re-throw other errors
157
- throw retryError;
158
- }
159
- } else {
160
- // Refresh failed
161
- throw new Error('Authentication token has expired and automatic refresh failed. Please login again using "nestbox login <domain>".');
162
- }
163
- }
164
-
165
- // If not a 401 error, re-throw
166
- throw error;
167
- }
168
- }