buildx-cli 1.0.0 → 1.0.2

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.
@@ -1,64 +0,0 @@
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
- });
@@ -1,154 +0,0 @@
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 DELETED
@@ -1,49 +0,0 @@
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
- }
@@ -1,132 +0,0 @@
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();
@@ -1,132 +0,0 @@
1
- import fs from "fs-extra";
2
- import path from "path";
3
- import { SchemaResponse, SchemaCollection, SchemaField } from "../types/index";
4
-
5
- export class SchemaGenerator {
6
- private generateFieldType(field: SchemaField): string {
7
- const baseType = this.mapFieldTypeToTypeScript(field.type);
8
- return field.required ? baseType : `${baseType} | null`;
9
- }
10
-
11
- private mapFieldTypeToTypeScript(apiType: string): string {
12
- const typeMap: Record<string, string> = {
13
- "string": "string",
14
- "text": "string",
15
- "number": "number",
16
- "integer": "number",
17
- "float": "number",
18
- "boolean": "boolean",
19
- "date": "string",
20
- "datetime": "string",
21
- "timestamp": "string",
22
- "json": "Record<string, any>",
23
- "array": "any[]",
24
- "object": "Record<string, any>",
25
- "email": "string",
26
- "url": "string",
27
- "uuid": "string",
28
- "id": "string"
29
- };
30
-
31
- return typeMap[apiType.toLowerCase()] || "any";
32
- }
33
-
34
- private generateCollectionInterface(collection: SchemaCollection): string {
35
- const interfaceName = this.toPascalCase(collection.name);
36
- const fields = collection.fields.map(field => {
37
- const fieldType = this.generateFieldType(field);
38
- const optional = field.required ? "" : "?";
39
- const comment = field.description ? `\n /** ${field.description} */` : "";
40
- return `${comment}\n ${field.name}${optional}: ${fieldType};`;
41
- }).join("\n");
42
-
43
- const description = collection.description ? `\n/** ${collection.description} */` : "";
44
-
45
- return `${description}
46
- export interface ${interfaceName} {
47
- ${fields}
48
- }`;
49
- }
50
-
51
- private toPascalCase(str: string): string {
52
- return str
53
- .split(/[-_\s]+/)
54
- .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
55
- .join("");
56
- }
57
-
58
- private generateIndexExports(collections: SchemaCollection[]): string {
59
- const exports = collections.map(collection => {
60
- const interfaceName = this.toPascalCase(collection.name);
61
- return `export type { ${interfaceName} } from './${collection.name}';`;
62
- }).join("\n");
63
-
64
- return exports;
65
- }
66
-
67
- private generateCollectionFile(collection: SchemaCollection): string {
68
- const interfaceContent = this.generateCollectionInterface(collection);
69
- return `// Generated by BuildX CLI
70
- // Collection: ${collection.name}
71
- // Generated at: ${new Date().toISOString()}
72
-
73
- ${interfaceContent}
74
- `;
75
- }
76
-
77
- async generateTypes(schema: SchemaResponse, outputPath: string): Promise<void> {
78
- const outputDir = path.dirname(outputPath);
79
- const baseName = path.basename(outputPath, path.extname(outputPath));
80
- const outputDirPath = path.join(outputDir, baseName);
81
-
82
- // Ensure output directory exists
83
- await fs.ensureDir(outputDirPath);
84
-
85
- // Generate individual collection files
86
- for (const collection of schema.collections) {
87
- const collectionFileName = `${collection.name}.ts`;
88
- const collectionFilePath = path.join(outputDirPath, collectionFileName);
89
- const collectionContent = this.generateCollectionFile(collection);
90
-
91
- await fs.writeFile(collectionFilePath, collectionContent, "utf8");
92
- }
93
-
94
- // Generate index file
95
- const indexContent = `// Generated by BuildX CLI
96
- // Schema version: ${schema.version}
97
- // Generated at: ${schema.generatedAt}
98
-
99
- ${this.generateIndexExports(schema.collections)}
100
-
101
- // Re-export all types for convenience
102
- export * from './${schema.collections[0]?.name || "index"}';
103
- `;
104
-
105
- const indexFilePath = path.join(outputDirPath, "index.ts");
106
- await fs.writeFile(indexFilePath, indexContent, "utf8");
107
-
108
- // Generate main types file
109
- const mainContent = `// Generated by BuildX CLI
110
- // Schema version: ${schema.version}
111
- // Generated at: ${schema.generatedAt}
112
-
113
- ${schema.collections.map(collection => this.generateCollectionInterface(collection)).join("\n\n")}
114
-
115
- // Export all collection types
116
- ${schema.collections.map(collection => {
117
- const interfaceName = this.toPascalCase(collection.name);
118
- return `export type { ${interfaceName} };`;
119
- }).join("\n")}
120
- `;
121
-
122
- await fs.writeFile(outputPath, mainContent, "utf8");
123
- }
124
-
125
- async generateTypesToFile(schema: SchemaResponse, outputPath: string): Promise<string> {
126
- await this.generateTypes(schema, outputPath);
127
- return outputPath;
128
- }
129
- }
130
-
131
- // Export singleton instance
132
- export const schemaGenerator = new SchemaGenerator();
@@ -1,91 +0,0 @@
1
- export interface AuthConfig {
2
- token: string;
3
- expiresAt?: string;
4
- username?: string;
5
- }
6
-
7
- export interface LoginCredentials {
8
- username: string;
9
- password: string;
10
- }
11
-
12
- export interface LoginResponse {
13
- token: string;
14
- expiresAt?: string;
15
- user?: {
16
- id: string;
17
- username: string;
18
- email?: string;
19
- };
20
- }
21
-
22
- export interface ApiConfig {
23
- endpoint: string;
24
- apiKey: string;
25
- }
26
-
27
- export interface Project {
28
- id: string;
29
- name: string;
30
- apiUrl?: string;
31
- }
32
-
33
- export interface ProjectsConfig {
34
- default?: string;
35
- list: Project[];
36
- }
37
-
38
- export interface SyncConfig {
39
- outputPath: string;
40
- }
41
-
42
- export interface GlobalConfig {
43
- api?: ApiConfig;
44
- auth?: AuthConfig;
45
- projects?: ProjectsConfig;
46
- sync?: SyncConfig;
47
- }
48
-
49
- export interface ApiResponse<T = any> {
50
- data: T;
51
- status: number;
52
- message?: string;
53
- }
54
-
55
- export interface SchemaField {
56
- name: string;
57
- type: string;
58
- required?: boolean;
59
- description?: string;
60
- defaultValue?: any;
61
- }
62
-
63
- export interface SchemaCollection {
64
- name: string;
65
- fields: SchemaField[];
66
- description?: string;
67
- }
68
-
69
- export interface SchemaResponse {
70
- collections: SchemaCollection[];
71
- version: string;
72
- generatedAt: string;
73
- }
74
-
75
- export interface LoginOptions {
76
- token?: string;
77
- username?: string;
78
- password?: string;
79
- interactive?: boolean;
80
- }
81
-
82
- export interface SyncOptions {
83
- projectId: string;
84
- output?: string;
85
- apiUrl?: string;
86
- force?: boolean;
87
- }
88
-
89
- export interface ProjectOptions {
90
- projectId: string;
91
- }
@@ -1,29 +0,0 @@
1
- import chalk from "chalk";
2
-
3
- export class Logger {
4
- static info(message: string): void {
5
- console.log(chalk.blue("ℹ"), message);
6
- }
7
-
8
- static success(message: string): void {
9
- console.log(chalk.green("✓"), message);
10
- }
11
-
12
- static warning(message: string): void {
13
- console.log(chalk.yellow("⚠"), message);
14
- }
15
-
16
- static error(message: string): void {
17
- console.error(chalk.red("✗"), message);
18
- }
19
-
20
- static debug(message: string): void {
21
- if (process.env.DEBUG) {
22
- console.log(chalk.gray("🐛"), message);
23
- }
24
- }
25
-
26
- static log(message: string): void {
27
- console.log(message);
28
- }
29
- }
package/tsconfig.json DELETED
@@ -1,29 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "lib": ["ES2020"],
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "declaration": true,
13
- "declarationMap": true,
14
- "sourceMap": true,
15
- "resolveJsonModule": true,
16
- "moduleResolution": "node",
17
- "allowSyntheticDefaultImports": true,
18
- "experimentalDecorators": true,
19
- "emitDecoratorMetadata": true
20
- },
21
- "include": [
22
- "src/**/*"
23
- ],
24
- "exclude": [
25
- "node_modules",
26
- "dist",
27
- "**/*.test.ts"
28
- ]
29
- }
File without changes