Compare commits

...

8 Commits

Author SHA1 Message Date
b6a4095a53 3.0.17 2024-01-09 11:38:06 +01:00
622da78180 fix(core): update 2024-01-09 11:38:06 +01:00
21938e5f20 3.0.16 2024-01-09 10:25:04 +01:00
99427f5835 fix(core): update 2024-01-09 10:25:03 +01:00
552a15bb2f 3.0.15 2024-01-09 10:21:02 +01:00
b0efc48b96 fix(core): update 2024-01-09 10:21:01 +01:00
8c3aad69a0 3.0.14 2024-01-09 10:14:07 +01:00
fb2692b50e fix(core): update 2024-01-09 10:14:06 +01:00
8 changed files with 70 additions and 22 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@api.global/typedserver",
"version": "3.0.13",
"version": "3.0.17",
"description": "easy serving of static files",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@api.global/typedserver',
version: '3.0.13',
version: '3.0.17',
description: 'easy serving of static files'
}

View File

@ -1,8 +1,14 @@
import * as plugins from '../typedserver.plugins.js';
export type TCompressionMethod = 'gzip' | 'deflate' | 'br' | 'none';
export interface ICompressionResult {
result: Buffer;
compressionMethod: TCompressionMethod;
}
export class Compressor {
private _cache: Map<string, Buffer>;
private MAX_CACHE_SIZE: number = 20 * 1024 * 1024; // 20 MB
private MAX_CACHE_SIZE: number = 100 * 1024 * 1024; // 100 MB
constructor() {
this._cache = new Map<string, Buffer>();
@ -46,10 +52,12 @@ export class Compressor {
switch (method) {
case 'gzip':
plugins.zlib.gzip(content, callback);
plugins.zlib.gzip(content, {
level: 1,
},callback,);
break;
case 'br':
plugins.zlib.brotliCompress(content, callback);
plugins.zlib.brotliCompress(content, {}, callback);
break;
case 'deflate':
plugins.zlib.deflate(content, callback);
@ -61,15 +69,22 @@ export class Compressor {
});
}
public determineCompression(acceptEncoding: string | string[]) {
public determineCompression(acceptEncoding: string | string[], preferredCompressionMethodsArg: TCompressionMethod[] = []) {
// Ensure acceptEncoding is a single string
const encodingString = Array.isArray(acceptEncoding)
? acceptEncoding.join(', ')
: acceptEncoding;
let compressionMethod: 'gzip' | 'deflate' | 'br' | 'none' = 'none';
let compressionMethod: TCompressionMethod = 'none';
// Check and prioritize compression methods
// Prioritize preferred compression methods if provided
for (const preferredMethod of preferredCompressionMethodsArg) {
if (new RegExp(`\\b${preferredMethod}\\b`).test(encodingString)) {
return preferredMethod;
}
}
// Fallback to default prioritization if no preferred method matches
if (/\bbr\b/.test(encodingString)) {
compressionMethod = 'br';
} else if (/\bgzip\b/.test(encodingString)) {
@ -81,9 +96,9 @@ export class Compressor {
return compressionMethod;
}
public async maybeCompress(requestHeaders: plugins.http.IncomingHttpHeaders, content: Buffer) {
public async maybeCompress(requestHeaders: plugins.http.IncomingHttpHeaders, content: Buffer, preferredCompressionMethodsArg?: TCompressionMethod[]): Promise<ICompressionResult> {
const acceptEncoding = requestHeaders['accept-encoding'];
const compressionMethod = this.determineCompression(acceptEncoding);
const compressionMethod = this.determineCompression(acceptEncoding, preferredCompressionMethodsArg);
const result = await this.compressContent(content, compressionMethod);
return {
result,
@ -92,15 +107,21 @@ export class Compressor {
}
public createCompressionStream(method: 'gzip' | 'deflate' | 'br' | 'none') {
let compressionStream: any;
switch (method) {
case 'gzip':
return plugins.zlib.createGzip();
compressionStream = plugins.zlib.createGzip();
case 'br':
return plugins.zlib.createBrotliCompress();
compressionStream = plugins.zlib.createBrotliCompress({
chunkSize: 16 * 1024,
params: {
},
});
case 'deflate':
return plugins.zlib.createDeflate();
compressionStream = plugins.zlib.createDeflate();
default:
throw new Error('Invalid compression method');
compressionStream = plugins.smartstream.createPassThrough();
}
}
}

View File

@ -2,7 +2,7 @@ import * as plugins from '../typedserver.plugins.js';
import * as interfaces from '../interfaces/index.js';
import { Handler } from './classes.handler.js';
import { Compressor } from './classes.compressor.js';
import { Compressor, type TCompressionMethod, type ICompressionResult } from './classes.compressor.js';
export class HandlerStatic extends Handler {
public compressor = new Compressor();
@ -13,6 +13,8 @@ export class HandlerStatic extends Handler {
responseModifier?: interfaces.TResponseModifier;
headers?: { [key: string]: string };
serveIndexHtmlDefault?: boolean;
enableCompression?: boolean;
preferredCompressionMethod?: TCompressionMethod;
}
) {
super('GET', async (req, res) => {
@ -118,10 +120,16 @@ export class HandlerStatic extends Handler {
}
// lets finally deal with compression
const compressionResult = await this.compressor.maybeCompress(requestHeaders, fileBuffer);
let compressionResult: ICompressionResult;
if (optionsArg && optionsArg.enableCompression) {
compressionResult = await this.compressor.maybeCompress(requestHeaders, fileBuffer, [optionsArg.preferredCompressionMethod]);
}
res.status(200);
res.header('Content-Encoding', compressionResult.compressionMethod);
if (compressionResult?.compressionMethod) {
res.header('Content-Encoding', compressionResult.compressionMethod);
}
res.write(compressionResult.result);
res.end();
});

View File

@ -2,6 +2,7 @@ import * as plugins from './typedserver.plugins.js';
import * as paths from './typedserver.paths.js';
import * as interfaces from './interfaces/index.js';
import * as servertools from './servertools/index.js';
import { type TCompressionMethod } from './servertools/classes.compressor.js';
export interface IServerOptions {
/**
@ -14,6 +15,16 @@ export interface IServerOptions {
*/
injectReload?: boolean;
/**
* enable compression
*/
enableCompression?: boolean;
/**
* choose a preferred compression method
*/
preferredCompressionMethod?: TCompressionMethod;
/**
* watch the serve directory?
*/
@ -157,6 +168,8 @@ export class TypedServer {
};
},
serveIndexHtmlDefault: true,
enableCompression: this.options.enableCompression,
preferredCompressionMethod: this.options.preferredCompressionMethod,
})
);
} else if (this.options.injectReload) {

View File

@ -3,6 +3,7 @@ import * as http from 'http';
import * as https from 'https';
import * as net from 'net';
import * as path from 'path';
import * as stream from 'stream';
import * as zlib from 'zlib';
export { http, https, net, path, zlib };

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@api.global/typedserver',
version: '3.0.13',
version: '3.0.17',
description: 'easy serving of static files'
}

View File

@ -1,9 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "nodenext",
"esModuleInterop": true
}
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"exclude": [
"dist_*/**/*.d.ts"
]
}