@server/next 0.33.0 → 0.34.1
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/index.d.ts +15 -2
- package/index.js +63 -21
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
|
|
1
3
|
type LimitOptions = {
|
|
2
4
|
maxSize?: number | string;
|
|
3
5
|
minSize?: number | string;
|
|
@@ -129,9 +131,20 @@ type Logger = {
|
|
|
129
131
|
};
|
|
130
132
|
type SecurityOptions = {
|
|
131
133
|
trustProxy?: boolean;
|
|
134
|
+
frameguard?: boolean | string;
|
|
135
|
+
noSniff?: boolean;
|
|
136
|
+
referrerPolicy?: boolean | string;
|
|
137
|
+
hsts?: boolean | string;
|
|
138
|
+
xssProtection?: boolean;
|
|
139
|
+
csp?: boolean | string;
|
|
140
|
+
coop?: boolean | string;
|
|
141
|
+
corp?: boolean | string;
|
|
142
|
+
permissionsPolicy?: string;
|
|
132
143
|
};
|
|
133
144
|
type SecuritySettings = {
|
|
134
145
|
trustProxy: boolean;
|
|
146
|
+
headers: Record<string, string>;
|
|
147
|
+
hsts: string | null;
|
|
135
148
|
};
|
|
136
149
|
type OnError = (error: Error, ctx: Context) => Response | Promise<Response>;
|
|
137
150
|
type Options = {
|
|
@@ -150,7 +163,7 @@ type Options = {
|
|
|
150
163
|
onError?: OnError;
|
|
151
164
|
log?: LogLevel | boolean;
|
|
152
165
|
favicon?: string | Bucket;
|
|
153
|
-
security?: SecurityOptions;
|
|
166
|
+
security?: boolean | SecurityOptions;
|
|
154
167
|
body?: BodyMode;
|
|
155
168
|
};
|
|
156
169
|
type Settings = {
|
|
@@ -332,7 +345,7 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
332
345
|
port?: number;
|
|
333
346
|
constructor(options?: Options);
|
|
334
347
|
self(): this;
|
|
335
|
-
node(): Promise<
|
|
348
|
+
node(): Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>>;
|
|
336
349
|
fetch(request: Request, env?: BunEnv): Promise<Response>;
|
|
337
350
|
callback(request: Request, context: unknown): Promise<Response>;
|
|
338
351
|
test(): {
|
package/index.js
CHANGED
|
@@ -1358,6 +1358,47 @@ function createLogger(level) {
|
|
|
1358
1358
|
};
|
|
1359
1359
|
}
|
|
1360
1360
|
|
|
1361
|
+
// src/helpers/security.ts
|
|
1362
|
+
function resolveSecurity(security) {
|
|
1363
|
+
const off = security === false;
|
|
1364
|
+
const o = security && typeof security === "object" ? security : {};
|
|
1365
|
+
const val = (v, def) => v === false ? null : v === true || v == null ? def : v;
|
|
1366
|
+
const map2 = off ? {} : {
|
|
1367
|
+
"x-frame-options": val(o.frameguard, "SAMEORIGIN"),
|
|
1368
|
+
"x-content-type-options": o.noSniff === false ? null : "nosniff",
|
|
1369
|
+
"referrer-policy": val(
|
|
1370
|
+
o.referrerPolicy,
|
|
1371
|
+
"strict-origin-when-cross-origin"
|
|
1372
|
+
),
|
|
1373
|
+
"x-xss-protection": o.xssProtection === false ? null : "0",
|
|
1374
|
+
// Opt-in: default off
|
|
1375
|
+
"content-security-policy": val(o.csp, null),
|
|
1376
|
+
"cross-origin-opener-policy": val(o.coop, null),
|
|
1377
|
+
"cross-origin-resource-policy": val(o.corp, null),
|
|
1378
|
+
"permissions-policy": o.permissionsPolicy ?? null
|
|
1379
|
+
};
|
|
1380
|
+
const headers2 = {};
|
|
1381
|
+
for (const key in map2) {
|
|
1382
|
+
const value = map2[key];
|
|
1383
|
+
if (value) headers2[key] = value;
|
|
1384
|
+
}
|
|
1385
|
+
return {
|
|
1386
|
+
trustProxy: o.trustProxy ?? true,
|
|
1387
|
+
headers: headers2,
|
|
1388
|
+
hsts: off ? null : val(o.hsts, "max-age=15552000; includeSubDomains")
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
function applySecurity(res, ctx) {
|
|
1392
|
+
const security = ctx.options.security;
|
|
1393
|
+
if (!security) return;
|
|
1394
|
+
for (const key in security.headers) {
|
|
1395
|
+
if (!res.headers.has(key)) res.headers.set(key, security.headers[key]);
|
|
1396
|
+
}
|
|
1397
|
+
if (security.hsts && ctx.platform.production && !res.headers.has("strict-transport-security")) {
|
|
1398
|
+
res.headers.set("strict-transport-security", security.hsts);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1361
1402
|
// src/helpers/config.ts
|
|
1362
1403
|
function config(options = {}) {
|
|
1363
1404
|
const env2 = globalThis.env;
|
|
@@ -1371,11 +1412,9 @@ function config(options = {}) {
|
|
|
1371
1412
|
// How request bodies are read: parsed into ctx.body by default; `raw` keeps
|
|
1372
1413
|
// the Buffer, `stream` hands the handler the unread web ReadableStream.
|
|
1373
1414
|
body: options.body ?? "parse",
|
|
1374
|
-
//
|
|
1375
|
-
//
|
|
1376
|
-
security:
|
|
1377
|
-
trustProxy: options.security?.trustProxy ?? true
|
|
1378
|
-
}
|
|
1415
|
+
// Secure-by-default response headers + trustProxy for ctx.ip. `false` turns
|
|
1416
|
+
// the added headers off; see resolveSecurity for the defaults.
|
|
1417
|
+
security: resolveSecurity(options.security)
|
|
1379
1418
|
};
|
|
1380
1419
|
options.cors = options.cors || env2.CORS || null;
|
|
1381
1420
|
if (options.cors) {
|
|
@@ -1600,6 +1639,7 @@ async function parseResponse(out, ctx) {
|
|
|
1600
1639
|
throw new Error(`Invalid response type ${out}`);
|
|
1601
1640
|
}
|
|
1602
1641
|
applyCors(out, ctx);
|
|
1642
|
+
applySecurity(out, ctx);
|
|
1603
1643
|
if (ctx.time?.times?.length > 1) {
|
|
1604
1644
|
out.headers.set("Server-Timing", ctx.time.headers());
|
|
1605
1645
|
}
|
|
@@ -1756,6 +1796,7 @@ async function getResponse(app, ctx) {
|
|
|
1756
1796
|
} catch (error) {
|
|
1757
1797
|
const res = await ctx.options.onError(error, ctx);
|
|
1758
1798
|
applyCors(res, ctx);
|
|
1799
|
+
applySecurity(res, ctx);
|
|
1759
1800
|
return res;
|
|
1760
1801
|
}
|
|
1761
1802
|
}
|
|
@@ -2484,25 +2525,26 @@ var Winter = async (app, request, env2) => {
|
|
|
2484
2525
|
};
|
|
2485
2526
|
var Node = async (app) => {
|
|
2486
2527
|
const http = await import("http");
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2528
|
+
const { attachWebsocket } = await import("./wsNode-GEJUCJQ7.js");
|
|
2529
|
+
const server2 = http.createServer(
|
|
2530
|
+
async (request, response) => {
|
|
2531
|
+
const ctx = await createNode(request, app);
|
|
2532
|
+
if ("error" in ctx) throw ctx.error;
|
|
2533
|
+
const out = await handleRequest(app, ctx);
|
|
2534
|
+
response.writeHead(out.status || 200, parseHeaders_default(out.headers));
|
|
2535
|
+
if (out.body instanceof ReadableStream) {
|
|
2536
|
+
await iterate(out.body, (chunk) => response.write(chunk));
|
|
2537
|
+
} else {
|
|
2538
|
+
response.write(out.body || "");
|
|
2539
|
+
}
|
|
2540
|
+
response.end();
|
|
2496
2541
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2542
|
+
);
|
|
2543
|
+
attachWebsocket(server2, app);
|
|
2544
|
+
server2.listen(app.settings.port, () => {
|
|
2499
2545
|
app.settings.log.start(`http://localhost:${app.settings.port}/`);
|
|
2500
|
-
if (app.handlers.socket.length) {
|
|
2501
|
-
console.warn(
|
|
2502
|
-
"[server] WebSockets (.socket()) are only supported on Bun, not Node"
|
|
2503
|
-
);
|
|
2504
|
-
}
|
|
2505
2546
|
});
|
|
2547
|
+
return server2;
|
|
2506
2548
|
};
|
|
2507
2549
|
var Netlify = async (app, request, context) => {
|
|
2508
2550
|
request.context = context;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "A fully-fledged web server with routing, file uploads, sessions, static files, schema validation, websockets, testing, etc.",
|
|
5
5
|
"homepage": "https://server-js.com/",
|
|
6
6
|
"repository": "github:franciscop/server-next",
|