{"version":3,"file":"session.mjs","names":[],"sources":["../../../src/api/routes/session.ts"],"sourcesContent":["import type {\n\tBetterAuthOptions,\n\tGenericEndpointContext,\n} from \"@better-auth/core\";\nimport {\n\tcreateAuthEndpoint,\n\tcreateAuthMiddleware,\n} from \"@better-auth/core/api\";\nimport { APIError, BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { safeJSONParse } from \"@better-auth/core/utils/json\";\nimport { base64Url } from \"@better-auth/utils/base64\";\nimport { binary } from \"@better-auth/utils/binary\";\nimport { createHMAC } from \"@better-auth/utils/hmac\";\n\nimport * as z from \"zod\";\nimport {\n\tdeleteSessionCookie,\n\texpireCookie,\n\tgetChunkedCookie,\n\tsetCookieCache,\n\tsetSessionCookie,\n} from \"../../cookies\";\nimport { getSessionQuerySchema } from \"../../cookies/session-store\";\nimport { symmetricDecodeJWT, verifyJWT } from \"../../crypto\";\nimport { parseSessionOutput, parseUserOutput } from \"../../db\";\nimport type { Prettify, Session, User } from \"../../types\";\nimport { getDate } from \"../../utils/date\";\nimport { isAPIError } from \"../../utils/is-api-error\";\nimport { getShouldSkipSessionRefresh } from \"../state/should-session-refresh\";\n\nexport const getSession = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/get-session\",\n\t\t{\n\t\t\tmethod: [\"GET\", \"POST\"],\n\t\t\toperationId: \"getSession\",\n\t\t\tquery: getSessionQuerySchema,\n\t\t\trequireHeaders: true,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"getSession\",\n\t\t\t\t\tdescription: \"Get the current session\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\trequired: [\"session\", \"user\"],\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (\n\t\t\tctx,\n\t\t): Promise<{\n\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t} | null> => {\n\t\t\tconst deferSessionRefresh =\n\t\t\t\tctx.context.options.session?.deferSessionRefresh;\n\t\t\tconst isPostRequest = ctx.method === \"POST\";\n\n\t\t\tif (isPostRequest && !deferSessionRefresh) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"METHOD_NOT_ALLOWED\",\n\t\t\t\t\tBASE_ERROR_CODES.METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst sessionCookieToken = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\n\t\t\t\tif (!sessionCookieToken) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst sessionDataCookie = getChunkedCookie(\n\t\t\t\t\tctx,\n\t\t\t\t\tctx.context.authCookies.sessionData.name,\n\t\t\t\t);\n\n\t\t\t\tlet sessionDataPayload: {\n\t\t\t\t\tsession: {\n\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t};\n\t\t\t\t\texpiresAt: number;\n\t\t\t\t} | null = null;\n\n\t\t\t\tif (sessionDataCookie) {\n\t\t\t\t\tconst strategy =\n\t\t\t\t\t\tctx.context.options.session?.cookieCache?.strategy || \"compact\";\n\n\t\t\t\t\tif (strategy === \"jwe\") {\n\t\t\t\t\t\t// Decode JWE (encrypted)\n\t\t\t\t\t\tconst payload = await symmetricDecodeJWT<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\texp?: number;\n\t\t\t\t\t\t}>(\n\t\t\t\t\t\t\tsessionDataCookie,\n\t\t\t\t\t\t\tctx.context.secretConfig,\n\t\t\t\t\t\t\t\"better-auth-session\",\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (payload && payload.session && payload.user) {\n\t\t\t\t\t\t\tsessionDataPayload = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\tsession: payload.session,\n\t\t\t\t\t\t\t\t\tuser: payload.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: payload.updatedAt,\n\t\t\t\t\t\t\t\t\tversion: payload.version,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texpiresAt: payload.exp ? payload.exp * 1000 : Date.now(),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\texpireCookie(ctx, ctx.context.authCookies.sessionData);\n\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (strategy === \"jwt\") {\n\t\t\t\t\t\t// Decode JWT (signed with HMAC, not encrypted)\n\t\t\t\t\t\tconst payload = await verifyJWT<{\n\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\texp?: number;\n\t\t\t\t\t\t}>(sessionDataCookie, ctx.context.secret);\n\n\t\t\t\t\t\tif (payload && payload.session && payload.user) {\n\t\t\t\t\t\t\tsessionDataPayload = {\n\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\tsession: payload.session,\n\t\t\t\t\t\t\t\t\tuser: payload.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: payload.updatedAt,\n\t\t\t\t\t\t\t\t\tversion: payload.version,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\texpiresAt: payload.exp ? payload.exp * 1000 : Date.now(),\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\texpireCookie(ctx, ctx.context.authCookies.sessionData);\n\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Decode compact format (or legacy base64-hmac)\n\t\t\t\t\t\tconst parsed = safeJSONParse<{\n\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\tsession: Session;\n\t\t\t\t\t\t\t\tuser: User;\n\t\t\t\t\t\t\t\tupdatedAt: number;\n\t\t\t\t\t\t\t\tversion?: string;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tsignature: string;\n\t\t\t\t\t\t\texpiresAt: number;\n\t\t\t\t\t\t}>(binary.decode(base64Url.decode(sessionDataCookie)));\n\n\t\t\t\t\t\tif (parsed) {\n\t\t\t\t\t\t\tconst isValid = await createHMAC(\n\t\t\t\t\t\t\t\t\"SHA-256\",\n\t\t\t\t\t\t\t\t\"base64urlnopad\",\n\t\t\t\t\t\t\t).verify(\n\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t...parsed.session,\n\t\t\t\t\t\t\t\t\texpiresAt: parsed.expiresAt,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\tparsed.signature,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (isValid) {\n\t\t\t\t\t\t\t\tsessionDataPayload = parsed;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\texpireCookie(ctx, ctx.context.authCookies.sessionData);\n\t\t\t\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst dontRememberMe = await ctx.getSignedCookie(\n\t\t\t\t\tctx.context.authCookies.dontRememberToken.name,\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t);\n\n\t\t\t\t/**\n\t\t\t\t * If session data is present in the cookie, check if it should be used or refreshed\n\t\t\t\t */\n\t\t\t\tif (\n\t\t\t\t\tsessionDataPayload?.session &&\n\t\t\t\t\tctx.context.options.session?.cookieCache?.enabled &&\n\t\t\t\t\t!ctx.query?.disableCookieCache\n\t\t\t\t) {\n\t\t\t\t\tconst session = sessionDataPayload.session;\n\n\t\t\t\t\tconst versionConfig =\n\t\t\t\t\t\tctx.context.options.session?.cookieCache?.version;\n\t\t\t\t\tlet expectedVersion = \"1\";\n\t\t\t\t\tif (versionConfig) {\n\t\t\t\t\t\tif (typeof versionConfig === \"string\") {\n\t\t\t\t\t\t\texpectedVersion = versionConfig;\n\t\t\t\t\t\t} else if (typeof versionConfig === \"function\") {\n\t\t\t\t\t\t\tconst result = versionConfig(session.session, session.user);\n\t\t\t\t\t\t\texpectedVersion =\n\t\t\t\t\t\t\t\tresult instanceof Promise ? await result : result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst cookieVersion = session.version || \"1\";\n\t\t\t\t\tif (cookieVersion !== expectedVersion) {\n\t\t\t\t\t\t// Version mismatch - invalidate the cookie cache\n\t\t\t\t\t\texpireCookie(ctx, ctx.context.authCookies.sessionData);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst cachedSessionExpiresAt = new Date(\n\t\t\t\t\t\t\tsession.session.expiresAt as unknown as string | number | Date,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst hasExpired =\n\t\t\t\t\t\t\tsessionDataPayload.expiresAt < Date.now() ||\n\t\t\t\t\t\t\tcachedSessionExpiresAt < new Date();\n\n\t\t\t\t\t\tif (hasExpired) {\n\t\t\t\t\t\t\t// When the session data cookie has expired, delete it;\n\t\t\t\t\t\t\t//  then we try to fetch from DB\n\t\t\t\t\t\t\texpireCookie(ctx, ctx.context.authCookies.sessionData);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Check if the cookie cache needs to be refreshed based on refreshCache\n\t\t\t\t\t\t\tconst cookieRefreshCache =\n\t\t\t\t\t\t\t\tctx.context.sessionConfig.cookieRefreshCache;\n\n\t\t\t\t\t\t\tif (cookieRefreshCache === false) {\n\t\t\t\t\t\t\t\t// If refreshCache is disabled, return the session from cookie as-is\n\t\t\t\t\t\t\t\tctx.context.session = session;\n\t\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\t\t// Rehydrate date fields from JSON strings before parsing\n\t\t\t\t\t\t\t\tconst parsedSession = parseSessionOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\t\texpiresAt: new Date(session.session.expiresAt),\n\t\t\t\t\t\t\t\t\tcreatedAt: new Date(session.session.createdAt),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(session.session.updatedAt),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t\t...session.user,\n\t\t\t\t\t\t\t\t\tcreatedAt: new Date(session.user.createdAt),\n\t\t\t\t\t\t\t\t\tupdatedAt: new Date(session.user.updatedAt),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst timeUntilExpiry = sessionDataPayload.expiresAt - Date.now();\n\t\t\t\t\t\t\tconst updateAge = cookieRefreshCache.updateAge * 1000; // Convert to milliseconds\n\t\t\t\t\t\t\tconst shouldSkipSessionRefresh =\n\t\t\t\t\t\t\t\tawait getShouldSkipSessionRefresh();\n\n\t\t\t\t\t\t\tif (timeUntilExpiry < updateAge && !shouldSkipSessionRefresh) {\n\t\t\t\t\t\t\t\tconst cookieMaxAge =\n\t\t\t\t\t\t\t\t\tctx.context.options.session?.cookieCache?.maxAge || 60 * 5;\n\t\t\t\t\t\t\t\tconst newExpiresAt = getDate(cookieMaxAge, \"sec\");\n\t\t\t\t\t\t\t\tconst refreshedSession = {\n\t\t\t\t\t\t\t\t\tsession: {\n\t\t\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\t\t\texpiresAt: newExpiresAt,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t\t\t\tupdatedAt: Date.now(),\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t// Set the refreshed cookie cache\n\t\t\t\t\t\t\t\tawait setCookieCache(ctx, refreshedSession, false);\n\n\t\t\t\t\t\t\t\t// Also refresh the session_token cookie expiry\n\t\t\t\t\t\t\t\tconst sessionTokenOptions =\n\t\t\t\t\t\t\t\t\tctx.context.authCookies.sessionToken.attributes;\n\t\t\t\t\t\t\t\tconst sessionTokenMaxAge = dontRememberMe\n\t\t\t\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t\t\t\t: ctx.context.sessionConfig.expiresIn;\n\t\t\t\t\t\t\t\tawait ctx.setSignedCookie(\n\t\t\t\t\t\t\t\t\tctx.context.authCookies.sessionToken.name,\n\t\t\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t\t\t\tctx.context.secret,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...sessionTokenOptions,\n\t\t\t\t\t\t\t\t\t\tmaxAge: sessionTokenMaxAge,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\t\t// Rehydrate date fields from JSON strings before parsing\n\t\t\t\t\t\t\t\tconst parsedRefreshedSession = parseSessionOutput(\n\t\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...refreshedSession.session,\n\t\t\t\t\t\t\t\t\t\texpiresAt: new Date(refreshedSession.session.expiresAt),\n\t\t\t\t\t\t\t\t\t\tcreatedAt: new Date(refreshedSession.session.createdAt),\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(refreshedSession.session.updatedAt),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tconst parsedRefreshedUser = parseUserOutput(\n\t\t\t\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t...refreshedSession.user,\n\t\t\t\t\t\t\t\t\t\tcreatedAt: new Date(refreshedSession.user.createdAt),\n\t\t\t\t\t\t\t\t\t\tupdatedAt: new Date(refreshedSession.user.updatedAt),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tctx.context.session = {\n\t\t\t\t\t\t\t\t\tsession: parsedRefreshedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedRefreshedUser,\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\t\tsession: parsedRefreshedSession,\n\t\t\t\t\t\t\t\t\tuser: parsedRefreshedUser,\n\t\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\t\t\tconst parsedSession = parseSessionOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t...session.session,\n\t\t\t\t\t\t\t\texpiresAt: new Date(session.session.expiresAt),\n\t\t\t\t\t\t\t\tcreatedAt: new Date(session.session.createdAt),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(session.session.updatedAt),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, {\n\t\t\t\t\t\t\t\t...session.user,\n\t\t\t\t\t\t\t\tcreatedAt: new Date(session.user.createdAt),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(session.user.updatedAt),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.context.session = {\n\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\t\t} as {\n\t\t\t\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst session =\n\t\t\t\t\tawait ctx.context.internalAdapter.findSession(sessionCookieToken);\n\t\t\t\tctx.context.session = session;\n\t\t\t\tif (!session || session.session.expiresAt < new Date()) {\n\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\tif (session) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * if session expired clean up the session\n\t\t\t\t\t\t * Only delete on POST when deferSessionRefresh is enabled\n\t\t\t\t\t\t */\n\t\t\t\t\t\tif (!deferSessionRefresh || isPostRequest) {\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.deleteSession(\n\t\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn ctx.json(null);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * We don't need to update the session if the user doesn't want to be remembered\n\t\t\t\t * or if the session refresh is disabled\n\t\t\t\t */\n\t\t\t\tif (dontRememberMe || ctx.query?.disableRefresh) {\n\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\tconst parsedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tsession.session,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t} as {\n\t\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tconst expiresIn = ctx.context.sessionConfig.expiresIn;\n\t\t\t\tconst updateAge = ctx.context.sessionConfig.updateAge;\n\t\t\t\t/**\n\t\t\t\t * Calculate last updated date to throttle write updates to database\n\t\t\t\t * Formula: ({expiry date} - sessionMaxAge) + sessionUpdateAge\n\t\t\t\t *\n\t\t\t\t * e.g. ({expiry date} - 30 days) + 1 hour\n\t\t\t\t *\n\t\t\t\t * inspired by: https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/lib/actions/session.ts\n\t\t\t\t */\n\t\t\t\tconst sessionIsDueToBeUpdatedDate =\n\t\t\t\t\tsession.session.expiresAt.valueOf() -\n\t\t\t\t\texpiresIn * 1000 +\n\t\t\t\t\tupdateAge * 1000;\n\t\t\t\tconst shouldBeUpdated = sessionIsDueToBeUpdatedDate <= Date.now();\n\t\t\t\tconst disableRefresh =\n\t\t\t\t\tctx.query?.disableRefresh ||\n\t\t\t\t\tctx.context.options.session?.disableSessionRefresh;\n\t\t\t\tconst shouldSkipSessionRefresh = await getShouldSkipSessionRefresh();\n\t\t\t\tconst needsRefresh =\n\t\t\t\t\tshouldBeUpdated && !disableRefresh && !shouldSkipSessionRefresh;\n\n\t\t\t\t/**\n\t\t\t\t * When deferSessionRefresh is enabled and this is a GET request,\n\t\t\t\t * return the session without performing writes, but include needsRefresh flag\n\t\t\t\t */\n\t\t\t\tif (deferSessionRefresh && !isPostRequest) {\n\t\t\t\t\tawait setCookieCache(ctx, session, !!dontRememberMe);\n\t\t\t\t\tconst parsedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tsession.session,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t\tneedsRefresh,\n\t\t\t\t\t} as unknown as {\n\t\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (needsRefresh) {\n\t\t\t\t\tconst updatedSession =\n\t\t\t\t\t\tawait ctx.context.internalAdapter.updateSession(\n\t\t\t\t\t\t\tsession.session.token,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\texpiresAt: getDate(ctx.context.sessionConfig.expiresIn, \"sec\"),\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\tif (!updatedSession) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * Handle case where session update fails (e.g., concurrent deletion)\n\t\t\t\t\t\t */\n\t\t\t\t\t\tdeleteSessionCookie(ctx);\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"UNAUTHORIZED\",\n\t\t\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst maxAge =\n\t\t\t\t\t\t(updatedSession.expiresAt.valueOf() - Date.now()) / 1000;\n\t\t\t\t\tawait setSessionCookie(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tsession: updatedSession,\n\t\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmaxAge,\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\t\tconst parsedUpdatedSession = parseSessionOutput(\n\t\t\t\t\t\tctx.context.options,\n\t\t\t\t\t\tupdatedSession,\n\t\t\t\t\t);\n\t\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\t\treturn ctx.json({\n\t\t\t\t\t\tsession: parsedUpdatedSession,\n\t\t\t\t\t\tuser: parsedUser,\n\t\t\t\t\t} as unknown as {\n\t\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait setCookieCache(ctx, session, !!dontRememberMe);\n\t\t\t\t// Parse session and user to ensure additionalFields are included\n\t\t\t\tconst parsedSession = parseSessionOutput(\n\t\t\t\t\tctx.context.options,\n\t\t\t\t\tsession.session,\n\t\t\t\t);\n\t\t\t\tconst parsedUser = parseUserOutput(ctx.context.options, session.user);\n\t\t\t\treturn ctx.json({\n\t\t\t\t\tsession: parsedSession,\n\t\t\t\t\tuser: parsedUser,\n\t\t\t\t} as {\n\t\t\t\t\tsession: Session<Option[\"session\"], Option[\"plugins\"]>;\n\t\t\t\t\tuser: User<Option[\"user\"], Option[\"plugins\"]>;\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tif (isAPIError(error)) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tctx.context.logger.error(\"INTERNAL_SERVER_ERROR\", error);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tBASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n\nexport const getSessionFromCtx = async <\n\tU extends Record<string, any> = Record<string, any>,\n\tS extends Record<string, any> = Record<string, any>,\n>(\n\tctx: GenericEndpointContext,\n\tconfig?:\n\t\t| {\n\t\t\t\tdisableCookieCache?: boolean;\n\t\t\t\tdisableRefresh?: boolean;\n\t\t  }\n\t\t| undefined,\n) => {\n\tif (ctx.context.session) {\n\t\treturn ctx.context.session as {\n\t\t\tsession: S & Session;\n\t\t\tuser: U & User;\n\t\t};\n\t}\n\n\tconst session = await getSession()({\n\t\t...ctx,\n\t\tmethod: \"GET\",\n\t\tasResponse: false,\n\t\theaders: ctx.headers!,\n\t\treturnHeaders: false,\n\t\treturnStatus: false,\n\t\tquery: {\n\t\t\t...config,\n\t\t\t...ctx.query,\n\t\t},\n\t}).catch((e) => {\n\t\treturn null;\n\t});\n\tctx.context.session = session;\n\treturn session as {\n\t\tsession: S & Session;\n\t\tuser: U & User;\n\t} | null;\n};\n\n/**\n * The middleware forces the endpoint to require a valid session.\n */\nexport const sessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\tmessage: \"Unauthorized\",\n\t\t\tcode: \"UNAUTHORIZED\",\n\t\t});\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * This middleware forces the endpoint to require a valid session and ignores cookie cache.\n * This should be used for sensitive operations like password changes, account deletion, etc.\n * to ensure that revoked sessions cannot be used even if they're still cached in cookies.\n */\nexport const sensitiveSessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx, { disableCookieCache: true });\n\tif (!session?.session) {\n\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\tmessage: \"Unauthorized\",\n\t\t\tcode: \"UNAUTHORIZED\",\n\t\t});\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n\n/**\n * This middleware allows you to call the endpoint on the client if session is valid.\n * However, if called on the server, no session is required.\n */\nexport const requestOnlySessionMiddleware = createAuthMiddleware(\n\tasync (ctx) => {\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session?.session && (ctx.request || ctx.headers)) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Unauthorized\",\n\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t});\n\t\t}\n\t\treturn { session };\n\t},\n);\n\n/**\n * This middleware forces the endpoint to require a valid session,\n * as well as making sure the session is fresh before proceeding.\n *\n * Session freshness check will be skipped if the session config's freshAge\n * is set to 0\n */\nexport const freshSessionMiddleware = createAuthMiddleware(async (ctx) => {\n\tconst session = await getSessionFromCtx(ctx);\n\tif (!session?.session) {\n\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\tmessage: \"Unauthorized\",\n\t\t\tcode: \"UNAUTHORIZED\",\n\t\t});\n\t}\n\tif (ctx.context.sessionConfig.freshAge === 0) {\n\t\treturn {\n\t\t\tsession,\n\t\t};\n\t}\n\tconst freshAge = ctx.context.sessionConfig.freshAge;\n\tconst lastUpdated = new Date(\n\t\tsession.session.updatedAt || session.session.createdAt,\n\t).getTime();\n\tconst now = Date.now();\n\tconst isFresh = now - lastUpdated < freshAge * 1000;\n\tif (!isFresh) {\n\t\tthrow APIError.from(\"FORBIDDEN\", BASE_ERROR_CODES.SESSION_NOT_FRESH);\n\t}\n\treturn {\n\t\tsession,\n\t};\n});\n/**\n * user active sessions list\n */\nexport const listSessions = <Option extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/list-sessions\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\toperationId: \"listUserSessions\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\trequireHeaders: true,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listUserSessions\",\n\t\t\t\t\tdescription: \"List all active sessions for the user\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/Session\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\ttry {\n\t\t\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\t\t\tctx.context.session.user.id,\n\t\t\t\t\t{ onlyActiveSessions: true },\n\t\t\t\t);\n\t\t\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\t\t\treturn session.expiresAt > new Date();\n\t\t\t\t});\n\t\t\t\treturn ctx.json(\n\t\t\t\t\tactiveSessions.map((session) =>\n\t\t\t\t\t\tparseSessionOutput(ctx.context.options, session),\n\t\t\t\t\t) as unknown as Prettify<\n\t\t\t\t\t\tSession<Option[\"session\"], Option[\"plugins\"]>\n\t\t\t\t\t>[],\n\t\t\t\t);\n\t\t\t} catch (e: any) {\n\t\t\t\tctx.context.logger.error(e);\n\t\t\t\tthrow ctx.error(\"INTERNAL_SERVER_ERROR\");\n\t\t\t}\n\t\t},\n\t);\n\n/**\n * revoke a single session\n */\nexport const revokeSession = createAuthEndpoint(\n\t\"/revoke-session\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"The token to revoke\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\trequireHeaders: true,\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription: \"Revoke a single session\",\n\t\t\t\trequestBody: {\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"The token to revoke\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\trequired: [\"token\"],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if the session was revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst token = ctx.body.token;\n\t\tconst session = await ctx.context.internalAdapter.findSession(token);\n\n\t\tif (session?.session.userId === ctx.context.session.user.id) {\n\t\t\ttry {\n\t\t\t\tawait ctx.context.internalAdapter.deleteSession(token);\n\t\t\t} catch (error) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\terror && typeof error === \"object\" && \"name\" in error\n\t\t\t\t\t\t? (error.name as string)\n\t\t\t\t\t\t: \"\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\tmessage: \"Internal Server Error\",\n\t\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n/**\n * revoke all user sessions\n */\nexport const revokeSessions = createAuthEndpoint(\n\t\"/revoke-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sensitiveSessionMiddleware],\n\t\trequireHeaders: true,\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription: \"Revoke all sessions for the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if all sessions were revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\ttry {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(\n\t\t\t\tctx.context.session.user.id,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tctx.context.logger.error(\n\t\t\t\terror && typeof error === \"object\" && \"name\" in error\n\t\t\t\t\t? (error.name as string)\n\t\t\t\t\t: \"\",\n\t\t\t\terror,\n\t\t\t);\n\t\t\tthrow APIError.from(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: \"Internal Server Error\",\n\t\t\t\tcode: \"INTERNAL_SERVER_ERROR\",\n\t\t\t});\n\t\t}\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n\nexport const revokeOtherSessions = createAuthEndpoint(\n\t\"/revoke-other-sessions\",\n\t{\n\t\tmethod: \"POST\",\n\t\trequireHeaders: true,\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Revoke all other sessions for the user except the current one\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"Indicates if all other sessions were revoked successfully\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session;\n\t\tif (!session.user) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", {\n\t\t\t\tmessage: \"Unauthorized\",\n\t\t\t\tcode: \"UNAUTHORIZED\",\n\t\t\t});\n\t\t}\n\t\tconst sessions = await ctx.context.internalAdapter.listSessions(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst activeSessions = sessions.filter((session) => {\n\t\t\treturn session.expiresAt > new Date();\n\t\t});\n\t\tconst otherSessions = activeSessions.filter(\n\t\t\t(session) => session.token !== ctx.context.session.session.token,\n\t\t);\n\t\tawait Promise.all(\n\t\t\totherSessions.map((session) =>\n\t\t\t\tctx.context.internalAdapter.deleteSession(session.token),\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}