@gasket/plugin-fastify 8.0.0-next.1 → 8.0.0-next.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.
package/README.md CHANGED
@@ -24,6 +24,18 @@ export default makeGasket({
24
24
  });
25
25
  ```
26
26
 
27
+ ## Fastify Version Support
28
+
29
+ This plugin supports both Fastify v4 and v5 through an internal adapter pattern. The appropriate version-specific adapter is automatically selected based on your installed Fastify version.
30
+
31
+ ### Fastify v4
32
+ - **Installation**: `npm install fastify@^4`
33
+
34
+ ### Fastify v5
35
+ - **Installation**: `npm install fastify@^5`
36
+
37
+ The plugin automatically detects your Fastify version and applies the correct configuration. No manual configuration is required.
38
+
27
39
  ## Configuration
28
40
 
29
41
  All the configurations for the plugin are added under `fastify` in the config:
@@ -0,0 +1,46 @@
1
+ import { createRequire } from 'module';
2
+ import { FastifyV4Adapter } from './fastify-v4-adapter.js';
3
+ import { FastifyV5Adapter } from './fastify-v5-adapter.js';
4
+
5
+ const require = createRequire(import.meta.url);
6
+
7
+ /**
8
+ * Detect the installed Fastify version.
9
+ * Reads the version from fastify/package.json in node_modules.
10
+ * This works reliably with npm, pnpm, yarn, and bun.
11
+ * @returns {string} - Version string (e.g., '5.2.1')
12
+ */
13
+ export function detectFastifyVersion() {
14
+ try {
15
+ const fastifyModule = require('fastify/package.json');
16
+ return fastifyModule.version;
17
+ } catch (err) {
18
+ throw new Error(
19
+ 'Could not detect Fastify version. Ensure fastify is installed.\n' +
20
+ `Error: ${err.message}`
21
+ );
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Create the appropriate Fastify adapter based on the installed Fastify version.
27
+ * Automatically detects the version from fastify/package.json.
28
+ * @returns {import('./base-adapter.js').FastifyAdapter} - Adapter instance
29
+ */
30
+ export function createFastifyAdapter() {
31
+ const version = detectFastifyVersion();
32
+ const majorVersion = parseInt(version.split('.')[0], 10);
33
+
34
+ switch (majorVersion) {
35
+ case 4:
36
+ return new FastifyV4Adapter();
37
+ case 5:
38
+ return new FastifyV5Adapter();
39
+ default:
40
+ throw new Error(
41
+ `Unsupported Fastify version: ${version}\n` +
42
+ 'Gasket supports Fastify v4 and v5. Please upgrade or downgrade Fastify, ' +
43
+ 'or open an issue at https://github.com/godaddy/gasket'
44
+ );
45
+ }
46
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Base abstract class for Fastify version adapters.
3
+ * Provides a common interface for creating and configuring Fastify instances
4
+ * across different major versions.
5
+ * @abstract
6
+ */
7
+ export class FastifyAdapter {
8
+ constructor() {
9
+ if (new.target === FastifyAdapter) {
10
+ throw new Error('FastifyAdapter is an abstract class and cannot be instantiated directly');
11
+ }
12
+ }
13
+
14
+ /**
15
+ * Create a Fastify instance with version-specific configuration.
16
+ * Subclasses must implement this method to handle version-specific options.
17
+ * @abstract
18
+ * @param {object} config - Fastify configuration options
19
+ * @param {boolean} [config.trustProxy] - Trust proxy headers
20
+ * @param {object} [config.https] - HTTPS configuration
21
+ * @param {boolean} [config.http2] - Enable HTTP/2
22
+ * @param {boolean} [config.disableRequestLogging] - Disable request logging
23
+ * @param {object} logger - Gasket logger instance
24
+ * @returns {ReturnType<typeof import('fastify').default>} - Configured Fastify instance
25
+ */
26
+ // eslint-disable-next-line no-unused-vars
27
+ createInstance(config, logger) {
28
+ throw new Error('createInstance() must be implemented by subclass');
29
+ }
30
+ }
@@ -0,0 +1,55 @@
1
+ import fastify from 'fastify';
2
+ import { FastifyAdapter } from './base-adapter.js';
3
+
4
+ const fallbackMap = {
5
+ fatal: 'error',
6
+ trace: 'debug'
7
+ };
8
+
9
+ /**
10
+ * Adapter for Fastify v4.x
11
+ *
12
+ * Key differences from v5:
13
+ * - Uses 'logger' option (not 'loggerInstance')
14
+ * - No 'useSemicolonDelimiter' option
15
+ * - Supports Node.js v14+
16
+ */
17
+ export class FastifyV4Adapter extends FastifyAdapter {
18
+ /**
19
+ * Align Gasket logger with Fastify v4 requirements.
20
+ * Ensures 'fatal' and 'trace' log levels exist.
21
+ * @param {object} logger - Gasket logger instance
22
+ * @returns {object} - Fastify-compatible logger
23
+ */
24
+ alignLogger(logger) {
25
+ const fastifyLogger = logger;
26
+ ['fatal', 'trace'].forEach(level => {
27
+ if (!logger[level]) {
28
+ fastifyLogger[level] = logger[fallbackMap[level]];
29
+ }
30
+ });
31
+ return fastifyLogger;
32
+ }
33
+
34
+ /**
35
+ * Create a Fastify v4 instance.
36
+ * @param {object} config - Fastify configuration
37
+ * @param {object} logger - Gasket logger
38
+ * @returns {ReturnType<typeof import('fastify').default>} - Configured Fastify v4 instance
39
+ */
40
+ createInstance(config, logger) {
41
+ const { trustProxy = false, disableRequestLogging = true, https, http2, ...restConfig } = config;
42
+
43
+ const fastifyLogger = this.alignLogger(logger);
44
+
45
+ // Fastify v4 uses 'logger' option
46
+ return fastify({
47
+ logger: fastifyLogger,
48
+ trustProxy,
49
+ disableRequestLogging,
50
+ https,
51
+ http2,
52
+ ...restConfig
53
+ });
54
+ }
55
+ }
@@ -0,0 +1,67 @@
1
+ import fastify from 'fastify';
2
+ import { FastifyAdapter } from './base-adapter.js';
3
+
4
+ const fallbackMap = {
5
+ fatal: 'error',
6
+ trace: 'debug'
7
+ };
8
+
9
+ /**
10
+ * Adapter for Fastify v5.x
11
+ *
12
+ * Key differences from v4:
13
+ * - Uses 'loggerInstance' option (not 'logger')
14
+ * - Adds 'useSemicolonDelimiter' option (defaults to true)
15
+ * - Requires Node.js v20+
16
+ * - Stricter JSON Schema validation
17
+ */
18
+ export class FastifyV5Adapter extends FastifyAdapter {
19
+ /**
20
+ * Align Gasket logger with Fastify v5 requirements.
21
+ * Ensures 'fatal' and 'trace' log levels exist.
22
+ * @param {object} logger - Gasket logger instance
23
+ * @returns {object} - Fastify-compatible logger
24
+ */
25
+ alignLogger(logger) {
26
+ const fastifyLogger = logger;
27
+ ['fatal', 'trace'].forEach(level => {
28
+ if (!logger[level]) {
29
+ fastifyLogger[level] = logger[fallbackMap[level]];
30
+ }
31
+ });
32
+ return fastifyLogger;
33
+ }
34
+
35
+ /**
36
+ * Create a Fastify v5 instance.
37
+ * @param {object} config - Fastify configuration
38
+ * @param {object} logger - Gasket logger
39
+ * @returns {ReturnType<typeof import('fastify').default>} - Configured Fastify v5 instance
40
+ */
41
+ createInstance(config, logger) {
42
+ const {
43
+ trustProxy = false,
44
+ disableRequestLogging = true,
45
+ https,
46
+ http2,
47
+ useSemicolonDelimiter = true,
48
+ ...restConfig
49
+ } = config;
50
+
51
+ const fastifyLogger = this.alignLogger(logger);
52
+
53
+ // Fastify v5 uses 'loggerInstance' instead of 'logger'
54
+ // Router options are nested under 'routerOptions' to avoid deprecation warnings
55
+ return fastify({
56
+ loggerInstance: fastifyLogger,
57
+ trustProxy,
58
+ disableRequestLogging,
59
+ https,
60
+ http2,
61
+ routerOptions: {
62
+ useSemicolonDelimiter
63
+ },
64
+ ...restConfig
65
+ });
66
+ }
67
+ }
@@ -0,0 +1,4 @@
1
+ export { FastifyAdapter } from './base-adapter.js';
2
+ export { FastifyV4Adapter } from './fastify-v4-adapter.js';
3
+ export { FastifyV5Adapter } from './fastify-v5-adapter.js';
4
+ export { createFastifyAdapter, detectFastifyVersion } from './adapter-factory.js';
package/lib/utils.js CHANGED
@@ -1,29 +1,9 @@
1
1
  // @ts-nocheck
2
2
 
3
- import fastify from 'fastify';
4
-
5
- const fallbackMap = {
6
- fatal: 'error',
7
- trace: 'debug'
8
- };
9
-
10
- /**
11
- * A helper function to ensure that all the required log levels
12
- * for a Fastify server are present.
13
- * @type {import('@gasket/plugin-fastify').alignLogger}
14
- */
15
- function alignLogger(logger) {
16
- const fastifyLogger = logger;
17
- ['fatal', 'trace'].map(level => {
18
- if (!logger[level]) {
19
- fastifyLogger[level] = logger[fallbackMap[level]];
20
- }
21
- });
22
-
23
- return fastifyLogger;
24
- }
3
+ import { createFastifyAdapter } from './adapters/index.js';
25
4
 
26
5
  let instance = null;
6
+ let adapter = null;
27
7
 
28
8
  /**
29
9
  * Get the Fastify instance.
@@ -33,21 +13,29 @@ let instance = null;
33
13
  export function getAppInstance(gasket) {
34
14
  if (!instance) {
35
15
  const { fastify: fastifyConfig = {}, http2, https } = gasket.config;
36
- const { trustProxy = false, disableRequestLogging = true } = fastifyConfig;
37
- const fastifyLogger = alignLogger(gasket.logger);
38
16
 
39
- instance = fastify({ logger: fastifyLogger, trustProxy, https, http2, disableRequestLogging });
17
+ // Create the appropriate adapter for the installed Fastify version
18
+ adapter = createFastifyAdapter();
19
+
20
+ // Use the adapter to create the Fastify instance
21
+ instance = adapter.createInstance(
22
+ {
23
+ ...fastifyConfig,
24
+ https,
25
+ http2
26
+ },
27
+ gasket.logger
28
+ );
40
29
  }
41
30
 
42
31
  return instance;
43
32
  }
44
33
 
45
- export { alignLogger };
46
-
47
34
  /**
48
35
  * Clear the Fastify app instance (for testing only)
49
36
  * @returns {void}
50
37
  */
51
38
  export function testClearAppInstance() {
52
39
  instance = null;
40
+ adapter = null;
53
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gasket/plugin-fastify",
3
- "version": "8.0.0-next.1",
3
+ "version": "8.0.0-next.2",
4
4
  "description": "Adds fastify support to your application",
5
5
  "type": "module",
6
6
  "types": "./lib/index.d.ts",
@@ -29,13 +29,9 @@
29
29
  "license": "MIT",
30
30
  "bugs": "https://github.com/godaddy/gasket/issues",
31
31
  "homepage": "https://github.com/godaddy/gasket/tree/main/packages/gasket-plugin-fastify",
32
- "dependencies": {
33
- "@fastify/express": "^3.0.0",
34
- "fastify": "^4.29.1"
35
- },
36
32
  "devDependencies": {
37
33
  "@types/connect": "^3.4.38",
38
- "fastify": "^4.29.1",
34
+ "fastify": "^5.0.0",
39
35
  "vitest": "^3.2.0",
40
36
  "@gasket/core": "^8.0.0-next.1",
41
37
  "@gasket/plugin-https": "^8.0.0-next.1",
@@ -44,7 +40,7 @@
44
40
  "create-gasket-app": "^8.0.0-next.1"
45
41
  },
46
42
  "peerDependencies": {
47
- "fastify": "^4.29.1"
43
+ "fastify": "^4.29.1 || ^5.0.0"
48
44
  },
49
45
  "scripts": {
50
46
  "lint": "eslint .",