Upgrade NestJS from 10.x to 11.x (#15836)

## Overview
This PR upgrades all NestJS dependencies from version 10.x to 11.x,
following the [official migration
guide](https://docs.nestjs.com/migration-guide). This builds on top of
the v9 to v10 upgrade completed in PR #15835.

## Changes

### Dependencies Updated
**Core packages (10.x → 11.x):**
- `@nestjs/common`: 10.4.16 → 11.0.8
- `@nestjs/core`: 10.4.16 → 11.0.8
- `@nestjs/platform-express`: 10.4.16 → 11.0.8
- `@nestjs/config`: 3.2.3 → 3.3.0
- `@nestjs/passport`: 10.0.3 → 11.0.0
- `@nestjs/axios`: 3.0.2 → 3.1.2
- `@nestjs/schedule`: ^3.0.0 → ^4.1.1
- `@nestjs/serve-static`: 4.0.2 → 5.0.1
- `@nestjs/cache-manager`: ^2.2.1 → ^2.3.0
- `@nestjs/jwt`: 10.2.0 → 11.0.0
- `@nestjs/typeorm`: 10.0.2 → 11.0.0
- `@nestjs/terminus`: 11.0.0 (already on v11)
- `@nestjs/event-emitter`: 2.1.0 (compatible)

**DevDependencies:**
- `@nestjs/testing`: ^10.4.16 → ^11.0.8
- `@nestjs/schematics`: ^10.1.0 → ^11.0.2
- `@nestjs/cli`: 10.3.0 → 11.0.0

### Code Changes
**Fixed: TwentyConfigModule conditional imports**
- Updated `TwentyConfigModule.forRoot()` to use spread operator for
conditional imports
- Fixes TypeScript error with NestJS 11's stricter DynamicModule type
checking

**Cleanup: Removed unused package**
- Removed `@revertdotdev/revert-react` (not being used anywhere in the
codebase)

## Breaking Changes Addressed

### 1.  Reflector Type Inference
- **Impact**: None - codebase only uses `reflector.get()` method
- **Analysis**: Does not use `getAllAndMerge()` or `getAllAndOverride()`
(the methods with breaking changes)
- **Files reviewed**: feature-flag.guard.ts,
message-queue-metadata.accessor.ts,
workspace-query-hook-metadata.accessor.ts

### 2.  Lifecycle Hooks Execution Order
- **Change**: Termination hooks (`OnModuleDestroy`,
`BeforeApplicationShutdown`, `OnApplicationShutdown`) now execute in
REVERSE order
- **Analysis**: Reviewed all lifecycle hook implementations
  - Redis client cleanup
  - Database connection cleanup (GlobalWorkspaceDataSource)
  - BullMQ queue/worker cleanup
  - Cache storage cleanup
- **Result**: Dependency order is safe - services using connections
clean up before the connections themselves

### 3.  Middleware Registration Order
- **Change**: Global middleware now executes first regardless of import
order
- **Analysis**: Middleware is not registered as global, so execution
order remains consistent
- **Files reviewed**: app.module.ts, middleware.module.ts

## Testing

All tests passing and build successful:

**Unit Tests (283+ tests):**
-  Health module: 38 tests passed
-  Auth module: 115 tests passed (passport v11 integration)
-  REST API: 90 tests passed (middleware and express platform)
-  Feature flags: 17 tests passed (Reflector usage)
-  Workspace: 23 tests passed

**Build & Quality:**
-  Type checking: Passed
-  Linting: Passed
-  Build: 3,683 files compiled successfully

## Verification

Tested critical NestJS functionality:
-  Authentication & Security (JWT, OAuth, guards)
-  HTTP Platform (Express integration, REST endpoints)
-  Dependency Injection (Services, factories, providers)
-  Cache Management (Redis with @nestjs/cache-manager)
-  GraphQL (Query runners, resolvers)
-  Configuration (Environment config)
-  Scheduling (Cron jobs with @nestjs/schedule v4)
-  Lifecycle Hooks (Module initialization and cleanup)
-  Reflector (Metadata reflection in guards)

## Related PRs
- #15835 - Upgrade NestJS from 9.x to 10.x (completed)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Upgrades NestJS to v11 and updates routing patterns, auth strategies,
GraphQL schema options, and build/dist paths (scripts, Docker, Nx,
migrations, assets), plus enables Devtools in development.
> 
> - **Backend (NestJS 11 upgrade)**:
> - Bump `@nestjs/*` packages (core, platform-express, jwt, passport,
typeorm, serve-static, schedule, cli/testing/schematics) to v11.
> - Update REST/route-trigger/file controllers to new wildcard syntax
(`*path`).
> - Refactor OAuth (Google/Microsoft) and SAML strategies (abstract base
+ explicit `validate`); minor typings.
>   - Enable `DevtoolsModule` in development.
> - **GraphQL**:
> - Add `buildSchemaOptions.orphanedTypes` for client-config types; keep
Yoga/Sentry setup.
> - **Build/Runtime & Config**:
> - Standardize dist layout (remove `src` in paths): update scripts,
Docker `CMD`, Nx `project.json`, render scripts, TypeORM migration
paths, asset resolution.
> - Adjust `nest-cli.json` (watchOptions, asset globs, migrations
outDir, monorepo/root).
> - Improve config module imports (spread conditional); tsconfig
excludes `node_modules`.
>   - Minor Nx default: `start` target caching disabled.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1139fd85a97d0c72314d416d07464cc3c9942783. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This commit is contained in:
Félix Malfait
2025-11-16 18:20:06 +01:00
committed by GitHub
parent a2a7ff8b4b
commit 5dfb66917c
27 changed files with 1102 additions and 655 deletions
+9
View File
@@ -83,6 +83,15 @@ export class AppModule {
const modules: DynamicModule[] = [];
const frontPath = join(__dirname, '..', 'front');
// NestJS DevTools - can be useful for debugging and profiling
/* if (process.env.NODE_ENV === NodeEnvironment.DEVELOPMENT) {
modules.push(
DevtoolsModule.register({
http: true,
}),
);
} */
if (existsSync(frontPath)) {
modules.push(
ServeStaticModule.forRoot({
@@ -5,4 +5,4 @@ const IS_BUILT_THROUGH_TESTING_MODULE = !__dirname.includes('/dist/');
export const ASSET_PATH = IS_BUILT_THROUGH_TESTING_MODULE
? path.resolve(__dirname, `../`)
: path.resolve(__dirname, `../../assets`);
: path.resolve(__dirname, `..`);
@@ -76,7 +76,7 @@ export abstract class UpgradeCommandRunner extends ActiveOrSuspendedWorkspacesMi
try {
this.logger.log('Running core datasource migrations...');
const coreResult = await execPromise(
'npx -y typeorm migration:run -d dist/src/database/typeorm/core/core.datasource',
'npx -y typeorm migration:run -d dist/database/typeorm/core/core.datasource',
);
this.logger.log(coreResult.stdout);
@@ -45,12 +45,12 @@ export const typeORMCoreModuleOptions: TypeOrmModuleOptions = {
entities:
process.env.IS_BILLING_ENABLED === 'true'
? [
`${isJest ? '' : 'dist/'}src/engine/core-modules/**/*.entity{.ts,.js}`,
`${isJest ? '' : 'dist/'}src/engine/metadata-modules/**/*.entity{.ts,.js}`,
`${isJest ? 'src/' : 'dist/'}engine/core-modules/**/*.entity{.ts,.js}`,
`${isJest ? 'src/' : 'dist/'}engine/metadata-modules/**/*.entity{.ts,.js}`,
]
: [
`${isJest ? '' : 'dist/'}src/engine/core-modules/**/!(billing-*).entity.{ts,js}`,
`${isJest ? '' : 'dist/'}src/engine/metadata-modules/**/*.entity{.ts,.js}`,
`${isJest ? 'src/' : 'dist/'}engine/core-modules/**/!(billing-*).entity.{ts,js}`,
`${isJest ? 'src/' : 'dist/'}engine/metadata-modules/**/*.entity{.ts,.js}`,
],
synchronize: false,
migrationsRun: false,
@@ -59,11 +59,11 @@ export const typeORMCoreModuleOptions: TypeOrmModuleOptions = {
migrations:
process.env.IS_BILLING_ENABLED === 'true'
? [
`${isJest ? '' : 'dist/'}src/database/typeorm/core/migrations/common/*{.ts,.js}`,
`${isJest ? '' : 'dist/'}src/database/typeorm/core/migrations/billing/*{.ts,.js}`,
`${isJest ? 'src/' : 'dist/'}database/typeorm/core/migrations/common/*{.ts,.js}`,
`${isJest ? 'src/' : 'dist/'}database/typeorm/core/migrations/billing/*{.ts,.js}`,
]
: [
`${isJest ? '' : 'dist/'}src/database/typeorm/core/migrations/common/*{.ts,.js}`,
`${isJest ? 'src/' : 'dist/'}database/typeorm/core/migrations/common/*{.ts,.js}`,
],
ssl:
process.env.PG_SSL_ALLOW_SELF_SIGNED === 'true'
@@ -19,6 +19,17 @@ import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interface
import { WorkspaceSchemaFactory } from 'src/engine/api/graphql/workspace-schema.factory';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import {
ApiConfig,
Billing,
Captcha,
ClientAIModelConfig,
NativeModelCapabilities,
PublicFeatureFlag,
PublicFeatureFlagMetadata,
Sentry as SentryConfig,
Support,
} from 'src/engine/core-modules/client-config/client-config.entity';
import { CoreEngineModule } from 'src/engine/core-modules/core-engine.module';
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
import { useSentryTracing } from 'src/engine/core-modules/exception-handler/hooks/use-sentry-tracing';
@@ -69,6 +80,19 @@ export class GraphQLConfigService
const config: YogaDriverConfig = {
autoSchemaFile: true,
include: [CoreEngineModule],
buildSchemaOptions: {
orphanedTypes: [
ApiConfig,
Billing,
Captcha,
ClientAIModelConfig,
NativeModelCapabilities,
PublicFeatureFlag,
PublicFeatureFlagMetadata,
SentryConfig,
Support,
],
},
conditionalSchema: async (context) => {
let user: UserEntity | null | undefined;
let workspace: WorkspaceEntity | undefined;
@@ -28,7 +28,7 @@ export class RestApiCoreController {
private readonly logger = new Logger(RestApiCoreController.name);
constructor(private readonly restApiCoreService: RestApiCoreService) {}
@Post('batch/*')
@Post('batch/*path')
async handleApiPostBatch(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -41,7 +41,7 @@ export class RestApiCoreController {
res.status(201).send(result);
}
@Post('*/duplicates')
@Post('*path/duplicates')
async handleApiFindDuplicates(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -54,7 +54,7 @@ export class RestApiCoreController {
res.status(200).send(result);
}
@Post('*')
@Post('*path')
async handleApiPost(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -68,7 +68,7 @@ export class RestApiCoreController {
}
//TODO: Refacto-common - Document this endpoint
@Get('*/groupBy')
@Get('*path/groupBy')
async handleApiGroupBy(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -81,7 +81,7 @@ export class RestApiCoreController {
res.status(200).send(result);
}
@Get('*')
@Get('*path')
async handleApiGet(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -94,7 +94,7 @@ export class RestApiCoreController {
res.status(200).send(result);
}
@Delete('*')
@Delete('*path')
async handleApiDelete(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -107,7 +107,7 @@ export class RestApiCoreController {
res.status(200).send(result);
}
@Patch('restore/*')
@Patch('restore/*path')
async handleApiRestore(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -120,7 +120,7 @@ export class RestApiCoreController {
res.status(200).send(result);
}
@Patch('*/merge')
@Patch('*path/merge')
async handleApiMerge(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -133,7 +133,7 @@ export class RestApiCoreController {
res.status(200).send(result);
}
@Patch('*')
@Patch('*path')
async handleApiPatch(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -149,7 +149,7 @@ export class RestApiCoreController {
// This endpoint is not documented in the OpenAPI schema.
// We keep it to avoid a breaking change since it initially used PUT instead
// of PATCH, and because the PUT verb is often used as a PATCH.
@Put('*')
@Put('*path')
async handleApiPut(
@Req() request: AuthenticatedRequest,
@Res() res: Response,
@@ -19,7 +19,7 @@ import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.g
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants';
@Controller('rest/metadata/*')
@Controller('rest/metadata/*path')
@UseGuards(
JwtAuthGuard,
WorkspaceAuthGuard,
@@ -8,6 +8,7 @@ import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity';
import { ApiKeyModule } from 'src/engine/core-modules/api-key/api-key.module';
import { AppTokenEntity } from 'src/engine/core-modules/app-token/app-token.entity';
import { AppTokenService } from 'src/engine/core-modules/app-token/services/app-token.service';
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
import { GoogleAPIsAuthController } from 'src/engine/core-modules/auth/controllers/google-apis-auth.controller';
import { GoogleAuthController } from 'src/engine/core-modules/auth/controllers/google-auth.controller';
@@ -62,7 +63,6 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
import { MessagingFolderSyncManagerModule } from 'src/modules/messaging/message-folder-manager/messaging-folder-sync-manager.module';
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
import { TwoFactorAuthenticationMethodEntity } from '../two-factor-authentication/entities/two-factor-authentication-method.entity';
import { TwoFactorAuthenticationModule } from '../two-factor-authentication/two-factor-authentication.module';
@@ -92,8 +92,8 @@ import { JwtAuthStrategy } from './strategies/jwt.auth.strategy';
KeyValuePairEntity,
UserWorkspaceEntity,
TwoFactorAuthenticationMethodEntity,
ObjectMetadataEntity,
]),
TypeOrmModule.forFeature([ObjectMetadataEntity]),
HttpModule,
UserWorkspaceModule,
WorkspaceModule,
@@ -1,18 +1,16 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-google-oauth20';
import { Strategy, type VerifyCallback } from 'passport-google-oauth20';
import { getGoogleApisOauthScopes } from 'src/engine/core-modules/auth/utils/get-google-apis-oauth-scopes';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { type TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
export type GoogleAPIScopeConfig = {
isCalendarEnabled?: boolean;
isMessagingAliasFetchingEnabled?: boolean;
};
@Injectable()
export class GoogleAPIsOauthCommonStrategy extends PassportStrategy(
export abstract class GoogleAPIsOauthCommonStrategy extends PassportStrategy(
Strategy,
'google-apis',
) {
@@ -27,4 +25,12 @@ export class GoogleAPIsOauthCommonStrategy extends PassportStrategy(
passReqToCallback: true,
});
}
abstract validate(
request: Express.Request,
accessToken: string,
refreshToken: string,
profile: unknown,
done: VerifyCallback,
): Promise<void>;
}
@@ -1,5 +1,7 @@
import { Injectable } from '@nestjs/common';
import { type VerifyCallback } from 'passport-google-oauth20';
import { GoogleAPIsOauthCommonStrategy } from 'src/engine/core-modules/auth/strategies/google-apis-oauth-common.auth.strategy';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@@ -31,4 +33,16 @@ export class GoogleAPIsOauthRequestCodeStrategy extends GoogleAPIsOauthCommonStr
return super.authenticate(req, options);
}
async validate(
_request: Express.Request,
_accessToken: string,
_refreshToken: string,
_profile: unknown,
done: VerifyCallback,
): Promise<void> {
// This strategy is only used for requesting authorization code
// No validation is performed here
done(null, {});
}
}
@@ -1,18 +1,17 @@
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-microsoft';
import { type VerifyCallback } from 'passport-google-oauth20';
import { getMicrosoftApisOauthScopes } from 'src/engine/core-modules/auth/utils/get-microsoft-apis-oauth-scopes';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { type TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
export type MicrosoftAPIScopeConfig = {
isCalendarEnabled?: boolean;
isMessagingAliasFetchingEnabled?: boolean;
};
@Injectable()
export class MicrosoftAPIsOauthCommonStrategy extends PassportStrategy(
export abstract class MicrosoftAPIsOauthCommonStrategy extends PassportStrategy(
Strategy,
'microsoft-apis',
) {
@@ -28,4 +27,12 @@ export class MicrosoftAPIsOauthCommonStrategy extends PassportStrategy(
passReqToCallback: true,
});
}
abstract validate(
request: Express.Request,
accessToken: string,
refreshToken: string,
profile: unknown,
done: VerifyCallback,
): Promise<void>;
}
@@ -1,5 +1,7 @@
import { Injectable } from '@nestjs/common';
import { type VerifyCallback } from 'passport-google-oauth20';
import { MicrosoftAPIsOauthCommonStrategy } from 'src/engine/core-modules/auth/strategies/microsoft-apis-oauth-common.auth.strategy';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
@@ -26,4 +28,16 @@ export class MicrosoftAPIsOauthRequestCodeStrategy extends MicrosoftAPIsOauthCom
return super.authenticate(req, options);
}
async validate(
_request: Express.Request,
_accessToken: string,
_refreshToken: string,
_profile: unknown,
done: VerifyCallback,
): Promise<void> {
// This strategy is only used for requesting authorization code
// No validation is performed here
done(null, {});
}
}
@@ -37,40 +37,46 @@ export class SamlAuthStrategy extends PassportStrategy(
'saml',
) {
constructor(private readonly sSOService: SSOService) {
super({
getSamlOptions: (req, callback) => {
this.sSOService
.findSSOIdentityProviderById(req.params.identityProviderId)
.then((identityProvider) => {
if (
identityProvider &&
this.sSOService.isSAMLIdentityProvider(identityProvider)
) {
const config: SamlConfig = {
entryPoint: identityProvider.ssoURL,
issuer: this.sSOService.buildIssuerURL(identityProvider),
callbackUrl: this.sSOService.buildCallbackUrl(identityProvider),
idpCert: identityProvider.certificate,
// TODO: Improve the feature by sign the response
wantAssertionsSigned: false,
wantAuthnResponseSigned: false,
disableRequestedAuthnContext: true,
signatureAlgorithm: 'sha256',
};
super(
{
getSamlOptions: (req, callback) => {
this.sSOService
.findSSOIdentityProviderById(req.params.identityProviderId)
.then((identityProvider) => {
if (
identityProvider &&
this.sSOService.isSAMLIdentityProvider(identityProvider)
) {
const config: SamlConfig = {
entryPoint: identityProvider.ssoURL,
issuer: this.sSOService.buildIssuerURL(identityProvider),
callbackUrl:
this.sSOService.buildCallbackUrl(identityProvider),
idpCert: identityProvider.certificate,
// TODO: Improve the feature by sign the response
wantAssertionsSigned: false,
wantAuthnResponseSigned: false,
disableRequestedAuthnContext: true,
signatureAlgorithm: 'sha256',
};
return callback(null, config);
}
return callback(null, config);
}
// TODO: improve error management
return callback(new Error('Invalid SAML identity provider'));
})
.catch((err) => {
// TODO: improve error management
return callback(err);
});
// TODO: improve error management
return callback(new Error('Invalid SAML identity provider'));
})
.catch((err) => {
// TODO: improve error management
return callback(err);
});
},
passReqToCallback: true,
} as PassportSamlConfig & MultiStrategyConfig,
async (request: Request, profile, done) => {
await this.validate(request, profile, done);
},
passReqToCallback: true,
} as PassportSamlConfig & MultiStrategyConfig);
);
}
authenticate(req: Request, options: AuthenticateOptions) {
@@ -20,7 +20,7 @@ registerEnumType(ModelProvider, {
});
@ObjectType()
class NativeModelCapabilities {
export class NativeModelCapabilities {
@Field(() => Boolean, { nullable: true })
webSearch?: boolean;
@@ -50,7 +50,7 @@ export class ClientAIModelConfig {
}
@ObjectType()
class Billing {
export class Billing {
@Field(() => Boolean)
isBillingEnabled: boolean;
@@ -62,7 +62,7 @@ class Billing {
}
@ObjectType()
class Support {
export class Support {
@Field(() => SupportDriver)
supportDriver: SupportDriver;
@@ -71,7 +71,7 @@ class Support {
}
@ObjectType()
class Sentry {
export class Sentry {
@Field(() => String, { nullable: true })
environment?: string;
@@ -83,7 +83,7 @@ class Sentry {
}
@ObjectType()
class Captcha {
export class Captcha {
@Field(() => CaptchaDriverType, { nullable: true })
provider: CaptchaDriverType | undefined;
@@ -92,13 +92,13 @@ class Captcha {
}
@ObjectType()
class ApiConfig {
export class ApiConfig {
@Field(() => Number, { nullable: false })
mutationMaximumAffectedRecords: number;
}
@ObjectType()
class PublicFeatureFlagMetadata {
export class PublicFeatureFlagMetadata {
@Field(() => String)
label: string;
@@ -110,7 +110,7 @@ class PublicFeatureFlagMetadata {
}
@ObjectType()
class PublicFeatureFlag {
export class PublicFeatureFlag {
@Field(() => FeatureFlagKey)
key: FeatureFlagKey;
@@ -32,7 +32,7 @@ import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
export class FileController {
constructor(private readonly fileService: FileService) {}
@Get('*/:filename')
@Get('*path/:filename')
@UseGuards(PublicEndpointGuard, NoPermissionGuard)
async getFile(
@Param() _params: string[],
@@ -25,12 +25,9 @@ export class TwentyConfigModule extends ConfigurableModuleClass {
validate,
envFilePath: process.env.NODE_ENV === 'test' ? '.env.test' : '.env',
}),
...(isConfigVariablesInDbEnabled ? [DatabaseConfigModule.forRoot()] : []),
];
if (isConfigVariablesInDbEnabled) {
imports.push(DatabaseConfigModule.forRoot());
}
return {
module: TwentyConfigModule,
imports,
@@ -24,7 +24,7 @@ import { RouteTriggerService } from 'src/engine/metadata-modules/route-trigger/r
export class RouteTriggerController {
constructor(private readonly routeTriggerService: RouteTriggerService) {}
@Get('*')
@Get('*path')
async get(@Req() request: Request) {
return await this.routeTriggerService.handle({
request,
@@ -32,7 +32,7 @@ export class RouteTriggerController {
});
}
@Post('*')
@Post('*path')
async post(@Req() request: Request) {
return await this.routeTriggerService.handle({
request,
@@ -40,7 +40,7 @@ export class RouteTriggerController {
});
}
@Put('*')
@Put('*path')
async put(@Req() request: Request) {
return await this.routeTriggerService.handle({
request,
@@ -48,7 +48,7 @@ export class RouteTriggerController {
});
}
@Patch('*')
@Patch('*path')
async patch(@Req() request: Request) {
return await this.routeTriggerService.handle({
request,
@@ -56,7 +56,7 @@ export class RouteTriggerController {
});
}
@Delete('*')
@Delete('*path')
async delete(@Req() request: Request) {
return await this.routeTriggerService.handle({
request,
@@ -379,7 +379,7 @@ export class DevSeederDataService {
const sampleFilesDir = IS_BUILT
? join(
__dirname,
'../../../../../../assets/engine/workspace-manager/dev-seeder/data/sample-files',
'../../../../../assets/engine/workspace-manager/dev-seeder/data/sample-files',
)
: join(__dirname, '../sample-files');