@gasket/plugin-fastify 0.0.0-canary-20250922152503

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/EXAMPLES.md ADDED
@@ -0,0 +1,144 @@
1
+ # @gasket/plugin-fastify Examples
2
+
3
+ This document provides working examples for all exported interfaces from `@gasket/plugin-fastify`.
4
+
5
+ ## Plugin Installation and Configuration
6
+
7
+ ### Basic Plugin Setup
8
+
9
+ ```js
10
+ // gasket.js
11
+ import { makeGasket } from '@gasket/core';
12
+ import pluginFastify from '@gasket/plugin-fastify';
13
+
14
+ export default makeGasket({
15
+ plugins: [
16
+ pluginFastify
17
+ ]
18
+ });
19
+ ```
20
+
21
+ ### Plugin Configuration
22
+
23
+ ```js
24
+ // gasket.js
25
+ export default makeGasket({
26
+ plugins: [
27
+ pluginFastify
28
+ ],
29
+ fastify: {
30
+ compression: true,
31
+ trustProxy: true,
32
+ disableRequestLogging: false
33
+ }
34
+ });
35
+ ```
36
+
37
+ ## Lifecycle Hooks
38
+
39
+ ### `fastify` Lifecycle Hook
40
+
41
+ Access and modify the Fastify instance:
42
+
43
+ ```js
44
+ // Example plugin or lifecycle file
45
+ export default {
46
+ name: 'my-fastify-plugin',
47
+ hooks: {
48
+ fastify: async function (gasket, app) {
49
+ // Register plugins
50
+ app.register(require('@fastify/cors'), {
51
+ origin: true
52
+ });
53
+
54
+ // Add hooks
55
+ app.addHook('preHandler', async (request, reply) => {
56
+ console.log('Processing request:', request.url);
57
+ });
58
+
59
+ // Add custom decorators
60
+ app.decorate('customMethod', function() {
61
+ return 'custom value';
62
+ });
63
+
64
+ // Add routes
65
+ app.get('/hello', async (request, reply) => {
66
+ return { hello: 'world' };
67
+ });
68
+ }
69
+ }
70
+ };
71
+ ```
72
+
73
+ ### `errorMiddleware` Lifecycle Hook
74
+
75
+ Add Express-style error handling middleware:
76
+
77
+ ```js
78
+ // Example plugin
79
+ export default {
80
+ name: 'my-error-handler',
81
+ hooks: {
82
+ errorMiddleware: function (gasket) {
83
+ return (error, req, res, next) => {
84
+ gasket.logger.error('Request error:', error);
85
+
86
+ // Handle different error types
87
+ if (error.statusCode) {
88
+ res.status(error.statusCode);
89
+ } else {
90
+ res.status(500);
91
+ }
92
+
93
+ res.send({
94
+ error: 'Internal Server Error',
95
+ message: error.message
96
+ });
97
+ };
98
+ }
99
+ }
100
+ };
101
+ ```
102
+
103
+ ## Configuration Examples
104
+
105
+ ### Route Plugin Example
106
+
107
+ ```js
108
+ // plugins/routes-plugin.js
109
+ export default {
110
+ name: 'routes-plugin',
111
+ hooks: {
112
+ fastify: async function (gasket, app) {
113
+ // API routes
114
+ app.get('/api/health', async (request, reply) => {
115
+ return {
116
+ status: 'healthy',
117
+ timestamp: new Date().toISOString(),
118
+ version: process.env.npm_package_version
119
+ };
120
+ });
121
+
122
+ app.get('/api/config', async (request, reply) => {
123
+ return {
124
+ environment: gasket.config.env,
125
+ features: gasket.config.features || {}
126
+ };
127
+ });
128
+
129
+ // Protected route example
130
+ app.get('/api/protected', {
131
+ preHandler: async (request, reply) => {
132
+ const auth = request.headers.authorization;
133
+ if (!auth || !auth.startsWith('Bearer ')) {
134
+ reply.code(401).send({ error: 'Unauthorized' });
135
+ return;
136
+ }
137
+ }
138
+ }, async (request, reply) => {
139
+ return { message: 'Protected data' };
140
+ });
141
+ }
142
+ }
143
+ };
144
+ ```
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 GoDaddy Operating Company, LLC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # @gasket/plugin-fastify
2
+
3
+ Adds Fastify to your application.
4
+
5
+ ## Installation
6
+
7
+ #### New apps
8
+
9
+ ```
10
+ npm i @gasket/plugin-fastify
11
+ ```
12
+
13
+ Update your `gasket` file plugin configuration:
14
+
15
+ ```diff
16
+ // gasket.js
17
+
18
+ + import pluginFastify from '@gasket/plugin-fastify';
19
+
20
+ export default makeGasket({
21
+ plugins: [
22
+ + pluginFastify
23
+ ]
24
+ });
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ All the configurations for the plugin are added under `fastify` in the config:
30
+
31
+ - `compression`: true by default. Can be set to false if applying compression
32
+ differently.
33
+ - `trustProxy`: Enable trust proxy option, [see Fastify documentation for possible values](https://fastify.dev/docs/latest/Reference/Server/#trustproxy)
34
+ - `disableRequestLogging`: Turn off request logging, true by default
35
+
36
+ #### Example configuration
37
+
38
+ ```js
39
+ export default makeGasket({
40
+ plugins: [
41
+ pluginFastify
42
+ ],
43
+ fastify: {
44
+ compression: false,
45
+ excludedRoutesRegex: /^(?!\/_next\/)/,
46
+ trustProxy: true
47
+ }
48
+ });
49
+ ```
50
+
51
+ ### Route Definition
52
+
53
+ Routes can be defined in a in-app plugin in the `plugins` directory. The plugin will hook the `fastify` lifecycle to add the routes to the fastify app.
54
+
55
+ ```js
56
+ // plugins/routes-plugin.js
57
+ export default {
58
+ name: 'routes-plugin',
59
+ hooks: {
60
+ fastify: async function (gasket, app) {
61
+ app.get('/hello', (req, res) => {
62
+ res.send('Hello World!');
63
+ });
64
+ }
65
+ }
66
+ };
67
+ ```
68
+
69
+ ## Lifecycles
70
+
71
+ ### fastify
72
+
73
+ Executed **after** the `middleware` event for when you need full control over
74
+ the `fastify` instance.
75
+
76
+ ```js
77
+ export default {
78
+ name: 'sample-plugin',
79
+ hooks: {
80
+ /**
81
+ * Update Fastify app instance
82
+ *
83
+ * @param {Gasket} gasket The Gasket API
84
+ * @param {Fastify} fastify Fastify app instance
85
+ * @returns {function|function[]} middleware(s)
86
+ */
87
+ fastify: async function (gasket, fastify) {
88
+ }
89
+ }
90
+ };
91
+ ```
92
+
93
+ ### errorMiddleware
94
+
95
+ Executed after the `fastify` event. All middleware functions returned from this
96
+ hook will be applied to Fastify.
97
+
98
+ ```js
99
+ export default {
100
+ name: 'sample-plugin',
101
+ hooks: {
102
+ /**
103
+ * Add Fastify error middlewares
104
+ *
105
+ * @param {Gasket} gasket The Gasket API
106
+ * @returns {function|function[]} error middleware(s)
107
+ */
108
+ errorMiddleware: function (gasket) {
109
+ }
110
+ }
111
+ };
112
+ ```
113
+
114
+ ## How it works
115
+
116
+ This plugins hooks the [createServers] lifecycles from [@gasket/plugin-https].
117
+
118
+ ## License
119
+
120
+ [MIT](./LICENSE.md)
121
+
122
+ <!-- LINKS -->
123
+
124
+ [@gasket/plugin-https]:/packages/gasket-plugin-https/README.md
125
+ [createServers]:/packages/gasket-plugin-https/README.md#createservers
@@ -0,0 +1,11 @@
1
+ # Local Plugins
2
+
3
+ ### Routes plugin
4
+
5
+ A local plugin is used to define Fastify routes. The plugin hooks the `fastify` lifecycle and mutates the Fastify app.
6
+
7
+ The following routes are available:
8
+
9
+ ```javascript
10
+ GET /default
11
+ ```
@@ -0,0 +1,30 @@
1
+ export const defaultHandler = async (req, res) => {
2
+ if (res.statusCode === 200) {
3
+ res.send({ message: 'Welcome to your default route...' });
4
+ }
5
+ };
6
+
7
+ export default {
8
+ name: 'routes-plugin',
9
+ hooks: {
10
+ fastify(gasket, app) {
11
+ {{#if useSwagger }}
12
+ /**
13
+ * @swagger
14
+ *
15
+ * /default:
16
+ * get:
17
+ * summary: "Get default route"
18
+ * produces:
19
+ * - "application/json"
20
+ * responses:
21
+ * "200":
22
+ * description: "Returns welcome message."
23
+ * content:
24
+ * application/json
25
+ */
26
+ {{/if }}
27
+ app.get('/default', defaultHandler);
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,29 @@
1
+ export const defaultHandler = async (req, res) => {
2
+ if (res.statusCode === 200) {
3
+ res.send({ message: 'Welcome to your default route...' });
4
+ }
5
+ };
6
+ export default {
7
+ name: 'routes-plugin',
8
+ hooks: {
9
+ fastify(gasket, app) {
10
+ {{#if useSwagger }}
11
+ /**
12
+ * @swagger
13
+ *
14
+ * /default:
15
+ * get:
16
+ * summary: "Get default route"
17
+ * produces:
18
+ * - "application/json"
19
+ * responses:
20
+ * "200":
21
+ * description: "Returns welcome message."
22
+ * content:
23
+ * application/json
24
+ */
25
+ {{/if }}
26
+ app.get('/default', defaultHandler);
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,21 @@
1
+ {{#if typescript}}
2
+ const config = {
3
+ preset: 'ts-jest/presets/default-esm',
4
+ testEnvironment: 'node',
5
+ injectGlobals: true,
6
+ moduleDirectories: ['node_modules', '<rootDir>'],
7
+ moduleNameMapper: {
8
+ '^(\\.{1,2}/.*)\\.js$': '$1'
9
+ },
10
+ transform: {
11
+ '^.+.ts$': ['ts-jest', { useESM: true }]
12
+ }
13
+ };
14
+
15
+ export default config;
16
+ {{else}}
17
+ export default {
18
+ testEnvironment: 'node',
19
+ injectGlobals: true
20
+ };
21
+ {{/if}}
@@ -0,0 +1,20 @@
1
+ import { jest } from '@jest/globals';
2
+ import { defaultHandler } from '../plugins/routes-plugin.js';
3
+
4
+ describe('Routes', () => {
5
+ let mockRequest, mockResponse;
6
+ beforeEach(() => {
7
+ mockRequest = {};
8
+ mockResponse = {
9
+ statusCode: 200,
10
+ send: jest.fn()
11
+ };
12
+ });
13
+
14
+ it('defaultHandler should use expeced message', async () => {
15
+ await defaultHandler(mockRequest, mockResponse);
16
+ expect(mockResponse.send).toHaveBeenCalledWith({
17
+ message: 'Welcome to your default route...'
18
+ });
19
+ });
20
+ });
@@ -0,0 +1,26 @@
1
+ import {
2
+ jest,
3
+ describe,
4
+ beforeEach,
5
+ it,
6
+ expect
7
+ } from '@jest/globals';
8
+ import { defaultHandler } from '../plugins/routes-plugin.js';
9
+
10
+ describe('Routes', () => {
11
+ let mockRequest, mockResponse;
12
+ beforeEach(() => {
13
+ mockRequest = {};
14
+ mockResponse = {
15
+ statusCode: 200,
16
+ send: jest.fn()
17
+ };
18
+ });
19
+
20
+ it('defaultHandler should use expeced message', async () => {
21
+ await defaultHandler(mockRequest, mockResponse);
22
+ expect(mockResponse.send).toHaveBeenCalledWith({
23
+ message: 'Welcome to your default route...'
24
+ });
25
+ });
26
+ });
@@ -0,0 +1,23 @@
1
+ import { expect } from 'chai';
2
+ import sinon from 'sinon';
3
+ import { defaultHandler } from '../plugins/routes-plugin.js';
4
+
5
+ describe('Routes', () => {
6
+ let mockRequest, mockResponse, sendSpy;
7
+
8
+ beforeEach(() => {
9
+ mockRequest = {};
10
+ sendSpy = sinon.spy();
11
+ mockResponse = {
12
+ statusCode: 200,
13
+ send: sendSpy
14
+ };
15
+ });
16
+
17
+ it('defaultHandler should use expected message', async () => {
18
+ await defaultHandler(mockRequest, mockResponse);
19
+ expect(sendSpy.calledWith({
20
+ message: 'Welcome to your default route...'
21
+ })).to.be.true;
22
+ });
23
+ });
@@ -0,0 +1,23 @@
1
+ import { expect } from 'chai';
2
+ import sinon from 'sinon';
3
+ import { defaultHandler } from '../plugins/routes-plugin.js';
4
+
5
+ describe('Routes', () => {
6
+ let mockRequest, mockResponse, sendSpy;
7
+
8
+ beforeEach(() => {
9
+ mockRequest = {};
10
+ sendSpy = sinon.spy();
11
+ mockResponse = {
12
+ statusCode: 200,
13
+ send: sendSpy
14
+ };
15
+ });
16
+
17
+ it('defaultHandler should use expected message', async () => {
18
+ await defaultHandler(mockRequest, mockResponse);
19
+ expect(sendSpy.calledWith({
20
+ message: 'Welcome to your default route...'
21
+ })).to.be.true;
22
+ });
23
+ });
@@ -0,0 +1,21 @@
1
+ import { vi, expect } from 'vitest';
2
+ import { defaultHandler } from '../plugins/routes-plugin.js';
3
+
4
+ describe('Routes', () => {
5
+ let mockRequest, mockResponse;
6
+
7
+ beforeEach(() => {
8
+ mockRequest = {};
9
+ mockResponse = {
10
+ statusCode: 200,
11
+ send: vi.fn()
12
+ };
13
+ });
14
+
15
+ it('defaultHeader should use expected message', async () => {
16
+ await defaultHandler(mockRequest, mockResponse);
17
+ expect(mockResponse.send).toHaveBeenCalledWith({
18
+ message: 'Welcome to your default route...'
19
+ });
20
+ });
21
+ });
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { defaultHandler } from '../plugins/routes-plugin.js';
3
+
4
+ describe('Routes', () => {
5
+ let mockRequest, mockResponse;
6
+
7
+ beforeEach(() => {
8
+ mockRequest = {};
9
+ mockResponse = {
10
+ statusCode: 200,
11
+ send: vi.fn()
12
+ };
13
+ });
14
+
15
+ it('defaultHeader should use expected message', async () => {
16
+ await defaultHandler(mockRequest, mockResponse);
17
+ expect(mockResponse.send).toHaveBeenCalledWith({
18
+ message: 'Welcome to your default route...'
19
+ });
20
+ });
21
+ });
package/lib/actions.js ADDED
@@ -0,0 +1,17 @@
1
+ const { getAppInstance } = require('./utils.js');
2
+
3
+ const actions = {
4
+ /**
5
+ * @deprecated
6
+ * @param {import('@gasket/core').Gasket} gasket - Gasket instance
7
+ * @returns {import('fastify').FastifyInstance} - Fastify instance
8
+ */
9
+ getFastifyApp(gasket) {
10
+ gasket.logger.warn(
11
+ `DEPRECATED \`getFastifyApp\` action will not be support in future major release.`
12
+ );
13
+ return getAppInstance(gasket);
14
+ }
15
+ };
16
+
17
+ module.exports = actions;
@@ -0,0 +1,32 @@
1
+ /// <reference types="@gasket/plugin-https" />
2
+ /// <reference types="@gasket/plugin-logger" />
3
+
4
+ const { getAppInstance } = require('./utils.js');
5
+ /**
6
+ * Create the Fastify instance and setup the lifecycle hooks.
7
+ * Fastify is compatible with express middleware out of the box, so we can
8
+ * use the same middleware lifecycles.
9
+ * @type {import('@gasket/core').HookHandler<'createServers'>}
10
+ */
11
+ module.exports = async function createServers(gasket, serverOpts) {
12
+ /** Cast to Fastify + Express hybrid because Gasket adds `.use()` via @fastify/express plugin */
13
+ const app = /** @type {import('fastify').FastifyInstance & { use: Function }} */ (getAppInstance(gasket));
14
+
15
+ // allow consuming apps to directly append options to their server
16
+ await gasket.exec('fastify', app);
17
+
18
+ const postRenderingStacks = (await gasket.exec('errorMiddleware')).filter(Boolean);
19
+ postRenderingStacks.forEach((stack) => {
20
+ /** @type {import('connect').NextHandleFunction} */
21
+ const middleware = stack;
22
+ app.use(middleware);
23
+ });
24
+
25
+ return {
26
+ ...serverOpts,
27
+ handler: async function handler(...args) {
28
+ await app.ready();
29
+ app.server.emit('request', ...args);
30
+ }
31
+ };
32
+ };
package/lib/create.js ADDED
@@ -0,0 +1,56 @@
1
+ /// <reference types="@gasket/core" />
2
+ /// <reference types="create-gasket-app" />
3
+
4
+ const { name, version, devDependencies } = require('../package.json');
5
+
6
+ const createTestFiles = ({ files, generatorDir, testPlugins, globIgnore }) => {
7
+ if (!testPlugins || testPlugins.length === 0) return;
8
+ const unit = ['jest', 'mocha', 'vitest'];
9
+ const integration = ['cypress'];
10
+ const frameworks = [...unit, ...integration];
11
+ const frameworksRegex = new RegExp(frameworks.join('|'));
12
+
13
+ testPlugins.forEach((testPlugin) => {
14
+ const match = frameworksRegex.exec(testPlugin);
15
+ if (match) {
16
+ const matchedFramework = match[0];
17
+ if (unit.includes(matchedFramework)) {
18
+ files.add(`${generatorDir}/${matchedFramework}/*`, `${generatorDir}/${matchedFramework}/**/${globIgnore}`);
19
+ } else {
20
+ files.add(`${generatorDir}/${matchedFramework}/*`, `${generatorDir}/${matchedFramework}/**/*`);
21
+ }
22
+ }
23
+ });
24
+ };
25
+
26
+ /**
27
+ * Add files & extend package.json for new apps.
28
+ * @type {import('@gasket/core').HookHandler<'create'>}
29
+ */
30
+ module.exports = async function create(gasket, context) {
31
+ const {
32
+ files,
33
+ typescript,
34
+ apiApp,
35
+ addApiRoutes = true,
36
+ testPlugins,
37
+ pkg,
38
+ gasketConfig
39
+ } = context;
40
+ const generatorDir = `${__dirname}/../generator`;
41
+
42
+ gasketConfig.addPlugin('pluginFastify', name);
43
+
44
+ pkg.add('dependencies', {
45
+ [name]: `^${version}`,
46
+ fastify: devDependencies.fastify
47
+ });
48
+
49
+ if (apiApp && addApiRoutes) {
50
+ const globIgnore = typescript ? '!(*.js)' : '!(*.ts)';
51
+ files.add(`${generatorDir}/app/**/${globIgnore}`);
52
+ gasketConfig.addPlugin('pluginRoutes', './plugins/routes-plugin.js');
53
+
54
+ createTestFiles({ files, generatorDir, testPlugins, globIgnore });
55
+ }
56
+ };
package/lib/index.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ import type { MaybeAsync, MaybeMultiple, Plugin } from '@gasket/core';
2
+ import type { Logger } from '@gasket/plugin-logger';
3
+ import type {
4
+ FastifyInstance,
5
+ FastifyRequest,
6
+ FastifyReply,
7
+ FastifyServerOptions,
8
+ FastifyBaseLogger,
9
+ FastifyTypeProviderDefault,
10
+ RawServerDefault
11
+ } from 'fastify';
12
+ import type { IncomingMessage, ServerResponse } from 'http';
13
+
14
+ export interface FastifyConfig {
15
+ /** Enable compression */
16
+ compression?: boolean;
17
+ /** Trust proxy configuration */
18
+ trustProxy?: FastifyServerOptions['trustProxy'];
19
+ /** Fastify request logging per route */
20
+ disableRequestLogging?: boolean;
21
+ }
22
+
23
+ export type FastifyOptions = FastifyServerOptions & {
24
+ https?: any,
25
+ http2?: boolean | object
26
+ }
27
+
28
+ declare module '@gasket/core' {
29
+ export interface GasketActions {
30
+ /** @deprecated */
31
+ getFastifyApp(): FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>;
32
+ }
33
+
34
+ export interface GasketConfig {
35
+ fastify?: FastifyConfig
36
+ }
37
+
38
+
39
+ /** Error handler function type */
40
+ type ErrorHandler = (
41
+ error: Error,
42
+ req: FastifyRequest,
43
+ res: FastifyReply,
44
+ next: (error?: Error) => void
45
+ ) => void;
46
+
47
+ export interface HookExecTypes {
48
+ fastify(app: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>): MaybeAsync<void>;
49
+ errorMiddleware(): MaybeAsync<MaybeMultiple<ErrorHandler>>;
50
+ }
51
+ }
52
+
53
+ export function alignLogger(
54
+ logger: Logger
55
+ ): FastifyBaseLogger
56
+
57
+ declare module 'create-gasket-app' {
58
+ export interface CreateContext {
59
+ /** Flag indicating if API app is enabled */
60
+ apiApp?: boolean;
61
+ addApiRoutes?: boolean;
62
+ }
63
+ }
64
+
65
+ declare const plugin: Plugin;
66
+
67
+ export default plugin;
package/lib/index.js ADDED
@@ -0,0 +1,74 @@
1
+ /// <reference types="@gasket/core" />
2
+ /// <reference types="@gasket/plugin-metadata" />
3
+
4
+ const { name, version, description } = require('../package.json');
5
+ const create = require('./create');
6
+ const createServers = require('./create-servers');
7
+ const actions = require('./actions');
8
+
9
+ /** @type {import('@gasket/core').Plugin} */
10
+ const plugin = {
11
+ name,
12
+ version,
13
+ description,
14
+ actions,
15
+ hooks: {
16
+ create,
17
+ createServers,
18
+ metadata(gasket, meta) {
19
+ return {
20
+ ...meta,
21
+ actions: [
22
+ {
23
+ name: 'getFastifyApp',
24
+ description: 'Get the Fastify app instance',
25
+ link: 'README.md#getFastifyApp',
26
+ deprecated: true
27
+ }
28
+ ],
29
+ lifecycles: [
30
+ {
31
+ name: 'fastify',
32
+ method: 'exec',
33
+ description: 'Modify the Fastify instance to for adding endpoints',
34
+ link: 'README.md#express',
35
+ parent: 'createServers',
36
+ after: 'middleware'
37
+ },
38
+ {
39
+ name: 'errorMiddleware',
40
+ method: 'exec',
41
+ description:
42
+ 'Add Express style middleware for handling errors with Fastify',
43
+ link: 'README.md#errorMiddleware',
44
+ parent: 'createServers',
45
+ after: 'express'
46
+ }
47
+ ],
48
+ configurations: [
49
+ {
50
+ name: 'fastify',
51
+ link: 'README.md#configuration',
52
+ description: 'Fastify configuration object',
53
+ type: 'object'
54
+ },
55
+ {
56
+ name: 'fastify.compression',
57
+ link: 'README.md#configuration',
58
+ description: 'Automatic compression',
59
+ type: 'boolean',
60
+ default: true
61
+ },
62
+ {
63
+ name: 'fastify.excludedRoutesRegex',
64
+ link: 'README.md#configuration',
65
+ description: 'Routes to be excluded based on a regex',
66
+ type: 'RegExp'
67
+ }
68
+ ]
69
+ };
70
+ }
71
+ }
72
+ };
73
+
74
+ module.exports = plugin;
package/lib/utils.js ADDED
@@ -0,0 +1,50 @@
1
+ // @ts-nocheck
2
+
3
+ const fallbackMap = {
4
+ fatal: 'error',
5
+ trace: 'debug'
6
+ };
7
+
8
+ /**
9
+ * A helper function to ensure that all the required log levels
10
+ * for a Fastify server are present.
11
+ * @type {import('@gasket/plugin-fastify').alignLogger}
12
+ */
13
+ function alignLogger(logger) {
14
+ const fastifyLogger = logger;
15
+ ['fatal', 'trace'].map(level => {
16
+ if (!logger[level]) {
17
+ fastifyLogger[level] = logger[fallbackMap[level]];
18
+ }
19
+ });
20
+
21
+ return fastifyLogger;
22
+ }
23
+
24
+ let instance = null;
25
+
26
+ /**
27
+ * Get the Fastify instance.
28
+ * @param {import('@gasket/core').Gasket} gasket - Gasket instance
29
+ * @returns {import('fastify').FastifyInstance} - Fastify instance
30
+ */
31
+ function getAppInstance(gasket) {
32
+ if (!instance) {
33
+ const fastify = require('fastify');
34
+ const { fastify: fastifyConfig = {}, http2, https } = gasket.config;
35
+ const { trustProxy = false, disableRequestLogging = true } = fastifyConfig;
36
+ const fastifyLogger = alignLogger(gasket.logger);
37
+
38
+ instance = fastify({ logger: fastifyLogger, trustProxy, https, http2, disableRequestLogging });
39
+ }
40
+
41
+ return instance;
42
+ }
43
+
44
+ module.exports = {
45
+ alignLogger,
46
+ getAppInstance,
47
+ testClearAppInstance: () => {
48
+ instance = null;
49
+ }
50
+ };
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@gasket/plugin-fastify",
3
+ "version": "0.0.0-canary-20250922152503",
4
+ "description": "Adds fastify support to your application",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "files": [
8
+ "generator",
9
+ "lib",
10
+ "EXAMPLES.md"
11
+ ],
12
+ "repository": "godaddy/gasket.git",
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "keywords": [
17
+ "fastify",
18
+ "gasket",
19
+ "plugin"
20
+ ],
21
+ "author": "GoDaddy Operating Company, LLC",
22
+ "license": "MIT",
23
+ "bugs": "https://github.com/godaddy/gasket/issues",
24
+ "homepage": "https://github.com/godaddy/gasket/tree/main/packages/gasket-plugin-fastify",
25
+ "dependencies": {
26
+ "@fastify/express": "^3.0.0",
27
+ "fastify": "^4.29.1"
28
+ },
29
+ "devDependencies": {
30
+ "@types/connect": "^3.4.38",
31
+ "fastify": "^4.29.1",
32
+ "jest": "^29.7.0",
33
+ "@gasket/core": "^0.0.0-canary-20250922152503",
34
+ "@gasket/plugin-https": "^0.0.0-canary-20250922152503",
35
+ "@gasket/plugin-logger": "^0.0.0-canary-20250922152503",
36
+ "create-gasket-app": "^0.0.0-canary-20250922152503",
37
+ "@gasket/plugin-metadata": "^0.0.0-canary-20250922152503"
38
+ },
39
+ "peerDependencies": {
40
+ "fastify": "^4.29.1"
41
+ },
42
+ "jest": {
43
+ "rootDir": "test"
44
+ },
45
+ "scripts": {
46
+ "lint": "eslint .",
47
+ "lint:fix": "pnpm run lint --fix",
48
+ "posttest": "pnpm run lint && pnpm run typecheck",
49
+ "test": "cross-env NODE_OPTIONS='--unhandled-rejections=strict' jest",
50
+ "test:coverage": "jest --coverage",
51
+ "test:watch": "jest --watch",
52
+ "typecheck": "tsc",
53
+ "typecheck:watch": "tsc --watch"
54
+ }
55
+ }