Files
twenty/packages/twenty-sdk/src/cli/commands/logic-function/logic-function-execute.ts
T
martmullandGitHub 53c314d0fa 2094 extensibility define postinstall orand preinstall function to run in application (#18037)
- add a new optional key `postInstallLogicFunctionUniversalIdentifier`
in applicationConfig
- seed postInstall function in create-twenty-app
- update execute:function options
- update doc
2026-02-18 15:38:22 +00:00

181 lines
5.4 KiB
TypeScript

import { ApiService } from '@/cli/utilities/api/api-service';
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory';
import chalk from 'chalk';
import { type Manifest } from 'twenty-shared/application';
import { isDefined } from 'twenty-shared/utils';
import { readManifestFromFile } from '@/cli/utilities/build/manifest/manifest-reader';
export class LogicFunctionExecuteCommand {
private apiService = new ApiService();
async execute({
appPath = CURRENT_EXECUTION_DIRECTORY,
postInstall = false,
functionUniversalIdentifier,
functionName,
payload = '{}',
}: {
appPath?: string;
postInstall?: boolean;
functionUniversalIdentifier?: string;
functionName?: string;
payload?: string;
}): Promise<void> {
try {
let parsedPayload: Record<string, unknown>;
try {
parsedPayload = JSON.parse(payload);
} catch {
console.error(
chalk.red('Invalid JSON payload. Please provide valid JSON.'),
);
process.exit(1);
}
const manifest = await readManifestFromFile(appPath);
if (!manifest) {
console.error(chalk.red('Failed to build manifest.'));
process.exit(1);
}
const functionsResult = await this.apiService.findLogicFunctions();
if (!functionsResult.success) {
console.error(
chalk.red('Failed to fetch functions:'),
functionsResult.error instanceof Error
? functionsResult.error.message
: functionsResult.error,
);
process.exit(1);
}
const appFunctions = functionsResult.data.filter(
(fn) =>
fn.universalIdentifier && this.belongsToApplication(fn, manifest),
);
const targetFunction = appFunctions.find((fn) => {
if (postInstall) {
return (
fn.universalIdentifier ===
manifest.application.postInstallLogicFunctionUniversalIdentifier
);
}
if (functionUniversalIdentifier) {
return fn.universalIdentifier === functionUniversalIdentifier;
}
if (functionName) {
return fn.name === functionName;
}
return false;
});
if (!targetFunction) {
const identifier = postInstall
? 'post install'
: functionUniversalIdentifier || functionName;
console.error(
chalk.red(`Function "${identifier}" not found in application.`),
);
console.log('');
if (appFunctions.length > 0) {
console.log(chalk.cyan('Available functions:'));
appFunctions.forEach((fn) => {
console.log(
` - ${chalk.white(fn.name)} (${fn.universalIdentifier})`,
);
});
} else {
console.log(
chalk.yellow(
'No functions found for this application. Have you synced your app with `yarn app:dev`?',
),
);
}
process.exit(1);
}
console.log(
chalk.blue(`🚀 Executing function "${targetFunction.name}"...`),
);
console.log(chalk.gray(` Payload: ${JSON.stringify(parsedPayload)}`));
console.log('');
const result = await this.apiService.executeLogicFunction({
functionId: targetFunction.id,
payload: parsedPayload,
});
if (!result.success) {
console.error(
chalk.red('Execution failed:'),
result.error instanceof Error ? result.error.message : result.error,
);
process.exit(1);
}
const executionResult = result.data!;
console.log(chalk.cyan('─'.repeat(60)));
console.log(chalk.cyan('Execution Result'));
console.log(chalk.cyan('─'.repeat(60)));
const statusColor =
executionResult.status === 'SUCCESS' ? chalk.green : chalk.red;
console.log(
`${chalk.bold('Status:')} ${statusColor(executionResult.status)}`,
);
console.log(`${chalk.bold('Duration:')} ${executionResult.duration}ms`);
if (isDefined(executionResult.data)) {
console.log('');
console.log(chalk.bold('Data:'));
console.log(chalk.white(JSON.stringify(executionResult.data, null, 2)));
}
if (executionResult.error) {
console.log('');
console.log(chalk.bold.red('Error:'));
console.log(chalk.red(` Type: ${executionResult.error.errorType}`));
console.log(
chalk.red(` Message: ${executionResult.error.errorMessage}`),
);
if (executionResult.error.stackTrace) {
console.log('');
console.log(chalk.gray('Stack trace:'));
console.log(chalk.gray(executionResult.error.stackTrace));
}
}
if (executionResult.logs) {
console.log('');
console.log(chalk.bold('Logs:'));
console.log(chalk.gray(executionResult.logs));
}
console.log(chalk.cyan('─'.repeat(60)));
if (executionResult.status !== 'SUCCESS') {
process.exit(1);
}
} catch (error) {
console.error(
chalk.red('Execution failed:'),
error instanceof Error ? error.message : error,
);
process.exit(1);
}
}
private belongsToApplication(
fn: { universalIdentifier: string; applicationId: string | null },
manifest: Manifest,
): boolean {
return manifest.logicFunctions.some(
(manifestFn) => manifestFn.universalIdentifier === fn.universalIdentifier,
);
}
}