@bureaudouble/context-session@0.0.9
latest
It is unknown whether this package works with Cloudflare Workers, Node.js, Deno, Bun, Browsers




JSR Score
29%
Published
4 months ago (0.0.9)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126import { getCookies, setCookie } from "jsr:/@std/http@1.0.13/cookie"; import { generateKey, signJWT, validateJWT } from "jsr:@cross/jwt@0.5.1"; export { signJWT, validateJWT } from "jsr:@cross/jwt@0.5.1" import type { CookieOptions } from "./cookie_option.ts"; import { Session } from "./session.ts"; export type { WithSession } from "./interface.ts"; export type { Session } from "./session.ts"; export function key(): Promise<CryptoKey> { const key = Deno.env.get("APP_KEY"); if (!key) { console.warn( "[FRESH SESSION] Warning: We didn't detect a env variable `APP_KEY`, if you are in production please fix this ASAP to avoid any security issue.", ); } return generateKey(key || "not-secret", { algorithm: "HS512", allowInsecureKeyLengths: true, }); } export function createCookieSessionStorage( cookieOptions?: CookieOptions, ): Promise<CookieSessionStorage> { let cookieOptionsParam = cookieOptions; if (!cookieOptionsParam) { cookieOptionsParam = {}; } return CookieSessionStorage.init(cookieOptionsParam); } export class CookieSessionStorage { #key: CryptoKey; #cookieOptions: CookieOptions; constructor(key: CryptoKey, cookieOptions: CookieOptions) { this.#key = key; this.#cookieOptions = cookieOptions; } static async init( cookieOptions: CookieOptions, ): Promise<CookieSessionStorage> { return new CookieSessionStorage(await key(), cookieOptions); } create(): Session { return new Session(); } exists(sessionId: string): Promise<boolean> { return Promise.resolve(validateJWT(sessionId, this.#key)) .then(() => true) .catch((e) => { console.warn("Invalid JWT token, creating new session..."); return false; }); } async get(sessionId: string): Promise<Session> { const payload = (await validateJWT(sessionId, this.#key)) ?? {}; const { _flash = {}, ...data } = payload as any; return new Session(data as object, _flash); } async persist(response: Response, session: Session): Promise<Response> { if (session.doKeyRotate) { this.keyRotate(); } setCookie(response.headers, { name: "sessionId", value: await signJWT( { ...session.data, _flash: session.flashedData }, this.#key, ), path: "/", ...this.#cookieOptions, }); return response; } /** * Does not work in cookie sessions. */ keyRotate() { console.warn( "%c*****************************************************\n* '.keyRotate' is not supported for cookie sessions *\n*****************************************************", "color: yellow;", ); } } export function cookieSession<T>( cookieOptions: CookieOptions & { apply: (ctx: T, session: Session) => void; get: (ctx: T) => Session; headers: (ctx: T) => Headers; next: (ctx: T) => Response | Promise<Response>; }, ): (ctx: T) => Promise<Response> { return async (ctx) => { const { sessionId } = getCookies(cookieOptions?.headers(ctx)); const cookieSessionStorage = await createCookieSessionStorage( cookieOptions, ); if (sessionId && (await cookieSessionStorage.exists(sessionId))) { cookieOptions?.apply(ctx, await cookieSessionStorage.get(sessionId)); } if (!cookieOptions?.get(ctx)) { cookieOptions?.apply(ctx, cookieSessionStorage.create()); } const response = await cookieOptions.next(ctx); const session = cookieOptions?.get(ctx); return session ? cookieSessionStorage.persist(response, session) : response; }; }