@entity-access/server-pages 1.1.348 → 1.1.350
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/dist/Content.d.ts +17 -31
- package/dist/Content.d.ts.map +1 -1
- package/dist/Content.js +117 -97
- package/dist/Content.js.map +1 -1
- package/dist/Page.d.ts +2 -4
- package/dist/Page.d.ts.map +1 -1
- package/dist/Page.js +32 -24
- package/dist/Page.js.map +1 -1
- package/dist/ServerPages.d.ts.map +1 -1
- package/dist/ServerPages.js +9 -3
- package/dist/ServerPages.js.map +1 -1
- package/dist/core/Compression.d.ts +5 -2
- package/dist/core/Compression.d.ts.map +1 -1
- package/dist/core/Compression.js +11 -3
- package/dist/core/Compression.js.map +1 -1
- package/dist/core/Executor.d.ts +1 -1
- package/dist/core/RouteTree.js +1 -2
- package/dist/core/RouteTree.js.map +1 -1
- package/dist/core/Utf8Readable.d.ts +6 -0
- package/dist/core/Utf8Readable.d.ts.map +1 -0
- package/dist/core/Utf8Readable.js +12 -0
- package/dist/core/Utf8Readable.js.map +1 -0
- package/dist/core/Wrapped.d.ts +2 -4
- package/dist/core/Wrapped.d.ts.map +1 -1
- package/dist/core/Wrapped.js +115 -108
- package/dist/core/Wrapped.js.map +1 -1
- package/dist/html/HtmlComment.d.ts +1 -0
- package/dist/html/HtmlComment.d.ts.map +1 -1
- package/dist/html/HtmlComment.js +9 -0
- package/dist/html/HtmlComment.js.map +1 -1
- package/dist/html/HtmlDocument.d.ts.map +1 -1
- package/dist/html/HtmlDocument.js +4 -0
- package/dist/html/HtmlDocument.js.map +1 -1
- package/dist/html/XNode.d.ts +1 -0
- package/dist/html/XNode.d.ts.map +1 -1
- package/dist/html/XNode.js +38 -0
- package/dist/html/XNode.js.map +1 -1
- package/dist/routes/api/entity/expand/[entity]/[property]/[keys]/get.js +2 -2
- package/dist/routes/api/entity/expand/[entity]/[property]/[keys]/get.js.map +1 -1
- package/dist/routes/api/entity/index.d.ts +1 -1
- package/dist/routes/api/entity/invoke/[entityName]/[methodName]/post.d.ts +2 -2
- package/dist/routes/api/entity/invoke/[entityName]/[methodName]/post.d.ts.map +1 -1
- package/dist/routes/api/entity/invoke/[entityName]/[methodName]/post.js +9 -3
- package/dist/routes/api/entity/invoke/[entityName]/[methodName]/post.js.map +1 -1
- package/dist/routes/api/entity/model.ts/get.d.ts +2 -1
- package/dist/routes/api/entity/model.ts/get.d.ts.map +1 -1
- package/dist/routes/api/entity/model.ts/get.js +6 -1
- package/dist/routes/api/entity/model.ts/get.js.map +1 -1
- package/dist/routes/api/entity/query/[entity]/get.js +2 -2
- package/dist/routes/api/entity/query/[entity]/get.js.map +1 -1
- package/dist/routes/api/entity/run/[entity]/[methodName]/index.d.ts +2 -2
- package/dist/routes/api/entity/run/[entity]/[methodName]/index.d.ts.map +1 -1
- package/dist/routes/api/entity/run/[entity]/[methodName]/index.js +7 -3
- package/dist/routes/api/entity/run/[entity]/[methodName]/index.js.map +1 -1
- package/dist/services/DbJsonService.d.ts +5 -5
- package/dist/services/DbJsonService.d.ts.map +1 -1
- package/dist/services/DbJsonService.js +13 -7
- package/dist/services/DbJsonService.js.map +1 -1
- package/dist/services/EntityAccessServer.d.ts +1 -2
- package/dist/services/EntityAccessServer.d.ts.map +1 -1
- package/dist/services/EntityAccessServer.js +1 -8
- package/dist/services/EntityAccessServer.js.map +1 -1
- package/dist/tests/logger/index.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/Content.tsx +149 -120
- package/src/Page.tsx +34 -24
- package/src/ServerPages.ts +15 -6
- package/src/core/Compression.ts +14 -3
- package/src/core/RouteTree.ts +1 -1
- package/src/core/Utf8Readable.ts +15 -0
- package/src/core/Wrapped.ts +121 -111
- package/src/html/HtmlComment.ts +10 -0
- package/src/html/HtmlDocument.tsx +5 -0
- package/src/html/XNode.ts +58 -0
- package/src/routes/api/entity/expand/[entity]/[property]/[keys]/get.ts +2 -2
- package/src/routes/api/entity/invoke/[entityName]/[methodName]/post.tsx +9 -3
- package/src/routes/api/entity/model.ts/get.tsx +7 -1
- package/src/routes/api/entity/query/[entity]/get.ts +2 -2
- package/src/routes/api/entity/run/[entity]/[methodName]/index.ts +7 -5
- package/src/services/DbJsonService.ts +13 -8
- package/src/services/EntityAccessServer.ts +1 -10
- package/src/tests/logger/index.tsx +1 -1
package/src/Content.tsx
CHANGED
|
@@ -6,43 +6,71 @@ import { LocalFile } from "./core/LocalFile.js";
|
|
|
6
6
|
import { SessionUser } from "./core/SessionUser.js";
|
|
7
7
|
import { WrappedResponse } from "./core/Wrapped.js";
|
|
8
8
|
import { OutgoingHttpHeaders } from "http";
|
|
9
|
-
import
|
|
9
|
+
import { Readable } from "stream";
|
|
10
|
+
import Utf8Readable from "./core/Utf8Readable.js";
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const EmptyReader = Readable.from([]);
|
|
13
|
+
|
|
14
|
+
export default class Content {
|
|
15
|
+
|
|
16
|
+
public readonly reader: Readable;
|
|
17
|
+
public readonly status: number = 200;
|
|
18
|
+
public readonly headers: OutgoingHttpHeaders;
|
|
19
|
+
|
|
20
|
+
public suppressLog: boolean;
|
|
14
21
|
|
|
15
|
-
export class JsonReaderResult extends PageResult {
|
|
16
22
|
constructor(
|
|
17
|
-
|
|
18
|
-
public readonly status = 200,
|
|
19
|
-
public readonly headers?: OutgoingHttpHeaders
|
|
23
|
+
p: Partial<Content>
|
|
20
24
|
) {
|
|
21
|
-
|
|
25
|
+
Object.setPrototypeOf(p, Content.prototype);
|
|
26
|
+
return p as Content;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
send(res: WrappedResponse, user?: SessionUser): Promise<any> {
|
|
25
|
-
return res.
|
|
30
|
+
return res.sendReader(this.status, this.headers, this.reader);
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
}
|
|
33
|
+
static readable(readable: Readable, { status = 200, headers = void 0 as OutgoingHttpHeaders }) {
|
|
34
|
+
return new Content({
|
|
35
|
+
reader: readable,
|
|
36
|
+
status,
|
|
37
|
+
headers
|
|
38
|
+
});
|
|
39
|
+
}
|
|
29
40
|
|
|
30
|
-
export class StatusResult extends PageResult {
|
|
31
41
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
static text(
|
|
43
|
+
text: string | Iterable<string> | XNode,
|
|
44
|
+
{
|
|
45
|
+
status = 200,
|
|
46
|
+
headers = void 0 as OutgoingHttpHeaders,
|
|
47
|
+
suppressLog = false
|
|
48
|
+
} = {
|
|
49
|
+
}) {
|
|
50
|
+
|
|
51
|
+
let reader: Readable;
|
|
52
|
+
|
|
53
|
+
headers ??= {};
|
|
54
|
+
headers["content-type"] ??= "text/html; charset=utf-8"
|
|
55
|
+
|
|
56
|
+
if (typeof text === "string") {
|
|
57
|
+
reader = Readable.from([ Buffer.from(text, "utf8") ]);
|
|
58
|
+
} else if (text instanceof XNode) {
|
|
59
|
+
reader = Utf8Readable.from(text.readable());
|
|
60
|
+
} else {
|
|
61
|
+
reader = Utf8Readable.from(text);
|
|
62
|
+
}
|
|
38
63
|
|
|
39
|
-
|
|
40
|
-
|
|
64
|
+
return new Content({
|
|
65
|
+
reader,
|
|
66
|
+
status,
|
|
67
|
+
headers,
|
|
68
|
+
suppressLog
|
|
69
|
+
});
|
|
41
70
|
}
|
|
42
|
-
|
|
43
71
|
}
|
|
44
72
|
|
|
45
|
-
export class FileResult extends
|
|
73
|
+
export class FileResult extends Content {
|
|
46
74
|
|
|
47
75
|
public contentDisposition: "inline" | "attachment" = "inline";
|
|
48
76
|
public cacheControl = true;
|
|
@@ -64,7 +92,7 @@ export class FileResult extends PageResult {
|
|
|
64
92
|
headers
|
|
65
93
|
}: Partial<FileResult> = {}
|
|
66
94
|
) {
|
|
67
|
-
super();
|
|
95
|
+
super({});
|
|
68
96
|
this.contentDisposition = contentDisposition;
|
|
69
97
|
this.cacheControl = cacheControl;
|
|
70
98
|
this.maxAge = maxAge;
|
|
@@ -103,109 +131,110 @@ export class TempFileResult extends FileResult {
|
|
|
103
131
|
|
|
104
132
|
|
|
105
133
|
|
|
106
|
-
export class Redirect extends
|
|
134
|
+
export class Redirect extends Content {
|
|
107
135
|
|
|
108
|
-
constructor(public location: string,
|
|
109
|
-
super();
|
|
136
|
+
constructor(public location: string, status = 301, headers = void 0 as OutgoingHttpHeaders) {
|
|
137
|
+
super({ status, headers });
|
|
110
138
|
}
|
|
111
139
|
|
|
140
|
+
|
|
112
141
|
async send(res: WrappedResponse) {
|
|
113
142
|
return res.sendRedirect(this.location, this.status, this.headers);
|
|
114
143
|
}
|
|
115
144
|
|
|
116
145
|
}
|
|
117
146
|
|
|
118
|
-
export default class Content extends PageResult {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
147
|
+
// export default class Content extends PageResult {
|
|
148
|
+
|
|
149
|
+
// // public static json(json: any, status = 200) {
|
|
150
|
+
// // return new Content({
|
|
151
|
+
// // body: JSON.stringify(json),
|
|
152
|
+
// // contentType: "application/json",
|
|
153
|
+
// // status,
|
|
154
|
+
// // compress: "gzip"
|
|
155
|
+
// // });
|
|
156
|
+
// // }
|
|
157
|
+
|
|
158
|
+
// // public static html(html, status = 200) {
|
|
159
|
+
// // return new Content({
|
|
160
|
+
// // body: html,
|
|
161
|
+
// // contentType: "text/html",
|
|
162
|
+
// // status,
|
|
163
|
+
// // compress: "gzip"
|
|
164
|
+
// // });
|
|
165
|
+
// // }
|
|
166
|
+
|
|
167
|
+
// public static create(
|
|
168
|
+
// body: Partial<Content>
|
|
169
|
+
// ) {
|
|
170
|
+
// return new Content(body);
|
|
171
|
+
// }
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
// public status: number;
|
|
175
|
+
|
|
176
|
+
// public contentType: string;
|
|
177
|
+
|
|
178
|
+
// public suppressLog: boolean;
|
|
179
|
+
|
|
180
|
+
// public body: string | Buffer | XNode;
|
|
181
|
+
|
|
182
|
+
// public headers: OutgoingHttpHeaders;
|
|
183
|
+
|
|
184
|
+
// public compress: "gzip" | "deflate" | null = null;
|
|
185
|
+
|
|
186
|
+
// private constructor(p: Partial<Content>) {
|
|
187
|
+
// super();
|
|
188
|
+
// Object.setPrototypeOf(p, Content.prototype);
|
|
189
|
+
// p.contentType ??= "text/plain";
|
|
190
|
+
// p.status ??= 200;
|
|
191
|
+
// if (p.body === void 0) {
|
|
192
|
+
// throw new Error(`Body cannot be undefined`);
|
|
193
|
+
// }
|
|
194
|
+
// return p as Content;
|
|
195
|
+
// }
|
|
196
|
+
|
|
197
|
+
// public async send(res: WrappedResponse, user?: SessionUser) {
|
|
198
|
+
// const { status, body, contentType } = this;
|
|
199
|
+
// const { headers } = this;
|
|
200
|
+
// if (headers) {
|
|
201
|
+
// for (const key in headers) {
|
|
202
|
+
// if (Object.hasOwn(headers, key)) {
|
|
203
|
+
// const element = headers[key];
|
|
204
|
+
// res.setHeader(key, element);
|
|
205
|
+
// }
|
|
206
|
+
// }
|
|
207
|
+
// }
|
|
208
|
+
|
|
209
|
+
// res.compress = this.compress;
|
|
210
|
+
|
|
211
|
+
// res.setHeader("content-type", contentType);
|
|
212
|
+
// res.statusCode = status;
|
|
213
|
+
// if (typeof body === "string") {
|
|
214
|
+
// if (status >= 300 && !this.suppressLog) {
|
|
215
|
+
// const u = user ? `User: ${user.userID},${user.userName}` : "User: Anonymous";
|
|
216
|
+
// console.error(`${res.req.method} ${res.req.url}\n${status}\n${u}\n${body}`);
|
|
217
|
+
// } else {
|
|
218
|
+
// res.compress ||= "gzip";
|
|
219
|
+
// }
|
|
220
|
+
// res.sendReader(status, headers, Readable.from([ body ]));
|
|
221
|
+
// return;
|
|
222
|
+
// }
|
|
223
|
+
// if (body instanceof XNode) {
|
|
224
|
+
// const text = body.render();
|
|
225
|
+
// if (status >= 300 && !this.suppressLog) {
|
|
226
|
+
// console.error(`${res.req.method} ${res.req.url}\n${status}\n${text}`);
|
|
227
|
+
// } else {
|
|
228
|
+
// res.compress ||= "gzip";
|
|
229
|
+
// }
|
|
230
|
+
// res.send(text);
|
|
231
|
+
// return;
|
|
232
|
+
// }
|
|
233
|
+
// if (status >= 300 && !this.suppressLog) {
|
|
234
|
+
// console.error(`${res.req.method} ${res.req.url}\n${status}\nBINARY DATA`);
|
|
235
|
+
// }
|
|
236
|
+
// res.send(body);
|
|
237
|
+
// return;
|
|
238
|
+
// }
|
|
239
|
+
|
|
240
|
+
// }
|
package/src/Page.tsx
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import busboy from "busboy";
|
|
2
2
|
import HtmlDocument from "./html/HtmlDocument.js";
|
|
3
3
|
import XNode from "./html/XNode.js";
|
|
4
|
-
import Content, { PageResult, Redirect } from "./Content.js";
|
|
4
|
+
// import Content, { PageResult, Redirect } from "./Content.js";
|
|
5
5
|
import { LocalFile } from "./core/LocalFile.js";
|
|
6
6
|
import { WrappedRequest, WrappedResponse } from "./core/Wrapped.js";
|
|
7
7
|
import { ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
|
|
8
8
|
import { IClassOf } from "@entity-access/entity-access/dist/decorators/IClassOf.js";
|
|
9
9
|
import { OutgoingHttpHeaders } from "http";
|
|
10
|
+
import Content, { Redirect } from "./Content.js";
|
|
11
|
+
import JsonGenerator from "@entity-access/entity-access/dist/common/JsonGenerator.js";
|
|
10
12
|
|
|
11
13
|
export const isPage = Symbol("isPage");
|
|
12
14
|
|
|
@@ -94,7 +96,7 @@ export default abstract class Page<TInput = any, TQuery = any> {
|
|
|
94
96
|
this.cacheControl = "no-cache, no-store, max-age=0";
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
abstract run():
|
|
99
|
+
abstract run(): Content | Promise<Content>;
|
|
98
100
|
|
|
99
101
|
resolve<T>(c: IClassOf<T>): T {
|
|
100
102
|
return ServiceProvider.resolve(this, c);
|
|
@@ -104,22 +106,27 @@ export default abstract class Page<TInput = any, TQuery = any> {
|
|
|
104
106
|
console.error(error);
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
protected content(h: Partial<Content>): Content;
|
|
108
|
-
protected content(body: string, status?: number, contentType?: string, headers?: OutgoingHttpHeaders): Content;
|
|
109
|
-
protected content(body: string | Partial<Content>, status?: number, contentType?: string, headers?: OutgoingHttpHeaders) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
109
|
+
// protected content(h: Partial<Content>): Content;
|
|
110
|
+
// protected content(body: string, status?: number, contentType?: string, headers?: OutgoingHttpHeaders): Content;
|
|
111
|
+
// protected content(body: string | Partial<Content>, status?: number, contentType?: string, headers?: OutgoingHttpHeaders) {
|
|
112
|
+
// if (typeof body !== "object") {
|
|
113
|
+
// body = { body, status, contentType, headers};
|
|
114
|
+
// }
|
|
115
|
+
// body.status ??= 200;
|
|
116
|
+
// body.contentType ??= "text/html";
|
|
117
|
+
// return Content.create(body);
|
|
118
|
+
// }
|
|
117
119
|
|
|
118
120
|
protected json(o: any, indent = 0, headers = void 0 as OutgoingHttpHeaders) {
|
|
119
|
-
const content = indent
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
// const content = indent
|
|
122
|
+
// ? JSON.stringify(o, undefined, indent)
|
|
123
|
+
// : JSON.stringify(o);
|
|
124
|
+
const jsr = new JsonGenerator(this);
|
|
125
|
+
headers ??= {};
|
|
126
|
+
headers["content-type"] = "application/json; charset=utf8";
|
|
127
|
+
return Content.readable(jsr.reader(o), {
|
|
128
|
+
headers
|
|
129
|
+
});
|
|
123
130
|
}
|
|
124
131
|
|
|
125
132
|
protected redirect(location: string) {
|
|
@@ -127,7 +134,7 @@ export default abstract class Page<TInput = any, TQuery = any> {
|
|
|
127
134
|
}
|
|
128
135
|
|
|
129
136
|
protected notFound(suppressLog = true): Content | Promise<Content> {
|
|
130
|
-
|
|
137
|
+
return Content.text(<HtmlDocument>
|
|
131
138
|
<head>
|
|
132
139
|
<title>Not found</title>
|
|
133
140
|
</head>
|
|
@@ -136,15 +143,16 @@ export default abstract class Page<TInput = any, TQuery = any> {
|
|
|
136
143
|
<pre>{this.url} not found</pre>
|
|
137
144
|
</body>
|
|
138
145
|
</HtmlDocument>,
|
|
139
|
-
|
|
146
|
+
{
|
|
147
|
+
status: 404,
|
|
148
|
+
suppressLog
|
|
149
|
+
}
|
|
140
150
|
);
|
|
141
|
-
c.suppressLog = suppressLog;
|
|
142
|
-
return c;
|
|
143
151
|
}
|
|
144
152
|
|
|
145
153
|
protected serverError(error, status = 500): Content | Promise<Content> {
|
|
146
|
-
return Content.
|
|
147
|
-
|
|
154
|
+
return Content.text(
|
|
155
|
+
<HtmlDocument>
|
|
148
156
|
<head>
|
|
149
157
|
<title>Server Error</title>
|
|
150
158
|
</head>
|
|
@@ -153,7 +161,9 @@ export default abstract class Page<TInput = any, TQuery = any> {
|
|
|
153
161
|
<pre>{error.stack ?? error}</pre>
|
|
154
162
|
</body>
|
|
155
163
|
</HtmlDocument>,
|
|
156
|
-
|
|
157
|
-
|
|
164
|
+
{
|
|
165
|
+
status
|
|
166
|
+
}
|
|
167
|
+
);
|
|
158
168
|
}
|
|
159
169
|
}
|
package/src/ServerPages.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { WebSocket } from "ws";
|
|
|
21
21
|
import { UrlParser } from "./core/UrlParser.js";
|
|
22
22
|
import { createConnection } from "node:net";
|
|
23
23
|
import HttpIPCProxyReceiver from "./core/HttpIPCProxyReceiver.js";
|
|
24
|
+
import JsonGenerator from "@entity-access/entity-access/dist/common/JsonGenerator.js";
|
|
24
25
|
|
|
25
26
|
export const wsData = Symbol("wsData");
|
|
26
27
|
|
|
@@ -338,17 +339,25 @@ export default class ServerPages {
|
|
|
338
339
|
try {
|
|
339
340
|
|
|
340
341
|
if (acceptJson || error.errorModel) {
|
|
341
|
-
|
|
342
|
+
|
|
343
|
+
const json = new JsonGenerator(this);
|
|
344
|
+
const reader = json.reader({
|
|
345
|
+
details: error.stack ?? error,
|
|
346
|
+
... error.errorModel ?? {},
|
|
347
|
+
message: error.message ?? error,
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
await new Content(
|
|
342
351
|
{
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
message: error.message ?? error,
|
|
352
|
+
reader,
|
|
353
|
+
status: error.errorModel?.status ?? 500
|
|
346
354
|
}
|
|
347
|
-
,
|
|
355
|
+
,).send(resp);
|
|
348
356
|
return;
|
|
349
357
|
}
|
|
350
358
|
|
|
351
|
-
const content = Content.
|
|
359
|
+
const content = Content.text(`<!DOCTYPE html>\n<html><body><pre>Server Error for ${req.url}\r\n${error?.stack ?? error}</pre></body></html>`,
|
|
360
|
+
{ status: 500});
|
|
352
361
|
await content.send(resp);
|
|
353
362
|
} catch (e1) {
|
|
354
363
|
e1 = e1.stack ?? e1.toString();
|
package/src/core/Compression.ts
CHANGED
|
@@ -1,15 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
import { createGzip, deflateSync, gzipSync, createDeflate } from "zlib";
|
|
2
3
|
|
|
3
4
|
export default class Compression {
|
|
4
5
|
|
|
5
|
-
public static gzip(
|
|
6
|
+
public static gzip(readable: Readable) {
|
|
7
|
+
const stream = createGzip();
|
|
8
|
+
return readable.pipe(stream);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public static deflate(readable: Readable) {
|
|
12
|
+
const stream = createDeflate();
|
|
13
|
+
return readable.pipe(stream);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public static gzipSync(data: Buffer | string) {
|
|
6
17
|
if (typeof data === "string") {
|
|
7
18
|
data = Buffer.from(data, "utf-8");
|
|
8
19
|
}
|
|
9
20
|
return gzipSync(data);
|
|
10
21
|
}
|
|
11
22
|
|
|
12
|
-
public static
|
|
23
|
+
public static deflateSync(data: Buffer | string) {
|
|
13
24
|
if (typeof data === "string") {
|
|
14
25
|
data = Buffer.from(data, "utf-8");
|
|
15
26
|
}
|
package/src/core/RouteTree.ts
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
|
|
3
|
+
export default class Utf8Readable {
|
|
4
|
+
|
|
5
|
+
static from(text: Iterable<string>) {
|
|
6
|
+
return Readable.from( this.toUtf8Iterable(text));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
private static *toUtf8Iterable(text: Iterable<string>) {
|
|
10
|
+
for (const element of text) {
|
|
11
|
+
yield Buffer.from(element, "utf8");
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
}
|