mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-06 05:23:08 +00:00
feat: implement session persistence for v2.19.0 (Phase 1 + Phase 2)
Phase 1 - Lazy Session Restoration (REQ-1, REQ-2, REQ-8): - Add onSessionNotFound hook for restoring sessions from external storage - Implement idempotent session creation to prevent race conditions - Add session ID validation for security (prevent injection attacks) - Comprehensive error handling (400/408/500 status codes) - 13 integration tests covering all scenarios Phase 2 - Session Management API (REQ-5): - getActiveSessions(): Get all active session IDs - getSessionState(sessionId): Get session state for persistence - getAllSessionStates(): Bulk session state retrieval - restoreSession(sessionId, context): Manual session restoration - deleteSession(sessionId): Manual session termination - 21 unit tests covering all API methods Benefits: - Sessions survive container restarts - Horizontal scaling support (no session stickiness needed) - Zero-downtime deployments - 100% backwards compatible Implementation Details: - Backend methods in http-server-single-session.ts - Public API methods in mcp-engine.ts - SessionState type exported from index.ts - Synchronous session creation and deletion for reliable testing - Version updated from 2.18.10 to 2.19.0 Tests: 34 passing (13 integration + 21 unit) Coverage: Full API coverage with edge cases Security: Session ID validation prevents SQL/NoSQL injection and path traversal 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
111
src/types/session-restoration.ts
Normal file
111
src/types/session-restoration.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Session Restoration Types
|
||||
*
|
||||
* Defines types for session persistence and restoration functionality.
|
||||
* Enables multi-tenant backends to restore sessions after container restarts.
|
||||
*
|
||||
* @since 2.19.0
|
||||
*/
|
||||
|
||||
import { InstanceContext } from './instance-context';
|
||||
|
||||
/**
|
||||
* Session restoration hook callback
|
||||
*
|
||||
* Called when a client tries to use an unknown session ID.
|
||||
* The backend can load session state from external storage (database, Redis, etc.)
|
||||
* and return the instance context to recreate the session.
|
||||
*
|
||||
* @param sessionId - The session ID that was not found in memory
|
||||
* @returns Instance context to restore the session, or null if session should not be restored
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const engine = new N8NMCPEngine({
|
||||
* onSessionNotFound: async (sessionId) => {
|
||||
* // Load from database
|
||||
* const session = await db.loadSession(sessionId);
|
||||
* if (!session || session.expired) return null;
|
||||
* return session.instanceContext;
|
||||
* }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export type SessionRestoreHook = (sessionId: string) => Promise<InstanceContext | null>;
|
||||
|
||||
/**
|
||||
* Session restoration configuration options
|
||||
*
|
||||
* @since 2.19.0
|
||||
*/
|
||||
export interface SessionRestorationOptions {
|
||||
/**
|
||||
* Session timeout in milliseconds
|
||||
* After this period of inactivity, sessions are expired and cleaned up
|
||||
* @default 1800000 (30 minutes)
|
||||
*/
|
||||
sessionTimeout?: number;
|
||||
|
||||
/**
|
||||
* Maximum time to wait for session restoration hook to complete
|
||||
* If the hook takes longer than this, the request will fail with 408 Request Timeout
|
||||
* @default 5000 (5 seconds)
|
||||
*/
|
||||
sessionRestorationTimeout?: number;
|
||||
|
||||
/**
|
||||
* Hook called when a client tries to use an unknown session ID
|
||||
* Return instance context to restore the session, or null to reject
|
||||
*
|
||||
* @param sessionId - The session ID that was not found
|
||||
* @returns Instance context for restoration, or null
|
||||
*
|
||||
* Error handling:
|
||||
* - Hook throws exception → 500 Internal Server Error
|
||||
* - Hook times out → 408 Request Timeout
|
||||
* - Hook returns null → 400 Bad Request (session not found)
|
||||
* - Hook returns invalid context → 400 Bad Request (invalid context)
|
||||
*/
|
||||
onSessionNotFound?: SessionRestoreHook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Session state for persistence
|
||||
* Contains all information needed to restore a session after restart
|
||||
*
|
||||
* @since 2.19.0
|
||||
*/
|
||||
export interface SessionState {
|
||||
/**
|
||||
* Unique session identifier
|
||||
*/
|
||||
sessionId: string;
|
||||
|
||||
/**
|
||||
* Instance-specific configuration
|
||||
* Contains n8n API credentials and instance ID
|
||||
*/
|
||||
instanceContext: InstanceContext;
|
||||
|
||||
/**
|
||||
* When the session was created
|
||||
*/
|
||||
createdAt: Date;
|
||||
|
||||
/**
|
||||
* Last time the session was accessed
|
||||
* Used for TTL-based expiration
|
||||
*/
|
||||
lastAccess: Date;
|
||||
|
||||
/**
|
||||
* When the session will expire
|
||||
* Calculated from lastAccess + sessionTimeout
|
||||
*/
|
||||
expiresAt: Date;
|
||||
|
||||
/**
|
||||
* Optional metadata for application-specific use
|
||||
*/
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
Reference in New Issue
Block a user