import { type Response } from "playwright-core"; import { FastMossSelectionSessions } from "./fastmoss-selection-session.js"; import type { SelectionConfig } from "./fastmoss-opportunity.js"; export type FastMossRankingSource = "new" | "hot" | "video" | "sales"; export type FastMossPhase = "idle" | "saved" | "launching" | "login_required" | "ready" | "verification_required" | "membership_expired" | "error"; export type FastMossStatus = { phase: FastMossPhase; browserOpen: boolean; authenticated: boolean; verificationRequired: boolean; membershipExpired: boolean; message: string; url: string | null; captured: number; lastCapture?: string; }; type CaptureContext = { market?: string; category?: string; categories?: string[]; shopType?: string; periodDays?: number; }; type VideoLearningCaptureContext = { market?: string; target?: number; }; type VideoLearningDimension = "commerce-video" | "high-sales" | "high-roas" | "high-exposure" | "high-engagement"; type VisibleVideoItem = { text: string; links: string[]; media: string[]; images: string[]; headers: string[]; cells: string[]; previewIndex?: number; }; export type ObservedVideoRecord = { videoId: string; authorId?: string; title?: string; sourceUrl?: string; thumbnailUrl?: string; metrics?: Record; }; export declare class FastMossIntegration { private context; private page; private phase; private authenticated; private verificationRequired; private membershipExpired; private message; private captured; private lastCapture?; private lastMembershipCheckAt; private readonly profileDir; private readonly authenticatedMarker; private readonly dataDir; private selectionPage; readonly selection: FastMossSelectionSessions; private savedAuthenticated; private observedVideoRecords; private videoResponseTasks; private observedVideoPages; constructor(); startSelection(id: string, config: Partial, resume?: boolean): Promise<{ candidates: { source: string; sourceProductId: string; platformProductId: string; title: string; market: string; category: string; storeName: string; productUrl: string; imageUrls: string[]; metrics: { strategy: "fastmoss-evidence-v2"; selectionSessionId: string; selectionDecision: "test" | "watch" | "skip"; selectionEligible: boolean; portfolioSelected: boolean; selectionReasons: string[]; selectionRisks: string[]; sales: number | null; growthPercent: number | null; price: number | null; currency: string | null; captureDate: string; sourceVerified: boolean; opportunityAssessment: import("./fastmoss-opportunity.js").Assessment; opportunityEvidence: import("./fastmoss-opportunity.js").ProductEvidence; }; }[]; id: string; config: SelectionConfig; createdAt: string; updatedAt: string; phase: "collecting" | "reviewing" | "complete" | "interrupted"; active: boolean; completedRankings: import("./fastmoss-opportunity.js").Ranking[]; rankingErrors: Partial>; products: import("./fastmoss-opportunity.js").ProductEvidence[]; error?: string; } | null>; private selectionBrowser; status(): FastMossStatus; start(): Promise; inspect(): Promise; capture(input?: CaptureContext): Promise<{ records: Record[]; allRows: Record[]; trendProducts: number; detailFailures: number; interrupted: boolean; phase: FastMossPhase; browserOpen: boolean; authenticated: boolean; verificationRequired: boolean; membershipExpired: boolean; message: string; url: string | null; captured: number; lastCapture?: string; } | { records: Record[]; allRows: Record[]; trendProducts: number; detailFailures: number; phase: FastMossPhase; browserOpen: boolean; authenticated: boolean; verificationRequired: boolean; membershipExpired: boolean; message: string; url: string | null; captured: number; lastCapture?: string; }>; /** * Reuse the exact same local, persistent FastMoss browser used by product selection. * This reads only visible ranking pages and visible media elements. It never creates * private FastMoss API requests and pauses for the operator when a CAPTCHA appears. */ captureLearningVideos(input?: VideoLearningCaptureContext): Promise<{ sources: Record[]; rejected: { dimension: VideoLearningDimension; reason: string; }[]; requestedTarget: number; complete: boolean; phase: FastMossPhase; browserOpen: boolean; authenticated: boolean; verificationRequired: boolean; membershipExpired: boolean; message: string; url: string | null; captured: number; lastCapture?: string; }>; close(): Promise; observations(): Promise<{ rows: Record[]; }>; /** * Capture timestamped visual evidence from a public TikTok work. This is * deliberately separate from ranking collection: the learning pipeline * must see the actual moving picture, never a FastMoss cover or HTML page. */ capturePublicVideoFrames(sourceUrl: string, expectedVideoId?: string): Promise<{ videoId: string; playerUrl: string; durationMs: number; frames: { timestampMs: number; dataUrl: string; }[]; }>; switchAccount(): Promise; private loadRows; private useLatestPage; private openProductRanking; private waitForManualVerification; private openVideoLearningPage; private readVideoLearningItems; /** * AI ranking cards expose their TikTok video id only through the visible * preview action. Open only the cards needed for this batch, capture the * public FastMoss video-detail URL, and close the temporary tab again. */ private resolveVideoLearningCardLinks; private resetObservedVideoRecords; private observeVideoRankingResponses; private waitForVideoResponseTasks; private waitForObservedVideoRecords; private clickVideoLearningTab; private clickVideoLearningNextPage; private waitForVideoLearningNavigation; } export declare function waitForFastMossVerificationClear(inspect: () => Promise>, options?: { timeoutMs?: number; pollMs?: number; sleep?: (milliseconds: number) => Promise; }): Promise; export declare function videoEvidenceTimestamps(durationMs: number): number[]; export declare function fastMossSalesRankUrl(market?: string): string; export declare function fastMossRankingUrl(source: FastMossRankingSource, market?: string): string; export declare function fastMossVideoLearningRankUrl(market?: string): string; export declare function fastMossAiVideoLearningRankUrl(market?: string): string; export declare function mergeRankingRecord(target: Map>, row: Record, source: FastMossRankingSource, position: number): void; export declare function selectDetailCandidates(records: Array>, limit?: number): Record[]; export declare function isTransientFastMossNavigation(error: unknown): boolean; export declare function isVideoRankingResponse(response: Response | string): boolean; export declare function publicVideoRecordsFromRankPayload(payload: unknown): ObservedVideoRecord[]; export declare function videoLearningSourcesFromObservedRecords(records: ObservedVideoRecord[], context: { market: string; dimension: VideoLearningDimension; observedAt: string; }): { source: string; platform: string; platformVideoId: string; sourceUrl: string; market: string; rankingDimension: VideoLearningDimension; rank: number; title: string; productTitle: string; thumbnailUrl: string | null; metrics: Record; observedAt: string; }[]; export declare function isAnalyzableVideoUrl(value: string): boolean; export declare function isFastMossVideoDetailUrl(value: string): boolean; export declare function publicTikTokVideoUrlFromFastMoss(value: string): string; export declare function videoLearningSourcesFromItems(items: VisibleVideoItem[], context: { market: string; dimension: VideoLearningDimension; observedAt: string; }): Record[]; export declare function productIdFromUrl(value: string): string; /** Extract only the evidence required by the AI short-video selection model. */ export declare function detailOverviewEvidence(overviewPayload: unknown, basePayload?: unknown): { recentVideoSales: number; recentLiveSales: number; recentCreatorCount: number; recentVideoCount: number; recentLiveCount: number; videoTransactionShare: number | null; liveTransactionShare: number | null; adSalesShare: number | null; organicTrafficShare: number | null; creatorAdds: number; videoAdds: number; stock: number; rating: number; reviewCount: number; totalCreatorCount: number; totalVideoCount: number; totalLiveCount: number; viralIndex: number; popularityIndex: number; countryRank: number; categoryRank: number; launchTime: number; commission: number | null; }; export declare function detailTrendRows(record: Record, payload: unknown, days?: number): { date: string; source: string; units_sold: number; gmv: number; creators: number; price: number; currency: string; period_days: number; recentVideoSales: number; recentLiveSales: number; recentCreatorCount: number; recentVideoCount: number; recentLiveCount: number; videoTransactionShare: number | null; liveTransactionShare: number | null; adSalesShare: number | null; organicTrafficShare: number | null; creatorAdds: number; videoAdds: number; stock: number; rating: number; reviewCount: number; totalCreatorCount: number; totalVideoCount: number; totalLiveCount: number; viralIndex: number; popularityIndex: number; countryRank: number; categoryRank: number; launchTime: number; commission: number | null; }[]; export {};