claude-playwright
Version:
Seamless integration between Claude Code and Playwright MCP for efficient browser automation and testing
1 lines • 7.38 kB
Source Map (JSON)
{"version":3,"sources":["../../src/core/snapshot-cache.ts"],"sourcesContent":["import { Page } from 'playwright';\nimport { CacheManager } from './cache-manager';\nimport crypto from 'crypto';\n\ninterface SnapshotEntry {\n snapshot: any;\n url: string;\n timestamp: number;\n domHash: string;\n viewportSize: { width: number; height: number };\n}\n\nexport class SnapshotCache {\n private cacheManager: CacheManager;\n private currentUrl: string = '';\n private currentProfile?: string;\n private page?: Page;\n private lastDomHash?: string;\n\n constructor(cacheManager: CacheManager) {\n this.cacheManager = cacheManager;\n }\n\n setContext(page: Page, url: string, profile?: string): void {\n this.page = page;\n this.currentUrl = url;\n this.currentProfile = profile;\n }\n\n async getCachedSnapshot(): Promise<any | null> {\n if (!this.page) return null;\n\n const domHash = await this.computeDomHash();\n const cacheKey = {\n url: this.currentUrl,\n domHash\n };\n\n const cached = await this.cacheManager.get(\n cacheKey,\n 'snapshot',\n this.currentProfile\n );\n\n if (cached) {\n this.lastDomHash = domHash;\n return cached.snapshot;\n }\n\n return null;\n }\n\n async cacheSnapshot(snapshot: any): Promise<void> {\n if (!this.page) return;\n\n const domHash = await this.computeDomHash();\n const viewportSize = await this.page.viewportSize();\n\n const entry: SnapshotEntry = {\n snapshot,\n url: this.currentUrl,\n timestamp: Date.now(),\n domHash,\n viewportSize: viewportSize || { width: 1280, height: 720 }\n };\n\n const cacheKey = {\n url: this.currentUrl,\n domHash\n };\n\n await this.cacheManager.set(\n cacheKey,\n entry,\n 'snapshot',\n {\n url: this.currentUrl,\n profile: this.currentProfile,\n ttl: 1800000 // 30 minutes\n }\n );\n\n this.lastDomHash = domHash;\n }\n\n async getOrCreateSnapshot(): Promise<any> {\n // Try to get cached snapshot first\n const cached = await this.getCachedSnapshot();\n if (cached) {\n return cached;\n }\n\n // Create new snapshot\n if (!this.page) {\n throw new Error('Page context not set');\n }\n\n const snapshot = await this.page.accessibility.snapshot();\n await this.cacheSnapshot(snapshot);\n return snapshot;\n }\n\n private async computeDomHash(): Promise<string> {\n if (!this.page) return '';\n\n try {\n // Get a simplified representation of the DOM structure\n const domStructure = await this.page.evaluate(() => {\n const getStructure = (element: Element, depth: number = 0): string => {\n if (depth > 5) return ''; // Limit depth\n \n let structure = element.tagName;\n const id = element.id ? `#${element.id}` : '';\n const classes = element.className ? `.${element.className.split(' ').join('.')}` : '';\n structure += id + classes;\n\n // Get child elements structure\n const children = Array.from(element.children)\n .slice(0, 10) // Limit children\n .map(child => getStructure(child, depth + 1))\n .filter(s => s)\n .join(',');\n\n if (children) {\n structure += `[${children}]`;\n }\n\n return structure;\n };\n\n return getStructure(document.body);\n });\n\n return crypto.createHash('md5').update(domStructure).digest('hex');\n } catch (error) {\n console.error('Error computing DOM hash:', error);\n return crypto.createHash('md5').update(this.currentUrl + Date.now()).digest('hex');\n }\n }\n\n async hasPageChanged(): Promise<boolean> {\n if (!this.page || !this.lastDomHash) return true;\n\n const currentHash = await this.computeDomHash();\n return currentHash !== this.lastDomHash;\n }\n\n async invalidateIfChanged(): Promise<boolean> {\n if (await this.hasPageChanged()) {\n await this.invalidateSnapshot();\n return true;\n }\n return false;\n }\n\n async invalidateSnapshot(): Promise<void> {\n await this.cacheManager.invalidate({\n url: this.currentUrl,\n type: 'snapshot',\n profile: this.currentProfile\n });\n this.lastDomHash = undefined;\n }\n\n async prefetchRelatedPages(urls: string[]): Promise<void> {\n // This would be used to prefetch snapshots for related pages\n // Implementation would depend on specific use cases\n }\n\n async getSnapshotMetrics(): Promise<any> {\n const metrics = await this.cacheManager.getMetrics();\n return metrics.find((m: any) => m.cache_type === 'snapshot');\n }\n}"],"mappings":"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","names":["crypto"]}