@prairielearn/session 3.0.9 → 3.0.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @prairielearn/session
2
2
 
3
+ ## 3.0.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 49bb3fa: Upgrade all JavaScript dependencies
8
+
9
+ ## 3.0.10
10
+
11
+ ### Patch Changes
12
+
13
+ - 4a8b376: Upgrade all JavaScript dependencies
14
+
3
15
  ## 3.0.9
4
16
 
5
17
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  import { assert } from 'chai';
2
- import express from 'express';
2
+ import express, {} from 'express';
3
3
  import fetch from 'node-fetch';
4
4
  import { withServer } from '@prairielearn/express-test-utils';
5
5
  import { beforeEnd } from './before-end.js';
@@ -1 +1 @@
1
- {"version":3,"file":"before-end.test.js","sourceRoot":"","sources":["../src/before-end.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,OAA2D,MAAM,SAAS,CAAC;AAClF,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YAC1B,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;gBAC9B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YAEH,IAAI,EAAE,CAAC;QACT,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAEjD,IAAI,KAAK,GAAiB,IAAI,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,IAAa,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE;YACtE,KAAK,GAAG,GAAG,CAAC;YACZ,IAAI,EAAE,CAAC;QACT,CAAC,CAAC,CAAC;QAEH,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;YACtC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAE7B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { assert } from 'chai';\nimport express, { type Request, type Response, type NextFunction } from 'express';\nimport fetch from 'node-fetch';\n\nimport { withServer } from '@prairielearn/express-test-utils';\n\nimport { beforeEnd } from './before-end.js';\n\ndescribe('beforeEnd', () => {\n it('handles errors correctly', async () => {\n const app = express();\n app.use((_req, res, next) => {\n beforeEnd(res, next, async () => {\n throw new Error('oops');\n });\n\n next();\n });\n\n app.get('/', (_req, res) => res.sendStatus(200));\n\n let error: Error | null = null;\n app.use((err: any, _req: Request, _res: Response, next: NextFunction) => {\n error = err;\n next();\n });\n\n await withServer(app, async ({ url }) => {\n const res = await fetch(url);\n\n assert.equal(res.status, 200);\n assert.equal(error?.message, 'oops');\n });\n });\n});\n"]}
1
+ {"version":3,"file":"before-end.test.js","sourceRoot":"","sources":["../src/before-end.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAC9B,OAAO,OAAO,EAAE,EAAkD,MAAM,SAAS,CAAC;AAClF,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAE9D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACxC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;QACtB,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YAC1B,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;gBAC9B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC,CAAC,CAAC;YAEH,IAAI,EAAE,CAAC;QACT,CAAC,CAAC,CAAC;QAEH,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;QAEjD,IAAI,KAAK,GAAiB,IAAI,CAAC;QAC/B,GAAG,CAAC,GAAG,CAAC,CAAC,GAAQ,EAAE,IAAa,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE;YACtE,KAAK,GAAG,GAAG,CAAC;YACZ,IAAI,EAAE,CAAC;QACT,CAAC,CAAC,CAAC;QAEH,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;YACtC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAE7B,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { assert } from 'chai';\nimport express, { type Request, type Response, type NextFunction } from 'express';\nimport fetch from 'node-fetch';\n\nimport { withServer } from '@prairielearn/express-test-utils';\n\nimport { beforeEnd } from './before-end.js';\n\ndescribe('beforeEnd', () => {\n it('handles errors correctly', async () => {\n const app = express();\n app.use((_req, res, next) => {\n beforeEnd(res, next, async () => {\n throw new Error('oops');\n });\n\n next();\n });\n\n app.get('/', (_req, res) => res.sendStatus(200));\n\n let error: Error | null = null;\n app.use((err: any, _req: Request, _res: Response, next: NextFunction) => {\n error = err;\n next();\n });\n\n await withServer(app, async ({ url }) => {\n const res = await fetch(url);\n\n assert.equal(res.status, 200);\n assert.equal(error?.message, 'oops');\n });\n });\n});\n"]}
package/dist/index.d.ts CHANGED
@@ -37,5 +37,5 @@ export interface SessionOptions {
37
37
  writeOverrides?: Omit<CookieOptions, 'secure'>[];
38
38
  };
39
39
  }
40
- export { SessionStore };
40
+ export type { SessionStore };
41
41
  export declare function createSessionMiddleware(options: SessionOptions): import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import onHeaders from 'on-headers';
5
5
  import { beforeEnd } from './before-end.js';
6
6
  import { shouldSecureCookie, getSessionIdFromCookie } from './cookie.js';
7
7
  import { generateSessionId, loadSession, hashSession, truncateExpirationDate, } from './session.js';
8
+ import {} from './store.js';
8
9
  const DEFAULT_COOKIE_NAME = 'session';
9
10
  const DEFAULT_COOKIE_MAX_AGE = 86400000; // 1 day
10
11
  export function createSessionMiddleware(options) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import cookie from 'cookie';\nimport signature from 'cookie-signature';\nimport type { Request, Response, NextFunction } from 'express';\nimport asyncHandler from 'express-async-handler';\nimport onHeaders from 'on-headers';\n\nimport { beforeEnd } from './before-end.js';\nimport { type CookieSecure, shouldSecureCookie, getSessionIdFromCookie } from './cookie.js';\nimport {\n type Session,\n generateSessionId,\n loadSession,\n hashSession,\n truncateExpirationDate,\n} from './session.js';\nimport { type SessionStore } from './store.js';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n session: Session;\n }\n }\n}\n\ninterface CookieOptions {\n secure?: CookieSecure;\n httpOnly?: boolean;\n domain?: string;\n sameSite?: boolean | 'none' | 'lax' | 'strict';\n maxAge?: number;\n}\n\nexport interface SessionOptions {\n secret: string | string[];\n store: SessionStore;\n cookie?: CookieOptions & {\n /**\n * The name of the session cookie. The session is always read from this\n * named cookie, but it may be written to multiple cookies if `writeNames`\n * is provided.\n */\n name?: string;\n /**\n * Multiple write names can be provided to allow for a session cookie to be\n * written to multiple names. This can be useful for a migration of a cookie\n * to an explicit subdomain, for example.\n */\n writeNames?: string[];\n /**\n * Used with `writeNames` to provide additional options for each written cookie.\n */\n writeOverrides?: Omit<CookieOptions, 'secure'>[];\n };\n}\n\nexport { SessionStore };\n\nconst DEFAULT_COOKIE_NAME = 'session';\nconst DEFAULT_COOKIE_MAX_AGE = 86400000; // 1 day\n\nexport function createSessionMiddleware(options: SessionOptions) {\n const secrets = Array.isArray(options.secret) ? options.secret : [options.secret];\n const cookieName = options.cookie?.name ?? DEFAULT_COOKIE_NAME;\n const cookieMaxAge = options.cookie?.maxAge ?? DEFAULT_COOKIE_MAX_AGE;\n const store = options.store;\n\n // Ensure that the session cookie that we're reading from will be written to.\n const writeCookieNames = options.cookie?.writeNames ?? [cookieName];\n if (!writeCookieNames.includes(cookieName)) {\n throw new Error('cookie.name must be included in cookie.writeNames');\n }\n\n // Validate write overrides.\n if (options.cookie?.writeOverrides && !options.cookie.writeNames) {\n throw new Error('cookie.writeOverrides must be used with cookie.writeNames');\n }\n if (\n options.cookie?.writeOverrides &&\n options.cookie.writeOverrides.length !== writeCookieNames.length\n ) {\n throw new Error('cookie.writeOverrides must have the same length as cookie.writeNames');\n }\n\n return asyncHandler(async function sessionMiddleware(\n req: Request,\n res: Response,\n next: NextFunction,\n ) {\n const cookies = cookie.parse(req.headers.cookie ?? '');\n const sessionCookie = cookies[cookieName];\n const cookieSessionId = getSessionIdFromCookie(sessionCookie, secrets);\n const sessionId = cookieSessionId ?? (await generateSessionId());\n req.session = await loadSession(sessionId, req, store, cookieMaxAge);\n\n const originalHash = hashSession(req.session);\n const originalExpirationDate = req.session.getExpirationDate();\n\n onHeaders(res, () => {\n if (!req.session) {\n if (cookieSessionId) {\n // If the request arrived with a session cookie but the session was\n // destroyed, clear the cookie.\n //\n // To cover all our bases, we'll clear *all* known session cookies to\n // ensure that state sessions aren't left behind. We'll also send commands\n // to clear the cookies both on and off the explicit domain, to handle\n // the case where the application has moved from one domain to another.\n writeCookieNames.forEach((cookieName, i) => {\n res.clearCookie(cookieName);\n const domain = options.cookie?.writeOverrides?.[i]?.domain ?? options.cookie?.domain;\n if (domain) {\n res.clearCookie(cookieName, { domain: options.cookie?.domain });\n }\n });\n return;\n }\n\n // There is no session to do anything with.\n return;\n }\n\n const secureCookie = shouldSecureCookie(req, options.cookie?.secure ?? 'auto');\n if (secureCookie && req.protocol !== 'https') {\n // Avoid sending cookie over insecure connection.\n return;\n }\n\n // Ensure that all known session cookies are set to the same value.\n const hasAllCookies = writeCookieNames.every((cookieName) => !!cookies[cookieName]);\n const isNewSession = !cookieSessionId || cookieSessionId !== req.session.id;\n const didExpirationChange =\n originalExpirationDate.getTime() !== req.session.getExpirationDate().getTime();\n if (isNewSession || didExpirationChange || !hasAllCookies) {\n const signedSessionId = signSessionId(req.session.id, secrets[0]);\n writeCookieNames.forEach((cookieName, i) => {\n res.cookie(cookieName, signedSessionId, {\n secure: secureCookie,\n httpOnly: options.cookie?.httpOnly ?? true,\n domain: options.cookie?.domain,\n sameSite: options.cookie?.sameSite ?? false,\n expires: req.session.getExpirationDate(),\n ...(options.cookie?.writeOverrides?.[i] ?? {}),\n });\n });\n }\n });\n\n let sessionPersisted = false;\n\n async function persistSession(req: Request) {\n if (!req.session || sessionPersisted) {\n // There is no session to do anything with.\n return;\n }\n\n sessionPersisted = true;\n\n // If this is a new session, we would have already persisted it to the\n // store, so we don't need to take that into consideration here.\n //\n // If the hash of the session data changed, we'll unconditionally persist\n // the updated data to the store. However, if the hash didn't change, we\n // only want to persist it if the expiration changed *and* if we can set\n // a cookie to reflect the updated expiration date.\n const hashChanged = hashSession(req.session) !== originalHash;\n const expirationChanged =\n originalExpirationDate.getTime() !== req.session.getExpirationDate().getTime();\n if (hashChanged || expirationChanged) {\n await store.set(\n req.session.id,\n req.session,\n // Cookies only support second-level resolution. To ensure consistency\n // between the cookie and the store, truncate the expiration date to\n // the nearest second.\n truncateExpirationDate(req.session.getExpirationDate()),\n );\n }\n }\n\n // We'll attempt to persist the session at the end of the request. This\n // hacky strategy is borrowed from `express-session`.\n beforeEnd(res, next, async () => {\n await persistSession(req);\n });\n\n // We'll also attempt to persist the session before performing a redirect.\n // This is necessary because browsers and `fetch()` implementations aren't\n // required to wait for a response body to be received before following a\n // redirect. So, we need to make sure that the session is persisted before\n // we send the redirect response. This way, the subsequent GET will be able\n // to load the latest session data.\n const originalRedirect = res.redirect as any;\n res.redirect = function redirect(...args: any[]) {\n persistSession(req).then(\n () => originalRedirect.apply(res, args),\n (err) => next(err),\n );\n };\n\n next();\n });\n}\n\nfunction signSessionId(sessionId: string, secret: string): string {\n return signature.sign(sessionId, secret);\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import cookie from 'cookie';\nimport signature from 'cookie-signature';\nimport type { Request, Response, NextFunction } from 'express';\nimport asyncHandler from 'express-async-handler';\nimport onHeaders from 'on-headers';\n\nimport { beforeEnd } from './before-end.js';\nimport { type CookieSecure, shouldSecureCookie, getSessionIdFromCookie } from './cookie.js';\nimport {\n type Session,\n generateSessionId,\n loadSession,\n hashSession,\n truncateExpirationDate,\n} from './session.js';\nimport { type SessionStore } from './store.js';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n interface Request {\n session: Session;\n }\n }\n}\n\ninterface CookieOptions {\n secure?: CookieSecure;\n httpOnly?: boolean;\n domain?: string;\n sameSite?: boolean | 'none' | 'lax' | 'strict';\n maxAge?: number;\n}\n\nexport interface SessionOptions {\n secret: string | string[];\n store: SessionStore;\n cookie?: CookieOptions & {\n /**\n * The name of the session cookie. The session is always read from this\n * named cookie, but it may be written to multiple cookies if `writeNames`\n * is provided.\n */\n name?: string;\n /**\n * Multiple write names can be provided to allow for a session cookie to be\n * written to multiple names. This can be useful for a migration of a cookie\n * to an explicit subdomain, for example.\n */\n writeNames?: string[];\n /**\n * Used with `writeNames` to provide additional options for each written cookie.\n */\n writeOverrides?: Omit<CookieOptions, 'secure'>[];\n };\n}\n\nexport type { SessionStore };\n\nconst DEFAULT_COOKIE_NAME = 'session';\nconst DEFAULT_COOKIE_MAX_AGE = 86400000; // 1 day\n\nexport function createSessionMiddleware(options: SessionOptions) {\n const secrets = Array.isArray(options.secret) ? options.secret : [options.secret];\n const cookieName = options.cookie?.name ?? DEFAULT_COOKIE_NAME;\n const cookieMaxAge = options.cookie?.maxAge ?? DEFAULT_COOKIE_MAX_AGE;\n const store = options.store;\n\n // Ensure that the session cookie that we're reading from will be written to.\n const writeCookieNames = options.cookie?.writeNames ?? [cookieName];\n if (!writeCookieNames.includes(cookieName)) {\n throw new Error('cookie.name must be included in cookie.writeNames');\n }\n\n // Validate write overrides.\n if (options.cookie?.writeOverrides && !options.cookie.writeNames) {\n throw new Error('cookie.writeOverrides must be used with cookie.writeNames');\n }\n if (\n options.cookie?.writeOverrides &&\n options.cookie.writeOverrides.length !== writeCookieNames.length\n ) {\n throw new Error('cookie.writeOverrides must have the same length as cookie.writeNames');\n }\n\n return asyncHandler(async function sessionMiddleware(\n req: Request,\n res: Response,\n next: NextFunction,\n ) {\n const cookies = cookie.parse(req.headers.cookie ?? '');\n const sessionCookie = cookies[cookieName];\n const cookieSessionId = getSessionIdFromCookie(sessionCookie, secrets);\n const sessionId = cookieSessionId ?? (await generateSessionId());\n req.session = await loadSession(sessionId, req, store, cookieMaxAge);\n\n const originalHash = hashSession(req.session);\n const originalExpirationDate = req.session.getExpirationDate();\n\n onHeaders(res, () => {\n if (!req.session) {\n if (cookieSessionId) {\n // If the request arrived with a session cookie but the session was\n // destroyed, clear the cookie.\n //\n // To cover all our bases, we'll clear *all* known session cookies to\n // ensure that state sessions aren't left behind. We'll also send commands\n // to clear the cookies both on and off the explicit domain, to handle\n // the case where the application has moved from one domain to another.\n writeCookieNames.forEach((cookieName, i) => {\n res.clearCookie(cookieName);\n const domain = options.cookie?.writeOverrides?.[i]?.domain ?? options.cookie?.domain;\n if (domain) {\n res.clearCookie(cookieName, { domain: options.cookie?.domain });\n }\n });\n return;\n }\n\n // There is no session to do anything with.\n return;\n }\n\n const secureCookie = shouldSecureCookie(req, options.cookie?.secure ?? 'auto');\n if (secureCookie && req.protocol !== 'https') {\n // Avoid sending cookie over insecure connection.\n return;\n }\n\n // Ensure that all known session cookies are set to the same value.\n const hasAllCookies = writeCookieNames.every((cookieName) => !!cookies[cookieName]);\n const isNewSession = !cookieSessionId || cookieSessionId !== req.session.id;\n const didExpirationChange =\n originalExpirationDate.getTime() !== req.session.getExpirationDate().getTime();\n if (isNewSession || didExpirationChange || !hasAllCookies) {\n const signedSessionId = signSessionId(req.session.id, secrets[0]);\n writeCookieNames.forEach((cookieName, i) => {\n res.cookie(cookieName, signedSessionId, {\n secure: secureCookie,\n httpOnly: options.cookie?.httpOnly ?? true,\n domain: options.cookie?.domain,\n sameSite: options.cookie?.sameSite ?? false,\n expires: req.session.getExpirationDate(),\n ...(options.cookie?.writeOverrides?.[i] ?? {}),\n });\n });\n }\n });\n\n let sessionPersisted = false;\n\n async function persistSession(req: Request) {\n if (!req.session || sessionPersisted) {\n // There is no session to do anything with.\n return;\n }\n\n sessionPersisted = true;\n\n // If this is a new session, we would have already persisted it to the\n // store, so we don't need to take that into consideration here.\n //\n // If the hash of the session data changed, we'll unconditionally persist\n // the updated data to the store. However, if the hash didn't change, we\n // only want to persist it if the expiration changed *and* if we can set\n // a cookie to reflect the updated expiration date.\n const hashChanged = hashSession(req.session) !== originalHash;\n const expirationChanged =\n originalExpirationDate.getTime() !== req.session.getExpirationDate().getTime();\n if (hashChanged || expirationChanged) {\n await store.set(\n req.session.id,\n req.session,\n // Cookies only support second-level resolution. To ensure consistency\n // between the cookie and the store, truncate the expiration date to\n // the nearest second.\n truncateExpirationDate(req.session.getExpirationDate()),\n );\n }\n }\n\n // We'll attempt to persist the session at the end of the request. This\n // hacky strategy is borrowed from `express-session`.\n beforeEnd(res, next, async () => {\n await persistSession(req);\n });\n\n // We'll also attempt to persist the session before performing a redirect.\n // This is necessary because browsers and `fetch()` implementations aren't\n // required to wait for a response body to be received before following a\n // redirect. So, we need to make sure that the session is persisted before\n // we send the redirect response. This way, the subsequent GET will be able\n // to load the latest session data.\n const originalRedirect = res.redirect as any;\n res.redirect = function redirect(...args: any[]) {\n persistSession(req).then(\n () => originalRedirect.apply(res, args),\n (err) => next(err),\n );\n };\n\n next();\n });\n}\n\nfunction signSessionId(sessionId: string, secret: string): string {\n return signature.sign(sessionId, secret);\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import {} from './store.js';
1
2
  export class MemoryStore {
2
3
  sessions = new Map();
3
4
  async set(id, session, expiresAt) {
@@ -1 +1 @@
1
- {"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../src/memory-store.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,WAAW;IACd,QAAQ,GAAG,IAAI,GAAG,EAA6C,CAAC;IAExE,KAAK,CAAC,GAAG,CAAC,EAAU,EAAE,OAAY,EAAE,SAAe;QACjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE;YACpB,SAAS;YACT,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO;YACL,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;SAC7B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;CACF","sourcesContent":["import { type SessionStore, type SessionStoreData } from './store.js';\n\nexport class MemoryStore implements SessionStore {\n private sessions = new Map<string, { expiresAt: Date; data: string }>();\n\n async set(id: string, session: any, expiresAt: Date): Promise<void> {\n this.sessions.set(id, {\n expiresAt,\n data: JSON.stringify(session),\n });\n }\n\n async get(id: string): Promise<SessionStoreData | null> {\n const value = this.sessions.get(id);\n if (!value) return null;\n return {\n expiresAt: value.expiresAt,\n data: JSON.parse(value.data),\n };\n }\n\n async destroy(id: string): Promise<void> {\n this.sessions.delete(id);\n }\n}\n"]}
1
+ {"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../src/memory-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,MAAM,YAAY,CAAC;AAEtE,MAAM,OAAO,WAAW;IACd,QAAQ,GAAG,IAAI,GAAG,EAA6C,CAAC;IAExE,KAAK,CAAC,GAAG,CAAC,EAAU,EAAE,OAAY,EAAE,SAAe;QACjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE;YACpB,SAAS;YACT,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,EAAU;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO;YACL,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC;SAC7B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;CACF","sourcesContent":["import { type SessionStore, type SessionStoreData } from './store.js';\n\nexport class MemoryStore implements SessionStore {\n private sessions = new Map<string, { expiresAt: Date; data: string }>();\n\n async set(id: string, session: any, expiresAt: Date): Promise<void> {\n this.sessions.set(id, {\n expiresAt,\n data: JSON.stringify(session),\n });\n }\n\n async get(id: string): Promise<SessionStoreData | null> {\n const value = this.sessions.get(id);\n if (!value) return null;\n return {\n expiresAt: value.expiresAt,\n data: JSON.parse(value.data),\n };\n }\n\n async destroy(id: string): Promise<void> {\n this.sessions.delete(id);\n }\n}\n"]}
package/dist/session.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import crypto from 'node:crypto';
2
2
  import uid from 'uid-safe';
3
+ import {} from './store.js';
3
4
  export async function generateSessionId() {
4
5
  return await uid(24);
5
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC,OAAO,GAAG,MAAM,UAAU,CAAC;AAa3B,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,MAAM,GAAG,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,GAAY,EACZ,KAAmB,EACnB,MAAc;IAEd,MAAM,gBAAgB,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,gBAAgB,EAAE,SAAS,IAAI,IAAI,CAAC;IAEtD,MAAM,OAAO,GAAG,WAAW,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;IAEtE,IAAI,gBAAgB,IAAI,IAAI,EAAE,CAAC;QAC7B,wEAAwE;QACxE,6DAA6D;QAC7D,MAAM,KAAK,CAAC,GAAG,CACb,SAAS,EACT,OAAO;QACP,sEAAsE;QACtE,oEAAoE;QACpE,sBAAsB;QACtB,sBAAsB,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CACpD,CAAC;IACJ,CAAC;IAED,6CAA6C;IAC7C,IAAI,gBAAgB,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC;QAClC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,SAAiB,EACjB,GAAY,EACZ,KAAmB,EACnB,cAA2B,EAC3B,MAAc;IAEd,MAAM,OAAO,GAAG,EAAE,CAAC;IAEnB,IAAI,SAAS,GAAG,cAAc,CAAC;IAE/B,oBAAoB,CAAgB,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAE9D,oBAAoB,CAAqB,OAAO,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE;QACtE,OAAQ,GAAW,CAAC,OAAO,CAAC;QAC5B,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,oBAAoB,CAAwB,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC/B,GAAG,CAAC,OAAO,GAAG,WAAW,CAAC,MAAM,iBAAiB,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,oBAAoB,CAA+B,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE;QACpF,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;YACtB,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,oBAAoB,CAA2B,OAAO,EAAE,eAAe,EAAE,CAAC,UAAU,EAAE,EAAE;QACtF,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;YACnC,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,UAAU,CAAC;QACzB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,OAAkB,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,oBAAoB,CAAI,GAAW,EAAE,IAAY,EAAE,EAAK;IAC/D,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE;QAC/B,YAAY,EAAE,KAAK;QACnB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,EAAE;KACV,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAU;IAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC5B,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IACrD,OAAO,IAAI,IAAI,CAAC,aAAa,CAAC,CAAC;AACjC,CAAC","sourcesContent":["import crypto from 'node:crypto';\n\nimport type { Request } from 'express';\nimport uid from 'uid-safe';\n\nimport { type SessionStore } from './store.js';\n\nexport interface Session {\n id: string;\n destroy(): Promise<void>;\n regenerate(): Promise<void>;\n setExpiration(expiry: Date | number): void;\n getExpirationDate(): Date;\n [key: string]: any;\n}\n\nexport async function generateSessionId(): Promise<string> {\n return await uid(24);\n}\n\nexport async function loadSession(\n sessionId: string,\n req: Request,\n store: SessionStore,\n maxAge: number,\n): Promise<Session> {\n const sessionStoreData = await store.get(sessionId);\n const expiresAt = sessionStoreData?.expiresAt ?? null;\n\n const session = makeSession(sessionId, req, store, expiresAt, maxAge);\n\n if (sessionStoreData == null) {\n // Immediately persis the new session to the store so that it's assigned\n // an ID and available to query later on in the same request.\n await store.set(\n sessionId,\n session,\n // Cookies only support second-level resolution. To ensure consistency\n // between the cookie and the store, truncate the expiration date to\n // the nearest second.\n truncateExpirationDate(session.getExpirationDate()),\n );\n }\n\n // Copy session data into the session object.\n if (sessionStoreData != null) {\n const { data } = sessionStoreData;\n for (const prop in data) {\n if (!(prop in session)) {\n session[prop] = data[prop];\n }\n }\n }\n\n return session;\n}\n\nexport function makeSession(\n sessionId: string,\n req: Request,\n store: SessionStore,\n expirationDate: Date | null,\n maxAge: number,\n): Session {\n const session = {};\n\n let expiresAt = expirationDate;\n\n defineStaticProperty<Session['id']>(session, 'id', sessionId);\n\n defineStaticProperty<Session['destroy']>(session, 'destroy', async () => {\n delete (req as any).session;\n await store.destroy(sessionId);\n });\n\n defineStaticProperty<Session['regenerate']>(session, 'regenerate', async () => {\n await store.destroy(sessionId);\n req.session = makeSession(await generateSessionId(), req, store, null, maxAge);\n });\n\n defineStaticProperty<Session['getExpirationDate']>(session, 'getExpirationDate', () => {\n if (expiresAt == null) {\n expiresAt = new Date(Date.now() + maxAge);\n }\n return expiresAt;\n });\n\n defineStaticProperty<Session['setExpiration']>(session, 'setExpiration', (expiration) => {\n if (typeof expiration === 'number') {\n expiresAt = new Date(Date.now() + expiration);\n } else {\n expiresAt = expiration;\n }\n });\n\n return session as Session;\n}\n\nexport function hashSession(session: Session): string {\n const str = JSON.stringify(session);\n return crypto.createHash('sha1').update(str, 'utf8').digest('hex');\n}\n\nfunction defineStaticProperty<T>(obj: object, name: string, fn: T) {\n Object.defineProperty(obj, name, {\n configurable: false,\n enumerable: false,\n writable: false,\n value: fn,\n });\n}\n\nexport function truncateExpirationDate(date: Date) {\n const time = date.getTime();\n const truncatedTime = Math.floor(time / 1000) * 1000;\n return new Date(truncatedTime);\n}\n"]}
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from 'node:crypto';\n\nimport type { Request } from 'express';\nimport uid from 'uid-safe';\n\nimport { type SessionStore } from './store.js';\n\nexport interface Session {\n id: string;\n destroy(): Promise<void>;\n regenerate(): Promise<void>;\n setExpiration(expiry: Date | number): void;\n getExpirationDate(): Date;\n [key: string]: any;\n}\n\nexport async function generateSessionId(): Promise<string> {\n return await uid(24);\n}\n\nexport async function loadSession(\n sessionId: string,\n req: Request,\n store: SessionStore,\n maxAge: number,\n): Promise<Session> {\n const sessionStoreData = await store.get(sessionId);\n const expiresAt = sessionStoreData?.expiresAt ?? null;\n\n const session = makeSession(sessionId, req, store, expiresAt, maxAge);\n\n if (sessionStoreData == null) {\n // Immediately persis the new session to the store so that it's assigned\n // an ID and available to query later on in the same request.\n await store.set(\n sessionId,\n session,\n // Cookies only support second-level resolution. To ensure consistency\n // between the cookie and the store, truncate the expiration date to\n // the nearest second.\n truncateExpirationDate(session.getExpirationDate()),\n );\n }\n\n // Copy session data into the session object.\n if (sessionStoreData != null) {\n const { data } = sessionStoreData;\n for (const prop in data) {\n if (!(prop in session)) {\n session[prop] = data[prop];\n }\n }\n }\n\n return session;\n}\n\nexport function makeSession(\n sessionId: string,\n req: Request,\n store: SessionStore,\n expirationDate: Date | null,\n maxAge: number,\n): Session {\n const session = {};\n\n let expiresAt = expirationDate;\n\n defineStaticProperty<Session['id']>(session, 'id', sessionId);\n\n defineStaticProperty<Session['destroy']>(session, 'destroy', async () => {\n delete (req as any).session;\n await store.destroy(sessionId);\n });\n\n defineStaticProperty<Session['regenerate']>(session, 'regenerate', async () => {\n await store.destroy(sessionId);\n req.session = makeSession(await generateSessionId(), req, store, null, maxAge);\n });\n\n defineStaticProperty<Session['getExpirationDate']>(session, 'getExpirationDate', () => {\n if (expiresAt == null) {\n expiresAt = new Date(Date.now() + maxAge);\n }\n return expiresAt;\n });\n\n defineStaticProperty<Session['setExpiration']>(session, 'setExpiration', (expiration) => {\n if (typeof expiration === 'number') {\n expiresAt = new Date(Date.now() + expiration);\n } else {\n expiresAt = expiration;\n }\n });\n\n return session as Session;\n}\n\nexport function hashSession(session: Session): string {\n const str = JSON.stringify(session);\n return crypto.createHash('sha1').update(str, 'utf8').digest('hex');\n}\n\nfunction defineStaticProperty<T>(obj: object, name: string, fn: T) {\n Object.defineProperty(obj, name, {\n configurable: false,\n enumerable: false,\n writable: false,\n value: fn,\n });\n}\n\nexport function truncateExpirationDate(date: Date) {\n const time = date.getTime();\n const truncatedTime = Math.floor(time / 1000) * 1000;\n return new Date(truncatedTime);\n}\n"]}
@@ -1,3 +1,5 @@
1
+ import {} from 'node:http';
2
+ import {} from 'express';
1
3
  export async function withServer(app, fn) {
2
4
  const server = app.listen();
3
5
  await new Promise((resolve, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAY,EAAE,EAA6C;IAC1F,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;IAE5B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,EAAE,CAAC;YACP,MAAM;YACN,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;YAC3B,GAAG,EAAE,oBAAoB,aAAa,CAAC,MAAM,CAAC,EAAE;SACjD,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAEjC,uBAAuB;IACvB,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAEzD,uBAAuB;IACvB,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAElF,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC","sourcesContent":["import { type Server } from 'node:http';\n\nimport { type Express } from 'express';\n\ninterface WithServerContext {\n server: Server;\n port: number;\n url: string;\n}\n\nexport async function withServer(app: Express, fn: (ctx: WithServerContext) => Promise<void>) {\n const server = app.listen();\n\n await new Promise<void>((resolve, reject) => {\n server.on('listening', () => resolve());\n server.on('error', (err) => reject(err));\n });\n\n try {\n await fn({\n server,\n port: getServerPort(server),\n url: `http://localhost:${getServerPort(server)}`,\n });\n } finally {\n server.close();\n }\n}\n\nfunction getServerPort(server: Server): number {\n const address = server.address();\n\n // istanbul ignore next\n if (!address) throw new Error('Server is not listening');\n\n // istanbul ignore next\n if (typeof address === 'string') throw new Error('Server is listening on a pipe');\n\n return address.port;\n}\n"]}
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../src/test-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,MAAM,WAAW,CAAC;AAExC,OAAO,EAAgB,MAAM,SAAS,CAAC;AAQvC,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAY,EAAE,EAA6C;IAC1F,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;IAE5B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QACxC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,EAAE,CAAC;YACP,MAAM;YACN,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;YAC3B,GAAG,EAAE,oBAAoB,aAAa,CAAC,MAAM,CAAC,EAAE;SACjD,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IAEjC,uBAAuB;IACvB,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAEzD,uBAAuB;IACvB,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAElF,OAAO,OAAO,CAAC,IAAI,CAAC;AACtB,CAAC","sourcesContent":["import { type Server } from 'node:http';\n\nimport { type Express } from 'express';\n\ninterface WithServerContext {\n server: Server;\n port: number;\n url: string;\n}\n\nexport async function withServer(app: Express, fn: (ctx: WithServerContext) => Promise<void>) {\n const server = app.listen();\n\n await new Promise<void>((resolve, reject) => {\n server.on('listening', () => resolve());\n server.on('error', (err) => reject(err));\n });\n\n try {\n await fn({\n server,\n port: getServerPort(server),\n url: `http://localhost:${getServerPort(server)}`,\n });\n } finally {\n server.close();\n }\n}\n\nfunction getServerPort(server: Server): number {\n const address = server.address();\n\n // istanbul ignore next\n if (!address) throw new Error('Server is not listening');\n\n // istanbul ignore next\n if (typeof address === 'string') throw new Error('Server is listening on a pipe');\n\n return address.port;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prairielearn/session",
3
- "version": "3.0.9",
3
+ "version": "3.0.11",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -27,21 +27,21 @@
27
27
  "@types/chai": "^5.0.1",
28
28
  "@types/cookie": "^0.6.0",
29
29
  "@types/cookie-signature": "^1.1.2",
30
- "@types/node": "^20.17.11",
30
+ "@types/node": "^20.17.23",
31
31
  "@types/node-fetch": "^2.6.12",
32
32
  "@types/on-headers": "^1.0.3",
33
33
  "@types/set-cookie-parser": "^2.4.10",
34
34
  "@types/uid-safe": "^2.1.5",
35
35
  "c8": "^10.1.3",
36
- "chai": "^5.1.2",
36
+ "chai": "^5.2.0",
37
37
  "express": "^4.21.2",
38
38
  "fetch-cookie": "^3.1.0",
39
- "mocha": "^10.8.2",
39
+ "mocha": "^11.1.0",
40
40
  "node-fetch": "^3.3.2",
41
41
  "set-cookie-parser": "^2.7.1",
42
42
  "source-map-support": "^0.5.21",
43
- "tsx": "^4.19.2",
44
- "typescript": "^5.7.2"
43
+ "tsx": "^4.19.3",
44
+ "typescript": "^5.8.2"
45
45
  },
46
46
  "c8": {
47
47
  "reporter": [
package/src/index.ts CHANGED
@@ -55,7 +55,7 @@ export interface SessionOptions {
55
55
  };
56
56
  }
57
57
 
58
- export { SessionStore };
58
+ export type { SessionStore };
59
59
 
60
60
  const DEFAULT_COOKIE_NAME = 'session';
61
61
  const DEFAULT_COOKIE_MAX_AGE = 86400000; // 1 day