@dooboostore/simple-boot-http-server 1.0.29 → 1.0.31
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/README.md +58 -1
- package/dist/cjs/SimpleBootHttpServer.js +9 -4
- package/dist/cjs/SimpleBootHttpServer.js.map +2 -2
- package/dist/cjs/codes/Mimes.js +2 -0
- package/dist/cjs/codes/Mimes.js.map +2 -2
- package/dist/cjs/generators/ContentTypeGenerator.js +320 -0
- package/dist/cjs/generators/ContentTypeGenerator.js.map +7 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/models/RequestResponse.js +3 -2
- package/dist/cjs/models/RequestResponse.js.map +2 -2
- package/dist/esm/SimpleBootHttpServer.js +9 -4
- package/dist/esm/SimpleBootHttpServer.js.map +2 -2
- package/dist/esm/codes/Mimes.js +2 -0
- package/dist/esm/codes/Mimes.js.map +2 -2
- package/dist/esm/generators/ContentTypeGenerator.js +287 -0
- package/dist/esm/generators/ContentTypeGenerator.js.map +7 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/models/RequestResponse.js +3 -2
- package/dist/esm/models/RequestResponse.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js +628 -5219
- package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js.map +4 -4
- package/dist/types/SimpleBootHttpServer.d.ts.map +1 -1
- package/dist/types/codes/Mimes.d.ts +2 -0
- package/dist/types/codes/Mimes.d.ts.map +1 -1
- package/dist/types/generators/ContentTypeGenerator.d.ts +172 -0
- package/dist/types/generators/ContentTypeGenerator.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/models/RequestResponse.d.ts +4 -1
- package/dist/types/models/RequestResponse.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js +628 -5219
- package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js.map +4 -4
- package/package.json +4 -4
- package/src/SimpleBootHttpServer.ts +12 -4
- package/src/codes/Mimes.ts +2 -0
- package/src/generators/ContentTypeGenerator.ts +431 -0
- package/src/index.ts +1 -0
- package/src/models/RequestResponse.ts +3 -2
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { randomBytes } from "crypto";
|
|
2
|
+
import mime from "mime-types";
|
|
3
|
+
import { ValidUtils } from "@dooboostore/core";
|
|
4
|
+
import { Mimes } from "../codes/Mimes.js";
|
|
5
|
+
var ContentTypeGenerator;
|
|
6
|
+
((ContentTypeGenerator2) => {
|
|
7
|
+
ContentTypeGenerator2.isStream = (value) => ValidUtils.isAsyncGenerator(value) && typeof value.contentType === "string";
|
|
8
|
+
const oneLine = (v) => v.replace(/[\r\n]/g, " ");
|
|
9
|
+
ContentTypeGenerator2.sseChunk = (e) => {
|
|
10
|
+
const ev = typeof e === "string" ? { data: e } : e;
|
|
11
|
+
let out = "";
|
|
12
|
+
if (ev.comment !== void 0) out += ev.comment.split(/\r\n|\r|\n/).map((l) => `: ${l}
|
|
13
|
+
`).join("");
|
|
14
|
+
if (ev.event !== void 0) out += `event: ${oneLine(ev.event)}
|
|
15
|
+
`;
|
|
16
|
+
if (ev.id !== void 0) out += `id: ${oneLine(ev.id)}
|
|
17
|
+
`;
|
|
18
|
+
if (ev.retry !== void 0) out += `retry: ${Math.max(0, Math.floor(ev.retry))}
|
|
19
|
+
`;
|
|
20
|
+
if (ev.data !== void 0) {
|
|
21
|
+
const text2 = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
|
|
22
|
+
out += text2.split(/\r\n|\r|\n/).map((l) => `data: ${l}
|
|
23
|
+
`).join("");
|
|
24
|
+
}
|
|
25
|
+
return out + "\n";
|
|
26
|
+
};
|
|
27
|
+
ContentTypeGenerator2.ssePing = () => ": ping\n\n";
|
|
28
|
+
const sniff = (b) => {
|
|
29
|
+
if (b.length >= 3 && b[0] === 255 && b[1] === 216 && b[2] === 255) return Mimes.ImageJpeg;
|
|
30
|
+
if (b.length >= 8 && b.readUInt32BE(0) === 2303741511 && b.readUInt32BE(4) === 218765834) return Mimes.ImagePng;
|
|
31
|
+
if (b.length >= 6 && b.toString("ascii", 0, 4) === "GIF8") return Mimes.ImageGif;
|
|
32
|
+
if (b.length >= 12 && b.toString("ascii", 0, 4) === "RIFF" && b.toString("ascii", 8, 12) === "WEBP") return "image/webp";
|
|
33
|
+
return void 0;
|
|
34
|
+
};
|
|
35
|
+
ContentTypeGenerator2.partType = (part, fallback) => {
|
|
36
|
+
const p = isPartObject(part) ? part : { body: part };
|
|
37
|
+
if (p.type) return p.type;
|
|
38
|
+
if (p.name) {
|
|
39
|
+
const byName = mime.lookup(p.name);
|
|
40
|
+
if (byName) return mime.contentType(byName) || byName;
|
|
41
|
+
}
|
|
42
|
+
if (typeof p.body === "string") return fallback ?? Mimes.TextPlainUtf8;
|
|
43
|
+
return sniff(Buffer.from(p.body.buffer, p.body.byteOffset, p.body.byteLength)) ?? fallback ?? Mimes.ApplicationOctetStream;
|
|
44
|
+
};
|
|
45
|
+
const isPartObject = (part) => typeof part === "object" && !(part instanceof Uint8Array);
|
|
46
|
+
const toBuffer = (body) => typeof body === "string" ? Buffer.from(body, "utf8") : Buffer.isBuffer(body) ? body : Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
47
|
+
ContentTypeGenerator2.multipartPart = (part, boundary2, fallbackType) => {
|
|
48
|
+
const p = isPartObject(part) ? part : { body: part };
|
|
49
|
+
const body = toBuffer(p.body);
|
|
50
|
+
let head = `--${boundary2}\r
|
|
51
|
+
Content-Type: ${(0, ContentTypeGenerator2.partType)(part, fallbackType)}\r
|
|
52
|
+
Content-Length: ${body.length}\r
|
|
53
|
+
`;
|
|
54
|
+
for (const [k, v] of Object.entries(p.headers ?? {})) head += `${oneLine(k)}: ${oneLine(v)}\r
|
|
55
|
+
`;
|
|
56
|
+
return Buffer.concat([Buffer.from(head + "\r\n", "latin1"), body, Buffer.from("\r\n")]);
|
|
57
|
+
};
|
|
58
|
+
ContentTypeGenerator2.multipartEnd = (boundary2) => Buffer.from(`--${boundary2}--\r
|
|
59
|
+
`);
|
|
60
|
+
ContentTypeGenerator2.ndjsonLine = (value) => json(value) + "\n";
|
|
61
|
+
const json = (value) => JSON.stringify(value) ?? "null";
|
|
62
|
+
ContentTypeGenerator2.jsonSeqRecord = (value) => "" + json(value) + "\n";
|
|
63
|
+
ContentTypeGenerator2.csvCell = (value) => {
|
|
64
|
+
if (value === null || value === void 0) return "";
|
|
65
|
+
const s = typeof value === "string" ? value : value instanceof Date ? value.toISOString() : typeof value === "object" ? json(value) : String(value);
|
|
66
|
+
return /[",\r\n]|^\s|\s$/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
|
|
67
|
+
};
|
|
68
|
+
ContentTypeGenerator2.csvRow = (cells) => cells.map(ContentTypeGenerator2.csvCell).join(",") + "\r\n";
|
|
69
|
+
ContentTypeGenerator2.textLine = (value) => (typeof value === "string" ? value : json(value)) + "\n";
|
|
70
|
+
ContentTypeGenerator2.boundary = (value) => {
|
|
71
|
+
const b = value ?? `boundary-${randomBytes(12).toString("hex")}`;
|
|
72
|
+
if (!/^[0-9A-Za-z'()+_,\-./:=? ]{0,69}[0-9A-Za-z'()+_,\-./:=?]$/.test(b)) {
|
|
73
|
+
throw new Error(`invalid multipart boundary: ${JSON.stringify(b)}`);
|
|
74
|
+
}
|
|
75
|
+
return b;
|
|
76
|
+
};
|
|
77
|
+
const toStream = (gen, contentType, compress) => Object.assign(gen, { contentType, compress });
|
|
78
|
+
async function* encode(src, fn) {
|
|
79
|
+
for await (const v of src) yield fn(v);
|
|
80
|
+
}
|
|
81
|
+
async function* framed(src, fn, start, end) {
|
|
82
|
+
if (start !== void 0) yield start;
|
|
83
|
+
yield* encode(src, fn);
|
|
84
|
+
if (end !== void 0) yield end;
|
|
85
|
+
}
|
|
86
|
+
const jsonArrayItem = () => {
|
|
87
|
+
let n = 0;
|
|
88
|
+
return (v) => (n++ ? "," : "") + json(v);
|
|
89
|
+
};
|
|
90
|
+
const csvEncoder = (opt) => (r) => (0, ContentTypeGenerator2.csvRow)(Array.isArray(r) ? r : opt.columns ? opt.columns.map((c) => r[c]) : Object.values(r));
|
|
91
|
+
const csvStart = (opt) => opt.bom || opt.columns ? (opt.bom ? "\uFEFF" : "") + (opt.columns ? (0, ContentTypeGenerator2.csvRow)(opt.columns) : "") : void 0;
|
|
92
|
+
const CsvType = `${Mimes.TextCsv}; charset=utf-8`;
|
|
93
|
+
function sse(src, opt = {}) {
|
|
94
|
+
const contentType = Mimes.TextEventStream;
|
|
95
|
+
if (!opt.heartbeatMs) return toStream(encode(src, ContentTypeGenerator2.sseChunk), contentType, true);
|
|
96
|
+
const ms = opt.heartbeatMs;
|
|
97
|
+
async function* withPing() {
|
|
98
|
+
const it = Symbol.asyncIterator in src ? src[Symbol.asyncIterator]() : src[Symbol.iterator]();
|
|
99
|
+
let pending;
|
|
100
|
+
try {
|
|
101
|
+
while (true) {
|
|
102
|
+
pending ??= Promise.resolve(it.next());
|
|
103
|
+
let timer;
|
|
104
|
+
const tick = new Promise((r2) => timer = setTimeout(() => r2("ping"), ms));
|
|
105
|
+
const r = await Promise.race([pending, tick]);
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
if (r === "ping") {
|
|
108
|
+
yield (0, ContentTypeGenerator2.ssePing)();
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
pending = void 0;
|
|
112
|
+
if (r.done) return;
|
|
113
|
+
yield (0, ContentTypeGenerator2.sseChunk)(r.value);
|
|
114
|
+
}
|
|
115
|
+
} finally {
|
|
116
|
+
await it.return?.();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return toStream(withPing(), contentType, true);
|
|
120
|
+
}
|
|
121
|
+
ContentTypeGenerator2.sse = sse;
|
|
122
|
+
function multipartReplace(src, opt = {}) {
|
|
123
|
+
const b = (0, ContentTypeGenerator2.boundary)(opt.boundary);
|
|
124
|
+
return toStream(encode(src, (p) => (0, ContentTypeGenerator2.multipartPart)(p, b, opt.type)), `multipart/x-mixed-replace; boundary=${b}`, false);
|
|
125
|
+
}
|
|
126
|
+
ContentTypeGenerator2.multipartReplace = multipartReplace;
|
|
127
|
+
function multipartMixed(src, opt = {}) {
|
|
128
|
+
const b = (0, ContentTypeGenerator2.boundary)(opt.boundary);
|
|
129
|
+
return toStream(framed(src, (p) => (0, ContentTypeGenerator2.multipartPart)(p, b, opt.type), void 0, (0, ContentTypeGenerator2.multipartEnd)(b)), `multipart/mixed; boundary=${b}`, true);
|
|
130
|
+
}
|
|
131
|
+
ContentTypeGenerator2.multipartMixed = multipartMixed;
|
|
132
|
+
function ndjson(src) {
|
|
133
|
+
return toStream(encode(src, ContentTypeGenerator2.ndjsonLine), Mimes.ApplicationXndjson, true);
|
|
134
|
+
}
|
|
135
|
+
ContentTypeGenerator2.ndjson = ndjson;
|
|
136
|
+
function jsonSeq(src) {
|
|
137
|
+
return toStream(encode(src, ContentTypeGenerator2.jsonSeqRecord), Mimes.ApplicationJsonSeq, true);
|
|
138
|
+
}
|
|
139
|
+
ContentTypeGenerator2.jsonSeq = jsonSeq;
|
|
140
|
+
function jsonArray(src) {
|
|
141
|
+
return toStream(framed(src, jsonArrayItem(), "[", "]"), Mimes.ApplicationJson, true);
|
|
142
|
+
}
|
|
143
|
+
ContentTypeGenerator2.jsonArray = jsonArray;
|
|
144
|
+
function csv(src, opt = {}) {
|
|
145
|
+
return toStream(framed(src, csvEncoder(opt), csvStart(opt)), CsvType, true);
|
|
146
|
+
}
|
|
147
|
+
ContentTypeGenerator2.csv = csv;
|
|
148
|
+
function text(src) {
|
|
149
|
+
return toStream(encode(src, ContentTypeGenerator2.textLine), Mimes.TextPlainUtf8, true);
|
|
150
|
+
}
|
|
151
|
+
ContentTypeGenerator2.text = text;
|
|
152
|
+
function channel(encodeFn, contentType, compress, opt = {}) {
|
|
153
|
+
const keep = opt.keep ?? "queue";
|
|
154
|
+
const max = Math.max(1, opt.max ?? 1e3);
|
|
155
|
+
const queue = [];
|
|
156
|
+
const closers = [];
|
|
157
|
+
let closed = false;
|
|
158
|
+
let finished = false;
|
|
159
|
+
let startSent = false;
|
|
160
|
+
let endSent = false;
|
|
161
|
+
let wake;
|
|
162
|
+
const finish = () => {
|
|
163
|
+
if (finished) return;
|
|
164
|
+
finished = closed = true;
|
|
165
|
+
queue.length = 0;
|
|
166
|
+
opt.signal?.removeEventListener("abort", onAbort);
|
|
167
|
+
wake?.();
|
|
168
|
+
for (const fn of closers.splice(0)) {
|
|
169
|
+
try {
|
|
170
|
+
fn();
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const onAbort = () => finish();
|
|
176
|
+
if (opt.signal?.aborted) closed = finished = true;
|
|
177
|
+
else opt.signal?.addEventListener("abort", onAbort, { once: true });
|
|
178
|
+
const next = async () => {
|
|
179
|
+
while (!finished) {
|
|
180
|
+
if (opt.start && !startSent) {
|
|
181
|
+
startSent = true;
|
|
182
|
+
return { value: opt.start(), done: false };
|
|
183
|
+
}
|
|
184
|
+
if (queue.length) return { value: encodeFn(queue.shift()), done: false };
|
|
185
|
+
if (closed) {
|
|
186
|
+
if (opt.end && !endSent) {
|
|
187
|
+
endSent = true;
|
|
188
|
+
return { value: opt.end(), done: false };
|
|
189
|
+
}
|
|
190
|
+
finish();
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
let timer;
|
|
194
|
+
const ping = await new Promise((resolve) => {
|
|
195
|
+
wake = () => resolve(false);
|
|
196
|
+
if (opt.heartbeat) timer = setTimeout(() => resolve(true), opt.heartbeat.ms);
|
|
197
|
+
});
|
|
198
|
+
wake = void 0;
|
|
199
|
+
clearTimeout(timer);
|
|
200
|
+
if (ping && !finished && !queue.length && !closed) return { value: opt.heartbeat.chunk(), done: false };
|
|
201
|
+
}
|
|
202
|
+
return { value: void 0, done: true };
|
|
203
|
+
};
|
|
204
|
+
const iterator = {
|
|
205
|
+
contentType,
|
|
206
|
+
compress,
|
|
207
|
+
get closed() {
|
|
208
|
+
return closed;
|
|
209
|
+
},
|
|
210
|
+
push(value) {
|
|
211
|
+
if (closed) return false;
|
|
212
|
+
if (keep === "latest") queue.length = 0;
|
|
213
|
+
else if (queue.length >= max) queue.shift();
|
|
214
|
+
queue.push(value);
|
|
215
|
+
wake?.();
|
|
216
|
+
return true;
|
|
217
|
+
},
|
|
218
|
+
close() {
|
|
219
|
+
closed = true;
|
|
220
|
+
wake?.();
|
|
221
|
+
},
|
|
222
|
+
onClose(fn) {
|
|
223
|
+
if (finished) fn();
|
|
224
|
+
else closers.push(fn);
|
|
225
|
+
},
|
|
226
|
+
next,
|
|
227
|
+
async return() {
|
|
228
|
+
finish();
|
|
229
|
+
return { value: void 0, done: true };
|
|
230
|
+
},
|
|
231
|
+
async throw(e) {
|
|
232
|
+
finish();
|
|
233
|
+
throw e;
|
|
234
|
+
},
|
|
235
|
+
[Symbol.asyncIterator]() {
|
|
236
|
+
return this;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
const dispose = Symbol.asyncDispose;
|
|
240
|
+
if (dispose) iterator[dispose] = async () => finish();
|
|
241
|
+
return iterator;
|
|
242
|
+
}
|
|
243
|
+
ContentTypeGenerator2.channel = channel;
|
|
244
|
+
((sse2) => {
|
|
245
|
+
sse2.channel = (opt = {}) => ContentTypeGenerator2.channel(ContentTypeGenerator2.sseChunk, Mimes.TextEventStream, true, {
|
|
246
|
+
...opt,
|
|
247
|
+
heartbeat: opt.heartbeatMs ? { ms: opt.heartbeatMs, chunk: ContentTypeGenerator2.ssePing } : void 0
|
|
248
|
+
});
|
|
249
|
+
})(sse = ContentTypeGenerator2.sse || (ContentTypeGenerator2.sse = {}));
|
|
250
|
+
((multipartReplace2) => {
|
|
251
|
+
multipartReplace2.channel = (opt = {}) => {
|
|
252
|
+
const b = (0, ContentTypeGenerator2.boundary)(opt.boundary);
|
|
253
|
+
return ContentTypeGenerator2.channel((p) => (0, ContentTypeGenerator2.multipartPart)(p, b, opt.type), `multipart/x-mixed-replace; boundary=${b}`, false, opt);
|
|
254
|
+
};
|
|
255
|
+
})(multipartReplace = ContentTypeGenerator2.multipartReplace || (ContentTypeGenerator2.multipartReplace = {}));
|
|
256
|
+
((multipartMixed2) => {
|
|
257
|
+
multipartMixed2.channel = (opt = {}) => {
|
|
258
|
+
const b = (0, ContentTypeGenerator2.boundary)(opt.boundary);
|
|
259
|
+
return ContentTypeGenerator2.channel((p) => (0, ContentTypeGenerator2.multipartPart)(p, b, opt.type), `multipart/mixed; boundary=${b}`, true, {
|
|
260
|
+
...opt,
|
|
261
|
+
end: () => (0, ContentTypeGenerator2.multipartEnd)(b)
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
})(multipartMixed = ContentTypeGenerator2.multipartMixed || (ContentTypeGenerator2.multipartMixed = {}));
|
|
265
|
+
((ndjson2) => {
|
|
266
|
+
ndjson2.channel = (opt = {}) => ContentTypeGenerator2.channel(ContentTypeGenerator2.ndjsonLine, Mimes.ApplicationXndjson, true, opt);
|
|
267
|
+
})(ndjson = ContentTypeGenerator2.ndjson || (ContentTypeGenerator2.ndjson = {}));
|
|
268
|
+
((jsonSeq2) => {
|
|
269
|
+
jsonSeq2.channel = (opt = {}) => ContentTypeGenerator2.channel(ContentTypeGenerator2.jsonSeqRecord, Mimes.ApplicationJsonSeq, true, opt);
|
|
270
|
+
})(jsonSeq = ContentTypeGenerator2.jsonSeq || (ContentTypeGenerator2.jsonSeq = {}));
|
|
271
|
+
((jsonArray2) => {
|
|
272
|
+
jsonArray2.channel = (opt = {}) => ContentTypeGenerator2.channel(jsonArrayItem(), Mimes.ApplicationJson, true, { ...opt, start: () => "[", end: () => "]" });
|
|
273
|
+
})(jsonArray = ContentTypeGenerator2.jsonArray || (ContentTypeGenerator2.jsonArray = {}));
|
|
274
|
+
((csv2) => {
|
|
275
|
+
csv2.channel = (opt = {}) => {
|
|
276
|
+
const start = csvStart(opt);
|
|
277
|
+
return ContentTypeGenerator2.channel(csvEncoder(opt), CsvType, true, { ...opt, start: start === void 0 ? void 0 : () => start });
|
|
278
|
+
};
|
|
279
|
+
})(csv = ContentTypeGenerator2.csv || (ContentTypeGenerator2.csv = {}));
|
|
280
|
+
((text2) => {
|
|
281
|
+
text2.channel = (opt = {}) => ContentTypeGenerator2.channel(ContentTypeGenerator2.textLine, Mimes.TextPlainUtf8, true, opt);
|
|
282
|
+
})(text = ContentTypeGenerator2.text || (ContentTypeGenerator2.text = {}));
|
|
283
|
+
})(ContentTypeGenerator || (ContentTypeGenerator = {}));
|
|
284
|
+
export {
|
|
285
|
+
ContentTypeGenerator
|
|
286
|
+
};
|
|
287
|
+
//# sourceMappingURL=ContentTypeGenerator.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/generators/ContentTypeGenerator.ts"],
|
|
4
|
+
"sourcesContent": ["import { randomBytes } from 'crypto';\nimport mime from 'mime-types';\nimport { ValidUtils } from '@dooboostore/core';\nimport { Mimes } from '../codes/Mimes';\n\n/**\n * Content-Type \uBCC4 \uC2A4\uD2B8\uB9AC\uBC0D \uC751\uB2F5 \uBB36\uC74C.\n * \uD578\uB4E4\uB7EC\uB294 \uB0B4\uC6A9(payload)\uB9CC \uB118\uAE30\uACE0, \uD615\uC2DD(SSE `data:`\u00B7multipart boundary\u00B7CRLF\u00B7Content-Type\u00B7Content-Length\u00B7NDJSON \uC904\uBC14\uAFC8)\uC740 \uC5EC\uAE30\uC11C \uBD99\uC778\uB2E4.\n *\n * \uB3CC\uB824\uC8FC\uB294 Stream \uC740 \uADF8\uB300\uB85C async generator \uB77C\uC11C \uD578\uB4E4\uB7EC\uC5D0\uC11C return \uD558\uBA74 \uD504\uB808\uC784\uC6CC\uD06C\uAC00 yield \uB9C8\uB2E4 \uBC14\uB85C body \uB85C \uC3DC\uB2E4.\n * Stream \uC774 contentType(boundary \uD3EC\uD568)\u00B7compress \uB97C \uB4E4\uACE0 \uC788\uC5B4 \uB370\uCF54\uB808\uC774\uD130\uC5D0 contentType \uC744 \uB530\uB85C \uC801\uC9C0 \uC54A\uC544\uB3C4 \uB41C\uB2E4.\n *\n * pull \u2014 \uB0B4 \uBC18\uBCF5\uBB38\uC774 \uB9CC\uB4E4\uC5B4 yield \uD560 \uB54C:\n * return ContentTypeGenerator.multipartReplace(this.frames(file, signal));\n * push \u2014 \uCF5C\uBC31\u00B7\uC774\uBCA4\uD2B8\uB85C \uC62C \uB54C\uB9C8\uB2E4 \uB123\uC744 \uB54C:\n * const out = ContentTypeGenerator.multipartReplace.channel({ signal, keep: 'latest' });\n * watcher.on('change', buf => out.push(buf));\n * out.onClose(() => watcher.close());\n * return out;\n */\nexport namespace ContentTypeGenerator {\n export type Source<T> = Iterable<T> | AsyncIterable<T>;\n\n /** \uD504\uB808\uC784\uC6CC\uD06C\uAC00 \uBC1B\uB294 \uC2A4\uD2B8\uB9BC: async generator + \uC751\uB2F5 \uD5E4\uB354 \uC815\uBCF4 */\n export type Stream<T = string | Buffer> = AsyncGenerator<T, void, undefined> & {\n readonly contentType: string;\n /** false \uBA74 Accept-Encoding: gzip \uC774\uC5B4\uB3C4 \uC555\uCD95 \uC548 \uD568 (JPEG \uCC98\uB7FC \uC774\uBBF8 \uC555\uCD95\uB41C \uB0B4\uC6A9) */\n readonly compress: boolean;\n };\n\n /** push \uC6A9: Stream + \uB123\uAE30\u00B7\uB2EB\uAE30 */\n export type Channel<In, Out = string | Buffer> = Stream<Out> & {\n /** \uB123\uAE30. \uB2EB\uD614\uC73C\uBA74 false */\n push(value: In): boolean;\n /** \uB354 \uB123\uC744 \uAC8C \uC5C6\uC74C \u2014 \uC313\uC778 \uAC74 \uB9C8\uC800 \uBCF4\uB0B4\uACE0 \uB05D\uB0C4 */\n close(): void;\n readonly closed: boolean;\n /** \uB05D\uB0A0 \uB54C(\uD074\uB77C\uC774\uC5B8\uD2B8 \uB04A\uAE40\u00B7close\u00B7signal abort) \uD55C \uBC88 \u2014 \uAC10\uC2DC\uC790\u00B7\uB9AC\uC2A4\uB108 \uC815\uB9AC\uC6A9 */\n onClose(fn: () => void): void;\n };\n\n export type ChannelOption = {\n /** abort \uB418\uBA74 \uCC44\uB110\uC744 \uB2EB\uC74C */\n signal?: AbortSignal;\n /** 'queue': \uD558\uB098\uB3C4 \uC548 \uBC84\uB9AC\uACE0 \uC21C\uC11C\uB300\uB85C (\uC774\uBCA4\uD2B8) \u00B7 'latest': \uBC00\uB9AC\uBA74 \uCD5C\uC2E0 \uD558\uB098\uB9CC (\uC601\uC0C1 \uD504\uB808\uC784) */\n keep?: 'queue' | 'latest';\n /** 'queue' \uCD5C\uB300 \uAC1C\uC218 \u2014 \uB118\uCE58\uBA74 \uAC00\uC7A5 \uC624\uB798\uB41C \uAC83\uBD80\uD130 \uBC84\uB9BC (\uAE30\uBCF8 1000) */\n max?: number;\n };\n\n export const isStream = (value: any): value is Stream =>\n ValidUtils.isAsyncGenerator(value) && typeof (value as any).contentType === 'string';\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \uD615\uC2DD \uADDC\uCE59 (\uC21C\uC218 \uD568\uC218) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n export type SseEvent =\n | string\n | { data?: unknown; event?: string; id?: string; retry?: number; comment?: string };\n\n const oneLine = (v: string) => v.replace(/[\\r\\n]/g, ' ');\n\n /**\n * SSE \uC774\uBCA4\uD2B8 \uD558\uB098 \u2192 `field: value\\n` \uC904\uB4E4 + \uBE48 \uC904(\\n).\n * data \uAC00 \uC5EC\uB7EC \uC904\uC774\uBA74 \uC904\uB9C8\uB2E4 `data: ` (\uADF8\uB0E5 \uB123\uC73C\uBA74 \uC904\uBC14\uAFC8\uC5D0\uC11C \uC774\uBCA4\uD2B8\uAC00 \uB04A\uAE40). \uBB38\uC790\uC5F4\uC774 \uC544\uB2C8\uBA74 JSON.\n */\n export const sseChunk = (e: SseEvent): string => {\n const ev = typeof e === 'string' ? { data: e } : e;\n let out = '';\n if (ev.comment !== undefined) out += ev.comment.split(/\\r\\n|\\r|\\n/).map(l => `: ${l}\\n`).join('');\n if (ev.event !== undefined) out += `event: ${oneLine(ev.event)}\\n`;\n if (ev.id !== undefined) out += `id: ${oneLine(ev.id)}\\n`;\n if (ev.retry !== undefined) out += `retry: ${Math.max(0, Math.floor(ev.retry))}\\n`;\n if (ev.data !== undefined) {\n const text = typeof ev.data === 'string' ? ev.data : JSON.stringify(ev.data);\n out += text.split(/\\r\\n|\\r|\\n/).map(l => `data: ${l}\\n`).join('');\n }\n return out + '\\n';\n };\n\n /** \uC5F0\uACB0 \uC720\uC9C0\uC6A9 SSE \uC8FC\uC11D (\uBE0C\uB77C\uC6B0\uC800 EventSource \uB294 \uBB34\uC2DC) */\n export const ssePing = (): string => ': ping\\n\\n';\n\n export type Part =\n | Buffer\n | Uint8Array\n | string\n | { body: Buffer | Uint8Array | string; type?: string; name?: string; headers?: Record<string, string> };\n\n /** \uBC14\uC774\uD2B8 \uC55E\uBD80\uBD84\uC73C\uB85C \uD754\uD55C \uC774\uBBF8\uC9C0 \uD310\uBCC4 (mime-types \uB294 \uC774\uB984\uC73C\uB85C\uB9CC \uCC3E\uC74C) \u2014 \uC774\uB984 \uC5C6\uC774 Buffer\uB9CC \uC628 \uD504\uB808\uC784\uC6A9 */\n const sniff = (b: Buffer): string | undefined => {\n if (b.length >= 3 && b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff) return Mimes.ImageJpeg;\n if (b.length >= 8 && b.readUInt32BE(0) === 0x89504e47 && b.readUInt32BE(4) === 0x0d0a1a0a) return Mimes.ImagePng;\n if (b.length >= 6 && b.toString('ascii', 0, 4) === 'GIF8') return Mimes.ImageGif;\n if (b.length >= 12 && b.toString('ascii', 0, 4) === 'RIFF' && b.toString('ascii', 8, 12) === 'WEBP') return 'image/webp';\n return undefined;\n };\n\n /**\n * \uD30C\uD2B8 MIME: type > mime-types(name) > \uBC14\uC774\uD2B8 \uD310\uBCC4 > \uBB38\uC790\uC5F4\uC774\uBA74 text/plain;utf-8 > octet-stream\n */\n export const partType = (part: Part, fallback?: string): string => {\n const p = isPartObject(part) ? part : { body: part };\n if (p.type) return p.type;\n if (p.name) {\n const byName = mime.lookup(p.name);\n if (byName) return mime.contentType(byName) || byName;\n }\n if (typeof p.body === 'string') return fallback ?? Mimes.TextPlainUtf8;\n return sniff(Buffer.from(p.body.buffer, p.body.byteOffset, p.body.byteLength)) ?? fallback ?? Mimes.ApplicationOctetStream;\n };\n\n const isPartObject = (part: Part): part is Exclude<Part, Buffer | Uint8Array | string> =>\n typeof part === 'object' && !(part instanceof Uint8Array);\n\n const toBuffer = (body: Buffer | Uint8Array | string): Buffer =>\n typeof body === 'string' ? Buffer.from(body, 'utf8') : Buffer.isBuffer(body) ? body : Buffer.from(body.buffer, body.byteOffset, body.byteLength);\n\n /**\n * multipart \uD30C\uD2B8 \uD558\uB098: `--boundary\\r\\nContent-Type: \u2026\\r\\nContent-Length: <\uBC14\uC774\uD2B8 \uC218>\\r\\n[\uD5E4\uB354\u2026]\\r\\n\\r\\n<body>\\r\\n`\n * Content-Length \uB294 \uBB38\uC790\uC5F4\uB3C4 \uAE00\uC790 \uC218\uAC00 \uC544\uB2C8\uB77C UTF-8 \uBC14\uC774\uD2B8 \uC218.\n */\n export const multipartPart = (part: Part, boundary: string, fallbackType?: string): Buffer => {\n const p = isPartObject(part) ? part : { body: part };\n const body = toBuffer(p.body);\n let head = `--${boundary}\\r\\nContent-Type: ${partType(part, fallbackType)}\\r\\nContent-Length: ${body.length}\\r\\n`;\n for (const [k, v] of Object.entries(p.headers ?? {})) head += `${oneLine(k)}: ${oneLine(v)}\\r\\n`;\n return Buffer.concat([Buffer.from(head + '\\r\\n', 'latin1'), body, Buffer.from('\\r\\n')]);\n };\n\n /** multipart \uB05D \uD45C\uC2DC (multipart/mixed \uCC98\uB7FC \uB05D\uC774 \uC788\uB294 \uACBD\uC6B0) */\n export const multipartEnd = (boundary: string): Buffer => Buffer.from(`--${boundary}--\\r\\n`);\n\n /** NDJSON \uD55C \uC904: JSON + \\n (\uADF8\uB0E5 \uAC1D\uCCB4\uB97C yield \uD558\uBA74 \uC904\uBC14\uAFC8 \uC5C6\uC774 \uBD99\uC5B4\uC11C \uBC1B\uB294 \uCABD\uC774 \uBABB \uB098\uB214) */\n export const ndjsonLine = (value: unknown): string => json(value) + '\\n';\n\n /** JSON.stringify(undefined) \uB294 undefined \uB77C \uADF8\uB300\uB85C \uBD99\uC774\uBA74 \uAE68\uC9C4 JSON \u2014 \uBC30\uC5F4 \uC548\uCC98\uB7FC null \uB85C */\n const json = (value: unknown): string => JSON.stringify(value) ?? 'null';\n\n /** RFC 7464 application/json-seq \uB808\uCF54\uB4DC: RS(0x1E) + JSON + \\n */\n export const jsonSeqRecord = (value: unknown): string => '\\x1e' + json(value) + '\\n';\n\n /** CSV \uCE78 \uD558\uB098 (RFC 4180): \uC27C\uD45C\u00B7\uB530\uC634\uD45C\u00B7\uC904\uBC14\uAFC8\u00B7\uC55E\uB4A4 \uACF5\uBC31\uC774 \uC788\uC73C\uBA74 \"\u2026\" \uB85C \uAC10\uC2F8\uACE0 \" \uB294 \"\" */\n export const csvCell = (value: unknown): string => {\n if (value === null || value === undefined) return '';\n const s = typeof value === 'string' ? value : value instanceof Date ? value.toISOString() : typeof value === 'object' ? json(value) : String(value);\n return /[\",\\r\\n]|^\\s|\\s$/.test(s) ? `\"${s.replace(/\"/g, '\"\"')}\"` : s;\n };\n\n /** CSV \uD55C \uC904: \uCE78\uB4E4 + CRLF */\n export const csvRow = (cells: readonly unknown[]): string => cells.map(csvCell).join(',') + '\\r\\n';\n\n /** text/plain \uD55C \uC904: \uBB38\uC790\uC5F4\uC740 \uADF8\uB300\uB85C, \uB098\uBA38\uC9C0\uB294 JSON + \\n */\n export const textLine = (value: unknown): string => (typeof value === 'string' ? value : json(value)) + '\\n';\n\n /** RFC 2046: 1~70\uC790, \uD5C8\uC6A9 \uBB38\uC790\uB9CC, \uACF5\uBC31\uC73C\uB85C \uB05D\uB098\uC9C0 \uC54A\uAC8C */\n export const boundary = (value?: string): string => {\n const b = value ?? `boundary-${randomBytes(12).toString('hex')}`;\n if (!/^[0-9A-Za-z'()+_,\\-./:=? ]{0,69}[0-9A-Za-z'()+_,\\-./:=?]$/.test(b)) {\n throw new Error(`invalid multipart boundary: ${JSON.stringify(b)}`);\n }\n return b;\n };\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 pull: \uC6D0\uBCF8 generator \uAC10\uC2F8\uAE30 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const toStream = <T>(gen: AsyncGenerator<T, void, undefined>, contentType: string, compress: boolean): Stream<T> =>\n Object.assign(gen, { contentType, compress });\n\n async function* encode<In, Out>(src: Source<In>, fn: (v: In) => Out): AsyncGenerator<Out, void, undefined> {\n // \uBC14\uAE65\uC774 return \uB418\uBA74(\uD074\uB77C\uC774\uC5B8\uD2B8 \uB04A\uAE40) for await \uAC00 \uC6D0\uBCF8\uC5D0\uB3C4 return \uC744 \uBD88\uB7EC \uC6D0\uBCF8\uC758 finally \uAC00 \uB3C8\uB2E4\n for await (const v of src as AsyncIterable<In>) yield fn(v);\n }\n\n /** \uC55E(start)\u00B7\uB0B4\uC6A9\u00B7\uB4A4(end). \uC911\uAC04\uC5D0 \uB04A\uAE30\uBA74(return) end \uB294 \uC548 \uB098\uAC10 */\n async function* framed<In, Out>(src: Source<In>, fn: (v: In) => Out, start?: Out, end?: Out): AsyncGenerator<Out, void, undefined> {\n if (start !== undefined) yield start;\n yield* encode(src, fn);\n if (end !== undefined) yield end;\n }\n\n /** JSON \uBC30\uC5F4 \uD56D\uBAA9: \uCCAB \uD56D\uBAA9 \uB9D0\uACE0\uB294 \uC55E\uC5D0 \uC27C\uD45C (\uC2A4\uD2B8\uB9BC\uB9C8\uB2E4 \uD558\uB098\uC529 \uB9CC\uB4E4\uC5B4 \uC500) */\n const jsonArrayItem = () => {\n let n = 0;\n return (v: unknown) => (n++ ? ',' : '') + json(v);\n };\n\n export type CsvRow = readonly unknown[] | Record<string, unknown>;\n export type CsvOption = {\n /** \uD5E4\uB354 \uC904 + \uAC1D\uCCB4 \uD589\uC744 \uC774 \uC21C\uC11C\uB85C \uCE78\uC5D0 \uB9DE\uCDA4 (\uC5C6\uC73C\uBA74 \uAC1D\uCCB4\uB294 Object.values \uC21C\uC11C, \uD5E4\uB354 \uC5C6\uC74C) */\n columns?: string[];\n /** UTF-8 BOM \u2014 Excel \uC774 \uD55C\uAE00 CSV \uB97C \uAE68\uC9C0\uC9C0 \uC54A\uAC8C \uC5F4\uB824\uBA74 \uD544\uC694 */\n bom?: boolean;\n };\n const csvEncoder = (opt: CsvOption) => (r: CsvRow) =>\n csvRow(Array.isArray(r) ? r : opt.columns ? opt.columns.map(c => (r as Record<string, unknown>)[c]) : Object.values(r));\n const csvStart = (opt: CsvOption): string | undefined =>\n opt.bom || opt.columns ? (opt.bom ? '\uFEFF' : '') + (opt.columns ? csvRow(opt.columns) : '') : undefined;\n const CsvType = `${Mimes.TextCsv}; charset=utf-8`;\n\n /**\n * text/event-stream. heartbeatMs \uB97C \uC8FC\uBA74 \uADF8\uB3D9\uC548 \uC774\uBCA4\uD2B8\uAC00 \uC5C6\uC744 \uB54C `: ping` \uC744 \uB07C\uC6CC \uC5F0\uACB0 \uC720\uC9C0\n * (\uD504\uB85D\uC2DC\u00B7\uBE0C\uB77C\uC6B0\uC800\uB294 \uC624\uB798 \uC870\uC6A9\uD55C \uC5F0\uACB0\uC744 \uB04A\uB294\uB2E4).\n */\n export function sse(src: Source<SseEvent>, opt: { heartbeatMs?: number } = {}): Stream<string> {\n const contentType = Mimes.TextEventStream;\n if (!opt.heartbeatMs) return toStream(encode(src, sseChunk), contentType, true);\n const ms = opt.heartbeatMs;\n async function* withPing(): AsyncGenerator<string, void, undefined> {\n const it = (Symbol.asyncIterator in (src as any)\n ? (src as AsyncIterable<SseEvent>)[Symbol.asyncIterator]()\n : (src as Iterable<SseEvent>)[Symbol.iterator]()) as AsyncIterator<SseEvent> | Iterator<SseEvent>;\n let pending: Promise<IteratorResult<SseEvent>> | undefined;\n try {\n while (true) {\n pending ??= Promise.resolve(it.next());\n let timer: ReturnType<typeof setTimeout> | undefined;\n const tick = new Promise<'ping'>(r => (timer = setTimeout(() => r('ping'), ms)));\n const r = await Promise.race([pending, tick]);\n clearTimeout(timer);\n if (r === 'ping') {\n yield ssePing(); // \uC6D0\uBCF8 next \uB294 \uADF8\uB300\uB85C \uAE30\uB2E4\uB9BC (pending \uC720\uC9C0)\n continue;\n }\n pending = undefined;\n if (r.done) return;\n yield sseChunk(r.value);\n }\n } finally {\n await it.return?.();\n }\n }\n return toStream(withPing(), contentType, true);\n }\n\n /** multipart/x-mixed-replace (MJPEG \uB4F1 \u2014 \uD30C\uD2B8\uAC00 \uC62C \uB54C\uB9C8\uB2E4 \uC55E \uAC83\uC744 \uAC08\uC544\uB07C\uC6C0). \uC774\uBBF8 \uC555\uCD95\uB41C \uB0B4\uC6A9\uC774\uB77C gzip \uC548 \uD568 */\n export function multipartReplace(src: Source<Part>, opt: { boundary?: string; type?: string } = {}): Stream<Buffer> {\n const b = boundary(opt.boundary);\n return toStream(encode(src, p => multipartPart(p, b, opt.type)), `multipart/x-mixed-replace; boundary=${b}`, false);\n }\n\n /** multipart/mixed (\uB05D\uC774 \uC788\uB294 \uC5EC\uB7EC \uD30C\uD2B8). \uC6D0\uBCF8\uC774 \uB05D\uB098\uBA74 `--boundary--` */\n export function multipartMixed(src: Source<Part>, opt: { boundary?: string; type?: string } = {}): Stream<Buffer> {\n const b = boundary(opt.boundary);\n return toStream(framed(src, p => multipartPart(p, b, opt.type), undefined, multipartEnd(b)), `multipart/mixed; boundary=${b}`, true);\n }\n\n /** application/x-ndjson (\uD55C \uC904\uC5D0 JSON \uD558\uB098) */\n export function ndjson(src: Source<unknown>): Stream<string> {\n return toStream(encode(src, ndjsonLine), Mimes.ApplicationXndjson, true);\n }\n\n /** application/json-seq (RFC 7464, \uB808\uCF54\uB4DC\uB9C8\uB2E4 RS \uB85C \uC2DC\uC791) */\n export function jsonSeq(src: Source<unknown>): Stream<string> {\n return toStream(encode(src, jsonSeqRecord), Mimes.ApplicationJsonSeq, true);\n }\n\n /**\n * application/json \uBC30\uC5F4\uC744 \uD56D\uBAA9\uB9C8\uB2E4 \uD758\uB824\uBCF4\uB0C4: `[` \uD56D\uBAA9 `,` \uD56D\uBAA9 \u2026 `]`.\n * \uBC1B\uB294 \uCABD\uC740 \uB2E4 \uBC1B\uC740 \uB4A4 \uD3C9\uBC94\uD55C JSON \uC73C\uB85C \uD30C\uC2F1 (\uB05D\uAE4C\uC9C0 \uBC1B\uC544\uC57C \uC720\uD6A8\uD55C JSON \u2014 \uC911\uAC04\uC5D0 \uB04A\uAE30\uBA74 \uAE68\uC9C4 JSON)\n */\n export function jsonArray(src: Source<unknown>): Stream<string> {\n return toStream(framed(src, jsonArrayItem(), '[', ']'), Mimes.ApplicationJson, true);\n }\n\n /** text/csv; charset=utf-8 \u2014 \uD589\uC740 \uBC30\uC5F4 \uB610\uB294 \uAC1D\uCCB4(columns \uC21C\uC11C). \uC904\uBC14\uAFC8 CRLF */\n export function csv(src: Source<CsvRow>, opt: CsvOption = {}): Stream<string> {\n return toStream(framed(src, csvEncoder(opt), csvStart(opt)), CsvType, true);\n }\n\n /** text/plain; charset=utf-8 \u2014 \uD55C \uC904\uC5D0 \uD558\uB098 (\uB85C\uADF8 tail \uB4F1) */\n export function text(src: Source<unknown>): Stream<string> {\n return toStream(encode(src, textLine), Mimes.TextPlainUtf8, true);\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 push: \uCC44\uB110 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * push \uD55C \uAC12\uC744 \uD050\uC5D0 \uB2F4\uC558\uB2E4\uAC00 yield \uD558\uB294 \uC2A4\uD2B8\uB9BC.\n * \uC9C1\uC811 iterator \uB97C \uB9CC\uB4DC\uB294 \uC774\uC720: \uAE30\uB2E4\uB9AC\uB294 \uC911(await)\uC5D0 \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uB04A\uACA8\uB3C4 return() \uC774 \uBC14\uB85C \uB05D\uB0B4\uACE0 onClose \uB97C \uBD80\uB974\uAC8C\n * (async generator \uB294 await \uC911\uC758 return \uC744 \uB2E4\uC74C yield \uAE4C\uC9C0 \uBBF8\uB904\uC11C, \uC870\uC6A9\uD55C \uCC44\uB110\uC774\uBA74 \uC815\uB9AC\uAC00 \uC548 \uB428).\n */\n export function channel<In, Out>(\n encodeFn: (v: In) => Out,\n contentType: string,\n compress: boolean,\n opt: ChannelOption & { start?: () => Out; end?: () => Out; heartbeat?: { ms: number; chunk: () => Out } } = {}\n ): Channel<In, Out> {\n const keep = opt.keep ?? 'queue';\n const max = Math.max(1, opt.max ?? 1000);\n const queue: In[] = [];\n const closers: (() => void)[] = [];\n let closed = false; // \uB354 \uC548 \uBC1B\uC74C (\uC313\uC778 \uAC74 \uBCF4\uB0C4)\n let finished = false; // \uC644\uC804\uD788 \uB05D\uB0A8\n let startSent = false;\n let endSent = false;\n let wake: (() => void) | undefined;\n\n const finish = () => {\n if (finished) return;\n finished = closed = true;\n queue.length = 0;\n opt.signal?.removeEventListener('abort', onAbort);\n wake?.();\n for (const fn of closers.splice(0)) {\n try { fn(); } catch { /* \uC815\uB9AC \uC2E4\uD328\uAC00 \uC751\uB2F5\uC744 \uAE68\uC9C0 \uC54A\uAC8C */ }\n }\n };\n const onAbort = () => finish();\n if (opt.signal?.aborted) closed = finished = true;\n else opt.signal?.addEventListener('abort', onAbort, { once: true });\n\n const next = async (): Promise<IteratorResult<Out, void>> => {\n while (!finished) {\n // \uC55E\uBD80\uBD84(JSON \uBC30\uC5F4 '[', CSV \uD5E4\uB354 \uB4F1)\uC740 \uCCAB next \uC5D0 \uBC14\uB85C \u2014 \uC544\uBB34\uAC83\uB3C4 push \uC548 \uD558\uACE0 close \uD574\uB3C4 \uB098\uAC10\n if (opt.start && !startSent) {\n startSent = true;\n return { value: opt.start(), done: false };\n }\n if (queue.length) return { value: encodeFn(queue.shift() as In), done: false };\n if (closed) {\n if (opt.end && !endSent) {\n endSent = true;\n return { value: opt.end(), done: false };\n }\n finish();\n break;\n }\n let timer: ReturnType<typeof setTimeout> | undefined;\n const ping = await new Promise<boolean>(resolve => {\n wake = () => resolve(false);\n if (opt.heartbeat) timer = setTimeout(() => resolve(true), opt.heartbeat.ms);\n });\n wake = undefined;\n clearTimeout(timer);\n if (ping && !finished && !queue.length && !closed) return { value: opt.heartbeat!.chunk(), done: false };\n }\n return { value: undefined, done: true };\n };\n\n const iterator: Channel<In, Out> = {\n contentType,\n compress,\n get closed() { return closed; },\n push(value: In) {\n if (closed) return false;\n if (keep === 'latest') queue.length = 0;\n else if (queue.length >= max) queue.shift();\n queue.push(value);\n wake?.();\n return true;\n },\n close() {\n closed = true;\n wake?.();\n },\n onClose(fn: () => void) {\n if (finished) fn();\n else closers.push(fn);\n },\n next,\n async return() {\n finish();\n return { value: undefined, done: true };\n },\n async throw(e?: unknown) {\n finish();\n throw e;\n },\n [Symbol.asyncIterator]() { return this; }\n } as unknown as Channel<In, Out>;\n // `await using` \uC815\uB9AC \uC9C0\uC6D0 (Symbol.asyncDispose \uAC00 \uC788\uB294 \uB7F0\uD0C0\uC784\uB9CC \u2014 AsyncGenerator \uD0C0\uC785\uC774 \uC694\uAD6C)\n const dispose = (Symbol as any).asyncDispose as symbol | undefined;\n if (dispose) (iterator as any)[dispose] = async () => finish();\n return iterator;\n }\n\n export namespace sse {\n /** push \uB85C SSE: out.push('hello') \u00B7 out.push({ event: 'tick', data: { n: 1 } }) */\n export const channel = (opt: ChannelOption & { heartbeatMs?: number } = {}): Channel<SseEvent, string> =>\n ContentTypeGenerator.channel(sseChunk, Mimes.TextEventStream, true, {\n ...opt,\n heartbeat: opt.heartbeatMs ? { ms: opt.heartbeatMs, chunk: ssePing } : undefined\n });\n }\n\n export namespace multipartReplace {\n /** push \uB85C MJPEG \uB4F1: out.push(jpegBuffer) \u2014 \uD504\uB808\uC784\uC740 \uBCF4\uD1B5 keep: 'latest' */\n export const channel = (opt: ChannelOption & { boundary?: string; type?: string } = {}): Channel<Part, Buffer> => {\n const b = boundary(opt.boundary);\n return ContentTypeGenerator.channel((p: Part) => multipartPart(p, b, opt.type), `multipart/x-mixed-replace; boundary=${b}`, false, opt);\n };\n }\n\n export namespace multipartMixed {\n export const channel = (opt: ChannelOption & { boundary?: string; type?: string } = {}): Channel<Part, Buffer> => {\n const b = boundary(opt.boundary);\n return ContentTypeGenerator.channel((p: Part) => multipartPart(p, b, opt.type), `multipart/mixed; boundary=${b}`, true, {\n ...opt,\n end: () => multipartEnd(b)\n });\n };\n }\n\n export namespace ndjson {\n export const channel = (opt: ChannelOption = {}): Channel<unknown, string> =>\n ContentTypeGenerator.channel(ndjsonLine, Mimes.ApplicationXndjson, true, opt);\n }\n\n export namespace jsonSeq {\n export const channel = (opt: ChannelOption = {}): Channel<unknown, string> =>\n ContentTypeGenerator.channel(jsonSeqRecord, Mimes.ApplicationJsonSeq, true, opt);\n }\n\n export namespace jsonArray {\n /** close \uD574\uC57C `]` \uAC00 \uB098\uAC00\uC11C \uC720\uD6A8\uD55C JSON \uC774 \uB428 */\n export const channel = (opt: ChannelOption = {}): Channel<unknown, string> =>\n ContentTypeGenerator.channel(jsonArrayItem(), Mimes.ApplicationJson, true, { ...opt, start: () => '[', end: () => ']' });\n }\n\n export namespace csv {\n export const channel = (opt: ChannelOption & CsvOption = {}): Channel<CsvRow, string> => {\n const start = csvStart(opt);\n return ContentTypeGenerator.channel(csvEncoder(opt), CsvType, true, { ...opt, start: start === undefined ? undefined : () => start });\n };\n }\n\n export namespace text {\n export const channel = (opt: ChannelOption = {}): Channel<unknown, string> =>\n ContentTypeGenerator.channel(textLine, Mimes.TextPlainUtf8, true, opt);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["ContentTypeGenerator", "text", "boundary", "r", "sse", "multipartReplace", "multipartMixed", "ndjson", "jsonSeq", "jsonArray", "csv"]
|
|
7
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export * from "./decorators/index.js";
|
|
|
3
3
|
export * from "./endpoints/index.js";
|
|
4
4
|
export * from "./errors/index.js";
|
|
5
5
|
export * from "./filters/index.js";
|
|
6
|
+
export * from "./generators/ContentTypeGenerator.js";
|
|
6
7
|
export * from "./proxy/index.js";
|
|
7
8
|
export * from "./inject/index.js";
|
|
8
9
|
export * from "./lifecycle/index.js";
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './codes';\nexport * from './decorators';\nexport * from './endpoints';\nexport * from './errors';\nexport * from './filters';\nexport * from './proxy';\nexport * from './inject';\nexport * from './lifecycle';\nexport * from './models';\nexport * from './option';\nexport * from './resolvers';\nexport * from './session';\nexport * from './SimpleBootHttpServer';\nexport default {}"],
|
|
5
|
-
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,IAAO,cAAQ,CAAC;",
|
|
4
|
+
"sourcesContent": ["export * from './codes';\nexport * from './decorators';\nexport * from './endpoints';\nexport * from './errors';\nexport * from './filters';\nexport * from './generators/ContentTypeGenerator';\nexport * from './proxy';\nexport * from './inject';\nexport * from './lifecycle';\nexport * from './models';\nexport * from './option';\nexport * from './resolvers';\nexport * from './session';\nexport * from './SimpleBootHttpServer';\nexport default {}"],
|
|
5
|
+
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,IAAO,cAAQ,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -454,11 +454,12 @@ class RequestResponse {
|
|
|
454
454
|
* - 문자열/Buffer 는 그대로, 그 외는 JSON.stringify
|
|
455
455
|
* - Accept-Encoding 에 gzip 이 있으면 gzip 스트림으로 압축하고, 청크마다 Z_SYNC_FLUSH 로 바로 내보낸다
|
|
456
456
|
* (flush 없이 쓰면 zlib 내부 버퍼에 모였다가 늦게 나가서 SSE 실시간성이 깨짐)
|
|
457
|
+
* option.compress === false 면 압축 안 함 (MJPEG 처럼 이미 압축된 내용 — CPU만 쓰고, gzip 못 푸는 클라이언트도 있음)
|
|
457
458
|
* - 클라이언트가 끊으면 source.return() 으로 제너레이터를 종료시켜 finally 가 돌게 한다
|
|
458
459
|
*/
|
|
459
|
-
async resStream(source) {
|
|
460
|
+
async resStream(source, option = {}) {
|
|
460
461
|
const res = this.res;
|
|
461
|
-
const gz = this.reqHeaderFirst(HttpHeaders.AcceptEncoding)?.includes("gzip") ? createGzip() : void 0;
|
|
462
|
+
const gz = option.compress !== false && this.reqHeaderFirst(HttpHeaders.AcceptEncoding)?.includes("gzip") ? createGzip() : void 0;
|
|
462
463
|
if (gz) {
|
|
463
464
|
res.setHeader(HttpHeaders.ContentEncoding, "gzip");
|
|
464
465
|
res.removeHeader(HttpHeaders.ContentLength);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/models/RequestResponse.ts"],
|
|
4
|
-
"sourcesContent": ["import { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from 'http';\nimport { HttpHeaders, HttpHeadersType } from '../codes/HttpHeaders';\nimport { Mimes } from '../codes/Mimes';\nimport { Intent } from '@dooboostore/simple-boot';\nimport { URL, URLSearchParams } from 'url';\nimport { Buffer } from 'buffer';\nimport { MultipartData } from './datas/MultipartData';\nimport { ReqFormUrlBody } from './datas/body/ReqFormUrlBody';\nimport { ReqJsonBody } from './datas/body/ReqJsonBody';\nimport { ReqHeader } from './datas/ReqHeader';\nimport { ReqMultipartFormBody } from './datas/body/ReqMultipartFormBody';\nimport { HttpStatus } from '../codes/HttpStatus';\nimport { gzip } from 'node-gzip';\nimport { createGzip, constants as zlibConstants } from 'zlib';\nimport { SessionManager } from '../session/SessionManager';\nimport { HttpServerOption } from '../option/HttpServerOption';\nimport { Blob } from 'node:buffer';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport { RandomUtils } from '@dooboostore/core';\nimport { FileUtils } from '@dooboostore/core-node';\nimport { ConvertUtils as CoreConvertUtils } from '@dooboostore/core';\nimport { ConvertUtils } from '@dooboostore/core-node';\nimport {HttpMethod} from \"../codes\";\n\ntype Config = { sessionManager?: SessionManager; option: HttpServerOption };\n\nexport class RequestResponse {\n protected resWriteChunk: string | Buffer | undefined;\n protected reqBodyChunk?: Buffer;\n protected req: IncomingMessage;\n protected res: ServerResponse;\n protected config: Config;\n\n // [\uC544\uD0A4\uD14D\uD2B8\uB2D8\uC758 \uC815\uC11D] RequestResponse \uAC1D\uCCB4 \uACE0\uC720\uC758 \uC18D\uC131 \uC800\uC7A5\uC18C (\uD2B8\uB79C\uC7AD\uC158 \uC0DD\uBA85\uC8FC\uAE30)\n protected attributes = new Map<string, any>();\n\n constructor(req: IncomingMessage | RequestResponse, res: ServerResponse, config: Config) {\n if (req instanceof RequestResponse) {\n this.req = req.req;\n this.res = req.res;\n this.config = config;\n this.attributes = req.attributes;\n } else {\n this.req = req;\n this.res = res!;\n this.config = config;\n }\n }\n\n // --- RequestResponse Attributes (Transaction Life-cycle) ---\n\n setAttribute(key: string, value: any): void {\n this.attributes.set(key, value);\n }\n\n getAttribute<T = any>(key: string): T | undefined {\n return this.attributes.get(key) as T;\n }\n\n get reqSocket() {\n return this.req.socket;\n }\n\n get reqCookieMap() {\n let cookies = this.reqHeader(HttpHeaders.Cookie) ?? '';\n if (Array.isArray(cookies)) {\n cookies = cookies.join(';');\n }\n\n const map = new Map<string, string>();\n cookies\n .split(';')\n .map(it => it.trim().split('='))\n .forEach(it => {\n if (it[0]) map.set(it[0], it[1]);\n });\n return map;\n }\n\n reqCookieGet(key: string) {\n return this.reqCookieMap.get(key);\n }\n\n get reqRemoteAddress(): string | undefined {\n const ipHeader = this.req.headers['x-forwarded-for'];\n let ip = this.req.socket.remoteAddress;\n if (Array.isArray(ipHeader)) {\n ip = ipHeader.join(',').split(',').shift();\n } else if (typeof ipHeader === 'string') {\n ip = ipHeader.split(',').shift();\n }\n return ip;\n }\n\n get reqUrlObject(): URL {\n return new URL(this.reqUrl, `${this.reqSocket ? 'https://' : 'http://'}${this.reqHost ?? 'localhost'}`);\n }\n\n get reqUrlPathName(): string {\n return this.reqUrlObj().pathname ?? '';\n }\n\n get reqUrl(): string {\n return this.req.url ?? '';\n }\n\n reqUrlObj(config?: { scheme?: string; host?: string }): URL {\n return new URL(`${config?.scheme ?? 'http'}://${config?.host ? config?.host : (this.reqHeaderFirst(HttpHeaders.Host) ?? 'localhost')}${this.req.url ?? ''}`);\n }\n\n get reqUrlSearchParamTuples(): [string, string][] {\n return Array.from(this.reqUrlObj().searchParams as any);\n }\n\n get reqUrlSearchParams(): URLSearchParams {\n return this.reqUrlObj().searchParams;\n }\n\n get reqUrlSearchParamsObj(): { [p: string]: string | string[] } {\n const entries = this.reqUrlObj().searchParams;\n return CoreConvertUtils.toObject(entries);\n }\n\n get reqPathSearchParamUrl(): string {\n const reqUrlObj = this.reqUrlObj();\n return reqUrlObj.pathname + (reqUrlObj.searchParams.toString() ? '?' + reqUrlObj.searchParams.toString() : '');\n }\n\n get reqReadable() {\n return this.req.readable;\n }\n\n get reqIntent() {\n return new Intent(this.reqPathSearchParamUrl);\n }\n\n reqHasContentTypeHeader(mime: Mimes | string): boolean {\n const contentType = this.reqHeader(HttpHeaders.ContentType);\n if (!contentType) return false;\n \n const targetMime = mime.toString().toLowerCase();\n const contentTypes = Array.isArray(contentType) ? contentType : [contentType];\n \n // \uBAA8\uB4E0 Content-Type \uD5E4\uB354\uB97C \uD655\uC778\n return contentTypes.some(ct => {\n // Content-Type\uC740 \uBCF4\uD1B5 \uB2E8\uC77C \uAC12\uC774\uC9C0\uB9CC, \uD30C\uB77C\uBBF8\uD130\uAC00 \uBD99\uC744 \uC218 \uC788\uC74C (charset=utf-8 \uB4F1)\n // \uC138\uBBF8\uCF5C\uB860\uC73C\uB85C split\uD574\uC11C \uC55E \uBD80\uBD84(MIME \uD0C0\uC785)\uB9CC \uBE44\uAD50\n const [mimeType] = ct.split(';').map(m => m.trim());\n return mimeType.toLowerCase() === targetMime || mimeType.toLowerCase().includes(targetMime);\n });\n }\n\n reqHasAcceptHeader(mime: Mimes | string): boolean {\n const accept = this.reqHeader(HttpHeaders.Accept);\n if (!accept) return false;\n\n const targetMime = mime.toString().toLowerCase();\n const acceptHeaders = Array.isArray(accept) ? accept : [accept];\n\n return acceptHeaders.some(acceptHeader => {\n const acceptMimes = acceptHeader.split(',').map(m => m.split(';')[0].trim().toLowerCase());\n return acceptMimes.some(acceptMime => acceptMime.includes(targetMime));\n });\n }\n\n reqBodyData(): Promise<Buffer> {\n return new Promise<Buffer>((resolve, reject) => {\n if (this.reqReadable) {\n const data: Uint8Array[] = [];\n this.req.on('data', chunk => data.push(chunk));\n this.req.on('error', err => reject(err));\n this.req.on('end', () => {\n this.reqBodyChunk = Buffer.concat(data);\n resolve(this.reqBodyChunk);\n });\n } else {\n resolve(this.reqBodyChunk ?? Buffer.alloc(0));\n }\n });\n }\n\n resBodyData(): string | Buffer | undefined {\n return this.resWriteChunk;\n }\n\n async reqBodyMultipartFormDataObject<T>(): Promise<T> {\n const m = await this.reqBodyMultipartFormData();\n const formData = {} as any;\n\n for (const it of m) {\n if (it.isFile) {\n formData[it.name] = await FileUtils.writeFile(it.value, { originalName: it.filename, etcData: it });\n } else {\n const target = formData[it.name];\n if (Array.isArray(target)) {\n target.push(it.value);\n } else if (typeof target === 'string') {\n formData[it.name] = [target, it.value];\n } else {\n formData[it.name] = it.value;\n }\n }\n }\n return formData;\n }\n\n reqBodyMultipartFormData(): Promise<MultipartData[]> {\n return new Promise((resolve, reject) => {\n const contentTypeHeader = this.req.headers['content-type'];\n if (!contentTypeHeader || !contentTypeHeader.startsWith('multipart/form-data')) {\n return reject(new Error('Invalid Content-Type. Expected multipart/form-data.'));\n }\n\n const boundaryMatch = contentTypeHeader.match(/boundary=(?:\"([^\"]+)\"|([^;]+))/i);\n if (!boundaryMatch) {\n return reject(new Error('Boundary not found in Content-Type header.'));\n }\n const boundary = boundaryMatch[1] || boundaryMatch[2];\n if (!boundary) {\n return reject(new Error('Failed to extract boundary.'));\n }\n\n const boundaryBuffer = Buffer.from(`--${boundary}`);\n const crlfBuffer = Buffer.from('\\r\\n');\n const doubleCrlfBuffer = Buffer.from('\\r\\n\\r\\n');\n\n const chunks: Buffer[] = [];\n let totalLength = 0;\n\n this.req.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n totalLength += chunk.length;\n });\n\n this.req.on('error', err => {\n reject(err);\n });\n\n this.req.on('end', () => {\n if (totalLength === 0) {\n return resolve([]);\n }\n\n const fullBuffer = Buffer.concat(chunks, totalLength);\n const parsedParts: MultipartData[] = [];\n let currentPosition = 0;\n\n let boundaryStartIndex = fullBuffer.indexOf(boundaryBuffer, currentPosition);\n if (boundaryStartIndex === -1) {\n return reject(new Error('Initial boundary not found.'));\n }\n currentPosition = boundaryStartIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n\n while (currentPosition < fullBuffer.length) {\n const nextBoundaryIndex = fullBuffer.indexOf(boundaryBuffer, currentPosition);\n if (nextBoundaryIndex === -1) {\n break;\n }\n\n let partEndIndex = nextBoundaryIndex;\n if (partEndIndex > crlfBuffer.length && fullBuffer.slice(partEndIndex - crlfBuffer.length, partEndIndex).equals(crlfBuffer)) {\n partEndIndex -= crlfBuffer.length;\n }\n const partBuffer = fullBuffer.slice(currentPosition, partEndIndex);\n\n const headerBodySeparatorIndex = partBuffer.indexOf(doubleCrlfBuffer);\n if (headerBodySeparatorIndex === -1) {\n currentPosition = nextBoundaryIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') break;\n continue;\n }\n\n const headerBuffer = partBuffer.slice(0, headerBodySeparatorIndex);\n const bodyBuffer = partBuffer.slice(headerBodySeparatorIndex + doubleCrlfBuffer.length);\n const headersStr = headerBuffer.toString('utf-8');\n\n const headers: { [key: string]: string } = {};\n headersStr.split('\\r\\n').forEach(line => {\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0) {\n const key = line.substring(0, colonIndex).trim().toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n headers[key] = value;\n }\n });\n\n const contentDisposition = headers['content-disposition'];\n if (!contentDisposition) {\n currentPosition = nextBoundaryIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') break;\n continue;\n }\n\n const nameMatch = contentDisposition.match(/name=\"([^\"]+)\"/i);\n const filenameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);\n\n const name = nameMatch ? nameMatch[1] : null;\n const filename = filenameMatch ? filenameMatch[1] : null;\n const contentType = headers['content-type'] || null;\n\n if (name) {\n if (filename) {\n parsedParts.push({\n isFile: true,\n name: name,\n filename: filename,\n contentType: contentType ?? 'application/octet-stream',\n value: bodyBuffer\n });\n } else {\n parsedParts.push({\n isFile: false,\n name: name,\n value: bodyBuffer.toString('utf-8')\n });\n }\n }\n\n currentPosition = nextBoundaryIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n\n if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') {\n break;\n }\n }\n resolve(parsedParts);\n });\n });\n }\n\n async reqBodyStringData(): Promise<string> {\n const data = (await this.reqBodyData()).toString();\n return data;\n }\n\n async reqBodyJsonData<T>(): Promise<T> {\n return JSON.parse(await this.reqBodyStringData());\n }\n\n async reqBodyFormUrlData<T>(): Promise<T> {\n const data = await this.reqBodyStringData();\n const formData = {} as any;\n Array.from(new URLSearchParams(data).entries()).forEach(([k, v]) => {\n const target = formData[k];\n if (Array.isArray(target)) {\n target.push(v);\n } else if (typeof target === 'string') {\n formData[k] = [target, v];\n } else {\n formData[k] = v;\n }\n });\n return formData;\n }\n\n async reqBodyReqFormUrlBody() {\n const data = await this.reqBodyFormUrlData();\n return Object.assign(new ReqFormUrlBody(), data);\n }\n\n async reqBodyReqJsonBody(): Promise<ReqJsonBody> {\n const data = await this.reqBodyStringData();\n return Object.assign(new ReqJsonBody(), data ? JSON.parse(data) : {});\n }\n\n resBodyJsonData<T>(): T | null {\n const data = ConvertUtils.toString(this.resBodyData());\n return data ? JSON.parse(data) : null;\n }\n\n resBodyStringData() {\n return ConvertUtils.toString(this.resBodyData());\n }\n\n reqMethod() {\n return this.req.method?.toUpperCase();\n }\n\n reqIsMethod(method: HttpMethod | string) {\n return this.reqMethod().toUpperCase() === (method as string).toUpperCase();\n }\n\n reqHeader(key: keyof typeof HttpHeaders | string) {\n return this.req.headers[(key as string).toLowerCase()];\n }\n\n get reqHost() {\n return this.reqHeaderFirst(HttpHeaders.Host);\n }\n\n get reqHeaderObj(): ReqHeader {\n const h = new ReqHeader();\n Object.entries(this.req.headers).forEach(([k, v]) => {\n h[k] = v;\n });\n return h;\n }\n\n reqHeaderFirst(key: HttpHeadersType | string, defaultValue?: string) {\n const header = this.req.headers[(key as string).toLowerCase()];\n if (header && Array.isArray(header)) {\n return header[0] ?? defaultValue;\n } else {\n return (header as string) ?? defaultValue;\n }\n }\n\n public reqAuthorizationHeader() {\n return this.reqHeaderFirst(HttpHeaders.Authorization);\n }\n\n reqRefreshTokenHeader() {\n return this.reqHeaderFirst(HttpHeaders.Authorization);\n }\n\n resStatusCode(code?: undefined): number;\n resStatusCode(code: number | HttpStatus): RequestResponseChain<number>;\n resStatusCode(code: number | undefined | HttpStatus): number | RequestResponseChain<number> {\n if (code) {\n this.res.statusCode = code;\n return new RequestResponseChain<number>(this.req, this.res, this.config, this.res.statusCode);\n } else {\n return this.res.statusCode;\n }\n }\n\n resHeader(key: HttpHeadersType | string) {\n return this.res.getHeader((key as string).toLowerCase());\n }\n\n resHeaderFirst(key: HttpHeadersType | string, defaultValue?: string) {\n const header = this.res.getHeader((key as string).toLowerCase());\n if (header && Array.isArray(header)) {\n return header[0] ?? defaultValue;\n } else {\n return (header as string) ?? defaultValue;\n }\n }\n\n async reqSession(): Promise<{ [key: string]: any }> {\n if (this.config.sessionManager) {\n const session = await this.config.sessionManager.session(this);\n session.dataSet.data ??= {};\n return session.dataSet.data;\n } else {\n return Promise.reject(new Error('Not SessionManager'));\n }\n }\n\n async reqSessionSet(key: string, value: any): Promise<void> {\n const sessionData = await this.reqSession();\n sessionData[key] = value;\n }\n\n async reqSessionGet<T = any>(key: string): Promise<T | undefined> {\n const sessionData = await this.reqSession();\n return sessionData[key] as T;\n }\n\n resSetStatusCode(statusCode: number) {\n this.res.statusCode = statusCode;\n return this.createRequestResponseChain(this.res.statusCode);\n }\n\n resWrite(chunk: string | Buffer | any, encoding: BufferEncoding = 'utf8') {\n this.resWriteChunk = chunk;\n return this.createRequestResponseChain(this.resWriteChunk);\n }\n\n resWriteJson(chunk: any, encoding: BufferEncoding = 'utf8') {\n return this.resWrite(JSON.stringify(chunk), encoding);\n }\n\n resSetHeader(key: HttpHeadersType | string, value: string | string[]) {\n this.res.setHeader((key as string).toLowerCase(), value);\n return this.createRequestResponseChain();\n }\n\n resAddHeader(key: HttpHeadersType | string, value: string | string[]) {\n const existingValue = this.res.getHeader((key as string).toLowerCase());\n const newValue = Array.isArray(existingValue) ? existingValue.concat(value) : existingValue ? [existingValue.toString(), ...[].concat(value as any)] : value;\n this.res.setHeader((key as string).toLowerCase(), newValue as any);\n return this.createRequestResponseChain();\n }\n\n resSetHeaders(headers: { [key: string]: string | string[] }) {\n Object.entries(headers).forEach(([key, value]) => this.resSetHeader(key, value));\n return this.createRequestResponseChain();\n }\n\n resAddHeaders(headers: { [key: string]: string | string[] }) {\n Object.entries(headers).forEach(([key, value]) => this.resAddHeader(key, value));\n return this.createRequestResponseChain();\n }\n\n private async resEndChunk() {\n const encoding = this.reqHeaderFirst(HttpHeaders.AcceptEncoding);\n let data = this.resWriteChunk;\n if (encoding?.includes('gzip') && data) {\n data = await gzip(data);\n this.resSetHeader(HttpHeaders.ContentEncoding, 'gzip');\n }\n this.res.end(data);\n }\n\n async resEnd(chunk?: string | Buffer | Blob | ArrayBuffer | Response) {\n if (chunk instanceof Response) {\n chunk.headers.forEach((value, key) => {\n this.res.setHeader(`ORIGIN-${key}`, value);\n });\n if (!this.resHeader(HttpHeaders.ContentType)) {\n const contentType = chunk.headers.get(HttpHeaders.ContentType);\n if (contentType) this.res.setHeader(HttpHeaders.ContentType, contentType);\n }\n this.res.statusCode = chunk.status;\n this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());\n } else if (chunk instanceof Blob) {\n this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());\n if (!this.resHeader(HttpHeaders.ContentType)) {\n this.res.setHeader(HttpHeaders.ContentType, chunk.type);\n }\n } else if (chunk instanceof ArrayBuffer) {\n this.resWriteChunk = Buffer.from(chunk);\n } else {\n this.resWriteChunk = chunk ?? this.resWriteChunk;\n }\n\n if (this.req.readable) {\n await this.reqBodyData();\n await this.resEndChunk();\n } else {\n await this.resEndChunk();\n }\n }\n\n resRedirect(statusCode: number, location: string) {\n this.res.statusCode = statusCode;\n this.res.setHeader(HttpHeaders.Location, location);\n this.res.end();\n }\n resWriteHead(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | { [key: string]: string | string[] }) {\n return this.createRequestResponseChain(this.res.writeHead(statusCode, headers as any));\n }\n resWriteHeadEnd(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | { [key: string]: string | string[] }) {\n this.createRequestResponseChain(this.res.writeHead(statusCode, headers as any));\n this.res.end();\n }\n\n /**\n * \uD5E4\uB354\uB97C \uC989\uC2DC \uBCF4\uB0B4\uACE0, source \uAC00 \uB0B4\uB193\uB294 \uAC12\uC744 \uD558\uB098\uC529 \uBC14\uB85C body \uC5D0 \uC4F4 \uB4A4 end.\n * (SSE / \uC2A4\uD2B8\uB9AC\uBC0D \uC751\uB2F5\uC6A9. resWrite \uB294 \uBC84\uD37C\uB9C1 \uD6C4 resEnd \uC5D0\uC11C \uD55C \uBC88\uC5D0 \uBCF4\uB0B4\uBBC0\uB85C \uC2A4\uD2B8\uB9AC\uBC0D \uBD88\uAC00)\n * - \uBB38\uC790\uC5F4/Buffer \uB294 \uADF8\uB300\uB85C, \uADF8 \uC678\uB294 JSON.stringify\n * - Accept-Encoding \uC5D0 gzip \uC774 \uC788\uC73C\uBA74 gzip \uC2A4\uD2B8\uB9BC\uC73C\uB85C \uC555\uCD95\uD558\uACE0, \uCCAD\uD06C\uB9C8\uB2E4 Z_SYNC_FLUSH \uB85C \uBC14\uB85C \uB0B4\uBCF4\uB0B8\uB2E4\n * (flush \uC5C6\uC774 \uC4F0\uBA74 zlib \uB0B4\uBD80 \uBC84\uD37C\uC5D0 \uBAA8\uC600\uB2E4\uAC00 \uB2A6\uAC8C \uB098\uAC00\uC11C SSE \uC2E4\uC2DC\uAC04\uC131\uC774 \uAE68\uC9D0)\n * - \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uB04A\uC73C\uBA74 source.return() \uC73C\uB85C \uC81C\uB108\uB808\uC774\uD130\uB97C \uC885\uB8CC\uC2DC\uCF1C finally \uAC00 \uB3CC\uAC8C \uD55C\uB2E4\n */\n async resStream(source: Iterable<any> | AsyncIterable<any>) {\n const res = this.res;\n const gz = this.reqHeaderFirst(HttpHeaders.AcceptEncoding)?.includes('gzip') ? createGzip() : undefined;\n if (gz) {\n res.setHeader(HttpHeaders.ContentEncoding, 'gzip');\n res.removeHeader(HttpHeaders.ContentLength);\n gz.pipe(res);\n }\n const out = gz ?? res;\n res.flushHeaders();\n let closed = false;\n const onClose = () => {\n closed = true;\n (source as any).return?.();\n };\n res.once('close', onClose);\n try {\n for await (const chunk of source) {\n if (closed) break;\n const data = typeof chunk === 'string' || Buffer.isBuffer(chunk) ? chunk : JSON.stringify(chunk);\n const ok = out.write(data);\n gz?.flush(zlibConstants.Z_SYNC_FLUSH);\n // backpressure: \uBC84\uD37C\uAC00 \uCC28\uBA74 drain(\uB610\uB294 \uC5F0\uACB0 \uC885\uB8CC)\uAE4C\uC9C0 \uB300\uAE30\n if (!ok) await new Promise(resolve => { out.once('drain', resolve); res.once('close', resolve); });\n }\n } catch (e) {\n // \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uB04A\uAE34 \uB4A4\uC758 \uC5D0\uB7EC(AbortSignal \uB85C \uB300\uAE30\uB97C \uD47C AbortError \uB4F1)\uB294 \uBC1B\uC744 \uC0C1\uB300\uAC00 \uC5C6\uC73C\uB2C8 \uC0BC\uD0A8\uB2E4\n if (!closed) throw e;\n } finally {\n res.off('close', onClose);\n if (closed) {\n gz?.destroy();\n } else if (!res.writableEnded) {\n // gzip \uC774\uBA74 gz.end() \u2192 pipe \uAC00 res.end() \uAE4C\uC9C0 \uD574\uC900\uB2E4. \uB05D\uAE4C\uC9C0 \uD758\uB824\uBCF4\uB0B8 \uB4A4 \uB9AC\uD134\n const finished = new Promise(resolve => { res.once('finish', resolve); res.once('close', resolve); });\n out.end();\n await finished;\n }\n }\n }\n\n resIsDone() {\n return this.res.finished || this.res.writableEnded || this.res.headersSent;\n }\n\n createRequestResponseChain<T = any>(data?: T) {\n const requestResponseChain = new RequestResponseChain(this.req, this.res, this.config, data);\n requestResponseChain.resWriteChunk = this.resWriteChunk;\n requestResponseChain.reqBodyChunk = this.reqBodyChunk;\n return requestResponseChain;\n }\n}\n\nexport class RequestResponseChain<T> extends RequestResponse {\n constructor(\n req: IncomingMessage,\n res: ServerResponse,\n config: Config,\n public result?: T\n ) {\n super(req, res, config);\n }\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,mBAAoC;AAE7C,SAAS,cAAc;AACvB,SAAS,KAAK,uBAAuB;AACrC,SAAS,cAAc;AAEvB,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAC5B,SAAS,iBAAiB;AAG1B,SAAS,YAAY;AACrB,SAAS,YAAY,aAAa,qBAAqB;AAGvD,SAAS,YAAY;AAIrB,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB,wBAAwB;AACjD,SAAS,oBAAoB;AAKtB,MAAM,gBAAgB;AAAA,EAU3B,YAAY,KAAwC,KAAqB,QAAgB;AAFzF;AAAA,SAAU,aAAa,oBAAI,IAAiB;AAG1C,QAAI,eAAe,iBAAiB;AAClC,WAAK,MAAM,IAAI;AACf,WAAK,MAAM,IAAI;AACf,WAAK,SAAS;AACd,WAAK,aAAa,IAAI;AAAA,IACxB,OAAO;AACL,WAAK,MAAM;AACX,WAAK,MAAM;AACX,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,KAAa,OAAkB;AAC1C,SAAK,WAAW,IAAI,KAAK,KAAK;AAAA,EAChC;AAAA,EAEA,aAAsB,KAA4B;AAChD,WAAO,KAAK,WAAW,IAAI,GAAG;AAAA,EAChC;AAAA,EAEA,IAAI,YAAY;AACd,WAAO,KAAK,IAAI;AAAA,EAClB;AAAA,EAEA,IAAI,eAAe;AACjB,QAAI,UAAU,KAAK,UAAU,YAAY,MAAM,KAAK;AACpD,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,gBAAU,QAAQ,KAAK,GAAG;AAAA,IAC5B;AAEA,UAAM,MAAM,oBAAI,IAAoB;AACpC,YACG,MAAM,GAAG,EACT,IAAI,QAAM,GAAG,KAAK,EAAE,MAAM,GAAG,CAAC,EAC9B,QAAQ,QAAM;AACb,UAAI,GAAG,CAAC,EAAG,KAAI,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;AAAA,IACjC,CAAC;AACH,WAAO;AAAA,EACT;AAAA,EAEA,aAAa,KAAa;AACxB,WAAO,KAAK,aAAa,IAAI,GAAG;AAAA,EAClC;AAAA,EAEA,IAAI,mBAAuC;AACzC,UAAM,WAAW,KAAK,IAAI,QAAQ,iBAAiB;AACnD,QAAI,KAAK,KAAK,IAAI,OAAO;AACzB,QAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,WAAK,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM;AAAA,IAC3C,WAAW,OAAO,aAAa,UAAU;AACvC,WAAK,SAAS,MAAM,GAAG,EAAE,MAAM;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,eAAoB;AACtB,WAAO,IAAI,IAAI,KAAK,QAAQ,GAAG,KAAK,YAAY,aAAa,SAAS,GAAG,KAAK,WAAW,WAAW,EAAE;AAAA,EACxG;AAAA,EAEA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,UAAU,EAAE,YAAY;AAAA,EACtC;AAAA,EAEA,IAAI,SAAiB;AACnB,WAAO,KAAK,IAAI,OAAO;AAAA,EACzB;AAAA,EAEA,UAAU,QAAkD;AAC1D,WAAO,IAAI,IAAI,GAAG,QAAQ,UAAU,MAAM,MAAM,QAAQ,OAAO,QAAQ,OAAQ,KAAK,eAAe,YAAY,IAAI,KAAK,WAAY,GAAG,KAAK,IAAI,OAAO,EAAE,EAAE;AAAA,EAC7J;AAAA,EAEA,IAAI,0BAA8C;AAChD,WAAO,MAAM,KAAK,KAAK,UAAU,EAAE,YAAmB;AAAA,EACxD;AAAA,EAEA,IAAI,qBAAsC;AACxC,WAAO,KAAK,UAAU,EAAE;AAAA,EAC1B;AAAA,EAEA,IAAI,wBAA4D;AAC9D,UAAM,UAAU,KAAK,UAAU,EAAE;AACjC,WAAO,iBAAiB,SAAS,OAAO;AAAA,EAC1C;AAAA,EAEA,IAAI,wBAAgC;AAClC,UAAM,YAAY,KAAK,UAAU;AACjC,WAAO,UAAU,YAAY,UAAU,aAAa,SAAS,IAAI,MAAM,UAAU,aAAa,SAAS,IAAI;AAAA,EAC7G;AAAA,EAEA,IAAI,cAAc;AAChB,WAAO,KAAK,IAAI;AAAA,EAClB;AAAA,EAEA,IAAI,YAAY;AACd,WAAO,IAAI,OAAO,KAAK,qBAAqB;AAAA,EAC9C;AAAA,EAEA,wBAAwB,MAA+B;AACrD,UAAM,cAAc,KAAK,UAAU,YAAY,WAAW;AAC1D,QAAI,CAAC,YAAa,QAAO;AAEzB,UAAM,aAAa,KAAK,SAAS,EAAE,YAAY;AAC/C,UAAM,eAAe,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW;AAG5E,WAAO,aAAa,KAAK,QAAM;AAG7B,YAAM,CAAC,QAAQ,IAAI,GAAG,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC;AAClD,aAAO,SAAS,YAAY,MAAM,cAAc,SAAS,YAAY,EAAE,SAAS,UAAU;AAAA,IAC5F,CAAC;AAAA,EACH;AAAA,EAEA,mBAAmB,MAA+B;AAChD,UAAM,SAAS,KAAK,UAAU,YAAY,MAAM;AAChD,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,aAAa,KAAK,SAAS,EAAE,YAAY;AAC/C,UAAM,gBAAgB,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;AAE9D,WAAO,cAAc,KAAK,kBAAgB;AACxC,YAAM,cAAc,aAAa,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC;AACzF,aAAO,YAAY,KAAK,gBAAc,WAAW,SAAS,UAAU,CAAC;AAAA,IACvE,CAAC;AAAA,EACH;AAAA,EAEA,cAA+B;AAC7B,WAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,UAAI,KAAK,aAAa;AACpB,cAAM,OAAqB,CAAC;AAC5B,aAAK,IAAI,GAAG,QAAQ,WAAS,KAAK,KAAK,KAAK,CAAC;AAC7C,aAAK,IAAI,GAAG,SAAS,SAAO,OAAO,GAAG,CAAC;AACvC,aAAK,IAAI,GAAG,OAAO,MAAM;AACvB,eAAK,eAAe,OAAO,OAAO,IAAI;AACtC,kBAAQ,KAAK,YAAY;AAAA,QAC3B,CAAC;AAAA,MACH,OAAO;AACL,gBAAQ,KAAK,gBAAgB,OAAO,MAAM,CAAC,CAAC;AAAA,MAC9C;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,cAA2C;AACzC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,iCAAgD;AACpD,UAAM,IAAI,MAAM,KAAK,yBAAyB;AAC9C,UAAM,WAAW,CAAC;AAElB,eAAW,MAAM,GAAG;AAClB,UAAI,GAAG,QAAQ;AACb,iBAAS,GAAG,IAAI,IAAI,MAAM,UAAU,UAAU,GAAG,OAAO,EAAE,cAAc,GAAG,UAAU,SAAS,GAAG,CAAC;AAAA,MACpG,OAAO;AACL,cAAM,SAAS,SAAS,GAAG,IAAI;AAC/B,YAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,iBAAO,KAAK,GAAG,KAAK;AAAA,QACtB,WAAW,OAAO,WAAW,UAAU;AACrC,mBAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,GAAG,KAAK;AAAA,QACvC,OAAO;AACL,mBAAS,GAAG,IAAI,IAAI,GAAG;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,2BAAqD;AACnD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,oBAAoB,KAAK,IAAI,QAAQ,cAAc;AACzD,UAAI,CAAC,qBAAqB,CAAC,kBAAkB,WAAW,qBAAqB,GAAG;AAC9E,eAAO,OAAO,IAAI,MAAM,qDAAqD,CAAC;AAAA,MAChF;AAEA,YAAM,gBAAgB,kBAAkB,MAAM,iCAAiC;AAC/E,UAAI,CAAC,eAAe;AAClB,eAAO,OAAO,IAAI,MAAM,4CAA4C,CAAC;AAAA,MACvE;AACA,YAAM,WAAW,cAAc,CAAC,KAAK,cAAc,CAAC;AACpD,UAAI,CAAC,UAAU;AACb,eAAO,OAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,MACxD;AAEA,YAAM,iBAAiB,OAAO,KAAK,KAAK,QAAQ,EAAE;AAClD,YAAM,aAAa,OAAO,KAAK,MAAM;AACrC,YAAM,mBAAmB,OAAO,KAAK,UAAU;AAE/C,YAAM,SAAmB,CAAC;AAC1B,UAAI,cAAc;AAElB,WAAK,IAAI,GAAG,QAAQ,CAAC,UAAkB;AACrC,eAAO,KAAK,KAAK;AACjB,uBAAe,MAAM;AAAA,MACvB,CAAC;AAED,WAAK,IAAI,GAAG,SAAS,SAAO;AAC1B,eAAO,GAAG;AAAA,MACZ,CAAC;AAED,WAAK,IAAI,GAAG,OAAO,MAAM;AACvB,YAAI,gBAAgB,GAAG;AACrB,iBAAO,QAAQ,CAAC,CAAC;AAAA,QACnB;AAEA,cAAM,aAAa,OAAO,OAAO,QAAQ,WAAW;AACpD,cAAM,cAA+B,CAAC;AACtC,YAAI,kBAAkB;AAEtB,YAAI,qBAAqB,WAAW,QAAQ,gBAAgB,eAAe;AAC3E,YAAI,uBAAuB,IAAI;AAC7B,iBAAO,OAAO,IAAI,MAAM,6BAA6B,CAAC;AAAA,QACxD;AACA,0BAAkB,qBAAqB,eAAe;AACtD,YAAI,WAAW,MAAM,iBAAiB,kBAAkB,WAAW,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7F,6BAAmB,WAAW;AAAA,QAChC;AAEA,eAAO,kBAAkB,WAAW,QAAQ;AAC1C,gBAAM,oBAAoB,WAAW,QAAQ,gBAAgB,eAAe;AAC5E,cAAI,sBAAsB,IAAI;AAC5B;AAAA,UACF;AAEA,cAAI,eAAe;AACnB,cAAI,eAAe,WAAW,UAAU,WAAW,MAAM,eAAe,WAAW,QAAQ,YAAY,EAAE,OAAO,UAAU,GAAG;AAC3H,4BAAgB,WAAW;AAAA,UAC7B;AACA,gBAAM,aAAa,WAAW,MAAM,iBAAiB,YAAY;AAEjE,gBAAM,2BAA2B,WAAW,QAAQ,gBAAgB;AACpE,cAAI,6BAA6B,IAAI;AACnC,8BAAkB,oBAAoB,eAAe;AACrD,gBAAI,WAAW,MAAM,iBAAiB,kBAAkB,WAAW,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7F,iCAAmB,WAAW;AAAA,YAChC;AACA,gBAAI,WAAW,MAAM,iBAAiB,kBAAkB,CAAC,EAAE,SAAS,MAAM,KAAM;AAChF;AAAA,UACF;AAEA,gBAAM,eAAe,WAAW,MAAM,GAAG,wBAAwB;AACjE,gBAAM,aAAa,WAAW,MAAM,2BAA2B,iBAAiB,MAAM;AACtF,gBAAM,aAAa,aAAa,SAAS,OAAO;AAEhD,gBAAM,UAAqC,CAAC;AAC5C,qBAAW,MAAM,MAAM,EAAE,QAAQ,UAAQ;AACvC,kBAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,gBAAI,aAAa,GAAG;AAClB,oBAAM,MAAM,KAAK,UAAU,GAAG,UAAU,EAAE,KAAK,EAAE,YAAY;AAC7D,oBAAM,QAAQ,KAAK,UAAU,aAAa,CAAC,EAAE,KAAK;AAClD,sBAAQ,GAAG,IAAI;AAAA,YACjB;AAAA,UACF,CAAC;AAED,gBAAM,qBAAqB,QAAQ,qBAAqB;AACxD,cAAI,CAAC,oBAAoB;AACvB,8BAAkB,oBAAoB,eAAe;AACrD,gBAAI,WAAW,MAAM,iBAAiB,kBAAkB,WAAW,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7F,iCAAmB,WAAW;AAAA,YAChC;AACA,gBAAI,WAAW,MAAM,iBAAiB,kBAAkB,CAAC,EAAE,SAAS,MAAM,KAAM;AAChF;AAAA,UACF;AAEA,gBAAM,YAAY,mBAAmB,MAAM,iBAAiB;AAC5D,gBAAM,gBAAgB,mBAAmB,MAAM,qBAAqB;AAEpE,gBAAM,OAAO,YAAY,UAAU,CAAC,IAAI;AACxC,gBAAM,WAAW,gBAAgB,cAAc,CAAC,IAAI;AACpD,gBAAM,cAAc,QAAQ,cAAc,KAAK;AAE/C,cAAI,MAAM;AACR,gBAAI,UAAU;AACZ,0BAAY,KAAK;AAAA,gBACf,QAAQ;AAAA,gBACR;AAAA,gBACA;AAAA,gBACA,aAAa,eAAe;AAAA,gBAC5B,OAAO;AAAA,cACT,CAAC;AAAA,YACH,OAAO;AACL,0BAAY,KAAK;AAAA,gBACf,QAAQ;AAAA,gBACR;AAAA,gBACA,OAAO,WAAW,SAAS,OAAO;AAAA,cACpC,CAAC;AAAA,YACH;AAAA,UACF;AAEA,4BAAkB,oBAAoB,eAAe;AACrD,cAAI,WAAW,MAAM,iBAAiB,kBAAkB,WAAW,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7F,+BAAmB,WAAW;AAAA,UAChC;AAEA,cAAI,WAAW,MAAM,iBAAiB,kBAAkB,CAAC,EAAE,SAAS,MAAM,MAAM;AAC9E;AAAA,UACF;AAAA,QACF;AACA,gBAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,oBAAqC;AACzC,UAAM,QAAQ,MAAM,KAAK,YAAY,GAAG,SAAS;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,kBAAiC;AACrC,WAAO,KAAK,MAAM,MAAM,KAAK,kBAAkB,CAAC;AAAA,EAClD;AAAA,EAEA,MAAM,qBAAoC;AACxC,UAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,UAAM,WAAW,CAAC;AAClB,UAAM,KAAK,IAAI,gBAAgB,IAAI,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM;AAClE,YAAM,SAAS,SAAS,CAAC;AACzB,UAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,eAAO,KAAK,CAAC;AAAA,MACf,WAAW,OAAO,WAAW,UAAU;AACrC,iBAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;AAAA,MAC1B,OAAO;AACL,iBAAS,CAAC,IAAI;AAAA,MAChB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,wBAAwB;AAC5B,UAAM,OAAO,MAAM,KAAK,mBAAmB;AAC3C,WAAO,OAAO,OAAO,IAAI,eAAe,GAAG,IAAI;AAAA,EACjD;AAAA,EAEA,MAAM,qBAA2C;AAC/C,UAAM,OAAO,MAAM,KAAK,kBAAkB;AAC1C,WAAO,OAAO,OAAO,IAAI,YAAY,GAAG,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC;AAAA,EACtE;AAAA,EAEA,kBAA+B;AAC7B,UAAM,OAAO,aAAa,SAAS,KAAK,YAAY,CAAC;AACrD,WAAO,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EACnC;AAAA,EAEA,oBAAoB;AAClB,WAAO,aAAa,SAAS,KAAK,YAAY,CAAC;AAAA,EACjD;AAAA,EAEA,YAAY;AACV,WAAO,KAAK,IAAI,QAAQ,YAAY;AAAA,EACtC;AAAA,EAEA,YAAY,QAA6B;AACvC,WAAO,KAAK,UAAU,EAAE,YAAY,MAAO,OAAkB,YAAY;AAAA,EAC3E;AAAA,EAEA,UAAU,KAAwC;AAChD,WAAO,KAAK,IAAI,QAAS,IAAe,YAAY,CAAC;AAAA,EACvD;AAAA,EAEA,IAAI,UAAU;AACZ,WAAO,KAAK,eAAe,YAAY,IAAI;AAAA,EAC7C;AAAA,EAEA,IAAI,eAA0B;AAC5B,UAAM,IAAI,IAAI,UAAU;AACxB,WAAO,QAAQ,KAAK,IAAI,OAAO,EAAE,QAAQ,CAAC,CAAC,GAAG,CAAC,MAAM;AACnD,QAAE,CAAC,IAAI;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,KAA+B,cAAuB;AACnE,UAAM,SAAS,KAAK,IAAI,QAAS,IAAe,YAAY,CAAC;AAC7D,QAAI,UAAU,MAAM,QAAQ,MAAM,GAAG;AACnC,aAAO,OAAO,CAAC,KAAK;AAAA,IACtB,OAAO;AACL,aAAQ,UAAqB;AAAA,IAC/B;AAAA,EACF;AAAA,EAEO,yBAAyB;AAC9B,WAAO,KAAK,eAAe,YAAY,aAAa;AAAA,EACtD;AAAA,EAEA,wBAAwB;AACtB,WAAO,KAAK,eAAe,YAAY,aAAa;AAAA,EACtD;AAAA,EAIA,cAAc,MAA8E;AAC1F,QAAI,MAAM;AACR,WAAK,IAAI,aAAa;AACtB,aAAO,IAAI,qBAA6B,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,KAAK,IAAI,UAAU;AAAA,IAC9F,OAAO;AACL,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,EACF;AAAA,EAEA,UAAU,KAA+B;AACvC,WAAO,KAAK,IAAI,UAAW,IAAe,YAAY,CAAC;AAAA,EACzD;AAAA,EAEA,eAAe,KAA+B,cAAuB;AACnE,UAAM,SAAS,KAAK,IAAI,UAAW,IAAe,YAAY,CAAC;AAC/D,QAAI,UAAU,MAAM,QAAQ,MAAM,GAAG;AACnC,aAAO,OAAO,CAAC,KAAK;AAAA,IACtB,OAAO;AACL,aAAQ,UAAqB;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,MAAM,aAA8C;AAClD,QAAI,KAAK,OAAO,gBAAgB;AAC9B,YAAM,UAAU,MAAM,KAAK,OAAO,eAAe,QAAQ,IAAI;AAC7D,cAAQ,QAAQ,SAAS,CAAC;AAC1B,aAAO,QAAQ,QAAQ;AAAA,IACzB,OAAO;AACL,aAAO,QAAQ,OAAO,IAAI,MAAM,oBAAoB,CAAC;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,KAAa,OAA2B;AAC1D,UAAM,cAAc,MAAM,KAAK,WAAW;AAC1C,gBAAY,GAAG,IAAI;AAAA,EACrB;AAAA,EAEA,MAAM,cAAuB,KAAqC;AAChE,UAAM,cAAc,MAAM,KAAK,WAAW;AAC1C,WAAO,YAAY,GAAG;AAAA,EACxB;AAAA,EAEA,iBAAiB,YAAoB;AACnC,SAAK,IAAI,aAAa;AACtB,WAAO,KAAK,2BAA2B,KAAK,IAAI,UAAU;AAAA,EAC5D;AAAA,EAEA,SAAS,OAA8B,WAA2B,QAAQ;AACxE,SAAK,gBAAgB;AACrB,WAAO,KAAK,2BAA2B,KAAK,aAAa;AAAA,EAC3D;AAAA,EAEA,aAAa,OAAY,WAA2B,QAAQ;AAC1D,WAAO,KAAK,SAAS,KAAK,UAAU,KAAK,GAAG,QAAQ;AAAA,EACtD;AAAA,EAEA,aAAa,KAA+B,OAA0B;AACpE,SAAK,IAAI,UAAW,IAAe,YAAY,GAAG,KAAK;AACvD,WAAO,KAAK,2BAA2B;AAAA,EACzC;AAAA,EAEA,aAAa,KAA+B,OAA0B;AACpE,UAAM,gBAAgB,KAAK,IAAI,UAAW,IAAe,YAAY,CAAC;AACtE,UAAM,WAAW,MAAM,QAAQ,aAAa,IAAI,cAAc,OAAO,KAAK,IAAI,gBAAgB,CAAC,cAAc,SAAS,GAAG,GAAG,CAAC,EAAE,OAAO,KAAY,CAAC,IAAI;AACvJ,SAAK,IAAI,UAAW,IAAe,YAAY,GAAG,QAAe;AACjE,WAAO,KAAK,2BAA2B;AAAA,EACzC;AAAA,EAEA,cAAc,SAA+C;AAC3D,WAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM,KAAK,aAAa,KAAK,KAAK,CAAC;AAC/E,WAAO,KAAK,2BAA2B;AAAA,EACzC;AAAA,EAEA,cAAc,SAA+C;AAC3D,WAAO,QAAQ,OAAO,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM,KAAK,aAAa,KAAK,KAAK,CAAC;AAC/E,WAAO,KAAK,2BAA2B;AAAA,EACzC;AAAA,EAEA,MAAc,cAAc;AAC1B,UAAM,WAAW,KAAK,eAAe,YAAY,cAAc;AAC/D,QAAI,OAAO,KAAK;AAChB,QAAI,UAAU,SAAS,MAAM,KAAK,MAAM;AACtC,aAAO,MAAM,KAAK,IAAI;AACtB,WAAK,aAAa,YAAY,iBAAiB,MAAM;AAAA,IACvD;AACA,SAAK,IAAI,IAAI,IAAI;AAAA,EACnB;AAAA,EAEA,MAAM,OAAO,OAAyD;AACpE,QAAI,iBAAiB,UAAU;AAC7B,YAAM,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACpC,aAAK,IAAI,UAAU,UAAU,GAAG,IAAI,KAAK;AAAA,MAC3C,CAAC;AACD,UAAI,CAAC,KAAK,UAAU,YAAY,WAAW,GAAG;AAC5C,cAAM,cAAc,MAAM,QAAQ,IAAI,YAAY,WAAW;AAC7D,YAAI,YAAa,MAAK,IAAI,UAAU,YAAY,aAAa,WAAW;AAAA,MAC1E;AACA,WAAK,IAAI,aAAa,MAAM;AAC5B,WAAK,gBAAgB,OAAO,KAAK,MAAM,MAAM,YAAY,CAAC;AAAA,IAC5D,WAAW,iBAAiB,MAAM;AAChC,WAAK,gBAAgB,OAAO,KAAK,MAAM,MAAM,YAAY,CAAC;AAC1D,UAAI,CAAC,KAAK,UAAU,YAAY,WAAW,GAAG;AAC5C,aAAK,IAAI,UAAU,YAAY,aAAa,MAAM,IAAI;AAAA,MACxD;AAAA,IACF,WAAW,iBAAiB,aAAa;AACvC,WAAK,gBAAgB,OAAO,KAAK,KAAK;AAAA,IACxC,OAAO;AACL,WAAK,gBAAgB,SAAS,KAAK;AAAA,IACrC;AAEA,QAAI,KAAK,IAAI,UAAU;AACrB,YAAM,KAAK,YAAY;AACvB,YAAM,KAAK,YAAY;AAAA,IACzB,OAAO;AACL,YAAM,KAAK,YAAY;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,YAAY,YAAoB,UAAkB;AAChD,SAAK,IAAI,aAAa;AACtB,SAAK,IAAI,UAAU,YAAY,UAAU,QAAQ;AACjD,SAAK,IAAI,IAAI;AAAA,EACf;AAAA,EACA,aAAa,YAAoB,SAA6F;AAC5H,WAAO,KAAK,2BAA2B,KAAK,IAAI,UAAU,YAAY,OAAc,CAAC;AAAA,EACvF;AAAA,EACA,gBAAgB,YAAoB,SAA6F;AAC/H,SAAK,2BAA2B,KAAK,IAAI,UAAU,YAAY,OAAc,CAAC;AAC9E,SAAK,IAAI,IAAI;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,UAAU,QAA4C;AAC1D,UAAM,MAAM,KAAK;AACjB,UAAM,KAAK,KAAK,eAAe,YAAY,cAAc,GAAG,SAAS,MAAM,IAAI,WAAW,IAAI;AAC9F,QAAI,IAAI;AACN,UAAI,UAAU,YAAY,iBAAiB,MAAM;AACjD,UAAI,aAAa,YAAY,aAAa;AAC1C,SAAG,KAAK,GAAG;AAAA,IACb;AACA,UAAM,MAAM,MAAM;AAClB,QAAI,aAAa;AACjB,QAAI,SAAS;AACb,UAAM,UAAU,MAAM;AACpB,eAAS;AACT,MAAC,OAAe,SAAS;AAAA,IAC3B;AACA,QAAI,KAAK,SAAS,OAAO;AACzB,QAAI;AACF,uBAAiB,SAAS,QAAQ;AAChC,YAAI,OAAQ;AACZ,cAAM,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ,KAAK,UAAU,KAAK;AAC/F,cAAM,KAAK,IAAI,MAAM,IAAI;AACzB,YAAI,MAAM,cAAc,YAAY;AAEpC,YAAI,CAAC,GAAI,OAAM,IAAI,QAAQ,aAAW;AAAE,cAAI,KAAK,SAAS,OAAO;AAAG,cAAI,KAAK,SAAS,OAAO;AAAA,QAAG,CAAC;AAAA,MACnG;AAAA,IACF,SAAS,GAAG;AAEV,UAAI,CAAC,OAAQ,OAAM;AAAA,IACrB,UAAE;AACA,UAAI,IAAI,SAAS,OAAO;AACxB,UAAI,QAAQ;AACV,YAAI,QAAQ;AAAA,MACd,WAAW,CAAC,IAAI,eAAe;AAE7B,cAAM,WAAW,IAAI,QAAQ,aAAW;AAAE,cAAI,KAAK,UAAU,OAAO;AAAG,cAAI,KAAK,SAAS,OAAO;AAAA,QAAG,CAAC;AACpG,YAAI,IAAI;AACR,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,KAAK,IAAI,YAAY,KAAK,IAAI,iBAAiB,KAAK,IAAI;AAAA,EACjE;AAAA,EAEA,2BAAoC,MAAU;AAC5C,UAAM,uBAAuB,IAAI,qBAAqB,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,IAAI;AAC3F,yBAAqB,gBAAgB,KAAK;AAC1C,yBAAqB,eAAe,KAAK;AACzC,WAAO;AAAA,EACT;AACF;AAEO,MAAM,6BAAgC,gBAAgB;AAAA,EAC3D,YACE,KACA,KACA,QACO,QACP;AACA,UAAM,KAAK,KAAK,MAAM;AAFf;AAAA,EAGT;AACF;",
|
|
4
|
+
"sourcesContent": ["import { IncomingMessage, OutgoingHttpHeader, OutgoingHttpHeaders, ServerResponse } from 'http';\nimport { HttpHeaders, HttpHeadersType } from '../codes/HttpHeaders';\nimport { Mimes } from '../codes/Mimes';\nimport { Intent } from '@dooboostore/simple-boot';\nimport { URL, URLSearchParams } from 'url';\nimport { Buffer } from 'buffer';\nimport { MultipartData } from './datas/MultipartData';\nimport { ReqFormUrlBody } from './datas/body/ReqFormUrlBody';\nimport { ReqJsonBody } from './datas/body/ReqJsonBody';\nimport { ReqHeader } from './datas/ReqHeader';\nimport { ReqMultipartFormBody } from './datas/body/ReqMultipartFormBody';\nimport { HttpStatus } from '../codes/HttpStatus';\nimport { gzip } from 'node-gzip';\nimport { createGzip, constants as zlibConstants } from 'zlib';\nimport { SessionManager } from '../session/SessionManager';\nimport { HttpServerOption } from '../option/HttpServerOption';\nimport { Blob } from 'node:buffer';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport { RandomUtils } from '@dooboostore/core';\nimport { FileUtils } from '@dooboostore/core-node';\nimport { ConvertUtils as CoreConvertUtils } from '@dooboostore/core';\nimport { ConvertUtils } from '@dooboostore/core-node';\nimport {HttpMethod} from \"../codes\";\n\ntype Config = { sessionManager?: SessionManager; option: HttpServerOption };\n\nexport class RequestResponse {\n protected resWriteChunk: string | Buffer | undefined;\n protected reqBodyChunk?: Buffer;\n protected req: IncomingMessage;\n protected res: ServerResponse;\n protected config: Config;\n\n // [\uC544\uD0A4\uD14D\uD2B8\uB2D8\uC758 \uC815\uC11D] RequestResponse \uAC1D\uCCB4 \uACE0\uC720\uC758 \uC18D\uC131 \uC800\uC7A5\uC18C (\uD2B8\uB79C\uC7AD\uC158 \uC0DD\uBA85\uC8FC\uAE30)\n protected attributes = new Map<string, any>();\n\n constructor(req: IncomingMessage | RequestResponse, res: ServerResponse, config: Config) {\n if (req instanceof RequestResponse) {\n this.req = req.req;\n this.res = req.res;\n this.config = config;\n this.attributes = req.attributes;\n } else {\n this.req = req;\n this.res = res!;\n this.config = config;\n }\n }\n\n // --- RequestResponse Attributes (Transaction Life-cycle) ---\n\n setAttribute(key: string, value: any): void {\n this.attributes.set(key, value);\n }\n\n getAttribute<T = any>(key: string): T | undefined {\n return this.attributes.get(key) as T;\n }\n\n get reqSocket() {\n return this.req.socket;\n }\n\n get reqCookieMap() {\n let cookies = this.reqHeader(HttpHeaders.Cookie) ?? '';\n if (Array.isArray(cookies)) {\n cookies = cookies.join(';');\n }\n\n const map = new Map<string, string>();\n cookies\n .split(';')\n .map(it => it.trim().split('='))\n .forEach(it => {\n if (it[0]) map.set(it[0], it[1]);\n });\n return map;\n }\n\n reqCookieGet(key: string) {\n return this.reqCookieMap.get(key);\n }\n\n get reqRemoteAddress(): string | undefined {\n const ipHeader = this.req.headers['x-forwarded-for'];\n let ip = this.req.socket.remoteAddress;\n if (Array.isArray(ipHeader)) {\n ip = ipHeader.join(',').split(',').shift();\n } else if (typeof ipHeader === 'string') {\n ip = ipHeader.split(',').shift();\n }\n return ip;\n }\n\n get reqUrlObject(): URL {\n return new URL(this.reqUrl, `${this.reqSocket ? 'https://' : 'http://'}${this.reqHost ?? 'localhost'}`);\n }\n\n get reqUrlPathName(): string {\n return this.reqUrlObj().pathname ?? '';\n }\n\n get reqUrl(): string {\n return this.req.url ?? '';\n }\n\n reqUrlObj(config?: { scheme?: string; host?: string }): URL {\n return new URL(`${config?.scheme ?? 'http'}://${config?.host ? config?.host : (this.reqHeaderFirst(HttpHeaders.Host) ?? 'localhost')}${this.req.url ?? ''}`);\n }\n\n get reqUrlSearchParamTuples(): [string, string][] {\n return Array.from(this.reqUrlObj().searchParams as any);\n }\n\n get reqUrlSearchParams(): URLSearchParams {\n return this.reqUrlObj().searchParams;\n }\n\n get reqUrlSearchParamsObj(): { [p: string]: string | string[] } {\n const entries = this.reqUrlObj().searchParams;\n return CoreConvertUtils.toObject(entries);\n }\n\n get reqPathSearchParamUrl(): string {\n const reqUrlObj = this.reqUrlObj();\n return reqUrlObj.pathname + (reqUrlObj.searchParams.toString() ? '?' + reqUrlObj.searchParams.toString() : '');\n }\n\n get reqReadable() {\n return this.req.readable;\n }\n\n get reqIntent() {\n return new Intent(this.reqPathSearchParamUrl);\n }\n\n reqHasContentTypeHeader(mime: Mimes | string): boolean {\n const contentType = this.reqHeader(HttpHeaders.ContentType);\n if (!contentType) return false;\n \n const targetMime = mime.toString().toLowerCase();\n const contentTypes = Array.isArray(contentType) ? contentType : [contentType];\n \n // \uBAA8\uB4E0 Content-Type \uD5E4\uB354\uB97C \uD655\uC778\n return contentTypes.some(ct => {\n // Content-Type\uC740 \uBCF4\uD1B5 \uB2E8\uC77C \uAC12\uC774\uC9C0\uB9CC, \uD30C\uB77C\uBBF8\uD130\uAC00 \uBD99\uC744 \uC218 \uC788\uC74C (charset=utf-8 \uB4F1)\n // \uC138\uBBF8\uCF5C\uB860\uC73C\uB85C split\uD574\uC11C \uC55E \uBD80\uBD84(MIME \uD0C0\uC785)\uB9CC \uBE44\uAD50\n const [mimeType] = ct.split(';').map(m => m.trim());\n return mimeType.toLowerCase() === targetMime || mimeType.toLowerCase().includes(targetMime);\n });\n }\n\n reqHasAcceptHeader(mime: Mimes | string): boolean {\n const accept = this.reqHeader(HttpHeaders.Accept);\n if (!accept) return false;\n\n const targetMime = mime.toString().toLowerCase();\n const acceptHeaders = Array.isArray(accept) ? accept : [accept];\n\n return acceptHeaders.some(acceptHeader => {\n const acceptMimes = acceptHeader.split(',').map(m => m.split(';')[0].trim().toLowerCase());\n return acceptMimes.some(acceptMime => acceptMime.includes(targetMime));\n });\n }\n\n reqBodyData(): Promise<Buffer> {\n return new Promise<Buffer>((resolve, reject) => {\n if (this.reqReadable) {\n const data: Uint8Array[] = [];\n this.req.on('data', chunk => data.push(chunk));\n this.req.on('error', err => reject(err));\n this.req.on('end', () => {\n this.reqBodyChunk = Buffer.concat(data);\n resolve(this.reqBodyChunk);\n });\n } else {\n resolve(this.reqBodyChunk ?? Buffer.alloc(0));\n }\n });\n }\n\n resBodyData(): string | Buffer | undefined {\n return this.resWriteChunk;\n }\n\n async reqBodyMultipartFormDataObject<T>(): Promise<T> {\n const m = await this.reqBodyMultipartFormData();\n const formData = {} as any;\n\n for (const it of m) {\n if (it.isFile) {\n formData[it.name] = await FileUtils.writeFile(it.value, { originalName: it.filename, etcData: it });\n } else {\n const target = formData[it.name];\n if (Array.isArray(target)) {\n target.push(it.value);\n } else if (typeof target === 'string') {\n formData[it.name] = [target, it.value];\n } else {\n formData[it.name] = it.value;\n }\n }\n }\n return formData;\n }\n\n reqBodyMultipartFormData(): Promise<MultipartData[]> {\n return new Promise((resolve, reject) => {\n const contentTypeHeader = this.req.headers['content-type'];\n if (!contentTypeHeader || !contentTypeHeader.startsWith('multipart/form-data')) {\n return reject(new Error('Invalid Content-Type. Expected multipart/form-data.'));\n }\n\n const boundaryMatch = contentTypeHeader.match(/boundary=(?:\"([^\"]+)\"|([^;]+))/i);\n if (!boundaryMatch) {\n return reject(new Error('Boundary not found in Content-Type header.'));\n }\n const boundary = boundaryMatch[1] || boundaryMatch[2];\n if (!boundary) {\n return reject(new Error('Failed to extract boundary.'));\n }\n\n const boundaryBuffer = Buffer.from(`--${boundary}`);\n const crlfBuffer = Buffer.from('\\r\\n');\n const doubleCrlfBuffer = Buffer.from('\\r\\n\\r\\n');\n\n const chunks: Buffer[] = [];\n let totalLength = 0;\n\n this.req.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n totalLength += chunk.length;\n });\n\n this.req.on('error', err => {\n reject(err);\n });\n\n this.req.on('end', () => {\n if (totalLength === 0) {\n return resolve([]);\n }\n\n const fullBuffer = Buffer.concat(chunks, totalLength);\n const parsedParts: MultipartData[] = [];\n let currentPosition = 0;\n\n let boundaryStartIndex = fullBuffer.indexOf(boundaryBuffer, currentPosition);\n if (boundaryStartIndex === -1) {\n return reject(new Error('Initial boundary not found.'));\n }\n currentPosition = boundaryStartIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n\n while (currentPosition < fullBuffer.length) {\n const nextBoundaryIndex = fullBuffer.indexOf(boundaryBuffer, currentPosition);\n if (nextBoundaryIndex === -1) {\n break;\n }\n\n let partEndIndex = nextBoundaryIndex;\n if (partEndIndex > crlfBuffer.length && fullBuffer.slice(partEndIndex - crlfBuffer.length, partEndIndex).equals(crlfBuffer)) {\n partEndIndex -= crlfBuffer.length;\n }\n const partBuffer = fullBuffer.slice(currentPosition, partEndIndex);\n\n const headerBodySeparatorIndex = partBuffer.indexOf(doubleCrlfBuffer);\n if (headerBodySeparatorIndex === -1) {\n currentPosition = nextBoundaryIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') break;\n continue;\n }\n\n const headerBuffer = partBuffer.slice(0, headerBodySeparatorIndex);\n const bodyBuffer = partBuffer.slice(headerBodySeparatorIndex + doubleCrlfBuffer.length);\n const headersStr = headerBuffer.toString('utf-8');\n\n const headers: { [key: string]: string } = {};\n headersStr.split('\\r\\n').forEach(line => {\n const colonIndex = line.indexOf(':');\n if (colonIndex > 0) {\n const key = line.substring(0, colonIndex).trim().toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n headers[key] = value;\n }\n });\n\n const contentDisposition = headers['content-disposition'];\n if (!contentDisposition) {\n currentPosition = nextBoundaryIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') break;\n continue;\n }\n\n const nameMatch = contentDisposition.match(/name=\"([^\"]+)\"/i);\n const filenameMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);\n\n const name = nameMatch ? nameMatch[1] : null;\n const filename = filenameMatch ? filenameMatch[1] : null;\n const contentType = headers['content-type'] || null;\n\n if (name) {\n if (filename) {\n parsedParts.push({\n isFile: true,\n name: name,\n filename: filename,\n contentType: contentType ?? 'application/octet-stream',\n value: bodyBuffer\n });\n } else {\n parsedParts.push({\n isFile: false,\n name: name,\n value: bodyBuffer.toString('utf-8')\n });\n }\n }\n\n currentPosition = nextBoundaryIndex + boundaryBuffer.length;\n if (fullBuffer.slice(currentPosition, currentPosition + crlfBuffer.length).equals(crlfBuffer)) {\n currentPosition += crlfBuffer.length;\n }\n\n if (fullBuffer.slice(currentPosition, currentPosition + 2).toString() === '--') {\n break;\n }\n }\n resolve(parsedParts);\n });\n });\n }\n\n async reqBodyStringData(): Promise<string> {\n const data = (await this.reqBodyData()).toString();\n return data;\n }\n\n async reqBodyJsonData<T>(): Promise<T> {\n return JSON.parse(await this.reqBodyStringData());\n }\n\n async reqBodyFormUrlData<T>(): Promise<T> {\n const data = await this.reqBodyStringData();\n const formData = {} as any;\n Array.from(new URLSearchParams(data).entries()).forEach(([k, v]) => {\n const target = formData[k];\n if (Array.isArray(target)) {\n target.push(v);\n } else if (typeof target === 'string') {\n formData[k] = [target, v];\n } else {\n formData[k] = v;\n }\n });\n return formData;\n }\n\n async reqBodyReqFormUrlBody() {\n const data = await this.reqBodyFormUrlData();\n return Object.assign(new ReqFormUrlBody(), data);\n }\n\n async reqBodyReqJsonBody(): Promise<ReqJsonBody> {\n const data = await this.reqBodyStringData();\n return Object.assign(new ReqJsonBody(), data ? JSON.parse(data) : {});\n }\n\n resBodyJsonData<T>(): T | null {\n const data = ConvertUtils.toString(this.resBodyData());\n return data ? JSON.parse(data) : null;\n }\n\n resBodyStringData() {\n return ConvertUtils.toString(this.resBodyData());\n }\n\n reqMethod() {\n return this.req.method?.toUpperCase();\n }\n\n reqIsMethod(method: HttpMethod | string) {\n return this.reqMethod().toUpperCase() === (method as string).toUpperCase();\n }\n\n reqHeader(key: keyof typeof HttpHeaders | string) {\n return this.req.headers[(key as string).toLowerCase()];\n }\n\n get reqHost() {\n return this.reqHeaderFirst(HttpHeaders.Host);\n }\n\n get reqHeaderObj(): ReqHeader {\n const h = new ReqHeader();\n Object.entries(this.req.headers).forEach(([k, v]) => {\n h[k] = v;\n });\n return h;\n }\n\n reqHeaderFirst(key: HttpHeadersType | string, defaultValue?: string) {\n const header = this.req.headers[(key as string).toLowerCase()];\n if (header && Array.isArray(header)) {\n return header[0] ?? defaultValue;\n } else {\n return (header as string) ?? defaultValue;\n }\n }\n\n public reqAuthorizationHeader() {\n return this.reqHeaderFirst(HttpHeaders.Authorization);\n }\n\n reqRefreshTokenHeader() {\n return this.reqHeaderFirst(HttpHeaders.Authorization);\n }\n\n resStatusCode(code?: undefined): number;\n resStatusCode(code: number | HttpStatus): RequestResponseChain<number>;\n resStatusCode(code: number | undefined | HttpStatus): number | RequestResponseChain<number> {\n if (code) {\n this.res.statusCode = code;\n return new RequestResponseChain<number>(this.req, this.res, this.config, this.res.statusCode);\n } else {\n return this.res.statusCode;\n }\n }\n\n resHeader(key: HttpHeadersType | string) {\n return this.res.getHeader((key as string).toLowerCase());\n }\n\n resHeaderFirst(key: HttpHeadersType | string, defaultValue?: string) {\n const header = this.res.getHeader((key as string).toLowerCase());\n if (header && Array.isArray(header)) {\n return header[0] ?? defaultValue;\n } else {\n return (header as string) ?? defaultValue;\n }\n }\n\n async reqSession(): Promise<{ [key: string]: any }> {\n if (this.config.sessionManager) {\n const session = await this.config.sessionManager.session(this);\n session.dataSet.data ??= {};\n return session.dataSet.data;\n } else {\n return Promise.reject(new Error('Not SessionManager'));\n }\n }\n\n async reqSessionSet(key: string, value: any): Promise<void> {\n const sessionData = await this.reqSession();\n sessionData[key] = value;\n }\n\n async reqSessionGet<T = any>(key: string): Promise<T | undefined> {\n const sessionData = await this.reqSession();\n return sessionData[key] as T;\n }\n\n resSetStatusCode(statusCode: number) {\n this.res.statusCode = statusCode;\n return this.createRequestResponseChain(this.res.statusCode);\n }\n\n resWrite(chunk: string | Buffer | any, encoding: BufferEncoding = 'utf8') {\n this.resWriteChunk = chunk;\n return this.createRequestResponseChain(this.resWriteChunk);\n }\n\n resWriteJson(chunk: any, encoding: BufferEncoding = 'utf8') {\n return this.resWrite(JSON.stringify(chunk), encoding);\n }\n\n resSetHeader(key: HttpHeadersType | string, value: string | string[]) {\n this.res.setHeader((key as string).toLowerCase(), value);\n return this.createRequestResponseChain();\n }\n\n resAddHeader(key: HttpHeadersType | string, value: string | string[]) {\n const existingValue = this.res.getHeader((key as string).toLowerCase());\n const newValue = Array.isArray(existingValue) ? existingValue.concat(value) : existingValue ? [existingValue.toString(), ...[].concat(value as any)] : value;\n this.res.setHeader((key as string).toLowerCase(), newValue as any);\n return this.createRequestResponseChain();\n }\n\n resSetHeaders(headers: { [key: string]: string | string[] }) {\n Object.entries(headers).forEach(([key, value]) => this.resSetHeader(key, value));\n return this.createRequestResponseChain();\n }\n\n resAddHeaders(headers: { [key: string]: string | string[] }) {\n Object.entries(headers).forEach(([key, value]) => this.resAddHeader(key, value));\n return this.createRequestResponseChain();\n }\n\n private async resEndChunk() {\n const encoding = this.reqHeaderFirst(HttpHeaders.AcceptEncoding);\n let data = this.resWriteChunk;\n if (encoding?.includes('gzip') && data) {\n data = await gzip(data);\n this.resSetHeader(HttpHeaders.ContentEncoding, 'gzip');\n }\n this.res.end(data);\n }\n\n async resEnd(chunk?: string | Buffer | Blob | ArrayBuffer | Response) {\n if (chunk instanceof Response) {\n chunk.headers.forEach((value, key) => {\n this.res.setHeader(`ORIGIN-${key}`, value);\n });\n if (!this.resHeader(HttpHeaders.ContentType)) {\n const contentType = chunk.headers.get(HttpHeaders.ContentType);\n if (contentType) this.res.setHeader(HttpHeaders.ContentType, contentType);\n }\n this.res.statusCode = chunk.status;\n this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());\n } else if (chunk instanceof Blob) {\n this.resWriteChunk = Buffer.from(await chunk.arrayBuffer());\n if (!this.resHeader(HttpHeaders.ContentType)) {\n this.res.setHeader(HttpHeaders.ContentType, chunk.type);\n }\n } else if (chunk instanceof ArrayBuffer) {\n this.resWriteChunk = Buffer.from(chunk);\n } else {\n this.resWriteChunk = chunk ?? this.resWriteChunk;\n }\n\n if (this.req.readable) {\n await this.reqBodyData();\n await this.resEndChunk();\n } else {\n await this.resEndChunk();\n }\n }\n\n resRedirect(statusCode: number, location: string) {\n this.res.statusCode = statusCode;\n this.res.setHeader(HttpHeaders.Location, location);\n this.res.end();\n }\n resWriteHead(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | { [key: string]: string | string[] }) {\n return this.createRequestResponseChain(this.res.writeHead(statusCode, headers as any));\n }\n resWriteHeadEnd(statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[] | { [key: string]: string | string[] }) {\n this.createRequestResponseChain(this.res.writeHead(statusCode, headers as any));\n this.res.end();\n }\n\n /**\n * \uD5E4\uB354\uB97C \uC989\uC2DC \uBCF4\uB0B4\uACE0, source \uAC00 \uB0B4\uB193\uB294 \uAC12\uC744 \uD558\uB098\uC529 \uBC14\uB85C body \uC5D0 \uC4F4 \uB4A4 end.\n * (SSE / \uC2A4\uD2B8\uB9AC\uBC0D \uC751\uB2F5\uC6A9. resWrite \uB294 \uBC84\uD37C\uB9C1 \uD6C4 resEnd \uC5D0\uC11C \uD55C \uBC88\uC5D0 \uBCF4\uB0B4\uBBC0\uB85C \uC2A4\uD2B8\uB9AC\uBC0D \uBD88\uAC00)\n * - \uBB38\uC790\uC5F4/Buffer \uB294 \uADF8\uB300\uB85C, \uADF8 \uC678\uB294 JSON.stringify\n * - Accept-Encoding \uC5D0 gzip \uC774 \uC788\uC73C\uBA74 gzip \uC2A4\uD2B8\uB9BC\uC73C\uB85C \uC555\uCD95\uD558\uACE0, \uCCAD\uD06C\uB9C8\uB2E4 Z_SYNC_FLUSH \uB85C \uBC14\uB85C \uB0B4\uBCF4\uB0B8\uB2E4\n * (flush \uC5C6\uC774 \uC4F0\uBA74 zlib \uB0B4\uBD80 \uBC84\uD37C\uC5D0 \uBAA8\uC600\uB2E4\uAC00 \uB2A6\uAC8C \uB098\uAC00\uC11C SSE \uC2E4\uC2DC\uAC04\uC131\uC774 \uAE68\uC9D0)\n * option.compress === false \uBA74 \uC555\uCD95 \uC548 \uD568 (MJPEG \uCC98\uB7FC \uC774\uBBF8 \uC555\uCD95\uB41C \uB0B4\uC6A9 \u2014 CPU\uB9CC \uC4F0\uACE0, gzip \uBABB \uD478\uB294 \uD074\uB77C\uC774\uC5B8\uD2B8\uB3C4 \uC788\uC74C)\n * - \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uB04A\uC73C\uBA74 source.return() \uC73C\uB85C \uC81C\uB108\uB808\uC774\uD130\uB97C \uC885\uB8CC\uC2DC\uCF1C finally \uAC00 \uB3CC\uAC8C \uD55C\uB2E4\n */\n async resStream(source: Iterable<any> | AsyncIterable<any>, option: { compress?: boolean } = {}) {\n const res = this.res;\n const gz = option.compress !== false && this.reqHeaderFirst(HttpHeaders.AcceptEncoding)?.includes('gzip') ? createGzip() : undefined;\n if (gz) {\n res.setHeader(HttpHeaders.ContentEncoding, 'gzip');\n res.removeHeader(HttpHeaders.ContentLength);\n gz.pipe(res);\n }\n const out = gz ?? res;\n res.flushHeaders();\n let closed = false;\n const onClose = () => {\n closed = true;\n (source as any).return?.();\n };\n res.once('close', onClose);\n try {\n for await (const chunk of source) {\n if (closed) break;\n const data = typeof chunk === 'string' || Buffer.isBuffer(chunk) ? chunk : JSON.stringify(chunk);\n const ok = out.write(data);\n gz?.flush(zlibConstants.Z_SYNC_FLUSH);\n // backpressure: \uBC84\uD37C\uAC00 \uCC28\uBA74 drain(\uB610\uB294 \uC5F0\uACB0 \uC885\uB8CC)\uAE4C\uC9C0 \uB300\uAE30\n if (!ok) await new Promise(resolve => { out.once('drain', resolve); res.once('close', resolve); });\n }\n } catch (e) {\n // \uD074\uB77C\uC774\uC5B8\uD2B8\uAC00 \uB04A\uAE34 \uB4A4\uC758 \uC5D0\uB7EC(AbortSignal \uB85C \uB300\uAE30\uB97C \uD47C AbortError \uB4F1)\uB294 \uBC1B\uC744 \uC0C1\uB300\uAC00 \uC5C6\uC73C\uB2C8 \uC0BC\uD0A8\uB2E4\n if (!closed) throw e;\n } finally {\n res.off('close', onClose);\n if (closed) {\n gz?.destroy();\n } else if (!res.writableEnded) {\n // gzip \uC774\uBA74 gz.end() \u2192 pipe \uAC00 res.end() \uAE4C\uC9C0 \uD574\uC900\uB2E4. \uB05D\uAE4C\uC9C0 \uD758\uB824\uBCF4\uB0B8 \uB4A4 \uB9AC\uD134\n const finished = new Promise(resolve => { res.once('finish', resolve); res.once('close', resolve); });\n out.end();\n await finished;\n }\n }\n }\n\n resIsDone() {\n return this.res.finished || this.res.writableEnded || this.res.headersSent;\n }\n\n createRequestResponseChain<T = any>(data?: T) {\n const requestResponseChain = new RequestResponseChain(this.req, this.res, this.config, data);\n requestResponseChain.resWriteChunk = this.resWriteChunk;\n requestResponseChain.reqBodyChunk = this.reqBodyChunk;\n return requestResponseChain;\n }\n}\n\nexport class RequestResponseChain<T> extends RequestResponse {\n constructor(\n req: IncomingMessage,\n res: ServerResponse,\n config: Config,\n public result?: T\n ) {\n super(req, res, config);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|