/** * Source Manager * * Manages sources within NotebookLM notebooks (list, add, remove). */ import type { Page } from "patchright"; import { AuthManager } from "../auth/auth-manager.js"; import { SharedContextManager } from "../session/shared-context-manager.js"; import type { NotebookSource } from "./types.js"; export interface SourceInfo { id: string; title: string; type: "url" | "text" | "file" | "drive" | "unknown"; status: "ready" | "processing" | "failed" | "unknown"; } export interface ListSourcesResult { sources: SourceInfo[]; count: number; notebookUrl: string; } export interface AddSourceResult { success: boolean; source?: SourceInfo; error?: string; } export interface RemoveSourceResult { success: boolean; removedId?: string; error?: string; } export declare class SourceManager { private authManager; private contextManager; private page; private opChain; constructor(authManager: AuthManager, contextManager: SharedContextManager); /** * Serialize a public operation onto the op chain so concurrent invocations do * not race on the shared this.page field. Failures of one operation must not * poison the chain for the next, so the chain link always resolves. */ private runExclusive; /** * Derive a STABLE source id from a DOM identity attribute when available, * otherwise from a hash of the (title, occurrence) pair. Hashing the title * gives an id that denotes the same source across sessions far better than a * raw enumeration index, while staying opaque/stable for the removeSource * contract. Occurrence disambiguates equal-titled rows within one listing. */ private deriveSourceId; /** * Navigate to a notebook and ensure we're on the right page */ private navigateToNotebook; /** * List all sources in a notebook */ listSources(notebookUrl: string): Promise; private listSourcesInternal; /** * Add a source to an existing notebook */ addSource(notebookUrl: string, source: NotebookSource): Promise; private addSourceInternal; /** * Remove a source from a notebook */ removeSource(notebookUrl: string, sourceId: string): Promise; private removeSourceInternal; /** * Internal: Add URL source */ private addUrlSourceInternal; /** * Internal: Add text source */ private addTextSourceInternal; private findValidTextInputSelectorOnPage; /** * Internal: Add file source * December 2025: NotebookLM creates a hidden input[type="file"] AFTER clicking * the "choose file" button. The key is: click first, then find the input. */ private addFileSourceInternal; /** * Wait for source processing to complete. * * Returns an honest status: * - "failed" — an error alert/toast appeared * - "ready" — the processing indicator cleared (positive completion) * - "processing" — we timed out before any conclusion (do NOT report "ready") */ private waitForSourceProcessing; /** * Detect an error alert/toast for a source. Returns the error text if found, * otherwise null. Mirrors NotebookCreationSourceManager.throwIfSourceErrorAlert. */ private detectSourceErrorAlert; /** * Close the page if open */ private closePage; } export declare class NotebookCreationSourceManager { private getPage; constructor(getPage: () => Page | null); addSource(source: NotebookSource): Promise; getSourceDescription(source: NotebookSource): string; private requirePage; private isSourceDialogOpen; private tryAddSourceByAria; private tryAddSourceByClass; private tryAddSourceByJs; private clickAddSource; private addUrlSource; private addTextSource; private tryFileUploadViaTrigger; private addFileSource; private clickSourceTypeByText; private findValidTextInputSelector; private getVisibleSourceOptions; private getVisibleTextareas; private clickDialogSubmit; private waitForSourceProcessing; private throwIfSourceErrorAlert; }