UNPKG

@mgcrea/fastify-session

Version:

Session plugin for fastify written in TypeScript supporting both stateless and stateful sessions

227 lines (207 loc) 7.45 kB
import * as fastify from 'fastify'; import { CookieSerializeOptions } from '@fastify/cookie'; import { BinaryToTextEncoding } from 'crypto'; import { EventEmitter } from 'events'; type SecretKey = Buffer | string | (Buffer | string)[]; declare abstract class SessionCrypto { abstract readonly protocol: string; abstract readonly stateless: boolean; abstract deriveSecretKeys(key?: SecretKey, secret?: Buffer | string, salt?: Buffer | string): Buffer[]; abstract sealMessage(message: Buffer, secretKey: Buffer): string; abstract unsealMessage(message: string, secretKeys: Buffer[]): { buffer: Buffer; rotated: boolean; }; } declare class Hmac implements SessionCrypto { readonly protocol = "/hmac"; readonly stateless = false; private readonly algorithm; private readonly encoding; constructor(encoding?: BinaryToTextEncoding, algorithm?: string); deriveSecretKeys(key?: SecretKey, secret?: Buffer | string): Buffer[]; sealMessage(message: Buffer, secretKey: Buffer): string; unsealMessage(message: string, secretKeys: Buffer[]): { buffer: Buffer; rotated: boolean; }; } declare const HMAC: Hmac; type SessionConfiguration = { cookieOptions?: CookieSerializeOptions; crypto?: SessionCrypto; store?: SessionStore | undefined; secretKeys: Buffer[]; }; type SessionOptions = CookieSerializeOptions & { id?: string; }; /** * The Session class is responsible for managing user session data. * It can operate in a stateful or stateless mode depending on the configuration. */ declare class Session<T extends SessionData = SessionData> { #private; readonly id: string; created: boolean; rotated: boolean; changed: boolean; deleted: boolean; saved: boolean; skipped: boolean; /** * This method is used to setup the Session class with global options. */ static configure({ secretKeys, crypto, store, cookieOptions, }: SessionConfiguration): void; /** * Private constructor - instances should be created via the static `create` method */ private constructor(); /** * Create a new session instance. * Checks if the class is configured before creating a session. */ static create<T extends SessionData = SessionData>(data?: Partial<T>, options?: SessionOptions): Promise<Session>; /** * Decoding */ /** * Create a Session from a serialized cookie. * Determines the type of the session (stateful/stateless) and delegates to the appropriate method. */ static fromCookie(cookie: string): Promise<Session>; /** * Create a Session from a stateless cookie. The session data is all stored in the cookie. */ private static fromStatelessCookie; /** * Create a Session from a stateful cookie. The cookie only contains the session id. * The rest of the session data is retrieved from the session store. */ private static fromStatefulCookie; /** * Encoding */ /** * Serialize the Session into a cookie. * The format of the cookie depends on whether the session is stateful or stateless. */ toCookie(): Promise<string>; /** * Refresh the expiration time of the session. Only applicable for stateful sessions. */ touch(): Promise<void>; /** * Delete the session. */ destroy(): Promise<void>; /** * Save the session data to the session store. Only applicable for stateful sessions. */ save(): Promise<void>; get data(): SessionData; get expiry(): number | null; /** * Get a value from the session data. */ get<K extends keyof T = keyof T>(key: K): T[K] | undefined; set<K extends keyof T = keyof T>(key: K, value: T[K]): void; get options(): CookieSerializeOptions; /** * Update the session cookie options. */ setOptions(options: CookieSerializeOptions): void; /** * Check if the session data is empty. */ isEmpty(): boolean; } declare module "fastify" { interface FastifyRequest { session: Session; destroySession: () => Promise<void>; } } /** Matches a JSON object. This type can be useful to enforce some input to be JSON-compatible or as a super-type to be extended from. Don't use this as a direct return type as the user would have to double-cast it: `jsonObject as unknown as CustomResponse`. Instead, you could extend your CustomResponse type from it to ensure your type only uses JSON-compatible types: `interface CustomResponse extends JsonObject { … }`. @category JSON */ type JsonObject = { [Key in string]?: JsonValue | undefined; }; /** Matches a JSON array. @category JSON */ type JsonArray = JsonValue[]; /** Matches any valid JSON primitive value. @category JSON */ type JsonPrimitive = string | number | boolean | null; /** Matches any valid JSON value. @see `Jsonify` if you need to transform a type to one that is assignable to `JsonValue`. @category JSON */ type JsonValue = JsonPrimitive | JsonObject | JsonArray; /** * This interface allows you to declare additional properties on your session object * using [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html). * * @example * declare module '@mgcrea/fastify-session' { * interface SessionData { * views: number; * } * } * */ interface SessionData extends JsonObject { id?: string; } declare abstract class SessionStore { abstract get(sid: string): Promise<[SessionData, number | null] | null>; abstract set(sid: string, session: SessionData, expiry?: number | null): Promise<void>; abstract destroy(sid: string): Promise<void>; all?(): Promise<SessionData[] | Record<string, SessionData> | null>; length?(): Promise<number>; clear?(): Promise<void>; touch?(sid: string, expiry?: number | null): Promise<void>; } type StoredData<T> = [T, number | null]; type MemoryStoreOptions<T> = { store?: Map<string, StoredData<T>>; prefix?: string; }; declare class MemoryStore<T extends SessionData = SessionData> extends EventEmitter implements SessionStore { private store; private readonly prefix; constructor({ store, prefix }?: MemoryStoreOptions<T>); private getKey; set(sessionId: string, session: T, expiry?: number | null): Promise<void>; get(sessionId: string): Promise<[T, number | null] | null>; destroy(sessionId: string): Promise<void>; touch(sessionId: string, expiry?: number | null): Promise<void>; all(): Promise<Record<string, SessionData>>; } type FastifySessionOptions = { salt?: Buffer | string; secret?: Buffer | string; key?: SecretKey; cookieName?: string; cookie?: CookieSerializeOptions; store?: SessionStore; crypto?: SessionCrypto; saveUninitialized?: boolean; logBindings?: Record<string, unknown>; }; declare const CRYPTO_SPLIT_CHAR = "."; declare class ErrorWithCode extends Error { code: string; constructor(code: string, message?: string); } declare const createError: (code: string, message?: string) => ErrorWithCode; declare const _default: fastify.FastifyPluginAsync<FastifySessionOptions>; export { CRYPTO_SPLIT_CHAR, ErrorWithCode, type FastifySessionOptions, HMAC, Hmac, MemoryStore, type SecretKey, Session, SessionCrypto, type SessionData, SessionStore, createError, _default as default };