mirror of
https://github.com/twentyhq/twenty
synced 2026-04-21 21:47:38 +00:00
# Introduction Important note: for the moment testing this locally will require some hack due to latest twenty-sdk not being published. You will need to build twenty-cli and `cd packages/twenty-cli && yarn link` To finally sync the app in your app folder as `cd app-folder && twenty app sync` close https://github.com/twentyhq/core-team-issues/issues/1863 In this PR is introduced the generate sdk programmatic call to [genql](https://genql.dev/) exposed in a `client` barrel of `twenty-sdk` located in this package as there's high chances that will add a codegen layer above it at some point ? The cli calls this method after a sync application and writes a client in a generated folder. It will make a graql introspection query on the whole workspace. We should later improve that and only filter by current applicationId and its dependencies ( when twenty-standard application is introduced ) Fully typesafe ( input, output, filters etc ) auto-completed client ## Hello-world app serverless refactor <img width="2480" height="1326" alt="image" src="https://github.com/user-attachments/assets/b18ea372-b21d-4560-8fbc-1dc348427a95" /> --------- Co-authored-by: martmull <martmull@hotmail.fr>
86 lines
2.2 KiB
TypeScript
86 lines
2.2 KiB
TypeScript
import chalk from 'chalk';
|
|
import * as chokidar from 'chokidar';
|
|
import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory';
|
|
import { AppSyncCommand } from './app-sync.command';
|
|
|
|
export class AppDevCommand {
|
|
private syncCommand = new AppSyncCommand();
|
|
|
|
async execute(options: {
|
|
appPath?: string;
|
|
debounce: string;
|
|
}): Promise<void> {
|
|
try {
|
|
const appPath = options.appPath ?? CURRENT_EXECUTION_DIRECTORY;
|
|
|
|
const debounceMs = parseInt(options.debounce, 10);
|
|
|
|
this.logStartupInfo(appPath, debounceMs);
|
|
|
|
await this.syncCommand.execute(appPath);
|
|
|
|
const watcher = this.setupFileWatcher(appPath, debounceMs);
|
|
|
|
this.setupGracefulShutdown(watcher);
|
|
} catch (error) {
|
|
console.error(
|
|
chalk.red('Development mode failed:'),
|
|
error instanceof Error ? error.message : error,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
private logStartupInfo(appPath: string, debounceMs: number): void {
|
|
console.log(chalk.blue('🚀 Starting Twenty Application Development Mode'));
|
|
console.log(chalk.gray(`📁 App Path: ${appPath}`));
|
|
console.log(chalk.gray(`⏱️ Debounce: ${debounceMs}ms`));
|
|
console.log('');
|
|
}
|
|
|
|
private setupFileWatcher(
|
|
appPath: string,
|
|
debounceMs: number,
|
|
): chokidar.FSWatcher {
|
|
const watcher = chokidar.watch(appPath, {
|
|
ignored: /node_modules|\.git/,
|
|
persistent: true,
|
|
});
|
|
|
|
let timeout: NodeJS.Timeout | null = null;
|
|
|
|
const debouncedSync = () => {
|
|
if (timeout) {
|
|
clearTimeout(timeout);
|
|
}
|
|
|
|
timeout = setTimeout(async () => {
|
|
console.log(chalk.blue('🔄 Changes detected, syncing...'));
|
|
|
|
await this.syncCommand.execute(appPath);
|
|
|
|
console.log(
|
|
chalk.gray('👀 Watching for changes... (Press Ctrl+C to stop)'),
|
|
);
|
|
}, debounceMs);
|
|
};
|
|
|
|
watcher.on('change', () => {
|
|
debouncedSync();
|
|
});
|
|
|
|
console.log(
|
|
chalk.gray('👀 Watching for changes... (Press Ctrl+C to stop)'),
|
|
);
|
|
|
|
return watcher;
|
|
}
|
|
|
|
private setupGracefulShutdown(watcher: chokidar.FSWatcher): void {
|
|
process.on('SIGINT', () => {
|
|
console.log(chalk.yellow('\n🛑 Stopping development mode...'));
|
|
watcher.close();
|
|
process.exit(0);
|
|
});
|
|
}
|
|
}
|