@nestjs/platform-fastify 12.0.0 → 12.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -125,8 +125,24 @@ export declare class FastifyAdapter<TServer extends RawServerBase = RawServerDef
125
125
  private registerMiddie;
126
126
  private getRequestOriginalUrl;
127
127
  private injectRouteOptions;
128
+ /**
129
+ * Fastify still accepts the router options ("ignoreTrailingSlash",
130
+ * "caseSensitive", ...) at the top level, but "initialConfig.routerOptions"
131
+ * only reflects them when they are passed through "routerOptions". As the
132
+ * adapter always passes "routerOptions" (for the version constraint), the
133
+ * top-level values are folded in so that plugins relying on
134
+ * "initialConfig.routerOptions" (like @fastify/middie) normalize request
135
+ * paths exactly like the router does.
136
+ */
137
+ private getTopLevelRouterOptions;
128
138
  private sanitizeUrl;
129
139
  private removeDuplicateSlashes;
130
140
  private trimLastSlash;
141
+ /**
142
+ * Mirrors the absolute-form request target handling of "find-my-way".
143
+ * Returns the path of an absolute-form target ("http://host/path" -> "/path")
144
+ * and leaves any other request target untouched.
145
+ */
146
+ private getPathFromRequestTarget;
131
147
  }
132
148
  export {};
@@ -1,8 +1,9 @@
1
1
  import { HttpException, HttpStatus, Logger, StreamableFile, VERSION_NEUTRAL, VersioningType, } from '@nestjs/common';
2
2
  import { fastify, } from 'fastify';
3
- import * as Reply from 'fastify/lib/reply.js';
3
+ import Reply from 'fastify/lib/reply.js';
4
4
  import fastifySymbols from 'fastify/lib/symbols.js';
5
5
  import { pathToRegexp } from 'path-to-regexp';
6
+ import middie from '@fastify/middie';
6
7
  import { loadPackage, isNil, isString, isUndefined, } from '@nestjs/common/internal';
7
8
  import { AbstractHttpAdapter } from '@nestjs/core';
8
9
  import { LegacyRouteConverter } from '@nestjs/core/internal';
@@ -11,7 +12,6 @@ const { kRouteContext } = fastifySymbols;
11
12
  import { parse as querystringParse } from 'fast-querystring';
12
13
  import urlSanitizer from 'find-my-way/lib/url-sanitizer.js';
13
14
  import { FASTIFY_ROUTE_CONFIG_METADATA, FASTIFY_ROUTE_CONSTRAINTS_METADATA, FASTIFY_ROUTE_SCHEMA_METADATA, } from '../constants.js';
14
- import middie from './middie/fastify-middie.js';
15
15
  const { safeDecodeURI } = urlSanitizer;
16
16
  /**
17
17
  * @publicApi
@@ -68,7 +68,7 @@ export class FastifyAdapter extends AbstractHttpAdapter {
68
68
  const acceptHeaderValue = (req.headers?.[MEDIA_TYPE_HEADER] || req.headers?.[MEDIA_TYPE_HEADER.toLowerCase()]);
69
69
  const acceptHeaderVersionParameter = acceptHeaderValue
70
70
  ? acceptHeaderValue.split(';')[1]
71
- : '';
71
+ : undefined;
72
72
  return isUndefined(acceptHeaderVersionParameter)
73
73
  ? VERSION_NEUTRAL // No version was supplied
74
74
  : acceptHeaderVersionParameter.split(this.versioningOptions.key)[1];
@@ -99,6 +99,7 @@ export class FastifyAdapter extends AbstractHttpAdapter {
99
99
  : fastify({
100
100
  ...instanceOrOptions,
101
101
  routerOptions: {
102
+ ...this.getTopLevelRouterOptions(instanceOrOptions),
102
103
  ...instanceOrOptions?.routerOptions,
103
104
  constraints: {
104
105
  version: this.versionConstraint,
@@ -540,9 +541,39 @@ export class FastifyAdapter extends AbstractHttpAdapter {
540
541
  }
541
542
  return this.instance.route(routeToInject);
542
543
  }
544
+ /**
545
+ * Fastify still accepts the router options ("ignoreTrailingSlash",
546
+ * "caseSensitive", ...) at the top level, but "initialConfig.routerOptions"
547
+ * only reflects them when they are passed through "routerOptions". As the
548
+ * adapter always passes "routerOptions" (for the version constraint), the
549
+ * top-level values are folded in so that plugins relying on
550
+ * "initialConfig.routerOptions" (like @fastify/middie) normalize request
551
+ * paths exactly like the router does.
552
+ */
553
+ getTopLevelRouterOptions(options) {
554
+ const routerOptions = {};
555
+ const routerOptionKeys = [
556
+ 'ignoreTrailingSlash',
557
+ 'ignoreDuplicateSlashes',
558
+ 'caseSensitive',
559
+ 'useSemicolonDelimiter',
560
+ 'maxParamLength',
561
+ 'allowUnsafeRegex',
562
+ ];
563
+ for (const key of routerOptionKeys) {
564
+ if (options?.[key] !== undefined) {
565
+ routerOptions[key] = options[key];
566
+ }
567
+ }
568
+ return routerOptions;
569
+ }
543
570
  sanitizeUrl(url) {
544
571
  const initialConfig = this.instance.initialConfig;
545
572
  const routerOptions = initialConfig.routerOptions;
573
+ // Absolute-form request targets ("GET http://host/path HTTP/1.1") must be
574
+ // resolved to their path before any other normalization, as the Fastify
575
+ // router does, so that middleware and routes always match the same path.
576
+ url = this.getPathFromRequestTarget(url);
546
577
  if (routerOptions.ignoreDuplicateSlashes ||
547
578
  initialConfig.ignoreDuplicateSlashes) {
548
579
  url = this.removeDuplicateSlashes(url);
@@ -570,4 +601,29 @@ export class FastifyAdapter extends AbstractHttpAdapter {
570
601
  }
571
602
  return path;
572
603
  }
604
+ /**
605
+ * Mirrors the absolute-form request target handling of "find-my-way".
606
+ * Returns the path of an absolute-form target ("http://host/path" -> "/path")
607
+ * and leaves any other request target untouched.
608
+ */
609
+ getPathFromRequestTarget(url) {
610
+ if (url.charCodeAt(0) === 47 /* '/' */) {
611
+ return url;
612
+ }
613
+ const schemeEnd = url.indexOf('://');
614
+ if (schemeEnd === -1) {
615
+ return url;
616
+ }
617
+ const scheme = url.slice(0, schemeEnd).toLowerCase();
618
+ if (scheme !== 'http' && scheme !== 'https') {
619
+ return url;
620
+ }
621
+ const authorityStart = schemeEnd + 3;
622
+ const pathStart = url.indexOf('/', authorityStart);
623
+ if (pathStart === authorityStart || !URL.canParse(url)) {
624
+ // Malformed target: the router rejects it before any middleware runs
625
+ return url;
626
+ }
627
+ return pathStart === -1 ? '/' : url.slice(pathStart);
628
+ }
573
629
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestjs/platform-fastify",
3
- "version": "12.0.0",
3
+ "version": "12.0.2",
4
4
  "description": "Nest - modern, fast, powerful node.js web framework (@platform-fastify)",
5
5
  "author": "Kamil Mysliwiec",
6
6
  "license": "MIT",
@@ -27,20 +27,19 @@
27
27
  "dependencies": {
28
28
  "@fastify/cors": "11.3.0",
29
29
  "@fastify/formbody": "9.0.0",
30
+ "@fastify/middie": "9.3.4",
30
31
  "fast-querystring": "1.1.2",
31
- "fastify": "5.12.1",
32
- "fastify-plugin": "6.0.0",
32
+ "fastify": "5.12.4",
33
33
  "find-my-way": "9.9.0",
34
34
  "light-my-request": "6.6.0",
35
35
  "path-to-regexp": "8.4.2",
36
- "reusify": "1.1.0",
37
36
  "tslib": "2.8.1"
38
37
  },
39
38
  "peerDependencies": {
40
39
  "@fastify/static": "^10.1.2",
41
40
  "@fastify/view": "^10.0.0 || ^11.0.0 || ^12.0.0",
42
- "@nestjs/common": "^11.0.0",
43
- "@nestjs/core": "^11.0.0"
41
+ "@nestjs/common": "^12.0.0",
42
+ "@nestjs/core": "^12.0.0"
44
43
  },
45
44
  "peerDependenciesMeta": {
46
45
  "@fastify/static": {
@@ -50,5 +49,5 @@
50
49
  "optional": true
51
50
  }
52
51
  },
53
- "gitHead": "6494a6c27400547ea6cd9b78da07b2e9c2547ca0"
52
+ "gitHead": "ee168a569d30e600d301ed38abb14d2171a6f315"
54
53
  }