@remix-run/session-middleware 0.3.4 → 0.4.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/README.md CHANGED
@@ -24,7 +24,6 @@ import { session } from 'remix/middleware/session'
24
24
 
25
25
  let sessionCookie = createCookie('__session', {
26
26
  secrets: ['s3cr3t'], // session cookies must be signed!
27
- httpOnly: true,
28
27
  secure: true,
29
28
  sameSite: 'lax',
30
29
  })
@@ -50,21 +49,24 @@ The middleware:
50
49
  Use `context.session` (or `context.get(Session)`) for normal session reads and writes.
51
50
 
52
51
  Note: The session cookie must be signed for security. This prevents tampering with the session data on the client.
52
+ Session cookies are HTTP-only by default.
53
53
 
54
54
  ### Login/Logout Flow
55
55
 
56
56
  A basic login/logout flow could look like this:
57
57
 
58
58
  ```ts
59
- import * as res from 'remix/router/response-helpers'
59
+ import { html } from 'remix/html-template'
60
+ import { createHtmlResponse } from 'remix/response/html'
61
+ import { redirect } from 'remix/response/redirect'
60
62
 
61
63
  router.get('/login', ({ session }) => {
62
64
  let error = session.get('error')
63
- return res.html(`
65
+ return createHtmlResponse(html`
64
66
  <html>
65
67
  <body>
66
68
  <h1>Login</h1>
67
- ${typeof error === 'string' ? <div class="error">${error}</div> : null}
69
+ ${typeof error === 'string' ? html`<div class="error">${error}</div>` : null}
68
70
  <form method="POST" action="/login">
69
71
  <input type="text" name="username" placeholder="Username" />
70
72
  <input type="password" name="password" placeholder="Password" />
@@ -83,18 +85,18 @@ router.post('/login', ({ get, session }) => {
83
85
  let user = authenticateUser(username, password)
84
86
  if (!user) {
85
87
  session.flash('error', 'Invalid username or password')
86
- return res.redirect('/login')
88
+ return redirect('/login')
87
89
  }
88
90
 
89
91
  session.regenerateId()
90
92
  session.set('userId', user.id)
91
93
 
92
- return res.redirect('/dashboard')
94
+ return redirect('/dashboard')
93
95
  })
94
96
 
95
97
  router.post('/logout', ({ session }) => {
96
98
  session.destroy()
97
- return res.redirect('/')
99
+ return redirect('/')
98
100
  })
99
101
  ```
100
102
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { session } from "./lib/session.js";
1
+ export { session } from './lib/session.js';
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/lib/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEjE;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,cAAc,GAC7B,UAAU,CAAC;IAAE,GAAG,EAAE,OAAO,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC,CA8B1E"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/lib/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEjE;;;;;;GAMG;AACH,wBAAgB,OAAO,CACrB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,cAAc,GAC7B,UAAU,CAAC;IAAE,GAAG,EAAE,OAAO,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC,CAyC1E"}
@@ -10,6 +10,9 @@ export function session(sessionCookie, sessionStorage) {
10
10
  if (!sessionCookie.signed) {
11
11
  throw new Error('Session cookie must be signed');
12
12
  }
13
+ if (sessionCookie.httpOnly === false) {
14
+ console.warn(`Session cookie "${sessionCookie.name}" is configured with httpOnly: false and may be accessible to client-side JavaScript.`);
15
+ }
13
16
  return async (context, next) => {
14
17
  if (context.has(Session)) {
15
18
  throw new Error('Existing session found, refusing to overwrite');
@@ -25,7 +28,9 @@ export function session(sessionCookie, sessionStorage) {
25
28
  if (setCookieValue != null) {
26
29
  // make sure the response is mutable
27
30
  response = new Response(response.body, response);
28
- response.headers.append('Set-Cookie', await sessionCookie.serialize(setCookieValue));
31
+ response.headers.append('Set-Cookie', await sessionCookie.serialize(setCookieValue, {
32
+ httpOnly: sessionCookie.httpOnly ?? true,
33
+ }));
29
34
  }
30
35
  return response;
31
36
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/session-middleware",
3
- "version": "0.3.4",
3
+ "version": "0.4.1",
4
4
  "description": "Middleware for managing sessions with cookie-based storage",
5
5
  "author": "Michael Jackson <mjijackson@gmail.com>",
6
6
  "license": "MIT",
@@ -27,18 +27,18 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^24.6.0",
30
- "@typescript/native-preview": "7.0.0-dev.20251125.1",
30
+ "typescript": "^7.0.2",
31
31
  "@remix-run/assert": "0.3.0",
32
- "@remix-run/cookie": "0.5.4",
32
+ "@remix-run/cookie": "0.6.0",
33
+ "@remix-run/fetch-router": "0.22.0",
33
34
  "@remix-run/headers": "0.21.1",
34
- "@remix-run/fetch-router": "0.20.1",
35
- "@remix-run/test": "0.5.0",
36
- "@remix-run/session": "0.4.2"
35
+ "@remix-run/session": "0.4.2",
36
+ "@remix-run/test": "0.6.0"
37
37
  },
38
38
  "dependencies": {
39
+ "@remix-run/cookie": "^0.6.0",
39
40
  "@remix-run/session": "^0.4.2",
40
- "@remix-run/fetch-router": "^0.20.1",
41
- "@remix-run/cookie": "^0.5.4"
41
+ "@remix-run/fetch-router": "^0.22.0"
42
42
  },
43
43
  "keywords": [
44
44
  "fetch",
@@ -49,10 +49,10 @@
49
49
  "session-management"
50
50
  ],
51
51
  "scripts": {
52
- "build": "tsgo -p tsconfig.build.json",
52
+ "build": "tsc -p tsconfig.build.json",
53
53
  "clean": "git clean -fdX",
54
- "test": "remix-test",
55
- "test:bun": "bun x --bun remix-test",
56
- "typecheck": "tsgo --noEmit"
54
+ "test": "remix test",
55
+ "test:bun": "bun x --bun remix test",
56
+ "typecheck": "tsc --noEmit"
57
57
  }
58
58
  }
@@ -17,6 +17,12 @@ export function session(
17
17
  throw new Error('Session cookie must be signed')
18
18
  }
19
19
 
20
+ if (sessionCookie.httpOnly === false) {
21
+ console.warn(
22
+ `Session cookie "${sessionCookie.name}" is configured with httpOnly: false and may be accessible to client-side JavaScript.`,
23
+ )
24
+ }
25
+
20
26
  return async (context, next) => {
21
27
  if (context.has(Session)) {
22
28
  throw new Error('Existing session found, refusing to overwrite')
@@ -37,7 +43,12 @@ export function session(
37
43
  if (setCookieValue != null) {
38
44
  // make sure the response is mutable
39
45
  response = new Response(response.body, response)
40
- response.headers.append('Set-Cookie', await sessionCookie.serialize(setCookieValue))
46
+ response.headers.append(
47
+ 'Set-Cookie',
48
+ await sessionCookie.serialize(setCookieValue, {
49
+ httpOnly: sessionCookie.httpOnly ?? true,
50
+ }),
51
+ )
41
52
  }
42
53
 
43
54
  return response