-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
126 lines (102 loc) · 2.99 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { createDeflate, createGzip, createBrotliCompress } from "node:zlib";
import { Middleware, IMiddlewareParams, Context } from "binden";
export const DefaultCompression = "br";
export type IComressFormats = "auto" | "br" | "deflate" | "gzip";
export interface ICompressionOptions extends IMiddlewareParams {
format?: IComressFormats;
}
export class Compression extends Middleware {
readonly #format: IComressFormats;
public constructor({ format = "auto", ...rest }: ICompressionOptions = {}) {
super(rest);
this.#format = format;
}
public get format(): IComressFormats {
return this.#format;
}
public run(context: Context): Context {
const format = Compression.#getFormat(context, this.format);
if (format === "identity") {
return context;
}
const { response } = context;
const raw = response.getHeader("Content-Encoding");
response.setHeader(
"Content-Encoding",
typeof raw === "undefined"
? format
: [format, ...(Array.isArray(raw) ? raw : [`${raw}`])],
);
const compress =
format === "br"
? createBrotliCompress()
: format === "deflate"
? createDeflate()
: createGzip();
compress.pipe(response);
const proxyResponse = new Proxy(response, {
get(_r, p: string): unknown {
if (p === "write") {
return function write(
data?: unknown,
encoding?: BufferEncoding,
cb?: (error?: Error | null) => void,
): void {
compress.write(data, encoding, cb);
};
} else if (p === "end") {
return function end(
data?: unknown,
encoding?: BufferEncoding,
cb?: () => void,
): void {
compress.end(data, encoding, cb);
};
}
return (response as unknown as Record<string, unknown>)[p];
},
});
return new Proxy(context, {
get(_ct, p: string): unknown {
if (p === "response") {
return proxyResponse;
}
return (context as unknown as Record<string, unknown>)[p];
},
set(_ct, p: string, value: unknown): boolean {
(context as unknown as Record<string, unknown>)[p] = value;
return true;
},
});
}
static #getFormat(
context: Context,
format: IComressFormats,
): Exclude<IComressFormats, "auto"> | "identity" {
if (format !== "auto") {
return format;
}
const { accept_encoding } = context.request;
if (!accept_encoding.length) {
return DefaultCompression;
}
for (const { encoding } of accept_encoding) {
switch (encoding) {
case "*":
return DefaultCompression;
case "identity":
return "identity";
case "x-gzip":
return "gzip";
case "br":
case "deflate":
case "gzip":
return encoding;
default:
break;
}
}
return "identity";
}
}
export default new Compression();