Framework-agnostic session management for AT Protocol applications using Iron Session encryption
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

1.0.0: Breaking changes - standardize Logger interface and rename SessionData

- Logger: Changed from (log, warn, error) to (debug, info, warn, error)
- SessionData renamed to CookieSessionData to avoid collision with oauth-client-deno

+68 -15
+42
CHANGELOG.md
··· 2 2 3 3 All notable changes to this project will be documented in this file. 4 4 5 + ## [1.0.0] - 2025-11-28 6 + 7 + ### Breaking Changes 8 + 9 + - **Logger interface**: Changed from 3 methods (`log`, `warn`, `error`) to 4 10 + methods (`debug`, `info`, `warn`, `error`) for compatibility with 11 + oauth-client-deno 12 + - **SessionData renamed**: `SessionData` is now `CookieSessionData` to avoid 13 + naming collision with oauth-client-deno's `SessionData` (which represents full 14 + OAuth session state). The old name is available as a deprecated type alias. 15 + 16 + ### Migration Guide 17 + 18 + **Logger interface:** 19 + 20 + ```typescript 21 + // Before 22 + const logger = { 23 + log: console.log, 24 + warn: console.warn, 25 + error: console.error, 26 + }; 27 + 28 + // After 29 + const logger = { 30 + debug: console.debug, 31 + info: console.info, 32 + warn: console.warn, 33 + error: console.error, 34 + }; 35 + ``` 36 + 37 + **SessionData type:** 38 + 39 + ```typescript 40 + // Before 41 + import type { SessionData } from "@tijs/atproto-sessions"; 42 + 43 + // After 44 + import type { CookieSessionData } from "@tijs/atproto-sessions"; 45 + ``` 46 + 5 47 ## [0.1.1] - 2025-11-27 6 48 7 49 ### Fixed
+1 -1
deno.json
··· 1 1 { 2 2 "$schema": "https://jsr.io/schema/config-file.v1.json", 3 3 "name": "@tijs/atproto-sessions", 4 - "version": "0.1.1", 4 + "version": "1.0.0", 5 5 "license": "MIT", 6 6 "exports": "./mod.ts", 7 7 "publish": {
+12 -11
src/sessions.ts
··· 1 1 import { sealData, unsealData } from "iron-session"; 2 2 3 3 import type { 4 + CookieSessionData, 4 5 Logger, 5 6 MobileTokenData, 6 7 SessionConfig, 7 - SessionData, 8 8 SessionResult, 9 9 } from "./types.ts"; 10 10 import { ConfigurationError } from "./errors.ts"; ··· 20 20 21 21 /** No-op logger for production use */ 22 22 const noopLogger: Logger = { 23 - log: () => {}, 23 + debug: () => {}, 24 + info: () => {}, 24 25 warn: () => {}, 25 26 error: () => {}, 26 27 }; ··· 84 85 */ 85 86 async getSessionFromRequest( 86 87 req: Request, 87 - ): Promise<SessionResult<SessionData>> { 88 + ): Promise<SessionResult<CookieSessionData>> { 88 89 try { 89 90 const cookieHeader = req.headers.get("cookie"); 90 91 if (!cookieHeader?.includes(`${this.cookieName}=`)) { 91 - this.logger.log("No session cookie found in request"); 92 + this.logger.debug("No session cookie found in request"); 92 93 return { 93 94 data: null, 94 95 error: { ··· 106 107 ?.substring(cookiePrefix.length); 107 108 108 109 if (!sessionCookie) { 109 - this.logger.log("Session cookie found but could not be parsed"); 110 + this.logger.debug("Session cookie found but could not be parsed"); 110 111 return { 111 112 data: null, 112 113 error: { ··· 117 118 } 118 119 119 120 // Unseal session data 120 - let sessionData: SessionData; 121 + let sessionData: CookieSessionData; 121 122 try { 122 123 sessionData = await unsealData(decodeURIComponent(sessionCookie), { 123 124 password: this.cookieSecret, 124 - }) as SessionData; 125 + }) as CookieSessionData; 125 126 } catch (unsealError) { 126 127 this.logger.error("Failed to unseal session cookie:", { 127 128 error: unsealError instanceof Error ··· 151 152 }; 152 153 } 153 154 154 - this.logger.log( 155 + this.logger.info( 155 156 `Session extracted: DID=${sessionData.did}, created=${ 156 157 new Date(sessionData.createdAt).toISOString() 157 158 }`, 158 159 ); 159 160 160 161 // Create refreshed session with updated lastAccessed 161 - const refreshedData: SessionData = { 162 + const refreshedData: CookieSessionData = { 162 163 did: sessionData.did, 163 164 createdAt: sessionData.createdAt, 164 165 lastAccessed: Date.now(), ··· 166 167 167 168 const setCookieHeader = await this.createSession(refreshedData); 168 169 169 - this.logger.log( 170 + this.logger.info( 170 171 `Session refreshed for DID: ${sessionData.did}, expires in ${ 171 172 Math.round(this.sessionTtl / 86400) 172 173 } days`, ··· 197 198 * @param data - Session data to store (did, createdAt, lastAccessed) 198 199 * @returns Set-Cookie header string to set on response 199 200 */ 200 - async createSession(data: SessionData): Promise<string> { 201 + async createSession(data: CookieSessionData): Promise<string> { 201 202 const sealedSession = await sealData(data, { 202 203 password: this.cookieSecret, 203 204 ttl: this.sessionTtl,
+13 -3
src/types.ts
··· 1 1 /** 2 - * Logger interface for custom logging implementations 2 + * Logger interface for custom logging implementations. 3 + * Compatible with oauth-client-deno's Logger interface. 3 4 */ 4 5 export interface Logger { 5 - log(...args: unknown[]): void; 6 + debug(...args: unknown[]): void; 7 + info(...args: unknown[]): void; 6 8 warn(...args: unknown[]): void; 7 9 error(...args: unknown[]): void; 8 10 } ··· 40 42 /** 41 43 * Session data stored in the encrypted cookie. 42 44 * Contains user identity and timing information. 45 + * 46 + * Named CookieSessionData to avoid collision with oauth-client-deno's 47 + * SessionData which represents full OAuth session state. 43 48 */ 44 - export interface SessionData { 49 + export interface CookieSessionData { 45 50 /** User's DID (Decentralized Identifier) */ 46 51 did: string; 47 52 ··· 51 56 /** Timestamp of last access (for session refresh) */ 52 57 lastAccessed: number; 53 58 } 59 + 60 + /** 61 + * @deprecated Use CookieSessionData instead. Will be removed in 1.0. 62 + */ 63 + export type SessionData = CookieSessionData; 54 64 55 65 /** 56 66 * Error types for session operations