buildx-cli 1.0.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.
@@ -0,0 +1,75 @@
1
+ import { Command } from 'commander';
2
+ import inquirer from 'inquirer';
3
+ import chalk from 'chalk';
4
+ import { configManager } from '../../config/index';
5
+
6
+ export const setupCommand = new Command('setup')
7
+ .description('Configure API endpoint and API key')
8
+ .option('-e, --endpoint <endpoint>', 'API endpoint URL')
9
+ .option('-k, --api-key <apiKey>', 'API key')
10
+ .action(async (options) => {
11
+ try {
12
+ let endpoint = options.endpoint;
13
+ let apiKey = options.apiKey;
14
+
15
+ // If not provided via options, prompt interactively
16
+ if (!endpoint || !apiKey) {
17
+ console.log(chalk.blue('šŸ”§ BuildX CLI Setup'));
18
+ console.log(chalk.gray('Configure your API endpoint and API key to get started.\n'));
19
+
20
+ const currentConfig = configManager.getApiConfig();
21
+
22
+ const answers = await inquirer.prompt([
23
+ {
24
+ type: 'input',
25
+ name: 'endpoint',
26
+ message: 'Enter your API endpoint URL:',
27
+ default: currentConfig?.endpoint || 'https://api.buildx.com',
28
+ validate: (input: string) => {
29
+ if (!input.trim()) {
30
+ return 'Endpoint URL is required';
31
+ }
32
+ try {
33
+ new URL(input);
34
+ return true;
35
+ } catch {
36
+ return 'Please enter a valid URL';
37
+ }
38
+ }
39
+ },
40
+ {
41
+ type: 'password',
42
+ name: 'apiKey',
43
+ message: 'Enter your API key:',
44
+ default: currentConfig?.apiKey || '',
45
+ validate: (input: string) => {
46
+ if (!input.trim()) {
47
+ return 'API key is required';
48
+ }
49
+ return true;
50
+ }
51
+ }
52
+ ]);
53
+
54
+ endpoint = answers.endpoint;
55
+ apiKey = answers.apiKey;
56
+ }
57
+
58
+ // Save the configuration
59
+ configManager.setApiConfig({
60
+ endpoint: endpoint.trim(),
61
+ apiKey: apiKey.trim()
62
+ });
63
+
64
+ console.log(chalk.green('āœ… Configuration saved successfully!'));
65
+ console.log(chalk.gray(`Endpoint: ${endpoint}`));
66
+ console.log(chalk.gray(`API Key: ${'*'.repeat(Math.min(apiKey.length, 8))}...`));
67
+ console.log(chalk.blue('\nYou can now use the CLI commands. Start with:'));
68
+ console.log(chalk.cyan(' buildx login'));
69
+ console.log(chalk.cyan(' buildx projects:list'));
70
+
71
+ } catch (error) {
72
+ console.error(chalk.red('āŒ Setup failed:'), error instanceof Error ? error.message : 'Unknown error');
73
+ process.exit(1);
74
+ }
75
+ });
@@ -0,0 +1,70 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { configManager } from '../../config/index';
4
+
5
+ export const configShowCommand = new Command('show')
6
+ .description('Show current configuration')
7
+ .action(() => {
8
+ try {
9
+ const apiConfig = configManager.getApiConfig();
10
+ const authConfig = configManager.getAuth();
11
+ const projectsConfig = configManager.getProjects();
12
+ const syncConfig = configManager.getSyncConfig();
13
+
14
+ console.log(chalk.blue('šŸ”§ BuildX CLI Configuration'));
15
+ console.log(chalk.gray('='.repeat(50)));
16
+
17
+ // API Configuration
18
+ console.log(chalk.yellow('\nšŸ“” API Configuration:'));
19
+ if (apiConfig) {
20
+ console.log(chalk.green(' āœ… Configured'));
21
+ console.log(chalk.gray(` Endpoint: ${apiConfig.endpoint}`));
22
+ console.log(chalk.gray(` API Key: ${'*'.repeat(Math.min(apiConfig.apiKey.length, 8))}...`));
23
+ } else {
24
+ console.log(chalk.red(' āŒ Not configured'));
25
+ console.log(chalk.gray(' Run "buildx setup" to configure'));
26
+ }
27
+
28
+ // Authentication
29
+ console.log(chalk.yellow('\nšŸ” Authentication:'));
30
+ if (authConfig && configManager.isAuthenticated()) {
31
+ console.log(chalk.green(' āœ… Authenticated'));
32
+ console.log(chalk.gray(` Token: ${authConfig.token.substring(0, 20)}...`));
33
+ if (authConfig.expiresAt) {
34
+ console.log(chalk.gray(` Expires: ${new Date(authConfig.expiresAt).toLocaleString()}`));
35
+ }
36
+ } else {
37
+ console.log(chalk.red(' āŒ Not authenticated'));
38
+ console.log(chalk.gray(' Run "buildx login" to authenticate'));
39
+ }
40
+
41
+ // Projects
42
+ console.log(chalk.yellow('\nšŸ“ Projects:'));
43
+ if (projectsConfig?.list && projectsConfig.list.length > 0) {
44
+ console.log(chalk.green(` āœ… ${projectsConfig.list.length} project(s) available`));
45
+ if (projectsConfig.default) {
46
+ const defaultProject = projectsConfig.list.find(p => p.id === projectsConfig.default);
47
+ console.log(chalk.gray(` Default: ${defaultProject?.name || projectsConfig.default}`));
48
+ }
49
+ } else {
50
+ console.log(chalk.red(' āŒ No projects available'));
51
+ console.log(chalk.gray(' Run "buildx projects:list" to fetch projects'));
52
+ }
53
+
54
+ // Sync Configuration
55
+ console.log(chalk.yellow('\nšŸ”„ Sync Configuration:'));
56
+ if (syncConfig) {
57
+ console.log(chalk.gray(` Output Path: ${syncConfig.outputPath}`));
58
+ } else {
59
+ console.log(chalk.gray(' Using default sync configuration'));
60
+ }
61
+
62
+ // Configuration file location
63
+ console.log(chalk.yellow('\nšŸ“‚ Configuration File:'));
64
+ console.log(chalk.gray(` ${configManager.getConfigPath()}`));
65
+
66
+ } catch (error) {
67
+ console.error(chalk.red('āŒ Failed to show configuration:'), error instanceof Error ? error.message : 'Unknown error');
68
+ process.exit(1);
69
+ }
70
+ });
@@ -0,0 +1,36 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { configManager } from '../../config/index';
4
+
5
+ export const projectsCurrentCommand = new Command('projects:current')
6
+ .description('Show current default project')
7
+ .action(() => {
8
+ try {
9
+ const defaultProjectId = configManager.getDefaultProject();
10
+
11
+ if (!defaultProjectId) {
12
+ console.log(chalk.yellow('No default project set'));
13
+ console.log(chalk.blue('Use "buildx projects:set-default <project-id>" to set a default project'));
14
+ return;
15
+ }
16
+
17
+ const project = configManager.getProject(defaultProjectId);
18
+
19
+ if (!project) {
20
+ console.log(chalk.red('Error: Default project not found in configuration'));
21
+ console.log(chalk.blue('Project ID:'), defaultProjectId);
22
+ return;
23
+ }
24
+
25
+ console.log(chalk.green('Current default project:'));
26
+ console.log(chalk.blue('Name:'), project.name);
27
+ console.log(chalk.blue('ID:'), project.id);
28
+ if (project.apiUrl) {
29
+ console.log(chalk.blue('API URL:'), project.apiUrl);
30
+ }
31
+
32
+ } catch (error) {
33
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
34
+ process.exit(1);
35
+ }
36
+ });
@@ -0,0 +1,61 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import { configManager } from '../../config/index';
5
+ import { apiService } from '../../services/api';
6
+
7
+ export const projectsListCommand = new Command('projects:list')
8
+ .description('List available projects')
9
+ .action(async () => {
10
+ try {
11
+ // Check API configuration
12
+ if (!apiService.isConfigured()) {
13
+ console.error(chalk.red('āŒ API not configured'));
14
+ console.log(chalk.yellow('Please configure your API endpoint and API key first:'));
15
+ console.log(chalk.cyan(' buildx config setup'));
16
+ process.exit(1);
17
+ }
18
+ // Check authentication
19
+ if (!configManager.isAuthenticated()) {
20
+ console.error(chalk.red('Error: Not authenticated'));
21
+ console.log(chalk.yellow('Run "buildx login" to authenticate first'));
22
+ process.exit(1);
23
+ }
24
+
25
+ const spinner = ora('Fetching projects...').start();
26
+
27
+ try {
28
+ const projects = await apiService.getProjects();
29
+ spinner.succeed(`Found ${projects.length} projects`);
30
+
31
+ if (projects.length === 0) {
32
+ console.log(chalk.yellow('No projects found'));
33
+ return;
34
+ }
35
+
36
+ const defaultProject = configManager.getDefaultProject();
37
+
38
+ console.log('\n' + chalk.blue.bold('Available Projects:'));
39
+ projects.forEach(project => {
40
+ const isDefault = project.id === defaultProject;
41
+ const prefix = isDefault ? chalk.green('ā˜… ') : ' ';
42
+ console.log(`${prefix}${chalk.bold(project.name)} (${project.id})`);
43
+ if (project.apiUrl) {
44
+ console.log(` API: ${chalk.gray(project.apiUrl)}`);
45
+ }
46
+ });
47
+
48
+ if (defaultProject) {
49
+ console.log(chalk.green('\nā˜… Default project'));
50
+ }
51
+
52
+ } catch (error) {
53
+ spinner.fail('Failed to fetch projects');
54
+ throw error;
55
+ }
56
+
57
+ } catch (error) {
58
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
59
+ process.exit(1);
60
+ }
61
+ });
@@ -0,0 +1,33 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { configManager } from '../../config/index';
4
+
5
+ export const projectsSetDefaultCommand = new Command('projects:set-default')
6
+ .description('Set default project')
7
+ .argument('<project-id>', 'Project ID to set as default')
8
+ .action(async (projectId: string) => {
9
+ try {
10
+ // Check authentication
11
+ if (!configManager.isAuthenticated()) {
12
+ console.error(chalk.red('Error: Not authenticated'));
13
+ console.log(chalk.yellow('Run "buildx login" to authenticate first'));
14
+ process.exit(1);
15
+ }
16
+
17
+ // Check if project exists in config
18
+ const project = configManager.getProject(projectId);
19
+ if (!project) {
20
+ console.error(chalk.red('Error: Project not found in configuration'));
21
+ console.log(chalk.yellow('Run "buildx projects:list" to see available projects'));
22
+ process.exit(1);
23
+ }
24
+
25
+ configManager.setDefaultProject(projectId);
26
+ console.log(chalk.green('āœ“ Default project set to:'), project.name);
27
+ console.log(chalk.blue('Project ID:'), projectId);
28
+
29
+ } catch (error) {
30
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : 'Unknown error');
31
+ process.exit(1);
32
+ }
33
+ });
@@ -0,0 +1,64 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import fs from "fs-extra";
5
+ import path from "path";
6
+ import { configManager } from "../config/index";
7
+ import { apiService } from "../services/api";
8
+
9
+ export const syncCommand = new Command("sync")
10
+ .description("Sync schema and generate TypeScript types")
11
+ .requiredOption("-p, --project-id <project-id>", "Project ID to sync schema from")
12
+ .option("-o, --output <path>", "Output path for generated types", "./generated/types.ts")
13
+ .option("-u, --api-url <url>", "Custom API base URL")
14
+ .option("-f, --force", "Force overwrite existing files")
15
+ .action(async (options) => {
16
+ try {
17
+ // Check API configuration
18
+ if (!apiService.isConfigured()) {
19
+ console.error(chalk.red('āŒ API not configured'));
20
+ console.log(chalk.yellow('Please configure your API endpoint and API key first:'));
21
+ console.log(chalk.cyan(' buildx config setup'));
22
+ process.exit(1);
23
+ }
24
+ // Check authentication
25
+ if (!configManager.isAuthenticated()) {
26
+ console.error(chalk.red("Error: Not authenticated"));
27
+ console.log(chalk.yellow("Run \"buildx login\" to authenticate first"));
28
+ process.exit(1);
29
+ }
30
+
31
+ const { projectId, output, apiUrl, force } = options;
32
+
33
+ // Set custom API URL if provided
34
+ if (apiUrl) {
35
+ apiService.setBaseUrl(apiUrl);
36
+ }
37
+
38
+ // Fetch schema
39
+ const spinner = ora("Fetching TypeScript types...").start();
40
+
41
+ try {
42
+ const typescriptCode = await apiService.getSchema(projectId);
43
+ spinner.succeed("TypeScript types fetched successfully");
44
+
45
+ // Ensure output directory exists
46
+ const outputDir = path.dirname(output);
47
+ await fs.ensureDir(outputDir);
48
+
49
+ // Write the TypeScript code directly to file
50
+ await fs.writeFile(output, typescriptCode, "utf8");
51
+
52
+ console.log(chalk.green("āœ“ Types generated at:"), output);
53
+ console.log(chalk.blue("File size:"), `${(typescriptCode.length / 1024).toFixed(2)} KB`);
54
+
55
+ } catch (error) {
56
+ spinner.fail("Failed to fetch TypeScript types");
57
+ throw error;
58
+ }
59
+
60
+ } catch (error) {
61
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
62
+ process.exit(1);
63
+ }
64
+ });
@@ -0,0 +1,154 @@
1
+ import Conf from "conf";
2
+ import { GlobalConfig, AuthConfig, ProjectsConfig, SyncConfig, ApiConfig } from "../types/index";
3
+
4
+ export class ConfigManager {
5
+ private config: Conf<GlobalConfig>;
6
+
7
+ constructor() {
8
+ this.config = new Conf<GlobalConfig>({
9
+ projectName: "buildx-cli",
10
+ schema: {
11
+ api: {
12
+ type: "object",
13
+ properties: {
14
+ endpoint: { type: "string" },
15
+ apiKey: { type: "string" }
16
+ }
17
+ },
18
+ auth: {
19
+ type: "object",
20
+ properties: {
21
+ token: { type: "string" },
22
+ expiresAt: { type: "string" }
23
+ }
24
+ },
25
+ projects: {
26
+ type: "object",
27
+ properties: {
28
+ default: { type: "string" },
29
+ list: { type: "array" }
30
+ }
31
+ },
32
+ sync: {
33
+ type: "object",
34
+ properties: {
35
+ outputPath: { type: "string" }
36
+ }
37
+ }
38
+ },
39
+ defaults: {
40
+ sync: {
41
+ outputPath: "./generated/types.ts"
42
+ }
43
+ }
44
+ });
45
+ }
46
+
47
+ // API configuration methods
48
+ getApiConfig(): ApiConfig | undefined {
49
+ return this.config.get("api");
50
+ }
51
+
52
+ setApiConfig(api: ApiConfig): void {
53
+ this.config.set("api", api);
54
+ }
55
+
56
+ clearApiConfig(): void {
57
+ this.config.delete("api");
58
+ }
59
+
60
+ isApiConfigured(): boolean {
61
+ const api = this.getApiConfig();
62
+ return !!(api?.endpoint && api?.apiKey);
63
+ }
64
+
65
+ // Auth methods
66
+ getAuth(): AuthConfig | undefined {
67
+ return this.config.get("auth");
68
+ }
69
+
70
+ setAuth(auth: AuthConfig): void {
71
+ this.config.set("auth", auth);
72
+ }
73
+
74
+ clearAuth(): void {
75
+ this.config.delete("auth");
76
+ }
77
+
78
+ isAuthenticated(): boolean {
79
+ const auth = this.getAuth();
80
+ if (!auth || !auth.token) {
81
+ return false;
82
+ }
83
+
84
+ // Check if token is expired
85
+ if (auth.expiresAt) {
86
+ const expiresAt = new Date(auth.expiresAt);
87
+ if (expiresAt < new Date()) {
88
+ this.clearAuth();
89
+ return false;
90
+ }
91
+ }
92
+
93
+ return true;
94
+ }
95
+
96
+ // Projects methods
97
+ getProjects(): ProjectsConfig | undefined {
98
+ return this.config.get("projects");
99
+ }
100
+
101
+ setProjects(projects: ProjectsConfig): void {
102
+ this.config.set("projects", projects);
103
+ }
104
+
105
+ getDefaultProject(): string | undefined {
106
+ const projects = this.getProjects();
107
+ return projects?.default;
108
+ }
109
+
110
+ setDefaultProject(projectId: string): void {
111
+ const projects = this.getProjects() || { list: [] };
112
+ projects.default = projectId;
113
+ this.setProjects(projects);
114
+ }
115
+
116
+ addProject(project: { id: string; name: string; apiUrl?: string }): void {
117
+ const projects = this.getProjects() || { list: [] };
118
+ const existingIndex = projects.list.findIndex(p => p.id === project.id);
119
+
120
+ if (existingIndex >= 0) {
121
+ projects.list[existingIndex] = project;
122
+ } else {
123
+ projects.list.push(project);
124
+ }
125
+
126
+ this.setProjects(projects);
127
+ }
128
+
129
+ getProject(projectId: string): { id: string; name: string; apiUrl?: string } | undefined {
130
+ const projects = this.getProjects();
131
+ return projects?.list.find(p => p.id === projectId);
132
+ }
133
+
134
+ // Sync methods
135
+ getSyncConfig(): SyncConfig | undefined {
136
+ return this.config.get("sync");
137
+ }
138
+
139
+ setSyncConfig(sync: SyncConfig): void {
140
+ this.config.set("sync", sync);
141
+ }
142
+
143
+ // Utility methods
144
+ getConfigPath(): string {
145
+ return this.config.path;
146
+ }
147
+
148
+ clear(): void {
149
+ this.config.clear();
150
+ }
151
+ }
152
+
153
+ // Export singleton instance
154
+ export const configManager = new ConfigManager();
package/src/index.ts ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import fs from 'fs';
6
+
7
+ // Import commands
8
+ import { loginCommand } from './commands/auth/login';
9
+ import { logoutCommand } from './commands/auth/logout';
10
+ import { authStatusCommand } from './commands/auth/status';
11
+ import { syncCommand } from './commands/sync';
12
+ import { projectsListCommand } from './commands/projects/list';
13
+ import { projectsSetDefaultCommand } from './commands/projects/set-default';
14
+ import { projectsCurrentCommand } from './commands/projects/current';
15
+ import { configCommand } from './commands/config/index';
16
+
17
+ const program = new Command();
18
+ const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
19
+ const version = packageJson.version;
20
+
21
+ // Set up the CLI
22
+ program
23
+ .name('buildx')
24
+ .description('BuildX CLI - API authentication and schema synchronization tool')
25
+ .version(version, '-v, --version');
26
+
27
+ // Add commands
28
+ program.addCommand(loginCommand);
29
+ program.addCommand(logoutCommand);
30
+ program.addCommand(authStatusCommand);
31
+ program.addCommand(syncCommand);
32
+ program.addCommand(projectsListCommand);
33
+ program.addCommand(projectsSetDefaultCommand);
34
+ program.addCommand(projectsCurrentCommand);
35
+ program.addCommand(configCommand);
36
+
37
+ // Global error handler
38
+ program.exitOverride();
39
+
40
+ try {
41
+ program.parse();
42
+ } catch (err) {
43
+ if (err instanceof Error) {
44
+ console.error(chalk.red('Error:'), err.message);
45
+ } else {
46
+ console.error(chalk.red('An unexpected error occurred'));
47
+ }
48
+ process.exit(1);
49
+ }
@@ -0,0 +1,132 @@
1
+ import axios, { AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig } from "axios";
2
+ import { configManager } from "../config/index";
3
+ import { ApiResponse, LoginCredentials, LoginResponse } from "../types/index";
4
+
5
+ export class ApiService {
6
+ private client: AxiosInstance;
7
+
8
+ constructor() {
9
+ this.client = axios.create({
10
+ timeout: 30000,
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ "User-Agent": "buildx-cli/1.0.0"
14
+ }
15
+ });
16
+
17
+ // Add request interceptor to include auth token and API key
18
+ this.client.interceptors.request.use((config: InternalAxiosRequestConfig) => {
19
+ // Ensure client is initialized with current config before each request
20
+ this.initializeClient();
21
+
22
+ // Add API key from configuration
23
+ const apiConfig = configManager.getApiConfig();
24
+ if (apiConfig?.apiKey) {
25
+ config.headers["X-API-Key"] = apiConfig.apiKey;
26
+ }
27
+
28
+ // Add auth token
29
+ const auth = configManager.getAuth();
30
+ if (auth?.token) {
31
+ config.headers.Authorization = `Bearer ${auth.token}`;
32
+ }
33
+ return config;
34
+ });
35
+
36
+ // Add response interceptor for error handling
37
+ this.client.interceptors.response.use(
38
+ (response) => response,
39
+ (error: any) => {
40
+ if (error.response?.status === 401) {
41
+ configManager.clearAuth();
42
+ throw new Error("Authentication failed. Please login again.");
43
+ }
44
+ throw error;
45
+ }
46
+ );
47
+ }
48
+
49
+ private initializeClient(): void {
50
+ const apiConfig = configManager.getApiConfig();
51
+ if (apiConfig?.endpoint) {
52
+ this.client.defaults.baseURL = apiConfig.endpoint;
53
+ console.log(`Debug: Setting base URL to ${apiConfig.endpoint}`);
54
+ } else {
55
+ throw new Error("API endpoint not configured. Please run 'buildx config setup' first.");
56
+ }
57
+ }
58
+
59
+ private async request<T>(config: AxiosRequestConfig): Promise<ApiResponse<T>> {
60
+ // Always set baseURL from config before making the request
61
+ const apiConfig = configManager.getApiConfig();
62
+ if (!apiConfig?.endpoint) {
63
+ throw new Error("API endpoint not configured. Please run 'buildx config setup' first.");
64
+ }
65
+ config.baseURL = apiConfig.endpoint;
66
+ try {
67
+ const response = await this.client.request(config);
68
+ return {
69
+ data: response.data,
70
+ status: response.status,
71
+ message: response.statusText
72
+ };
73
+ } catch (error: any) {
74
+ if (error.response) {
75
+ throw new Error(`API Error: ${error.response.status} - ${error.response.data?.message || error.response.statusText}`);
76
+ } else if (error.request) {
77
+ throw new Error("Network error: Unable to connect to the API");
78
+ } else {
79
+ throw new Error(`Request error: ${error.message}`);
80
+ }
81
+ }
82
+ }
83
+
84
+ async login(credentials: LoginCredentials): Promise<LoginResponse> {
85
+ const response = await this.request<LoginResponse>({
86
+ method: "POST",
87
+ url: "/auth/login",
88
+ data: credentials
89
+ });
90
+ return response.data;
91
+ }
92
+
93
+ async getProjects(): Promise<{ id: string; name: string; apiUrl?: string }[]> {
94
+ const response = await this.request<{ projects: { id: string; name: string; apiUrl?: string }[] }>({
95
+ method: "GET",
96
+ url: "/projects"
97
+ });
98
+ return response.data.projects;
99
+ }
100
+
101
+ async getSchema(projectId: string): Promise<string> {
102
+ const response = await this.request<string>({
103
+ method: "GET",
104
+ url: `/project/${projectId}/collections/schema`
105
+ });
106
+
107
+ return response.data;
108
+ }
109
+
110
+ async getMe(): Promise<{ username: string;[key: string]: any }> {
111
+ const response = await this.request<{ username: string;[key: string]: any }>({
112
+ method: "GET",
113
+ url: "/auth/me"
114
+ });
115
+ return response.data;
116
+ }
117
+
118
+ setBaseUrl(baseUrl: string): void {
119
+ this.client.defaults.baseURL = baseUrl;
120
+ }
121
+
122
+ getBaseUrl(): string {
123
+ return this.client.defaults.baseURL || '';
124
+ }
125
+
126
+ isConfigured(): boolean {
127
+ return configManager.isApiConfigured();
128
+ }
129
+ }
130
+
131
+ // Export singleton instance
132
+ export const apiService = new ApiService();