nukejs 0.0.19 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-common.js +37 -15
- package/dist/http-server.js +25 -22
- package/package.json +1 -1
package/dist/build-common.js
CHANGED
|
@@ -225,7 +225,9 @@ function makeApiAdapterSource(handlerFilename) {
|
|
|
225
225
|
return `import type { IncomingMessage, ServerResponse } from 'http';
|
|
226
226
|
import * as mod from ${JSON.stringify("./" + handlerFilename)};
|
|
227
227
|
|
|
228
|
-
|
|
228
|
+
const MAX_BODY_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
229
|
+
|
|
230
|
+
function enhanceRes(res: ServerResponse) {
|
|
229
231
|
(res as any).json = function (data: any, status = 200) {
|
|
230
232
|
this.statusCode = status;
|
|
231
233
|
this.setHeader('Content-Type', 'application/json');
|
|
@@ -235,26 +237,46 @@ function enhance(res: ServerResponse) {
|
|
|
235
237
|
return res;
|
|
236
238
|
}
|
|
237
239
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
240
|
+
function enhanceReq(req: IncomingMessage) {
|
|
241
|
+
const apiReq = req as any;
|
|
242
|
+
let bufferPromise: Promise<Buffer> | null = null;
|
|
243
|
+
|
|
244
|
+
const getBuffer = (): Promise<Buffer> => {
|
|
245
|
+
if (!bufferPromise) {
|
|
246
|
+
bufferPromise = new Promise((resolve, reject) => {
|
|
247
|
+
const chunks: Buffer[] = [];
|
|
248
|
+
let bytes = 0;
|
|
249
|
+
req.on('data', (chunk: Buffer) => {
|
|
250
|
+
bytes += chunk.length;
|
|
251
|
+
if (bytes > MAX_BODY_BYTES) { req.destroy(); return reject(new Error('Request body too large')); }
|
|
252
|
+
chunks.push(chunk);
|
|
253
|
+
});
|
|
254
|
+
req.on('end', () => resolve(Buffer.concat(chunks)));
|
|
255
|
+
req.on('error', reject);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return bufferPromise;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
apiReq.buffer = () => getBuffer();
|
|
262
|
+
apiReq.text = () => getBuffer().then(buf => buf.toString('utf8'));
|
|
263
|
+
apiReq.json = () => getBuffer().then(buf => {
|
|
264
|
+
const parsed = JSON.parse(buf.toString('utf8'));
|
|
265
|
+
if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
266
|
+
delete parsed.__proto__;
|
|
267
|
+
delete parsed.constructor;
|
|
268
|
+
}
|
|
269
|
+
return parsed;
|
|
249
270
|
});
|
|
271
|
+
|
|
272
|
+
return apiReq;
|
|
250
273
|
}
|
|
251
274
|
|
|
252
275
|
export default async function handler(req: IncomingMessage, res: ServerResponse) {
|
|
253
276
|
const method = (req.method || 'GET').toUpperCase();
|
|
254
|
-
const apiRes =
|
|
255
|
-
const apiReq = req
|
|
277
|
+
const apiRes = enhanceRes(res);
|
|
278
|
+
const apiReq = enhanceReq(req);
|
|
256
279
|
|
|
257
|
-
apiReq.body = await parseBody(req);
|
|
258
280
|
// In production, route dynamic segments are injected as query-string keys by
|
|
259
281
|
// the server entry, so params and query share the same parsed URL values.
|
|
260
282
|
const qs = Object.fromEntries(new URL(req.url || '/', 'http://localhost').searchParams);
|
package/dist/http-server.js
CHANGED
|
@@ -31,9 +31,9 @@ function discoverApiPrefixes(serverDir) {
|
|
|
31
31
|
return prefixes;
|
|
32
32
|
}
|
|
33
33
|
const MAX_BODY_BYTES = 10 * 1024 * 1024;
|
|
34
|
-
|
|
34
|
+
function collectBuffer(req) {
|
|
35
35
|
return new Promise((resolve, reject) => {
|
|
36
|
-
|
|
36
|
+
const chunks = [];
|
|
37
37
|
let bytes = 0;
|
|
38
38
|
req.on("data", (chunk) => {
|
|
39
39
|
bytes += chunk.length;
|
|
@@ -41,27 +41,31 @@ async function parseBody(req) {
|
|
|
41
41
|
req.destroy();
|
|
42
42
|
return reject(new Error("Request body too large"));
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
});
|
|
46
|
-
req.on("end", () => {
|
|
47
|
-
try {
|
|
48
|
-
if (body && req.headers["content-type"]?.includes("application/json")) {
|
|
49
|
-
const parsed = JSON.parse(body);
|
|
50
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
51
|
-
delete parsed.__proto__;
|
|
52
|
-
delete parsed.constructor;
|
|
53
|
-
}
|
|
54
|
-
resolve(parsed);
|
|
55
|
-
} else {
|
|
56
|
-
resolve(body);
|
|
57
|
-
}
|
|
58
|
-
} catch (err) {
|
|
59
|
-
reject(err);
|
|
60
|
-
}
|
|
44
|
+
chunks.push(chunk);
|
|
61
45
|
});
|
|
46
|
+
req.on("end", () => resolve(Buffer.concat(chunks)));
|
|
62
47
|
req.on("error", reject);
|
|
63
48
|
});
|
|
64
49
|
}
|
|
50
|
+
function enhanceRequest(req) {
|
|
51
|
+
const apiReq = req;
|
|
52
|
+
let bufferPromise = null;
|
|
53
|
+
const getBuffer = () => {
|
|
54
|
+
if (!bufferPromise) bufferPromise = collectBuffer(req);
|
|
55
|
+
return bufferPromise;
|
|
56
|
+
};
|
|
57
|
+
apiReq.buffer = () => getBuffer();
|
|
58
|
+
apiReq.text = () => getBuffer().then((buf) => buf.toString("utf8"));
|
|
59
|
+
apiReq.json = () => getBuffer().then((buf) => {
|
|
60
|
+
const parsed = JSON.parse(buf.toString("utf8"));
|
|
61
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
62
|
+
delete parsed.__proto__;
|
|
63
|
+
delete parsed.constructor;
|
|
64
|
+
}
|
|
65
|
+
return parsed;
|
|
66
|
+
});
|
|
67
|
+
return apiReq;
|
|
68
|
+
}
|
|
65
69
|
function parseQuery(url, port) {
|
|
66
70
|
const query = {};
|
|
67
71
|
new URL(url, `http://localhost:${port}`).searchParams.forEach((v, k) => {
|
|
@@ -145,8 +149,7 @@ function createApiHandler({ apiPrefixes, port, isDev }) {
|
|
|
145
149
|
respondOptions(apiRes);
|
|
146
150
|
return;
|
|
147
151
|
}
|
|
148
|
-
const apiReq = req;
|
|
149
|
-
apiReq.body = await parseBody(req);
|
|
152
|
+
const apiReq = enhanceRequest(req);
|
|
150
153
|
apiReq.params = params;
|
|
151
154
|
apiReq.query = parseQuery(url, port);
|
|
152
155
|
const apiModule = isDev ? await importFreshInDev(filePath) : await import(pathToFileURL(filePath).href);
|
|
@@ -165,8 +168,8 @@ function createApiHandler({ apiPrefixes, port, isDev }) {
|
|
|
165
168
|
export {
|
|
166
169
|
createApiHandler,
|
|
167
170
|
discoverApiPrefixes,
|
|
171
|
+
enhanceRequest,
|
|
168
172
|
enhanceResponse,
|
|
169
173
|
matchApiPrefix,
|
|
170
|
-
parseBody,
|
|
171
174
|
parseQuery
|
|
172
175
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nukejs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"description": "A minimal, opinionated full-stack React framework on Node.js that server-renders everything and hydrates only interactive parts.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|