iron-session 1.0.3 → 2.0.0-alpha.10

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/LICENSE CHANGED
@@ -1,9 +1,21 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) CodeAgain SASU
3
+ Copyright (c) 2021 Vincent Voyer
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
6
11
 
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
8
14
 
9
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,114 +1,103 @@
1
- # iron-session [![GitHub license](https://img.shields.io/github/license/vvo/iron-session?style=flat)](https://github.com/vvo/iron-session/blob/master/LICENSE) ![Tests](https://github.com/vvo/iron-session/workflows/Tests/badge.svg) [![codecov](https://codecov.io/gh/vvo/iron-session/branch/master/graph/badge.svg)](https://codecov.io/gh/vvo/iron-session) ![npm](https://img.shields.io/npm/v/iron-session)
1
+ # TSDX User Guide
2
2
 
3
- **This JavaScript backend utility** allows you to create a session to then be stored in browser cookies via a signed and encrypted token value. This provides client sessions that are ⚒️ iron-strong.
3
+ Congrats! You just saved yourself hours of work by bootstrapping this project with TSDX. Let’s get you oriented with what’s here and how to use it.
4
4
 
5
- The token stored on the client contains the session data, not your server, making it a "stateless" session from the server point of view. The token is signed and encrypted using [@hapi/iron](https://github.com/hapijs/iron).
5
+ > This TSDX setup is meant for developing libraries (not apps!) that can be published to NPM. If you’re looking to build a Node app, you could use `ts-node-dev`, plain `ts-node`, or simple `tsc`.
6
6
 
7
- **⚡️ Flash session data is supported**. It means you can store some data which will be deleted when read. This is useful for temporary tokens, redirects or notices on your UI.
7
+ > If you’re new to TypeScript, checkout [this handy cheatsheet](https://devhints.io/typescript)
8
8
 
9
- **By default the cookie has an ⏰ expiration time of 15 days**, set via [`maxAge`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#Directives). After that, even if someone tries to reuse the cookie, @hapi/iron will not accept the underlying token. Because the expiration is also part of the token value. See https://hapi.dev/family/iron for more information on @hapi/iron mechanisms.
9
+ ## Commands
10
10
 
11
- **Why use pure 🍪 cookies for sessions?** This makes your sessions stateless: you do not have to store session data on your server. This is particularly useful in serverless architectures. Still, there are some drawbacks to this approach:
11
+ TSDX scaffolds your new library inside `/src`.
12
12
 
13
- - you cannot invalidate a cookie when needed because there's no state stored on the server-side about the tokens. We consider that the way the cookie is stored reduces the possibility for this eventuality to happen.
14
- - application not supporting cookies won't work, this could be solved in the future by exposing the underlying token instead of signed and encrypted cookies. Open an issue if you're interested.
15
- - on most browsers, you're limited to 4,096 bytes per cookie. To give you an idea, an `iron-session` containing `{user: {id: 230, admin: true}}` is 358 bytes signed and encrypted: still plenty of available cookie space in here.
13
+ To run TSDX, use:
16
14
 
17
- Now that you know the drawbacks, you can decide if they are an issue for your application or not.
15
+ ```bash
16
+ npm start # or yarn start
17
+ ```
18
18
 
19
- **🤓 References:**
19
+ This builds to `/dist` and runs the project in watch mode so any edits you save inside `src` causes a rebuild to `/dist`.
20
20
 
21
- - https://owasp.org/www-project-cheat-sheets/cheatsheets/Session_Management_Cheat_Sheet.html#cookies
22
- - https://owasp.org/www-project-cheat-sheets/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#encryption-based-token-pattern
21
+ To do a one-off build, use `npm run build` or `yarn build`.
23
22
 
24
- ## How is this different from [JWT](https://jwt.io/)?
23
+ To run tests, use `npm test` or `yarn test`.
25
24
 
26
- Not so much:
25
+ ## Configuration
27
26
 
28
- - JWT is a standard, it stores metadata in the JWT token themselves to ensure communication between different systems is flawless.
29
- - JWT tokens are not encrypted, the payload is visible by customers if they manage to inspect the token. You would have to use [JWE](https://tools.ietf.org/html/rfc7516) to achieve the same.
30
- - @hapi/iron mechanism is not a standard, it's a way to sign and encrypt data into tokens
27
+ Code quality is set up for you with `prettier`, `husky`, and `lint-staged`. Adjust the respective fields in `package.json` accordingly.
31
28
 
32
- Depending on your own needs and preferences, `iron-session-cookie` may or may not fit you.
29
+ ### Jest
33
30
 
34
- ## Instalation
31
+ Jest tests are set up to run with `npm test` or `yarn test`.
35
32
 
36
- ```bash
37
- npm add iron-session
33
+ ### Bundle Analysis
34
+
35
+ [`size-limit`](https://github.com/ai/size-limit) is set up to calculate the real cost of your library with `npm run size` and visualize the bundle with `npm run analyze`.
36
+
37
+ #### Setup Files
38
+
39
+ This is the folder structure we set up for you:
40
+
41
+ ```txt
42
+ /src
43
+ index.tsx # EDIT THIS
44
+ /test
45
+ blah.test.tsx # EDIT THIS
46
+ .gitignore
47
+ package.json
48
+ README.md # EDIT THIS
49
+ tsconfig.json
38
50
  ```
39
51
 
40
- ## Usage
52
+ ### Rollup
41
53
 
42
- The examples are using a user login flow: login, verify, log out. But you can use `iron-session` for any other session need.
54
+ TSDX uses [Rollup](https://rollupjs.org) as a bundler and generates multiple rollup configs for various module formats and build settings. See [Optimizations](#optimizations) for details.
43
55
 
44
- The password is a private key you must pass at runtime, it has to be at least 32 characters long. https://1password.com/password-generator/ is a good way to generate a strong password.
56
+ ### TypeScript
45
57
 
46
- ### When the user logs in
58
+ `tsconfig.json` is set up to interpret `dom` and `esnext` types, as well as `react` for `jsx`. Adjust according to your needs.
47
59
 
48
- ```js
49
- import { createSession } from "iron-session";
50
- export default async (req, res) => {
51
- // when user successfully logs in using email/password, oauth, ... then we create a session
52
- // const user = ...
60
+ ## Continuous Integration
53
61
 
54
- const session = await createSession({
55
- password: process.env.SECRET_SESSION_PASSWORD
56
- });
62
+ ### GitHub Actions
57
63
 
58
- session.set({ name: "user", value: { id: 230, admin: true } });
59
- session.set({ name: "message", value: "Login success", flash: true });
64
+ Two actions are added by default:
60
65
 
61
- res.writeHead(200, {
62
- "set-cookie": await session.serializeCookie()
63
- });
66
+ - `main` which installs deps w/ cache, lints, tests, and builds on all pushes against a Node and OS matrix
67
+ - `size` which comments cost comparison of your library on every pull request using [`size-limit`](https://github.com/ai/size-limit)
64
68
 
65
- res.end("ok");
66
- };
67
- ```
69
+ ## Optimizations
68
70
 
69
- `serializeCookie` accepts all the options from https://github.com/jshttp/cookie#cookieserializename-value-options, merged with `iron-session` defaults. The defaults are:
71
+ Please see the main `tsdx` [optimizations docs](https://github.com/palmerhq/tsdx#optimizations). In particular, know that you can take advantage of development-only optimizations:
70
72
 
71
73
  ```js
72
- {
73
- httpOnly: true,
74
- secure: true,
75
- sameSite: "lax",
76
- maxAge: (ttl === 0 ? 2147483647 : ttl) - 60, // For Iron, ttl 0 means it will never expire. For browser cookies, maxAge 0 means it will expire immediately. WhilCookie must expire before the seal, otherwise you could have expired seals stored in a cookie
74
+ // ./types/index.d.ts
75
+ declare var __DEV__: boolean;
76
+
77
+ // inside your code...
78
+ if (__DEV__) {
79
+ console.log('foo');
77
80
  }
78
81
  ```
79
82
 
80
- ### Checking if the user is logged in
83
+ You can also choose to install and use [invariant](https://github.com/palmerhq/tsdx#invariant) and [warning](https://github.com/palmerhq/tsdx#warning) functions.
81
84
 
82
- ```js
83
- import { getSession, parseCookie } from "iron-session";
84
- export default async (req, res) => {
85
- const session = await getSession({
86
- password: process.env.SECRET_SESSION_PASSWORD,
87
- sealed: parseCookie({ cookie: req.getHeader("cookie") })
88
- });
89
-
90
- const user = session.get({ name: "user" });
91
- const flashMessage = session.get({ name: "message" });
92
-
93
- res.end("ok");
94
- };
95
- ```
85
+ ## Module Formats
96
86
 
97
- ### When the user logs out
87
+ CJS, ESModules, and UMD module formats are supported.
98
88
 
99
- ```js
100
- import { deleteCookie } from "iron-session";
101
- export default async (req, res) => {
102
- res.writeHead(200, {
103
- "set-cookie": deleteCookie()
104
- });
105
-
106
- res.end("ok");
107
- };
108
- ```
89
+ The appropriate paths are configured in `package.json` and `dist/index.js` accordingly. Please report if any issues are found.
90
+
91
+ ## Named Exports
92
+
93
+ Per Palmer Group guidelines, [always use named exports.](https://github.com/palmerhq/typescript#exports) Code split inside your React app instead of your React library.
94
+
95
+ ## Including Styles
96
+
97
+ There are many ways to ship styles, including with CSS-in-JS. TSDX has no opinion on this, configure how you like.
109
98
 
110
- ## Project status
99
+ For vanilla CSS, you can include it at the root directory and add it to the `files` section in your `package.json`, so that it can be imported separately by your users and run through their bundler's loader.
111
100
 
112
- This is a recent library I authored because I needed it. While @hapi/iron is battle-tested and [used in production on a lot of websites](https://hapi.dev/), this library is not. Please use it at your own risk.
101
+ ## Publishing to NPM
113
102
 
114
- If you find bugs or have API ideas, create an issue.
103
+ We recommend using [np](https://github.com/sindresorhus/np).
@@ -0,0 +1,29 @@
1
+ import { CookieSerializeOptions } from 'cookie';
2
+ import { IncomingMessage, ServerResponse } from 'http';
3
+
4
+ declare type password = string | {
5
+ id: number;
6
+ password: string;
7
+ }[];
8
+ interface IronSessionOptions {
9
+ cookieName: string;
10
+ password: password;
11
+ ttl?: number;
12
+ cookieOptions?: CookieSerializeOptions;
13
+ }
14
+ interface IronSession {
15
+ set: <T = unknown>(name: string, value: T) => T;
16
+ get: <T = unknown>(name: string) => T | undefined;
17
+ unset: (name: string) => void;
18
+ destroy: () => void;
19
+ save: () => Promise<string>;
20
+ }
21
+ declare function getIronSession<RequestType extends IncomingMessage, ResponseType extends ServerResponse>(req: RequestType, res: ResponseType, userOptions: IronSessionOptions): Promise<{
22
+ set: <T = any>(name: string, value: T) => T;
23
+ get: (name?: string | undefined) => any;
24
+ unset: (name: string) => void;
25
+ save(): Promise<string>;
26
+ destroy(): void;
27
+ }>;
28
+
29
+ export { IronSession, IronSessionOptions, getIronSession };
package/dist/index.js ADDED
@@ -0,0 +1,127 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
8
+ var __export = (target, all) => {
9
+ __markAsModule(target);
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __reExport = (target, module2, desc) => {
14
+ if (module2 && typeof module2 === "object" || typeof module2 === "function") {
15
+ for (let key of __getOwnPropNames(module2))
16
+ if (!__hasOwnProp.call(target, key) && key !== "default")
17
+ __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
18
+ }
19
+ return target;
20
+ };
21
+ var __toModule = (module2) => {
22
+ return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
23
+ };
24
+
25
+ // src/index.ts
26
+ __export(exports, {
27
+ getIronSession: () => getIronSession
28
+ });
29
+ var import_iron_store = __toModule(require("iron-store"));
30
+ var import_cookie = __toModule(require("cookie"));
31
+ var timestampSkewSec = 60;
32
+ var defaultOptions = {
33
+ ttl: 15 * 24 * 3600,
34
+ cookieOptions: {
35
+ httpOnly: true,
36
+ secure: true,
37
+ sameSite: "lax",
38
+ path: "/"
39
+ }
40
+ };
41
+ async function getIronSession(req, res, userOptions) {
42
+ var _a, _b;
43
+ if (!req || !res || !userOptions || !userOptions.cookieName || !userOptions.password) {
44
+ throw new Error(`iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: "...", password: "...". Check the usage here: https://github.com/vvo/iron-session`);
45
+ }
46
+ const passwordAsAnArray = Array.isArray(userOptions.password) ? userOptions.password : [{ id: 1, password: userOptions.password }];
47
+ passwordAsAnArray.forEach(({ password }) => {
48
+ if (password.length < 32) {
49
+ throw new Error(`iron-session: Bad usage. Password must be at least 32 characters long.`);
50
+ }
51
+ });
52
+ const options = {
53
+ ...defaultOptions,
54
+ ...userOptions,
55
+ cookieOptions: {
56
+ ...defaultOptions.cookieOptions,
57
+ ...userOptions.cookieOptions || {}
58
+ }
59
+ };
60
+ if (options.ttl === 0) {
61
+ options.ttl = 2147483647;
62
+ }
63
+ options.cookieOptions.maxAge = computeCookieMaxAge((_b = (_a = userOptions.cookieOptions) == null ? void 0 : _a.maxAge) != null ? _b : options.ttl);
64
+ const store = await getOrCreateStore({
65
+ sealed: import_cookie.default.parse(req.headers.cookie || "")[options.cookieName],
66
+ password: passwordAsAnArray,
67
+ ttl: options.ttl * 1e3
68
+ });
69
+ return {
70
+ set: store.set,
71
+ get: store.get,
72
+ unset: store.unset,
73
+ async save() {
74
+ const seal = await store.seal();
75
+ const cookieValue = import_cookie.default.serialize(options.cookieName, seal, options.cookieOptions);
76
+ if (cookieValue.length > 4096) {
77
+ throw new Error(`iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`);
78
+ }
79
+ addToCookies(cookieValue, res);
80
+ return cookieValue;
81
+ },
82
+ destroy() {
83
+ store.clear();
84
+ const cookieValue = import_cookie.default.serialize(options.cookieName, "", {
85
+ ...options.cookieOptions,
86
+ maxAge: 0
87
+ });
88
+ addToCookies(cookieValue, res);
89
+ }
90
+ };
91
+ }
92
+ function addToCookies(cookieValue, res) {
93
+ var _a;
94
+ let existingSetCookie = (_a = res.getHeader("set-cookie")) != null ? _a : [];
95
+ if (typeof existingSetCookie === "string") {
96
+ existingSetCookie = [existingSetCookie];
97
+ }
98
+ res.setHeader("set-cookie", [...existingSetCookie, cookieValue]);
99
+ }
100
+ function computeCookieMaxAge(ttl) {
101
+ return ttl - timestampSkewSec;
102
+ }
103
+ async function getOrCreateStore({
104
+ sealed,
105
+ password,
106
+ ttl
107
+ }) {
108
+ try {
109
+ return await (0, import_iron_store.default)({
110
+ sealed,
111
+ password,
112
+ ttl
113
+ });
114
+ } catch (error) {
115
+ if (error instanceof Error) {
116
+ if (error.message === "Expired seal" || error.message === "Bad hmac value" || error.message === "Cannot find password: ") {
117
+ return await (0, import_iron_store.default)({ password, ttl });
118
+ }
119
+ }
120
+ throw error;
121
+ }
122
+ }
123
+ // Annotate the CommonJS export names for ESM import in node:
124
+ 0 && (module.exports = {
125
+ getIronSession
126
+ });
127
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import ironStore from \"iron-store\";\nimport cookie, { CookieSerializeOptions } from \"cookie\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/family/iron/api/?v=6.0.0#options\nconst timestampSkewSec = 60;\n\ntype password = string | { id: number; password: string }[];\n\nconst defaultOptions: {\n ttl: number;\n cookieOptions: CookieSerializeOptions;\n} = {\n ttl: 15 * 24 * 3600,\n cookieOptions: {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n path: \"/\",\n },\n};\n\nexport interface IronSessionOptions {\n cookieName: string;\n password: password;\n ttl?: number;\n cookieOptions?: CookieSerializeOptions;\n}\n\nexport interface IronSession {\n set: <T = unknown>(name: string, value: T) => T;\n get: <T = unknown>(name: string) => T | undefined;\n unset: (name: string) => void;\n destroy: () => void;\n save: () => Promise<string>;\n}\n\nexport async function getIronSession<\n RequestType extends IncomingMessage,\n ResponseType extends ServerResponse,\n>(req: RequestType, res: ResponseType, userOptions: IronSessionOptions) {\n if (\n !req ||\n !res ||\n !userOptions ||\n !userOptions.cookieName ||\n !userOptions.password\n ) {\n throw new Error(\n `iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: \"...\", password: \"...\". Check the usage here: https://github.com/vvo/iron-session`,\n );\n }\n\n const passwordAsAnArray = Array.isArray(userOptions.password)\n ? userOptions.password\n : [{ id: 1, password: userOptions.password }];\n\n passwordAsAnArray.forEach(({ password }) => {\n if (password.length < 32) {\n throw new Error(\n `iron-session: Bad usage. Password must be at least 32 characters long.`,\n );\n }\n });\n\n const options: Required<IronSessionOptions> = {\n ...defaultOptions,\n ...userOptions,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...(userOptions.cookieOptions || {}),\n },\n };\n\n if (options.ttl === 0) {\n // ttl = 0 means no expiration\n // but in reality cookies have to expire (can't have no max-age)\n // 2147483647 is the max value for max-age in cookies\n // see https://stackoverflow.com/a/11685301/147079\n options.ttl = 2147483647;\n }\n\n options.cookieOptions.maxAge = computeCookieMaxAge(\n userOptions.cookieOptions?.maxAge ?? options.ttl,\n );\n\n const store = await getOrCreateStore({\n sealed: cookie.parse(req.headers.cookie || \"\")[options.cookieName],\n password: passwordAsAnArray,\n ttl: options.ttl * 1000,\n });\n\n return {\n set: store.set,\n get: store.get,\n unset: store.unset,\n async save() {\n const seal = await store.seal();\n const cookieValue = cookie.serialize(\n options.cookieName,\n seal,\n options.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`,\n );\n }\n\n addToCookies(cookieValue, res);\n return cookieValue;\n },\n destroy() {\n store.clear();\n const cookieValue = cookie.serialize(options.cookieName, \"\", {\n ...options.cookieOptions,\n maxAge: 0,\n });\n addToCookies(cookieValue, res);\n },\n };\n}\n\nfunction addToCookies(cookieValue: string, res: ServerResponse) {\n let existingSetCookie =\n (res.getHeader(\"set-cookie\") as string[] | string) ?? [];\n if (typeof existingSetCookie === \"string\") {\n existingSetCookie = [existingSetCookie];\n }\n res.setHeader(\"set-cookie\", [...existingSetCookie, cookieValue]);\n}\n\nfunction computeCookieMaxAge(ttl: number) {\n // The next line makes sure browser will expire cookies before seals are considered expired by the server.\n // It also allows for clock difference of 60 seconds maximum between server and clients.\n // It also makes sure to expire the cookie immediately when value is 0\n return ttl - timestampSkewSec;\n}\n\nasync function getOrCreateStore({\n sealed,\n password,\n ttl,\n}: {\n sealed: string;\n password: password;\n ttl: number;\n}) {\n try {\n return await ironStore({\n sealed,\n password,\n ttl,\n });\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message === \"Expired seal\" ||\n error.message === \"Bad hmac value\" ||\n error.message === \"Cannot find password: \"\n ) {\n // if seal expired or\n // if seal is not valid (encrypted using a different password, when passwords are updated) or\n // if we can't find back the password in the seal\n // then we just start a new session over\n return await ironStore({ password, ttl });\n }\n }\n\n throw error;\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA,wBAAsB;AACtB,oBAA+C;AAK/C,IAAM,mBAAmB;AAIzB,IAAM,iBAGF;AAAA,EACF,KAAK,KAAK,KAAK;AAAA,EACf,eAAe;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,MAAM;AAAA;AAAA;AAmBV,8BAGE,KAAkB,KAAmB,aAAiC;AAzCxE;AA0CE,MACE,CAAC,OACD,CAAC,OACD,CAAC,eACD,CAAC,YAAY,cACb,CAAC,YAAY,UACb;AACA,UAAM,IAAI,MACR;AAAA;AAIJ,QAAM,oBAAoB,MAAM,QAAQ,YAAY,YAChD,YAAY,WACZ,CAAC,EAAE,IAAI,GAAG,UAAU,YAAY;AAEpC,oBAAkB,QAAQ,CAAC,EAAE,eAAe;AAC1C,QAAI,SAAS,SAAS,IAAI;AACxB,YAAM,IAAI,MACR;AAAA;AAAA;AAKN,QAAM,UAAwC;AAAA,OACzC;AAAA,OACA;AAAA,IACH,eAAe;AAAA,SACV,eAAe;AAAA,SACd,YAAY,iBAAiB;AAAA;AAAA;AAIrC,MAAI,QAAQ,QAAQ,GAAG;AAKrB,YAAQ,MAAM;AAAA;AAGhB,UAAQ,cAAc,SAAS,oBAC7B,wBAAY,kBAAZ,mBAA2B,WAA3B,YAAqC,QAAQ;AAG/C,QAAM,QAAQ,MAAM,iBAAiB;AAAA,IACnC,QAAQ,sBAAO,MAAM,IAAI,QAAQ,UAAU,IAAI,QAAQ;AAAA,IACvD,UAAU;AAAA,IACV,KAAK,QAAQ,MAAM;AAAA;AAGrB,SAAO;AAAA,IACL,KAAK,MAAM;AAAA,IACX,KAAK,MAAM;AAAA,IACX,OAAO,MAAM;AAAA,UACP,OAAO;AACX,YAAM,OAAO,MAAM,MAAM;AACzB,YAAM,cAAc,sBAAO,UACzB,QAAQ,YACR,MACA,QAAQ;AAGV,UAAI,YAAY,SAAS,MAAM;AAC7B,cAAM,IAAI,MACR,0CAA0C,YAAY;AAAA;AAI1D,mBAAa,aAAa;AAC1B,aAAO;AAAA;AAAA,IAET,UAAU;AACR,YAAM;AACN,YAAM,cAAc,sBAAO,UAAU,QAAQ,YAAY,IAAI;AAAA,WACxD,QAAQ;AAAA,QACX,QAAQ;AAAA;AAEV,mBAAa,aAAa;AAAA;AAAA;AAAA;AAKhC,sBAAsB,aAAqB,KAAqB;AA7HhE;AA8HE,MAAI,oBACD,UAAI,UAAU,kBAAd,YAAqD;AACxD,MAAI,OAAO,sBAAsB,UAAU;AACzC,wBAAoB,CAAC;AAAA;AAEvB,MAAI,UAAU,cAAc,CAAC,GAAG,mBAAmB;AAAA;AAGrD,6BAA6B,KAAa;AAIxC,SAAO,MAAM;AAAA;AAGf,gCAAgC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,GAKC;AACD,MAAI;AACF,WAAO,MAAM,+BAAU;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA;AAAA,WAEK,OAAP;AACA,QAAI,iBAAiB,OAAO;AAC1B,UACE,MAAM,YAAY,kBAClB,MAAM,YAAY,oBAClB,MAAM,YAAY,0BAClB;AAKA,eAAO,MAAM,+BAAU,EAAE,UAAU;AAAA;AAAA;AAIvC,UAAM;AAAA;AAAA;",
6
+ "names": []
7
+ }
package/dist/index.mjs ADDED
@@ -0,0 +1,99 @@
1
+ // src/index.ts
2
+ import ironStore from "iron-store";
3
+ import cookie from "cookie";
4
+ var timestampSkewSec = 60;
5
+ var defaultOptions = {
6
+ ttl: 15 * 24 * 3600,
7
+ cookieOptions: {
8
+ httpOnly: true,
9
+ secure: true,
10
+ sameSite: "lax",
11
+ path: "/"
12
+ }
13
+ };
14
+ async function getIronSession(req, res, userOptions) {
15
+ var _a, _b;
16
+ if (!req || !res || !userOptions || !userOptions.cookieName || !userOptions.password) {
17
+ throw new Error(`iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: "...", password: "...". Check the usage here: https://github.com/vvo/iron-session`);
18
+ }
19
+ const passwordAsAnArray = Array.isArray(userOptions.password) ? userOptions.password : [{ id: 1, password: userOptions.password }];
20
+ passwordAsAnArray.forEach(({ password }) => {
21
+ if (password.length < 32) {
22
+ throw new Error(`iron-session: Bad usage. Password must be at least 32 characters long.`);
23
+ }
24
+ });
25
+ const options = {
26
+ ...defaultOptions,
27
+ ...userOptions,
28
+ cookieOptions: {
29
+ ...defaultOptions.cookieOptions,
30
+ ...userOptions.cookieOptions || {}
31
+ }
32
+ };
33
+ if (options.ttl === 0) {
34
+ options.ttl = 2147483647;
35
+ }
36
+ options.cookieOptions.maxAge = computeCookieMaxAge((_b = (_a = userOptions.cookieOptions) == null ? void 0 : _a.maxAge) != null ? _b : options.ttl);
37
+ const store = await getOrCreateStore({
38
+ sealed: cookie.parse(req.headers.cookie || "")[options.cookieName],
39
+ password: passwordAsAnArray,
40
+ ttl: options.ttl * 1e3
41
+ });
42
+ return {
43
+ set: store.set,
44
+ get: store.get,
45
+ unset: store.unset,
46
+ async save() {
47
+ const seal = await store.seal();
48
+ const cookieValue = cookie.serialize(options.cookieName, seal, options.cookieOptions);
49
+ if (cookieValue.length > 4096) {
50
+ throw new Error(`iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`);
51
+ }
52
+ addToCookies(cookieValue, res);
53
+ return cookieValue;
54
+ },
55
+ destroy() {
56
+ store.clear();
57
+ const cookieValue = cookie.serialize(options.cookieName, "", {
58
+ ...options.cookieOptions,
59
+ maxAge: 0
60
+ });
61
+ addToCookies(cookieValue, res);
62
+ }
63
+ };
64
+ }
65
+ function addToCookies(cookieValue, res) {
66
+ var _a;
67
+ let existingSetCookie = (_a = res.getHeader("set-cookie")) != null ? _a : [];
68
+ if (typeof existingSetCookie === "string") {
69
+ existingSetCookie = [existingSetCookie];
70
+ }
71
+ res.setHeader("set-cookie", [...existingSetCookie, cookieValue]);
72
+ }
73
+ function computeCookieMaxAge(ttl) {
74
+ return ttl - timestampSkewSec;
75
+ }
76
+ async function getOrCreateStore({
77
+ sealed,
78
+ password,
79
+ ttl
80
+ }) {
81
+ try {
82
+ return await ironStore({
83
+ sealed,
84
+ password,
85
+ ttl
86
+ });
87
+ } catch (error) {
88
+ if (error instanceof Error) {
89
+ if (error.message === "Expired seal" || error.message === "Bad hmac value" || error.message === "Cannot find password: ") {
90
+ return await ironStore({ password, ttl });
91
+ }
92
+ }
93
+ throw error;
94
+ }
95
+ }
96
+ export {
97
+ getIronSession
98
+ };
99
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts"],
4
+ "sourcesContent": ["import ironStore from \"iron-store\";\nimport cookie, { CookieSerializeOptions } from \"cookie\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\n\n// default time allowed to check for iron seal validity when ttl passed\n// see https://hapi.dev/family/iron/api/?v=6.0.0#options\nconst timestampSkewSec = 60;\n\ntype password = string | { id: number; password: string }[];\n\nconst defaultOptions: {\n ttl: number;\n cookieOptions: CookieSerializeOptions;\n} = {\n ttl: 15 * 24 * 3600,\n cookieOptions: {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n path: \"/\",\n },\n};\n\nexport interface IronSessionOptions {\n cookieName: string;\n password: password;\n ttl?: number;\n cookieOptions?: CookieSerializeOptions;\n}\n\nexport interface IronSession {\n set: <T = unknown>(name: string, value: T) => T;\n get: <T = unknown>(name: string) => T | undefined;\n unset: (name: string) => void;\n destroy: () => void;\n save: () => Promise<string>;\n}\n\nexport async function getIronSession<\n RequestType extends IncomingMessage,\n ResponseType extends ServerResponse,\n>(req: RequestType, res: ResponseType, userOptions: IronSessionOptions) {\n if (\n !req ||\n !res ||\n !userOptions ||\n !userOptions.cookieName ||\n !userOptions.password\n ) {\n throw new Error(\n `iron-session: Bad usage. Minimum usage is const session = await getIronSession(req, res, { cookieName: \"...\", password: \"...\". Check the usage here: https://github.com/vvo/iron-session`,\n );\n }\n\n const passwordAsAnArray = Array.isArray(userOptions.password)\n ? userOptions.password\n : [{ id: 1, password: userOptions.password }];\n\n passwordAsAnArray.forEach(({ password }) => {\n if (password.length < 32) {\n throw new Error(\n `iron-session: Bad usage. Password must be at least 32 characters long.`,\n );\n }\n });\n\n const options: Required<IronSessionOptions> = {\n ...defaultOptions,\n ...userOptions,\n cookieOptions: {\n ...defaultOptions.cookieOptions,\n ...(userOptions.cookieOptions || {}),\n },\n };\n\n if (options.ttl === 0) {\n // ttl = 0 means no expiration\n // but in reality cookies have to expire (can't have no max-age)\n // 2147483647 is the max value for max-age in cookies\n // see https://stackoverflow.com/a/11685301/147079\n options.ttl = 2147483647;\n }\n\n options.cookieOptions.maxAge = computeCookieMaxAge(\n userOptions.cookieOptions?.maxAge ?? options.ttl,\n );\n\n const store = await getOrCreateStore({\n sealed: cookie.parse(req.headers.cookie || \"\")[options.cookieName],\n password: passwordAsAnArray,\n ttl: options.ttl * 1000,\n });\n\n return {\n set: store.set,\n get: store.get,\n unset: store.unset,\n async save() {\n const seal = await store.seal();\n const cookieValue = cookie.serialize(\n options.cookieName,\n seal,\n options.cookieOptions,\n );\n\n if (cookieValue.length > 4096) {\n throw new Error(\n `iron-session: Cookie length is too big ${cookieValue.length}, browsers will refuse it. Try to remove some data.`,\n );\n }\n\n addToCookies(cookieValue, res);\n return cookieValue;\n },\n destroy() {\n store.clear();\n const cookieValue = cookie.serialize(options.cookieName, \"\", {\n ...options.cookieOptions,\n maxAge: 0,\n });\n addToCookies(cookieValue, res);\n },\n };\n}\n\nfunction addToCookies(cookieValue: string, res: ServerResponse) {\n let existingSetCookie =\n (res.getHeader(\"set-cookie\") as string[] | string) ?? [];\n if (typeof existingSetCookie === \"string\") {\n existingSetCookie = [existingSetCookie];\n }\n res.setHeader(\"set-cookie\", [...existingSetCookie, cookieValue]);\n}\n\nfunction computeCookieMaxAge(ttl: number) {\n // The next line makes sure browser will expire cookies before seals are considered expired by the server.\n // It also allows for clock difference of 60 seconds maximum between server and clients.\n // It also makes sure to expire the cookie immediately when value is 0\n return ttl - timestampSkewSec;\n}\n\nasync function getOrCreateStore({\n sealed,\n password,\n ttl,\n}: {\n sealed: string;\n password: password;\n ttl: number;\n}) {\n try {\n return await ironStore({\n sealed,\n password,\n ttl,\n });\n } catch (error) {\n if (error instanceof Error) {\n if (\n error.message === \"Expired seal\" ||\n error.message === \"Bad hmac value\" ||\n error.message === \"Cannot find password: \"\n ) {\n // if seal expired or\n // if seal is not valid (encrypted using a different password, when passwords are updated) or\n // if we can't find back the password in the seal\n // then we just start a new session over\n return await ironStore({ password, ttl });\n }\n }\n\n throw error;\n }\n}\n"],
5
+ "mappings": ";AAAA;AACA;AAKA,IAAM,mBAAmB;AAIzB,IAAM,iBAGF;AAAA,EACF,KAAK,KAAK,KAAK;AAAA,EACf,eAAe;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,MAAM;AAAA;AAAA;AAmBV,8BAGE,KAAkB,KAAmB,aAAiC;AAzCxE;AA0CE,MACE,CAAC,OACD,CAAC,OACD,CAAC,eACD,CAAC,YAAY,cACb,CAAC,YAAY,UACb;AACA,UAAM,IAAI,MACR;AAAA;AAIJ,QAAM,oBAAoB,MAAM,QAAQ,YAAY,YAChD,YAAY,WACZ,CAAC,EAAE,IAAI,GAAG,UAAU,YAAY;AAEpC,oBAAkB,QAAQ,CAAC,EAAE,eAAe;AAC1C,QAAI,SAAS,SAAS,IAAI;AACxB,YAAM,IAAI,MACR;AAAA;AAAA;AAKN,QAAM,UAAwC;AAAA,OACzC;AAAA,OACA;AAAA,IACH,eAAe;AAAA,SACV,eAAe;AAAA,SACd,YAAY,iBAAiB;AAAA;AAAA;AAIrC,MAAI,QAAQ,QAAQ,GAAG;AAKrB,YAAQ,MAAM;AAAA;AAGhB,UAAQ,cAAc,SAAS,oBAC7B,wBAAY,kBAAZ,mBAA2B,WAA3B,YAAqC,QAAQ;AAG/C,QAAM,QAAQ,MAAM,iBAAiB;AAAA,IACnC,QAAQ,OAAO,MAAM,IAAI,QAAQ,UAAU,IAAI,QAAQ;AAAA,IACvD,UAAU;AAAA,IACV,KAAK,QAAQ,MAAM;AAAA;AAGrB,SAAO;AAAA,IACL,KAAK,MAAM;AAAA,IACX,KAAK,MAAM;AAAA,IACX,OAAO,MAAM;AAAA,UACP,OAAO;AACX,YAAM,OAAO,MAAM,MAAM;AACzB,YAAM,cAAc,OAAO,UACzB,QAAQ,YACR,MACA,QAAQ;AAGV,UAAI,YAAY,SAAS,MAAM;AAC7B,cAAM,IAAI,MACR,0CAA0C,YAAY;AAAA;AAI1D,mBAAa,aAAa;AAC1B,aAAO;AAAA;AAAA,IAET,UAAU;AACR,YAAM;AACN,YAAM,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI;AAAA,WACxD,QAAQ;AAAA,QACX,QAAQ;AAAA;AAEV,mBAAa,aAAa;AAAA;AAAA;AAAA;AAKhC,sBAAsB,aAAqB,KAAqB;AA7HhE;AA8HE,MAAI,oBACD,UAAI,UAAU,kBAAd,YAAqD;AACxD,MAAI,OAAO,sBAAsB,UAAU;AACzC,wBAAoB,CAAC;AAAA;AAEvB,MAAI,UAAU,cAAc,CAAC,GAAG,mBAAmB;AAAA;AAGrD,6BAA6B,KAAa;AAIxC,SAAO,MAAM;AAAA;AAGf,gCAAgC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,GAKC;AACD,MAAI;AACF,WAAO,MAAM,UAAU;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA;AAAA,WAEK,OAAP;AACA,QAAI,iBAAiB,OAAO;AAC1B,UACE,MAAM,YAAY,kBAClB,MAAM,YAAY,oBAClB,MAAM,YAAY,0BAClB;AAKA,eAAO,MAAM,UAAU,EAAE,UAAU;AAAA;AAAA;AAIvC,UAAM;AAAA;AAAA;",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ import { NextApiRequest, NextApiResponse, GetServerSidePropsResult, GetServerSidePropsContext } from 'next';
2
+ import { IronSession, IronSessionOptions } from 'iron-session';
3
+
4
+ interface NextApiRequestWithIronSession extends NextApiRequest {
5
+ session: IronSession;
6
+ }
7
+ declare type NextApiHandlerWithIronSession<T = unknown> = (req: NextApiRequestWithIronSession, res: NextApiResponse<T>) => void | Promise<void>;
8
+ interface NextGetSeverSideContextWithIronSession extends GetServerSidePropsContext {
9
+ req: NextApiRequestWithIronSession;
10
+ }
11
+ declare type NextGetServerSidePropsHandlerWithIronSession<P> = (context: NextGetSeverSideContextWithIronSession) => Promise<GetServerSidePropsResult<P>>;
12
+ declare function withIronSessionApiRoute(handler: NextApiHandlerWithIronSession, options: IronSessionOptions): NextApiHandlerWithIronSession;
13
+ declare function withIronSessionSsr<P>(handler: NextGetServerSidePropsHandlerWithIronSession<P>, options: IronSessionOptions): NextGetServerSidePropsHandlerWithIronSession<P>;
14
+
15
+ export { NextApiHandlerWithIronSession, NextApiRequestWithIronSession, NextGetServerSidePropsHandlerWithIronSession, withIronSessionApiRoute, withIronSessionSsr };
@@ -0,0 +1,48 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
8
+ var __export = (target, all) => {
9
+ __markAsModule(target);
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __reExport = (target, module2, desc) => {
14
+ if (module2 && typeof module2 === "object" || typeof module2 === "function") {
15
+ for (let key of __getOwnPropNames(module2))
16
+ if (!__hasOwnProp.call(target, key) && key !== "default")
17
+ __defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
18
+ }
19
+ return target;
20
+ };
21
+ var __toModule = (module2) => {
22
+ return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
23
+ };
24
+
25
+ // next/index.ts
26
+ __export(exports, {
27
+ withIronSessionApiRoute: () => withIronSessionApiRoute,
28
+ withIronSessionSsr: () => withIronSessionSsr
29
+ });
30
+ var import_iron_session = __toModule(require("iron-session"));
31
+ function withIronSessionApiRoute(handler, options) {
32
+ return async function nextApiHandlerWrappedWithIronSession(req, res) {
33
+ req.session = await (0, import_iron_session.getIronSession)(req, res, options);
34
+ return handler(req, res);
35
+ };
36
+ }
37
+ function withIronSessionSsr(handler, options) {
38
+ return async function nextGetServerSidePropsHandlerWrappedWithIronSession(context) {
39
+ context.req.session = await (0, import_iron_session.getIronSession)(context.req, context.res, options);
40
+ return handler(context);
41
+ };
42
+ }
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ withIronSessionApiRoute,
46
+ withIronSessionSsr
47
+ });
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../index.ts"],
4
+ "sourcesContent": ["import type {\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n NextApiRequest,\n NextApiResponse,\n} from \"next\";\nimport type { IronSession, IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\n\nexport interface NextApiRequestWithIronSession extends NextApiRequest {\n session: IronSession;\n}\n\nexport declare type NextApiHandlerWithIronSession<T = unknown> = (\n req: NextApiRequestWithIronSession,\n res: NextApiResponse<T>,\n) => void | Promise<void>;\n\ninterface NextGetSeverSideContextWithIronSession\n extends GetServerSidePropsContext {\n req: NextApiRequestWithIronSession;\n}\n\nexport declare type NextGetServerSidePropsHandlerWithIronSession<P> = (\n context: NextGetSeverSideContextWithIronSession,\n) => Promise<GetServerSidePropsResult<P>>;\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandlerWithIronSession,\n options: IronSessionOptions,\n): NextApiHandlerWithIronSession {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n req.session = await getIronSession(req, res, options);\n return handler(req, res);\n };\n}\n\nexport function withIronSessionSsr<P>(\n handler: NextGetServerSidePropsHandlerWithIronSession<P>,\n options: IronSessionOptions,\n): NextGetServerSidePropsHandlerWithIronSession<P> {\n return async function nextGetServerSidePropsHandlerWrappedWithIronSession(\n context: NextGetSeverSideContextWithIronSession,\n ) {\n context.req.session = await getIronSession(\n context.req,\n context.res,\n options,\n );\n return handler(context);\n };\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAOA,0BAA+B;AAoBxB,iCACL,SACA,SAC+B;AAC/B,SAAO,oDAAoD,KAAK,KAAK;AACnE,QAAI,UAAU,MAAM,wCAAe,KAAK,KAAK;AAC7C,WAAO,QAAQ,KAAK;AAAA;AAAA;AAIjB,4BACL,SACA,SACiD;AACjD,SAAO,mEACL,SACA;AACA,YAAQ,IAAI,UAAU,MAAM,wCAC1B,QAAQ,KACR,QAAQ,KACR;AAEF,WAAO,QAAQ;AAAA;AAAA;",
6
+ "names": []
7
+ }
@@ -0,0 +1,19 @@
1
+ // next/index.ts
2
+ import { getIronSession } from "iron-session";
3
+ function withIronSessionApiRoute(handler, options) {
4
+ return async function nextApiHandlerWrappedWithIronSession(req, res) {
5
+ req.session = await getIronSession(req, res, options);
6
+ return handler(req, res);
7
+ };
8
+ }
9
+ function withIronSessionSsr(handler, options) {
10
+ return async function nextGetServerSidePropsHandlerWrappedWithIronSession(context) {
11
+ context.req.session = await getIronSession(context.req, context.res, options);
12
+ return handler(context);
13
+ };
14
+ }
15
+ export {
16
+ withIronSessionApiRoute,
17
+ withIronSessionSsr
18
+ };
19
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../index.ts"],
4
+ "sourcesContent": ["import type {\n GetServerSidePropsContext,\n GetServerSidePropsResult,\n NextApiRequest,\n NextApiResponse,\n} from \"next\";\nimport type { IronSession, IronSessionOptions } from \"iron-session\";\nimport { getIronSession } from \"iron-session\";\n\nexport interface NextApiRequestWithIronSession extends NextApiRequest {\n session: IronSession;\n}\n\nexport declare type NextApiHandlerWithIronSession<T = unknown> = (\n req: NextApiRequestWithIronSession,\n res: NextApiResponse<T>,\n) => void | Promise<void>;\n\ninterface NextGetSeverSideContextWithIronSession\n extends GetServerSidePropsContext {\n req: NextApiRequestWithIronSession;\n}\n\nexport declare type NextGetServerSidePropsHandlerWithIronSession<P> = (\n context: NextGetSeverSideContextWithIronSession,\n) => Promise<GetServerSidePropsResult<P>>;\n\nexport function withIronSessionApiRoute(\n handler: NextApiHandlerWithIronSession,\n options: IronSessionOptions,\n): NextApiHandlerWithIronSession {\n return async function nextApiHandlerWrappedWithIronSession(req, res) {\n req.session = await getIronSession(req, res, options);\n return handler(req, res);\n };\n}\n\nexport function withIronSessionSsr<P>(\n handler: NextGetServerSidePropsHandlerWithIronSession<P>,\n options: IronSessionOptions,\n): NextGetServerSidePropsHandlerWithIronSession<P> {\n return async function nextGetServerSidePropsHandlerWrappedWithIronSession(\n context: NextGetSeverSideContextWithIronSession,\n ) {\n context.req.session = await getIronSession(\n context.req,\n context.res,\n options,\n );\n return handler(context);\n };\n}\n"],
5
+ "mappings": ";AAOA;AAoBO,iCACL,SACA,SAC+B;AAC/B,SAAO,oDAAoD,KAAK,KAAK;AACnE,QAAI,UAAU,MAAM,eAAe,KAAK,KAAK;AAC7C,WAAO,QAAQ,KAAK;AAAA;AAAA;AAIjB,4BACL,SACA,SACiD;AACjD,SAAO,mEACL,SACA;AACA,YAAQ,IAAI,UAAU,MAAM,eAC1B,QAAQ,KACR,QAAQ,KACR;AAEF,WAAO,QAAQ;AAAA;AAAA;",
6
+ "names": []
7
+ }
package/package.json CHANGED
@@ -1,83 +1,142 @@
1
1
  {
2
2
  "name": "iron-session",
3
- "version": "1.0.3",
4
- "private": false,
5
- "description": "Backend agnostic session utility based on @hapi/iron with signed and encrypted cookie serialization ability",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/vvo/iron-session.git"
9
- },
3
+ "version": "2.0.0-alpha.10",
10
4
  "license": "MIT",
11
5
  "author": "Vincent Voyer <vincent@codeagain.com>",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/index.mjs",
9
+ "require": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ },
12
+ "./next": {
13
+ "import": "./next/dist/index.mjs",
14
+ "require": "./next/dist/index.js",
15
+ "types": "./next/dist/index.d.ts"
16
+ }
17
+ },
18
+ "main": "./dist/index.js",
19
+ "module": "./dist/index.mjs",
20
+ "types": "./dist/index.d.ts",
12
21
  "files": [
13
- "index.dist.js",
14
- "index.dist.js.map",
15
- "LICENSE",
16
- "README.md"
22
+ "dist",
23
+ "next/dist"
24
+ ],
25
+ "workspaces": [
26
+ "examples/next.js",
27
+ "examples/next.js-typescript"
17
28
  ],
18
- "main": "index.dist.js",
19
29
  "scripts": {
20
- "build": "babel index.js -o index.dist.js --source-maps",
21
- "prepublishOnly": "yarn build",
22
- "semantic-release": "semantic-release",
23
- "test": "jest --coverage && prettier --check './**/*.?(json|js|md|css)' && eslint ."
30
+ "build": "rimraf dist/ next/dist && tsup src/index.ts && tsup next/index.ts -d next/dist",
31
+ "lint": "eslint . && (cd examples/next.js && npm run lint) && (cd examples/next.js-typescript && npm run lint)",
32
+ "prepublishOnly": "npm run build",
33
+ "test": "jest --coverage && npm run lint"
24
34
  },
25
- "babel": {
26
- "presets": [
27
- [
28
- "@babel/preset-env",
29
- {
30
- "targets": {
31
- "node": "12"
32
- }
33
- }
34
- ]
35
- ]
35
+ "prettier": {
36
+ "trailingComma": "all"
36
37
  },
37
38
  "eslintConfig": {
38
- "env": {
39
- "jest": true,
40
- "node": true
41
- },
39
+ "parser": "@typescript-eslint/parser",
42
40
  "parserOptions": {
43
- "ecmaVersion": 2019,
41
+ "ecmaVersion": 2021,
44
42
  "sourceType": "module"
45
43
  },
46
44
  "plugins": [
47
- "jest"
45
+ "@typescript-eslint"
48
46
  ],
49
47
  "extends": [
50
48
  "eslint:recommended",
51
- "plugin:jest/recommended"
52
- ]
49
+ "plugin:@typescript-eslint/recommended"
50
+ ],
51
+ "rules": {
52
+ "@typescript-eslint/ban-ts-comment": [
53
+ "warn",
54
+ {
55
+ "ts-ignore": "allow-with-description"
56
+ }
57
+ ]
58
+ }
53
59
  },
54
60
  "jest": {
55
- "setupFiles": [
56
- "jest-date-mock"
57
- ]
61
+ "collectCoverageFrom": [
62
+ "src/*.ts",
63
+ "next/*.ts"
64
+ ],
65
+ "coverageProvider": "v8",
66
+ "coverageReporters": [
67
+ "text"
68
+ ],
69
+ "transform": {
70
+ ".ts$": [
71
+ "@swc-node/jest",
72
+ {
73
+ "jsc": {
74
+ "minify": false
75
+ }
76
+ }
77
+ ]
78
+ }
58
79
  },
59
80
  "dependencies": {
60
- "@hapi/iron": "^6.0.0",
61
- "clone": "^2.1.2",
62
- "cookie": "^0.4.0"
81
+ "@types/cookie": "^0.4.0",
82
+ "@types/node": "^16.11.1",
83
+ "cookie": "^0.4.1",
84
+ "iron-store": "^1.3.5"
63
85
  },
64
86
  "devDependencies": {
65
- "@babel/cli": "7.8.4",
66
- "@babel/core": "7.8.7",
67
- "@babel/preset-env": "7.8.7",
68
- "@types/jest": "25.1.3",
69
- "babel-jest": "25.1.0",
70
- "eslint": "6.8.0",
71
- "eslint-plugin-jest": "23.8.1",
72
- "jest": "25.1.0",
87
+ "@swc-node/jest": "1.3.3",
88
+ "@tsconfig/node12": "1.0.9",
89
+ "@types/jest": "27.0.2",
90
+ "@typescript-eslint/eslint-plugin": "5.1.0",
91
+ "@typescript-eslint/parser": "5.1.0",
92
+ "eslint": "8.0.1",
93
+ "jest": "27.3.1",
73
94
  "jest-date-mock": "1.0.8",
74
- "prettier": "1.19.1",
75
- "prettier-plugin-packagejson": "2.0.10",
76
- "semantic-release": "17.0.4"
95
+ "prettier": "2.4.1",
96
+ "prettier-plugin-packagejson": "2.2.13",
97
+ "rimraf": "3.0.2",
98
+ "tsup": "5.4.1",
99
+ "typescript": "4.4.4"
100
+ },
101
+ "peerDependencies": {
102
+ "next": ">=10"
103
+ },
104
+ "peerDependenciesMeta": {
105
+ "next": {
106
+ "optional": true
107
+ }
108
+ },
109
+ "engines": {
110
+ "node": ">=12"
77
111
  },
78
112
  "renovate": {
79
113
  "extends": [
80
- "config:js-lib"
114
+ "config:js-lib",
115
+ ":automergePatch",
116
+ ":automergeBranch",
117
+ ":automergePatch",
118
+ ":automergeBranch",
119
+ ":automergeLinters",
120
+ ":automergeTesters",
121
+ ":automergeTypes"
122
+ ],
123
+ "timezone": "Europe/Paris",
124
+ "schedule": [
125
+ "before 3am on Monday"
126
+ ]
127
+ },
128
+ "tsup": {
129
+ "splitting": false,
130
+ "sourcemap": true,
131
+ "clean": true,
132
+ "dts": true,
133
+ "target": "es2019",
134
+ "format": [
135
+ "esm",
136
+ "cjs"
137
+ ],
138
+ "external": [
139
+ "iron-session"
81
140
  ]
82
141
  }
83
142
  }
package/index.dist.js DELETED
@@ -1,103 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.createSession = createSession;
7
- exports.getSession = getSession;
8
- exports.parseCookie = parseCookie;
9
- exports.deleteCookie = deleteCookie;
10
-
11
- var _iron = _interopRequireDefault(require("@hapi/iron"));
12
-
13
- var _cookie = _interopRequireDefault(require("cookie"));
14
-
15
- var _clone = _interopRequireDefault(require("clone"));
16
-
17
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
-
19
- const defaultTtl = 15 * 24 * 3600;
20
- const cookieName = "__ironSession";
21
-
22
- async function createSession({
23
- password,
24
- ttl = defaultTtl
25
- }) {
26
- return getSession({
27
- password,
28
- ttl
29
- });
30
- }
31
-
32
- async function getSession({
33
- sealed,
34
- password,
35
- ttl = defaultTtl
36
- }) {
37
- const options = { ..._iron.default.defaults,
38
- ttl
39
- };
40
- const store = sealed !== undefined ? await _iron.default.unseal(sealed, password, options) : {
41
- persistent: {},
42
- flash: {}
43
- };
44
- return {
45
- set({
46
- name,
47
- value,
48
- flash = false
49
- }) {
50
- if (flash === true) {
51
- store.flash[name] = (0, _clone.default)(value);
52
- } else {
53
- store.persistent[name] = (0, _clone.default)(value);
54
- }
55
- },
56
-
57
- get({
58
- name = undefined
59
- } = {}) {
60
- if (name === undefined) {
61
- const flash = store.flash;
62
- store.flash = {};
63
- return (0, _clone.default)({ ...flash,
64
- ...store.persistent
65
- });
66
- }
67
-
68
- if (store.flash[name] !== undefined) {
69
- const value = store.flash[name];
70
- delete store.flash[name];
71
- return value; // no need to clone, we removed the reference from the flash store
72
- } else {
73
- return (0, _clone.default)(store.persistent[name]);
74
- }
75
- },
76
-
77
- async serializeCookie(cookieOptions = {}) {
78
- return _cookie.default.serialize(cookieName, (await _iron.default.seal(store, password, options)), {
79
- httpOnly: true,
80
- secure: true,
81
- sameSite: "lax",
82
- maxAge: (ttl === 0 ? 2147483647 : ttl) - 60,
83
- // For Iron, ttl 0 means it will never expire. For browser cookies, maxAge 0 means it will expire immediately. WhilCookie must expire before the seal, otherwise you could have expired seals stored in a cookie
84
- ...cookieOptions
85
- });
86
- }
87
-
88
- };
89
- }
90
-
91
- function parseCookie({
92
- cookie: cookieValue
93
- }) {
94
- return _cookie.default.parse(cookieValue)[cookieName];
95
- }
96
-
97
- function deleteCookie() {
98
- return _cookie.default.serialize(cookieName, "", {
99
- maxAge: 0
100
- });
101
- }
102
-
103
- //# sourceMappingURL=index.dist.js.map
package/index.dist.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["index.js"],"names":[],"mappings":";;;;;;;;;;AAAA;;AACA;;AACA;;;;AAEA,MAAM,UAAU,GAAG,KAAK,EAAL,GAAU,IAA7B;AACA,MAAM,UAAU,GAAG,eAAnB;;AAEO,eAAe,aAAf,CAA6B;AAAE,EAAA,QAAF;AAAY,EAAA,GAAG,GAAG;AAAlB,CAA7B,EAA6D;AAClE,SAAO,UAAU,CAAC;AAAE,IAAA,QAAF;AAAY,IAAA;AAAZ,GAAD,CAAjB;AACD;;AAEM,eAAe,UAAf,CAA0B;AAAE,EAAA,MAAF;AAAU,EAAA,QAAV;AAAoB,EAAA,GAAG,GAAG;AAA1B,CAA1B,EAAkE;AACvE,QAAM,OAAO,GAAG,EAAE,GAAG,cAAK,QAAV;AAAoB,IAAA;AAApB,GAAhB;AACA,QAAM,KAAK,GACT,MAAM,KAAK,SAAX,GACI,MAAM,cAAK,MAAL,CAAY,MAAZ,EAAoB,QAApB,EAA8B,OAA9B,CADV,GAEI;AAAE,IAAA,UAAU,EAAE,EAAd;AAAkB,IAAA,KAAK,EAAE;AAAzB,GAHN;AAKA,SAAO;AACL,IAAA,GAAG,CAAC;AAAE,MAAA,IAAF;AAAQ,MAAA,KAAR;AAAe,MAAA,KAAK,GAAG;AAAvB,KAAD,EAAiC;AAClC,UAAI,KAAK,KAAK,IAAd,EAAoB;AAClB,QAAA,KAAK,CAAC,KAAN,CAAY,IAAZ,IAAoB,oBAAM,KAAN,CAApB;AACD,OAFD,MAEO;AACL,QAAA,KAAK,CAAC,UAAN,CAAiB,IAAjB,IAAyB,oBAAM,KAAN,CAAzB;AACD;AACF,KAPI;;AAQL,IAAA,GAAG,CAAC;AAAE,MAAA,IAAI,GAAG;AAAT,QAAuB,EAAxB,EAA4B;AAC7B,UAAI,IAAI,KAAK,SAAb,EAAwB;AACtB,cAAM,KAAK,GAAG,KAAK,CAAC,KAApB;AACA,QAAA,KAAK,CAAC,KAAN,GAAc,EAAd;AACA,eAAO,oBAAM,EACX,GAAG,KADQ;AAEX,aAAG,KAAK,CAAC;AAFE,SAAN,CAAP;AAID;;AAED,UAAI,KAAK,CAAC,KAAN,CAAY,IAAZ,MAAsB,SAA1B,EAAqC;AACnC,cAAM,KAAK,GAAG,KAAK,CAAC,KAAN,CAAY,IAAZ,CAAd;AACA,eAAO,KAAK,CAAC,KAAN,CAAY,IAAZ,CAAP;AACA,eAAO,KAAP,CAHmC,CAGrB;AACf,OAJD,MAIO;AACL,eAAO,oBAAM,KAAK,CAAC,UAAN,CAAiB,IAAjB,CAAN,CAAP;AACD;AACF,KAzBI;;AA0BL,UAAM,eAAN,CAAsB,aAAa,GAAG,EAAtC,EAA0C;AACxC,aAAO,gBAAO,SAAP,CACL,UADK,GAEL,MAAM,cAAK,IAAL,CAAU,KAAV,EAAiB,QAAjB,EAA2B,OAA3B,CAFD,GAGL;AACE,QAAA,QAAQ,EAAE,IADZ;AAEE,QAAA,MAAM,EAAE,IAFV;AAGE,QAAA,QAAQ,EAAE,KAHZ;AAIE,QAAA,MAAM,EAAE,CAAC,GAAG,KAAK,CAAR,GAAY,UAAZ,GAAyB,GAA1B,IAAiC,EAJ3C;AAI+C;AAC7C,WAAG;AALL,OAHK,CAAP;AAWD;;AAtCI,GAAP;AAwCD;;AAEM,SAAS,WAAT,CAAqB;AAAE,EAAA,MAAM,EAAE;AAAV,CAArB,EAA8C;AACnD,SAAO,gBAAO,KAAP,CAAa,WAAb,EAA0B,UAA1B,CAAP;AACD;;AAEM,SAAS,YAAT,GAAwB;AAC7B,SAAO,gBAAO,SAAP,CAAiB,UAAjB,EAA6B,EAA7B,EAAiC;AACtC,IAAA,MAAM,EAAE;AAD8B,GAAjC,CAAP;AAGD","file":"index.dist.js","sourcesContent":["import Iron from \"@hapi/iron\";\nimport cookie from \"cookie\";\nimport clone from \"clone\";\n\nconst defaultTtl = 15 * 24 * 3600;\nconst cookieName = \"__ironSession\";\n\nexport async function createSession({ password, ttl = defaultTtl }) {\n return getSession({ password, ttl });\n}\n\nexport async function getSession({ sealed, password, ttl = defaultTtl }) {\n const options = { ...Iron.defaults, ttl };\n const store =\n sealed !== undefined\n ? await Iron.unseal(sealed, password, options)\n : { persistent: {}, flash: {} };\n\n return {\n set({ name, value, flash = false }) {\n if (flash === true) {\n store.flash[name] = clone(value);\n } else {\n store.persistent[name] = clone(value);\n }\n },\n get({ name = undefined } = {}) {\n if (name === undefined) {\n const flash = store.flash;\n store.flash = {};\n return clone({\n ...flash,\n ...store.persistent\n });\n }\n\n if (store.flash[name] !== undefined) {\n const value = store.flash[name];\n delete store.flash[name];\n return value; // no need to clone, we removed the reference from the flash store\n } else {\n return clone(store.persistent[name]);\n }\n },\n async serializeCookie(cookieOptions = {}) {\n return cookie.serialize(\n cookieName,\n await Iron.seal(store, password, options),\n {\n httpOnly: true,\n secure: true,\n sameSite: \"lax\",\n maxAge: (ttl === 0 ? 2147483647 : ttl) - 60, // For Iron, ttl 0 means it will never expire. For browser cookies, maxAge 0 means it will expire immediately. WhilCookie must expire before the seal, otherwise you could have expired seals stored in a cookie\n ...cookieOptions\n }\n );\n }\n };\n}\n\nexport function parseCookie({ cookie: cookieValue }) {\n return cookie.parse(cookieValue)[cookieName];\n}\n\nexport function deleteCookie() {\n return cookie.serialize(cookieName, \"\", {\n maxAge: 0\n });\n}\n"]}