/** * The sealed cookie carries only what `verify()` reads back — the sid * is the store lookup key; everything else about the session (userId, * claims, freshAt, …) lives server-side in the {@link SessionRecord} * so it can never go stale inside an already-issued cookie. * * @typedef {object} SessionTokenPayload * @property {string} sid Server-side session ID (opaque, from CSPRNG). * @property {number} iat Issued-at (ms epoch). * @property {number} exp Absolute expiry (ms epoch). * @property {string} [fp] Fingerprint hash (IP + UA), when `bindTo` is enabled. * @property {string} [imp] Admin user ID that started the impersonation. */ /** * Generate a fresh session ID — 128 bits of CSPRNG entropy, base64url. * Comfortably beyond the birthday-collision bound for any realistic * user base. * * @returns {string} */ declare function generateSessionId(): string; /** * Encode a session payload as a sealed (AES-256-GCM authenticated) * opaque token. Wraps `@exortek/crypto.seal` — the TTL of the seal * matches the payload's own `exp - now`, so the transport layer refuses * to open an expired token before we even parse it. * * @param {SessionTokenPayload} payload * @param {string | Buffer | Uint8Array} secret * @param {{ now?: number }} [options] * @returns {string} base64url token. */ declare function encodeToken(payload: SessionTokenPayload$1, secret: string | Buffer | Uint8Array, options?: { now?: number; }): string; /** * Decode + authenticate a session token. Returns the payload on * success, or a structured failure via {@link SessionError}. Callers * generally want to catch and translate to `null` — the manager does * this so `verify(req)` never throws for a wrong-shape stored value. * * `secret` may be a single key or an array `[newest, …older]` for * secret rotation. `crypto.unseal` walks the list; the first that * authenticates wins. * * @param {string} token * @param {string | Buffer | Uint8Array | Array} secret * @param {{ now?: number }} [options] * @returns {SessionTokenPayload} * @throws {SessionError} — with `INVALID_TOKEN` / `EXPIRED` / `INVALID_ARGUMENT`. */ declare function decodeToken(token: string, secret: string | Buffer | Uint8Array | Array, options?: { now?: number; }): SessionTokenPayload$1; /** * The sealed cookie carries only what `verify()` reads back — the sid * is the store lookup key; everything else about the session (userId, * claims, freshAt, …) lives server-side in the {@link SessionRecord} * so it can never go stale inside an already-issued cookie. */ type SessionTokenPayload$1 = { /** * Server-side session ID (opaque, from CSPRNG). */ sid: string; /** * Issued-at (ms epoch). */ iat: number; /** * Absolute expiry (ms epoch). */ exp: number; /** * Fingerprint hash (IP + UA), when `bindTo` is enabled. */ fp?: string | undefined; /** * Admin user ID that started the impersonation. */ imp?: string | undefined; }; /** * Parse a `Cookie:` request header into a name → value map. Values are * URL-decoded per RFC 6265. Duplicate names keep the first occurrence * (browsers send at most one value per name, but proxies sometimes * fold headers). * * @param {string | null | undefined} header * @returns {Record} */ declare function parseCookies$1(header: string | null | undefined): Record; type CookieOptions$2 = { domain?: string | undefined; path?: string | undefined; secure?: boolean | undefined; httpOnly?: boolean | undefined; sameSite?: "lax" | "strict" | "none" | undefined; /** * Seconds. */ maxAge?: number | undefined; expires?: Date | undefined; }; /** * Build a `Set-Cookie` header value. Attribute violations (bad * SameSite, __Host- / __Secure- prefix, unsafe Domain / Path) surface * as {@link SessionError} `INVALID_ARGUMENT` at boot time. * * @param {string} name * @param {string} value * @param {CookieOptions} [options] * @returns {string} */ declare function serialiseCookie(name: string, value: string, options?: CookieOptions$1): string; /** * Build a `Set-Cookie` value that instructs the browser to delete the * cookie. * * @param {string} name * @param {CookieOptions} [options] * @returns {string} */ declare function serialiseDeleteCookie(name: string, options?: CookieOptions$1): string; /** * @typedef {import('@exortek/shared/cookie').CookieOptions} CookieOptions */ /** * Parse a `Cookie:` request header into a name → value map. Pure * re-export of the shared parser — never throws. * * @param {string | null | undefined} header * @returns {Record} */ declare const parseCookies: typeof parseCookies$1; type CookieOptions$1 = CookieOptions$2; /** * @typedef {object} SessionRecord * @property {string} sid * @property {string | null} uid * @property {object} claims * @property {number} issuedAt * @property {number} expiresAt Absolute TTL — after this the session is dead. * @property {number} lastSeenAt Refreshed on `touch`; drives the idle-TTL check. * @property {number} [freshAt] Last fresh-auth timestamp (sudo mode). * @property {string} [deviceLabel] * @property {string} [ip] * @property {string} [ua] * @property {string} [impersonatedBy] Admin user ID if this is an impersonation. * @property {boolean} isAnonymous * @property {boolean} revoked `true` once `revoke` has been called. * @property {string} [revokedReason] */ /** * @typedef {object} SessionStore * @property {(sid: string) => Promise} get * @property {(record: SessionRecord) => Promise} put * Insert-or-replace. Also updates the reverse `user → set(sid)` index. * @property {(sid: string, patch: Partial) => Promise} update * Merge-patch a session. Returns the updated record, or `null` if the * sid isn't present. * @property {(sid: string, reason?: string) => Promise} revoke * Mark a single session as revoked. Returns `true` if it was already * in the store (whether previously revoked or not), `false` if not * present. * @property {(uid: string, reason?: string) => Promise} revokeAllForUser * Revoke every session belonging to `uid`. Returns the count revoked. * @property {(uid: string, keepSid: string, reason?: string) => Promise} revokeAllExcept * Revoke every session for `uid` other than `keepSid`. Returns the * count revoked. * @property {(uid: string) => Promise} listByUser * Return every non-revoked, non-expired session for `uid`, newest first. * @property {(uid: string) => Promise} countActive * Number of non-revoked, non-expired sessions for `uid`. Cheaper than * materialising the array when you only need the count. * @property {() => void} [_stop] * Optional cleanup — memory store starts a sweep timer that * `_stop()` cancels. Called from tests; production doesn't need it. */ /** * @typedef {object} MemoryStoreOptions * @property {number} [maxSessions=100000] * Absolute cap on session count. Protects against a leaky app slowly * filling process memory. When hit, expired/revoked entries are swept * first; if still full, the least-recently-seen ANONYMOUS session is * evicted before any authenticated one — so an anonymous-session * flood can't force-logout real users. With `anonymous: true`, still * pair this store with an IP rate limit on session creation. * @property {number} [sweepMs=60000] * How often the store scans for expired entries and drops them. * Deferred cleanup is fine — expired records never verify, and * `listByUser` filters them out — but a periodic sweep keeps the * backing map from ballooning. */ /** * In-process session store. Single-worker deployments and integration * tests only. For anything that runs across more than one Node process, * use `@exortek/session/stores/redis`. * * @param {MemoryStoreOptions} [options] * @returns {SessionStore} */ declare function memoryStore(options?: MemoryStoreOptions): SessionStore$1; type SessionRecord$1 = { sid: string; uid: string | null; claims: object; issuedAt: number; /** * Absolute TTL — after this the session is dead. */ expiresAt: number; /** * Refreshed on `touch`; drives the idle-TTL check. */ lastSeenAt: number; /** * Last fresh-auth timestamp (sudo mode). */ freshAt?: number | undefined; deviceLabel?: string | undefined; ip?: string | undefined; ua?: string | undefined; /** * Admin user ID if this is an impersonation. */ impersonatedBy?: string | undefined; isAnonymous: boolean; /** * `true` once `revoke` has been called. */ revoked: boolean; revokedReason?: string | undefined; }; type SessionStore$1 = { get: (sid: string) => Promise; /** * Insert-or-replace. Also updates the reverse `user → set(sid)` index. */ put: (record: SessionRecord$1) => Promise; /** * Merge-patch a session. Returns the updated record, or `null` if the * sid isn't present. */ update: (sid: string, patch: Partial) => Promise; /** * Mark a single session as revoked. Returns `true` if it was already * in the store (whether previously revoked or not), `false` if not * present. */ revoke: (sid: string, reason?: string) => Promise; /** * Revoke every session belonging to `uid`. Returns the count revoked. */ revokeAllForUser: (uid: string, reason?: string) => Promise; /** * Revoke every session for `uid` other than `keepSid`. Returns the * count revoked. */ revokeAllExcept: (uid: string, keepSid: string, reason?: string) => Promise; /** * Return every non-revoked, non-expired session for `uid`, newest first. */ listByUser: (uid: string) => Promise; /** * Number of non-revoked, non-expired sessions for `uid`. Cheaper than * materialising the array when you only need the count. */ countActive: (uid: string) => Promise; /** * Optional cleanup — memory store starts a sweep timer that * `_stop()` cancels. Called from tests; production doesn't need it. */ _stop?: (() => void) | undefined; }; type MemoryStoreOptions = { /** * Absolute cap on session count. Protects against a leaky app slowly * filling process memory. When hit, expired/revoked entries are swept * first; if still full, the least-recently-seen ANONYMOUS session is * evicted before any authenticated one — so an anonymous-session * flood can't force-logout real users. With `anonymous: true`, still * pair this store with an IP rate limit on session creation. */ maxSessions?: number | undefined; /** * How often the store scans for expired entries and drops them. * Deferred cleanup is fine — expired records never verify, and * `listByUser` filters them out — but a periodic sweep keeps the * backing map from ballooning. */ sweepMs?: number | undefined; }; /** * @typedef {import('./token.js').SessionTokenPayload} SessionTokenPayload * @typedef {import('./stores/memory.js').SessionStore} SessionStore * @typedef {import('./stores/memory.js').SessionRecord} SessionRecord * @typedef {import('./cookie.js').CookieOptions} CookieOptions */ /** * @typedef {object} SessionEvents * @property {(session: Session) => void | Promise} [onIssue] * @property {(session: Session) => void | Promise} [onVerify] * @property {(oldId: string, session: Session) => void | Promise} [onRotate] * @property {(sessionId: string, reason?: string) => void | Promise} [onRevoke] * @property {(reason: string, req: any) => void | Promise} [onDeny] * @property {(payload: { userId: string | null, sessionId: string, reason: string, previous: object, current: object }) => void | Promise} [onSuspicious] */ /** * @typedef {object} SessionManagerConfig * @property {string | Buffer | Uint8Array | Array} secret * @property {string | number} ttl * @property {string | number} idleTtl * @property {CookieOptions & { name?: string }} [cookie] * @property {SessionStore} [store] * @property {boolean} [anonymous=false] * @property {string | number} [touchEvery] How often `verify` persists a * rolling `lastSeenAt` update to the * store. Defaults to 60s (or half the * idleTtl, whichever is smaller). * Larger values cut store write * traffic; the idle-timeout check * only ever errs by at most this * much. Must be shorter than idleTtl. * @property {number} [concurrentLimit] * @property {ReadonlyArray<'ip' | 'ua'>} [bindTo] Fingerprint binding. * @property {'strict' | 'soft'} [bindStrictness='strict'] Behaviour on fingerprint mismatch. * `strict` (default) — hard revoke, * verify returns null. * `soft` — fire `onSuspicious` with * `reason: 'fingerprint-mismatch'` but * let the request through. Useful for * mobile users who move between wifi * and 5G. * @property {boolean} [impersonation=false] Enable impersonate() API. * @property {string | number} [impersonationTtl='30m'] Absolute lifetime of an * impersonation session. Defaults to * 30 minutes — impersonation is a * high-risk mode; the tight window * matches AWS / GCP admin console * patterns and cuts audit surface. * @property {boolean} [deviceLabels=false] Auto-generate device labels from UA. * @property {SessionEvents} [events] Audit trail callbacks. * @property {boolean | { onDetected?: SessionEvents['onSuspicious'] }} [suspiciousActivity] * IP-change detection. */ /** * @typedef {object} IssueOptions * @property {string | null} [userId=null] * @property {object} [claims={}] * @property {string} [deviceLabel] * @property {boolean} [rememberMe=false] * @property {number} [now] * @property {any} [req] When present, used to sample fingerprint (ip/ua). */ /** * @typedef {object} Session * @property {string} id * @property {string | null} userId * @property {object} claims * @property {number} issuedAt * @property {number} expiresAt * @property {number} lastSeenAt * @property {number} [freshAt] * @property {string} [deviceLabel] * @property {string} [ip] * @property {string} [ua] * @property {string} [impersonatedBy] * @property {string} [impersonationReason] * @property {boolean} isAnonymous */ /** * @typedef {object} IssueResult * @property {string} token * @property {string} cookie * @property {Session} session */ /** * Create a session manager — the package's main entrypoint. Issues * sealed cookie/bearer tokens backed by a server-side store, and * exposes the verify / rotate / revoke lifecycle around them. * * The returned object's type is inferred — consumers get the full * method surface in the generated `.d.ts` without a hand-maintained * typedef drifting out of sync. * * @param {SessionManagerConfig} config */ declare function createSessionManager(config: SessionManagerConfig$1): { issue: (options?: IssueOptions$1) => Promise; verify: (req: any, options?: { now?: number; }) => Promise; touch: (sessionId: string, options?: { now?: number; }) => Promise; rotate: (req: any, options?: {}) => Promise<{ token: string; cookie: string; session: Session$1; previousId: any; }>; markFresh: (req: any, options?: { now?: number; }) => Promise<{ freshAt: number; }>; requireFreshAuth: (req: any, options?: { maxAgeSeconds: number; now?: number; }) => Promise; impersonate: (adminReq: any, targetUserId: string, options?: { ttl?: string | number; claims?: object; reason?: string; now?: number; }) => Promise; revoke: (req: any, options?: { reason?: string; now?: number; }) => Promise<{ cookie: string; revoked: boolean; }>; revokeById: (sessionId: string, options?: { reason?: string; }) => Promise; revokeAllForUser: (userId: string, options?: { reason?: string; }) => Promise; revokeAllExceptCurrent: (req: any, options?: { reason?: string; now?: number; }) => Promise; listActive: (userId: string) => Promise; upgrade: (req: any, userId: string, options?: { mergeClaims?: object; now?: number; }) => Promise; readonly cookieName: string; readonly store: SessionStore$1; extractToken: (req: any) => string | undefined; }; type SessionEvents$1 = { onIssue?: ((session: Session$1) => void | Promise) | undefined; onVerify?: ((session: Session$1) => void | Promise) | undefined; onRotate?: ((oldId: string, session: Session$1) => void | Promise) | undefined; onRevoke?: ((sessionId: string, reason?: string) => void | Promise) | undefined; onDeny?: ((reason: string, req: any) => void | Promise) | undefined; onSuspicious?: ((payload: { userId: string | null; sessionId: string; reason: string; previous: object; current: object; }) => void | Promise) | undefined; }; type SessionManagerConfig$1 = { secret: string | Buffer | Uint8Array | Array; ttl: string | number; idleTtl: string | number; cookie?: (CookieOptions$2 & { name?: string; }) | undefined; store?: SessionStore$1 | undefined; anonymous?: boolean | undefined; /** * How often `verify` persists a * rolling `lastSeenAt` update to the * store. Defaults to 60s (or half the * idleTtl, whichever is smaller). * Larger values cut store write * traffic; the idle-timeout check * only ever errs by at most this * much. Must be shorter than idleTtl. */ touchEvery?: string | number | undefined; concurrentLimit?: number | undefined; /** * Fingerprint binding. */ bindTo?: readonly ("ip" | "ua")[] | undefined; /** * Behaviour on fingerprint mismatch. * `strict` (default) — hard revoke, * verify returns null. * `soft` — fire `onSuspicious` with * `reason: 'fingerprint-mismatch'` but * let the request through. Useful for * mobile users who move between wifi * and 5G. */ bindStrictness?: "strict" | "soft" | undefined; /** * Enable impersonate() API. */ impersonation?: boolean | undefined; /** * Absolute lifetime of an * impersonation session. Defaults to * 30 minutes — impersonation is a * high-risk mode; the tight window * matches AWS / GCP admin console * patterns and cuts audit surface. */ impersonationTtl?: string | number | undefined; /** * Auto-generate device labels from UA. */ deviceLabels?: boolean | undefined; /** * Audit trail callbacks. */ events?: SessionEvents$1 | undefined; /** * IP-change detection. */ suspiciousActivity?: boolean | { onDetected?: SessionEvents$1["onSuspicious"]; } | undefined; }; type IssueOptions$1 = { userId?: string | null | undefined; claims?: object | undefined; deviceLabel?: string | undefined; rememberMe?: boolean | undefined; now?: number | undefined; /** * When present, used to sample fingerprint (ip/ua). */ req?: any; }; type Session$1 = { id: string; userId: string | null; claims: object; issuedAt: number; expiresAt: number; lastSeenAt: number; freshAt?: number | undefined; deviceLabel?: string | undefined; ip?: string | undefined; ua?: string | undefined; impersonatedBy?: string | undefined; impersonationReason?: string | undefined; isAnonymous: boolean; }; type IssueResult$1 = { token: string; cookie: string; session: Session$1; }; declare function customStore(impl: any): Record Promise>; /** * "Trusted device" cookie — long-lived, opaque, HMAC-authenticated * cookie separate from the session cookie. The classic use case is the * 2FA "remember this device for 30 days" tick-box: on subsequent logins * the caller can skip the TOTP prompt when this cookie is present and * valid. * * Deliberately kept independent from `createSessionManager` — the two * live at different scopes (the session cookie is per-session, the * trusted-device cookie is per-user across many sessions), so they * don't share config or a store. * * @param {{ * secret: string | Buffer | Uint8Array | Array, * ttl: string | number, // e.g. '30d' * cookie?: Omit & { name?: string }, * }} config */ declare function createTrustedDeviceCookie(config: { secret: string | Buffer | Uint8Array | Array; ttl: string | number; cookie?: Omit & { name?: string; }; }): { /** * Mint a trusted-device cookie for a user. Call this at 2FA completion * when the user ticked "remember me on this device". * * `extraClaims` keys named `uid`, `iat`, or `exp` are ignored — the * reserved fields always win. * * @param {string} userId * @param {{ now?: number, extraClaims?: object }} [options] * @returns {string} Set-Cookie header value. */ issue(userId: string, options?: { now?: number; extraClaims?: object; }): string; /** * Check whether the incoming request carries a trusted-device * cookie belonging to `userId`. Returns `true` on a valid, * unexpired, correctly-scoped cookie; `false` otherwise. Never * throws. * * @param {any} req * @param {string} userId * @param {{ now?: number }} [options] * @returns {boolean} */ verify(req: any, userId: string, options?: { now?: number; }): boolean; /** * Produce a delete-cookie header value — call this on explicit * logout / "forget this device" flows. * @returns {string} */ revoke(): string; readonly cookieName: string; }; /** * Shared base error class — the single error structure behind every * `@exortek/*` package's `errors.js`. * * Every package keeps its own class identity with a one-liner subclass; * codes stay per-package frozen maps, status mapping is declared as a * static field: * * import { BaseError } from '@exortek/shared/errors'; * * export const ErrorCode = Object.freeze({ * INVALID_ARGUMENT: 'INVALID_ARGUMENT', * INVALID_TOKEN: 'INVALID_TOKEN', * }); * * export class JwtError extends BaseError { * static statuses = { INVALID_ARGUMENT: 400, INVALID_TOKEN: 401 }; * static defaultStatus = 500; * } * * Instances carry a stable machine-readable `code` (branch on this, * never on the message), an optional HTTP `status`, an optional * `details` object, and the standard `cause` chain. */ declare class BaseError extends Error { /** * Optional `code → HTTP status` map declared on the subclass. When * absent the instance carries no `status` at all — for HTTP-agnostic * packages like `@exortek/crypto`. * * @type {Record | undefined} */ static statuses: Record | undefined; /** * Fallback status for codes missing from `statuses`. * * @type {number} */ static defaultStatus: number; /** * @param {string} code Stable machine-readable code; branch on this. * @param {string} message Human-readable diagnostic. Free-form; may * change across versions. * @param {{ cause?: unknown, status?: number, details?: Record }} [options] */ constructor(code: string, message: string, options?: { cause?: unknown; status?: number; details?: Record; }); /** @type {string} */ code: string; /** @type {number | undefined} */ status: number | undefined; /** @type {Record | undefined} */ details: Record | undefined; } declare const ErrorCode: Readonly<{ INVALID_ARGUMENT: "INVALID_ARGUMENT"; INVALID_TOKEN: "INVALID_TOKEN"; EXPIRED: "EXPIRED"; SESSION_NOT_FOUND: "SESSION_NOT_FOUND"; }>; /** * Every recoverable failure raised by this package. Carries a stable * {@link ErrorCode} `code` (branch on this) and a `status` — the HTTP * response status a middleware layer would use when translating the * error into a response. * * @example * try { * const session = await sessions.verify(req) * } catch (err) { * if (err instanceof SessionError) { * if (err.code === ErrorCode.EXPIRED) return res.redirect('/login?expired=1') * } * throw err * } */ declare class SessionError extends BaseError { static statuses: { INVALID_ARGUMENT: number; INVALID_TOKEN: number; EXPIRED: number; SESSION_NOT_FOUND: number; }; } /** * Derive a CSRF token from a session ID + a server-side secret. The * output is a base64url string safe for cookies, form fields, and JSON * bodies. * * @param {string} sessionId * @param {string | Buffer | Uint8Array} secret * @returns {string} */ declare function deriveCsrfToken(sessionId: string, secret: string | Buffer | Uint8Array): string; /** * Constant-time verify a candidate CSRF token against a session ID + * secret pair. Returns `false` on any mismatch, including malformed * input — never throws for user-supplied values. * * @param {unknown} candidate * @param {string} sessionId * @param {string | Buffer | Uint8Array} secret * @returns {boolean} */ declare function verifyCsrfToken(candidate: unknown, sessionId: string, secret: string | Buffer | Uint8Array): boolean; /** * One-time-pad mask a CSRF token for embedding in compressed HTML * (BREACH mitigation, per OWASP). Output is `base64url(pad ‖ pad⊕token)` * — a fresh random pad per call, so two renders of the same token never * produce the same bytes. * * @param {string} token Output of {@link deriveCsrfToken}. * @returns {string} */ declare function maskCsrfToken(token: string): string; /** * Reverse {@link maskCsrfToken}. Returns the underlying token, or * `null` for malformed input — never throws for user-supplied values. * Feed the result into {@link verifyCsrfToken}. * * @param {unknown} masked * @returns {string | null} */ declare function unmaskCsrfToken(masked: unknown): string | null; /** * Read the client IP from a request. Honours the "trust proxy" contract * of Fastify / Express (`req.ip`); otherwise falls back to the socket * peer address. Never trusts `X-Forwarded-For` unless the framework * already resolved it into `req.ip` — matches the default distrust of * XFF in `@exortek/security`. * * @param {any} req * @returns {string | undefined} */ declare function readIp(req: any): string | undefined; /** * Read the User-Agent header from a request, tolerant of both Node * `IncomingMessage` (headers dict) and WHATWG `Request` (`.headers.get`). * * @param {any} req * @returns {string | undefined} */ declare function readUserAgent(req: any): string | undefined; /** * Derive a compact fingerprint from the pieces the caller opted into. * Uses SHA-256 truncated to 16 bytes (128 bits) — enough to make * collisions unrealistic without bloating the sealed cookie payload. * * `bindTo` is an array — order MUST be stable across issue and verify. * We always concatenate in the same canonical order regardless of the * caller's array order. * * @param {any} req * @param {ReadonlyArray<'ip' | 'ua'>} bindTo * @returns {string | undefined} base64url hash, or `undefined` when no bindTo entry resolved. */ declare function computeFingerprint(req: any, bindTo: ReadonlyArray<"ip" | "ua">): string | undefined; /** * Convert a User-Agent string into a short, human-readable label. Meant * for a settings/sessions list — deliberately lossy so users see * "iPhone (iOS 17.4) · Safari" instead of parsing 300 characters of UA. * * @param {string | undefined | null} ua * @returns {string} Empty string when input is not a usable UA. */ declare function deriveDeviceLabel(ua: string | undefined | null): string; /** * @typedef {import('./manager.js').SessionManagerConfig} SessionManagerConfig * @typedef {import('./manager.js').IssueOptions} IssueOptions * @typedef {import('./manager.js').IssueResult} IssueResult * @typedef {import('./manager.js').Session} Session * @typedef {import('./manager.js').SessionEvents} SessionEvents * @typedef {import('./stores/memory.js').SessionStore} SessionStore * @typedef {import('./stores/memory.js').SessionRecord} SessionRecord * @typedef {import('./cookie.js').CookieOptions} CookieOptions * @typedef {import('./token.js').SessionTokenPayload} SessionTokenPayload */ declare const sessionStore: Readonly<{ memory: typeof memoryStore; custom: typeof customStore; }>; type SessionManagerConfig = SessionManagerConfig$1; type IssueOptions = IssueOptions$1; type IssueResult = IssueResult$1; type Session = Session$1; type SessionEvents = SessionEvents$1; type SessionStore = SessionStore$1; type SessionRecord = SessionRecord$1; type CookieOptions = CookieOptions$1; type SessionTokenPayload = SessionTokenPayload$1; export { ErrorCode, SessionError, computeFingerprint, createSessionManager, createTrustedDeviceCookie, customStore, decodeToken, deriveCsrfToken, deriveDeviceLabel, encodeToken, generateSessionId, maskCsrfToken, memoryStore, parseCookies, readIp, readUserAgent, serialiseCookie, serialiseDeleteCookie, sessionStore, unmaskCsrfToken, verifyCsrfToken }; export type { CookieOptions, IssueOptions, IssueResult, Session, SessionEvents, SessionManagerConfig, SessionRecord, SessionStore, SessionTokenPayload };