Publish twenty-cli npm package (#14871)

as title
This commit is contained in:
martmull
2025-10-03 15:08:06 +02:00
committed by GitHub
parent 0648dc5c65
commit f973a1bcdb
14 changed files with 235 additions and 45 deletions
@@ -0,0 +1,54 @@
import inquirer from 'inquirer';
import chalk from 'chalk';
import { ApiService } from '../services/api.service';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { loadManifest } from '../utils/app-manifest-loader';
export class AppDeleteCommand {
private apiService = new ApiService();
async execute(): Promise<void> {
try {
const appPath = CURRENT_EXECUTION_DIRECTORY;
console.log(chalk.blue('🚀 Deleting Twenty Application'));
console.log(chalk.gray(`📁 App Path: ${appPath}`));
console.log('');
if (!(await this.confirmationPrompt())) {
console.error(chalk.red('⛔️ Aborting deletion'));
process.exit(1);
}
const { packageJson } = await loadManifest(appPath);
const result = await this.apiService.deleteApplication(packageJson);
if (!result.success) {
console.error(chalk.red('❌ Deletion failed:'), result.error);
process.exit(1);
}
console.log(chalk.green('✅ Application deleted successfully'));
} catch (error) {
console.error(
chalk.red('Deletion failed:'),
error instanceof Error ? error.message : error,
);
process.exit(1);
}
}
private async confirmationPrompt(): Promise<boolean> {
const { confirmation } = await inquirer.prompt([
{
type: 'confirm',
name: 'confirmation',
message: 'Are you sure you want to delete this application?',
default: false,
},
]);
return confirmation;
}
}
@@ -1,8 +1,8 @@
import chalk from 'chalk';
import * as chokidar from 'chokidar';
import { ApiService } from '../services/api.service';
import { syncApp } from '../utils/app-sync';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { loadManifest } from '../utils/app-manifest-loader';
export class AppDevCommand {
private apiService = new ApiService();
@@ -15,7 +15,13 @@ export class AppDevCommand {
this.logStartupInfo(appPath, debounceMs);
await syncApp(appPath, this.apiService);
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
await this.apiService.syncApplication({
manifest,
packageJson,
yarnLock,
});
const watcher = this.setupFileWatcher(appPath, debounceMs);
@@ -54,7 +60,15 @@ export class AppDevCommand {
timeout = setTimeout(async () => {
console.log(chalk.blue('🔄 Changes detected, syncing...'));
await syncApp(appPath, this.apiService);
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
await this.apiService.syncApplication({
manifest,
packageJson,
yarnLock,
});
console.log(
chalk.gray('👀 Watching for changes... (Press Ctrl+C to stop)'),
);
@@ -1,7 +1,7 @@
import chalk from 'chalk';
import { ApiService } from '../services/api.service';
import { syncApp } from '../utils/app-sync';
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
import { loadManifest } from '../utils/app-manifest-loader';
export class AppSyncCommand {
private apiService = new ApiService();
@@ -14,7 +14,13 @@ export class AppSyncCommand {
console.log(chalk.gray(`📁 App Path: ${appPath}`));
console.log('');
const result = await syncApp(appPath, this.apiService);
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
const result = await this.apiService.syncApplication({
manifest,
packageJson,
yarnLock,
});
if (!result.success) {
console.error(chalk.red('❌ Sync failed:'), result.error);
@@ -2,6 +2,7 @@ import { Command } from 'commander';
import { AppSyncCommand } from './app-sync.command';
import { AppDevCommand } from './app-dev.command';
import { AppInitCommand } from './app-init.command';
import { AppDeleteCommand } from './app-delete.command';
import {
AppAddCommand,
isSyncableEntity,
@@ -12,6 +13,7 @@ import chalk from 'chalk';
export class AppCommand {
private devCommand = new AppDevCommand();
private syncCommand = new AppSyncCommand();
private deleteCommand = new AppDeleteCommand();
private initCommand = new AppInitCommand();
private addCommand = new AppAddCommand();
@@ -34,6 +36,13 @@ export class AppCommand {
await this.syncCommand.execute();
});
appCommand
.command('delete')
.description('Delete application from Twenty')
.action(async () => {
await this.deleteCommand.execute();
});
appCommand
.command('init [directory]')
.description('Initialize a new Twenty application')
@@ -72,7 +72,6 @@ export class ApiService {
headers: {
'Content-Type': 'application/json',
Accept: '*/*',
'x-schema-version': '6',
},
},
);
@@ -115,7 +114,6 @@ export class ApiService {
headers: {
'Content-Type': 'application/json',
Accept: '*/*',
'x-schema-version': '6',
},
},
);
@@ -143,4 +141,52 @@ export class ApiService {
throw error;
}
}
async deleteApplication(packageJson: PackageJson): Promise<ApiResponse> {
try {
const mutation = `
mutation DeleteApplication($packageJson: JSON!) {
deleteApplication(packageJson: $packageJson)
}
`;
const variables = { packageJson };
const response: AxiosResponse = await this.client.post(
'/metadata',
{
query: mutation,
variables,
},
{
headers: {
'Content-Type': 'application/json',
Accept: '*/*',
},
},
);
if (response.data.errors) {
return {
success: false,
error:
response.data.errors[0]?.message || 'Failed to delete application',
};
}
return {
success: true,
data: response.data.data.deleteApplication,
message: `Successfully deleted application: ${packageJson.name}`,
};
} catch (error) {
if (axios.isAxiosError(error) && error.response) {
return {
success: false,
error: error.response.data?.errors?.[0]?.message || error.message,
};
}
throw error;
}
}
}
-32
View File
@@ -1,32 +0,0 @@
import chalk from 'chalk';
import { ApiService } from '../services/api.service';
import { loadManifest } from './app-manifest-loader';
export const syncApp = async (
appPath: string,
apiService: ApiService,
): Promise<any> => {
const { manifest, packageJson, yarnLock } = await loadManifest(appPath);
try {
const result = await apiService.syncApplication({
manifest,
packageJson,
yarnLock,
});
if (result.success) {
console.log(chalk.green('✅ Application synced successfully'));
} else {
console.error(chalk.red('❌ Sync failed:'), result.error);
}
return result;
} catch (error) {
console.error(
chalk.red('Sync error:'),
error instanceof Error ? error.message : error,
);
throw error;
}
};