Remove logic function layer (#17697)
## Remove logic function layer Package.json and yarn.lock are now on the application entity, so the logic function layer is no longer used except as a legacy source for the 1.17 backfill. This PR removes all layer usage outside of that migration and keeps only the entity for backfill. ### Summary - **Kept:** `LogicFunctionLayerEntity` and its table, only used by the 1.17 backfill command to read legacy layer data and backfill application package files. - **Removed:** All other layer logic: CRUD, cache, resolvers, services, DTOs, and frontend types. Logic functions now depend only on the application for package/dependency context. ### Why Dependencies instead of Source for package files Package.json and yarn.lock are the application’s dependency set and are stored under the application in **FileFolder.Dependencies**. The build service and drivers now read them only from Dependencies; nothing is written to Source for these files.
This commit is contained in:
@@ -1968,14 +1968,6 @@ export type LogicFunctionIdInput = {
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type LogicFunctionLayer = {
|
||||
__typename?: 'LogicFunctionLayer';
|
||||
applicationId?: Maybe<Scalars['UUID']>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
id: Scalars['UUID'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export type LogicFunctionLogs = {
|
||||
__typename?: 'LogicFunctionLogs';
|
||||
/** Execution Logs */
|
||||
@@ -2067,7 +2059,6 @@ export type Mutation = {
|
||||
createOneApplication: Application;
|
||||
createOneField: Field;
|
||||
createOneLogicFunction: LogicFunction;
|
||||
createOneLogicFunctionLayer: LogicFunctionLayer;
|
||||
createOneObject: Object;
|
||||
createOneRole: Role;
|
||||
createPageLayout: PageLayout;
|
||||
@@ -2403,13 +2394,6 @@ export type MutationCreateOneLogicFunctionArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneLogicFunctionLayerArgs = {
|
||||
applicationUniversalIdentifier: Scalars['String'];
|
||||
packageJsonChecksum: Scalars['JSON'];
|
||||
yarnLockChecksum: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneObjectArgs = {
|
||||
input: CreateOneObjectInput;
|
||||
};
|
||||
|
||||
@@ -1940,14 +1940,6 @@ export type LogicFunctionIdInput = {
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type LogicFunctionLayer = {
|
||||
__typename?: 'LogicFunctionLayer';
|
||||
applicationId?: Maybe<Scalars['UUID']>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
id: Scalars['UUID'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export type LogicFunctionLogs = {
|
||||
__typename?: 'LogicFunctionLogs';
|
||||
/** Execution Logs */
|
||||
@@ -2036,7 +2028,6 @@ export type Mutation = {
|
||||
createOneApplication: Application;
|
||||
createOneField: Field;
|
||||
createOneLogicFunction: LogicFunction;
|
||||
createOneLogicFunctionLayer: LogicFunctionLayer;
|
||||
createOneObject: Object;
|
||||
createOneRole: Role;
|
||||
createPageLayout: PageLayout;
|
||||
@@ -2349,13 +2340,6 @@ export type MutationCreateOneLogicFunctionArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneLogicFunctionLayerArgs = {
|
||||
applicationUniversalIdentifier: Scalars['String'];
|
||||
packageJsonChecksum: Scalars['JSON'];
|
||||
yarnLockChecksum: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateOneObjectArgs = {
|
||||
input: CreateOneObjectInput;
|
||||
};
|
||||
|
||||
-1
@@ -194,7 +194,6 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces
|
||||
name: oldLogicFunction.name,
|
||||
description: oldLogicFunction.description ?? undefined,
|
||||
timeoutSeconds: oldLogicFunction.timeoutSeconds ?? 300,
|
||||
logicFunctionLayerId: oldLogicFunction.logicFunctionLayerId,
|
||||
toolInputSchema: oldLogicFunction.toolInputSchema ?? undefined,
|
||||
isTool: oldLogicFunction.isTool ?? false,
|
||||
},
|
||||
|
||||
+1
-10
@@ -1,15 +1,14 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
|
||||
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
@@ -66,7 +65,6 @@ export class SeedWorkflowV1_16Command extends ActiveOrSuspendedWorkspacesMigrati
|
||||
protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
protected readonly dataSourceService: DataSourceService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly logicFunctionLayerService: LogicFunctionLayerService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
private readonly recordPositionService: RecordPositionService,
|
||||
) {
|
||||
@@ -421,12 +419,6 @@ export class SeedWorkflowV1_16Command extends ActiveOrSuspendedWorkspacesMigrati
|
||||
{ workspaceId },
|
||||
);
|
||||
const applicationId = workspaceCustomFlatApplication.id;
|
||||
const { id: logicFunctionLayerId } =
|
||||
await this.logicFunctionLayerService.createCommonLayer({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
});
|
||||
const id = uuidv4();
|
||||
const universalIdentifier = uuidv4();
|
||||
const now = new Date();
|
||||
@@ -446,7 +438,6 @@ export class SeedWorkflowV1_16Command extends ActiveOrSuspendedWorkspacesMigrati
|
||||
checksum: null,
|
||||
toolInputSchema: null,
|
||||
isTool: false,
|
||||
logicFunctionLayerId,
|
||||
cronTriggerSettings: null,
|
||||
databaseEventTriggerSettings: null,
|
||||
httpRouteTriggerSettings: null,
|
||||
|
||||
-2
@@ -16,7 +16,6 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module';
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
import { CoreLogicFunctionLayerModule } from 'src/engine/core-modules/logic-function/logic-function-layer/logic-function-layer.module';
|
||||
import { RecordPositionModule } from 'src/engine/core-modules/record-position/record-position.module';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
@@ -58,7 +57,6 @@ import { TaskTargetWorkspaceEntity } from 'src/modules/task/standard-objects/tas
|
||||
FieldMetadataModule,
|
||||
ObjectMetadataModule,
|
||||
ApplicationModule,
|
||||
CoreLogicFunctionLayerModule,
|
||||
LogicFunctionModule,
|
||||
RecordPositionModule,
|
||||
GlobalWorkspaceDataSourceModule,
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
import { type MigrationInterface, type QueryRunner } from 'typeorm';
|
||||
|
||||
export class DropLogicFunctionLayerIdFromLogicFunction1770193825210
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'DropLogicFunctionLayerIdFromLogicFunction1770193825210';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" DROP CONSTRAINT IF EXISTS "FK_87e3f7b8f23cd90709e127f60c5"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" DROP CONSTRAINT IF EXISTS "FK_4b9625a4babf7f4fa942fd26514"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`DROP INDEX IF EXISTS "core"."IDX_LOGIC_FUNCTION_LAYER_ID"`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" DROP COLUMN IF EXISTS "logicFunctionLayerId"`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ADD "logicFunctionLayerId" uuid`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "IDX_LOGIC_FUNCTION_LAYER_ID" ON "core"."logicFunction" ("logicFunctionLayerId")`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."logicFunction" ADD CONSTRAINT "FK_4b9625a4babf7f4fa942fd26514" FOREIGN KEY ("logicFunctionLayerId") REFERENCES "core"."logicFunctionLayer"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
|
||||
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
|
||||
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
|
||||
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
||||
import { ObjectPermissionModule } from 'src/engine/metadata-modules/object-permission/object-permission.module';
|
||||
@@ -33,7 +32,6 @@ import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-commo
|
||||
ObjectMetadataModule,
|
||||
FieldMetadataModule,
|
||||
DataSourceModule,
|
||||
LogicFunctionLayerModule,
|
||||
LogicFunctionModule,
|
||||
WorkspaceMigrationModule,
|
||||
PermissionsModule,
|
||||
|
||||
+14
-37
@@ -26,7 +26,6 @@ import { type FlatApplication } from 'src/engine/core-modules/application/types/
|
||||
import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application/utils/get-default-application-package-fields.util';
|
||||
import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
|
||||
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
|
||||
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
|
||||
@@ -54,7 +53,6 @@ export class ApplicationSyncService {
|
||||
constructor(
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly applicationVariableService: ApplicationVariableEntityService,
|
||||
private readonly logicFunctionLayerService: LogicFunctionLayerService,
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
private readonly fieldMetadataService: FieldMetadataService,
|
||||
private readonly logicFunctionService: LogicFunctionService,
|
||||
@@ -102,19 +100,11 @@ export class ApplicationSyncService {
|
||||
}
|
||||
|
||||
if (manifest.logicFunctions.length > 0) {
|
||||
if (!isDefined(application.logicFunctionLayerId)) {
|
||||
throw new ApplicationException(
|
||||
`Failed to sync logic function, could not find a logic function layer.`,
|
||||
ApplicationExceptionCode.FIELD_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
await this.syncLogicFunctions({
|
||||
logicFunctionsToSync: manifest.logicFunctions,
|
||||
code: manifest.sources,
|
||||
workspaceId,
|
||||
ownerFlatApplication,
|
||||
logicFunctionLayerId: application.logicFunctionLayerId,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -162,7 +152,6 @@ export class ApplicationSyncService {
|
||||
description: manifest.application.description,
|
||||
version: packageJson.version,
|
||||
sourcePath: 'cli-sync', // Placeholder for CLI-synced apps
|
||||
logicFunctionLayerId: null,
|
||||
defaultRoleId: null,
|
||||
workspaceId,
|
||||
packageJsonChecksum: defaultPackageFields.packageJsonChecksum,
|
||||
@@ -179,35 +168,27 @@ export class ApplicationSyncService {
|
||||
application = created;
|
||||
}
|
||||
|
||||
let logicFunctionLayerId = application.logicFunctionLayerId;
|
||||
|
||||
if (
|
||||
manifest.logicFunctions.length > 0 &&
|
||||
isDefined(manifest.application.packageJsonChecksum) &&
|
||||
isDefined(manifest.application.yarnLockChecksum)
|
||||
) {
|
||||
if (!isDefined(logicFunctionLayerId)) {
|
||||
logicFunctionLayerId = (
|
||||
await this.logicFunctionLayerService.create(
|
||||
{
|
||||
packageJsonChecksum: manifest.application.packageJsonChecksum,
|
||||
yarnLockChecksum: manifest.application.yarnLockChecksum,
|
||||
applicationUniversalIdentifier:
|
||||
manifest.application.universalIdentifier,
|
||||
},
|
||||
const yarnLockContent = (
|
||||
await streamToBuffer(
|
||||
await this.fileStorageService.readFile_v2({
|
||||
applicationUniversalIdentifier:
|
||||
manifest.application.universalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: 'yarn.lock',
|
||||
workspaceId,
|
||||
)
|
||||
).id;
|
||||
}
|
||||
}),
|
||||
)
|
||||
).toString('utf-8');
|
||||
|
||||
await this.logicFunctionLayerService.update(
|
||||
logicFunctionLayerId,
|
||||
{
|
||||
packageJsonChecksum: manifest.application.packageJsonChecksum,
|
||||
yarnLockChecksum: manifest.application.yarnLockChecksum,
|
||||
},
|
||||
manifest.application.universalIdentifier,
|
||||
workspaceId,
|
||||
await this.applicationService.uploadPackageFilesFromContent(
|
||||
application,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
yarnLockContent,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -223,7 +204,6 @@ export class ApplicationSyncService {
|
||||
name,
|
||||
description: manifest.application.description,
|
||||
version: packageJson.version,
|
||||
logicFunctionLayerId,
|
||||
defaultRoleId: null,
|
||||
});
|
||||
}
|
||||
@@ -848,13 +828,11 @@ export class ApplicationSyncService {
|
||||
code,
|
||||
workspaceId,
|
||||
ownerFlatApplication,
|
||||
logicFunctionLayerId,
|
||||
}: {
|
||||
logicFunctionsToSync: LogicFunctionManifest[];
|
||||
workspaceId: string;
|
||||
code: Sources;
|
||||
ownerFlatApplication: FlatApplication;
|
||||
logicFunctionLayerId: string;
|
||||
}) {
|
||||
const { flatLogicFunctionMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
@@ -964,7 +942,6 @@ export class ApplicationSyncService {
|
||||
sourceHandlerPath: logicFunctionToCreate.sourceHandlerPath,
|
||||
handlerName: logicFunctionToCreate.handlerName,
|
||||
builtHandlerPath: logicFunctionToCreate.builtHandlerPath,
|
||||
logicFunctionLayerId,
|
||||
toolInputSchema: logicFunctionToCreate.toolInputSchema,
|
||||
isTool: logicFunctionToCreate.isTool,
|
||||
},
|
||||
|
||||
+45
@@ -405,6 +405,51 @@ export class ApplicationService {
|
||||
}
|
||||
}
|
||||
|
||||
async uploadPackageFilesFromContent(
|
||||
application: Pick<
|
||||
ApplicationEntity,
|
||||
'id' | 'universalIdentifier' | 'workspaceId'
|
||||
>,
|
||||
packageJsonContent: string,
|
||||
yarnLockContent: string,
|
||||
): Promise<void> {
|
||||
const packageJsonChecksum = logicFunctionCreateHash(packageJsonContent);
|
||||
const yarnLockChecksum = logicFunctionCreateHash(yarnLockContent);
|
||||
const availablePackages = parseAvailablePackagesFromPackageJsonAndYarnLock(
|
||||
packageJsonContent,
|
||||
yarnLockContent,
|
||||
);
|
||||
|
||||
const packageJsonFile = await this.fileStorageService.writeFile_v2({
|
||||
sourceFile: packageJsonContent,
|
||||
mimeType: undefined,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
applicationUniversalIdentifier: application.universalIdentifier,
|
||||
workspaceId: application.workspaceId,
|
||||
resourcePath: 'package.json',
|
||||
settings: { isTemporaryFile: false, toDelete: false },
|
||||
});
|
||||
|
||||
const yarnLockFile = await this.fileStorageService.writeFile_v2({
|
||||
sourceFile: yarnLockContent,
|
||||
mimeType: undefined,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
applicationUniversalIdentifier: application.universalIdentifier,
|
||||
workspaceId: application.workspaceId,
|
||||
resourcePath: 'yarn.lock',
|
||||
settings: { isTemporaryFile: false, toDelete: false },
|
||||
});
|
||||
|
||||
await this.update(application.id, {
|
||||
packageJsonFileId: packageJsonFile.id,
|
||||
yarnLockFileId: yarnLockFile.id,
|
||||
packageJsonChecksum,
|
||||
yarnLockChecksum,
|
||||
availablePackages,
|
||||
workspaceId: application.workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
async create(
|
||||
data: Partial<ApplicationEntity> & { workspaceId: string },
|
||||
queryRunner?: QueryRunner,
|
||||
|
||||
+15
-39
@@ -1,20 +1,20 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs/promises';
|
||||
import { dirname, join } from 'path';
|
||||
import crypto from 'crypto';
|
||||
|
||||
import { build } from 'esbuild';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import {
|
||||
getLogicFunctionBaseFolderPath,
|
||||
getRelativePathFromBase,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
|
||||
import { FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
|
||||
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
|
||||
export type FunctionBuildParams = {
|
||||
flatLogicFunction: FlatLogicFunction;
|
||||
@@ -26,23 +26,22 @@ export class LogicFunctionBuildService {
|
||||
constructor(private readonly fileStorageService: FileStorageService) {}
|
||||
|
||||
async hasLayerDependencies({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): Promise<boolean> {
|
||||
const packageJsonExists = await this.fileStorageService.checkFileExists_v2({
|
||||
workspaceId: flatLogicFunctionLayer.workspaceId,
|
||||
workspaceId: flatApplication.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
resourcePath: 'package.json',
|
||||
});
|
||||
|
||||
const yarnLockExists = await this.fileStorageService.checkFileExists_v2({
|
||||
workspaceId: flatLogicFunctionLayer.workspaceId,
|
||||
workspaceId: flatApplication.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
resourcePath: 'yarn.lock',
|
||||
});
|
||||
|
||||
@@ -50,37 +49,14 @@ export class LogicFunctionBuildService {
|
||||
}
|
||||
|
||||
async uploadDependencies({
|
||||
flatLogicFunctionLayer,
|
||||
applicationUniversalIdentifier,
|
||||
flatApplication: _flatApplication,
|
||||
applicationUniversalIdentifier: _applicationUniversalIdentifier,
|
||||
}: {
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
await this.fileStorageService.writeFile_v2({
|
||||
workspaceId: flatLogicFunctionLayer.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: 'package.json',
|
||||
sourceFile: JSON.stringify(flatLogicFunctionLayer.packageJson, null, 2),
|
||||
mimeType: undefined,
|
||||
settings: {
|
||||
isTemporaryFile: false,
|
||||
toDelete: false,
|
||||
},
|
||||
});
|
||||
|
||||
await this.fileStorageService.writeFile_v2({
|
||||
workspaceId: flatLogicFunctionLayer.workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: 'yarn.lock',
|
||||
sourceFile: flatLogicFunctionLayer.yarnLock,
|
||||
mimeType: undefined,
|
||||
settings: {
|
||||
isTemporaryFile: false,
|
||||
toDelete: false,
|
||||
},
|
||||
});
|
||||
// Package files live in Dependencies; no copy needed – drivers read from
|
||||
// Dependencies when building the layer.
|
||||
}
|
||||
|
||||
async isBuilt({
|
||||
|
||||
+18
-18
@@ -28,15 +28,15 @@ import {
|
||||
type LogicFunctionExecutorDriver,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { copyExecutor } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-executor';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { createZipFile } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file';
|
||||
import {
|
||||
LambdaBuildDirectoryManager,
|
||||
NODE_LAYER_SUBFOLDER,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
|
||||
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
|
||||
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import {
|
||||
@@ -138,8 +138,8 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
);
|
||||
}
|
||||
|
||||
private getLayerName(flatLogicFunctionLayer: FlatLogicFunctionLayer) {
|
||||
return flatLogicFunctionLayer.yarnLockChecksum;
|
||||
private getLayerName(flatApplication: FlatApplication) {
|
||||
return flatApplication.yarnLockChecksum ?? 'default';
|
||||
}
|
||||
|
||||
private async copyDependenciesInMemory({
|
||||
@@ -155,14 +155,14 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
this.fileStorageService.downloadFile_v2({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
resourcePath: 'package.json',
|
||||
localPath: join(inMemoryLayerFolderPath, 'package.json'),
|
||||
}),
|
||||
this.fileStorageService.downloadFile_v2({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
resourcePath: 'yarn.lock',
|
||||
localPath: join(inMemoryLayerFolderPath, 'yarn.lock'),
|
||||
}),
|
||||
@@ -170,13 +170,13 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
}
|
||||
|
||||
private async createLayerIfNotExists({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
}): Promise<string> {
|
||||
const layerName = this.getLayerName(flatLogicFunctionLayer);
|
||||
const layerName = this.getLayerName(flatApplication);
|
||||
|
||||
const listLayerParams: ListLayerVersionsCommandInput = {
|
||||
LayerName: layerName,
|
||||
@@ -204,7 +204,7 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
|
||||
await this.copyDependenciesInMemory({
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId: flatLogicFunctionLayer.workspaceId,
|
||||
workspaceId: flatApplication.workspaceId,
|
||||
inMemoryLayerFolderPath: nodeDependenciesFolder,
|
||||
});
|
||||
await copyYarnEngineAndBuildDependencies(nodeDependenciesFolder);
|
||||
@@ -263,7 +263,7 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
|
||||
private async isAlreadyBuilt(
|
||||
flatLogicFunction: FlatLogicFunction,
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer,
|
||||
flatApplication: FlatApplication,
|
||||
) {
|
||||
const lambdaExecutor = await this.getLambdaExecutor(flatLogicFunction);
|
||||
|
||||
@@ -279,7 +279,7 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
return false;
|
||||
}
|
||||
|
||||
const layerName = this.getLayerName(flatLogicFunctionLayer);
|
||||
const layerName = this.getLayerName(flatApplication);
|
||||
|
||||
if (layers[0].Arn?.includes(layerName)) {
|
||||
return true;
|
||||
@@ -292,19 +292,19 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
|
||||
private async build({
|
||||
flatLogicFunction,
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
flatLogicFunction: FlatLogicFunction;
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
if (await this.isAlreadyBuilt(flatLogicFunction, flatLogicFunctionLayer)) {
|
||||
if (await this.isAlreadyBuilt(flatLogicFunction, flatApplication)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const layerArn = await this.createLayerIfNotExists({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
@@ -353,14 +353,14 @@ export class LambdaDriver implements LogicFunctionExecutorDriver {
|
||||
|
||||
async execute({
|
||||
flatLogicFunction,
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
payload,
|
||||
env,
|
||||
}: LogicFunctionExecuteParams): Promise<LogicFunctionExecuteResult> {
|
||||
await this.build({
|
||||
flatLogicFunction,
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
|
||||
+23
-27
@@ -10,17 +10,17 @@ import {
|
||||
type LogicFunctionExecutorDriver,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { ConsoleListener } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/intercept-console';
|
||||
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
|
||||
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
|
||||
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import {
|
||||
getLogicFunctionBaseFolderPath,
|
||||
getRelativePathFromBase,
|
||||
} from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
|
||||
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder';
|
||||
import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies';
|
||||
import { ConsoleListener } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/intercept-console';
|
||||
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
|
||||
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
|
||||
export interface LocalDriverOptions {
|
||||
fileStorageService: FileStorageService;
|
||||
@@ -33,13 +33,10 @@ export class LocalDriver implements LogicFunctionExecutorDriver {
|
||||
this.fileStorageService = options.fileStorageService;
|
||||
}
|
||||
|
||||
private getInMemoryLayerFolderPath = (
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer,
|
||||
) => {
|
||||
return join(
|
||||
LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER,
|
||||
flatLogicFunctionLayer.yarnLockChecksum,
|
||||
);
|
||||
private getInMemoryLayerFolderPath = (flatApplication: FlatApplication) => {
|
||||
const checksum = flatApplication.yarnLockChecksum ?? 'default';
|
||||
|
||||
return join(LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER, checksum);
|
||||
};
|
||||
|
||||
private async copyDependenciesInMemory({
|
||||
@@ -55,14 +52,14 @@ export class LocalDriver implements LogicFunctionExecutorDriver {
|
||||
this.fileStorageService.downloadFile_v2({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
resourcePath: 'package.json',
|
||||
localPath: join(inMemoryLayerFolderPath, 'package.json'),
|
||||
}),
|
||||
this.fileStorageService.downloadFile_v2({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
fileFolder: FileFolder.Dependencies,
|
||||
resourcePath: 'yarn.lock',
|
||||
localPath: join(inMemoryLayerFolderPath, 'yarn.lock'),
|
||||
}),
|
||||
@@ -70,22 +67,21 @@ export class LocalDriver implements LogicFunctionExecutorDriver {
|
||||
}
|
||||
|
||||
private async createLayerIfNotExists({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
const inMemoryLayerFolderPath = this.getInMemoryLayerFolderPath(
|
||||
flatLogicFunctionLayer,
|
||||
);
|
||||
const inMemoryLayerFolderPath =
|
||||
this.getInMemoryLayerFolderPath(flatApplication);
|
||||
|
||||
try {
|
||||
await fs.access(inMemoryLayerFolderPath);
|
||||
} catch {
|
||||
await this.copyDependenciesInMemory({
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId: flatLogicFunctionLayer.workspaceId,
|
||||
workspaceId: flatApplication.workspaceId,
|
||||
inMemoryLayerFolderPath,
|
||||
});
|
||||
await copyYarnEngineAndBuildDependencies(inMemoryLayerFolderPath);
|
||||
@@ -95,27 +91,27 @@ export class LocalDriver implements LogicFunctionExecutorDriver {
|
||||
async delete() {}
|
||||
|
||||
private async build({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
await this.createLayerIfNotExists({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
}
|
||||
|
||||
async execute({
|
||||
flatLogicFunction,
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
payload,
|
||||
env,
|
||||
}: LogicFunctionExecuteParams): Promise<LogicFunctionExecuteResult> {
|
||||
await this.build({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
@@ -141,7 +137,7 @@ export class LocalDriver implements LogicFunctionExecutorDriver {
|
||||
try {
|
||||
await fs.symlink(
|
||||
join(
|
||||
this.getInMemoryLayerFolderPath(flatLogicFunctionLayer),
|
||||
this.getInMemoryLayerFolderPath(flatApplication),
|
||||
'node_modules',
|
||||
),
|
||||
join(sourceTemporaryDir, 'node_modules'),
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
|
||||
@@ -18,7 +18,7 @@ export type LogicFunctionExecuteResult = {
|
||||
|
||||
export type LogicFunctionExecuteParams = {
|
||||
flatLogicFunction: FlatLogicFunction;
|
||||
flatLogicFunctionLayer: FlatLogicFunctionLayer;
|
||||
flatApplication: FlatApplication;
|
||||
applicationUniversalIdentifier: string;
|
||||
payload: object;
|
||||
env?: Record<string, string>;
|
||||
|
||||
-2
@@ -12,7 +12,6 @@ import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.mod
|
||||
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -23,7 +22,6 @@ import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-func
|
||||
SubscriptionsModule,
|
||||
WorkspaceCacheModule,
|
||||
LogicFunctionBuildModule,
|
||||
LogicFunctionLayerModule,
|
||||
FileModule,
|
||||
TypeOrmModule.forFeature([LogicFunctionEntity]),
|
||||
],
|
||||
|
||||
+11
-31
@@ -6,7 +6,7 @@ import {
|
||||
DEFAULT_API_URL_NAME,
|
||||
} from 'twenty-shared/application';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
import { isDefined, isEmptyObject } from 'twenty-shared/utils';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
@@ -35,7 +35,6 @@ import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription
|
||||
import { SubscriptionService } from 'src/engine/subscriptions/subscription.service';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { cleanServerUrl } from 'src/utils/clean-server-url';
|
||||
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
|
||||
|
||||
const MIN_TOKEN_EXPIRATION_IN_SECONDS = 5;
|
||||
|
||||
@@ -69,7 +68,6 @@ export class LogicFunctionExecutorService
|
||||
private readonly functionBuildService: LogicFunctionBuildService,
|
||||
private readonly subscriptionService: SubscriptionService,
|
||||
private readonly auditService: AuditService,
|
||||
private readonly logicFunctionLayerService: LogicFunctionLayerService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
@InjectRepository(LogicFunctionEntity)
|
||||
private readonly logicFunctionRepository: Repository<LogicFunctionEntity>,
|
||||
@@ -100,12 +98,10 @@ export class LogicFunctionExecutorService
|
||||
flatLogicFunctionMaps,
|
||||
flatApplicationMaps,
|
||||
applicationVariableMaps,
|
||||
logicFunctionLayerMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatLogicFunctionMaps',
|
||||
'flatApplicationMaps',
|
||||
'applicationVariableMaps',
|
||||
'logicFunctionLayerMaps',
|
||||
]);
|
||||
|
||||
const flatLogicFunction = findFlatEntityByIdInFlatEntityMaps({
|
||||
@@ -123,12 +119,13 @@ export class LogicFunctionExecutorService
|
||||
);
|
||||
}
|
||||
|
||||
const flatLogicFunctionLayer =
|
||||
logicFunctionLayerMaps.byId[flatLogicFunction.logicFunctionLayerId];
|
||||
const flatApplication = isDefined(flatLogicFunction.applicationId)
|
||||
? flatApplicationMaps.byId[flatLogicFunction.applicationId]
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(flatLogicFunctionLayer)) {
|
||||
if (!isDefined(flatApplication)) {
|
||||
throw new LogicFunctionExecutionException(
|
||||
`Logic function layer with id ${flatLogicFunction.logicFunctionLayerId} not found`,
|
||||
`Application not found for logic function ${id}`,
|
||||
LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
@@ -180,15 +177,14 @@ export class LogicFunctionExecutorService
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: remove when all logic functions are migrated
|
||||
if (
|
||||
!(await this.functionBuildService.hasLayerDependencies({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
}))
|
||||
) {
|
||||
await this.functionBuildService.uploadDependencies({
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
}
|
||||
@@ -210,7 +206,7 @@ export class LogicFunctionExecutorService
|
||||
callback: () =>
|
||||
this.execute({
|
||||
flatLogicFunction,
|
||||
flatLogicFunctionLayer,
|
||||
flatApplication,
|
||||
applicationUniversalIdentifier,
|
||||
payload,
|
||||
env: envVariables,
|
||||
@@ -307,26 +303,10 @@ export class LogicFunctionExecutorService
|
||||
async getAvailablePackages(logicFunctionId: string) {
|
||||
const logicFunction = await this.logicFunctionRepository.findOneOrFail({
|
||||
where: { id: logicFunctionId },
|
||||
relations: ['logicFunctionLayer', 'application'],
|
||||
relations: ['application'],
|
||||
});
|
||||
|
||||
if (isEmptyObject(logicFunction.logicFunctionLayer.availablePackages)) {
|
||||
await this.logicFunctionLayerService.update(
|
||||
logicFunction.logicFunctionLayer.id,
|
||||
{},
|
||||
logicFunction.application.universalIdentifier,
|
||||
logicFunction.workspaceId,
|
||||
);
|
||||
|
||||
return (
|
||||
await this.logicFunctionRepository.findOneOrFail({
|
||||
where: { id: logicFunctionId },
|
||||
relations: ['logicFunctionLayer'],
|
||||
})
|
||||
).logicFunctionLayer.availablePackages;
|
||||
}
|
||||
|
||||
return logicFunction.logicFunctionLayer.availablePackages;
|
||||
return logicFunction.application.availablePackages ?? {};
|
||||
}
|
||||
|
||||
private async throttleExecution(workspaceId: string) {
|
||||
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
|
||||
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([LogicFunctionLayerEntity]),
|
||||
WorkspaceCacheModule,
|
||||
],
|
||||
providers: [LogicFunctionLayerService],
|
||||
exports: [LogicFunctionLayerService],
|
||||
})
|
||||
export class CoreLogicFunctionLayerModule {}
|
||||
-186
@@ -1,186 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
import { PackageJson } from 'type-fest';
|
||||
|
||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';
|
||||
|
||||
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
import { CreateLogicFunctionLayerInput } from 'src/engine/metadata-modules/logic-function-layer/dtos/create-logic-function-layer.input';
|
||||
import { getLastCommonLayerDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-last-common-layer-dependencies';
|
||||
import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
|
||||
@Injectable()
|
||||
export class LogicFunctionLayerService {
|
||||
constructor(
|
||||
@InjectRepository(LogicFunctionLayerEntity)
|
||||
private readonly logicFunctionLayerRepository: Repository<LogicFunctionLayerEntity>,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
) {}
|
||||
|
||||
async create(
|
||||
{
|
||||
packageJsonChecksum,
|
||||
yarnLockChecksum,
|
||||
applicationUniversalIdentifier,
|
||||
}: CreateLogicFunctionLayerInput,
|
||||
workspaceId: string,
|
||||
) {
|
||||
const logicFunctionLayer = this.logicFunctionLayerRepository.create({
|
||||
packageJson: {}, // TODO: Delete when migration to Source files storage is done
|
||||
yarnLock: '', // TODO: Delete when migration to Source files storage is done
|
||||
packageJsonChecksum,
|
||||
yarnLockChecksum,
|
||||
workspaceId,
|
||||
} as Omit<LogicFunctionLayerEntity, 'workspace'>);
|
||||
|
||||
const availablePackages = await this.getAvailablePackages({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const savedLayer = await this.logicFunctionLayerRepository.save({
|
||||
...logicFunctionLayer,
|
||||
availablePackages,
|
||||
});
|
||||
|
||||
await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [
|
||||
'logicFunctionLayerMaps',
|
||||
]);
|
||||
|
||||
return savedLayer;
|
||||
}
|
||||
|
||||
async update(
|
||||
id: string,
|
||||
data: QueryDeepPartialEntity<Omit<LogicFunctionLayerEntity, 'workspace'>>,
|
||||
applicationUniversalIdentifier: string,
|
||||
workspaceId: string,
|
||||
) {
|
||||
const availablePackages = await this.getAvailablePackages({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
});
|
||||
|
||||
const result = await this.logicFunctionLayerRepository.update(id, {
|
||||
...data,
|
||||
availablePackages,
|
||||
});
|
||||
|
||||
await this.workspaceCacheService.invalidateAndRecompute(workspaceId, [
|
||||
'logicFunctionLayerMaps',
|
||||
]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async createCommonLayer({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
const { packageJson, yarnLock } = await getLastCommonLayerDependencies();
|
||||
|
||||
await this.fileStorageService.writeFile_v2({
|
||||
sourceFile: packageJson,
|
||||
mimeType: undefined,
|
||||
fileFolder: FileFolder.Source,
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
resourcePath: 'package.json',
|
||||
settings: { isTemporaryFile: false, toDelete: false },
|
||||
});
|
||||
|
||||
await this.fileStorageService.writeFile_v2({
|
||||
sourceFile: yarnLock,
|
||||
mimeType: undefined,
|
||||
fileFolder: FileFolder.Source,
|
||||
applicationUniversalIdentifier,
|
||||
workspaceId,
|
||||
resourcePath: 'yarn.lock',
|
||||
settings: { isTemporaryFile: false, toDelete: false },
|
||||
});
|
||||
|
||||
const packageJsonChecksum = logicFunctionCreateHash(
|
||||
JSON.stringify(packageJson),
|
||||
);
|
||||
|
||||
const yarnLockChecksum = logicFunctionCreateHash(yarnLock);
|
||||
|
||||
const commonLayer = await this.logicFunctionLayerRepository.findOne({
|
||||
where: {
|
||||
yarnLockChecksum,
|
||||
packageJsonChecksum,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
if (isDefined(commonLayer)) {
|
||||
return commonLayer;
|
||||
}
|
||||
|
||||
return this.create(
|
||||
{ packageJsonChecksum, yarnLockChecksum, applicationUniversalIdentifier },
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
private async getAvailablePackages({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
}) {
|
||||
const packageJson = JSON.parse(
|
||||
(
|
||||
await streamToBuffer(
|
||||
await this.fileStorageService.readFile_v2({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: 'package.json',
|
||||
}),
|
||||
)
|
||||
).toString('utf-8'),
|
||||
) as PackageJson;
|
||||
|
||||
const yarnLock = (
|
||||
await streamToBuffer(
|
||||
await this.fileStorageService.readFile_v2({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
fileFolder: FileFolder.Source,
|
||||
resourcePath: 'yarn.lock',
|
||||
}),
|
||||
)
|
||||
).toString('utf-8');
|
||||
|
||||
const packageVersionRegex =
|
||||
/^"(@?[^@]+(?:\/[^@]+)?)@.*?":\n\s+version:\s*(.+)$/gm;
|
||||
|
||||
const versions: Record<string, string> = {};
|
||||
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = packageVersionRegex.exec(yarnLock)) !== null) {
|
||||
const packageName = match[1];
|
||||
const version = match[2];
|
||||
|
||||
if (packageJson.dependencies?.[packageName]) {
|
||||
versions[packageName] = version;
|
||||
}
|
||||
}
|
||||
|
||||
return versions;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { type LogicFunctionExecutorModuleAsyncOptions } from 'src/engine/core-mo
|
||||
import { LogicFunctionBuildModule } from 'src/engine/core-modules/logic-function/logic-function-build/logic-function-build.module';
|
||||
import { LogicFunctionDriversModule } from 'src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.module';
|
||||
import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module';
|
||||
import { CoreLogicFunctionLayerModule } from 'src/engine/core-modules/logic-function/logic-function-layer/logic-function-layer.module';
|
||||
import { LogicFunctionTriggerModule } from 'src/engine/core-modules/logic-function/logic-function-trigger/logic-function-trigger.module';
|
||||
|
||||
@Global()
|
||||
@@ -20,14 +19,12 @@ export class LogicFunctionModule {
|
||||
LogicFunctionDriversModule.forRootAsync(options),
|
||||
LogicFunctionExecutorModule,
|
||||
LogicFunctionBuildModule,
|
||||
CoreLogicFunctionLayerModule,
|
||||
LogicFunctionTriggerModule,
|
||||
],
|
||||
exports: [
|
||||
LogicFunctionDriversModule,
|
||||
LogicFunctionExecutorModule,
|
||||
LogicFunctionBuildModule,
|
||||
CoreLogicFunctionLayerModule,
|
||||
LogicFunctionTriggerModule,
|
||||
],
|
||||
};
|
||||
|
||||
-1
@@ -267,7 +267,6 @@ export const ALL_METADATA_RELATIONS = {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
application: null,
|
||||
logicFunctionLayer: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
import { ArgsType, Field } from '@nestjs/graphql';
|
||||
|
||||
import { IsString } from 'class-validator';
|
||||
import GraphQLJSON from 'graphql-type-json';
|
||||
|
||||
@ArgsType()
|
||||
export class CreateLogicFunctionLayerInput {
|
||||
@Field(() => GraphQLJSON, { nullable: false })
|
||||
packageJsonChecksum: string;
|
||||
|
||||
@IsString()
|
||||
@Field(() => String, { nullable: false })
|
||||
yarnLockChecksum: string;
|
||||
|
||||
@Field(() => String)
|
||||
applicationUniversalIdentifier: string;
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { IsDateString } from 'class-validator';
|
||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@ObjectType('LogicFunctionLayer')
|
||||
export class LogicFunctionLayerDTO {
|
||||
@IDField(() => UUIDScalarType)
|
||||
id: string;
|
||||
|
||||
@IDField(() => UUIDScalarType, { nullable: true })
|
||||
applicationId?: string;
|
||||
|
||||
@IsDateString()
|
||||
@Field()
|
||||
createdAt: Date;
|
||||
|
||||
@IsDateString()
|
||||
@Field()
|
||||
updatedAt: Date;
|
||||
}
|
||||
-12
@@ -3,13 +3,10 @@ import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
OneToMany,
|
||||
PrimaryGeneratedColumn,
|
||||
Relation,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { WorkspaceRelatedEntity } from 'src/engine/workspace-manager/types/workspace-related-entity';
|
||||
|
||||
@Entity('logicFunctionLayer')
|
||||
@@ -32,15 +29,6 @@ export class LogicFunctionLayerEntity extends WorkspaceRelatedEntity {
|
||||
@Column({ type: 'jsonb', nullable: false, default: {} })
|
||||
availablePackages: Record<string, string>;
|
||||
|
||||
@OneToMany(
|
||||
() => LogicFunctionEntity,
|
||||
(logicFunction) => logicFunction.logicFunctionLayer,
|
||||
{
|
||||
onDelete: 'RESTRICT',
|
||||
},
|
||||
)
|
||||
logicFunctions: Relation<LogicFunctionEntity[]>;
|
||||
|
||||
@CreateDateColumn({ type: 'timestamptz' })
|
||||
createdAt: Date;
|
||||
|
||||
|
||||
+2
-12
@@ -1,20 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
import { LogicFunctionLayerResolver } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.resolver';
|
||||
import { WorkspaceLogicFunctionLayerMapCacheService } from 'src/engine/metadata-modules/logic-function-layer/services/workspace-logic-function-layer-map-cache.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([LogicFunctionLayerEntity]),
|
||||
PermissionsModule,
|
||||
],
|
||||
providers: [
|
||||
LogicFunctionLayerResolver,
|
||||
WorkspaceLogicFunctionLayerMapCacheService,
|
||||
],
|
||||
exports: [WorkspaceLogicFunctionLayerMapCacheService],
|
||||
imports: [TypeOrmModule.forFeature([LogicFunctionLayerEntity])],
|
||||
exports: [TypeOrmModule],
|
||||
})
|
||||
export class LogicFunctionLayerModule {}
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { CreateLogicFunctionLayerInput } from 'src/engine/metadata-modules/logic-function-layer/dtos/create-logic-function-layer.input';
|
||||
import { LogicFunctionLayerDTO } from 'src/engine/metadata-modules/logic-function-layer/dtos/logic-function-layer.dto';
|
||||
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
|
||||
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
@Resolver()
|
||||
export class LogicFunctionLayerResolver {
|
||||
constructor(
|
||||
private readonly logicFunctionLayerService: LogicFunctionLayerService,
|
||||
) {}
|
||||
|
||||
@Mutation(() => LogicFunctionLayerDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS))
|
||||
async createOneLogicFunctionLayer(
|
||||
@Args()
|
||||
createLogicFunctionLayerInput: CreateLogicFunctionLayerInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
) {
|
||||
return this.logicFunctionLayerService.create(
|
||||
createLogicFunctionLayerInput,
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service';
|
||||
|
||||
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
import { type LogicFunctionLayerCacheMaps } from 'src/engine/metadata-modules/logic-function-layer/types/logic-function-layer-cache-maps.type';
|
||||
import { fromLogicFunctionLayerEntityToFlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/utils/from-logic-function-layer-entity-to-flat-logic-function-layer.util';
|
||||
import { WorkspaceCache } from 'src/engine/workspace-cache/decorators/workspace-cache.decorator';
|
||||
|
||||
@Injectable()
|
||||
@WorkspaceCache('logicFunctionLayerMaps')
|
||||
export class WorkspaceLogicFunctionLayerMapCacheService extends WorkspaceCacheProvider<LogicFunctionLayerCacheMaps> {
|
||||
constructor(
|
||||
@InjectRepository(LogicFunctionLayerEntity)
|
||||
private readonly logicFunctionLayerRepository: Repository<LogicFunctionLayerEntity>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async computeForCache(
|
||||
workspaceId: string,
|
||||
): Promise<LogicFunctionLayerCacheMaps> {
|
||||
const logicFunctionLayerEntities =
|
||||
await this.logicFunctionLayerRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
const logicFunctionLayerMaps: LogicFunctionLayerCacheMaps = {
|
||||
byId: {},
|
||||
};
|
||||
|
||||
for (const entity of logicFunctionLayerEntities) {
|
||||
const flatLogicFunctionLayer =
|
||||
fromLogicFunctionLayerEntityToFlatLogicFunctionLayer(entity);
|
||||
|
||||
logicFunctionLayerMaps.byId[flatLogicFunctionLayer.id] =
|
||||
flatLogicFunctionLayer;
|
||||
}
|
||||
|
||||
return logicFunctionLayerMaps;
|
||||
}
|
||||
}
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
|
||||
export type FlatLogicFunctionLayer = FlatEntityFrom<LogicFunctionLayerEntity>;
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
|
||||
|
||||
export type LogicFunctionLayerCacheMaps = {
|
||||
byId: Partial<Record<string, FlatLogicFunctionLayer>>;
|
||||
};
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
import { type LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
|
||||
|
||||
export const fromLogicFunctionLayerEntityToFlatLogicFunctionLayer = (
|
||||
entity: LogicFunctionLayerEntity,
|
||||
): FlatLogicFunctionLayer => ({
|
||||
id: entity.id,
|
||||
packageJson: entity.packageJson,
|
||||
packageJsonChecksum: entity.packageJsonChecksum,
|
||||
yarnLock: entity.yarnLock,
|
||||
yarnLockChecksum: entity.yarnLockChecksum,
|
||||
workspaceId: entity.workspaceId,
|
||||
createdAt: entity.createdAt.toISOString(),
|
||||
updatedAt: entity.updatedAt.toISOString(),
|
||||
logicFunctionIds: entity.logicFunctions?.map((lf) => lf.id) ?? [],
|
||||
availablePackages: entity.availablePackages ?? {},
|
||||
});
|
||||
-3
@@ -38,9 +38,6 @@ export class CreateLogicFunctionInput {
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
logicFunctionLayerId?: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
|
||||
+1
-17
@@ -6,16 +6,12 @@ import {
|
||||
DeleteDateColumn,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
PrimaryGeneratedColumn,
|
||||
Relation,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
export type CronTriggerSettings = {
|
||||
pattern: string;
|
||||
@@ -46,7 +42,6 @@ export const DEFAULT_HANDLER_NAME = 'main';
|
||||
|
||||
@Entity('logicFunction')
|
||||
@Index('IDX_LOGIC_FUNCTION_ID_DELETED_AT', ['id', 'deletedAt'])
|
||||
@Index('IDX_LOGIC_FUNCTION_LAYER_ID', ['logicFunctionLayerId'])
|
||||
export class LogicFunctionEntity
|
||||
extends SyncableEntity
|
||||
implements Required<LogicFunctionEntity>
|
||||
@@ -85,17 +80,6 @@ export class LogicFunctionEntity
|
||||
@Column({ nullable: false, default: false })
|
||||
isTool: boolean;
|
||||
|
||||
@Column({ nullable: false, type: 'uuid' })
|
||||
logicFunctionLayerId: string;
|
||||
|
||||
@ManyToOne(
|
||||
() => LogicFunctionLayerEntity,
|
||||
(logicFunctionLayer) => logicFunctionLayer.logicFunctions,
|
||||
{ nullable: false },
|
||||
)
|
||||
@JoinColumn({ name: 'logicFunctionLayerId' })
|
||||
logicFunctionLayer: Relation<LogicFunctionLayerEntity>;
|
||||
|
||||
@Column({ nullable: true, type: 'jsonb' })
|
||||
cronTriggerSettings: JsonbProperty<CronTriggerSettings> | null;
|
||||
|
||||
|
||||
-2
@@ -12,7 +12,6 @@ import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-
|
||||
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
||||
import { FileModule } from 'src/engine/core-modules/file/file.module';
|
||||
import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module';
|
||||
import { CoreLogicFunctionLayerModule } from 'src/engine/core-modules/logic-function/logic-function-layer/logic-function-layer.module';
|
||||
import { SecretEncryptionModule } from 'src/engine/core-modules/secret-encryption/secret-encryption.module';
|
||||
import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
@@ -40,7 +39,6 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
WorkspaceMigrationModule,
|
||||
LogicFunctionLayerModule,
|
||||
CoreLogicFunctionLayerModule,
|
||||
LogicFunctionExecutorModule,
|
||||
SubscriptionsModule,
|
||||
WorkspaceCacheModule,
|
||||
|
||||
+3
-31
@@ -7,10 +7,9 @@ import { ApplicationService } from 'src/engine/core-modules/application/services
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
|
||||
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import type { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import type { UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input';
|
||||
import {
|
||||
@@ -31,7 +30,6 @@ export class LogicFunctionService {
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly logicFunctionLayerService: LogicFunctionLayerService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
) {}
|
||||
@@ -41,9 +39,7 @@ export class LogicFunctionService {
|
||||
workspaceId,
|
||||
ownerFlatApplication,
|
||||
}: {
|
||||
input: Omit<CreateLogicFunctionInput, 'applicationId'> & {
|
||||
logicFunctionLayerId?: string;
|
||||
};
|
||||
input: Omit<CreateLogicFunctionInput, 'applicationId'>;
|
||||
ownerFlatApplication?: FlatApplication;
|
||||
workspaceId: string;
|
||||
applicationId?: string;
|
||||
@@ -56,32 +52,9 @@ export class LogicFunctionService {
|
||||
)
|
||||
).workspaceCustomFlatApplication;
|
||||
|
||||
let logicFunctionToCreateLayerId = input.logicFunctionLayerId;
|
||||
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
if (!isDefined(logicFunctionToCreateLayerId)) {
|
||||
const { id: commonLogicFunctionLayerId } =
|
||||
await this.logicFunctionLayerService.createCommonLayer({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
});
|
||||
|
||||
logicFunctionToCreateLayerId = commonLogicFunctionLayerId;
|
||||
}
|
||||
|
||||
const flatLogicFunctionToCreate =
|
||||
fromCreateLogicFunctionInputToFlatLogicFunction({
|
||||
createLogicFunctionInput: {
|
||||
...input,
|
||||
logicFunctionLayerId: logicFunctionToCreateLayerId,
|
||||
},
|
||||
createLogicFunctionInput: input,
|
||||
workspaceId,
|
||||
ownerFlatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
@@ -333,7 +306,6 @@ export class LogicFunctionService {
|
||||
name: existingLogicFunction.name,
|
||||
description: existingLogicFunction.description ?? undefined,
|
||||
timeoutSeconds: existingLogicFunction.timeoutSeconds,
|
||||
logicFunctionLayerId: existingLogicFunction.logicFunctionLayerId,
|
||||
},
|
||||
workspaceId,
|
||||
applicationId: existingLogicFunction.applicationId ?? undefined,
|
||||
|
||||
+1
-4
@@ -16,9 +16,7 @@ import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-funct
|
||||
const WORKFLOW_BASE_FOLDER_PREFIX = 'workflow';
|
||||
|
||||
export type FromCreateLogicFunctionInputToFlatLogicFunctionArgs = {
|
||||
createLogicFunctionInput: CreateLogicFunctionInput & {
|
||||
logicFunctionLayerId: string;
|
||||
};
|
||||
createLogicFunctionInput: CreateLogicFunctionInput;
|
||||
workspaceId: string;
|
||||
ownerFlatApplication: FlatApplication;
|
||||
};
|
||||
@@ -61,7 +59,6 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({
|
||||
applicationId: ownerFlatApplication.id,
|
||||
runtime: LogicFunctionRuntime.NODE22,
|
||||
timeoutSeconds: rawCreateLogicFunctionInput.timeoutSeconds ?? 300,
|
||||
logicFunctionLayerId: rawCreateLogicFunctionInput.logicFunctionLayerId,
|
||||
workspaceId,
|
||||
code: rawCreateLogicFunctionInput?.code,
|
||||
checksum: rawCreateLogicFunctionInput?.code
|
||||
|
||||
@@ -7,7 +7,6 @@ import { type FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/
|
||||
import { type FlatWorkspaceMemberMaps } from 'src/engine/core-modules/user/types/flat-workspace-member-maps.type';
|
||||
import { type FlatRoleTargetByAgentIdMaps } from 'src/engine/metadata-modules/flat-agent/types/flat-role-target-by-agent-id-maps.type';
|
||||
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { type LogicFunctionLayerCacheMaps } from 'src/engine/metadata-modules/logic-function-layer/types/logic-function-layer-cache-maps.type';
|
||||
import { type UserWorkspaceRoleMap } from 'src/engine/metadata-modules/role-target/services/workspace-user-workspace-role-map-cache.service';
|
||||
import { type FlatRowLevelPermissionPredicateGroupMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group-maps.type';
|
||||
import { type FlatRowLevelPermissionPredicateMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-maps.type';
|
||||
@@ -45,7 +44,6 @@ export const WORKSPACE_CACHE_KEYS_V2 = {
|
||||
flatFrontComponentMaps: 'flat-maps:front-component',
|
||||
flatWebhookMaps: 'flat-maps:webhook',
|
||||
flatWorkspaceMemberMaps: 'flat-maps:workspace-member',
|
||||
logicFunctionLayerMaps: 'cache:logic-function-layer',
|
||||
applicationVariableMaps: 'cache:application-variable',
|
||||
} as const satisfies Record<WorkspaceCacheKeyName, string>;
|
||||
|
||||
@@ -60,7 +58,6 @@ export type AdditionalCacheDataMaps = {
|
||||
flatRowLevelPermissionPredicateMaps: FlatRowLevelPermissionPredicateMaps;
|
||||
flatRowLevelPermissionPredicateGroupMaps: FlatRowLevelPermissionPredicateGroupMaps;
|
||||
flatWorkspaceMemberMaps: FlatWorkspaceMemberMaps;
|
||||
logicFunctionLayerMaps: LogicFunctionLayerCacheMaps;
|
||||
applicationVariableMaps: ApplicationVariableCacheMaps;
|
||||
};
|
||||
|
||||
|
||||
-2
@@ -256,7 +256,6 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
checksum: null,
|
||||
toolInputSchema: null,
|
||||
isTool: false,
|
||||
logicFunctionLayerId: 'layer-id',
|
||||
universalIdentifier: 'universal-id',
|
||||
applicationId: 'application-id',
|
||||
cronTriggerSettings: null,
|
||||
@@ -327,7 +326,6 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
|
||||
checksum: null,
|
||||
toolInputSchema: null,
|
||||
isTool: false,
|
||||
logicFunctionLayerId: 'layer-id',
|
||||
universalIdentifier: 'universal-id',
|
||||
applicationId: 'application-id',
|
||||
cronTriggerSettings: null,
|
||||
|
||||
+1
-2
@@ -7,8 +7,8 @@ import { getAuthTokensFromLoginToken } from 'test/integration/graphql/utils/get-
|
||||
import { getCurrentUser } from 'test/integration/graphql/utils/get-current-user.util';
|
||||
import { signUpInNewWorkspace } from 'test/integration/graphql/utils/sign-up-in-new-workspace.util';
|
||||
import { signUp } from 'test/integration/graphql/utils/sign-up.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { createOneLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-one-logic-function.util';
|
||||
import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util';
|
||||
import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
@@ -218,7 +218,6 @@ describe('Successful user and workspace creation', () => {
|
||||
'fieldPermission',
|
||||
'permissionFlag',
|
||||
'logicFunction',
|
||||
'logicFunctionLayer',
|
||||
'agent',
|
||||
'view',
|
||||
'viewField',
|
||||
|
||||
Reference in New Issue
Block a user