/** * Unbrowser HTTP Client * * Client for interacting with the Unbrowser cloud API. * Provides a simple interface for browsing URLs via the cloud service. */ export interface UnbrowserConfig { /** API key for authentication (required) */ apiKey: string; /** Base URL for the API (default: https://api.unbrowser.ai) */ baseUrl?: string; /** Request timeout in milliseconds (default: 60000) */ timeout?: number; /** Retry failed requests (default: true) */ retry?: boolean; /** Maximum retry attempts (default: 3) */ maxRetries?: number; } export interface BrowseOptions { /** Content type to return (default: markdown) */ contentType?: 'markdown' | 'text' | 'html'; /** CSS selector to wait for before extraction */ waitForSelector?: string; /** Scroll page to trigger lazy loading */ scrollToLoad?: boolean; /** Maximum characters to return */ maxChars?: number; /** Include tables in response */ includeTables?: boolean; /** Maximum latency allowed (will skip slower tiers) */ maxLatencyMs?: number; /** Maximum cost tier to use */ maxCostTier?: 'intelligence' | 'lightweight' | 'playwright'; /** Verification options (COMP-015) */ verify?: { /** Enable verification (default: true for basic mode) */ enabled?: boolean; /** Verification mode: basic, standard, or thorough */ mode?: 'basic' | 'standard' | 'thorough'; }; /** Debug mode for Playwright tier (PLAY-001) */ debug?: { /** Show browser window (headless: false) */ visible?: boolean; /** ms delay between actions */ slowMotion?: number; /** Capture screenshots after actions */ screenshots?: boolean; /** Collect browser console output */ consoleLogs?: boolean; }; } export interface FuzzDiscoveryOptions { /** Paths to probe (default: common API paths) */ paths?: string[]; /** HTTP methods to test (default: ['GET']) */ methods?: string[]; /** Timeout per probe in ms (default: 3000) */ probeTimeout?: number; /** Maximum total discovery time in ms (default: 30000) */ maxDuration?: number; /** Whether to learn patterns from discoveries (default: true) */ learnPatterns?: boolean; /** Custom headers for probes */ headers?: Record; /** Status codes considered successful (default: [200, 201, 301, 302, 307, 308]) */ successCodes?: number[]; } export interface FuzzDiscoveryResult { /** Domain that was fuzzed */ domain: string; /** Base URL used for fuzzing */ baseUrl: string; /** Successfully discovered endpoints */ discovered: Array<{ path: string; method: string; statusCode: number; responseTime: number; contentType?: string; }>; /** Discovery statistics */ stats: { totalProbes: number; successfulEndpoints: number; failedProbes: number; patternsLearned: number; duration: number; }; /** Request metadata */ metadata: { timestamp: number; requestDuration: number; }; } export interface SessionData { /** Cookies to send with the request */ cookies?: Cookie[]; /** LocalStorage values to set */ localStorage?: Record; } export interface Cookie { name: string; value: string; domain?: string; path?: string; } export interface BrowseResult { /** The original URL requested */ url: string; /** The final URL after redirects */ finalUrl: string; /** Page title */ title: string; /** Extracted content */ content: { markdown: string; text: string; html?: string; }; /** Extracted tables (if includeTables was true) */ tables?: Array<{ headers: string[]; rows: string[][]; }>; /** Discovered API endpoints */ discoveredApis?: Array<{ url: string; method: string; contentType: string; }>; /** Request metadata */ metadata: { loadTime: number; tier: string; tiersAttempted: string[]; }; /** New cookies set during the request */ newCookies?: Cookie[]; /** Verification result (COMP-015) */ verification?: { /** Whether all checks passed */ passed: boolean; /** Overall confidence (0-1) */ confidence: number; /** Number of checks run */ checksRun: number; /** Error messages from failed checks */ errors?: string[]; /** Warning messages */ warnings?: string[]; }; } export interface BatchResult { results: Array<{ url: string; success: boolean; data?: BrowseResult; error?: { code: string; message: string; }; }>; totalTime: number; } export interface ExecutionStep { order: number; action: string; description: string; tier: 'intelligence' | 'lightweight' | 'playwright'; expectedDuration: number; confidence: 'high' | 'medium' | 'low'; reason?: string; } export interface ExecutionPlan { steps: ExecutionStep[]; tier: 'intelligence' | 'lightweight' | 'playwright'; reasoning: string; fallbackPlan?: ExecutionPlan; } export interface TimeEstimate { min: number; max: number; expected: number; breakdown: { [tier: string]: number; }; } export interface ConfidenceFactors { hasLearnedPatterns: boolean; domainFamiliarity: 'high' | 'medium' | 'low' | 'none'; apiDiscovered: boolean; requiresAuth: boolean; botDetectionLikely: boolean; skillsAvailable: boolean; patternCount: number; patternSuccessRate: number; } export interface ConfidenceLevel { overall: 'high' | 'medium' | 'low'; factors: ConfidenceFactors; } export interface BrowsePreview { schemaVersion: string; plan: ExecutionPlan; estimatedTime: TimeEstimate; confidence: ConfidenceLevel; alternativePlans?: ExecutionPlan[]; } export interface DomainIntelligence { domain: string; knownPatterns: number; selectorChains: number; validators: number; paginationPatterns: number; recentFailures: number; successRate: number; domainGroup: string | null; recommendedWaitStrategy: string; shouldUseSession: boolean; } export interface ProgressEvent { stage: string; tier?: string; elapsed: number; message?: string; } export type ProgressCallback = (event: ProgressEvent) => void; export type SkillVertical = 'developer' | 'ecommerce' | 'social' | 'news' | 'finance' | 'research' | 'travel' | 'general'; export type SkillTier = 'essential' | 'domain-specific' | 'advanced'; export interface BrowsingSkill { id: string; name: string; description: string; preconditions: { urlPatterns?: string[]; domainPatterns?: string[]; requiredSelectors?: string[]; pageType?: string; }; actionSequence: Array<{ type: string; [key: string]: any; }>; metrics: { successCount: number; failureCount: number; timesUsed: number; }; sourceDomain?: string; tier?: SkillTier; loadPriority?: number; sizeEstimate?: number; } export interface AntiPattern { id: string; pattern: string; reason: string; learnedFrom: string; occurrences: number; } export interface SkillWorkflow { id: string; name: string; description: string; domain: string; steps: Array<{ skillId?: string; action: string; description: string; }>; } export interface SkillPackMetadata { id: string; name: string; description: string; version: string; createdAt: number; sourceInstance?: string; verticals: SkillVertical[]; domains: string[]; stats: { skillCount: number; antiPatternCount: number; workflowCount: number; totalSuccessCount: number; avgSuccessRate: number; }; compatibility: { minVersion: string; schemaVersion: string; }; } export interface SkillPack { metadata: SkillPackMetadata; skills: BrowsingSkill[]; antiPatterns: AntiPattern[]; workflows: SkillWorkflow[]; } export interface SkillExportOptions { domainPatterns?: string[]; verticals?: SkillVertical[]; includeAntiPatterns?: boolean; includeWorkflows?: boolean; minSuccessRate?: number; minUsageCount?: number; packName?: string; packDescription?: string; } export type SkillConflictResolution = 'skip' | 'overwrite' | 'merge' | 'rename'; export interface SkillImportOptions { conflictResolution?: SkillConflictResolution; domainFilter?: string[]; verticalFilter?: SkillVertical[]; importAntiPatterns?: boolean; importWorkflows?: boolean; resetMetrics?: boolean; namePrefix?: string; } export interface SkillImportResult { success: boolean; skillsImported: number; skillsSkipped: number; skillsMerged: number; antiPatternsImported: number; workflowsImported: number; errors: string[]; warnings: string[]; } /** Urgency level for content change predictions */ export type UrgencyLevel = 0 | 1 | 2 | 3; /** Calendar trigger for recurring annual changes */ export interface CalendarTrigger { /** Month (1-12) */ month: number; /** Day of month (1-31) */ dayOfMonth: number; /** Human-readable description */ description?: string; /** Confidence in this trigger (0-1) */ confidence: number; /** Number of historical occurrences */ historicalCount: number; } /** Seasonal pattern analysis */ export interface SeasonalPattern { /** Months with higher-than-average change frequency */ highChangeMonths: number[]; /** Days of month with higher-than-average change frequency */ highChangeDays?: number[]; /** Total observations used for this analysis */ totalObservations: number; } /** Next predicted change */ export interface PredictionForecast { /** Predicted timestamp of next change (ms since epoch) */ predictedAt: number; /** ISO string of predicted time */ predictedAtISO?: string; /** Confidence in this prediction (0-1) */ confidence: number; /** Uncertainty window in ms */ uncertaintyWindowMs?: number; /** Human-readable reason for prediction */ reason: string; } /** Content change pattern for a URL */ export interface ContentChangePattern { /** Pattern ID */ id: string; /** Domain of the content */ domain: string; /** URL pattern (regex or literal) */ urlPattern: string; /** Detected pattern type */ detectedPattern: 'hourly' | 'daily' | 'weekly' | 'monthly' | 'static' | 'irregular'; /** Confidence in pattern detection (0-1) */ patternConfidence: number; /** Current urgency level (0=low, 1=normal, 2=high, 3=critical) */ urgencyLevel: UrgencyLevel; /** Next predicted change */ nextPrediction?: PredictionForecast; /** Detected calendar triggers */ calendarTriggers?: CalendarTrigger[]; /** Seasonal pattern analysis */ seasonalPattern?: SeasonalPattern; /** Recommended polling interval in ms */ recommendedPollIntervalMs: number; /** Number of changes observed */ changeCount: number; /** When pattern was last analyzed */ lastAnalyzedAt?: number; } /** Result from getPredictions */ export interface PredictionsResult { success: boolean; data: { patterns: ContentChangePattern[]; summary?: { totalPatterns: number; byUrgency: { critical: number; high: number; normal: number; low: number; }; withCalendarTriggers: number; }; metadata: { timestamp: number; requestDuration: number; }; }; } /** Result from getPredictionsByDomain */ export interface DomainPredictionsResult { success: boolean; data: { domain: string; patterns: ContentChangePattern[]; metadata: { timestamp: number; requestDuration: number; }; }; } /** Prediction accuracy statistics */ export interface PredictionAccuracyResult { success: boolean; data: { domain: string; urlPattern: string; accuracy: { totalPredictions: number; successfulPredictions: number; successRate: number; recentAccuracy?: number; averageErrorMs?: number; averageErrorHours?: number; }; metadata: { timestamp: number; requestDuration: number; }; }; } /** Result from recording an observation */ export interface ObservationResult { success: boolean; data: { pattern: ContentChangePattern; metadata: { timestamp: number; requestDuration: number; }; }; } export declare class UnbrowserError extends Error { code: string; constructor(code: string, message: string); } export declare class UnbrowserClient { private apiKey; private baseUrl; private timeout; private retry; private maxRetries; constructor(config: UnbrowserConfig); /** * Make an authenticated request to the API */ private request; /** * Browse a URL and extract content */ browse(url: string, options?: BrowseOptions, session?: SessionData): Promise; /** * Preview what will happen when browsing a URL (without executing) * * Returns execution plan, time estimates, and confidence levels. * Completes in <50ms vs 2-5s for browser automation. * * @example * ```typescript * const preview = await client.previewBrowse('https://reddit.com/r/programming'); * console.log(`Expected time: ${preview.estimatedTime.expected}ms`); * console.log(`Confidence: ${preview.confidence.overall}`); * console.log(`Plan: ${preview.plan.steps.length} steps using ${preview.plan.tier} tier`); * ``` */ previewBrowse(url: string, options?: BrowseOptions): Promise; /** * Browse a URL with progress updates via SSE */ browseWithProgress(url: string, onProgress: ProgressCallback, options?: BrowseOptions, session?: SessionData): Promise; /** * Fast content fetch (tiered rendering) */ fetch(url: string, options?: BrowseOptions, session?: SessionData): Promise; /** * Browse multiple URLs in parallel */ batch(urls: string[], options?: BrowseOptions, session?: SessionData): Promise; /** * Get domain intelligence summary */ getDomainIntelligence(domain: string): Promise; /** * Get usage statistics for the current billing period */ getUsage(): Promise<{ period: { start: string; end: string; }; requests: { total: number; byTier: Record; }; limits: { daily: number; remaining: number; }; }>; /** * Check API health (no auth required) */ health(): Promise<{ status: string; version: string; uptime?: number; }>; /** * Start a workflow recording session * * Records all browse operations for later replay. * Use with browse() by passing the recordingId in headers. * * @example * ```typescript * // Start recording * const session = await client.startRecording({ * name: 'Extract product pricing', * description: 'Navigate to product page and extract price', * domain: 'example.com' * }); * * // Browse (auto-captured) * await client.browse('https://example.com/products/123', { * headers: { 'X-Recording-Session': session.recordingId } * }); * * // Stop and save * const workflow = await client.stopRecording(session.recordingId); * ``` */ startRecording(request: { name: string; description: string; domain: string; tags?: string[]; }): Promise<{ recordingId: string; status: string; startedAt: string; }>; /** * Stop a recording session and optionally save as workflow */ stopRecording(recordingId: string, save?: boolean): Promise<{ workflowId: string; skillId: string; name: string; steps: number; estimatedDuration: number; } | null>; /** * Annotate a step in an active recording * * Mark steps as critical/important/optional and add descriptions. */ annotateRecording(recordingId: string, annotation: { stepNumber: number; annotation: string; importance?: 'critical' | 'important' | 'optional'; }): Promise<{ recordingId: string; stepNumber: number; annotated: boolean; }>; /** * Replay a saved workflow with optional variable substitution * * @example * ```typescript * // Replay with different product ID * const results = await client.replayWorkflow('wf_xyz789', { * productId: '456' * }); * * console.log(results.overallSuccess); // true * console.log(results.results[0].data); // First step result * ``` */ replayWorkflow(workflowId: string, variables?: Record): Promise<{ workflowId: string; overallSuccess: boolean; totalDuration: number; results: Array<{ stepNumber: number; success: boolean; duration: number; tier?: 'intelligence' | 'lightweight' | 'playwright'; error?: string; }>; }>; /** * List saved workflows */ listWorkflows(options?: { domain?: string; tags?: string[]; }): Promise<{ workflows: Array<{ id: string; name: string; description: string; domain: string; tags: string[]; steps: number; version: number; usageCount: number; successRate: number; createdAt: string; updatedAt: string; }>; total: number; }>; /** * Get workflow details including full step information */ getWorkflow(workflowId: string): Promise<{ id: string; name: string; description: string; domain: string; tags: string[]; version: number; usageCount: number; successRate: number; skillId?: string; steps: Array<{ stepNumber: number; action: string; url?: string; description: string; userAnnotation?: string; importance: 'critical' | 'important' | 'optional'; tier?: 'intelligence' | 'lightweight' | 'playwright'; duration?: number; success: boolean; }>; createdAt: string; updatedAt: string; }>; /** * Delete a saved workflow */ deleteWorkflow(workflowId: string): Promise<{ workflowId: string; deleted: boolean; }>; /** * Export skills as a portable skill pack * * Create a JSON skill pack that can be shared via npm, GitHub, or imported * into other Unbrowser instances. Filter by domain, vertical, or quality metrics. * * @example * ```typescript * // Export all GitHub skills * const pack = await client.exportSkillPack({ * domainPatterns: ['github.com'], * minSuccessRate: 0.8, * packName: 'My GitHub Skills' * }); * * // Save to file * await fs.writeFile('github-skills.json', JSON.stringify(pack, null, 2)); * ``` */ exportSkillPack(options?: SkillExportOptions): Promise<{ success: boolean; pack: SkillPack; metadata: { skillCount: number; antiPatternCount: number; workflowCount: number; version: string; createdAt: number; }; }>; /** * Import a skill pack into ProceduralMemory * * Install skills from a downloaded pack, npm package, or custom source. * Configure conflict resolution and filtering options. * * @example * ```typescript * // Import skills from a pack * const packJson = await fs.readFile('github-skills.json', 'utf-8'); * const pack = JSON.parse(packJson); * * const result = await client.importSkillPack(pack, { * conflictResolution: 'skip', * resetMetrics: false * }); * * console.log(`Imported ${result.result.skillsImported} skills`); * console.log(`Skipped ${result.result.skillsSkipped} duplicates`); * ``` */ importSkillPack(pack: SkillPack, options?: SkillImportOptions): Promise<{ success: boolean; result: SkillImportResult; }>; /** * Browse official skill pack library * * List verified skill packs published by Unbrowser and the community. * Filter by vertical or search by keywords. * * @example * ```typescript * // List all developer-focused packs * const { packs } = await client.listSkillPackLibrary({ vertical: 'developer' }); * * packs.forEach(pack => { * console.log(`${pack.name}: ${pack.skillCount} skills`); * }); * ``` */ listSkillPackLibrary(options?: { vertical?: SkillVertical; search?: string; }): Promise<{ success: boolean; packs: Array<{ id: string; name: string; description: string; version: string; verticals: SkillVertical[]; domains: string[]; skillCount: number; downloadCount: number; verified: boolean; npmUrl: string; }>; total: number; }>; /** * Install a skill pack from the official library * * Download and install a published skill pack by ID. Currently returns * 501 Not Implemented - use exportSkillPack() and importSkillPack() instead. * * @example * ```typescript * // Install GitHub skills (when implemented) * const result = await client.installSkillPack('@unbrowser/skills-github', { * conflictResolution: 'skip' * }); * ``` */ installSkillPack(packId: string, options?: SkillImportOptions): Promise<{ success: boolean; result: SkillImportResult; }>; /** * Get statistics about loaded skills * * Returns skill counts by vertical and tier, plus progressive loading stats. * Useful for monitoring memory usage and lazy loading behavior. * * @example * ```typescript * const stats = await client.getSkillPackStats(); * * console.log(`Total skills: ${stats.totalSkills}`); * console.log(`Essential (loaded): ${stats.loadingStats.totalLoaded}`); * console.log(`Domain-specific (lazy): ${stats.byTier['domain-specific']}`); * console.log(`Memory savings: ${stats.loadingStats.totalUnloaded} skills unloaded`); * ``` */ getSkillPackStats(): Promise<{ success: boolean; totalSkills: number; totalWorkflows: number; totalAntiPatterns: number; byVertical: Record; byTier: { essential: number; 'domain-specific': number; advanced: number; }; loadingStats: { totalLoaded: number; totalUnloaded: number; loadedDomains: string[]; }; }>; /** * Discover API endpoints via fuzzing (FUZZ-001) * * Proactively discovers API endpoints by testing common path patterns. * Once discovered, APIs are cached and used directly for future requests, * bypassing browser rendering for 10x speedup. * * @param domain - Domain to discover APIs on (e.g., 'api.example.com') * @param options - Discovery options (paths, methods, timeouts) * @returns Discovery results with found endpoints and statistics * * @example * ```typescript * // Conservative discovery (GET only, safe) * const result = await client.discoverApis('api.github.com', { * methods: ['GET'], * learnPatterns: true, * }); * * console.log(`Discovered ${result.discovered.length} endpoints`); * console.log(`Learned ${result.stats.patternsLearned} patterns`); * * // Now browse() will use discovered APIs directly * const data = await client.browse('https://api.github.com/users/octocat'); * ``` * * @example * ```typescript * // Aggressive discovery (all methods) * const result = await client.discoverApis('api.example.com', { * methods: ['GET', 'POST', 'PUT', 'DELETE'], * paths: ['/api', '/api/v1', '/graphql'], * probeTimeout: 5000, * maxDuration: 60000, * }); * ``` */ discoverApis(domain: string, options?: FuzzDiscoveryOptions): Promise; /** * Get all content change predictions, sorted by urgency * * Returns patterns with calendar triggers, seasonal patterns, and * recommended polling intervals based on urgency levels. * * @param options - Filter options * @returns Predictions result with patterns and summary * * @example * ```typescript * // Get all predictions * const result = await client.getPredictions(); * console.log(`${result.data.summary.totalPatterns} patterns tracked`); * console.log(`${result.data.summary.byUrgency.critical} critical urgency`); * * // Filter by minimum urgency (2 = high, 3 = critical) * const urgent = await client.getPredictions({ minUrgency: 2 }); * for (const pattern of urgent.data.patterns) { * console.log(`${pattern.domain}: ${pattern.nextPrediction?.reason}`); * } * * // Filter by domain * const govPatterns = await client.getPredictions({ domain: 'gov.es' }); * ``` */ getPredictions(options?: { /** Minimum urgency level (0-3) */ minUrgency?: UrgencyLevel; /** Filter by domain (partial match) */ domain?: string; }): Promise; /** * Get predictions for a specific domain * * @param domain - Domain to get predictions for * @returns Domain predictions with full pattern details * * @example * ```typescript * const result = await client.getPredictionsByDomain('extranjeros.inclusion.gob.es'); * for (const pattern of result.data.patterns) { * console.log(`${pattern.urlPattern}: urgency ${pattern.urgencyLevel}`); * if (pattern.calendarTriggers?.length) { * console.log(` Calendar triggers: ${pattern.calendarTriggers.map(t => `${t.month}/${t.dayOfMonth}`).join(', ')}`); * } * } * ``` */ getPredictionsByDomain(domain: string): Promise; /** * Get prediction accuracy statistics for a domain * * @param domain - Domain to get accuracy stats for * @param urlPattern - Optional URL pattern filter * @returns Accuracy statistics * * @example * ```typescript * const stats = await client.getPredictionAccuracy('gov.es'); * console.log(`Success rate: ${(stats.data.accuracy.successRate * 100).toFixed(1)}%`); * console.log(`Average error: ${stats.data.accuracy.averageErrorHours?.toFixed(1)} hours`); * ``` */ getPredictionAccuracy(domain: string, urlPattern?: string): Promise; /** * Get all patterns at or above a specific urgency level * * Urgency levels: * - 0: Low (static content, rarely changes) * - 1: Normal (regular patterns detected) * - 2: High (change predicted within recommended poll interval) * - 3: Critical (calendar trigger within 7 days) * * @param level - Minimum urgency level (0-3) * @returns Patterns at or above the specified urgency * * @example * ```typescript * // Get critical urgency patterns (calendar triggers soon) * const critical = await client.getUrgentPredictions(3); * for (const pattern of critical.data.patterns) { * console.log(`URGENT: ${pattern.domain} - ${pattern.nextPrediction?.reason}`); * } * * // Get high+ urgency for refresh scheduling * const highPriority = await client.getUrgentPredictions(2); * for (const pattern of highPriority.data.patterns) { * scheduleRefresh(pattern.domain, pattern.recommendedPollIntervalMs); * } * ``` */ getUrgentPredictions(level: UrgencyLevel): Promise; /** * Record a content observation for prediction learning * * Call this after checking content to train the prediction model. * The system will track changes and improve future predictions. * * @param domain - Domain of the content * @param urlPattern - URL pattern being observed * @param contentHash - Hash of the current content * @param changed - Whether the content changed since last observation * @returns Updated pattern with new predictions * * @example * ```typescript * // After checking content * const newHash = hashContent(pageContent); * const changed = newHash !== previousHash; * * const result = await client.recordObservation( * 'extranjeros.inclusion.gob.es', * '/es/informacion/nie', * newHash, * changed * ); * * console.log(`Next predicted change: ${result.data.pattern.nextPrediction?.reason}`); * console.log(`Recommended poll: ${result.data.pattern.recommendedPollIntervalMs / 3600000}h`); * ``` */ recordObservation(domain: string, urlPattern: string, contentHash: string, changed: boolean): Promise; } /** * Create an Unbrowser client for cloud API access * * @example * ```typescript * import { createUnbrowser } from '@unbrowser/core'; * * const client = createUnbrowser({ * apiKey: 'ub_live_xxxxx', * }); * * const result = await client.browse('https://example.com'); * console.log(result.content.markdown); * ``` */ export declare function createUnbrowser(config: UnbrowserConfig): UnbrowserClient; //# sourceMappingURL=http-client.d.ts.map