mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-07-03 02:21:38 +00:00
fix: Replace connect-gzip-static with express-static-gzip to become compatible with Node 23 (#24619)
Old versions of connect-gzip-static are not compatible with node 23, new versions of connect-gzip-static are not compatible with node 18, but we want to support both. express-static-gzip is compatible with all versions.
This commit is contained in:
@@ -9,7 +9,7 @@ import {posix} from 'path';
|
||||
import {parse} from 'url';
|
||||
|
||||
import bind from 'bind-decorator';
|
||||
import gzipStatic, {RequestHandler} from 'connect-gzip-static';
|
||||
import expressStaticGzip, {RequestHandler} from 'express-static-gzip';
|
||||
import finalhandler from 'finalhandler';
|
||||
import stringify from 'json-stable-stringify-without-jsonify';
|
||||
import WebSocket from 'ws';
|
||||
@@ -73,13 +73,16 @@ export default class Frontend extends Extension {
|
||||
override async start(): Promise<void> {
|
||||
/* istanbul ignore next */
|
||||
const options = {
|
||||
setHeaders: (res: ServerResponse, path: string): void => {
|
||||
if (path.endsWith('index.html')) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
}
|
||||
enableBrotli: true,
|
||||
serveStatic: {
|
||||
setHeaders: (res: ServerResponse, path: string): void => {
|
||||
if (path.endsWith('index.html')) {
|
||||
res.setHeader('Cache-Control', 'no-store');
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
this.fileServer = gzipStatic(frontend.getPath(), options);
|
||||
this.fileServer = expressStaticGzip(frontend.getPath(), options);
|
||||
this.wss = new WebSocket.Server({noServer: true, path: posix.join(this.baseUrl, 'api')});
|
||||
|
||||
this.wss.on('connection', this.onWebSocketConnection);
|
||||
@@ -133,6 +136,7 @@ export default class Frontend extends Extension {
|
||||
// This is necessary for the browser to resolve relative assets paths correctly.
|
||||
request.originalUrl = request.url;
|
||||
request.url = '/' + newUrl;
|
||||
request.path = request.url;
|
||||
|
||||
this.fileServer(request, response, fin);
|
||||
}
|
||||
|
||||
Vendored
+3
-2
@@ -5,11 +5,12 @@ declare module 'zigbee2mqtt-frontend' {
|
||||
declare module 'http' {
|
||||
interface IncomingMessage {
|
||||
originalUrl?: string;
|
||||
path?: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'connect-gzip-static' {
|
||||
declare module 'express-static-gzip' {
|
||||
import {IncomingMessage, ServerResponse} from 'http';
|
||||
export type RequestHandler = (req: IncomingMessage, res: ServerResponse, finalhandler: (err: unknown) => void) => void;
|
||||
export default function gzipStatic(root: string, options?: Record<string, unknown>): RequestHandler;
|
||||
export default function expressStaticGzip(root: string, options?: Record<string, unknown>): RequestHandler;
|
||||
}
|
||||
|
||||
Generated
+49
-68
@@ -11,8 +11,8 @@
|
||||
"dependencies": {
|
||||
"ajv": "^8.17.1",
|
||||
"bind-decorator": "^1.0.11",
|
||||
"connect-gzip-static": "3.0.1",
|
||||
"debounce": "^2.2.0",
|
||||
"express-static-gzip": "^2.1.8",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"finalhandler": "^1.3.1",
|
||||
"git-last-commit": "^1.0.1",
|
||||
@@ -57,6 +57,7 @@
|
||||
"@types/object-assign-deep": "^0.4.3",
|
||||
"@types/readable-stream": "4.0.18",
|
||||
"@types/sd-notify": "^2.8.2",
|
||||
"@types/serve-static": "^1.15.7",
|
||||
"@types/ws": "8.5.13",
|
||||
"babel-jest": "^29.7.0",
|
||||
"eslint": "^9.14.0",
|
||||
@@ -68,7 +69,7 @@
|
||||
"typescript-eslint": "^8.12.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || ^22"
|
||||
"node": "^18 || ^20 || ^22 || ^23"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"sd-notify": "^2.8.0"
|
||||
@@ -2149,20 +2150,6 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@folder/readdir": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@folder/readdir/-/readdir-3.1.0.tgz",
|
||||
"integrity": "sha512-mqkVdQ77BcCOWur/dxoPxjJS2eJg8Eqqx1Dgdc/qbTeGI5UMPDLmT0peGEjxLdlnD9SvhMnpJuiyaYl2btdT6A==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/jonschlinkert",
|
||||
"https://paypal.me/jonathanschlinkert",
|
||||
"https://jonschlinkert.dev/sponsor"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanfs/core": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
|
||||
@@ -3056,6 +3043,13 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-errors": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
|
||||
"integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/humanize-duration": {
|
||||
"version": "3.27.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.27.4.tgz",
|
||||
@@ -3115,6 +3109,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.6.tgz",
|
||||
@@ -3148,6 +3149,29 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/send": {
|
||||
"version": "0.17.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
|
||||
"integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/mime": "^1",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/serve-static": {
|
||||
"version": "1.15.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz",
|
||||
"integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/http-errors": "*",
|
||||
"@types/node": "*",
|
||||
"@types/send": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/stack-utils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
|
||||
@@ -4182,19 +4206,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/connect-gzip-static": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/connect-gzip-static/-/connect-gzip-static-3.0.1.tgz",
|
||||
"integrity": "sha512-VVqi1fJ4uZK8aIrb1BN9n7tsRAbc3BhkIo/mz1VuNhYC2KDuP1ZgCDapjYIfT3mcGgWzyUr04kv7nmnGOnCvWg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@folder/readdir": "^3.1.0",
|
||||
"debug": "~2||~3||~4",
|
||||
"parseurl": "~1",
|
||||
"send": "~0",
|
||||
"serve-static": "~1"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
@@ -4813,6 +4824,15 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express-static-gzip": {
|
||||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.1.8.tgz",
|
||||
"integrity": "sha512-g8tiJuI9Y9Ffy59ehVXvqb0hhP83JwZiLxzanobPaMbkB5qBWA8nuVgd+rcd5qzH3GkgogTALlc0BaADYwnMbQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"serve-static": "^1.16.2"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
@@ -7563,45 +7583,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz",
|
||||
"integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/debug/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
|
||||
+3
-2
@@ -8,7 +8,7 @@
|
||||
"url": "git+https://github.com/Koenkk/zigbee2mqtt.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || ^22"
|
||||
"node": "^18 || ^20 || ^22 || ^23"
|
||||
},
|
||||
"keywords": [
|
||||
"xiaomi",
|
||||
@@ -39,8 +39,8 @@
|
||||
"dependencies": {
|
||||
"ajv": "^8.17.1",
|
||||
"bind-decorator": "^1.0.11",
|
||||
"connect-gzip-static": "3.0.1",
|
||||
"debounce": "^2.2.0",
|
||||
"express-static-gzip": "^2.1.8",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"finalhandler": "^1.3.1",
|
||||
"git-last-commit": "^1.0.1",
|
||||
@@ -82,6 +82,7 @@
|
||||
"@types/object-assign-deep": "^0.4.3",
|
||||
"@types/readable-stream": "4.0.18",
|
||||
"@types/sd-notify": "^2.8.2",
|
||||
"@types/serve-static": "^1.15.7",
|
||||
"@types/ws": "8.5.13",
|
||||
"babel-jest": "^29.7.0",
|
||||
"eslint": "^9.14.0",
|
||||
|
||||
+18
-6
@@ -86,7 +86,7 @@ jest.mock('https', () => ({
|
||||
Agent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('connect-gzip-static', () =>
|
||||
jest.mock('express-static-gzip', () =>
|
||||
jest.fn().mockImplementation((path) => {
|
||||
mockNodeStatic.variables.path = path;
|
||||
return mockNodeStatic.implementation;
|
||||
@@ -321,7 +321,11 @@ describe('Frontend', () => {
|
||||
|
||||
mockHTTP.variables.onRequest({url: '/file.txt'}, 2);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith({originalUrl: '/file.txt', url: '/file.txt'}, 2, expect.any(Function));
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith(
|
||||
{originalUrl: '/file.txt', url: '/file.txt', path: '/file.txt'},
|
||||
2,
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('Static server', async () => {
|
||||
@@ -367,14 +371,18 @@ describe('Frontend', () => {
|
||||
|
||||
mockHTTP.variables.onRequest({url: '/z2m'}, 2);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith({originalUrl: '/z2m', url: '/'}, 2, expect.any(Function));
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith({originalUrl: '/z2m', url: '/', path: '/'}, 2, expect.any(Function));
|
||||
expect(mockFinalHandler.implementation).not.toHaveBeenCalledWith();
|
||||
|
||||
mockNodeStatic.implementation.mockReset();
|
||||
expect(mockFinalHandler.implementation).not.toHaveBeenCalledWith();
|
||||
mockHTTP.variables.onRequest({url: '/z2m/file.txt'}, 2);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith({originalUrl: '/z2m/file.txt', url: '/file.txt'}, 2, expect.any(Function));
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith(
|
||||
{originalUrl: '/z2m/file.txt', url: '/file.txt', path: '/file.txt'},
|
||||
2,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(mockFinalHandler.implementation).not.toHaveBeenCalledWith();
|
||||
|
||||
mockNodeStatic.implementation.mockReset();
|
||||
@@ -393,7 +401,11 @@ describe('Frontend', () => {
|
||||
|
||||
mockHTTP.variables.onRequest({url: '/z2m-more++/c0mplex.url'}, 2);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith({originalUrl: '/z2m-more++/c0mplex.url', url: '/'}, 2, expect.any(Function));
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith(
|
||||
{originalUrl: '/z2m-more++/c0mplex.url', url: '/', path: '/'},
|
||||
2,
|
||||
expect.any(Function),
|
||||
);
|
||||
expect(mockFinalHandler.implementation).not.toHaveBeenCalledWith();
|
||||
|
||||
mockNodeStatic.implementation.mockReset();
|
||||
@@ -401,7 +413,7 @@ describe('Frontend', () => {
|
||||
mockHTTP.variables.onRequest({url: '/z2m-more++/c0mplex.url/file.txt'}, 2);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledTimes(1);
|
||||
expect(mockNodeStatic.implementation).toHaveBeenCalledWith(
|
||||
{originalUrl: '/z2m-more++/c0mplex.url/file.txt', url: '/file.txt'},
|
||||
{originalUrl: '/z2m-more++/c0mplex.url/file.txt', url: '/file.txt', path: '/file.txt'},
|
||||
2,
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user