mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
chore: resolve conflicts
This commit is contained in:
@@ -50,6 +50,16 @@ class TestController {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('legacy-wildcard/overview')
|
||||
testLegacyWildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('splat-wildcard/overview')
|
||||
testSplatWildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('overview/:id')
|
||||
overviewById() {
|
||||
return RETURN_VALUE;
|
||||
@@ -64,10 +74,17 @@ class TestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer
|
||||
.apply((req, res, next) => res.end(MIDDLEWARE_VALUE))
|
||||
.exclude('test', 'overview/:id', 'wildcard/(.*)', {
|
||||
path: 'middleware',
|
||||
method: RequestMethod.POST,
|
||||
})
|
||||
.exclude(
|
||||
'test',
|
||||
'overview/:id',
|
||||
'wildcard/*',
|
||||
'legacy-wildcard/(.*)',
|
||||
'splat-wildcard/*splat',
|
||||
{
|
||||
path: 'middleware',
|
||||
method: RequestMethod.POST,
|
||||
},
|
||||
)
|
||||
.forRoutes('*');
|
||||
}
|
||||
}
|
||||
@@ -126,6 +143,18 @@ describe('Exclude middleware (fastify)', () => {
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
it(`should exclude "/legacy-wildcard/overview" endpoint (by wildcard, legacy syntax)`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/legacy-wildcard/overview')
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
it(`should exclude "/splat-wildcard/overview" endpoint (by wildcard, new syntax)`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/splat-wildcard/overview')
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -41,6 +41,16 @@ class TestController {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('legacy-wildcard/overview')
|
||||
testLegacyWildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('splat-wildcard/overview')
|
||||
testSplatWildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('overview/:id')
|
||||
overviewById() {
|
||||
return RETURN_VALUE;
|
||||
@@ -60,12 +70,19 @@ class TestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer
|
||||
.apply((req, res, next) => res.send(MIDDLEWARE_VALUE))
|
||||
.exclude('test', 'overview/:id', 'wildcard/(.*)', {
|
||||
path: 'middleware',
|
||||
method: RequestMethod.POST,
|
||||
})
|
||||
.exclude(
|
||||
'test',
|
||||
'overview/:id',
|
||||
'wildcard/*',
|
||||
'legacy-wildcard/(.*)',
|
||||
'splat-wildcard/*splat',
|
||||
{
|
||||
path: 'middleware',
|
||||
method: RequestMethod.POST,
|
||||
},
|
||||
)
|
||||
.exclude('multiple/exclude')
|
||||
.forRoutes('*');
|
||||
.forRoutes('*path');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +133,18 @@ describe('Exclude middleware', () => {
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
it(`should exclude "/legacy-wildcard/overview" endpoint (by wildcard, legacy syntax)`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/legacy-wildcard/overview')
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
it(`should exclude "/splat-wildcard/overview" endpoint (by wildcard, new syntax)`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/splat-wildcard/overview')
|
||||
.expect(200, RETURN_VALUE);
|
||||
});
|
||||
|
||||
it(`should exclude "/multiple/exclude" endpoint`, () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/multiple/exclude')
|
||||
|
||||
@@ -3,10 +3,11 @@ import { ExpressAdapter } from '@nestjs/platform-express';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as express from 'express';
|
||||
import * as request from 'supertest';
|
||||
import { App } from 'supertest/types';
|
||||
import { AppModule } from '../src/app.module';
|
||||
|
||||
describe('Hello world (express instance)', () => {
|
||||
let server;
|
||||
let server: App;
|
||||
let app: INestApplication;
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
@@ -8,9 +8,9 @@ import {
|
||||
RequestMethod,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Response } from 'express';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { Response } from 'express';
|
||||
|
||||
const INCLUDED_VALUE = 'test_included';
|
||||
const RETURN_VALUE = 'test';
|
||||
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import * as request from 'supertest';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
|
||||
describe('Middleware (FastifyAdapter)', () => {
|
||||
let app: NestFastifyApplication;
|
||||
@@ -37,6 +37,11 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('legacy_style_wildcard/wildcard_nested')
|
||||
legacy_style_wildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('test')
|
||||
test() {
|
||||
return RETURN_VALUE;
|
||||
@@ -76,9 +81,13 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
.apply((req, res, next) => res.end(INCLUDED_VALUE))
|
||||
.forRoutes({ path: 'tests/included', method: RequestMethod.POST })
|
||||
.apply((req, res, next) => res.end(REQ_URL_VALUE))
|
||||
.forRoutes('req/url/(.*)')
|
||||
.forRoutes('req/url/*')
|
||||
.apply((req, res, next) => res.end(WILDCARD_VALUE))
|
||||
.forRoutes('express_style_wildcard/*', 'tests/(.*)')
|
||||
.forRoutes(
|
||||
'express_style_wildcard/*',
|
||||
'tests/*path',
|
||||
'legacy_style_wildcard/(.*)',
|
||||
)
|
||||
.apply((req, res, next) => res.end(QUERY_VALUE))
|
||||
.forRoutes('query')
|
||||
.apply((req, res, next) => next())
|
||||
@@ -87,7 +96,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
.forRoutes(TestController)
|
||||
.apply((req, res, next) => res.end(RETURN_VALUE))
|
||||
.exclude({ path: QUERY_VALUE, method: -1 as any })
|
||||
.forRoutes('(.*)');
|
||||
.forRoutes('*');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,7 +110,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it(`forRoutes((.*))`, () => {
|
||||
it(`forRoutes(*)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
@@ -143,7 +152,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(tests/(.*))`, () => {
|
||||
it(`forRoutes(tests/*path)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
@@ -161,6 +170,15 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(legacy_style_wildcard/*)`, () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/legacy_style_wildcard/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(req/url/)`, () => {
|
||||
const reqUrl = '/test';
|
||||
return app
|
||||
|
||||
@@ -26,6 +26,11 @@ class TestController {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('legacy-wildcard/overview')
|
||||
legacyWildcard() {
|
||||
return RETURN_VALUE;
|
||||
}
|
||||
|
||||
@Get('exclude')
|
||||
exclude() {
|
||||
return EXCLUDE_VALUE;
|
||||
@@ -40,7 +45,7 @@ class TestModule {
|
||||
configure(consumer: MiddlewareConsumer) {
|
||||
consumer
|
||||
.apply((req, res, next) => res.send(WILDCARD_VALUE))
|
||||
.forRoutes('tests/*')
|
||||
.forRoutes('tests/*path', 'legacy-wildcard/*')
|
||||
.apply((req, res, next) => res.send(SCOPED_VALUE))
|
||||
.exclude('exclude')
|
||||
.forRoutes(TestController)
|
||||
@@ -86,6 +91,13 @@ describe('Middleware', () => {
|
||||
.expect(200, WILDCARD_VALUE);
|
||||
});
|
||||
|
||||
it(`forRoutes(legacy-wildcard/*)`, async () => {
|
||||
app = await createApp();
|
||||
return request(app.getHttpServer())
|
||||
.get('/legacy-wildcard/overview')
|
||||
.expect(200, WILDCARD_VALUE);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('Global prefix', () => {
|
||||
|
||||
await request(server)
|
||||
.get('/api/test/params')
|
||||
.expect(200, { '0': 'params', tenantId: 'test' });
|
||||
.expect(200, { tenantId: 'test', path: ['params'] });
|
||||
});
|
||||
|
||||
it(`should execute middleware only once`, async () => {
|
||||
|
||||
@@ -16,24 +16,30 @@ export class AppModule {
|
||||
.apply((req, res, next) => res.status(201).end(MIDDLEWARE_VALUE))
|
||||
.forRoutes({ path: MIDDLEWARE_VALUE, method: RequestMethod.POST })
|
||||
.apply((req, res, next) => res.end(MIDDLEWARE_PARAM_VALUE))
|
||||
.forRoutes({ path: MIDDLEWARE_VALUE + '/*', method: RequestMethod.GET })
|
||||
.forRoutes({
|
||||
path: MIDDLEWARE_VALUE + '/*path',
|
||||
method: RequestMethod.GET,
|
||||
})
|
||||
.apply((req, res, next) => res.status(201).end(MIDDLEWARE_PARAM_VALUE))
|
||||
.forRoutes({ path: MIDDLEWARE_VALUE + '/*', method: RequestMethod.POST })
|
||||
.forRoutes({
|
||||
path: MIDDLEWARE_VALUE + '/*path',
|
||||
method: RequestMethod.POST,
|
||||
})
|
||||
.apply((req, res, next) => {
|
||||
req.extras = { data: 'Data attached in middleware' };
|
||||
next();
|
||||
})
|
||||
.forRoutes({ path: '*', method: RequestMethod.GET })
|
||||
.forRoutes({ path: '*path', method: RequestMethod.GET })
|
||||
.apply((req, res, next) => {
|
||||
req.middlewareParams = req.params;
|
||||
next();
|
||||
})
|
||||
.forRoutes({ path: '*', method: RequestMethod.GET })
|
||||
.forRoutes({ path: '*path', method: RequestMethod.GET })
|
||||
.apply((req, res, next) => {
|
||||
this.count += 1;
|
||||
req.count = this.count;
|
||||
next();
|
||||
})
|
||||
.forRoutes('*');
|
||||
.forRoutes('*path');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{
|
||||
"lerna": "2.4.0",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "10.4.15"
|
||||
"packages": ["packages/*"],
|
||||
"version": "11.0.0-next.1"
|
||||
}
|
||||
|
||||
795
package-lock.json
generated
795
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -64,12 +64,12 @@
|
||||
"class-transformer": "0.5.1",
|
||||
"class-validator": "0.14.1",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.21.2",
|
||||
"express": "5.0.1",
|
||||
"fast-json-stringify": "6.0.0",
|
||||
"fast-safe-stringify": "2.1.1",
|
||||
"iterare": "1.2.1",
|
||||
"object-hash": "3.0.0",
|
||||
"path-to-regexp": "3.3.0",
|
||||
"path-to-regexp": "8.2.0",
|
||||
"reflect-metadata": "0.2.2",
|
||||
"rxjs": "7.8.1",
|
||||
"socket.io": "4.8.1",
|
||||
@@ -84,10 +84,10 @@
|
||||
"@commitlint/config-angular": "19.6.0",
|
||||
"@eslint/eslintrc": "3.2.0",
|
||||
"@eslint/js": "9.15.0",
|
||||
"@fastify/cors": "9.0.1",
|
||||
"@fastify/formbody": "7.4.0",
|
||||
"@fastify/middie": "8.3.3",
|
||||
"@fastify/multipart": "8.3.0",
|
||||
"@fastify/cors": "10.0.1",
|
||||
"@fastify/formbody": "8.0.1",
|
||||
"@fastify/middie": "9.0.2",
|
||||
"@fastify/multipart": "9.0.1",
|
||||
"@fastify/static": "7.0.4",
|
||||
"@fastify/view": "9.1.0",
|
||||
"@grpc/grpc-js": "1.12.4",
|
||||
@@ -102,7 +102,7 @@
|
||||
"@types/chai-as-promised": "7.1.8",
|
||||
"@types/cors": "2.8.17",
|
||||
"@types/eslint__js": "8.42.3",
|
||||
"@types/express": "4.17.21",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/gulp": "4.0.17",
|
||||
"@types/http-errors": "2.0.4",
|
||||
"@types/mocha": "10.0.10",
|
||||
|
||||
@@ -102,4 +102,5 @@ export interface HttpServer<
|
||||
version: VersionValue,
|
||||
versioningOptions: VersioningOptions,
|
||||
): (req: TRequest, res: TResponse, next: () => void) => Function;
|
||||
normalizePath?(path: string): string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/common",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"homepage": "https://nestjs.com",
|
||||
|
||||
@@ -143,6 +143,10 @@ export abstract class AbstractHttpAdapter<
|
||||
return this.instance as T;
|
||||
}
|
||||
|
||||
public normalizePath(path: string): string {
|
||||
return path;
|
||||
}
|
||||
|
||||
abstract close();
|
||||
abstract initHttpServer(options: NestApplicationOptions);
|
||||
abstract useStaticAssets(...args: any[]);
|
||||
@@ -158,11 +162,7 @@ export abstract class AbstractHttpAdapter<
|
||||
abstract setErrorHandler(handler: Function, prefix?: string);
|
||||
abstract setNotFoundHandler(handler: Function, prefix?: string);
|
||||
abstract isHeadersSent(response: any);
|
||||
// TODO remove optional signature (v11)
|
||||
abstract getHeader?(response: any, name: string);
|
||||
abstract setHeader(response: any, name: string, value: string);
|
||||
// TODO remove optional signature (v11)
|
||||
abstract appendHeader?(response: any, name: string, value: string);
|
||||
abstract registerParserMiddleware(prefix?: string, rawBody?: boolean);
|
||||
abstract enableCors(
|
||||
options: CorsOptions | CorsOptionsDelegate<TRequest>,
|
||||
|
||||
@@ -71,7 +71,9 @@ export class RouteInfoPathExtractor {
|
||||
}
|
||||
|
||||
private isAWildcard(path: string): boolean {
|
||||
return ['*', '/*', '/*/', '(.*)', '/(.*)'].includes(path);
|
||||
return ['*', '/*', '/*/', '*path', '/*path', '(.*)', '/(.*)'].includes(
|
||||
path,
|
||||
);
|
||||
}
|
||||
|
||||
private extractNonWildcardPathsFrom({
|
||||
|
||||
@@ -6,27 +6,38 @@ import {
|
||||
isString,
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import { iterate } from 'iterare';
|
||||
import * as pathToRegexp from 'path-to-regexp';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import { uid } from 'uid';
|
||||
import { ExcludeRouteMetadata } from '../router/interfaces/exclude-route-metadata.interface';
|
||||
import { LegacyRouteConverter } from '../router/legacy-route-converter';
|
||||
import { isRouteExcluded } from '../router/utils';
|
||||
|
||||
export const mapToExcludeRoute = (
|
||||
routes: (string | RouteInfo)[],
|
||||
): ExcludeRouteMetadata[] => {
|
||||
return routes.map(route => {
|
||||
if (isString(route)) {
|
||||
const originalPath = isString(route) ? route : route.path;
|
||||
const path = LegacyRouteConverter.tryConvert(originalPath);
|
||||
|
||||
try {
|
||||
if (isString(route)) {
|
||||
return {
|
||||
path,
|
||||
requestMethod: RequestMethod.ALL,
|
||||
pathRegex: pathToRegexp(addLeadingSlash(path)).regexp,
|
||||
};
|
||||
}
|
||||
return {
|
||||
path: route,
|
||||
requestMethod: RequestMethod.ALL,
|
||||
pathRegex: pathToRegexp(addLeadingSlash(route)),
|
||||
path,
|
||||
requestMethod: route.method,
|
||||
pathRegex: pathToRegexp(addLeadingSlash(path)).regexp,
|
||||
};
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
LegacyRouteConverter.printError(originalPath);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return {
|
||||
path: route.path,
|
||||
requestMethod: route.method,
|
||||
pathRegex: pathToRegexp(addLeadingSlash(route.path)),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/core",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -31,12 +31,12 @@
|
||||
"@nuxtjs/opencollective": "0.3.2",
|
||||
"fast-safe-stringify": "2.1.1",
|
||||
"iterare": "1.2.1",
|
||||
"path-to-regexp": "3.3.0",
|
||||
"path-to-regexp": "8.2.0",
|
||||
"tslib": "2.8.1",
|
||||
"uid": "2.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "10.4.15"
|
||||
"@nestjs/common": "^11.0.0-next.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
|
||||
53
packages/core/router/legacy-route-converter.ts
Normal file
53
packages/core/router/legacy-route-converter.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
|
||||
const UNSUPPORTED_PATH_MESSAGE = (text: TemplateStringsArray, route: string) =>
|
||||
`Unsupported route path: "${route}". In previous versions, the symbols ?, *, and + were used to denote optional or repeating path parameters. The latest version of "path-to-regexp" now requires the use of named parameters. For example, instead of using a route like /users/* to capture all routes starting with "/users", you should use /users/*path. For more details, refer to the migration guide.`;
|
||||
|
||||
export class LegacyRouteConverter {
|
||||
private static readonly logger = new Logger(LegacyRouteConverter.name);
|
||||
|
||||
/**
|
||||
* Convert legacy routes to the new format (syntax).
|
||||
* path-to-regexp used by Express>=v5 and @fastify/middie>=v9 no longer support unnamed wildcards.
|
||||
* This method attempts to convert the old syntax to the new one, and logs an error if it fails.
|
||||
* @param route The route to convert.
|
||||
* @returns The converted route, or the original route if it cannot be converted.
|
||||
*/
|
||||
static tryConvert(route: string): string {
|
||||
// Normalize path to eliminate additional conditions.
|
||||
const routeWithLeadingSlash = route.startsWith('/') ? route : `/${route}`;
|
||||
const normalizedRoute = route.endsWith('/')
|
||||
? routeWithLeadingSlash
|
||||
: `${routeWithLeadingSlash}/`;
|
||||
|
||||
if (normalizedRoute.endsWith('/(.*)/')) {
|
||||
// Skip printing warning for the "all" wildcard.
|
||||
if (normalizedRoute !== '/(.*)/') {
|
||||
this.printWarning(route);
|
||||
}
|
||||
return route.replace('(.*)', '{*path}');
|
||||
}
|
||||
if (normalizedRoute.endsWith('/*/')) {
|
||||
// Skip printing warning for the "all" wildcard.
|
||||
if (normalizedRoute !== '/*/') {
|
||||
this.printWarning(route);
|
||||
}
|
||||
return route.replace('*', '{*path}');
|
||||
}
|
||||
if (normalizedRoute.endsWith('/+/')) {
|
||||
this.printWarning(route);
|
||||
return route.replace('/+', '/*path');
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
static printError(route: string): void {
|
||||
this.logger.error(UNSUPPORTED_PATH_MESSAGE`${route}`);
|
||||
}
|
||||
|
||||
static printWarning(route: string): void {
|
||||
this.logger.warn(
|
||||
UNSUPPORTED_PATH_MESSAGE`${route}` + ' Attempting to convert...',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
addLeadingSlash,
|
||||
isUndefined,
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import * as pathToRegexp from 'path-to-regexp';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import { ApplicationConfig } from '../application-config';
|
||||
import { UnknownRequestMappingException } from '../errors/exceptions/unknown-request-mapping.exception';
|
||||
import { GuardsConsumer, GuardsContextCreator } from '../guards';
|
||||
@@ -231,7 +231,10 @@ export class RouterExplorer {
|
||||
};
|
||||
|
||||
this.copyMetadataToCallback(targetCallback, routeHandler);
|
||||
routerMethodRef(path, routeHandler);
|
||||
const normalizedPath = router.normalizePath
|
||||
? router.normalizePath(path)
|
||||
: path;
|
||||
routerMethodRef(normalizedPath, routeHandler);
|
||||
|
||||
this.graphInspector.insertEntrypointDefinition<HttpEntrypointMetadata>(
|
||||
entrypointDefinition,
|
||||
@@ -270,9 +273,19 @@ export class RouterExplorer {
|
||||
const httpAdapterRef = this.container.getHttpAdapterRef();
|
||||
const hosts = Array.isArray(host) ? host : [host];
|
||||
const hostRegExps = hosts.map((host: string | RegExp) => {
|
||||
const keys: any[] = [];
|
||||
const regexp = pathToRegexp(host, keys);
|
||||
return { regexp, keys };
|
||||
if (typeof host === 'string') {
|
||||
try {
|
||||
return pathToRegexp(host);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
this.logger.error(
|
||||
`Unsupported host "${host}" syntax. In past releases, ?, *, and + were used to denote optional or repeating path parameters. The latest version of "path-to-regexp" now requires the use of named parameters. For example, instead of using a route like /users/* to capture all routes starting with "/users", you should use /users/*path. Please see the migration guide for more information.`,
|
||||
);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return { regexp: host, keys: [] };
|
||||
});
|
||||
|
||||
const unsupportedFilteringErrorMessage = Array.isArray(host)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { RequestMethod, Type } from '@nestjs/common';
|
||||
import { RequestMethod } from '@nestjs/common';
|
||||
import { addLeadingSlash } from '@nestjs/common/utils/shared.utils';
|
||||
import { expect } from 'chai';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import * as sinon from 'sinon';
|
||||
import {
|
||||
assignToken,
|
||||
@@ -11,7 +12,6 @@ import {
|
||||
mapToExcludeRoute,
|
||||
} from '../../middleware/utils';
|
||||
import { NoopHttpAdapter } from '../utils/noop-adapter.spec';
|
||||
import * as pathToRegexp from 'path-to-regexp';
|
||||
|
||||
describe('middleware utils', () => {
|
||||
const noopAdapter = new NoopHttpAdapter({});
|
||||
@@ -30,12 +30,12 @@ describe('middleware utils', () => {
|
||||
{
|
||||
path: stringRoute,
|
||||
requestMethod: RequestMethod.ALL,
|
||||
pathRegex: pathToRegexp(addLeadingSlash(stringRoute)),
|
||||
pathRegex: pathToRegexp(addLeadingSlash(stringRoute)).regexp,
|
||||
},
|
||||
{
|
||||
path: routeInfo.path,
|
||||
requestMethod: routeInfo.method,
|
||||
pathRegex: pathToRegexp(addLeadingSlash(routeInfo.path)),
|
||||
pathRegex: pathToRegexp(addLeadingSlash(routeInfo.path)).regexp,
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -121,7 +121,20 @@ describe('middleware utils', () => {
|
||||
sinon.stub(adapter, 'getRequestMethod').callsFake(() => 'GET');
|
||||
sinon.stub(adapter, 'getRequestUrl').callsFake(() => '/cats/3');
|
||||
});
|
||||
describe('when route is excluded', () => {
|
||||
describe('when route is excluded (new syntax *path)', () => {
|
||||
const path = '/cats/*path';
|
||||
const excludedRoutes = mapToExcludeRoute([
|
||||
{
|
||||
path,
|
||||
method: RequestMethod.GET,
|
||||
},
|
||||
]);
|
||||
it('should return true', () => {
|
||||
expect(isMiddlewareRouteExcluded({}, excludedRoutes, adapter)).to.be
|
||||
.true;
|
||||
});
|
||||
});
|
||||
describe('when route is excluded (legacy syntax (.*))', () => {
|
||||
const path = '/cats/(.*)';
|
||||
const excludedRoutes = mapToExcludeRoute([
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequestMethod, VersioningType, VERSION_NEUTRAL } from '@nestjs/common';
|
||||
import { RequestMethod, VERSION_NEUTRAL, VersioningType } from '@nestjs/common';
|
||||
import { expect } from 'chai';
|
||||
import * as pathToRegexp from 'path-to-regexp';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
import * as sinon from 'sinon';
|
||||
import { ApplicationConfig } from '../../application-config';
|
||||
import { RoutePathFactory } from '../../router/route-path-factory';
|
||||
@@ -248,7 +248,7 @@ describe('RoutePathFactory', () => {
|
||||
exclude: [
|
||||
{
|
||||
path: '/random',
|
||||
pathRegex: pathToRegexp('/random'),
|
||||
pathRegex: pathToRegexp('/random').regexp,
|
||||
requestMethod: RequestMethod.ALL,
|
||||
},
|
||||
],
|
||||
@@ -267,7 +267,7 @@ describe('RoutePathFactory', () => {
|
||||
exclude: [
|
||||
{
|
||||
path: '/cats',
|
||||
pathRegex: pathToRegexp('/cats'),
|
||||
pathRegex: pathToRegexp('/cats').regexp,
|
||||
requestMethod: RequestMethod.ALL,
|
||||
},
|
||||
],
|
||||
@@ -286,7 +286,7 @@ describe('RoutePathFactory', () => {
|
||||
exclude: [
|
||||
{
|
||||
path: '/cats',
|
||||
pathRegex: pathToRegexp('/cats'),
|
||||
pathRegex: pathToRegexp('/cats').regexp,
|
||||
requestMethod: RequestMethod.GET,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/microservices",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@microservices)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -22,8 +22,8 @@
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "10.4.15",
|
||||
"@nestjs/core": "10.4.15"
|
||||
"@nestjs/common": "^11.0.0-next.1",
|
||||
"@nestjs/core": "^11.0.0-next.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@grpc/grpc-js": "*",
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
} from '@nestjs/common/utils/shared.utils';
|
||||
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
|
||||
import { RouterMethodFactory } from '@nestjs/core/helpers/router-method-factory';
|
||||
import { LegacyRouteConverter } from '@nestjs/core/router/legacy-route-converter';
|
||||
import * as bodyparser from 'body-parser';
|
||||
import {
|
||||
json as bodyParserJson,
|
||||
@@ -143,7 +144,7 @@ export class ExpressAdapter extends AbstractHttpAdapter<
|
||||
return response.headersSent;
|
||||
}
|
||||
|
||||
public getHeader?(response: any, name: string) {
|
||||
public getHeader(response: any, name: string) {
|
||||
return response.get(name);
|
||||
}
|
||||
|
||||
@@ -151,10 +152,22 @@ export class ExpressAdapter extends AbstractHttpAdapter<
|
||||
return response.set(name, value);
|
||||
}
|
||||
|
||||
public appendHeader?(response: any, name: string, value: string) {
|
||||
public appendHeader(response: any, name: string, value: string) {
|
||||
return response.append(name, value);
|
||||
}
|
||||
|
||||
public normalizePath(path: string): string {
|
||||
try {
|
||||
const convertedPath = LegacyRouteConverter.tryConvert(path);
|
||||
return convertedPath;
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
LegacyRouteConverter.printError(path);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public listen(port: string | number, callback?: () => void): Server;
|
||||
public listen(
|
||||
port: string | number,
|
||||
@@ -224,9 +237,19 @@ export class ExpressAdapter extends AbstractHttpAdapter<
|
||||
public createMiddlewareFactory(
|
||||
requestMethod: RequestMethod,
|
||||
): (path: string, callback: Function) => any {
|
||||
return this.routerMethodFactory
|
||||
.get(this.instance, requestMethod)
|
||||
.bind(this.instance);
|
||||
return (path: string, callback: Function) => {
|
||||
try {
|
||||
const convertedPath = LegacyRouteConverter.tryConvert(path);
|
||||
return this.routerMethodFactory
|
||||
.get(this.instance, requestMethod)
|
||||
.call(this.instance, convertedPath, callback);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
LegacyRouteConverter.printError(path);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public initHttpServer(options: NestApplicationOptions) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-express",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-express)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -20,13 +20,13 @@
|
||||
"dependencies": {
|
||||
"body-parser": "1.20.3",
|
||||
"cors": "2.8.5",
|
||||
"express": "4.21.2",
|
||||
"express": "5.0.1",
|
||||
"multer": "1.4.4-lts.1",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "10.4.15",
|
||||
"@nestjs/core": "10.4.15"
|
||||
"@nestjs/common": "^11.0.0-next.1",
|
||||
"@nestjs/core": "^11.0.0-next.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { loadPackage } from '@nestjs/common/utils/load-package.util';
|
||||
import { isString, isUndefined } from '@nestjs/common/utils/shared.utils';
|
||||
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';
|
||||
import { LegacyRouteConverter } from '@nestjs/core/router/legacy-route-converter';
|
||||
import {
|
||||
FastifyBaseLogger,
|
||||
FastifyBodyParser,
|
||||
@@ -49,7 +50,7 @@ import {
|
||||
Chain as LightMyRequestChain,
|
||||
Response as LightMyRequestResponse,
|
||||
} from 'light-my-request';
|
||||
import * as pathToRegexp from 'path-to-regexp';
|
||||
import { pathToRegexp } from 'path-to-regexp';
|
||||
// `querystring` is used internally in fastify for registering urlencoded body parser.
|
||||
import { parse as querystringParse } from 'querystring';
|
||||
import {
|
||||
@@ -142,6 +143,7 @@ export class FastifyAdapter<
|
||||
TRawResponse
|
||||
> = FastifyInstance<TServer, TRawRequest, TRawResponse>,
|
||||
> extends AbstractHttpAdapter<TServer, TRequest, TReply> {
|
||||
protected readonly logger = new Logger(FastifyAdapter.name);
|
||||
protected readonly instance: TInstance;
|
||||
protected _pathPrefix?: string;
|
||||
|
||||
@@ -622,39 +624,46 @@ export class FastifyAdapter<
|
||||
const hasEndOfStringCharacter = path.endsWith('$');
|
||||
path = hasEndOfStringCharacter ? path.slice(0, -1) : path;
|
||||
|
||||
let normalizedPath = path.endsWith('/*')
|
||||
? `${path.slice(0, -1)}(.*)`
|
||||
: path;
|
||||
let normalizedPath = LegacyRouteConverter.tryConvert(path);
|
||||
|
||||
// Fallback to "(.*)" to support plugins like GraphQL
|
||||
normalizedPath = normalizedPath === '/(.*)' ? '(.*)' : normalizedPath;
|
||||
// Fallback to "*path" to support plugins like GraphQL
|
||||
normalizedPath = normalizedPath === '/*path' ? '*path' : normalizedPath;
|
||||
|
||||
// Normalize the path to support the prefix if it set in application
|
||||
normalizedPath =
|
||||
this._pathPrefix && !normalizedPath.startsWith(this._pathPrefix)
|
||||
? `${this._pathPrefix}${normalizedPath}(.*)`
|
||||
? `${this._pathPrefix}${normalizedPath}*path`
|
||||
: normalizedPath;
|
||||
|
||||
let re = pathToRegexp(normalizedPath);
|
||||
re = hasEndOfStringCharacter ? new RegExp(re.source + '$', re.flags) : re;
|
||||
try {
|
||||
let { regexp: re } = pathToRegexp(normalizedPath);
|
||||
re = hasEndOfStringCharacter
|
||||
? new RegExp(re.source + '$', re.flags)
|
||||
: re;
|
||||
|
||||
// The following type assertion is valid as we use import('@fastify/middie') rather than require('@fastify/middie')
|
||||
// ref https://github.com/fastify/middie/pull/55
|
||||
this.instance.use(
|
||||
normalizedPath,
|
||||
(req: any, res: any, next: Function) => {
|
||||
const queryParamsIndex = req.originalUrl.indexOf('?');
|
||||
const pathname =
|
||||
queryParamsIndex >= 0
|
||||
? req.originalUrl.slice(0, queryParamsIndex)
|
||||
: req.originalUrl;
|
||||
// The following type assertion is valid as we use import('@fastify/middie') rather than require('@fastify/middie')
|
||||
// ref https://github.com/fastify/middie/pull/55
|
||||
this.instance.use(
|
||||
normalizedPath,
|
||||
(req: any, res: any, next: Function) => {
|
||||
const queryParamsIndex = req.originalUrl.indexOf('?');
|
||||
const pathname =
|
||||
queryParamsIndex >= 0
|
||||
? req.originalUrl.slice(0, queryParamsIndex)
|
||||
: req.originalUrl;
|
||||
|
||||
if (!re.exec(pathname + '/') && normalizedPath) {
|
||||
return next();
|
||||
}
|
||||
return callback(req, res, next);
|
||||
},
|
||||
);
|
||||
if (!re.exec(pathname + '/') && normalizedPath) {
|
||||
return next();
|
||||
}
|
||||
return callback(req, res, next);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
LegacyRouteConverter.printError(path);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-fastify",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-fastify)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -23,7 +23,7 @@
|
||||
"@fastify/middie": "9.0.2",
|
||||
"fastify": "5.2.1",
|
||||
"light-my-request": "6.3.0",
|
||||
"path-to-regexp": "3.3.0",
|
||||
"path-to-regexp": "8.2.0",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-socket.io",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-socket.io)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/platform-ws",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@platform-ws)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/testing",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@testing)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nestjs/websockets",
|
||||
"version": "10.4.15",
|
||||
"version": "11.0.0-next.1",
|
||||
"description": "Nest - modern, fast, powerful node.js web framework (@websockets)",
|
||||
"author": "Kamil Mysliwiec",
|
||||
"license": "MIT",
|
||||
@@ -18,8 +18,8 @@
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/common": "10.4.15",
|
||||
"@nestjs/core": "10.4.15"
|
||||
"@nestjs/common": "^11.0.0-next.1",
|
||||
"@nestjs/core": "^11.0.0-next.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
|
||||
Reference in New Issue
Block a user