All files / src/handlers session-handlers.ts

88.88% Statements 24/27
90.9% Branches 20/22
100% Functions 5/5
88.88% Lines 24/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142        14x   14x     14x                     14x 7x 7x                                     5x 5x 5x       2x       14x                                     7x   7x         7x                               5x   5x 5x 5x   5x                     5x 1x                   4x     5x       4x                          
import { BaseHandler } from './base-handler.js';
 
export class SessionHandlers extends BaseHandler {
  async createSession(options: { session_id?: string; initial_url?: string; browser_type?: string }) {
    try {
      // Generate session ID if not provided
      const sessionId = options.session_id || `session-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
 
      // Store session info locally
      this.sessions.set(sessionId, {
        id: sessionId,
        created_at: new Date(),
        last_used: new Date(),
        initial_url: options.initial_url,
        metadata: {
          browser_type: options.browser_type || 'chromium',
        },
      });
 
      // If initial_url provided, make first crawl to establish session
      if (options.initial_url) {
        try {
          await this.axiosClient.post(
            '/crawl',
            {
              urls: [options.initial_url],
              browser_config: {
                headless: true,
                browser_type: options.browser_type || 'chromium',
              },
              crawler_config: {
                session_id: sessionId,
                cache_mode: 'BYPASS',
              },
            },
            {
              timeout: 30000, // 30 second timeout for initial crawl
            },
          );
 
          // Update last_used
          const session = this.sessions.get(sessionId);
          Eif (session) {
            session.last_used = new Date();
          }
        } catch (error) {
          // Session created but initial crawl failed - still return success
          console.error(`Initial crawl failed for session ${sessionId}:`, error);
        }
      }
 
      return {
        content: [
          {
            type: 'text',
            text: `Session created successfully:\nSession ID: ${sessionId}\nBrowser: ${options.browser_type || 'chromium'}\n${options.initial_url ? `Pre-warmed with: ${options.initial_url}` : 'Ready for use'}\n\nUse this session_id with the crawl tool to maintain state across requests.`,
          },
        ],
        // Include all session parameters for easier programmatic access
        session_id: sessionId,
        browser_type: options.browser_type || 'chromium',
        initial_url: options.initial_url,
        created_at: this.sessions.get(sessionId)?.created_at.toISOString(),
      };
    } catch (error) {
      throw this.formatError(error, 'create session');
    }
  }
 
  async clearSession(options: { session_id: string }) {
    try {
      // Remove from local store
      const deleted = this.sessions.delete(options.session_id);
 
      // Note: The actual browser session in Crawl4AI will be cleaned up
      // automatically after inactivity or when the server restarts
 
      return {
        content: [
          {
            type: 'text',
            text: deleted
              ? `Session cleared successfully: ${options.session_id}`
              : `Session not found: ${options.session_id}`,
          },
        ],
      };
    } catch (error) {
      throw this.formatError(error, 'clear session');
    }
  }
 
  async listSessions() {
    try {
      // Return locally stored sessions
      const sessions = Array.from(this.sessions.entries()).map(([id, info]) => {
        const ageMinutes = Math.floor((Date.now() - info.created_at.getTime()) / 60000);
        const lastUsedMinutes = Math.floor((Date.now() - info.last_used.getTime()) / 60000);
 
        return {
          session_id: id,
          created_at: info.created_at.toISOString(),
          last_used: info.last_used.toISOString(),
          age_minutes: ageMinutes,
          last_used_minutes_ago: lastUsedMinutes,
          initial_url: info.initial_url,
          browser_type: info.metadata?.browser_type || 'chromium',
        };
      });
 
      if (sessions.length === 0) {
        return {
          content: [
            {
              type: 'text',
              text: 'No active sessions found.',
            },
          ],
        };
      }
 
      const sessionList = sessions
        .map(
          (session) =>
            `- ${session.session_id} (${session.browser_type}, created ${session.age_minutes}m ago, last used ${session.last_used_minutes_ago}m ago)`,
        )
        .join('\n');
 
      return {
        content: [
          {
            type: 'text',
            text: `Active sessions (${sessions.length}):\n${sessionList}`,
          },
        ],
      };
    } catch (error) {
      throw this.formatError(error, 'list sessions');
    }
  }
}