Add checksum to manifest (#17368)
## Refactor app-dev state management and build utilities - Store only `manifest` in `AppDevState` instead of full `ManifestBuildResult`; add `sourcePath` to `FileStatus` - Pass `sourcePaths` directly to watchers instead of `ManifestBuildResult` - Only reset `fileUploadStatus` for functions/components when their source paths change - Add pure `updateManifestChecksum` utility that returns a new manifest without side effects - Extract `processEsbuildResult` to deduplicate build result processing between watchers - Rename `serverlessFunctions` → `functions` in SDK code (API unchanged) - Extract `writeManifestToOutput` to shared `manifest-writer.ts`
This commit is contained in:
@@ -2,8 +2,13 @@ import { type ApiResponse } from '@/cli/utilities/api/types/api-response.types';
|
||||
import { createLogger } from '@/cli/utilities/build/common/logger';
|
||||
import { FrontComponentsWatcher } from '@/cli/utilities/build/front-components/front-component-watcher';
|
||||
import { FunctionsWatcher } from '@/cli/utilities/build/functions/function-watcher';
|
||||
import { runManifestBuild, type ManifestBuildResult } from '@/cli/utilities/build/manifest/manifest-build';
|
||||
import {
|
||||
runManifestBuild,
|
||||
updateManifestChecksum,
|
||||
type ManifestBuildResult,
|
||||
} from '@/cli/utilities/build/manifest/manifest-build';
|
||||
import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server';
|
||||
import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer';
|
||||
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory';
|
||||
|
||||
const initLogger = createLogger('init');
|
||||
@@ -45,7 +50,7 @@ export class AppBuildCommand {
|
||||
|
||||
await this.buildFunctions(buildResult);
|
||||
await this.buildFrontComponents(buildResult);
|
||||
|
||||
await writeManifestToOutput(this.appPath, buildResult.manifest);
|
||||
await this.cleanup();
|
||||
|
||||
return buildResult;
|
||||
@@ -54,8 +59,21 @@ export class AppBuildCommand {
|
||||
private async buildFunctions(buildResult: ManifestBuildResult): Promise<void> {
|
||||
this.functionsBuilder = new FunctionsWatcher({
|
||||
appPath: this.appPath,
|
||||
buildResult,
|
||||
sourcePaths: buildResult.filePaths.functions,
|
||||
watch: false,
|
||||
onFileBuilt: (builtPath, checksum) => {
|
||||
if (buildResult.manifest) {
|
||||
const updatedManifest = updateManifestChecksum({
|
||||
manifest: buildResult.manifest,
|
||||
entityType: 'function',
|
||||
builtPath,
|
||||
checksum,
|
||||
});
|
||||
if (updatedManifest) {
|
||||
buildResult.manifest = updatedManifest;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await this.functionsBuilder.start();
|
||||
@@ -64,8 +82,21 @@ export class AppBuildCommand {
|
||||
private async buildFrontComponents(buildResult: ManifestBuildResult): Promise<void> {
|
||||
this.frontComponentsBuilder = new FrontComponentsWatcher({
|
||||
appPath: this.appPath,
|
||||
buildResult,
|
||||
sourcePaths: buildResult.filePaths.frontComponents,
|
||||
watch: false,
|
||||
onFileBuilt: (builtPath, checksum) => {
|
||||
if (buildResult.manifest) {
|
||||
const updatedManifest = updateManifestChecksum({
|
||||
manifest: buildResult.manifest,
|
||||
entityType: 'frontComponent',
|
||||
builtPath,
|
||||
checksum,
|
||||
});
|
||||
if (updatedManifest) {
|
||||
buildResult.manifest = updatedManifest;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await this.frontComponentsBuilder.start();
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { createLogger } from '@/cli/utilities/build/common/logger';
|
||||
import { FrontComponentsWatcher } from '@/cli/utilities/build/front-components/front-component-watcher';
|
||||
import { FunctionsWatcher } from '@/cli/utilities/build/functions/function-watcher';
|
||||
import { runManifestBuild, type ManifestBuildResult } from '@/cli/utilities/build/manifest/manifest-build';
|
||||
import { runManifestBuild, updateManifestChecksum } from '@/cli/utilities/build/manifest/manifest-build';
|
||||
import { ManifestWatcher } from '@/cli/utilities/build/manifest/manifest-watcher';
|
||||
import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer';
|
||||
import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory';
|
||||
import { type ApplicationManifest } from 'twenty-shared/application';
|
||||
|
||||
const initLogger = createLogger('init');
|
||||
|
||||
@@ -11,8 +13,21 @@ export type AppDevOptions = {
|
||||
appPath?: string;
|
||||
};
|
||||
|
||||
export type FileStatus = {
|
||||
sourcePath: string;
|
||||
builtPath: string;
|
||||
checksum: string | null;
|
||||
isUploaded: boolean;
|
||||
};
|
||||
|
||||
export type FileStatusMaps = {
|
||||
functions: Map<string, FileStatus>;
|
||||
frontComponents: Map<string, FileStatus>;
|
||||
};
|
||||
|
||||
type AppDevState = {
|
||||
buildResult: ManifestBuildResult | null;
|
||||
manifest: ApplicationManifest | null;
|
||||
fileStatusMaps: FileStatusMaps;
|
||||
};
|
||||
|
||||
export class AppDevCommand {
|
||||
@@ -22,7 +37,11 @@ export class AppDevCommand {
|
||||
|
||||
private appPath: string = '';
|
||||
private state: AppDevState = {
|
||||
buildResult: null,
|
||||
manifest: null,
|
||||
fileStatusMaps: {
|
||||
functions: new Map(),
|
||||
frontComponents: new Map(),
|
||||
},
|
||||
};
|
||||
|
||||
async execute(options: AppDevOptions): Promise<void> {
|
||||
@@ -44,11 +63,39 @@ export class AppDevCommand {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.buildResult = buildResult;
|
||||
this.state.manifest = buildResult.manifest;
|
||||
this.initializeFunctionsFileUploadStatus(buildResult.manifest);
|
||||
this.initializeFrontComponentsFileUploadStatus(buildResult.manifest);
|
||||
|
||||
await this.startManifestWatcher();
|
||||
await this.startFunctionsWatcher(buildResult);
|
||||
await this.startFrontComponentsWatcher(buildResult);
|
||||
await this.startFunctionsWatcher(buildResult.filePaths.functions);
|
||||
await this.startFrontComponentsWatcher(buildResult.filePaths.frontComponents);
|
||||
}
|
||||
|
||||
private initializeFunctionsFileUploadStatus(manifest: ApplicationManifest): void {
|
||||
this.state.fileStatusMaps.functions.clear();
|
||||
|
||||
for (const fn of manifest.functions ?? []) {
|
||||
this.state.fileStatusMaps.functions.set(fn.universalIdentifier, {
|
||||
sourcePath: fn.sourceHandlerPath,
|
||||
builtPath: fn.builtHandlerPath,
|
||||
checksum: null,
|
||||
isUploaded: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private initializeFrontComponentsFileUploadStatus(manifest: ApplicationManifest): void {
|
||||
this.state.fileStatusMaps.frontComponents.clear();
|
||||
|
||||
for (const component of manifest.frontComponents ?? []) {
|
||||
this.state.fileStatusMaps.frontComponents.set(component.universalIdentifier, {
|
||||
sourcePath: component.sourceComponentPath,
|
||||
builtPath: component.builtComponentPath,
|
||||
checksum: null,
|
||||
isUploaded: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async startManifestWatcher(): Promise<void> {
|
||||
@@ -56,14 +103,24 @@ export class AppDevCommand {
|
||||
appPath: this.appPath,
|
||||
callbacks: {
|
||||
onBuildSuccess: (result) => {
|
||||
this.state.buildResult = result;
|
||||
this.state.manifest = result.manifest;
|
||||
|
||||
if (this.functionsWatcher?.shouldRestart(result)) {
|
||||
this.functionsWatcher.restart(result);
|
||||
const functionSourcePaths = result.filePaths.functions;
|
||||
const shouldRestartFunctions = this.functionsWatcher?.shouldRestart(functionSourcePaths);
|
||||
if (shouldRestartFunctions) {
|
||||
if (result.manifest) {
|
||||
this.initializeFunctionsFileUploadStatus(result.manifest);
|
||||
}
|
||||
this.functionsWatcher?.restart(functionSourcePaths);
|
||||
}
|
||||
|
||||
if (this.frontComponentsWatcher?.shouldRestart(result)) {
|
||||
this.frontComponentsWatcher.restart(result);
|
||||
const componentSourcePaths = result.filePaths.frontComponents;
|
||||
const shouldRestartFrontComponents = this.frontComponentsWatcher?.shouldRestart(componentSourcePaths);
|
||||
if (shouldRestartFrontComponents) {
|
||||
if (result.manifest) {
|
||||
this.initializeFrontComponentsFileUploadStatus(result.manifest);
|
||||
}
|
||||
this.frontComponentsWatcher?.restart(componentSourcePaths);
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -72,24 +129,57 @@ export class AppDevCommand {
|
||||
await this.manifestWatcher.start();
|
||||
}
|
||||
|
||||
private async startFunctionsWatcher(buildResult: ManifestBuildResult): Promise<void> {
|
||||
private async startFunctionsWatcher(sourcePaths: string[]): Promise<void> {
|
||||
this.functionsWatcher = new FunctionsWatcher({
|
||||
appPath: this.appPath,
|
||||
buildResult,
|
||||
sourcePaths,
|
||||
onFileBuilt: (builtPath, checksum) => {
|
||||
this.updateFileStatus('function', builtPath, checksum);
|
||||
},
|
||||
});
|
||||
|
||||
await this.functionsWatcher.start();
|
||||
}
|
||||
|
||||
private async startFrontComponentsWatcher(buildResult: ManifestBuildResult): Promise<void> {
|
||||
private async startFrontComponentsWatcher(sourcePaths: string[]): Promise<void> {
|
||||
this.frontComponentsWatcher = new FrontComponentsWatcher({
|
||||
appPath: this.appPath,
|
||||
buildResult,
|
||||
sourcePaths,
|
||||
onFileBuilt: (builtPath, checksum) => {
|
||||
this.updateFileStatus('frontComponent', builtPath, checksum);
|
||||
},
|
||||
});
|
||||
|
||||
await this.frontComponentsWatcher.start();
|
||||
}
|
||||
|
||||
private updateFileStatus(
|
||||
entityType: 'function' | 'frontComponent',
|
||||
builtPath: string,
|
||||
checksum: string,
|
||||
): void {
|
||||
const statusMap = entityType === 'function'
|
||||
? this.state.fileStatusMaps.functions
|
||||
: this.state.fileStatusMaps.frontComponents;
|
||||
|
||||
for (const [_id, status] of statusMap) {
|
||||
if (status.builtPath === builtPath) {
|
||||
status.checksum = checksum;
|
||||
status.isUploaded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const manifest = this.state.manifest;
|
||||
if (manifest) {
|
||||
const updatedManifest = updateManifestChecksum({ manifest, entityType, builtPath, checksum });
|
||||
if (updatedManifest) {
|
||||
this.state.manifest = updatedManifest;
|
||||
writeManifestToOutput(this.appPath, updatedManifest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setupGracefulShutdown(): void {
|
||||
const shutdown = () => {
|
||||
console.log('');
|
||||
|
||||
@@ -164,7 +164,7 @@ export class FunctionExecuteCommand {
|
||||
fn: { universalIdentifier: string; applicationId: string | null },
|
||||
manifest: ApplicationManifest,
|
||||
): boolean {
|
||||
return manifest.serverlessFunctions.some(
|
||||
return manifest.functions.some(
|
||||
(manifestFn) => manifestFn.universalIdentifier === fn.universalIdentifier,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user