@server/next 0.35.0 → 0.36.0
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 +16 -8
- package/index.js +142 -70
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -34,11 +34,13 @@ type BodyOption = BodyMode | {
|
|
|
34
34
|
mode?: BodyMode;
|
|
35
35
|
max?: number | string | false;
|
|
36
36
|
};
|
|
37
|
+
type CacheOption = string | number | false;
|
|
37
38
|
type RouteOptions = {
|
|
38
39
|
tags?: string | string[];
|
|
39
40
|
title?: string;
|
|
40
41
|
description?: string;
|
|
41
42
|
body?: BodyOption;
|
|
43
|
+
cache?: CacheOption;
|
|
42
44
|
};
|
|
43
45
|
type Route = {
|
|
44
46
|
path: string;
|
|
@@ -188,6 +190,7 @@ type Options = {
|
|
|
188
190
|
favicon?: string | BucketFile;
|
|
189
191
|
security?: boolean | SecurityOptions;
|
|
190
192
|
body?: BodyOption;
|
|
193
|
+
cache?: CacheOption;
|
|
191
194
|
};
|
|
192
195
|
type Settings = {
|
|
193
196
|
port: number;
|
|
@@ -207,6 +210,7 @@ type Settings = {
|
|
|
207
210
|
favicon?: string | BucketFile;
|
|
208
211
|
security: SecuritySettings;
|
|
209
212
|
body: BodyOption;
|
|
213
|
+
cache?: CacheOption;
|
|
210
214
|
};
|
|
211
215
|
type Time = {
|
|
212
216
|
(name: string): void;
|
|
@@ -230,7 +234,9 @@ type ParamsToObject<Params extends string> = {
|
|
|
230
234
|
};
|
|
231
235
|
type PathToParams<Path extends string> = ParamsToObject<ExtractPathParams<Path>>;
|
|
232
236
|
type BunEnv = Record<string, string> & {
|
|
233
|
-
upgrade?: (req: Request
|
|
237
|
+
upgrade?: (req: Request, options?: {
|
|
238
|
+
data?: any;
|
|
239
|
+
}) => boolean;
|
|
234
240
|
};
|
|
235
241
|
type Context<Params extends Record<string, string | undefined> = Record<string, string>, O extends ServerConfig = object> = {
|
|
236
242
|
method: Method;
|
|
@@ -343,6 +349,7 @@ declare class Reply {
|
|
|
343
349
|
type(type?: string): this;
|
|
344
350
|
download(name?: string): this;
|
|
345
351
|
headers(key: string | Record<string, string>, value?: string): this;
|
|
352
|
+
cache(value: CacheOption): this;
|
|
346
353
|
cookies(key: string | Record<string, CookieOptions>, value?: CookieOptions): this;
|
|
347
354
|
json(body: unknown): Response;
|
|
348
355
|
redirect(path: string): Response;
|
|
@@ -353,6 +360,7 @@ type Params<K extends keyof Reply> = Reply[K] extends (...args: infer A) => any
|
|
|
353
360
|
declare const status: (...args: Params<"status">) => Reply;
|
|
354
361
|
declare const headers: (...args: Params<"headers">) => Reply;
|
|
355
362
|
declare const type: (...args: Params<"type">) => Reply;
|
|
363
|
+
declare const cache: (...args: Params<"cache">) => Reply;
|
|
356
364
|
declare const download: (...args: Params<"download">) => Reply;
|
|
357
365
|
declare const cookies: (...args: Params<"cookies">) => Reply;
|
|
358
366
|
declare const send: (...args: Params<"send">) => Response;
|
|
@@ -407,9 +415,9 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
407
415
|
signal?: AbortSignal | null;
|
|
408
416
|
window?: null;
|
|
409
417
|
}) => Promise<Response>;
|
|
410
|
-
post: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
418
|
+
post: (path: string, body?: string | number | boolean | ArrayBuffer | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams | {
|
|
411
419
|
[key: string]: SerializableValue;
|
|
412
|
-
} | SerializableValue[]
|
|
420
|
+
} | SerializableValue[], options?: {
|
|
413
421
|
cache?: RequestCache;
|
|
414
422
|
credentials?: RequestCredentials;
|
|
415
423
|
headers?: HeadersInit;
|
|
@@ -424,9 +432,9 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
424
432
|
signal?: AbortSignal | null;
|
|
425
433
|
window?: null;
|
|
426
434
|
}) => Promise<Response>;
|
|
427
|
-
put: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
435
|
+
put: (path: string, body?: string | number | boolean | ArrayBuffer | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams | {
|
|
428
436
|
[key: string]: SerializableValue;
|
|
429
|
-
} | SerializableValue[]
|
|
437
|
+
} | SerializableValue[], options?: {
|
|
430
438
|
cache?: RequestCache;
|
|
431
439
|
credentials?: RequestCredentials;
|
|
432
440
|
headers?: HeadersInit;
|
|
@@ -441,9 +449,9 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
441
449
|
signal?: AbortSignal | null;
|
|
442
450
|
window?: null;
|
|
443
451
|
}) => Promise<Response>;
|
|
444
|
-
patch: (path: string, body?: string | number | boolean | ArrayBuffer | {
|
|
452
|
+
patch: (path: string, body?: string | number | boolean | ArrayBuffer | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams | {
|
|
445
453
|
[key: string]: SerializableValue;
|
|
446
|
-
} | SerializableValue[]
|
|
454
|
+
} | SerializableValue[], options?: {
|
|
447
455
|
cache?: RequestCache;
|
|
448
456
|
credentials?: RequestCredentials;
|
|
449
457
|
headers?: HeadersInit;
|
|
@@ -492,4 +500,4 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
|
|
|
492
500
|
}
|
|
493
501
|
declare function server<Session extends Record<string, any> = {}, User extends Record<string, any> = {}>(options?: Options): Server<ServerConfig<Session, User>>;
|
|
494
502
|
|
|
495
|
-
export { type AuthOption, type AuthSession, type AuthSettings, type AuthUser, type BasicValue, type Body, type BodyMode, type BodyOption, type Bucket, type BucketFile, type BunEnv, type Context, type Cookie, type CorsSettings, type ExtractPathParams, type FileInfo, type InferParamType, type InlineReply, type KVStore, type LimitOptions, type LogLevel, type Logger, type Method, type Middleware, type Options, type ParamTypeMap, type ParamsToObject, type PathToParams, type Platform, type Provider, type Route, type RouteOptions, type RouterMethod, type SecurityOptions, type SecuritySettings, type SerializableValue, Server, type ServerConfig, TypedServerError as ServerError, type Settings, type Strategy, type Time, UploadPipeline, type UploadedFile, cookies, server as default, download, file, headers, json, redirect, router, send, status, type, upload };
|
|
503
|
+
export { type AuthOption, type AuthSession, type AuthSettings, type AuthUser, type BasicValue, type Body, type BodyMode, type BodyOption, type Bucket, type BucketFile, type BunEnv, type CacheOption, type Context, type Cookie, type CorsSettings, type ExtractPathParams, type FileInfo, type InferParamType, type InlineReply, type KVStore, type LimitOptions, type LogLevel, type Logger, type Method, type Middleware, type Options, type ParamTypeMap, type ParamsToObject, type PathToParams, type Platform, type Provider, type Route, type RouteOptions, type RouterMethod, type SecurityOptions, type SecuritySettings, type SerializableValue, Server, type ServerConfig, TypedServerError as ServerError, type Settings, type Strategy, type Time, UploadPipeline, type UploadedFile, cache, cookies, server as default, download, file, headers, json, redirect, router, send, status, type, upload };
|
package/index.js
CHANGED
|
@@ -683,6 +683,97 @@ async function resolveBody(ctx, body) {
|
|
|
683
683
|
return parsed;
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
+
// src/helpers/createCookies.ts
|
|
687
|
+
var EXPIRED = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
688
|
+
var times = /(-?(?:\d+\.?\d*|\d*\.?\d+)(?:e[-+]?\d+)?)\s*([\p{L}]*)/iu;
|
|
689
|
+
parse.millisecond = parse.ms = 1e-3;
|
|
690
|
+
parse.second = parse.sec = parse.s = parse[""] = 1;
|
|
691
|
+
parse.minute = parse.min = parse.m = parse.s * 60;
|
|
692
|
+
parse.hour = parse.hr = parse.h = parse.m * 60;
|
|
693
|
+
parse.day = parse.d = parse.h * 24;
|
|
694
|
+
parse.week = parse.wk = parse.w = parse.d * 7;
|
|
695
|
+
parse.year = parse.yr = parse.y = parse.d * 365.25;
|
|
696
|
+
parse.month = parse.b = parse.y / 12;
|
|
697
|
+
function parse(str) {
|
|
698
|
+
if (str === null || str === void 0) return null;
|
|
699
|
+
if (typeof str === "number") return str;
|
|
700
|
+
if (typeof str !== "string") {
|
|
701
|
+
throw new Error(`Not a string: ${str} (${typeof str})`);
|
|
702
|
+
}
|
|
703
|
+
str = str.toLowerCase().replace(/[,_]/g, "");
|
|
704
|
+
const [_, value, units] = times.exec(str) || [];
|
|
705
|
+
if (!units) return null;
|
|
706
|
+
const unitValue = parse[units] || parse[units.replace(/s$/, "")];
|
|
707
|
+
if (!unitValue) return null;
|
|
708
|
+
const result = unitValue * parseFloat(value);
|
|
709
|
+
return Math.abs(Math.round(result * 1e3));
|
|
710
|
+
}
|
|
711
|
+
function normalizeExpires(expires) {
|
|
712
|
+
if (expires === null || expires === void 0) return void 0;
|
|
713
|
+
if (expires === 0) return EXPIRED;
|
|
714
|
+
if (typeof expires === "string") {
|
|
715
|
+
if (/^[\d._]+\w+$/.test(expires)) {
|
|
716
|
+
return new Date(Date.now() + parse(expires)).toUTCString();
|
|
717
|
+
} else {
|
|
718
|
+
return expires;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (typeof expires === "number") {
|
|
722
|
+
return new Date(Date.now() + expires).toUTCString();
|
|
723
|
+
}
|
|
724
|
+
if (expires instanceof Date) {
|
|
725
|
+
return expires.toUTCString();
|
|
726
|
+
}
|
|
727
|
+
return void 0;
|
|
728
|
+
}
|
|
729
|
+
function createCookies(key, val) {
|
|
730
|
+
if (val.value === null) val.expires = EXPIRED;
|
|
731
|
+
const { value, path: path2, expires, maxAge, httpOnly, secure, sameSite } = val;
|
|
732
|
+
let str = `${key}=${value || ""};Path=${path2 || "/"}`;
|
|
733
|
+
if (typeof expires !== "undefined") str += `;Expires=${normalizeExpires(expires)}`;
|
|
734
|
+
if (typeof maxAge === "number") str += `;Max-Age=${maxAge}`;
|
|
735
|
+
if (httpOnly) str += ";HttpOnly";
|
|
736
|
+
if (secure) str += ";Secure";
|
|
737
|
+
if (sameSite) str += `;SameSite=${sameSite}`;
|
|
738
|
+
return str;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// src/helpers/etag.ts
|
|
742
|
+
function etag(bytes) {
|
|
743
|
+
let h = 2166136261;
|
|
744
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
745
|
+
h ^= bytes[i];
|
|
746
|
+
h = Math.imul(h, 16777619);
|
|
747
|
+
}
|
|
748
|
+
return `"${bytes.length.toString(16)}-${(h >>> 0).toString(16)}"`;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// src/helpers/cache.ts
|
|
752
|
+
function resolveCache(value) {
|
|
753
|
+
if (value === false || value === 0) return "no-store";
|
|
754
|
+
if (typeof value === "number") return `public, max-age=${Math.round(value)}`;
|
|
755
|
+
if (typeof value !== "string") return null;
|
|
756
|
+
const ms = parse(value);
|
|
757
|
+
return ms === null ? null : `public, max-age=${Math.round(ms / 1e3)}`;
|
|
758
|
+
}
|
|
759
|
+
async function applyCache(out, ctx) {
|
|
760
|
+
if (ctx.method !== "get" || out.status !== 200) return out;
|
|
761
|
+
if (!out.headers.has("cache-control")) {
|
|
762
|
+
const value = resolveCache(ctx.options.cache);
|
|
763
|
+
if (value) out.headers.set("cache-control", value);
|
|
764
|
+
}
|
|
765
|
+
if (out.headers.has("etag") || !out.headers.has("content-length")) return out;
|
|
766
|
+
const bytes = new Uint8Array(await out.arrayBuffer());
|
|
767
|
+
const tag = etag(bytes);
|
|
768
|
+
const headers2 = new Headers(out.headers);
|
|
769
|
+
headers2.set("etag", tag);
|
|
770
|
+
if (ctx.headers["if-none-match"] === tag) {
|
|
771
|
+
headers2.delete("content-length");
|
|
772
|
+
return new Response(null, { status: 304, headers: headers2 });
|
|
773
|
+
}
|
|
774
|
+
return new Response(bytes, { status: 200, headers: headers2 });
|
|
775
|
+
}
|
|
776
|
+
|
|
686
777
|
// src/helpers/clientIp.ts
|
|
687
778
|
var first = (v) => (Array.isArray(v) ? v[0] : v) || "";
|
|
688
779
|
var normalize = (ip) => ip.replace(/^::ffff:/, "");
|
|
@@ -707,7 +798,7 @@ function isReadableStream(obj) {
|
|
|
707
798
|
}
|
|
708
799
|
|
|
709
800
|
// src/reply.ts
|
|
710
|
-
var
|
|
801
|
+
var EXPIRED2 = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
711
802
|
var Reply = class {
|
|
712
803
|
res;
|
|
713
804
|
constructor() {
|
|
@@ -743,6 +834,11 @@ var Reply = class {
|
|
|
743
834
|
this.res.headers.append(key, value);
|
|
744
835
|
return this;
|
|
745
836
|
}
|
|
837
|
+
cache(value) {
|
|
838
|
+
const resolved = resolveCache(value);
|
|
839
|
+
if (resolved) this.res.headers.set("cache-control", resolved);
|
|
840
|
+
return this;
|
|
841
|
+
}
|
|
746
842
|
cookies(key, value) {
|
|
747
843
|
if (typeof key === "object") {
|
|
748
844
|
Object.entries(key).map(([key2, value2]) => this.cookies(key2, value2));
|
|
@@ -752,7 +848,7 @@ var Reply = class {
|
|
|
752
848
|
Object.values(value).map((val) => this.cookies(key, val));
|
|
753
849
|
return this;
|
|
754
850
|
}
|
|
755
|
-
if (value === null) return this.cookies(key, { expires:
|
|
851
|
+
if (value === null) return this.cookies(key, { expires: EXPIRED2 });
|
|
756
852
|
if (typeof value !== "object") return this.cookies(key, { value });
|
|
757
853
|
return this.headers("set-cookie", createCookies(key, value));
|
|
758
854
|
}
|
|
@@ -822,6 +918,7 @@ var r = () => new Reply();
|
|
|
822
918
|
var status = (...args) => r().status(...args);
|
|
823
919
|
var headers = (...args) => r().headers(...args);
|
|
824
920
|
var type = (...args) => r().type(...args);
|
|
921
|
+
var cache = (...args) => r().cache(...args);
|
|
825
922
|
var download = (...args) => r().download(...args);
|
|
826
923
|
var cookies = (...args) => r().cookies(...args);
|
|
827
924
|
var send = (...args) => r().send(...args);
|
|
@@ -939,61 +1036,6 @@ async function finishLogin(ctx, input) {
|
|
|
939
1036
|
throw new Error("Unknown auth type");
|
|
940
1037
|
}
|
|
941
1038
|
|
|
942
|
-
// src/helpers/createCookies.ts
|
|
943
|
-
var EXPIRED2 = (/* @__PURE__ */ new Date(0)).toUTCString();
|
|
944
|
-
var times = /(-?(?:\d+\.?\d*|\d*\.?\d+)(?:e[-+]?\d+)?)\s*([\p{L}]*)/iu;
|
|
945
|
-
parse.millisecond = parse.ms = 1e-3;
|
|
946
|
-
parse.second = parse.sec = parse.s = parse[""] = 1;
|
|
947
|
-
parse.minute = parse.min = parse.m = parse.s * 60;
|
|
948
|
-
parse.hour = parse.hr = parse.h = parse.m * 60;
|
|
949
|
-
parse.day = parse.d = parse.h * 24;
|
|
950
|
-
parse.week = parse.wk = parse.w = parse.d * 7;
|
|
951
|
-
parse.year = parse.yr = parse.y = parse.d * 365.25;
|
|
952
|
-
parse.month = parse.b = parse.y / 12;
|
|
953
|
-
function parse(str) {
|
|
954
|
-
if (str === null || str === void 0) return null;
|
|
955
|
-
if (typeof str === "number") return str;
|
|
956
|
-
if (typeof str !== "string") {
|
|
957
|
-
throw new Error(`Not a string: ${str} (${typeof str})`);
|
|
958
|
-
}
|
|
959
|
-
str = str.toLowerCase().replace(/[,_]/g, "");
|
|
960
|
-
const [_, value, units] = times.exec(str) || [];
|
|
961
|
-
if (!units) return null;
|
|
962
|
-
const unitValue = parse[units] || parse[units.replace(/s$/, "")];
|
|
963
|
-
if (!unitValue) return null;
|
|
964
|
-
const result = unitValue * parseFloat(value);
|
|
965
|
-
return Math.abs(Math.round(result * 1e3));
|
|
966
|
-
}
|
|
967
|
-
function normalizeExpires(expires) {
|
|
968
|
-
if (expires === null || expires === void 0) return void 0;
|
|
969
|
-
if (expires === 0) return EXPIRED2;
|
|
970
|
-
if (typeof expires === "string") {
|
|
971
|
-
if (/^[\d._]+\w+$/.test(expires)) {
|
|
972
|
-
return new Date(Date.now() + parse(expires)).toUTCString();
|
|
973
|
-
} else {
|
|
974
|
-
return expires;
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
if (typeof expires === "number") {
|
|
978
|
-
return new Date(Date.now() + expires).toUTCString();
|
|
979
|
-
}
|
|
980
|
-
if (expires instanceof Date) {
|
|
981
|
-
return expires.toUTCString();
|
|
982
|
-
}
|
|
983
|
-
return void 0;
|
|
984
|
-
}
|
|
985
|
-
function createCookies(key, val) {
|
|
986
|
-
if (val.value === null) val.expires = EXPIRED2;
|
|
987
|
-
const { value, path: path2, expires, maxAge, httpOnly, secure, sameSite } = val;
|
|
988
|
-
let str = `${key}=${value || ""};Path=${path2 || "/"}`;
|
|
989
|
-
if (typeof expires !== "undefined") str += `;Expires=${normalizeExpires(expires)}`;
|
|
990
|
-
if (typeof maxAge === "number") str += `;Max-Age=${maxAge}`;
|
|
991
|
-
if (httpOnly) str += ";HttpOnly";
|
|
992
|
-
if (secure) str += ";Secure";
|
|
993
|
-
if (sameSite) str += `;SameSite=${sameSite}`;
|
|
994
|
-
return str;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
1039
|
// src/auth/state.ts
|
|
998
1040
|
var NAME = "oauth_state";
|
|
999
1041
|
function startState(ctx, crossSite = false) {
|
|
@@ -1606,6 +1648,7 @@ function config(options = {}) {
|
|
|
1606
1648
|
// the added headers off; see resolveSecurity for the defaults.
|
|
1607
1649
|
security: resolveSecurity(options.security)
|
|
1608
1650
|
};
|
|
1651
|
+
if (options.cache !== void 0) settings.cache = options.cache;
|
|
1609
1652
|
options.cors = options.cors || env2.CORS || null;
|
|
1610
1653
|
if (options.cors) {
|
|
1611
1654
|
const cors2 = {
|
|
@@ -1683,6 +1726,7 @@ function config(options = {}) {
|
|
|
1683
1726
|
log.message("cors", origin);
|
|
1684
1727
|
}
|
|
1685
1728
|
if (settings.favicon) log.message("favicon", loc(settings.favicon));
|
|
1729
|
+
if (settings.cache !== void 0) log.message("cache", loc(options.cache));
|
|
1686
1730
|
if (settings.openapi) log.message("openapi", settings.openapi.path || "/docs");
|
|
1687
1731
|
return settings;
|
|
1688
1732
|
}
|
|
@@ -1722,23 +1766,14 @@ function applyCors(res, ctx) {
|
|
|
1722
1766
|
}
|
|
1723
1767
|
}
|
|
1724
1768
|
|
|
1725
|
-
// src/helpers/etag.ts
|
|
1726
|
-
function etag(bytes) {
|
|
1727
|
-
let h = 2166136261;
|
|
1728
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
1729
|
-
h ^= bytes[i];
|
|
1730
|
-
h = Math.imul(h, 16777619);
|
|
1731
|
-
}
|
|
1732
|
-
return `"${bytes.length.toString(16)}-${(h >>> 0).toString(16)}"`;
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
1769
|
// src/helpers/createWebsocket.ts
|
|
1736
1770
|
function createWebsocket(sockets, handlers) {
|
|
1737
1771
|
const run = (event, socket, body) => {
|
|
1738
1772
|
const routes = handlers.socket?.filter((r2) => r2.path === event) ?? [];
|
|
1773
|
+
const user = socket.user ?? socket.data?.user;
|
|
1739
1774
|
for (const route of routes) {
|
|
1740
1775
|
for (const fn of route.fns) {
|
|
1741
|
-
fn({ socket, sockets, body });
|
|
1776
|
+
fn({ socket, sockets, body, user });
|
|
1742
1777
|
}
|
|
1743
1778
|
}
|
|
1744
1779
|
};
|
|
@@ -1845,6 +1880,7 @@ async function parseResponse(out, ctx) {
|
|
|
1845
1880
|
}
|
|
1846
1881
|
applyCors(out, ctx);
|
|
1847
1882
|
applySecurity(out, ctx);
|
|
1883
|
+
out = await applyCache(out, ctx);
|
|
1848
1884
|
if (ctx.time?.times?.length > 1) {
|
|
1849
1885
|
out.headers.set("Server-Timing", ctx.time.headers());
|
|
1850
1886
|
}
|
|
@@ -2632,6 +2668,13 @@ function timer(ctx) {
|
|
|
2632
2668
|
ctx.time = createTime();
|
|
2633
2669
|
}
|
|
2634
2670
|
|
|
2671
|
+
// src/auth/socketUser.ts
|
|
2672
|
+
async function socketUser(app, headers2, cookies2) {
|
|
2673
|
+
if (!app.settings.auth) return void 0;
|
|
2674
|
+
const ctx = { options: app.settings, headers: headers2, cookies: cookies2 };
|
|
2675
|
+
return getUser(ctx);
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2635
2678
|
// src/helpers/wsNode.ts
|
|
2636
2679
|
var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
|
2637
2680
|
var CONTINUATION = 0;
|
|
@@ -2666,6 +2709,9 @@ var NodeWebSocket = class {
|
|
|
2666
2709
|
fragmentOpcode;
|
|
2667
2710
|
closed;
|
|
2668
2711
|
readyState;
|
|
2712
|
+
// The auth user resolved from the upgrade request (see attachWebsocket), or
|
|
2713
|
+
// undefined for an anonymous connection. Read by socket handlers as `ctx.user`.
|
|
2714
|
+
user;
|
|
2669
2715
|
constructor(socket, handlers) {
|
|
2670
2716
|
this.socket = socket;
|
|
2671
2717
|
this.handlers = handlers;
|
|
@@ -2764,13 +2810,24 @@ var NodeWebSocket = class {
|
|
|
2764
2810
|
};
|
|
2765
2811
|
async function attachWebsocket(server2, app) {
|
|
2766
2812
|
const { createHash } = await import("crypto");
|
|
2767
|
-
server2.on("upgrade", (req, socket, head) => {
|
|
2813
|
+
server2.on("upgrade", async (req, socket, head) => {
|
|
2768
2814
|
const key = req.headers["sec-websocket-key"];
|
|
2769
2815
|
const upgrade = String(req.headers.upgrade || "").toLowerCase();
|
|
2770
2816
|
if (upgrade !== "websocket" || !key || !app.handlers.socket.length) {
|
|
2771
2817
|
socket.destroy();
|
|
2772
2818
|
return;
|
|
2773
2819
|
}
|
|
2820
|
+
const cookies2 = parseCookies(req.headers.cookie);
|
|
2821
|
+
let user;
|
|
2822
|
+
try {
|
|
2823
|
+
user = await socketUser(app, req.headers, cookies2);
|
|
2824
|
+
} catch {
|
|
2825
|
+
socket.write(
|
|
2826
|
+
"HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
|
|
2827
|
+
);
|
|
2828
|
+
socket.destroy();
|
|
2829
|
+
return;
|
|
2830
|
+
}
|
|
2774
2831
|
const accept = createHash("sha1").update(key + GUID).digest("base64");
|
|
2775
2832
|
socket.write(
|
|
2776
2833
|
`HTTP/1.1 101 Switching Protocols\r
|
|
@@ -2786,6 +2843,7 @@ Sec-WebSocket-Accept: ${accept}\r
|
|
|
2786
2843
|
onMessage: (body) => app.websocket.message(ws, body),
|
|
2787
2844
|
onClose: () => app.websocket.close(ws)
|
|
2788
2845
|
});
|
|
2846
|
+
ws.user = user;
|
|
2789
2847
|
app.websocket.open(ws);
|
|
2790
2848
|
if (head?.length) ws.receive(head);
|
|
2791
2849
|
socket.on("data", (chunk) => ws.receive(chunk));
|
|
@@ -2902,7 +2960,20 @@ async function createWinter(req, app, server2) {
|
|
|
2902
2960
|
|
|
2903
2961
|
// src/context/handlers.ts
|
|
2904
2962
|
var Winter = async (app, request, env2) => {
|
|
2905
|
-
if (env2?.upgrade
|
|
2963
|
+
if (env2?.upgrade) {
|
|
2964
|
+
const wantsWs = String(request.headers.get("upgrade") || "").toLowerCase() === "websocket";
|
|
2965
|
+
if (wantsWs) {
|
|
2966
|
+
const headers2 = parseHeaders_default(request.headers);
|
|
2967
|
+
const cookies2 = parseCookies(headers2.cookie);
|
|
2968
|
+
let user;
|
|
2969
|
+
try {
|
|
2970
|
+
user = await socketUser(app, headers2, cookies2);
|
|
2971
|
+
} catch {
|
|
2972
|
+
return new Response("Unauthorized", { status: 401 });
|
|
2973
|
+
}
|
|
2974
|
+
if (env2.upgrade(request, { data: { user } })) return;
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2906
2977
|
Object.assign(globalThis.env, env2);
|
|
2907
2978
|
const ctx = await createWinter(request, app, env2);
|
|
2908
2979
|
const res = await handleRequest(app, ctx);
|
|
@@ -3137,6 +3208,7 @@ function server(options) {
|
|
|
3137
3208
|
export {
|
|
3138
3209
|
Server,
|
|
3139
3210
|
ServerError_default as ServerError,
|
|
3211
|
+
cache,
|
|
3140
3212
|
cookies,
|
|
3141
3213
|
server as default,
|
|
3142
3214
|
download,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@server/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
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",
|