Fix app:dev CLI by removing deleted createOneApplication mutation (#18460)
## Summary - The `createOneApplication` GraphQL mutation was removed from the server during the application architecture refactor (#18432), but the SDK CLI (`app:dev`, `app:build --sync`) still called it, causing failures. - Simplified the SDK to use `syncApplication` (which now internally creates the `ApplicationEntity` via `ensureApplicationExists`) instead of a separate create step. - On first run (clean install), the orchestrator now runs an initial sync before initializing the file uploader, so file uploads can proceed (they require the `ApplicationEntity` to exist). ## Test plan - [x] Typecheck passes for both `twenty-sdk` and `twenty-server` - [x] `app:dev` tested locally with existing app (finds app, uploads, syncs) - [x] `app:dev` tested locally after `app:uninstall` (creates app via sync, uploads, syncs) - [x] SDK unit tests pass (23/26 files, 3 pre-existing failures unrelated) Made with [Cursor](https://cursor.com)
This commit is contained in:
+4
-2
@@ -1,7 +1,6 @@
|
||||
import { type EntityFilePaths } from '@/cli/utilities/build/manifest/manifest-extract-config';
|
||||
import { type BuildManifestOrchestratorStepOutput } from '@/cli/utilities/dev/orchestrator/steps/build-manifest-orchestrator-step';
|
||||
import { type CheckServerOrchestratorStepOutput } from '@/cli/utilities/dev/orchestrator/steps/check-server-orchestrator-step';
|
||||
import { type ResolveApplicationOrchestratorStepOutput } from '@/cli/utilities/dev/orchestrator/steps/resolve-application-orchestrator-step';
|
||||
import { type StartWatchersOrchestratorStepOutput } from '@/cli/utilities/dev/orchestrator/steps/start-watchers-orchestrator-step';
|
||||
import { type SyncApplicationOrchestratorStepOutput } from '@/cli/utilities/dev/orchestrator/steps/sync-application-orchestrator-step';
|
||||
import { type UploadFilesOrchestratorStepOutput } from '@/cli/utilities/dev/orchestrator/steps/upload-files-orchestrator-step';
|
||||
@@ -96,7 +95,10 @@ export class OrchestratorState {
|
||||
steps: {
|
||||
checkServer: OrchestratorStepState<CheckServerOrchestratorStepOutput>;
|
||||
ensureValidTokens: OrchestratorStepState<Record<string, never>>;
|
||||
resolveApplication: OrchestratorStepState<ResolveApplicationOrchestratorStepOutput>;
|
||||
resolveApplication: OrchestratorStepState<{
|
||||
applicationId: string | null;
|
||||
universalIdentifier: string | null;
|
||||
}>;
|
||||
buildManifest: OrchestratorStepState<BuildManifestOrchestratorStepOutput>;
|
||||
uploadFiles: OrchestratorStepState<UploadFilesOrchestratorStepOutput>;
|
||||
generateApiClient: OrchestratorStepState<Record<string, never>>;
|
||||
|
||||
@@ -7,7 +7,6 @@ import { CheckServerOrchestratorStep } from '@/cli/utilities/dev/orchestrator/st
|
||||
import { EnsureValidTokensOrchestratorStep } from '@/cli/utilities/dev/orchestrator/steps/ensure-valid-tokens-orchestrator-step';
|
||||
import { GenerateApiClientOrchestratorStep } from '@/cli/utilities/dev/orchestrator/steps/generate-api-client-orchestrator-step';
|
||||
import { RegisterAppOrchestratorStep } from '@/cli/utilities/dev/orchestrator/steps/register-app-orchestrator-step';
|
||||
import { ResolveApplicationOrchestratorStep } from '@/cli/utilities/dev/orchestrator/steps/resolve-application-orchestrator-step';
|
||||
import {
|
||||
StartWatchersOrchestratorStep,
|
||||
type FileBuiltEvent,
|
||||
@@ -30,13 +29,13 @@ export class DevModeOrchestrator {
|
||||
private syncTimer: NodeJS.Timeout | null = null;
|
||||
private serverCheckInterval: NodeJS.Timeout | null = null;
|
||||
|
||||
private apiService: ApiService;
|
||||
private clientService: ClientService;
|
||||
private skipTypecheck = true;
|
||||
private checkServerStep: CheckServerOrchestratorStep;
|
||||
private ensureValidTokensStep: EnsureValidTokensOrchestratorStep;
|
||||
private buildManifestStep: BuildManifestOrchestratorStep;
|
||||
private registerAppStep: RegisterAppOrchestratorStep;
|
||||
private resolveApplicationStep: ResolveApplicationOrchestratorStep;
|
||||
private uploadFilesStep: UploadFilesOrchestratorStep;
|
||||
private generateApiClientStep: GenerateApiClientOrchestratorStep;
|
||||
private syncApplicationStep: SyncApplicationOrchestratorStep;
|
||||
@@ -46,7 +45,8 @@ export class DevModeOrchestrator {
|
||||
this.debounceMs = options.debounceMs ?? 200;
|
||||
this.state = options.state;
|
||||
|
||||
const apiService = new ApiService({ disableInterceptors: true });
|
||||
this.apiService = new ApiService({ disableInterceptors: true });
|
||||
const apiService = this.apiService;
|
||||
const configService = new ConfigService();
|
||||
this.clientService = new ClientService();
|
||||
const stepDeps = { state: this.state, notify: () => this.state.notify() };
|
||||
@@ -66,10 +66,6 @@ export class DevModeOrchestrator {
|
||||
apiService,
|
||||
configService,
|
||||
});
|
||||
this.resolveApplicationStep = new ResolveApplicationOrchestratorStep({
|
||||
...stepDeps,
|
||||
apiService,
|
||||
});
|
||||
this.uploadFilesStep = new UploadFilesOrchestratorStep(stepDeps);
|
||||
this.generateApiClientStep = new GenerateApiClientOrchestratorStep({
|
||||
...stepDeps,
|
||||
@@ -223,20 +219,37 @@ export class DevModeOrchestrator {
|
||||
}
|
||||
|
||||
private async initializePipeline(manifest: Manifest): Promise<boolean> {
|
||||
const registerResult = await this.registerAppStep.execute({ manifest });
|
||||
await this.registerAppStep.execute({ manifest });
|
||||
|
||||
const resolveResult = await this.resolveApplicationStep.execute({
|
||||
manifest,
|
||||
applicationRegistrationId:
|
||||
registerResult.applicationRegistrationId ?? undefined,
|
||||
const createResult = await this.apiService.createDevelopmentApplication({
|
||||
universalIdentifier: manifest.application.universalIdentifier,
|
||||
name: manifest.application.displayName,
|
||||
});
|
||||
|
||||
if (!resolveResult.applicationId) {
|
||||
if (!createResult.success || !createResult.data) {
|
||||
this.state.applyStepEvents([
|
||||
{
|
||||
message: 'Failed to create development application',
|
||||
status: 'error',
|
||||
},
|
||||
]);
|
||||
this.state.updatePipeline({ status: 'error' });
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
this.state.steps.resolveApplication.output = {
|
||||
applicationId: createResult.data.id,
|
||||
universalIdentifier: createResult.data.universalIdentifier,
|
||||
};
|
||||
this.state.steps.resolveApplication.status = 'done';
|
||||
|
||||
this.state.applyStepEvents([
|
||||
{ message: 'Application created', status: 'success' },
|
||||
]);
|
||||
|
||||
await this.ensureValidTokensStep.exchangeTokens({
|
||||
applicationId: resolveResult.applicationId,
|
||||
applicationId: createResult.data.id,
|
||||
});
|
||||
|
||||
this.uploadFilesStep.initialize({
|
||||
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
import { type ApiService } from '@/cli/utilities/api/api-service';
|
||||
import { findOrCreateApplication } from '@/cli/utilities/application/find-or-create-application';
|
||||
import { type OrchestratorState } from '@/cli/utilities/dev/orchestrator/dev-mode-orchestrator-state';
|
||||
import { type Manifest } from 'twenty-shared/application';
|
||||
|
||||
export type ResolveApplicationOrchestratorStepOutput = {
|
||||
applicationId: string | null;
|
||||
universalIdentifier: string | null;
|
||||
};
|
||||
|
||||
export class ResolveApplicationOrchestratorStep {
|
||||
private apiService: ApiService;
|
||||
private state: OrchestratorState;
|
||||
private notify: () => void;
|
||||
|
||||
constructor({
|
||||
apiService,
|
||||
state,
|
||||
notify,
|
||||
}: {
|
||||
apiService: ApiService;
|
||||
state: OrchestratorState;
|
||||
notify: () => void;
|
||||
}) {
|
||||
this.apiService = apiService;
|
||||
this.state = state;
|
||||
this.notify = notify;
|
||||
}
|
||||
|
||||
async execute(input: {
|
||||
manifest: Manifest;
|
||||
applicationRegistrationId?: string;
|
||||
}): Promise<ResolveApplicationOrchestratorStepOutput> {
|
||||
const step = this.state.steps.resolveApplication;
|
||||
|
||||
step.status = 'in_progress';
|
||||
this.notify();
|
||||
|
||||
const result = await findOrCreateApplication({
|
||||
apiService: this.apiService,
|
||||
manifest: input.manifest,
|
||||
applicationRegistrationId: input.applicationRegistrationId,
|
||||
});
|
||||
|
||||
if (!result.success) {
|
||||
this.state.applyStepEvents([
|
||||
{
|
||||
message: result.error,
|
||||
status: 'error',
|
||||
},
|
||||
]);
|
||||
step.status = 'error';
|
||||
this.state.updatePipeline({ status: 'error' });
|
||||
|
||||
return step.output;
|
||||
}
|
||||
|
||||
if (result.created) {
|
||||
this.state.applyStepEvents([
|
||||
{ message: 'Creating application', status: 'info' },
|
||||
{ message: 'Application created', status: 'success' },
|
||||
]);
|
||||
}
|
||||
|
||||
step.output = {
|
||||
applicationId: result.applicationId,
|
||||
universalIdentifier: result.universalIdentifier,
|
||||
};
|
||||
step.status = 'done';
|
||||
this.notify();
|
||||
|
||||
return step.output;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user