Add Client Api generation (#17961)
## Add API client generation to SDK dev mode and refactor orchestrator into step-based pipeline ### Why The SDK dev mode lacked typed API client generation, forcing developers to work without auto-generated GraphQL types when building applications. Additionally, the orchestrator was a monolithic class that mixed watcher management, token handling, and sync logic — making it difficult to extend with new steps like client generation. ### How - **Refactored the orchestrator** into a step-based pipeline with dedicated classes: `CheckServer`, `EnsureValidTokens`, `ResolveApplication`, `BuildManifest`, `UploadFiles`, `GenerateApiClient`, `SyncApplication`, and `StartWatchers`. Each step has typed input/output/status, managed by a new `OrchestratorState` class. - **Added `GenerateApiClientOrchestratorStep`** that detects object/field schema changes and regenerates a typed GraphQL client (via `@genql/cli`) into `node_modules/twenty-sdk/generated` for seamless imports. - **Replaced `checkApplicationExist`** with `findOneApplication` on both server resolver and SDK API service, returning the entity data instead of a boolean. - **Added application token pair mutations** (`generateApplicationToken`, `renewApplicationToken`) to the API service, with the server now returning `ApplicationTokenPairDTO` containing both access and refresh tokens. - **Restructured the dev UI** into `dev/ui/components/` with dedicated panel, section, and event log components. - **Simplified `AppDevCommand`** from ~180 lines of watcher management down to ~40 lines that delegate entirely to the orchestrator.
This commit is contained in:
+4
-4
@@ -26,7 +26,7 @@ import { UploadApplicationFileInput } from 'src/engine/core-modules/application/
|
||||
import { WorkspaceMigrationDTO } from 'src/engine/core-modules/application/dtos/workspace-migration.dto';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/services/application-sync.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { AuthToken } from 'src/engine/core-modules/auth/dto/auth-token.dto';
|
||||
import { ApplicationTokenPairDTO } from 'src/engine/core-modules/application/dtos/application-token-pair.dto';
|
||||
import { ApplicationTokenService } from 'src/engine/core-modules/auth/token/services/application-token.service';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
@@ -58,13 +58,13 @@ export class ApplicationDevelopmentResolver {
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
) {}
|
||||
|
||||
@Mutation(() => AuthToken)
|
||||
@Mutation(() => ApplicationTokenPairDTO)
|
||||
@RequireFeatureFlag(FeatureFlagKey.IS_APPLICATION_ENABLED)
|
||||
async generateApplicationToken(
|
||||
@Args() { applicationId }: GenerateApplicationTokenInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<AuthToken> {
|
||||
return this.applicationTokenService.generateApplicationAccessToken({
|
||||
): Promise<ApplicationTokenPairDTO> {
|
||||
return this.applicationTokenService.generateApplicationTokenPair({
|
||||
workspaceId,
|
||||
applicationId,
|
||||
});
|
||||
|
||||
-16
@@ -57,22 +57,6 @@ export class ApplicationResolver {
|
||||
return this.applicationService.findManyApplications(workspaceId);
|
||||
}
|
||||
|
||||
@Query(() => Boolean)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.APPLICATIONS))
|
||||
@RequireFeatureFlag(FeatureFlagKey.IS_APPLICATION_ENABLED)
|
||||
async checkApplicationExist(
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
@Args('id', { type: () => UUIDScalarType, nullable: true }) id?: string,
|
||||
@Args('universalIdentifier', { type: () => UUIDScalarType, nullable: true })
|
||||
universalIdentifier?: string,
|
||||
) {
|
||||
return await this.applicationService.checkApplicationExist({
|
||||
id,
|
||||
universalIdentifier,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
@Query(() => ApplicationDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.APPLICATIONS))
|
||||
@RequireFeatureFlag(FeatureFlagKey.IS_APPLICATION_ENABLED)
|
||||
|
||||
-14
@@ -130,20 +130,6 @@ export class ApplicationService {
|
||||
});
|
||||
}
|
||||
|
||||
async checkApplicationExist({
|
||||
id,
|
||||
universalIdentifier,
|
||||
workspaceId,
|
||||
}: {
|
||||
id?: string;
|
||||
universalIdentifier?: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
return isDefined(
|
||||
await this.findOneApplication({ id, universalIdentifier, workspaceId }),
|
||||
);
|
||||
}
|
||||
|
||||
async findOneApplication({
|
||||
id,
|
||||
universalIdentifier,
|
||||
|
||||
Reference in New Issue
Block a user