Skip to content

Commit 4127cba

Browse files
committed
chore(ilc/server): update fastify to v5
1 parent c60280a commit 4127cba

35 files changed

+1047
-1023
lines changed

docs/multi-domains.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,6 @@ ILC automatically updates canonical tags during client-side navigation.
185185

186186
## Additional information
187187

188-
- ILC detects a domain from the [**request.hostname** of Fastify](https://www.fastify.io/docs/latest/Reference/Request/) and checks whether this hostname is listed in the **Router domains**.
188+
- ILC detects a domain from the [**request.host** of Fastify](https://www.fastify.io/docs/latest/Reference/Request/) and checks whether this hostname is listed in the **Router domains**.
189189
- Each registered domain in the **Router domains** has its own set of routes that do not overlap.
190190
- For routes, the domain is optional. If the request goes from the domain that is not listed in the **Router domains**, the routes for the request will stay unassigned.

ilc/common/DefaultCacheWrapper.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Logger } from 'ilc-plugins-sdk';
22
import { CacheHashFn, CacheParams, CacheResult, CacheStorage, CacheWrapper } from './types/CacheWrapper';
3-
import { Context } from './types/Context';
3+
import { type Context } from '../server/context/context';
44
import { extendError, withTimeout } from './utils';
55

66
const CacheWrapperError = extendError('CacheWrapperError', { defaultData: {} });
@@ -42,8 +42,7 @@ export class DefaultCacheWrapper implements CacheWrapper {
4242

4343
private getRequestId(): string | undefined {
4444
if (this.context) {
45-
const contextStore = this.context.getStore();
46-
return contextStore?.get('requestId');
45+
return this.context.get('requestId');
4746
}
4847

4948
return undefined;

ilc/common/types/Context.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import '@fastify/request-context';
2+
3+
declare module '@fastify/request-context' {
4+
interface RequestContextData {
5+
requestId: string;
6+
url: string;
7+
domain: string;
8+
path: string;
9+
protocol: string;
10+
}
11+
}

ilc/common/types/Context.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

ilc/package-lock.json

Lines changed: 815 additions & 733 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ilc/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"author": "",
2121
"license": "Apache-2.0",
2222
"dependencies": {
23-
"@fastify/express": "^1.1.0",
23+
"@fastify/express": "^4.0.2",
24+
"@fastify/request-context": "^6.2.1",
2425
"@namecheap/error-extender": "^2.2.1",
2526
"@namecheap/tailorx": "^8.2.1",
2627
"@newrelic/native-metrics": "^12.0.0",
@@ -33,7 +34,7 @@
3334
"deepmerge": "4.3.1",
3435
"eventemitter3": "^5.0.1",
3536
"exponential-backoff": "^3.1.3",
36-
"fastify": "^3.29.5",
37+
"fastify": "^5.6.2",
3738
"http-status-codes": "^2.3.0",
3839
"ilc-plugins-sdk": "^2.3.0",
3940
"ilc-sdk": "^6.1.1",
@@ -63,6 +64,7 @@
6364
"@types/mocha": "^10.0.10",
6465
"@types/newrelic": "^9.14.8",
6566
"@types/node": "^22.19.2",
67+
"@types/parseurl": "^1.3.3",
6668
"@types/safe-json-stringify": "^1.1.5",
6769
"@types/sinon": "^21.0.0",
6870
"@types/supertest": "^6.0.3",

ilc/server/TransitionHooksExecutor.spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ describe('TransitionHooksExecutor', () => {
134134
const req = {
135135
raw: rawReq,
136136
log,
137-
hostname: 'test.com',
137+
host: 'test.com',
138138
};
139139

140140
describe('should have access to a provided URL', () => {
@@ -178,7 +178,7 @@ describe('TransitionHooksExecutor', () => {
178178
for (const hook of hooks) {
179179
chai.expect(
180180
hook.calledOnceWith({
181-
route: { meta: route.meta, url: route.reqUrl, hostname: req.hostname, route: route.route },
181+
route: { meta: route.meta, url: route.reqUrl, hostname: req.host, route: route.route },
182182
req: rawReq,
183183
log,
184184
}),
@@ -194,7 +194,7 @@ describe('TransitionHooksExecutor', () => {
194194
const reqWithoutRouter = {
195195
raw: {},
196196
log,
197-
hostname: 'test.com',
197+
host: 'test.com',
198198
};
199199

200200
pluginManager.getTransitionHooksPlugin.returns(transitionHooksPlugin);
@@ -288,7 +288,7 @@ describe('TransitionHooksExecutor', () => {
288288
for (const hook of [hooks[0], hooks[1]]) {
289289
chai.expect(
290290
hook.calledOnceWith({
291-
route: { meta: route.meta, url: route.reqUrl, hostname: req.hostname, route: route.route },
291+
route: { meta: route.meta, url: route.reqUrl, hostname: req.host, route: route.route },
292292
req: rawReq,
293293
log,
294294
}),
@@ -317,7 +317,7 @@ describe('TransitionHooksExecutor', () => {
317317
for (const hook of [hooks[0], hooks[1]]) {
318318
chai.expect(
319319
hook.calledOnceWith({
320-
route: { meta: route.meta, url: route.reqUrl, hostname: req.hostname, route: route.route },
320+
route: { meta: route.meta, url: route.reqUrl, hostname: req.host, route: route.route },
321321
req: rawReq,
322322
log,
323323
}),
@@ -347,7 +347,7 @@ describe('TransitionHooksExecutor', () => {
347347
for (const hook of [hooks[0], hooks[1]]) {
348348
chai.expect(
349349
hook.calledOnceWith({
350-
route: { meta: route.meta, url: route.reqUrl, hostname: req.hostname, route: route.route },
350+
route: { meta: route.meta, url: route.reqUrl, hostname: req.host, route: route.route },
351351
req: rawReq,
352352
log,
353353
}),

ilc/server/TransitionHooksExecutor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class TransitionHooksExecutor {
3636
route: {
3737
meta: route.meta,
3838
url: route.reqUrl,
39-
hostname: req.hostname,
39+
hostname: req.host,
4040
route: route.route,
4141
},
4242
log: req.log,

ilc/server/app.js

Lines changed: 41 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { fastifyExpress } from '@fastify/express';
2+
import { fastifyRequestContext } from '@fastify/request-context';
13
import config from 'config';
24
import fastify from 'fastify';
3-
import { fastifyExpress } from '@fastify/express';
4-
import { AsyncResource } from 'node:async_hooks';
5+
import { Application } from './application/application';
6+
import { context } from './context/context';
57
import { errorHandlerFactory } from './errorHandler/factory';
68
import { pingPluginFactroy } from './routes/pingPluginFactory';
79
import { renderTemplateHandlerFactory } from './routes/renderTemplateHandlerFactory';
@@ -12,94 +14,68 @@ const { Test500Error } = require('./errorHandler/ErrorHandler');
1214

1315
const serveStatic = require('./serveStatic');
1416
const i18n = require('./i18n');
15-
const Application = require('./application/application');
1617
const reportingPluginManager = require('./plugins/reportingPlugin');
1718
const AccessLogger = require('./logger/accessLogger');
1819
const { isStaticFile, isHealthCheck, isDataUri } = require('./utils/utils');
1920

2021
/**
2122
* @param {Registry} registryService
2223
*/
23-
module.exports = async function createApplication(registryService, pluginManager, context) {
24+
module.exports = async function createApplication(registryService, pluginManager) {
2425
const reportingPlugin = reportingPluginManager.getInstance();
2526
const errorHandler = errorHandlerFactory();
2627
const appConfig = Application.getConfig(reportingPlugin);
2728
const logger = reportingPluginManager.getLogger();
2829
const accessLogger = new AccessLogger(config, logger);
2930
const app = fastify(appConfig);
3031
await app.register(fastifyExpress);
32+
await app.register(fastifyRequestContext, {
33+
defaultStoreValues: (req) => context.createFromRequest(req, reportingPluginManager.getRequestId() ?? req.id),
34+
});
3135

32-
const asyncResourceSymbol = Symbol('asyncResource');
33-
34-
app.addHook('onRequest', (req, reply, done) => {
35-
context.run({ request: req, requestId: reportingPluginManager.getRequestId() ?? request.id }, async () => {
36-
try {
37-
const asyncResource = new AsyncResource('fastify-request-context');
38-
req[asyncResourceSymbol] = asyncResource;
39-
const doneWithContext = () => asyncResource.runInAsyncScope(done, req.raw);
40-
41-
const { url, method } = req.raw;
42-
accessLogger.logRequest();
43-
44-
if (!['GET', 'OPTIONS', 'HEAD'].includes(method)) {
45-
logger.warn(`Request method ${method} is not allowed for url ${url}`);
46-
reply.code(405).send({ message: 'Method Not Allowed' });
47-
return;
48-
}
49-
50-
if (isDataUri(url)) {
51-
reply.code(400).send({ message: 'Bad Request: Data URIs are not valid HTTP paths' });
52-
return;
53-
}
36+
app.addHook('onRequest', async (req, reply) => {
37+
const { url, method } = req.raw;
38+
accessLogger.logRequest();
5439

55-
req.raw.ilcState = {};
40+
if (!['GET', 'OPTIONS', 'HEAD'].includes(method)) {
41+
logger.warn(`Request method ${method} is not allowed for url ${url}`);
42+
reply.code(405).send({ message: 'Method Not Allowed' });
43+
return;
44+
}
5645

57-
if (isStaticFile(url) || isHealthCheck(url) || ['OPTIONS', 'HEAD'].includes(method)) {
58-
return doneWithContext();
59-
}
46+
if (isDataUri(url)) {
47+
reply.code(400).send({ message: 'Bad Request: Data URIs are not valid HTTP paths' });
48+
return;
49+
}
6050

61-
const domainName = req.hostname;
51+
req.raw.ilcState = {};
6252

63-
const registryConfig = await registryService.getConfig({ filter: { domain: domainName } });
64-
const i18nOnRequest = i18n.onRequestFactory(
65-
registryConfig.settings.i18n,
66-
pluginManager.getI18nParamsDetectionPlugin(),
67-
registryConfig.settings.trailingSlash,
68-
);
53+
if (isStaticFile(url) || isHealthCheck(url) || ['OPTIONS', 'HEAD'].includes(method)) {
54+
return;
55+
}
6956

70-
await i18nOnRequest(req, reply);
57+
const domainName = req.host;
7158

72-
doneWithContext();
73-
} catch (error) {
74-
errorHandler.handleError(error, req, reply);
75-
}
76-
});
77-
});
59+
const registryConfig = await registryService.getConfig({ filter: { domain: domainName } });
60+
const i18nOnRequest = i18n.onRequestFactory(
61+
registryConfig.settings.i18n,
62+
pluginManager.getI18nParamsDetectionPlugin(),
63+
registryConfig.settings.trailingSlash,
64+
);
7865

79-
/**
80-
* Solves issue when async context is lost in webpack-dev-middleware during initial bundle build
81-
* Took from here
82-
* https://github.com/fastify/fastify-request-context/blob/master/index.js#L46
83-
* TODO: after migration to fastify v4 makes sense to use above plugin instead of custom impl
84-
*/
85-
app.addHook('preValidation', (req, res, done) => {
86-
const asyncResource = req[asyncResourceSymbol];
87-
asyncResource.runInAsyncScope(done, req.raw);
66+
await i18nOnRequest(req, reply);
8867
});
8968

9069
app.addHook('onResponse', (req, reply, done) => {
91-
const asyncResource = req[asyncResourceSymbol];
92-
asyncResource.runInAsyncScope(() => {
93-
try {
94-
accessLogger.logResponse({
95-
statusCode: reply.statusCode,
96-
responseTime: reply.getResponseTime(),
97-
});
98-
done();
99-
} catch (error) {
100-
errorHandler.noticeError(error);
101-
}
102-
}, req.raw);
70+
try {
71+
accessLogger.logResponse({
72+
statusCode: reply.statusCode,
73+
responseTime: reply.elapsedTime,
74+
});
75+
done();
76+
} catch (error) {
77+
errorHandler.noticeError(error);
78+
}
10379
});
10480

10581
if (config.get('cdnUrl') === null) {

ilc/server/app.spec.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ const chai = require('chai');
22
const nock = require('nock');
33
const supertest = require('supertest');
44
const helpers = require('../tests/helpers');
5-
const { context } = require('./context/context');
65
const createApp = require('./app');
76

87
async function createTestServer(mockRegistryOptions = {}, mockPluginOptions = {}) {
98
const app = await createApp(
109
helpers.getRegistryMock(mockRegistryOptions),
1110
helpers.getPluginManagerMock(mockPluginOptions),
12-
context,
1311
);
1412

1513
await app.ready();

0 commit comments

Comments
 (0)