@server/next 0.35.0 → 0.35.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.
Files changed (3) hide show
  1. package/index.d.ts +9 -7
  2. package/index.js +39 -3
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -230,7 +230,9 @@ type ParamsToObject<Params extends string> = {
230
230
  };
231
231
  type PathToParams<Path extends string> = ParamsToObject<ExtractPathParams<Path>>;
232
232
  type BunEnv = Record<string, string> & {
233
- upgrade?: (req: Request) => boolean;
233
+ upgrade?: (req: Request, options?: {
234
+ data?: any;
235
+ }) => boolean;
234
236
  };
235
237
  type Context<Params extends Record<string, string | undefined> = Record<string, string>, O extends ServerConfig = object> = {
236
238
  method: Method;
@@ -407,9 +409,9 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
407
409
  signal?: AbortSignal | null;
408
410
  window?: null;
409
411
  }) => Promise<Response>;
410
- post: (path: string, body?: string | number | boolean | ArrayBuffer | {
412
+ post: (path: string, body?: string | number | boolean | ArrayBuffer | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams | {
411
413
  [key: string]: SerializableValue;
412
- } | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
414
+ } | SerializableValue[], options?: {
413
415
  cache?: RequestCache;
414
416
  credentials?: RequestCredentials;
415
417
  headers?: HeadersInit;
@@ -424,9 +426,9 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
424
426
  signal?: AbortSignal | null;
425
427
  window?: null;
426
428
  }) => Promise<Response>;
427
- put: (path: string, body?: string | number | boolean | ArrayBuffer | {
429
+ put: (path: string, body?: string | number | boolean | ArrayBuffer | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams | {
428
430
  [key: string]: SerializableValue;
429
- } | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
431
+ } | SerializableValue[], options?: {
430
432
  cache?: RequestCache;
431
433
  credentials?: RequestCredentials;
432
434
  headers?: HeadersInit;
@@ -441,9 +443,9 @@ declare class Server<O extends ServerConfig = {}> extends Router<O> {
441
443
  signal?: AbortSignal | null;
442
444
  window?: null;
443
445
  }) => Promise<Response>;
444
- patch: (path: string, body?: string | number | boolean | ArrayBuffer | {
446
+ patch: (path: string, body?: string | number | boolean | ArrayBuffer | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams | {
445
447
  [key: string]: SerializableValue;
446
- } | SerializableValue[] | ReadableStream<any> | Blob | ArrayBufferView<ArrayBuffer> | FormData | URLSearchParams, options?: {
448
+ } | SerializableValue[], options?: {
447
449
  cache?: RequestCache;
448
450
  credentials?: RequestCredentials;
449
451
  headers?: HeadersInit;
package/index.js CHANGED
@@ -1736,9 +1736,10 @@ function etag(bytes) {
1736
1736
  function createWebsocket(sockets, handlers) {
1737
1737
  const run = (event, socket, body) => {
1738
1738
  const routes = handlers.socket?.filter((r2) => r2.path === event) ?? [];
1739
+ const user = socket.user ?? socket.data?.user;
1739
1740
  for (const route of routes) {
1740
1741
  for (const fn of route.fns) {
1741
- fn({ socket, sockets, body });
1742
+ fn({ socket, sockets, body, user });
1742
1743
  }
1743
1744
  }
1744
1745
  };
@@ -2632,6 +2633,13 @@ function timer(ctx) {
2632
2633
  ctx.time = createTime();
2633
2634
  }
2634
2635
 
2636
+ // src/auth/socketUser.ts
2637
+ async function socketUser(app, headers2, cookies2) {
2638
+ if (!app.settings.auth) return void 0;
2639
+ const ctx = { options: app.settings, headers: headers2, cookies: cookies2 };
2640
+ return getUser(ctx);
2641
+ }
2642
+
2635
2643
  // src/helpers/wsNode.ts
2636
2644
  var GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2637
2645
  var CONTINUATION = 0;
@@ -2666,6 +2674,9 @@ var NodeWebSocket = class {
2666
2674
  fragmentOpcode;
2667
2675
  closed;
2668
2676
  readyState;
2677
+ // The auth user resolved from the upgrade request (see attachWebsocket), or
2678
+ // undefined for an anonymous connection. Read by socket handlers as `ctx.user`.
2679
+ user;
2669
2680
  constructor(socket, handlers) {
2670
2681
  this.socket = socket;
2671
2682
  this.handlers = handlers;
@@ -2764,13 +2775,24 @@ var NodeWebSocket = class {
2764
2775
  };
2765
2776
  async function attachWebsocket(server2, app) {
2766
2777
  const { createHash } = await import("crypto");
2767
- server2.on("upgrade", (req, socket, head) => {
2778
+ server2.on("upgrade", async (req, socket, head) => {
2768
2779
  const key = req.headers["sec-websocket-key"];
2769
2780
  const upgrade = String(req.headers.upgrade || "").toLowerCase();
2770
2781
  if (upgrade !== "websocket" || !key || !app.handlers.socket.length) {
2771
2782
  socket.destroy();
2772
2783
  return;
2773
2784
  }
2785
+ const cookies2 = parseCookies(req.headers.cookie);
2786
+ let user;
2787
+ try {
2788
+ user = await socketUser(app, req.headers, cookies2);
2789
+ } catch {
2790
+ socket.write(
2791
+ "HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n"
2792
+ );
2793
+ socket.destroy();
2794
+ return;
2795
+ }
2774
2796
  const accept = createHash("sha1").update(key + GUID).digest("base64");
2775
2797
  socket.write(
2776
2798
  `HTTP/1.1 101 Switching Protocols\r
@@ -2786,6 +2808,7 @@ Sec-WebSocket-Accept: ${accept}\r
2786
2808
  onMessage: (body) => app.websocket.message(ws, body),
2787
2809
  onClose: () => app.websocket.close(ws)
2788
2810
  });
2811
+ ws.user = user;
2789
2812
  app.websocket.open(ws);
2790
2813
  if (head?.length) ws.receive(head);
2791
2814
  socket.on("data", (chunk) => ws.receive(chunk));
@@ -2902,7 +2925,20 @@ async function createWinter(req, app, server2) {
2902
2925
 
2903
2926
  // src/context/handlers.ts
2904
2927
  var Winter = async (app, request, env2) => {
2905
- if (env2?.upgrade(request)) return;
2928
+ if (env2?.upgrade) {
2929
+ const wantsWs = String(request.headers.get("upgrade") || "").toLowerCase() === "websocket";
2930
+ if (wantsWs) {
2931
+ const headers2 = parseHeaders_default(request.headers);
2932
+ const cookies2 = parseCookies(headers2.cookie);
2933
+ let user;
2934
+ try {
2935
+ user = await socketUser(app, headers2, cookies2);
2936
+ } catch {
2937
+ return new Response("Unauthorized", { status: 401 });
2938
+ }
2939
+ if (env2.upgrade(request, { data: { user } })) return;
2940
+ }
2941
+ }
2906
2942
  Object.assign(globalThis.env, env2);
2907
2943
  const ctx = await createWinter(request, app, env2);
2908
2944
  const res = await handleRequest(app, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@server/next",
3
- "version": "0.35.0",
3
+ "version": "0.35.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",