Upgrade to Node22 (#12488)
BlocknoteJS requires an ESM module where our server is CJS, this forced us to pin the server-util version, which led us to force the resolution of several packages, leading to bugs downstream. From Node 22.12 Node supports requiring ESM modules (available from Node 22.0 with a flag). So I upgrade the module. I picked Node 22 and not Node 23 or Node 24 because 22 is the LTS and we don't plan to change node versions frequently. If you remain on Node 18, things should still mostly work, except if you edit a Rich Text field. I also starting changing the default runtime for Serverless Functions which isn't directly related. This means new serverless functions will be created on Node 22, but we will still need another PR to migrate existing serverless functions before September (end of support by AWS). (In this PR I also remove the upgrade commands from 0.43 since they rely on Blocknote and I didn't want to have to deal with this) --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
@ -16,6 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^1.3.22",
|
||||
"@blocknote/server-util": "^0.31.1",
|
||||
"@clickhouse/client": "^1.11.0",
|
||||
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
||||
"@graphql-yoga/nestjs": "patch:@graphql-yoga/nestjs@2.1.0#./patches/@graphql-yoga+nestjs+2.1.0.patch",
|
||||
@ -89,7 +90,7 @@
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.1",
|
||||
"node": "^22.12.0",
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": "^4.0.2"
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
"options": {
|
||||
"cwd": "packages/twenty-server",
|
||||
"commands": [
|
||||
"NODE_ENV=test nx jest --config ./jest-integration.config.ts"
|
||||
"NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" nx jest --config ./jest-integration.config.ts"
|
||||
]
|
||||
},
|
||||
"parallel": false,
|
||||
@ -26,7 +26,7 @@
|
||||
"with-db-reset": {
|
||||
"cwd": "packages/twenty-server",
|
||||
"commands": [
|
||||
"NODE_ENV=test nx database:reset > reset-logs.log && NODE_ENV=test nx jest --config ./jest-integration.config.ts"
|
||||
"NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" nx database:reset > reset-logs.log && NODE_ENV=test NODE_OPTIONS=\"--max-old-space-size=8192\" nx jest --config ./jest-integration.config.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,208 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
||||
RunOnWorkspaceArgs,
|
||||
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataDefaultOption } from 'src/engine/metadata-modules/field-metadata/dtos/options.input';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { tasksAssignedToMeView } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me';
|
||||
import { TASK_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids';
|
||||
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
|
||||
import { ViewFieldWorkspaceEntity } from 'src/modules/view/standard-objects/view-field.workspace-entity';
|
||||
import { ViewFilterWorkspaceEntity } from 'src/modules/view/standard-objects/view-filter.workspace-entity';
|
||||
import { ViewGroupWorkspaceEntity } from 'src/modules/view/standard-objects/view-group.workspace-entity';
|
||||
import { ViewWorkspaceEntity } from 'src/modules/view/standard-objects/view.workspace-entity';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:0-43:add-tasks-assigned-to-me-view',
|
||||
description: 'Add tasks assigned to me view',
|
||||
})
|
||||
export class AddTasksAssignedToMeViewCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
@InjectRepository(FieldMetadataEntity, 'metadata')
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
index,
|
||||
total,
|
||||
workspaceId,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
|
||||
);
|
||||
|
||||
await this.createTasksAssignedToMeView(workspaceId);
|
||||
|
||||
this.logger.log(
|
||||
chalk.green(`Command completed for workspace ${workspaceId}.`),
|
||||
);
|
||||
}
|
||||
|
||||
private async createTasksAssignedToMeView(
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
const objectMetadata = await this.objectMetadataRepository.find({
|
||||
where: { workspaceId },
|
||||
relations: ['fields'],
|
||||
});
|
||||
|
||||
const objectMetadataMap = objectMetadata.reduce((acc, object) => {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
acc[object.standardId ?? ''] = {
|
||||
id: object.id,
|
||||
fields: object.fields.reduce((acc, field) => {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
acc[field.standardId ?? ''] = field.id;
|
||||
|
||||
return acc;
|
||||
}, {}),
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const taskObjectMetadata = objectMetadata.find(
|
||||
(object) => object.standardId === STANDARD_OBJECT_IDS.task,
|
||||
);
|
||||
|
||||
if (!taskObjectMetadata) {
|
||||
throw new Error(`Task object not found for workspace ${workspaceId}`);
|
||||
}
|
||||
|
||||
const viewRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ViewWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'view',
|
||||
);
|
||||
|
||||
const existingView = await viewRepository.findOne({
|
||||
where: {
|
||||
name: 'Assigned to Me',
|
||||
objectMetadataId: taskObjectMetadata.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (existingView) {
|
||||
this.logger.log(
|
||||
chalk.yellow(
|
||||
`"Assigned to Me" view already exists for workspace ${workspaceId}`,
|
||||
),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const viewDefinition = tasksAssignedToMeView(objectMetadataMap);
|
||||
const viewId = v4();
|
||||
|
||||
const insertedView = await viewRepository.save({
|
||||
id: viewId,
|
||||
name: viewDefinition.name,
|
||||
objectMetadataId: viewDefinition.objectMetadataId,
|
||||
type: viewDefinition.type,
|
||||
position: viewDefinition.position,
|
||||
icon: viewDefinition.icon,
|
||||
kanbanFieldMetadataId: viewDefinition.kanbanFieldMetadataId,
|
||||
});
|
||||
|
||||
if (viewDefinition.fields && viewDefinition.fields.length > 0) {
|
||||
const viewFieldRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ViewFieldWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'viewField',
|
||||
);
|
||||
|
||||
const viewFields = viewDefinition.fields.map((field) => ({
|
||||
fieldMetadataId: field.fieldMetadataId,
|
||||
position: field.position,
|
||||
isVisible: field.isVisible,
|
||||
size: field.size,
|
||||
viewId: insertedView.id,
|
||||
}));
|
||||
|
||||
await viewFieldRepository.save(viewFields);
|
||||
}
|
||||
|
||||
if (viewDefinition.filters && viewDefinition.filters.length > 0) {
|
||||
const viewFilterRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ViewFilterWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'viewFilter',
|
||||
);
|
||||
|
||||
const viewFilters = viewDefinition.filters.map((filter) => ({
|
||||
fieldMetadataId: filter.fieldMetadataId,
|
||||
displayValue: filter.displayValue,
|
||||
operand: filter.operand,
|
||||
value: filter.value,
|
||||
viewId: insertedView.id,
|
||||
}));
|
||||
|
||||
await viewFilterRepository.save(viewFilters);
|
||||
}
|
||||
|
||||
await this.createTasksAssignedToMeViewGroups(workspaceId, insertedView.id);
|
||||
}
|
||||
|
||||
private async createTasksAssignedToMeViewGroups(
|
||||
workspaceId: string,
|
||||
viewId: string,
|
||||
) {
|
||||
const taskStatusFieldMetadata = await this.fieldMetadataRepository.findOne({
|
||||
where: {
|
||||
workspaceId,
|
||||
standardId: TASK_STANDARD_FIELD_IDS.status,
|
||||
},
|
||||
});
|
||||
|
||||
if (!taskStatusFieldMetadata) {
|
||||
throw new Error(
|
||||
`Task status field metadata not found for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const optionValueViewGroups = taskStatusFieldMetadata.options.map(
|
||||
(taskStatusOption: FieldMetadataDefaultOption, index) =>
|
||||
({
|
||||
fieldMetadataId: taskStatusFieldMetadata.id,
|
||||
viewId,
|
||||
fieldValue: taskStatusOption.value,
|
||||
position: index,
|
||||
}) satisfies Partial<ViewGroupWorkspaceEntity>,
|
||||
);
|
||||
|
||||
const noValueViewGroup: Partial<ViewGroupWorkspaceEntity> = {
|
||||
fieldMetadataId: taskStatusFieldMetadata.id,
|
||||
viewId,
|
||||
fieldValue: '',
|
||||
position: optionValueViewGroups.length,
|
||||
};
|
||||
|
||||
const viewGroups = [...optionValueViewGroups, noValueViewGroup];
|
||||
|
||||
const viewGroupRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace<ViewGroupWorkspaceEntity>(
|
||||
workspaceId,
|
||||
'viewGroup',
|
||||
);
|
||||
|
||||
await viewGroupRepository.insert(viewGroups);
|
||||
}
|
||||
}
|
||||
@ -1,51 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
||||
RunOnWorkspaceArgs,
|
||||
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:0-43:migrate-is-searchable-for-custom-object-metadata',
|
||||
description: 'Set isSearchable true for custom object metadata',
|
||||
})
|
||||
export class MigrateIsSearchableForCustomObjectMetadataCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
protected readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
index,
|
||||
total,
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
|
||||
);
|
||||
|
||||
if (!options.dryRun) {
|
||||
await this.objectMetadataRepository.update(
|
||||
{
|
||||
workspaceId,
|
||||
isCustom: true,
|
||||
},
|
||||
{
|
||||
isSearchable: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,275 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { ServerBlockNoteEditor } from '@blocknote/server-util';
|
||||
import chalk from 'chalk';
|
||||
import { Command } from 'nest-commander';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandOptions,
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
||||
RunOnWorkspaceArgs,
|
||||
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { computeTableName } from 'src/engine/utils/compute-table-name.util';
|
||||
import { WorkspaceDataSourceService } from 'src/engine/workspace-datasource/workspace-datasource.service';
|
||||
|
||||
type MigrateRichTextContentArgs = {
|
||||
richTextFieldsWithObjectMetadata: RichTextFieldsWithObjectMetadata[];
|
||||
workspaceId: string;
|
||||
options: ActiveOrSuspendedWorkspacesMigrationCommandOptions;
|
||||
};
|
||||
|
||||
type RichTextFieldsWithObjectMetadata = {
|
||||
richTextField: FieldMetadataEntity;
|
||||
objectMetadata: ObjectMetadataEntity | null;
|
||||
};
|
||||
|
||||
type ProcessRichTextFieldsArgs = {
|
||||
richTextFields: FieldMetadataEntity[];
|
||||
workspaceId: string;
|
||||
};
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:0-43:migrate-rich-text-content-patch',
|
||||
description: 'Migrate RICH_TEXT content from v1 to v2',
|
||||
})
|
||||
export class MigrateRichTextContentPatchCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
@InjectRepository(FieldMetadataEntity, 'metadata')
|
||||
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
@InjectRepository(FeatureFlag, 'core')
|
||||
protected readonly featureFlagRepository: Repository<FeatureFlag>,
|
||||
private readonly workspaceDataSourceService: WorkspaceDataSourceService,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
index,
|
||||
total,
|
||||
options,
|
||||
workspaceId,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`Running MigrateRichTextContentPatchCommand for workspace ${workspaceId} ${index + 1}/${total}`,
|
||||
);
|
||||
|
||||
if (await this.hasRichTextV2FeatureFlag(workspaceId)) {
|
||||
this.logger.log(
|
||||
chalk.yellow(
|
||||
'Rich text v2 feature flag is enabled, skipping migration',
|
||||
),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const richTextFields = await this.fieldMetadataRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
type: FieldMetadataType.RICH_TEXT,
|
||||
},
|
||||
});
|
||||
|
||||
if (!richTextFields.length) {
|
||||
this.logger.log(
|
||||
chalk.yellow('No RICH_TEXT fields found in this workspace'),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(`Found ${richTextFields.length} RICH_TEXT fields`);
|
||||
|
||||
const richTextFieldsWithObjectMetadata =
|
||||
await this.getRichTextFieldsWithObjectMetadata({
|
||||
richTextFields,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.migrateToNewRichTextFieldsColumn({
|
||||
richTextFieldsWithObjectMetadata,
|
||||
workspaceId,
|
||||
options,
|
||||
});
|
||||
|
||||
this.logger.log(
|
||||
chalk.green(`Command completed for workspace ${workspaceId}`),
|
||||
);
|
||||
}
|
||||
|
||||
private async hasRichTextV2FeatureFlag(
|
||||
workspaceId: string,
|
||||
): Promise<boolean> {
|
||||
return await this.featureFlagRepository.exists({
|
||||
where: {
|
||||
workspaceId,
|
||||
key: 'IS_RICH_TEXT_V2_ENABLED' as FeatureFlagKey,
|
||||
value: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async getRichTextFieldsWithObjectMetadata({
|
||||
richTextFields,
|
||||
workspaceId,
|
||||
}: ProcessRichTextFieldsArgs): Promise<RichTextFieldsWithObjectMetadata[]> {
|
||||
const richTextFieldsWithObjectMetadata: RichTextFieldsWithObjectMetadata[] =
|
||||
[];
|
||||
|
||||
for (const richTextField of richTextFields) {
|
||||
const objectMetadata = await this.objectMetadataRepository.findOne({
|
||||
where: { id: richTextField.objectMetadataId },
|
||||
relations: {
|
||||
fields: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (objectMetadata === null) {
|
||||
this.logger.log(
|
||||
`Object metadata not found for rich text field ${richTextField.name} in workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
richTextFieldsWithObjectMetadata.push({
|
||||
richTextField,
|
||||
objectMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
return richTextFieldsWithObjectMetadata;
|
||||
}
|
||||
|
||||
private jsonParseOrSilentlyFail(input: string): null | unknown {
|
||||
try {
|
||||
return JSON.parse(input);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private async getMarkdownFieldValue({
|
||||
blocknoteFieldValue,
|
||||
serverBlockNoteEditor,
|
||||
}: {
|
||||
blocknoteFieldValue: string | null;
|
||||
serverBlockNoteEditor: ServerBlockNoteEditor;
|
||||
}): Promise<string | null> {
|
||||
const blocknoteFieldValueIsDefined =
|
||||
blocknoteFieldValue !== null &&
|
||||
blocknoteFieldValue !== undefined &&
|
||||
blocknoteFieldValue !== '{}';
|
||||
|
||||
if (!blocknoteFieldValueIsDefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const jsonParsedblocknoteFieldValue =
|
||||
this.jsonParseOrSilentlyFail(blocknoteFieldValue);
|
||||
|
||||
if (jsonParsedblocknoteFieldValue === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Array.isArray(jsonParsedblocknoteFieldValue)) {
|
||||
this.logger.log(
|
||||
`blocknoteFieldValue is defined and is not an array got ${blocknoteFieldValue}`,
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
let markdown: string | null = null;
|
||||
|
||||
try {
|
||||
markdown = await serverBlockNoteEditor.blocksToMarkdownLossy(
|
||||
jsonParsedblocknoteFieldValue,
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.log(
|
||||
`Error converting blocknote to markdown for ${blocknoteFieldValue}`,
|
||||
);
|
||||
}
|
||||
|
||||
return markdown;
|
||||
}
|
||||
|
||||
private async migrateToNewRichTextFieldsColumn({
|
||||
richTextFieldsWithObjectMetadata,
|
||||
workspaceId,
|
||||
options,
|
||||
}: MigrateRichTextContentArgs) {
|
||||
const serverBlockNoteEditor = ServerBlockNoteEditor.create();
|
||||
|
||||
for (const {
|
||||
richTextField,
|
||||
objectMetadata,
|
||||
} of richTextFieldsWithObjectMetadata) {
|
||||
if (objectMetadata === null) {
|
||||
this.logger.log(
|
||||
`Object metadata not found for rich text field ${richTextField.name} in workspace ${workspaceId}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const schemaName =
|
||||
this.workspaceDataSourceService.getSchemaName(workspaceId);
|
||||
|
||||
const workspaceDataSource =
|
||||
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
|
||||
workspaceId,
|
||||
shouldFailIfMetadataNotFound: false,
|
||||
});
|
||||
|
||||
const rows = await workspaceDataSource.query(
|
||||
`SELECT id, "${richTextField.name}" FROM "${schemaName}"."${computeTableName(objectMetadata.nameSingular, objectMetadata.isCustom)}" WHERE "${richTextField.name}" IS NOT NULL`,
|
||||
undefined, // parameters
|
||||
undefined, // queryRunner
|
||||
{
|
||||
shouldBypassPermissionChecks: true,
|
||||
},
|
||||
);
|
||||
|
||||
this.logger.log(`Generating markdown for ${rows.length} records`);
|
||||
|
||||
for (const row of rows) {
|
||||
const blocknoteFieldValue = row[richTextField.name];
|
||||
const markdownFieldValue = await this.getMarkdownFieldValue({
|
||||
blocknoteFieldValue,
|
||||
serverBlockNoteEditor,
|
||||
});
|
||||
|
||||
if (!options.dryRun) {
|
||||
try {
|
||||
await workspaceDataSource.query(
|
||||
`UPDATE "${schemaName}"."${computeTableName(objectMetadata.nameSingular, objectMetadata.isCustom)}" SET "${richTextField.name}V2Blocknote" = $1, "${richTextField.name}V2Markdown" = $2 WHERE id = $3`,
|
||||
[blocknoteFieldValue, markdownFieldValue, row.id],
|
||||
undefined, // queryRunner
|
||||
{
|
||||
shouldBypassPermissionChecks: true,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
this.logger.log(
|
||||
chalk.red(
|
||||
`Error updating rich text field ${richTextField.name} for record ${row.id} in workspace ${workspaceId}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,96 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { Command } from 'nest-commander';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
||||
RunOnWorkspaceArgs,
|
||||
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { SearchVectorService } from 'src/engine/metadata-modules/search-vector/search-vector.service';
|
||||
import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { WorkspaceMigrationRunnerService } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service';
|
||||
import { SEARCH_FIELDS_FOR_NOTES } from 'src/modules/note/standard-objects/note.workspace-entity';
|
||||
import { SEARCH_FIELDS_FOR_TASKS } from 'src/modules/task/standard-objects/task.workspace-entity';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:0-43:migrate-search-vector-on-note-and-task-entities',
|
||||
description: 'Migrate search vector on note and task entities',
|
||||
})
|
||||
export class MigrateSearchVectorOnNoteAndTaskEntitiesCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
@InjectRepository(FeatureFlag, 'core')
|
||||
protected readonly featureFlagRepository: Repository<FeatureFlag>,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
protected readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
private readonly searchVectorService: SearchVectorService,
|
||||
private readonly workspaceMigrationRunnerService: WorkspaceMigrationRunnerService,
|
||||
private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
index,
|
||||
total,
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
|
||||
);
|
||||
|
||||
const noteObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneOrFail({
|
||||
select: ['id'],
|
||||
where: {
|
||||
workspaceId,
|
||||
nameSingular: 'note',
|
||||
},
|
||||
});
|
||||
|
||||
if (!options.dryRun) {
|
||||
await this.searchVectorService.updateSearchVector(
|
||||
noteObjectMetadata.id,
|
||||
SEARCH_FIELDS_FOR_NOTES,
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
const taskObjectMetadata =
|
||||
await this.objectMetadataRepository.findOneOrFail({
|
||||
select: ['id'],
|
||||
where: {
|
||||
workspaceId,
|
||||
nameSingular: 'task',
|
||||
},
|
||||
});
|
||||
|
||||
if (!options.dryRun) {
|
||||
await this.searchVectorService.updateSearchVector(
|
||||
taskObjectMetadata.id,
|
||||
SEARCH_FIELDS_FOR_TASKS,
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
await this.workspaceMetadataVersionService.incrementMetadataVersion(
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Migrated search vector on note and task entities for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import chalk from 'chalk';
|
||||
import { Command } from 'nest-commander';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
import {
|
||||
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
|
||||
RunOnWorkspaceArgs,
|
||||
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||
import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids';
|
||||
import { ViewOpenRecordInType } from 'src/modules/view/standard-objects/view.workspace-entity';
|
||||
|
||||
@Command({
|
||||
name: 'upgrade:0-43:update-default-view-record-opening-on-workflow-objects',
|
||||
description:
|
||||
'Update default view record opening on workflow objects to record page',
|
||||
})
|
||||
export class UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner {
|
||||
constructor(
|
||||
@InjectRepository(Workspace, 'core')
|
||||
protected readonly workspaceRepository: Repository<Workspace>,
|
||||
@InjectRepository(ObjectMetadataEntity, 'metadata')
|
||||
protected readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
|
||||
protected readonly twentyORMGlobalManager: TwentyORMGlobalManager,
|
||||
) {
|
||||
super(workspaceRepository, twentyORMGlobalManager);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
index,
|
||||
total,
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
this.logger.log(
|
||||
`Running command for workspace ${workspaceId} ${index + 1}/${total}`,
|
||||
);
|
||||
|
||||
const workflowObjectsMetadata = await this.objectMetadataRepository.find({
|
||||
select: ['id'],
|
||||
where: {
|
||||
workspaceId,
|
||||
standardId: In([
|
||||
STANDARD_OBJECT_IDS.workflow,
|
||||
STANDARD_OBJECT_IDS.workflowVersion,
|
||||
STANDARD_OBJECT_IDS.workflowRun,
|
||||
]),
|
||||
},
|
||||
});
|
||||
|
||||
if (workflowObjectsMetadata.length === 0) {
|
||||
this.logger.log(
|
||||
chalk.yellow(`No workflow objects found for workspace ${workspaceId}`),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.dryRun) {
|
||||
await this.updateDefaultViewsRecordOpening(
|
||||
workflowObjectsMetadata.map((metadata) => metadata.id),
|
||||
workspaceId,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
chalk.green(`Command completed for workspace ${workspaceId}.`),
|
||||
);
|
||||
}
|
||||
|
||||
private async updateDefaultViewsRecordOpening(
|
||||
workflowObjectMetadataIds: string[],
|
||||
workspaceId: string,
|
||||
): Promise<void> {
|
||||
const failOnMetadataCacheMiss = false;
|
||||
const viewRepository =
|
||||
await this.twentyORMGlobalManager.getRepositoryForWorkspace(
|
||||
workspaceId,
|
||||
'view',
|
||||
{
|
||||
shouldFailIfMetadataNotFound: failOnMetadataCacheMiss,
|
||||
},
|
||||
);
|
||||
|
||||
await viewRepository.update(
|
||||
{
|
||||
objectMetadataId: In(workflowObjectMetadataIds),
|
||||
key: 'INDEX',
|
||||
},
|
||||
{
|
||||
openRecordIn: ViewOpenRecordInType.RECORD_PAGE,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { AddTasksAssignedToMeViewCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-add-tasks-assigned-to-me-view.command';
|
||||
import { MigrateIsSearchableForCustomObjectMetadataCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-migrate-is-searchable-for-custom-object-metadata.command';
|
||||
import { MigrateRichTextContentPatchCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-migrate-rich-text-content-patch.command';
|
||||
import { MigrateSearchVectorOnNoteAndTaskEntitiesCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-migrate-search-vector-on-note-and-task-entities.command';
|
||||
import { UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-update-default-view-record-opening-on-workflow-objects.command';
|
||||
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { SearchVectorModule } from 'src/engine/metadata-modules/search-vector/search-vector.module';
|
||||
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
|
||||
import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module';
|
||||
import { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Workspace, FeatureFlag], 'core'),
|
||||
TypeOrmModule.forFeature(
|
||||
[FieldMetadataEntity, ObjectMetadataEntity],
|
||||
'metadata',
|
||||
),
|
||||
WorkspaceDataSourceModule,
|
||||
SearchVectorModule,
|
||||
WorkspaceMigrationRunnerModule,
|
||||
WorkspaceMetadataVersionModule,
|
||||
],
|
||||
providers: [
|
||||
MigrateRichTextContentPatchCommand,
|
||||
MigrateSearchVectorOnNoteAndTaskEntitiesCommand,
|
||||
UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand,
|
||||
MigrateIsSearchableForCustomObjectMetadataCommand,
|
||||
AddTasksAssignedToMeViewCommand,
|
||||
],
|
||||
exports: [
|
||||
MigrateRichTextContentPatchCommand,
|
||||
MigrateSearchVectorOnNoteAndTaskEntitiesCommand,
|
||||
UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand,
|
||||
MigrateIsSearchableForCustomObjectMetadataCommand,
|
||||
AddTasksAssignedToMeViewCommand,
|
||||
],
|
||||
})
|
||||
export class V0_43_UpgradeVersionCommandModule {}
|
||||
@ -1,7 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { V0_43_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/0-43/0-43-upgrade-version-command.module';
|
||||
import { V0_44_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/0-44/0-44-upgrade-version-command.module';
|
||||
import { V0_50_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/0-50/0-50-upgrade-version-command.module';
|
||||
import { V0_51_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/0-51/0-51-upgrade-version-command.module';
|
||||
@ -19,7 +18,6 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([Workspace], 'core'),
|
||||
V0_43_UpgradeVersionCommandModule,
|
||||
V0_44_UpgradeVersionCommandModule,
|
||||
V0_50_UpgradeVersionCommandModule,
|
||||
V0_51_UpgradeVersionCommandModule,
|
||||
|
||||
@ -15,11 +15,6 @@ import {
|
||||
UpgradeCommandRunner,
|
||||
VersionCommands,
|
||||
} from 'src/database/commands/command-runners/upgrade.command-runner';
|
||||
import { AddTasksAssignedToMeViewCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-add-tasks-assigned-to-me-view.command';
|
||||
import { MigrateIsSearchableForCustomObjectMetadataCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-migrate-is-searchable-for-custom-object-metadata.command';
|
||||
import { MigrateRichTextContentPatchCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-migrate-rich-text-content-patch.command';
|
||||
import { MigrateSearchVectorOnNoteAndTaskEntitiesCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-migrate-search-vector-on-note-and-task-entities.command';
|
||||
import { UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand } from 'src/database/commands/upgrade-version-command/0-43/0-43-update-default-view-record-opening-on-workflow-objects.command';
|
||||
import { InitializePermissionsCommand } from 'src/database/commands/upgrade-version-command/0-44/0-44-initialize-permissions.command';
|
||||
import { UpdateViewAggregateOperationsCommand } from 'src/database/commands/upgrade-version-command/0-44/0-44-update-view-aggregate-operations.command';
|
||||
import { UpgradeCreatedByEnumCommand } from 'src/database/commands/upgrade-version-command/0-51/0-51-update-workflow-trigger-type-enum.command';
|
||||
@ -152,13 +147,6 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
|
||||
private readonly databaseMigrationService: DatabaseMigrationService,
|
||||
|
||||
// 0.43 Commands
|
||||
protected readonly migrateRichTextContentPatchCommand: MigrateRichTextContentPatchCommand,
|
||||
protected readonly addTasksAssignedToMeViewCommand: AddTasksAssignedToMeViewCommand,
|
||||
protected readonly migrateIsSearchableForCustomObjectMetadataCommand: MigrateIsSearchableForCustomObjectMetadataCommand,
|
||||
protected readonly updateDefaultViewRecordOpeningOnWorkflowObjectsCommand: UpdateDefaultViewRecordOpeningOnWorkflowObjectsCommand,
|
||||
protected readonly migrateSearchVectorOnNoteAndTaskEntitiesCommand: MigrateSearchVectorOnNoteAndTaskEntitiesCommand,
|
||||
|
||||
// 0.44 Commands
|
||||
protected readonly initializePermissionsCommand: InitializePermissionsCommand,
|
||||
protected readonly updateViewAggregateOperationsCommand: UpdateViewAggregateOperationsCommand,
|
||||
@ -191,18 +179,6 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
syncWorkspaceMetadataCommand,
|
||||
);
|
||||
|
||||
const commands_043: VersionCommands = {
|
||||
beforeSyncMetadata: [
|
||||
this.migrateRichTextContentPatchCommand,
|
||||
this.migrateIsSearchableForCustomObjectMetadataCommand,
|
||||
this.migrateSearchVectorOnNoteAndTaskEntitiesCommand,
|
||||
this.migrateIsSearchableForCustomObjectMetadataCommand,
|
||||
],
|
||||
afterSyncMetadata: [
|
||||
this.updateDefaultViewRecordOpeningOnWorkflowObjectsCommand,
|
||||
this.addTasksAssignedToMeViewCommand,
|
||||
],
|
||||
};
|
||||
const commands_044: VersionCommands = {
|
||||
beforeSyncMetadata: [
|
||||
this.initializePermissionsCommand,
|
||||
@ -251,7 +227,6 @@ export class UpgradeCommand extends UpgradeCommandRunner {
|
||||
};
|
||||
|
||||
this.allCommands = {
|
||||
'0.43.0': commands_043,
|
||||
'0.44.0': commands_044,
|
||||
'0.50.0': commands_050,
|
||||
'0.51.0': commands_051,
|
||||
|
||||
@ -40,6 +40,11 @@ export const seedFeatureFlags = async (
|
||||
workspaceId: workspaceId,
|
||||
value: false,
|
||||
},
|
||||
{
|
||||
key: FeatureFlagKey.IS_AI_ENABLED,
|
||||
workspaceId: workspaceId,
|
||||
value: true,
|
||||
},
|
||||
])
|
||||
.execute();
|
||||
};
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class UpdateServerlessFunctionDefaultRuntimeToNode221749205425841
|
||||
implements MigrationInterface
|
||||
{
|
||||
name = 'UpdateServerlessFunctionDefaultRuntimeToNode221749205425841';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// Update the default value for the runtime column to nodejs22.x
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."serverlessFunction" ALTER COLUMN "runtime" SET DEFAULT 'nodejs22.x'`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
// Revert the default value back to nodejs18.x
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."serverlessFunction" ALTER COLUMN "runtime" SET DEFAULT 'nodejs18.x'`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { ServerBlockNoteEditor } from '@blocknote/server-util';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@ -101,6 +100,8 @@ export class RecordInputTransformerService {
|
||||
): Promise<RichTextV2Metadata> {
|
||||
const parsedValue = richTextV2ValueSchema.parse(richTextValue);
|
||||
|
||||
const { ServerBlockNoteEditor } = await import('@blocknote/server-util');
|
||||
|
||||
const serverBlockNoteEditor = ServerBlockNoteEditor.create();
|
||||
|
||||
// Patch: Handle cases where blocknote to markdown conversion fails for certain block types (custom/code blocks)
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import * as fs from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
|
||||
import ts, { transpileModule } from 'typescript';
|
||||
import {
|
||||
CreateFunctionCommandInput,
|
||||
CreateFunctionCommand,
|
||||
CreateFunctionCommandInput,
|
||||
DeleteFunctionCommand,
|
||||
GetFunctionCommand,
|
||||
InvokeCommand,
|
||||
@ -13,14 +12,15 @@ import {
|
||||
LambdaClientConfig,
|
||||
ListLayerVersionsCommand,
|
||||
ListLayerVersionsCommandInput,
|
||||
LogType,
|
||||
PublishLayerVersionCommand,
|
||||
PublishLayerVersionCommandInput,
|
||||
ResourceNotFoundException,
|
||||
waitUntilFunctionUpdatedV2,
|
||||
LogType,
|
||||
} from '@aws-sdk/client-lambda';
|
||||
import { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import ts, { transpileModule } from 'typescript';
|
||||
|
||||
import {
|
||||
ServerlessDriver,
|
||||
@ -28,8 +28,11 @@ import {
|
||||
} from 'src/engine/core-modules/serverless/drivers/interfaces/serverless-driver.interface';
|
||||
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { readFileContent } from 'src/engine/core-modules/file-storage/utils/read-file-content';
|
||||
import { COMMON_LAYER_NAME } from 'src/engine/core-modules/serverless/drivers/constants/common-layer-name';
|
||||
import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name';
|
||||
import { copyAndBuildDependencies } from 'src/engine/core-modules/serverless/drivers/utils/copy-and-build-dependencies';
|
||||
import { copyExecutor } from 'src/engine/core-modules/serverless/drivers/utils/copy-executor';
|
||||
import { createZipFile } from 'src/engine/core-modules/serverless/drivers/utils/create-zip-file';
|
||||
import {
|
||||
LambdaBuildDirectoryManager,
|
||||
@ -45,9 +48,6 @@ import {
|
||||
ServerlessFunctionException,
|
||||
ServerlessFunctionExceptionCode,
|
||||
} from 'src/engine/metadata-modules/serverless-function/serverless-function.exception';
|
||||
import { copyExecutor } from 'src/engine/core-modules/serverless/drivers/utils/copy-executor';
|
||||
import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name';
|
||||
import { readFileContent } from 'src/engine/core-modules/file-storage/utils/read-file-content';
|
||||
|
||||
const UPDATE_FUNCTION_DURATION_TIMEOUT_IN_SECONDS = 60;
|
||||
const CREDENTIALS_DURATION_IN_SECONDS = 60 * 60; // 1h
|
||||
@ -172,7 +172,10 @@ export class LambdaDriver implements ServerlessDriver {
|
||||
Content: {
|
||||
ZipFile: await fs.readFile(lambdaZipPath),
|
||||
},
|
||||
CompatibleRuntimes: [ServerlessFunctionRuntime.NODE18],
|
||||
CompatibleRuntimes: [
|
||||
ServerlessFunctionRuntime.NODE18,
|
||||
ServerlessFunctionRuntime.NODE22,
|
||||
],
|
||||
Description: `${version}`,
|
||||
};
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ const DEFAULT_SERVERLESS_TIMEOUT_SECONDS = 300; // 5 minutes
|
||||
|
||||
export enum ServerlessFunctionRuntime {
|
||||
NODE18 = 'nodejs18.x',
|
||||
NODE22 = 'nodejs22.x',
|
||||
}
|
||||
|
||||
@Entity('serverlessFunction')
|
||||
@ -38,7 +39,7 @@ export class ServerlessFunctionEntity {
|
||||
@Column({ nullable: true, type: 'jsonb' })
|
||||
latestVersionInputSchema: InputSchema;
|
||||
|
||||
@Column({ nullable: false, default: ServerlessFunctionRuntime.NODE18 })
|
||||
@Column({ nullable: false, default: ServerlessFunctionRuntime.NODE22 })
|
||||
runtime: ServerlessFunctionRuntime;
|
||||
|
||||
@Column({ nullable: false, default: DEFAULT_SERVERLESS_TIMEOUT_SECONDS })
|
||||
|
||||
Reference in New Issue
Block a user