iron-session 9.0.0-beta.1 → 9.0.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/MIGRATION.md +6 -2
  2. package/README.md +64 -1
  3. package/package.json +21 -19
package/MIGRATION.md CHANGED
@@ -2,15 +2,19 @@
2
2
 
3
3
  ## v8 to v9
4
4
 
5
+ ```sh
6
+ pnpm add iron-session
7
+ ```
8
+
5
9
  Most apps need two changes: Node 22 and one line if you store a `Date` in the
6
10
  session. Everything else below is either a type error TypeScript will point at,
7
11
  or a bug fix you want.
8
12
 
9
13
  ### Requirements
10
14
 
11
- - **Node 22.12 or later.** Node 20 reached end of life in April 2026.
15
+ - **Node 22.13 or later.** Node 20 reached end of life in April 2026.
12
16
  - **The package is ESM-only.** There is no CommonJS build. `require()` still
13
- works on Node 22.12+, which supports `require()` of an ES module, so most CJS
17
+ works on Node 22.13+, which supports `require()` of an ES module, so most CJS
14
18
  code keeps working. If you are bundling for an older target, keep v8.
15
19
 
16
20
  ### Do this
package/README.md CHANGED
@@ -14,6 +14,7 @@ The session data is stored in signed and encrypted cookies which are decoded by
14
14
 
15
15
  - [Table of Contents](#table-of-contents)
16
16
  - [Installation](#installation)
17
+ - [Upgrading to v9](#upgrading-to-v9)
17
18
  - [Usage](#usage)
18
19
  - [Examples](#examples)
19
20
  - [Runtimes](#runtimes)
@@ -25,6 +26,7 @@ The session data is stored in signed and encrypted cookies which are decoded by
25
26
  - [API](#api)
26
27
  - [`getIronSession<T>(req, res, sessionOptions): Promise<IronSession<T>>`](#getironsessiontreq-res-sessionoptions-promiseironsessiont)
27
28
  - [`getIronSession<T>(cookieStore, sessionOptions): Promise<IronSession<T>>`](#getironsessiontcookiestore-sessionoptions-promiseironsessiont)
29
+ - [`nodeCookies`, `webCookies`, `nextProxyCookies`](#nodecookiesreq-res-webcookiesrequest-responseorheaders-nextproxycookiesrequest-response)
28
30
  - [`session.save(): Promise<void>`](#sessionsave-promisevoid)
29
31
  - [`session.destroy(): void`](#sessiondestroy-void)
30
32
  - [`session.updateConfig(sessionOptions: SessionOptions): void`](#sessionupdateconfigsessionoptions-sessionoptions-void)
@@ -44,6 +46,51 @@ The session data is stored in signed and encrypted cookies which are decoded by
44
46
  pnpm add iron-session
45
47
  ```
46
48
 
49
+ v9 needs **Node 22.13 or later** and is **ESM-only**. `require()` still works on
50
+ Node 22.13+, which supports `require()` of an ES module. If you are stuck on an
51
+ older Node, stay on v8: `pnpm add iron-session@8`.
52
+
53
+ ## Upgrading to v9
54
+
55
+ Most apps change two things. Both are things v8 got wrong quietly.
56
+
57
+ **1. Store timestamps, not `Date` objects.**
58
+
59
+ ```diff
60
+ - session.lastSeen = new Date();
61
+ + session.lastSeen = Date.now();
62
+ ```
63
+
64
+ v8 turned a `Date` into a string when sealing, so the type you wrote was not the
65
+ type you read back. v9 throws and names the field.
66
+
67
+ **2. Handle a session that does not exist yet.**
68
+
69
+ ```diff
70
+ - const userId = session.user.id;
71
+ + const userId = session.user?.id;
72
+ ```
73
+
74
+ Reads are typed as `Partial<T>` now. A first visit, an expired cookie and a
75
+ `destroy()` all leave you an empty object, so the old type let this compile and
76
+ then throw at runtime.
77
+
78
+ Nothing else is required. `getIronSession(req, res, options)` and
79
+ `getIronSession(await cookies(), options)` both still work, v9 reads v8 cookies
80
+ and v8 reads v9 cookies, so you can roll a deploy back without signing everyone
81
+ out. If you had `as any` on `await cookies()`, delete it.
82
+
83
+ Worth adopting while you are here:
84
+
85
+ - [`nextProxyCookies`](#runtimes) if you ever tried to save a session in Next.js
86
+ middleware and it did not stick.
87
+ - [`onUnsealError`](#watching-for-unreadable-cookies) to see why cookies get
88
+ rejected instead of guessing.
89
+ - [`chunk: true`](#session-size) if your session outgrew one cookie.
90
+
91
+ The full guide, including the removed APIs and the security fix that signs pre-v8
92
+ cookies out once, is in [MIGRATION.md](./MIGRATION.md).
93
+
47
94
  ## Usage
48
95
 
49
96
  _We have extensive examples here too: https://get-iron-session.vercel.app/._
@@ -258,7 +305,21 @@ type SessionData = {
258
305
  // Your data
259
306
  };
260
307
 
261
- const session = await getIronSession<SessionData>(cookies(), sessionOptions);
308
+ const session = await getIronSession<SessionData>(await cookies(), sessionOptions);
309
+ ```
310
+
311
+ Reads are typed as `Partial<T>`, because a session that does not exist yet is an
312
+ empty object. Use optional chaining, or narrow once and pass the result around.
313
+
314
+ ### `nodeCookies(req, res)`, `webCookies(request, responseOrHeaders)`, `nextProxyCookies(request, response)`
315
+
316
+ Cookie jars you pass in place of `req, res`, for when the shorthand cannot tell
317
+ what your framework wants. See [Runtimes](#runtimes).
318
+
319
+ ```ts
320
+ import { getIronSession, nextProxyCookies } from "iron-session";
321
+
322
+ const session = await getIronSession(nextProxyCookies(request, response), sessionOptions);
262
323
  ```
263
324
 
264
325
  ### `session.save(): Promise<void>`
@@ -283,6 +344,8 @@ session.destroy();
283
344
 
284
345
  Updates the configuration of the session with new session options. You still need to call save() if you want them to be applied.
285
346
 
347
+ It rebuilds the whole configuration, including the password, so this is what you use to rotate a password mid-request. In v8 a new password passed here was ignored.
348
+
286
349
  ### `sealData(data: unknown, { password, ttl }): Promise<string>`
287
350
 
288
351
  This is the underlying method and seal mechanism that powers `iron-session`. You can use it to seal any `data` you want and pass it around. One usecase are magic links: you generate a seal that contains a user id to login and send it to a route on your website (like `/magic-login`). Once received, you can safely decode the seal with `unsealData` and log the user in.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iron-session",
3
- "version": "9.0.0-beta.1",
3
+ "version": "9.0.1",
4
4
  "description": "Secure, stateless, and cookie-based session library for JavaScript",
5
5
  "keywords": [
6
6
  "cookie",
@@ -15,7 +15,10 @@
15
15
  "bugs": "https://github.com/vvo/iron-session/issues",
16
16
  "license": "MIT",
17
17
  "author": "Vincent Voyer <vincent@codeagain.com> (https://github.com/vvo)",
18
- "repository": "github:vvo/iron-session",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "github:vvo/iron-session"
21
+ },
19
22
  "funding": [
20
23
  "https://github.com/sponsors/vvo",
21
24
  "https://github.com/sponsors/brc-dd"
@@ -35,20 +38,6 @@
35
38
  "provenance": true,
36
39
  "registry": "https://registry.npmjs.org"
37
40
  },
38
- "scripts": {
39
- "build": "tsdown",
40
- "dev": "pnpm build && concurrently \"pnpm build --watch\" \"pnpm --filter=next-example dev\" ",
41
- "format": "oxfmt .",
42
- "format:check": "oxfmt --check .",
43
- "lint": "oxlint --type-aware && tsc --noEmit && pnpm build && publint && attw --pack . --ignore-rules cjs-resolves-to-esm && pnpm lint:types",
44
- "lint:types": "tsdown && tsc --noEmit -p type-tests/tsconfig.json",
45
- "pretest": "node -e \"require('node:fs').mkdirSync('coverage',{recursive:true})\"",
46
- "size": "size-limit",
47
- "start": "pnpm --filter=next-example start",
48
- "test": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --import tsx src/*.test.ts",
49
- "test:e2e": "playwright test",
50
- "test:watch": "node --import tsx --test --watch src/*.test.ts"
51
- },
52
41
  "dependencies": {
53
42
  "cookie": "^2.0.1",
54
43
  "iron-webcrypto": "^2.0.0"
@@ -59,7 +48,7 @@
59
48
  "@size-limit/preset-small-lib": "13.0.3",
60
49
  "@types/node": "26.4.0",
61
50
  "@types/react": "19.2.7",
62
- "concurrently": "9.2.1",
51
+ "concurrently": "10.0.5",
63
52
  "next": "16.3.3",
64
53
  "oxfmt": "0.65.0",
65
54
  "oxlint": "1.80.0",
@@ -95,5 +84,18 @@
95
84
  "engines": {
96
85
  "node": ">=22.13.0"
97
86
  },
98
- "packageManager": "pnpm@11.24.0"
99
- }
87
+ "scripts": {
88
+ "build": "tsdown",
89
+ "dev": "pnpm build && concurrently \"pnpm build --watch\" \"pnpm --filter=next-example dev\" ",
90
+ "format": "oxfmt .",
91
+ "format:check": "oxfmt --check .",
92
+ "lint": "oxlint --type-aware && tsc --noEmit && pnpm build && publint && attw --pack . --ignore-rules cjs-resolves-to-esm && pnpm lint:types",
93
+ "lint:types": "tsdown && tsc --noEmit -p type-tests/tsconfig.json",
94
+ "pretest": "node -e \"require('node:fs').mkdirSync('coverage',{recursive:true})\"",
95
+ "size": "size-limit",
96
+ "start": "pnpm --filter=next-example start",
97
+ "test": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --import tsx src/*.test.ts",
98
+ "test:e2e": "playwright test",
99
+ "test:watch": "node --import tsx --test --watch src/*.test.ts"
100
+ }
101
+ }